aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/dmi_scan.c
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@novell.com>2011-06-28 09:19:35 +0100
committerJan Beulich <jbeulich@novell.com>2011-06-28 09:19:35 +0100
commitbf6501a62e80ec1cf756290d4c3ec4991455f64e (patch)
treefdd62100f57c6cd816e1f7cef369ced44f991027 /xen/arch/x86/dmi_scan.c
parentf402de45cd8b93cc41fff6f0666b1cdd3d765909 (diff)
downloadxen-bf6501a62e80ec1cf756290d4c3ec4991455f64e.tar.gz
xen-bf6501a62e80ec1cf756290d4c3ec4991455f64e.tar.bz2
xen-bf6501a62e80ec1cf756290d4c3ec4991455f64e.zip
x86-64: EFI boot code
Besides introducing the relevant code paralleling parts of what is under xen/arch/x86/boot/, this adjusts the build logic so that with a single compilation two images (gzip-compressed ELF and EFI application) can get created. The EFI part of this depends on a new enough compiler (supposedly gcc 4.4.x and above, but so far only tested to work with 4.5.x) and a properly configured linker (must support the i386pep emulation). If either functionality is found to not be available, the EFI part of the build will simply be skipped. The patch adds all code to allow Xen and the (accordingly enabled) Dom0 kernel to boot, but doesn't allow Dom0 to make use of EFI runtime calls (this will be the subject of the next patch). Parts of the code were lifted from an earlier never published OS project of ours - whether respective license information needs to be added to the respective source file is unclear to me (I was told internally that adding a GPLv2 license header can be done if needed by the community). Open issues (not preventing this from being committed imo): The trampoline allocation and initialization isn't really nice. This is due to the trampoline needing to be placed at a fixed address, and hence making the trampoline relocatable would seem desirable here (as well as for BIOS-based booting, where the trampoline location needed to be adjusted a number of time already in the past, due to it colliding with firmware data). By excluding mem.S, edd.S, and video.S from copied trampoline (i.e. moving up wakeup.S? and making sure none of the symbols are used from EFI code), the effective trampoline size could at least be reduced. Should the mappings of [__XEN_VIRT_START, mbi.mem_upper) and [_end, __XEN_VIRT_START+BOOTSTRAP_MAP_BASE) be destroyed, despite non-EFI code also keeping them? Signed-off-by: Jan Beulich <jbeulich@novell.com>
Diffstat (limited to 'xen/arch/x86/dmi_scan.c')
-rw-r--r--xen/arch/x86/dmi_scan.c66
1 files changed, 64 insertions, 2 deletions
diff --git a/xen/arch/x86/dmi_scan.c b/xen/arch/x86/dmi_scan.c
index f73a9a4c52..75b3507ac9 100644
--- a/xen/arch/x86/dmi_scan.c
+++ b/xen/arch/x86/dmi_scan.c
@@ -9,6 +9,7 @@
#include <asm/io.h>
#include <asm/system.h>
#include <xen/dmi.h>
+#include <xen/efi.h>
#define bt_ioremap(b,l) ((void *)__acpi_map_table(b,l))
#define bt_iounmap(b,l) ((void)0)
@@ -122,11 +123,39 @@ static inline bool_t __init dmi_checksum(const void __iomem *buf,
return sum == 0;
}
+static u32 __initdata efi_dmi_address;
+static u32 __initdata efi_dmi_size;
+
+/*
+ * Important: This function gets called while still in EFI
+ * (pseudo-)physical mode.
+ */
+void __init dmi_efi_get_table(void *smbios)
+{
+ struct smbios_eps *eps = smbios;
+
+ if (memcmp(eps->anchor, "_SM_", 4) &&
+ dmi_checksum(eps, eps->length) &&
+ memcmp(eps->dmi.anchor, "_DMI_", 5) == 0 &&
+ dmi_checksum(&eps->dmi, sizeof(eps->dmi))) {
+ efi_dmi_address = eps->dmi.address;
+ efi_dmi_size = eps->dmi.size;
+ }
+}
+
int __init dmi_get_table(u32 *base, u32 *len)
{
struct dmi_eps eps;
char __iomem *p, *q;
+ if (efi_enabled) {
+ if (!efi_dmi_size)
+ return -1;
+ *base = efi_dmi_address;
+ *len = efi_dmi_size;
+ return 0;
+ }
+
p = maddr_to_virt(0xF0000);
for (q = p; q < p + 0x10000; q += 16) {
memcpy_fromio(&eps, q, 15);
@@ -178,6 +207,39 @@ static int __init dmi_iterate(void (*decode)(struct dmi_header *))
return -1;
}
+static int __init dmi_efi_iterate(void (*decode)(struct dmi_header *))
+{
+ struct smbios_eps eps;
+ const struct smbios_eps __iomem *p;
+ int ret = -1;
+
+ if (efi.smbios == EFI_INVALID_TABLE_ADDR)
+ return -1;
+
+ p = bt_ioremap(efi.smbios, sizeof(eps));
+ if (!p)
+ return -1;
+ memcpy_fromio(&eps, p, sizeof(eps));
+ bt_iounmap(p, sizeof(eps));
+
+ if (memcmp(eps.anchor, "_SM_", 4))
+ return -1;
+
+ p = bt_ioremap(efi.smbios, eps.length);
+ if (!p)
+ return -1;
+ if (dmi_checksum(p, eps.length) &&
+ memcmp(eps.dmi.anchor, "_DMI_", 5) == 0 &&
+ dmi_checksum(&eps.dmi, sizeof(eps.dmi))) {
+ printk(KERN_INFO "SMBIOS %d.%d present.\n",
+ eps.major, eps.minor);
+ ret = _dmi_iterate(&eps.dmi, p, decode);
+ }
+ bt_iounmap(p, eps.length);
+
+ return ret;
+}
+
static char *__initdata dmi_ident[DMI_STRING_MAX];
/*
@@ -418,8 +480,8 @@ static void __init dmi_decode(struct dmi_header *dm)
void __init dmi_scan_machine(void)
{
- int err = dmi_iterate(dmi_decode);
- if(err == 0)
+ if ((!efi_enabled ? dmi_iterate(dmi_decode) :
+ dmi_efi_iterate(dmi_decode)) == 0)
dmi_check_system(dmi_blacklist);
else
printk(KERN_INFO "DMI not present.\n");