Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | // SPDX-License-Identifier: GPL-2.0+ /* * Block driver for EFI devices * This supports a media driver of UCLASS_EFI with a child UCLASS_BLK * It allows block-level access to EFI devices made available via EFI boot * services * * Copyright 2021 Google LLC */ #include <blk.h> #include <bootdev.h> #include <dm.h> #include <efi.h> #include <efi_api.h> struct efi_block_plat { struct efi_block_io *blkio; }; /** * Read from block device * * @dev: device * @blknr: first block to be read * @blkcnt: number of blocks to read * @buffer: output buffer * Return: number of blocks transferred */ static ulong efi_bl_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, void *buffer) { struct efi_block_plat *plat = dev_get_plat(dev); struct efi_block_io *io = plat->blkio; efi_status_t ret; log_debug("read buf=%p, block=%lx, count=%lx: ", buffer, (ulong)blknr, (ulong)blkcnt); ret = io->read_blocks(io, io->media->media_id, blknr, blkcnt * io->media->block_size, buffer); log_debug("ret=%lx (dec %ld)\n", ret & ~EFI_ERROR_MASK, ret & ~EFI_ERROR_MASK); if (ret) return 0; return blkcnt; } /** * Write to block device * * @dev: device * @blknr: first block to be write * @blkcnt: number of blocks to write * @buffer: input buffer * Return: number of blocks transferred */ static ulong efi_bl_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, const void *buffer) { struct efi_block_plat *plat = dev_get_plat(dev); struct efi_block_io *io = plat->blkio; efi_status_t ret; log_debug("write buf=%p, block=%lx, count=%lx: ", buffer, (ulong)blknr, (ulong)blkcnt); ret = io->write_blocks(io, io->media->media_id, blknr, blkcnt * io->media->block_size, (void *)buffer); log_debug("ret=%lx (dec %ld)\n", ret & ~EFI_ERROR_MASK, ret & ~EFI_ERROR_MASK); if (ret) return 0; return blkcnt; } /* Block device driver operators */ static const struct blk_ops efi_blk_ops = { .read = efi_bl_read, .write = efi_bl_write, }; static int efi_bootdev_bind(struct udevice *dev) { struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev); ucp->prio = BOOTDEVP_3_INTERNAL_SLOW; return 0; } struct bootdev_ops efi_bootdev_ops = { }; static const struct udevice_id efi_bootdev_ids[] = { { .compatible = "u-boot,bootdev-efi" }, { } }; U_BOOT_DRIVER(efi_bootdev) = { .name = "efi_bootdev", .id = UCLASS_BOOTDEV, .ops = &efi_bootdev_ops, .bind = efi_bootdev_bind, .of_match = efi_bootdev_ids, }; U_BOOT_DRIVER(efi_block) = { .name = "efi_block", .id = UCLASS_BLK, .ops = &efi_blk_ops, .plat_auto = sizeof(struct efi_block_plat), }; static int efi_media_bind(struct udevice *dev) { struct efi_media_plat *plat = dev_get_plat(dev); struct efi_block_plat *blk_plat; struct udevice *blk; int ret; ret = blk_create_devicef(dev, "efi_block", "blk", UCLASS_EFI_MEDIA, dev_seq(dev), plat->blkio->media->block_size, plat->blkio->media->last_block, &blk); if (ret) { debug("Cannot create block device\n"); return ret; } blk_plat = dev_get_plat(blk); blk_plat->blkio = plat->blkio; ret = bootdev_setup_for_sibling_blk(blk, "efi_bootdev"); if (ret) return log_msg_ret("emb", ret); return 0; } U_BOOT_DRIVER(efi_media) = { .name = "efi_media", .id = UCLASS_EFI_MEDIA, .bind = efi_media_bind, .plat_auto = sizeof(struct efi_media_plat), }; |