diff options
| author | Toomas Soome <tsoome@me.com> | 2021-01-17 11:13:43 +0200 |
|---|---|---|
| committer | Toomas Soome <tsoome@me.com> | 2021-02-11 22:44:21 +0200 |
| commit | 7449d3727c8ac1ccfb0a4c4de0a9ccf79c1d8cfd (patch) | |
| tree | b83c69fa1dc7c0dfb9c163315788f834cea2aebb | |
| parent | 168091e5da87ff8dbec35e48d0cebe8b5221365d (diff) | |
| download | illumos-joyent-7449d3727c8ac1ccfb0a4c4de0a9ccf79c1d8cfd.tar.gz | |
13454 loader: create local copy of mode list provided by vbeinfoblock
Reviewed by: Robert Mustacchi <rm@fingolfin.org>
Approved by: Richard Lowe <richlowe@richlowe.net>
| -rw-r--r-- | usr/src/boot/Makefile.version | 2 | ||||
| -rw-r--r-- | usr/src/boot/sys/boot/i386/libi386/vbe.c | 103 |
2 files changed, 67 insertions, 38 deletions
diff --git a/usr/src/boot/Makefile.version b/usr/src/boot/Makefile.version index cb628e3286..d4b95e1bef 100644 --- a/usr/src/boot/Makefile.version +++ b/usr/src/boot/Makefile.version @@ -34,4 +34,4 @@ LOADER_VERSION = 1.1 # Use date like formatting here, YYYY.MM.DD.XX, without leading zeroes. # The version is processed from left to right, the version number can only # be increased. -BOOT_VERSION = $(LOADER_VERSION)-2021.01.17.1 +BOOT_VERSION = $(LOADER_VERSION)-2021.01.17.2 diff --git a/usr/src/boot/sys/boot/i386/libi386/vbe.c b/usr/src/boot/sys/boot/i386/libi386/vbe.c index 4f98cdf747..c48427f5f4 100644 --- a/usr/src/boot/sys/boot/i386/libi386/vbe.c +++ b/usr/src/boot/sys/boot/i386/libi386/vbe.c @@ -47,13 +47,14 @@ static struct vbeinfoblock *vbe = (struct vbeinfoblock *)&vbestate.vbe_control_info; static struct modeinfoblock *vbe_mode = (struct modeinfoblock *)&vbestate.vbe_mode_info; +static uint16_t *vbe_mode_list; +static size_t vbe_mode_list_size; multiboot_color_t *cmap; /* 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) +#define VESA_MODE_BASE 0x100 +#define VESA_END_OF_MODE_LIST 0xffff /* Actually assuming mode 3. */ void @@ -278,9 +279,25 @@ vbe_check(void) return (1); } +/* + * Translate selector:offset style address to linear adress. + * selector = farptr >> 16; + * offset = farptr & 0xffff; + * linear = (selector * 4) + offset. + * By using mask 0xffff0000, we wil get the optimised line below. + * As a final step, translate physical address to loader virtual address. + */ +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_fb.framebuffer_common.mb_type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER; gfx_fb.framebuffer_common.framebuffer_type = @@ -301,9 +318,37 @@ vbe_init(void) if (memcmp(vbe->VbeSignature, "VESA", 4) != 0) return; + /* + * Copy mode list array. We must do this because some systems do + * place this array to scratch memory, which will be reused by + * subsequent VBE calls. (vbox 6.1 is one example). + */ + p = ml = vbe_farptr(vbe->VideoModePtr); + while (*p++ != VESA_END_OF_MODE_LIST) + ; + + vbe_mode_list_size = (uintptr_t)p - (uintptr_t)ml; + + /* + * Since vbe_init() is used only once at very start of the loader, + * we assume malloc will not fail there. But in case it does, + * we point vbe_mode_list to memory pointed by VideoModePtr. + * If the VideoModePtr memory area is not valid, we will fail to + * pick usable VBE mode and fall back to use text mode. + */ + vbe_mode_list = malloc(vbe_mode_list_size); + if (vbe_mode_list == NULL) + vbe_mode_list = ml; + else + bcopy(ml, vbe_mode_list, vbe_mode_list_size); + + /* reset VideoModePtr, to make sure, we only do use vbe_mode_list. */ + vbe->VideoModePtr = 0; + vbestate.mb_type = MULTIBOOT_TAG_TYPE_VBE; vbestate.mb_size = sizeof (vbestate); vbestate.vbe_mode = 0; + /* vbe_set_mode() will set up the rest. */ } @@ -446,12 +491,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. @@ -460,9 +499,9 @@ static int vbe_find_mode_xydm(int x, int y, int depth, int m) { struct modeinfoblock mi; - uint32_t farptr; uint16_t mode; - int safety, i; + size_t idx, nentries; + int i; memset(vbe, 0, sizeof (vbe)); memcpy(vbe->VbeSignature, "VBE2", 4); @@ -470,8 +509,6 @@ vbe_find_mode_xydm(int x, int y, int depth, int m) return (0); if (memcmp(vbe->VbeSignature, "VESA", 4) != 0) return (0); - if (vbe->VideoModePtr == 0) - return (0); if (m != -1) i = 8; @@ -480,17 +517,16 @@ vbe_find_mode_xydm(int x, int y, int depth, int m) else i = depth; + nentries = 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) - return (0); - if (biosvbe_get_mode_info(mode, &mi) != VBE_SUCCESS) { + for (idx = 0; idx < nentries; idx++) { + mode = vbe_mode_list[idx]; + if (mode == VESA_END_OF_MODE_LIST) + 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; @@ -624,9 +660,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; uint_t width, height; bool edid = false; @@ -662,6 +697,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) @@ -672,26 +708,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 == VESA_END_OF_MODE_LIST) 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; |
