×ðÁú¿­Ê±¹ÙÍøµÇ¼

RISC-V Linux»ã±àÆô¶¯Àú³ÌÆÊÎö

RISC-V LinuxµÄ»ã±àÆô¶¯²¿·Ö½ÏÁ¿¼òÆÓ£¬²»ËãÖØ´ó¡£ÓÐÁ½¸ö²¿·Ö½ÏÁ¿½¹µã£ºÒ³±í½¨ÉèºÍÖض¨Ïò¡£Ò³±í½¨ÉèÊÇÓÃCÓïÑÔдµÄ£¬½ñÌìÏÈÆÊÎö»ã±à²¿·Ö£¬ÏÈ´ø¸÷ÈËÆÊÎöÕûÌå»ã±àÆô¶¯Á÷³Ì£¬È»ºóÆÊÎöÖض¨Ïò¡£

×¢ÖØ£º±¾ÎÄ»ùÓÚlinux5.10.111ÄÚºË

»ã±àÆô¶¯Á÷³Ì

ÏÈ´ÓÕûÌåÆÊÎö»ã±à×öµÄÊÂÇ飬Óиö¸ÅÂÔ¿ò¼Ü¡£

·¾¶£ºarch/riscv/kernel/head.S£¬Èë¿ÚÊÇENTRY(_start_kernel)

´ÓENTRY(_start_kernel)×îÏȾÙÐÐÆô¶¯Ç°µÄһЩ³õʼ»¯£¬½¨ÉèÒ³±íÇ°µÄÖ÷ÒªÊÂÇ飺

¹Ø±ÕËùÓÐÖÐÖ¹

/* ¹Ø±ÕËùÓÐÖÐÖ¹ */
    csrw CSR_IE, zero
    csrw CSR_IP, zero

µÇ¼ºó¸´ÖÆ

¼ÓÔØÈ«¾ÖÖ¸Õëgp

/* ¼ÓÔØÈ«¾ÖÖ¸Õëgp */
.option push
.option norelax
    la gp, __global_pointer$
.option pop

µÇ¼ºó¸´ÖÆ

disable FPU

/* ½ûÓà FPU ÒÔ¼ì²âÄں˿ռäÖи¡µãµÄ²»·¨Ê¹ÓÃ*/
    li t0, SR_FS
    csrc CSR_STATUS, t0

µÇ¼ºó¸´ÖÆ

Ñ¡ÔñÒ»¸öºËÆô¶¯

/* Ñ¡ÔñÒ»¸öºËÆô¶¯ */
    la a3, hart_lottery
    li a2, 1
    amoadd.w a3, a2, (a3)
    bnez a3, .Lsecondary_start

µÇ¼ºó¸´ÖÆ

ÇåÎúbss¶Î

/* ɨ³ýbss */
    la a3, __bss_start
    la a4, __bss_stop
    ble a4, a3, clear_bss_done

µÇ¼ºó¸´ÖÆ

ÉúÑÄhart idºÍdtbµØµã

/* ÉúÑÄhatr idºÍdtbµØµã£¬hart idÉúÑĵ½a0£¬dtbµØµãÉúÑĵ½a1 */
    mv s0, a0
    mv s1, a1
    la a2, boot_cpu_hartid

µÇ¼ºó¸´ÖÆ

ÉèÖÃspÖ¸Õë

    la sp, init_thread_union + THREAD_SIZE

µÇ¼ºó¸´ÖÆ

ÉÏÊöÊÂÇéÍê³É£¬»á×îÏÈÔÝʱҳ±íµÄ½¨É裬Ìøתµ½Cº¯Êýsetup_vm½¨ÉèÔÝʱҳ±í

    mv a0, s1
    call setup_vm // Ìøתµ½Cº¯Êýsetup_vm£¬setup_vm»á½¨ÉèÔÝʱҳ±í

µÇ¼ºó¸´ÖÆ

Öض¨Ïò

