prochw.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. /*++
  2. Copyright (c) 2013 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. prochw.c
  9. Abstract:
  10. This module processor architecture specific support for the boot loader.
  11. Author:
  12. Evan Green 1-Aug-2013
  13. Environment:
  14. Boot
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include <minoca/kernel/kernel.h>
  20. #include <minoca/kernel/bootload.h>
  21. #include <minoca/kernel/x86.h>
  22. #include <minoca/kernel/ioport.h>
  23. //
  24. // ---------------------------------------------------------------- Definitions
  25. //
  26. #define BOOT_GDT_ENTRIES 3
  27. #define BOOT_IDT_SIZE (VECTOR_DEBUG_SERVICE + 1)
  28. //
  29. // ------------------------------------------------------ Data Type Definitions
  30. //
  31. //
  32. // ----------------------------------------------- Internal Function Prototypes
  33. //
  34. //
  35. // Assembly routines
  36. //
  37. VOID
  38. EfipBreakExceptionHandlerAsm (
  39. ULONG ReturnEip,
  40. ULONG ReturnCodeSelector,
  41. ULONG ReturnEflags
  42. );
  43. VOID
  44. EfipSingleStepExceptionHandlerAsm (
  45. ULONG ReturnEip,
  46. ULONG ReturnCodeSelector,
  47. ULONG ReturnEflags
  48. );
  49. VOID
  50. EfipDebugServiceHandlerAsm (
  51. ULONG ReturnEip,
  52. ULONG ReturnCodeSelector,
  53. ULONG ReturnEflags
  54. );
  55. VOID
  56. EfipDivideByZeroExceptionHandlerAsm (
  57. ULONG ReturnEip,
  58. ULONG ReturnCodeSelector,
  59. ULONG ReturnEflags
  60. );
  61. VOID
  62. EfipProtectionFaultHandlerAsm (
  63. ULONG ReturnEip,
  64. ULONG ReturnCodeSelector,
  65. ULONG ReturnEflags
  66. );
  67. VOID
  68. EfipPageFaultHandlerAsm (
  69. ULONG ReturnEip,
  70. ULONG ReturnCodeSelector,
  71. ULONG ReturnEflags
  72. );
  73. VOID
  74. EfipLoadBootDataSegments (
  75. VOID
  76. );
  77. //
  78. // C routines
  79. //
  80. VOID
  81. EfipInitializeGdt (
  82. PGDT_ENTRY GdtTable
  83. );
  84. VOID
  85. EfipInitializeInterrupts (
  86. PVOID Idt
  87. );
  88. VOID
  89. EfipCreateGate (
  90. PPROCESSOR_GATE Gate,
  91. PVOID HandlerRoutine,
  92. USHORT Selector,
  93. UCHAR Access
  94. );
  95. VOID
  96. EfipCreateSegmentDescriptor (
  97. PGDT_ENTRY GdtEntry,
  98. PVOID Base,
  99. ULONG Limit,
  100. UCHAR Granularity,
  101. UCHAR Access
  102. );
  103. //
  104. // -------------------------------------------------------------------- Globals
  105. //
  106. //
  107. // Store global processor structures.
  108. //
  109. GDT_ENTRY EfiGdt[BOOT_GDT_ENTRIES];
  110. PROCESSOR_GATE EfiIdt[BOOT_IDT_SIZE];
  111. PVOID EfiInterruptTable[PROCESSOR_VECTOR_COUNT] = {NULL};
  112. //
  113. // ------------------------------------------------------------------ Functions
  114. //
  115. ULONG
  116. MmPageSize (
  117. VOID
  118. )
  119. /*++
  120. Routine Description:
  121. This routine returns the size of a page of memory.
  122. Arguments:
  123. None.
  124. Return Value:
  125. Returns the size of one page of memory (ie the minimum mapping granularity).
  126. --*/
  127. {
  128. return PAGE_SIZE;
  129. }
  130. VOID
  131. EfipInitializeProcessor (
  132. VOID
  133. )
  134. /*++
  135. Routine Description:
  136. This routine initializes processor-specific structures. In the case of x86,
  137. it initializes the GDT and TSS.
  138. Arguments:
  139. None.
  140. Return Value:
  141. None.
  142. --*/
  143. {
  144. //
  145. // Initialize and load the GDT and Tasks.
  146. //
  147. EfipInitializeGdt(EfiGdt);
  148. EfipInitializeInterrupts(EfiIdt);
  149. return;
  150. }
  151. VOID
  152. EfipDivideByZeroHandler (
  153. PTRAP_FRAME TrapFrame
  154. )
  155. /*++
  156. Routine Description:
  157. This routine responds to a divide by zero exception.
  158. Arguments:
  159. TrapFrame - Supplies a pointer to the trap frame.
  160. Return Value:
  161. None.
  162. --*/
  163. {
  164. RtlDebugPrint(" *** Divide by zero ***\n");
  165. KdDebugExceptionHandler(EXCEPTION_DIVIDE_BY_ZERO, NULL, TrapFrame);
  166. return;
  167. }
  168. VOID
  169. EfipPageFaultHandler (
  170. PVOID FaultingAddress,
  171. PTRAP_FRAME TrapFrame
  172. )
  173. /*++
  174. Routine Description:
  175. This routine handles page faults, or rather doesn't handle them.
  176. Arguments:
  177. FaultingAddress - Supplies the address that caused the fault.
  178. TrapFrame - Supplies a pointer to the trap frame of the fault.
  179. Return Value:
  180. None.
  181. --*/
  182. {
  183. RtlDebugPrint(" *** Page Fault: Faulting Address 0x%08x, "
  184. "Instruction 0x%08x",
  185. FaultingAddress,
  186. TrapFrame->Eip);
  187. if ((TrapFrame->ErrorCode & X86_FAULT_ERROR_CODE_PRESENT) != 0) {
  188. RtlDebugPrint(", Protection Violation");
  189. } else {
  190. RtlDebugPrint(", Page Not Present");
  191. }
  192. if ((TrapFrame->ErrorCode & X86_FAULT_ERROR_CODE_WRITE) != 0) {
  193. RtlDebugPrint(", Write ***\n");
  194. } else {
  195. RtlDebugPrint(", Read ***\n");
  196. }
  197. KdDebugExceptionHandler(EXCEPTION_ACCESS_VIOLATION, NULL, TrapFrame);
  198. return;
  199. }
  200. //
  201. // --------------------------------------------------------- Internal Functions
  202. //
  203. VOID
  204. EfipInitializeGdt (
  205. PGDT_ENTRY GdtTable
  206. )
  207. /*++
  208. Routine Description:
  209. This routine initializes and loads the system's Global Descriptor Table
  210. (GDT).
  211. Arguments:
  212. GdtTable - Supplies a pointer to the global descriptor table to use. It is
  213. assumed this table contains enough entries to hold all the segment
  214. descriptors.
  215. Task - Supplies a pointer to the main task.
  216. Return Value:
  217. None.
  218. --*/
  219. {
  220. TABLE_REGISTER Gdt;
  221. //
  222. // The first segment descriptor must be unused. Set it to zero.
  223. //
  224. GdtTable[0].LimitLow = 0;
  225. GdtTable[0].BaseLow = 0;
  226. GdtTable[0].BaseMiddle = 0;
  227. GdtTable[0].Access = 0;
  228. GdtTable[0].Granularity = 0;
  229. GdtTable[0].BaseHigh = 0;
  230. //
  231. // Initialize the kernel code segment. Initialize the entry to cover all
  232. // 4GB of memory, with read/write permissions, and only on ring 0. This is
  233. // not a system segment.
  234. //
  235. EfipCreateSegmentDescriptor(
  236. &(GdtTable[KERNEL_CS / sizeof(GDT_ENTRY)]),
  237. NULL,
  238. MAX_GDT_LIMIT,
  239. GDT_GRANULARITY_KILOBYTE | GDT_GRANULARITY_32BIT,
  240. GDT_TYPE_CODE);
  241. //
  242. // Initialize the kernel data segment. Initialize the entry to cover
  243. // all 4GB of memory, with read/write permissions, and only on ring 0. This
  244. // is not a system segment.
  245. //
  246. EfipCreateSegmentDescriptor(
  247. &(GdtTable[KERNEL_DS / sizeof(GDT_ENTRY)]),
  248. NULL,
  249. MAX_GDT_LIMIT,
  250. GDT_GRANULARITY_KILOBYTE | GDT_GRANULARITY_32BIT,
  251. GDT_TYPE_DATA_WRITE);
  252. //
  253. // Install the new GDT table.
  254. //
  255. Gdt.Limit = sizeof(GDT_ENTRY) * BOOT_GDT_ENTRIES;
  256. Gdt.Base = (ULONG)GdtTable;
  257. ArLoadGdtr(Gdt);
  258. EfipLoadBootDataSegments();
  259. return;
  260. }
  261. VOID
  262. EfipInitializeInterrupts (
  263. PVOID Idt
  264. )
  265. /*++
  266. Routine Description:
  267. This routine initializes and enables interrupts.
  268. Arguments:
  269. Idt - Supplies a pointer to the Interrrupt Descriptor Table for this
  270. processor.
  271. Return Value:
  272. None.
  273. --*/
  274. {
  275. TABLE_REGISTER IdtRegister;
  276. PPROCESSOR_GATE IdtTable;
  277. IdtTable = Idt;
  278. //
  279. // Set up the debug trap handlers.
  280. //
  281. EfipCreateGate(IdtTable + VECTOR_DIVIDE_ERROR,
  282. EfipDivideByZeroExceptionHandlerAsm,
  283. KERNEL_CS,
  284. GATE_ACCESS_USER | GATE_TYPE_TRAP);
  285. EfipCreateGate(IdtTable + VECTOR_BREAKPOINT,
  286. EfipBreakExceptionHandlerAsm,
  287. KERNEL_CS,
  288. GATE_ACCESS_USER | GATE_TYPE_INTERRUPT);
  289. EfipCreateGate(IdtTable + VECTOR_DEBUG,
  290. EfipSingleStepExceptionHandlerAsm,
  291. KERNEL_CS,
  292. GATE_TYPE_INTERRUPT);
  293. EfipCreateGate(IdtTable + VECTOR_DEBUG_SERVICE,
  294. EfipDebugServiceHandlerAsm,
  295. KERNEL_CS,
  296. GATE_TYPE_INTERRUPT);
  297. EfipCreateGate(IdtTable + VECTOR_PROTECTION_FAULT,
  298. EfipProtectionFaultHandlerAsm,
  299. KERNEL_CS,
  300. GATE_TYPE_INTERRUPT);
  301. //
  302. // Set up the page fault handler.
  303. //
  304. EfipCreateGate(IdtTable + VECTOR_PAGE_FAULT,
  305. EfipPageFaultHandlerAsm,
  306. KERNEL_CS,
  307. GATE_TYPE_INTERRUPT);
  308. EfipCreateGate(IdtTable + VECTOR_STACK_EXCEPTION,
  309. EfipPageFaultHandlerAsm,
  310. KERNEL_CS,
  311. GATE_TYPE_INTERRUPT);
  312. //
  313. // Load the IDT register with our interrupt descriptor table.
  314. //
  315. IdtRegister.Limit = (BOOT_IDT_SIZE * sizeof(PROCESSOR_GATE)) - 1;
  316. IdtRegister.Base = (ULONG)IdtTable;
  317. ArLoadIdtr(&IdtRegister);
  318. return;
  319. }
  320. VOID
  321. EfipCreateGate (
  322. PPROCESSOR_GATE Gate,
  323. PVOID HandlerRoutine,
  324. USHORT Selector,
  325. UCHAR Access
  326. )
  327. /*++
  328. Routine Description:
  329. This routine initializes a task, call, trap, or interrupt gate with the
  330. given values.
  331. Arguments:
  332. Gate - Supplies a pointer to the structure where the gate will be returned.
  333. It is assumed this structure is already allocated.
  334. HandlerRoutine - Supplies a pointer to the destination routine of this gate.
  335. Selector - Supplies the code selector this gate should run in.
  336. Access - Supplies the gate access bits, similar to the GDT access bits.
  337. Return Value:
  338. None.
  339. --*/
  340. {
  341. Gate->LowOffset = (USHORT)((ULONG)HandlerRoutine & 0xFFFF);
  342. Gate->HighOffset = (USHORT)((ULONG)HandlerRoutine >> 16);
  343. Gate->Selector = Selector;
  344. //
  345. // Set bit 5-7 of the count to 0. Bits 4-0 are reserved and need to be set
  346. // to 0 as well.
  347. //
  348. Gate->Count = 0;
  349. Gate->Access = GATE_ACCESS_PRESENT | Access;
  350. return;
  351. }
  352. VOID
  353. EfipCreateSegmentDescriptor (
  354. PGDT_ENTRY GdtEntry,
  355. PVOID Base,
  356. ULONG Limit,
  357. UCHAR Granularity,
  358. UCHAR Access
  359. )
  360. /*++
  361. Routine Description:
  362. This routine initializes a GDT entry given the parameters.
  363. Arguments:
  364. GdtEntry - Supplies a pointer to the GDT entry that will be initialized.
  365. Base - Supplies the base address where this segment begins.
  366. Limit - Supplies the size of the segment, either in bytes or kilobytes,
  367. depending on the Granularity parameter.
  368. Granularity - Supplies the granularity of the segment. Valid values are byte
  369. granularity or kilobyte granularity.
  370. Access - Supplies the access permissions on the segment.
  371. Return Value:
  372. None.
  373. --*/
  374. {
  375. //
  376. // If all these magic numbers seem cryptic, see the comment above the
  377. // definition for the GDT_ENTRY structure.
  378. //
  379. GdtEntry->LimitLow = Limit & 0xFFFF;
  380. GdtEntry->BaseLow = (ULONG)Base & 0xFFFF;
  381. GdtEntry->BaseMiddle = ((ULONG)Base >> 16) & 0xFF;
  382. GdtEntry->Access = GATE_ACCESS_PRESENT | Access;
  383. GdtEntry->Granularity = Granularity | ((Limit >> 16) & 0xF);
  384. GdtEntry->BaseHigh = ((ULONG)Base >> 24) & 0xFF;
  385. return;
  386. }