diff -ur a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c --- a/grub-core/loader/i386/bsd.c 2021-03-10 16:50:44.000000000 +0300 +++ b/grub-core/loader/i386/bsd.c 2022-03-03 12:13:06.094295311 +0300 @@ -49,9 +49,9 @@ #endif #ifdef GRUB_MACHINE_EFI #include -#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 #endif #include @@ -62,6 +62,10 @@ #include #include +#ifdef GRUB_MACHINE_EFI +#include +#endif + #define ALIGN_DWORD(a) ALIGN_UP (a, 4) #define ALIGN_QWORD(a) ALIGN_UP (a, 8) #define ALIGN_VAR(a) ((is_64bit) ? (ALIGN_QWORD(a)) : (ALIGN_DWORD(a))) @@ -232,7 +236,9 @@ *ptr = newtag->data; if (kernel_type == KERNEL_TYPE_FREEBSD - && type == (FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_SMAP)) + && (type == (FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_SMAP) + || type == (FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_VBE_FB) + || type == (FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_EFI_FB))) { struct bsd_tag *p; for (p = tags; @@ -593,6 +599,84 @@ } static grub_err_t +grub_bsd_setup_video_common (struct grub_bsd_setup_video_common *mode_info, + void **framebuffer, + int *needs_video) +{ + const char *modevar; + grub_err_t err; + grub_video_driver_id_t driv_id; + + *needs_video = 0; + + modevar = grub_env_get ("gfxpayload"); + + /* Now all graphical modes are acceptable. + May change in future if we have modes without framebuffer. */ + if (modevar && *modevar != 0) + { + char *tmp; + 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 (BSD_DEFAULT_VIDEO_MODE, 0, 0); + + if (err) + return err; + + driv_id = grub_video_get_driver_id (); + if (driv_id == GRUB_VIDEO_DRIVER_NONE) + return GRUB_ERR_NONE; + + err = grub_video_get_info_and_fini (mode_info, framebuffer); + + if (err) + return err; + + *needs_video = 1; + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_freebsd_setup_video (void) +{ + struct grub_video_mode_info mode_info; + void *framebuffer; + union grub_freebsd_fb params; + grub_err_t err; + int needs_video; + + err = grub_bsd_setup_video_common (&mode_info, &framebuffer, &needs_video); + + if (err || !needs_video) + return err; + + params.vbe.fb_width = mode_info.width; + params.vbe.fb_height = mode_info.height; + params.vbe.fb_bpp = mode_info.bpp; + params.vbe.fb_stride = mode_info.pitch / ((params.vbe.fb_bpp + 7) / 8); + + params.vbe.fb_addr = (grub_addr_t) framebuffer; + + params.vbe.fb_mask_red = ((1ull << mode_info.red_mask_size) - 1) << mode_info.red_field_pos; + params.vbe.fb_mask_green = ((1ull << mode_info.green_mask_size) - 1) << mode_info.green_field_pos; + params.vbe.fb_mask_blue = ((1ull << mode_info.blue_mask_size) - 1) << mode_info.blue_field_pos; + params.vbe.fb_mask_reserved = ~(params.vbe.fb_mask_red|params.vbe.fb_mask_green|params.vbe.fb_mask_blue); + params.vbe.fb_size = params.vbe.fb_height * params.vbe.fb_stride * ((params.vbe.fb_bpp + 7) / 8); + +#ifdef GRUB_MACHINE_PCBIOS + err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_VBE_FB, ¶ms.vbe, sizeof (params.vbe)); +#else + err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_EFI_FB, ¶ms.efi, sizeof (params.efi)); +#endif + return err; +} + +static grub_err_t grub_freebsd_boot (void) { struct grub_freebsd_bootinfo bi; @@ -604,6 +688,16 @@ struct grub_env_var *var; +#ifdef GRUB_MACHINE_EFI + /* Pass RSDP to FreeBSD. It cannot find it in EFI mode. */ + if (!(grub_env_get ("kFreeBSD.hint.acpi.0.rsdp"))) + { + const char rsdp[20]; + grub_snprintf (rsdp, sizeof(rsdp), "%p", grub_acpi_get_rsdpv2 ()); + grub_env_set ("kFreeBSD.hint.acpi.0.rsdp", rsdp); + } +#endif + grub_memset (&bi, 0, sizeof (bi)); bi.version = FREEBSD_BOOTINFO_VERSION; bi.length = sizeof (bi); @@ -630,6 +724,14 @@ if (err) return err; + err = grub_freebsd_setup_video (); + if (err) + { + grub_print_error (); + grub_puts_ (N_("Booting in blind mode")); + grub_errno = GRUB_ERR_NONE; + } + err = grub_bsd_add_meta (FREEBSD_MODINFO_END, 0, 0); if (err) return err; @@ -928,37 +1030,13 @@ { struct grub_video_mode_info mode_info; void *framebuffer; - const char *modevar; struct grub_netbsd_btinfo_framebuf params; grub_err_t err; - grub_video_driver_id_t driv_id; + int needs_video; - modevar = grub_env_get ("gfxpayload"); + err = grub_bsd_setup_video_common (&mode_info, &framebuffer, &needs_video); - /* Now all graphical modes are acceptable. - May change in future if we have modes without framebuffer. */ - if (modevar && *modevar != 0) - { - char *tmp; - tmp = grub_xasprintf ("%s;" NETBSD_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); - - if (err) - return err; - - driv_id = grub_video_get_driver_id (); - if (driv_id == GRUB_VIDEO_DRIVER_NONE) - return GRUB_ERR_NONE; - - err = grub_video_get_info_and_fini (&mode_info, &framebuffer); - - if (err) + if (err || !needs_video) return err; params.width = mode_info.width; diff -ur a/include/grub/i386/freebsd_linker.h b/include/grub/i386/freebsd_linker.h --- a/include/grub/i386/freebsd_linker.h 2018-11-24 20:13:02.000000000 +0300 +++ b/include/grub/i386/freebsd_linker.h 2022-03-03 12:13:06.103295304 +0300 @@ -71,4 +71,37 @@ #define FREEBSD_MODINFOMD_DEPLIST (0x4001 | FREEBSD_MODINFOMD_NOCOPY) /* depends on */ +#define FREEBSD_MODINFOMD_EFI_FB 0x1005 +#define FREEBSD_MODINFOMD_VBE_FB 0x1007 + +struct grub_freebsd_efi_fb { + grub_uint64_t fb_addr; + grub_uint64_t fb_size; + grub_uint32_t fb_height; + grub_uint32_t fb_width; + grub_uint32_t fb_stride; + grub_uint32_t fb_mask_red; + grub_uint32_t fb_mask_green; + grub_uint32_t fb_mask_blue; + grub_uint32_t fb_mask_reserved; +}; + +struct grub_freebsd_vbe_fb { + grub_uint64_t fb_addr; + grub_uint64_t fb_size; + grub_uint32_t fb_height; + grub_uint32_t fb_width; + grub_uint32_t fb_stride; + grub_uint32_t fb_mask_red; + grub_uint32_t fb_mask_green; + grub_uint32_t fb_mask_blue; + grub_uint32_t fb_mask_reserved; + grub_uint32_t fb_bpp; +}; + +union grub_freebsd_fb { + struct grub_freebsd_efi_fb efi; + struct grub_freebsd_vbe_fb vbe; +}; + #endif