RISC-V LinuxÆô¶¯Ö®Ò³±í½¨ÉèÆÊÎö
ÉÏƪÆÊÎöÁËRISC-V LinuxµÄ»ã±àÆô¶¯Àú³Ì£¬ÆäÖн²µ½ÁËrelocateÖض¨ÏòÐèÒª¿ªÆôMMU£¬½ñÌìÆÊÎöRISC-V LinuxµÄÒ³±í½¨Éè¡£
×¢ÖØ£º±¾ÎÄ»ùÓÚlinux5.10.111ÄÚºË
sv39 mmu
RISC-V LinuxÖ§³Ösv32¡¢sv39¡¢sv48µÈÐéÄâµØµãÃûÌ㬻®·Ö´ú±í32ΪÐéÄâµØµã¡¢38λÐéÄâµØµãºÍ48λÐéÄâµØµã¡£RISC-V LinuxĬÈÏÒ²ÊÇʹÓÃsv39ÃûÌã¬sv39µÄÐéÄâµØµã¡¢ÎïÀíµØµã¡¢PTEÃûÌÃÈçÏ£º
ÐéÄâµØµãÃûÌãº
ÎïÀíµØµãÃûÌãº
PTE̞틼
ÐéÄâµØµãʹÓÃ39λÌåÏÖ£¬ÆäÖеÍ12λ´ú±ípage offset£¬¸ßλ»®·ÖΪÁËÈý²¿·Ö£ºVP N[0]¡¢VP N[1]ºÍVP N[2]£¬»®·Ö´ú±íÐéÄâµØµãVAÔÚPTE¡¢PMDºÍPGDÖеÄË÷Òý¡£
ÎïÀíµØµãʹÓÃ56λÌåÏÖ£¬µÍ12λ´ú±ípage offset£¬¸ßλÊÇÎïÀíÒ³PPN[0]¡¢PPN[1]ºÍPPN[2]
PTEÉúÑÄÁËÎïÀíÒ³PPN[0]¡¢PPN[1]ºÍPPN[2]£¬ºÍÎïÀíµØµãÖеÄPPNÏà¶ÔÓ¦£»PTEµÄµÍ10λ´ú±íÎïÀíµØµãµÄ»á¼ûȨÏÞ£¬µ±RWXȫΪ0ʱ£¬Ôò´ú±í¸ÃPTE´æ´¢µÄµØµãÊÇÏÂÒ»¼¶Ò³±íµÄÎïÀíµØµã£¬²»È»´ú±íÄ¿½ñÒ³±íÊÇ×îºóÒ»¼¶Ò³±í¡£
ÔÙ¿´¿´sv39 µÄÒ³±íÃûÌã¬sv39ʹÓõÄÊÇÈý¼¶Ò³±í£¬PGD¡¢PMDºÍPTE£¬Ã¿Ò»¸ö¼¶Ò³±íʹÓÃ9bitÌåÏÖ£¬¼´Ã¿Ò»¼¶Ò³±í¶¼ÓÐ512¸öÒ³±íÏî¡£
ÔÚ´úÂëÖУ¬½¨ÉèÒ»¸öÓÐ512¸öÔªËصÄÊý×é¼´´ú±íÒ»¸öÒ³±í¡£Ò»¸öPTEÓÐ512¸öÒ³±íÏÿһ¸öÒ³±íÏîÕ¼ÓÃ8×Ö½Ú£¬512*8=4096×Ö½Ú£¬ÒÔÊÇÒ»¸öPTE´ú±í4K¡£Ò»¸öPMDÒ²ÊÇ512¸öÒ³±íÏÿһÏî¿É´ú±íÒ»¸öPTE£¬512 *4 K=2M£¬ÒÔÊÇÒ»¸öPMD¾Í´ú±í2M¡£ÒÔ´ËÀàÍÆ£¬Ò»¸öPGD´ú±í512 * 2M=1G¡£
Ö÷Òª½áÂÛ£ºPGD´ú±í1G¡¢PMD´ú±í2M¡¢PTE´ú±í4K¡£sv39ĬÈϵÄÒ³¾ÞϸÊÇ4K¡£
Èý¼¶Ò³±íÐéÄâµØµãתΪÎïÀíµØµãÀú³ÌʾÒâͼ£º
sv39Èý¼¶Ò³±íÐéÄâµØµãתΪÎïÀíµØµãÀú³Ì£º
MMUͨ¹ýsatp¼Ä´æÆ÷»ñµÃPGDµÄÎïÀíµØµã£¬ÍŽáPGD index£¨¼´V PN[2]£©ÕÒµ½PMD£»ÕÒµ½PMDºó£¬ÔÙÍŽáPMD index£¨¼´V PN[1]£©ÕÒµ½PTE£¬È»ºóÍŽáPTE index£¨¼´V PN[0]£©»ñµÃVAÔÚPTEË÷ÒýÖеÄÖµ£¬´Ó¶ø»ñµÃÎïÀíµØµã¡£
×îºóÔÚPTEÖÐÈ¡³öPPN[2]¡¢PPN[1]ºÍPPN[0],ÔÙºÍÐéÄâµØµãµÄµÍ12λoffsetÏà¼Ó£¬»ñµÃ×îÖÕµÄÎïÀíµØµã¡£
ÔÝʱҳ±íÆÊÎö
MMU¿ªÆôÇ°£¬ÐèÒª½¨ÉèºÃkernel¡¢dtb¡¢trampolineµÈÒ³±í¡£ÒÔ±ãMMU¿ªÆôºó£¬²¢ÇÒÔÚÄÚ´æÖÎÀíÄ£¿éÔËÐÐ֮ǰ£¬kernel¿ÉÒÔÕý³£³õʼ»¯£¬dtb¿ÉÒÔÕý³£µØ±»ÆÊÎö¡£Õⲿ·ÖÒ³±í¶¼ÊÇÔÝʱҳ±í£¬×îÖÕµÄÒ³±íÔÚsetup_vm_final()½¨Éè¡£
ÔÝʱҳ±í½¨Éè˳Ðò£º
Ê×ÏÈΪfixmap½¨ÉèÔçÆÚµÄPGD¡¢PMD£¬ÕâʱPGDʹÓÃearly_pg_dir¡£È»ºó¶Ô´Ókernel×îÏȵÄÇ°2MÄڴ潨Éè¶þ¼¶Ò³±í£¬´ËʱPGDʹÓÃtrampoline_pg_dir£¬ÎªÕâ2M½¨ÉèµÄÒ³±íÒ²½Ð×÷superpage¡£ÔÙÈ»ºó£¬¶ÔÕû¸ökernel½¨Éè¶þ¼¶Ò³±í£¬´ËʱPGDʹÓÃearly_pg_dir¡£×îºóΪdtbÔ¤Áô4M¾Þϸ½¨Éè¶þ¼¶Ò³±í¡£
Ò³±í½¨É躯Êý
create_pgd_mapping()
void __init create_pgd_mapping(pgd_t *pgdp, uintptr_t va, phys_addr_t pa, phys_addr_t sz, pgprot_t prot)
µÇ¼ºó¸´ÖÆ
pgdp£ºPGDÒ³±í
va£ºÐéÄâµØµã
pa£ºÎïÀíµØµã
sz£ºÓ³Éä¾Þϸ£¬PGDIR_SIZE»òPMD_SIZE»òPTE_SIZE
prot£ºPAGE_KERNEL_EXEC/PAGE_KERNELÌåÏÖÄ¿½ñÊÇ×îºóÒ»¼¶Ò³±í£¬²»È»pa´ú±íÏÂÒ»¼¶Ò³±íµÄÎïÀíµØµã
create_pmd_mapping()
static void __init create_pmd_mapping(pmd_t *pmdp, uintptr_t va, phys_addr_t pa, phys_addr_t sz, pgprot_t prot)
µÇ¼ºó¸´ÖÆ
pmdp£ºPMDÒ³±í
va£ºÐéÄâµØµã
pa£ºÎïÀíµØµã
sz£ºÓ³Éä¾Þϸ£¬PMD_SIZE»òPAGE_SIZE
prot£ºÈ¨ÏÞ£¬PAGE_KERNEL_EXEC/PAGE_KERNELÌåÏÖÄ¿½ñÊÇ×îºóÒ»¼¶Ò³±í£¬²»È»pa´ú±íÏÂÒ»¼¶Ò³±íµÄÎïÀíµØµã
create_pte_mapping()
static void __init create_pte_mapping(pte_t *ptep, uintptr_t va, phys_addr_t pa, phys_addr_t sz, pgprot_t prot)
µÇ¼ºó¸´ÖÆ
ptep£ºPTEÒ³±í
va£ºÐéÄâµØµã
pa£ºÎïÀíµØµã
sz£ºÓ³Éä¾Þϸ£¬PAGE_SIZE
prot£ºÈ¨ÏÞ£¬PAGE_KERNEL_EXEC/PAGE_KERNELÌåÏÖÄ¿½ñÊÇ×îºóÒ»¼¶Ò³±í£¬²»È»pa´ú±íÏÂÒ»¼¶Ò³±íµÄÎïÀíµØµã
ʹÓþÙÀý
ÀýÈ磬½«ÐéÄâµØµãPAGE_OFFSETÓ³Éäµ½ÎïÀíµØµãpa£¬Ó³Éä¾ÞϸΪ4K£¬½¨ÉèÈý¼¶Ò³±íPGD¡¢PMDºÍPTE£º
create_pgd_mapping(early_pg_dir£¬PAGE_OFFSET£¬ (uintptr_t)early_pmd£¬PGDIR_SIZE,PAGE_TABLE); create_pmd_mapping(early_pmd£¬PAGE_OFFSET£¬ (uintptr_t)early_pte£¬PGDIR_SIZE,PAGE_TABLE); create_pte_mapping(early_pte£¬PAGE_OFFSET£¬ (uintptr_t)pa£¬PAGE_SIZE,PAGE_KERNEL_EXEC);
µÇ¼ºó¸´ÖÆ
ÕâÑù½¨Éèºó£¬MMU¾Í»áƾ֤PAGE_OFFSETÔÚPGDÖÐÕÒµ½PMD£¬È»ºóÔÙPMDÖÐÕÒµ½PTE£¬×îºóÈ¡³öÎïÀíµØµã¡£
Ò³±í½¨ÉèÔ´ÂëÆÊÎö
RISC-V LinuxÆô¶¯£¬ÂÄÀúÁËÁ½´ÎÒ³±í½¨ÉèÀú³Ì£¬µÚÒ»´ÎʹÓÃCº¯Êýsetup_vm()½¨ÉèÔÝʱҳ±í£¬µÚ¶þ´ÎʹÓÃCº¯Êýsetup_vm_final()½¨Éè×îÖÕÒ³±í¡£
Ïêϸϸ½Ú²Î¿¼´úÂëÖеÄ×¢ÊÍ£¬ÏÂÃæµÄ´úÂëÊ¡ÂÔÁËһЩ²»Ö÷ÒªµÄ²¿·Ö¡£
setup_vm()
asmlinkage void __init setup_vm(uintptr_t dtb_pa) { uintptr_t va, pa, end_va; uintptr_t load_pa = (uintptr_t)(&_start); uintptr_t load_sz = (uintptr_t)(&_end) - load_pa; uintptr_t map_size; //load_pa¾ÍÊÇkernel¼ÓÔصÄ×ÅʵÎïÀíµØµã //load_sz¾ÍÊÇkernelµÄÏÖʵ¾Þϸ //page_offset¾ÍÊÇkernelµÄÆðʼÎïÀíµØµã¶ÔÓ¦µÄÐéÄâµØµã£¬va_pa_offsetÊÇËûÃǵÄÆ«ÒÆÁ¿ va_pa_offset = PAGE_OFFSET - load_pa; //ÅÌËã»ñµÃkernelÆðʼÎïÀíµØµãµÄÎïÀíÒ³£¬PFN_DOWNÊǽ«ÎïÀíµØµãÓÒÒÆ12룬ÓÉÓÚsv39µÄÎïÀíµØµãµÄµÍ12λÊÇpa_offset£¬ÒÔÊÇÓÒÒÆ12룬»ñµÃpfn pfn_base = PFN_DOWN(load_pa); map_size = PMD_SIZE;//PMD_SIZEΪ2M£¬ÔÚÄ¿½ñ£¬map_sizeÖ»ÄÜΪPGDIR_SIZE»òPMD_SIZE¡£ÕâʱkernelĬÈϲ»ÔÊÐí½¨ÉèPTE¡£ //¼ì²éPAGE_OFFSETÊÇ·ñ1G¶ÔÆ룬ÒÔ¼°kernelÈë¿ÚµØµãÊÇ·ñ2M¶ÔÆë BUG_ON((PAGE_OFFSET % PGDIR_SIZE) != 0); BUG_ON((load_pa % map_size) != 0); //allc_pte_earlyÄÚÀïÊÇBUG(),¹ØÓÚÔÝʱҳ±í£¬kernel²»ÔÊÐíÎÒÃǽ¨ÉèPTE pt_ops.alloc_pte = alloc_pte_early; pt_ops.get_pte_virt = get_pte_virt_early; #ifndef __PAGETABLE_PMD_FOLDED pt_ops.alloc_pmd = alloc_pmd_early; pt_ops.get_pmd_virt = get_pmd_virt_early; #endif /* ÉèÖà early PGD for fixmap */ create_pgd_mapping(early_pg_dir, FIXADDR_START, (uintptr_t)fixmap_pgd_next, PGDIR_SIZE, PAGE_TABLE); /* ÉèÖà fixmap PMD */ create_pmd_mapping(fixmap_pmd, FIXADDR_START, (uintptr_t)fixmap_pte, PMD_SIZE, PAGE_TABLE); /* ÉèÖà trampoline PGD and PMD */ create_pgd_mapping(trampoline_pg_dir, PAGE_OFFSET, (uintptr_t)trampoline_pmd, PGDIR_SIZE, PAGE_TABLE); create_pmd_mapping(trampoline_pmd, PAGE_OFFSET, load_pa, PMD_SIZE, PAGE_KERNEL_EXEC); /* * ÉèÖÃÁýÕÖÕû¸öÄں˵ÄÔçÆÚPGD£¬Õ⽫ʹÎÒÃÇÄܹ»µÖ´ïpaging_init£¨£©¡£ * ÉÔºóÔÚÏÂÃæµÄ setup_vm_final£¨£© ÖÐÓ³ÉäËùÓÐÄÚ´æ¡£ */ end_va = PAGE_OFFSET + load_sz; for (va = PAGE_OFFSET; va < end_va; va += map_size) create_pgd_mapping(early_pg_dir, va, load_pa + (va - PAGE_OFFSET), map_size, PAGE_KERNEL_EXEC); /* Ϊdtb½¨ÉèÔçÆÚµÄPMD */ create_pgd_mapping(early_pg_dir, DTB_EARLY_BASE_VA, (uintptr_t)early_dtb_pmd, PGDIR_SIZE, PAGE_TABLE); /* Ϊ FDT ÔçÆÚɨÃ轨ÉèÁ½¸öÒ»Á¬µÄ PMD Ó³Éä */ pa = dtb_pa & ~(PMD_SIZE - 1); create_pmd_mapping(early_dtb_pmd, DTB_EARLY_BASE_VA, pa, PMD_SIZE, PAGE_KERNEL); create_pmd_mapping(early_dtb_pmd, DTB_EARLY_BASE_VA + PMD_SIZE, pa + PMD_SIZE, PMD_SIZE, PAGE_KERNEL); dtb_early_va = (void *)DTB_EARLY_BASE_VA + (dtb_pa & (PMD_SIZE - 1)); ...... }
µÇ¼ºó¸´ÖÆ
setup_vm()ÔÚ×î×îÏȾ;ÙÐÐÁËkernelÈë¿ÚµØµãµÄ¶ÔÆë¼ì²é£¬ÒªÇóÈë¿ÚµØµã2M¶ÔÆë¡£¼ÙÉèÄÚ´æÆðʼµØµãΪ0x80000000£¬ÄÇôkernelÖ»ÄÜ·ÅÔÚ0x80000000¡¢0x80200000µÈ2M¶ÔÆë´¦¡£ÎªÊ²Ã´»áÓÐÕâÖÖ¶ÔÆëÒªÇóÄØ£¿
ÎÒÍƲⴿ´âÊÇΪ¸øopensbiÔ¤ÁôÁË2M¿Õ¼ä£¬ÓÉÓÚkernel֮ǰÉÐÓÐopensbi£¬¶øopensbiÔËÐÐÍêÖ®ºó£¬Ä¬ÈÏÌøתµØµã¾ÍÊÇÆ«ÒÆ2M£¬kernelÖ»ÊÇΪÁ˸úopensbi¶ÔÓ¦£¬ÒÔÊÇÉèÖÃÁË2M¶ÔÆë¡£
ÄÇopensbiÐèÒªÕ¼ÓÃ2MÕâô´ó£¿ÏÖʵÉÏÖ»ÐèÒª¼¸°ÙKB£¬Òò´ËopensbiºÍkernelÖÐÐÄÓÐÒ»¶ÎÄÚ´æÊÇ¿ÕÏеģ¬Ã»ÓÐÈËʹÓá£Õâ¸öÎÊÌâÎÒÃÇÏÂƪÔÙ½²¡£
setup_vm_final()
Ôڸú¯ÊýÖÐ×îÏÈΪÕû¸öÎïÀíÄÚ´æ×öÄÚ´æÓ³É䣬ͨ¹ýswapperÒ³±íÀ´ÖÎÀí£¬²¢ÇÒɨ³ýµô»ã±à½×¶ÎµÄÒ³±í¡£
static void __init setup_vm_final(void) { uintptr_t va, map_size; phys_addr_t pa, start, end; u64 i; /** * ´ËʱMMUÒѾ¿ªÆô£¬¿ÉÊÇÒ³±í»¹Ã»ÍêÈ«½¨Éè¡£ */ pt_ops.alloc_pte = alloc_pte_fixmap; pt_ops.get_pte_virt = get_pte_virt_fixmap; #ifndef __PAGETABLE_PMD_FOLDED pt_ops.alloc_pmd = alloc_pmd_fixmap; pt_ops.get_pmd_virt = get_pmd_virt_fixmap; #endif /* Setup swapper PGD for fixmap */ create_pgd_mapping(swapper_pg_dir, FIXADDR_START, __pa_symbol(fixmap_pgd_next), PGDIR_SIZE, PAGE_TABLE); /* ΪÕû¸öÎïÀíÄڴ潨ÉèÒ³±í */ for_each_mem_range(i, &start, &end) { if (start >= end) break; if (start <= __pa(PAGE_OFFSET) && __pa(PAGE_OFFSET) < end) start = __pa(PAGE_OFFSET); //best_map_sizeÊÇÑ¡ÔñºÏÊʵÄÓ³Éä¾Þϸ£¬kernelÈë¿ÚµØµã2M¶ÔÆë»òÕßkernel¾ÞϸÄܱ»2MÕû³ýʱ£¬map_size¾ÍÊÇ2M£¬²»È»¾ÍÊÇ4K¡£ map_size = best_map_size(start, end - start); for (pa = start; pa < end; pa += map_size) { va = (uintptr_t)__va(pa); create_pgd_mapping(swapper_pg_dir, va, pa, map_size, PAGE_KERNEL_EXEC); } } /* ɨ³ýfixmapµÄPMDºÍPTE */ clear_fixmap(FIX_PTE); clear_fixmap(FIX_PMD); /* Çл»µ½swapperÒ³±í£¬Õâ¸öÊÇ×îÖÕµÄÒ³±í£¬»ã±à½×¶Îrelocate¿ªÆôMMUµÄ²Ù×÷£¬¸úÏÂÃæÕâ¾äÊÇÒ»ÑùµÄ¡£ */ csr_write(CSR_SATP, PFN_DOWN(__pa_symbol(swapper_pg_dir)) | SATP_MODE); local_flush_tlb_all();//Ë¢ÐÂTLB ...... }
µÇ¼ºó¸´ÖÆ
˵Ã÷£º
ÔÚsetup_vm_final()º¯ÊýÖУ¬Í¨¹ýswapper_pg_dirÒ³±íÀ´ÖÎÀíÕû¸öÎïÀíÄÚ´æµÄ»á¼û¡£²¢ÇÒɨ³ý»ã±à½×¶ÎµÄÒ³±ífixmap_pteºÍearly_pg_dir¡££¨ÊµÖÊÉϾÍÊǰѸÃÒ³±íÏîµÄÄÚÈÝÇå0£¬¼´¸³ÖµÎª0£©
×îÖÕ°Ñswapper_pg_dirÒ³±íµÄÎïÀíµØµã¸³Öµ¸øSATP¼Ä´æÆ÷¡£ÕâÑùCPU¾Í¿ÉÒÔͨ¹ý¸ÃÒ³±í»á¼ûÕû¸öÎïÀíÄÚ´æ¡£
Çл»Ò³±íͨ¹ýÈçÏÂʵÏÖ£º
csr_write(CSR_SATP,PFN_DOWN(_pa(swapper_pg_dir))|SATP_MODE);
ÔÚswapper_pg_dirÖÎÀíµÄkernel spaceÖУ¬ÆäÐéÄâµØµãÓëÎïÀíµØµã¿Õ¼äµÄÆ«ÒÆÊÇÀο¿µÄ£¬Îªva_pa_offset£¨½ç˵ÔÚarch/riscv/mm/init.cÖеÄÒ»¸öÈ«¾Ö±äÁ¿£©
×¢ÖØ£ºswapper_pg_dirÖÎÀíµÄÊÇkernel spaceµÄÒ³±í£¬¼´Ëü°ÑÎïÀíÄÚ´æÓ³Éäµ½µÄÐéÄâµØµã¿Õ¼äÊÇÖ»ÄÜkernel»á¼ûµÄ¡£user space²»¿É»á¼û£¬Óû§¿Õ¼äÈôÊÇ»á¼û£¬±ØÐè×ÔÐн¨ÉèÒ³±í£¬°ÑÎïÀíµØµãÓ³Éäµ½user spaceµÄÐéÄâµØµã¿Õ¼ä¡£kernelÏ̹߳²ÏíÕâ¸öswapper_pg_dirÒ³±í¡£
×ܽá
RISC-V LinuxÆô¶¯Ê±µÄÒ³±í½¨ÉèÏà¶ÔÀ´ËÃ÷ÈÕվɽÏÁ¿ÈÝÒ×Ã÷È·µÄ£¬¶¼ÊÇCÓïÑÔ½¨ÉèµÄ£¬´úÂëÒ²½ÏÁ¿ÉÙ¡£Ö÷Òª¾ÍÊÇsetup_vm()ºÍsetup_vm_final()Á½¸öÒ³±í½¨É躯Êý¡£Ã÷È·ÁËsv39µÄһЩµØµãÃûÌúó£¬ÔÙÈ¥ÆÊÎöÔ´Âë¾Í½ÏÁ¿ÈÝÒס£²»¹ý²î±ðkernel°æ±¾´úÂ붼·×ÆçÑù£¬ÐèÒªÏêϸÇéÐÎÏêϸÆÊÎö¡£
±¾ÆªÌáµ½ÁËsetup_vm()»á¼ì²ékernelÈë¿ÚµØµãÊÇ·ñ2M¶ÔÆ룬ÈôÊDzî³ØÆëkernelÎÞ·¨Æô¶¯£¬µ«×ÅʵÎÒÃÇ¿ÉÒÔɨ³ýÕâ¸ö2M¶ÔÆëÏÞÖÆ£¬½«Õⲿ·Ö¿Õ¼äʹÓÃÆðÀ´£¬ÏÂƪ½Ì¸÷ÈËÓÅ»¯Õⲿ·ÖÄÚ´æ¡£
ÒÔÉϾÍÊÇRISC-V LinuxÆô¶¯Ö®Ò³±í½¨ÉèÆÊÎöµÄÏêϸÄÚÈÝ£¬¸ü¶àÇë¹Ø×¢±¾ÍøÄÚÆäËüÏà¹ØÎÄÕ£¡