git: 027b66d64b54 - main - x86/xen: do video console fixup as part of early initialization

From: Roger Pau Monné <royger_at_FreeBSD.org>
Date: Thu, 22 Feb 2024 10:31:25 UTC
The branch main has been updated by royger:

URL: https://cgit.FreeBSD.org/src/commit/?id=027b66d64b547b2133c11b596a7e308ea8c83ccb

commit 027b66d64b547b2133c11b596a7e308ea8c83ccb
Author:     Roger Pau Monné <royger@FreeBSD.org>
AuthorDate: 2024-02-02 10:29:57 +0000
Commit:     Roger Pau Monné <royger@FreeBSD.org>
CommitDate: 2024-02-22 10:08:05 +0000

    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
---
 sys/x86/xen/hvm.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 sys/x86/xen/pv.c  | 83 ----------------------------------------------------
 2 files changed, 87 insertions(+), 83 deletions(-)

diff --git a/sys/x86/xen/hvm.c b/sys/x86/xen/hvm.c
index 9dc9360d719c..85f274175ac6 100644
--- a/sys/x86/xen/hvm.c
+++ b/sys/x86/xen/hvm.c
@@ -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
diff --git a/sys/x86/xen/pv.c b/sys/x86/xen/pv.c
index 515e5c58d304..e33fa41c83d7 100644
--- a/sys/x86/xen/pv.c
+++ b/sys/x86/xen/pv.c
@@ -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)