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.

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