2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2009 Jared D. McNeill <jmcneill@invisible.ca>
6 * Copyright 2020 Toomas Soome
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
32 #include <sys/param.h>
33 #include <machine/psl.h>
34 #include <machine/cpufunc.h>
36 #include <bootstrap.h>
39 #include <dev/vt/hw/vga/vt_vga_reg.h>
44 * VESA BIOS Extensions routines
47 static struct vbeinfoblock *vbe;
48 static struct modeinfoblock *vbe_mode;
50 static uint16_t *vbe_mode_list;
51 static size_t vbe_mode_list_size;
52 struct vesa_edid_info *edid_info = NULL;
54 /* The default VGA color palette format is 6 bits per primary color. */
55 int palette_format = 6;
57 #define VESA_MODE_BASE 0x100
60 * palette array for 8-bit indexed colors. In this case, cmap does store
61 * index and pe8 does store actual RGB. This is needed because we may
62 * not be able to read palette data from hardware.
64 struct paletteentry *pe8 = NULL;
66 static struct named_resolution {
101 vbe_resolution_compare(struct named_resolution *res, const char *cmp)
104 if (strcasecmp(res->name, cmp) == 0)
106 if (res->alias != NULL && strcasecmp(res->alias, cmp) == 0)
112 vbe_get_max_resolution(int *width, int *height)
114 struct named_resolution *res;
116 char *height_start, *width_start;
119 *width = *height = 0;
120 maxres = getenv("vbe_max_resolution");
121 /* No max_resolution set? Bail out; choose highest resolution */
124 /* See if it matches one of our known resolutions */
125 for (idx = 0; idx < nitems(resolutions); ++idx) {
126 res = &resolutions[idx];
127 if (vbe_resolution_compare(res, maxres)) {
129 *height = res->height;
133 /* Not a known resolution, try to parse it; make a copy we can modify */
134 maxres = strdup(maxres);
137 height_start = strchr(maxres, 'x');
138 if (height_start == NULL) {
142 width_start = maxres;
144 /* Errors from this will effectively mean "no max" */
145 *width = (int)strtol(width_start, NULL, 0);
146 *height = (int)strtol(height_start, NULL, 0);
151 vga_get_reg(int reg, int index)
153 return (inb(reg + index));
157 vga_get_atr(int reg, int i)
161 (void) inb(reg + VGA_GEN_INPUT_STAT_1);
162 outb(reg + VGA_AC_WRITE, i);
163 ret = inb(reg + VGA_AC_READ);
165 (void) inb(reg + VGA_GEN_INPUT_STAT_1);
171 vga_set_atr(int reg, int i, int v)
173 (void) inb(reg + VGA_GEN_INPUT_STAT_1);
174 outb(reg + VGA_AC_WRITE, i);
175 outb(reg + VGA_AC_WRITE, v);
177 (void) inb(reg + VGA_GEN_INPUT_STAT_1);
181 vga_set_indexed(int reg, int indexreg, int datareg, uint8_t index, uint8_t val)
183 outb(reg + indexreg, index);
184 outb(reg + datareg, val);
188 vga_get_indexed(int reg, int indexreg, int datareg, uint8_t index)
190 outb(reg + indexreg, index);
191 return (inb(reg + datareg));
195 vga_get_crtc(int reg, int i)
197 return (vga_get_indexed(reg, VGA_CRTC_ADDRESS, VGA_CRTC_DATA, i));
201 vga_set_crtc(int reg, int i, int v)
203 vga_set_indexed(reg, VGA_CRTC_ADDRESS, VGA_CRTC_DATA, i, v);
207 vga_get_seq(int reg, int i)
209 return (vga_get_indexed(reg, VGA_SEQ_ADDRESS, VGA_SEQ_DATA, i));
213 vga_set_seq(int reg, int i, int v)
215 vga_set_indexed(reg, VGA_SEQ_ADDRESS, VGA_SEQ_DATA, i, v);
219 vga_get_grc(int reg, int i)
221 return (vga_get_indexed(reg, VGA_GC_ADDRESS, VGA_GC_DATA, i));
225 vga_set_grc(int reg, int i, int v)
227 vga_set_indexed(reg, VGA_GC_ADDRESS, VGA_GC_DATA, i, v);
231 * Return true when this controller is VGA compatible.
239 return ((vbe->Capabilities & VBE_CAP_NONVGA) == 0);
242 /* Actually assuming mode 3. */
244 bios_set_text_mode(int mode)
248 if (vbe->Capabilities & VBE_CAP_DAC8) {
252 * The mode change should reset the palette format to
253 * 6 bits, but apparently some systems do fail with 8-bit
254 * palette, so we switch to 6-bit here.
257 (void) biosvbe_palette_format(&m);
262 v86.eax = mode; /* set VGA text mode */
264 atr = vga_get_atr(VGA_REG_BASE, VGA_AC_MODE_CONTROL);
265 atr &= ~VGA_AC_MC_BI;
266 atr &= ~VGA_AC_MC_ELG;
267 vga_set_atr(VGA_REG_BASE, VGA_AC_MODE_CONTROL, atr);
269 gfx_state.tg_mode = mode;
270 gfx_state.tg_fb_type = FB_TEXT;
271 gfx_state.tg_fb.fb_height = TEXT_ROWS;
272 gfx_state.tg_fb.fb_width = TEXT_COLS;
274 gfx_state.tg_fb.fb_mask_red = (1 << palette_format) - 1 << 16;
275 gfx_state.tg_fb.fb_mask_green = (1 << palette_format) - 1 << 8;
276 gfx_state.tg_fb.fb_mask_blue = (1 << palette_format) - 1 << 0;
277 gfx_state.tg_ctype = CT_INDEXED;
278 env_setenv("screen.textmode", EV_VOLATILE | EV_NOHOOK, "1", NULL, NULL);
281 /* Function 00h - Return VBE Controller Information */
283 biosvbe_info(struct vbeinfoblock *vbep)
285 struct vbeinfoblock *rvbe;
291 rvbe = bio_alloc(sizeof(*rvbe));
295 /* Now check if we have vesa. */
296 memset(rvbe, 0, sizeof (*vbe));
297 memcpy(rvbe->VbeSignature, "VBE2", 4);
302 v86.es = VTOPSEG(rvbe);
303 v86.edi = VTOPOFF(rvbe);
305 ret = v86.eax & 0xffff;
307 if (ret != VBE_SUCCESS)
310 if (memcmp(rvbe->VbeSignature, "VESA", 4) != 0) {
314 bcopy(rvbe, vbep, sizeof(*vbep));
316 bio_free(rvbe, sizeof(*rvbe));
320 /* Function 01h - Return VBE Mode Information */
322 biosvbe_get_mode_info(int mode, struct modeinfoblock *mi)
324 struct modeinfoblock *rmi;
327 rmi = bio_alloc(sizeof(*rmi));
335 v86.es = VTOPSEG(rmi);
336 v86.edi = VTOPOFF(rmi);
339 ret = v86.eax & 0xffff;
340 if (ret != VBE_SUCCESS)
342 bcopy(rmi, mi, sizeof(*rmi));
344 bio_free(rmi, sizeof(*rmi));
348 /* Function 02h - Set VBE Mode */
350 biosvbe_set_mode(int mode, struct crtciinfoblock *ci)
354 if (vbe->Capabilities & VBE_CAP_DAC8) {
358 * The mode change should reset the palette format to
359 * 6 bits, but apparently some systems do fail with 8-bit
360 * palette, so we switch to 6-bit here.
363 if (biosvbe_palette_format(&m) == VBE_SUCCESS)
369 v86.ebx = mode | 0x4000; /* set linear FB bit */
370 v86.es = VTOPSEG(ci);
371 v86.edi = VTOPOFF(ci);
373 rv = v86.eax & 0xffff;
374 if (vbe->Capabilities & VBE_CAP_DAC8) {
377 /* Switch to 8-bits per primary color. */
379 if (biosvbe_palette_format(&m) == VBE_SUCCESS)
382 env_setenv("screen.textmode", EV_VOLATILE | EV_NOHOOK, "0", NULL, NULL);
386 /* Function 03h - Get VBE Mode */
388 biosvbe_get_mode(int *mode)
394 *mode = v86.ebx & 0x3fff; /* Bits 0-13 */
395 return (v86.eax & 0xffff);
398 /* Function 08h - Set/Get DAC Palette Format */
400 biosvbe_palette_format(int *format)
407 *format = (v86.ebx >> 8) & 0xff;
408 return (v86.eax & 0xffff);
411 /* Function 09h - Set/Get Palette Data */
413 biosvbe_palette_data(int mode, int reg, struct paletteentry *pe)
421 v86.es = VTOPSEG(pe);
422 v86.edi = VTOPOFF(pe);
424 return (v86.eax & 0xffff);
428 * Function 15h BL=00h - Report VBE/DDC Capabilities
430 * int biosvbe_ddc_caps(void)
431 * return: VBE/DDC capabilities
434 biosvbe_ddc_caps(void)
438 v86.eax = 0x4f15; /* display identification extensions */
439 v86.ebx = 0; /* report DDC capabilities */
440 v86.ecx = 0; /* controller unit number (00h = primary) */
444 if (VBE_ERROR(v86.eax & 0xffff))
446 return (v86.ebx & 0xffff);
449 /* Function 11h BL=01h - Flat Panel status */
451 biosvbe_ddc_read_flat_panel_info(void *buf)
455 v86.eax = 0x4f11; /* Flat Panel Interface extensions */
456 v86.ebx = 1; /* Return Flat Panel Information */
457 v86.es = VTOPSEG(buf);
458 v86.edi = VTOPOFF(buf);
460 return (v86.eax & 0xffff);
463 /* Function 15h BL=01h - Read EDID */
465 biosvbe_ddc_read_edid(int blockno, void *buf)
469 v86.eax = 0x4f15; /* display identification extensions */
470 v86.ebx = 1; /* read EDID */
471 v86.ecx = 0; /* controller unit number (00h = primary) */
473 v86.es = VTOPSEG(buf);
474 v86.edi = VTOPOFF(buf);
476 return (v86.eax & 0xffff);
480 vbe_mode_is_supported(struct modeinfoblock *mi)
482 if ((mi->ModeAttributes & 0x01) == 0)
483 return (0); /* mode not supported by hardware */
484 if ((mi->ModeAttributes & 0x08) == 0)
485 return (0); /* linear fb not available */
486 if ((mi->ModeAttributes & 0x10) == 0)
487 return (0); /* text mode */
488 if (mi->NumberOfPlanes != 1)
489 return (0); /* planar mode not supported */
490 if (mi->MemoryModel != 0x04 /* Packed pixel */ &&
491 mi->MemoryModel != 0x06 /* Direct Color */)
492 return (0); /* unsupported pixel format */
501 printf("VBE not available\n");
508 mode_set(struct env_var *ev, int flags __unused, const void *value)
512 if (strcmp(ev->ev_name, "screen.textmode") == 0) {
519 v = strtoul(value, &end, 0);
520 if (errno != 0 || *(char *)value == '\0' || *end != '\0' ||
523 env_setenv("screen.textmode", EV_VOLATILE | EV_NOHOOK,
527 bios_text_font(true);
528 bios_set_text_mode(VGA_TEXT_MODE);
529 (void) cons_update_mode(false);
532 } else if (strcmp(ev->ev_name, "vbe_max_resolution") == 0) {
533 env_setenv("vbe_max_resolution", EV_VOLATILE | EV_NOHOOK,
539 mode = vbe_default_mode();
540 if (gfx_state.tg_mode != mode) {
542 bios_text_font(false);
544 cons_update_mode(true);
550 vbe_farptr(uint32_t farptr)
552 return (PTOV((((farptr & 0xffff0000) >> 12) + (farptr & 0xffff))));
560 /* First set FB for text mode. */
561 gfx_state.tg_fb_type = FB_TEXT;
562 gfx_state.tg_fb.fb_height = TEXT_ROWS;
563 gfx_state.tg_fb.fb_width = TEXT_COLS;
564 gfx_state.tg_ctype = CT_INDEXED;
565 gfx_state.tg_mode = 3;
567 env_setenv("screen.textmode", EV_VOLATILE, "1", mode_set,
569 env_setenv("vbe_max_resolution", EV_VOLATILE, NULL, mode_set,
573 vbe = malloc(sizeof(*vbe));
578 if (vbe_mode == NULL) {
579 vbe_mode = malloc(sizeof(*vbe_mode));
580 if (vbe_mode == NULL) {
586 if (biosvbe_info(vbe) != VBE_SUCCESS) {
595 * Copy mode list. We must do this because some systems do
596 * corrupt the provided list (vbox 6.1 is one example).
598 p = ml = vbe_farptr(vbe->VideoModePtr);
599 while(*p++ != 0xFFFF)
602 vbe_mode_list_size = (uintptr_t)p - (uintptr_t)ml;
605 * Since vbe_init() is used only once at very start of the loader,
606 * we assume malloc will not fail there, but in case it does,
607 * we point vbe_mode_list to memory pointed by VideoModePtr.
609 vbe_mode_list = malloc(vbe_mode_list_size);
610 if (vbe_mode_list == NULL)
613 bcopy(ml, vbe_mode_list, vbe_mode_list_size);
615 /* reset VideoModePtr, to make sure, we only do use vbe_mode_list. */
616 vbe->VideoModePtr = 0;
618 /* vbe_set_mode() will set up the rest. */
624 return (gfx_state.tg_fb_type == FB_VBE);
628 vbe_set_palette(const struct paletteentry *entry, size_t slot)
630 struct paletteentry pe;
633 if (!vbe_check() || (vbe->Capabilities & VBE_CAP_DAC8) == 0)
636 if (gfx_state.tg_ctype != CT_INDEXED) {
640 pe.Blue = entry->Blue;
641 pe.Green = entry->Green;
643 pe.Reserved = entry->Reserved;
645 if (vbe->Capabilities & VBE_CAP_SNOW)
650 ret = biosvbe_palette_data(mode, slot, &pe);
652 return (ret == VBE_SUCCESS ? 0 : 1);
658 return (gfx_state.tg_mode);
662 vbe_set_mode(int modenum)
664 struct modeinfoblock mi;
670 ret = biosvbe_get_mode_info(modenum, &mi);
671 if (VBE_ERROR(ret)) {
672 printf("mode 0x%x invalid\n", modenum);
676 if (!vbe_mode_is_supported(&mi)) {
677 printf("mode 0x%x not supported\n", modenum);
681 /* calculate bytes per pixel */
682 switch (mi.BitsPerPixel) {
690 printf("BitsPerPixel %d is not supported\n", mi.BitsPerPixel);
694 ret = biosvbe_set_mode(modenum, NULL);
695 if (VBE_ERROR(ret)) {
696 printf("mode 0x%x could not be set\n", modenum);
700 gfx_state.tg_mode = modenum;
701 gfx_state.tg_fb_type = FB_VBE;
702 /* make sure we have current MI in vbestate */
703 memcpy(vbe_mode, &mi, sizeof (*vbe_mode));
705 gfx_state.tg_fb.fb_addr = (uint64_t)mi.PhysBasePtr & 0xffffffff;
706 gfx_state.tg_fb.fb_height = mi.YResolution;
707 gfx_state.tg_fb.fb_width = mi.XResolution;
708 gfx_state.tg_fb.fb_bpp = mi.BitsPerPixel;
710 free(gfx_state.tg_shadow_fb);
711 gfx_state.tg_shadow_fb = malloc(mi.YResolution * mi.XResolution *
712 sizeof(struct paletteentry));
714 /* Bytes per pixel */
715 bpp = roundup2(mi.BitsPerPixel, NBBY) / NBBY;
717 /* vbe_mode_is_supported() excludes the rest */
718 switch (mi.MemoryModel) {
720 gfx_state.tg_ctype = CT_INDEXED;
723 gfx_state.tg_ctype = CT_RGB;
727 #define COLOR_MASK(size, pos) (((1 << size) - 1) << pos)
728 if (gfx_state.tg_ctype == CT_INDEXED) {
729 gfx_state.tg_fb.fb_mask_red = COLOR_MASK(palette_format, 16);
730 gfx_state.tg_fb.fb_mask_green = COLOR_MASK(palette_format, 8);
731 gfx_state.tg_fb.fb_mask_blue = COLOR_MASK(palette_format, 0);
732 } else if (vbe->VbeVersion >= 0x300) {
733 gfx_state.tg_fb.fb_mask_red =
734 COLOR_MASK(mi.LinRedMaskSize, mi.LinRedFieldPosition);
735 gfx_state.tg_fb.fb_mask_green =
736 COLOR_MASK(mi.LinGreenMaskSize, mi.LinGreenFieldPosition);
737 gfx_state.tg_fb.fb_mask_blue =
738 COLOR_MASK(mi.LinBlueMaskSize, mi.LinBlueFieldPosition);
740 gfx_state.tg_fb.fb_mask_red =
741 COLOR_MASK(mi.RedMaskSize, mi.RedFieldPosition);
742 gfx_state.tg_fb.fb_mask_green =
743 COLOR_MASK(mi.GreenMaskSize, mi.GreenFieldPosition);
744 gfx_state.tg_fb.fb_mask_blue =
745 COLOR_MASK(mi.BlueMaskSize, mi.BlueFieldPosition);
747 gfx_state.tg_fb.fb_mask_reserved = ~(gfx_state.tg_fb.fb_mask_red |
748 gfx_state.tg_fb.fb_mask_green |
749 gfx_state.tg_fb.fb_mask_blue);
751 if (vbe->VbeVersion >= 0x300)
752 gfx_state.tg_fb.fb_stride = mi.LinBytesPerScanLine / bpp;
754 gfx_state.tg_fb.fb_stride = mi.BytesPerScanLine / bpp;
756 gfx_state.tg_fb.fb_size = mi.YResolution * gfx_state.tg_fb.fb_stride *
763 * Verify existence of mode number or find mode by
764 * dimensions. If depth is not given, walk values 32, 24, 16, 8.
767 vbe_find_mode_xydm(int x, int y, int depth, int m)
769 struct modeinfoblock mi;
772 int idx, nentries, i;
774 memset(vbe, 0, sizeof (*vbe));
775 if (biosvbe_info(vbe) != VBE_SUCCESS)
780 else if (depth == -1)
785 nentries = vbe_mode_list_size / sizeof(*vbe_mode_list);
787 for (idx = 0; idx < nentries; idx++) {
788 mode = vbe_mode_list[idx];
792 if (biosvbe_get_mode_info(mode, &mi) != VBE_SUCCESS) {
796 /* we only care about linear modes here */
797 if (vbe_mode_is_supported(&mi) == 0)
807 if (mi.XResolution == x &&
808 mi.YResolution == y &&
809 mi.BitsPerPixel == i)
822 vbe_find_mode(char *str)
826 if (!gfx_parse_mode_str(str, &x, &y, &depth))
829 return (vbe_find_mode_xydm(x, y, depth, -1));
833 vbe_dump_mode(int modenum, struct modeinfoblock *mi)
835 printf("0x%x=%dx%dx%d", modenum,
836 mi->XResolution, mi->YResolution, mi->BitsPerPixel);
840 vbe_get_edid(edid_res_list_t *res)
842 struct vesa_edid_info *edidp;
843 const uint8_t magic[] = EDID_MAGIC;
847 if (edid_info != NULL)
848 return (gfx_get_edid_resolution(edid_info, res));
850 ddc_caps = biosvbe_ddc_caps();
855 edidp = bio_alloc(sizeof(*edidp));
858 memset(edidp, 0, sizeof(*edidp));
860 if (VBE_ERROR(biosvbe_ddc_read_edid(0, edidp)))
863 if (memcmp(edidp, magic, sizeof(magic)) != 0)
866 /* Unknown EDID version. */
867 if (edidp->header.version != 1)
870 ret = gfx_get_edid_resolution(edidp, res);
871 edid_info = malloc(sizeof(*edid_info));
872 if (edid_info != NULL)
873 memcpy(edid_info, edidp, sizeof (*edid_info));
875 bio_free(edidp, sizeof(*edidp));
880 vbe_get_flatpanel(uint32_t *pwidth, uint32_t *pheight)
882 struct vesa_flat_panel_info *fp_info;
885 fp_info = bio_alloc(sizeof (*fp_info));
888 memset(fp_info, 0, sizeof (*fp_info));
890 if (VBE_ERROR(biosvbe_ddc_read_flat_panel_info(fp_info)))
893 *pwidth = fp_info->HSize;
894 *pheight = fp_info->VSize;
898 bio_free(fp_info, sizeof (*fp_info));
903 vbe_print_memory(unsigned vmem)
908 if (vmem >= 10240000) {
911 } else if (vmem >= 10000) {
915 printf("Total memory: %u%cB\n", vmem, unit);
919 vbe_print_vbe_info(struct vbeinfoblock *vbep)
921 char *oemstring = "";
922 char *oemvendor = "", *oemproductname = "", *oemproductrev = "";
924 if (vbep->OemStringPtr != 0)
925 oemstring = vbe_farptr(vbep->OemStringPtr);
927 if (vbep->OemVendorNamePtr != 0)
928 oemvendor = vbe_farptr(vbep->OemVendorNamePtr);
930 if (vbep->OemProductNamePtr != 0)
931 oemproductname = vbe_farptr(vbep->OemProductNamePtr);
933 if (vbep->OemProductRevPtr != 0)
934 oemproductrev = vbe_farptr(vbep->OemProductRevPtr);
936 printf("VESA VBE Version %d.%d\n%s\n", vbep->VbeVersion >> 8,
937 vbep->VbeVersion & 0xF, oemstring);
939 if (vbep->OemSoftwareRev != 0) {
940 printf("OEM Version %d.%d, %s (%s, %s)\n",
941 vbep->OemSoftwareRev >> 8, vbep->OemSoftwareRev & 0xF,
942 oemvendor, oemproductname, oemproductrev);
944 vbe_print_memory(vbep->TotalMemory << 16);
945 printf("Number of Image Pages: %d\n", vbe_mode->LinNumberOfImagePages);
948 /* List available modes, filter by depth. If depth is -1, list all. */
950 vbe_modelist(int depth)
952 struct modeinfoblock mi;
954 int nmodes, idx, nentries;
956 uint32_t width, height;
959 struct resolution *rp;
964 ddc_caps = biosvbe_ddc_caps();
973 edid = vbe_get_edid(&res);
976 while ((rp = TAILQ_FIRST(&res)) != NULL) {
977 printf(" %dx%d", rp->width, rp->height);
978 TAILQ_REMOVE(&res, rp, next);
983 printf(": no EDID information\n");
987 if (vbe_get_flatpanel(&width, &height))
988 printf(": Panel %dx%d\n", width, height);
991 memset(vbe, 0, sizeof (*vbe));
992 memcpy(vbe->VbeSignature, "VBE2", 4);
993 if (biosvbe_info(vbe) != VBE_SUCCESS)
995 if (memcmp(vbe->VbeSignature, "VESA", 4) != 0)
998 vbe_print_vbe_info(vbe);
1001 nentries = vbe_mode_list_size / sizeof(*vbe_mode_list);
1002 for (idx = 0; idx < nentries; idx++) {
1003 mode = vbe_mode_list[idx];
1007 if (biosvbe_get_mode_info(mode, &mi) != VBE_SUCCESS)
1010 /* we only care about linear modes here */
1011 if (vbe_mode_is_supported(&mi) == 0)
1014 /* apply requested filter */
1015 if (depth != -1 && mi.BitsPerPixel != depth)
1018 if (nmodes % 4 == 0)
1023 vbe_dump_mode(mode, &mi);
1029 printf("none found");
1034 vbe_print_mode(bool verbose __unused)
1036 int nc, mode, i, rc;
1040 memset(vbe, 0, sizeof (*vbe));
1041 if (biosvbe_info(vbe) != VBE_SUCCESS)
1044 vbe_print_vbe_info(vbe);
1046 if (biosvbe_get_mode(&mode) != VBE_SUCCESS) {
1047 printf("Error getting current VBE mode\n");
1051 if (biosvbe_get_mode_info(mode, vbe_mode) != VBE_SUCCESS ||
1052 vbe_mode_is_supported(vbe_mode) == 0) {
1053 printf("VBE mode (0x%x) is not framebuffer mode\n", mode);
1057 printf("\nCurrent VBE mode: ");
1058 vbe_dump_mode(mode, vbe_mode);
1061 printf("%ux%ux%u, stride=%u\n",
1062 gfx_state.tg_fb.fb_width,
1063 gfx_state.tg_fb.fb_height,
1064 gfx_state.tg_fb.fb_bpp,
1065 gfx_state.tg_fb.fb_stride *
1066 (roundup2(gfx_state.tg_fb.fb_bpp, NBBY) / NBBY));
1067 printf(" frame buffer: address=%jx, size=%jx\n",
1068 (uintmax_t)gfx_state.tg_fb.fb_addr,
1069 (uintmax_t)gfx_state.tg_fb.fb_size);
1071 if (vbe_mode->MemoryModel == 0x6) {
1072 printf(" color mask: R=%08x, G=%08x, B=%08x\n",
1073 gfx_state.tg_fb.fb_mask_red,
1074 gfx_state.tg_fb.fb_mask_green,
1075 gfx_state.tg_fb.fb_mask_blue);
1077 for (i = 0; i < nc; i++) {
1078 printf("%d: R=%02x, G=%02x, B=%02x %08x", i,
1079 (cmap[i] & gfx_state.tg_fb.fb_mask_red) >>
1080 ffs(gfx_state.tg_fb.fb_mask_red) - 1,
1081 (cmap[i] & gfx_state.tg_fb.fb_mask_green) >>
1082 ffs(gfx_state.tg_fb.fb_mask_green) - 1,
1083 (cmap[i] & gfx_state.tg_fb.fb_mask_blue) >>
1084 ffs(gfx_state.tg_fb.fb_mask_blue) - 1, cmap[i]);
1085 if (pager_output("\n") != 0)
1092 mode = 1; /* get DAC palette width */
1093 rc = biosvbe_palette_format(&mode);
1094 if (rc != VBE_SUCCESS)
1097 printf(" palette format: %x bits per primary\n", mode);
1102 for (i = 0; i < nc; i++) {
1103 printf("%d: R=%02x, G=%02x, B=%02x", i,
1104 pe8[i].Red, pe8[i].Green, pe8[i].Blue);
1105 if (pager_output("\n") != 0)
1112 * Try EDID preferred mode, if EDID or the suggested mode is not available,
1113 * then try flat panel information.
1114 * Fall back to VBE_DEFAULT_MODE.
1117 vbe_default_mode(void)
1119 edid_res_list_t res;
1120 struct resolution *rp;
1122 uint32_t width, height;
1125 vbe_get_max_resolution(&width, &height);
1126 if (width != 0 && height != 0)
1127 modenum = vbe_find_mode_xydm(width, height, -1, -1);
1130 if (vbe_get_edid(&res)) {
1131 while ((rp = TAILQ_FIRST(&res)) != NULL) {
1133 modenum = vbe_find_mode_xydm(
1134 rp->width, rp->height, -1, -1);
1136 TAILQ_REMOVE(&res, rp, next);
1142 vbe_get_flatpanel(&width, &height)) {
1143 modenum = vbe_find_mode_xydm(width, height, -1, -1);
1146 /* Still no mode? Fall back to default. */
1148 modenum = vbe_find_mode(VBE_DEFAULT_MODE);
1152 COMMAND_SET(vbe, "vbe", "vesa framebuffer mode management", command_vesa);
1155 command_vesa(int argc, char *argv[])
1158 int modenum = -1, n;
1166 if (strcmp(argv[1], "list") == 0) {
1168 if (argc != 2 && argc != 3)
1174 n = strtoul(arg, &cp, 0);
1175 if (errno != 0 || *arg == '\0' || cp[0] != '\0') {
1176 snprintf(command_errbuf,
1177 sizeof (command_errbuf),
1178 "depth should be an integer");
1186 if (strcmp(argv[1], "get") == 0) {
1187 bool verbose = false;
1190 if (argc > 3 || strcmp(argv[2], "-v") != 0)
1194 vbe_print_mode(verbose);
1198 if (strcmp(argv[1], "off") == 0) {
1202 if (gfx_state.tg_mode == VGA_TEXT_MODE)
1206 bios_text_font(true);
1207 bios_set_text_mode(VGA_TEXT_MODE);
1208 cons_update_mode(false);
1212 if (strcmp(argv[1], "on") == 0) {
1216 modenum = vbe_default_mode();
1218 snprintf(command_errbuf, sizeof (command_errbuf),
1219 "%s: no suitable VBE mode number found", argv[0]);
1222 } else if (strcmp(argv[1], "set") == 0) {
1226 if (strncmp(argv[2], "0x", 2) == 0) {
1229 n = strtoul(arg, &cp, 0);
1230 if (errno != 0 || *arg == '\0' || cp[0] != '\0') {
1231 snprintf(command_errbuf,
1232 sizeof (command_errbuf),
1233 "mode should be an integer");
1236 modenum = vbe_find_mode_xydm(0, 0, 0, n);
1237 } else if (strchr(argv[2], 'x') != NULL) {
1238 modenum = vbe_find_mode(argv[2]);
1245 snprintf(command_errbuf, sizeof (command_errbuf),
1246 "%s: mode %s not supported by firmware\n",
1251 if (modenum >= VESA_MODE_BASE) {
1252 if (gfx_state.tg_mode != modenum) {
1254 bios_text_font(false);
1255 vbe_set_mode(modenum);
1256 cons_update_mode(true);
1260 snprintf(command_errbuf, sizeof (command_errbuf),
1261 "%s: mode %s is not framebuffer mode\n", argv[0], argv[2]);
1266 snprintf(command_errbuf, sizeof (command_errbuf),
1267 "usage: %s on | off | get | list [depth] | "
1268 "set <display or VBE mode number>", argv[0]);