Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1504 lines
39 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. pbiosc.c
  5. Abstract:
  6. This module contains Pnp BIOS dependent routines. It includes code to initialize
  7. 16 bit GDT selectors and to call pnp bios api.
  8. Author:
  9. Shie-Lin Tzong (shielint) 15-Jan-1998
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. --*/
  14. #include "pnpmgrp.h"
  15. #include "pnpcvrt.h"
  16. #include "pbios.h"
  17. #include "..\..\ke\i386\abios.h"
  18. //
  19. // Functions for PNP_BIOS_ENUMERATION_CONTEXT
  20. //
  21. #define PI_SHUTDOWN_EXAMINE_BIOS_DEVICE 1
  22. #define PI_SHUTDOWN_LEGACY_RESOURCES 2
  23. typedef struct _PNP_BIOS_DEVICE_NODE_LIST {
  24. struct _PNP_BIOS_DEVICE_NODE_LIST *Next;
  25. PNP_BIOS_DEVICE_NODE DeviceNode;
  26. } PNP_BIOS_DEVICE_NODE_LIST, *PPNP_BIOS_DEVICE_NODE_LIST;
  27. typedef struct _PNP_BIOS_ENUMERATION_CONTEXT {
  28. PUNICODE_STRING KeyName;
  29. ULONG Function;
  30. union {
  31. struct {
  32. PVOID BiosInfo;
  33. ULONG BiosInfoLength;
  34. PPNP_BIOS_DEVICE_NODE_LIST *DeviceList;
  35. } ExamineBiosDevice;
  36. struct {
  37. PCM_RESOURCE_LIST LegacyResources;
  38. } LegacyResources;
  39. } u;
  40. } PNP_BIOS_ENUMERATION_CONTEXT, *PPNP_BIOS_ENUMERATION_CONTEXT;
  41. typedef struct _PNP_BIOS_SHUT_DOWN_CONTEXT {
  42. PPNP_BIOS_DEVICE_NODE_LIST DeviceList;
  43. PVOID Resources;
  44. } PNP_BIOS_SHUT_DOWN_CONTEXT, *PPNP_BIOS_SHUT_DOWN_CONTEXT;
  45. //
  46. // A big structure for calling Pnp BIOS functions
  47. //
  48. #define PNP_BIOS_GET_NUMBER_DEVICE_NODES 0
  49. #define PNP_BIOS_GET_DEVICE_NODE 1
  50. #define PNP_BIOS_SET_DEVICE_NODE 2
  51. #define PNP_BIOS_GET_EVENT 3
  52. #define PNP_BIOS_SEND_MESSAGE 4
  53. #define PNP_BIOS_GET_DOCK_INFORMATION 5
  54. // Function 6 is reserved
  55. #define PNP_BIOS_SELECT_BOOT_DEVICE 7
  56. #define PNP_BIOS_GET_BOOT_DEVICE 8
  57. #define PNP_BIOS_SET_OLD_ISA_RESOURCES 9
  58. #define PNP_BIOS_GET_OLD_ISA_RESOURCES 0xA
  59. #define PNP_BIOS_GET_ISA_CONFIGURATION 0x40
  60. //
  61. // Control Flags for Set_Device_node
  62. //
  63. #define SET_CONFIGURATION_NOW 1
  64. #define SET_CONFIGURATION_FOR_NEXT_BOOT 2
  65. typedef struct _PB_PARAMETERS {
  66. USHORT Function;
  67. union {
  68. struct {
  69. USHORT *NumberNodes;
  70. USHORT *NodeSize;
  71. } GetNumberDeviceNodes;
  72. struct {
  73. USHORT *Node;
  74. PPNP_BIOS_DEVICE_NODE NodeBuffer;
  75. USHORT Control;
  76. } GetDeviceNode;
  77. struct {
  78. USHORT Node;
  79. PPNP_BIOS_DEVICE_NODE NodeBuffer;
  80. USHORT Control;
  81. } SetDeviceNode;
  82. struct {
  83. USHORT *Message;
  84. } GetEvent;
  85. struct {
  86. USHORT Message;
  87. } SendMessage;
  88. struct {
  89. PVOID Resources;
  90. } SetAllocatedResources;
  91. } u;
  92. } PB_PARAMETERS, *PPB_PARAMETERS;
  93. #define PB_MAXIMUM_STACK_SIZE (sizeof(PB_PARAMETERS) + sizeof(USHORT) * 2)
  94. //
  95. // PbBiosInitialized is set to the return of PnPBiosInitializePnPBios. It
  96. // should not be checked before that function is called.
  97. //
  98. NTSTATUS PbBiosInitialized ;
  99. //
  100. // PbBiosCodeSelector contains the selector of the PNP
  101. // BIOS code.
  102. //
  103. USHORT PbBiosCodeSelector;
  104. //
  105. // PbBiosDataSelector contains the selector of the PNP
  106. // BIOS data area (F0000-FFFFF)
  107. //
  108. USHORT PbBiosDataSelector;
  109. //
  110. // PbSelectors[] contains general purpose preallocated selectors
  111. //
  112. USHORT PbSelectors[2];
  113. //
  114. // PbBiosEntryPoint contains the Pnp Bios entry offset
  115. //
  116. ULONG PbBiosEntryPoint;
  117. //
  118. // SpinLock to serialize Pnp Bios call
  119. //
  120. KSPIN_LOCK PbBiosSpinlock;
  121. //
  122. // PiShutdownContext
  123. //
  124. PNP_BIOS_SHUT_DOWN_CONTEXT PiShutdownContext;
  125. //
  126. // External References
  127. //
  128. extern
  129. USHORT
  130. PbCallPnpBiosWorker (
  131. IN ULONG EntryOffset,
  132. IN ULONG EntrySelector,
  133. IN PUSHORT Parameters,
  134. IN USHORT Size
  135. );
  136. //
  137. // Internal prototypes
  138. //
  139. VOID
  140. PnPBiosCollectLegacyDeviceResources (
  141. IN PCM_RESOURCE_LIST *ReturnedResources
  142. );
  143. VOID
  144. PnPBiosReserveLegacyDeviceResources (
  145. IN PUCHAR BiosResources
  146. );
  147. NTSTATUS
  148. PnPBiosExamineDeviceKeys (
  149. IN PVOID BiosInfo,
  150. IN ULONG BiosInfoLength,
  151. IN OUT PPNP_BIOS_DEVICE_NODE_LIST *DeviceList
  152. );
  153. BOOLEAN
  154. PnPBiosExamineBiosDeviceKey(
  155. IN HANDLE KeyHandle,
  156. IN PUNICODE_STRING KeyName,
  157. IN OUT PPNP_BIOS_ENUMERATION_CONTEXT Context
  158. );
  159. BOOLEAN
  160. PnPBiosExamineBiosDeviceInstanceKey(
  161. IN HANDLE KeyHandle,
  162. IN PUNICODE_STRING KeyName,
  163. IN OUT PPNP_BIOS_ENUMERATION_CONTEXT Context
  164. );
  165. NTSTATUS
  166. PnPBiosExtractInfo(
  167. IN ULONG BiosHandle,
  168. IN PVOID BiosInfo,
  169. IN ULONG BiosInfoLength,
  170. OUT PVOID *Header,
  171. OUT ULONG *HeaderLength,
  172. OUT PVOID *Tail,
  173. OUT ULONG *TailLength
  174. );
  175. VOID
  176. PnPBiosSetDeviceNodes (
  177. IN PVOID Context
  178. );
  179. NTSTATUS
  180. PbHardwareService (
  181. IN PPB_PARAMETERS Parameters
  182. );
  183. VOID
  184. PbAddress32ToAddress16 (
  185. IN PVOID Address32,
  186. IN PUSHORT Address16,
  187. IN USHORT Selector
  188. );
  189. #ifdef ALLOC_PRAGMA
  190. BOOLEAN
  191. PnPBiosGetBiosHandleFromDeviceKey(
  192. IN HANDLE KeyHandle,
  193. OUT PULONG BiosDeviceId
  194. );
  195. NTSTATUS
  196. PnPBiosSetDeviceNodeDynamically(
  197. IN PDEVICE_OBJECT DeviceObject
  198. );
  199. #pragma alloc_text(PAGE, PnPBiosGetBiosHandleFromDeviceKey)
  200. #pragma alloc_text(PAGE, PnPBiosCollectLegacyDeviceResources)
  201. #pragma alloc_text(PAGE, PnPBiosExamineDeviceKeys)
  202. #pragma alloc_text(PAGE, PnPBiosExamineBiosDeviceKey)
  203. #pragma alloc_text(PAGE, PnPBiosExamineBiosDeviceInstanceKey)
  204. #pragma alloc_text(PAGE, PnPBiosExtractInfo)
  205. #pragma alloc_text(PAGE, PnPBiosInitializePnPBios)
  206. #pragma alloc_text(PAGE, PnPBiosSetDeviceNodes)
  207. #pragma alloc_text(PAGE, PnPBiosSetDeviceNodeDynamically)
  208. #pragma alloc_text(PAGE, PnPBiosReserveLegacyDeviceResources)
  209. #pragma alloc_text(PAGE, PbAddress32ToAddress16)
  210. #pragma alloc_text(PAGELK, PbHardwareService)
  211. #pragma alloc_text(PAGELK, PnPBiosShutdownSystem)
  212. #endif
  213. VOID
  214. PnPBiosShutdownSystem (
  215. IN ULONG Phase,
  216. IN OUT PVOID *Context
  217. )
  218. /*++
  219. Routine Description:
  220. This routine performs the Pnp shutdowm preparation.
  221. At phase 0, it prepares the data for the Pnp bios devices whose states needed to be
  222. updated to pnp bios.
  223. At phase 1, we write the data to pnp bios.
  224. Arguments:
  225. Phase - specifies the shutdown phase.
  226. Context - at phase 0, it supplies a variable to receive the returned context info.
  227. at phase 1, it supplies a variable to specify the context info.
  228. Return Value:
  229. None.
  230. --*/
  231. {
  232. PVOID biosInfo;
  233. ULONG length;
  234. NTSTATUS status;
  235. PPNP_BIOS_DEVICE_NODE_LIST pnpBiosDeviceNode;
  236. PCM_RESOURCE_LIST legacyResources;
  237. PUCHAR biosResources;
  238. if (Phase == 0) {
  239. *Context = NULL;
  240. status = PnPBiosGetBiosInfo(&biosInfo, &length);
  241. if (NT_SUCCESS( status )) {
  242. PnPBiosExamineDeviceKeys(
  243. biosInfo,
  244. length,
  245. (PPNP_BIOS_DEVICE_NODE_LIST *) &PiShutdownContext.DeviceList
  246. );
  247. PnPBiosCollectLegacyDeviceResources (&legacyResources);
  248. if (legacyResources) {
  249. status = PpCmResourcesToBiosResources (legacyResources, NULL, &biosResources, &length);
  250. if (NT_SUCCESS(status) && biosResources) {
  251. PiShutdownContext.Resources = (PCM_RESOURCE_LIST)ExAllocatePool(NonPagedPool, length);
  252. if (PiShutdownContext.Resources) {
  253. RtlMoveMemory(PiShutdownContext.Resources, biosResources, length);
  254. ExFreePool(biosResources);
  255. }
  256. }
  257. ExFreePool(legacyResources);
  258. }
  259. if (PiShutdownContext.DeviceList || PiShutdownContext.Resources) {
  260. *Context = &PiShutdownContext;
  261. }
  262. ExFreePool(biosInfo);
  263. }
  264. return;
  265. } else if (*Context) {
  266. ASSERT(*Context == &PiShutdownContext);
  267. pnpBiosDeviceNode = PiShutdownContext.DeviceList;
  268. biosResources = PiShutdownContext.Resources;
  269. if (pnpBiosDeviceNode || biosResources) {
  270. //
  271. // Call pnp bios from boot processor
  272. //
  273. KeSetSystemAffinityThread(1);
  274. if (pnpBiosDeviceNode) {
  275. PnPBiosSetDeviceNodes(pnpBiosDeviceNode);
  276. }
  277. if (biosResources) {
  278. PnPBiosReserveLegacyDeviceResources(biosResources);
  279. }
  280. //
  281. // Restore old affinity for current thread.
  282. //
  283. KeRevertToUserAffinityThread();
  284. }
  285. }
  286. }
  287. BOOLEAN
  288. PnPBiosGetBiosHandleFromDeviceKey(
  289. IN HANDLE KeyHandle,
  290. OUT PULONG BiosDeviceId
  291. )
  292. /*++
  293. Routine Description:
  294. This routine takes a handle to System\Enum\Root\<Device Instance> and sets
  295. BiosDeviceId to the PNPBIOS ID of the device.
  296. Arguments:
  297. KeyHandle - handle to System\Enum\Root\<Device Instance>
  298. BiosDeviceId - After this function is ran, this value will be filled with
  299. the ID assigned to the device by PNPBIOS.
  300. Return Value:
  301. FALSE if the handle does not refer to a PNPBIOS device.
  302. --*/
  303. {
  304. UNICODE_STRING unicodeName;
  305. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  306. NTSTATUS status;
  307. HANDLE handle;
  308. ULONG biosDeviceHandle = ~0ul;
  309. PAGED_CODE();
  310. //
  311. // Make sure this is a pnp bios device by checking its pnp bios device
  312. // handle.
  313. //
  314. PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_CONTROL);
  315. status = IopOpenRegistryKeyEx( &handle,
  316. KeyHandle,
  317. &unicodeName,
  318. KEY_READ
  319. );
  320. if (!NT_SUCCESS(status)) {
  321. return FALSE ;
  322. }
  323. status = IopGetRegistryValue (handle,
  324. L"PnpBiosDeviceHandle",
  325. &keyValueInformation);
  326. ZwClose(handle);
  327. if (NT_SUCCESS(status)) {
  328. if ((keyValueInformation->Type == REG_DWORD) &&
  329. (keyValueInformation->DataLength == sizeof(ULONG))) {
  330. biosDeviceHandle = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
  331. }
  332. ExFreePool(keyValueInformation);
  333. }
  334. if (biosDeviceHandle > 0xffff) {
  335. return FALSE;
  336. }
  337. *BiosDeviceId = biosDeviceHandle ;
  338. return TRUE ;
  339. }
  340. VOID
  341. PnPBiosCollectLegacyDeviceResources (
  342. IN PCM_RESOURCE_LIST *ReturnedResources
  343. )
  344. /*++
  345. Routine Description:
  346. Arguments:
  347. ReturnedResources - supplies a pointer to a variable to receive legacy resources.
  348. Return Value:
  349. None.
  350. --*/
  351. {
  352. NTSTATUS status;
  353. HANDLE baseHandle;
  354. PNP_BIOS_ENUMERATION_CONTEXT context;
  355. PVOID buffer;
  356. UNICODE_STRING workName, tmpName;
  357. PAGED_CODE();
  358. *ReturnedResources = NULL;
  359. buffer = ExAllocatePool(PagedPool, PNP_LARGE_SCRATCH_BUFFER_SIZE);
  360. if (!buffer) {
  361. return;
  362. }
  363. //
  364. // Open System\CurrentControlSet\Enum\Root key and call worker routine to recursively
  365. // scan through the subkeys.
  366. //
  367. status = IopCreateRegistryKeyEx( &baseHandle,
  368. NULL,
  369. &CmRegistryMachineSystemCurrentControlSetEnumRootName,
  370. KEY_READ,
  371. REG_OPTION_NON_VOLATILE,
  372. NULL
  373. );
  374. if (NT_SUCCESS(status)) {
  375. workName.Buffer = (PWSTR)buffer;
  376. RtlFillMemory(buffer, PNP_LARGE_SCRATCH_BUFFER_SIZE, 0);
  377. workName.MaximumLength = PNP_LARGE_SCRATCH_BUFFER_SIZE;
  378. workName.Length = 0;
  379. PiWstrToUnicodeString(&tmpName, REGSTR_KEY_ROOTENUM);
  380. RtlAppendStringToString((PSTRING)&workName, (PSTRING)&tmpName);
  381. //
  382. // Enumerate all subkeys under the System\CCS\Enum\Root.
  383. //
  384. context.KeyName = &workName;
  385. context.Function = PI_SHUTDOWN_LEGACY_RESOURCES;
  386. context.u.LegacyResources.LegacyResources = NULL;
  387. status = PipApplyFunctionToSubKeys(baseHandle,
  388. NULL,
  389. KEY_READ,
  390. FUNCTIONSUBKEY_FLAG_IGNORE_NON_CRITICAL_ERRORS,
  391. PnPBiosExamineBiosDeviceKey,
  392. &context
  393. );
  394. ZwClose(baseHandle);
  395. *ReturnedResources = context.u.LegacyResources.LegacyResources;
  396. }
  397. ExFreePool(buffer);
  398. }
  399. NTSTATUS
  400. PnPBiosExamineDeviceKeys (
  401. IN PVOID BiosInfo,
  402. IN ULONG BiosInfoLength,
  403. IN OUT PPNP_BIOS_DEVICE_NODE_LIST *DeviceList
  404. )
  405. /*++
  406. Routine Description:
  407. This routine scans through System\Enum\Root subtree to build a device node for
  408. each root device.
  409. Arguments:
  410. DeviceRelations - supplies a variable to receive the returned DEVICE_RELATIONS structure.
  411. Return Value:
  412. A NTSTATUS code.
  413. --*/
  414. {
  415. NTSTATUS status;
  416. HANDLE baseHandle;
  417. PNP_BIOS_ENUMERATION_CONTEXT context;
  418. PVOID buffer;
  419. UNICODE_STRING workName, tmpName;
  420. PAGED_CODE();
  421. buffer = ExAllocatePool(PagedPool, PNP_LARGE_SCRATCH_BUFFER_SIZE);
  422. if (!buffer) {
  423. return STATUS_INSUFFICIENT_RESOURCES;
  424. }
  425. //
  426. // Open System\CurrentControlSet\Enum\Root key and call worker routine to recursively
  427. // scan through the subkeys.
  428. //
  429. status = IopCreateRegistryKeyEx( &baseHandle,
  430. NULL,
  431. &CmRegistryMachineSystemCurrentControlSetEnumRootName,
  432. KEY_READ,
  433. REG_OPTION_NON_VOLATILE,
  434. NULL
  435. );
  436. if (NT_SUCCESS(status)) {
  437. workName.Buffer = (PWSTR)buffer;
  438. RtlFillMemory(buffer, PNP_LARGE_SCRATCH_BUFFER_SIZE, 0);
  439. workName.MaximumLength = PNP_LARGE_SCRATCH_BUFFER_SIZE;
  440. workName.Length = 0;
  441. PiWstrToUnicodeString(&tmpName, REGSTR_KEY_ROOTENUM);
  442. RtlAppendStringToString((PSTRING)&workName, (PSTRING)&tmpName);
  443. //
  444. // Enumerate all subkeys under the System\CCS\Enum\Root.
  445. //
  446. context.KeyName = &workName;
  447. context.Function = PI_SHUTDOWN_EXAMINE_BIOS_DEVICE;
  448. context.u.ExamineBiosDevice.BiosInfo = BiosInfo;
  449. context.u.ExamineBiosDevice.BiosInfoLength = BiosInfoLength;
  450. context.u.ExamineBiosDevice.DeviceList = DeviceList;
  451. status = PipApplyFunctionToSubKeys(baseHandle,
  452. NULL,
  453. KEY_READ,
  454. FUNCTIONSUBKEY_FLAG_IGNORE_NON_CRITICAL_ERRORS,
  455. PnPBiosExamineBiosDeviceKey,
  456. &context
  457. );
  458. ZwClose(baseHandle);
  459. }
  460. return status;
  461. }
  462. BOOLEAN
  463. PnPBiosExamineBiosDeviceKey(
  464. IN HANDLE KeyHandle,
  465. IN PUNICODE_STRING KeyName,
  466. IN OUT PPNP_BIOS_ENUMERATION_CONTEXT Context
  467. )
  468. /*++
  469. Routine Description:
  470. This routine is a callback function for PipApplyFunctionToSubKeys.
  471. It is called for each subkey under HKLM\System\CCS\Enum\BusKey.
  472. Arguments:
  473. KeyHandle - Supplies a handle to this key.
  474. KeyName - Supplies the name of this key.
  475. Context - points to the ROOT_ENUMERATOR_CONTEXT structure.
  476. Returns:
  477. TRUE to continue the enumeration.
  478. FALSE to abort it.
  479. --*/
  480. {
  481. PAGED_CODE();
  482. if (Context->Function != PI_SHUTDOWN_EXAMINE_BIOS_DEVICE ||
  483. KeyName->Buffer[0] == L'*') {
  484. USHORT length;
  485. PWSTR p;
  486. PUNICODE_STRING unicodeName = ((PPNP_BIOS_ENUMERATION_CONTEXT)Context)->KeyName;
  487. length = unicodeName->Length;
  488. p = unicodeName->Buffer;
  489. if ( unicodeName->Length / sizeof(WCHAR) != 0) {
  490. p += unicodeName->Length / sizeof(WCHAR);
  491. *p = OBJ_NAME_PATH_SEPARATOR;
  492. unicodeName->Length += sizeof (WCHAR);
  493. }
  494. RtlAppendStringToString((PSTRING)unicodeName, (PSTRING)KeyName);
  495. //
  496. // Enumerate all subkeys under the current device key.
  497. //
  498. PipApplyFunctionToSubKeys(KeyHandle,
  499. NULL,
  500. KEY_ALL_ACCESS,
  501. FUNCTIONSUBKEY_FLAG_IGNORE_NON_CRITICAL_ERRORS,
  502. PnPBiosExamineBiosDeviceInstanceKey,
  503. Context
  504. );
  505. unicodeName->Length = length;
  506. }
  507. return TRUE;
  508. }
  509. BOOLEAN
  510. PnPBiosExamineBiosDeviceInstanceKey(
  511. IN HANDLE KeyHandle,
  512. IN PUNICODE_STRING KeyName,
  513. IN OUT PPNP_BIOS_ENUMERATION_CONTEXT Context
  514. )
  515. /*++
  516. Routine Description:
  517. This routine is a callback function for PipApplyFunctionToSubKeys.
  518. It is called for each subkey under HKLM\System\Enum\Root\DeviceKey.
  519. Arguments:
  520. KeyHandle - Supplies a handle to this key.
  521. KeyName - Supplies the name of this key.
  522. Context - points to the ROOT_ENUMERATOR_CONTEXT structure.
  523. Returns:
  524. TRUE to continue the enumeration.
  525. FALSE to abort it.
  526. --*/
  527. {
  528. UNICODE_STRING unicodeName;
  529. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  530. NTSTATUS status;
  531. HANDLE handle;
  532. ULONG biosDeviceHandle = ~0ul;
  533. PCM_RESOURCE_LIST config = NULL;
  534. ULONG length, totalLength;
  535. PPNP_BIOS_DEVICE_NODE_LIST deviceNode;
  536. PUCHAR p;
  537. PVOID header, tail;
  538. ULONG headerLength, tailLength ;
  539. PUCHAR biosResources;
  540. BOOLEAN isEnabled ;
  541. UNREFERENCED_PARAMETER( KeyName );
  542. PAGED_CODE();
  543. if (Context->Function == PI_SHUTDOWN_LEGACY_RESOURCES) {
  544. ULONG tmp = 0;
  545. //
  546. // Skip any firmware identified device.
  547. //
  548. status = IopGetRegistryValue (KeyHandle,
  549. L"FirmwareIdentified",
  550. &keyValueInformation);
  551. if (NT_SUCCESS(status)) {
  552. if ((keyValueInformation->Type == REG_DWORD) &&
  553. (keyValueInformation->DataLength == sizeof(ULONG))) {
  554. tmp = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
  555. }
  556. ExFreePool(keyValueInformation);
  557. }
  558. if (tmp != 0) {
  559. return TRUE;
  560. }
  561. //
  562. // Skip any IoReportDetectedDevice and virtual/madeup device.
  563. //
  564. status = IopGetRegistryValue (KeyHandle,
  565. L"Legacy",
  566. &keyValueInformation);
  567. if (NT_SUCCESS(status)) {
  568. ExFreePool(keyValueInformation);
  569. }
  570. if (status != STATUS_OBJECT_NAME_NOT_FOUND) {
  571. return TRUE;
  572. }
  573. //
  574. // Process it.
  575. // Check if the device has BOOT config
  576. //
  577. PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_LOG_CONF);
  578. status = IopOpenRegistryKeyEx( &handle,
  579. KeyHandle,
  580. &unicodeName,
  581. KEY_READ
  582. );
  583. if (NT_SUCCESS(status)) {
  584. status = PipReadDeviceConfiguration (
  585. handle,
  586. REGISTRY_BOOT_CONFIG,
  587. &config,
  588. &length);
  589. ZwClose(handle);
  590. if (NT_SUCCESS(status) && config && length != 0) {
  591. PCM_RESOURCE_LIST list;
  592. list = Context->u.LegacyResources.LegacyResources;
  593. status = IopMergeCmResourceLists(list, config, &Context->u.LegacyResources.LegacyResources);
  594. if (NT_SUCCESS(status) && list) {
  595. ExFreePool(list);
  596. }
  597. ExFreePool(config);
  598. }
  599. }
  600. } else if (Context->Function == PI_SHUTDOWN_EXAMINE_BIOS_DEVICE) {
  601. //
  602. // First check if this key was created by firmware mapper. If yes, make sure
  603. // the device is still present.
  604. //
  605. if (PipIsFirmwareMapperDevicePresent(KeyHandle) == FALSE) {
  606. return TRUE;
  607. }
  608. //
  609. // Make sure this is a pnp bios device by checking its pnp bios
  610. // device handle.
  611. //
  612. if (!PnPBiosGetBiosHandleFromDeviceKey(KeyHandle, &biosDeviceHandle)) {
  613. return TRUE ;
  614. }
  615. //
  616. // Get pointers to the header and tail.
  617. //
  618. // Gross hack warning -
  619. // In the disable case, we need a bios resource template to whack
  620. // to "off". We will index into header to do this, as header and tail
  621. // point directly into the BIOS resource list!
  622. //
  623. status = PnPBiosExtractInfo (
  624. biosDeviceHandle,
  625. Context->u.ExamineBiosDevice.BiosInfo,
  626. Context->u.ExamineBiosDevice.BiosInfoLength,
  627. &header,
  628. &headerLength,
  629. &tail,
  630. &tailLength
  631. );
  632. if (!NT_SUCCESS(status)) {
  633. return TRUE;
  634. }
  635. //
  636. // Has this PnPBIOS device been disabled?
  637. //
  638. // N.B. This check examines flags for the current profile. We actually
  639. // have no clue what profile we will next be booting into, so the UI
  640. // should not show disable in current profile for PnPBIOS devices. A
  641. // work item yet to be done...
  642. //
  643. isEnabled = IopIsDeviceInstanceEnabled(KeyHandle, Context->KeyName, FALSE) ;
  644. if (!isEnabled) {
  645. //
  646. // This device is being disabled. Set up and attain a pointer to
  647. // the appropriately built BIOS resource list.
  648. //
  649. biosResources = ((PUCHAR)header) + sizeof(PNP_BIOS_DEVICE_NODE) ;
  650. PpBiosResourcesSetToDisabled (biosResources, &length);
  651. } else {
  652. //
  653. // Check if the pnp bios device has any assigned ForcedConfig
  654. //
  655. PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_LOG_CONF);
  656. status = IopOpenRegistryKeyEx( &handle,
  657. KeyHandle,
  658. &unicodeName,
  659. KEY_READ
  660. );
  661. if (!NT_SUCCESS(status)) {
  662. return TRUE ;
  663. }
  664. status = PipReadDeviceConfiguration (
  665. handle,
  666. REGISTRY_FORCED_CONFIG,
  667. &config,
  668. &length
  669. );
  670. ZwClose(handle);
  671. if ((!NT_SUCCESS(status)) || (!config) || (length == 0)) {
  672. return TRUE ;
  673. }
  674. status = PpCmResourcesToBiosResources (
  675. config,
  676. tail,
  677. &biosResources,
  678. &length
  679. );
  680. ExFreePool(config);
  681. if (!NT_SUCCESS(status) || !biosResources) {
  682. return TRUE;
  683. }
  684. }
  685. //
  686. // Allocate PNP_BIOS_DEVICE_NODE_LIST structure
  687. //
  688. totalLength = headerLength + length + tailLength;
  689. deviceNode = ExAllocatePool(NonPagedPool, totalLength + sizeof(PVOID));
  690. if (deviceNode) {
  691. deviceNode->Next = *(Context->u.ExamineBiosDevice.DeviceList);
  692. *(Context->u.ExamineBiosDevice.DeviceList) = deviceNode;
  693. p = (PUCHAR)&deviceNode->DeviceNode;
  694. RtlCopyMemory(p, header, headerLength);
  695. p += headerLength;
  696. RtlCopyMemory(p, biosResources, length);
  697. p += length;
  698. RtlCopyMemory(p, tail, tailLength);
  699. deviceNode->DeviceNode.Size = (USHORT)totalLength;
  700. }
  701. if (isEnabled) {
  702. ExFreePool(biosResources);
  703. }
  704. }
  705. return TRUE;
  706. }
  707. NTSTATUS
  708. PnPBiosExtractInfo(
  709. IN ULONG BiosHandle,
  710. IN PVOID BiosInfo,
  711. IN ULONG BiosInfoLength,
  712. OUT PVOID *Header,
  713. OUT ULONG *HeaderLength,
  714. OUT PVOID *Tail,
  715. OUT ULONG *TailLength
  716. )
  717. /*++
  718. Routine Description:
  719. This routine extracts desired information for the specified bios device.
  720. Arguments:
  721. BiosHandle - specifies the bios device.
  722. BiosInfo - The PnP BIOS Installation Check Structure followed by the
  723. DevNode Structures reported by the BIOS. The detailed format is
  724. documented in the PnP BIOS spec.
  725. BiosInfoLength - Length in bytes of the block whose address is stored in
  726. BiosInfo.
  727. Header - specifies a variable to receive the beginning address of the bios
  728. device node structure.
  729. HeaderLength - specifies a variable to receive the length of the bios device
  730. node header.
  731. Tail - specifies a variable to receive the address of the bios device node's
  732. PossibleResourceBlock.
  733. TailLength - specifies a variable to receive the size of the tail.
  734. Return Value:
  735. STATUS_SUCCESS if no errors, otherwise the appropriate error.
  736. --*/
  737. {
  738. PCM_PNP_BIOS_INSTALLATION_CHECK biosInstallCheck;
  739. PCM_PNP_BIOS_DEVICE_NODE devNodeHeader;
  740. NTSTATUS status = STATUS_UNSUCCESSFUL;
  741. PUCHAR currentPtr;
  742. int lengthRemaining;
  743. int remainingNodeLength;
  744. int numNodes;
  745. PUCHAR configPtr;
  746. PAGED_CODE();
  747. #if DBG
  748. //
  749. // Make sure the data is at least large enough to hold the BIOS Installation
  750. // Check structure and check that the PnP signature is correct.
  751. //
  752. if (BiosInfoLength < sizeof(CM_PNP_BIOS_INSTALLATION_CHECK)) {
  753. return STATUS_UNSUCCESSFUL;
  754. }
  755. #endif
  756. biosInstallCheck = (PCM_PNP_BIOS_INSTALLATION_CHECK)BiosInfo;
  757. #if DBG
  758. if (biosInstallCheck->Signature[0] != '$' ||
  759. biosInstallCheck->Signature[1] != 'P' ||
  760. biosInstallCheck->Signature[2] != 'n' ||
  761. biosInstallCheck->Signature[3] != 'P') {
  762. return STATUS_UNSUCCESSFUL;
  763. }
  764. #endif
  765. //
  766. //
  767. //
  768. //
  769. currentPtr = (PUCHAR)BiosInfo + biosInstallCheck->Length;
  770. lengthRemaining = BiosInfoLength - biosInstallCheck->Length;
  771. for (numNodes = 0; lengthRemaining > sizeof(CM_PNP_BIOS_DEVICE_NODE); numNodes++) {
  772. devNodeHeader = (PCM_PNP_BIOS_DEVICE_NODE)currentPtr;
  773. if (devNodeHeader->Size > lengthRemaining) {
  774. IopDbgPrint((IOP_PNPBIOS_WARNING_LEVEL,
  775. "Node # %d, invalid size (%d), length remaining (%d)\n",
  776. devNodeHeader->Node,
  777. devNodeHeader->Size,
  778. lengthRemaining));
  779. return STATUS_UNSUCCESSFUL;
  780. }
  781. if (devNodeHeader->Node == BiosHandle) {
  782. *Header = devNodeHeader;
  783. *HeaderLength = sizeof(CM_PNP_BIOS_DEVICE_NODE);
  784. configPtr = currentPtr + sizeof(*devNodeHeader);
  785. remainingNodeLength = devNodeHeader->Size - sizeof(*devNodeHeader) - 1;
  786. while (*configPtr != TAG_COMPLETE_END && remainingNodeLength) {
  787. configPtr++;
  788. remainingNodeLength--;
  789. }
  790. if (*configPtr == TAG_COMPLETE_END && remainingNodeLength) {
  791. configPtr += 2;
  792. remainingNodeLength--;
  793. }
  794. *Tail = configPtr;
  795. *TailLength = remainingNodeLength;
  796. status = STATUS_SUCCESS;
  797. break;
  798. }
  799. currentPtr += devNodeHeader->Size;
  800. lengthRemaining -= devNodeHeader->Size;
  801. }
  802. return status;
  803. }
  804. NTSTATUS
  805. PnPBiosInitializePnPBios (
  806. VOID
  807. )
  808. /*++
  809. Routine Description:
  810. This routine setup selectors to invoke Pnp BIOS.
  811. Arguments:
  812. None.
  813. Return Value:
  814. A NTSTATUS code to indicate the result of the initialization.
  815. --*/
  816. {
  817. KGDTENTRY gdtEntry;
  818. ULONG codeBase, i;
  819. NTSTATUS status;
  820. USHORT selectors[4];
  821. PHYSICAL_ADDRESS physicalAddr;
  822. PVOID virtualAddr;
  823. PVOID biosData;
  824. ULONG biosDataLength;
  825. //
  826. // Initialize BIOS call spinlock
  827. //
  828. KeInitializeSpinLock (&PbBiosSpinlock);
  829. //
  830. // Grab the PnPBIOS settings stored in the registry by NTDetect
  831. //
  832. status = PnPBiosGetBiosInfo(&biosData, &biosDataLength);
  833. if (!NT_SUCCESS(status)) {
  834. PbBiosInitialized = status ;
  835. return status ;
  836. }
  837. //
  838. // Call pnp bios from boot processor
  839. //
  840. KeSetSystemAffinityThread(1);
  841. //
  842. // Initialize stack segment
  843. //
  844. KiStack16GdtEntry = KiAbiosGetGdt() + KGDT_STACK16;
  845. KiInitializeAbiosGdtEntry(
  846. (PKGDTENTRY)KiStack16GdtEntry,
  847. 0L,
  848. 0xffff,
  849. TYPE_DATA
  850. );
  851. //
  852. // Allocate 4 selectors for calling PnP Bios APIs.
  853. //
  854. i = 4;
  855. status = KeI386AllocateGdtSelectors (selectors, (USHORT) i);
  856. if (!NT_SUCCESS(status)) {
  857. IopDbgPrint((IOP_PNPBIOS_WARNING_LEVEL,
  858. "PnpBios: Failed to allocate selectors to call PnP BIOS at shutdown.\n"));
  859. goto PnpBiosInitExit ;
  860. }
  861. PbBiosCodeSelector = selectors[0];
  862. PbBiosDataSelector = selectors[1];
  863. PbSelectors[0] = selectors[2];
  864. PbSelectors[1] = selectors[3];
  865. PbBiosEntryPoint = (ULONG)
  866. ((PPNP_BIOS_INSTALLATION_CHECK)biosData)->ProtectedModeEntryOffset;
  867. //
  868. // Initialize selectors to use PNP bios code
  869. //
  870. //
  871. // initialize 16 bit code selector
  872. //
  873. gdtEntry.LimitLow = 0xFFFF;
  874. gdtEntry.HighWord.Bytes.Flags1 = 0;
  875. gdtEntry.HighWord.Bytes.Flags2 = 0;
  876. gdtEntry.HighWord.Bits.Pres = 1;
  877. gdtEntry.HighWord.Bits.Dpl = DPL_SYSTEM;
  878. gdtEntry.HighWord.Bits.Granularity = GRAN_BYTE;
  879. gdtEntry.HighWord.Bits.Type = 31;
  880. gdtEntry.HighWord.Bits.Default_Big = 0;
  881. physicalAddr.HighPart = 0;
  882. physicalAddr.LowPart =
  883. ((PPNP_BIOS_INSTALLATION_CHECK)biosData)->ProtectedModeCodeBaseAddress;
  884. virtualAddr = MmMapIoSpace (physicalAddr, 0x10000, TRUE);
  885. codeBase = (ULONG)virtualAddr;
  886. gdtEntry.BaseLow = (USHORT) (codeBase & 0xffff);
  887. gdtEntry.HighWord.Bits.BaseMid = (UCHAR) (codeBase >> 16) & 0xff;
  888. gdtEntry.HighWord.Bits.BaseHi = (UCHAR) (codeBase >> 24) & 0xff;
  889. KeI386SetGdtSelector (PbBiosCodeSelector, &gdtEntry);
  890. //
  891. // initialize 16 bit data selector for Pnp BIOS
  892. //
  893. gdtEntry.LimitLow = 0xFFFF;
  894. gdtEntry.HighWord.Bytes.Flags1 = 0;
  895. gdtEntry.HighWord.Bytes.Flags2 = 0;
  896. gdtEntry.HighWord.Bits.Pres = 1;
  897. gdtEntry.HighWord.Bits.Dpl = DPL_SYSTEM;
  898. gdtEntry.HighWord.Bits.Granularity = GRAN_BYTE;
  899. gdtEntry.HighWord.Bits.Type = 19;
  900. gdtEntry.HighWord.Bits.Default_Big = 1;
  901. physicalAddr.LowPart =
  902. ((PPNP_BIOS_INSTALLATION_CHECK)biosData)->ProtectedModeDataBaseAddress;
  903. virtualAddr = MmMapIoSpace (physicalAddr, 0x10000, TRUE);
  904. codeBase = (ULONG)virtualAddr;
  905. gdtEntry.BaseLow = (USHORT) (codeBase & 0xffff);
  906. gdtEntry.HighWord.Bits.BaseMid = (UCHAR) (codeBase >> 16) & 0xff;
  907. gdtEntry.HighWord.Bits.BaseHi = (UCHAR) (codeBase >> 24) & 0xff;
  908. KeI386SetGdtSelector (PbBiosDataSelector, &gdtEntry);
  909. //
  910. // Initialize the other two general purpose data selector such that
  911. // on subsequent init we only need to init the base addr.
  912. //
  913. KeI386SetGdtSelector (PbSelectors[0], &gdtEntry);
  914. KeI386SetGdtSelector (PbSelectors[1], &gdtEntry);
  915. //
  916. // Locked in code for Pnp BIOS shutdown processing.
  917. //
  918. status = STATUS_SUCCESS;
  919. PnpBiosInitExit:
  920. //
  921. // We don't need this data anymore, free it.
  922. //
  923. ExFreePool(biosData);
  924. //
  925. // Restore old affinity for current thread.
  926. //
  927. KeRevertToUserAffinityThread();
  928. PbBiosInitialized = status ;
  929. return status;
  930. }
  931. VOID
  932. PnPBiosSetDeviceNodes (
  933. IN PVOID Context
  934. )
  935. /*++
  936. Routine Description:
  937. This function sets the caller specified resource to pnp bios slot/device
  938. data.
  939. Arguments:
  940. Context - specifies a list of Pnp bios device to be set.
  941. Return Value:
  942. NTSTATUS code
  943. --*/
  944. {
  945. PB_PARAMETERS biosParameters;
  946. PPNP_BIOS_DEVICE_NODE_LIST deviceList = (PPNP_BIOS_DEVICE_NODE_LIST)Context;
  947. PPNP_BIOS_DEVICE_NODE deviceNode;
  948. while (deviceList) {
  949. deviceNode = &deviceList->DeviceNode;
  950. //
  951. // call Pnp Bios to set the resources
  952. //
  953. biosParameters.Function = PNP_BIOS_SET_DEVICE_NODE;
  954. biosParameters.u.SetDeviceNode.Node = deviceNode->Node;
  955. biosParameters.u.SetDeviceNode.NodeBuffer = deviceNode;
  956. biosParameters.u.SetDeviceNode.Control = SET_CONFIGURATION_FOR_NEXT_BOOT;
  957. PbHardwareService (&biosParameters); // Ignore the return status
  958. deviceList = deviceList->Next;
  959. }
  960. }
  961. NTSTATUS
  962. PnPBiosSetDeviceNodeDynamically(
  963. IN PDEVICE_OBJECT DeviceObject
  964. )
  965. {
  966. PNP_BIOS_ENUMERATION_CONTEXT context;
  967. NTSTATUS status;
  968. PDEVICE_NODE deviceNode ;
  969. PVOID biosInfo = NULL ;
  970. ULONG length;
  971. HANDLE handle;
  972. PPNP_BIOS_DEVICE_NODE_LIST deviceList = NULL ;
  973. PB_PARAMETERS biosParameters;
  974. PPNP_BIOS_DEVICE_NODE biosDevNode;
  975. //
  976. // First. get a handle to the device
  977. //
  978. status = IopDeviceObjectToDeviceInstance(DeviceObject, &handle, KEY_READ);
  979. if (!NT_SUCCESS(status)) {
  980. return status;
  981. }
  982. //
  983. // Yuck, to see if it is a PnPBIOS device, let us verify the ID starts with
  984. // the '*'. To do so, we need to see the device ID. Luckily, if the above
  985. // call succeeded, so should this...
  986. //
  987. deviceNode = (PDEVICE_NODE) DeviceObject->DeviceObjectExtension->DeviceNode;
  988. status = STATUS_NO_SUCH_DEVICE ;
  989. if (!deviceNode) {
  990. goto SetDynaExit ;
  991. }
  992. if (deviceNode->InstancePath.Length == 0) {
  993. goto SetDynaExit ;
  994. }
  995. if (deviceNode->InstancePath.Buffer[0] != L'*') {
  996. goto SetDynaExit ;
  997. }
  998. //
  999. // Now get the BIOS data
  1000. //
  1001. status = PnPBiosGetBiosInfo(&biosInfo, &length);
  1002. if (!NT_SUCCESS( status )) {
  1003. goto SetDynaExit ;
  1004. }
  1005. //
  1006. // Fake the call we do during shutdown, as we want the BIOS data for this
  1007. // device if present
  1008. //
  1009. context.Function = PI_SHUTDOWN_EXAMINE_BIOS_DEVICE;
  1010. context.u.ExamineBiosDevice.BiosInfo = biosInfo;
  1011. context.u.ExamineBiosDevice.BiosInfoLength = length;
  1012. context.u.ExamineBiosDevice.DeviceList = &deviceList;
  1013. PnPBiosExamineBiosDeviceInstanceKey(handle, &deviceNode->InstancePath, &context) ;
  1014. if (!deviceList) {
  1015. status = STATUS_UNSUCCESSFUL ;
  1016. goto SetDynaExit ;
  1017. }
  1018. //
  1019. // Call pnp bios from boot processor
  1020. //
  1021. KeSetSystemAffinityThread(1);
  1022. biosDevNode = &deviceList->DeviceNode;
  1023. if (PipIsDevNodeProblem(deviceNode, CM_PROB_DISABLED)) {
  1024. PpBiosResourcesSetToDisabled (((PUCHAR)biosDevNode) + sizeof(PNP_BIOS_DEVICE_NODE), &length);
  1025. }
  1026. //
  1027. // call Pnp Bios to set the resources
  1028. //
  1029. biosParameters.Function = PNP_BIOS_SET_DEVICE_NODE;
  1030. biosParameters.u.SetDeviceNode.Node = biosDevNode->Node;
  1031. biosParameters.u.SetDeviceNode.NodeBuffer = biosDevNode;
  1032. biosParameters.u.SetDeviceNode.Control = SET_CONFIGURATION_NOW ;
  1033. status = PbHardwareService (&biosParameters);
  1034. //
  1035. // Restore old affinity for current thread.
  1036. //
  1037. KeRevertToUserAffinityThread();
  1038. SetDynaExit:
  1039. if (biosInfo) {
  1040. ExFreePool(biosInfo) ;
  1041. }
  1042. ZwClose(handle);
  1043. return status ;
  1044. }
  1045. VOID
  1046. PnPBiosReserveLegacyDeviceResources (
  1047. IN PUCHAR biosResources
  1048. )
  1049. /*++
  1050. Routine Description:
  1051. Arguments:
  1052. ReturnedResources - supplies a pointer to a variable to receive legacy resources.
  1053. Return Value:
  1054. None.
  1055. --*/
  1056. {
  1057. PB_PARAMETERS biosParameters;
  1058. //
  1059. // call Pnp Bios to reserve the resources
  1060. //
  1061. biosParameters.Function = PNP_BIOS_SET_OLD_ISA_RESOURCES;
  1062. biosParameters.u.SetAllocatedResources.Resources = biosResources;
  1063. PbHardwareService (&biosParameters); // Ignore the return status
  1064. }
  1065. NTSTATUS
  1066. PbHardwareService (
  1067. IN PPB_PARAMETERS Parameters
  1068. )
  1069. /*++
  1070. Routine Description:
  1071. This routine sets up stack parameters and calls an
  1072. assembly worker routine to actually invoke the PNP BIOS code.
  1073. Arguments:
  1074. Parameters - supplies a pointer to the parameter block.
  1075. Return Value:
  1076. An NTSTATUS code to indicate the result of the operation.
  1077. --*/
  1078. {
  1079. NTSTATUS status ;
  1080. USHORT stackParameters[PB_MAXIMUM_STACK_SIZE / 2];
  1081. ULONG i = 0;
  1082. USHORT retCode;
  1083. KIRQL oldIrql;
  1084. //
  1085. // Did we initialize correctly?
  1086. //
  1087. status = PbBiosInitialized ;
  1088. if (!NT_SUCCESS(status)) {
  1089. return status ;
  1090. }
  1091. //
  1092. // Convert and copy the caller's parameters to the format that
  1093. // will be used to invoked pnp bios.
  1094. //
  1095. stackParameters[i] = Parameters->Function;
  1096. i++;
  1097. switch (Parameters->Function) {
  1098. case PNP_BIOS_SET_DEVICE_NODE:
  1099. stackParameters[i++] = Parameters->u.SetDeviceNode.Node;
  1100. PbAddress32ToAddress16(Parameters->u.SetDeviceNode.NodeBuffer,
  1101. &stackParameters[i],
  1102. PbSelectors[0]);
  1103. i += 2;
  1104. stackParameters[i++] = Parameters->u.SetDeviceNode.Control;
  1105. stackParameters[i++] = PbBiosDataSelector;
  1106. break;
  1107. case PNP_BIOS_SET_OLD_ISA_RESOURCES:
  1108. PbAddress32ToAddress16(Parameters->u.SetAllocatedResources.Resources,
  1109. &stackParameters[i],
  1110. PbSelectors[0]);
  1111. i += 2;
  1112. stackParameters[i++] = PbBiosDataSelector;
  1113. break;
  1114. default:
  1115. return STATUS_NOT_IMPLEMENTED;
  1116. }
  1117. MmLockPagableSectionByHandle(ExPageLockHandle);
  1118. //
  1119. // Copy the parameters to stack and invoke Pnp Bios.
  1120. //
  1121. ExAcquireSpinLock (&PbBiosSpinlock, &oldIrql);
  1122. retCode = PbCallPnpBiosWorker (
  1123. PbBiosEntryPoint,
  1124. PbBiosCodeSelector,
  1125. stackParameters,
  1126. (USHORT)(i * sizeof(USHORT)));
  1127. ExReleaseSpinLock (&PbBiosSpinlock, oldIrql);
  1128. MmUnlockPagableImageSection(ExPageLockHandle);
  1129. //
  1130. // Map Bios returned code to nt status code.
  1131. //
  1132. if (retCode == 0) {
  1133. return STATUS_SUCCESS;
  1134. } else {
  1135. IopDbgPrint((IOP_PNPBIOS_WARNING_LEVEL,
  1136. "PnpBios: Bios API call failed. Returned Code = %x\n", retCode));
  1137. return STATUS_UNSUCCESSFUL;
  1138. }
  1139. }
  1140. VOID
  1141. PbAddress32ToAddress16 (
  1142. IN PVOID Address32,
  1143. IN PUSHORT Address16,
  1144. IN USHORT Selector
  1145. )
  1146. /*++
  1147. Routine Description:
  1148. This routine converts the 32 bit address to 16 bit selector:offset address
  1149. and stored in user specified location.
  1150. Arguments:
  1151. Address32 - the 32 bit address to be converted.
  1152. Address16 - supplies the location to receive the 16 bit sel:offset address
  1153. Selector - the 16 bit selector for seg:offset address
  1154. Return Value:
  1155. None.
  1156. --*/
  1157. {
  1158. KGDTENTRY gdtEntry;
  1159. ULONG baseAddr;
  1160. //
  1161. // Map virtual address to selector:0 address
  1162. //
  1163. gdtEntry.LimitLow = 0xFFFF;
  1164. gdtEntry.HighWord.Bytes.Flags1 = 0;
  1165. gdtEntry.HighWord.Bytes.Flags2 = 0;
  1166. gdtEntry.HighWord.Bits.Pres = 1;
  1167. gdtEntry.HighWord.Bits.Dpl = DPL_SYSTEM;
  1168. gdtEntry.HighWord.Bits.Granularity = GRAN_BYTE;
  1169. gdtEntry.HighWord.Bits.Type = 19;
  1170. gdtEntry.HighWord.Bits.Default_Big = 1;
  1171. baseAddr = (ULONG)Address32;
  1172. gdtEntry.BaseLow = (USHORT) (baseAddr & 0xffff);
  1173. gdtEntry.HighWord.Bits.BaseMid = (UCHAR) (baseAddr >> 16) & 0xff;
  1174. gdtEntry.HighWord.Bits.BaseHi = (UCHAR) (baseAddr >> 24) & 0xff;
  1175. KeI386SetGdtSelector (Selector, &gdtEntry);
  1176. *Address16 = 0;
  1177. *(Address16 + 1) = Selector;
  1178. }