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.

2441 lines
66 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. biosdrv.c
  5. Abstract:
  6. Provides the ARC emulation routines for I/O to a device supported by
  7. real-mode INT 13h BIOS calls.
  8. Author:
  9. John Vert (jvert) 7-Aug-1991
  10. Revision History:
  11. --*/
  12. #include "arccodes.h"
  13. #include "bootx86.h"
  14. #include "stdlib.h"
  15. #include "string.h"
  16. #include "flop.h"
  17. #if 0
  18. #define DBGOUT(x) BlPrint x
  19. #define DBGPAUSE while(!GET_KEY());
  20. #else
  21. #define DBGOUT(x)
  22. #define DBGPAUSE
  23. #endif
  24. //
  25. // Defines for buffer alignment and boundary checks in BiosDisk*
  26. // functions.
  27. //
  28. #define BIOSDISK_1MB (1 * 1024 * 1024)
  29. #define BIOSDISK_64KB (64 * 1024)
  30. #define BIOSDISK_64KB_MASK (~(BIOSDISK_64KB - 1))
  31. //
  32. // Definitions for caching the last read sector.
  33. //
  34. #define BL_LAST_SECTOR_CACHE_MAX_SIZE 4096
  35. typedef struct _BL_LAST_SECTOR_CACHE
  36. {
  37. BOOLEAN Initialized;
  38. BOOLEAN Valid;
  39. ULONG DeviceId;
  40. ULONGLONG SectorNumber;
  41. PUCHAR Data;
  42. } BL_LAST_SECTOR_CACHE, *PBL_LAST_SECTOR_CACHE;
  43. //
  44. // This is the global variable used for caching the last sector read
  45. // from the last disk. Callers who access files sequentially but do
  46. // not make sure their offsets are sector aligned end up reading the
  47. // last sector they read again with their next request. This solves
  48. // the problem. Its Data buffer is allocated from the pool at the
  49. // first disk read. It is setup and used in BiosDiskRead, invalidated
  50. // in BiosDiskWrite.
  51. //
  52. BL_LAST_SECTOR_CACHE FwLastSectorCache = {0};
  53. //
  54. // defines for doing console I/O
  55. //
  56. #define CSI 0x95
  57. #define SGR_INVERSE 7
  58. #define SGR_NORMAL 0
  59. //
  60. // static data for console I/O
  61. //
  62. BOOLEAN ControlSequence=FALSE;
  63. BOOLEAN EscapeSequence=FALSE;
  64. BOOLEAN FontSelection=FALSE;
  65. BOOLEAN HighIntensity=FALSE;
  66. BOOLEAN Blink=FALSE;
  67. ULONG PCount=0;
  68. #define CONTROL_SEQUENCE_MAX_PARAMETER 10
  69. ULONG Parameter[CONTROL_SEQUENCE_MAX_PARAMETER];
  70. #define KEY_INPUT_BUFFER_SIZE 16
  71. UCHAR KeyBuffer[KEY_INPUT_BUFFER_SIZE];
  72. ULONG KeyBufferEnd=0;
  73. ULONG KeyBufferStart=0;
  74. //
  75. // array for translating between ANSI colors and the VGA standard
  76. //
  77. UCHAR TranslateColor[] = {0,4,2,6,1,5,3,7};
  78. ARC_STATUS
  79. BiosDiskClose(
  80. IN ULONG FileId
  81. );
  82. VOID
  83. BiosConsoleFillBuffer(
  84. IN ULONG Key
  85. );
  86. //
  87. // There are two sorts of things we can open in this module, disk partitions,
  88. // and raw disk devices. The following device entry tables are
  89. // used for these things.
  90. //
  91. BL_DEVICE_ENTRY_TABLE BiosPartitionEntryTable =
  92. {
  93. (PARC_CLOSE_ROUTINE)BiosPartitionClose,
  94. (PARC_MOUNT_ROUTINE)BlArcNotYetImplemented,
  95. (PARC_OPEN_ROUTINE)BiosPartitionOpen,
  96. (PARC_READ_ROUTINE)BiosPartitionRead,
  97. (PARC_READ_STATUS_ROUTINE)BlArcNotYetImplemented,
  98. (PARC_SEEK_ROUTINE)BiosPartitionSeek,
  99. (PARC_WRITE_ROUTINE)BiosPartitionWrite,
  100. (PARC_GET_FILE_INFO_ROUTINE)BiosPartitionGetFileInfo,
  101. (PARC_SET_FILE_INFO_ROUTINE)BlArcNotYetImplemented,
  102. (PRENAME_ROUTINE)BlArcNotYetImplemented,
  103. (PARC_GET_DIRECTORY_ENTRY_ROUTINE)BlArcNotYetImplemented,
  104. (PBOOTFS_INFO)NULL
  105. };
  106. BL_DEVICE_ENTRY_TABLE BiosDiskEntryTable =
  107. {
  108. (PARC_CLOSE_ROUTINE)BiosDiskClose,
  109. (PARC_MOUNT_ROUTINE)BlArcNotYetImplemented,
  110. (PARC_OPEN_ROUTINE)BiosDiskOpen,
  111. (PARC_READ_ROUTINE)BiosDiskRead,
  112. (PARC_READ_STATUS_ROUTINE)BlArcNotYetImplemented,
  113. (PARC_SEEK_ROUTINE)BiosPartitionSeek,
  114. (PARC_WRITE_ROUTINE)BiosDiskWrite,
  115. (PARC_GET_FILE_INFO_ROUTINE)BiosDiskGetFileInfo,
  116. (PARC_SET_FILE_INFO_ROUTINE)BlArcNotYetImplemented,
  117. (PRENAME_ROUTINE)BlArcNotYetImplemented,
  118. (PARC_GET_DIRECTORY_ENTRY_ROUTINE)BlArcNotYetImplemented,
  119. (PBOOTFS_INFO)NULL
  120. };
  121. BL_DEVICE_ENTRY_TABLE BiosEDDSEntryTable =
  122. {
  123. (PARC_CLOSE_ROUTINE)BiosDiskClose,
  124. (PARC_MOUNT_ROUTINE)BlArcNotYetImplemented,
  125. (PARC_OPEN_ROUTINE)BiosDiskOpen,
  126. (PARC_READ_ROUTINE)BiosElToritoDiskRead,
  127. (PARC_READ_STATUS_ROUTINE)BlArcNotYetImplemented,
  128. (PARC_SEEK_ROUTINE)BiosPartitionSeek,
  129. (PARC_WRITE_ROUTINE)BlArcNotYetImplemented,
  130. (PARC_GET_FILE_INFO_ROUTINE)BiosDiskGetFileInfo,
  131. (PARC_SET_FILE_INFO_ROUTINE)BlArcNotYetImplemented,
  132. (PRENAME_ROUTINE)BlArcNotYetImplemented,
  133. (PARC_GET_DIRECTORY_ENTRY_ROUTINE)BlArcNotYetImplemented,
  134. (PBOOTFS_INFO)NULL
  135. };
  136. ARC_STATUS
  137. BiosDiskClose(
  138. IN ULONG FileId
  139. )
  140. /*++
  141. Routine Description:
  142. Closes the specified device
  143. Arguments:
  144. FileId - Supplies file id of the device to be closed
  145. Return Value:
  146. ESUCCESS - Device closed successfully
  147. !ESUCCESS - Device was not closed.
  148. --*/
  149. {
  150. if (BlFileTable[FileId].Flags.Open == 0) {
  151. #if DBG
  152. BlPrint("ERROR - Unopened fileid %lx closed\n",FileId);
  153. #endif
  154. }
  155. BlFileTable[FileId].Flags.Open = 0;
  156. //
  157. // Invalidate the last read sector cache if it was for this disk.
  158. //
  159. if (FwLastSectorCache.DeviceId == FileId) {
  160. FwLastSectorCache.Valid = FALSE;
  161. }
  162. return(ESUCCESS);
  163. }
  164. ARC_STATUS
  165. BiosPartitionClose(
  166. IN ULONG FileId
  167. )
  168. /*++
  169. Routine Description:
  170. Closes the specified device
  171. Arguments:
  172. FileId - Supplies file id of the device to be closed
  173. Return Value:
  174. ESUCCESS - Device closed successfully
  175. !ESUCCESS - Device was not closed.
  176. --*/
  177. {
  178. if (BlFileTable[FileId].Flags.Open == 0) {
  179. #if DBG
  180. BlPrint("ERROR - Unopened fileid %lx closed\n",FileId);
  181. #endif
  182. }
  183. BlFileTable[FileId].Flags.Open = 0;
  184. return(BiosDiskClose((ULONG)BlFileTable[FileId].u.PartitionContext.DiskId));
  185. }
  186. ARC_STATUS
  187. BiosPartitionOpen(
  188. IN PCHAR OpenPath,
  189. IN OPEN_MODE OpenMode,
  190. OUT PULONG FileId
  191. )
  192. /*++
  193. Routine Description:
  194. Opens the disk partition specified by OpenPath. This routine will open
  195. floppy drives 0 and 1, and any partition on hard drive 0 or 1.
  196. Arguments:
  197. OpenPath - Supplies a pointer to the name of the partition. If OpenPath
  198. is "A:" or "B:" the corresponding floppy drive will be opened.
  199. If it is "C:" or above, this routine will find the corresponding
  200. partition on hard drive 0 or 1 and open it.
  201. OpenMode - Supplies the mode to open the file.
  202. 0 - Read Only
  203. 1 - Write Only
  204. 2 - Read/Write
  205. FileId - Returns the file descriptor for use with the Close, Read, Write,
  206. and Seek routines
  207. Return Value:
  208. ESUCCESS - File successfully opened.
  209. --*/
  210. {
  211. ARC_STATUS Status;
  212. ULONG DiskFileId;
  213. UCHAR PartitionNumber;
  214. ULONG Controller;
  215. ULONG Key;
  216. BOOLEAN IsEisa = FALSE;
  217. UNREFERENCED_PARAMETER( OpenMode );
  218. //
  219. // BIOS devices are always "multi(0)" (except for EISA flakiness
  220. // where we treat "eisa(0)..." like "multi(0)..." in floppy cases.
  221. //
  222. if(FwGetPathMnemonicKey(OpenPath,"multi",&Key)) {
  223. if(FwGetPathMnemonicKey(OpenPath,"eisa", &Key)) {
  224. return(EBADF);
  225. } else {
  226. IsEisa = TRUE;
  227. }
  228. }
  229. if (Key!=0) {
  230. return(EBADF);
  231. }
  232. //
  233. // If we're opening a floppy drive, there are no partitions
  234. // so we can just return the physical device.
  235. //
  236. if((_stricmp(OpenPath,"multi(0)disk(0)fdisk(0)partition(0)") == 0) ||
  237. (_stricmp(OpenPath,"eisa(0)disk(0)fdisk(0)partition(0)" ) == 0))
  238. {
  239. return(BiosDiskOpen( 0, 0, FileId));
  240. }
  241. if((_stricmp(OpenPath,"multi(0)disk(0)fdisk(1)partition(0)") == 0) ||
  242. (_stricmp(OpenPath,"eisa(0)disk(0)fdisk(1)partition(0)" ) == 0))
  243. {
  244. return(BiosDiskOpen( 1, 0, FileId));
  245. }
  246. if((_stricmp(OpenPath,"multi(0)disk(0)fdisk(0)") == 0) ||
  247. (_stricmp(OpenPath,"eisa(0)disk(0)fdisk(0)" ) == 0))
  248. {
  249. return(BiosDiskOpen( 0, 0, FileId));
  250. }
  251. if((_stricmp(OpenPath,"multi(0)disk(0)fdisk(1)") == 0) ||
  252. (_stricmp(OpenPath,"eisa(0)disk(0)fdisk(1)" ) == 0))
  253. {
  254. return(BiosDiskOpen( 1, 0, FileId));
  255. }
  256. //
  257. // We can't handle eisa(0) cases for hard disks.
  258. //
  259. if(IsEisa) {
  260. return(EBADF);
  261. }
  262. //
  263. // We can only deal with disk controller 0
  264. //
  265. if (FwGetPathMnemonicKey(OpenPath,"disk",&Controller)) {
  266. return(EBADF);
  267. }
  268. if ( Controller!=0 ) {
  269. return(EBADF);
  270. }
  271. if (!FwGetPathMnemonicKey(OpenPath,"cdrom",&Key)) {
  272. //
  273. // Now we have a CD-ROM disk number, so we open that for raw access.
  274. // Use a special bit to indicate CD-ROM, because otherwise
  275. // the BiosDiskOpen routine thinks a third or greater disk is
  276. // a CD-ROM.
  277. //
  278. return(BiosDiskOpen( Key | 0x80000000, 0, FileId ) );
  279. }
  280. if (FwGetPathMnemonicKey(OpenPath,"rdisk",&Key)) {
  281. return(EBADF);
  282. }
  283. //
  284. // Now we have a disk number, so we open that for raw access.
  285. // We need to add 0x80 to translate it to a BIOS number.
  286. //
  287. Status = BiosDiskOpen( 0x80 + Key,
  288. 0,
  289. &DiskFileId );
  290. if (Status != ESUCCESS) {
  291. return(Status);
  292. }
  293. //
  294. // Find the partition number to open
  295. //
  296. if (FwGetPathMnemonicKey(OpenPath,"partition",&Key)) {
  297. BiosPartitionClose(DiskFileId);
  298. return(EBADF);
  299. }
  300. //
  301. // If the partition number was 0, then we are opening the device
  302. // for raw access, so we are already done.
  303. //
  304. if (Key == 0) {
  305. *FileId = DiskFileId;
  306. return(ESUCCESS);
  307. }
  308. //
  309. // Before we open the partition, we need to find an available
  310. // file descriptor.
  311. //
  312. *FileId=2;
  313. while (BlFileTable[*FileId].Flags.Open != 0) {
  314. *FileId += 1;
  315. if (*FileId == BL_FILE_TABLE_SIZE) {
  316. return(ENOENT);
  317. }
  318. }
  319. //
  320. // We found an entry we can use, so mark it as open.
  321. //
  322. BlFileTable[*FileId].Flags.Open = 1;
  323. BlFileTable[*FileId].DeviceEntryTable=&BiosPartitionEntryTable;
  324. //
  325. // Convert to zero-based partition number
  326. //
  327. PartitionNumber = (UCHAR)(Key - 1);
  328. //
  329. // Try to open the MBR partition
  330. //
  331. Status = HardDiskPartitionOpen( *FileId,
  332. DiskFileId,
  333. PartitionNumber);
  334. #ifdef EFI_PARTITION_SUPPORT
  335. if (Status != ESUCCESS) {
  336. //
  337. // Try to open the GPT partition
  338. //
  339. Status = BlOpenGPTDiskPartition( *FileId,
  340. DiskFileId,
  341. PartitionNumber);
  342. }
  343. #endif
  344. return Status;
  345. }
  346. ARC_STATUS
  347. BiosPartitionRead (
  348. IN ULONG FileId,
  349. OUT PVOID Buffer,
  350. IN ULONG Length,
  351. OUT PULONG Count
  352. )
  353. /*++
  354. Routine Description:
  355. Reads from the specified file
  356. NOTE John Vert (jvert) 18-Jun-1991
  357. This only supports block sector reads. Thus, everything
  358. is assumed to start on a sector boundary, and every offset
  359. is considered an offset from the logical beginning of the disk
  360. partition.
  361. Arguments:
  362. FileId - Supplies the file to read from
  363. Buffer - Supplies buffer to hold the data that is read
  364. Length - Supplies maximum number of bytes to read
  365. Count - Returns actual bytes read.
  366. Return Value:
  367. ESUCCESS - Read completed successfully
  368. !ESUCCESS - Read failed.
  369. --*/
  370. {
  371. ARC_STATUS Status;
  372. LARGE_INTEGER PhysicalOffset;
  373. ULONG DiskId;
  374. PhysicalOffset.QuadPart = BlFileTable[FileId].Position.QuadPart +
  375. SECTOR_SIZE * (LONGLONG)BlFileTable[FileId].u.PartitionContext.StartingSector;
  376. DiskId = BlFileTable[FileId].u.PartitionContext.DiskId;
  377. Status = (BlFileTable[DiskId].DeviceEntryTable->Seek)(DiskId,
  378. &PhysicalOffset,
  379. SeekAbsolute );
  380. if (Status != ESUCCESS) {
  381. return(Status);
  382. }
  383. Status = (BlFileTable[DiskId].DeviceEntryTable->Read)(DiskId,
  384. Buffer,
  385. Length,
  386. Count );
  387. BlFileTable[FileId].Position.QuadPart += *Count;
  388. return(Status);
  389. }
  390. ARC_STATUS
  391. BiosPartitionSeek (
  392. IN ULONG FileId,
  393. IN PLARGE_INTEGER Offset,
  394. IN SEEK_MODE SeekMode
  395. )
  396. /*++
  397. Routine Description:
  398. Changes the current offset of the file specified by FileId
  399. Arguments:
  400. FileId - specifies the file on which the current offset is to
  401. be changed.
  402. Offset - New offset into file.
  403. SeekMode - Either SeekAbsolute or SeekRelative
  404. SeekEndRelative is not supported
  405. Return Value:
  406. ESUCCESS - Operation completed succesfully
  407. EBADF - Operation did not complete successfully.
  408. --*/
  409. {
  410. switch (SeekMode) {
  411. case SeekAbsolute:
  412. BlFileTable[FileId].Position = *Offset;
  413. break;
  414. case SeekRelative:
  415. BlFileTable[FileId].Position.QuadPart += Offset->QuadPart;
  416. break;
  417. default:
  418. #if DBG
  419. BlPrint("SeekMode %lx not supported\n",SeekMode);
  420. #endif
  421. return(EACCES);
  422. }
  423. return(ESUCCESS);
  424. }
  425. ARC_STATUS
  426. BiosPartitionWrite(
  427. IN ULONG FileId,
  428. OUT PVOID Buffer,
  429. IN ULONG Length,
  430. OUT PULONG Count
  431. )
  432. /*++
  433. Routine Description:
  434. Writes to the specified file
  435. NOTE John Vert (jvert) 18-Jun-1991
  436. This only supports block sector reads. Thus, everything
  437. is assumed to start on a sector boundary, and every offset
  438. is considered an offset from the logical beginning of the disk
  439. partition.
  440. Arguments:
  441. FileId - Supplies the file to write to
  442. Buffer - Supplies buffer with data to write
  443. Length - Supplies number of bytes to write
  444. Count - Returns actual bytes written.
  445. Return Value:
  446. ESUCCESS - write completed successfully
  447. !ESUCCESS - write failed.
  448. --*/
  449. {
  450. ARC_STATUS Status;
  451. LARGE_INTEGER PhysicalOffset;
  452. ULONG DiskId;
  453. PhysicalOffset.QuadPart = BlFileTable[FileId].Position.QuadPart +
  454. SECTOR_SIZE * (LONGLONG)BlFileTable[FileId].u.PartitionContext.StartingSector;
  455. DiskId = BlFileTable[FileId].u.PartitionContext.DiskId;
  456. Status = (BlFileTable[DiskId].DeviceEntryTable->Seek)(DiskId,
  457. &PhysicalOffset,
  458. SeekAbsolute );
  459. if (Status != ESUCCESS) {
  460. return(Status);
  461. }
  462. Status = (BlFileTable[DiskId].DeviceEntryTable->Write)(DiskId,
  463. Buffer,
  464. Length,
  465. Count );
  466. if(Status == ESUCCESS) {
  467. BlFileTable[FileId].Position.QuadPart += *Count;
  468. }
  469. return(Status);
  470. }
  471. ARC_STATUS
  472. BiosConsoleOpen(
  473. IN PCHAR OpenPath,
  474. IN OPEN_MODE OpenMode,
  475. OUT PULONG FileId
  476. )
  477. /*++
  478. Routine Description:
  479. Attempts to open either the console input or output
  480. Arguments:
  481. OpenPath - Supplies a pointer to the name of the device to open. If
  482. this is either CONSOLE_INPUT_NAME or CONSOLE_OUTPUT_NAME,
  483. a file descriptor is allocated and filled in.
  484. OpenMode - Supplies the mode to open the file.
  485. 0 - Read Only (CONSOLE_INPUT_NAME)
  486. 1 - Write Only (CONSOLE_OUTPUT_NAME)
  487. FileId - Returns the file descriptor for use with the Close, Read and
  488. Write routines
  489. Return Value:
  490. ESUCCESS - Console successfully opened.
  491. --*/
  492. {
  493. if (_stricmp(OpenPath, CONSOLE_INPUT_NAME)==0) {
  494. //
  495. // Open the keyboard for input
  496. //
  497. if (OpenMode != ArcOpenReadOnly) {
  498. return(EACCES);
  499. }
  500. *FileId = 0;
  501. return(ESUCCESS);
  502. }
  503. if (_stricmp(OpenPath, CONSOLE_OUTPUT_NAME)==0) {
  504. //
  505. // Open the display for output
  506. //
  507. if (OpenMode != ArcOpenWriteOnly) {
  508. return(EACCES);
  509. }
  510. *FileId = 1;
  511. return(ESUCCESS);
  512. }
  513. return(ENOENT);
  514. }
  515. ARC_STATUS
  516. BiosConsoleReadStatus(
  517. IN ULONG FileId
  518. )
  519. /*++
  520. Routine Description:
  521. This routine determines if there is a keypress pending
  522. Arguments:
  523. FileId - Supplies the FileId to be read. (should always be 0 for this
  524. function)
  525. Return Value:
  526. ESUCCESS - There is a key pending
  527. EAGAIN - There is not a key pending
  528. --*/
  529. {
  530. ULONG Key;
  531. //
  532. // enforce file id to be 0 by no reading console otherwise
  533. //
  534. if (FileId != 0) {
  535. return EINVAL;
  536. }
  537. //
  538. // If we have buffered input...
  539. //
  540. if (KeyBufferEnd != KeyBufferStart) {
  541. return(ESUCCESS);
  542. }
  543. //
  544. // Check for a key
  545. //
  546. Key = GET_KEY();
  547. if (Key != 0) {
  548. //
  549. // We got a key, so we have to stick it back into our buffer
  550. // and return ESUCCESS.
  551. //
  552. BiosConsoleFillBuffer(Key);
  553. return(ESUCCESS);
  554. } else {
  555. //
  556. // no key pending
  557. //
  558. return(EAGAIN);
  559. }
  560. }
  561. ARC_STATUS
  562. BiosConsoleRead(
  563. IN ULONG FileId,
  564. OUT PUCHAR Buffer,
  565. IN ULONG Length,
  566. OUT PULONG Count
  567. )
  568. /*++
  569. Routine Description:
  570. Gets input from the keyboard.
  571. Arguments:
  572. FileId - Supplies the FileId to be read (should always be 0 for this
  573. function)
  574. Buffer - Returns the keyboard input.
  575. Length - Supplies the length of the buffer (in bytes)
  576. Count - Returns the actual number of bytes read
  577. Return Value:
  578. ESUCCESS - Keyboard read completed succesfully.
  579. --*/
  580. {
  581. ULONG Key;
  582. //
  583. // enforce file id to be 0 by no reading console otherwise
  584. //
  585. if (FileId != 0) {
  586. return EINVAL;
  587. }
  588. *Count = 0;
  589. while (*Count < Length) {
  590. if (KeyBufferEnd == KeyBufferStart) { // then buffer is presently empty
  591. do {
  592. //
  593. // Poll the keyboard until input is available
  594. //
  595. Key = GET_KEY();
  596. } while ( Key==0 );
  597. BiosConsoleFillBuffer(Key);
  598. }
  599. Buffer[*Count] = KeyBuffer[KeyBufferStart];
  600. KeyBufferStart = (KeyBufferStart+1) % KEY_INPUT_BUFFER_SIZE;
  601. *Count = *Count + 1;
  602. }
  603. return(ESUCCESS);
  604. }
  605. VOID
  606. BiosConsoleFillBuffer(
  607. IN ULONG Key
  608. )
  609. /*++
  610. Routine Description:
  611. Places input from the keyboard into the keyboard buffer, expanding the
  612. special keys as appropriate.
  613. All keys translated here use the ARC translation table, as defined in the
  614. ARC specification, with one exception -- the BACKTAB_KEY, for which the
  615. ARC spec is lacking. I have decided that BACKTAB_KEY is ESC+TAB.
  616. Arguments:
  617. Key - Raw keypress value as returned by GET_KEY().
  618. Return Value:
  619. none.
  620. --*/
  621. {
  622. switch(Key) {
  623. case UP_ARROW:
  624. KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
  625. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  626. KeyBuffer[KeyBufferEnd] = 'A';
  627. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  628. break;
  629. case DOWN_ARROW:
  630. KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
  631. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  632. KeyBuffer[KeyBufferEnd] = 'B';
  633. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  634. break;
  635. case RIGHT_KEY:
  636. KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
  637. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  638. KeyBuffer[KeyBufferEnd] = 'C';
  639. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  640. break;
  641. case LEFT_KEY:
  642. KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
  643. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  644. KeyBuffer[KeyBufferEnd] = 'D';
  645. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  646. break;
  647. case INS_KEY:
  648. KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
  649. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  650. KeyBuffer[KeyBufferEnd] = '@';
  651. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  652. break;
  653. case DEL_KEY:
  654. KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
  655. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  656. KeyBuffer[KeyBufferEnd] = 'P';
  657. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  658. break;
  659. case F1_KEY:
  660. KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
  661. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  662. KeyBuffer[KeyBufferEnd] = 'O';
  663. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  664. KeyBuffer[KeyBufferEnd] = 'P';
  665. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  666. break;
  667. case F2_KEY:
  668. KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
  669. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  670. KeyBuffer[KeyBufferEnd] = 'O';
  671. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  672. KeyBuffer[KeyBufferEnd] = 'Q';
  673. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  674. break;
  675. case F3_KEY:
  676. KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
  677. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  678. KeyBuffer[KeyBufferEnd] = 'O';
  679. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  680. KeyBuffer[KeyBufferEnd] = 'w';
  681. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  682. break;
  683. case F4_KEY:
  684. KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
  685. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  686. KeyBuffer[KeyBufferEnd] = 'O';
  687. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  688. KeyBuffer[KeyBufferEnd] = 'x';
  689. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  690. break;
  691. case F5_KEY:
  692. KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
  693. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  694. KeyBuffer[KeyBufferEnd] = 'O';
  695. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  696. KeyBuffer[KeyBufferEnd] = 't';
  697. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  698. break;
  699. case F6_KEY:
  700. KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
  701. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  702. KeyBuffer[KeyBufferEnd] = 'O';
  703. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  704. KeyBuffer[KeyBufferEnd] = 'u';
  705. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  706. break;
  707. case F7_KEY:
  708. KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
  709. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  710. KeyBuffer[KeyBufferEnd] = 'O';
  711. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  712. KeyBuffer[KeyBufferEnd] = 'q';
  713. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  714. break;
  715. case F8_KEY:
  716. KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
  717. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  718. KeyBuffer[KeyBufferEnd] = 'O';
  719. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  720. KeyBuffer[KeyBufferEnd] = 'r';
  721. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  722. break;
  723. case F10_KEY:
  724. KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
  725. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  726. KeyBuffer[KeyBufferEnd] = 'O';
  727. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  728. KeyBuffer[KeyBufferEnd] = 'M';
  729. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  730. break;
  731. case F11_KEY:
  732. KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
  733. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  734. KeyBuffer[KeyBufferEnd] = 'O';
  735. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  736. KeyBuffer[KeyBufferEnd] = 'A';
  737. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  738. break;
  739. case F12_KEY:
  740. KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
  741. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  742. KeyBuffer[KeyBufferEnd] = 'O';
  743. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  744. KeyBuffer[KeyBufferEnd] = 'B';
  745. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  746. break;
  747. case HOME_KEY:
  748. KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
  749. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  750. KeyBuffer[KeyBufferEnd] = 'H';
  751. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  752. break;
  753. case END_KEY:
  754. KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
  755. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  756. KeyBuffer[KeyBufferEnd] = 'K';
  757. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  758. break;
  759. case ESCAPE_KEY:
  760. KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
  761. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  762. break;
  763. case BACKTAB_KEY:
  764. KeyBuffer[KeyBufferEnd] = ASCI_CSI_IN;
  765. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  766. KeyBuffer[KeyBufferEnd] = (UCHAR)(TAB_KEY & 0xFF);
  767. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  768. break;
  769. default:
  770. //
  771. // The ASCII code is the low byte of Key
  772. //
  773. KeyBuffer[KeyBufferEnd] = (UCHAR)(Key & 0xff);
  774. KeyBufferEnd = (KeyBufferEnd+1) % KEY_INPUT_BUFFER_SIZE;
  775. }
  776. }
  777. ARC_STATUS
  778. BiosConsoleWrite(
  779. IN ULONG FileId,
  780. OUT PUCHAR Buffer,
  781. IN ULONG Length,
  782. OUT PULONG Count
  783. )
  784. /*++
  785. Routine Description:
  786. Outputs to the console. (In this case, the VGA display)
  787. Arguments:
  788. FileId - Supplies the FileId to be written (should always be 1 for this
  789. function)
  790. Buffer - Supplies characters to be output
  791. Length - Supplies the length of the buffer (in bytes)
  792. Count - Returns the actual number of bytes written
  793. Return Value:
  794. ESUCCESS - Console write completed succesfully.
  795. --*/
  796. {
  797. ARC_STATUS Status;
  798. PUCHAR String;
  799. ULONG Index;
  800. UCHAR a;
  801. PUCHAR p;
  802. //
  803. // enforce file id to be 0 by no reading console otherwise
  804. //
  805. if (FileId != 1) {
  806. return EINVAL;
  807. }
  808. //
  809. // Process each character in turn.
  810. //
  811. Status = ESUCCESS;
  812. String = (PUCHAR)Buffer;
  813. for ( *Count = 0 ;
  814. *Count < Length ;
  815. (*Count)++, String++ ) {
  816. //
  817. // If we're in the middle of a control sequence, continue scanning,
  818. // otherwise process character.
  819. //
  820. if (ControlSequence) {
  821. //
  822. // If the character is a digit, update parameter value.
  823. //
  824. if ((*String >= '0') && (*String <= '9')) {
  825. Parameter[PCount] = Parameter[PCount] * 10 + *String - '0';
  826. continue;
  827. }
  828. //
  829. // If we are in the middle of a font selection sequence, this
  830. // character must be a 'D', otherwise reset control sequence.
  831. //
  832. if (FontSelection) {
  833. //if (*String == 'D') {
  834. //
  835. // //
  836. // // Other fonts not implemented yet.
  837. // //
  838. //
  839. //} else {
  840. //}
  841. ControlSequence = FALSE;
  842. FontSelection = FALSE;
  843. continue;
  844. }
  845. switch (*String) {
  846. //
  847. // If a semicolon, move to the next parameter.
  848. //
  849. case ';':
  850. PCount++;
  851. if (PCount > CONTROL_SEQUENCE_MAX_PARAMETER) {
  852. PCount = CONTROL_SEQUENCE_MAX_PARAMETER;
  853. }
  854. Parameter[PCount] = 0;
  855. break;
  856. //
  857. // If a 'J', erase part or all of the screen.
  858. //
  859. case 'J':
  860. switch (Parameter[0]) {
  861. case 0:
  862. //
  863. // Erase to end of the screen
  864. //
  865. TextClearToEndOfDisplay();
  866. break;
  867. case 1:
  868. //
  869. // Erase from the beginning of the screen
  870. //
  871. break;
  872. default:
  873. //
  874. // Erase entire screen
  875. //
  876. TextClearDisplay();
  877. break;
  878. }
  879. ControlSequence = FALSE;
  880. break;
  881. //
  882. // If a 'K', erase part or all of the line.
  883. //
  884. case 'K':
  885. switch (Parameter[0]) {
  886. //
  887. // Erase to end of the line.
  888. //
  889. case 0:
  890. TextClearToEndOfLine();
  891. break;
  892. //
  893. // Erase from the beginning of the line.
  894. //
  895. case 1:
  896. TextClearFromStartOfLine();
  897. break;
  898. //
  899. // Erase entire line.
  900. //
  901. default :
  902. TextClearFromStartOfLine();
  903. TextClearToEndOfLine();
  904. break;
  905. }
  906. ControlSequence = FALSE;
  907. break;
  908. //
  909. // If a 'H', move cursor to position.
  910. //
  911. case 'H':
  912. TextSetCursorPosition(Parameter[1]-1, Parameter[0]-1);
  913. ControlSequence = FALSE;
  914. break;
  915. //
  916. // If a ' ', could be a FNT selection command.
  917. //
  918. case ' ':
  919. FontSelection = TRUE;
  920. break;
  921. case 'm':
  922. //
  923. // Select action based on each parameter.
  924. //
  925. // Blink and HighIntensity are by default disabled
  926. // each time a new SGR is specified, unless they are
  927. // explicitly specified again, in which case these
  928. // will be set to TRUE at that time.
  929. //
  930. HighIntensity = FALSE;
  931. Blink = FALSE;
  932. for ( Index = 0 ; Index <= PCount ; Index++ ) {
  933. switch (Parameter[Index]) {
  934. //
  935. // Attributes off.
  936. //
  937. case 0:
  938. TextSetCurrentAttribute(7);
  939. HighIntensity = FALSE;
  940. Blink = FALSE;
  941. break;
  942. //
  943. // High Intensity.
  944. //
  945. case 1:
  946. TextSetCurrentAttribute(0xf);
  947. HighIntensity = TRUE;
  948. break;
  949. //
  950. // Underscored.
  951. //
  952. case 4:
  953. break;
  954. //
  955. // Blink.
  956. //
  957. case 5:
  958. TextSetCurrentAttribute(0x87);
  959. Blink = TRUE;
  960. break;
  961. //
  962. // Reverse Video.
  963. //
  964. case 7:
  965. TextSetCurrentAttribute(0x70);
  966. HighIntensity = FALSE;
  967. Blink = FALSE;
  968. break;
  969. //
  970. // Font selection, not implemented yet.
  971. //
  972. case 10:
  973. case 11:
  974. case 12:
  975. case 13:
  976. case 14:
  977. case 15:
  978. case 16:
  979. case 17:
  980. case 18:
  981. case 19:
  982. break;
  983. //
  984. // Foreground Color
  985. //
  986. case 30:
  987. case 31:
  988. case 32:
  989. case 33:
  990. case 34:
  991. case 35:
  992. case 36:
  993. case 37:
  994. a = TextGetCurrentAttribute();
  995. a &= 0x70;
  996. a |= TranslateColor[Parameter[Index]-30];
  997. if (HighIntensity) {
  998. a |= 0x08;
  999. }
  1000. if (Blink) {
  1001. a |= 0x80;
  1002. }
  1003. TextSetCurrentAttribute(a);
  1004. break;
  1005. //
  1006. // Background Color
  1007. //
  1008. case 40:
  1009. case 41:
  1010. case 42:
  1011. case 43:
  1012. case 44:
  1013. case 45:
  1014. case 46:
  1015. case 47:
  1016. a = TextGetCurrentAttribute();
  1017. a &= 0x8f;
  1018. a |= TranslateColor[Parameter[Index]-40] << 4;
  1019. TextSetCurrentAttribute(a);
  1020. break;
  1021. default:
  1022. break;
  1023. }
  1024. }
  1025. default:
  1026. ControlSequence = FALSE;
  1027. break;
  1028. }
  1029. //
  1030. // This is not a control sequence, check for escape sequence.
  1031. //
  1032. } else {
  1033. //
  1034. // If escape sequence, check for control sequence, otherwise
  1035. // process single character.
  1036. //
  1037. if (EscapeSequence) {
  1038. //
  1039. // Check for '[', means control sequence, any other following
  1040. // character is ignored.
  1041. //
  1042. if (*String == '[') {
  1043. ControlSequence = TRUE;
  1044. //
  1045. // Initialize first parameter.
  1046. //
  1047. PCount = 0;
  1048. Parameter[0] = 0;
  1049. }
  1050. EscapeSequence = FALSE;
  1051. //
  1052. // This is not a control or escape sequence, process single character.
  1053. //
  1054. } else {
  1055. switch (*String) {
  1056. //
  1057. // Check for escape sequence.
  1058. //
  1059. case ASCI_ESC:
  1060. EscapeSequence = TRUE;
  1061. break;
  1062. default:
  1063. p = TextCharOut(String);
  1064. //
  1065. // Each pass through the loop increments String by 1.
  1066. // If we output a dbcs char we need to increment by
  1067. // one more.
  1068. //
  1069. (*Count) += (p - String) - 1;
  1070. String += (p - String) - 1;
  1071. break;
  1072. }
  1073. }
  1074. }
  1075. }
  1076. return Status;
  1077. }
  1078. ARC_STATUS
  1079. BiosDiskOpen(
  1080. IN ULONG DriveId,
  1081. IN OPEN_MODE OpenMode,
  1082. OUT PULONG FileId
  1083. )
  1084. /*++
  1085. Routine Description:
  1086. Opens a BIOS-accessible disk for raw sector access.
  1087. Arguments:
  1088. DriveId - Supplies the BIOS DriveId of the drive to open
  1089. 0 - Floppy 0
  1090. 1 - Floppy 1
  1091. 0x80 - Hard Drive 0
  1092. 0x81 - Hard Drive 1
  1093. 0x82 - Hard Drive 2
  1094. etc
  1095. High bit set and ID > 0x81 means the device is expected to be
  1096. a CD-ROM drive.
  1097. OpenMode - Supplies the mode of the open
  1098. FileId - Supplies a pointer to a variable that specifies the file
  1099. table entry that is filled in if the open is successful.
  1100. Return Value:
  1101. ESUCCESS is returned if the open operation is successful. Otherwise,
  1102. an unsuccessful status is returned that describes the reason for failure.
  1103. --*/
  1104. {
  1105. USHORT NumberHeads;
  1106. UCHAR NumberSectors;
  1107. USHORT NumberCylinders;
  1108. UCHAR NumberDrives;
  1109. ULONG Result;
  1110. PDRIVE_CONTEXT Context;
  1111. BOOLEAN IsCd;
  1112. UCHAR *Buffer = FwDiskCache;
  1113. ULONG BufferSize = 512; // sector size
  1114. BOOLEAN xInt13;
  1115. UNREFERENCED_PARAMETER( OpenMode );
  1116. DBGOUT(("BiosDiskOpen: enter, id = 0x%lx\r\n",DriveId));
  1117. //
  1118. // Check special drive number encoding for CD-ROM case
  1119. //
  1120. if(DriveId > 0x80000081) {
  1121. IsCd = TRUE;
  1122. DriveId &= 0x7fffffff;
  1123. } else {
  1124. IsCd = FALSE;
  1125. }
  1126. xInt13 = FALSE;
  1127. //
  1128. // If we are opening Floppy 0 or Floppy 1, we want to read the BPB off
  1129. // the disk so we can deal with all the odd disk formats.
  1130. //
  1131. // If we are opening a hard drive, we can just call the BIOS to find out
  1132. // its characteristics
  1133. //
  1134. if(DriveId < 128) {
  1135. PPACKED_BOOT_SECTOR BootSector;
  1136. BIOS_PARAMETER_BLOCK Bpb;
  1137. //
  1138. // Read the boot sector off the floppy and extract the cylinder,
  1139. // sector, and head information. We fake the CHS values here
  1140. // to allow sector 0 to be read before we actually know the
  1141. // geometry we want to use.
  1142. //
  1143. if(ReadPhysicalSectors((UCHAR)DriveId,0,1,Buffer,1,1,1,FALSE)) {
  1144. DBGOUT(("BiosDiskOpen: error reading from floppy drive\r\n"));
  1145. DBGPAUSE
  1146. return(EIO);
  1147. }
  1148. BootSector = (PPACKED_BOOT_SECTOR)Buffer;
  1149. FatUnpackBios(&Bpb, &(BootSector->PackedBpb));
  1150. NumberHeads = Bpb.Heads;
  1151. NumberSectors = (UCHAR)Bpb.SectorsPerTrack;
  1152. if (Bpb.Sectors != 0) {
  1153. NumberCylinders = Bpb.Sectors / (NumberSectors * NumberHeads);
  1154. }
  1155. else {
  1156. ULONG Cylinders = Bpb.LargeSectors / (NumberSectors * NumberHeads);
  1157. //
  1158. // LargeSectors has size of ULONG.
  1159. // so truncate size at MAX(USHORT) and check for xint13
  1160. // so it can be used for the higher sectors
  1161. //
  1162. NumberCylinders = ( Cylinders > (USHORT)-1 ) ? (USHORT) -1 :
  1163. (USHORT) Cylinders;
  1164. //
  1165. // Attempt to get extended int13 parameters.
  1166. // Note that we use a buffer that's on the stack, so it's guaranteed
  1167. // to be under the 1 MB line (required when passing buffers to real-mode
  1168. // services).
  1169. //
  1170. // Note that we don't actually care about the parameters, just whether
  1171. // extended int13 services are available.
  1172. //
  1173. RtlZeroMemory(Buffer,BufferSize);
  1174. xInt13 = GET_XINT13_PARAMS(Buffer,(UCHAR)DriveId);
  1175. }
  1176. } else if(IsCd) {
  1177. //
  1178. // This is an El Torito drive
  1179. // Just use bogus values since CHS values are meaningless for no-emulation El Torito boot
  1180. //
  1181. NumberCylinders = 1;
  1182. NumberHeads = 1;
  1183. NumberSectors = 1;
  1184. } else {
  1185. //
  1186. // Get Drive Parameters via int13 function 8
  1187. // Return of 0 means success; otherwise we get back what the BIOS
  1188. // returned in ax.
  1189. //
  1190. ULONG Retries = 0;
  1191. do {
  1192. if(BIOS_IO(0x08,(UCHAR)DriveId,0,0,0,0,0)) {
  1193. DBGOUT(("BiosDiskOpen: error getting params for drive\r\n"));
  1194. DBGPAUSE
  1195. return(EIO);
  1196. }
  1197. //
  1198. // At this point, ECX looks like this:
  1199. //
  1200. // bits 31..22 - Maximum cylinder
  1201. // bits 21..16 - Maximum sector
  1202. // bits 15..8 - Maximum head
  1203. // bits 7..0 - Number of drives
  1204. //
  1205. // Unpack the information from ecx.
  1206. //
  1207. _asm {
  1208. mov Result, ecx
  1209. }
  1210. NumberDrives = (UCHAR)Result;
  1211. NumberHeads = (((USHORT)Result >> 8) & 0xff) + 1;
  1212. NumberSectors = (UCHAR)((Result >> 16) & 0x3f);
  1213. NumberCylinders = (USHORT)(((Result >> 24) + ((Result >> 14) & 0x300)) + 1);
  1214. ++Retries;
  1215. } while ( ((NumberHeads==0) || (NumberSectors==0) || (NumberCylinders==0))
  1216. && (Retries < 5) );
  1217. DBGOUT((
  1218. "BiosDiskOpen: cyl=%u, heads=%u, sect=%u, drives=%u\r\n",
  1219. NumberCylinders,
  1220. NumberHeads,
  1221. NumberSectors,
  1222. NumberDrives
  1223. ));
  1224. if(((UCHAR)DriveId & 0x7f) >= NumberDrives) {
  1225. //
  1226. // The requested drive does not exist
  1227. //
  1228. DBGOUT(("BiosDiskOpen: invalid drive\r\n"));
  1229. DBGPAUSE
  1230. return(EIO);
  1231. }
  1232. if (Retries == 5) {
  1233. DBGOUT(("Couldn't get BIOS configuration info\n"));
  1234. DBGPAUSE
  1235. return(EIO);
  1236. }
  1237. //
  1238. // Attempt to get extended int13 parameters.
  1239. // Note that we use a buffer that's on the stack, so it's guaranteed
  1240. // to be under the 1 MB line (required when passing buffers to real-mode
  1241. // services).
  1242. //
  1243. // Note that we don't actually care about the parameters, just whether
  1244. // extended int13 services are available.
  1245. //
  1246. RtlZeroMemory(Buffer,BufferSize);
  1247. xInt13 = GET_XINT13_PARAMS(Buffer,(UCHAR)DriveId);
  1248. DBGOUT(("BiosDiskOpen: xint13 for drive: %s\r\n",xInt13 ? "yes" : "no"));
  1249. }
  1250. //
  1251. // Find an available FileId descriptor to open the device with
  1252. //
  1253. *FileId=2;
  1254. while (BlFileTable[*FileId].Flags.Open != 0) {
  1255. *FileId += 1;
  1256. if(*FileId == BL_FILE_TABLE_SIZE) {
  1257. DBGOUT(("BiosDiskOpen: no file table entry available\r\n"));
  1258. DBGPAUSE
  1259. return(ENOENT);
  1260. }
  1261. }
  1262. //
  1263. // We found an entry we can use, so mark it as open.
  1264. //
  1265. BlFileTable[*FileId].Flags.Open = 1;
  1266. BlFileTable[*FileId].DeviceEntryTable = IsCd
  1267. ? &BiosEDDSEntryTable
  1268. : &BiosDiskEntryTable;
  1269. Context = &(BlFileTable[*FileId].u.DriveContext);
  1270. Context->IsCd = IsCd;
  1271. Context->Drive = (UCHAR)DriveId;
  1272. Context->Cylinders = NumberCylinders;
  1273. Context->Heads = NumberHeads;
  1274. Context->Sectors = NumberSectors;
  1275. Context->xInt13 = xInt13;
  1276. DBGOUT(("BiosDiskOpen: exit success\r\n"));
  1277. return(ESUCCESS);
  1278. }
  1279. ARC_STATUS
  1280. BiospWritePartialSector(
  1281. IN UCHAR Int13Unit,
  1282. IN ULONGLONG Sector,
  1283. IN PUCHAR Buffer,
  1284. IN BOOLEAN IsHead,
  1285. IN ULONG Bytes,
  1286. IN UCHAR SectorsPerTrack,
  1287. IN USHORT Heads,
  1288. IN USHORT Cylinders,
  1289. IN BOOLEAN AllowXInt13
  1290. )
  1291. {
  1292. ARC_STATUS Status;
  1293. //
  1294. // Read sector into the write buffer
  1295. //
  1296. Status = ReadPhysicalSectors(
  1297. Int13Unit,
  1298. Sector,
  1299. 1,
  1300. FwDiskCache,
  1301. SectorsPerTrack,
  1302. Heads,
  1303. Cylinders,
  1304. AllowXInt13
  1305. );
  1306. if(Status != ESUCCESS) {
  1307. return(Status);
  1308. }
  1309. //
  1310. // Transfer the appropriate bytes from the user buffer to the write buffer
  1311. //
  1312. RtlMoveMemory(
  1313. IsHead ? (FwDiskCache + Bytes) : FwDiskCache,
  1314. Buffer,
  1315. IsHead ? (SECTOR_SIZE - Bytes) : Bytes
  1316. );
  1317. //
  1318. // Write the sector out
  1319. //
  1320. Status = WritePhysicalSectors(
  1321. Int13Unit,
  1322. Sector,
  1323. 1,
  1324. FwDiskCache,
  1325. SectorsPerTrack,
  1326. Heads,
  1327. Cylinders,
  1328. AllowXInt13
  1329. );
  1330. return(Status);
  1331. }
  1332. ARC_STATUS
  1333. BiosDiskWrite(
  1334. IN ULONG FileId,
  1335. OUT PVOID Buffer,
  1336. IN ULONG Length,
  1337. OUT PULONG Count
  1338. )
  1339. /*++
  1340. Routine Description:
  1341. Writes sectors directly to an open physical disk.
  1342. Arguments:
  1343. FileId - Supplies the file to write to
  1344. Buffer - Supplies buffer with data to write
  1345. Length - Supplies number of bytes to write
  1346. Count - Returns actual bytes written
  1347. Return Value:
  1348. ESUCCESS - write completed successfully
  1349. !ESUCCESS - write failed
  1350. --*/
  1351. {
  1352. ULONGLONG HeadSector,TailSector,CurrentSector;
  1353. UCHAR Int13Unit;
  1354. ULONG HeadOffset,TailByteCount;
  1355. UCHAR SectorsPerTrack;
  1356. USHORT Heads,Cylinders;
  1357. BOOLEAN AllowXInt13;
  1358. ARC_STATUS Status;
  1359. ULONG BytesLeftToTransfer;
  1360. UCHAR SectorsToTransfer;
  1361. BOOLEAN Under1MegLine;
  1362. PVOID TransferBuffer;
  1363. PUCHAR UserBuffer;
  1364. ULONG PhysicalSectors;
  1365. BytesLeftToTransfer = Length;
  1366. PhysicalSectors = SECTOR_SIZE;
  1367. HeadSector = BlFileTable[FileId].Position.QuadPart / PhysicalSectors;
  1368. HeadOffset = (ULONG)(BlFileTable[FileId].Position.QuadPart % PhysicalSectors);
  1369. TailSector = (BlFileTable[FileId].Position.QuadPart + Length) / PhysicalSectors;
  1370. TailByteCount = (ULONG)((BlFileTable[FileId].Position.QuadPart + Length) % PhysicalSectors);
  1371. Int13Unit = BlFileTable[FileId].u.DriveContext.Drive;
  1372. SectorsPerTrack = BlFileTable[FileId].u.DriveContext.Sectors;
  1373. Heads = BlFileTable[FileId].u.DriveContext.Heads;
  1374. Cylinders = BlFileTable[FileId].u.DriveContext.Cylinders;
  1375. AllowXInt13 = BlFileTable[FileId].u.DriveContext.xInt13;
  1376. UserBuffer = Buffer;
  1377. //
  1378. // If this write will even partially write over the sector cached
  1379. // in the last read sector cache, invalidate the cache.
  1380. //
  1381. if (FwLastSectorCache.Initialized &&
  1382. FwLastSectorCache.Valid &&
  1383. (FwLastSectorCache.SectorNumber >= HeadSector) &&
  1384. (FwLastSectorCache.SectorNumber <= TailSector)) {
  1385. FwLastSectorCache.Valid = FALSE;
  1386. }
  1387. //
  1388. // Special case of transfer occuring entirely within one sector
  1389. //
  1390. CurrentSector = HeadSector;
  1391. if(HeadOffset && TailByteCount && (HeadSector == TailSector)) {
  1392. Status = ReadPhysicalSectors(
  1393. Int13Unit,
  1394. CurrentSector,
  1395. 1,
  1396. FwDiskCache,
  1397. SectorsPerTrack,
  1398. Heads,
  1399. Cylinders,
  1400. AllowXInt13
  1401. );
  1402. if(Status != ESUCCESS) {
  1403. goto BiosDiskWriteDone;
  1404. }
  1405. RtlMoveMemory(FwDiskCache+HeadOffset,Buffer,Length);
  1406. Status = WritePhysicalSectors(
  1407. Int13Unit,
  1408. CurrentSector,
  1409. 1,
  1410. FwDiskCache,
  1411. SectorsPerTrack,
  1412. Heads,
  1413. Cylinders,
  1414. AllowXInt13
  1415. );
  1416. if(Status != ESUCCESS) {
  1417. goto BiosDiskWriteDone;
  1418. }
  1419. BytesLeftToTransfer = 0;
  1420. goto BiosDiskWriteDone;
  1421. }
  1422. if(HeadOffset) {
  1423. Status = BiospWritePartialSector(
  1424. Int13Unit,
  1425. HeadSector,
  1426. Buffer,
  1427. TRUE,
  1428. HeadOffset,
  1429. SectorsPerTrack,
  1430. Heads,
  1431. Cylinders,
  1432. AllowXInt13
  1433. );
  1434. if(Status != ESUCCESS) {
  1435. return(Status);
  1436. }
  1437. BytesLeftToTransfer -= PhysicalSectors - HeadOffset;
  1438. UserBuffer += PhysicalSectors - HeadOffset;
  1439. CurrentSector += 1;
  1440. }
  1441. if(TailByteCount) {
  1442. Status = BiospWritePartialSector(
  1443. Int13Unit,
  1444. TailSector,
  1445. (PUCHAR)Buffer + Length - TailByteCount,
  1446. FALSE,
  1447. TailByteCount,
  1448. SectorsPerTrack,
  1449. Heads,
  1450. Cylinders,
  1451. AllowXInt13
  1452. );
  1453. if(Status != ESUCCESS) {
  1454. return(Status);
  1455. }
  1456. BytesLeftToTransfer -= TailByteCount;
  1457. }
  1458. //
  1459. // The following calculation is not inside the transfer loop because
  1460. // it is unlikely that a caller's buffer will *cross* the 1 meg line
  1461. // due to the PC memory map.
  1462. //
  1463. if((ULONG)UserBuffer + BytesLeftToTransfer <= 0x100000) {
  1464. Under1MegLine = TRUE;
  1465. } else {
  1466. Under1MegLine = FALSE;
  1467. }
  1468. //
  1469. // Now handle the middle part. This is some number of whole sectors.
  1470. //
  1471. while(BytesLeftToTransfer) {
  1472. //
  1473. // The number of sectors to transfer is the minimum of:
  1474. // - the number of sectors left in the current track
  1475. // - BytesLeftToTransfer / SECTOR_SIZE
  1476. //
  1477. // Because sectors per track is 1-63 we know this will fit in a UCHAR
  1478. //
  1479. SectorsToTransfer = (UCHAR)min(
  1480. SectorsPerTrack - (CurrentSector % SectorsPerTrack),
  1481. BytesLeftToTransfer / PhysicalSectors
  1482. );
  1483. //
  1484. // Now we'll figure out where to transfer the data from. If the
  1485. // caller's buffer is under the 1 meg line, we can transfer the
  1486. // data directly from the caller's buffer. Otherwise we'll copy the
  1487. // user's buffer to our local buffer and transfer from there.
  1488. // In the latter case we can only transfer in chunks of
  1489. // SCRATCH_BUFFER_SIZE because that's the size of the local buffer.
  1490. //
  1491. // Also make sure the transfer won't cross a 64k boundary.
  1492. //
  1493. if(Under1MegLine) {
  1494. //
  1495. // Check if the transfer would cross a 64k boundary. If so,
  1496. // use the local buffer. Otherwise use the user's buffer.
  1497. //
  1498. if(((ULONG)UserBuffer & 0xffff0000) !=
  1499. (((ULONG)UserBuffer + (SectorsToTransfer * PhysicalSectors) - 1) & 0xffff0000))
  1500. {
  1501. TransferBuffer = FwDiskCache;
  1502. SectorsToTransfer = (UCHAR)min(SectorsToTransfer, SCRATCH_BUFFER_SIZE / (USHORT)PhysicalSectors);
  1503. } else {
  1504. TransferBuffer = UserBuffer;
  1505. }
  1506. } else {
  1507. TransferBuffer = FwDiskCache;
  1508. SectorsToTransfer = (UCHAR)min(SectorsToTransfer, SCRATCH_BUFFER_SIZE / (USHORT)PhysicalSectors);
  1509. }
  1510. if(TransferBuffer == FwDiskCache) {
  1511. RtlMoveMemory(FwDiskCache,UserBuffer,SectorsToTransfer*PhysicalSectors);
  1512. }
  1513. Status = WritePhysicalSectors(
  1514. Int13Unit,
  1515. CurrentSector,
  1516. SectorsToTransfer,
  1517. TransferBuffer,
  1518. SectorsPerTrack,
  1519. Heads,
  1520. Cylinders,
  1521. AllowXInt13
  1522. );
  1523. if(Status != ESUCCESS) {
  1524. //
  1525. // Tail part isn't contiguous with middle part
  1526. //
  1527. BytesLeftToTransfer += TailByteCount;
  1528. return(Status);
  1529. }
  1530. CurrentSector += SectorsToTransfer;
  1531. BytesLeftToTransfer -= SectorsToTransfer * PhysicalSectors;
  1532. UserBuffer += SectorsToTransfer * PhysicalSectors;
  1533. }
  1534. Status = ESUCCESS;
  1535. BiosDiskWriteDone:
  1536. *Count = Length - BytesLeftToTransfer;
  1537. BlFileTable[FileId].Position.QuadPart += *Count;
  1538. return(Status);
  1539. }
  1540. ARC_STATUS
  1541. pBiosDiskReadWorker(
  1542. IN ULONG FileId,
  1543. OUT PVOID Buffer,
  1544. IN ULONG Length,
  1545. OUT PULONG Count,
  1546. IN USHORT SectorSize,
  1547. IN BOOLEAN xInt13
  1548. )
  1549. /*++
  1550. Routine Description:
  1551. Reads sectors directly from an open physical disk.
  1552. Arguments:
  1553. FileId - Supplies the file to read from
  1554. Buffer - Supplies buffer to hold the data that is read
  1555. Length - Supplies maximum number of bytes to read
  1556. Count - Returns actual bytes read
  1557. Return Value:
  1558. ESUCCESS - Read completed successfully
  1559. !ESUCCESS - Read failed
  1560. --*/
  1561. {
  1562. ULONGLONG HeadSector,TailSector,CurrentSector;
  1563. ULONG HeadOffset,TailByteCount;
  1564. USHORT Heads,Cylinders;
  1565. UCHAR SectorsPerTrack;
  1566. UCHAR Int13Unit;
  1567. ARC_STATUS Status;
  1568. UCHAR SectorsToTransfer;
  1569. ULONG NumBytesToTransfer;
  1570. BOOLEAN AllowXInt13;
  1571. PUCHAR pDestInUserBuffer;
  1572. PUCHAR pEndOfUserBuffer;
  1573. PUCHAR pTransferDest;
  1574. PUCHAR pSrc;
  1575. ULONG CopyLength;
  1576. ULONG ReadLength;
  1577. PUCHAR pLastReadSector = NULL;
  1578. ULONGLONG LastReadSectorNumber = 0;
  1579. PUCHAR TargetBuffer;
  1580. DBGOUT(("BiosDiskRead: enter; length=0x%lx, sector size=%u, xint13=%u\r\n",Length,SectorSize,xInt13));
  1581. //
  1582. // Reset number of bytes transfered.
  1583. //
  1584. *Count = 0;
  1585. //
  1586. // Complete 0 length requests immediately.
  1587. //
  1588. if (Length == 0) {
  1589. return ESUCCESS;
  1590. }
  1591. //
  1592. // Initialize the last sector cache if it has not been
  1593. // initialized.
  1594. //
  1595. if (!FwLastSectorCache.Initialized) {
  1596. FwLastSectorCache.Data =
  1597. FwAllocatePool(BL_LAST_SECTOR_CACHE_MAX_SIZE);
  1598. if (FwLastSectorCache.Data) {
  1599. FwLastSectorCache.Initialized = TRUE;
  1600. }
  1601. }
  1602. //
  1603. // Gather disk stats.
  1604. //
  1605. SectorsPerTrack = BlFileTable[FileId].u.DriveContext.Sectors;
  1606. Heads = BlFileTable[FileId].u.DriveContext.Heads;
  1607. Cylinders = BlFileTable[FileId].u.DriveContext.Cylinders;
  1608. AllowXInt13 = BlFileTable[FileId].u.DriveContext.xInt13;
  1609. Int13Unit = BlFileTable[FileId].u.DriveContext.Drive;
  1610. DBGOUT(("BiosDiskRead: unit 0x%x CHS=%lu %lu %lu\r\n",
  1611. Int13Unit,
  1612. Cylinders,
  1613. Heads,
  1614. SectorsPerTrack));
  1615. //
  1616. // Initialize locals that denote where we are in satisfying the
  1617. // request.
  1618. //
  1619. //
  1620. // If the buffer is in the first 1MB of KSEG0, we want to use the
  1621. // identity-mapped address
  1622. //
  1623. if (((ULONG_PTR)((PUCHAR)Buffer+Length) & ~KSEG0_BASE) < BIOSDISK_1MB) {
  1624. pDestInUserBuffer = (PUCHAR)((ULONG_PTR)Buffer & ~KSEG0_BASE);
  1625. } else {
  1626. pDestInUserBuffer = Buffer;
  1627. }
  1628. pEndOfUserBuffer = (PUCHAR) pDestInUserBuffer + Length;
  1629. TargetBuffer = pDestInUserBuffer;
  1630. //
  1631. // Calculating these before hand makes it easier to hand the
  1632. // special cases. Note that tail sector is the last sector this
  1633. // read wants bytes from. That is why we subtract one. We handle
  1634. // the Length == 0 case above.
  1635. //
  1636. HeadSector = BlFileTable[FileId].Position.QuadPart / SectorSize;
  1637. HeadOffset = (ULONG)(BlFileTable[FileId].Position.QuadPart % SectorSize);
  1638. TailSector = (BlFileTable[FileId].Position.QuadPart + Length - 1) / SectorSize;
  1639. TailByteCount = (ULONG)((BlFileTable[FileId].Position.QuadPart + Length - 1) % SectorSize);
  1640. TailByteCount ++;
  1641. //
  1642. // While there is data we should read, read.
  1643. //
  1644. CurrentSector = HeadSector;
  1645. while (pDestInUserBuffer != pEndOfUserBuffer) {
  1646. //
  1647. // Look to see if we can find the current sector we have to
  1648. // read in the last sector cache.
  1649. //
  1650. if (FwLastSectorCache.Valid &&
  1651. FwLastSectorCache.DeviceId == FileId &&
  1652. FwLastSectorCache.SectorNumber == CurrentSector) {
  1653. pSrc = FwLastSectorCache.Data;
  1654. CopyLength = SectorSize;
  1655. //
  1656. // Adjust copy parameters depending on whether
  1657. // this sector is the Head and/or Tail sector.
  1658. //
  1659. if (HeadSector == CurrentSector) {
  1660. pSrc += HeadOffset;
  1661. CopyLength -= HeadOffset;
  1662. }
  1663. if (TailSector == CurrentSector) {
  1664. CopyLength -= (SectorSize - TailByteCount);
  1665. }
  1666. //
  1667. // Copy the cached data to users buffer.
  1668. //
  1669. RtlCopyMemory(pDestInUserBuffer, pSrc, CopyLength);
  1670. //
  1671. // Update our status.
  1672. //
  1673. CurrentSector += 1;
  1674. pDestInUserBuffer += CopyLength;
  1675. *Count += CopyLength;
  1676. continue;
  1677. }
  1678. //
  1679. // Calculate number of sectors we have to read. Read a maximum
  1680. // of SCRATCH_BUFFER_SIZE so we can use our local buffer if the
  1681. // user's buffer crosses 64KB boundary or is not under 1MB.
  1682. //
  1683. SectorsToTransfer = (UCHAR)min ((LONG) (TailSector - CurrentSector + 1),
  1684. SCRATCH_BUFFER_SIZE / SectorSize);
  1685. if (!xInt13) {
  1686. //
  1687. // Make sure the number of sectors to transfer does not exceed
  1688. // the number of sectors left in the track.
  1689. //
  1690. SectorsToTransfer = (UCHAR)min(SectorsPerTrack - (CurrentSector % SectorsPerTrack),
  1691. SectorsToTransfer);
  1692. }
  1693. NumBytesToTransfer = SectorsToTransfer * SectorSize;
  1694. //
  1695. // Determine where we want to read into. We can use the
  1696. // current chunk of user buffer only if it is under 1MB and
  1697. // does not cross a 64KB boundary, and it can take all we want
  1698. // to read into it.
  1699. //
  1700. if (((ULONG_PTR) pDestInUserBuffer + NumBytesToTransfer < BIOSDISK_1MB) &&
  1701. (((ULONG_PTR) pDestInUserBuffer & BIOSDISK_64KB_MASK) ==
  1702. (((ULONG_PTR) pDestInUserBuffer + NumBytesToTransfer) & BIOSDISK_64KB_MASK)) &&
  1703. ((pEndOfUserBuffer - pDestInUserBuffer) >= (LONG) NumBytesToTransfer)) {
  1704. pTransferDest = pDestInUserBuffer;
  1705. } else {
  1706. pTransferDest = FwDiskCache;
  1707. }
  1708. //
  1709. // Perform the read.
  1710. //
  1711. if(xInt13) {
  1712. Status = ReadExtendedPhysicalSectors(Int13Unit,
  1713. CurrentSector,
  1714. SectorsToTransfer,
  1715. pTransferDest);
  1716. } else {
  1717. Status = ReadPhysicalSectors(Int13Unit,
  1718. CurrentSector,
  1719. SectorsToTransfer,
  1720. pTransferDest,
  1721. SectorsPerTrack,
  1722. Heads,
  1723. Cylinders,
  1724. AllowXInt13);
  1725. }
  1726. if(Status != ESUCCESS) {
  1727. DBGOUT(("BiosDiskRead: read failed with %u\r\n",Status));
  1728. goto BiosDiskReadDone;
  1729. }
  1730. //
  1731. // Note the last sector that was read from the disk.
  1732. //
  1733. pLastReadSector = pTransferDest + (SectorsToTransfer - 1) * SectorSize;
  1734. LastReadSectorNumber = CurrentSector + SectorsToTransfer - 1;
  1735. //
  1736. // Note the amount read.
  1737. //
  1738. ReadLength = NumBytesToTransfer;
  1739. //
  1740. // Copy transfered data into user's buffer if we did not
  1741. // directly read into that.
  1742. //
  1743. if (pTransferDest != pDestInUserBuffer) {
  1744. pSrc = pTransferDest;
  1745. CopyLength = NumBytesToTransfer;
  1746. //
  1747. // Adjust copy parameters depending on whether
  1748. // we have read the Head and/or Tail sectors.
  1749. //
  1750. if (HeadSector == CurrentSector) {
  1751. pSrc += HeadOffset;
  1752. CopyLength -= HeadOffset;
  1753. }
  1754. if (TailSector == CurrentSector + SectorsToTransfer - 1) {
  1755. CopyLength -= (SectorSize - TailByteCount);
  1756. }
  1757. //
  1758. // Copy the read data to users buffer.
  1759. //
  1760. ASSERT(pDestInUserBuffer >= TargetBuffer);
  1761. ASSERT(pEndOfUserBuffer >= pDestInUserBuffer + CopyLength);
  1762. ASSERT(CopyLength <= SCRATCH_BUFFER_SIZE);
  1763. ASSERT(pSrc >= (PUCHAR) FwDiskCache);
  1764. ASSERT(pSrc < (PUCHAR) FwDiskCache + SCRATCH_BUFFER_SIZE);
  1765. RtlCopyMemory(pDestInUserBuffer, pSrc, CopyLength);
  1766. //
  1767. // Adjust the amount read into user's buffer.
  1768. //
  1769. ReadLength = CopyLength;
  1770. }
  1771. //
  1772. // Update our status.
  1773. //
  1774. CurrentSector += SectorsToTransfer;
  1775. pDestInUserBuffer += ReadLength;
  1776. *Count += ReadLength;
  1777. }
  1778. //
  1779. // Update the last read sector cache.
  1780. //
  1781. if (pLastReadSector &&
  1782. FwLastSectorCache.Initialized &&
  1783. BL_LAST_SECTOR_CACHE_MAX_SIZE >= SectorSize) {
  1784. FwLastSectorCache.DeviceId = FileId;
  1785. FwLastSectorCache.SectorNumber = LastReadSectorNumber;
  1786. RtlCopyMemory(FwLastSectorCache.Data,
  1787. pLastReadSector,
  1788. SectorSize);
  1789. FwLastSectorCache.Valid = TRUE;
  1790. }
  1791. DBGOUT(("BiosDiskRead: exit success\r\n"));
  1792. Status = ESUCCESS;
  1793. BiosDiskReadDone:
  1794. BlFileTable[FileId].Position.QuadPart += *Count;
  1795. return(Status);
  1796. }
  1797. ARC_STATUS
  1798. BiosDiskRead(
  1799. IN ULONG FileId,
  1800. OUT PVOID Buffer,
  1801. IN ULONG Length,
  1802. OUT PULONG Count
  1803. )
  1804. {
  1805. USHORT PhysicalSectors;
  1806. PhysicalSectors = SECTOR_SIZE;
  1807. return(pBiosDiskReadWorker(FileId,Buffer,Length,Count,PhysicalSectors,FALSE));
  1808. }
  1809. ARC_STATUS
  1810. BiosElToritoDiskRead(
  1811. IN ULONG FileId,
  1812. OUT PVOID Buffer,
  1813. IN ULONG Length,
  1814. OUT PULONG Count
  1815. )
  1816. {
  1817. return(pBiosDiskReadWorker(FileId,Buffer,Length,Count,2048,TRUE));
  1818. }
  1819. ARC_STATUS
  1820. BiosPartitionGetFileInfo(
  1821. IN ULONG FileId,
  1822. OUT PFILE_INFORMATION Finfo
  1823. )
  1824. {
  1825. //
  1826. // THIS ROUTINE DOES NOT WORK FOR PARTITION 0.
  1827. //
  1828. PPARTITION_CONTEXT Context;
  1829. RtlZeroMemory(Finfo, sizeof(FILE_INFORMATION));
  1830. Context = &BlFileTable[FileId].u.PartitionContext;
  1831. Finfo->StartingAddress.QuadPart = Context->StartingSector;
  1832. Finfo->StartingAddress.QuadPart = Finfo->StartingAddress.QuadPart << (CCHAR)Context->SectorShift;
  1833. Finfo->EndingAddress.QuadPart = Finfo->StartingAddress.QuadPart + Context->PartitionLength.QuadPart;
  1834. Finfo->Type = DiskPeripheral;
  1835. return ESUCCESS;
  1836. }
  1837. ARC_STATUS
  1838. BiosDiskGetFileInfo(
  1839. IN ULONG FileId,
  1840. OUT PFILE_INFORMATION FileInfo
  1841. )
  1842. /*++
  1843. Routine Description:
  1844. Gets the information about the isk.
  1845. Arguments:
  1846. FileId - The file id to the disk for which information is needed
  1847. FileInfo - Place holder for returning information about the disk
  1848. Return Value:
  1849. ESUCCESS if successful, otherwise appropriate ARC error code.
  1850. --*/
  1851. {
  1852. ARC_STATUS Result = EINVAL;
  1853. if (FileInfo) {
  1854. PDRIVE_CONTEXT DriveContext;
  1855. LONGLONG DriveSize = 0;
  1856. ULONG SectorSize = SECTOR_SIZE;
  1857. DriveContext = &(BlFileTable[FileId].u.DriveContext);
  1858. Result = EIO;
  1859. //
  1860. // NOTE : SectorSize == 512 bytes for everything except
  1861. // Eltorito disks for which sector size is 2048.
  1862. //
  1863. if (DriveContext->IsCd) {
  1864. SectorSize = 2048;
  1865. }
  1866. DriveSize = (DriveContext->Heads * DriveContext->Cylinders *
  1867. DriveContext->Sectors * SectorSize);
  1868. if (DriveSize) {
  1869. RtlZeroMemory(FileInfo, sizeof(FILE_INFORMATION));
  1870. FileInfo->StartingAddress.QuadPart = 0;
  1871. FileInfo->EndingAddress.QuadPart = DriveSize;
  1872. FileInfo->CurrentPosition = BlFileTable[FileId].Position;
  1873. //
  1874. // Any thing less than 3MB is floppy drive
  1875. //
  1876. if (DriveSize <= 0x300000) {
  1877. FileInfo->Type = FloppyDiskPeripheral;
  1878. } else {
  1879. FileInfo->Type = DiskPeripheral;
  1880. }
  1881. Result = ESUCCESS;
  1882. }
  1883. }
  1884. return Result;
  1885. }