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.

965 lines
24 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. main.c
  5. Abstract:
  6. Main for the SU (startup) module for the OS loader. The SU module
  7. must take the x86 from a real-mode 16bit state to a FLAT model,
  8. 32bit protect/paging enabled state.
  9. Author:
  10. Thomas Parslow (tomp) Created 20-Dec-90
  11. Revision History:
  12. --*/
  13. int _acrtused = 0;
  14. #define NTAPI
  15. #include "su.h"
  16. #include "eisa.h"
  17. #define _SYS_GUID_OPERATORS_
  18. #include <guiddef.h>
  19. // Prevent ntimage.h from defining the COM+ IL structs and enums. The enum
  20. // has a value > 16 bits so the 16-bit build fails. The startrom code doesn't
  21. // need to know about COM+ IL.
  22. #define __IMAGE_COR20_HEADER_DEFINED__
  23. #include "ntimage.h"
  24. #include "strings.h"
  25. #include "pxe_cmn.h"
  26. #include "pxe_api.h"
  27. #include "undi_api.h"
  28. #include <sdistructs.h>
  29. extern VOID RealMode(VOID);
  30. extern USHORT IDTregisterZero;
  31. extern IMAGE_DOS_HEADER edata;
  32. extern VOID MoveMemory(ULONG,ULONG,ULONG);
  33. extern USHORT SuStackBegin;
  34. extern UCHAR Beginx86Relocation;
  35. extern UCHAR Endx86Relocation;
  36. extern USHORT BackEnd;
  37. extern ULONG FileStart;
  38. extern BOOLEAN IsNpxPresent(VOID);
  39. extern USHORT HwGetProcessorType(VOID);
  40. extern USHORT HwGetCpuStepping(USHORT);
  41. extern ULONG MachineType;
  42. extern ULONG OsLoaderStart;
  43. extern ULONG OsLoaderEnd;
  44. extern ULONG ResourceDirectory;
  45. extern ULONG ResourceOffset;
  46. extern ULONG OsLoaderBase;
  47. extern ULONG OsLoaderExports;
  48. extern ULONG NetPcRomEntry;
  49. extern ULONG BootFlags;
  50. extern ULONG NtDetectStart;
  51. extern ULONG NtDetectEnd;
  52. extern ULONG SdiAddress;
  53. extern
  54. TurnMotorOff(
  55. VOID
  56. );
  57. extern
  58. EnableA20(
  59. VOID
  60. );
  61. extern
  62. BOOLEAN
  63. ConstructMemoryDescriptors(
  64. VOID
  65. );
  66. extern
  67. USHORT
  68. IsaConstructMemoryDescriptors(
  69. VOID
  70. );
  71. VOID
  72. Relocatex86Structures(
  73. VOID
  74. );
  75. ULONG
  76. RelocateLoaderSections(
  77. OUT PULONG Start,
  78. OUT PULONG End
  79. );
  80. t_PXENV_ENTRY far *
  81. PxenvGetEntry(
  82. VOID
  83. );
  84. BOOLEAN
  85. PxenvVerifyEntry(
  86. t_PXENV_ENTRY far *entry
  87. );
  88. extern UINT16
  89. PxenvApiCall(
  90. UINT16 service,
  91. void far *param
  92. );
  93. BOOLEAN
  94. PxenvTftp(
  95. );
  96. VOID
  97. Reboot(
  98. VOID
  99. );
  100. VOID
  101. Wait(
  102. IN ULONG WaitTime
  103. );
  104. ULONG
  105. GetTickCount(
  106. VOID
  107. );
  108. extern
  109. FSCONTEXT_RECORD
  110. FsContext;
  111. #define REVISION_NUMBER "1.1"
  112. #define DISK_TABLE_VECTOR (0x1e*4)
  113. VOID
  114. SuMain(
  115. IN ULONG BtBootDrive
  116. )
  117. /*++
  118. Routine Description:
  119. Main entrypoint of the SU module. Control is passed from the boot
  120. sector to startup.asm which does some run-time fixups on the stack
  121. and data segments and then passes control here.
  122. Arguments:
  123. BtBootDrive - The low byte contains the drive that we booted from (int13
  124. unit number). If 0x41, this is an SDI boot, and the upper three bytes
  125. of BtBootDrive contain the upper three bytes of the physical address
  126. of the SDI image (which must be page aligned)
  127. Returns:
  128. Does not return. Passes control to the OS loader
  129. --*/
  130. {
  131. ULONG LoaderEntryPoint;
  132. ULONG EisaNumPages;
  133. USHORT IsaNumPages;
  134. MEMORY_LIST_ENTRY _far *CurrentEntry;
  135. IMAGE_OPTIONAL_HEADER far *OptionalHeader;
  136. ULONG BlockEnd;
  137. ULONG ImageSize;
  138. ULONG ImageBase;
  139. UCHAR bootDrive;
  140. //
  141. // Get the boot drive out of the input argument. If this is an SDI boot,
  142. // store the SDI address in the boot context record.
  143. //
  144. bootDrive = (UCHAR)BtBootDrive;
  145. if ( bootDrive == 0x41 ) {
  146. SdiAddress = BtBootDrive & ~(PAGE_SIZE - 1);
  147. }
  148. //
  149. // Save fs context info
  150. //
  151. FsContext.BootDrive = bootDrive;
  152. //
  153. // Set the NTLDR boot flags that are passed in the BootContext.
  154. //
  155. #ifdef DEFAULT_BOOTFLAGS
  156. BootFlags = DEFAULT_BOOTFLAGS;
  157. #endif
  158. //
  159. // Initialize the video subsystem first so that
  160. // errors end exceptions can be displayed.
  161. //
  162. InitializeVideoSubSystem();
  163. //
  164. // In case we booted from a floppy, turn the drive motor off.
  165. //
  166. TurnMotorOff();
  167. //
  168. // Set up machine type based on its Bus type.
  169. //
  170. if (BtIsEisaSystem()) {
  171. MachineType = MACHINE_TYPE_EISA;
  172. } else {
  173. MachineType = MACHINE_TYPE_ISA;
  174. }
  175. if (!ConstructMemoryDescriptors()) {
  176. //
  177. // If INT 15 E802h fails...
  178. //
  179. if (MachineType == MACHINE_TYPE_EISA) {
  180. //
  181. // HACKHACK John Vert (jvert)
  182. // This is completely bogus. Since there are a number of EISA
  183. // machines which do not let you correctly configure the EISA
  184. // NVRAM, and even MORE machines which are improperly configured,
  185. // we first check to see how much memory the ISA routines say
  186. // exists. Then we check what the EISA routines tell us, and
  187. // compare the two. If the EISA number is much lower (where "much"
  188. // is a completely random fudge factor) than the ISA number, we
  189. // assume the machine is improperly configured and we throw away
  190. // the EISA numbers and use the ISA ones. If not, we assume that
  191. // the machine is actually configured properly and we trust the
  192. // EISA numbers..
  193. //
  194. IsaNumPages = IsaConstructMemoryDescriptors();
  195. EisaNumPages = EisaConstructMemoryDescriptors();
  196. if (EisaNumPages + 0x80 < IsaNumPages) {
  197. IsaConstructMemoryDescriptors();
  198. }
  199. } else {
  200. IsaConstructMemoryDescriptors();
  201. }
  202. }
  203. //
  204. // Search for memory descriptor describing low memory
  205. //
  206. CurrentEntry = MemoryDescriptorList;
  207. while ((CurrentEntry->BlockBase != 0) &&
  208. (CurrentEntry->BlockSize != 0)) {
  209. CurrentEntry++;
  210. }
  211. if ((CurrentEntry->BlockBase == 0) &&
  212. (CurrentEntry->BlockSize < (ULONG)512 * (ULONG)1024)) {
  213. BlPrint(SU_NO_LOW_MEMORY,CurrentEntry->BlockSize/1024);
  214. goto StartFailed;
  215. }
  216. //
  217. // Is this a network boot?
  218. //
  219. if (bootDrive == 0x40) {
  220. t_PXENV_ENTRY far *entry;
  221. //
  222. // Get the address of the NetPC ROM entry point.
  223. //
  224. entry = PxenvGetEntry( );
  225. if ( PxenvVerifyEntry(entry) != 0 ) {
  226. BlPrint( "\nUnable to verify NetPC ROM entry point.\n" );
  227. goto StartFailed;
  228. }
  229. FP_SEG(NetPcRomEntry) = entry->rm_entry_seg;
  230. FP_OFF(NetPcRomEntry) = entry->rm_entry_off;
  231. #if 0
  232. //
  233. // Disable broadcast reception.
  234. //
  235. // chuckl: Don't do this. We added it to solve a problem with DEC cards
  236. // and the boot floppy, but we need to have broadcasts enabled in case
  237. // the server needs to ARP us. We tried enabling/disabling broadcasts
  238. // during the receive loop, but that seems to put Compaq cards to sleep.
  239. // So we need to leave broadcasts enabled. The DEC card problem will
  240. // have to be fixed another way.
  241. //
  242. {
  243. t_PXENV_UNDI_SET_PACKET_FILTER UndiSetPF;
  244. UndiSetPF.Status = 0;
  245. UndiSetPF.filter = FLTR_DIRECTED;
  246. if (PxenvApiCall(PXENV_UNDI_SET_PACKET_FILTER, &UndiSetPF) != PXENV_EXIT_SUCCESS) {
  247. BlPrint("\nSet packet filter failed.\n");
  248. goto StartFailed;
  249. }
  250. }
  251. #endif
  252. if ( PxenvTftp() ) {
  253. BlPrint("\nTFTP download failed.\n");
  254. goto StartFailed;
  255. }
  256. }
  257. //
  258. // Enable the A20 line for protect mode
  259. //
  260. EnableA20();
  261. //
  262. // Relocate x86 structures. This includes the GDT, IDT,
  263. // page directory, and first level page table.
  264. //
  265. Relocatex86Structures();
  266. //
  267. // Enable protect and paging modes for the first time
  268. //
  269. EnableProtectPaging(ENABLING);
  270. //
  271. // If this is an SDI boot, copy the OS loader from the SDI image to 0x100000.
  272. //
  273. if ( bootDrive == 0x41 ) {
  274. int i;
  275. ULONG osloaderOffset;
  276. ULONG osloaderLength;
  277. SDI_HEADER *sdiHeader;
  278. UCHAR *sig1;
  279. UCHAR *sig2;
  280. //
  281. // In the code below, edata is a near pointer to the end of
  282. // startrom.com. Since we are using 16-bit selectors here,
  283. // edata is the only thing we can directly reference. FileStart
  284. // is a 32-bit linear pointer to edata. MoveMemory() uses this
  285. // pointer.
  286. //
  287. // First, copy the SDI header to edata so that we can look at it.
  288. // Verify that it's really an SDI image.
  289. //
  290. MoveMemory(SdiAddress,
  291. FileStart,
  292. sizeof(SDI_HEADER));
  293. //
  294. // Verify that the SDI header looks right by checking the signature.
  295. //
  296. sdiHeader = (SDI_HEADER *)&edata;
  297. sig1 = sdiHeader->Signature;
  298. sig2 = SDI_SIGNATURE;
  299. for ( i = 0; i < SDI_SIZEOF_SIGNATURE; i++ ) {
  300. if ( *sig1++ != *sig2++ ) {
  301. BlPrint("\nSDI image format corrupt.\n");
  302. goto StartFailed;
  303. }
  304. }
  305. //
  306. // Scan the TOC looking for a LOAD entry.
  307. //
  308. for ( i = 0; i < SDI_TOCMAXENTRIES; i++ ) {
  309. if ( sdiHeader->ToC[i].dwType == SDI_BLOBTYPE_LOAD ) {
  310. break;
  311. }
  312. }
  313. if ( i >= SDI_TOCMAXENTRIES ) {
  314. BlPrint("\nSDI image missing LOAD entry.\n");
  315. goto StartFailed;
  316. }
  317. //
  318. // Copy the loader to 0x100000.
  319. //
  320. osloaderOffset = (ULONG)sdiHeader->ToC[i].llOffset.LowPart;
  321. osloaderLength = (ULONG)sdiHeader->ToC[i].llSize.LowPart;
  322. MoveMemory(SdiAddress + osloaderOffset,
  323. (ULONG)0x100000,
  324. osloaderLength);
  325. }
  326. //
  327. // If this is a network boot or an SDI boot, copy the section headers from
  328. // the loader image (at 0x100000) down into low memory (at &edata).
  329. //
  330. if ((bootDrive == 0x40) || (bootDrive == 0x41)) {
  331. //
  332. // This is a tricky bit of code. The only pointer that can be dereferenced
  333. // is edata. edata is the near pointer which can be used here. FileStart is
  334. // the far pointer which must be passed to MoveMemory.
  335. //
  336. IMAGE_DOS_HEADER far *src = (IMAGE_DOS_HEADER far*)0x100000;
  337. IMAGE_DOS_HEADER far *dst = (IMAGE_DOS_HEADER far*)FileStart;
  338. //
  339. // Copy the fixed part of the header so we can find the start of the optional
  340. // header.
  341. //
  342. MoveMemory((ULONG)src,
  343. (ULONG)dst,
  344. sizeof(IMAGE_DOS_HEADER));
  345. //
  346. // Copy the optional header so we can find the size of all the headers
  347. //
  348. OptionalHeader = &((IMAGE_NT_HEADERS far *) ((UCHAR far *) src + edata.e_lfanew))->OptionalHeader;
  349. MoveMemory((ULONG)OptionalHeader,
  350. (ULONG)&((IMAGE_NT_HEADERS far *) ((UCHAR far *) dst + edata.e_lfanew))->OptionalHeader,
  351. sizeof(IMAGE_OPTIONAL_HEADER));
  352. //
  353. // Now we know the size of all the headers, so just recopy the entire first chunk
  354. // that contains all the headers.
  355. ///
  356. MoveMemory((ULONG)src,
  357. (ULONG)dst,
  358. ((PIMAGE_NT_HEADERS)((PUCHAR)&edata + edata.e_lfanew))->OptionalHeader.SizeOfHeaders);
  359. FileStart = (ULONG)src;
  360. }
  361. //
  362. // Ensure there is a memory descriptor to contain osloader image
  363. //
  364. OptionalHeader = &((PIMAGE_NT_HEADERS) ((PUCHAR) &edata + edata.e_lfanew))->OptionalHeader;
  365. ImageBase = OptionalHeader->ImageBase;
  366. ImageSize = OptionalHeader->SizeOfImage;
  367. OsLoaderBase = ImageBase;
  368. OsLoaderExports = ImageBase + OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
  369. CurrentEntry = MemoryDescriptorList;
  370. while (ImageSize > 0) {
  371. while (CurrentEntry->BlockSize != 0) {
  372. BlockEnd = CurrentEntry->BlockBase + CurrentEntry->BlockSize;
  373. if ((CurrentEntry->BlockBase <= ImageBase) &&
  374. (BlockEnd > ImageBase)) {
  375. //
  376. // this descriptor at least partially contains a chunk
  377. // of the osloader.
  378. //
  379. if (BlockEnd-ImageBase > ImageSize) {
  380. ImageSize = 0;
  381. } else {
  382. ImageSize -= (BlockEnd-ImageBase);
  383. ImageBase = BlockEnd;
  384. }
  385. //
  386. // look for remaining part (if any) of osloader
  387. //
  388. CurrentEntry = MemoryDescriptorList;
  389. break;
  390. }
  391. CurrentEntry++;
  392. }
  393. if (CurrentEntry->BlockSize == 0) {
  394. break;
  395. }
  396. }
  397. if (ImageSize > 0) {
  398. //
  399. // We could not relocate the osloader to high memory. Error out
  400. // and display the memory map.
  401. //
  402. BlPrint(SU_NO_EXTENDED_MEMORY);
  403. CurrentEntry = MemoryDescriptorList;
  404. while (CurrentEntry->BlockSize != 0) {
  405. BlPrint(" %lx - %lx\n",
  406. CurrentEntry->BlockBase,
  407. CurrentEntry->BlockBase + CurrentEntry->BlockSize);
  408. CurrentEntry++;
  409. }
  410. goto StartFailed;
  411. }
  412. //
  413. // Go relocate loader sections and build page table entries
  414. //
  415. LoaderEntryPoint = RelocateLoaderSections(&OsLoaderStart, &OsLoaderEnd);
  416. //
  417. // Search for memory descriptor containing the osloader and
  418. // change it.
  419. //
  420. //
  421. // Transfer control to the OS loader
  422. //
  423. TransferToLoader(LoaderEntryPoint);
  424. StartFailed:
  425. if (BootFlags & 1) { // BOOTFLAG_REBOOT_ON_FAILURE == 1 from bldr.h
  426. ULONG WaitTime = 5;
  427. BlPrint("\nRebooting in %d seconds...\n", WaitTime);
  428. Wait(WaitTime);
  429. Reboot();
  430. }
  431. WAITFOREVER
  432. }
  433. ULONG
  434. RelocateLoaderSections(
  435. OUT PULONG Start,
  436. OUT PULONG End
  437. )
  438. /*++
  439. Routine Description:
  440. The SU module is prepended to the OS loader file. The OS loader file
  441. is a coff++ file. This routine computes the beginning of the OS loader
  442. file, then relocates the OS loader's sections as if it were just
  443. loading the file from disk file.
  444. Arguments:
  445. Start - Returns the address of the start of the image
  446. End - Returns the address of the end of the image
  447. Returns:
  448. Entry point of loader
  449. --*/
  450. {
  451. USHORT Section;
  452. ULONG Source,Destination;
  453. ULONG VirtualSize;
  454. ULONG SizeOfRawData;
  455. PIMAGE_FILE_HEADER FileHeader;
  456. PIMAGE_OPTIONAL_HEADER OptionalHeader;
  457. PIMAGE_SECTION_HEADER SectionHeader;
  458. //
  459. // Make a pointer to the beginning of the loader's coff header
  460. //
  461. FileHeader = &((PIMAGE_NT_HEADERS) ((PUCHAR) &edata + edata.e_lfanew))->FileHeader;
  462. //
  463. // Validate the appended loader image by checking signatures.
  464. // 1st - is it an executable image?
  465. // 2nd - is the target environment the 386?
  466. //
  467. if ((FileHeader->Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 0) {
  468. puts(SU_NTLDR_CORRUPT);
  469. WAITFOREVER;
  470. }
  471. if (FileHeader->Machine != IMAGE_FILE_MACHINE_I386) {
  472. puts(SU_NTLDR_CORRUPT);
  473. WAITFOREVER;
  474. }
  475. //
  476. // Make a pointer to the optional header in the header-buffer
  477. //
  478. OptionalHeader = (PIMAGE_OPTIONAL_HEADER)((PUCHAR)FileHeader +
  479. sizeof(IMAGE_FILE_HEADER));
  480. //
  481. // Make a pointer to the first section in the header buffer
  482. //
  483. SectionHeader = (PIMAGE_SECTION_HEADER)((PUCHAR)OptionalHeader +
  484. FileHeader->SizeOfOptionalHeader);
  485. *Start = OptionalHeader->ImageBase+SectionHeader->VirtualAddress;
  486. *End = *Start + SectionHeader->SizeOfRawData;
  487. //
  488. // Display some debug stuff for now
  489. //
  490. DBG1(
  491. BlPrint("Machine = %x\n",FileHeader->Machine);
  492. BlPrint("NumberOfSections = %x\n",FileHeader->NumberOfSections);
  493. BlPrint("TimeDateStamp %lx\n",FileHeader->TimeDateStamp);
  494. BlPrint("PointerToSymbolTable = %lx\n",FileHeader->PointerToSymbolTable);
  495. BlPrint("NumberOfSymbols %lx\n",FileHeader->NumberOfSymbols);
  496. BlPrint("SizeOfOptionalHeader = %x\n",FileHeader->SizeOfOptionalHeader);
  497. BlPrint("Characteristics = %x\n",FileHeader->Characteristics);
  498. )
  499. //
  500. // Loop and relocate each section with a non-zero RawData size
  501. //
  502. for (Section=FileHeader->NumberOfSections ; Section-- ; SectionHeader++) {
  503. //
  504. // Compute source, destination, and count arguments
  505. //
  506. Source = FileStart + SectionHeader->PointerToRawData;
  507. Destination = OptionalHeader->ImageBase + SectionHeader->VirtualAddress;
  508. VirtualSize = SectionHeader->Misc.VirtualSize;
  509. SizeOfRawData = SectionHeader->SizeOfRawData;
  510. if (VirtualSize == 0) {
  511. VirtualSize = SizeOfRawData;
  512. }
  513. if (SectionHeader->PointerToRawData == 0) {
  514. //
  515. // SizeOfRawData can be non-zero even if PointerToRawData is zero
  516. //
  517. SizeOfRawData = 0;
  518. } else if (SizeOfRawData > VirtualSize) {
  519. //
  520. // Don't load more from image than is expected in memory
  521. //
  522. SizeOfRawData = VirtualSize;
  523. }
  524. if (Destination < *Start) {
  525. *Start = Destination;
  526. }
  527. if (Destination+VirtualSize > *End) {
  528. *End = Destination+VirtualSize;
  529. }
  530. DBG1(BlPrint("src=%lx dest=%lx raw=%lx\n",Source,Destination,SizeOfRawData);)
  531. if (SizeOfRawData != 0) {
  532. //
  533. // This section is either a code (.TEXT) section or an
  534. // initialized data (.DATA) section.
  535. // Relocate the section to memory at the virtual/physical
  536. // addresses specified in the section header.
  537. //
  538. MoveMemory(Source,Destination,SizeOfRawData);
  539. }
  540. if (SizeOfRawData < VirtualSize) {
  541. //
  542. // Zero the portion not loaded from the image
  543. //
  544. DBG1( BlPrint("Zeroing destination %lx\n",Destination+SizeOfRawData); )
  545. ZeroMemory(Destination+SizeOfRawData,VirtualSize - SizeOfRawData);
  546. }
  547. //
  548. // Check if this is the resource section. If so, we need
  549. // to pass its location to the osloader.
  550. //
  551. if ((SectionHeader->Name[0] == '.') &&
  552. (SectionHeader->Name[1] == 'r') &&
  553. (SectionHeader->Name[2] == 's') &&
  554. (SectionHeader->Name[3] == 'r') &&
  555. (SectionHeader->Name[4] == 'c')) {
  556. ResourceDirectory = Destination;
  557. ResourceOffset = SectionHeader->VirtualAddress;
  558. }
  559. //
  560. // look for the .detect section that will contain the contents
  561. // of ntdetect.com. This is optional.
  562. //
  563. if ((SectionHeader->Name[0] == '.') &&
  564. (SectionHeader->Name[1] == 'd') &&
  565. (SectionHeader->Name[2] == 'e') &&
  566. (SectionHeader->Name[3] == 't') &&
  567. (SectionHeader->Name[4] == 'e') &&
  568. (SectionHeader->Name[5] == 'c') &&
  569. (SectionHeader->Name[6] == 't')) {
  570. NtDetectStart = Destination;
  571. NtDetectEnd = NtDetectStart + SizeOfRawData;
  572. }
  573. }
  574. DBG1( BlPrint("RelocateLoaderSections done - EntryPoint == %lx\n",
  575. OptionalHeader->AddressOfEntryPoint + OptionalHeader->ImageBase);)
  576. return(OptionalHeader->AddressOfEntryPoint + OptionalHeader->ImageBase);
  577. }
  578. VOID
  579. Relocatex86Structures(
  580. VOID
  581. )
  582. /*++
  583. Routine Description:
  584. The gdt and idt are statically defined and imbedded in the SU modules
  585. data segment. This routine moves then out of the data segment and into
  586. a page mapped at a defined location.
  587. Arguments:
  588. None
  589. Returns:
  590. Nothing
  591. --*/
  592. {
  593. FPUCHAR Fpsrc, Fpdst;
  594. USHORT Count;
  595. //
  596. // Make pointers to the data and compute the size
  597. // of the block to use.
  598. //
  599. Fpsrc = (FPUCHAR)&Beginx86Relocation;
  600. MAKE_FP(Fpdst,SYSTEM_STRUCTS_BASE_PA);
  601. Count = (&Endx86Relocation - &Beginx86Relocation);
  602. //
  603. // Move the data to its new location
  604. //
  605. while (Count--) {
  606. *Fpdst++ = *Fpsrc++;
  607. }
  608. }
  609. VOID
  610. DisplayArgs(
  611. USHORT es,
  612. USHORT bx,
  613. USHORT cx,
  614. USHORT dx,
  615. USHORT ax
  616. )
  617. /*++
  618. Routine Description:
  619. Just a debugging routine to dump some registers.
  620. Arguments:
  621. The x86 registers es, bx, cx, dx, and ax are pushed on the stack
  622. before this routine is called.
  623. Returns:
  624. Nothing
  625. Environment:
  626. Real Mode ONLY
  627. --*/
  628. {
  629. BlPrint("ax:%x dx:%x cx:%x bx:%x es:%x\n",
  630. (USHORT) ax,
  631. (USHORT) dx,
  632. (USHORT) cx,
  633. (USHORT) bx,
  634. (USHORT) es);
  635. return;
  636. }
  637. //
  638. // PxenvVerifyEntry()
  639. //
  640. // Description:
  641. // Verify that the contents of the PXENV Entry Point structure are
  642. // valid.
  643. //
  644. // Passed:
  645. // entry := Far pointer to PXENV Entry Point structure
  646. //
  647. // Returns:
  648. // TRUE := Structure is invalid
  649. // FALSE := Structure is valid
  650. //
  651. BOOLEAN
  652. PxenvVerifyEntry(
  653. t_PXENV_ENTRY far *entry
  654. )
  655. {
  656. unsigned n;
  657. UINT8 cksum = 0;
  658. //
  659. // Is structure pointer NULL?
  660. //
  661. if (entry == NULL) {
  662. BlPrint("\nNULL PXENV Entry Point structure\n");
  663. return TRUE;
  664. }
  665. //
  666. // Is real-mode API entry point NULL?
  667. //
  668. if (!(entry->rm_entry_off | entry->rm_entry_seg)) {
  669. BlPrint("\nNULL PXENV API Entry Point\n");
  670. return TRUE;
  671. }
  672. //
  673. // Verify structure signature
  674. //
  675. for (n = sizeof entry->signature; n--; ) {
  676. if (entry->signature[n] != (UINT8)(PXENV_ENTRY_SIG[n])) {
  677. BlPrint("\nBad PXENV Entry Point signature\n");
  678. return TRUE;
  679. }
  680. }
  681. //
  682. // Verify structure signature
  683. //
  684. if (entry->length < sizeof(t_PXENV_ENTRY) ) {
  685. BlPrint("\nBad PXENV Entry Point size\n");
  686. return TRUE;
  687. }
  688. //
  689. // Verify structure checksum
  690. //
  691. #if 0
  692. for (n = 0; n < entry->length; n++ ) {
  693. BlPrint( "%x ", ((UINT8 far *)entry)[n] );
  694. if ((n & 15) == 15) {
  695. BlPrint( "\n" );
  696. }
  697. }
  698. #endif
  699. for (n = entry->length; n--; ) {
  700. cksum += ((UINT8 far *)entry)[n];
  701. }
  702. if (cksum) {
  703. BlPrint("\nBad PXENV Entry Point structure checksum\n");
  704. return TRUE;
  705. }
  706. return FALSE;
  707. }
  708. VOID
  709. Reboot(
  710. VOID
  711. )
  712. /*++
  713. Routine Description:
  714. Reboots the machine using the keyboard port.
  715. Arguments:
  716. None
  717. Returns:
  718. Nothing
  719. --*/
  720. {
  721. RealMode();
  722. __asm {
  723. mov ax, 040h
  724. mov ds, ax
  725. mov word ptr ds:[72h], 1234h // set location 472 to 1234 to indicate warm reboot
  726. mov al, 0feh
  727. out 64h, al // write to keyboard port to cause reboot
  728. }
  729. }
  730. VOID
  731. Wait(
  732. IN ULONG WaitTime
  733. )
  734. /*++
  735. Routine Description:
  736. Waits for the requested number of seconds.
  737. Arguments:
  738. WaitTime - in seconds
  739. Returns:
  740. Nothing
  741. --*/
  742. {
  743. ULONG startTime = GetTickCount();
  744. while ( (((GetTickCount() - startTime) * 10) / 182) < WaitTime ) {
  745. }
  746. }
  747. // END OF FILE //