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 0x8000000000000000ULL 21#define SATP_MODE_48 0x9000000000000000ULL 22#define SATP_MODE_57 0xa000000000000000ULL 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 call __initial_reloacate_enable_mmu 88 89.option push 90.option norelax 91 92 la a0, BSP_IDLE_STACK_SPACE 93 mv sp, a0 94 li t0, 32752 // 预留16字节防止越界 95 add sp, sp, t0 96.option pop 97 /* 98 * Disable FPU & VECTOR to detect illegal usage of 99 * floating point or vector in kernel space 100 */ 101 li t0, SR_FS_VS 102 csrc CSR_STATUS, t0 103 104 /* Call the kernel */ 105 la a0, __initial_hartid_ptr 106 ld a0, 0(a0) 107 la a1, __initial_fdt_ptr 108 ld a1, 0(a1) 109 110 111 // 跳转到kernel_main 112 call kernel_main 113 nop 114 wfi 115 116 117__initial_reloacate_enable_mmu: 118 // 计算起始物理地址与内核高虚拟地址的偏移量 119 la t0, __initial_start_load_paddr 120 ld t0, 0(t0) 121 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, 1f 132 add a2, a2, t1 133 csrw CSR_TVEC, a2 134 // enable MMU 135 la a2, __initial_pgtable 136 srli a2, a2, 12 137 la a0, __initial_satp_mode 138 ld a0, 0(a0) 139 or a2, a2, a0 140 141 142 sfence.vma 143 csrw satp, a2 144 1451: 146 la a0, __initial_Lsecondary_park 147 add a0, a0, t1 148 csrw CSR_TVEC, a0 149 150 csrw satp, a2 151 sfence.vma 152 153 ret 154 155// 映射物理地址到虚拟地址(2M页,1G大小) 156// 参数: 157// a0: 物理地址 158// a1: 虚拟地址 159initial_map_256M_phys_addr: 160 // 检查物理地址是否对齐到2M 161 li t0, 0x1fffff 162 and t0, t0, a0 163 bnez t0, __initial_map_1g_phys_failed 164 165 // 检查虚拟地址是否对齐到2M 166 li t0, 0x1fffff 167 and t0, t0, a1 168 bnez t0, __initial_map_1g_phys_failed 169 170 // 把起始虚拟地址存储到t2中 171 mv t2, a1 172 // 按照2M对齐 173 li t1, -0x200000 174 and t2, t2, t1 175 176 // 计算L0页表项的索引 177 srli t2, t2, 30 178 andi t2, t2, 511 179 180 181 // 填写第一个L0页表项 182 la t4, __initial_pgtable 183 slli t5, t2, 3 // t5 = t2 * 8 184 add t4, t4, t5 // t4 = t4 + t5, t4指向L0页表项 185 186 // 提取L1页表的地址 187 la t5, __initial_l1_pgtable 188 srli t5, t5, 12 189 slli t5, t5, 10 190 ori t5, t5, 0x1 // 设置L1页表项属性,V = 1 191 // 设置L0页表项的值 192 sd t5, 0(t4) 193 194 // 计算是否需要填写第二个L1页表项(判断是否超过第一个L1页表的范围) 195 addi t3, t2, 128 196 li t5, 512 197 blt t3, t5, __initial_set_l1_pgtable 198 // 填写第二个L1页表 199 la t3, __initial_l1_pgtable 200 li t5, 4096 201 add t3, t3, t5 202 srli t3, t3, 12 203 slli t3, t3, 10 204 ori t3, t3, 0x1 // 设置L1页表项属性,V = 1 205 // 设置L0页表项的值 206 sd t3, 8(t4) 207 208__initial_set_l1_pgtable: // 开始填写L1页表 209 210 // 获取起始物理地址 211 mv t6, a0 212 // 获取L1页表的地址 213 la t0, __initial_l1_pgtable 214 215 // 计算起始L1页表项的索引 216 mv t3, a1 217 srli t3, t3, 21 218 andi t3, t3, 511 219 220 slli t3, t3, 3 // t3 = t3 * 8 221 add t0, t0, t3 // t0 = t0 + t3 222 223 // 加载计数器 224 li t5, 0 225__initial_set_l1_pgtable_loop: 226 227 mv t3, t6 228 srli t3, t3, 12 // t3 = t6 >> 12 (page frame number) 229 li t1, 0x3FFFFFFFFFFFFF 230 and t3, t3, t1 // t3 = t3 & 0x3FFFFFFFFFFFFF 231 slli t3, t3, 10 // t3 = t3 << 10 232 ori t3, t3, 0xEF // 设置L1页表项属性,set R/W/X/V/A/D/G = 1 233 // 设置L1页表项的值 234 sd t3, 0(t0) 235 236 // 增加 页表项指针 237 addi t0, t0, 8 238 // 增加 t6 的值(2M) 239 li t2, 0x200000 240 add t6, t6, t2 241 242 // 增加计数器 243 addi t5, t5, 1 244 // 判断计数器是否超过128 245 li t2, 128 246 blt t5, t2, __initial_set_l1_pgtable_loop 247 248 249 // 填写完成 250 ret 251 252 253 254 255__initial_map_1g_phys_failed: 256 // 地址没有对齐到2M 257 wfi 258 la a0, __initial_map_1g_phys_failed 259 // 跳转 260 jr a0 261 262 263 264// 映射物理地址到虚拟地址(恒等映射) 265// 参数: 266// a0: 物理地址 267initial_map_1g_identical: 268 mv a1, a0 269 // 把_start向下对齐到1GB 270 li t0, -0x40000000 271 // 计算起始物理地址,存放在t0中 272 and t0, t0, a0 273 274 275 // 把起始虚拟地址存储到t2中 276 mv t2, a1 277 // 按照1g对齐 278 li t1, -0x40000000 279 and t2, t2, t1 280 281 282 // 右移30位,得到L0页表项的索引 283 srli t2, t2, 30 284 // 与511进行与运算,得到L0页表项的索引 285 andi t2, t2, 511 286 287 288 // 填写页表项 289 la t4, __initial_pgtable 290 slli t3, t2, 3 // t3 = t2 * 8 291 add t4, t4, t3 // t4 = t4 + t3 292 293 294 mv t3, t0 295 srli t3, t3, 12 // t3 = t0 >> 12 (page frame number) 296 slli t3, t3, 10 // t3 = t3 << 10 297 ori t3, t3, 0xEF // set R/W/X/V/A/D/G = 1 298 299 // 计算delta的pfn 300 li t2, 0x40000000 301 srli t2, t2, 12 302 // 把delta pfn移位到页表项的第10位的位置 303 slli t2, t2, 10 304 li t1, 2 305 306__loop_set_8g: 307 308 309 sd t3, 0(t4) 310 311 // 增加 t4 的值 312 addi t4, t4, 8 313 // 增加1G的pfn 314 add t3, t3, t2 315 316 317 addi t1, t1, -1 318 bnez t1, __loop_set_8g 319 320 ret 321 322 323// 用于清空页表的空间 324// 参数: 325// a0: page table address 326__initial_clear_pgtable: 327 mv t0, a0 328 li t1, 512 329 li t2, 0 // 用于存储 0 330 331__initial_clear_pgtable_loop: 332 333 sd t2, 0(t0) // 将 0 存储到当前word 334 addi t0, t0, 8 // 增加 t0 的值 335 addi t1, t1, -1 // 减少剩余的word数 336 bnez t1, __initial_clear_pgtable_loop 337 338 ret 339 340.align 2 341__initial_Lsecondary_park: 342 /* We lack SMP support or have too many harts, so park this hart */ 343 wfi 344 j __initial_Lsecondary_park 345 346// 全局变量,存储平坦设备树的地址和hartid 347.global __initial_fdt_ptr 348__initial_fdt_ptr: 349 .quad 0 350 351.global __initial_hartid_ptr 352__initial_hartid_ptr: 353 .quad 0 354 355// _start标签在启动时被加载到的物理地址 356.global __initial_start_load_paddr 357__initial_start_load_paddr: 358 .quad 0 359 360__initial_kernel_main_vaddr: 361 .quad 0 362 363 364 365.global __initial_satp_mode 366__initial_satp_mode: 367 .quad SATP_MODE_39 368 369// 初始页表的空间(sv39模式的L0页表) 370.section .initial_pgtable_section 371.global __initial_pgtable 372__initial_pgtable: 373 .skip 4096 374 375.global __initial_l1_pgtable 376__initial_l1_pgtable: 377 .skip 8192 378 379