Sorry for making noise, let me update the diff. > + if (ed->blkio->Media->IoAlign > 1 && > + ((UINTN)buf + i_lblks * DEV_BSIZE) > + % ed->blkio->Media->IoAlign == 0)
first condition was reversed.. On Wed, 10 Mar 2021 20:35:41 +0900 (JST) YASUOKA Masahiko <yasu...@openbsd.org> wrote: > efiboot cannot load the kernel properly on some machines if booted > from CD-ROM. In that case boot fails with a message like follow: > > booting cd0a:..... [359648read symbols: Unknown error: code 255 > > As far as Asou and my test, this happens on hosts on VMware ESXi 6.7, > 7.0 and asou's physical machine. > > The problem happens because efiboot calls ReadBlocks function with an > unaligned pointer for medias which requires an aligned pointer. When > efiboot loads a kernel, the pointer becomes unaligned since there is > an ELF section located at unaligned place in CD-ROM. Previously our > kernel didn't have such a section but it does after switching lld as > the default linker. > > For test, let me show sample commands which creates a bootable cdrom > image for EFI: > > mkdir -p efiboot/EFI/BOOT > cp /usr/mdec/BOOTX64.EFI efiboot/EFI/BOOT > makefs -M 1m -m 1m -t msdos -o fat_type=12,sectors_per_cluster=1 \ > efiboot.img efiboot > mkdir -p cd-dir/etc > cp bsd.rd cd-dir/ > echo "set image bsd.rd" > cd-dir/etc/boot.conf > makefs -t cd9660 -o > 'rockridge,bootimage=i386;/usr/mdec/cdbr,no-emul-boot,allow-multidot,bootimage=efi;efiboot.img,no-emul-boot' > \ > boot.iso cd-dir > > the diff is to fix the problem. > > ok? Index: sys/arch/amd64/stand/efiboot/efidev.c =================================================================== RCS file: /disk/cvs/openbsd/src/sys/arch/amd64/stand/efiboot/efidev.c,v retrieving revision 1.32 diff -u -p -r1.32 efidev.c --- sys/arch/amd64/stand/efiboot/efidev.c 9 Dec 2020 18:10:18 -0000 1.32 +++ sys/arch/amd64/stand/efiboot/efidev.c 10 Mar 2021 11:41:39 -0000 @@ -84,7 +84,7 @@ efid_init(struct diskinfo *dip, void *ha static EFI_STATUS efid_io(int rw, efi_diskinfo_t ed, u_int off, int nsect, void *buf) { - u_int blks, lba, i_lblks, i_tblks, i_nblks; + u_int i, blks, lba, i_lblks, i_tblks, i_nblks; EFI_STATUS status = EFI_SUCCESS; static u_char *iblk = NULL; static u_int iblksz = 0; @@ -127,10 +127,29 @@ efid_io(int rw, efi_diskinfo_t ed, u_int min(nsect, i_lblks) * DEV_BSIZE); } if (i_nblks > 0) { - status = EFI_CALL(ed->blkio->ReadBlocks, - ed->blkio, ed->mediaid, lba, - ed->blkio->Media->BlockSize * (i_nblks / blks), - buf + (i_lblks * DEV_BSIZE)); + /* + * Pass the buffer directly to the EFI function only if + * the buffer is properly aligned as the media requires + */ + if (ed->blkio->Media->IoAlign <= 1 || + ((UINTN)buf + i_lblks * DEV_BSIZE) + % ed->blkio->Media->IoAlign == 0) + status = EFI_CALL(ed->blkio->ReadBlocks, + ed->blkio, ed->mediaid, lba, + ed->blkio->Media->BlockSize * (i_nblks / + blks), buf + i_lblks * DEV_BSIZE); + else { + for (i = 0; i < i_nblks; i += blks) { + status = EFI_CALL(ed->blkio->ReadBlocks, + ed->blkio, ed->mediaid, + lba + i / blks, + ed->blkio->Media->BlockSize, iblk); + if (EFI_ERROR(status)) + break; + memcpy(buf + i * DEV_BSIZE, iblk, + ed->blkio->Media->BlockSize); + } + } if (EFI_ERROR(status)) goto on_eio; } @@ -160,10 +179,30 @@ efid_io(int rw, efi_diskinfo_t ed, u_int ed->blkio->Media->BlockSize, iblk); } if (i_nblks > 0) { - status = EFI_CALL(ed->blkio->WriteBlocks, - ed->blkio, ed->mediaid, lba, - ed->blkio->Media->BlockSize * (i_nblks / blks), - buf + (i_lblks * DEV_BSIZE)); + /* + * Pass the buffer directly to the EFI function only if + * the buffer is properly aligned as the media requires + */ + if (ed->blkio->Media->IoAlign <= 1 || + ((UINTN)buf + i_lblks * DEV_BSIZE) + % ed->blkio->Media->IoAlign == 0) + status = EFI_CALL(ed->blkio->WriteBlocks, + ed->blkio, ed->mediaid, lba, + ed->blkio->Media->BlockSize * (i_nblks / + blks), buf + i_lblks * DEV_BSIZE); + else { + for (i = 0; i < i_nblks; i += blks) { + memcpy(iblk, buf + i * DEV_BSIZE, + ed->blkio->Media->BlockSize); + status = EFI_CALL( + ed->blkio->WriteBlocks, + ed->blkio, ed->mediaid, + lba + i / blks, + ed->blkio->Media->BlockSize, iblk); + if (EFI_ERROR(status)) + break; + } + } if (EFI_ERROR(status)) goto on_eio; }