123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352 |
- #include "common/asm.h"
- .section .bootstrap
- #define CSR_SSTATUS 0x100
- #define CSR_SIE 0x104
- #define CSR_STVEC 0x105
- #define CSR_SIP 0x144
- # define CSR_TVEC CSR_STVEC
- # define CSR_STATUS CSR_SSTATUS
- #define CSR_IE CSR_SIE
- #define CSR_IP CSR_SIP
- #define SR_FS 0x00006000
- #define SR_VS 0x00000600
- #define SR_FS_VS (SR_FS | SR_VS) /* Vector and Floating-Point Unit */
- #define SATP_MODE_39 0x8000000000000000UL
- #define SATP_MODE_48 0x9000000000000000UL
- #define SATP_MODE_57 0xa000000000000000UL
- #define PAGE_OFFSET 0xffffffc000000000
- #define KERNEL_LINK_OFFSET 0x1000000
- #define KERNEL_VIRT_START (PAGE_OFFSET + KERNEL_LINK_OFFSET)
- // 内核入口(从DragonStub跳转到这里)
- // 参数:
- // a0: hartid (核心ID)
- // a1: fdt (平坦设备树)
- .global _start
- .type _start, @function
- ENTRY(_start)
- /* Mask all interrupts */
- csrw CSR_IE, zero
- csrw CSR_IP, zero
-
- // 暂存hartid
- la t0, __initial_hartid_ptr
- sd a0, 0(t0)
- // 暂存平坦设备树地址
- la t0, __initial_fdt_ptr
- sd a1, 0(t0)
- // 暂存_start标签被DragonStub加载到的物理地址
- auipc t0, 0
- li t1, -4095
- and t0, t0, t1
- la t1, __initial_start_load_paddr
- sd t0, 0(t1)
- // 清空页表的空间
- la a0, __initial_pgtable
- call __initial_clear_pgtable
- la a0, __initial_l1_pgtable
- call __initial_clear_pgtable
- la a0, __initial_l1_pgtable
- li a1, 4096
- add a0, a0, a1
- call __initial_clear_pgtable
- // 设置页表,把内核当前所在的物理地址映射到链接时的内核虚拟空间
- la a0, __initial_start_load_paddr
- ld a0, 0(a0)
- // 偏移量0xffffffc000000000,计算起始的L0页表项
- // 因为内核链接地址还有16M的空间,所以这里加上0x1000000
- li a1, KERNEL_VIRT_START
-
- // 映射物理地址到虚拟地址
- call initial_map_256M_phys_addr
- // 增加恒等映射
- la a0, __initial_start_load_paddr
- ld a0, 0(a0)
- mv a1, a0
- call initial_map_1g_identical
- __init_set_pgtable_loop_end:
-
- call __initial_reloacate_enable_mmu
- .option push
- .option norelax
-
- la a0, BSP_IDLE_STACK_SPACE
- mv sp, a0
- li t0, 32768
- add sp, sp, t0
- .option pop
- /*
- * Disable FPU & VECTOR to detect illegal usage of
- * floating point or vector in kernel space
- */
- li t0, SR_FS_VS
- csrc CSR_STATUS, t0
-
- /* Call the kernel */
- la a0, __initial_hartid_ptr
- ld a0, 0(a0)
- la a1, __initial_fdt_ptr
- ld a1, 0(a1)
-
-
- // 跳转到kernel_main
- call kernel_main
- nop
- wfi
- __initial_reloacate_enable_mmu:
- // 计算起始物理地址与内核高虚拟地址的偏移量
- la t0, __initial_start_load_paddr
- ld t0, 0(t0)
-
- li t1, KERNEL_VIRT_START
- sub t1, t1, t0
- // 重定位返回地址
- add ra, ra, t1
- /* Point stvec to virtual address of intruction after satp write */
- /* Set trap vector to spin forever to help debug */
- la a2, __initial_Lsecondary_park
- add a2, a2, t1
- csrw CSR_TVEC, a2
-
- // enable MMU
- la a2, __initial_pgtable
- srli a2, a2, 12
- la a0, __initial_satp_mode
- ld a0, 0(a0)
- or a2, a2, a0
- sfence.vma
- csrw satp, a2
- ret
- // 映射物理地址到虚拟地址(2M页,1G大小)
- // 参数:
- // a0: 物理地址
- // a1: 虚拟地址
- initial_map_256M_phys_addr:
- // 检查物理地址是否对齐到2M
- li t0, 0x1fffff
- and t0, t0, a0
- bnez t0, __initial_map_1g_phys_failed
- // 检查虚拟地址是否对齐到2M
- li t0, 0x1fffff
- and t0, t0, a1
- bnez t0, __initial_map_1g_phys_failed
- // 把起始虚拟地址存储到t2中
- mv t2, a1
- // 按照2M对齐
- li t1, -0x200000
- and t2, t2, t1
- // 计算L0页表项的索引
- srl t2, t2, 30
- andi t2, t2, 511
-
-
- // 填写第一个L0页表项
- la t4, __initial_pgtable
- slli t5, t2, 3 // t5 = t2 * 8
- add t4, t4, t5 // t4 = t4 + t5, t4指向L0页表项
- // 提取L1页表的地址
- la t5, __initial_l1_pgtable
- srli t5, t5, 12
- slli t5, t5, 10
- ori t5, t5, 0x1 // 设置L1页表项属性,V = 1
- // 设置L0页表项的值
- sd t5, 0(t4)
- // 计算是否需要填写第二个L1页表项(判断是否超过第一个L1页表的范围)
- addi t3, t2, 128
- li t5, 512
- blt t3, t5, __initial_set_l1_pgtable
- // 填写第二个L1页表
- la t3, __initial_l1_pgtable
- li t5, 4096
- add t3, t3, t5
- srli t3, t3, 12
- slli t3, t3, 10
- ori t3, t3, 0x1 // 设置L1页表项属性,V = 1
- // 设置L0页表项的值
- sd t3, 8(t4)
- __initial_set_l1_pgtable: // 开始填写L1页表
- // 获取起始物理地址
- mv t6, a0
- // 获取L1页表的地址
- la t0, __initial_l1_pgtable
- // 计算起始L1页表项的索引
- mv t3, a1
- srli t3, t3, 21
- andi t3, t3, 511
- slli t3, t3, 3 // t3 = t3 * 8
- add t0, t0, t3 // t0 = t0 + t3
-
- // 加载计数器
- li t5, 0
- __initial_set_l1_pgtable_loop:
-
- mv t3, t6
- srli t3, t3, 12 // t3 = t6 >> 12 (page frame number)
- li t1, 0x3FFFFFFFFFFFFF
- and t3, t3, t1 // t3 = t3 & 0x3FFFFFFFFFFFFF
- slli t3, t3, 10 // t3 = t3 << 10
- ori t3, t3, 0xf // 设置L1页表项属性,R/W/X/V = 1
- // 设置L1页表项的值
- sd t3, 0(t0)
- // 增加 页表项指针
- addi t0, t0, 8
- // 增加 t6 的值(2M)
- li t2, 0x200000
- add t6, t6, t2
- // 增加计数器
- addi t5, t5, 1
- // 判断计数器是否超过128
- li t2, 128
- blt t5, t2, __initial_set_l1_pgtable_loop
-
- // 填写完成
- ret
- __initial_map_1g_phys_failed:
- // 地址没有对齐到2M
- wfi
- la a0, __initial_map_1g_phys_failed
- // 跳转
- jr a0
- // 映射物理地址到虚拟地址(恒等映射)
- // 参数:
- // a0: 物理地址
- initial_map_1g_identical:
- mv a1, a0
- // 把_start向下对齐到1GB
- li t0, -0x40000000
- // 计算起始物理地址,存放在t0中
- and t0, t0, a0
-
- // 把起始虚拟地址存储到t2中
- mv t2, a1
- // 按照1g对齐
- li t1, -0x40000000
- and t2, t2, t1
-
- // 右移30位,得到L0页表项的索引
- srl t2, t2, 30
- // 与511进行与运算,得到L0页表项的索引
- andi t2, t2, 511
-
- // 填写页表项
- // li t2, 0xf // 页表项属性, R/W/X/V = 1
- la t4, __initial_pgtable
- slli t3, t2, 3 // t3 = t2 * 8
- add t4, t4, t3 // t4 = t4 + t3
- mv t3, t0
- srli t3, t3, 12 // t3 = t0 >> 12 (page frame number)
- slli t3, t3, 10 // t3 = t3 << 10
- ori t3, t3, 0xf // set R/W/X/V = 1
- // 设置t0地址在L0页表中的值
- sd t3, 0(t4)
- // 增加 t4 的值
- addi t4, t4, 8
- // 增加 t3 的值(1G)
- li t2, 0x40000000
- add t3, t3, t2
- sd t3, 0(t4)
- ret
- // 用于清空页表的空间
- // 参数:
- // a0: page table address
- __initial_clear_pgtable:
- mv t0, a0
- li t1, 512
- li t2, 0 // 用于存储 0
- __initial_clear_pgtable_loop:
- sd t2, 0(t0) // 将 0 存储到当前word
- addi t0, t0, 8 // 增加 t0 的值
- addi t1, t1, -1 // 减少剩余的word数
- bnez t1, __initial_clear_pgtable_loop
- ret
- .align 2
- __initial_Lsecondary_park:
- /* We lack SMP support or have too many harts, so park this hart */
- wfi
- j __initial_Lsecondary_park
- // 全局变量,存储平坦设备树的地址和hartid
- .global __initial_fdt_ptr
- __initial_fdt_ptr:
- .quad 0
- .global __initial_hartid_ptr
- __initial_hartid_ptr:
- .quad 0
- // _start标签在启动时被加载到的物理地址
- __initial_start_load_paddr:
- .quad 0
- __initial_kernel_main_vaddr:
- .quad 0
- .global __initial_satp_mode
- __initial_satp_mode:
- .quad SATP_MODE_39
- // 初始页表的空间(sv39模式的L0页表)
- .section .initial_pgtable_section
- __initial_pgtable:
- .skip 4096
- __initial_l1_pgtable:
- .skip 8192
|