prochw.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  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. //
  19. // ---------------------------------------------------------------- Definitions
  20. //
  21. #define BOOT_GDT_ENTRIES 3
  22. #define BOOT_IDT_SIZE (VECTOR_PROTECTION_FAULT + 1)
  23. //
  24. // ------------------------------------------------------ Data Type Definitions
  25. //
  26. //
  27. // ----------------------------------------------- Internal Function Prototypes
  28. //
  29. //
  30. // Assembly routines
  31. //
  32. VOID
  33. BoBreakExceptionHandlerAsm (
  34. ULONG ReturnEip,
  35. ULONG ReturnCodeSelector,
  36. ULONG ReturnEflags
  37. );
  38. VOID
  39. BoSingleStepExceptionHandlerAsm (
  40. ULONG ReturnEip,
  41. ULONG ReturnCodeSelector,
  42. ULONG ReturnEflags
  43. );
  44. VOID
  45. BoDebugServiceHandlerAsm (
  46. ULONG ReturnEip,
  47. ULONG ReturnCodeSelector,
  48. ULONG ReturnEflags
  49. );
  50. VOID
  51. BoProtectionFaultHandlerAsm (
  52. ULONG ReturnEip,
  53. ULONG ReturnCodeSelector,
  54. ULONG ReturnEflags
  55. );
  56. VOID
  57. BoLoadBootDataSegments (
  58. VOID
  59. );
  60. //
  61. // C routines
  62. //
  63. VOID
  64. BopInitializeGdt (
  65. PGDT_ENTRY GdtTable
  66. );
  67. VOID
  68. BopInitializeInterrupts (
  69. PVOID Idt
  70. );
  71. VOID
  72. BopCreateGate (
  73. PPROCESSOR_GATE Gate,
  74. PVOID HandlerRoutine,
  75. USHORT Selector,
  76. UCHAR Type,
  77. UCHAR Privilege
  78. );
  79. VOID
  80. BopCreateSegmentDescriptor (
  81. PGDT_ENTRY GdtEntry,
  82. PVOID Base,
  83. ULONG Limit,
  84. GDT_GRANULARITY Granularity,
  85. GDT_SEGMENT_TYPE Access,
  86. UCHAR PrivilegeLevel,
  87. BOOL System
  88. );
  89. //
  90. // -------------------------------------------------------------------- Globals
  91. //
  92. //
  93. // Store global processor structures.
  94. //
  95. GDT_ENTRY BoGdt[BOOT_GDT_ENTRIES];
  96. PROCESSOR_GATE BoIdt[BOOT_IDT_SIZE];
  97. //
  98. // ------------------------------------------------------------------ Functions
  99. //
  100. VOID
  101. BoInitializeProcessor (
  102. VOID
  103. )
  104. /*++
  105. Routine Description:
  106. This routine initializes processor-specific structures. In the case of x86,
  107. it initializes the GDT and TSS.
  108. Arguments:
  109. None.
  110. Return Value:
  111. None.
  112. --*/
  113. {
  114. //
  115. // Initialize and load the GDT and Tasks.
  116. //
  117. BopInitializeGdt(BoGdt);
  118. BopInitializeInterrupts(BoIdt);
  119. return;
  120. }
  121. //
  122. // --------------------------------------------------------- Internal Functions
  123. //
  124. VOID
  125. BopInitializeGdt (
  126. PGDT_ENTRY GdtTable
  127. )
  128. /*++
  129. Routine Description:
  130. This routine initializes and loads the system's Global Descriptor Table
  131. (GDT).
  132. Arguments:
  133. GdtTable - Supplies a pointer to the global descriptor table to use. It is
  134. assumed this table contains enough entries to hold all the segment
  135. descriptors.
  136. Return Value:
  137. None.
  138. --*/
  139. {
  140. TABLE_REGISTER Gdt;
  141. //
  142. // The first segment descriptor must be unused. Set it to zero.
  143. //
  144. GdtTable[0].LimitLow = 0;
  145. GdtTable[0].BaseLow = 0;
  146. GdtTable[0].BaseMiddle = 0;
  147. GdtTable[0].Access = 0;
  148. GdtTable[0].Granularity = 0;
  149. GdtTable[0].BaseHigh = 0;
  150. //
  151. // Initialize the kernel code segment. Initialize the entry to cover all
  152. // 4GB of memory, with read/write permissions, and only on ring 0. This is
  153. // not a system segment.
  154. //
  155. BopCreateSegmentDescriptor(&(GdtTable[KERNEL_CS / sizeof(GDT_ENTRY)]),
  156. NULL,
  157. MAX_GDT_LIMIT,
  158. GdtKilobyteGranularity,
  159. GdtCodeExecuteOnly,
  160. 0,
  161. FALSE);
  162. //
  163. // Initialize the kernel data segment. Initialize the entry to cover
  164. // all 4GB of memory, with read/write permissions, and only on ring 0. This
  165. // is not a system segment.
  166. //
  167. BopCreateSegmentDescriptor(&(GdtTable[KERNEL_DS / sizeof(GDT_ENTRY)]),
  168. NULL,
  169. MAX_GDT_LIMIT,
  170. GdtKilobyteGranularity,
  171. GdtDataReadWrite,
  172. 0,
  173. FALSE);
  174. //
  175. // Install the new GDT table.
  176. //
  177. Gdt.Limit = sizeof(GDT_ENTRY) * BOOT_GDT_ENTRIES;
  178. Gdt.Base = (ULONG)GdtTable;
  179. ArLoadGdtr(Gdt);
  180. BoLoadBootDataSegments();
  181. return;
  182. }
  183. VOID
  184. BopInitializeInterrupts (
  185. PVOID Idt
  186. )
  187. /*++
  188. Routine Description:
  189. This routine initializes and enables interrupts.
  190. Arguments:
  191. Idt - Supplies a pointer to the Interrrupt Descriptor Table for this
  192. processor.
  193. Return Value:
  194. None.
  195. --*/
  196. {
  197. TABLE_REGISTER IdtRegister;
  198. PPROCESSOR_GATE IdtTable;
  199. IdtTable = Idt;
  200. //
  201. // Set up the debug trap handlers.
  202. //
  203. BopCreateGate(IdtTable + VECTOR_BREAKPOINT,
  204. BoBreakExceptionHandlerAsm,
  205. KERNEL_CS,
  206. INTERRUPT_GATE_TYPE,
  207. 3);
  208. BopCreateGate(IdtTable + VECTOR_DEBUG,
  209. BoSingleStepExceptionHandlerAsm,
  210. KERNEL_CS,
  211. INTERRUPT_GATE_TYPE,
  212. 0);
  213. BopCreateGate(IdtTable + VECTOR_PROTECTION_FAULT,
  214. BoProtectionFaultHandlerAsm,
  215. KERNEL_CS,
  216. INTERRUPT_GATE_TYPE,
  217. 0);
  218. //
  219. // Load the IDT register with our interrupt descriptor table.
  220. //
  221. IdtRegister.Limit = (BOOT_IDT_SIZE * 8) - 1;
  222. IdtRegister.Base = (ULONG)IdtTable;
  223. ArLoadIdtr(&IdtRegister);
  224. return;
  225. }
  226. VOID
  227. BopCreateGate (
  228. PPROCESSOR_GATE Gate,
  229. PVOID HandlerRoutine,
  230. USHORT Selector,
  231. UCHAR Type,
  232. UCHAR Privilege
  233. )
  234. /*++
  235. Routine Description:
  236. This routine initializes a task, call, trap, or interrupt gate with the
  237. given values.
  238. Arguments:
  239. Gate - Supplies a pointer to the structure where the gate will be returned.
  240. It is assumed this structure is already allocated.
  241. HandlerRoutine - Supplies a pointer to the destination routine of this gate.
  242. Selector - Supplies the code selector this gate should run in.
  243. Type - Supplies the type of the gate. Set this to CALL_GATE_TYPE,
  244. INTERRUPT_GATE_TYPE, TASK_GATE_TYPE, or TRAP_GATE_TYPE.
  245. Privilege - Supplies the privilege level this gate should run in. 0 is the
  246. most privileged level, and 3 is the least privileged.
  247. Return Value:
  248. None.
  249. --*/
  250. {
  251. Gate->LowOffset = (USHORT)((ULONG)HandlerRoutine & 0xFFFF);
  252. Gate->HighOffset = (USHORT)((ULONG)HandlerRoutine >> 16);
  253. Gate->Selector = Selector;
  254. //
  255. // Set bit 5-7 of the count to 0. Bits 4-0 are reserved and need to be set
  256. // to 0 as well.
  257. //
  258. Gate->Count = 0;
  259. //
  260. // Access is programmed as follows:
  261. // Bit 7: Present. Set to 1 to indicate that this gate is present.
  262. // Bits 5-6: Privilege level.
  263. // Bit 4: Set to 0 to indicate it's a system gate.
  264. // Bits 3-0: Type.
  265. //
  266. Gate->Access = Type | (Privilege << 5) | (1 << 7);
  267. return;
  268. }
  269. VOID
  270. BopCreateSegmentDescriptor (
  271. PGDT_ENTRY GdtEntry,
  272. PVOID Base,
  273. ULONG Limit,
  274. GDT_GRANULARITY Granularity,
  275. GDT_SEGMENT_TYPE Access,
  276. UCHAR PrivilegeLevel,
  277. BOOL System
  278. )
  279. /*++
  280. Routine Description:
  281. This routine initializes a GDT entry given the parameters.
  282. Arguments:
  283. GdtEntry - Supplies a pointer to the GDT entry that will be initialized.
  284. Base - Supplies the base address where this segment begins.
  285. Limit - Supplies the size of the segment, either in bytes or kilobytes,
  286. depending on the Granularity parameter.
  287. Granularity - Supplies the granularity of the segment. Valid values are byte
  288. granularity or kilobyte granularity.
  289. Access - Supplies the access permissions on the segment.
  290. PrivilegeLevel - Supplies the privilege level that this segment requires.
  291. Valid values are 0 (most privileged, kernel) to 3 (user mode, least
  292. privileged).
  293. System - Supplies a flag indicating whether this is a system segment (TRUE)
  294. or a code/data segment.
  295. Return Value:
  296. None.
  297. --*/
  298. {
  299. //
  300. // If all these magic numbers seem cryptic, see the comment above the
  301. // definition for the GDT_ENTRY structure.
  302. //
  303. GdtEntry->LimitLow = Limit & 0xFFFF;
  304. GdtEntry->BaseLow = (ULONG)Base & 0xFFFF;
  305. GdtEntry->BaseMiddle = ((ULONG)Base >> 16) & 0xFF;
  306. GdtEntry->Access = DEFAULT_GDT_ACCESS |
  307. ((PrivilegeLevel & 0x3) << 5) |
  308. (Access & 0xF);
  309. if (System != FALSE) {
  310. GdtEntry->Access |= GDT_SYSTEM_SEGMENT;
  311. } else {
  312. GdtEntry->Access |= GDT_CODE_DATA_SEGMENT;
  313. }
  314. GdtEntry->Granularity = DEFAULT_GDT_GRANULARITY |
  315. Granularity |
  316. ((Limit >> 16) & 0xF);
  317. GdtEntry->BaseHigh = ((ULONG)Base >> 24) & 0xFF;
  318. return;
  319. }