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.

2963 lines
74 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. John Vert (jvert) 13-Jun-1991
  13. Environment:
  14. x86 only
  15. Revision History:
  16. --*/
  17. #include "arccodes.h"
  18. #include "bootx86.h"
  19. #include "ntdddisk.h"
  20. #include "string.h"
  21. #include "stdio.h"
  22. #include "stdlib.h"
  23. #include "scsi.h"
  24. #include "scsiboot.h"
  25. #include "ramdisk.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. BOOLEAN AEBiosDisabled = FALSE;
  37. // spew UTF8 data over the headless port on FE builds.
  38. #define UTF8_CLIENT_SUPPORT (1)
  39. BOOLEAN AEArcDiskInformationInitialized = FALSE;
  40. ARC_DISK_INFORMATION AEArcDiskInformation;
  41. PDRIVER_UNLOAD AEDriverUnloadRoutine = NULL;
  42. #define PORT_BUFFER_SIZE 10
  43. UCHAR PortBuffer[PORT_BUFFER_SIZE];
  44. ULONG PortBufferStart = 0;
  45. ULONG PortBufferEnd = 0;
  46. //
  47. // Macro for aligning buffers. It returns the aligned pointer into the
  48. // buffer. Buffer should be of size you want to use + alignment.
  49. //
  50. #define ALIGN_BUFFER_ON_BOUNDARY(Buffer,Alignment) ((PVOID) \
  51. ((((ULONG_PTR)(Buffer) + (Alignment) - 1)) & (~((ULONG_PTR)(Alignment) - 1))))
  52. //
  53. // Miniport DriverEntry typedef
  54. //
  55. typedef NTSTATUS
  56. (*PDRIVER_ENTRY) (
  57. IN PDRIVER_OBJECT DriverObject,
  58. IN PVOID Parameter2
  59. );
  60. typedef
  61. BOOLEAN
  62. (*PFWNODE_CALLBACK)(
  63. IN PCONFIGURATION_COMPONENT FoundComponent
  64. );
  65. //
  66. // Private function prototypes
  67. //
  68. ARC_STATUS
  69. BlArcNotYetImplemented(
  70. IN ULONG FileId
  71. );
  72. PCONFIGURATION_COMPONENT
  73. AEComponentInfo(
  74. IN PCONFIGURATION_COMPONENT Current
  75. );
  76. PCONFIGURATION_COMPONENT
  77. FwGetChild(
  78. IN PCONFIGURATION_COMPONENT Current
  79. );
  80. BOOLEAN
  81. FwSearchTree(
  82. IN PCONFIGURATION_COMPONENT Node,
  83. IN CONFIGURATION_CLASS Class,
  84. IN CONFIGURATION_TYPE Type,
  85. IN ULONG Key,
  86. IN PFWNODE_CALLBACK CallbackRoutine
  87. );
  88. PCHAR
  89. AEGetEnvironment(
  90. IN PCHAR Variable
  91. );
  92. PCONFIGURATION_COMPONENT
  93. FwGetPeer(
  94. IN PCONFIGURATION_COMPONENT Current
  95. );
  96. BOOLEAN
  97. AEEnumerateDisks(
  98. PCONFIGURATION_COMPONENT Disk
  99. );
  100. VOID
  101. AEGetArcDiskInformation(
  102. VOID
  103. );
  104. VOID
  105. AEGetPathnameFromComponent(
  106. IN PCONFIGURATION_COMPONENT Component,
  107. OUT PCHAR ArcName
  108. );
  109. PCONFIGURATION_COMPONENT
  110. AEGetParent(
  111. IN PCONFIGURATION_COMPONENT Current
  112. );
  113. ARC_STATUS
  114. AEGetConfigurationData(
  115. IN PVOID ConfigurationData,
  116. IN PCONFIGURATION_COMPONENT Current
  117. );
  118. PMEMORY_DESCRIPTOR
  119. AEGetMemoryDescriptor(
  120. IN PMEMORY_DESCRIPTOR MemoryDescriptor OPTIONAL
  121. );
  122. ARC_STATUS
  123. AEOpen(
  124. IN PCHAR OpenPath,
  125. IN OPEN_MODE OpenMode,
  126. OUT PULONG FileId
  127. );
  128. ARC_STATUS
  129. AEClose(
  130. IN ULONG FileId
  131. );
  132. ARC_STATUS
  133. AERead (
  134. IN ULONG FileId,
  135. OUT PVOID Buffer,
  136. IN ULONG Length,
  137. OUT PULONG Count
  138. );
  139. ARC_STATUS
  140. AEReadStatus (
  141. IN ULONG FileId
  142. );
  143. VOID
  144. AEReboot(
  145. VOID
  146. );
  147. ARC_STATUS
  148. AESeek (
  149. IN ULONG FileId,
  150. IN PLARGE_INTEGER Offset,
  151. IN SEEK_MODE SeekMode
  152. );
  153. ARC_STATUS
  154. AEWrite (
  155. IN ULONG FileId,
  156. OUT PVOID Buffer,
  157. IN ULONG Length,
  158. OUT PULONG Count
  159. );
  160. ARC_STATUS
  161. AEGetFileInformation(
  162. IN ULONG FileId,
  163. OUT PFILE_INFORMATION FileInformation
  164. );
  165. PTIME_FIELDS
  166. AEGetTime(
  167. VOID
  168. );
  169. ULONG
  170. AEGetRelativeTime(
  171. VOID
  172. );
  173. ARC_STATUS
  174. ScsiDiskClose (
  175. IN ULONG FileId
  176. );
  177. ARC_STATUS
  178. ScsiDiskMount (
  179. IN PCHAR MountPath,
  180. IN MOUNT_OPERATION Operation
  181. );
  182. ARC_STATUS
  183. ScsiDiskOpen (
  184. IN PCHAR OpenPath,
  185. IN OPEN_MODE OpenMode,
  186. OUT PULONG FileId
  187. );
  188. ARC_STATUS
  189. ScsiDiskRead (
  190. IN ULONG FileId,
  191. IN PVOID Buffer,
  192. IN ULONG Length,
  193. OUT PULONG Count
  194. );
  195. ARC_STATUS
  196. ScsiDiskSeek (
  197. IN ULONG FileId,
  198. IN PLARGE_INTEGER Offset,
  199. IN SEEK_MODE SeekMode
  200. );
  201. ARC_STATUS
  202. ScsiDiskWrite (
  203. IN ULONG FileId,
  204. IN PVOID Buffer,
  205. IN ULONG Length,
  206. OUT PULONG Count
  207. );
  208. VOID
  209. HardDiskInitialize(
  210. IN OUT PVOID LookupTable,
  211. IN ULONG Entries,
  212. IN PVOID DeviceFoundCallback
  213. );
  214. BOOLEAN
  215. AEReadDiskSignature(
  216. IN PCHAR DiskName,
  217. IN BOOLEAN IsCdRom
  218. );
  219. //
  220. // This is the x86 version of the system parameter block on the ARC machines.
  221. // It lives here, and any module that uses an ArcXXXX routine must declare
  222. // it external. Machines that have other than very plain-vanilla hardware
  223. // may have to replace some of the hard-wired vectors with different
  224. // procedures.
  225. //
  226. PVOID GlobalFirmwareVectors[MaximumRoutine];
  227. SYSTEM_PARAMETER_BLOCK GlobalSystemBlock =
  228. {
  229. 0, // Signature??
  230. sizeof(SYSTEM_PARAMETER_BLOCK), // Length
  231. 0, // Version
  232. 0, // Revision
  233. NULL, // RestartBlock
  234. NULL, // DebugBlock
  235. NULL, // GenerateExceptionVector
  236. NULL, // TlbMissExceptionVector
  237. MaximumRoutine, // FirmwareVectorLength
  238. GlobalFirmwareVectors, // Pointer to vector block
  239. 0, // VendorVectorLength
  240. NULL // Pointer to vendor vector block
  241. };
  242. extern BL_FILE_TABLE BlFileTable[BL_FILE_TABLE_SIZE];
  243. //
  244. // temptemp John Vert (jvert) 6-Sep-1991
  245. // Just do this until we can make our device driver interface look
  246. // like the ARC firmware one.
  247. //
  248. extern BL_DEVICE_ENTRY_TABLE ScsiDiskEntryTable;
  249. ULONG FwStallCounter;
  250. //
  251. // This table provides a quick lookup conversion between ASCII values
  252. // that fall between 128 and 255, and their UNICODE counterpart.
  253. //
  254. // Note that ASCII values between 0 and 127 are equvilent to their
  255. // unicode counter parts, so no lookups would be required.
  256. //
  257. // Therefore when using this table, remove the high bit from the ASCII
  258. // value and use the resulting value as an offset into this array. For
  259. // example, 0x80 ->(remove the high bit) 00 -> 0x00C7.
  260. //
  261. USHORT PcAnsiToUnicode[0xFF] = {
  262. 0x00C7,
  263. 0x00FC,
  264. 0x00E9,
  265. 0x00E2,
  266. 0x00E4,
  267. 0x00E0,
  268. 0x00E5,
  269. 0x0087,
  270. 0x00EA,
  271. 0x00EB,
  272. 0x00E8,
  273. 0x00EF,
  274. 0x00EE,
  275. 0x00EC,
  276. 0x00C4,
  277. 0x00C5,
  278. 0x00C9,
  279. 0x00E6,
  280. 0x00C6,
  281. 0x00F4,
  282. 0x00F6,
  283. 0x00F2,
  284. 0x00FB,
  285. 0x00F9,
  286. 0x00FF,
  287. 0x00D6,
  288. 0x00DC,
  289. 0x00A2,
  290. 0x00A3,
  291. 0x00A5,
  292. 0x20A7,
  293. 0x0192,
  294. 0x00E1,
  295. 0x00ED,
  296. 0x00F3,
  297. 0x00FA,
  298. 0x00F1,
  299. 0x00D1,
  300. 0x00AA,
  301. 0x00BA,
  302. 0x00BF,
  303. 0x2310,
  304. 0x00AC,
  305. 0x00BD,
  306. 0x00BC,
  307. 0x00A1,
  308. 0x00AB,
  309. 0x00BB,
  310. 0x2591,
  311. 0x2592,
  312. 0x2593,
  313. 0x2502,
  314. 0x2524,
  315. 0x2561,
  316. 0x2562,
  317. 0x2556,
  318. 0x2555,
  319. 0x2563,
  320. 0x2551,
  321. 0x2557,
  322. 0x255D,
  323. 0x255C,
  324. 0x255B,
  325. 0x2510,
  326. 0x2514,
  327. 0x2534,
  328. 0x252C,
  329. 0x251C,
  330. 0x2500,
  331. 0x253C,
  332. 0x255E,
  333. 0x255F,
  334. 0x255A,
  335. 0x2554,
  336. 0x2569,
  337. 0x2566,
  338. 0x2560,
  339. 0x2550,
  340. 0x256C,
  341. 0x2567,
  342. 0x2568,
  343. 0x2564,
  344. 0x2565,
  345. 0x2559,
  346. 0x2558,
  347. 0x2552,
  348. 0x2553,
  349. 0x256B,
  350. 0x256A,
  351. 0x2518,
  352. 0x250C,
  353. 0x2588,
  354. 0x2584,
  355. 0x258C,
  356. 0x2590,
  357. 0x2580,
  358. 0x03B1,
  359. 0x00DF,
  360. 0x0393,
  361. 0x03C0,
  362. 0x03A3,
  363. 0x03C3,
  364. 0x00B5,
  365. 0x03C4,
  366. 0x03A6,
  367. 0x0398,
  368. 0x03A9,
  369. 0x03B4,
  370. 0x221E,
  371. 0x03C6,
  372. 0x03B5,
  373. 0x2229,
  374. 0x2261,
  375. 0x00B1,
  376. 0x2265,
  377. 0x2264,
  378. 0x2320,
  379. 0x2321,
  380. 0x00F7,
  381. 0x2248,
  382. 0x00B0,
  383. 0x2219,
  384. 0x00B7,
  385. 0x221A,
  386. 0x207F,
  387. 0x00B2,
  388. 0x25A0,
  389. 0x00A0
  390. };
  391. VOID
  392. AEInitializeStall(
  393. VOID
  394. )
  395. {
  396. FwStallCounter = GET_STALL_COUNT();
  397. return;
  398. }
  399. ARC_STATUS
  400. AEInitializeIo(
  401. IN ULONG DriveId
  402. )
  403. /*++
  404. Routine Description:
  405. Initializes SCSI boot driver, if any. Loads ntbootdd.sys from the
  406. boot partition, binds it to the osloader, and initializes it.
  407. Arguments:
  408. DriveId - file id of the opened boot partition
  409. Return Value:
  410. ESUCCESS - Drivers successfully initialized
  411. --*/
  412. {
  413. extern ULONG ScsiPortCount;
  414. extern ULONG MachineType;
  415. ARC_STATUS Status;
  416. PVOID Buffer;
  417. PVOID ImageBase;
  418. PKLDR_DATA_TABLE_ENTRY DriverDataTableEntry;
  419. PDRIVER_ENTRY Entry;
  420. extern MEMORY_DESCRIPTOR MDArray[];
  421. ScsiPortCount = 0;
  422. FwStallCounter = GET_STALL_COUNT();
  423. Status = BlLoadImage(DriveId,
  424. MemoryFirmwarePermanent,
  425. "\\NTBOOTDD.SYS",
  426. TARGET_IMAGE,
  427. &ImageBase);
  428. if (Status != ESUCCESS) {
  429. return(Status);
  430. }
  431. //
  432. // Find the memory descriptor for this entry in the table in the loader
  433. // block and then allocate it in the MD array.
  434. //
  435. {
  436. ULONG imageBasePage;
  437. ULONG imageEndPage = 0;
  438. PLIST_ENTRY entry;
  439. imageBasePage = (((ULONG)ImageBase) & 0x7fffffff) >> PAGE_SHIFT;
  440. entry = BlLoaderBlock->MemoryDescriptorListHead.Flink;
  441. while(entry != &(BlLoaderBlock->MemoryDescriptorListHead)) {
  442. PMEMORY_ALLOCATION_DESCRIPTOR descriptor;
  443. descriptor = CONTAINING_RECORD(entry,
  444. MEMORY_ALLOCATION_DESCRIPTOR,
  445. ListEntry);
  446. if(descriptor->BasePage == imageBasePage) {
  447. imageEndPage = imageBasePage + descriptor->PageCount;
  448. break;
  449. }
  450. entry = entry->Flink;
  451. }
  452. if(imageEndPage == 0) {
  453. return EINVAL;
  454. }
  455. Status = MempAllocDescriptor(imageBasePage,
  456. imageEndPage,
  457. MemoryFirmwareTemporary);
  458. if(Status != ESUCCESS) {
  459. return EINVAL;
  460. }
  461. }
  462. Status = BlAllocateDataTableEntry("NTBOOTDD.SYS",
  463. "\\NTBOOTDD.SYS",
  464. ImageBase,
  465. &DriverDataTableEntry);
  466. if (Status != ESUCCESS) {
  467. return(Status);
  468. }
  469. //
  470. // [ChuckL 2001-Dec-04]
  471. // BlAllocateDataTableEntry inserts the data table entry for NTBOOTDD.SYS
  472. // into BlLoaderBlock->LoadOrderListHead. We don't want this, for at least
  473. // two reasons:
  474. //
  475. // 1) This entry is only temporarily loaded for use by the loader. We
  476. // don't want the kernel to think that it's loaded.
  477. //
  478. // 2) There is code in the kernel (MM) that assumes that the first two
  479. // entries in the list are the kernel and HAL. But we've just
  480. // inserted ntbootdd.sys as the first entry. This really screws up
  481. // MM, because it ends up moving the HAL as if it were a loaded
  482. // driver.
  483. //
  484. // Prior to a change to boot\bldr\osloader.c, the routine BlMemoryInitialize()
  485. // was called twice during loader init. The second call occurred after ntbootdd
  486. // was loaded, and reinitialized the LoadOrderListHead, thereby eliminating (by
  487. // accident) ntbootdd from the module list. Now we don't do the second memory
  488. // initialization, so we have to explicitly remove ntbootdd from the list.
  489. //
  490. RemoveEntryList(&DriverDataTableEntry->InLoadOrderLinks);
  491. //
  492. // Scan the import table and bind to osloader
  493. //
  494. Status = BlScanOsloaderBoundImportTable(DriverDataTableEntry);
  495. if (Status != ESUCCESS) {
  496. return(Status);
  497. }
  498. Entry = (PDRIVER_ENTRY)DriverDataTableEntry->EntryPoint;
  499. //
  500. // Before calling into the driver we need to collect ARC info blocks
  501. // for all the bios based devices.
  502. //
  503. AEGetArcDiskInformation();
  504. //
  505. // Zero out the driver object.
  506. //
  507. Status = (*Entry)(NULL, NULL);
  508. if (Status == ESUCCESS) {
  509. Buffer = FwAllocateHeap(SIZE_FOR_SUPPORTED_DISK_STRUCTURE);
  510. if(Buffer == NULL) {
  511. return ENOMEM;
  512. }
  513. HardDiskInitialize(Buffer, SUPPORTED_NUMBER_OF_DISKS, NULL);
  514. }
  515. if(Status == ESUCCESS) {
  516. AEBiosDisabled = TRUE;
  517. }
  518. return(Status);
  519. }
  520. VOID
  521. BlFillInSystemParameters(
  522. IN PBOOT_CONTEXT BootContextRecord
  523. )
  524. /*++
  525. Routine Description:
  526. This routine fills in all the fields in the Global System Parameter Block
  527. that it can. This includes all the firmware vectors, the vendor-specific
  528. information, and anything else that may come up.
  529. Arguments:
  530. None.
  531. Return Value:
  532. None.
  533. --*/
  534. {
  535. int cnt;
  536. //
  537. // Fill in the pointers to the firmware functions which we emulate.
  538. // Those which we don't emulate are stubbed by BlArcNotYetImplemented,
  539. // which will print an error message if it is accidentally called.
  540. //
  541. for (cnt=0; cnt<MaximumRoutine; cnt++) {
  542. GlobalFirmwareVectors[cnt]=(PVOID)BlArcNotYetImplemented;
  543. }
  544. GlobalFirmwareVectors[CloseRoutine] = (PVOID)AEClose;
  545. GlobalFirmwareVectors[OpenRoutine] = (PVOID)AEOpen;
  546. GlobalFirmwareVectors[MemoryRoutine]= (PVOID)AEGetMemoryDescriptor;
  547. GlobalFirmwareVectors[SeekRoutine] = (PVOID)AESeek;
  548. GlobalFirmwareVectors[ReadRoutine] = (PVOID)AERead;
  549. GlobalFirmwareVectors[ReadStatusRoutine] = (PVOID)AEReadStatus;
  550. GlobalFirmwareVectors[WriteRoutine] = (PVOID)AEWrite;
  551. GlobalFirmwareVectors[GetFileInformationRoutine] = (PVOID)AEGetFileInformation;
  552. GlobalFirmwareVectors[GetTimeRoutine] = (PVOID)AEGetTime;
  553. GlobalFirmwareVectors[GetRelativeTimeRoutine] = (PVOID)AEGetRelativeTime;
  554. GlobalFirmwareVectors[GetPeerRoutine] = (PVOID)FwGetPeer;
  555. GlobalFirmwareVectors[GetChildRoutine] = (PVOID)FwGetChild;
  556. GlobalFirmwareVectors[GetParentRoutine] = (PVOID)AEGetParent;
  557. GlobalFirmwareVectors[GetComponentRoutine] = (PVOID)FwGetComponent;
  558. GlobalFirmwareVectors[GetDataRoutine] = (PVOID)AEGetConfigurationData;
  559. GlobalFirmwareVectors[GetEnvironmentRoutine] = (PVOID)AEGetEnvironment;
  560. GlobalFirmwareVectors[RestartRoutine] = (PVOID)AEReboot;
  561. GlobalFirmwareVectors[RebootRoutine] = (PVOID)AEReboot;
  562. }
  563. PMEMORY_DESCRIPTOR
  564. AEGetMemoryDescriptor(
  565. IN PMEMORY_DESCRIPTOR MemoryDescriptor OPTIONAL
  566. )
  567. /*++
  568. Routine Description:
  569. Emulates the Arc GetMemoryDescriptor call. This must translate
  570. between the memory description passed to us by the SU module and
  571. the MEMORYDESCRIPTOR type defined by ARC.
  572. Arguments:
  573. MemoryDescriptor - Supplies current memory descriptor.
  574. If MemoryDescriptor==NULL, return the first memory descriptor.
  575. If MemoryDescriptor!=NULL, return the next memory descriptor.
  576. Return Value:
  577. Next memory descriptor in the list.
  578. NULL if MemoryDescriptor is the last descriptor in the list.
  579. --*/
  580. {
  581. extern MEMORY_DESCRIPTOR MDArray[];
  582. extern ULONG NumberDescriptors;
  583. PMEMORY_DESCRIPTOR Return;
  584. if (MemoryDescriptor==NULL) {
  585. Return=MDArray;
  586. } else {
  587. if((ULONG)(MemoryDescriptor-MDArray) >= (NumberDescriptors-1)) {
  588. return NULL;
  589. } else {
  590. Return = ++MemoryDescriptor;
  591. }
  592. }
  593. return(Return);
  594. }
  595. ARC_STATUS
  596. BlArcNotYetImplemented(
  597. IN ULONG FileId
  598. )
  599. /*++
  600. Routine Description:
  601. This is a stub routine used to fill in the firmware vectors which haven't
  602. been defined yet. It uses BlPrint to print a message on the screen.
  603. Arguments:
  604. None.
  605. Return Value:
  606. EINVAL
  607. --*/
  608. {
  609. BlPrint("ERROR - Unimplemented Firmware Vector called (FID %lx)\n",
  610. FileId );
  611. return(EINVAL);
  612. }
  613. PCONFIGURATION_COMPONENT
  614. FwGetChild(
  615. IN PCONFIGURATION_COMPONENT Current
  616. )
  617. /*++
  618. Routine Description:
  619. This is the arc emulation routine for GetChild. Based on the current
  620. component, it returns the component's child component.
  621. Arguments:
  622. Current - Supplies pointer to the current configuration component
  623. Return Value:
  624. A pointer to a CONFIGURATION_COMPONENT structure OR
  625. NULL - No more configuration information
  626. --*/
  627. {
  628. PCONFIGURATION_COMPONENT_DATA CurrentEntry;
  629. //
  630. // if current component is NULL, return a pointer to first system
  631. // component; otherwise return current component's child component.
  632. //
  633. if (Current) {
  634. CurrentEntry = CONTAINING_RECORD(Current,
  635. CONFIGURATION_COMPONENT_DATA,
  636. ComponentEntry);
  637. if (CurrentEntry->Child) {
  638. return(&(CurrentEntry->Child->ComponentEntry));
  639. } else {
  640. return(NULL);
  641. }
  642. } else {
  643. if (FwConfigurationTree) {
  644. return(&(FwConfigurationTree->ComponentEntry));
  645. } else {
  646. return(NULL);
  647. }
  648. }
  649. }
  650. PCONFIGURATION_COMPONENT
  651. FwGetPeer(
  652. IN PCONFIGURATION_COMPONENT Current
  653. )
  654. /*++
  655. Routine Description:
  656. This is the arc emulation routine for GetPeer. Based on the current
  657. component, it returns the component's sibling.
  658. Arguments:
  659. Current - Supplies pointer to the current configuration component
  660. Return Value:
  661. A pointer to a CONFIGURATION_COMPONENT structure OR
  662. NULL - No more configuration information
  663. --*/
  664. {
  665. PCONFIGURATION_COMPONENT_DATA CurrentEntry;
  666. if (Current) {
  667. CurrentEntry = CONTAINING_RECORD(Current,
  668. CONFIGURATION_COMPONENT_DATA,
  669. ComponentEntry);
  670. if (CurrentEntry->Sibling) {
  671. return(&(CurrentEntry->Sibling->ComponentEntry));
  672. } else {
  673. return(NULL);
  674. }
  675. } else {
  676. return(NULL);
  677. }
  678. }
  679. PCONFIGURATION_COMPONENT
  680. AEGetParent(
  681. IN PCONFIGURATION_COMPONENT Current
  682. )
  683. /*++
  684. Routine Description:
  685. This is the arc emulation routine for GetParent. Based on the current
  686. component, it returns the component's parent.
  687. Arguments:
  688. Current - Supplies pointer to the current configuration component
  689. Return Value:
  690. A pointer to a CONFIGURATION_COMPONENT structure OR
  691. NULL - No more configuration information
  692. --*/
  693. {
  694. PCONFIGURATION_COMPONENT_DATA CurrentEntry;
  695. if (Current) {
  696. CurrentEntry = CONTAINING_RECORD(Current,
  697. CONFIGURATION_COMPONENT_DATA,
  698. ComponentEntry);
  699. if (CurrentEntry->Parent) {
  700. return(&(CurrentEntry->Parent->ComponentEntry));
  701. } else {
  702. return(NULL);
  703. }
  704. } else {
  705. return(NULL);
  706. }
  707. }
  708. ARC_STATUS
  709. AEGetConfigurationData(
  710. IN PVOID ConfigurationData,
  711. IN PCONFIGURATION_COMPONENT Current
  712. )
  713. /*++
  714. Routine Description:
  715. This is the arc emulation routine for GetParent. Based on the current
  716. component, it returns the component's parent.
  717. Arguments:
  718. Current - Supplies pointer to the current configuration component
  719. Return Value:
  720. ESUCCESS - Data successfully returned.
  721. --*/
  722. {
  723. PCONFIGURATION_COMPONENT_DATA CurrentEntry;
  724. if (Current) {
  725. CurrentEntry = CONTAINING_RECORD(Current,
  726. CONFIGURATION_COMPONENT_DATA,
  727. ComponentEntry);
  728. RtlMoveMemory(ConfigurationData,
  729. CurrentEntry->ConfigurationData,
  730. Current->ConfigurationDataLength);
  731. return(ESUCCESS);
  732. } else {
  733. return(EINVAL);
  734. }
  735. }
  736. PCHAR
  737. AEGetEnvironment(
  738. IN PCHAR Variable
  739. )
  740. /*++
  741. Routine Description:
  742. This is the arc emulation routine for ArcGetEnvironment. It returns
  743. the value of the specified NVRAM environment variable.
  744. NOTE John Vert (jvert) 23-Apr-1992
  745. This particular implementation uses the Daylight Savings Bit on
  746. the Real Time Clock to reflect the state of the LastKnownGood
  747. environment variable. This is the only variable we support.
  748. Arguments:
  749. Variable - Supplies the name of the environment variable to look up.
  750. Return Value:
  751. A pointer to the specified environment variable's value, or
  752. NULL if the variable does not exist.
  753. --*/
  754. {
  755. UCHAR StatusByte;
  756. if (_stricmp(Variable, "LastKnownGood") != 0) {
  757. return(NULL);
  758. }
  759. //
  760. // Read the Daylight Savings Bit out of the RTC to determine whether
  761. // the LastKnownGood environment variable is TRUE or FALSE.
  762. //
  763. WRITE_PORT_UCHAR(CMOS_CONTROL_PORT, CMOS_STATUS_B);
  764. StatusByte = READ_PORT_UCHAR(CMOS_DATA_PORT);
  765. if (StatusByte & CMOS_DAYLIGHT_BIT) {
  766. return("TRUE");
  767. } else {
  768. return(NULL);
  769. }
  770. }
  771. ARC_STATUS
  772. AEOpen(
  773. IN PCHAR OpenPath,
  774. IN OPEN_MODE OpenMode,
  775. OUT PULONG FileId
  776. )
  777. /*++
  778. Routine Description:
  779. Opens the file or device specified by OpenPath.
  780. Arguments:
  781. OpenPath - Supplies a pointer to the fully-qualified path name.
  782. OpenMode - Supplies the mode to open the file.
  783. 0 - Read Only
  784. 1 - Write Only
  785. 2 - Read/Write
  786. FileId - Returns the file descriptor for use with the Close, Read, Write,
  787. and Seek routines
  788. Return Value:
  789. ESUCCESS - File successfully opened.
  790. --*/
  791. {
  792. ARC_STATUS Status;
  793. CHAR Buffer[128];
  794. Status = RamdiskOpen( OpenPath,
  795. OpenMode,
  796. FileId );
  797. if (Status == ESUCCESS) {
  798. return(ESUCCESS);
  799. }
  800. Status = BiosConsoleOpen( OpenPath,
  801. OpenMode,
  802. FileId );
  803. if (Status == ESUCCESS) {
  804. return(ESUCCESS);
  805. }
  806. //
  807. // Once a disk driver has been loaded we need to disable bios access to
  808. // all drives to avoid mixing bios & driver i/o operations.
  809. //
  810. if(AEBiosDisabled == FALSE) {
  811. Status = BiosPartitionOpen( OpenPath,
  812. OpenMode,
  813. FileId );
  814. if (Status == ESUCCESS) {
  815. return(ESUCCESS);
  816. }
  817. }
  818. //
  819. // It's not the console or a BIOS partition, so let's try the SCSI
  820. // driver.
  821. //
  822. //
  823. // Find a free FileId
  824. //
  825. *FileId = 2;
  826. while (BlFileTable[*FileId].Flags.Open == 1) {
  827. *FileId += 1;
  828. if (*FileId == BL_FILE_TABLE_SIZE) {
  829. return(ENOENT);
  830. }
  831. }
  832. strcpy(Buffer,OpenPath);
  833. Status = ScsiDiskOpen( Buffer,
  834. OpenMode,
  835. FileId );
  836. if (Status == ESUCCESS) {
  837. //
  838. // SCSI successfully opened it. For now, we stick the appropriate
  839. // SCSI DeviceEntryTable into the BlFileTable. This is temporary.
  840. //
  841. BlFileTable[*FileId].Flags.Open = 1;
  842. BlFileTable[*FileId].DeviceEntryTable = &ScsiDiskEntryTable;
  843. return(ESUCCESS);
  844. }
  845. return(Status);
  846. }
  847. ARC_STATUS
  848. AESeek (
  849. IN ULONG FileId,
  850. IN PLARGE_INTEGER Offset,
  851. IN SEEK_MODE SeekMode
  852. )
  853. /*++
  854. Routine Description:
  855. Changes the current offset of the file specified by FileId
  856. Arguments:
  857. FileId - specifies the file on which the current offset is to
  858. be changed.
  859. Offset - New offset into file.
  860. SeekMode - Either SeekAbsolute or SeekRelative
  861. SeekEndRelative is not supported
  862. Return Value:
  863. ESUCCESS - Operation completed succesfully
  864. EBADF - Operation did not complete successfully.
  865. --*/
  866. {
  867. return(BlFileTable[FileId].DeviceEntryTable->Seek)( FileId,
  868. Offset,
  869. SeekMode );
  870. }
  871. ARC_STATUS
  872. AEClose (
  873. IN ULONG FileId
  874. )
  875. /*++
  876. Routine Description:
  877. Closes the file specified by FileId
  878. Arguments:
  879. FileId - specifies the file to close
  880. Return Value:
  881. ESUCCESS - Operation completed succesfully
  882. EBADF - Operation did not complete successfully.
  883. --*/
  884. {
  885. return(BlFileTable[FileId].DeviceEntryTable->Close)(FileId);
  886. }
  887. ARC_STATUS
  888. AEReadStatus(
  889. IN ULONG FileId
  890. )
  891. /*++
  892. Routine Description:
  893. Determines if data is available on the specified device
  894. Arguments:
  895. FileId - Specifies the device to check for data.
  896. Return Value:
  897. ESUCCESS - At least one byte is available.
  898. EAGAIN - No data is available
  899. --*/
  900. {
  901. //
  902. // Special case for console input
  903. //
  904. if (FileId == 0) {
  905. //
  906. // Give priority to dumb terminal
  907. //
  908. if (BlIsTerminalConnected() && (PortBufferStart != PortBufferEnd)) {
  909. return(ESUCCESS);
  910. }
  911. if (BlIsTerminalConnected() && (BlPortPollOnly(BlTerminalDeviceId) == CP_GET_SUCCESS)) {
  912. return(ESUCCESS);
  913. }
  914. return(BiosConsoleReadStatus(FileId));
  915. } else {
  916. return(BlArcNotYetImplemented(FileId));
  917. }
  918. }
  919. ARC_STATUS
  920. AERead (
  921. IN ULONG FileId,
  922. OUT PVOID Buffer,
  923. IN ULONG Length,
  924. OUT PULONG Count
  925. )
  926. /*++
  927. Routine Description:
  928. Reads from the specified file or device
  929. Arguments:
  930. FileId - specifies the file to read from
  931. Buffer - Address of buffer to hold the data that is read
  932. Length - Maximum number of bytes to read
  933. Count - Address of location in which to store the actual bytes read.
  934. Return Value:
  935. ESUCCESS - Read completed successfully
  936. !ESUCCESS - Read failed.
  937. --*/
  938. {
  939. ARC_STATUS Status;
  940. ULONG Limit;
  941. ULONG PartCount;
  942. PCHAR TmpBuffer;
  943. ULONG StartTime;
  944. ULONG LastTime;
  945. UCHAR Ch;
  946. //
  947. // Special case console input
  948. //
  949. if (FileId == 0) {
  950. RetryRead:
  951. if (BlIsTerminalConnected()) {
  952. *Count = 0;
  953. TmpBuffer = (PCHAR)Buffer;
  954. while (*Count < Length) {
  955. //
  956. // First return any buffered input
  957. //
  958. if (PortBufferStart != PortBufferEnd) {
  959. TmpBuffer[*Count] = PortBuffer[PortBufferStart];
  960. PortBufferStart++;
  961. PortBufferStart = PortBufferStart % PORT_BUFFER_SIZE;
  962. *Count = *Count + 1;
  963. continue;
  964. }
  965. //
  966. // Now check for new input
  967. //
  968. if (BlPortPollByte(BlTerminalDeviceId, TmpBuffer + *Count) != CP_GET_SUCCESS) {
  969. break;
  970. }
  971. //
  972. // Convert ESC key to the local equivalent
  973. //
  974. if (TmpBuffer[*Count] == 0x1b) {
  975. TmpBuffer[*Count] = (CHAR)ASCI_CSI_IN;
  976. //
  977. // Wait for the user to type a key.
  978. //
  979. StartTime = AEGetRelativeTime();
  980. while (BlPortPollOnly(BlTerminalDeviceId) != CP_GET_SUCCESS) {
  981. LastTime = AEGetRelativeTime();
  982. //
  983. // if the counter wraps back to zero, just restart the wait.
  984. //
  985. if (LastTime < StartTime) {
  986. StartTime = LastTime;
  987. }
  988. //
  989. // If one second has passed, the user must have just wanted a single
  990. // escape key, so return with that.
  991. //
  992. if ((LastTime - StartTime) > 1) {
  993. *Count = *Count + 1;
  994. return (ESUCCESS);
  995. }
  996. }
  997. //
  998. // We have another key, get it and translate the escape sequence.
  999. //
  1000. if (BlPortPollByte(BlTerminalDeviceId, &Ch) != CP_GET_SUCCESS) {
  1001. *Count = *Count + 1;
  1002. return (ESUCCESS);
  1003. }
  1004. switch (Ch) {
  1005. case '@': // F12 key
  1006. PortBuffer[PortBufferEnd] = 'O';
  1007. PortBufferEnd++;
  1008. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1009. PortBuffer[PortBufferEnd] = 'B';
  1010. PortBufferEnd++;
  1011. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1012. break;
  1013. case '!': // F11 key
  1014. PortBuffer[PortBufferEnd] = 'O';
  1015. PortBufferEnd++;
  1016. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1017. PortBuffer[PortBufferEnd] = 'A';
  1018. PortBufferEnd++;
  1019. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1020. break;
  1021. case '0': // F10 key
  1022. PortBuffer[PortBufferEnd] = 'O';
  1023. PortBufferEnd++;
  1024. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1025. PortBuffer[PortBufferEnd] = 'M';
  1026. PortBufferEnd++;
  1027. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1028. break;
  1029. case '9': // F9 key
  1030. PortBuffer[PortBufferEnd] = 'O';
  1031. PortBufferEnd++;
  1032. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1033. PortBuffer[PortBufferEnd] = 'p';
  1034. PortBufferEnd++;
  1035. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1036. break;
  1037. case '8': // F8 key
  1038. PortBuffer[PortBufferEnd] = 'O';
  1039. PortBufferEnd++;
  1040. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1041. PortBuffer[PortBufferEnd] = 'r';
  1042. PortBufferEnd++;
  1043. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1044. break;
  1045. case '7': // F7 key
  1046. PortBuffer[PortBufferEnd] = 'O';
  1047. PortBufferEnd++;
  1048. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1049. PortBuffer[PortBufferEnd] = 'q';
  1050. PortBufferEnd++;
  1051. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1052. break;
  1053. case '6': // F6 key
  1054. PortBuffer[PortBufferEnd] = 'O';
  1055. PortBufferEnd++;
  1056. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1057. PortBuffer[PortBufferEnd] = 'u';
  1058. PortBufferEnd++;
  1059. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1060. break;
  1061. case '5': // F5 key
  1062. PortBuffer[PortBufferEnd] = 'O';
  1063. PortBufferEnd++;
  1064. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1065. PortBuffer[PortBufferEnd] = 't';
  1066. PortBufferEnd++;
  1067. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1068. break;
  1069. case '4': // F4 key
  1070. PortBuffer[PortBufferEnd] = 'O';
  1071. PortBufferEnd++;
  1072. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1073. PortBuffer[PortBufferEnd] = 'x';
  1074. PortBufferEnd++;
  1075. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1076. break;
  1077. case '3': // F3 key
  1078. PortBuffer[PortBufferEnd] = 'O';
  1079. PortBufferEnd++;
  1080. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1081. PortBuffer[PortBufferEnd] = 'w';
  1082. PortBufferEnd++;
  1083. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1084. break;
  1085. case '2': // F2 key
  1086. PortBuffer[PortBufferEnd] = 'O';
  1087. PortBufferEnd++;
  1088. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1089. PortBuffer[PortBufferEnd] = 'Q';
  1090. PortBufferEnd++;
  1091. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1092. break;
  1093. case '1': // F1 key
  1094. PortBuffer[PortBufferEnd] = 'O';
  1095. PortBufferEnd++;
  1096. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1097. PortBuffer[PortBufferEnd] = 'P';
  1098. PortBufferEnd++;
  1099. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1100. break;
  1101. case 'H': // Home key
  1102. case 'h': // Home key
  1103. PortBuffer[PortBufferEnd] = 'H';
  1104. PortBufferEnd++;
  1105. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1106. break;
  1107. case 'K': // End key
  1108. case 'k': // End key
  1109. PortBuffer[PortBufferEnd] = 'K';
  1110. PortBufferEnd++;
  1111. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1112. break;
  1113. case '+': // Insert key
  1114. PortBuffer[PortBufferEnd] = '@';
  1115. PortBufferEnd++;
  1116. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1117. break;
  1118. case '-': // Del key
  1119. PortBuffer[PortBufferEnd] = 'P';
  1120. PortBufferEnd++;
  1121. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1122. break;
  1123. case (UCHAR)TAB_KEY: // Tab key
  1124. PortBuffer[PortBufferEnd] = (UCHAR)TAB_KEY;
  1125. PortBufferEnd++;
  1126. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1127. break;
  1128. case '[': // Cursor movement key
  1129. //
  1130. // The local computer can run a lot faster than the serial port can give bytes,
  1131. // so spin, polling, for a second.
  1132. //
  1133. StartTime = AEGetRelativeTime();
  1134. while (BlPortPollOnly(BlTerminalDeviceId) != CP_GET_SUCCESS) {
  1135. LastTime = AEGetRelativeTime();
  1136. //
  1137. // if the counter wraps back to zero, just restart the wait.
  1138. //
  1139. if (LastTime < StartTime) {
  1140. StartTime = LastTime;
  1141. }
  1142. //
  1143. // If one second has passed, we must be done.
  1144. //
  1145. if ((LastTime - StartTime) > 1) {
  1146. break;
  1147. }
  1148. }
  1149. if (BlPortPollByte(BlTerminalDeviceId, &Ch) != CP_GET_SUCCESS) {
  1150. PortBuffer[PortBufferEnd] = '[';
  1151. PortBufferEnd++;
  1152. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1153. break;
  1154. }
  1155. if ((Ch == 'A') || (Ch == 'B') || (Ch == 'C') || (Ch == 'D')) { // Arrow key.
  1156. PortBuffer[PortBufferEnd] = Ch;
  1157. PortBufferEnd++;
  1158. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1159. } else {
  1160. //
  1161. // Leave it as is
  1162. //
  1163. PortBuffer[PortBufferEnd] = '[';
  1164. PortBufferEnd++;
  1165. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1166. PortBuffer[PortBufferEnd] = Ch;
  1167. PortBufferEnd++;
  1168. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1169. }
  1170. break;
  1171. default:
  1172. PortBuffer[PortBufferEnd] = Ch;
  1173. PortBufferEnd++;
  1174. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1175. break;
  1176. }
  1177. } else if (TmpBuffer[*Count] == 0x7F) { // DEL key
  1178. TmpBuffer[*Count] = (CHAR)ASCI_CSI_IN;
  1179. PortBuffer[PortBufferEnd] = 'P';
  1180. PortBufferEnd++;
  1181. PortBufferEnd = PortBufferEnd % PORT_BUFFER_SIZE;
  1182. }
  1183. *Count = *Count + 1;
  1184. }
  1185. if (*Count != 0) {
  1186. return(ESUCCESS);
  1187. }
  1188. }
  1189. if (BiosConsoleReadStatus(FileId) == ESUCCESS) {
  1190. return(BiosConsoleRead(FileId,Buffer,Length,Count));
  1191. }
  1192. goto RetryRead;
  1193. } else {
  1194. //
  1195. // Declare a local 64KB aligned buffer, so we don't have to
  1196. // break up I/Os of size less than 64KB, because the buffer
  1197. // crosses a 64KB boundary.
  1198. //
  1199. static PCHAR AlignedBuf = 0;
  1200. BOOLEAN fUseAlignedBuf;
  1201. //
  1202. // Initialize the AlignedBuf once from the pool.
  1203. //
  1204. if (!AlignedBuf) {
  1205. AlignedBuf = FwAllocatePool(128 * 1024);
  1206. AlignedBuf = ALIGN_BUFFER_ON_BOUNDARY(AlignedBuf, 64 * 1024);
  1207. }
  1208. *Count = 0;
  1209. do {
  1210. fUseAlignedBuf = FALSE;
  1211. if (((ULONG) Buffer & 0xffff0000) !=
  1212. (((ULONG) Buffer + Length - 1) & 0xffff0000)) {
  1213. //
  1214. // If the buffer crosses the 64KB boundary use our
  1215. // aligned buffer instead. If we don't have an aligned
  1216. // buffer, adjust the read size.
  1217. //
  1218. if (AlignedBuf) {
  1219. fUseAlignedBuf = TRUE;
  1220. //
  1221. // We can read max 64KB into our aligned
  1222. // buffer.
  1223. //
  1224. Limit = Length;
  1225. if (Limit > (ULONG) 0xFFFF) {
  1226. Limit = (ULONG) 0xFFFF;
  1227. }
  1228. } else {
  1229. Limit = (64 * 1024) - ((ULONG_PTR) Buffer & 0xFFFF);
  1230. }
  1231. } else {
  1232. Limit = Length;
  1233. }
  1234. Status = (BlFileTable[FileId].DeviceEntryTable->Read)( FileId,
  1235. (fUseAlignedBuf) ? AlignedBuf : Buffer,
  1236. Limit,
  1237. &PartCount );
  1238. //
  1239. // If we used our aligned buffer, copy the read data
  1240. // to the callers buffer.
  1241. //
  1242. if (fUseAlignedBuf) {
  1243. RtlCopyMemory(Buffer, AlignedBuf, PartCount);
  1244. }
  1245. *Count += PartCount;
  1246. Length -= Limit;
  1247. (PCHAR) Buffer += Limit;
  1248. if (Status != ESUCCESS) {
  1249. #if DBG
  1250. BlPrint("Disk I/O error: Status = %lx\n",Status);
  1251. #endif
  1252. return(Status);
  1253. }
  1254. } while (Length > 0);
  1255. return(Status);
  1256. }
  1257. }
  1258. ARC_STATUS
  1259. AEWrite (
  1260. IN ULONG FileId,
  1261. OUT PVOID Buffer,
  1262. IN ULONG Length,
  1263. OUT PULONG Count
  1264. )
  1265. /*++
  1266. Routine Description:
  1267. Writes to the specified file or device
  1268. Arguments:
  1269. FileId - Supplies the file or device to write to
  1270. Buffer - Supplies address of the data to be written
  1271. Length - Supplies number of bytes to write
  1272. Count - Address of location in which to store the actual bytes written.
  1273. Return Value:
  1274. ESUCCESS - Read completed successfully
  1275. !ESUCCESS - Read failed.
  1276. --*/
  1277. {
  1278. ARC_STATUS Status;
  1279. ULONG Limit;
  1280. ULONG PartCount;
  1281. PUCHAR TmpBuffer, String;
  1282. UCHAR Char;
  1283. USHORT WChar;
  1284. //
  1285. // Special case for console output
  1286. //
  1287. if (FileId == 1) {
  1288. if (BlIsTerminalConnected()) {
  1289. BOOLEAN InTerminalEscape = FALSE;
  1290. //
  1291. // Translate ANSI codes to vt100 escape sequences
  1292. //
  1293. TmpBuffer = (PUCHAR)Buffer;
  1294. Limit = Length;
  1295. if (Length == 4) {
  1296. if (strncmp(TmpBuffer, "\033[2J", Length)==0) {
  1297. //
  1298. // <CSI>2J turns into <CSI>H<CSI>J
  1299. //
  1300. // (erase entire screen)
  1301. //
  1302. TmpBuffer = "\033[H\033[J";
  1303. Limit = 6;
  1304. } else if (strncmp(TmpBuffer, "\033[0J", Length)==0) {
  1305. //
  1306. // <CSI>0J turns into <CSI>J
  1307. //
  1308. // (erase to end of screen)
  1309. //
  1310. TmpBuffer = "\033[J";
  1311. Limit = 3;
  1312. } else if (strncmp(TmpBuffer, "\033[0K", Length)==0) {
  1313. //
  1314. // <CSI>0K turns into <CSI>K
  1315. //
  1316. // (erase to end of the line)
  1317. //
  1318. TmpBuffer = "\033[K";
  1319. Limit = 3;
  1320. } else if (strncmp(TmpBuffer, "\033[0m", Length)==0) {
  1321. //
  1322. // <CSI>0m turns into <CSI>m
  1323. //
  1324. // (turn attributes off)
  1325. //
  1326. TmpBuffer = "\033[m";
  1327. Limit = 3;
  1328. }
  1329. }
  1330. //
  1331. // loop through the string to be output, printing data to the
  1332. // headless terminal.
  1333. //
  1334. String = TmpBuffer;
  1335. for (PartCount = 0; PartCount < Limit; PartCount++, String++) {
  1336. #if UTF8_CLIENT_SUPPORT
  1337. //
  1338. // check if we're in a DBCS language. If we are, then we
  1339. // need to translate the characters into UTF8 codes by
  1340. // referencing a lookup table in bootfont.bin
  1341. //
  1342. if (DbcsLangId) {
  1343. UCHAR UTF8Encoding[3];
  1344. ULONG i;
  1345. if (GrIsDBCSLeadByte(*String)) {
  1346. //
  1347. // double byte characters have their own separate table
  1348. // from the SBCS characters.
  1349. //
  1350. // we need to advance the string forward 2 characters
  1351. // for double byte characters.
  1352. //
  1353. GetDBCSUtf8Translation(String,UTF8Encoding);
  1354. String += 1;
  1355. PartCount += 1;
  1356. } else {
  1357. ULONG Bytes;
  1358. LPSTR p;
  1359. //
  1360. // single byte characters have their own separate table
  1361. // from the DBCS characters.
  1362. //
  1363. GetSBCSUtf8Translation(String,UTF8Encoding);
  1364. }
  1365. for( i = 0; i < 3; i++ ) {
  1366. if( UTF8Encoding[i] != 0 ) {
  1367. BlPortPutByte( BlTerminalDeviceId, UTF8Encoding[i] );
  1368. FwStallExecution(BlTerminalDelay);
  1369. }
  1370. }
  1371. } else
  1372. #endif
  1373. {
  1374. //
  1375. // standard ASCII character
  1376. //
  1377. Char = *String;
  1378. #if 1
  1379. //
  1380. // filter some characters that aren't printable in VT100
  1381. // into substitute characters which are printable
  1382. //
  1383. if (Char & 0x80) {
  1384. switch (Char) {
  1385. case 0xB0: // Light shaded block
  1386. case 0xB3: // Light vertical
  1387. case 0xBA: // Double vertical line
  1388. Char = '|';
  1389. break;
  1390. case 0xB1: // Middle shaded block
  1391. case 0xDC: // Lower half block
  1392. case 0xDD: // Right half block
  1393. case 0xDE: // Left half block
  1394. case 0xDF: // Upper half block
  1395. Char = '%';
  1396. break;
  1397. case 0xB2: // Dark shaded block
  1398. case 0xDB: // Full block
  1399. Char = '#';
  1400. break;
  1401. case 0xA9: // Reversed NOT sign
  1402. case 0xAA: // NOT sign
  1403. case 0xBB: // '�'
  1404. case 0xBC: // '�'
  1405. case 0xBF: // '�'
  1406. case 0xC0: // '�'
  1407. case 0xC8: // '�'
  1408. case 0xC9: // '�'
  1409. case 0xD9: // '�'
  1410. case 0xDA: // '�'
  1411. Char = '+';
  1412. break;
  1413. case 0xC4: // '�'
  1414. Char = '-';
  1415. break;
  1416. case 0xCD: // '�'
  1417. Char = '=';
  1418. break;
  1419. }
  1420. }
  1421. #endif
  1422. //
  1423. // If the high-bit is still set, and we're here, then we know we're
  1424. // not doing DBCS/SBCS characters. We need to convert this
  1425. // 8bit ANSI character into unicode, then UTF8 encode that, then send
  1426. // it over the wire.
  1427. //
  1428. if( Char & 0x80 ) {
  1429. UCHAR UTF8Encoding[3];
  1430. ULONG i;
  1431. //
  1432. // Lookup the Unicode equivilent of this 8-bit ANSI value.
  1433. //
  1434. UTF8Encode( PcAnsiToUnicode[(Char & 0x7F)],
  1435. UTF8Encoding );
  1436. for( i = 0; i < 3; i++ ) {
  1437. if( UTF8Encoding[i] != 0 ) {
  1438. BlPortPutByte( BlTerminalDeviceId, UTF8Encoding[i] );
  1439. FwStallExecution(BlTerminalDelay);
  1440. }
  1441. }
  1442. } else {
  1443. //
  1444. // write the data to the port. Note that we write an 8 bit
  1445. // character to the terminal, and that the remote display
  1446. // must correctly interpret the code for it to display
  1447. // properly.
  1448. //
  1449. BlPortPutByte(BlTerminalDeviceId, Char);
  1450. FwStallExecution(BlTerminalDelay);
  1451. }
  1452. }
  1453. }
  1454. }
  1455. return (BiosConsoleWrite(FileId,Buffer,Length,Count));
  1456. } else {
  1457. *Count = 0;
  1458. do {
  1459. if (((ULONG) Buffer & 0xffff0000) !=
  1460. (((ULONG) Buffer + Length) & 0xffff0000)) {
  1461. Limit = 0x10000 - ((ULONG) Buffer & 0x0000ffff);
  1462. } else {
  1463. Limit = Length;
  1464. }
  1465. Status = (BlFileTable[FileId].DeviceEntryTable->Write)( FileId,
  1466. Buffer,
  1467. Limit,
  1468. &PartCount );
  1469. *Count += PartCount;
  1470. Length -= Limit;
  1471. (PCHAR) Buffer += Limit;
  1472. if (Status != ESUCCESS) {
  1473. #if DBG
  1474. BlPrint("AERead: Status = %lx\n",Status);
  1475. #endif
  1476. return(Status);
  1477. }
  1478. } while (Length > 0);
  1479. return(Status);
  1480. }
  1481. }
  1482. ARC_STATUS
  1483. AEGetFileInformation(
  1484. IN ULONG FileId,
  1485. OUT PFILE_INFORMATION FileInformation
  1486. )
  1487. {
  1488. return(BlFileTable[FileId].DeviceEntryTable->GetFileInformation)( FileId,
  1489. FileInformation);
  1490. }
  1491. TIME_FIELDS AETime;
  1492. PTIME_FIELDS
  1493. AEGetTime(
  1494. VOID
  1495. )
  1496. {
  1497. ULONG Date,Time;
  1498. GET_DATETIME(&Date,&Time);
  1499. //
  1500. // Date and time are filled as as follows:
  1501. //
  1502. // Date:
  1503. //
  1504. // bits 0 - 4 : day
  1505. // bits 5 - 8 : month
  1506. // bits 9 - 31 : year
  1507. //
  1508. // Time:
  1509. //
  1510. // bits 0 - 5 : second
  1511. // bits 6 - 11 : minute
  1512. // bits 12 - 16 : hour
  1513. //
  1514. AETime.Second = (CSHORT)((Time & 0x0000003f) >> 0);
  1515. AETime.Minute = (CSHORT)((Time & 0x00000fc0) >> 6);
  1516. AETime.Hour = (CSHORT)((Time & 0x0001f000) >> 12);
  1517. AETime.Day = (CSHORT)((Date & 0x0000001f) >> 0);
  1518. AETime.Month = (CSHORT)((Date & 0x000001e0) >> 5);
  1519. AETime.Year = (CSHORT)((Date & 0xfffffe00) >> 9);
  1520. AETime.Milliseconds = 0; // info is not available
  1521. AETime.Weekday = 7; // info is not available - set out of range
  1522. return(&AETime);
  1523. }
  1524. ULONG
  1525. AEGetRelativeTime(
  1526. VOID
  1527. )
  1528. /*++
  1529. Routine Description:
  1530. Returns the time in seconds since some arbitrary starting point.
  1531. Arguments:
  1532. None
  1533. Return Value:
  1534. Time in seconds since some arbitrary starting point.
  1535. --*/
  1536. {
  1537. ULONG TimerTicks;
  1538. TimerTicks = GET_COUNTER();
  1539. return((TimerTicks*10) / 182);
  1540. }
  1541. VOID
  1542. AEReboot(
  1543. VOID
  1544. )
  1545. /*++
  1546. Routine Description:
  1547. Reboots the machine.
  1548. Arguments:
  1549. None
  1550. Return Value:
  1551. Does not return
  1552. --*/
  1553. {
  1554. ULONG DriveId;
  1555. ULONG Status;
  1556. TextGrTerminate();
  1557. //
  1558. // HACKHACK John Vert (jvert)
  1559. // Some SCSI drives get really confused and return zeroes when
  1560. // you use the BIOS to query their size after the AHA driver has
  1561. // initialized. This can completely tube OS/2 or DOS. So here
  1562. // we try and open both BIOS-accessible hard drives. Our open
  1563. // code is smart enough to retry if it gets back zeros, so hopefully
  1564. // this will give the SCSI drives a chance to get their act together.
  1565. //
  1566. Status = ArcOpen("multi(0)disk(0)rdisk(0)partition(0)",
  1567. ArcOpenReadOnly,
  1568. &DriveId);
  1569. if (Status == ESUCCESS) {
  1570. ArcClose(DriveId);
  1571. }
  1572. Status = ArcOpen("multi(0)disk(0)rdisk(1)partition(0)",
  1573. ArcOpenReadOnly,
  1574. &DriveId);
  1575. if (Status == ESUCCESS) {
  1576. ArcClose(DriveId);
  1577. }
  1578. REBOOT_PROCESSOR();
  1579. }
  1580. ARC_STATUS
  1581. HardDiskPartitionOpen(
  1582. IN ULONG FileId,
  1583. IN ULONG DiskId,
  1584. IN UCHAR PartitionNumber
  1585. )
  1586. /*++
  1587. Routine Description:
  1588. This routine opens the specified partition and sets the partition info
  1589. in the FileTable at the specified index. It does not fill in the
  1590. Device Entry table.
  1591. It reads the partition information until the requested partition
  1592. is found or no more partitions are defined.
  1593. Arguments:
  1594. FileId - Supplies the file id for the file table entry.
  1595. DiskId - Supplies the file id for the physical device.
  1596. PartitionNumber - Supplies the zero-based partition number
  1597. Return Value:
  1598. If a valid partition is found on the hard disk, then ESUCCESS is
  1599. returned. Otherwise, EIO is returned.
  1600. --*/
  1601. {
  1602. USHORT DataBuffer[SECTOR_SIZE / sizeof(USHORT)];
  1603. PPARTITION_DESCRIPTOR Partition;
  1604. ULONG PartitionLength;
  1605. ULONG StartingSector;
  1606. ULONG VolumeOffset;
  1607. ARC_STATUS Status;
  1608. BOOLEAN PrimaryPartitionTable;
  1609. ULONG PartitionOffset=0;
  1610. ULONG PartitionIndex,PartitionCount=0;
  1611. ULONG Count;
  1612. LARGE_INTEGER SeekPosition;
  1613. BlFileTable[FileId].u.PartitionContext.DiskId=(UCHAR)DiskId;
  1614. BlFileTable[FileId].Position.QuadPart=0;
  1615. VolumeOffset=0;
  1616. PrimaryPartitionTable=TRUE;
  1617. //
  1618. // Change to a 1-based partition number
  1619. //
  1620. PartitionNumber++;
  1621. do {
  1622. SeekPosition.QuadPart = (LONGLONG)PartitionOffset * SECTOR_SIZE;
  1623. Status = (BlFileTable[DiskId].DeviceEntryTable->Seek)(DiskId,
  1624. &SeekPosition,
  1625. SeekAbsolute );
  1626. if (Status != ESUCCESS) {
  1627. return(Status);
  1628. }
  1629. Status = (BlFileTable[DiskId].DeviceEntryTable->Read)(DiskId,
  1630. DataBuffer,
  1631. SECTOR_SIZE,
  1632. &Count );
  1633. if (Status != ESUCCESS) {
  1634. return Status;
  1635. }
  1636. //
  1637. // If sector zero is not a master boot record, then return failure
  1638. // status. Otherwise return success.
  1639. //
  1640. if (DataBuffer[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) {
  1641. #if DBG
  1642. BlPrint("Boot record signature %x not found (%x found)\n",
  1643. BOOT_RECORD_SIGNATURE,
  1644. DataBuffer[BOOT_SIGNATURE_OFFSET] );
  1645. #endif
  1646. Status = EIO;
  1647. break;
  1648. }
  1649. //
  1650. // Read the partition information until the four entries are
  1651. // checked or until we found the requested one.
  1652. //
  1653. Partition = (PPARTITION_DESCRIPTOR)&DataBuffer[PARTITION_TABLE_OFFSET];
  1654. for (PartitionIndex=0;
  1655. PartitionIndex < NUM_PARTITION_TABLE_ENTRIES;
  1656. PartitionIndex++,Partition++) {
  1657. //
  1658. // Count first the partitions in the MBR. The units
  1659. // inside the extended partition are counted later.
  1660. //
  1661. if ((Partition->PartitionType != PARTITION_ENTRY_UNUSED) &&
  1662. (Partition->PartitionType != STALE_GPT_PARTITION_ENTRY) &&
  1663. !IsContainerPartition(Partition->PartitionType))
  1664. {
  1665. PartitionCount++; // another partition found.
  1666. }
  1667. //
  1668. // Check if the requested partition has already been found.
  1669. // set the partition info in the file table and return.
  1670. //
  1671. if (PartitionCount == PartitionNumber) {
  1672. StartingSector = (ULONG)(Partition->StartingSectorLsb0) |
  1673. (ULONG)(Partition->StartingSectorLsb1 << 8) |
  1674. (ULONG)(Partition->StartingSectorMsb0 << 16) |
  1675. (ULONG)(Partition->StartingSectorMsb1 << 24);
  1676. PartitionLength = (ULONG)(Partition->PartitionLengthLsb0) |
  1677. (ULONG)(Partition->PartitionLengthLsb1 << 8) |
  1678. (ULONG)(Partition->PartitionLengthMsb0 << 16) |
  1679. (ULONG)(Partition->PartitionLengthMsb1 << 24);
  1680. BlFileTable[FileId].u.PartitionContext.PartitionLength.QuadPart =
  1681. (PartitionLength << SECTOR_SHIFT);
  1682. BlFileTable[FileId].u.PartitionContext.StartingSector=PartitionOffset + StartingSector;
  1683. return ESUCCESS;
  1684. }
  1685. }
  1686. //
  1687. // If requested partition was not yet found.
  1688. // Look for an extended partition.
  1689. //
  1690. Partition = (PPARTITION_DESCRIPTOR)&DataBuffer[PARTITION_TABLE_OFFSET];
  1691. PartitionOffset = 0;
  1692. for (PartitionIndex=0;
  1693. PartitionIndex < NUM_PARTITION_TABLE_ENTRIES;
  1694. PartitionIndex++,Partition++) {
  1695. if (IsContainerPartition(Partition->PartitionType)) {
  1696. StartingSector = (ULONG)(Partition->StartingSectorLsb0) |
  1697. (ULONG)(Partition->StartingSectorLsb1 << 8) |
  1698. (ULONG)(Partition->StartingSectorMsb0 << 16) |
  1699. (ULONG)(Partition->StartingSectorMsb1 << 24);
  1700. PartitionOffset = VolumeOffset+StartingSector;
  1701. if (PrimaryPartitionTable) {
  1702. VolumeOffset = StartingSector;
  1703. }
  1704. break; // only one partition can be extended.
  1705. }
  1706. }
  1707. PrimaryPartitionTable=FALSE;
  1708. } while (PartitionOffset != 0);
  1709. return EBADF;
  1710. }
  1711. VOID
  1712. BlpTranslateDosToArc(
  1713. IN PCHAR DosName,
  1714. OUT PCHAR ArcName
  1715. )
  1716. /*++
  1717. Routine Description:
  1718. This routine takes a DOS drive name ("A:" "B:" "C:" etc.) and translates
  1719. it into an ARC name. ("multi(0)disk(0)rdisk(0)partition(1)")
  1720. N.B. This will always return some sort of name suitable for passing
  1721. to BiosPartitionOpen. The name it constructs may not be an
  1722. actual partition. BiosPartitionOpen is responsible for
  1723. determining whether the partition actually exists.
  1724. Since no other driver should ever use ARC names beginning with
  1725. "multi(0)disk(0)..." this will not be a problem. (there is no
  1726. way this routine will construct a name that BiosPartitionOpen
  1727. will not open, but some other random driver will grab and
  1728. successfully open)
  1729. Arguments:
  1730. DosName - Supplies the DOS name of the drive.
  1731. ArcName - Returns the ARC name of the drive.
  1732. Return Value:
  1733. --*/
  1734. {
  1735. ARC_STATUS Status;
  1736. ULONG DriveId;
  1737. ULONG PartitionNumber;
  1738. ULONG PartitionCount;
  1739. ULONG Count;
  1740. USHORT DataBuffer[SECTOR_SIZE / sizeof(USHORT)];
  1741. PPARTITION_DESCRIPTOR Partition;
  1742. ULONG PartitionIndex;
  1743. BOOLEAN HasPrimary;
  1744. LARGE_INTEGER SeekPosition;
  1745. //
  1746. // Eliminate the easy ones first.
  1747. // A: is always "multi(0)disk(0)fdisk(0)partition(0)"
  1748. // B: is always "multi(0)disk(0)fdisk(1)partition(0)"
  1749. // C: is always "multi(0)disk(0)rdisk(0)partition(1)"
  1750. //
  1751. if (_stricmp(DosName,"A:")==0) {
  1752. strcpy(ArcName,"multi(0)disk(0)fdisk(0)partition(0)");
  1753. return;
  1754. }
  1755. if (_stricmp(DosName,"B:")==0) {
  1756. strcpy(ArcName,"multi(0)disk(0)fdisk(1)partition(0)");
  1757. return;
  1758. }
  1759. if (_stricmp(DosName,"C:")==0) {
  1760. strcpy(ArcName,"multi(0)disk(0)rdisk(0)partition(1)");
  1761. return;
  1762. }
  1763. //
  1764. // Now things get more unpleasant. If there are two drives, then
  1765. // D: is the primary partition on the second drive. Successive letters
  1766. // are the secondary partitions on the first drive, then back to the
  1767. // second drive when that runs out.
  1768. //
  1769. // The exception to this is when there is no primary partition on the
  1770. // second drive. Then, we letter the partitions on the first driver
  1771. // consecutively, and when those partitions run out, we letter the
  1772. // partitions on the second drive.
  1773. //
  1774. // I have no idea who came up with this wonderful scheme, but we have
  1775. // to live with it.
  1776. //
  1777. //
  1778. // Try to open the second drive. If this doesn't work, we only have
  1779. // one drive and life is easy.
  1780. //
  1781. Status = ArcOpen("multi(0)disk(0)rdisk(1)partition(0)",
  1782. ArcOpenReadOnly,
  1783. &DriveId );
  1784. if (Status != ESUCCESS) {
  1785. //
  1786. // We only have one drive, so whatever drive letter he's requesting
  1787. // has got to be on it.
  1788. //
  1789. sprintf(ArcName,
  1790. "multi(0)disk(0)rdisk(0)partition(%d)",
  1791. toupper(DosName[0]) - 'C' + 1 );
  1792. return;
  1793. } else {
  1794. //
  1795. // Now we read the partition table off the second drive, so we can
  1796. // tell if there is a primary partition or not.
  1797. //
  1798. SeekPosition.QuadPart = 0;
  1799. Status = ArcSeek(DriveId,
  1800. &SeekPosition,
  1801. SeekAbsolute);
  1802. if (Status != ESUCCESS) {
  1803. ArcName[0]='\0';
  1804. return;
  1805. }
  1806. Status = ArcRead(DriveId, DataBuffer, SECTOR_SIZE, &Count);
  1807. ArcClose(DriveId);
  1808. if (Status != ESUCCESS) {
  1809. ArcName[0] = '\0';
  1810. return;
  1811. }
  1812. HasPrimary = FALSE;
  1813. Partition = (PPARTITION_DESCRIPTOR)&DataBuffer[PARTITION_TABLE_OFFSET];
  1814. for (PartitionIndex = 0;
  1815. PartitionIndex < NUM_PARTITION_TABLE_ENTRIES;
  1816. PartitionIndex++,Partition++) {
  1817. if (IsRecognizedPartition(Partition->PartitionType)) {
  1818. HasPrimary = TRUE;
  1819. }
  1820. }
  1821. //
  1822. // Now we have to go through and count
  1823. // the partitions on the first drive. We do this by just constructing
  1824. // ARC names for each successive partition until one BiosPartitionOpen
  1825. // call fails.
  1826. //
  1827. PartitionCount = 0;
  1828. do {
  1829. ++PartitionCount;
  1830. sprintf(ArcName,
  1831. "multi(0)disk(0)rdisk(0)partition(%d)",
  1832. PartitionCount+1);
  1833. Status = BiosPartitionOpen( ArcName,
  1834. ArcOpenReadOnly,
  1835. &DriveId );
  1836. if (Status==ESUCCESS) {
  1837. BiosPartitionClose(DriveId);
  1838. }
  1839. } while ( Status == ESUCCESS );
  1840. PartitionNumber = toupper(DosName[0])-'C' + 1;
  1841. if (HasPrimary) {
  1842. //
  1843. // There is Windows NT primary partition on the second drive.
  1844. //
  1845. // If the DosName is "D:" then we know
  1846. // this is the first partition on the second drive.
  1847. //
  1848. if (_stricmp(DosName,"D:")==0) {
  1849. strcpy(ArcName,"multi(0)disk(0)rdisk(1)partition(1)");
  1850. return;
  1851. }
  1852. if (PartitionNumber-1 > PartitionCount) {
  1853. PartitionNumber -= PartitionCount;
  1854. sprintf(ArcName,
  1855. "multi(0)disk(0)rdisk(1)partition(%d)",
  1856. PartitionNumber );
  1857. } else {
  1858. sprintf(ArcName,
  1859. "multi(0)disk(0)rdisk(0)partition(%d)",
  1860. PartitionNumber-1);
  1861. }
  1862. } else {
  1863. //
  1864. // There is no primary partition on the second drive, so we
  1865. // consecutively letter the partitions on the first drive,
  1866. // then the second drive.
  1867. //
  1868. if (PartitionNumber > PartitionCount) {
  1869. PartitionNumber -= PartitionCount;
  1870. sprintf(ArcName,
  1871. "multi(0)disk(0)rdisk(1)partition(%d)",
  1872. PartitionNumber );
  1873. } else {
  1874. sprintf(ArcName,
  1875. "multi(0)disk(0)rdisk(0)partition(%d)",
  1876. PartitionNumber);
  1877. }
  1878. }
  1879. return;
  1880. }
  1881. }
  1882. VOID
  1883. FwStallExecution(
  1884. IN ULONG Microseconds
  1885. )
  1886. /*++
  1887. Routine Description:
  1888. Does a busy wait for a specified number of microseconds (very approximate!)
  1889. Arguments:
  1890. Microseconds - Supplies the number of microseconds to busy wait.
  1891. Return Value:
  1892. None.
  1893. --*/
  1894. {
  1895. ULONG FinalCount;
  1896. FinalCount = Microseconds * FwStallCounter;
  1897. _asm {
  1898. mov eax,FinalCount
  1899. looptop:
  1900. sub eax,1
  1901. jnz short looptop
  1902. }
  1903. }
  1904. BOOLEAN
  1905. FwGetPathMnemonicKey(
  1906. IN PCHAR OpenPath,
  1907. IN PCHAR Mnemonic,
  1908. IN PULONG Key
  1909. )
  1910. /*++
  1911. Routine Description:
  1912. This routine looks for the given Mnemonic in OpenPath.
  1913. If Mnemonic is a component of the path, then it converts the key
  1914. value to an integer wich is returned in Key.
  1915. Arguments:
  1916. OpenPath - Pointer to a string that contains an ARC pathname.
  1917. Mnemonic - Pointer to a string that contains a ARC Mnemonic
  1918. Key - Pointer to a ULONG where the Key value is stored.
  1919. Return Value:
  1920. FALSE if mnemonic is found in path and a valid key is converted.
  1921. TRUE otherwise.
  1922. --*/
  1923. {
  1924. return(BlGetPathMnemonicKey(OpenPath,Mnemonic,Key));
  1925. }
  1926. PCONFIGURATION_COMPONENT
  1927. FwAddChild (
  1928. IN PCONFIGURATION_COMPONENT Component,
  1929. IN PCONFIGURATION_COMPONENT NewComponent,
  1930. IN PVOID ConfigurationData OPTIONAL
  1931. )
  1932. {
  1933. ULONG Size;
  1934. PCONFIGURATION_COMPONENT_DATA NewEntry;
  1935. PCONFIGURATION_COMPONENT_DATA Parent;
  1936. if (Component==NULL) {
  1937. return(NULL);
  1938. }
  1939. Parent = CONTAINING_RECORD(Component,
  1940. CONFIGURATION_COMPONENT_DATA,
  1941. ComponentEntry);
  1942. Size = sizeof(CONFIGURATION_COMPONENT_DATA) +
  1943. NewComponent->IdentifierLength + 1;
  1944. NewEntry = FwAllocateHeap(Size);
  1945. if (NewEntry==NULL) {
  1946. return(NULL);
  1947. }
  1948. RtlCopyMemory(&NewEntry->ComponentEntry,
  1949. NewComponent,
  1950. sizeof(CONFIGURATION_COMPONENT));
  1951. NewEntry->ComponentEntry.Identifier = (PUCHAR)(NewEntry+1);
  1952. NewEntry->ComponentEntry.ConfigurationDataLength = 0;
  1953. strncpy(NewEntry->ComponentEntry.Identifier,
  1954. NewComponent->Identifier,
  1955. NewComponent->IdentifierLength);
  1956. //
  1957. // Add the new component as the first child of its parent.
  1958. //
  1959. NewEntry->Child = NULL;
  1960. NewEntry->Sibling = Parent->Child;
  1961. Parent->Child = NewEntry;
  1962. return(&NewEntry->ComponentEntry);
  1963. }
  1964. PCONFIGURATION_COMPONENT
  1965. FwGetComponent(
  1966. IN PCHAR Pathname
  1967. )
  1968. {
  1969. PCONFIGURATION_COMPONENT Component;
  1970. PCONFIGURATION_COMPONENT MatchComponent;
  1971. PCHAR PathString;
  1972. PCHAR MatchString;
  1973. PCHAR Token;
  1974. ULONG Key;
  1975. PathString = Pathname;
  1976. //
  1977. // Get the the root component.
  1978. //
  1979. MatchComponent = FwGetChild(NULL);
  1980. //
  1981. // Repeat search for each new match component.
  1982. //
  1983. do {
  1984. //
  1985. // Get the first child of the current match component.
  1986. //
  1987. Component = FwGetChild( MatchComponent );
  1988. //
  1989. // Search each child of the current match component for the next match.
  1990. //
  1991. while ( Component != NULL ) {
  1992. //
  1993. // Reset Token to be the current position on the pathname.
  1994. //
  1995. Token = PathString;
  1996. MatchString = MnemonicTable[Component->Type];
  1997. //
  1998. // Compare strings.
  1999. //
  2000. while (*MatchString == tolower(*Token)) {
  2001. MatchString++;
  2002. Token++;
  2003. }
  2004. //
  2005. // Strings compare if the first mismatch is the terminator for
  2006. // each.
  2007. //
  2008. if ((*MatchString == 0) && (*Token == '(')) {
  2009. //
  2010. // Form key.
  2011. //
  2012. Key = 0;
  2013. Token++;
  2014. while ((*Token != ')') && (*Token != 0)) {
  2015. Key = (Key * 10) + *Token++ - '0';
  2016. }
  2017. //
  2018. // If the key matches the component matches, so update
  2019. // pointers and break.
  2020. //
  2021. if (Component->Key == Key) {
  2022. PathString = Token + 1;
  2023. MatchComponent = Component;
  2024. break;
  2025. }
  2026. }
  2027. Component = FwGetPeer( Component );
  2028. }
  2029. } while ((Component != NULL) && (*PathString != 0));
  2030. return MatchComponent;
  2031. }
  2032. /**********************
  2033. *
  2034. * The following are just stubs for the MIPS firmware. They all return NULL
  2035. *
  2036. ***********************/
  2037. ARC_STATUS
  2038. FwDeleteComponent (
  2039. IN PCONFIGURATION_COMPONENT Component
  2040. )
  2041. {
  2042. return(ESUCCESS);
  2043. }
  2044. VOID
  2045. AEGetArcDiskInformation(
  2046. VOID
  2047. )
  2048. {
  2049. InitializeListHead(&(AEArcDiskInformation.DiskSignatures));
  2050. AEArcDiskInformationInitialized = TRUE;
  2051. //
  2052. // Scan through each node of the hardware tree - look for disk type
  2053. // devices hanging off of multi-function controllers.
  2054. //
  2055. FwSearchTree(FwGetChild(NULL),
  2056. PeripheralClass,
  2057. DiskPeripheral,
  2058. -1,
  2059. AEEnumerateDisks);
  2060. return;
  2061. }
  2062. BOOLEAN
  2063. FwSearchTree(
  2064. IN PCONFIGURATION_COMPONENT Node,
  2065. IN CONFIGURATION_CLASS Class,
  2066. IN CONFIGURATION_TYPE Type,
  2067. IN ULONG Key,
  2068. IN PFWNODE_CALLBACK CallbackRoutine
  2069. )
  2070. /*++
  2071. Routine Description:
  2072. Conduct a depth-first search of the firmware configuration tree starting
  2073. at a given node, looking for nodes that match a given class and type.
  2074. When a matching node is found, call a callback routine.
  2075. Arguments:
  2076. CurrentNode - node at which to begin the search.
  2077. Class - configuration class to match, or -1 to match any class
  2078. Type - configuration type to match, or -1 to match any class
  2079. Key - key to match, or -1 to match any key
  2080. FoundRoutine - pointer to a routine to be called when a node whose
  2081. class and type match the class and type passed in is located.
  2082. The routine takes a pointer to the configuration node and must
  2083. return a boolean indicating whether to continue with the traversal.
  2084. Return Value:
  2085. FALSE if the caller should abandon the search.
  2086. --*/
  2087. {
  2088. PCONFIGURATION_COMPONENT child;
  2089. do {
  2090. if (child = FwGetChild(Node)) {
  2091. if (!FwSearchTree(child,
  2092. Class,
  2093. Type,
  2094. Key,
  2095. CallbackRoutine)) {
  2096. return(FALSE);
  2097. }
  2098. }
  2099. if (((Class == -1) || (Node->Class == Class)) &&
  2100. ((Type == -1) || (Node->Type == Type)) &&
  2101. ((Key == (ULONG)-1) || (Node->Key == Key))) {
  2102. if (!CallbackRoutine(Node)) {
  2103. return(FALSE);
  2104. }
  2105. }
  2106. Node = FwGetPeer(Node);
  2107. } while ( Node != NULL );
  2108. return(TRUE);
  2109. }
  2110. VOID
  2111. AEGetPathnameFromComponent(
  2112. IN PCONFIGURATION_COMPONENT Component,
  2113. OUT PCHAR ArcName
  2114. )
  2115. /*++
  2116. Routine Description:
  2117. This function builds an ARC pathname for the specified component.
  2118. Arguments:
  2119. Component - Supplies a pointer to a configuration component.
  2120. ArcName - Returns the ARC name of the specified component. Caller must
  2121. provide a large enough buffer.
  2122. Return Value:
  2123. None.
  2124. --*/
  2125. {
  2126. if (AEGetParent(Component) != NULL) {
  2127. AEGetPathnameFromComponent(AEGetParent(Component),ArcName);
  2128. //
  2129. // append our segment to the arcname
  2130. //
  2131. sprintf(ArcName+strlen(ArcName),
  2132. "%s(%d)",
  2133. MnemonicTable[Component->Type],
  2134. Component->Key);
  2135. } else {
  2136. //
  2137. // We are the parent, initialize the string and return
  2138. //
  2139. ArcName[0] = '\0';
  2140. }
  2141. return;
  2142. }
  2143. BOOLEAN
  2144. AEEnumerateDisks(
  2145. IN PCONFIGURATION_COMPONENT Disk
  2146. )
  2147. /*++
  2148. Routine Description:
  2149. Callback routine for enumerating the disks in the ARC firmware tree. It
  2150. reads all the necessary information from the disk to uniquely identify
  2151. it.
  2152. Arguments:
  2153. ConfigData - Supplies a pointer to the disk's ARC component data.
  2154. Return Value:
  2155. TRUE - continue searching
  2156. FALSE - stop searching tree.
  2157. --*/
  2158. {
  2159. UCHAR path[100] = "";
  2160. ULONG key;
  2161. AEGetPathnameFromComponent(Disk, path);
  2162. #if 0
  2163. if((BlGetPathMnemonicKey(path, "multi", &key) == FALSE) ||
  2164. (BlGetPathMnemonicKey(path, "eisa", &key) == FALSE)) {
  2165. DbgPrint("Found multi disk %s\n", path);
  2166. } else {
  2167. DbgPrint("Found disk %s\n", path);
  2168. }
  2169. #endif
  2170. AEReadDiskSignature(path, FALSE);
  2171. return TRUE;
  2172. }
  2173. BOOLEAN
  2174. AEReadDiskSignature(
  2175. IN PCHAR DiskName,
  2176. IN BOOLEAN IsCdRom
  2177. )
  2178. /*++
  2179. Routine Description:
  2180. Given an ARC disk name, reads the MBR and adds its signature to the list of
  2181. disks.
  2182. Arguments:
  2183. Diskname - Supplies the name of the disk.
  2184. IsCdRom - Indicates whether the disk is a CD-ROM.
  2185. Return Value:
  2186. TRUE - Success
  2187. FALSE - Failure
  2188. --*/
  2189. {
  2190. PARC_DISK_SIGNATURE signature;
  2191. BOOLEAN status;
  2192. signature = FwAllocateHeap(sizeof(ARC_DISK_SIGNATURE));
  2193. if (signature==NULL) {
  2194. return(FALSE);
  2195. }
  2196. signature->ArcName = FwAllocateHeap(strlen(DiskName)+2);
  2197. if (signature->ArcName==NULL) {
  2198. return(FALSE);
  2199. }
  2200. status = BlGetDiskSignature(DiskName, IsCdRom, signature);
  2201. if (status) {
  2202. InsertHeadList(&(AEArcDiskInformation.DiskSignatures),
  2203. &(signature->ListEntry));
  2204. }
  2205. return(TRUE);
  2206. }
  2207. BOOLEAN
  2208. BlFindDiskSignature(
  2209. IN PCHAR DiskName,
  2210. IN PARC_DISK_SIGNATURE Signature
  2211. )
  2212. {
  2213. PARC_DISK_SIGNATURE match;
  2214. UCHAR buffer[] = "multi(xxx)disk(xxx)rdisk(xxx)";
  2215. if(AEArcDiskInformationInitialized == FALSE) {
  2216. return FALSE;
  2217. }
  2218. //
  2219. // If the disk name passed in contains an eisa component then convert
  2220. // the entire string into one with a multi component.
  2221. //
  2222. if(strncmp(DiskName, "eisa", strlen("eisa")) == 0) {
  2223. strcpy(&(buffer[1]), DiskName);
  2224. RtlCopyMemory(buffer, "multi", 5);
  2225. DiskName = buffer;
  2226. }
  2227. match = CONTAINING_RECORD(AEArcDiskInformation.DiskSignatures.Flink,
  2228. ARC_DISK_SIGNATURE,
  2229. ListEntry);
  2230. while(&(match->ListEntry) != &(AEArcDiskInformation.DiskSignatures)) {
  2231. if(strcmp(DiskName, match->ArcName) == 0) {
  2232. PCHAR c;
  2233. //
  2234. // We found a match. Copy all the information out of this node.
  2235. //
  2236. // DbgPrint("BlFindDiskSignature found a match for %s - %#08lx\n", DiskName, match);
  2237. Signature->CheckSum = match->CheckSum;
  2238. Signature->Signature = match->Signature;
  2239. Signature->ValidPartitionTable = match->ValidPartitionTable;
  2240. strcpy(Signature->ArcName, match->ArcName);
  2241. return TRUE;
  2242. }
  2243. match = CONTAINING_RECORD(match->ListEntry.Flink,
  2244. ARC_DISK_SIGNATURE,
  2245. ListEntry);
  2246. }
  2247. DbgPrint("BlFindDiskSignature found no match for %s\n", DiskName);
  2248. return FALSE;
  2249. }
  2250. VOID
  2251. AETerminateIo(
  2252. VOID
  2253. )
  2254. {
  2255. if(AEDriverUnloadRoutine != NULL) {
  2256. AEDriverUnloadRoutine(NULL);
  2257. }
  2258. return;
  2259. }