Commit 08c38d20 authored by Mike Hibler's avatar Mike Hibler
Browse files

Set kFreeBSD vars for EFI-related hints that FreeBSD kernel expects.

parent 6f4d886d
......@@ -38,6 +38,7 @@
#ifdef GRUB_MACHINE_PCBIOS
#include <grub/machine/int.h>
#endif
#include <grub/acpi.h>
GRUB_MOD_LICENSE ("GPLv3+");
......@@ -365,6 +366,59 @@ generate_e820_mmap (grub_size_t *len, grub_size_t *cnt, void *buf)
return;
}
#ifdef GRUB_MACHINE_EFI
/*
* Read the EFI memory map and package it up with the expected header.
* This semi-mimics the boot/amd64/efi/bootinfo.c code.
*/
static void
generate_efi_mmap (void **bufp, grub_size_t *lenp)
{
void *buf;
int ret, hdr_size;
grub_efi_memory_descriptor_t *mmap;
grub_efi_uintn_t mmap_size, desc_size;
grub_efi_uint32_t desc_vers;
struct grub_freebsd_efi_map_header *hdr;
*bufp = NULL;
hdr_size = (sizeof(*hdr) + 0xf) & ~0xf;
/* Find out how big the map is. Start by assuming one page - header size. */
mmap_size = (1 << 12);
again:
buf = grub_malloc (mmap_size);
if (! buf)
return;
mmap = (grub_efi_memory_descriptor_t *)((grub_uint8_t *)buf + hdr_size);
mmap_size -= hdr_size;
ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, &desc_vers);
if (ret < 0)
{
grub_error (GRUB_ERR_IO, "cannot get memory map");
return;
}
if (ret == 0)
{
/* Not enough space, one page beyond what it says should be enough */
grub_free (buf);
mmap_size += hdr_size + (1 << 12);
goto again;
}
/* Got it! Fill out the header and return */
hdr = buf;
hdr->memory_size = mmap_size;
hdr->descriptor_size = desc_size;
hdr->descriptor_version = desc_vers;
*bufp = buf;
*lenp = hdr_size + mmap_size;
}
#endif
static grub_err_t
grub_bsd_add_mmap (void)
{
......@@ -402,9 +456,19 @@ grub_bsd_add_mmap (void)
else if (kernel_type == KERNEL_TYPE_OPENBSD)
grub_bsd_add_meta (OPENBSD_BOOTARG_MMAP, buf0, len);
else
grub_bsd_add_meta (FREEBSD_MODINFO_METADATA |
FREEBSD_MODINFOMD_SMAP, buf0, len);
{
grub_bsd_add_meta (FREEBSD_MODINFO_METADATA |
FREEBSD_MODINFOMD_SMAP, buf0, len);
#ifdef GRUB_MACHINE_EFI
generate_efi_mmap(&buf, &len);
if (buf)
{
grub_bsd_add_meta (FREEBSD_MODINFO_METADATA |
FREEBSD_MODINFOMD_EFI_MAP, buf, len);
grub_free (buf);
}
#endif
}
grub_free (buf0);
return grub_errno;
......@@ -585,6 +649,62 @@ freebsd_get_zfs (void)
grub_free (uuid);
}
/*
* Configure some kFreeBSD.* hints with ACPI info
*/
static void
grub_freebsd_acpi_info (void)
{
#ifdef GRUB_MACHINE_EFI
struct grub_acpi_rsdp_v10 *rsdp;
struct grub_acpi_rsdp_v20 *rsdp2;
char buf[24];
int revision;
/* FreeBSD stashes ACPI info for the kernel. They do it only for 64-bit
ELF EFI loads, so that is the only time we do it too! */
if (is_elf_kernel && is_64bit)
{
rsdp2 = grub_machine_acpi_get_rsdpv2 ();
if (! rsdp2)
{
rsdp = grub_machine_acpi_get_rsdpv1 ();
}
else
{
rsdp = &rsdp2->rsdpv1;
}
if (rsdp)
{
grub_snprintf(buf, sizeof(buf), "0x%016llx",
(unsigned long long)rsdp);
grub_env_set("kFreeBSD.hint.acpi.0.rsdp", buf);
revision = rsdp->revision;
if (revision == 0)
revision = 1;
grub_snprintf(buf, sizeof(buf), "%d", revision);
grub_env_set("kFreeBSD.hint.acpi.0.revision", buf);
grub_strncpy(buf, (char *)rsdp->oemid, sizeof(rsdp->oemid));
buf[sizeof(rsdp->oemid)] = '\0';
grub_env_set("kFreeBSD.hint.acpi.0.oem", buf);
grub_snprintf(buf, sizeof(buf), "0x%016x", rsdp->rsdt_addr);
grub_env_set("kFreeBSD.hint.acpi.0.rsdt", buf);
if (revision >= 2)
{
/* XXX extended checksum? */
grub_snprintf(buf, sizeof(buf), "0x%016llx",
(unsigned long long)rsdp2->xsdt_addr);
grub_env_set("kFreeBSD.hint.acpi.0.xsdt", buf);
grub_snprintf(buf, sizeof(buf), "%d", rsdp2->length);
grub_env_set("kFreeBSD.hint.acpi.0.xsdt_length", buf);
}
grub_dprintf ("bsd", "Loaded ACPI hints from 0x%llx\n",
(unsigned long long)rsdp);
}
}
#endif
}
static grub_err_t
grub_freebsd_boot (void)
{
......@@ -603,6 +723,9 @@ grub_freebsd_boot (void)
bi.boot_device = freebsd_biosdev;
/* Load up acpi info for kernel */
grub_freebsd_acpi_info ();
p_size = 0;
FOR_SORTED_ENV (var)
if ((grub_memcmp (var->name, "kFreeBSD.", sizeof("kFreeBSD.") - 1) == 0) && (var->name[sizeof("kFreeBSD.") - 1]))
......
......@@ -68,7 +68,15 @@
#define FREEBSD_MODINFOMD_NOCOPY 0x8000 /* don't copy this metadata to the kernel */
#define FREEBSD_MODINFOMD_SMAP 0x1001
#define FREEBSD_MODINFOMD_EFI_MAP 0x1004
#define FREEBSD_MODINFOMD_DEPLIST (0x4001 | FREEBSD_MODINFOMD_NOCOPY) /* depends on */
/* XXX first two should be size_t, but this header is for amd64 only */
struct grub_freebsd_efi_map_header
{
grub_uint64_t memory_size;
grub_uint64_t descriptor_size;
grub_uint32_t descriptor_version;
};
#endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment