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