Avoid panic when amd64 kernel is booted from 32bit UEFI.
This commit is contained in:
parent
148f109aa3
commit
fcf5cd9bd4
|
@ -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 @@ enum efi_reset {
|
|||
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_systbl {
|
|||
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);
|
||||
|
|
|
@ -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_aprintcfgtbl(void);
|
|||
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 @@ efi_getcfgtblhead(void)
|
|||
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 @@ void
|
|||
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 @@ void *
|
|||
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 @@ efi_getcfgtblpa(const struct uuid * uuid)
|
|||
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 @@ efi_getsystblpa(void)
|
|||
/* Unable to locate the 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;
|
||||
if (sizeof(paddr_t) == 4 && /* XXX i386 with PAE */
|
||||
(bi->systblpa & 0xffffffff00000000ULL)) {
|
||||
/* Unable to access EFI System Table. */
|
||||
return 0;
|
||||
}
|
||||
pa = (paddr_t)bi->systblpa;
|
||||
if (bi->common.len > 16 && (bi->flags & BI_EFI_32BIT)) {
|
||||
/* 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;
|
||||
return pa;
|
||||
}
|
||||
|
||||
|
@ -253,34 +321,78 @@ efi_getsystblpa(void)
|
|||
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);
|
||||
|
||||
if (efi_is32x64) {
|
||||
#if defined(__amd64__)
|
||||
struct efi_systbl32 *systbl32 = (struct efi_systbl32 *) 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;
|
||||
/* 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 */
|
||||
aprint_debug("efi: signature %" PRIx64 " revision %" PRIx32
|
||||
" crc32 %" PRIx32 "\n", systbl64->st_hdr.th_sig,
|
||||
systbl64->st_hdr.th_rev, systbl64->st_hdr.th_crc32);
|
||||
aprint_debug("efi: firmware revision %" PRIx32 "\n",
|
||||
systbl64->st_fwrev);
|
||||
/*
|
||||
* XXX Also print fwvendor, which is an UCS-2 string (use
|
||||
* some UTF-16 routine?)
|
||||
*/
|
||||
aprint_debug("efi: runtime services at pa 0x%016" PRIx64 "\n",
|
||||
systbl64->st_rt);
|
||||
aprint_debug("efi: boot services at pa 0x%016" PRIx64 "\n",
|
||||
systbl64->st_bs);
|
||||
|
||||
efi_systbl_va = (struct efi_systbl *) systbl64;
|
||||
#endif
|
||||
return efi_systbl_va;
|
||||
}
|
||||
|
||||
systbl = (struct efi_systbl *) 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);
|
||||
aprint_debug("efi: firmware revision %" PRIx32 "\n", systbl->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;
|
||||
return efi_systbl_va;
|
||||
}
|
||||
|
||||
|
@ -290,11 +402,11 @@ efi_getsystbl(void)
|
|||
bool
|
||||
efi_probe(void)
|
||||
{
|
||||
if (efi_getsystbl() == 0) {
|
||||
if (efi_getsystbl() == NULL) {
|
||||
aprint_debug("efi: missing or invalid systbl\n");
|
||||
return false;
|
||||
}
|
||||
if (efi_getcfgtblhead() == 0) {
|
||||
if (efi_getcfgtblhead() == NULL) {
|
||||
aprint_debug("efi: missing or invalid cfgtbl\n");
|
||||
efi_relva((vaddr_t) efi_systbl_va);
|
||||
return false;
|
||||
|
|
Loading…
Reference in New Issue