aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2011-12-06 15:49:41 +0000
committerMatt Fleming <matt.fleming@intel.com>2011-12-16 16:31:19 +0000
commit4567631499532d5515abbaeffe792ca50bba6be5 (patch)
tree5f01e0213b1cf005db83ec24bf86ffc230e571e5
parent94903138ac9a9c35fbdb24bbd90d9c94213395f3 (diff)
downloadsyslinux-4567631499532d5515abbaeffe792ca50bba6be5.tar.gz
syslinux-4567631499532d5515abbaeffe792ca50bba6be5.tar.xz
syslinux-4567631499532d5515abbaeffe792ca50bba6be5.zip
efi: Disk I/O support
Implement .disk_init() for the EFI firmware backend.
-rw-r--r--core/include/disk.h1
-rw-r--r--efi/diskio.c98
2 files changed, 99 insertions, 0 deletions
diff --git a/core/include/disk.h b/core/include/disk.h
index dd377150..d0d50ede 100644
--- a/core/include/disk.h
+++ b/core/include/disk.h
@@ -13,6 +13,7 @@ typedef uint64_t block_t;
* contains the I/O function.
*/
struct disk {
+ void *private; /* Firmware-private disk info */
unsigned int disk_number; /* in BIOS style */
unsigned int sector_size; /* gener512B or 2048B */
unsigned int sector_shift;
diff --git a/efi/diskio.c b/efi/diskio.c
new file mode 100644
index 00000000..89779a5b
--- /dev/null
+++ b/efi/diskio.c
@@ -0,0 +1,98 @@
+#define DEBUG 1
+#include <fs.h>
+#include <ilog2.h>
+#include <disk.h>
+#include <dprintf.h>
+#include "efi.h"
+
+struct disk_efi_private {
+ EFI_BLOCK_IO *bio;
+ EFI_DISK_IO *dio;
+};
+
+static inline EFI_STATUS read_blocks(EFI_BLOCK_IO *bio, uint32_t id,
+ sector_t lba, UINTN bytes, void *buf)
+{
+ return uefi_call_wrapper(bio->ReadBlocks, 5, bio, id, lba, bytes, buf);
+}
+
+static inline EFI_STATUS write_blocks(EFI_BLOCK_IO *bio, uint32_t id,
+ sector_t lba, UINTN bytes, void *buf)
+{
+ return uefi_call_wrapper(bio->WriteBlocks, 5, bio, id, lba, bytes, buf);
+}
+
+static int efi_rdwr_sectors(struct disk *disk, void *buf,
+ sector_t lba, size_t count, bool is_write)
+{
+ struct disk_efi_private *priv = disk->private;
+ EFI_BLOCK_IO *bio = priv->bio;
+ EFI_DISK_IO *dio = priv->dio;
+ EFI_STATUS status;
+ UINTN bytes = count * disk->sector_size;
+
+
+ if (is_write)
+ status = write_blocks(bio, disk->disk_number, lba, bytes, buf);
+ else
+ status = read_blocks(bio, disk->disk_number, lba, bytes, buf);
+
+ if (status != EFI_SUCCESS)
+ Print(L"Failed to %s blocks: 0x%x\n",
+ is_write ? "write" : "read",
+ status);
+
+ return count << disk->sector_shift;
+}
+
+struct disk *efi_disk_init(EFI_HANDLE handle)
+{
+ static struct disk_efi_private priv;
+ static struct disk disk;
+ unsigned int hard_max_transfer;
+ EFI_BLOCK_IO *bio;
+ EFI_DISK_IO *dio;
+ EFI_STATUS status;
+ int sector_size;
+
+ status = uefi_call_wrapper(BS->HandleProtocol, 3, handle,
+ &DiskIoProtocol, (void **)&dio);
+ if (status != EFI_SUCCESS)
+ return NULL;
+
+ status = uefi_call_wrapper(BS->HandleProtocol, 3, handle,
+ &BlockIoProtocol, (void **)&bio);
+ if (status != EFI_SUCCESS)
+ return NULL;
+
+ /*
+ * XXX Do we need to map this to a BIOS disk number?
+ */
+ disk.disk_number = bio->Media->MediaId;
+
+ disk.sector_size = bio->Media->BlockSize;
+ disk.rdwr_sectors = efi_rdwr_sectors;
+ disk.sector_shift = ilog2(disk.sector_size);
+
+ dprintf("foo!\n");
+ Print(L"sector_size=%d, disk_number=%d\n", disk.sector_size,
+ disk.disk_number);
+
+ priv.bio = bio;
+ priv.dio = dio;
+ disk.private = &priv;
+#if 0
+
+ disk.part_start = part_start;
+ disk.secpercyl = disk.h * disk.s;
+
+
+ disk.maxtransfer = MaxTransfer;
+
+ dprintf("disk %02x cdrom %d type %d sector %u/%u offset %llu limit %u\n",
+ media_id, cdrom, ebios, sector_size, disk.sector_shift,
+ part_start, disk.maxtransfer);
+#endif
+
+ return &disk;
+}