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.

2065 lines
50 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. arcemul.c
  5. Abstract:
  6. This module provides the x86 emulation for the Arc routines which are
  7. built into the firmware on ARC machines.
  8. N. B. This is where all the initialization of the SYSTEM_PARAMETER_BLOCK
  9. takes place. If there is any non-standard hardware, some of the
  10. vectors may have to be changed. This is where to do it.
  11. Author:
  12. Allen Kay (akay) 26-Jan-1996
  13. Base on i386 version by John Vert (jvert) 13-Jun-1991
  14. Environment:
  15. EFI
  16. Revision History:
  17. --*/
  18. #include "arccodes.h"
  19. #include "bootia64.h"
  20. #include "ntdddisk.h"
  21. #include "string.h"
  22. #include "stdio.h"
  23. #include "stdlib.h"
  24. #include "scsi.h"
  25. #include "scsiboot.h"
  26. #define CMOS_CONTROL_PORT ((PUCHAR)0x70)
  27. #define CMOS_DATA_PORT ((PUCHAR)0x71)
  28. #define CMOS_STATUS_B 0x0B
  29. #define CMOS_DAYLIGHT_BIT 1
  30. extern PCHAR MnemonicTable[];
  31. //
  32. // Size definitions for HardDiskInitialize()
  33. //
  34. #define SUPPORTED_NUMBER_OF_DISKS 32
  35. #define SIZE_FOR_SUPPORTED_DISK_STRUCTURE (SUPPORTED_NUMBER_OF_DISKS*sizeof(DRIVER_LOOKUP_ENTRY))
  36. PDRIVER_UNLOAD AEDriverUnloadRoutine = NULL;
  37. #define PORT_BUFFER_SIZE 10
  38. UCHAR PortBuffer[PORT_BUFFER_SIZE];
  39. ULONG PortBufferStart = 0;
  40. ULONG PortBufferEnd = 0;
  41. //
  42. // Miniport DriverEntry typedef
  43. //
  44. typedef NTSTATUS
  45. (*PDRIVER_ENTRY) (
  46. IN PVOID DriverObject,
  47. IN PVOID Parameter2
  48. );
  49. //
  50. // Private function prototypes
  51. //
  52. ARC_STATUS
  53. BlArcNotYetImplemented(
  54. IN ULONG FileId
  55. );
  56. PCONFIGURATION_COMPONENT
  57. AEComponentInfo(
  58. IN PCONFIGURATION_COMPONENT Current
  59. );
  60. PCONFIGURATION_COMPONENT
  61. FwGetChild(
  62. IN PCONFIGURATION_COMPONENT Current
  63. );
  64. PCHAR
  65. AEGetEnvironment(
  66. IN PCHAR Variable
  67. );
  68. PCONFIGURATION_COMPONENT
  69. FwGetPeer(
  70. IN PCONFIGURATION_COMPONENT Current
  71. );
  72. PCONFIGURATION_COMPONENT
  73. AEGetParent(
  74. IN PCONFIGURATION_COMPONENT Current
  75. );
  76. ARC_STATUS
  77. AEGetConfigurationData(
  78. IN PVOID ConfigurationData,
  79. IN PCONFIGURATION_COMPONENT Current
  80. );
  81. PMEMORY_DESCRIPTOR
  82. AEGetMemoryDescriptor(
  83. IN PMEMORY_DESCRIPTOR MemoryDescriptor OPTIONAL
  84. );
  85. ARC_STATUS
  86. AEOpen(
  87. IN PCHAR OpenPath,
  88. IN OPEN_MODE OpenMode,
  89. OUT PULONG FileId
  90. );
  91. ARC_STATUS
  92. AEClose(
  93. IN ULONG FileId
  94. );
  95. ARC_STATUS
  96. AERead (
  97. IN ULONG FileId,
  98. OUT PVOID Buffer,
  99. IN ULONG Length,
  100. OUT PULONG Count
  101. );
  102. ARC_STATUS
  103. AEReadStatus (
  104. IN ULONG FileId
  105. );
  106. VOID
  107. AEReboot(
  108. VOID
  109. );
  110. ARC_STATUS
  111. AESeek (
  112. IN ULONG FileId,
  113. IN PLARGE_INTEGER Offset,
  114. IN SEEK_MODE SeekMode
  115. );
  116. ARC_STATUS
  117. AEWrite (
  118. IN ULONG FileId,
  119. OUT PVOID Buffer,
  120. IN ULONG Length,
  121. OUT PULONG Count
  122. );
  123. ARC_STATUS
  124. AEGetFileInformation(
  125. IN ULONG FileId,
  126. OUT PFILE_INFORMATION FileInformation
  127. );
  128. PTIME_FIELDS
  129. AEGetTime(
  130. VOID
  131. );
  132. ULONG
  133. AEGetRelativeTime(
  134. VOID
  135. );
  136. ARC_STATUS
  137. ScsiDiskClose (
  138. IN ULONG FileId
  139. );
  140. ARC_STATUS
  141. ScsiDiskMount (
  142. IN PCHAR MountPath,
  143. IN MOUNT_OPERATION Operation
  144. );
  145. ARC_STATUS
  146. ScsiDiskOpen (
  147. IN PCHAR OpenPath,
  148. IN OPEN_MODE OpenMode,
  149. OUT PULONG FileId
  150. );
  151. ARC_STATUS
  152. ScsiDiskRead (
  153. IN ULONG FileId,
  154. IN PVOID Buffer,
  155. IN ULONG Length,
  156. OUT PULONG Count
  157. );
  158. ARC_STATUS
  159. ScsiDiskSeek (
  160. IN ULONG FileId,
  161. IN PLARGE_INTEGER Offset,
  162. IN SEEK_MODE SeekMode
  163. );
  164. ARC_STATUS
  165. ScsiDiskWrite (
  166. IN ULONG FileId,
  167. IN PVOID Buffer,
  168. IN ULONG Length,
  169. OUT PULONG Count
  170. );
  171. VOID
  172. HardDiskInitialize(
  173. IN OUT PVOID LookupTable,
  174. IN ULONG Entries,
  175. IN PVOID DeviceFoundCallback
  176. );
  177. //
  178. // This is the x86 version of the system parameter block on the ARC machines.
  179. // It lives here, and any module that uses an ArcXXXX routine must declare
  180. // it external. Machines that have other than very plain-vanilla hardware
  181. // may have to replace some of the hard-wired vectors with different
  182. // procedures.
  183. //
  184. PVOID GlobalFirmwareVectors[MaximumRoutine];
  185. SYSTEM_PARAMETER_BLOCK GlobalSystemBlock =
  186. {
  187. 0, // Signature??
  188. sizeof(SYSTEM_PARAMETER_BLOCK), // Length
  189. 0, // Version
  190. 0, // Revision
  191. NULL, // RestartBlock
  192. NULL, // DebugBlock
  193. NULL, // GenerateExceptionVector
  194. NULL, // TlbMissExceptionVector
  195. MaximumRoutine, // FirmwareVectorLength
  196. GlobalFirmwareVectors, // Pointer to vector block
  197. 0, // VendorVectorLength
  198. NULL // Pointer to vendor vector block
  199. };
  200. extern BL_FILE_TABLE BlFileTable[BL_FILE_TABLE_SIZE];
  201. //
  202. // temptemp John Vert (jvert) 6-Sep-1991
  203. // Just do this until we can make our device driver interface look
  204. // like the ARC firmware one.
  205. //
  206. extern BL_DEVICE_ENTRY_TABLE ScsiDiskEntryTable;
  207. ULONG FwStallCounter;
  208. VOID
  209. AEInitializeStall(
  210. VOID
  211. )
  212. {
  213. FwStallCounter = GET_STALL_COUNT();
  214. return;
  215. }
  216. #if !defined(NO_LEGACY_DRIVERS)
  217. ARC_STATUS
  218. AEInitializeIo(
  219. IN ULONG DriveId
  220. )
  221. /*++
  222. Routine Description:
  223. Initializes SCSI boot driver, if any. Loads ntbootdd.sys from the
  224. boot partition, binds it to the osloader, and initializes it.
  225. Arguments:
  226. DriveId - file id of the opened boot partition
  227. Return Value:
  228. ESUCCESS - Drivers successfully initialized
  229. --*/
  230. {
  231. extern ULONG ScsiPortCount;
  232. extern ULONG MachineType;
  233. ARC_STATUS Status;
  234. PVOID Buffer;
  235. PVOID ImageBase;
  236. PLDR_DATA_TABLE_ENTRY DriverDataTableEntry;
  237. PDRIVER_ENTRY Entry;
  238. ULONG i;
  239. ULONG ImageBasePage;
  240. ScsiPortCount = 0;
  241. FwStallCounter = GET_STALL_COUNT();
  242. Status = BlLoadImage(DriveId,
  243. MemoryFirmwarePermanent,
  244. "\\NTBOOTDD.SYS",
  245. TARGET_IMAGE,
  246. &ImageBase);
  247. if (Status != ESUCCESS) {
  248. return(Status);
  249. }
  250. Status = BlAllocateDataTableEntry("NTBOOTDD.SYS",
  251. "\\NTBOOTDD.SYS",
  252. ImageBase,
  253. &DriverDataTableEntry);
  254. if (Status != ESUCCESS) {
  255. return(Status);
  256. }
  257. //
  258. // Scan the import table and bind to osloader
  259. //
  260. Status = BlScanOsloaderBoundImportTable(DriverDataTableEntry);
  261. if (Status != ESUCCESS) {
  262. return(Status);
  263. }
  264. Entry = (PDRIVER_ENTRY)DriverDataTableEntry->EntryPoint;
  265. Status = (*Entry)(NULL,NULL);
  266. if (Status == ESUCCESS) {
  267. //
  268. // Find the firmware's copy of the memory descriptor that
  269. // contains the driver and change it from MemoryFree to
  270. // MemoryFirmwareTemporary.
  271. //
  272. ImageBasePage = ((PtrToUlong(ImageBase) & 0x7fffffff) >> PAGE_SHIFT);
  273. i=0;
  274. while ((MDArray[i].BasePage >= ImageBasePage) ||
  275. (MDArray[i].BasePage + MDArray[i].PageCount < ImageBasePage)) {
  276. i++;
  277. }
  278. MDArray[i].MemoryType = MemoryFirmwareTemporary;
  279. Buffer = BlAllocateHeap(SIZE_FOR_SUPPORTED_DISK_STRUCTURE);
  280. if(Buffer == NULL) {
  281. return ENOMEM;
  282. }
  283. HardDiskInitialize(Buffer, SUPPORTED_NUMBER_OF_DISKS, NULL);
  284. }
  285. return(Status);
  286. }
  287. #endif // NO_LEGACY_DRIVERS
  288. VOID
  289. BlFillInSystemParameters(
  290. IN PBOOT_CONTEXT BootContextRecord
  291. )
  292. /*++
  293. Routine Description:
  294. This routine fills in all the fields in the Global System Parameter Block
  295. that it can. This includes all the firmware vectors, the vendor-specific
  296. information, and anything else that may come up.
  297. Arguments:
  298. None.
  299. Return Value:
  300. None.
  301. --*/
  302. {
  303. int cnt;
  304. //
  305. // Fill in the pointers to the firmware functions which we emulate.
  306. // Those which we don't emulate are stubbed by BlArcNotYetImplemented,
  307. // which will print an error message if it is accidentally called.
  308. //
  309. for (cnt=0; cnt<MaximumRoutine; cnt++) {
  310. GlobalFirmwareVectors[cnt]=(PVOID)BlArcNotYetImplemented;
  311. }
  312. GlobalFirmwareVectors[CloseRoutine] = (PVOID)AEClose;
  313. GlobalFirmwareVectors[OpenRoutine] = (PVOID)AEOpen;
  314. GlobalFirmwareVectors[MemoryRoutine]= (PVOID)AEGetMemoryDescriptor;
  315. GlobalFirmwareVectors[SeekRoutine] = (PVOID)AESeek;
  316. GlobalFirmwareVectors[ReadRoutine] = (PVOID)AERead;
  317. GlobalFirmwareVectors[ReadStatusRoutine] = (PVOID)AEReadStatus;
  318. GlobalFirmwareVectors[WriteRoutine] = (PVOID)AEWrite;
  319. GlobalFirmwareVectors[GetFileInformationRoutine] = (PVOID)AEGetFileInformation;
  320. GlobalFirmwareVectors[GetTimeRoutine] = (PVOID)AEGetTime;
  321. GlobalFirmwareVectors[GetRelativeTimeRoutine] = (PVOID)AEGetRelativeTime;
  322. GlobalFirmwareVectors[GetPeerRoutine] = (PVOID)FwGetPeer;
  323. GlobalFirmwareVectors[GetChildRoutine] = (PVOID)FwGetChild;
  324. GlobalFirmwareVectors[GetParentRoutine] = (PVOID)AEGetParent;
  325. GlobalFirmwareVectors[GetComponentRoutine] = (PVOID)FwGetComponent;
  326. GlobalFirmwareVectors[GetDataRoutine] = (PVOID)AEGetConfigurationData;
  327. GlobalFirmwareVectors[GetEnvironmentRoutine] = (PVOID)AEGetEnvironment;
  328. GlobalFirmwareVectors[RestartRoutine] = (PVOID)AEReboot;
  329. GlobalFirmwareVectors[RebootRoutine] = (PVOID)AEReboot;
  330. }
  331. PMEMORY_DESCRIPTOR
  332. AEGetMemoryDescriptor(
  333. IN PMEMORY_DESCRIPTOR MemoryDescriptor OPTIONAL
  334. )
  335. /*++
  336. Routine Description:
  337. Emulates the Arc GetMemoryDescriptor call. This must translate
  338. between the memory description passed to us by the SU module and
  339. the MEMORYDESCRIPTOR type defined by ARC.
  340. Arguments:
  341. MemoryDescriptor - Supplies current memory descriptor.
  342. If MemoryDescriptor==NULL, return the first memory descriptor.
  343. If MemoryDescriptor!=NULL, return the next memory descriptor.
  344. Return Value:
  345. Next memory descriptor in the list.
  346. NULL if MemoryDescriptor is the last descriptor in the list.
  347. --*/
  348. {
  349. extern ULONG NumberDescriptors;
  350. PMEMORY_DESCRIPTOR Return;
  351. if (MemoryDescriptor==NULL) {
  352. Return=MDArray;
  353. } else {
  354. if((ULONG)(MemoryDescriptor-MDArray) >= (NumberDescriptors-1)) {
  355. return NULL;
  356. } else {
  357. Return = ++MemoryDescriptor;
  358. }
  359. }
  360. return(Return);
  361. }
  362. ARC_STATUS
  363. BlArcNotYetImplemented(
  364. IN ULONG FileId
  365. )
  366. /*++
  367. Routine Description:
  368. This is a stub routine used to fill in the firmware vectors which haven't
  369. been defined yet. It uses BlPrint to print a message on the screen.
  370. Arguments:
  371. None.
  372. Return Value:
  373. EINVAL
  374. --*/
  375. {
  376. #if DBG
  377. BlPrint(TEXT("ERROR - Unimplemented Firmware Vector called (FID %lx)\r\n"),
  378. FileId );
  379. #endif
  380. return(EINVAL);
  381. }
  382. PCONFIGURATION_COMPONENT
  383. FwGetChild(
  384. IN PCONFIGURATION_COMPONENT Current
  385. )
  386. /*++
  387. Routine Description:
  388. This is the arc emulation routine for GetChild. Based on the current
  389. component, it returns the component's child component.
  390. Arguments:
  391. Current - Supplies pointer to the current configuration component
  392. Return Value:
  393. A pointer to a CONFIGURATION_COMPONENT structure OR
  394. NULL - No more configuration information
  395. --*/
  396. {
  397. PCONFIGURATION_COMPONENT_DATA CurrentEntry;
  398. //
  399. // if current component is NULL, return a pointer to first system
  400. // component; otherwise return current component's child component.
  401. //
  402. if (Current) {
  403. CurrentEntry = CONTAINING_RECORD(Current,
  404. CONFIGURATION_COMPONENT_DATA,
  405. ComponentEntry);
  406. if (CurrentEntry->Child) {
  407. return(&(CurrentEntry->Child->ComponentEntry));
  408. } else {
  409. return(NULL);
  410. }
  411. } else {
  412. if (FwConfigurationTree) {
  413. return(&(FwConfigurationTree->ComponentEntry));
  414. } else {
  415. return(NULL);
  416. }
  417. }
  418. }
  419. PCONFIGURATION_COMPONENT
  420. FwGetPeer(
  421. IN PCONFIGURATION_COMPONENT Current
  422. )
  423. /*++
  424. Routine Description:
  425. This is the arc emulation routine for GetPeer. Based on the current
  426. component, it returns the component's sibling.
  427. Arguments:
  428. Current - Supplies pointer to the current configuration component
  429. Return Value:
  430. A pointer to a CONFIGURATION_COMPONENT structure OR
  431. NULL - No more configuration information
  432. --*/
  433. {
  434. PCONFIGURATION_COMPONENT_DATA CurrentEntry;
  435. if (Current) {
  436. CurrentEntry = CONTAINING_RECORD(Current,
  437. CONFIGURATION_COMPONENT_DATA,
  438. ComponentEntry);
  439. if (CurrentEntry->Sibling) {
  440. return(&(CurrentEntry->Sibling->ComponentEntry));
  441. } else {
  442. return(NULL);
  443. }
  444. } else {
  445. return(NULL);
  446. }
  447. }
  448. PCONFIGURATION_COMPONENT
  449. AEGetParent(
  450. IN PCONFIGURATION_COMPONENT Current
  451. )
  452. /*++
  453. Routine Description:
  454. This is the arc emulation routine for GetParent. Based on the current
  455. component, it returns the component's parent.
  456. Arguments:
  457. Current - Supplies pointer to the current configuration component
  458. Return Value:
  459. A pointer to a CONFIGURATION_COMPONENT structure OR
  460. NULL - No more configuration information
  461. --*/
  462. {
  463. PCONFIGURATION_COMPONENT_DATA CurrentEntry;
  464. if (Current) {
  465. CurrentEntry = CONTAINING_RECORD(Current,
  466. CONFIGURATION_COMPONENT_DATA,
  467. ComponentEntry);
  468. if (CurrentEntry->Parent) {
  469. return(&(CurrentEntry->Parent->ComponentEntry));
  470. } else {
  471. return(NULL);
  472. }
  473. } else {
  474. return(NULL);
  475. }
  476. }
  477. ARC_STATUS
  478. AEGetConfigurationData(
  479. IN PVOID ConfigurationData,
  480. IN PCONFIGURATION_COMPONENT Current
  481. )
  482. /*++
  483. Routine Description:
  484. This is the arc emulation routine for GetParent. Based on the current
  485. component, it returns the component's parent.
  486. Arguments:
  487. Current - Supplies pointer to the current configuration component
  488. Return Value:
  489. ESUCCESS - Data successfully returned.
  490. --*/
  491. {
  492. PCONFIGURATION_COMPONENT_DATA CurrentEntry;
  493. if (Current) {
  494. CurrentEntry = CONTAINING_RECORD(Current,
  495. CONFIGURATION_COMPONENT_DATA,
  496. ComponentEntry);
  497. RtlMoveMemory(ConfigurationData,
  498. CurrentEntry->ConfigurationData,
  499. Current->ConfigurationDataLength);
  500. return(ESUCCESS);
  501. } else {
  502. return(EINVAL);
  503. }
  504. }
  505. PCHAR
  506. AEGetEnvironment(
  507. IN PCHAR Variable
  508. )
  509. /*++
  510. Routine Description:
  511. This is the arc emulation routine for ArcGetEnvironment. It returns
  512. the value of the specified NVRAM environment variable.
  513. NOTE John Vert (jvert) 23-Apr-1992
  514. This particular implementation uses the Daylight Savings Bit on
  515. the Real Time Clock to reflect the state of the LastKnownGood
  516. environment variable. This is the only variable we support.
  517. Arguments:
  518. Variable - Supplies the name of the environment variable to look up.
  519. Return Value:
  520. A pointer to the specified environment variable's value, or
  521. NULL if the variable does not exist.
  522. --*/
  523. {
  524. UCHAR StatusByte;
  525. #if 1
  526. //
  527. // Until firmware implements LastKnownGood variable,
  528. // return NULL for now.
  529. //
  530. return(NULL);
  531. #else
  532. if (_stricmp(Variable, "LastKnownGood") != 0) {
  533. return(NULL);
  534. }
  535. //
  536. // Read the Daylight Savings Bit out of the RTC to determine whether
  537. // the LastKnownGood environment variable is TRUE or FALSE.
  538. //
  539. WRITE_PORT_UCHAR(CMOS_CONTROL_PORT, CMOS_STATUS_B);
  540. StatusByte = READ_PORT_UCHAR(CMOS_DATA_PORT);
  541. if (StatusByte & CMOS_DAYLIGHT_BIT) {
  542. return("TRUE");
  543. } else {
  544. return(NULL);
  545. }
  546. #endif
  547. }
  548. ARC_STATUS
  549. AEOpen(
  550. IN PCHAR OpenPath,
  551. IN OPEN_MODE OpenMode,
  552. OUT PULONG FileId
  553. )
  554. /*++
  555. Routine Description:
  556. Opens the file or device specified by OpenPath.
  557. Arguments:
  558. OpenPath - Supplies a pointer to the fully-qualified path name.
  559. OpenMode - Supplies the mode to open the file.
  560. 0 - Read Only
  561. 1 - Write Only
  562. 2 - Read/Write
  563. FileId - Returns the file descriptor for use with the Close, Read, Write,
  564. and Seek routines
  565. Return Value:
  566. ESUCCESS - File successfully opened.
  567. --*/
  568. {
  569. ARC_STATUS Status;
  570. CHAR Buffer[128];
  571. Status = BiosConsoleOpen( OpenPath,
  572. OpenMode,
  573. FileId );
  574. if (Status == ESUCCESS) {
  575. return(ESUCCESS);
  576. }
  577. Status = BiosPartitionOpen( OpenPath,
  578. OpenMode,
  579. FileId );
  580. if (Status == ESUCCESS) {
  581. return(ESUCCESS);
  582. }
  583. #if !defined(NO_LEGACY_DRIVERS)
  584. //
  585. // It's not the console or a BIOS partition, so let's try the SCSI
  586. // driver.
  587. //
  588. //
  589. // Find a free FileId
  590. //
  591. *FileId = 2;
  592. while (BlFileTable[*FileId].Flags.Open == 1) {
  593. *FileId += 1;
  594. if (*FileId == BL_FILE_TABLE_SIZE) {
  595. return(ENOENT);
  596. }
  597. }
  598. strcpy(Buffer,OpenPath);
  599. Status = ScsiDiskOpen( Buffer,
  600. OpenMode,
  601. FileId );
  602. if (Status == ESUCCESS) {
  603. //
  604. // SCSI successfully opened it. For now, we stick the appropriate
  605. // SCSI DeviceEntryTable into the BlFileTable. This is temporary.
  606. //
  607. BlFileTable[*FileId].Flags.Open = 1;
  608. BlFileTable[*FileId].DeviceEntryTable = &ScsiDiskEntryTable;
  609. return(ESUCCESS);
  610. }
  611. #endif // NO_LEGACY_DRIVERS
  612. return(Status);
  613. }
  614. ARC_STATUS
  615. AESeek (
  616. IN ULONG FileId,
  617. IN PLARGE_INTEGER Offset,
  618. IN SEEK_MODE SeekMode
  619. )
  620. /*++
  621. Routine Description:
  622. Changes the current offset of the file specified by FileId
  623. Arguments:
  624. FileId - specifies the file on which the current offset is to
  625. be changed.
  626. Offset - New offset into file.
  627. SeekMode - Either SeekAbsolute or SeekRelative
  628. SeekEndRelative is not supported
  629. Return Value:
  630. ESUCCESS - Operation completed succesfully
  631. EBADF - Operation did not complete successfully.
  632. --*/
  633. {
  634. return(BlFileTable[FileId].DeviceEntryTable->Seek)( FileId,
  635. Offset,
  636. SeekMode );
  637. }
  638. ARC_STATUS
  639. AEClose (
  640. IN ULONG FileId
  641. )
  642. /*++
  643. Routine Description:
  644. Closes the file specified by FileId
  645. Arguments:
  646. FileId - specifies the file to close
  647. Return Value:
  648. ESUCCESS - Operation completed succesfully
  649. EBADF - Operation did not complete successfully.
  650. --*/
  651. {
  652. return(BlFileTable[FileId].DeviceEntryTable->Close)(FileId);
  653. }
  654. ARC_STATUS
  655. AEReadStatus(
  656. IN ULONG FileId
  657. )
  658. /*++
  659. Routine Description:
  660. Determines if data is available on the specified device
  661. Arguments:
  662. FileId - Specifies the device to check for data.
  663. Return Value:
  664. ESUCCESS - At least one byte is available.
  665. EAGAIN - No data is available
  666. --*/
  667. {
  668. //
  669. // Special case for console input
  670. //
  671. if (FileId == 0) {
  672. #if 0
  673. //
  674. // Give priority to dumb terminal
  675. //
  676. if (BlIsTerminalConnected() && (PortBufferStart != PortBufferEnd)) {
  677. return(ESUCCESS);
  678. }
  679. if (BlIsTerminalConnected() && (BlPortPollOnly(BlTerminalDeviceId) == CP_GET_SUCCESS)) {
  680. return(ESUCCESS);
  681. }
  682. #endif
  683. return(BiosConsoleReadStatus(FileId));
  684. } else {
  685. return(BlArcNotYetImplemented(FileId));
  686. }
  687. }
  688. ARC_STATUS
  689. AERead (
  690. IN ULONG FileId,
  691. OUT PVOID Buffer,
  692. IN ULONG Length,
  693. OUT PULONG Count
  694. )
  695. /*++
  696. Routine Description:
  697. Reads from the specified file or device
  698. Arguments:
  699. FileId - specifies the file to read from
  700. Buffer - Address of buffer to hold the data that is read
  701. Length - Maximum number of bytes to read
  702. Count - Address of location in which to store the actual bytes read.
  703. Return Value:
  704. ESUCCESS - Read completed successfully
  705. !ESUCCESS - Read failed.
  706. --*/
  707. {
  708. ARC_STATUS Status;
  709. ULONG Limit;
  710. ULONG PartCount;
  711. PCHAR TmpBuffer;
  712. ULONG StartTime;
  713. ULONG LastTime;
  714. UCHAR Ch;
  715. //
  716. // Special case for console input
  717. //
  718. if (FileId == 0) {
  719. RetryRead:
  720. #if 0
  721. if (BlIsTerminalConnected()) {
  722. *Count = 0;
  723. TmpBuffer = (PCHAR)Buffer;
  724. while (*Count < Length) {
  725. //
  726. // First return any buffered input
  727. //
  728. if (PortBufferStart != PortBufferEnd) {
  729. TmpBuffer[*Count] = PortBuffer[PortBufferStart];
  730. PortBufferStart++;
  731. PortBufferStart = PortBufferStart % PORT_BUFFER_SIZE;
  732. *Count = *Count + 1;
  733. continue;
  734. }
  735. //
  736. // Now check for new input
  737. //
  738. if (BlPortPollByte(BlTerminalDeviceId, TmpBuffer + *Count) != CP_GET_SUCCESS) {
  739. break;
  740. }
  741. //
  742. // Convert ESC key to the local equivalent
  743. //
  744. if (TmpBuffer[*Count] == 0x1b) {
  745. TmpBuffer[*Count] = (CHAR)ASCI_CSI_IN;
  746. //
  747. // Wait for the user to type a key.
  748. //
  749. StartTime = AEGetRelativeTime();
  750. while (BlPortPollOnly(BlTerminalDeviceId) != CP_GET_SUCCESS) {
  751. LastTime = AEGetRelativeTime();
  752. //
  753. // if the counter wraps back to zero, just restart the wait.
  754. //
  755. if (LastTime < StartTime) {
  756. StartTime = LastTime;
  757. }
  758. //
  759. // If one second has passed, the user must have just wanted a single
  760. // escape key, so return with that.
  761. //
  762. if ((LastTime - StartTime) > 1) {
  763. *Count = *Count + 1;
  764. return (ESUCCESS);
  765. }
  766. }
  767. //
  768. // We have another key, get it and translate the escape sequence.
  769. //
  770. if (BlPortPollByte(BlTerminalDeviceId, &Ch) != CP_GET_SUCCESS) {
  771. *Count = *Count + 1;
  772. return (ESUCCESS);
  773. }
  774. switch (Ch) {
  775. case '@': // F12 key
  776. PortBuffer[PortBufferEnd] = 'O';
  777. PortBufferEnd++;
  778. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  779. PortBuffer[PortBufferEnd] = 'B';
  780. PortBufferEnd++;
  781. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  782. break;
  783. case '!': // F11 key
  784. PortBuffer[PortBufferEnd] = 'O';
  785. PortBufferEnd++;
  786. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  787. PortBuffer[PortBufferEnd] = 'A';
  788. PortBufferEnd++;
  789. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  790. break;
  791. case '0': // F10 key
  792. PortBuffer[PortBufferEnd] = 'O';
  793. PortBufferEnd++;
  794. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  795. PortBuffer[PortBufferEnd] = 'M';
  796. PortBufferEnd++;
  797. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  798. break;
  799. case '8': // F8 key
  800. PortBuffer[PortBufferEnd] = 'O';
  801. PortBufferEnd++;
  802. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  803. PortBuffer[PortBufferEnd] = 'r';
  804. PortBufferEnd++;
  805. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  806. break;
  807. case '6': // F6 key
  808. PortBuffer[PortBufferEnd] = 'O';
  809. PortBufferEnd++;
  810. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  811. PortBuffer[PortBufferEnd] = 'u';
  812. PortBufferEnd++;
  813. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  814. break;
  815. case '5': // F5 key
  816. PortBuffer[PortBufferEnd] = 'O';
  817. PortBufferEnd++;
  818. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  819. PortBuffer[PortBufferEnd] = 't';
  820. PortBufferEnd++;
  821. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  822. break;
  823. case '3': // F3 key
  824. PortBuffer[PortBufferEnd] = 'O';
  825. PortBufferEnd++;
  826. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  827. PortBuffer[PortBufferEnd] = 'w';
  828. PortBufferEnd++;
  829. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  830. break;
  831. case '1': // F1 key
  832. PortBuffer[PortBufferEnd] = 'O';
  833. PortBufferEnd++;
  834. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  835. PortBuffer[PortBufferEnd] = 'P';
  836. PortBufferEnd++;
  837. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  838. break;
  839. case '+': // Home key
  840. PortBuffer[PortBufferEnd] = 'H';
  841. PortBufferEnd++;
  842. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  843. break;
  844. case '-': // End key
  845. PortBuffer[PortBufferEnd] = 'K';
  846. PortBufferEnd++;
  847. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  848. break;
  849. case '[': // Cursor movement key
  850. //
  851. // The local computer can run a lot faster than the serial port can give bytes,
  852. // so spin, polling, for a second.
  853. //
  854. StartTime = AEGetRelativeTime();
  855. while (BlPortPollOnly(BlTerminalDeviceId) != CP_GET_SUCCESS) {
  856. LastTime = AEGetRelativeTime();
  857. //
  858. // if the counter wraps back to zero, just restart the wait.
  859. //
  860. if (LastTime < StartTime) {
  861. StartTime = LastTime;
  862. }
  863. //
  864. // If one second has passed, we must be done.
  865. //
  866. if ((LastTime - StartTime) > 1) {
  867. break;
  868. }
  869. }
  870. if (BlPortPollByte(BlTerminalDeviceId, &Ch) != CP_GET_SUCCESS) {
  871. PortBuffer[PortBufferEnd] = '[';
  872. PortBufferEnd++;
  873. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  874. break;
  875. }
  876. if ((Ch == 'A') || (Ch == 'B') || (Ch == 'C') || (Ch == 'D')) { // Arrow key.
  877. PortBuffer[PortBufferEnd] = Ch;
  878. PortBufferEnd++;
  879. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  880. } else {
  881. //
  882. // Leave it as is
  883. //
  884. PortBuffer[PortBufferEnd] = '[';
  885. PortBufferEnd++;
  886. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  887. PortBuffer[PortBufferEnd] = Ch;
  888. PortBufferEnd++;
  889. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  890. }
  891. break;
  892. default:
  893. PortBuffer[PortBufferEnd] = Ch;
  894. PortBufferEnd++;
  895. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  896. break;
  897. }
  898. } else if (TmpBuffer[*Count] == 0x7F) { // DEL key
  899. TmpBuffer[*Count] = (CHAR)ASCI_CSI_IN;
  900. PortBuffer[PortBufferEnd] = 'P';
  901. PortBufferEnd++;
  902. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  903. }
  904. *Count = *Count + 1;
  905. }
  906. if (*Count != 0) {
  907. return(ESUCCESS);
  908. }
  909. }
  910. #endif
  911. if (BiosConsoleReadStatus(FileId) == ESUCCESS) {
  912. return(BiosConsoleRead(FileId,Buffer,Length,Count));
  913. }
  914. goto RetryRead;
  915. } else {
  916. *Count = 0;
  917. do {
  918. if ((PtrToUlong(Buffer) & 0xffff0000) !=
  919. ((PtrToUlong(Buffer) + Length) & 0xffff0000)) {
  920. Limit = 0x10000 - (PtrToUlong(Buffer) & 0x0000ffff);
  921. } else {
  922. Limit = Length;
  923. }
  924. Status = (BlFileTable[FileId].DeviceEntryTable->Read)( FileId,
  925. Buffer,
  926. Limit,
  927. &PartCount );
  928. *Count += PartCount;
  929. Length -= Limit;
  930. (PCHAR) Buffer += Limit;
  931. if (Status != ESUCCESS) {
  932. #if DBG
  933. BlPrint(TEXT("Disk I/O error: Status = %lx\r\n"),Status);
  934. #endif
  935. return(Status);
  936. }
  937. } while (Length > 0);
  938. return(Status);
  939. }
  940. }
  941. ARC_STATUS
  942. AEWrite (
  943. IN ULONG FileId,
  944. OUT PVOID Buffer,
  945. IN ULONG Length,
  946. OUT PULONG Count
  947. )
  948. /*++
  949. Routine Description:
  950. Writes to the specified file or device
  951. Arguments:
  952. FileId - Supplies the file or device to write to
  953. Buffer - Supplies address of the data to be written
  954. Length - Supplies number of bytes to write
  955. Count - Address of location in which to store the actual bytes written.
  956. Return Value:
  957. ESUCCESS - Read completed successfully
  958. !ESUCCESS - Read failed.
  959. --*/
  960. {
  961. ARC_STATUS Status;
  962. ULONG Limit;
  963. ULONG PartCount;
  964. PCHAR TmpBuffer;
  965. //
  966. // Special case for console output
  967. //
  968. if (FileId == 1) {
  969. #if 0
  970. if (BlIsTerminalConnected()) {
  971. for (PartCount = 0, TmpBuffer = (PCHAR)Buffer; PartCount < Length; PartCount++) {
  972. BlPortPutByte(BlTerminalDeviceId, TmpBuffer[PartCount]);
  973. }
  974. }
  975. #endif
  976. return(BiosConsoleWrite(FileId,(PWCHAR)Buffer,Length,Count));
  977. } else {
  978. *Count = 0;
  979. do {
  980. if ((PtrToUlong(Buffer) & 0xffff0000) !=
  981. ((PtrToUlong(Buffer) + Length) & 0xffff0000)) {
  982. Limit = 0x10000 - (PtrToUlong(Buffer) & 0x0000ffff);
  983. } else {
  984. Limit = Length;
  985. }
  986. Status = (BlFileTable[FileId].DeviceEntryTable->Write)( FileId,
  987. Buffer,
  988. Limit,
  989. &PartCount );
  990. *Count += PartCount;
  991. Length -= Limit;
  992. (PCHAR) Buffer += Limit;
  993. if (Status != ESUCCESS) {
  994. #if DBG
  995. BlPrint(TEXT("AERead: Status = %lx\r\n"),Status);
  996. #endif
  997. return(Status);
  998. }
  999. } while (Length > 0);
  1000. return(Status);
  1001. }
  1002. }
  1003. ARC_STATUS
  1004. AEGetFileInformation(
  1005. IN ULONG FileId,
  1006. OUT PFILE_INFORMATION FileInformation
  1007. )
  1008. {
  1009. return(BlFileTable[FileId].DeviceEntryTable->GetFileInformation)( FileId,
  1010. FileInformation);
  1011. }
  1012. TIME_FIELDS AETime;
  1013. PTIME_FIELDS
  1014. AEGetTime(
  1015. VOID
  1016. )
  1017. {
  1018. ULONG Date,Time;
  1019. GET_DATETIME(&Date,&Time);
  1020. //
  1021. // Date and time are filled as as follows:
  1022. //
  1023. // Date:
  1024. //
  1025. // bits 0 - 4 : day
  1026. // bits 5 - 8 : month
  1027. // bits 9 - 31 : year
  1028. //
  1029. // Time:
  1030. //
  1031. // bits 0 - 5 : second
  1032. // bits 6 - 11 : minute
  1033. // bits 12 - 16 : hour
  1034. //
  1035. AETime.Second = (CSHORT)((Time & 0x0000003f) >> 0);
  1036. AETime.Minute = (CSHORT)((Time & 0x00000fc0) >> 6);
  1037. AETime.Hour = (CSHORT)((Time & 0x0001f000) >> 12);
  1038. AETime.Day = (CSHORT)((Date & 0x0000001f) >> 0);
  1039. AETime.Month = (CSHORT)((Date & 0x000001e0) >> 5);
  1040. AETime.Year = (CSHORT)((Date & 0xfffffe00) >> 9);
  1041. AETime.Milliseconds = 0; // info is not available
  1042. AETime.Weekday = 7; // info is not available - set out of range
  1043. return(&AETime);
  1044. }
  1045. ULONG
  1046. AEGetRelativeTime(
  1047. VOID
  1048. )
  1049. /*++
  1050. Routine Description:
  1051. Returns the time in seconds since some arbitrary starting point.
  1052. Arguments:
  1053. None
  1054. Return Value:
  1055. Time in seconds since some arbitrary starting point.
  1056. --*/
  1057. {
  1058. ULONG TimerTicks;
  1059. TimerTicks = GET_COUNTER();
  1060. return((TimerTicks*10) / 182);
  1061. }
  1062. VOID
  1063. AEReboot(
  1064. VOID
  1065. )
  1066. /*++
  1067. Routine Description:
  1068. Reboots the machine.
  1069. Arguments:
  1070. None
  1071. Return Value:
  1072. Does not return
  1073. --*/
  1074. {
  1075. REBOOT_PROCESSOR();
  1076. }
  1077. ARC_STATUS
  1078. HardDiskPartitionOpen(
  1079. IN ULONG FileId,
  1080. IN ULONG DiskId,
  1081. IN UCHAR PartitionNumber
  1082. )
  1083. /*++
  1084. Routine Description:
  1085. This routine opens the specified partition and sets the partition info
  1086. in the FileTable at the specified index. It does not fill in the
  1087. Device Entry table.
  1088. It reads the partition information until the requested partition
  1089. is found or no more partitions are defined.
  1090. Arguments:
  1091. FileId - Supplies the file id for the file table entry.
  1092. DiskId - Supplies the file id for the physical device.
  1093. PartitionNumber - Supplies the zero-based partition number
  1094. Return Value:
  1095. If a valid partition is found on the hard disk, then ESUCCESS is
  1096. returned. Otherwise, EIO is returned.
  1097. --*/
  1098. {
  1099. USHORT DataBuffer[SECTOR_SIZE / sizeof(USHORT)];
  1100. PPARTITION_DESCRIPTOR Partition;
  1101. ULONG PartitionLength;
  1102. ULONG StartingSector;
  1103. ULONG VolumeOffset;
  1104. ARC_STATUS Status;
  1105. BOOLEAN PrimaryPartitionTable;
  1106. ULONG PartitionOffset=0;
  1107. ULONG PartitionIndex,PartitionCount=0;
  1108. ULONG Count;
  1109. LARGE_INTEGER SeekPosition;
  1110. BlFileTable[FileId].u.PartitionContext.DiskId=(UCHAR)DiskId;
  1111. BlFileTable[FileId].Position.QuadPart=0;
  1112. VolumeOffset=0;
  1113. PrimaryPartitionTable=TRUE;
  1114. //
  1115. // Change to a 1-based partition number
  1116. //
  1117. PartitionNumber++;
  1118. do {
  1119. SeekPosition.QuadPart = (ULONGLONG)PartitionOffset * (ULONGLONG)SECTOR_SIZE;
  1120. Status = (BlFileTable[DiskId].DeviceEntryTable->Seek)(DiskId,
  1121. &SeekPosition,
  1122. SeekAbsolute );
  1123. if (Status != ESUCCESS) {
  1124. return(Status);
  1125. }
  1126. Status = (BlFileTable[DiskId].DeviceEntryTable->Read)(DiskId,
  1127. DataBuffer,
  1128. SECTOR_SIZE,
  1129. &Count );
  1130. if (Status != ESUCCESS) {
  1131. return Status;
  1132. }
  1133. //
  1134. // If sector zero is not a master boot record, then return failure
  1135. // status. Otherwise return success.
  1136. //
  1137. if (DataBuffer[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) {
  1138. #if DBG
  1139. BlPrint(TEXT("Boot record signature %x not found (%x found)\r\n"),
  1140. BOOT_RECORD_SIGNATURE,
  1141. DataBuffer[BOOT_SIGNATURE_OFFSET] );
  1142. #endif
  1143. Status = EIO;
  1144. break;
  1145. }
  1146. //
  1147. // Read the partition information until the four entries are
  1148. // checked or until we found the requested one.
  1149. //
  1150. Partition = (PPARTITION_DESCRIPTOR)&DataBuffer[PARTITION_TABLE_OFFSET];
  1151. for (PartitionIndex=0;
  1152. PartitionIndex < NUM_PARTITION_TABLE_ENTRIES;
  1153. PartitionIndex++,Partition++) {
  1154. //
  1155. // Count first the partitions in the MBR. The units
  1156. // inside the extended partition are counted later.
  1157. //
  1158. if ((Partition->PartitionType != PARTITION_ENTRY_UNUSED) &&
  1159. (Partition->PartitionType != STALE_GPT_PARTITION_ENTRY)
  1160. && !IsContainerPartition(Partition->PartitionType))
  1161. {
  1162. PartitionCount++; // another partition found.
  1163. }
  1164. //
  1165. // Check if the requested partition has already been found.
  1166. // set the partition info in the file table and return.
  1167. //
  1168. if (PartitionCount == PartitionNumber) {
  1169. StartingSector = (ULONG)(Partition->StartingSectorLsb0) |
  1170. (ULONG)(Partition->StartingSectorLsb1 << 8) |
  1171. (ULONG)(Partition->StartingSectorMsb0 << 16) |
  1172. (ULONG)(Partition->StartingSectorMsb1 << 24);
  1173. PartitionLength = (ULONG)(Partition->PartitionLengthLsb0) |
  1174. (ULONG)(Partition->PartitionLengthLsb1 << 8) |
  1175. (ULONG)(Partition->PartitionLengthMsb0 << 16) |
  1176. (ULONG)(Partition->PartitionLengthMsb1 << 24);
  1177. BlFileTable[FileId].u.PartitionContext.PartitionLength.QuadPart =
  1178. (PartitionLength << SECTOR_SHIFT);
  1179. BlFileTable[FileId].u.PartitionContext.StartingSector=PartitionOffset + StartingSector;
  1180. return ESUCCESS;
  1181. }
  1182. }
  1183. //
  1184. // If requested partition was not yet found.
  1185. // Look for an extended partition.
  1186. //
  1187. Partition = (PPARTITION_DESCRIPTOR)&DataBuffer[PARTITION_TABLE_OFFSET];
  1188. PartitionOffset = 0;
  1189. for (PartitionIndex=0;
  1190. PartitionIndex < NUM_PARTITION_TABLE_ENTRIES;
  1191. PartitionIndex++,Partition++) {
  1192. if (IsContainerPartition(Partition->PartitionType)) {
  1193. StartingSector = (ULONG)(Partition->StartingSectorLsb0) |
  1194. (ULONG)(Partition->StartingSectorLsb1 << 8) |
  1195. (ULONG)(Partition->StartingSectorMsb0 << 16) |
  1196. (ULONG)(Partition->StartingSectorMsb1 << 24);
  1197. PartitionOffset = VolumeOffset+StartingSector;
  1198. if (PrimaryPartitionTable) {
  1199. VolumeOffset = StartingSector;
  1200. }
  1201. break; // only one partition can be extended.
  1202. }
  1203. }
  1204. PrimaryPartitionTable = FALSE;
  1205. } while (PartitionOffset != 0);
  1206. return EBADF;
  1207. }
  1208. #if 0
  1209. VOID
  1210. BlpTranslateDosToArc(
  1211. IN PCHAR DosName,
  1212. OUT PCHAR ArcName
  1213. )
  1214. /*++
  1215. Routine Description:
  1216. This routine takes a DOS drive name ("A:" "B:" "C:" etc.) and translates
  1217. it into an ARC name. ("multi(0)disk(0)rdisk(0)partition(1)")
  1218. N.B. This will always return some sort of name suitable for passing
  1219. to BiosPartitionOpen. The name it constructs may not be an
  1220. actual partition. BiosPartitionOpen is responsible for
  1221. determining whether the partition actually exists.
  1222. Since no other driver should ever use ARC names beginning with
  1223. "multi(0)disk(0)..." this will not be a problem. (there is no
  1224. way this routine will construct a name that BiosPartitionOpen
  1225. will not open, but some other random driver will grab and
  1226. successfully open)
  1227. Arguments:
  1228. DosName - Supplies the DOS name of the drive.
  1229. ArcName - Returns the ARC name of the drive.
  1230. Return Value:
  1231. --*/
  1232. {
  1233. ARC_STATUS Status;
  1234. ULONG DriveId;
  1235. ULONG PartitionNumber;
  1236. ULONG PartitionCount;
  1237. ULONG Count;
  1238. USHORT DataBuffer[SECTOR_SIZE / sizeof(USHORT)];
  1239. PPARTITION_DESCRIPTOR Partition;
  1240. ULONG PartitionIndex;
  1241. BOOLEAN HasPrimary;
  1242. LARGE_INTEGER SeekPosition;
  1243. //
  1244. // Eliminate the easy ones first.
  1245. // A: is always "multi(0)disk(0)fdisk(0)partition(0)"
  1246. // B: is always "multi(0)disk(0)fdisk(1)partition(0)"
  1247. // C: is always "multi(0)disk(0)rdisk(0)partition(1)"
  1248. //
  1249. if (_stricmp(DosName,"A:")==0) {
  1250. strcpy(ArcName,"multi(0)disk(0)fdisk(0)partition(0)");
  1251. return;
  1252. }
  1253. if (_stricmp(DosName,"B:")==0) {
  1254. strcpy(ArcName,"multi(0)disk(0)fdisk(1)partition(0)");
  1255. return;
  1256. }
  1257. if (_stricmp(DosName,"C:")==0) {
  1258. strcpy(ArcName,"multi(0)disk(0)rdisk(0)partition(1)");
  1259. return;
  1260. }
  1261. //
  1262. // Now things get more unpleasant. If there are two drives, then
  1263. // D: is the primary partition on the second drive. Successive letters
  1264. // are the secondary partitions on the first drive, then back to the
  1265. // second drive when that runs out.
  1266. //
  1267. // The exception to this is when there is no primary partition on the
  1268. // second drive. Then, we letter the partitions on the first driver
  1269. // consecutively, and when those partitions run out, we letter the
  1270. // partitions on the second drive.
  1271. //
  1272. // I have no idea who came up with this wonderful scheme, but we have
  1273. // to live with it.
  1274. //
  1275. //
  1276. // Try to open the second drive. If this doesn't work, we only have
  1277. // one drive and life is easy.
  1278. //
  1279. Status = ArcOpen("multi(0)disk(0)rdisk(1)partition(0)",
  1280. ArcOpenReadOnly,
  1281. &DriveId );
  1282. if (Status != ESUCCESS) {
  1283. //
  1284. // We only have one drive, so whatever drive letter he's requesting
  1285. // has got to be on it.
  1286. //
  1287. sprintf(ArcName,
  1288. "multi(0)disk(0)rdisk(0)partition(%d)",
  1289. toupper(DosName[0]) - 'C' + 1 );
  1290. return;
  1291. } else {
  1292. //
  1293. // Now we read the partition table off the second drive, so we can
  1294. // tell if there is a primary partition or not.
  1295. //
  1296. SeekPosition.QuadPart = 0;
  1297. Status = ArcSeek(DriveId,
  1298. &SeekPosition,
  1299. SeekAbsolute);
  1300. if (Status != ESUCCESS) {
  1301. ArcName[0]='\0';
  1302. return;
  1303. }
  1304. Status = ArcRead(DriveId, DataBuffer, SECTOR_SIZE, &Count);
  1305. ArcClose(DriveId);
  1306. if (Status != ESUCCESS) {
  1307. ArcName[0] = '\0';
  1308. return;
  1309. }
  1310. HasPrimary = FALSE;
  1311. Partition = (PPARTITION_DESCRIPTOR)&DataBuffer[PARTITION_TABLE_OFFSET];
  1312. for (PartitionIndex = 0;
  1313. PartitionIndex < NUM_PARTITION_TABLE_ENTRIES;
  1314. PartitionIndex++,Partition++) {
  1315. if (IsRecognizedPartition(Partition->PartitionType)) {
  1316. HasPrimary = TRUE;
  1317. }
  1318. }
  1319. //
  1320. // Now we have to go through and count
  1321. // the partitions on the first drive. We do this by just constructing
  1322. // ARC names for each successive partition until one BiosPartitionOpen
  1323. // call fails.
  1324. //
  1325. PartitionCount = 0;
  1326. do {
  1327. ++PartitionCount;
  1328. sprintf(ArcName,
  1329. "multi(0)disk(0)rdisk(0)partition(%d)",
  1330. PartitionCount+1);
  1331. Status = BiosPartitionOpen( ArcName,
  1332. ArcOpenReadOnly,
  1333. &DriveId );
  1334. if (Status==ESUCCESS) {
  1335. BiosPartitionClose(DriveId);
  1336. }
  1337. } while ( Status == ESUCCESS );
  1338. PartitionNumber = toupper(DosName[0])-'C' + 1;
  1339. if (HasPrimary) {
  1340. //
  1341. // There is Windows NT primary partition on the second drive.
  1342. //
  1343. // If the DosName is "D:" then we know
  1344. // this is the first partition on the second drive.
  1345. //
  1346. if (_stricmp(DosName,"D:")==0) {
  1347. strcpy(ArcName,"multi(0)disk(0)rdisk(1)partition(1)");
  1348. return;
  1349. }
  1350. if (PartitionNumber-1 > PartitionCount) {
  1351. PartitionNumber -= PartitionCount;
  1352. sprintf(ArcName,
  1353. "multi(0)disk(0)rdisk(1)partition(%d)",
  1354. PartitionNumber );
  1355. } else {
  1356. sprintf(ArcName,
  1357. "multi(0)disk(0)rdisk(0)partition(%d)",
  1358. PartitionNumber-1);
  1359. }
  1360. } else {
  1361. //
  1362. // There is no primary partition on the second drive, so we
  1363. // consecutively letter the partitions on the first drive,
  1364. // then the second drive.
  1365. //
  1366. if (PartitionNumber > PartitionCount) {
  1367. PartitionNumber -= PartitionCount;
  1368. sprintf(ArcName,
  1369. "multi(0)disk(0)rdisk(1)partition(%d)",
  1370. PartitionNumber );
  1371. } else {
  1372. sprintf(ArcName,
  1373. "multi(0)disk(0)rdisk(0)partition(%d)",
  1374. PartitionNumber);
  1375. }
  1376. }
  1377. return;
  1378. }
  1379. }
  1380. #endif
  1381. VOID
  1382. FwStallExecution(
  1383. IN ULONG Microseconds
  1384. )
  1385. /*++
  1386. Routine Description:
  1387. Does a busy wait for a specified number of microseconds (very approximate!)
  1388. Arguments:
  1389. Microseconds - Supplies the number of microseconds to busy wait.
  1390. Return Value:
  1391. None.
  1392. --*/
  1393. {
  1394. extern EFI_SYSTEM_TABLE *EfiST;
  1395. EfiST->BootServices->Stall( Microseconds );
  1396. }
  1397. BOOLEAN
  1398. FwGetPathMnemonicKey(
  1399. IN PCHAR OpenPath,
  1400. IN PCHAR Mnemonic,
  1401. IN PULONG Key
  1402. )
  1403. /*++
  1404. Routine Description:
  1405. This routine looks for the given Mnemonic in OpenPath.
  1406. If Mnemonic is a component of the path, then it converts the key
  1407. value to an integer wich is returned in Key.
  1408. Arguments:
  1409. OpenPath - Pointer to a string that contains an ARC pathname.
  1410. Mnemonic - Pointer to a string that contains a ARC Mnemonic
  1411. Key - Pointer to a ULONG where the Key value is stored.
  1412. Return Value:
  1413. FALSE if mnemonic is found in path and a valid key is converted.
  1414. TRUE otherwise.
  1415. --*/
  1416. {
  1417. return(BlGetPathMnemonicKey(OpenPath,Mnemonic,Key));
  1418. }
  1419. PCONFIGURATION_COMPONENT
  1420. FwAddChild (
  1421. IN PCONFIGURATION_COMPONENT Component,
  1422. IN PCONFIGURATION_COMPONENT NewComponent,
  1423. IN PVOID ConfigurationData OPTIONAL
  1424. )
  1425. {
  1426. ULONG Size;
  1427. PCONFIGURATION_COMPONENT_DATA NewEntry;
  1428. PCONFIGURATION_COMPONENT_DATA Parent;
  1429. if (Component==NULL) {
  1430. return(NULL);
  1431. }
  1432. Parent = CONTAINING_RECORD(Component,
  1433. CONFIGURATION_COMPONENT_DATA,
  1434. ComponentEntry);
  1435. Size = sizeof(CONFIGURATION_COMPONENT_DATA) +
  1436. NewComponent->IdentifierLength + 1;
  1437. NewEntry = BlAllocateHeap(Size);
  1438. if (NewEntry==NULL) {
  1439. return(NULL);
  1440. }
  1441. RtlCopyMemory(&NewEntry->ComponentEntry,
  1442. NewComponent,
  1443. sizeof(CONFIGURATION_COMPONENT));
  1444. NewEntry->ComponentEntry.Identifier = (PUCHAR)(NewEntry+1);
  1445. NewEntry->ComponentEntry.ConfigurationDataLength = 0;
  1446. strncpy(NewEntry->ComponentEntry.Identifier,
  1447. NewComponent->Identifier,
  1448. NewComponent->IdentifierLength);
  1449. //
  1450. // Add the new component as the first child of its parent.
  1451. //
  1452. NewEntry->Child = NULL;
  1453. NewEntry->Sibling = Parent->Child;
  1454. Parent->Child = NewEntry;
  1455. return(&NewEntry->ComponentEntry);
  1456. }
  1457. PCONFIGURATION_COMPONENT
  1458. FwGetComponent(
  1459. IN PCHAR Pathname
  1460. )
  1461. {
  1462. PCONFIGURATION_COMPONENT Component;
  1463. PCONFIGURATION_COMPONENT MatchComponent;
  1464. PCHAR PathString;
  1465. PCHAR MatchString;
  1466. PCHAR Token;
  1467. ULONG Key;
  1468. PathString = Pathname;
  1469. //
  1470. // Get the the root component.
  1471. //
  1472. MatchComponent = FwGetChild(NULL);
  1473. //
  1474. // Repeat search for each new match component.
  1475. //
  1476. do {
  1477. //
  1478. // Get the first child of the current match component.
  1479. //
  1480. Component = FwGetChild( MatchComponent );
  1481. //
  1482. // Search each child of the current match component for the next match.
  1483. //
  1484. while ( Component != NULL ) {
  1485. //
  1486. // Reset Token to be the current position on the pathname.
  1487. //
  1488. Token = PathString;
  1489. MatchString = MnemonicTable[Component->Type];
  1490. //
  1491. // Compare strings.
  1492. //
  1493. while (*MatchString == tolower(*Token)) {
  1494. MatchString++;
  1495. Token++;
  1496. }
  1497. //
  1498. // Strings compare if the first mismatch is the terminator for
  1499. // each.
  1500. //
  1501. if ((*MatchString == 0) && (*Token == '(')) {
  1502. //
  1503. // Form key.
  1504. //
  1505. Key = 0;
  1506. Token++;
  1507. while ((*Token != ')') && (*Token != 0)) {
  1508. Key = (Key * 10) + *Token++ - '0';
  1509. }
  1510. //
  1511. // If the key matches the component matches, so update
  1512. // pointers and break.
  1513. //
  1514. if (Component->Key == Key) {
  1515. PathString = Token + 1;
  1516. MatchComponent = Component;
  1517. break;
  1518. }
  1519. }
  1520. Component = FwGetPeer( Component );
  1521. }
  1522. } while ((Component != NULL) && (*PathString != 0));
  1523. return MatchComponent;
  1524. }