一. 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
}
上一篇:I2C协议->裸机程序->adapter驱动程序分析
下一篇:linux arm mmu基础
推荐阅读最新更新时间:2024-10-28 10:50
设计资源 培训 开发板 精华推荐
- 【RA】瑞萨RA2E1@Cortex-M23
- AD5335 并行接口、四路电压输出、10 位 DAC 的典型应用
- LTC3728LCUH 双通道、550kHz、2 相同步稳压器的典型应用电路
- Simple-FOC-V1.0
- 【 新版本】 USB转TTL
- 101020639,Grove - 3 轴数字加速度计 ±40g (ADXL357) 评估套件
- EVAL-AD7785EBZ,AD7785 评估板,20 位,470SPS,用于热电偶的 3CH ADC
- 智能动态天气多彩桌面时钟
- LT4276CHUFD 25.5W(类型 2)PoE+ 电源在反激模式下的典型应用电路,具有 24V、1A 输出
- LTC3832-1,一款 7A 时的紧凑型 5V 至 1V 电源