Source-Changes-HG archive

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

[src/trunk]: src/sys/arch/x86 Avoid panic when amd64 kernel is booted from 32...



details:   https://anonhg.NetBSD.org/src/rev/79bea61d8d5f
branches:  trunk
changeset: 821967:79bea61d8d5f
user:      nonaka <nonaka%NetBSD.org@localhost>
date:      Thu Feb 23 12:17:36 2017 +0000

description:
Avoid panic when amd64 kernel is booted from 32bit UEFI.

diffstat:

 sys/arch/x86/include/efi.h |   54 ++++++++++++-
 sys/arch/x86/x86/efi.c     |  180 ++++++++++++++++++++++++++++++++++++--------
 2 files changed, 195 insertions(+), 39 deletions(-)

diffs (truncated from 350 to 300 lines):

diff -r faca43840ac2 -r 79bea61d8d5f sys/arch/x86/include/efi.h
--- a/sys/arch/x86/include/efi.h        Thu Feb 23 12:16:30 2017 +0000
+++ b/sys/arch/x86/include/efi.h        Thu Feb 23 12:17:36 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: efi.h,v 1.5 2017/02/14 13:29:09 nonaka Exp $   */
+/*     $NetBSD: efi.h,v 1.6 2017/02/23 12:17:36 nonaka Exp $   */
 
 /*-
  * Copyright (c) 2004 Marcel Moolenaar
@@ -42,9 +42,6 @@
 extern const struct uuid EFI_UUID_ACPI20;
 extern const struct uuid EFI_UUID_ACPI10;
 
-#define        EFI_TABLE_SAL                           \
-       {0xeb9d2d32,0x2d88,0x11d3,0x9a,0x16,{0x00,0x90,0x27,0x3f,0xc1,0x4d}}
-
 enum efi_reset {
        EFI_RESET_COLD,
        EFI_RESET_WARM
@@ -53,11 +50,11 @@
 typedef uint16_t       efi_char;
 typedef unsigned long efi_status;
 
-
 struct efi_cfgtbl {
        struct uuid     ct_uuid;
        void           *ct_data;
 };
+
 struct efi_md {
        uint32_t        md_type;
 #define        EFI_MD_TYPE_NULL        0
@@ -159,6 +156,53 @@
        struct efi_cfgtbl *st_cfgtbl;
 };
 
+#if defined(__amd64__)
+struct efi_cfgtbl32 {
+       struct uuid             ct_uuid;
+       uint32_t                ct_data;        /* void * */
+};
+
+struct efi_systbl32 {
+       struct efi_tblhdr       st_hdr;
+
+       uint32_t                st_fwvendor;
+       uint32_t                st_fwrev;
+       uint32_t                st_cin;         /* = 0 */
+       uint32_t                st_cinif;       /* = 0 */
+       uint32_t                st_cout;        /* = 0 */
+       uint32_t                st_coutif;      /* = 0 */
+       uint32_t                st_cerr;        /* = 0 */
+       uint32_t                st_cerrif;      /* = 0 */
+       uint32_t                st_rt;          /* struct efi_rt32 * */
+       uint32_t                st_bs;          /* = 0 */
+       uint32_t                st_entries;
+       uint32_t                st_cfgtbl;      /* struct efi_cfgtbl32 * */
+};
+#elif defined(__i386__)
+struct efi_cfgtbl64 {
+       struct uuid             ct_uuid;
+       uint64_t                ct_data;        /* void * */
+};
+
+struct efi_systbl64 {
+       struct efi_tblhdr       st_hdr;
+
+       uint64_t                st_fwvendor;
+       uint32_t                st_fwrev;
+       uint32_t                __pad;
+       uint64_t                st_cin;         /* = 0 */
+       uint64_t                st_cinif;       /* = 0 */
+       uint64_t                st_cout;        /* = 0 */
+       uint64_t                st_coutif;      /* = 0 */
+       uint64_t                st_cerr;        /* = 0 */
+       uint64_t                st_cerrif;      /* = 0 */
+       uint64_t                st_rt;          /* struct efi_rt64 * */
+       uint64_t                st_bs;          /* = 0 */
+       uint64_t                st_entries;
+       uint64_t                st_cfgtbl;      /* struct efi_cfgtbl64 * */
+};
+#endif
+
 bool               efi_probe(void);
 paddr_t            efi_getsystblpa(void);
 struct efi_systbl *efi_getsystbl(void);
