历史上的今天
今天是:2024年11月24日(星期日)
2021年11月24日 | Linux ARMv7中断向量表搬移(2)
2021-11-24 来源:eefocus
一. Linux ARMv7启动阶段对中断向量表的搬移
1、中断向量表和中断处理部分代码的搬移
经历过kernel的汇编阶段,进入C语言start_kernel后对中断向量表的位置进行搬移,搬移函数是early_trap_init。
early_trap_init函数的调用流程为:
start_kernel(init/main.c)--->setup_arch(arch/arm/kernel/setup.c)--->paging_init(arch/arm/mm/mmu.c)--->devicemaps_init(arch/arm/mm/mmu.c)--->early_trap_init(arch/arm/kernel/traps.c)
/*
* Set up the device mappings. Since we clear out the page tables for all
* mappings above VMALLOC_START, except early fixmap, we might remove debug
* device mappings. This means earlycon can be used to debug this function
* Any other function or debugging method which may touch any device _will_
* crash the kernel.
*/
static void __init devicemaps_init(const struct machine_desc *mdesc)
{
struct map_desc map;
unsigned long addr;
void *vectors;
/*
* Allocate the vector page early.
*分配两个页的内存空间,arm中每个页的大小为4K,这两个页的内存空间,一个是为保存中断向量
*表,一个是为了保存中断的处理部分代码,这两部分代码的排布可以在
*(arch/arm/kernel/vmlinux.lds和arch/arm/kernel/entry-armv.S)中可以具体分析出来
*/
vectors = early_alloc(PAGE_SIZE * 2);
early_trap_init(vectors);
/*
* Clear page table except top pmd used by early fixmaps
*/
for (addr = VMALLOC_START; addr < (FIXADDR_TOP & PMD_MASK); addr += PMD_SIZE)
pmd_clear(pmd_off_k(addr));
/*
* Map the kernel if it is XIP.
* It is always first in the modulearea.
*/
#ifdef CONFIG_XIP_KERNEL //此宏未定义
map.pfn = __phys_to_pfn(CONFIG_XIP_PHYS_ADDR & SECTION_MASK);
map.virtual = MODULES_VADDR;
map.length = ((unsigned long)_etext - map.virtual + ~SECTION_MASK) & SECTION_MASK;
map.type = MT_ROM;
create_mapping(&map);
#endif
/*
* Map the cache flushing regions.
*/
#ifdef FLUSH_BASE //此宏未定义
map.pfn = __phys_to_pfn(FLUSH_BASE_PHYS);
map.virtual = FLUSH_BASE;
map.length = SZ_1M;
map.type = MT_CACHECLEAN;
create_mapping(&map);
#endif
#ifdef FLUSH_BASE_MINICACHE //此宏未定义
map.pfn = __phys_to_pfn(FLUSH_BASE_PHYS + SZ_1M);
map.virtual = FLUSH_BASE_MINICACHE;
map.length = SZ_1M;
map.type = MT_MINICLEAN;
create_mapping(&map);
#endif
/*
* Create a mapping for the machine vectors at the high-vectors
* location (0xffff0000). If we aren't using high-vectors, also
* create a mapping at the low-vectors virtual address.
*/
/*
*创建一个页的内存地址映射,虚拟地址为0xffff0000,此地址为中断向量表的高端地址
*设置中断向量表的高端地址在汇编的v7_setup中,使用的v7_crval设置了cp15的c1寄存器
*v7_crval定义在arch/arm/mm/proc-v7-2level.S。
*/
map.pfn = __phys_to_pfn(virt_to_phys(vectors));
map.virtual = 0xffff0000;
map.length = PAGE_SIZE;
#ifdef CONFIG_KUSER_HELPERS //此宏有定义
map.type = MT_HIGH_VECTORS;
#else
map.type = MT_LOW_VECTORS;
#endif
create_mapping(&map);
/*
*判断中断向量表的位置是否设置在高端地址,如果中断向量表没有设置在高端地址,
*在映射低端中断向量表地址。
*/
if (!vectors_high()) {
map.virtual = 0;
map.length = PAGE_SIZE * 2;
map.type = MT_LOW_VECTORS;
create_mapping(&map);
}
/* Now create a kernel read-only mapping */
map.pfn += 1;
map.virtual = 0xffff0000 + PAGE_SIZE;
map.length = PAGE_SIZE;
map.type = MT_LOW_VECTORS;
create_mapping(&map);
/*
* Ask the machine support to map in the statically mapped devices.
*/
if (mdesc->map_io)
mdesc->map_io();
else
debug_ll_io_init();
fill_pmd_gaps();
/* Reserve fixed i/o space in VMALLOC region */
pci_reserve_io();
/*
* Finally flush the caches and tlb to ensure that we're in a
* consistent state wrt the writebuffer. This also ensures that
* any write-allocated cache lines in the vector page are written
* back. After this point, we can start to touch devices again.
*/
local_flush_tlb_all();
flush_cache_all();
/* Enable asynchronous aborts */
early_abt_enable();
}
/* AT
* TFR EV X F I D LR S
* .EEE ..EE PUI. .T.T 4RVI ZWRS BLDP WCAM
* rxxx rrxx xxx0 0101 xxxx xxxx x111 xxxx < forced
* 01 0 110 0011 1100 .111 1101 < we want
*/
.align 2
.type v7_crval, #object
v7_crval:
crval clear=0x2120c302, mmuset=0x10c03c7d, ucset=0x00c01c7c
early_trap_init函数的分析
void __init early_trap_init(void *vectors_base)
{
#ifndef CONFIG_CPU_V7M
unsigned long vectors = (unsigned long)vectors_base;
extern char __stubs_start[], __stubs_end[];
extern char __vectors_start[], __vectors_end[];
unsigned i;
vectors_page = vectors_base;
/*
* Poison the vectors page with an undefined instruction. This
* rly_trap_init instruction is chosen to be undefined for both ARM and Thumb
* ISAs. The Thumb version is an undefined instruction with a
* branch back to the undefined instruction.
* 将申请的4K先设置为未定义指令,防止在发生其他中断时,没有处理导致cpu错误
*/
for (i = 0; i < PAGE_SIZE / sizeof(u32); i++)
((u32 *)vectors_base)[i] = 0xe7fddef1;/*
* Copy the vectors, stubs and kuser helpers (in entry-armv.S)
* into the vector page, mapped at 0xffff0000, and ensure these
* are visible to the instruction stream.
*/
/*
*将中断向量表和中断处理的代码搬移到申请的两页地址空间内
*/
memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
memcpy((void *)vectors + 0x1000, __stubs_start, __stubs_end - __stubs_start);
kuser_init(vectors_base);
flush_icache_range(vectors, vectors + PAGE_SIZE * 2);
#else /* ifndef CONFIG_CPU_V7M */
/*
* on V7-M there is no need to copy the vector table to a dedicated
* memory area. The address is configurable and so a table in the kernel
* image can be used.
*/
#endif
}
史海拾趣
|
请教如下两个问题: 1. synplify不能综合状态机的“when others”状态:我用的是VHDL,编码风格中要求对case语句的使用要做到取值完全覆盖,即要加一个“when others”的判断(我想Verilog也一样吧,用default?),用c ...… 查看全部问答> |
|
我刚学PROTEL,如果是一个有很多元件的双层板或者是三层板。如何布线呢。 能不能选中一层后,隐藏掉其他层的线啊,密密麻麻的看的眼花啊。 大哥大姐,我新手,没分啊,多谢了… 查看全部问答> |
|
个人补充说明 在其他ARM上实现了1588 PTP协议的软件实现,但是由于芯片不支持1588协议,精度不够,所以改在8962加入硬件时间标记,达到微秒级对时精度要求。… 查看全部问答> |
|
我使用STM32F103VC的芯片跑UCOS。但是执行了如下的代码就是进入不了PendSV_Handler。用软件仿真还是可以的,但是烧到板上就不可以了。执行这段代码的时候BASEPRI = 0,PRIMASK = 0.这应该没有关中断吧。为什么就是进入不了 ...… 查看全部问答> |




