1
0

trap.S 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218
  1. /*++
  2. Copyright (c) 2012 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. trap.S
  9. Abstract:
  10. This module implements interrupt and exception trap management, such as
  11. saving and restoring registers.
  12. Author:
  13. Evan Green 3-Jul-2012
  14. Environment:
  15. Kernel mode
  16. --*/
  17. //
  18. // ------------------------------------------------------------------- Includes
  19. //
  20. #include <minoca/kernel/x86.inc>
  21. //
  22. // ---------------------------------------------------------------- Definitions
  23. //
  24. //
  25. // -------------------------------------------------------------------- Globals
  26. //
  27. //
  28. // ----------------------------------------------------------------------- Code
  29. //
  30. //
  31. // .text specifies that this code belongs in the executable section.
  32. //
  33. // .code32 specifies that this is 32-bit protected mode code.
  34. //
  35. .text
  36. .code32
  37. .globl HlVectorStart
  38. .globl HlVectorEnd
  39. .hidden HlVectorStart
  40. .hidden HlVectorEnd
  41. //
  42. // VOID
  43. // ArBreakExceptionHandlerAsm (
  44. // ULONG ReturnEip,
  45. // ULONG ReturnCodeSelector,
  46. // ULONG ReturnEflags
  47. // )
  48. //
  49. /*++
  50. Routine Description:
  51. This routine is called directly when an debug exception occurs. It sets up
  52. the parameters and calls a C routine to handle the break. It then restores
  53. machine state to return from the exception. The arguments to this function
  54. are pushed by the hardware.
  55. Arguments:
  56. ReturnEip - Supplies the address after the instruction that caused the trap.
  57. ReturnCodeSelector - Supplies the code selector the code that trapped was
  58. running under.
  59. ReturnEflags - Supplies the EFLAGS register immediately before the trap.
  60. Return Value:
  61. None.
  62. --*/
  63. FUNCTION(ArBreakExceptionHandlerAsm)
  64. pushl $0 # Push a dummy error code.
  65. call ArGenerateTrapFrame # Create a local trap frame.
  66. CFI_TRAP_FRAME_PUSHED # Set unwind info for the debugger.
  67. pushl %ebx # Push a pointer to it as a parameter.
  68. call KeDispatchBreakPointTrap # Call the main exception handler.
  69. addl $0x4, %esp # Pop the parameter.
  70. call ArRestoreTrapFrame # Restore the trap frame
  71. CFI_TRAP_FRAME_POPPED # Let the debugger know.
  72. addl $4, %esp # Pop the error code.
  73. iret # Return from the exception.
  74. END_FUNCTION(ArBreakExceptionHandlerAsm)
  75. //
  76. // VOID
  77. // KdNmiHandlerAsm (
  78. // VOID
  79. // )
  80. //
  81. /*++
  82. Routine Description:
  83. This routine is called directly when an NMI occurs. Since it is a hardware
  84. task switch, no registers need to be saved.
  85. Arguments:
  86. ReturnEip - Supplies the address after the instruction that caused the trap.
  87. ReturnCodeSelector - Supplies the code selector the code that trapped was
  88. running under.
  89. ReturnEflags - Supplies the EFLAGS register immediately before the trap.
  90. Return Value:
  91. None.
  92. --*/
  93. FUNCTION(KdNmiHandlerAsm)
  94. LoadKernelDataSegments # Load valid data segments.
  95. call KeDispatchNmiTrap # Call to the C routine to handle this mess.
  96. iret # Return from the exception.
  97. jmp KdNmiHandlerAsm # The next NMI starts here, jump back up.
  98. END_FUNCTION(KdNmiHandlerAsm)
  99. //
  100. // VOID
  101. // ArSingleStepExceptionHandlerAsm (
  102. // ULONG ReturnEip,
  103. // ULONG ReturnCodeSelector,
  104. // ULONG ReturnEflags
  105. // )
  106. //
  107. /*++
  108. Routine Description:
  109. This routine is called directly when an debug exception occurs. It sets up
  110. the parameters and calls the executive to dispatch the trap.
  111. Arguments:
  112. ReturnEip - Supplies the address after the instruction that caused the trap.
  113. ReturnCodeSelector - Supplies the code selector the code that trapped was
  114. running under.
  115. ReturnEflags - Supplies the EFLAGS register immediately before the trap.
  116. Return Value:
  117. None.
  118. --*/
  119. FUNCTION(ArSingleStepExceptionHandlerAsm)
  120. pushl $0 # Push a dummy error code.
  121. call ArGenerateTrapFrame # Create a local trap frame.
  122. CFI_TRAP_FRAME_PUSHED # Set unwind info for the debugger.
  123. pushl %ebx # Push a pointer to it as a parameter.
  124. call KeDispatchSingleStepTrap # Call the main exception handler.
  125. addl $0x4, %esp # Pop the parameter.
  126. call ArRestoreTrapFrame # Restore the trap frame
  127. CFI_TRAP_FRAME_POPPED # Let the debugger know.
  128. addl $4, %esp # Pop the error code.
  129. iret # Return from the exception.
  130. END_FUNCTION(ArSingleStepExceptionHandlerAsm)
  131. //
  132. // VOID
  133. // KdDebugServiceHandlerAsm (
  134. // ULONG ReturnEip,
  135. // ULONG ReturnCodeSelector,
  136. // ULONG ReturnEflags
  137. // )
  138. //
  139. /*++
  140. Routine Description:
  141. This routine is entered via an IDT entry to request debug service. It sets
  142. up the parameters and calls KdDebugExceptionHandler, and then restores
  143. machine state to return from the exception. The arguments to this function
  144. are pushed by the hardware. Upon Entry:
  145. eax - Supplies the debug service request.
  146. ecx - Supplies the parameter to the request.
  147. Arguments:
  148. ReturnEip - Supplies the address after the instruction that caused the trap.
  149. ReturnCodeSelector - Supplies the code selector the code that trapped was
  150. running under.
  151. ReturnEflags - Supplies the EFLAGS register immediately before the trap.
  152. Return Value:
  153. None.
  154. --*/
  155. FUNCTION(KdDebugServiceHandlerAsm)
  156. pushl $0 # Push a dummy error code.
  157. call ArGenerateTrapFrame # Create a local trap frame.
  158. CFI_TRAP_FRAME_PUSHED # Set unwind info for the debugger.
  159. pushl %ebx # Push a pointer to the trap frame.
  160. call KeDispatchDebugServiceTrap # Call the main exception handler.
  161. addl $0x4, %esp # Pop the parameter.
  162. call ArRestoreTrapFrame # Restore the trap frame
  163. CFI_TRAP_FRAME_POPPED # Let the debugger know.
  164. addl $4, %esp # Pop the error code.
  165. iret # Return from the exception.
  166. END_FUNCTION(KdDebugServiceHandlerAsm)
  167. //
  168. // VOID
  169. // ArDivideByZeroExceptionHandlerAsm (
  170. // ULONG ReturnEip,
  171. // ULONG ReturnCodeSelector,
  172. // ULONG ReturnEflags
  173. // )
  174. //
  175. /*++
  176. Routine Description:
  177. This routine is called directly when a divide by zero exception occurs.
  178. Arguments:
  179. ReturnEip - Supplies the address after the instruction that caused the trap.
  180. ReturnCodeSelector - Supplies the code selector the code that trapped was
  181. running under.
  182. ReturnEflags - Supplies the EFLAGS register immediately before the trap.
  183. Return Value:
  184. None.
  185. --*/
  186. FUNCTION(ArDivideByZeroExceptionHandlerAsm)
  187. pushl $0 # Push a dummy error code.
  188. call ArGenerateTrapFrame # Create a local trap frame.
  189. CFI_TRAP_FRAME_PUSHED # Set unwind info for the debugger.
  190. pushl %ebx # Push a pointer to it as a parameter.
  191. call KeDispatchDivideByZeroTrap # Call the main exception handler.
  192. addl $0x4, %esp # Pop the parameters.
  193. call ArRestoreTrapFrame # Restore the trap frame
  194. CFI_TRAP_FRAME_POPPED # Let the debugger know.
  195. addl $4, %esp # Pop the error code.
  196. iret # Return from the exception.
  197. END_FUNCTION(ArDivideByZeroExceptionHandlerAsm)
  198. //
  199. // VOID
  200. // ArFpuAccessExceptionHandlerAsm (
  201. // ULONG ReturnEip,
  202. // ULONG ReturnCodeSelector,
  203. // ULONG ReturnEflags
  204. // )
  205. //
  206. /*++
  207. Routine Description:
  208. This routine is called directly when floating point access occurs and the
  209. TS bit in CR0 is
  210. Arguments:
  211. ReturnEip - Supplies the address after the instruction that caused the trap.
  212. ReturnCodeSelector - Supplies the code selector the code that trapped was
  213. running under.
  214. ReturnEflags - Supplies the EFLAGS register immediately before the trap.
  215. Return Value:
  216. None.
  217. --*/
  218. FUNCTION(ArFpuAccessExceptionHandlerAsm)
  219. pushl $0 # Push a dummy error code.
  220. call ArGenerateTrapFrame # Create a local trap frame.
  221. CFI_TRAP_FRAME_PUSHED # Set unwind info for the debugger.
  222. pushl %ebx # Push a pointer to it as a parameter.
  223. call KeDispatchFpuAccessTrap # Call the main exception handler.
  224. addl $0x4, %esp # Pop the parameters.
  225. call ArRestoreTrapFrame # Restore the trap frame
  226. CFI_TRAP_FRAME_POPPED # Let the debugger know.
  227. addl $4, %esp # Pop the error code.
  228. iret # Return from the exception.
  229. END_FUNCTION(ArFpuAccessExceptionHandlerAsm)
  230. //
  231. // VOID
  232. // ArDoubleFaultHandlerAsm (
  233. // VOID
  234. // )
  235. //
  236. /*++
  237. Routine Description:
  238. This routine is entered via an IDT entry when a double fault exception
  239. occurs. Double faults are non-recoverable. This machine loops attempting
  240. to enter the debugger indefinitely.
  241. Arguments:
  242. None.
  243. Return Value:
  244. None, this routine does not return.
  245. --*/
  246. FUNCTION(ArDoubleFaultHandlerAsm)
  247. LoadKernelDataSegments # Load valid data segments.
  248. call ArpHandleDoubleFault # Call to the C routine to handle this mess.
  249. nop
  250. END_FUNCTION(ArDoubleFaultHandlerAsm)
  251. //
  252. // VOID
  253. // ArProtectionFaultHandlerAsm (
  254. // ULONG ReturnEip,
  255. // ULONG ReturnCodeSelector,
  256. // ULONG ReturnEflags
  257. // )
  258. //
  259. /*++
  260. Routine Description:
  261. This routine is called directly when a general protection fault occurs.
  262. It's job is to prepare the trap frame, call the appropriate handler, and
  263. then restore the trap frame.
  264. Arguments:
  265. ReturnEip - Supplies the address after the instruction that caused the trap.
  266. ReturnCodeSelector - Supplies the code selector the code that trapped was
  267. running under.
  268. ReturnEflags - Supplies the EFLAGS register immediately before the trap.
  269. Return Value:
  270. None.
  271. --*/
  272. FUNCTION(ArProtectionFaultHandlerAsm)
  273. call ArGenerateTrapFrame # Create a local trap frame.
  274. CFI_TRAP_FRAME_PUSHED # Set unwind info for the debugger.
  275. pushl %ebx # Push a pointer to it as a parameter.
  276. call KeDispatchProtectionFault # Call the main handler.
  277. addl $0x4, %esp # Pop the parameter.
  278. call ArRestoreTrapFrame # Restore the trap frame
  279. CFI_TRAP_FRAME_POPPED # Let the debugger know.
  280. addl $4, %esp
  281. iret # Return from the exception.
  282. END_FUNCTION(ArProtectionFaultHandlerAsm)
  283. //
  284. // VOID
  285. // ArMathFaultHandlerAsm (
  286. // ULONG ReturnEip,
  287. // ULONG ReturnCodeSelector,
  288. // ULONG ReturnEflags
  289. // )
  290. //
  291. /*++
  292. Routine Description:
  293. This routine is called directly when a x87 FPU fault occurs.
  294. Arguments:
  295. ReturnEip - Supplies the address after the instruction that caused the trap.
  296. ReturnCodeSelector - Supplies the code selector the code that trapped was
  297. running under.
  298. ReturnEflags - Supplies the EFLAGS register immediately before the trap.
  299. Return Value:
  300. None.
  301. --*/
  302. FUNCTION(ArMathFaultHandlerAsm)
  303. pushl $0 # Push a dummy error code.
  304. call ArGenerateTrapFrame # Create a local trap frame.
  305. CFI_TRAP_FRAME_PUSHED # Set unwind info for the debugger.
  306. pushl %ebx # Push a pointer to it as a parameter.
  307. call KeDispatchMathFault # Call the main handler.
  308. addl $0x4, %esp # Pop the parameter.
  309. call ArRestoreTrapFrame # Restore the trap frame
  310. CFI_TRAP_FRAME_POPPED # Let the debugger know.
  311. addl $4, %esp # Pop dummy error code.
  312. iret # Return from the exception.
  313. END_FUNCTION(ArMathFaultHandlerAsm)
  314. //
  315. // VOID
  316. // ArTrapSystemCallHandlerAsm (
  317. // ULONG ReturnEip,
  318. // ULONG ReturnCodeSelector,
  319. // ULONG ReturnEflags
  320. // )
  321. //
  322. /*++
  323. Routine Description:
  324. This routine is entered when the sysenter routine is entered with the TF
  325. flag set. It performs a normal save and sets the TF.
  326. Arguments:
  327. ReturnEip - Supplies the address after the instruction that caused the trap.
  328. ReturnCodeSelector - Supplies the code selector the code that trapped was
  329. running under.
  330. ReturnEflags - Supplies the EFLAGS register immediately before the trap.
  331. Return Value:
  332. None.
  333. --*/
  334. FUNCTION(ArTrapSystemCallHandlerAsm)
  335. //
  336. // ESP is currently pointing at the processor double fault stack, which
  337. // is also the main TSS. Switch to the thread stack.
  338. //
  339. movl TSS_ESP0(%esp), %esp # Load the stack.
  340. sti # Re-enable interrupts.
  341. //
  342. // Fake a user mode exception by pushing SS, Esp, Eflags, CS and Eip.
  343. //
  344. pushl $USER_DS # Push user mode SS.
  345. pushl %eax # Push user ESP supplied by sysenter.
  346. pushfl # Push the Eflags.
  347. pushl $USER32_CS # Push user CS.
  348. pushl %ebx # Push return address supplied by sysenter.
  349. pushl $0 # Push a dummy error code.
  350. call ArGenerateTrapFrame # Create a local trap frame.
  351. CFI_TRAP_FRAME_PUSHED # Set unwind info for the debugger.
  352. orl $IA32_EFLAG_TF, TRAP_EFLAGS(%ebx) # Set the trap flag.
  353. jmp ArSystemCallHandlerAfterTrapSave # Go to the regular path.
  354. END_FUNCTION(ArTrapSystemCallHandlerAsm)
  355. //
  356. // INTN
  357. // ArSystemCallHandlerAsm (
  358. // ULONG ReturnEip,
  359. // ULONG ReturnCodeSelector,
  360. // ULONG ReturnEflags
  361. // )
  362. //
  363. /*++
  364. Routine Description:
  365. This routine is entered via an IDT entry to service a user mode request.
  366. Ecx contains the system call number, and Edx contains the argument.
  367. Arguments:
  368. ReturnEip - Supplies the address after the instruction that caused the trap.
  369. ReturnCodeSelector - Supplies the code selector the code that trapped was
  370. running under.
  371. ReturnEflags - Supplies the EFLAGS register immediately before the trap.
  372. Return Value:
  373. STATUS_SUCCESS or positive integer on success.
  374. Error status code on failure.
  375. --*/
  376. FUNCTION(ArSystemCallHandlerAsm)
  377. pushl $0 # Push a dummy error code.
  378. //
  379. // Save the complete trap frame. This routine is aware that
  380. // ArGenerateTrapFrame doesn't clobber ecx and edx, which hold the system
  381. // call number and parameter. If ArGenerateTrapFrame did clobber those
  382. // registers, they'd need to be reloaded after this.
  383. //
  384. call ArGenerateTrapFrame # Create a local trap frame.
  385. CFI_TRAP_FRAME_PUSHED # Set unwind info for the debugger.
  386. ArSystemCallHandlerAfterTrapSave:
  387. //
  388. // Push the parameters for the system call handler. The compiler is free to
  389. // modify the parameters on the stack in the callee, so this second push is
  390. // necessary.
  391. //
  392. subl $4, %esp # Make room for the boolean.
  393. pushl %esp # Push the boolean pointer parameter.
  394. pushl %ebx # Push a pointer to the trap frame.
  395. pushl %edx # Push system call parameter.
  396. pushl %ecx # Push system call number.
  397. CFI_ADJUST_CFA_OFFSET(20) # Tell the debugger.
  398. call KeSystemCallHandler # Call the main exception handler.
  399. addl $0x10, %esp # Pop the parameters.
  400. CFI_ADJUST_CFA_OFFSET(-16) # Tell the debugger.
  401. movl %eax, TRAP_EAX(%ebx) # Save the return value in the trap frame.
  402. //
  403. // See if there is a signal pending on the current thread, as returned by
  404. // the system call handler.
  405. //
  406. popl %ecx # Get the signal pending boolean
  407. CFI_ADJUST_CFA_OFFSET(-4) # Tell the debugger.
  408. testl %ecx, %ecx # See if it's zero.
  409. jz ArSystemCallHandlerExit # Skip the expensive signal stuff.
  410. //
  411. // Push the trap frame as the first parameter. The system call number and
  412. // system call parameter were saved on the stack earlier for this call.
  413. //
  414. pushl %ebx # Push trap frame.
  415. CFI_ADJUST_CFA_OFFSET(4) # Notify about the push.
  416. call PsApplyPendingSignalsOrRestart # Apply signals or restart the call.
  417. addl $0x4, %esp # Pop the trap frame.
  418. CFI_ADJUST_CFA_OFFSET(-4) # Notify about the pop.
  419. ArSystemCallHandlerExit:
  420. call ArRestoreTrapFrame # Restore the trap frame
  421. CFI_TRAP_FRAME_POPPED # Let the debugger know.
  422. addl $0x4, %esp # Pop the error code.
  423. iret # Return from the exception.
  424. END_FUNCTION(ArSystemCallHandlerAsm)
  425. //
  426. // INTN
  427. // ArSysenterHandlerAsm (
  428. // VOID
  429. // )
  430. //
  431. /*++
  432. Routine Description:
  433. This routine is executed when user mode invokes the SYSENTER instruction.
  434. Upon entry, CS, EIP, and ESP are set to predefined values set in MSRs.
  435. Arguments:
  436. None.
  437. Return Value:
  438. STATUS_SUCCESS or positive integer on success.
  439. Error status code on failure.
  440. --*/
  441. FUNCTION(ArSysenterHandlerAsm)
  442. //
  443. // ESP is currently pointing at the processor double fault stack, which
  444. // is also the main TSS. Switch to the thread stack. Make room on the stack
  445. // as if the hardware has pushed SS, ESP, EFLAGS, CS, EIP, and an error
  446. // code, since the return path might go out with a full iret.
  447. //
  448. movl TSS_ESP0(%esp), %esp # Load the stack.
  449. subl $24, %esp # Fake the hardware pushes.
  450. //
  451. // Make a fake trap frame but fill in the bare minimum: Eip and Esp.
  452. // These are needed so they can be saved if a signal is dispatched.
  453. //
  454. pushl %eax # Save user ESP in trap frame.
  455. LoadKernelDataSegments # Load kernel data segments (using EAX).
  456. sti # Re-enable interrupts.
  457. subl $(TRAP_FRAME_SIZE - 4), %esp # Allocate the rest of the trap frame.
  458. movl %ebx, TRAP_EIP(%esp) # EBX contains the return address.
  459. movl %esp, %ebx # Save the trap frame in EBX.
  460. movl %ecx, TRAP_ECX(%esp) # Save system call number for restarts.
  461. movl %edx, TRAP_EDX(%esp) # Save system call parameter for restarts.
  462. //
  463. // There's a trap frame at ebx, which is nice since it won't require
  464. // maintenance over all these upcoming push/pops of the stack.
  465. //
  466. CFI_DEF_CFA(%ebx, 0)
  467. CFI_OFFSET(%eip, TRAP_EIP)
  468. CFI_OFFSET(%esp, TRAP_ESP)
  469. CFI_OFFSET(%ecx, TRAP_ECX)
  470. CFI_OFFSET(%edx, TRAP_EDX)
  471. //
  472. // Move user DS (rather than user CS) into the trap frame to indicate
  473. // 1) this is a user mode trap frame and 2) it's incomplete.
  474. //
  475. movl $USER_DS, TRAP_CS(%ebx) # Indicate a user mode trap frame.
  476. //
  477. // Push the parameters for the system call handler and execute it.
  478. //
  479. subl $4, %esp # Make room for the boolean.
  480. pushl %esp # Push the boolean pointer parameter.
  481. pushl %ebx # Push a pointer to the sort-of trap frame.
  482. pushl %edx # Push EDX, the system call parameter.
  483. pushl %ecx # Push ECX, the system call number.
  484. call KeSystemCallHandler # Call out to the main service handler.
  485. addl $0x10, %esp # Pop the function parameters.
  486. //
  487. // See if there is a signal pending on the current thread, as returned by
  488. // the system call handler.
  489. //
  490. popl %ecx # Get the signal pending boolean
  491. testl %ecx, %ecx # See if it's zero.
  492. jz ArSysenterHandlerRestore # Skip the expensive signal stuff.
  493. //
  494. // See if the trap frame is already complete, as a result perhaps of the
  495. // system call itself. If so, skip the full save part, as it might undo
  496. // useful work (like restoring pre-signal context).
  497. //
  498. cmpl $USER32_CS, TRAP_CS(%ebx) # See if the trap frame is complete.
  499. je ArSysenterSignalDispatch # Skip the save if complete already.
  500. //
  501. // Upgrade the trap frame to a complete one. Update user CS to indicate the
  502. // trap frame is complete. This will also mean the expensive iret exit path
  503. // is used.
  504. //
  505. movl $USER32_CS, TRAP_CS(%ebx) # Save CS.
  506. movl $USER_DS, TRAP_DS(%ebx) # Save DS.
  507. movl $USER_DS, TRAP_ES(%ebx) # Save ES.
  508. movl $GDT_THREAD, TRAP_FS(%ebx) # Save FS.
  509. movl $GDT_THREAD, TRAP_GS(%ebx) # Save GS.
  510. movl $USER_DS, TRAP_SS(%ebx) # Save SS.
  511. //
  512. // Save the registers.
  513. //
  514. movl %eax, TRAP_EAX(%ebx) # Save the return value in the trap frame.
  515. movl $0x0, TRAP_EBX(%ebx) # Zero EBX. It holds the kernel trap pointer.
  516. movl %esi, TRAP_ESI(%ebx) # Save ESI. It is non-volatile.
  517. movl %edi, TRAP_EDI(%ebx) # Save EDI. It is non-volatile.
  518. movl %ebp, TRAP_EBP(%ebx) # Save EBP. It is non-volatile.
  519. movl $0x0, TRAP_ERRORCODE(%ebx) # Scrub the error code.
  520. movl $(IA32_EFLAG_ALWAYS_1 | IA32_EFLAG_IF), TRAP_EFLAGS(%ebx)
  521. ArSysenterSignalDispatch:
  522. //
  523. // Push the trap frame as the first parameter, either apply signals now
  524. // that a full trap frame is available, or potentially restart the system
  525. // call if no signals were applied (maybe a process-wide signal got
  526. // serviced by another thread).
  527. //
  528. pushl %ebx # Pass the trap frame.
  529. call PsApplyPendingSignalsOrRestart # Dispatch signals or restart.
  530. addl $0x4, %esp # Pop the parameter.
  531. ArSysenterHandlerRestore:
  532. //
  533. // See if the trap frame is complete. If it is, then go do the slower
  534. // complete restore.
  535. //
  536. cmpl $USER32_CS, TRAP_CS(%ebx) # See if the trap frame is complete.
  537. je ArSystemCallHandlerExit # Do a full restore if so.
  538. //
  539. // Reset the segment registers to user mode and return.
  540. //
  541. mov $USER_DS, %cx # Get the user mode DS.
  542. mov %cx, %ds # Move to DS.
  543. mov %cx, %es # Move to ES.
  544. mov $GDT_THREAD, %cx # Get the user-mode GS.
  545. mov %cx, %fs # Move to FS.
  546. mov %cx, %gs # Move to GS.
  547. CFI_DEF_CFA(%esp, 0) # The trap frame is at ESP, EBX is gone.
  548. //
  549. // Restore some portions of the pseudo trap frame. Do not zero EAX as it
  550. // holds the return value from the system call.
  551. //
  552. movl TRAP_ESP(%esp), %ecx # Sysexit moves ECX to ESP.
  553. movl TRAP_EIP(%esp), %edx # Sysexit moves EDX to EIP.
  554. sysexit # Return to user mode, slickly.
  555. END_FUNCTION(ArSysenterHandlerAsm)
  556. //
  557. // VOID
  558. // ArpPageFaultHandlerAsm (
  559. // ULONG ReturnEip,
  560. // ULONG ReturnCodeSelector,
  561. // ULONG ReturnEflags
  562. // )
  563. //
  564. /*++
  565. Routine Description:
  566. This routine is called directly when a page fault occurs.
  567. Arguments:
  568. ReturnEip - Supplies the address after the instruction that caused the
  569. fault.
  570. ReturnCodeSelector - Supplies the code selector the code that faulted was
  571. running under.
  572. ReturnEflags - Supplies the EFLAGS register immediately before the fault.
  573. Return Value:
  574. None.
  575. --*/
  576. FUNCTION(ArpPageFaultHandlerAsm)
  577. call ArGenerateTrapFrame # Create a local trap frame.
  578. CFI_TRAP_FRAME_PUSHED # Set unwind info for the debugger.
  579. movl %cr2, %ecx # Get the faulting address.
  580. xor %edx, %edx # Zero edx.
  581. movl %edx, %cr2 # Clear CR2.
  582. sti # Re-enable interrupts.
  583. pushl %ebx # Push a pointer to to the trap frame.
  584. pushl %ecx # Push CR2.
  585. CFI_ADJUST_CFA_OFFSET(8) # Tell the debugger.
  586. call KeDispatchPageFault # Call the main exception handler.
  587. addl $8, %esp # Pop the parameters.
  588. CFI_ADJUST_CFA_OFFSET(-8) # Pop them in the debugger.
  589. call ArRestoreTrapFrame # Restore the trap frame
  590. CFI_TRAP_FRAME_POPPED # Let the debugger know.
  591. addl $4, %esp # Pop the error code.
  592. iret # Return from the exception.
  593. END_FUNCTION(ArpPageFaultHandlerAsm)
  594. //
  595. // VOID
  596. // HlSpuriousInterruptHandlerAsm (
  597. // ULONG ReturnEip,
  598. // ULONG ReturnCodeSelector,
  599. // ULONG ReturnEflags
  600. // )
  601. //
  602. /*++
  603. Routine Description:
  604. This routine handles spurious interrupts. It does not require an EOI or
  605. other interrupt acknowledgement.
  606. Arguments:
  607. ReturnEip - Supplies the address after the instruction that caused the trap.
  608. ReturnCodeSelector - Supplies the code selector the code that trapped was
  609. running under.
  610. ReturnEflags - Supplies the EFLAGS register immediately before the trap.
  611. Return Value:
  612. None.
  613. --*/
  614. FUNCTION(HlSpuriousInterruptHandlerAsm)
  615. pushl $0 # Push a dummy error code.
  616. call ArGenerateTrapFrame # Create a local trap frame.
  617. CFI_TRAP_FRAME_PUSHED # Set unwind info for the debugger.
  618. addl $1, HlSpuriousInterruptCount # Count interrupts
  619. call ArRestoreTrapFrame # Restore the trap frame
  620. CFI_TRAP_FRAME_POPPED # Let the debugger know.
  621. addl $4, %esp # Pop the error code.
  622. iret # Return from the exception.
  623. END_FUNCTION(HlSpuriousInterruptHandlerAsm)
  624. //
  625. // VOID
  626. // ArRestoreTrapFrame (
  627. // PTRAP_FRAME TrapFrame
  628. // )
  629. //
  630. /*++
  631. Routine Description:
  632. This routine restores information contained in a trap frame to the
  633. processor and prepares the machine for an iret back to the code that
  634. generated this trap frame. It's not really a function because it assumes
  635. a specific stack layout and modifies data that technically belongs to the
  636. caller. It should only be called immediately before returning from an
  637. exception or interrupt.
  638. Arguments:
  639. TrapFrame - Supplies the trap frame to restore, in ebx.
  640. Return Value:
  641. Upon return, the trap frame will have been popped off the stack, and the
  642. machine will be in the same state as right after the exception happened.
  643. --*/
  644. FUNCTION(ArRestoreTrapFrame)
  645. mov %ebx, %ecx # Move trap frame to ecx.
  646. addl $TRAP_FRAME_SIZE+16, %ebx # Compute the pre-exception stack.
  647. movl TRAP_CS(%ecx), %edx # Get the destination CS.
  648. //
  649. // The exception is returning to either kernel or user mode. Either way restore
  650. // the common data segment registers. Hold off on DS, as this routine will
  651. // make a couple more DS: accesses. Save it in ESI.
  652. //
  653. movl TRAP_DS(%ecx), %esi # Save DS into ESI for now.
  654. movl TRAP_ES(%ecx), %eax # Restore ES.
  655. movw %ax, %es #
  656. movl TRAP_FS(%ecx), %eax # Restore FS.
  657. movw %ax, %fs #
  658. movl TRAP_GS(%ecx), %eax # Restore GS.
  659. movw %ax, %gs #
  660. //
  661. // Restore the remaining registers based on the destination mode.
  662. //
  663. movl %edx, %eax # Get CS (loaded above).
  664. andl $SEGMENT_PRIVILEGE_MASK, %eax # AND out the privilege.
  665. jz RestoreTrapFrameToKernelMode # Jump over if not.
  666. //
  667. // The exception is going to jump back into user mode, so put the stack
  668. // pointer and segments back into the exception-generated part of the stack.
  669. //
  670. movl TRAP_ESP(%ecx), %eax # Restore Esp.
  671. movl %eax, TRAP_RET_ESP(%ecx) #
  672. movl TRAP_SS(%ecx), %eax # Restore SS.
  673. movl %eax, TRAP_RET_SS(%ecx) #
  674. jmp RestoreTrapFrameGeneralRegisters # Jump to the end.
  675. RestoreTrapFrameToKernelMode:
  676. //
  677. // The exception came from kernel mode, so restore the stack segment register.
  678. //
  679. movl TRAP_SS(%ecx), %eax # Restore SS. If this doesn't allow access
  680. movw %ax, %ss # to the current stack, this will be bad.
  681. //
  682. // Build the iret return. The parameters going on the new stack are Ebx, Return
  683. // Address, Error Code, Eip, CS, and Eflags.
  684. //
  685. // Note that if the stack pointer doesn't change, the Ebx and Return address
  686. // values destroy data that was on the stack there (immediately after the
  687. // Eflags, CS, Eip). This happens to be the last two values in the trap frame
  688. // structure. Luckily those members are Esp and Eflags, which are restored
  689. // immediately before their values are destroyed.
  690. //
  691. movl TRAP_ESP(%ecx), %ebx # Get the kernel Esp.
  692. RestoreTrapFrameGeneralRegisters:
  693. subl $24, %ebx # Make room for the new parameters.
  694. movl TRAP_EIP(%ecx), %eax # Restore Eip.
  695. movl %eax, 12(%ebx) #
  696. movl %edx, 16(%ebx) # Restore CS.
  697. movl TRAP_EFLAGS(%ecx), %eax # Restore Eflags.
  698. movl %eax, 20(%ebx) #
  699. movl TRAP_EBX(%ecx), %eax # Save Ebx.
  700. movl %eax, (%ebx) #
  701. movl (%esp), %eax # Save this function's return address.
  702. movl %eax, 4(%ebx) #
  703. //
  704. // Now that all DS: accesses are finished, restore DS.
  705. //
  706. movw %si, %ds
  707. //
  708. // Move the trap frame pointer to the stack, popping everything up until then,
  709. // including the extended state.
  710. //
  711. movl %ecx, %esp # Pop up to the trap frame.
  712. //
  713. // Restore the general registers.
  714. //
  715. movl TRAP_EAX(%esp), %eax #
  716. movl TRAP_ECX(%esp), %ecx #
  717. movl TRAP_EDX(%esp), %edx #
  718. movl TRAP_ESI(%esp), %esi #
  719. movl TRAP_EDI(%esp), %edi #
  720. movl TRAP_EBP(%esp), %ebp #
  721. //
  722. // Transition to the new kernel mode stack pointer, pop Ebx, and return.
  723. //
  724. movl %ebx, %esp # Move stacks!
  725. popl %ebx # Restore Ebx.
  726. ret
  727. END_FUNCTION(ArRestoreTrapFrame)
  728. //
  729. // --------------------------------------------------------- Internal Functions
  730. //
  731. //
  732. // This macro stamps out the assembly dispatch code necessary for interrupts
  733. // received at each vector. It will create code for all vectors between
  734. // MinimumVector and MaximumVector.
  735. //
  736. .macro InterruptVector _Vector
  737. //
  738. // 0x6A xx is the instruction for push imm8, except the immediate is sign
  739. // extended. The assembler will use the longer form for numbers >= 0x80
  740. // since those should not be sign extended. Use the shorter form directly
  741. // here to save space, and deal with it using a cast in the C code.
  742. //
  743. .byte 0x6A
  744. .byte (\_Vector)
  745. jmp KeInterruptEntry
  746. .endm
  747. .macro InterruptVectors16 _Vector
  748. InterruptVector (\_Vector)
  749. InterruptVector (\_Vector + 1)
  750. InterruptVector (\_Vector + 2)
  751. InterruptVector (\_Vector + 3)
  752. InterruptVector (\_Vector + 4)
  753. InterruptVector (\_Vector + 5)
  754. InterruptVector (\_Vector + 6)
  755. InterruptVector (\_Vector + 7)
  756. InterruptVector (\_Vector + 8)
  757. InterruptVector (\_Vector + 9)
  758. InterruptVector (\_Vector + 10)
  759. InterruptVector (\_Vector + 11)
  760. InterruptVector (\_Vector + 12)
  761. InterruptVector (\_Vector + 13)
  762. InterruptVector (\_Vector + 14)
  763. InterruptVector (\_Vector + 15)
  764. .endm
  765. //
  766. // Now actually instantiate the macro to create the vector code.
  767. //
  768. HlVectorStart:
  769. InterruptVectors16 0x30
  770. InterruptVectors16 0x40
  771. InterruptVectors16 0x50
  772. InterruptVectors16 0x60
  773. InterruptVectors16 0x70
  774. InterruptVectors16 0x80
  775. InterruptVectors16 0x90
  776. InterruptVectors16 0xA0
  777. InterruptVectors16 0xB0
  778. InterruptVectors16 0xC0
  779. InterruptVectors16 0xD0
  780. InterruptVectors16 0xE0
  781. InterruptVectors16 0xF0
  782. HlVectorEnd:
  783. //
  784. // PTRAP_FRAME
  785. // ArGenerateTrapFrame (
  786. // ULONG ReturnEip,
  787. // ULONG ReturnCs,
  788. // ULONG ReturnEflags,
  789. // ...
  790. // )
  791. //
  792. /*++
  793. Routine Description:
  794. This routine generates a trap frame based on the data pushed onto the
  795. stack by the processor after an exception. It is not really a function
  796. in that it assumes a certain stack layout and will modify data that
  797. belongs to the caller. This function should only be called immediately
  798. after an interrupt/exception.
  799. Arguments:
  800. ReturnEip - Supplies the instruction that generated the exception.
  801. ReturnCs - Supplies the code selector of the code that generated the
  802. exception.
  803. ReturnEflags - Supplies the flags of the code that generated the
  804. exception.
  805. Return Value:
  806. Returns a pointer to the trap frame in ebx.
  807. --*/
  808. FUNCTION(ArGenerateTrapFrame)
  809. //
  810. // Allocate room on the stack for the trap frame plus the return address,
  811. // minus the original return address.
  812. //
  813. subl $TRAP_FRAME_SIZE, %esp #
  814. pushl %eax # Save eax for a moment while the return
  815. movl TRAP_FRAME_SIZE+4(%esp), %eax # address is moved.
  816. movl %eax, 4(%esp) #
  817. popl %eax # Restore eax
  818. movl %eax, TRAP_EAX+4(%esp) # Save the general registers.
  819. movl %ebx, TRAP_EBX+4(%esp) #
  820. movl %ecx, TRAP_ECX+4(%esp) #
  821. movl %edx, TRAP_EDX+4(%esp) #
  822. movl %esi, TRAP_ESI+4(%esp) #
  823. movl %edi, TRAP_EDI+4(%esp) #
  824. movl %ebp, TRAP_EBP+4(%esp) #
  825. movl TRAP_RET_ERRORCODE+4(%esp), %eax # Save the error code.
  826. movl %eax, TRAP_ERRORCODE+4(%esp) #
  827. movl TRAP_RET_EIP+4(%esp), %eax # Save the return address.
  828. movl %eax, TRAP_EIP+4(%esp) #
  829. movl TRAP_RET_CS+4(%esp), %ebx # Save the return CS.
  830. movl %ebx, TRAP_CS+4(%esp) #
  831. movl TRAP_RET_EFLAGS+4(%esp), %eax # Save eflags.
  832. movl %eax, TRAP_EFLAGS+4(%esp)
  833. //
  834. // Figure out if a ring change occurred.
  835. //
  836. andl $SEGMENT_PRIVILEGE_MASK, %ebx # exception had a ring change.
  837. jz GenerateTrapFrameFromKernelMode # Jump over if not.
  838. //
  839. // The exception caused a privilege level change, so the stack contains the
  840. // following ULONGs: Eip, CS, Eflags, Esp, and SS. Get the other segment
  841. // selectors from their current values.
  842. //
  843. movl TRAP_RET_ESP+4(%esp), %eax # Save Esp.
  844. movl %eax, TRAP_ESP+4(%esp) #
  845. movl TRAP_RET_SS+4(%esp), %eax # Save SS.
  846. movl %eax, TRAP_SS+4(%esp) #
  847. xorl %eax, %eax # Zero out eax.
  848. movw %ds, %ax # Save DS.
  849. movl %eax, TRAP_DS+4(%esp) #
  850. movw %es, %ax # Save ES.
  851. movl %eax, TRAP_ES+4(%esp) #
  852. movw %fs, %ax # Save FS.
  853. movl %eax, TRAP_FS+4(%esp) #
  854. movw %gs, %ax # Save GS.
  855. movl %eax, TRAP_GS+4(%esp) #
  856. jmp GenerateTrapFrameEnd # All done.
  857. GenerateTrapFrameFromKernelMode:
  858. //
  859. // The exception came from kernel mode, so the only things pushed on the stack
  860. // by the processor are Eip, CS, and Eflags. The data segments also don't need
  861. // to be saved. Get the data segments from their current values. Since there
  862. // was no stack change, the Esp is simply this current one except all the
  863. // stuff pushed by the exception, plus the error code.
  864. //
  865. movl %esp, %eax # Save Esp.
  866. addl $TRAP_FRAME_SIZE+20, %eax # Remove exception stack items.
  867. movl %eax, TRAP_ESP+4(%esp) #
  868. xorl %eax, %eax # Zero out eax.
  869. movw %ds, %ax # Save DS.
  870. movl %eax, TRAP_DS+4(%esp) #
  871. movw %es, %ax # Save ES.
  872. movl %eax, TRAP_ES+4(%esp) #
  873. movw %fs, %ax # Save FS.
  874. movl %eax, TRAP_FS+4(%esp) #
  875. movw %gs, %ax # Save GS.
  876. movl %eax, TRAP_GS+4(%esp) #
  877. movw %ss, %ax # Save SS.
  878. movl %eax, TRAP_SS+4(%esp) #
  879. GenerateTrapFrameEnd:
  880. LoadKernelDataSegments # Load valid data segments.
  881. popl %edi # Pop the return address.
  882. movl %esp, %ebx # Return the trap pointer.
  883. jmp *%edi # Return
  884. END_FUNCTION(ArGenerateTrapFrame)
  885. //
  886. // Define the common interrupt entry code. At this point the vector number has
  887. // been pushed into the error code slot, but nothing else has been done. Note
  888. // that this code needs to be far enough away from the vectors themselves so
  889. // that none of the jumps in the vectors turn into shorter instructions
  890. // (distance >= 0x100).
  891. //
  892. FUNCTION(KeInterruptEntry)
  893. call ArGenerateTrapFrame # Create a local trap frame.
  894. CFI_TRAP_FRAME_PUSHED # Set unwind info for the debugger.
  895. pushl %ebx # Push a pointer to it as a parameter.
  896. CFI_ADJUST_CFA_OFFSET(4)
  897. call KeDispatchInterrupt # Dispatch the interrupt.
  898. addl $4, %esp # Pop the parameters.
  899. CFI_ADJUST_CFA_OFFSET(-4)
  900. call ArRestoreTrapFrame # Restore state.
  901. CFI_TRAP_FRAME_POPPED # Let the debugger know.
  902. addl $4, %esp # Pop the error code.
  903. CFI_OFFSET(%eip, 0) # The return address is right there.
  904. iret # Return from the exception.
  905. END_FUNCTION(KeInterruptEntry)