Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 16 Jan 2021 08:23:45 GMT
From:      Toomas Soome <tsoome@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: ad1ebbe5cea8 - main - loader: create local copy of mode list provided by vbeinfoblock
Message-ID:  <202101160823.10G8NjEi016925@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by tsoome:

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

commit ad1ebbe5cea8ffac0037966990ddf0f80faa55d5
Author:     Toomas Soome <tsoome@FreeBSD.org>
AuthorDate: 2021-01-16 10:18:32 +0000
Commit:     Toomas Soome <tsoome@FreeBSD.org>
CommitDate: 2021-01-16 10:23:22 +0000

    loader: create local copy of mode list provided by vbeinfoblock
    
    Apparently some systems do corrupt mode list memory area, so we need
    to use local copy instead.
---
 stand/i386/libi386/vbe.c | 82 +++++++++++++++++++++++++++++-------------------
 1 file changed, 49 insertions(+), 33 deletions(-)

diff --git a/stand/i386/libi386/vbe.c b/stand/i386/libi386/vbe.c
index 6a70cfe6f3e9..8b2c74ade92e 100644
--- a/stand/i386/libi386/vbe.c
+++ b/stand/i386/libi386/vbe.c
@@ -48,12 +48,14 @@
 
 static struct vbeinfoblock *vbe;
 static struct modeinfoblock *vbe_mode;
+
+static uint16_t *vbe_mode_list;
+static size_t vbe_mode_list_size;
+
 /* The default VGA color palette format is 6 bits per primary color. */
 int palette_format = 6;
 
 #define	VESA_MODE_BASE	0x100
-#define	VESA_MODE_MAX	0x1ff
-#define	VESA_MODE_COUNT	(VESA_MODE_MAX - VESA_MODE_BASE + 1)
 
 /*
  * palette array for 8-bit indexed colors. In this case, cmap does store
@@ -545,9 +547,17 @@ mode_set(struct env_var *ev, int flags __unused, const void *value)
 	return (0);
 }
 
+static void *
+vbe_farptr(uint32_t farptr)
+{
+	return (PTOV((((farptr & 0xffff0000) >> 12) + (farptr & 0xffff))));
+}
+
 void
 vbe_init(void)
 {
+	uint16_t *p, *ml;
+
 	/* First set FB for text mode. */
 	gfx_state.tg_fb_type = FB_TEXT;
 	gfx_state.tg_fb.fb_height = TEXT_ROWS;
@@ -573,6 +583,27 @@ vbe_init(void)
 		vbe_mode = NULL;
 	}
 
+	/*
+	 * Copy mode list. We must do this because some systems do
+	 * corrupt the provided list (vbox 6.1 is one example).
+	 */
+	p = ml = vbe_farptr(vbe->VideoModePtr);
+	while(*p++ != 0xFFFF)
+		;
+
+	vbe_mode_list_size = (uintptr_t)p - (uintptr_t)ml;
+	vbe_mode_list = malloc(vbe_mode_list_size);
+	if (vbe_mode_list == NULL) {
+		free(vbe);
+		vbe = NULL;
+		free(vbe_mode);
+		vbe_mode = NULL;
+	}
+	bcopy(ml, vbe_mode_list, vbe_mode_list_size);
+
+	/* reset VideoModePtr, so we will not have chance to use bad data. */
+	vbe->VideoModePtr = 0;
+
 	env_setenv("screen.textmode", EV_VOLATILE, "1", mode_set,
 	    env_nounset);
 	env_setenv("vbe_max_resolution", EV_VOLATILE, NULL, mode_set,
@@ -717,12 +748,6 @@ vbe_set_mode(int modenum)
 	return (0);
 }
 
-static void *
-vbe_farptr(uint32_t farptr)
-{
-	return (PTOV((((farptr & 0xffff0000) >> 12) + (farptr & 0xffff))));
-}
-
 /*
  * Verify existance of mode number or find mode by
  * dimensions. If depth is not given, walk values 32, 24, 16, 8.
@@ -731,15 +756,13 @@ static int
 vbe_find_mode_xydm(int x, int y, int depth, int m)
 {
 	struct modeinfoblock mi;
-	uint32_t farptr;
+	uint16_t *farptr;
 	uint16_t mode;
-	int safety, i;
+	int idx, nitems, i;
 
 	memset(vbe, 0, sizeof (*vbe));
 	if (biosvbe_info(vbe) != VBE_SUCCESS)
 		return (0);
-	if (vbe->VideoModePtr == 0)
-		return (0);
 
 	if (m != -1)
 		i = 8;
@@ -748,17 +771,17 @@ vbe_find_mode_xydm(int x, int y, int depth, int m)
 	else
 		i = depth;
 
+	nitems = vbe_mode_list_size / sizeof(*vbe_mode_list);
 	while (i > 0) {
-		farptr = vbe->VideoModePtr;
-		safety = 0;
-		while ((mode = *(uint16_t *)vbe_farptr(farptr)) != 0xffff) {
-			safety++;
-			farptr += 2;
-			if (safety == VESA_MODE_COUNT)
+		for (idx = 0; idx < nitems; idx++) {
+			mode = vbe_mode_list[idx];
+			if (mode == 0xffff)
 				break;
+
 			if (biosvbe_get_mode_info(mode, &mi) != VBE_SUCCESS) {
 				continue;
 			}
+
 			/* we only care about linear modes here */
 			if (vbe_mode_is_supported(&mi) == 0)
 				continue;
@@ -910,9 +933,8 @@ void
 vbe_modelist(int depth)
 {
 	struct modeinfoblock mi;
-	uint32_t farptr;
 	uint16_t mode;
-	int nmodes = 0, safety = 0;
+	int nmodes, idx, nentries;
 	int ddc_caps;
 	uint32_t width, height;
 	bool edid = false;
@@ -948,6 +970,7 @@ vbe_modelist(int depth)
 		if (vbe_get_flatpanel(&width, &height))
 			printf(": Panel %dx%d\n", width, height);
 
+	nmodes = 0;
 	memset(vbe, 0, sizeof (*vbe));
 	memcpy(vbe->VbeSignature, "VBE2", 4);
 	if (biosvbe_info(vbe) != VBE_SUCCESS)
@@ -958,26 +981,19 @@ vbe_modelist(int depth)
 	vbe_print_vbe_info(vbe);
 	printf("Modes: ");
 
-	farptr = vbe->VideoModePtr;
-	if (farptr == 0)
-		goto done;
-
-	while ((mode = *(uint16_t *)vbe_farptr(farptr)) != 0xffff) {
-		safety++;
-		farptr += 2;
-		if (safety == VESA_MODE_COUNT) {
-			printf("[?] ");
+	nentries = vbe_mode_list_size / sizeof(*vbe_mode_list);
+	for (idx = 0; idx < nentries; idx++) {
+		mode = vbe_mode_list[idx];
+		if (mode == 0xffff)
 			break;
-		}
+
 		if (biosvbe_get_mode_info(mode, &mi) != VBE_SUCCESS)
 			continue;
+
 		/* we only care about linear modes here */
 		if (vbe_mode_is_supported(&mi) == 0)
 			continue;
 
-		/* we found some mode so reset safety counter */
-		safety = 0;
-
 		/* apply requested filter */
 		if (depth != -1 && mi.BitsPerPixel != depth)
 			continue;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202101160823.10G8NjEi016925>