Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch Add reloc keyworkd to let EFI bootstrap load amd64 ...



details:   https://anonhg.NetBSD.org/src/rev/a69f36040458
branches:  trunk
changeset: 374343:a69f36040458
user:      manu <manu%NetBSD.org@localhost>
date:      Thu Apr 20 00:42:23 2023 +0000

description:
Add reloc keyworkd to let EFI bootstrap load amd64 kernel at any address

EFI bootstrap assumes it can copy the amd64 kernel to its ELF load
address (that is KERNTEXTOFF - KERNBASE = 0x200000), but it can
clash with previous UEFI memory allocation, as described here:
http://mail-index.netbsd.org/tech-kern/2023/04/07/msg028833.html

This change adds a reloc keyword for controling where the EFI
boostrap will copy the kernel image. Possible values are:
default - the default and prior behavior, copy at 0x200000.
none - do not copy and use the kernel image where it was loaded.
address - specify an explicit address where to copy the kernel.

This comes with an amd64 kernel patch that makes it self-relocatable.
It first discover where it was loaded in memory, and if this is
different than the expected 0x200000, hhe the kernel relocates
itself and start over at the right address.

diffstat:

 sys/arch/amd64/amd64/locore.S                      |  145 ++++++++++++++++++++-
 sys/arch/i386/stand/efiboot/boot.c                 |   47 ++++++-
 sys/arch/i386/stand/efiboot/bootia32/efibootia32.c |    4 +-
 sys/arch/i386/stand/efiboot/bootia32/startprog32.S |    7 +-
 sys/arch/i386/stand/efiboot/bootx64/efibootx64.c   |    4 +-
 sys/arch/i386/stand/efiboot/bootx64/startprog64.S  |    6 +-
 sys/arch/i386/stand/efiboot/efiboot.c              |    6 +-
 sys/arch/i386/stand/efiboot/efiboot.h              |   10 +-
 sys/arch/i386/stand/lib/exec.c                     |   23 +++-
 9 files changed, 238 insertions(+), 14 deletions(-)

diffs (truncated from 425 to 300 lines):

diff -r ea4caf1943d4 -r a69f36040458 sys/arch/amd64/amd64/locore.S
--- a/sys/arch/amd64/amd64/locore.S     Wed Apr 19 22:00:18 2023 +0000
+++ b/sys/arch/amd64/amd64/locore.S     Thu Apr 20 00:42:23 2023 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: locore.S,v 1.218 2023/03/03 14:32:48 riastradh Exp $   */
+/*     $NetBSD: locore.S,v 1.219 2023/04/20 00:42:23 manu Exp $        */
 
 /*
  * Copyright-o-rama!
@@ -456,6 +456,14 @@ ENTRY(start)
 #ifndef XENPV
        .code32
 
+       call    next
+next:  pop     %edi
+       sub     $(next - kernel_text), %edi 
+
+       /* If not KERNBASE, reloc ourselves to KERNBASE */
+       cmpl    $(KERNTEXTOFF_LO - KERNBASE_LO), %edi
+       jne     selfreloc_start
+
        /* Warm boot */
        movw    $0x1234,0x472
 
@@ -1757,3 +1765,138 @@ LABEL(mds_leave_end)
 LABEL(nomds_leave)
        NOMDS_LEAVE
 LABEL(nomds_leave_end)