#ifdef CONFIG_MMU
    la a0, early_pg_dir
    call relocate	//Öض¨Ïò£¬ÏÖʵ¾ÍÊÇ¿ªÆôMMU
#endif

µÇ¼ºó¸´ÖÆ

ÉèÖÃÒì³£ÏòÁ¿µØµã£¬ÖØÔØCÇéÐÎ

    call setup_trap_vector
/* ÖØÔØCÇéÐÎ */
    la tp, init_task
    sw zero, TASK_TI_CPU(tp)
    la sp, init_thread_union + THREAD_SIZE

µÇ¼ºó¸´ÖÆ

×îºóÌøתµ½Cº¯Êýstart_kernel£¬×îÏÈCÓïÑÔ²¿·Ö³õʼ»¯£¬»ã±à²¿·ÖÖ´ÐÐÍê±Ï

tail start_kernel

µÇ¼ºó¸´ÖÆ

ÍêÕû_start_kernel»ã±à´úÂ룺

ENTRY(_start_kernel)
	/* ¹Ø±ÕËùÓÐÖÐÖ¹ */
	csrw CSR_IE, zero
	csrw CSR_IP, zero

	/* ÔÚÔ´ÂëÖУ¬ÕâÀïÓÐÒ»¸öMģʽ´¦ÀíµÄºê£¬ÕâÀïûÓÐÓõ½£¬Ö±½ÓÌø¹ý*/

	/* ¼ÓÔØÈ«¾ÖÖ¸Õëgp */
.option push
.option norelax
	la gp, __global_pointer$
.option pop

	/* ½ûÓà FPU ÒÔ¼ì²âÄں˿ռäÖи¡µãµÄ²»·¨Ê¹ÓÃ*/
	li t0, SR_FS
	csrc CSR_STATUS, t0

#ifdef CONFIG_SMP
	li t0, CONFIG_NR_CPUS
	blt a0, t0, .Lgood_cores
	tail .Lsecondary_park
.Lgood_cores:
#endif

	/* Ñ¡ÔñÒ»¸öºËÆô¶¯ */
	la a3, hart_lottery
	li a2, 1
	amoadd.w a3, a2, (a3)
	bnez a3, .Lsecondary_start

	/* ɨ³ýbss */
	la a3, __bss_start
	la a4, __bss_stop
	ble a4, a3, clear_bss_done
clear_bss:
	REG_S zero, (a3)
	add a3, a3, RISCV_SZPTR
	blt a3, a4, clear_bss
clear_bss_done:

	/* ÉúÑÄhatr idºÍdtbµØµã£¬hart idÉúÑĵ½a0£¬dtbµØµãÉúÑĵ½a1 */
	mv s0, a0
	mv s1, a1
	la a2, boot_cpu_hartid
	REG_S a0, (a2)

	/* ³õʼ»¯Ò³±í£¬È»ºóÖض¨Ïòµ½ÐéÄâµØµã */
	la sp, init_thread_union + THREAD_SIZE
	mv a0, s1
	call setup_vm // Ìøתµ½Cº¯Êýsetup_vm£¬setup_vm»á½¨ÉèÔÝʱҳ±í
#ifdef CONFIG_MMU
	la a0, early_pg_dir
	call relocate	//Öض¨Ïò£¬ÏÖʵ¾ÍÊÇ¿ªÆôMMU
#endif /* CONFIG_MMU */

	call setup_trap_vector
	/* ÖØÔØCÇéÐÎ */
	la tp, init_task
	sw zero, TASK_TI_CPU(tp)
	la sp, init_thread_union + THREAD_SIZE

#ifdef CONFIG_KASAN
	call kasan_early_init
#endif
	/* Start the kernel */
	call soc_early_init
	tail start_kernel	//Ìøתµ½Cº¯Êýstart_kernel£¬×îÏÈCÓïÑÔ²¿·Ö³õʼ»¯

µÇ¼ºó¸´ÖÆ

