[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v2 2/4] loader/bsd: Improve loading of *BSD on EFI platforms
From: |
Vladimir Serbinenko |
Subject: |
[PATCH v2 2/4] loader/bsd: Improve loading of *BSD on EFI platforms |
Date: |
Fri, 17 May 2024 10:45:38 +0300 |
Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
---
grub-core/loader/i386/bsd.c | 515 +++++++++++++++++++++++-----
include/grub/i386/freebsd_linker.h | 39 +++
include/grub/i386/netbsd_bootinfo.h | 12 +-
include/grub/i386/openbsd_bootarg.h | 24 ++
4 files changed, 495 insertions(+), 95 deletions(-)
diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c
index 1f9128f6f..58b976861 100644
--- a/grub-core/loader/i386/bsd.c
+++ b/grub-core/loader/i386/bsd.c
@@ -40,6 +40,8 @@
#ifdef GRUB_MACHINE_PCBIOS
#include <grub/machine/int.h>
#endif
+#include <grub/acpi.h>
+#include <grub/smbios.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -48,10 +50,11 @@ GRUB_MOD_LICENSE ("GPLv3+");
#include <grub/machine/biosnum.h>
#endif
#ifdef GRUB_MACHINE_EFI
+#include <grub/coreboot/lbio.h>
#include <grub/efi/efi.h>
-#define NETBSD_DEFAULT_VIDEO_MODE "800x600"
+#define BSD_DEFAULT_VIDEO_MODE "800x600"
#else
-#define NETBSD_DEFAULT_VIDEO_MODE "text"
+#define BSD_DEFAULT_VIDEO_MODE "text"
#include <grub/i386/pc/vbe.h>
#endif
#include <grub/video.h>
@@ -76,6 +79,11 @@ static int is_elf_kernel, is_64bit;
static grub_uint32_t openbsd_root;
static struct grub_relocator *relocator = NULL;
static struct grub_openbsd_ramdisk_descriptor openbsd_ramdisk;
+#ifdef GRUB_MACHINE_EFI
+static struct grub_openbsd_bootarg_efiinfo openbsd_efi_info;
+#endif
+
+static grub_err_t grub_bsd_setup_video (void);
struct bsd_tag
{
@@ -219,7 +227,7 @@ grub_bsd_get_device (grub_uint32_t * biosdev,
}
static grub_err_t
-grub_bsd_add_meta_ptr (grub_uint32_t type, void **ptr, grub_uint32_t len)
+grub_bsd_add_meta_ptr (grub_uint32_t type, void **ptr, grub_uint32_t len, int
is_kernel_tag)
{
struct bsd_tag *newtag;
@@ -231,8 +239,7 @@ grub_bsd_add_meta_ptr (grub_uint32_t type, void **ptr,
grub_uint32_t len)
newtag->next = NULL;
*ptr = newtag->data;
- if (kernel_type == KERNEL_TYPE_FREEBSD
- && type == (FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_SMAP))
+ if (kernel_type == KERNEL_TYPE_FREEBSD && is_kernel_tag)
{
struct bsd_tag *p;
for (p = tags;
@@ -259,20 +266,34 @@ grub_bsd_add_meta_ptr (grub_uint32_t type, void **ptr,
grub_uint32_t len)
return GRUB_ERR_NONE;
}
-grub_err_t
-grub_bsd_add_meta (grub_uint32_t type, const void *data, grub_uint32_t len)
+static grub_err_t
+grub_bsd_add_meta_real (grub_uint32_t type, const void *data, grub_uint32_t
len, int is_kernel_tag)
{
grub_err_t err;
void *ptr = NULL;
- err = grub_bsd_add_meta_ptr (type, &ptr, len);
+ err = grub_bsd_add_meta_ptr (type, &ptr, len, is_kernel_tag);
if (err)
return err;
- if (len)
+ if (data && len)
grub_memcpy (ptr, data, len);
+ else if (!data && len)
+ grub_memset (ptr, 0, len);
+
return GRUB_ERR_NONE;
}
+static grub_err_t
+grub_bsd_add_kernel_meta (grub_uint32_t type, const void *data, grub_uint32_t
len)
+{
+ return grub_bsd_add_meta_real (type, data, len, 1);
+}
+
+grub_err_t
+grub_bsd_add_meta (grub_uint32_t type, const void *data, grub_uint32_t len)
+{
+ return grub_bsd_add_meta_real (type, data, len, 0);
+}
struct grub_e820_mmap
{
@@ -404,8 +425,8 @@ 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_kernel_meta (FREEBSD_MODINFO_METADATA |
+ FREEBSD_MODINFOMD_SMAP, buf0, len);
grub_free (buf0);
@@ -462,7 +483,7 @@ grub_freebsd_add_meta_module (const char *filename, const
char *type,
void *cmdline;
char *p;
- if (grub_bsd_add_meta_ptr (FREEBSD_MODINFO_ARGS, &cmdline, n))
+ if (grub_bsd_add_meta_ptr (FREEBSD_MODINFO_ARGS, &cmdline, n, 0))
return grub_errno;
p = cmdline;
@@ -592,6 +613,80 @@ freebsd_get_zfs (void)
grub_free (uuid);
}
+#ifdef GRUB_MACHINE_EFI
+
+#define NEXT_MEMORY_DESCRIPTOR(desc, size) \
+ ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size)))
+
+static void
+grub_swap_buffers(void *a, void *b, grub_size_t n)
+{
+ grub_uint8_t *ap = a, *bp = b;
+ for (; n; n--, ap++, bp++)
+ {
+ grub_uint8_t t = *ap;
+ *ap = *bp;
+ *bp = t;
+ }
+}
+
+static void
+grub_efi_sort_memory_map(void *buf, grub_efi_uintn_t desc_size,
grub_efi_uintn_t mmap_size)
+{
+ int done_any = 1;
+
+ while (done_any)
+ {
+ grub_efi_memory_descriptor_t *d_cur = buf;
+ grub_efi_memory_descriptor_t *d_next = NEXT_MEMORY_DESCRIPTOR(d_cur,
desc_size);
+
+ done_any = 0;
+ for (; d_next < NEXT_MEMORY_DESCRIPTOR(buf, mmap_size);
+ d_cur = d_next, d_next = NEXT_MEMORY_DESCRIPTOR(d_cur, desc_size))
+ {
+ if (d_next->physical_start < d_cur->physical_start)
+ {
+ done_any = 1;
+ grub_swap_buffers(d_cur, d_next, desc_size);
+ }
+ }
+ }
+}
+
+static int
+iterate_get_zerotables_size (grub_linuxbios_table_item_t table_item, void
*data)
+{
+ grub_uint64_t *ret = data;
+ mem_region_t mem_region;
+
+ if (table_item->tag != GRUB_LINUXBIOS_MEMBER_MEMORY)
+ return 0;
+
+ mem_region =
+ (mem_region_t) ((long) table_item +
+ sizeof (struct grub_linuxbios_table_item));
+ for (; (long) mem_region < (long) table_item + (long) table_item->size;
+ mem_region++)
+ {
+ if (mem_region->type == GRUB_MEMORY_COREBOOT_TABLES
+ && mem_region->addr == 0 && *ret < mem_region->addr +
mem_region->size)
+ *ret = mem_region->addr + mem_region->size;
+ }
+
+ return 0;
+}
+
+static grub_uint64_t
+grub_coreboot_get_zerotables_size(void)
+{
+ grub_uint64_t ret = 0;
+
+ grub_linuxbios_table_iterate (iterate_get_zerotables_size, &ret);
+
+ return ret;
+}
+#endif
+
static grub_err_t
grub_freebsd_boot (void)
{
@@ -604,6 +699,34 @@ grub_freebsd_boot (void)
struct grub_env_var *var;
+ err = grub_bsd_setup_video ();
+ if (err)
+ {
+ grub_print_error ();
+ grub_puts_ (N_("Booting in blind mode"));
+ grub_errno = GRUB_ERR_NONE;
+ }
+
+#ifdef GRUB_MACHINE_EFI
+ err = grub_bsd_add_kernel_meta (FREEBSD_MODINFO_METADATA |
+ FREEBSD_MODINFOMD_FW_HANDLE,
+ &grub_efi_system_table,
+ sizeof (grub_efi_system_table));
+ if (err)
+ return err;
+
+ grub_uint32_t efi_mmap_size = 0;
+
+ efi_mmap_size = 2 * grub_efi_find_mmap_size ();
+
+ err = grub_bsd_add_kernel_meta (FREEBSD_MODINFO_METADATA |
FREEBSD_MODINFOMD_EFI_MAP ,
+ NULL,
+ sizeof(struct
grub_freebsd_btinfo_efi_map_header)
+ + efi_mmap_size);
+ if (err)
+ return err;
+#endif
+
grub_memset (&bi, 0, sizeof (bi));
bi.version = FREEBSD_BOOTINFO_VERSION;
bi.length = sizeof (bi);
@@ -619,6 +742,30 @@ grub_freebsd_boot (void)
p_size += grub_strlen (var->value) + 1;
}
+ grub_addr_t rsdp = (grub_addr_t) grub_acpi_get_rsdpv2() ?: (grub_addr_t)
grub_acpi_get_rsdpv1();
+ grub_addr_t smbios = (grub_addr_t) grub_smbios_get_eps3() ?: (grub_addr_t)
grub_smbios_get_eps();
+ char rsdp_buf[sizeof("acpi.rsdp=") + 22];
+ char hint_rsdp_buf[sizeof("hint.acpi.0.rsdp=") + 22];
+ char smbios_buf[sizeof("hint.smbios.0.mem=") + 22];
+
+ grub_memset (rsdp_buf, 0, sizeof(rsdp_buf));
+ grub_memset (hint_rsdp_buf, 0, sizeof(hint_rsdp_buf));
+ grub_memset (smbios_buf, 0, sizeof(smbios_buf));
+ if (rsdp)
+ {
+ grub_snprintf(rsdp_buf, sizeof(rsdp_buf) - 2, "acpi.rsdp=0x%llx",
(unsigned long long) rsdp);
+ p_size += grub_strlen (rsdp_buf) + 1;
+ // pre-10 FreeBSD
+ grub_snprintf(hint_rsdp_buf, sizeof(hint_rsdp_buf) - 2,
"hint.acpi.0.rsdp=0x%llx", (unsigned long long) rsdp);
+ p_size += grub_strlen (hint_rsdp_buf) + 1;
+ }
+
+ if (smbios)
+ {
+ grub_snprintf(smbios_buf, sizeof(smbios_buf) - 2,
"hint.smbios.0.mem=0x%llx", (unsigned long long) smbios);
+ p_size += grub_strlen (smbios_buf) + 1;
+ }
+
if (p_size)
p_size = ALIGN_PAGE (kern_end + p_size + 1) - kern_end;
@@ -660,13 +807,26 @@ grub_freebsd_boot (void)
FOR_SORTED_ENV (var)
if ((grub_memcmp (var->name, "kFreeBSD.", sizeof("kFreeBSD.") - 1) == 0)
&& (var->name[sizeof("kFreeBSD.") - 1]))
{
- grub_strcpy ((char *) p, &var->name[sizeof("kFreeBSD.") - 1]);
- p += grub_strlen ((char *) p);
- *(p++) = '=';
- grub_strcpy ((char *) p, var->value);
- p += grub_strlen ((char *) p) + 1;
+ p = (grub_uint8_t *) grub_stpcpy ((char *) p,
&var->name[sizeof("kFreeBSD.") - 1]);
+ *p++ = '=';
+ p = (grub_uint8_t *) grub_stpcpy ((char *) p, var->value);
+ *p++ = '\0';
}
+ if (rsdp)
+ {
+ p = (grub_uint8_t *) grub_stpcpy ((char *) p, rsdp_buf);
+ *p++ = '\0';
+ p = (grub_uint8_t *) grub_stpcpy ((char *) p, hint_rsdp_buf);
+ *p++ = '\0';
+ }
+
+ if (smbios)
+ {
+ p = (grub_uint8_t *) grub_stpcpy ((char *) p, smbios_buf);
+ *p++ = '\0';
+ }
+
if (p != p0)
{
*(p++) = 0;
@@ -674,6 +834,9 @@ grub_freebsd_boot (void)
bi.environment = p_target;
}
+ struct freebsd_tag_header *efi_memmap = 0;
+ grub_uint8_t *p_tag_start = p, *p_tag_end = p;
+
if (is_elf_kernel)
{
grub_uint8_t *p_tag = p;
@@ -683,6 +846,8 @@ grub_freebsd_boot (void)
{
struct freebsd_tag_header *head
= (struct freebsd_tag_header *) p_tag;
+ if (tag->type == (FREEBSD_MODINFOMD_EFI_MAP |
FREEBSD_MODINFO_METADATA))
+ efi_memmap = head;
head->type = tag->type;
head->len = tag->len;
p_tag += sizeof (struct freebsd_tag_header);
@@ -714,46 +879,77 @@ grub_freebsd_boot (void)
break;
}
p_tag += tag->len;
- p_tag = ALIGN_VAR (p_tag - p) + p;
+ p_tag = ALIGN_VAR (p_tag - p_tag_start) + p_tag_start;
}
- bi.tags = (p - p0) + p_target;
+ p_tag_end = p_tag;
+ bi.tags = (p_tag_start - p0) + p_target;
p = (ALIGN_PAGE ((p_tag - p0) + p_target) - p_target) + p0;
}
bi.kern_end = kern_end;
- grub_video_set_mode ("text", 0, 0);
+ grub_addr_t stack_target;
+ grub_uint32_t *stack;
+ grub_relocator_chunk_t ch;
- if (is_64bit)
- {
- struct grub_relocator64_state state = {0};
- grub_uint8_t *pagetable;
- grub_uint32_t *stack;
- grub_addr_t stack_target;
+ err = grub_relocator_alloc_chunk_align (relocator, &ch,
+ 0x10000, 0x90000,
+ (is_64bit ? 3 : 9) * sizeof
(grub_uint32_t)
+ + sizeof (bi), 4,
+ GRUB_RELOCATOR_PREFERENCE_NONE,
+ 0);
- {
- grub_relocator_chunk_t ch;
- err = grub_relocator_alloc_chunk_align (relocator, &ch,
- 0x10000, 0x90000,
- 3 * sizeof (grub_uint32_t)
- + sizeof (bi), 4,
- GRUB_RELOCATOR_PREFERENCE_NONE,
- 0);
- if (err)
- return err;
- stack = get_virtual_current_address (ch);
- stack_target = get_physical_target_address (ch);
- }
+ if (err)
+ return err;
+ stack = get_virtual_current_address (ch);
+ stack_target = get_physical_target_address (ch);
#ifdef GRUB_MACHINE_EFI
- err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL);
- if (err)
- return err;
+ grub_efi_uintn_t efi_mmap_size_out = efi_mmap_size;
+ grub_efi_uintn_t efi_desc_size;
+ grub_efi_uint32_t efi_desc_version;
+ struct grub_freebsd_btinfo_efi_map_header *efi_mmap = (struct
grub_freebsd_btinfo_efi_map_header *) (efi_memmap + 1);
+ grub_efi_memory_descriptor_t *efidescs = (grub_efi_memory_descriptor_t *)
(efi_memmap ? efi_mmap + 1 : 0);
+
+ err = grub_efi_finish_boot_services (&efi_mmap_size_out, efidescs, NULL,
&efi_desc_size, &efi_desc_version);
+ if (err)
+ return err;
+
+ if (efi_memmap)
+ {
+ /* DragonFlyBSD needs them sorted. */
+ grub_efi_sort_memory_map(efidescs, efi_desc_size, efi_mmap_size_out);
+ /* Nowadays the tables at 0 don't contain anything important but
+ DragonFlyBSD needs the memory at 0 for own needs.
+ */
+ if (efi_mmap_size_out >= sizeof(grub_efi_memory_descriptor_t) &&
efidescs->physical_start == 0
+ && efidescs->type == GRUB_EFI_RESERVED_MEMORY_TYPE &&
efidescs->num_pages <= (grub_coreboot_get_zerotables_size() >>
GRUB_EFI_PAGE_SHIFT))
+ {
+ efidescs->type = GRUB_EFI_CONVENTIONAL_MEMORY;
+ }
+ grub_size_t newlen = sizeof(struct grub_freebsd_btinfo_efi_map_header) +
efi_mmap_size_out;
+ grub_uint8_t *old_next_tag = ALIGN_VAR ((grub_uint8_t *) efi_mmap +
efi_memmap->len - p_tag_start) + p_tag_start;
+ grub_uint8_t *new_next_tag = ALIGN_VAR ((grub_uint8_t *) efi_mmap +
newlen - p_tag_start) + p_tag_start;
+ efi_memmap->len = newlen;
+ if (new_next_tag != old_next_tag)
+ grub_memmove(new_next_tag, old_next_tag, p_tag_end - old_next_tag);
+ p_tag_end += (new_next_tag - old_next_tag);
+ efi_mmap->descriptor_version = efi_desc_version;
+ efi_mmap->descriptor_size = efi_desc_size;
+ efi_mmap->memory_size = efi_mmap_size_out;
+ }
+#else
+ (void) efi_memmap;
+ (void) p_tag_end;
#endif
- pagetable = p;
+ if (is_64bit)
+ {
+ struct grub_relocator64_state state = {0};
+ grub_uint8_t *pagetable = p;
+
fill_bsd64_pagetable (pagetable, (pagetable - p0) + p_target);
state.cr3 = (pagetable - p0) + p_target;
@@ -768,28 +964,6 @@ grub_freebsd_boot (void)
else
{
struct grub_relocator32_state state = {0};
- grub_uint32_t *stack;
- grub_addr_t stack_target;
-
- {
- grub_relocator_chunk_t ch;
- err = grub_relocator_alloc_chunk_align (relocator, &ch,
- 0x10000, 0x90000,
- 9 * sizeof (grub_uint32_t)
- + sizeof (bi), 4,
- GRUB_RELOCATOR_PREFERENCE_NONE,
- 0);
- if (err)
- return err;
- stack = get_virtual_current_address (ch);
- stack_target = get_physical_target_address (ch);
- }
-
-#ifdef GRUB_MACHINE_EFI
- err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL);
- if (err)
- return err;
-#endif
grub_memcpy (&stack[9], &bi, sizeof (bi));
state.eip = entry;
@@ -825,6 +999,31 @@ grub_openbsd_boot (void)
if (err)
return err;
+#ifdef GRUB_MACHINE_EFI
+ grub_memset(&openbsd_efi_info, 0, sizeof(openbsd_efi_info));
+
+ err = grub_bsd_setup_video ();
+ if (err)
+ {
+ grub_print_error ();
+ grub_puts_ (N_("Booting in blind mode"));
+ grub_errno = GRUB_ERR_NONE;
+ }
+
+ openbsd_efi_info.config_acpi = (grub_addr_t) grub_acpi_get_rsdpv2() ?:
(grub_addr_t) grub_acpi_get_rsdpv1();
+ openbsd_efi_info.config_smbios = (grub_addr_t) grub_smbios_get_eps();
+ openbsd_efi_info.system_table = (grub_addr_t) grub_efi_system_table;
+
+#ifdef __amd64__
+ openbsd_efi_info.flags |= GRUB_OPENBSD_BOOTARG_EFI_64BIT;
+#endif
+
+ err = grub_bsd_add_meta (OPENBSD_BOOTARG_EFIINFO, &openbsd_efi_info,
+ sizeof(openbsd_efi_info));
+ if (err)
+ return err;
+#endif
+
#ifdef GRUB_MACHINE_PCBIOS
{
struct grub_bios_int_registers regs;
@@ -864,10 +1063,17 @@ grub_openbsd_boot (void)
}
buf_target = GRUB_BSD_TEMP_BUFFER - 9 * sizeof (grub_uint32_t);
+
+ grub_uint32_t efi_mmap_size = 0;
+
+#ifdef GRUB_MACHINE_EFI
+ efi_mmap_size = 2 * grub_efi_find_mmap_size ();
+#endif
+
{
grub_relocator_chunk_t ch;
err = grub_relocator_alloc_chunk_addr (relocator, &ch, buf_target,
- tag_buf_len
+ tag_buf_len + efi_mmap_size
+ sizeof (struct
grub_openbsd_bootargs)
+ 9 * sizeof (grub_uint32_t));
if (err)
@@ -876,7 +1082,10 @@ grub_openbsd_boot (void)
}
stack = (grub_uint32_t *) buf0;
- arg0 = curarg = stack + 9;
+ void *efi_mmap_buf = stack + 9;
+ arg0 = curarg = (grub_uint8_t *) efi_mmap_buf + efi_mmap_size;
+
+ struct grub_openbsd_bootarg_efiinfo *openbsd_efi_info_ptr = 0;
{
struct bsd_tag *tag;
@@ -889,6 +1098,8 @@ grub_openbsd_boot (void)
head->ba_size = tag->len + sizeof (*head);
curarg = head + 1;
grub_memcpy (curarg, tag->data, tag->len);
+ if (tag->type == OPENBSD_BOOTARG_EFIINFO)
+ openbsd_efi_info_ptr = curarg;
curarg = (grub_uint8_t *) curarg + tag->len;
head->ba_next = (grub_uint8_t *) curarg - (grub_uint8_t *) buf0
+ buf_target;
@@ -899,12 +1110,25 @@ grub_openbsd_boot (void)
head->ba_next = 0;
}
+#ifndef GRUB_MACHINE_EFI
grub_video_set_mode ("text", 0, 0);
+#endif
#ifdef GRUB_MACHINE_EFI
- err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL);
+ grub_efi_uintn_t efi_mmap_size_out = efi_mmap_size;
+ grub_efi_uintn_t efi_desc_size;
+ grub_efi_uint32_t efi_desc_version;
+
+ err = grub_efi_finish_boot_services (&efi_mmap_size_out, efi_mmap_buf, NULL,
&efi_desc_size, &efi_desc_version);
if (err)
return err;
+
+ openbsd_efi_info_ptr->mmap_desc_ver = efi_desc_version;
+ openbsd_efi_info_ptr->mmap_desc_size = efi_desc_size;
+ openbsd_efi_info_ptr->mmap_size = efi_mmap_size_out;
+ openbsd_efi_info_ptr->mmap_start = ((grub_uint8_t *) efi_mmap_buf -
(grub_uint8_t *) buf0) + buf_target;
+#else
+ (void) openbsd_efi_info_ptr;
#endif
state.eip = entry;
@@ -924,12 +1148,88 @@ grub_openbsd_boot (void)
}
static grub_err_t
-grub_netbsd_setup_video (void)
+grub_netbsd_add_framebufer_info(const struct grub_video_mode_info *mode_info,
+ void *framebuffer) {
+ struct grub_netbsd_btinfo_framebuf params = {0};
+ params.width = mode_info->width;
+ params.height = mode_info->height;
+ params.bpp = mode_info->bpp;
+ params.pitch = mode_info->pitch;
+ params.flags = 0;
+
+ params.fbaddr = (grub_addr_t) framebuffer;
+
+ params.red_mask_size = mode_info->red_mask_size;
+ params.red_field_pos = mode_info->red_field_pos;
+ params.green_mask_size = mode_info->green_mask_size;
+ params.green_field_pos = mode_info->green_field_pos;
+ params.blue_mask_size = mode_info->blue_mask_size;
+ params.blue_field_pos = mode_info->blue_field_pos;
+
+ return grub_bsd_add_meta (NETBSD_BTINFO_FRAMEBUF, ¶ms, sizeof (params));
+}
+
+#ifdef GRUB_MACHINE_EFI
+
+static grub_err_t
+grub_openbsd_add_framebufer_info(const struct grub_video_mode_info *mode_info,
+ void *framebuffer) {
+ openbsd_efi_info.fb_red_mask = ((1 << mode_info->red_mask_size) - 1) <<
mode_info->red_field_pos;
+ openbsd_efi_info.fb_green_mask = ((1 << mode_info->green_mask_size) - 1) <<
mode_info->green_field_pos;
+ openbsd_efi_info.fb_blue_mask = ((1 << mode_info->blue_mask_size) - 1) <<
mode_info->blue_field_pos;
+ openbsd_efi_info.fb_reserved_mask = ((1LL << mode_info->bpp) - 1)
+ & ~(openbsd_efi_info.fb_red_mask | openbsd_efi_info.fb_green_mask |
openbsd_efi_info.fb_blue_mask);
+
+ openbsd_efi_info.fb_addr = (grub_addr_t) framebuffer;
+ openbsd_efi_info.fb_size = mode_info->height * mode_info->pitch;
+ openbsd_efi_info.fb_height = mode_info->height;
+ openbsd_efi_info.fb_width = mode_info->width;
+ openbsd_efi_info.fb_pixpsl = mode_info->pitch / (mode_info->bpp / 8);
+
+ return GRUB_ERR_NONE;
+}
+#endif
+
+static grub_err_t
+grub_freebsd_add_framebufer_info(const struct grub_video_mode_info *mode_info,
+ void *framebuffer) {
+#ifdef GRUB_MACHINE_EFI
+ struct grub_freebsd_btinfo_efi_framebuf params = {0};
+#else
+ struct grub_freebsd_btinfo_vbe_framebuf params = {0};
+#endif
+
+ params.width = mode_info->width;
+ params.height = mode_info->height;
+
+ params.fbaddr = (grub_addr_t) framebuffer;
+ params.fbsize = mode_info->height * mode_info->pitch;
+
+ params.red_mask = ((1 << mode_info->red_mask_size) - 1) <<
mode_info->red_field_pos;
+ params.green_mask = ((1 << mode_info->green_mask_size) - 1) <<
mode_info->green_field_pos;
+ params.blue_mask = ((1 << mode_info->blue_mask_size) - 1) <<
mode_info->blue_field_pos;
+ params.reserved_mask = ((1LL << mode_info->bpp) - 1)
+ & ~(params.red_mask | params.green_mask | params.blue_mask);
+
+ params.pitch = mode_info->pitch / (mode_info->bpp / 8);
+
+#ifdef GRUB_MACHINE_EFI
+ return grub_bsd_add_kernel_meta (FREEBSD_MODINFO_METADATA |
+ FREEBSD_MODINFOMD_EFI_FB, ¶ms, sizeof
(params));
+#else
+ params.bpp = mode_info->bpp;
+
+ return grub_bsd_add_kernel_meta (FREEBSD_MODINFO_METADATA |
+ FREEBSD_MODINFOMD_VBE_FB, ¶ms, sizeof
(params));
+#endif
+}
+
+static grub_err_t
+grub_bsd_setup_video (void)
{
struct grub_video_mode_info mode_info;
void *framebuffer;
const char *modevar;
- struct grub_netbsd_btinfo_framebuf params = {0};
grub_err_t err;
grub_video_driver_id_t driv_id;
@@ -940,14 +1240,14 @@ grub_netbsd_setup_video (void)
if (modevar && *modevar != 0)
{
char *tmp;
- tmp = grub_xasprintf ("%s;" NETBSD_DEFAULT_VIDEO_MODE, modevar);
+ tmp = grub_xasprintf ("%s;" BSD_DEFAULT_VIDEO_MODE, modevar);
if (! tmp)
return grub_errno;
err = grub_video_set_mode (tmp, 0, 0);
grub_free (tmp);
}
else
- err = grub_video_set_mode (NETBSD_DEFAULT_VIDEO_MODE, 0, 0);
+ err = grub_video_set_mode (BSD_DEFAULT_VIDEO_MODE, 0, 0);
if (err)
return err;
@@ -961,21 +1261,6 @@ grub_netbsd_setup_video (void)
if (err)
return err;
- params.width = mode_info.width;
- params.height = mode_info.height;
- params.bpp = mode_info.bpp;
- params.pitch = mode_info.pitch;
- params.flags = 0;
-
- params.fbaddr = (grub_addr_t) framebuffer;
-
- params.red_mask_size = mode_info.red_mask_size;
- params.red_field_pos = mode_info.red_field_pos;
- params.green_mask_size = mode_info.green_mask_size;
- params.green_field_pos = mode_info.green_field_pos;
- params.blue_mask_size = mode_info.blue_mask_size;
- params.blue_field_pos = mode_info.blue_field_pos;
-
#ifdef GRUB_MACHINE_PCBIOS
/* VESA packed modes may come with zeroed mask sizes, which need
to be set here according to DAC Palette width. If we don't,
@@ -996,12 +1281,20 @@ grub_netbsd_setup_video (void)
/* 6 is default after mode reset. */
width = 6;
- params.red_mask_size = params.green_mask_size
- = params.blue_mask_size = width;
+ mode_info.red_mask_size = mode_info.green_mask_size
+ = mode_info.blue_mask_size = width;
}
#endif
- err = grub_bsd_add_meta (NETBSD_BTINFO_FRAMEBUF, ¶ms, sizeof (params));
+ if (kernel_type == KERNEL_TYPE_FREEBSD)
+ return grub_freebsd_add_framebufer_info(&mode_info, framebuffer);
+ else if (kernel_type == KERNEL_TYPE_NETBSD)
+ return grub_netbsd_add_framebufer_info(&mode_info, framebuffer);
+#ifdef GRUB_MACHINE_EFI
+ else if (kernel_type == KERNEL_TYPE_OPENBSD)
+ return grub_openbsd_add_framebufer_info(&mode_info, framebuffer);
+#endif
+
return err;
}
@@ -1146,7 +1439,7 @@ grub_netbsd_boot (void)
if (err)
return err;
- err = grub_netbsd_setup_video ();
+ err = grub_bsd_setup_video ();
if (err)
{
grub_print_error ();
@@ -1159,11 +1452,29 @@ grub_netbsd_boot (void)
return err;
#ifdef GRUB_MACHINE_EFI
+ struct grub_netbsd_btinfo_efi efi_info;
+ grub_memset(&efi_info, 0, sizeof(efi_info));
+ efi_info.pa_systbl = (grub_addr_t) grub_efi_system_table;
+#ifdef __i386__
+ efi_info.flags |= GRUB_NETBSD_BI_EFI_32BIT;
+#endif
err = grub_bsd_add_meta (NETBSD_BTINFO_EFI,
- &grub_efi_system_table,
- sizeof (grub_efi_system_table));
+ &efi_info,
+ sizeof (efi_info));
+ if (err)
+ return err;
+
+ grub_uint32_t efi_mmap_size = 0;
+
+ efi_mmap_size = 2 * grub_efi_find_mmap_size ();
+
+ err = grub_bsd_add_meta (NETBSD_BTINFO_EFIMEMMAP,
+ NULL,
+ sizeof(struct grub_netbsd_btinfo_efimemmap)
+ + efi_mmap_size);
if (err)
return err;
+
#endif
{
@@ -1193,6 +1504,8 @@ grub_netbsd_boot (void)
arg0 = curarg;
bootinfo = (void *) ((grub_uint8_t *) arg0 + tag_buf_len);
+ struct grub_netbsd_btinfo_common *efi_memmap = 0;
+
{
struct bsd_tag *tag;
unsigned i;
@@ -1204,6 +1517,8 @@ grub_netbsd_boot (void)
bootinfo->bi_data[i] = ((grub_uint8_t *) curarg - (grub_uint8_t *) arg0)
+ arg_target;
head->type = tag->type;
+ if (tag->type == NETBSD_BTINFO_EFIMEMMAP)
+ efi_memmap = head;
head->len = tag->len + sizeof (*head);
curarg = head + 1;
grub_memcpy (curarg, tag->data, tag->len);
@@ -1224,9 +1539,21 @@ grub_netbsd_boot (void)
}
#ifdef GRUB_MACHINE_EFI
- err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL);
+ grub_efi_uintn_t efi_mmap_size_out = efi_mmap_size;
+ grub_efi_uintn_t efi_desc_size;
+ grub_efi_uint32_t efi_desc_version;
+ struct grub_netbsd_btinfo_efimemmap *efi_mmap = (struct
grub_netbsd_btinfo_efimemmap *) (efi_memmap + 1);
+
+ err = grub_efi_finish_boot_services (&efi_mmap_size_out, efi_mmap + 1, NULL,
&efi_desc_size, &efi_desc_version);
if (err)
return err;
+
+ efi_memmap->len = sizeof (struct grub_netbsd_btinfo_common) + sizeof(struct
grub_netbsd_btinfo_efimemmap) + efi_mmap_size_out;
+ efi_mmap->version = efi_desc_version;
+ efi_mmap->size = efi_desc_size;
+ efi_mmap->num = efi_desc_size > 0 ? (efi_mmap_size_out / efi_desc_size) : 0;
+#else
+ (void) efi_memmap;
#endif
state.eip = entry;
diff --git a/include/grub/i386/freebsd_linker.h
b/include/grub/i386/freebsd_linker.h
index 3c1eb64b6..dd53e4bcf 100644
--- a/include/grub/i386/freebsd_linker.h
+++ b/include/grub/i386/freebsd_linker.h
@@ -54,6 +54,7 @@
#define FREEBSD_MODINFO_SIZE 0x0004 /* Size of module */
#define FREEBSD_MODINFO_EMPTY 0x0005 /* Has been deleted */
#define FREEBSD_MODINFO_ARGS 0x0006 /* Parameters string */
+#define FREEBSD_MODINFOMD_FW_HANDLE 0x000c
#define FREEBSD_MODINFO_METADATA 0x8000 /* Module-specfic */
#define FREEBSD_MODINFOMD_AOUTEXEC 0x0001 /* a.out exec header */
@@ -68,7 +69,45 @@
#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_EFI_FB 0x1005
+#define FREEBSD_MODINFOMD_VBE_FB 0x1007
#define FREEBSD_MODINFOMD_DEPLIST (0x4001 | FREEBSD_MODINFOMD_NOCOPY) /*
depends on */
+struct grub_freebsd_btinfo_efi_framebuf
+{
+ grub_uint64_t fbaddr;
+ grub_uint64_t fbsize;
+ grub_uint32_t height;
+ grub_uint32_t width;
+ grub_uint32_t pitch;
+ grub_uint32_t red_mask;
+ grub_uint32_t green_mask;
+ grub_uint32_t blue_mask;
+ grub_uint32_t reserved_mask;
+};
+
+struct grub_freebsd_btinfo_vbe_framebuf
+{
+ grub_uint64_t fbaddr;
+ grub_uint64_t fbsize;
+ grub_uint32_t height;
+ grub_uint32_t width;
+ grub_uint32_t pitch;
+ grub_uint32_t red_mask;
+ grub_uint32_t green_mask;
+ grub_uint32_t blue_mask;
+ grub_uint32_t reserved_mask;
+ grub_uint32_t bpp;
+};
+
+struct grub_freebsd_btinfo_efi_map_header
+{
+ grub_uint64_t memory_size;
+ grub_uint64_t descriptor_size;
+ grub_uint32_t descriptor_version;
+ grub_uint32_t padding[3];
+};
+
#endif
diff --git a/include/grub/i386/netbsd_bootinfo.h
b/include/grub/i386/netbsd_bootinfo.h
index 9b4f46041..d80af966f 100644
--- a/include/grub/i386/netbsd_bootinfo.h
+++ b/include/grub/i386/netbsd_bootinfo.h
@@ -60,6 +60,7 @@
#define NETBSD_BTINFO_FRAMEBUF 12
#define NETBSD_BTINFO_USERCONFCOMMANDS 13
#define NETBSD_BTINFO_EFI 14
+#define NETBSD_BTINFO_EFIMEMMAP 15
struct grub_netbsd_bootinfo
{
@@ -150,7 +151,16 @@ struct grub_netbsd_btinfo_framebuf
struct grub_netbsd_btinfo_efi
{
- void *pa_systbl; /* Physical address of the EFI System Table */
+ grub_uint64_t pa_systbl; /* Physical address of the EFI System Table */
+ grub_uint32_t flags;
+#define GRUB_NETBSD_BI_EFI_32BIT 0x1
+ grub_uint8_t reserved[12];
+};
+
+struct grub_netbsd_btinfo_efimemmap {
+ grub_uint32_t num; /* number of memory descriptor */
+ grub_uint32_t version; /* version of memory descriptor */
+ grub_uint32_t size; /* size of memory descriptor */
};
#endif
diff --git a/include/grub/i386/openbsd_bootarg.h
b/include/grub/i386/openbsd_bootarg.h
index 8c28246d5..083b3de2b 100644
--- a/include/grub/i386/openbsd_bootarg.h
+++ b/include/grub/i386/openbsd_bootarg.h
@@ -63,6 +63,30 @@
#define OPENBSD_BOOTARG_MMAP 0
#define OPENBSD_BOOTARG_PCIBIOS 4
#define OPENBSD_BOOTARG_CONSOLE 5
+#define OPENBSD_BOOTARG_EFIINFO 11
+
+struct grub_openbsd_bootarg_efiinfo {
+ grub_uint64_t config_acpi;
+ grub_uint64_t config_smbios;
+ grub_uint64_t fb_addr;
+ grub_uint64_t fb_size;
+ grub_uint32_t fb_height;
+ grub_uint32_t fb_width;
+ grub_uint32_t fb_pixpsl; /* pixels per scan line */
+ grub_uint32_t fb_red_mask;
+ grub_uint32_t fb_green_mask;
+ grub_uint32_t fb_blue_mask;
+ grub_uint32_t fb_reserved_mask;
+ grub_uint32_t flags;
+#define GRUB_OPENBSD_BOOTARG_EFI_64BIT 0x00000001 /* 64-bit EFI
implementation */
+#define GRUB_OPENBSD_BOOTARG_EFI_ESRT 0x00000002 /* ESRT table */
+ grub_uint32_t mmap_desc_ver;
+ grub_uint32_t mmap_desc_size;
+ grub_uint32_t mmap_size;
+ grub_uint64_t mmap_start;
+ grub_uint64_t system_table;
+ grub_uint64_t config_esrt;
+} GRUB_PACKED;
struct grub_openbsd_bootargs
{
--
2.39.2