prochw.c 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569
  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. prochw.c
  9. Abstract:
  10. This module implements support functionality for hardware that is specific
  11. to the x86 architecture.
  12. Author:
  13. Evan Green 3-Jul-2012
  14. Environment:
  15. Kernel
  16. --*/
  17. //
  18. // ------------------------------------------------------------------- Includes
  19. //
  20. #include <minoca/kernel/kernel.h>
  21. #include <minoca/kernel/x86.h>
  22. #include <minoca/kernel/ioport.h>
  23. #include <minoca/kernel/kdebug.h>
  24. //
  25. // ---------------------------------------------------------------- Definitions
  26. //
  27. //
  28. // Define the number and size of alternate stacks. The TSS structures share
  29. // these regions of memory. This stack size should be a multiple of a page
  30. // size, since TSS segments should not cross page boundaries.
  31. //
  32. #define ALTERNATE_STACK_COUNT 2
  33. #define ALTERNATE_STACK_SIZE 4096
  34. //
  35. // ----------------------------------------------- Internal Function Prototypes
  36. //
  37. //
  38. // Declare any still-undefined built in interrupt handlers.
  39. //
  40. VOID
  41. KdDebugServiceHandlerAsm (
  42. ULONG ReturnEip,
  43. ULONG ReturnCodeSelector,
  44. ULONG ReturnEflags
  45. );
  46. VOID
  47. ArSingleStepExceptionHandlerAsm (
  48. ULONG ReturnEip,
  49. ULONG ReturnCodeSelector,
  50. ULONG ReturnEflags
  51. );
  52. VOID
  53. ArBreakExceptionHandlerAsm (
  54. ULONG ReturnEip,
  55. ULONG ReturnCodeSelector,
  56. ULONG ReturnEflags
  57. );
  58. VOID
  59. ArDivideByZeroExceptionHandlerAsm (
  60. ULONG ReturnEip,
  61. ULONG ReturnCodeSelector,
  62. ULONG ReturnEflags
  63. );
  64. VOID
  65. ArFpuAccessExceptionHandlerAsm (
  66. ULONG ReturnEip,
  67. ULONG ReturnCodeSelector,
  68. ULONG ReturnEflags
  69. );
  70. VOID
  71. HlSpuriousInterruptHandlerAsm (
  72. ULONG ReturnEip,
  73. ULONG ReturnCodeSelector,
  74. ULONG ReturnEflags
  75. );
  76. VOID
  77. ArpCreateGate (
  78. PPROCESSOR_GATE Gate,
  79. PVOID HandlerRoutine,
  80. USHORT Selector,
  81. UCHAR Access
  82. );
  83. VOID
  84. ArpInitializeTss (
  85. PTSS Task
  86. );
  87. VOID
  88. ArpInitializeGdt (
  89. PGDT_ENTRY GdtTable,
  90. PPROCESSOR_BLOCK ProcessorBlock,
  91. PTSS KernelTss,
  92. PTSS DoubleFaultTss,
  93. PTSS NmiTss
  94. );
  95. VOID
  96. ArpInitializeInterrupts (
  97. BOOL PhysicalMode,
  98. BOOL BootProcessor,
  99. PVOID Idt
  100. );
  101. VOID
  102. ArpSetProcessorFeatures (
  103. PPROCESSOR_BLOCK ProcessorBlock
  104. );
  105. //
  106. // ------------------------------------------------------ Data Type Definitions
  107. //
  108. //
  109. // -------------------------------------------------------------------- Globals
  110. //
  111. //
  112. // Store pointers to functions used to save and restore floating point state.
  113. //
  114. PAR_SAVE_RESTORE_FPU_CONTEXT ArSaveFpuState;
  115. PAR_SAVE_RESTORE_FPU_CONTEXT ArRestoreFpuState;
  116. //
  117. // Store globals for the per-processor data structures used by P0.
  118. //
  119. //
  120. // The P0 TSS will start out as the main kernel TSS, but will get swapped with
  121. // the double fault TSS so sysenter can reach its stack quickly.
  122. //
  123. TSS ArP0Tss;
  124. GDT_ENTRY ArP0Gdt[X86_GDT_ENTRIES];
  125. PROCESSOR_GATE ArP0Idt[IDT_SIZE];
  126. PROCESSOR_BLOCK ArP0ProcessorBlock;
  127. PVOID ArP0InterruptTable[MAXIMUM_VECTOR - MINIMUM_VECTOR + 1] = {NULL};
  128. //
  129. // Remember whether the processor was initialized with translation enabled or
  130. // not.
  131. //
  132. BOOL ArTranslationEnabled = FALSE;
  133. //
  134. // Pointers to the interrupt dispatch code, which is repeated from the minimum
  135. // to maximum device IDT entries.
  136. //
  137. extern UCHAR HlVectorStart;
  138. extern UCHAR HlVectorEnd;
  139. //
  140. // ------------------------------------------------------------------ Functions
  141. //
  142. VOID
  143. ArInitializeProcessor (
  144. BOOL PhysicalMode,
  145. PVOID ProcessorStructures
  146. )
  147. /*++
  148. Routine Description:
  149. This routine initializes processor-specific structures. In the case of x86,
  150. it initializes the GDT and TSS.
  151. Arguments:
  152. PhysicalMode - Supplies a boolean indicating whether or not the processor
  153. is operating in physical mode.
  154. ProcessorStructures - Supplies a pointer to the memory to use for basic
  155. processor structures, as returned by the allocate processor structures
  156. routine. For the boot processor, supply NULL here to use this routine's
  157. internal resources.
  158. Return Value:
  159. None.
  160. --*/
  161. {
  162. UINTN Address;
  163. BOOL BootProcessor;
  164. ULONG Cr0;
  165. PTSS DoubleFaultTss;
  166. PGDT_ENTRY Gdt;
  167. PPROCESSOR_GATE Idt;
  168. PVOID InterruptTable;
  169. PTSS NmiTss;
  170. UINTN PageSize;
  171. PPROCESSOR_BLOCK ProcessorBlock;
  172. PTSS Tss;
  173. BootProcessor = TRUE;
  174. DoubleFaultTss = NULL;
  175. NmiTss = NULL;
  176. if (PhysicalMode == FALSE) {
  177. ArTranslationEnabled = TRUE;
  178. }
  179. //
  180. // Physical mode implies P0.
  181. //
  182. if (PhysicalMode != FALSE) {
  183. Gdt = ArP0Gdt;
  184. Idt = ArP0Idt;
  185. InterruptTable = ArP0InterruptTable;
  186. ProcessorBlock = &ArP0ProcessorBlock;
  187. Tss = &ArP0Tss;
  188. } else {
  189. //
  190. // Use the globals if this is the boot processor because the memory
  191. // subsystem is not yet online.
  192. //
  193. if (ProcessorStructures == NULL) {
  194. Gdt = ArP0Gdt;
  195. Idt = ArP0Idt;
  196. InterruptTable = ArP0InterruptTable;
  197. ProcessorBlock = &ArP0ProcessorBlock;
  198. Tss = &ArP0Tss;
  199. } else {
  200. BootProcessor = FALSE;
  201. PageSize = MmPageSize();
  202. Address = ALIGN_RANGE_UP((UINTN)ProcessorStructures, PageSize);
  203. //
  204. // The main TSS is at the end of the double fault stack so that
  205. // sysenter can get to its thread stack in a single SS: dereference.
  206. // The double fault TSS is after the processor block.
  207. //
  208. Tss = (PVOID)(Address + ALTERNATE_STACK_SIZE - sizeof(TSS));
  209. Address += ALTERNATE_STACK_SIZE;
  210. NmiTss = (PVOID)(Address + ALTERNATE_STACK_SIZE - sizeof(TSS));
  211. Gdt = (PGDT_ENTRY)(Address + ALTERNATE_STACK_SIZE);
  212. ASSERT(ALIGN_RANGE_DOWN((UINTN)Gdt, 8) == (UINTN)Gdt);
  213. //
  214. // Use a global IDT space.
  215. //
  216. Idt = ArP0Idt;
  217. ProcessorBlock = (PPROCESSOR_BLOCK)((PUCHAR)Gdt + sizeof(ArP0Gdt));
  218. DoubleFaultTss = (PTSS)(ProcessorBlock + 1);
  219. Address = ALIGN_RANGE_UP((UINTN)(Tss + 1), 8);
  220. InterruptTable = ArP0InterruptTable;
  221. }
  222. }
  223. //
  224. // Initialize the pointer to the processor block.
  225. //
  226. ProcessorBlock->Self = ProcessorBlock;
  227. ProcessorBlock->Idt = Idt;
  228. ProcessorBlock->InterruptTable = InterruptTable;
  229. ProcessorBlock->Tss = Tss;
  230. ProcessorBlock->Gdt = Gdt;
  231. //
  232. // Initialize and load the GDT and Tasks.
  233. //
  234. ArpInitializeTss(Tss);
  235. Tss->Cr3 = ArGetCurrentPageDirectory();
  236. if (DoubleFaultTss != NULL) {
  237. ArpInitializeTss(DoubleFaultTss);
  238. DoubleFaultTss->Esp0 = (UINTN)Tss;
  239. DoubleFaultTss->Esp = DoubleFaultTss->Esp0;
  240. DoubleFaultTss->Eip = (UINTN)ArDoubleFaultHandlerAsm;
  241. DoubleFaultTss->Cr3 = Tss->Cr3;
  242. }
  243. if (NmiTss != NULL) {
  244. ArpInitializeTss(NmiTss);
  245. NmiTss->Esp0 = (UINTN)NmiTss;
  246. NmiTss->Esp = NmiTss->Esp0;
  247. NmiTss->Eip = (UINTN)KdNmiHandlerAsm;
  248. NmiTss->Cr3 = Tss->Cr3;
  249. }
  250. ArpInitializeGdt(Gdt, ProcessorBlock, Tss, DoubleFaultTss, NmiTss);
  251. ArLoadTr(KERNEL_TSS);
  252. ArpInitializeInterrupts(PhysicalMode, BootProcessor, Idt);
  253. ArpSetProcessorFeatures(ProcessorBlock);
  254. //
  255. // Initialize the FPU, then disable access to it again.
  256. //
  257. Cr0 = ArGetControlRegister0();
  258. ArEnableFpu();
  259. ArInitializeFpu();
  260. ArSetControlRegister0(Cr0);
  261. return;
  262. }
  263. KSTATUS
  264. ArFinishBootProcessorInitialization (
  265. VOID
  266. )
  267. /*++
  268. Routine Description:
  269. This routine performs additional initialization steps for processor 0 that
  270. were put off in pre-debugger initialization.
  271. Arguments:
  272. None.
  273. Return Value:
  274. Status code.
  275. --*/
  276. {
  277. UINTN Address;
  278. PVOID Allocation;
  279. UINTN AllocationSize;
  280. ULONG Cr3;
  281. PGDT_ENTRY GdtTable;
  282. PTSS MainTss;
  283. UINTN PageSize;
  284. PPROCESSOR_BLOCK ProcessorBlock;
  285. PVOID Stack;
  286. PTSS Tss;
  287. Cr3 = ArGetCurrentPageDirectory();
  288. PageSize = MmPageSize();
  289. GdtTable = ArP0Gdt;
  290. ProcessorBlock = KeGetCurrentProcessorBlock();
  291. MainTss = ProcessorBlock->Tss;
  292. //
  293. // Allocate and initialize double fault and NMI stacks now that MM is up
  294. // and running. Allocate extra for alignment purposes, as TSS structures
  295. // must not cross a page boundary.
  296. //
  297. AllocationSize = (ALTERNATE_STACK_SIZE * ALTERNATE_STACK_COUNT) + PageSize;
  298. Allocation = MmAllocateNonPagedPool(AllocationSize, ARCH_POOL_TAG);
  299. if (Allocation == NULL) {
  300. return STATUS_INSUFFICIENT_RESOURCES;
  301. }
  302. Address = ALIGN_RANGE_UP((UINTN)Allocation, PageSize);
  303. //
  304. // Initialize the double fault TSS and stack. The main TSS is put on the
  305. // double fault stack so that sysenter can get to its thread stack with
  306. // just a single SS: dereference.
  307. //
  308. MainTss = (PVOID)(Address + ALTERNATE_STACK_SIZE - sizeof(TSS));
  309. Stack = (PVOID)MainTss;
  310. //
  311. // Copy the old main TSS over to the new main TSS, and move the GDT entry
  312. // as well.
  313. //
  314. RtlCopyMemory(MainTss, ProcessorBlock->Tss, sizeof(TSS));
  315. ArpCreateSegmentDescriptor(&(GdtTable[KERNEL_TSS / sizeof(GDT_ENTRY)]),
  316. MainTss,
  317. sizeof(TSS),
  318. GDT_GRANULARITY_32BIT,
  319. GDT_TYPE_TSS);
  320. Tss = ProcessorBlock->Tss;
  321. ProcessorBlock->Tss = MainTss;
  322. ArLoadTr(KERNEL_TSS);
  323. //
  324. // Initialize the double fault TSS, which just used to be the main TSS.
  325. //
  326. Tss->Esp0 = (UINTN)Stack;
  327. Tss->Esp = Tss->Esp0;
  328. Tss->Eip = (UINTN)ArDoubleFaultHandlerAsm;
  329. Tss->Cr3 = Cr3;
  330. ArpCreateSegmentDescriptor(
  331. &(GdtTable[DOUBLE_FAULT_TSS / sizeof(GDT_ENTRY)]),
  332. Tss,
  333. sizeof(TSS),
  334. GDT_GRANULARITY_32BIT,
  335. GDT_TYPE_TSS);
  336. //
  337. // Initialize the NMI TSS and stack (separate stack needed to avoid
  338. // vulnerable window during/before sysret instruction.
  339. //
  340. Address += ALTERNATE_STACK_SIZE;
  341. Tss = (PVOID)(Address + ALTERNATE_STACK_SIZE - sizeof(TSS));
  342. Stack = (PVOID)(Tss) - sizeof(PVOID);
  343. ArpInitializeTss(Tss);
  344. Tss->Esp0 = (UINTN)Stack;
  345. Tss->Esp = Tss->Esp0;
  346. Tss->Eip = (UINTN)KdNmiHandlerAsm;
  347. Tss->Cr3 = Cr3;
  348. ArpCreateSegmentDescriptor(&(GdtTable[NMI_TSS / sizeof(GDT_ENTRY)]),
  349. Tss,
  350. sizeof(TSS),
  351. GDT_GRANULARITY_32BIT,
  352. GDT_TYPE_TSS);
  353. return STATUS_SUCCESS;
  354. }
  355. PVOID
  356. ArAllocateProcessorStructures (
  357. ULONG ProcessorNumber
  358. )
  359. /*++
  360. Routine Description:
  361. This routine attempts to allocate and initialize early structures needed by
  362. a new processor.
  363. Arguments:
  364. ProcessorNumber - Supplies the number of the processor that these resources
  365. will go to.
  366. Return Value:
  367. Returns a pointer to the new processor resources on success.
  368. NULL on failure.
  369. --*/
  370. {
  371. UINTN Address;
  372. PVOID Allocation;
  373. UINTN AllocationSize;
  374. UINTN PageSize;
  375. PPROCESSOR_BLOCK ProcessorBlock;
  376. //
  377. // Allocate an extra page for alignment purposes, as TSS structures are
  378. // not supposed to cross page boundaries.
  379. //
  380. PageSize = MmPageSize();
  381. AllocationSize = ALTERNATE_STACK_COUNT * ALTERNATE_STACK_SIZE;
  382. AllocationSize += sizeof(ArP0Gdt) + sizeof(PROCESSOR_BLOCK) +
  383. sizeof(ArP0Tss) + PageSize;
  384. Allocation = MmAllocateNonPagedPool(AllocationSize, ARCH_POOL_TAG);
  385. if (Allocation == NULL) {
  386. return NULL;
  387. }
  388. RtlZeroMemory(Allocation, AllocationSize);
  389. Address = ALIGN_RANGE_UP((UINTN)Allocation, PageSize);
  390. ProcessorBlock = (PPROCESSOR_BLOCK)((PUCHAR)Address +
  391. (ALTERNATE_STACK_COUNT *
  392. ALTERNATE_STACK_SIZE) +
  393. sizeof(ArP0Gdt));
  394. ProcessorBlock->ProcessorNumber = ProcessorNumber;
  395. return Allocation;
  396. }
  397. VOID
  398. ArFreeProcessorStructures (
  399. PVOID ProcessorStructures
  400. )
  401. /*++
  402. Routine Description:
  403. This routine destroys a set of processor structures that have been
  404. allocated. It should go without saying, but obviously a processor must not
  405. be actively using these resources.
  406. Arguments:
  407. ProcessorStructures - Supplies the pointer returned by the allocation
  408. routine.
  409. Return Value:
  410. None.
  411. --*/
  412. {
  413. MmFreeNonPagedPool(ProcessorStructures);
  414. return;
  415. }
  416. BOOL
  417. ArIsTranslationEnabled (
  418. VOID
  419. )
  420. /*++
  421. Routine Description:
  422. This routine determines if the processor was initialized with virtual-to-
  423. physical address translation enabled or not.
  424. Arguments:
  425. None.
  426. Return Value:
  427. TRUE if the processor is using a layer of translation between CPU accessible
  428. addresses and physical memory.
  429. FALSE if the processor was initialized in physical mode.
  430. --*/
  431. {
  432. return ArTranslationEnabled;
  433. }
  434. ULONG
  435. ArGetIoPortCount (
  436. VOID
  437. )
  438. /*++
  439. Routine Description:
  440. This routine returns the number of I/O port addresses architecturally
  441. available.
  442. Arguments:
  443. None.
  444. Return Value:
  445. Returns the number of I/O port address supported by the architecture.
  446. --*/
  447. {
  448. return IO_PORT_COUNT;
  449. }
  450. ULONG
  451. ArGetInterruptVectorCount (
  452. VOID
  453. )
  454. /*++
  455. Routine Description:
  456. This routine returns the number of interrupt vectors in the system, either
  457. architecturally defined or artificially created.
  458. Arguments:
  459. None.
  460. Return Value:
  461. Returns the number of interrupt vectors in use by the system.
  462. --*/
  463. {
  464. return INTERRUPT_VECTOR_COUNT;
  465. }
  466. ULONG
  467. ArGetMinimumDeviceVector (
  468. VOID
  469. )
  470. /*++
  471. Routine Description:
  472. This routine returns the first interrupt vector that can be used by
  473. devices.
  474. Arguments:
  475. None.
  476. Return Value:
  477. Returns the minimum interrupt vector available for use by devices.
  478. --*/
  479. {
  480. return MINIMUM_VECTOR;
  481. }
  482. ULONG
  483. ArGetMaximumDeviceVector (
  484. VOID
  485. )
  486. /*++
  487. Routine Description:
  488. This routine returns the last interrupt vector that can be used by
  489. devices.
  490. Arguments:
  491. None.
  492. Return Value:
  493. Returns the maximum interrupt vector available for use by devices.
  494. --*/
  495. {
  496. return MAXIMUM_DEVICE_VECTOR;
  497. }
  498. ULONG
  499. ArGetTrapFrameSize (
  500. VOID
  501. )
  502. /*++
  503. Routine Description:
  504. This routine returns the size of the trap frame structure, in bytes.
  505. Arguments:
  506. None.
  507. Return Value:
  508. Returns the size of the trap frame structure, in bytes.
  509. --*/
  510. {
  511. return sizeof(TRAP_FRAME);
  512. }
  513. PVOID
  514. ArGetInstructionPointer (
  515. PTRAP_FRAME TrapFrame
  516. )
  517. /*++
  518. Routine Description:
  519. This routine returns the instruction pointer out of the trap frame.
  520. Arguments:
  521. TrapFrame - Supplies the trap frame from which the instruction pointer
  522. will be returned.
  523. Return Value:
  524. Returns the instruction pointer the trap frame is pointing to.
  525. --*/
  526. {
  527. return (PVOID)TrapFrame->Eip;
  528. }
  529. BOOL
  530. ArIsTrapFrameFromPrivilegedMode (
  531. PTRAP_FRAME TrapFrame
  532. )
  533. /*++
  534. Routine Description:
  535. This routine determines if the given trap frame occurred in a privileged
  536. environment or not.
  537. Arguments:
  538. TrapFrame - Supplies the trap frame.
  539. Return Value:
  540. TRUE if the execution environment of the trap frame is privileged.
  541. FALSE if the execution environment of the trap frame is not privileged.
  542. --*/
  543. {
  544. return IS_TRAP_FRAME_FROM_PRIVILEGED_MODE(TrapFrame);
  545. }
  546. BOOL
  547. ArIsTrapFrameComplete (
  548. PTRAP_FRAME TrapFrame
  549. )
  550. /*++
  551. Routine Description:
  552. This routine determines if the given trap frame contains the full context
  553. or only partial context as saved by the system call handler.
  554. Arguments:
  555. TrapFrame - Supplies the trap frame.
  556. Return Value:
  557. TRUE if the trap frame has all registers filled out.
  558. FALSE if the the trap frame is largely uninitialized as left by the system
  559. call handler.
  560. --*/
  561. {
  562. return IS_TRAP_FRAME_COMPLETE(TrapFrame);
  563. }
  564. VOID
  565. ArGetKernelTssTrapFrame (
  566. PTRAP_FRAME TrapFrame
  567. )
  568. /*++
  569. Routine Description:
  570. This routine converts the kernel TSS to a trap frame.
  571. Arguments:
  572. TrapFrame - Supplies a pointer where the filled out trap frame information
  573. will be returned.
  574. Return Value:
  575. None.
  576. --*/
  577. {
  578. PTSS KernelTask;
  579. PPROCESSOR_BLOCK ProcessorBlock;
  580. //
  581. // Attempt to build the trap frame out of the kernel TSS. This code does
  582. // not take into account potential nesting of tasks, it always assumes the
  583. // kernel task was the one executing. If for example a double fault
  584. // occurred during an NMI handler, the wrong registers would be displayed.
  585. //
  586. RtlZeroMemory(TrapFrame, sizeof(TRAP_FRAME));
  587. ProcessorBlock = KeGetCurrentProcessorBlock();
  588. if (ProcessorBlock != NULL) {
  589. KernelTask = ProcessorBlock->Tss;
  590. if (KernelTask != NULL) {
  591. TrapFrame->Ds = KernelTask->Ds;
  592. TrapFrame->Es = KernelTask->Es;
  593. TrapFrame->Fs = KernelTask->Fs;
  594. TrapFrame->Gs = KernelTask->Gs;
  595. TrapFrame->Ss = KernelTask->Ss;
  596. TrapFrame->Eax = KernelTask->Eax;
  597. TrapFrame->Ebx = KernelTask->Ebx;
  598. TrapFrame->Ecx = KernelTask->Ecx;
  599. TrapFrame->Edx = KernelTask->Edx;
  600. TrapFrame->Esi = KernelTask->Esi;
  601. TrapFrame->Edi = KernelTask->Edi;
  602. TrapFrame->Ebp = KernelTask->Ebp;
  603. TrapFrame->Eip = KernelTask->Eip;
  604. TrapFrame->Cs = KernelTask->Cs;
  605. TrapFrame->Eflags = KernelTask->Eflags;
  606. TrapFrame->Esp = KernelTask->Esp;
  607. }
  608. }
  609. return;
  610. }
  611. VOID
  612. ArSetKernelTssTrapFrame (
  613. PTRAP_FRAME TrapFrame
  614. )
  615. /*++
  616. Routine Description:
  617. This routine converts writes the given trap frame into the kernel TSS.
  618. Arguments:
  619. TrapFrame - Supplies a pointer to the trap frame data to write.
  620. Return Value:
  621. None.
  622. --*/
  623. {
  624. PTSS KernelTask;
  625. PPROCESSOR_BLOCK ProcessorBlock;
  626. //
  627. // Just like above, this routine assumes the kernel task was actually the
  628. // previous task. If it was not, these writes would be going to the wrong
  629. // place.
  630. //
  631. ProcessorBlock = KeGetCurrentProcessorBlock();
  632. if (ProcessorBlock != NULL) {
  633. KernelTask = ProcessorBlock->Tss;
  634. if (KernelTask != NULL) {
  635. KernelTask->Ds = TrapFrame->Ds;
  636. KernelTask->Es = TrapFrame->Es;
  637. KernelTask->Fs = TrapFrame->Fs;
  638. KernelTask->Gs = TrapFrame->Gs;
  639. KernelTask->Ss = TrapFrame->Ss;
  640. KernelTask->Eax = TrapFrame->Eax;
  641. KernelTask->Ebx = TrapFrame->Ebx;
  642. KernelTask->Ecx = TrapFrame->Ecx;
  643. KernelTask->Edx = TrapFrame->Edx;
  644. KernelTask->Esi = TrapFrame->Esi;
  645. KernelTask->Edi = TrapFrame->Edi;
  646. KernelTask->Ebp = TrapFrame->Ebp;
  647. KernelTask->Eip = TrapFrame->Eip;
  648. KernelTask->Cs = TrapFrame->Cs;
  649. KernelTask->Eflags = TrapFrame->Eflags;
  650. KernelTask->Esp = TrapFrame->Esp;
  651. }
  652. }
  653. return;
  654. }
  655. VOID
  656. ArClearTssBusyBit (
  657. USHORT TssSegment
  658. )
  659. /*++
  660. Routine Description:
  661. This routine clears the busy bit in the GDT for the given segment. It is
  662. assumed this segment is used on the current processor.
  663. Arguments:
  664. TssSegment - Supplies the TSS segment for the busy bit to clear.
  665. Return Value:
  666. None.
  667. --*/
  668. {
  669. PGDT_ENTRY Gdt;
  670. PPROCESSOR_BLOCK ProcessorBlock;
  671. ProcessorBlock = KeGetCurrentProcessorBlock();
  672. Gdt = ProcessorBlock->Gdt;
  673. Gdt += TssSegment / sizeof(GDT_ENTRY);
  674. ASSERT((Gdt->Access & ~GDT_TSS_BUSY) ==
  675. (GATE_ACCESS_PRESENT | GDT_TYPE_TSS));
  676. Gdt->Access &= ~GDT_TSS_BUSY;
  677. return;
  678. }
  679. VOID
  680. ArpCreateSegmentDescriptor (
  681. PGDT_ENTRY GdtEntry,
  682. PVOID Base,
  683. ULONG Limit,
  684. UCHAR Granularity,
  685. UCHAR Access
  686. )
  687. /*++
  688. Routine Description:
  689. This routine initializes a GDT entry given the parameters.
  690. Arguments:
  691. GdtEntry - Supplies a pointer to the GDT entry that will be initialized.
  692. Base - Supplies the base address where this segment begins.
  693. Limit - Supplies the size of the segment, either in bytes or kilobytes,
  694. depending on the Granularity parameter.
  695. Granularity - Supplies the granularity of the segment. Valid values are byte
  696. granularity or kilobyte granularity.
  697. Access - Supplies the access permissions on the segment.
  698. Return Value:
  699. None.
  700. --*/
  701. {
  702. //
  703. // If all these magic numbers seem cryptic, see the comment above the
  704. // definition for the GDT_ENTRY structure.
  705. //
  706. GdtEntry->LimitLow = Limit & 0xFFFF;
  707. GdtEntry->BaseLow = (ULONG)Base & 0xFFFF;
  708. GdtEntry->BaseMiddle = ((ULONG)Base >> 16) & 0xFF;
  709. GdtEntry->Access = GATE_ACCESS_PRESENT | Access;
  710. GdtEntry->Granularity = Granularity | ((Limit >> 16) & 0xF);
  711. GdtEntry->BaseHigh = ((ULONG)Base >> 24) & 0xFF;
  712. return;
  713. }
  714. //
  715. // --------------------------------------------------------- Internal Functions
  716. //
  717. VOID
  718. ArpHandleDoubleFault (
  719. VOID
  720. )
  721. /*++
  722. Routine Description:
  723. This routine handles double faults as gracefully as possible.
  724. Arguments:
  725. None.
  726. Return Value:
  727. This routine does not return, double faults are not recoverable.
  728. --*/
  729. {
  730. TRAP_FRAME TrapFrame;
  731. ArGetKernelTssTrapFrame(&TrapFrame);
  732. KdDebugExceptionHandler(EXCEPTION_DOUBLE_FAULT, NULL, &TrapFrame);
  733. KeCrashSystem(CRASH_KERNEL_STACK_EXCEPTION, (UINTN)&TrapFrame, 0, 0, 0);
  734. return;
  735. }
  736. VOID
  737. ArpCreateGate (
  738. PPROCESSOR_GATE Gate,
  739. PVOID HandlerRoutine,
  740. USHORT Selector,
  741. UCHAR Access
  742. )
  743. /*++
  744. Routine Description:
  745. This routine initializes a task, call, trap, or interrupt gate with the
  746. given values.
  747. Arguments:
  748. Gate - Supplies a pointer to the structure where the gate will be returned.
  749. It is assumed this structure is already allocated.
  750. HandlerRoutine - Supplies a pointer to the destination routine of this gate.
  751. Selector - Supplies the code selector this gate should run in.
  752. Access - Supplies the gate access bits, similar to the GDT access bits.
  753. Return Value:
  754. None.
  755. --*/
  756. {
  757. Gate->LowOffset = (USHORT)((ULONG)HandlerRoutine & 0xFFFF);
  758. Gate->HighOffset = (USHORT)((ULONG)HandlerRoutine >> 16);
  759. Gate->Selector = Selector;
  760. //
  761. // Set bit 5-7 of the count to 0. Bits 4-0 are reserved and need to be set
  762. // to 0 as well.
  763. //
  764. Gate->Count = 0;
  765. Gate->Access = GATE_ACCESS_PRESENT | Access;
  766. return;
  767. }
  768. VOID
  769. ArpInitializeTss (
  770. PTSS Task
  771. )
  772. /*++
  773. Routine Description:
  774. This routine initializes and loads the kernel Task State Segment (TSS).
  775. Arguments:
  776. Task - Supplies a pointer to the task to initialize and load.
  777. Return Value:
  778. None.
  779. --*/
  780. {
  781. RtlZeroMemory(Task, sizeof(TSS));
  782. //
  783. // Initialize the ring 0 stack. This will be set to a more reasonable value
  784. // before a privilege level switch.
  785. //
  786. Task->Esp0 = 0;
  787. Task->Ss0 = KERNEL_DS;
  788. Task->Ss = KERNEL_DS;
  789. Task->Cs = KERNEL_CS;
  790. Task->Ds = KERNEL_DS;
  791. Task->Es = KERNEL_DS;
  792. Task->Fs = GDT_PROCESSOR;
  793. Task->Gs = KERNEL_DS;
  794. Task->Eflags = IA32_EFLAG_ALWAYS_1;
  795. Task->IoMapBase = sizeof(TSS);
  796. return;
  797. }
  798. VOID
  799. ArpInitializeGdt (
  800. PGDT_ENTRY GdtTable,
  801. PPROCESSOR_BLOCK ProcessorBlock,
  802. PTSS KernelTss,
  803. PTSS DoubleFaultTss,
  804. PTSS NmiTss
  805. )
  806. /*++
  807. Routine Description:
  808. This routine initializes and loads the kernel's Global Descriptor Table
  809. (GDT).
  810. Arguments:
  811. GdtTable - Supplies a pointer to the global descriptor table to use. It is
  812. assumed this table contains enough entries to hold all the segment
  813. descriptors.
  814. ProcessorBlock - Supplies a pointer to the processor block to use for this
  815. processor.
  816. KernelTss - Supplies a pointer to the main kernel task.
  817. DoubleFaultTss - Supplies a pointer to the double fault TSS.
  818. NmiTss - Supplies a pointer to the NMI TSS.
  819. Return Value:
  820. None.
  821. --*/
  822. {
  823. TABLE_REGISTER Gdt;
  824. //
  825. // The first segment descriptor must be unused. Set it to zero.
  826. //
  827. GdtTable[0].LimitLow = 0;
  828. GdtTable[0].BaseLow = 0;
  829. GdtTable[0].BaseMiddle = 0;
  830. GdtTable[0].Access = 0;
  831. GdtTable[0].Granularity = 0;
  832. GdtTable[0].BaseHigh = 0;
  833. //
  834. // Initialize the kernel code segment. Initialize the entry to cover all
  835. // 4GB of memory, with read/write permissions, and only on ring 0. This is
  836. // not a system segment.
  837. //
  838. ArpCreateSegmentDescriptor(&(GdtTable[KERNEL_CS / sizeof(GDT_ENTRY)]),
  839. NULL,
  840. MAX_GDT_LIMIT,
  841. GDT_GRANULARITY_KILOBYTE | GDT_GRANULARITY_32BIT,
  842. GDT_TYPE_CODE);
  843. //
  844. // Initialize the kernel data segment. Initialize the entry to cover
  845. // all 4GB of memory, with read/write permissions, and only on ring 0. This
  846. // is not a system segment.
  847. //
  848. ArpCreateSegmentDescriptor(&(GdtTable[KERNEL_DS / sizeof(GDT_ENTRY)]),
  849. NULL,
  850. MAX_GDT_LIMIT,
  851. GDT_GRANULARITY_KILOBYTE | GDT_GRANULARITY_32BIT,
  852. GDT_TYPE_DATA_WRITE);
  853. //
  854. // Initialize the user mode code segment. Initialize the entry to cover
  855. // the first 2GB of memory, with execute permissions, in ring 3. This is
  856. // not a system segment.
  857. //
  858. ArpCreateSegmentDescriptor(&(GdtTable[USER32_CS / sizeof(GDT_ENTRY)]),
  859. (PVOID)0,
  860. (ULONG)USER_VA_END >> PAGE_SHIFT,
  861. GDT_GRANULARITY_KILOBYTE | GDT_GRANULARITY_32BIT,
  862. GATE_ACCESS_USER | GDT_TYPE_CODE);
  863. //
  864. // Initialize the user mode data segment. Initialize the entry to cover
  865. // the first 2GB of memory, with read/write permissions, in ring 3. This is
  866. // not a system segment.
  867. //
  868. ArpCreateSegmentDescriptor(&(GdtTable[USER_DS / sizeof(GDT_ENTRY)]),
  869. (PVOID)0,
  870. (ULONG)USER_VA_END >> PAGE_SHIFT,
  871. GDT_GRANULARITY_KILOBYTE | GDT_GRANULARITY_32BIT,
  872. GATE_ACCESS_USER | GDT_TYPE_DATA_WRITE);
  873. //
  874. // Initialize the processor block segment.
  875. //
  876. ArpCreateSegmentDescriptor(&(GdtTable[GDT_PROCESSOR / sizeof(GDT_ENTRY)]),
  877. (PVOID)ProcessorBlock,
  878. sizeof(PROCESSOR_BLOCK),
  879. GDT_GRANULARITY_32BIT,
  880. GDT_TYPE_DATA_WRITE);
  881. //
  882. // Initialize the thread context segment, which can be programmed by
  883. // user mode.
  884. //
  885. ArpCreateSegmentDescriptor(&(GdtTable[GDT_THREAD / sizeof(GDT_ENTRY)]),
  886. NULL,
  887. sizeof(PROCESSOR_BLOCK),
  888. GDT_GRANULARITY_32BIT,
  889. GATE_ACCESS_USER | GDT_TYPE_DATA_WRITE);
  890. //
  891. // Initialize the kernel TSS segments. The entry covers only the TSS
  892. // segment. This is a system segment (a 32-bit Free TSS to be exact).
  893. //
  894. ArpCreateSegmentDescriptor(&(GdtTable[KERNEL_TSS / sizeof(GDT_ENTRY)]),
  895. KernelTss,
  896. sizeof(TSS),
  897. GDT_GRANULARITY_32BIT,
  898. GDT_TYPE_TSS);
  899. ArpCreateSegmentDescriptor(
  900. &(GdtTable[DOUBLE_FAULT_TSS / sizeof(GDT_ENTRY)]),
  901. DoubleFaultTss,
  902. sizeof(TSS),
  903. GDT_GRANULARITY_32BIT,
  904. GDT_TYPE_TSS);
  905. //
  906. // NMIs need a TSS so they can have their own stack, which is needed on
  907. // systems that use the "syscall" instruction. Because sysret doesn't
  908. // change stacks, there's a moment where kernel mode is running with a
  909. // user mode ESP. An NMI at that moment would mean executing kernel code
  910. // on a user mode stack, bad news.
  911. //
  912. ArpCreateSegmentDescriptor(&(GdtTable[NMI_TSS / sizeof(GDT_ENTRY)]),
  913. NmiTss,
  914. sizeof(TSS),
  915. GDT_GRANULARITY_32BIT,
  916. GDT_TYPE_TSS);
  917. //
  918. // Install the new GDT table.
  919. //
  920. Gdt.Limit = sizeof(GDT_ENTRY) * X86_GDT_ENTRIES;
  921. Gdt.Base = (ULONG)GdtTable;
  922. ArLoadGdtr(Gdt);
  923. ArLoadKernelDataSegments();
  924. return;
  925. }
  926. VOID
  927. ArpInitializeInterrupts (
  928. BOOL PhysicalMode,
  929. BOOL BootProcessor,
  930. PVOID Idt
  931. )
  932. /*++
  933. Routine Description:
  934. This routine initializes and enables interrupts.
  935. Arguments:
  936. PhysicalMode - Supplies a flag indicating that the processor is running
  937. with translation disabled.
  938. BootProcessor - Supplies a flag indicating whether this is processor 0 or
  939. an AP.
  940. Idt - Supplies a pointer to the Interrrupt Descriptor Table for this
  941. processor.
  942. Return Value:
  943. None.
  944. --*/
  945. {
  946. ULONG DispatchCodeLength;
  947. ULONG IdtIndex;
  948. TABLE_REGISTER IdtRegister;
  949. PPROCESSOR_GATE IdtTable;
  950. PVOID ServiceRoutine;
  951. IdtTable = Idt;
  952. if (BootProcessor != FALSE) {
  953. //
  954. // Initialize the device vectors of the IDT. The vector dispatch code
  955. // is a bunch of copies of the same code, the only difference is which
  956. // vector number they push as a parameter.
  957. //
  958. DispatchCodeLength = (ULONG)(&HlVectorEnd - &HlVectorStart) /
  959. (MAXIMUM_VECTOR - MINIMUM_VECTOR);
  960. for (IdtIndex = MINIMUM_VECTOR;
  961. IdtIndex < MAXIMUM_VECTOR;
  962. IdtIndex += 1) {
  963. ServiceRoutine = &HlVectorStart + ((IdtIndex - MINIMUM_VECTOR) *
  964. DispatchCodeLength);
  965. ArpCreateGate(IdtTable + IdtIndex,
  966. ServiceRoutine,
  967. KERNEL_CS,
  968. GATE_TYPE_INTERRUPT);
  969. }
  970. //
  971. // Set up the debug trap handlers.
  972. //
  973. ArpCreateGate(IdtTable + VECTOR_DIVIDE_ERROR,
  974. ArDivideByZeroExceptionHandlerAsm,
  975. KERNEL_CS,
  976. GATE_ACCESS_USER | GATE_TYPE_TRAP);
  977. ArpCreateGate(IdtTable + VECTOR_NMI,
  978. NULL,
  979. NMI_TSS,
  980. GATE_TYPE_TASK);
  981. ArpCreateGate(IdtTable + VECTOR_BREAKPOINT,
  982. ArBreakExceptionHandlerAsm,
  983. KERNEL_CS,
  984. GATE_ACCESS_USER | GATE_TYPE_INTERRUPT);
  985. ArpCreateGate(IdtTable + VECTOR_DEBUG,
  986. ArSingleStepExceptionHandlerAsm,
  987. KERNEL_CS,
  988. GATE_TYPE_INTERRUPT);
  989. ArpCreateGate(IdtTable + VECTOR_DEBUG_SERVICE,
  990. KdDebugServiceHandlerAsm,
  991. KERNEL_CS,
  992. GATE_TYPE_INTERRUPT);
  993. //
  994. // Set up the double fault and general protection fault handlers.
  995. //
  996. ArpCreateGate(IdtTable + VECTOR_DOUBLE_FAULT,
  997. NULL,
  998. DOUBLE_FAULT_TSS,
  999. GATE_TYPE_TASK);
  1000. ArpCreateGate(IdtTable + VECTOR_PROTECTION_FAULT,
  1001. ArProtectionFaultHandlerAsm,
  1002. KERNEL_CS,
  1003. GATE_TYPE_INTERRUPT);
  1004. ArpCreateGate(IdtTable + VECTOR_MATH_FAULT,
  1005. ArMathFaultHandlerAsm,
  1006. KERNEL_CS,
  1007. GATE_TYPE_INTERRUPT);
  1008. //
  1009. // Set up the system call handler.
  1010. //
  1011. ArpCreateGate(IdtTable + VECTOR_SYSTEM_CALL,
  1012. ArSystemCallHandlerAsm,
  1013. KERNEL_CS,
  1014. GATE_ACCESS_USER | GATE_TYPE_TRAP);
  1015. //
  1016. // Set up the spurious interrupt vector.
  1017. //
  1018. ArpCreateGate(IdtTable + VECTOR_SPURIOUS_INTERRUPT,
  1019. HlSpuriousInterruptHandlerAsm,
  1020. KERNEL_CS,
  1021. GATE_TYPE_INTERRUPT);
  1022. //
  1023. // Set up the page fault handler.
  1024. //
  1025. ArpCreateGate(IdtTable + VECTOR_PAGE_FAULT,
  1026. ArpPageFaultHandlerAsm,
  1027. KERNEL_CS,
  1028. GATE_TYPE_INTERRUPT);
  1029. ArpCreateGate(IdtTable + VECTOR_STACK_EXCEPTION,
  1030. ArpPageFaultHandlerAsm,
  1031. KERNEL_CS,
  1032. GATE_TYPE_INTERRUPT);
  1033. //
  1034. // Set up floating point access handlers.
  1035. //
  1036. ArpCreateGate(IdtTable + VECTOR_DEVICE_NOT_AVAILABLE,
  1037. ArFpuAccessExceptionHandlerAsm,
  1038. KERNEL_CS,
  1039. GATE_TYPE_TRAP);
  1040. }
  1041. //
  1042. // Load the IDT register with our interrupt descriptor table.
  1043. //
  1044. IdtRegister.Limit = (IDT_SIZE * sizeof(PROCESSOR_GATE)) - 1;
  1045. IdtRegister.Base = (ULONG)IdtTable;
  1046. ArLoadIdtr(&IdtRegister);
  1047. return;
  1048. }
  1049. VOID
  1050. ArpSetProcessorFeatures (
  1051. PPROCESSOR_BLOCK ProcessorBlock
  1052. )
  1053. /*++
  1054. Routine Description:
  1055. This routine reads processor features.
  1056. Arguments:
  1057. ProcessorBlock - Supplies a pointer to the processor block.
  1058. Return Value:
  1059. None.
  1060. --*/
  1061. {
  1062. ULONG Cr4;
  1063. ULONG Eax;
  1064. ULONG Ebx;
  1065. ULONG Ecx;
  1066. ULONG Edx;
  1067. ULONG ExtendedFamily;
  1068. ULONG ExtendedModel;
  1069. ULONG Family;
  1070. PPROCESSOR_IDENTIFICATION Identification;
  1071. ULONG Model;
  1072. Identification = &(ProcessorBlock->CpuVersion);
  1073. //
  1074. // First call CPUID to find out the highest supported value.
  1075. //
  1076. Eax = X86_CPUID_IDENTIFICATION;
  1077. ArCpuid(&Eax, &Ebx, &Ecx, &Edx);
  1078. Identification->Vendor = Ebx;
  1079. if (Eax < X86_CPUID_BASIC_INFORMATION) {
  1080. return;
  1081. }
  1082. Eax = X86_CPUID_BASIC_INFORMATION;
  1083. ArCpuid(&Eax, &Ebx, &Ecx, &Edx);
  1084. //
  1085. // Tease out the family, model, and stepping information.
  1086. //
  1087. Family = (Eax & X86_CPUID_BASIC_EAX_BASE_FAMILY_MASK) >>
  1088. X86_CPUID_BASIC_EAX_BASE_FAMILY_SHIFT;
  1089. Model = (Eax & X86_CPUID_BASIC_EAX_BASE_MODEL_MASK) >>
  1090. X86_CPUID_BASIC_EAX_BASE_MODEL_SHIFT;
  1091. ExtendedFamily = (Eax & X86_CPUID_BASIC_EAX_EXTENDED_FAMILY_MASK) >>
  1092. X86_CPUID_BASIC_EAX_EXTENDED_FAMILY_SHIFT;
  1093. ExtendedModel = (Eax & X86_CPUID_BASIC_EAX_EXTENDED_MODEL_MASK) >>
  1094. X86_CPUID_BASIC_EAX_EXTENDED_MODEL_SHIFT;
  1095. Identification->Family = Family;
  1096. Identification->Model = Model;
  1097. Identification->Stepping = Eax & X86_CPUID_BASIC_EAX_STEPPING_MASK;
  1098. //
  1099. // Certain well-known vendors have minor quirks about how their family and
  1100. // model values are computed.
  1101. //
  1102. if (Identification->Vendor == X86_VENDOR_INTEL) {
  1103. if (Family == 0xF) {
  1104. Identification->Family = Family + ExtendedFamily;
  1105. }
  1106. if ((Family == 0xF) || (Family == 0x6)) {
  1107. Identification->Model = (ExtendedModel << 4) + Model;
  1108. }
  1109. } else if (Identification->Vendor == X86_VENDOR_AMD) {
  1110. Identification->Family = Family + ExtendedFamily;
  1111. if (Model == 0xF) {
  1112. Identification->Model = (ExtendedModel << 4) + Model;
  1113. }
  1114. }
  1115. //
  1116. // If FXSAVE and FXRSTOR are supported, set the bits in CR4 to enable them.
  1117. //
  1118. if ((Edx & X86_CPUID_BASIC_EDX_FX_SAVE_RESTORE) != 0) {
  1119. ArSaveFpuState = ArFxSave;
  1120. ArRestoreFpuState = ArFxRestore;
  1121. Cr4 = ArGetControlRegister4();
  1122. Cr4 |= CR4_OS_FX_SAVE_RESTORE | CR4_OS_XMM_EXCEPTIONS |
  1123. CR4_PAGE_GLOBAL_ENABLE;
  1124. ArSetControlRegister4(Cr4);
  1125. //
  1126. // Fall back to the old FSAVE/FRSTOR instructions.
  1127. //
  1128. } else {
  1129. ArSaveFpuState = ArSaveX87State;
  1130. ArRestoreFpuState = ArRestoreX87State;
  1131. }
  1132. return;
  1133. }