diff -r faca43840ac2 -r 79bea61d8d5f sys/arch/x86/x86/efi.c
--- a/sys/arch/x86/x86/efi.c    Thu Feb 23 12:16:30 2017 +0000
+++ b/sys/arch/x86/x86/efi.c    Thu Feb 23 12:17:36 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: efi.c,v 1.9 2017/02/16 03:53:20 nonaka Exp $   */
+/*     $NetBSD: efi.c,v 1.10 2017/02/23 12:17:36 nonaka Exp $  */
 
 /*-
  * Copyright (c) 2016 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: efi.c,v 1.9 2017/02/16 03:53:20 nonaka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: efi.c,v 1.10 2017/02/23 12:17:36 nonaka Exp $");
 
 #include <sys/kmem.h>
 #include <sys/param.h>
@@ -65,7 +65,7 @@
 void           efi_aprintuuid(const struct uuid *);
 bool           efi_uuideq(const struct uuid *, const struct uuid *);
 
-static bool efi_is32bit = false;
+static bool efi_is32x64 = false;
 static struct efi_systbl *efi_systbl_va = NULL;
 static struct efi_cfgtbl *efi_cfgtblhead_va = NULL;
 static struct efi_e820memmap {
@@ -158,7 +158,18 @@
        if (efi_cfgtblhead_va != NULL)
                return efi_cfgtblhead_va;
 
-       pa = (paddr_t)(u_long) efi_systbl_va->st_cfgtbl;
+       if (efi_is32x64) {
+#if defined(__amd64__)
+               struct efi_systbl32 *systbl32 = (void *) efi_systbl_va;
+               pa = systbl32->st_cfgtbl;
+#elif defined(__i386__)
+               struct efi_systbl64 *systbl64 = (void *) efi_systbl_va;
+               if (systbl64->st_cfgtbl & 0xffffffff00000000ULL)
+                       return NULL;
+               pa = (paddr_t) systbl64->st_cfgtbl;
+#endif
+       } else
+               pa = (paddr_t)(u_long) efi_systbl_va->st_cfgtbl;
        aprint_debug("efi: cfgtbl at pa %" PRIxPADDR "\n", pa);
        va = efi_getva(pa);
        aprint_debug("efi: cfgtbl mapped at va %" PRIxVADDR "\n", va);
@@ -175,7 +186,34 @@
 efi_aprintcfgtbl(void)
 {
        struct efi_cfgtbl *ct;
-       unsigned long   count;
+       unsigned long count;
+
+       if (efi_is32x64) {
+#if defined(__amd64__)
+               struct efi_systbl32 *systbl32 = (void *) efi_systbl_va;
+               struct efi_cfgtbl32 *ct32 = (void *) efi_cfgtblhead_va;
+
+               count = systbl32->st_entries;
+               aprint_debug("efi: %lu cfgtbl entries:\n", count);
+               for (; count; count--, ct32++) {
+                       aprint_debug("efi: %08" PRIx32, ct32->ct_data);
+                       efi_aprintuuid(&ct32->ct_uuid);
+                       aprint_debug("\n");
+               }
+#elif defined(__i386__)
+               struct efi_systbl64 *systbl64 = (void *) efi_systbl_va;
+               struct efi_cfgtbl64 *ct64 = (void *) efi_cfgtblhead_va;
+               uint64_t count64 = systbl64->st_entries;
+
+               aprint_debug("efi: %" PRIu64 " cfgtbl entries:\n", count64);
+               for (; count64; count64--, ct64++) {
+                       aprint_debug("efi: %016" PRIx64, ct64->ct_data);
+                       efi_aprintuuid(&ct64->ct_uuid);
+                       aprint_debug("\n");
+               }
+#endif
+               return;
+       }
 
        ct = efi_cfgtblhead_va;
        count = efi_systbl_va->st_entries;
@@ -195,7 +233,7 @@
 efi_getcfgtbl(const struct uuid * uuid)
 {
        paddr_t pa;
-       vaddr_t  va;
+       vaddr_t va;
 
        pa = efi_getcfgtblpa(uuid);
        if (pa == 0)
@@ -213,6 +251,28 @@
        struct efi_cfgtbl *ct;
        unsigned long count;
 
+       if (efi_is32x64) {
+#if defined(__amd64__)
+               struct efi_systbl32 *systbl32 = (void *) efi_systbl_va;
+               struct efi_cfgtbl32 *ct32 = (void *) efi_cfgtblhead_va;
+
+               count = systbl32->st_entries;
+               for (; count; count--, ct32++)
+                       if (efi_uuideq(&ct32->ct_uuid, uuid))
+                               return ct32->ct_data;
+#elif defined(__i386__)
+               struct efi_systbl64 *systbl64 = (void *) efi_systbl_va;
+               struct efi_cfgtbl64 *ct64 = (void *) efi_cfgtblhead_va;
+               uint64_t count64 = systbl64->st_entries;
+
+               for (; count64; count64--, ct64++)
+                       if (efi_uuideq(&ct64->ct_uuid, uuid))
+                               if (!(ct64->ct_data & 0xffffffff00000000ULL))
+                                       return ct64->ct_data;
+#endif
+               return 0;       /* Not found. */
+       }
+
        ct = efi_cfgtblhead_va;
        count = efi_systbl_va->st_entries;
        for (; count; count--, ct++)
