经历过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, #objectv7_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}
Original: https://www.cnblogs.com/yifeichongtian2021/p/15512262.html
Author: 壹飞冲天
Title: Linux ARMv7中断向量表搬移(2)【转】
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/585777/
转载文章受原作者版权保护。转载请注明原作者出处!