loader: efipart should check disk size from partition table
While testing 32bit UEFI OVMF (which has bug about how the disk size is presented), I did witness the errors from blkio->ReadBlocks(). It became apparent we can not entirely trust UEFI interfaces either, so additional checks are needed. So we use disk_ioctl(DIOCGMEDIASIZE) for disks, with fallback of Media->LastBlock for other media. In addition, we need to check if there is media present. + small fixes for error printout, and avoiding multiple blk * 512. Reviewed by: allanjude Approved by: allanjude (mentor) Differential Revision: https://reviews.freebsd.org/D10197
This commit is contained in:
parent
21ffe1a952
commit
30249cacdc
@ -834,8 +834,10 @@ efipart_readwrite(EFI_BLOCK_IO *blkio, int rw, daddr_t blk, daddr_t nblks,
|
||||
return (ENOSYS);
|
||||
}
|
||||
|
||||
if (EFI_ERROR(status))
|
||||
printf("%s: rw=%d, status=%lu\n", __func__, rw, (u_long)status);
|
||||
if (EFI_ERROR(status)) {
|
||||
printf("%s: rw=%d, blk=%ju size=%ju status=%lu\n", __func__, rw,
|
||||
blk, nblks, EFI_ERROR_CODE(status));
|
||||
}
|
||||
return (efi_status_to_errno(status));
|
||||
}
|
||||
|
||||
@ -859,6 +861,10 @@ efipart_strategy(void *devdata, int rw, daddr_t blk, size_t size,
|
||||
if (pd == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
if (pd->pd_blkio->Media->RemovableMedia &&
|
||||
!pd->pd_blkio->Media->MediaPresent)
|
||||
return (EIO);
|
||||
|
||||
bcd.dv_strategy = efipart_realstrategy;
|
||||
bcd.dv_devdata = devdata;
|
||||
bcd.dv_cache = pd->pd_bcache;
|
||||
@ -878,7 +884,7 @@ efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t size,
|
||||
pdinfo_list_t *pdi;
|
||||
pdinfo_t *pd;
|
||||
EFI_BLOCK_IO *blkio;
|
||||
off_t off;
|
||||
uint64_t off, disk_blocks, d_offset = 0;
|
||||
char *blkbuf;
|
||||
size_t blkoff, blksz;
|
||||
int error;
|
||||
@ -902,11 +908,24 @@ efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t size,
|
||||
return (EIO);
|
||||
|
||||
off = blk * 512;
|
||||
/*
|
||||
* Get disk blocks, this value is either for whole disk or for
|
||||
* partition.
|
||||
*/
|
||||
disk_blocks = 0;
|
||||
if (dev->d_dev->dv_type == DEVT_DISK) {
|
||||
if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) {
|
||||
/* DIOCGMEDIASIZE does return bytes. */
|
||||
disk_blocks /= blkio->Media->BlockSize;
|
||||
}
|
||||
d_offset = dev->d_offset;
|
||||
}
|
||||
if (disk_blocks == 0)
|
||||
disk_blocks = blkio->Media->LastBlock + 1 - d_offset;
|
||||
|
||||
/* make sure we don't read past disk end */
|
||||
if ((off + size) / blkio->Media->BlockSize - 1 >
|
||||
blkio->Media->LastBlock) {
|
||||
size = blkio->Media->LastBlock + 1 -
|
||||
off / blkio->Media->BlockSize;
|
||||
if ((off + size) / blkio->Media->BlockSize > d_offset + disk_blocks) {
|
||||
size = d_offset + disk_blocks - off / blkio->Media->BlockSize;
|
||||
size = size * blkio->Media->BlockSize;
|
||||
}
|
||||
|
||||
@ -914,9 +933,9 @@ efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t size,
|
||||
*rsize = size;
|
||||
|
||||
if ((size % blkio->Media->BlockSize == 0) &&
|
||||
((blk * 512) % blkio->Media->BlockSize == 0))
|
||||
(off % blkio->Media->BlockSize == 0))
|
||||
return (efipart_readwrite(blkio, rw,
|
||||
blk * 512 / blkio->Media->BlockSize,
|
||||
off / blkio->Media->BlockSize,
|
||||
size / blkio->Media->BlockSize, buf));
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user