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;
                }

Reply via email to