disk.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949
  1. /*++
  2. Copyright (c) 2014 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. disk.c
  9. Abstract:
  10. This module enumerates the disks found on BIOS systems.
  11. Author:
  12. Evan Green 20-Mar-2014
  13. Environment:
  14. Firmware
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include <uefifw.h>
  20. #include <minoca/uefi/protocol/blockio.h>
  21. #include "biosfw.h"
  22. //
  23. // --------------------------------------------------------------------- Macros
  24. //
  25. //
  26. // This macro returns a pointer to the disk I/O data given a pointer to the
  27. // block I/O protocol instance.
  28. //
  29. #define EFI_PCAT_DISK_FROM_THIS(_BlockIo) \
  30. (EFI_PCAT_DISK *)((VOID *)(_BlockIo) - \
  31. ((VOID *)(&(((EFI_PCAT_DISK *)0)->BlockIo))))
  32. //
  33. // ---------------------------------------------------------------- Definitions
  34. //
  35. #define EFI_PCAT_DISK_MAGIC 0x73446350 // 'sDcP'
  36. //
  37. // Define the drive numbers to probe.
  38. //
  39. #define EFI_PCAT_HARD_DRIVE_START 0x80
  40. #define EFI_PCAT_HARD_DRIVE_COUNT 0x10
  41. #define EFI_PCAT_REMOVABLE_DRIVE_START 0x00
  42. #define EFI_PCAT_REMOVABLE_DRIVE_COUNT 0x10
  43. #define EFI_PCAT_MAX_SECTORS_PER_TRANSFER 0x08
  44. #define EFI_BIOS_BLOCK_IO_DEVICE_PATH_GUID \
  45. { \
  46. 0xCF31FAC5, 0xC24E, 0x11D2, \
  47. {0x85, 0xF3, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3C} \
  48. }
  49. //
  50. // ------------------------------------------------------ Data Type Definitions
  51. //
  52. /*++
  53. Structure Description:
  54. This structure stores the disk I/O protocol's private context.
  55. Members:
  56. Magic - Stores the magic constand EFI_PCAT_DISK_MAGIC.
  57. Handle - Stores the handle to the block I/O device.
  58. DevicePath - Stores a pointer to the device path.
  59. DriveNumber - Stores the BIOS drive number of this disk.
  60. SectorSize - Stores the size of a block in this device.
  61. TotalSectors - Stores the count of sectors in this device.
  62. BlockIo - Stores the block I/O protocol.
  63. Media - Stores the block I/O media information.
  64. --*/
  65. typedef struct _EFI_PCAT_DISK {
  66. UINT32 Magic;
  67. EFI_HANDLE Handle;
  68. EFI_DEVICE_PATH_PROTOCOL *DevicePath;
  69. UINT8 DriveNumber;
  70. UINT32 SectorSize;
  71. UINT64 TotalSectors;
  72. EFI_BLOCK_IO_PROTOCOL BlockIo;
  73. EFI_BLOCK_IO_MEDIA Media;
  74. } EFI_PCAT_DISK, *PEFI_PCAT_DISK;
  75. /*++
  76. Structure Description:
  77. This structure defines the BIOS block I/O device path.
  78. Members:
  79. DevicePath - Stores the standard vendor-specific device path.
  80. DriveNumber - Stores the BIOS drive number.
  81. --*/
  82. typedef struct _EFI_BIOS_BLOCK_IO_DEVICE_PATH {
  83. VENDOR_DEVICE_PATH DevicePath;
  84. UINT8 DriveNumber;
  85. } EFI_BIOS_BLOCK_IO_DEVICE_PATH, *PEFI_BIOS_BLOCK_IO_DEVICE_PATH;
  86. /*++
  87. Structure Description:
  88. This structure defines the BIOS block I/O device path.
  89. Members:
  90. DevicePath - Stores the standard vendor-specific device path.
  91. DriveNumber - Stores the BIOS drive number.
  92. --*/
  93. typedef struct _EFI_PCAT_DISK_DEVICE_PATH {
  94. EFI_BIOS_BLOCK_IO_DEVICE_PATH Disk;
  95. EFI_DEVICE_PATH_PROTOCOL End;
  96. } PACKED EFI_PCAT_DISK_DEVICE_PATH, *PEFI_PCAT_DISK_DEVICE_PATH;
  97. //
  98. // ----------------------------------------------- Internal Function Prototypes
  99. //
  100. EFIAPI
  101. EFI_STATUS
  102. EfipPcatDiskReset (
  103. EFI_BLOCK_IO_PROTOCOL *This,
  104. BOOLEAN ExtendedVerification
  105. );
  106. EFIAPI
  107. EFI_STATUS
  108. EfipPcatDiskReadBlocks (
  109. EFI_BLOCK_IO_PROTOCOL *This,
  110. UINT32 MediaId,
  111. EFI_LBA Lba,
  112. UINTN BufferSize,
  113. VOID *Buffer
  114. );
  115. EFIAPI
  116. EFI_STATUS
  117. EfipPcatDiskWriteBlocks (
  118. EFI_BLOCK_IO_PROTOCOL *This,
  119. UINT32 MediaId,
  120. EFI_LBA Lba,
  121. UINTN BufferSize,
  122. VOID *Buffer
  123. );
  124. EFIAPI
  125. EFI_STATUS
  126. EfipPcatDiskFlushBlocks (
  127. EFI_BLOCK_IO_PROTOCOL *This
  128. );
  129. EFI_STATUS
  130. EfipPcatProbeDrive (
  131. UINTN DriveNumber
  132. );
  133. EFI_STATUS
  134. EfipPcatGetDiskParameters (
  135. UINT8 DriveNumber,
  136. UINT64 *SectorCount,
  137. UINT32 *SectorSize
  138. );
  139. EFI_STATUS
  140. EfipPcatBlockOperation (
  141. PEFI_PCAT_DISK Disk,
  142. BOOLEAN Write,
  143. VOID *Buffer,
  144. UINT32 AbsoluteSector,
  145. UINT32 SectorCount
  146. );
  147. EFI_STATUS
  148. EfipPcatResetDisk (
  149. UINT8 DriveNumber
  150. );
  151. //
  152. // -------------------------------------------------------------------- Globals
  153. //
  154. //
  155. // Define the private data template.
  156. //
  157. EFI_PCAT_DISK EfiPcatDiskTemplate = {
  158. EFI_PCAT_DISK_MAGIC,
  159. NULL,
  160. NULL,
  161. 0xFF,
  162. 0,
  163. 0,
  164. {
  165. EFI_BLOCK_IO_PROTOCOL_REVISION3,
  166. NULL,
  167. EfipPcatDiskReset,
  168. EfipPcatDiskReadBlocks,
  169. EfipPcatDiskWriteBlocks,
  170. EfipPcatDiskFlushBlocks
  171. }
  172. };
  173. //
  174. // Define the device path template.
  175. //
  176. EFI_PCAT_DISK_DEVICE_PATH EfiPcatDevicePathTemplate = {
  177. {
  178. {
  179. {
  180. HARDWARE_DEVICE_PATH,
  181. HW_VENDOR_DP,
  182. sizeof(EFI_BIOS_BLOCK_IO_DEVICE_PATH)
  183. },
  184. EFI_BIOS_BLOCK_IO_DEVICE_PATH_GUID,
  185. },
  186. 0xFF
  187. },
  188. {
  189. END_DEVICE_PATH_TYPE,
  190. END_ENTIRE_DEVICE_PATH_SUBTYPE,
  191. END_DEVICE_PATH_LENGTH
  192. }
  193. };
  194. //
  195. // ------------------------------------------------------------------ Functions
  196. //
  197. EFI_STATUS
  198. EfipPcatEnumerateDisks (
  199. VOID
  200. )
  201. /*++
  202. Routine Description:
  203. This routine enumerates all the disks it can find on a BIOS machine.
  204. Arguments:
  205. None.
  206. Return Value:
  207. EFI Status code.
  208. --*/
  209. {
  210. UINTN DriveIndex;
  211. EFI_STATUS Status;
  212. for (DriveIndex = 0;
  213. DriveIndex < EFI_PCAT_HARD_DRIVE_COUNT;
  214. DriveIndex += 1) {
  215. Status = EfipPcatProbeDrive(DriveIndex + EFI_PCAT_HARD_DRIVE_START);
  216. if (EFI_ERROR(Status)) {
  217. break;
  218. }
  219. }
  220. for (DriveIndex = 0;
  221. DriveIndex < EFI_PCAT_REMOVABLE_DRIVE_COUNT;
  222. DriveIndex += 1) {
  223. Status = EfipPcatProbeDrive(
  224. DriveIndex + EFI_PCAT_REMOVABLE_DRIVE_START);
  225. if (EFI_ERROR(Status)) {
  226. break;
  227. }
  228. }
  229. return EFI_SUCCESS;
  230. }
  231. //
  232. // --------------------------------------------------------- Internal Functions
  233. //
  234. EFIAPI
  235. EFI_STATUS
  236. EfipPcatDiskReset (
  237. EFI_BLOCK_IO_PROTOCOL *This,
  238. BOOLEAN ExtendedVerification
  239. )
  240. /*++
  241. Routine Description:
  242. This routine resets the block device.
  243. Arguments:
  244. This - Supplies a pointer to the protocol instance.
  245. ExtendedVerification - Supplies a boolean indicating whether or not the
  246. driver should perform diagnostics on reset.
  247. Return Value:
  248. EFI_SUCCESS on success.
  249. EFI_DEVICE_ERROR if the device had an error and could not complete the
  250. request.
  251. --*/
  252. {
  253. PEFI_PCAT_DISK Disk;
  254. Disk = EFI_PCAT_DISK_FROM_THIS(This);
  255. return EfipPcatResetDisk(Disk->DriveNumber);
  256. }
  257. EFIAPI
  258. EFI_STATUS
  259. EfipPcatDiskReadBlocks (
  260. EFI_BLOCK_IO_PROTOCOL *This,
  261. UINT32 MediaId,
  262. EFI_LBA Lba,
  263. UINTN BufferSize,
  264. VOID *Buffer
  265. )
  266. /*++
  267. Routine Description:
  268. This routine performs a block I/O read from the device.
  269. Arguments:
  270. This - Supplies a pointer to the protocol instance.
  271. MediaId - Supplies the media identifier, which changes each time the media
  272. is replaced.
  273. Lba - Supplies the logical block address of the read.
  274. BufferSize - Supplies the size of the buffer in bytes.
  275. Buffer - Supplies the buffer where the read data will be returned.
  276. Return Value:
  277. EFI_SUCCESS on success.
  278. EFI_DEVICE_ERROR if the device had an error and could not complete the
  279. request.
  280. EFI_NO_MEDIA if there is no media in the device.
  281. EFI_MEDIA_CHANGED if the media ID does not match the current device.
  282. EFI_BAD_BUFFER_SIZE if the buffer was not a multiple of the device block
  283. size.
  284. EFI_INVALID_PARAMETER if the read request contains LBAs that are not valid,
  285. or the buffer is not properly aligned.
  286. --*/
  287. {
  288. PEFI_PCAT_DISK Disk;
  289. UINTN SectorCount;
  290. UINTN SectorsThisRound;
  291. EFI_STATUS Status;
  292. Disk = EFI_PCAT_DISK_FROM_THIS(This);
  293. if (MediaId != Disk->Media.MediaId) {
  294. return EFI_MEDIA_CHANGED;
  295. }
  296. if (Disk->Media.MediaPresent == FALSE) {
  297. return EFI_NO_MEDIA;
  298. }
  299. Status = EFI_SUCCESS;
  300. SectorCount = BufferSize / Disk->SectorSize;
  301. while (SectorCount != 0) {
  302. SectorsThisRound = EFI_PCAT_MAX_SECTORS_PER_TRANSFER;
  303. if (SectorsThisRound > SectorCount) {
  304. SectorsThisRound = SectorCount;
  305. }
  306. Status = EfipPcatBlockOperation(Disk,
  307. FALSE,
  308. Buffer,
  309. (UINT32)Lba,
  310. SectorsThisRound);
  311. if (EFI_ERROR(Status)) {
  312. break;
  313. }
  314. Lba += SectorsThisRound;
  315. Buffer += SectorsThisRound * Disk->SectorSize;
  316. SectorCount -= SectorsThisRound;
  317. }
  318. return Status;
  319. }
  320. EFIAPI
  321. EFI_STATUS
  322. EfipPcatDiskWriteBlocks (
  323. EFI_BLOCK_IO_PROTOCOL *This,
  324. UINT32 MediaId,
  325. EFI_LBA Lba,
  326. UINTN BufferSize,
  327. VOID *Buffer
  328. )
  329. /*++
  330. Routine Description:
  331. This routine performs a block I/O write to the device.
  332. Arguments:
  333. This - Supplies a pointer to the protocol instance.
  334. MediaId - Supplies the media identifier, which changes each time the media
  335. is replaced.
  336. Lba - Supplies the logical block address of the write.
  337. BufferSize - Supplies the size of the buffer in bytes.
  338. Buffer - Supplies the buffer containing the data to write.
  339. Return Value:
  340. EFI_SUCCESS on success.
  341. EFI_WRITE_PROTECTED if the device cannot be written to.
  342. EFI_DEVICE_ERROR if the device had an error and could not complete the
  343. request.
  344. EFI_NO_MEDIA if there is no media in the device.
  345. EFI_MEDIA_CHANGED if the media ID does not match the current device.
  346. EFI_BAD_BUFFER_SIZE if the buffer was not a multiple of the device block
  347. size.
  348. EFI_INVALID_PARAMETER if the read request contains LBAs that are not valid,
  349. or the buffer is not properly aligned.
  350. --*/
  351. {
  352. PEFI_PCAT_DISK Disk;
  353. UINTN SectorCount;
  354. UINTN SectorsThisRound;
  355. EFI_STATUS Status;
  356. Disk = EFI_PCAT_DISK_FROM_THIS(This);
  357. if (MediaId != Disk->Media.MediaId) {
  358. return EFI_MEDIA_CHANGED;
  359. }
  360. if (Disk->Media.MediaPresent == FALSE) {
  361. return EFI_NO_MEDIA;
  362. }
  363. Status = EFI_SUCCESS;
  364. SectorCount = BufferSize / Disk->SectorSize;
  365. while (SectorCount != 0) {
  366. SectorsThisRound = EFI_PCAT_MAX_SECTORS_PER_TRANSFER;
  367. if (SectorsThisRound > SectorCount) {
  368. SectorsThisRound = SectorCount;
  369. }
  370. Status = EfipPcatBlockOperation(Disk,
  371. TRUE,
  372. Buffer,
  373. (UINT32)Lba,
  374. SectorsThisRound);
  375. if (EFI_ERROR(Status)) {
  376. break;
  377. }
  378. Lba += SectorsThisRound;
  379. Buffer += SectorsThisRound * Disk->SectorSize;
  380. SectorCount -= SectorsThisRound;
  381. }
  382. return Status;
  383. }
  384. EFIAPI
  385. EFI_STATUS
  386. EfipPcatDiskFlushBlocks (
  387. EFI_BLOCK_IO_PROTOCOL *This
  388. )
  389. /*++
  390. Routine Description:
  391. This routine flushes the block device.
  392. Arguments:
  393. This - Supplies a pointer to the protocol instance.
  394. Return Value:
  395. EFI_SUCCESS on success.
  396. EFI_DEVICE_ERROR if the device had an error and could not complete the
  397. request.
  398. EFI_NO_MEDIA if there is no media in the device.
  399. --*/
  400. {
  401. return EFI_SUCCESS;
  402. }
  403. EFI_STATUS
  404. EfipPcatProbeDrive (
  405. UINTN DriveNumber
  406. )
  407. /*++
  408. Routine Description:
  409. This routine probes the given drive number and creates a device handle if
  410. there is a drive there.
  411. Arguments:
  412. DriveNumber - Supplies the drive number to probe.
  413. Return Value:
  414. EFI Status code.
  415. --*/
  416. {
  417. PEFI_PCAT_DISK_DEVICE_PATH DevicePath;
  418. PEFI_PCAT_DISK Disk;
  419. UINT64 SectorCount;
  420. UINT32 SectorSize;
  421. EFI_STATUS Status;
  422. Status = EfipPcatGetDiskParameters(DriveNumber, &SectorCount, &SectorSize);
  423. if (EFI_ERROR(Status)) {
  424. return Status;
  425. }
  426. //
  427. // There's a disk there. Allocate a data structure for it.
  428. //
  429. Status = EfiAllocatePool(EfiBootServicesData,
  430. sizeof(EFI_PCAT_DISK),
  431. (VOID **)&Disk);
  432. if (EFI_ERROR(Status)) {
  433. return Status;
  434. }
  435. EfiCopyMem(Disk, &EfiPcatDiskTemplate, sizeof(EFI_PCAT_DISK));
  436. Disk->Handle = NULL;
  437. Disk->DriveNumber = DriveNumber;
  438. Disk->SectorSize = SectorSize;
  439. Disk->TotalSectors = SectorCount;
  440. Disk->BlockIo.Media = &(Disk->Media);
  441. if (DriveNumber < EFI_PCAT_HARD_DRIVE_START) {
  442. Disk->Media.RemovableMedia = TRUE;
  443. }
  444. Disk->Media.MediaPresent = TRUE;
  445. Disk->Media.BlockSize = SectorSize;
  446. Disk->Media.LastBlock = SectorCount - 1;
  447. Status = EfiAllocatePool(EfiBootServicesData,
  448. sizeof(EFI_PCAT_DISK_DEVICE_PATH),
  449. (VOID **)&DevicePath);
  450. if (EFI_ERROR(Status)) {
  451. EfiFreePool(Disk);
  452. return Status;
  453. }
  454. EfiCopyMem(DevicePath,
  455. &EfiPcatDevicePathTemplate,
  456. sizeof(EFI_PCAT_DISK_DEVICE_PATH));
  457. DevicePath->Disk.DriveNumber = DriveNumber;
  458. Disk->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;
  459. Status = EfiInstallMultipleProtocolInterfaces(&(Disk->Handle),
  460. &EfiDevicePathProtocolGuid,
  461. Disk->DevicePath,
  462. &EfiBlockIoProtocolGuid,
  463. &(Disk->BlockIo),
  464. NULL);
  465. return Status;
  466. }
  467. EFI_STATUS
  468. EfipPcatGetDiskParameters (
  469. UINT8 DriveNumber,
  470. UINT64 *SectorCount,
  471. UINT32 *SectorSize
  472. )
  473. /*++
  474. Routine Description:
  475. This routine uses the BIOS to determine the geometry for the given disk.
  476. Arguments:
  477. DriveNumber - Supplies the drive number of the disk to query. Valid values
  478. are:
  479. 0x80 - Boot drive.
  480. 0x81, ... - Additional hard drives
  481. 0x0, ... - Floppy drives.
  482. SectorCount - Supplies a pointer where the total number of sectors will be
  483. returned (one beyond the last valid LBA).
  484. SectorSize - Supplies a pointer where the size of a sector will be returned
  485. on success.
  486. Return Value:
  487. STATUS_SUCCESS if the operation completed successfully.
  488. STATUS_FIRMWARE_ERROR if the BIOS returned an error.
  489. Other error codes.
  490. --*/
  491. {
  492. UINTN BufferAddress;
  493. PINT13_EXTENDED_DRIVE_PARAMETERS Parameters;
  494. BIOS_CALL_CONTEXT RealModeContext;
  495. EFI_STATUS Status;
  496. //
  497. // Create a standard BIOS call context.
  498. //
  499. Status = EfipCreateBiosCallContext(&RealModeContext, 0x13);
  500. if (EFI_ERROR(Status)) {
  501. goto GetDiskGeometryEnd;
  502. }
  503. //
  504. // Int 13 function 8 is "Get disk parameters". Ah takes the function number
  505. // (8), and dl takes the drive number.
  506. //
  507. RealModeContext.Eax = INT13_EXTENDED_GET_DRIVE_PARAMETERS << 8;
  508. RealModeContext.Edx = DriveNumber;
  509. RealModeContext.Ds = 0;
  510. BufferAddress = (UINTN)(RealModeContext.DataPage);
  511. RealModeContext.Esi = (UINT16)BufferAddress;
  512. Parameters = (PINT13_EXTENDED_DRIVE_PARAMETERS)(UINTN)BufferAddress;
  513. EfiSetMem(Parameters, sizeof(INT13_EXTENDED_DRIVE_PARAMETERS), 0);
  514. Parameters->PacketSize = sizeof(INT13_EXTENDED_DRIVE_PARAMETERS);
  515. //
  516. // Execute the firmware call.
  517. //
  518. EfipExecuteBiosCall(&RealModeContext);
  519. //
  520. // Check for an error. The status code is in Ah.
  521. //
  522. if (((RealModeContext.Eax & 0xFF00) != 0) ||
  523. ((RealModeContext.Eflags & IA32_EFLAG_CF) != 0)) {
  524. Status = EFI_NOT_FOUND;
  525. goto GetDiskGeometryEnd;
  526. }
  527. *SectorCount = Parameters->TotalSectorCount;
  528. *SectorSize = Parameters->SectorSize;
  529. Status = EFI_SUCCESS;
  530. GetDiskGeometryEnd:
  531. EfipDestroyBiosCallContext(&RealModeContext);
  532. return Status;
  533. }
  534. EFI_STATUS
  535. EfipPcatBlockOperation (
  536. PEFI_PCAT_DISK Disk,
  537. BOOLEAN Write,
  538. VOID *Buffer,
  539. UINT32 AbsoluteSector,
  540. UINT32 SectorCount
  541. )
  542. /*++
  543. Routine Description:
  544. This routine uses the BIOS to read from or write to the disk.
  545. Arguments:
  546. Disk - Supplies a pointer to the disk to operate on.
  547. Write - Supplies a boolean indicating if this is a read (FALSE) or write
  548. (TRUE) operation.
  549. Buffer - Supplies the buffer either containing the data to write or where
  550. the read data will be returned.
  551. AbsoluteSector - Supplies the zero-based sector number to read from.
  552. SectorCount - Supplies the number of sectors to read. The supplied buffer
  553. must be at least this large.
  554. Return Value:
  555. STATUS_SUCCESS if the operation completed successfully.
  556. STATUS_FIRMWARE_ERROR if the BIOS returned an error.
  557. Other error codes.
  558. --*/
  559. {
  560. UINTN RealModeBuffer;
  561. BIOS_CALL_CONTEXT RealModeContext;
  562. PINT13_DISK_ACCESS_PACKET Request;
  563. EFI_STATUS Status;
  564. //
  565. // Create a standard BIOS call context.
  566. //
  567. Status = EfipCreateBiosCallContext(&RealModeContext, 0x13);
  568. if (EFI_ERROR(Status)) {
  569. goto BlockOperationEnd;
  570. }
  571. //
  572. // Create the disk access packet on the stack.
  573. //
  574. Request = (PINT13_DISK_ACCESS_PACKET)(RealModeContext.Esp -
  575. sizeof(INT13_DISK_ACCESS_PACKET));
  576. Request->PacketSize = sizeof(INT13_DISK_ACCESS_PACKET);
  577. Request->Reserved = 0;
  578. Request->BlockCount = SectorCount;
  579. RealModeBuffer = (UINTN)(RealModeContext.DataPage);
  580. Request->TransferBuffer = (UINTN)RealModeBuffer;
  581. Request->BlockAddress = AbsoluteSector;
  582. RealModeContext.Edx = Disk->DriveNumber;
  583. RealModeContext.Esp = (UINTN)Request;
  584. RealModeContext.Esi = (UINTN)Request;
  585. if (Write != FALSE) {
  586. RealModeContext.Eax = INT13_EXTENDED_WRITE << 8;
  587. EfiCopyMem((VOID *)RealModeBuffer,
  588. Buffer,
  589. SectorCount * Disk->SectorSize);
  590. } else {
  591. RealModeContext.Eax = INT13_EXTENDED_READ << 8;
  592. }
  593. //
  594. // Execute the firmware call.
  595. //
  596. EfipExecuteBiosCall(&RealModeContext);
  597. //
  598. // Check for an error (carry flag set). The status code is in Ah.
  599. //
  600. if (((RealModeContext.Eax & 0xFF00) != 0) ||
  601. ((RealModeContext.Eflags & IA32_EFLAG_CF) != 0)) {
  602. Status = EFI_DEVICE_ERROR;
  603. goto BlockOperationEnd;
  604. }
  605. //
  606. // Copy the data over from the real mode data page to the caller's buffer.
  607. //
  608. if (Write == FALSE) {
  609. EfiCopyMem(Buffer,
  610. (VOID *)RealModeBuffer,
  611. SectorCount * Disk->SectorSize);
  612. }
  613. Status = EFI_SUCCESS;
  614. BlockOperationEnd:
  615. EfipDestroyBiosCallContext(&RealModeContext);
  616. return Status;
  617. }
  618. EFI_STATUS
  619. EfipPcatResetDisk (
  620. UINT8 DriveNumber
  621. )
  622. /*++
  623. Routine Description:
  624. This routine uses the BIOS to reset the disk.
  625. Arguments:
  626. DriveNumber - Supplies the drive number of the disk to reset. Valid values
  627. are:
  628. 0x80 - Boot drive.
  629. 0x81, ... - Additional hard drives
  630. 0x0, ... - Floppy drives.
  631. Return Value:
  632. STATUS_SUCCESS if the operation completed successfully.
  633. STATUS_FIRMWARE_ERROR if the BIOS returned an error.
  634. Other error codes.
  635. --*/
  636. {
  637. BIOS_CALL_CONTEXT RealModeContext;
  638. EFI_STATUS Status;
  639. //
  640. // Create a standard BIOS call context.
  641. //
  642. Status = EfipCreateBiosCallContext(&RealModeContext, 0x13);
  643. if (EFI_ERROR(Status)) {
  644. goto PcatResetDiskEnd;
  645. }
  646. //
  647. // Int 13 function zero is reset.
  648. //
  649. RealModeContext.Eax = INT13_EXTENDED_GET_DRIVE_PARAMETERS << 8;
  650. RealModeContext.Edx = DriveNumber;
  651. //
  652. // Execute the firmware call.
  653. //
  654. EfipExecuteBiosCall(&RealModeContext);
  655. //
  656. // Check for an error. The status code is in Ah.
  657. //
  658. if (((RealModeContext.Eax & 0xFF00) != 0) ||
  659. ((RealModeContext.Eflags & IA32_EFLAG_CF) != 0)) {
  660. Status = EFI_DEVICE_ERROR;
  661. goto PcatResetDiskEnd;
  662. }
  663. Status = EFI_SUCCESS;
  664. PcatResetDiskEnd:
  665. EfipDestroyBiosCallContext(&RealModeContext);
  666. return Status;
  667. }