+
+/*
+ * selfreloc(loadddr edi)
+ * This is adapted from sys/arch/i386/i386/locore.S
+ */
+       .code32
+ENTRY(selfreloc_start)
+       movl    %edi, %ebx              /* loadaddr saved in ebx */
+       movl    %edi, %esi                              /* src */
+       movl    $_RELOC(kernel_text), %edi              /* dest */
+       movl    16(%esp),%ecx                           /* esym */
+       subl    $_RELOC(kernel_text), %ecx              /* size */
+
+#if defined(NO_OVERLAP)
+        movl    %ecx, %eax
+#else 
+        movl    %edi, %eax
+        subl    %esi, %eax
+        cmpl    %ecx, %eax      /* overlapping? */
+        movl    %ecx, %eax
+        jb      .Lbackwards
+#endif
+        /* nope, copy forwards. */
+        shrl    $2, %ecx        /* copy by words */
+        rep
+        movsl
+        and     $3, %eax        /* any bytes left? */
+        jnz     .Ltrailing
+        jmp     .Lcopy_done
+
+.Ltrailing:
+        cmp     $2, %eax
+        jb      11f
+        movw    (%esi), %ax
+        movw    %ax, (%edi)
+        je      .Lcopy_done
+        movb    2(%esi), %al
+        movb    %al, 2(%edi)
+        jmp     .Lcopy_done
+11:     movb    (%esi), %al
+        movb    %al, (%edi)
+        jmp     .Lcopy_done
+
+#if !defined(NO_OVERLAP)
+.Lbackwards:
+        addl    %ecx, %edi      /* copy backwards. */
+        addl    %ecx, %esi
+        and     $3, %eax        /* any fractional bytes? */
+        jnz     .Lback_align
+.Lback_aligned:
+        shrl    $2, %ecx
+        subl    $4, %esi
+        subl    $4, %edi
+        std
+        rep
+        movsl
+        cld
+        jmp     .Lcopy_done
+
+.Lback_align:
+        sub     %eax, %esi
+        sub     %eax, %edi
+        cmp     $2, %eax
+        jb      11f
+        je      12f
+        movb    2(%esi), %al
+        movb    %al, 2(%edi)
+12:     movw    (%esi), %ax
+        movw    %ax, (%edi)
+        jmp     .Lback_aligned
+11:     movb    (%esi), %al
+        movb    %al, (%edi)
+        jmp     .Lback_aligned
+#endif
+        /* End of copy kernel */
+.Lcopy_done:
+       cld                     /* LynxOS depends on it */
+
+       /* load current selfreloc_start addesss in $edi */
+       movl    %ebx, %edi      /* loadaddr was saved in ebx */
+       addl    $(selfreloc_start - kernel_text), %edi
+
+       /* Prepare jump address */
+       lea     (selfreloc_start32a - selfreloc_start)(%edi), %eax
+       movl    %eax, (selfreloc_start32r - selfreloc_start)(%edi)
+
+       /* Setup GDT */
+       lea     (gdt - selfreloc_start)(%edi), %eax
+       mov     %eax, (gdtrr - selfreloc_start)(%edi)
+       lgdt    (gdtr - selfreloc_start)(%edi)
+
+       /* Jump to set %cs */
+       ljmp    *(selfreloc_start32r - selfreloc_start)(%edi)
+
+       .align  4
+selfreloc_start32a:
+       movl    $0x10, %eax     /* #define DATA_SEGMENT 0x10 */
+       movw    %ax, %ds
+       movw    %ax, %es
+       movw    %ax, %fs
+       movw    %ax, %gs
+       movw    %ax, %ss
+
+       /* Disable Paging in CR0 */
+       movl    %cr0, %eax
+       andl    $(~CR0_PG), %eax
+       movl    %eax, %cr0
+
+       /* Disable PAE in CR4 */
+       movl    %cr4, %eax
+       andl    $(~CR4_PAE), %eax
+       movl    %eax, %cr4
+
+       jmp     selfreloc_start32b
+
+       .align  4
+selfreloc_start32b:
+       xor     %eax, %eax
+       movl    $_RELOC(start), %esi
+       jmp     *%esi
+
+       .align  16
+selfreloc_start32r:
+       .long   0
+       .long   0x08    /* #define      CODE_SEGMENT    0x08 */
+       .align  16
+gdt:
+       .long   0, 0
+       .byte   0xff, 0xff, 0x00, 0x00, 0x00, 0x9f, 0xcf, 0x00
+       .byte   0xff, 0xff, 0x00, 0x00, 0x00, 0x93, 0xcf, 0x00
+gdtr:
+       .word   gdtr - gdt
+gdtrr:
+       .quad
+END(selfreloc_start)
diff -r ea4caf1943d4 -r a69f36040458 sys/arch/i386/stand/efiboot/boot.c
--- a/sys/arch/i386/stand/efiboot/boot.c        Wed Apr 19 22:00:18 2023 +0000
+++ b/sys/arch/i386/stand/efiboot/boot.c        Thu Apr 20 00:42:23 2023 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: boot.c,v 1.21 2022/06/08 21:43:45 wiz Exp $    */
+/*     $NetBSD: boot.c,v 1.22 2023/04/20 00:42:24 manu Exp $   */
 
 /*-
  * Copyright (c) 2016 Kimihiro Nonaka <nonaka%netbsd.org@localhost>
@@ -83,6 +83,7 @@ void  command_menu(char *);
 #endif
 void   command_modules(char *);
 void   command_multiboot(char *);
+void   command_reloc(char *);
 void   command_text(char *);
 void   command_version(char *);
 
@@ -109,6 +110,7 @@ const struct bootblk_command commands[] 
 #endif
        { "modules",    command_modules },
        { "multiboot",  command_multiboot },
+       { "reloc",      command_reloc },
        { "rndseed",    rnd_add },
        { "splash",     splash_add },
        { "text",       command_text },
@@ -406,6 +408,7 @@ command_help(char *arg)
 #endif
               "modules {on|off|enabled|disabled}\n"
               "multiboot [dev:][filename] [<args>]\n"
+              "reloc {address|none|default}\n"
               "rndseed {path_to_rndseed_file}\n"
               "splash {path_to_image_file}\n"
               "text [{modenum|list}]\n"
@@ -641,6 +644,48 @@ command_multiboot(char *arg)
 }
 
 void
+command_reloc(char *arg)
+{
+       char *ep;
+       
+       if (*arg == '\0') {
+               switch (efi_reloc_type) {
+               case RELOC_NONE:
+                       printf("reloc: none\n");
+                       break;
+               case RELOC_ADDR:
+                       printf("reloc: %p\n", (void *)efi_kernel_reloc);
+                       break;
+               case RELOC_DEFAULT:
+               default:
+                       printf("reloc: default\n");
+                       break;
+               }
+               goto out;
+       }
+
+       if (strcmp(arg, "default") == 0) {
+               efi_reloc_type = RELOC_DEFAULT;
+               goto out;
+       }
+
+       if (strcmp(arg, "none") == 0) {
+               efi_reloc_type = RELOC_NONE;
+               goto out;
+       }
+
+       errno = 0;
+       efi_kernel_reloc = strtoul(arg, &ep, 0);
+       if (ep == arg || *ep != '\0' || errno)
+               printf("could not parse address \"%s\"\n", arg);
+       else
+               efi_reloc_type = RELOC_ADDR;
+out:
+       return;
+
+}
+
+void
 command_version(char *arg)
 {
        CHAR16 *path;
diff -r ea4caf1943d4 -r a69f36040458 sys/arch/i386/stand/efiboot/bootia32/efibootia32.c
--- a/sys/arch/i386/stand/efiboot/bootia32/efibootia32.c        Wed Apr 19 22:00:18 2023 +0000
+++ b/sys/arch/i386/stand/efiboot/bootia32/efibootia32.c        Thu Apr 20 00:42:23 2023 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: efibootia32.c,v 1.5 2019/09/13 02:19:45 manu Exp $     */
+/*     $NetBSD: efibootia32.c,v 1.6 2023/04/20 00:42:24 manu Exp $     */
 
 /*-
  * Copyright (c) 2016 Kimihiro Nonaka <nonaka%netbsd.org@localhost>
@@ -76,7 +76,7 @@ startprog(physaddr_t entry, uint32_t arg
 
        (*startprog32)(entry, argc, argv,
            (physaddr_t)startprog32 + startprog32_size,
-           efi_kernel_start, efi_kernel_start + efi_loadaddr,
+           efi_kernel_start, efi_load_start,
            efi_kernel_size, startprog32);
 }
 
diff -r ea4caf1943d4 -r a69f36040458 sys/arch/i386/stand/efiboot/bootia32/startprog32.S
--- a/sys/arch/i386/stand/efiboot/bootia32/startprog32.S        Wed Apr 19 22:00:18 2023 +0000
+++ b/sys/arch/i386/stand/efiboot/bootia32/startprog32.S        Thu Apr 20 00:42:23 2023 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: startprog32.S,v 1.2 2017/02/24 12:24:25 nonaka Exp $   */
+/*     $NetBSD: startprog32.S,v 1.3 2023/04/20 00:42:24 manu Exp $     */
 /*     NetBSD: startprog.S,v 1.4 2016/12/04 08:21:08 maxv Exp  */
 
 /*
@@ -117,6 +117,11 @@ start:
        movl    24(%ebp), %edi  /* dest */
        movl    28(%ebp), %esi  /* src */
        movl    32(%ebp), %ecx  /* size */