»ã±àÖкÜÊÇÖ÷ÒªµÄÒ»¸ö²¿·Ö¾ÍÊÇÒ³±íµÄ½¨É裬¹ØºõןóÃæµÄ³ÌÐòÄܲ»¿É¼ÌÐøÍùÏÂÅÜ¡£setup_vm½¨ÉèÒ³±íºó¾Í»á×îÏÈÖ´ÐÐrelocateÖض¨Ïò£¬Õâ¸öÖض¨ÏòÖ÷Òª¿ªÆômmu£¬ÏÂÃæÆÊÎörelocateµÄ»ã±à¡£

relocate

relocateÖض¨Ïò£¬¾ÍÊÇÔÚ¿ªÆômmu¡£¿ªÆômmuµÄ²Ù×÷¾ÍÊǽ«Ò»¼¶Ò³±íµÄµØµãÒÔ¼°È¨ÏÞдµ½satp¼Ä´æÆ÷ÖУ¬Õâ¾ÍË㿪ÆômmuÁË¡£

#ifdef CONFIG_MMU
    la a0, early_pg_dir //Ìøתµ½relocateÇ°£¬ÏȰѵÚÒ»¼¶Ò³±íearly_pg_dirµÄµØµã´æÈëa0
    call relocate		//Ìøתµ½relocate,¿ªÆôMMU
#endif

µÇ¼ºó¸´ÖÆ

relocateÓÐÁ½´Î¿ªÆômmuµÄ²Ù×÷£¬µÚÒ»´Î¿ªÆômmuʹÓõÄÊÇsetup_vm()½¨ÉèµÄtrampoline_gd_dirÒ³±í£¬ÕâÒ³±íÉúÑĵÄÊÇkernelµÄÇ°2MÄÚ´æ¡£µÚ¶þ´Î¿ªÆôMMUʹÓõÄÊÇearly_pg_dirÒ³±í£¬Õâ¸öÒ³±íÓ³ÉäÁËÕû¸ökernelÄÚ´æÒÔ¼°dtbµÄ4M¿Õ¼ä¡£

ÈôÊÇtrampoline_pg_dir»òÕßearly_pg_dirÕâÁ½¸öÒ³±íµÄÓ³ÉäûŪºÃµÄ»°£¬¿ªÆôMMUµÄʱ¼ä¾Í»áʧ°Ü£¬ÒÔÊÇÒ³±íµÄ½¨ÉèÊ®·ÖÒªº¦¡£Ò³±í½¨ÉèºóÐøÔÙÉ£¬ÏÂÃæÆÊÎörelocate»ã±à´úÂë¡£

ÅÌËã·µ»ØµØµã

·µ»ØµØµã¾ÍÊÇra¼ÓÉÏÐéÄâµØµãºÍÎïÀíµØµãÖ®¼äµÄÆ«ÒÆÁ¿£¬Õâ¸öÊÇÀο¿Æ«ÒÆÁ¿¡£PAGE_OFFSETÊÇkernelÈë¿ÚµØµã¶ÔÓ¦µÄÐéÄâµØµã£¬_start¾ÍÊÇkernelÈë¿ÚµØµãµÄÐéÄâµØµã£¬PAGE_OFFSET – _start¾Í»ñµÃËüÃÇÖ®¼äµÄÆ«ÒÆ£¬È»ºóÔÙºÍraÏà¼Ó£¬¾ÍÊÇ·µ»ØµØµã¡£

/* Relocate return address */
	li a1, PAGE_OFFSET
	la a2, _start
	sub a1, a1, a2
	add ra, ra, a1

µÇ¼ºó¸´ÖÆ

½«Òì³£Èë¿Ú1fµÄÐéÄâµØµãдÈëstvec¼Ä´æÆ÷

ÓÉÓÚÒ»µ©¿ªÆôMMU£¬µØµã¶¼Äð³ÉÁËÐéÄâµØµã£¬Ô­À´»á¼ûµÄ¶¼ÊÇÎïÀíµØµã£¬¿ªÆôMMUʱ£¬µØµã±¬·¢Á˸ı䣬VA != PA£¬´Ó¶ø½øÈëÒì³££¬ÒÔÊÇÒªÏÈÉèÖÃÒì³£Èë¿ÚµØµã£¬´ËʱµÄÒì³£Èë¿ÚΪ1f¡£

