1
1

stub.asm 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. KRL_CODE_X64 equ 0x08
  2. KRL_DATA_X64 equ 0x10
  3. USR_CODE_X86 equ 0x18
  4. USR_DATA_X64 equ 0x20
  5. USR_CODE_X64 equ 0x28 + 3
  6. GS_BASE equ 0xc0000101
  7. KERNEL_GS_BASE equ 0xc0000102
  8. struc Frame
  9. .gs_base resq 1
  10. .fs_base resq 1
  11. .r15 resq 1
  12. .r14 resq 1
  13. .r13 resq 1
  14. .r12 resq 1
  15. .r11 resq 1
  16. .r10 resq 1
  17. .r9 resq 1
  18. .r8 resq 1
  19. .rsi resq 1
  20. .rdi resq 1
  21. .rbp resq 1
  22. .rbx resq 1
  23. .rdx resq 1
  24. .rcx resq 1
  25. .rax resq 1
  26. .errc resq 1
  27. .rip resq 1
  28. .cs resq 1
  29. .rflags resq 1
  30. .rsp resq 1
  31. .ss resq 1
  32. endstruc
  33. struc KernelGs
  34. .tss_rsp0 resq 1
  35. .syscall_user_stack resq 1
  36. .syscall_stack resq 1
  37. .kernel_fs resq 1
  38. endstruc
  39. %macro align_rsp 1
  40. mov %1, 0
  41. test rsp, 0xF
  42. jnz %%next
  43. mov %1, 1
  44. sub rsp, 8
  45. %%next:
  46. %endmacro
  47. %macro recover_rsp 1
  48. cmp %1, 0
  49. je %%next
  50. add rsp, 8
  51. %%next:
  52. %endmacro
  53. %macro align_call 2
  54. align_rsp %2
  55. call %1
  56. recover_rsp %2
  57. %endmacro
  58. %macro push_xs 1
  59. push rcx
  60. mov rcx, %1
  61. rdmsr
  62. shl rdx, 32
  63. add rax, rdx
  64. mov rcx, [rsp]
  65. mov [rsp], rax
  66. %endmacro
  67. %macro pop_xs 1
  68. mov rax, [rsp]
  69. mov [rsp], rcx
  70. mov rdx, rax
  71. shr rdx, 32
  72. mov rcx, %1
  73. wrmsr
  74. pop rcx
  75. %endmacro
  76. ; push_regs(bool save_ret_addr, bool gs_swapped)
  77. %macro push_regs 2
  78. %if %1 == 1
  79. push rcx ; | ret_addr |<-rsp | ret_addr | | rax |
  80. mov rcx, [rsp + 8] ; |-----------| ---> |-----------| ---> |-----------|, rcx=ret_addr
  81. mov [rsp + 8], rax ; | | | rcx |<-rsp | rcx |<-rsp
  82. %else
  83. push rax
  84. push rcx
  85. %endif
  86. push rdx
  87. push rbx
  88. push rbp
  89. push rdi
  90. push rsi
  91. push r8
  92. push r9
  93. push r10
  94. push r11
  95. push r12
  96. push r13
  97. push r14
  98. push r15
  99. push rcx
  100. rdfsbase rcx
  101. xchg [rsp], rcx
  102. %if %2 == 1
  103. push_xs KERNEL_GS_BASE
  104. %else
  105. push rcx
  106. rdgsbase rcx
  107. xchg [rsp], rcx
  108. %endif
  109. %if %1 == 1
  110. push rcx
  111. %endif
  112. xor rcx, rcx
  113. xor rdx, rdx
  114. xor rbx, rbx
  115. xor rbp, rbp
  116. xor r8, r8
  117. xor r9, r9
  118. xor r10, r10
  119. xor r11, r11
  120. xor r12, r12
  121. xor r13, r13
  122. xor r14, r14
  123. xor r15, r15
  124. %endmacro
  125. ; pop_regs(bool gs_swapped)
  126. %macro pop_regs 1
  127. cmp word [rsp + Frame.cs], KRL_CODE_X64
  128. jne %%set_user
  129. mov ax, KRL_DATA_X64
  130. jmp %%pop
  131. %%set_user:
  132. mov ax, USR_DATA_X64
  133. %%pop:
  134. mov fs, ax
  135. %if %1 == 1
  136. pop_xs KERNEL_GS_BASE
  137. %else
  138. xchg rcx, [rsp]
  139. wrgsbase rcx
  140. pop rcx
  141. %endif
  142. xchg rcx, [rsp]
  143. wrfsbase rcx
  144. pop rcx
  145. pop r15
  146. pop r14
  147. pop r13
  148. pop r12
  149. pop r11
  150. pop r10
  151. pop r9
  152. pop r8
  153. pop rsi
  154. pop rdi
  155. pop rbp
  156. pop rbx
  157. pop rdx
  158. pop rcx
  159. pop rax
  160. %endmacro
  161. ; ---------------------------------------------------------------------------------------
  162. ; Interrupts
  163. ExVec_DivideBy0 equ 0
  164. ExVec_Debug equ 1
  165. ExVec_Nmi equ 2
  166. ExVec_Breakpoint equ 3
  167. ExVec_Overflow equ 4
  168. ExVec_Bound equ 5
  169. ExVec_InvalidOp equ 6
  170. ExVec_DeviceNa equ 7
  171. ExVec_DoubleFault equ 8
  172. ExVec_CoprocOverrun equ 9
  173. ExVec_InvalidTss equ 10
  174. ExVec_SegmentNa equ 11
  175. ExVec_StackFault equ 12
  176. ExVec_GeneralProt equ 13
  177. ExVec_PageFault equ 14
  178. ExVec_FloatPoint equ 16
  179. ExVec_Alignment equ 17
  180. ExVec_MachineCheck equ 18
  181. ExVec_SimdExcep equ 19
  182. ExVec_Virtual equ 20
  183. ExVec_ControlProt equ 21
  184. ExVec_VmmComm equ 29
  185. ApicVec_Timer equ 0x20
  186. ApicVec_Error equ 0x21
  187. ApicVec_IpiTaskMigrate equ 0x22
  188. ApicVec_Spurious equ 0xFF
  189. ; define_intr(vec, asm_name, name, err_vec)
  190. %macro define_intr 4
  191. global %2:function
  192. extern %3
  193. %2:
  194. %if %4 != 0
  195. push %4
  196. %endif
  197. call intr_entry
  198. mov rdi, rsp
  199. align_call %3, r12
  200. jmp intr_exit
  201. %endmacro
  202. [section .text]
  203. global switch_kframe:function
  204. ; Switch the kernel frame of the current thread.
  205. ;
  206. ; # Safety
  207. ;
  208. ; The layout in the stack must matches [`h2o::sched::task::ctx::x86_64::Kframe`].
  209. ;
  210. ; switch_kframe(rdi *old_kframe, rsi new_kframe)
  211. switch_kframe:
  212. push rbp
  213. push rbx
  214. push r12
  215. push r13
  216. push r14
  217. push r15
  218. pushfq
  219. push qword [rdx]
  220. push qword [rcx]
  221. xor rax, rax
  222. mov ax, cs
  223. push rax
  224. ; Save the current stack context.
  225. cmp rdi, 0
  226. je .switch
  227. mov [rdi], rsp
  228. .switch:
  229. ; Switch the stack (a.k.a. the context).
  230. mov rsp, rsi
  231. push .pop_regs
  232. retfq
  233. .pop_regs:
  234. pop qword [rcx]
  235. pop qword [rdx]
  236. popfq
  237. pop r15
  238. pop r14
  239. pop r13
  240. pop r12
  241. pop rbx
  242. pop rbp
  243. ret
  244. global task_fresh:function
  245. extern switch_finishing
  246. ; The entry into the interrupt context of a new task.
  247. task_fresh:
  248. xor rdi, rdi
  249. xor rsi, rsi
  250. align_call switch_finishing, r12
  251. cli
  252. jmp intr_exit
  253. ; define_intr(vec, asm_name, name, has_code)
  254. ; x86 exceptions
  255. define_intr ExVec_DivideBy0, rout_div_0, hdl_div_0, -1
  256. define_intr ExVec_Debug, rout_debug, hdl_debug, -1
  257. define_intr ExVec_Nmi, rout_nmi, hdl_nmi, -1
  258. define_intr ExVec_Breakpoint, rout_breakpoint, hdl_breakpoint, -1
  259. define_intr ExVec_Overflow, rout_overflow, hdl_overflow, -1
  260. define_intr ExVec_Bound, rout_bound, hdl_bound, -1
  261. define_intr ExVec_InvalidOp, rout_invalid_op, hdl_invalid_op, -1
  262. define_intr ExVec_DeviceNa, rout_device_na, hdl_device_na, -1
  263. define_intr ExVec_DoubleFault, rout_double_fault, hdl_double_fault, 0
  264. define_intr ExVec_CoprocOverrun, rout_coproc_overrun, hdl_coproc_overrun, -1
  265. define_intr ExVec_InvalidTss, rout_invalid_tss, hdl_invalid_tss, 0
  266. define_intr ExVec_SegmentNa, rout_segment_na, hdl_segment_na, 0
  267. define_intr ExVec_StackFault, rout_stack_fault, hdl_stack_fault, 0
  268. define_intr ExVec_GeneralProt, rout_general_prot, hdl_general_prot, 0
  269. define_intr ExVec_PageFault, rout_page_fault, hdl_page_fault, 0
  270. define_intr ExVec_FloatPoint, rout_fp_excep, hdl_fp_excep, -1
  271. define_intr ExVec_Alignment, rout_alignment, hdl_alignment, -1
  272. ; define_intr ExVec_MachineCheck, rout_mach_check, hdl_mach_check, 0
  273. define_intr ExVec_SimdExcep, rout_simd, hdl_simd, 0
  274. ; Local APIC interrupts
  275. define_intr ApicVec_Timer, rout_lapic_timer, hdl_lapic_timer, -1
  276. define_intr ApicVec_Error, rout_lapic_error, hdl_lapic_error, -1
  277. define_intr ApicVec_IpiTaskMigrate, rout_lapic_ipi_task_migrate, hdl_lapic_ipi_task_migrate, -1
  278. define_intr ApicVec_Spurious, rout_lapic_spurious, hdl_lapic_spurious, -1
  279. ; All other interrupts
  280. %define rout_name(x) rout_ %+ x
  281. %assign i 0x40
  282. %rep (0xFF - 0x40)
  283. define_intr i, rout_name(i), common_interrupt, i
  284. %assign i (i + 1)
  285. %endrep
  286. %undef rout_name
  287. extern save_regs; Save the GPRs from the current stack and switch to the task's `intr_stack`.
  288. intr_entry:
  289. cld
  290. cmp qword [rsp + 8 * 3], 0xc; Test if it's a reentrancy.
  291. je .reent
  292. swapgs
  293. lfence
  294. ; If we came from a kernel task, manually switch to its kernel stack.
  295. cmp qword [rsp + 8 * 3], 0x8
  296. jne .push_regs
  297. push rdi
  298. mov rdi, rsp
  299. mov rsp, [gs:KernelGs.tss_rsp0]
  300. push qword [rdi + 8 * 7]
  301. push qword [rdi + 8 * 6]
  302. push qword [rdi + 8 * 5]
  303. push qword [rdi + 8 * 4]
  304. push qword [rdi + 8 * 3]
  305. push qword [rdi + 8 * 2]
  306. push qword [rdi + 8]
  307. mov rdi, [rdi]
  308. .push_regs:
  309. push_regs 1, 1; The routine has a return address, so we must preserve it.
  310. lea rbp, [rsp + 8 + 1]
  311. mov rax, [gs:(KernelGs.kernel_fs)]
  312. wrfsbase rax
  313. align_call save_regs, r12
  314. jmp .ret
  315. .reent:
  316. ; A preemption happens.
  317. lfence
  318. push_regs 1, 0; The routine has a return address, so we must preserve it.
  319. lea rbp, [rsp + 8 + 1]
  320. .ret:
  321. ret
  322. intr_exit:
  323. cmp qword [rsp + Frame.cs], 0xc; Test if it's a reentrancy.
  324. je .reent
  325. pop_regs 1
  326. ; The stack now consists of errc and 'iretq stuff'
  327. add rsp, 8
  328. swapgs
  329. jmp .ret
  330. .reent:
  331. ; A preemption happens.
  332. pop_regs 0
  333. add rsp, 8
  334. .ret:
  335. iretq
  336. ; ---------------------------------------------------------------------------------------
  337. ; Syscalls
  338. global rout_syscall:function
  339. extern hdl_syscall
  340. rout_syscall:
  341. swapgs
  342. mov [gs:(KernelGs.syscall_user_stack)], rsp
  343. mov rsp, [gs:(KernelGs.tss_rsp0)]
  344. ; Fit the context to [`x86_64::Frame`]
  345. push qword USR_DATA_X64 ; ss
  346. push qword [gs:(KernelGs.syscall_user_stack)] ; rsp
  347. push r11 ; rflags
  348. push qword USR_CODE_X64 ; cs
  349. push rcx ; rip
  350. push -1 ; errc_vec
  351. push_regs 0, 1
  352. lea rbp, [rsp + 8 + 1]
  353. mov rax, [gs:(KernelGs.kernel_fs)]
  354. wrfsbase rax
  355. mov rcx, GS_BASE
  356. rdmsr
  357. mov rcx, KERNEL_GS_BASE
  358. wrmsr
  359. align_call save_regs, r12
  360. mov rdi, rsp
  361. align_call hdl_syscall, r12
  362. pop_regs 1
  363. add rsp, 8 ; errc_vec
  364. ; Here we must test the return address because Intel's mistake of `sysret`
  365. ; machanism. Normally, only codes on ring 3 (lower half) can execute `syscall`.
  366. ; See https://xenproject.org/2012/06/13/the-intel-sysret-privilege-escalation/
  367. test dword [rsp + 4], 0xFFFF8000 ; test if the return address is on the higher half
  368. jnz .fault_iret
  369. cmp qword [rsp + 8], 0x8 ; test if the return segment is kernel.
  370. je .fault_iret
  371. pop rcx ; rip
  372. add rsp, 8 ; cs
  373. pop r11 ; rflags
  374. ; pop qword [gs:(KernelGs.syscall_user_stack)] ; rsp
  375. ; ;add rsp, 8 ; ss
  376. ; mov rsp, [gs:(KernelGs.syscall_user_stack)]
  377. pop rsp ; simplify 3 instructions above
  378. swapgs
  379. o64 sysret
  380. .fault_iret:
  381. xor rcx, rcx
  382. xor r11, r11
  383. swapgs
  384. iretq