> Date: Fri, 26 Mar 2021 19:43:23 +0900 (JST)
> From: YASUOKA Masahiko <yasu...@openbsd.org>
> 
> Hi,
> 
> On Fri, 26 Mar 2021 09:30:43 +0100
> Jan Klemkow <j.klem...@wemelug.de> wrote:
> > If you want to boot OpenBSD on an HP EliteBook 830 G7/G8, the bootloader
> > will hang while loading the kernel.  Because, the UEFI loads the
> > bootloader on the same place in memory, where the bootloader will copy
> > the kernel.  We are unable to load the kernel on arbitrary memory.
> > Thus, the following diff will help you, to get OpenBSD running on these
> > machines.  It moves the hardcoded Kernel address to a free place.
> 
> The openbsd efiboot copies the kernel to that place after
> ExitBootServices().
> 
> sys/arch/amd64/stand/efiboot/exec_i386.c
>     152         /*
>     153          * Move the loaded kernel image to the usual place after 
> calling
>     154          * ExitBootServices().
>     155          */
>     156 #ifdef __amd64__
>     157         protect_writeable(marks[MARK_START] + delta,
>     158             marks[MARK_END] - marks[MARK_START]);
>     159 #endif
>     160         memmove((void *)marks[MARK_START] + delta, (void 
> *)marks[MARK_START],
>     161             marks[MARK_END] - marks[MARK_START]);
>     162         for (i = 0; i < MARK_MAX; i++)
>     163                 marks[i] += delta;
>     164 
>     165 #ifdef __amd64__
>     166         (*run_i386)((u_long)run_i386, entry, howto, bootdev, 
> BOOTARG_APIVER,
>     167             marks[MARK_END], extmem, cnvmem, ac, (intptr_t)av);
> 
> 
> I think it should work without the ld.script change..

The (likely) problem is that the memmove() on line 160 is overwriting
the bootloader code itself.

There are essentially two ways to fix this:

1. Have the bootloader relocate itself to an address that doesn't
   conflict with the kernel to be loaded.

2. Make it possible for the kernel to be loaded at a (somewhat)
   arbitrary physical address.

In my view #2 is the way forward.  There are other reasons why that
would be beneficial as it would make it less predictable at which
physical address the kernel code lives which could prevent some
attacks that use the direct map.

#2 is also the approach taken by the EFIBOOT on armv7 and arm64.  On
arm64 for example, EFIBOOT loads the kernel into a 64MB memory block
that is aligned on a 2MB boundary.  The kernel then figures out its
load address based on that and and patches things up accordingly.

mlarkin@ was doing some work to change how we load the amd64 kernel.
His approach was to let the bootloader build the initial page tables
and jump into the kernel in 64-bit mode with the MMU enabled.  That
was more focussed on running the kernel at a randomized virtual
address.  But it should be fairly easy to make it run at a different
physical address as well this way.  Unfortunately that effort was
mostly focussed on the legacy bootloader.

Reply via email to