PageRenderTime 43ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/kernel/arch/x86_64/core/idt.d

http://github.com/xomboverlord/xomb
D | 325 lines | 208 code | 67 blank | 50 comment | 7 complexity | 6bd1d468a089377a00263b52cce31d18 MD5 | raw file
Possible License(s): WTFPL
  1. /*
  2. * idt.d
  3. *
  4. * The architecture code to implement an interface to the
  5. * IDT (Interrupt Descriptor Table)
  6. *
  7. */
  8. module kernel.arch.x86_64.core.idt;
  9. import kernel.arch.x86_64.core.descriptor;
  10. import user.util; // For BitField!()
  11. import kernel.core.error; // For ErrorVal so errors can be indicated
  12. import kernel.core.kprintf; // For printing the stack dump
  13. // This structure represents the appearance of the stack
  14. // upon receiving an interrupt on this architecture.
  15. struct InterruptStack {
  16. // Registers
  17. ulong r15, r14, r13, r12, r11, r10, r9, r8;
  18. ulong rbp, rdi, rsi, rdx, rcx, rbx, rax;
  19. // Data pushed by the isr
  20. ulong intNumber, errorCode;
  21. // Pushed by the processor
  22. ulong rip, cs, rflags, rsp, ss;
  23. // This function will dump the stack information to
  24. // the screen. Useful for debugging.
  25. void dump() {
  26. kprintfln!("Stack Dump:")();
  27. kprintfln!("r15:{x}|r14:{x}|r13:{x}|r12:{x}|r11:{x}")(r15,r14,r13,r12,r11);
  28. kprintfln!("r10:{x}| r9:{x}| r8:{x}|rbp:{x}|rdi:{x}")(r10,r9,r8,rbp,rdi);
  29. kprintfln!("rsi:{x}|rdx:{x}|rcx:{x}|rbx:{x}|rax:{x}")(rsi,rdx,rcx,rbx,rax);
  30. kprintfln!(" ss:{x}|rsp:{x}| cs:{x}")(ss,rsp,cs);
  31. }
  32. }
  33. struct IDT {
  34. static:
  35. public:
  36. alias void function(InterruptStack*) InterruptHandler;
  37. // -- Functions to initialize the interrupt table -- //
  38. ErrorVal initialize() {
  39. // Initialize the IDT base structure that will be
  40. // loaded via LIDT
  41. idtBase.limit = (InterruptGateDescriptor.sizeof * entries.length) - 1;
  42. idtBase.base = cast(ulong)entries.ptr;
  43. // Initialize the IDT entries to default values
  44. // They will be the equivalent of this function call:
  45. // setInterruptGate(0, &isr0);
  46. // But done across the entire array
  47. mixin(generateIDT!(40));
  48. // Now, set the IDT entries that differ from the norm
  49. setSystemGate(3, &isr3, StackType.Debug);
  50. setInterruptGate(8, &isrIgnore);
  51. return ErrorVal.Success;
  52. }
  53. ErrorVal install() {
  54. asm {
  55. lidt [idtBase];
  56. }
  57. return ErrorVal.Success;
  58. }
  59. // -- Stack Types -- //
  60. enum StackType : uint {
  61. RegisterStack,
  62. StackFault,
  63. DoubleFault,
  64. NMI,
  65. Debug,
  66. MCE
  67. }
  68. // -- Known Interrupt Types -- //
  69. enum InterruptType : uint {
  70. DivisionByZero,
  71. Debug,
  72. NMI,
  73. Breakpoint,
  74. INTO,
  75. OutOfBounds,
  76. InvalidOpcode,
  77. NoCoprocessor,
  78. DoubleFault,
  79. CoprocessorSegmentOverrun,
  80. BadTSS,
  81. SegmentNotPresent,
  82. StackFault,
  83. GeneralProtectionFault,
  84. PageFault,
  85. UnknownInterrupt,
  86. CoprocessorFault,
  87. AlignmentCheck,
  88. MachineCheck,
  89. Syscall = 128,
  90. }
  91. // -- Table Functions -- //
  92. // The following functions define entries within the table, where
  93. // num is the index of the entry to set.
  94. void setInterruptGate(uint num, void* funcPtr, uint ist = StackType.RegisterStack) {
  95. setGate(num, SystemSegmentType.InterruptGate, cast(ulong)funcPtr, 0, ist);
  96. }
  97. void setSystemGate(uint num, void* funcPtr, uint ist = StackType.RegisterStack) {
  98. setGate(num, SystemSegmentType.InterruptGate, cast(ulong)funcPtr, 3, ist);
  99. }
  100. void assignHandler(InterruptHandler func, uint vector) {
  101. handlers[vector] = func;
  102. }
  103. private:
  104. // -- IDT Table -- //
  105. // This, like GDT, is the base data to be loaded via LIDT
  106. align (1) struct IDTBase {
  107. ushort limit;
  108. ulong base;
  109. }
  110. // This is the value we will set via LIDT
  111. IDTBase idtBase;
  112. // This is the descriptor for the table
  113. align(1) struct InterruptGateDescriptor {
  114. ushort targetLo;
  115. ushort segment;
  116. ushort flags;
  117. ushort targetMid;
  118. uint targetHi;
  119. uint reserved = 0;
  120. mixin(Bitfield!(flags, "ist", 3, "zero0", 5, "type", 4, "zero1", 1, "dpl", 2, "p", 1));
  121. }
  122. // Compile time check for structure sanctity
  123. static assert(InterruptGateDescriptor.sizeof == 16);
  124. // The actual table
  125. InterruptGateDescriptor[256] entries;
  126. // -- Common Structures -- //
  127. // -- Table Mutators -- //
  128. // The generic setGate function
  129. void setGate(uint num, SystemSegmentType gateType, ulong funcPtr, uint dplFlags, uint istFlags) {
  130. with(entries[num]) {
  131. targetLo = funcPtr & 0xffff;
  132. segment = 0x10; // It will use CS_KERNEL (entry 2)
  133. ist = istFlags;
  134. p = 1;
  135. dpl = dplFlags;
  136. type = cast(uint)gateType;
  137. targetMid = (funcPtr >> 16) & 0xffff;
  138. targetHi = (funcPtr >> 32);
  139. }
  140. }
  141. // -- Template Foo -- //
  142. // This template generates (for initialize()) the IDT table
  143. // with default values for all interrupts
  144. template generateIDT(uint numberISRs, uint idx = 0) {
  145. static if (numberISRs == idx) {
  146. const char[] generateIDT = ``;
  147. }
  148. else {
  149. const char[] generateIDT = `
  150. setInterruptGate(` ~ idx.stringof ~ `, &isr` ~ idx.stringof[0..$-1] ~ `);
  151. ` ~ generateIDT!(numberISRs,idx+1);
  152. }
  153. }
  154. // This template generates a code stub for an ISR
  155. template generateISR(uint num, bool needDummyError = true) {
  156. const char[] generateISR = `
  157. void isr` ~ num.stringof[0..$-1] ~ `() {
  158. asm {
  159. naked; ` ~
  160. (needDummyError ? `pushq 0;` : ``) ~
  161. `pushq ` ~ num.stringof ~ `;` ~
  162. `jmp isr_common;` ~
  163. `
  164. }
  165. }
  166. `;
  167. }
  168. template generateISRs(uint start, uint end, bool needDummyError = true) {
  169. static if (start > end) {
  170. const char[] generateISRs = ``;
  171. }
  172. else {
  173. const char[] generateISRs = generateISR!(start, needDummyError)
  174. ~ generateISRs!(start+1,end,needDummyError);
  175. }
  176. }
  177. // -- The Interrupt Service Routine Stubs -- //
  178. mixin(generateISR!(0));
  179. mixin(generateISR!(1));
  180. mixin(generateISR!(2));
  181. mixin(generateISR!(3));
  182. mixin(generateISR!(4));
  183. mixin(generateISR!(5));
  184. mixin(generateISR!(6));
  185. mixin(generateISR!(7));
  186. mixin(generateISR!(8, false));
  187. mixin(generateISR!(9));
  188. mixin(generateISR!(10, false));
  189. mixin(generateISR!(11, false));
  190. mixin(generateISR!(12, false));
  191. mixin(generateISR!(13, false));
  192. mixin(generateISR!(14, false));
  193. mixin(generateISRs!(15,39));
  194. void isrIgnore() {
  195. asm {
  196. naked;
  197. nop;
  198. nop;
  199. nop;
  200. iretq;
  201. }
  202. }
  203. InterruptHandler[256] handlers;
  204. void dispatch(InterruptStack* stack) {
  205. if (handlers[stack.intNumber] !is null) {
  206. handlers[stack.intNumber](stack);
  207. return;
  208. }
  209. // kprintfln!("Interrupt: {} @ {x}")(stack.intNumber, stack.rip);
  210. // common interrupt handling
  211. }
  212. extern(C) void isr_common() {
  213. // ISR routine has pushed either one or two values to the stack
  214. // the stack will contain a few things pushed by hardware and then
  215. // these two values
  216. // Before an IRET can be issued, the first two values must be popped
  217. asm {
  218. naked;
  219. // Save context
  220. pushq RAX;
  221. pushq RBX;
  222. pushq RCX;
  223. pushq RDX;
  224. pushq RSI;
  225. pushq RDI;
  226. pushq RBP;
  227. pushq R8;
  228. pushq R9;
  229. pushq R10;
  230. pushq R11;
  231. pushq R12;
  232. pushq R13;
  233. pushq R14;
  234. pushq R15;
  235. // Run dispatcher
  236. mov RDI, RSP;
  237. call dispatch;
  238. // Restore context
  239. popq R15;
  240. popq R14;
  241. popq R13;
  242. popq R12;
  243. popq R11;
  244. popq R10;
  245. popq R9;
  246. popq R8;
  247. popq RBP;
  248. popq RDI;
  249. popq RSI;
  250. popq RDX;
  251. popq RCX;
  252. popq RBX;
  253. popq RAX;
  254. add RSP, 16;
  255. iretq;
  256. }
  257. }
  258. }