/* Point stvec to virtual address of intruction after satp write */
	la a2, 1f
	add a2, a2, a1
	csrw CSR_TVEC, a2

µÇ¼ºó¸´ÖÆ

ÌáÇ°ÅÌËãÇл»µ½early_pg_dirÒ³±íҪдÈësatpµÄÖµ

ÔÙ½øÈërelocate֮ǰ£¬¾ÍÒѾ­°Ñearly_pg_dir¸³Öµ¸øa0ÁË£¬ÒÔÊÇa0ÊÇearly_pg_dir¡£srlÊÇÂß¼­ÓÒÒÆ£¬mmuʹÓõÄÊÇsv39£¬ÐéÄâµØµã39룬ÎïÀíµØµã56λ£º

µÍ12λÊÇÆ«ÒÆÁ¿£¬ÒÔÊÇPAGE_SHIFT¼´ÊÇ12£¬½«early_pg_dirµØµãÓÒÒÆ12λ´æµ½a2¡£Æ¾Ö¤satp¼Ä´æÆ÷½ç˵£º

MODE¼´ÊÇ0x8´ú±íʹÓÃsv39 mmu£¬0x0´ú±í²»¾ÙÐеص㷭Ò룬¼´²»¿ªÆôMMU¡£ÕâÀïSTAP_MODEΪsv39£¬¼´0x8¡£½«early_pg_dirµØµãºÍSATP_MODE¾ÙÐлòÔËËãºó£¬¼´¿É»ñµÃдÈësatp¼Ä´æÆ÷µÄÖµ£¬×îºóÉúÑĵ½a2¡£

/* Compute satp for kernel page tables, but don't load it yet */
	srl a2, a0, PAGE_SHIFT
	li a1, SATP_MODE	//sv39 mmu
	or a2, a2, a1

µÇ¼ºó¸´ÖÆ

µÚÒ»´Î¿ªÆôMMU£¬Ê¹ÓÃtrampoline_pg_dirÒ³±í

satpÖµµÄÅÌËãºÍÉÏÊöÊÇÒ»ÑùµÄ¡£¿ªÆôMMU֮ǰ£¬Í¨¹ýsfence.vmaÏÂÁîÏÈË¢ÐÂTLB¡£´Ëʱ¿ªÆôMMU£¬¾Í»á½øÈëÏÂÃæµÄ±êºÅΪ1µÄ»ã±à¶Î

	la a0, trampoline_pg_dir
	srl a0, a0, PAGE_SHIFT
	or a0, a0, a1
	sfence.vma	
	csrw CSR_SATP, a0

µÇ¼ºó¸´ÖÆ

½øÈëÒì³£1f¶Î£¬ÖØÐÂÉèÖÃÒì³£Èë¿ÚΪ.Lsecondary_park£¬È»ºóÇл»µ½early_pg_dirÒ³±í£¬Ï൱ÓÚµÚ¶þ´Î¿ªÆôMMU¡£´Ëʱ£¬ÈôÊÇ֮ǰ½¨ÉèµÄearly_pg_dirÒ³±í²î³Ø£¬Ôò»á¾Í½øÈë.Lsecondary_park¡£.Lsecondary_parkÄÚÀïÊǸöwfiÖ¸ÁÊǸöËÀÑ­»·¡£

ÍêÕûrelocate»ã±à´úÂ룺

relocate:
	/* Relocate return address */
	li a1, PAGE_OFFSET
	la a2, _start
	sub a1, a1, a2
	add ra, ra, a1

	/* Point stvec to virtual address of intruction after satp write */
	la a2, 1f
	add a2, a2, a1
	csrw CSR_TVEC, a2

	/* Compute satp for kernel page tables, but don't load it yet */
	srl a2, a0, PAGE_SHIFT
	li a1, SATP_MODE
	or a2, a2, a1

	/*
	 * Load trampoline page directory, which will cause us to trap to
	 * stvec if VA != PA, or simply fall through if VA == PA.  We need a
	 * full fence here because setup_vm() just wrote these PTEs and we need
	 * to ensure the new translations are in use.
	 */
	la a0, trampoline_pg_dir
	srl a0, a0, PAGE_SHIFT
	or a0, a0, a1
	sfence.vma
	csrw CSR_SATP, a0
