mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-07 00:50:50 +00:00
x86/xen: do video console fixup as part of early initialization
When FreeBSD is running as dom0 the video console metadata provided by the bootloader might not be accurate, as Xen has very likely taken over the console and possibly changed the mode. Adjust the video console information in the kernel metadata as part of early Xen initialization. Sponsored by: Cloud Software Group Reviewed by: imp Differential revision: https://reviews.freebsd.org/D43934
This commit is contained in:
parent
5d62aba742
commit
027b66d64b
|
@ -30,6 +30,7 @@
|
|||
#include <sys/param.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/linker.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/smp.h>
|
||||
|
@ -45,6 +46,7 @@
|
|||
#include <machine/cpufunc.h>
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/metadata.h>
|
||||
#include <machine/smp.h>
|
||||
|
||||
#include <x86/apicreg.h>
|
||||
|
@ -246,6 +248,87 @@ map_shared_info(void)
|
|||
return (rc);
|
||||
}
|
||||
|
||||
static void
|
||||
fixup_console(void)
|
||||
{
|
||||
struct xen_platform_op op = {
|
||||
.cmd = XENPF_get_dom0_console,
|
||||
};
|
||||
xenpf_dom0_console_t *console = &op.u.dom0_console;
|
||||
union {
|
||||
struct efi_fb efi;
|
||||
struct vbe_fb vbe;
|
||||
} *fb = NULL;
|
||||
int size;
|
||||
caddr_t kmdp;
|
||||
|
||||
kmdp = preload_search_by_type("elf kernel");
|
||||
if (kmdp == NULL)
|
||||
kmdp = preload_search_by_type("elf64 kernel");
|
||||
if (kmdp == NULL) {
|
||||
xc_printf("Unable to find kernel metadata\n");
|
||||
return;
|
||||
}
|
||||
|
||||
size = HYPERVISOR_platform_op(&op);
|
||||
if (size < 0) {
|
||||
xc_printf("Failed to get video console info: %d\n", size);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (console->video_type) {
|
||||
case XEN_VGATYPE_VESA_LFB:
|
||||
fb = (__typeof__ (fb))preload_search_info(kmdp,
|
||||
MODINFO_METADATA | MODINFOMD_VBE_FB);
|
||||
|
||||
if (fb == NULL) {
|
||||
xc_printf("No VBE FB in kernel metadata\n");
|
||||
return;
|
||||
}
|
||||
|
||||
_Static_assert(offsetof(struct vbe_fb, fb_bpp) ==
|
||||
offsetof(struct efi_fb, fb_mask_reserved) +
|
||||
sizeof(fb->efi.fb_mask_reserved),
|
||||
"Bad structure overlay\n");
|
||||
fb->vbe.fb_bpp = console->u.vesa_lfb.bits_per_pixel;
|
||||
/* FALLTHROUGH */
|
||||
case XEN_VGATYPE_EFI_LFB:
|
||||
if (fb == NULL) {
|
||||
fb = (__typeof__ (fb))preload_search_info(kmdp,
|
||||
MODINFO_METADATA | MODINFOMD_EFI_FB);
|
||||
if (fb == NULL) {
|
||||
xc_printf("No EFI FB in kernel metadata\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fb->efi.fb_addr = console->u.vesa_lfb.lfb_base;
|
||||
if (size >
|
||||
offsetof(xenpf_dom0_console_t, u.vesa_lfb.ext_lfb_base))
|
||||
fb->efi.fb_addr |=
|
||||
(uint64_t)console->u.vesa_lfb.ext_lfb_base << 32;
|
||||
fb->efi.fb_size = console->u.vesa_lfb.lfb_size << 16;
|
||||
fb->efi.fb_height = console->u.vesa_lfb.height;
|
||||
fb->efi.fb_width = console->u.vesa_lfb.width;
|
||||
fb->efi.fb_stride = (console->u.vesa_lfb.bytes_per_line << 3) /
|
||||
console->u.vesa_lfb.bits_per_pixel;
|
||||
#define FBMASK(c) \
|
||||
((~0u << console->u.vesa_lfb.c ## _pos) & \
|
||||
(~0u >> (32 - console->u.vesa_lfb.c ## _pos - \
|
||||
console->u.vesa_lfb.c ## _size)))
|
||||
fb->efi.fb_mask_red = FBMASK(red);
|
||||
fb->efi.fb_mask_green = FBMASK(green);
|
||||
fb->efi.fb_mask_blue = FBMASK(blue);
|
||||
fb->efi.fb_mask_reserved = FBMASK(rsvd);
|
||||
#undef FBMASK
|
||||
break;
|
||||
|
||||
default:
|
||||
xc_printf("Video console type unsupported\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Early initialization when running as a Xen guest. */
|
||||
void
|
||||
xen_early_init(void)
|
||||
|
@ -273,6 +356,10 @@ xen_early_init(void)
|
|||
vm_guest = VM_GUEST_VM;
|
||||
return;
|
||||
}
|
||||
|
||||
if (xen_initial_domain())
|
||||
/* Fixup video console information in case Xen changed the mode. */
|
||||
fixup_console();
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -319,87 +319,6 @@ xen_pvh_parse_symtab(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
fixup_console(void)
|
||||
{
|
||||
struct xen_platform_op op = {
|
||||
.cmd = XENPF_get_dom0_console,
|
||||
};
|
||||
xenpf_dom0_console_t *console = &op.u.dom0_console;
|
||||
union {
|
||||
struct efi_fb efi;
|
||||
struct vbe_fb vbe;
|
||||
} *fb = NULL;
|
||||
int size;
|
||||
caddr_t kmdp;
|
||||
|
||||
kmdp = preload_search_by_type("elf kernel");
|
||||
if (kmdp == NULL)
|
||||
kmdp = preload_search_by_type("elf64 kernel");
|
||||
if (kmdp == NULL) {
|
||||
xc_printf("Unable to find kernel metadata\n");
|
||||
return;
|
||||
}
|
||||
|
||||
size = HYPERVISOR_platform_op(&op);
|
||||
if (size < 0) {
|
||||
xc_printf("Failed to get video console info: %d\n", size);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (console->video_type) {
|
||||
case XEN_VGATYPE_VESA_LFB:
|
||||
fb = (__typeof__ (fb))preload_search_info(kmdp,
|
||||
MODINFO_METADATA | MODINFOMD_VBE_FB);
|
||||
|
||||
if (fb == NULL) {
|
||||
xc_printf("No VBE FB in kernel metadata\n");
|
||||
return;
|
||||
}
|
||||
|
||||
_Static_assert(offsetof(struct vbe_fb, fb_bpp) ==
|
||||
offsetof(struct efi_fb, fb_mask_reserved) +
|
||||
sizeof(fb->efi.fb_mask_reserved),
|
||||
"Bad structure overlay\n");
|
||||
fb->vbe.fb_bpp = console->u.vesa_lfb.bits_per_pixel;
|
||||
/* FALLTHROUGH */
|
||||
case XEN_VGATYPE_EFI_LFB:
|
||||
if (fb == NULL) {
|
||||
fb = (__typeof__ (fb))preload_search_info(kmdp,
|
||||
MODINFO_METADATA | MODINFOMD_EFI_FB);
|
||||
if (fb == NULL) {
|
||||
xc_printf("No EFI FB in kernel metadata\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fb->efi.fb_addr = console->u.vesa_lfb.lfb_base;
|
||||
if (size >
|
||||
offsetof(xenpf_dom0_console_t, u.vesa_lfb.ext_lfb_base))
|
||||
fb->efi.fb_addr |=
|
||||
(uint64_t)console->u.vesa_lfb.ext_lfb_base << 32;
|
||||
fb->efi.fb_size = console->u.vesa_lfb.lfb_size << 16;
|
||||
fb->efi.fb_height = console->u.vesa_lfb.height;
|
||||
fb->efi.fb_width = console->u.vesa_lfb.width;
|
||||
fb->efi.fb_stride = (console->u.vesa_lfb.bytes_per_line << 3) /
|
||||
console->u.vesa_lfb.bits_per_pixel;
|
||||
#define FBMASK(c) \
|
||||
((~0u << console->u.vesa_lfb.c ## _pos) & \
|
||||
(~0u >> (32 - console->u.vesa_lfb.c ## _pos - \
|
||||
console->u.vesa_lfb.c ## _size)))
|
||||
fb->efi.fb_mask_red = FBMASK(red);
|
||||
fb->efi.fb_mask_green = FBMASK(green);
|
||||
fb->efi.fb_mask_blue = FBMASK(blue);
|
||||
fb->efi.fb_mask_reserved = FBMASK(rsvd);
|
||||
#undef FBMASK
|
||||
break;
|
||||
|
||||
default:
|
||||
xc_printf("Video console type unsupported\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static caddr_t
|
||||
xen_pvh_parse_preload_data(uint64_t modulep)
|
||||
{
|
||||
|
@ -479,8 +398,6 @@ xen_pvh_parse_preload_data(uint64_t modulep)
|
|||
strlcpy(bootmethod, "UEFI", sizeof(bootmethod));
|
||||
else
|
||||
strlcpy(bootmethod, "BIOS", sizeof(bootmethod));
|
||||
|
||||
fixup_console();
|
||||
} else {
|
||||
/* Parse the extra boot information given by Xen */
|
||||
if (start_info->cmdline_paddr != 0)
|
||||
|
|
Loading…
Reference in a new issue