prochw.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. prochw.c
  5. Abstract:
  6. This module processor architecture specific support for the boot loader.
  7. Author:
  8. Evan Green 1-Aug-2013
  9. Environment:
  10. Boot
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <minoca/kernel/kernel.h>
  16. #include <minoca/kernel/bootload.h>
  17. #include <minoca/kernel/x86.h>
  18. #include <minoca/kernel/ioport.h>
  19. //
  20. // ---------------------------------------------------------------- Definitions
  21. //
  22. #define BOOT_GDT_ENTRIES 3
  23. #define BOOT_IDT_SIZE (VECTOR_DEBUG_SERVICE + 1)
  24. #define PIC_BASE_VECTOR 0x30
  25. //
  26. // ------------------------------------------------------ Data Type Definitions
  27. //
  28. //
  29. // ----------------------------------------------- Internal Function Prototypes
  30. //
  31. //
  32. // Assembly routines
  33. //
  34. VOID
  35. BoBreakExceptionHandlerAsm (
  36. ULONG ReturnEip,
  37. ULONG ReturnCodeSelector,
  38. ULONG ReturnEflags
  39. );
  40. VOID
  41. BoSingleStepExceptionHandlerAsm (
  42. ULONG ReturnEip,
  43. ULONG ReturnCodeSelector,
  44. ULONG ReturnEflags
  45. );
  46. VOID
  47. BoDebugServiceHandlerAsm (
  48. ULONG ReturnEip,
  49. ULONG ReturnCodeSelector,
  50. ULONG ReturnEflags
  51. );
  52. VOID
  53. BoDivideByZeroExceptionHandlerAsm (
  54. ULONG ReturnEip,
  55. ULONG ReturnCodeSelector,
  56. ULONG ReturnEflags
  57. );
  58. VOID
  59. BoProtectionFaultHandlerAsm (
  60. ULONG ReturnEip,
  61. ULONG ReturnCodeSelector,
  62. ULONG ReturnEflags
  63. );
  64. VOID
  65. BoPageFaultHandlerAsm (
  66. ULONG ReturnEip,
  67. ULONG ReturnCodeSelector,
  68. ULONG ReturnEflags
  69. );
  70. VOID
  71. BoLoadBootDataSegments (
  72. VOID
  73. );
  74. //
  75. // C routines
  76. //
  77. VOID
  78. BopInitializeGdt (
  79. PGDT_ENTRY GdtTable
  80. );
  81. VOID
  82. BopInitializeInterrupts (
  83. PVOID Idt
  84. );
  85. VOID
  86. BopCreateGate (
  87. PPROCESSOR_GATE Gate,
  88. PVOID HandlerRoutine,
  89. USHORT Selector,
  90. UCHAR Type,
  91. UCHAR Privilege
  92. );
  93. VOID
  94. BopCreateSegmentDescriptor (
  95. PGDT_ENTRY GdtEntry,
  96. PVOID Base,
  97. ULONG Limit,
  98. GDT_GRANULARITY Granularity,
  99. GDT_SEGMENT_TYPE Access,
  100. UCHAR PrivilegeLevel,
  101. BOOL System
  102. );
  103. //
  104. // -------------------------------------------------------------------- Globals
  105. //
  106. //
  107. // Store global processor structures.
  108. //
  109. GDT_ENTRY BoGdt[GDT_ENTRIES];
  110. PROCESSOR_GATE BoIdt[BOOT_IDT_SIZE];
  111. PVOID BoInterruptTable[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. ULONG
  131. MmPageShift (
  132. VOID
  133. )
  134. /*++
  135. Routine Description:
  136. This routine returns the amount to shift by to truncate an address to a
  137. page number.
  138. Arguments:
  139. None.
  140. Return Value:
  141. Returns the amount to shift to reach page granularity.
  142. --*/
  143. {
  144. return PAGE_SHIFT;
  145. }
  146. VOID
  147. BoInitializeProcessor (
  148. VOID
  149. )
  150. /*++
  151. Routine Description:
  152. This routine initializes processor-specific structures. In the case of x86,
  153. it initializes the GDT and TSS.
  154. Arguments:
  155. None.
  156. Return Value:
  157. None.
  158. --*/
  159. {
  160. //
  161. // Initialize and load the GDT and Tasks.
  162. //
  163. BopInitializeGdt(BoGdt);
  164. BopInitializeInterrupts(BoIdt);
  165. return;
  166. }
  167. VOID
  168. BoDivideByZeroHandler (
  169. PTRAP_FRAME TrapFrame
  170. )
  171. /*++
  172. Routine Description:
  173. This routine responds to a divide by zero exception.
  174. Arguments:
  175. TrapFrame - Supplies a pointer to the trap frame.
  176. Return Value:
  177. None.
  178. --*/
  179. {
  180. RtlDebugPrint(" *** Divide by zero ***\n");
  181. KdDebugExceptionHandler(EXCEPTION_DIVIDE_BY_ZERO, NULL, TrapFrame);
  182. return;
  183. }
  184. VOID
  185. BoPageFaultHandler (
  186. PVOID FaultingAddress,
  187. PTRAP_FRAME TrapFrame
  188. )
  189. /*++
  190. Routine Description:
  191. This routine handles page faults, or rather doesn't handle them.
  192. Arguments:
  193. FaultingAddress - Supplies the address that caused the fault.
  194. TrapFrame - Supplies a pointer to the trap frame of the fault.
  195. Return Value:
  196. None.
  197. --*/
  198. {
  199. RtlDebugPrint(" *** Page Fault: Faulting Address %08x, Instruction %08x",
  200. FaultingAddress,
  201. TrapFrame->Eip);
  202. if ((TrapFrame->ErrorCode & X86_FAULT_FLAG_PROTECTION_VIOLATION) != 0) {
  203. RtlDebugPrint(", Protection Violation");
  204. } else {
  205. RtlDebugPrint(", Page Not Present");
  206. }
  207. if ((TrapFrame->ErrorCode & X86_FAULT_ERROR_CODE_WRITE) != 0) {
  208. RtlDebugPrint(", Write ***\n");
  209. } else {
  210. RtlDebugPrint(", Read ***\n");
  211. }
  212. KdDebugExceptionHandler(EXCEPTION_ACCESS_VIOLATION, NULL, TrapFrame);
  213. return;
  214. }
  215. //
  216. // --------------------------------------------------------- Internal Functions
  217. //
  218. VOID
  219. BopInitializeGdt (
  220. PGDT_ENTRY GdtTable
  221. )
  222. /*++
  223. Routine Description:
  224. This routine initializes and loads the system's Global Descriptor Table
  225. (GDT).
  226. Arguments:
  227. GdtTable - Supplies a pointer to the global descriptor table to use. It is
  228. assumed this table contains enough entries to hold all the segment
  229. descriptors.
  230. Task - Supplies a pointer to the main task.
  231. Return Value:
  232. None.
  233. --*/
  234. {
  235. TABLE_REGISTER Gdt;
  236. //
  237. // The first segment descriptor must be unused. Set it to zero.
  238. //
  239. GdtTable[0].LimitLow = 0;
  240. GdtTable[0].BaseLow = 0;
  241. GdtTable[0].BaseMiddle = 0;
  242. GdtTable[0].Access = 0;
  243. GdtTable[0].Granularity = 0;
  244. GdtTable[0].BaseHigh = 0;
  245. //
  246. // Initialize the kernel code segment. Initialize the entry to cover all
  247. // 4GB of memory, with read/write permissions, and only on ring 0. This is
  248. // not a system segment.
  249. //
  250. BopCreateSegmentDescriptor(&(GdtTable[KERNEL_CS / sizeof(GDT_ENTRY)]),
  251. NULL,
  252. MAX_GDT_LIMIT,
  253. GdtKilobyteGranularity,
  254. GdtCodeExecuteOnly,
  255. 0,
  256. FALSE);
  257. //
  258. // Initialize the kernel data segment. Initialize the entry to cover
  259. // all 4GB of memory, with read/write permissions, and only on ring 0. This
  260. // is not a system segment.
  261. //
  262. BopCreateSegmentDescriptor(&(GdtTable[KERNEL_DS / sizeof(GDT_ENTRY)]),
  263. NULL,
  264. MAX_GDT_LIMIT,
  265. GdtKilobyteGranularity,
  266. GdtDataReadWrite,
  267. 0,
  268. FALSE);
  269. //
  270. // Install the new GDT table.
  271. //
  272. Gdt.Limit = sizeof(GDT_ENTRY) * BOOT_GDT_ENTRIES;
  273. Gdt.Base = (ULONG)GdtTable;
  274. ArLoadGdtr(Gdt);
  275. BoLoadBootDataSegments();
  276. return;
  277. }
  278. VOID
  279. BopInitializeInterrupts (
  280. PVOID Idt
  281. )
  282. /*++
  283. Routine Description:
  284. This routine initializes and enables interrupts.
  285. Arguments:
  286. Idt - Supplies a pointer to the Interrrupt Descriptor Table for this
  287. processor.
  288. Return Value:
  289. None.
  290. --*/
  291. {
  292. TABLE_REGISTER IdtRegister;
  293. PPROCESSOR_GATE IdtTable;
  294. IdtTable = Idt;
  295. //
  296. // Set up the debug trap handlers.
  297. //
  298. BopCreateGate(IdtTable + VECTOR_DIVIDE_ERROR,
  299. BoDivideByZeroExceptionHandlerAsm,
  300. KERNEL_CS,
  301. TRAP_GATE_TYPE,
  302. 3);
  303. BopCreateGate(IdtTable + VECTOR_BREAKPOINT,
  304. BoBreakExceptionHandlerAsm,
  305. KERNEL_CS,
  306. INTERRUPT_GATE_TYPE,
  307. 3);
  308. BopCreateGate(IdtTable + VECTOR_DEBUG,
  309. BoSingleStepExceptionHandlerAsm,
  310. KERNEL_CS,
  311. INTERRUPT_GATE_TYPE,
  312. 0);
  313. BopCreateGate(IdtTable + VECTOR_DEBUG_SERVICE,
  314. BoDebugServiceHandlerAsm,
  315. KERNEL_CS,
  316. INTERRUPT_GATE_TYPE,
  317. 0);
  318. BopCreateGate(IdtTable + VECTOR_PROTECTION_FAULT,
  319. BoProtectionFaultHandlerAsm,
  320. KERNEL_CS,
  321. INTERRUPT_GATE_TYPE,
  322. 0);
  323. //
  324. // Set up the page fault handler.
  325. //
  326. BopCreateGate(IdtTable + VECTOR_PAGE_FAULT,
  327. BoPageFaultHandlerAsm,
  328. KERNEL_CS,
  329. INTERRUPT_GATE_TYPE,
  330. 0);
  331. BopCreateGate(IdtTable + VECTOR_STACK_EXCEPTION,
  332. BoPageFaultHandlerAsm,
  333. KERNEL_CS,
  334. INTERRUPT_GATE_TYPE,
  335. 0);
  336. //
  337. // Load the IDT register with our interrupt descriptor table.
  338. //
  339. IdtRegister.Limit = (BOOT_IDT_SIZE * 8) - 1;
  340. IdtRegister.Base = (ULONG)IdtTable;
  341. ArLoadIdtr(&IdtRegister);
  342. return;
  343. }
  344. VOID
  345. BopCreateGate (
  346. PPROCESSOR_GATE Gate,
  347. PVOID HandlerRoutine,
  348. USHORT Selector,
  349. UCHAR Type,
  350. UCHAR Privilege
  351. )
  352. /*++
  353. Routine Description:
  354. This routine initializes a task, call, trap, or interrupt gate with the
  355. given values.
  356. Arguments:
  357. Gate - Supplies a pointer to the structure where the gate will be returned.
  358. It is assumed this structure is already allocated.
  359. HandlerRoutine - Supplies a pointer to the destination routine of this gate.
  360. Selector - Supplies the code selector this gate should run in.
  361. Type - Supplies the type of the gate. Set this to CALL_GATE_TYPE,
  362. INTERRUPT_GATE_TYPE, TASK_GATE_TYPE, or TRAP_GATE_TYPE.
  363. Privilege - Supplies the privilege level this gate should run in. 0 is the
  364. most privileged level, and 3 is the least privileged.
  365. Return Value:
  366. None.
  367. --*/
  368. {
  369. Gate->LowOffset = (USHORT)((ULONG)HandlerRoutine & 0xFFFF);
  370. Gate->HighOffset = (USHORT)((ULONG)HandlerRoutine >> 16);
  371. Gate->Selector = Selector;
  372. //
  373. // Set bit 5-7 of the count to 0. Bits 4-0 are reserved and need to be set
  374. // to 0 as well.
  375. //
  376. Gate->Count = 0;
  377. //
  378. // Access is programmed as follows:
  379. // Bit 7: Present. Set to 1 to indicate that this gate is present.
  380. // Bits 5-6: Privilege level.
  381. // Bit 4: Set to 0 to indicate it's a system gate.
  382. // Bits 3-0: Type.
  383. //
  384. Gate->Access = Type | (Privilege << 5) | (1 << 7);
  385. return;
  386. }
  387. VOID
  388. BopCreateSegmentDescriptor (
  389. PGDT_ENTRY GdtEntry,
  390. PVOID Base,
  391. ULONG Limit,
  392. GDT_GRANULARITY Granularity,
  393. GDT_SEGMENT_TYPE Access,
  394. UCHAR PrivilegeLevel,
  395. BOOL System
  396. )
  397. /*++
  398. Routine Description:
  399. This routine initializes a GDT entry given the parameters.
  400. Arguments:
  401. GdtEntry - Supplies a pointer to the GDT entry that will be initialized.
  402. Base - Supplies the base address where this segment begins.
  403. Limit - Supplies the size of the segment, either in bytes or kilobytes,
  404. depending on the Granularity parameter.
  405. Granularity - Supplies the granularity of the segment. Valid values are byte
  406. granularity or kilobyte granularity.
  407. Access - Supplies the access permissions on the segment.
  408. PrivilegeLevel - Supplies the privilege level that this segment requires.
  409. Valid values are 0 (most privileged, kernel) to 3 (user mode, least
  410. privileged).
  411. System - Supplies a flag indicating whether this is a system segment (TRUE)
  412. or a code/data segment.
  413. Return Value:
  414. None.
  415. --*/
  416. {
  417. //
  418. // If all these magic numbers seem cryptic, see the comment above the
  419. // definition for the GDT_ENTRY structure.
  420. //
  421. GdtEntry->LimitLow = Limit & 0xFFFF;
  422. GdtEntry->BaseLow = (ULONG)Base & 0xFFFF;
  423. GdtEntry->BaseMiddle = ((ULONG)Base >> 16) & 0xFF;
  424. GdtEntry->Access = DEFAULT_GDT_ACCESS |
  425. ((PrivilegeLevel & 0x3) << 5) |
  426. (Access & 0xF);
  427. if (System != FALSE) {
  428. GdtEntry->Access |= GDT_SYSTEM_SEGMENT;
  429. } else {
  430. GdtEntry->Access |= GDT_CODE_DATA_SEGMENT;
  431. }
  432. GdtEntry->Granularity = DEFAULT_GDT_GRANULARITY |
  433. Granularity |
  434. ((Limit >> 16) & 0xF);
  435. GdtEntry->BaseHigh = ((ULONG)Base >> 24) & 0xFF;
  436. return;
  437. }