+
+       /* skip copy if same source and destination */
+       cmpl    %edi,%esi
+       jz      .Lcopy_done
+
 #if defined(NO_OVERLAP)
        movl    %ecx, %eax
 #else
diff -r ea4caf1943d4 -r a69f36040458 sys/arch/i386/stand/efiboot/bootx64/efibootx64.c
--- a/sys/arch/i386/stand/efiboot/bootx64/efibootx64.c  Wed Apr 19 22:00:18 2023 +0000
+++ b/sys/arch/i386/stand/efiboot/bootx64/efibootx64.c  Thu Apr 20 00:42:23 2023 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: efibootx64.c,v 1.5 2019/09/13 02:19:46 manu Exp $      */
+/*     $NetBSD: efibootx64.c,v 1.6 2023/04/20 00:42:24 manu Exp $      */
 
 /*-
  * Copyright (c) 2016 Kimihiro Nonaka <nonaka%netbsd.org@localhost>
@@ -80,7 +80,7 @@ startprog(physaddr_t entry, uint32_t arg
                memcpy(newsp, argv, sizeof(*argv) * argc);
        }
 
-       (*startprog64)(efi_kernel_start, efi_kernel_start + efi_loadaddr,
+       (*startprog64)(efi_kernel_start, efi_load_start,
            (physaddr_t)newsp, efi_kernel_size, startprog64, entry);



Home | Main Index | Thread Index | Old Index