Leaked source code of windows server 2003
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.

1396 lines
39 KiB

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