@@ -234,15 +294,23 @@
                /* Unable to locate the EFI System Table. */
                return 0;
        }
+       if (sizeof(paddr_t) == 4 &&     /* XXX i386 with PAE */
+           (bi->systblpa & 0xffffffff00000000ULL)) {
+               /* Unable to access EFI System Table. */
+               return 0;
+       }
        if (bi->common.len > 16 && (bi->flags & BI_EFI_32BIT)) {
-               /* 32Bit UEFI */
-               if (sizeof(paddr_t) == 4 &&
-                   (bi->systblpa & 0xffffffff00000000ULL))
-                       /* Unable to access EFI System Table. */
-                       return 0;
-               efi_is32bit = true;
+               /* boot from 32bit UEFI */
+#if defined(__amd64__)
+               efi_is32x64 = true;
+#endif
+       } else {
+               /* boot from 64bit UEFI */
+#if defined(__i386__)
+               efi_is32x64 = true;
+#endif
        }
-       pa = (paddr_t)bi->systblpa;
+       pa = (paddr_t) bi->systblpa;
        return pa;
 }
 
@@ -253,34 +321,78 @@
 struct efi_systbl *
 efi_getsystbl(void)
 {
-       if (!efi_systbl_va) {
-               paddr_t         pa;
-               vaddr_t         va;
-               struct efi_systbl *systbl;
+       paddr_t pa;
+       vaddr_t va;
+       struct efi_systbl *systbl;
+
+       if (efi_systbl_va)
+               return efi_systbl_va;
 
-               pa = efi_getsystblpa();
-               if (pa == 0)
-                       return NULL;
-               aprint_normal("efi: systbl at pa %" PRIxPADDR "\n", pa);
-               va = efi_getva(pa);
-               aprint_debug("efi: systbl mapped at va %" PRIxVADDR "\n", va);
-               systbl = (struct efi_systbl *) va;
+       pa = efi_getsystblpa();
+       if (pa == 0)
+               return NULL;
+
+       aprint_normal("efi: systbl at pa %" PRIxPADDR "\n", pa);
+       va = efi_getva(pa);
+       aprint_debug("efi: systbl mapped at va %" PRIxVADDR "\n", va);
+
+       if (efi_is32x64) {
+#if defined(__amd64__)
+               struct efi_systbl32 *systbl32 = (struct efi_systbl32 *) va;
+
                /* XXX Check the signature and the CRC32 */
                aprint_debug("efi: signature %" PRIx64 " revision %" PRIx32
-                   " crc32 %" PRIx32 "\n", systbl->st_hdr.th_sig,
-                   systbl->st_hdr.th_rev, systbl->st_hdr.th_crc32);
+                   " crc32 %" PRIx32 "\n", systbl32->st_hdr.th_sig,
+                   systbl32->st_hdr.th_rev, systbl32->st_hdr.th_crc32);
                aprint_debug("efi: firmware revision %" PRIx32 "\n",
-                   systbl->st_fwrev);
+                   systbl32->st_fwrev);
                /*
                 * XXX Also print fwvendor, which is an UCS-2 string (use
                 * some UTF-16 routine?)
                 */
-               aprint_debug("efi: runtime services at pa %p\n",
-                   systbl->st_rt);
-               aprint_debug("efi: boot services at pa %p\n",
-                   systbl->st_bs);
-               efi_systbl_va = systbl;
+               aprint_debug("efi: runtime services at pa 0x%08" PRIx32 "\n",
+                   systbl32->st_rt);
+               aprint_debug("efi: boot services at pa 0x%08" PRIx32 "\n",
+                   systbl32->st_bs);
+
+               efi_systbl_va = (struct efi_systbl *) systbl32;
+#elif defined(__i386__)
+               struct efi_systbl64 *systbl64 = (struct efi_systbl64 *) va;
+
+               /* XXX Check the signature and the CRC32 */



Home | Main Index | Thread Index | Old Index