-/* $OpenBSD: efidev.c,v 1.8 2021/06/07 21:18:31 krw Exp $ */
+/* $OpenBSD: efidev.c,v 1.9 2021/06/10 18:06:35 krw Exp $ */
/*
* Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
static EFI_STATUS
efid_io(int rw, efi_diskinfo_t ed, u_int off, int nsect, void *buf)
{
- EFI_STATUS status = EFI_SUCCESS;
+ u_int blks, start, end;
EFI_PHYSICAL_ADDRESS addr;
+ EFI_STATUS status;
caddr_t data;
+ size_t size;
- if (ed->blkio->Media->BlockSize != DEV_BSIZE)
+ /* block count of the intrinsic block size in DEV_BSIZE */
+ blks = EFI_BLKSPERSEC(ed);
+ if (blks == 0)
+ /* block size < 512. HP Stream 13 actually has such a disk. */
return (EFI_UNSUPPORTED);
+ start = off / blks;
+ end = (off + nsect + blks - 1) / blks;
+ size = (end - start) * ed->blkio->Media->BlockSize;
+
status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
- EFI_SIZE_TO_PAGES(nsect * DEV_BSIZE), &addr);
+ EFI_SIZE_TO_PAGES(size), &addr);
if (EFI_ERROR(status))
goto on_eio;
data = (caddr_t)(uintptr_t)addr;
switch (rw) {
case F_READ:
- status = ed->blkio->ReadBlocks(ed->blkio, ed->mediaid, off,
- nsect * DEV_BSIZE, data);
+ status = ed->blkio->ReadBlocks(ed->blkio, ed->mediaid, start,
+ size, data);
if (EFI_ERROR(status))
goto on_eio;
- memcpy(buf, data, nsect * DEV_BSIZE);
+ memcpy(buf, data + DEV_BSIZE * (off - start * blks),
+ DEV_BSIZE * nsect);
break;
case F_WRITE:
if (ed->blkio->Media->ReadOnly)
goto on_eio;
- memcpy(data, buf, nsect * DEV_BSIZE);
- status = ed->blkio->WriteBlocks(ed->blkio, ed->mediaid, off,
- nsect * DEV_BSIZE, data);
+ if (off % blks != 0 || nsect % blks != 0) {
+ status = ed->blkio->ReadBlocks(ed->blkio, ed->mediaid,
+ start, size, data);
+ if (EFI_ERROR(status))
+ goto on_eio;
+ }
+ memcpy(data + DEV_BSIZE * (off - start * blks), buf,
+ DEV_BSIZE * nsect);
+ status = ed->blkio->WriteBlocks(ed->blkio, ed->mediaid, start,
+ size, data);
if (EFI_ERROR(status))
goto on_eio;
break;
}
- return (EFI_SUCCESS);
on_eio:
- BS->FreePages(addr, EFI_SIZE_TO_PAGES(nsect * DEV_BSIZE));
+ BS->FreePages(addr, EFI_SIZE_TO_PAGES(size));
return (status);
}