disk.c 20 KB

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