diff options
Diffstat (limited to 'lib/efi_loader/efi_disk.c')
-rw-r--r-- | lib/efi_loader/efi_disk.c | 60 |
1 files changed, 55 insertions, 5 deletions
diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index 7a6b06821a..9007a5f77f 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -41,11 +41,26 @@ struct efi_disk_obj { struct blk_desc *desc; }; +/** + * efi_disk_reset() - reset block device + * + * This function implements the Reset service of the EFI_BLOCK_IO_PROTOCOL. + * + * As U-Boot's block devices do not have a reset function simply return + * EFI_SUCCESS. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * @this: pointer to the BLOCK_IO_PROTOCOL + * @extended_verification: extended verification + * Return: status code + */ static efi_status_t EFIAPI efi_disk_reset(struct efi_block_io *this, char extended_verification) { EFI_ENTRY("%p, %x", this, extended_verification); - return EFI_EXIT(EFI_DEVICE_ERROR); + return EFI_EXIT(EFI_SUCCESS); } enum efi_disk_direction { @@ -69,12 +84,12 @@ static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this, blocks = buffer_size / blksz; lba += diskobj->offset; - debug("EFI: %s:%d blocks=%x lba=%llx blksz=%x dir=%d\n", __func__, - __LINE__, blocks, lba, blksz, direction); + EFI_PRINT("blocks=%x lba=%llx blksz=%x dir=%d\n", + blocks, lba, blksz, direction); /* We only support full block access */ if (buffer_size & (blksz - 1)) - return EFI_DEVICE_ERROR; + return EFI_BAD_BUFFER_SIZE; if (direction == EFI_DISK_READ) n = blk_dread(desc, lba, blocks, buffer); @@ -84,7 +99,7 @@ static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this, /* We don't do interrupts, so check for timers cooperatively */ efi_timer_check(); - debug("EFI: %s:%d n=%lx blocks=%x\n", __func__, __LINE__, n, blocks); + EFI_PRINT("n=%lx blocks=%x\n", n, blocks); if (n != blocks) return EFI_DEVICE_ERROR; @@ -99,6 +114,20 @@ static efi_status_t EFIAPI efi_disk_read_blocks(struct efi_block_io *this, void *real_buffer = buffer; efi_status_t r; + if (!this) + return EFI_INVALID_PARAMETER; + /* TODO: check for media changes */ + if (media_id != this->media->media_id) + return EFI_MEDIA_CHANGED; + if (!this->media->media_present) + return EFI_NO_MEDIA; + /* media->io_align is a power of 2 */ + if ((uintptr_t)buffer & (this->media->io_align - 1)) + return EFI_INVALID_PARAMETER; + if (lba * this->media->block_size + buffer_size > + this->media->last_block * this->media->block_size) + return EFI_INVALID_PARAMETER; + #ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER if (buffer_size > EFI_LOADER_BOUNCE_BUFFER_SIZE) { r = efi_disk_read_blocks(this, media_id, lba, @@ -134,6 +163,22 @@ static efi_status_t EFIAPI efi_disk_write_blocks(struct efi_block_io *this, void *real_buffer = buffer; efi_status_t r; + if (!this) + return EFI_INVALID_PARAMETER; + if (this->media->read_only) + return EFI_WRITE_PROTECTED; + /* TODO: check for media changes */ + if (media_id != this->media->media_id) + return EFI_MEDIA_CHANGED; + if (!this->media->media_present) + return EFI_NO_MEDIA; + /* media->io_align is a power of 2 */ + if ((uintptr_t)buffer & (this->media->io_align - 1)) + return EFI_INVALID_PARAMETER; + if (lba * this->media->block_size + buffer_size > + this->media->last_block * this->media->block_size) + return EFI_INVALID_PARAMETER; + #ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER if (buffer_size > EFI_LOADER_BOUNCE_BUFFER_SIZE) { r = efi_disk_write_blocks(this, media_id, lba, @@ -288,6 +333,11 @@ static efi_status_t efi_disk_add_dev( /* Fill in EFI IO Media info (for read/write callbacks) */ diskobj->media.removable_media = desc->removable; diskobj->media.media_present = 1; + /* + * MediaID is just an arbitrary counter. + * We have to change it if the medium is removed or changed. + */ + diskobj->media.media_id = 1; diskobj->media.block_size = desc->blksz; diskobj->media.io_align = desc->blksz; diskobj->media.last_block = desc->lba - offset; |