内核中每种处理器架构抽象为一个proc_info_list结构体,在arch/arm/include/asm/procinfo.h中定义,
struct proc_info_list { unsigned int cpu_val; unsigned int cpu_mask; unsigned long __cpu_mm_mmu_flags; /* used by head.S */ unsigned long __cpu_io_mmu_flags; /* used by head.S */ unsigned long __cpu_flush; /* used by head.S */ const char *arch_name; const char *elf_name; unsigned int elf_hwcap; const char *cpu_name; struct processor *proc; struct cpu_tlb_fns *tlb; struct cpu_user_fns *user; struct cpu_cache_fns *cache; };
proc_info_list结构体的实现与处理器架构相关,这里以arch/arm/mm/proc-v6.S为例,
/* * Match any ARMv6 processor core. */ .type __v6_proc_info, #object __v6_proc_info: .long 0x0007b000 /*unsigned int cpu_val*/ .long 0x0007f000 /*unsigned int cpu_mask*/ /*unsigned long __cpu_mm_mmu_flags; used by head.S */ .long PMD_TYPE_SECT | PMD_SECT_BUFFERABLE | PMD_SECT_CACHEABLE | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ /*unsigned long __cpu_io_mmu_flags; used by head.S */ .long PMD_TYPE_SECT | PMD_SECT_XN | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ /*unsigned long __cpu_flush; used by head.S */ b __v6_setup .long cpu_arch_name /*const char *arch_name;*/ .long cpu_elf_name /*const char *elf_name;*/ /*unsigned int elf_hwcap;*/ .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_JAVA .long cpu_v6_name /*const char *cpu_name;*/ .long v6_processor_functions /*struct processor *proc*/ .long v6wbi_tlb_fns /*struct cpu_tlb_fns *tlb*/ .long v6_user_fns /*struct cpu_user_fns *user*/ .long v6_cache_fns /*struct cpu_cache_fns *cache*/ .size __v6_proc_info, . - __v6_proc_info
1. cpu_val,cpu_mask
用于匹配下面的协处理指令读出的cupID。
MRC p15,0,<Rd>,c0,c0,0 ;Read Main ID Register
2.__cpu_flush,arch/arm/mm/proc-v6.S
/* * __v6_setup * * Initialise TLB, Caches, and MMU state ready to switch the MMU * on. Return in r0 the new CP15 C1 control register setting. * * We automatically detect if we have a Harvard cache, and use the * Harvard cache control instructions insead of the unified cache * control instructions. * * This should be able to cover all ARMv6 cores. * * It is assumed that: * - cache type register is implemented */ __v6_setup: #ifdef CONFIG_SMP mrc p15, 0, r0, c1, c0, 1 @ Enable SMP/nAMP mode orr r0, r0, #0x20 mcr p15, 0, r0, c1, c0, 1 #endif mov r0, #0 mcr p15, 0, r0, c7, c14, 0 @ clean+invalidate D cache mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache mcr p15, 0, r0, c7, c15, 0 @ clean+invalidate cache mcr p15, 0, r0, c7, c10, 4 @ drain write buffer #ifdef CONFIG_MMU mcr p15, 0, r0, c8, c7, 0 @ invalidate I + D TLBs mcr p15, 0, r0, c2, c0, 2 @ TTB control register orr r4, r4, #TTB_FLAGS mcr p15, 0, r4, c2, c0, 1 @ load TTB1 #endif /* CONFIG_MMU */ adr r5, v6_crval ldmia r5, {r5, r6} mrc p15, 0, r0, c1, c0, 0 @ read control register bic r0, r0, r5 @ clear bits them orr r0, r0, r6 @ set them mov pc, lr @ return to head.S:__ret
3. arch_name
.type cpu_arch_name, #object cpu_arch_name: .asciz "armv6" .size cpu_arch_name, . - cpu_arch_name
4.elf_name
.type cpu_elf_name, #object cpu_elf_name: .asciz "v6" .size cpu_elf_name, . - cpu_elf_name .align
5.cpu_name
cpu_v6_name: .asciz "ARMv6-compatible processor" .align
6.struct processor *proc
该结构体在在arch/arm/include/asm/procinfo.h中声明,
struct processor;
在include/asm-arm/cpu-multi32.h中定义,是一系列函数指针的结构体。
/* * Don't change this structure - ASM code * relies on it. */ extern struct processor { /* MISC * get data abort address/flags */ void (*_data_abort)(unsigned long pc); /* * Retrieve prefetch fault address */ unsigned long (*_prefetch_abort)(unsigned long lr); /* * Set up any processor specifics */ void (*_proc_init)(void); /* * Disable any processor specifics */ void (*_proc_fin)(void); /* * Special stuff for a reset */ void (*reset)(unsigned long addr) __attribute__((noreturn)); /* * Idle the processor */ int (*_do_idle)(void); /* * Processor architecture specific */ /* * clean a virtual address range from the * D-cache without flushing the cache. */ void (*dcache_clean_area)(void *addr, int size); /* * Set the page table */ void (*switch_mm)(unsigned long pgd_phys, struct mm_struct *mm); /* * Set a possibly extended PTE. Non-extended PTEs should * ignore 'ext'. */ void (*set_pte_ext)(pte_t *ptep, pte_t pte, unsigned int ext); } processor;
这些函数指针在arch/arm/mm/proc-v6.S中指定,
.type v6_processor_functions, #object ENTRY(v6_processor_functions) .word v6_early_abort .word pabort_noifar .word cpu_v6_proc_init .word cpu_v6_proc_fin .word cpu_v6_reset .word cpu_v6_do_idle .word cpu_v6_dcache_clean_area .word cpu_v6_switch_mm .word cpu_v6_set_pte_ext .size v6_processor_functions, . - v6_processor_functions
7.struct cpu_tlb_fns *tlb
该结构体在在arch/arm/include/asm/procinfo.h中声明
struct cpu_tlb_fns;
在arch/arm/include/asm/tlbflush.h中定义,
struct cpu_tlb_fns { void (*flush_user_range)(unsigned long, unsigned long, struct vm_area_struct *); void (*flush_kern_range)(unsigned long, unsigned long); unsigned long tlb_flags; };
具体函数实现在arm/arm/mm/tlb-v6.S
.type v6wbi_tlb_fns, #object ENTRY(v6wbi_tlb_fns) .long v6wbi_flush_user_tlb_range .long v6wbi_flush_kern_tlb_range .long v6wbi_tlb_flags .size v6wbi_tlb_fns, . - v6wbi_tlb_fns
8.struct cpu_user_fns *user
该结构体在在arch/arm/include/asm/procinfo.h中声明
struct cpu_user_fns;
在arch/arm/include/asm/page.h中定义
struct cpu_user_fns { void (*cpu_clear_user_highpage)(struct page *page, unsigned long vaddr); void (*cpu_copy_user_highpage)(struct page *to, struct page *from, unsigned long vaddr); };
具体函数实现在arm/arm/mm/copypage-v6.S
struct cpu_user_fns v6_user_fns __initdata = { .cpu_clear_user_highpage = v6_clear_user_highpage_nonaliasing, .cpu_copy_user_highpage = v6_copy_user_highpage_nonaliasing, };
9.struct cpu_cache_fns *cache
该结构体在在arch/arm/include/asm/procinfo.h中声明
struct cpu_cache_fns;
在arch/arm/include/asm/cacheflush.h中定义,是包含一系列函数指针的结构体
struct cpu_cache_fns { void (*flush_kern_all)(void); void (*flush_user_all)(void); void (*flush_user_range)(unsigned long, unsigned long, unsigned int); void (*coherent_kern_range)(unsigned long, unsigned long); void (*coherent_user_range)(unsigned long, unsigned long); void (*flush_kern_dcache_page)(void *); void (*dma_inv_range)(const void *, const void *); void (*dma_clean_range)(const void *, const void *); void (*dma_flush_range)(const void *, const void *); };
具体函数实现在arm/arm/mm/cache-v6.S
.type v6_cache_fns, #object ENTRY(v6_cache_fns) .long v6_flush_kern_cache_all .long v6_flush_user_cache_all .long v6_flush_user_cache_range .long v6_coherent_kern_range .long v6_coherent_user_range .long v6_flush_kern_dcache_page .long v6_dma_inv_range .long v6_dma_clean_range .long v6_dma_flush_range .size v6_cache_fns, . - v6_cache_fns