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.

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