1#include "common/asm.h" 2 3.section .bootstrap 4 5#define CSR_SSTATUS 0x100 6#define CSR_SIE 0x104 7#define CSR_STVEC 0x105 8#define CSR_SIP 0x144 9 10# define CSR_TVEC CSR_STVEC 11 12# define CSR_STATUS CSR_SSTATUS 13#define CSR_IE CSR_SIE 14#define CSR_IP CSR_SIP 15 16#define SR_FS 0x00006000 17#define SR_VS 0x00000600 18#define SR_FS_VS (SR_FS | SR_VS) /* Vector and Floating-Point Unit */ 19 20#define SATP_MODE_39 0x8000000000000000UL 21#define SATP_MODE_48 0x9000000000000000UL 22#define SATP_MODE_57 0xa000000000000000UL 23 24#define PAGE_OFFSET 0xffffffc000000000 25#define KERNEL_LINK_OFFSET 0x1000000 26#define KERNEL_VIRT_START (PAGE_OFFSET + KERNEL_LINK_OFFSET) 27 28 29// 内核入口(从DragonStub跳转到这里) 30// 参数: 31// a0: hartid (核心ID) 32// a1: fdt (平坦设备树) 33.global _start 34.type _start, @function 35ENTRY(_start) 36 /* Mask all interrupts */ 37 csrw CSR_IE, zero 38 csrw CSR_IP, zero 39 40 41 // 暂存hartid 42 la t0, __initial_hartid_ptr 43 sd a0, 0(t0) 44 // 暂存平坦设备树地址 45 la t0, __initial_fdt_ptr 46 sd a1, 0(t0) 47 48 49 // 暂存_start标签被DragonStub加载到的物理地址 50 auipc t0, 0 51 li t1, -4095 52 and t0, t0, t1 53 la t1, __initial_start_load_paddr 54 sd t0, 0(t1) 55 56 // 清空页表的空间 57 la a0, __initial_pgtable 58 call __initial_clear_pgtable 59 la a0, __initial_l1_pgtable 60 call __initial_clear_pgtable 61 la a0, __initial_l1_pgtable 62 li a1, 4096 63 add a0, a0, a1 64 call __initial_clear_pgtable 65 66 67 68 // 设置页表,把内核当前所在的物理地址映射到链接时的内核虚拟空间 69 la a0, __initial_start_load_paddr 70 ld a0, 0(a0) 71 72 // 偏移量0xffffffc000000000,计算起始的L0页表项 73 // 因为内核链接地址还有16M的空间,所以这里加上0x1000000 74 li a1, KERNEL_VIRT_START 75 76 // 映射物理地址到虚拟地址 77 call initial_map_256M_phys_addr 78 79 // 增加恒等映射 80 la a0, __initial_start_load_paddr 81 ld a0, 0(a0) 82 83 mv a1, a0 84 call initial_map_1g_identical 85 86__init_set_pgtable_loop_end: 87 88 call __initial_reloacate_enable_mmu 89 90.option push 91.option norelax 92 93 la a0, BSP_IDLE_STACK_SPACE 94 mv sp, a0 95 li t0, 32752 // 预留16字节防止越界 96 add sp, sp, t0 97.option pop 98 /* 99 * Disable FPU & VECTOR to detect illegal usage of 100 * floating point or vector in kernel space 101 */ 102 li t0, SR_FS_VS 103 csrc CSR_STATUS, t0 104 105 /* Call the kernel */ 106 la a0, __initial_hartid_ptr 107 ld a0, 0(a0) 108 la a1, __initial_fdt_ptr 109 ld a1, 0(a1) 110 111 112 // 跳转到kernel_main 113 call kernel_main 114 nop 115 wfi 116 117 118__initial_reloacate_enable_mmu: 119 // 计算起始物理地址与内核高虚拟地址的偏移量 120 la t0, __initial_start_load_paddr 121 ld t0, 0(t0) 122 123 li t1, KERNEL_VIRT_START 124 sub t1, t1, t0 125 126 // 重定位返回地址 127 add ra, ra, t1 128 129 /* Point stvec to virtual address of intruction after satp write */ 130 /* Set trap vector to spin forever to help debug */ 131 la a2, __initial_Lsecondary_park 132 add a2, a2, t1 133 csrw CSR_TVEC, a2 134 135 // enable MMU 136 la a2, __initial_pgtable 137 srli a2, a2, 12 138 la a0, __initial_satp_mode 139 ld a0, 0(a0) 140 or a2, a2, a0 141 sfence.vma 142 csrw satp, a2 143 144 ret 145 146// 映射物理地址到虚拟地址(2M页,1G大小) 147// 参数: 148// a0: 物理地址 149// a1: 虚拟地址 150initial_map_256M_phys_addr: 151 // 检查物理地址是否对齐到2M 152 li t0, 0x1fffff 153 and t0, t0, a0 154 bnez t0, __initial_map_1g_phys_failed 155 156 // 检查虚拟地址是否对齐到2M 157 li t0, 0x1fffff 158 and t0, t0, a1 159 bnez t0, __initial_map_1g_phys_failed 160 161 // 把起始虚拟地址存储到t2中 162 mv t2, a1 163 // 按照2M对齐 164 li t1, -0x200000 165 and t2, t2, t1 166 167 // 计算L0页表项的索引 168 srl t2, t2, 30 169 andi t2, t2, 511 170 171 172 // 填写第一个L0页表项 173 la t4, __initial_pgtable 174 slli t5, t2, 3 // t5 = t2 * 8 175 add t4, t4, t5 // t4 = t4 + t5, t4指向L0页表项 176 177 // 提取L1页表的地址 178 la t5, __initial_l1_pgtable 179 srli t5, t5, 12 180 slli t5, t5, 10 181 ori t5, t5, 0x1 // 设置L1页表项属性,V = 1 182 // 设置L0页表项的值 183 sd t5, 0(t4) 184 185 // 计算是否需要填写第二个L1页表项(判断是否超过第一个L1页表的范围) 186 addi t3, t2, 128 187 li t5, 512 188 blt t3, t5, __initial_set_l1_pgtable 189 // 填写第二个L1页表 190 la t3, __initial_l1_pgtable 191 li t5, 4096 192 add t3, t3, t5 193 srli t3, t3, 12 194 slli t3, t3, 10 195 ori t3, t3, 0x1 // 设置L1页表项属性,V = 1 196 // 设置L0页表项的值 197 sd t3, 8(t4) 198 199__initial_set_l1_pgtable: // 开始填写L1页表 200 201 // 获取起始物理地址 202 mv t6, a0 203 // 获取L1页表的地址 204 la t0, __initial_l1_pgtable 205 206 // 计算起始L1页表项的索引 207 mv t3, a1 208 srli t3, t3, 21 209 andi t3, t3, 511 210 211 slli t3, t3, 3 // t3 = t3 * 8 212 add t0, t0, t3 // t0 = t0 + t3 213 214 // 加载计数器 215 li t5, 0 216__initial_set_l1_pgtable_loop: 217 218 mv t3, t6 219 srli t3, t3, 12 // t3 = t6 >> 12 (page frame number) 220 li t1, 0x3FFFFFFFFFFFFF 221 and t3, t3, t1 // t3 = t3 & 0x3FFFFFFFFFFFFF 222 slli t3, t3, 10 // t3 = t3 << 10 223 ori t3, t3, 0xf // 设置L1页表项属性,R/W/X/V = 1 224 // 设置L1页表项的值 225 sd t3, 0(t0) 226 227 // 增加 页表项指针 228 addi t0, t0, 8 229 // 增加 t6 的值(2M) 230 li t2, 0x200000 231 add t6, t6, t2 232 233 // 增加计数器 234 addi t5, t5, 1 235 // 判断计数器是否超过128 236 li t2, 128 237 blt t5, t2, __initial_set_l1_pgtable_loop 238 239 240 // 填写完成 241 ret 242 243 244 245 246__initial_map_1g_phys_failed: 247 // 地址没有对齐到2M 248 wfi 249 la a0, __initial_map_1g_phys_failed 250 // 跳转 251 jr a0 252 253 254 255// 映射物理地址到虚拟地址(恒等映射) 256// 参数: 257// a0: 物理地址 258initial_map_1g_identical: 259 mv a1, a0 260 // 把_start向下对齐到1GB 261 li t0, -0x40000000 262 // 计算起始物理地址,存放在t0中 263 and t0, t0, a0 264 265 266 // 把起始虚拟地址存储到t2中 267 mv t2, a1 268 // 按照1g对齐 269 li t1, -0x40000000 270 and t2, t2, t1 271 272 // 右移30位,得到L0页表项的索引 273 srl t2, t2, 30 274 // 与511进行与运算,得到L0页表项的索引 275 andi t2, t2, 511 276 277 278 // 填写页表项 279 // li t2, 0xf // 页表项属性, R/W/X/V = 1 280 la t4, __initial_pgtable 281 slli t3, t2, 3 // t3 = t2 * 8 282 add t4, t4, t3 // t4 = t4 + t3 283 284 mv t3, t0 285 srli t3, t3, 12 // t3 = t0 >> 12 (page frame number) 286 slli t3, t3, 10 // t3 = t3 << 10 287 ori t3, t3, 0xf // set R/W/X/V = 1 288 // 设置t0地址在L0页表中的值 289 sd t3, 0(t4) 290 291 // 增加 t4 的值 292 addi t4, t4, 8 293 // 增加 t3 的值(1G) 294 li t2, 0x40000000 295 add t3, t3, t2 296 sd t3, 0(t4) 297 298 ret 299 300// 用于清空页表的空间 301// 参数: 302// a0: page table address 303__initial_clear_pgtable: 304 mv t0, a0 305 li t1, 512 306 li t2, 0 // 用于存储 0 307 308__initial_clear_pgtable_loop: 309 310 sd t2, 0(t0) // 将 0 存储到当前word 311 addi t0, t0, 8 // 增加 t0 的值 312 addi t1, t1, -1 // 减少剩余的word数 313 bnez t1, __initial_clear_pgtable_loop 314 315 ret 316 317.align 2 318__initial_Lsecondary_park: 319 /* We lack SMP support or have too many harts, so park this hart */ 320 wfi 321 j __initial_Lsecondary_park 322 323// 全局变量,存储平坦设备树的地址和hartid 324.global __initial_fdt_ptr 325__initial_fdt_ptr: 326 .quad 0 327 328.global __initial_hartid_ptr 329__initial_hartid_ptr: 330 .quad 0 331 332// _start标签在启动时被加载到的物理地址 333.global __initial_start_load_paddr 334__initial_start_load_paddr: 335 .quad 0 336 337__initial_kernel_main_vaddr: 338 .quad 0 339 340 341 342.global __initial_satp_mode 343__initial_satp_mode: 344 .quad SATP_MODE_39 345 346// 初始页表的空间(sv39模式的L0页表) 347.section .initial_pgtable_section 348.global __initial_pgtable 349__initial_pgtable: 350 .skip 4096 351 352.global __initial_l1_pgtable 353__initial_l1_pgtable: 354 .skip 8192 355 356