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