.align 2
1:
	/* Set trap vector to spin forever to help debug */
	la a0, .Lsecondary_park
	csrw CSR_TVEC, a0

	/* Reload the global pointer */
.option push
.option norelax
	la gp, __global_pointer$
.option pop

	/*
	 * Switch to kernel page tables.  A full fence is necessary in order to
	 * avoid using the trampoline translations, which are only correct for
	 * the first superpage.  Fetching the fence is guarnteed to work
	 * because that first superpage is translated the same way.
	 */
	csrw CSR_SATP, a2
	sfence.vma

	ret

µÇ¼ºó¸´ÖÆ

×ܽá

ÒÔÉϾÍÊÇRISC-V LinuxµÄ»ã±àÆô¶¯Á÷³Ì£¬Ëä˵RISC-VµÄÖ¸Áî²»Öش󣬵«ÒªÃ÷È·Õâ¸ö»ã±àÆô¶¯µÄ²¿·Ö£¬ÕÕ¾ÉÐèÒªÒ»µã»ù´¡ºÍʱ¼ä¡£ÁíÍ⣬´ó´ó¶¼ÈËÊÂÇéÖлù±¾Óò»ÉÏ»ã±à£¬Ö»ÓÐÕæÕýÓÃÉÏÁËÃ÷È·²Å»á½ÏÁ¿ÉϣÍû±¾ÎÄÄܹ»×ÊÖúµ½ÓÐÐèÒªµÄÈË¡£

ÒÔÉϾÍÊÇRISC-V Linux»ã±àÆô¶¯Àú³ÌÆÊÎöµÄÏêϸÄÚÈÝ£¬¸ü¶àÇë¹Ø×¢±¾ÍøÄÚÆäËüÏà¹ØÎÄÕ£¡

ÃâÔð˵Ã÷£ºÒÔÉÏչʾÄÚÈÝȪԴÓÚÏàÖúýÌå¡¢ÆóÒµ»ú¹¹¡¢ÍøÓÑÌṩ»òÍøÂçÍøÂçÕûÀí£¬°æȨÕùÒéÓë±¾Õ¾Î޹أ¬ÎÄÕÂÉæ¼°¿´·¨Óë¿´·¨²»´ú±í×ðÁú¿­Ê±¹ÙÍøµÇ¼ÂËÓÍ»úÍø¹Ù·½Ì¬¶È£¬Çë¶ÁÕß½ö×ö²Î¿¼¡£±¾ÎĽӴýתÔØ£¬×ªÔØÇë˵Ã÷À´ÓÉ¡£ÈôÄúÒÔΪ±¾ÎÄÇÖÕ¼ÁËÄúµÄ°æȨÐÅÏ¢£¬»òÄú·¢Ã÷¸ÃÄÚÈÝÓÐÈκÎÉæ¼°ÓÐÎ¥¹«µÂ¡¢Ã°·¸Ö´·¨µÈÎ¥·¨ÐÅÏ¢£¬ÇëÄúÁ¬Ã¦ÁªÏµ×ðÁú¿­Ê±¹ÙÍøµÇ¼ʵʱÐÞÕý»òɾ³ý¡£

Ïà¹ØÐÂÎÅ

ÁªÏµ×ðÁú¿­Ê±¹ÙÍøµÇ¼

18523999891

¿É΢ÐÅÔÚÏß×Éѯ

ÊÂÇéʱ¼ä£ºÖÜÒ»ÖÁÖÜÎ壬9:30-18:30£¬½ÚãåÈÕÐÝÏ¢

QR code
ÍøÕ¾µØͼ