head.S 7.0 KB

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