From: Vladimir Serbinenko <phcoder@gmail.com>
To: grub-devel@gnu.org
Cc: Vladimir Serbinenko <phcoder@gmail.com>
Subject: [PATCH v2 2/4] loader/bsd: Improve loading of *BSD on EFI platforms
Date: Fri, 17 May 2024 10:45:38 +0300 [thread overview]
Message-ID: <20240517074540.2576-2-phcoder@gmail.com> (raw)
In-Reply-To: <20240517074540.2576-1-phcoder@gmail.com>
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
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
next prev parent reply other threads:[~2024-05-17 7:47 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-05-17 7:45 [PATCH v2 1/4] smbios: Export grub_smbios_get_eps3 function Vladimir Serbinenko
2024-05-17 7:45 ` Vladimir Serbinenko [this message]
2024-05-17 7:45 ` [PATCH v2 3/4] Do NULL memory quirk workaround only when explicitly requested Vladimir Serbinenko
2024-05-17 7:45 ` [PATCH v2 4/4] loader/bsd: Add missing zeros Vladimir Serbinenko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240517074540.2576-2-phcoder@gmail.com \
--to=phcoder@gmail.com \
--cc=grub-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.