head.S 7.4 KB

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