1 /* $NetBSD: vbe.c,v 1.2 2009/02/17 23:17:39 jmcneill Exp $ */ 2 3 /*- 4 * Copyright (c) 2009 Jared D. McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * VESA BIOS Extensions routines 31 */ 32 33 #include <lib/libsa/stand.h> 34 #include <lib/libkern/libkern.h> 35 #include <machine/bootinfo.h> 36 #include "libi386.h" 37 #include "vbe.h" 38 39 extern const uint8_t rasops_cmap[]; 40 41 static int vbeverbose = 1; 42 43 static struct _vbestate { 44 int available; 45 } vbestate; 46 47 static void 48 vbe_dump(struct vbeinfoblock *vbe) 49 { 50 int mem = (int)vbe->TotalMemory * 64; 51 52 if (!vbeverbose) 53 return; 54 55 printf(">> VESA VBE Version %d.%d %d k\n", 56 vbe->VbeVersion >> 8, vbe->VbeVersion & 0xff, mem); 57 } 58 59 static int 60 vbe_mode_is_supported(struct modeinfoblock *mi) 61 { 62 if ((mi->ModeAttributes & 0x01) == 0) 63 return 0; /* mode not supported by hardware */ 64 if ((mi->ModeAttributes & 0x08) == 0) 65 return 0; /* linear fb not available */ 66 if ((mi->ModeAttributes & 0x10) == 0) 67 return 0; /* text mode */ 68 if (mi->NumberOfPlanes != 1) 69 return 0; /* planar mode not supported */ 70 if (mi->MemoryModel != 0x04 /* Packed pixel */ && 71 mi->MemoryModel != 0x06 /* Direct Color */) 72 return 0; /* unsupported pixel format */ 73 return 1; 74 } 75 76 void 77 vbe_init(void) 78 { 79 struct vbeinfoblock vbe; 80 81 memset(&vbe, 0, sizeof(vbe)); 82 memcpy(vbe.VbeSignature, "VBE2", 4); 83 if (biosvbe_info(&vbe) != 0x004f) 84 return; 85 if (memcmp(vbe.VbeSignature, "VESA", 4) != 0) { 86 printf("VESA VBE: bad signature %c%c%c%c\n", 87 vbe.VbeSignature[0], vbe.VbeSignature[1], 88 vbe.VbeSignature[2], vbe.VbeSignature[3]); 89 return; 90 } 91 92 vbe_dump(&vbe); 93 vbestate.available = 1; 94 } 95 96 int 97 vbe_available(void) 98 { 99 return vbestate.available; 100 } 101 102 int 103 vbe_set_palette(const uint8_t *cmap, int slot) 104 { 105 struct paletteentry pe; 106 int ret; 107 108 if (!vbestate.available) { 109 printf("VESA BIOS extensions not available\n"); 110 return 1; 111 } 112 113 pe.Blue = cmap[2] >> 2; 114 pe.Green = cmap[1] >> 2; 115 pe.Red = cmap[0] >> 2; 116 pe.Alignment = 0; 117 118 ret = biosvbe_palette_data(0x0600, slot, &pe); 119 120 return ret == 0x004f ? 0 : 1; 121 } 122 123 int 124 vbe_set_mode(int modenum) 125 { 126 struct modeinfoblock mi; 127 struct btinfo_framebuffer fb; 128 int ret, i; 129 130 if (!vbestate.available) { 131 printf("VESA BIOS extensions not available\n"); 132 return 1; 133 } 134 135 ret = biosvbe_get_mode_info(modenum, &mi); 136 if (ret != 0x004f) { 137 printf("VESA VBE mode 0x%x is invalid.\n", modenum); 138 return 1; 139 } 140 141 if (!vbe_mode_is_supported(&mi)) { 142 printf("VESA VBE mode 0x%x is not supported.\n", modenum); 143 return 1; 144 } 145 146 ret = biosvbe_set_mode(modenum); 147 if (ret != 0x004f) { 148 printf("VESA VBE mode 0x%x could not be set.\n", modenum); 149 return 1; 150 } 151 152 /* Setup palette for packed pixel mode */ 153 if (mi.MemoryModel == 0x04) 154 for (i = 0; i < 256; i++) 155 vbe_set_palette(&rasops_cmap[i * 3], i); 156 157 fb.physaddr = (uint64_t)mi.PhysBasePtr & 0xffffffff; 158 fb.width = mi.XResolution; 159 fb.height = mi.YResolution; 160 fb.stride = mi.BytesPerScanLine; 161 fb.depth = mi.BitsPerPixel; 162 fb.flags = 0; 163 fb.rnum = mi.RedMaskSize; 164 fb.rpos = mi.RedFieldPosition; 165 fb.gnum = mi.GreenMaskSize; 166 fb.gpos = mi.GreenFieldPosition; 167 fb.bnum = mi.BlueMaskSize; 168 fb.bpos = mi.BlueFieldPosition; 169 170 framebuffer_configure(&fb); 171 172 return 0; 173 } 174 175 static void * 176 vbe_farptr(uint32_t farptr) 177 { 178 return VBEPHYPTR((((farptr & 0xffff0000) >> 12) + (farptr & 0xffff))); 179 } 180 181 static int 182 vbe_parse_mode_str(char *str, int *x, int *y, int *bpp) 183 { 184 char *p; 185 186 p = str; 187 *x = strtoul(p, NULL, 0); 188 if (*x == 0) 189 return 0; 190 p = strchr(p, 'x'); 191 if (!p) 192 return 0; 193 ++p; 194 *y = strtoul(p, NULL, 0); 195 if (*y == 0) 196 return 0; 197 p = strchr(p, 'x'); 198 if (!p) 199 *bpp = 8; 200 else { 201 ++p; 202 *bpp = strtoul(p, NULL, 0); 203 if (*bpp == 0) 204 return 0; 205 } 206 207 return 1; 208 } 209 210 static int 211 vbe_find_mode(char *str) 212 { 213 struct vbeinfoblock vbe; 214 struct modeinfoblock mi; 215 uint32_t farptr; 216 uint16_t mode; 217 int x, y, bpp; 218 int safety = 0; 219 220 if (!vbe_parse_mode_str(str, &x, &y, &bpp)) 221 return 0; 222 223 memset(&vbe, 0, sizeof(vbe)); 224 memcpy(vbe.VbeSignature, "VBE2", 4); 225 if (biosvbe_info(&vbe) != 0x004f) 226 return 0; 227 if (memcmp(vbe.VbeSignature, "VESA", 4) != 0) 228 return 0; 229 farptr = vbe.VideoModePtr; 230 if (farptr == 0) 231 return 0; 232 233 while ((mode = *(uint16_t *)vbe_farptr(farptr)) != 0xffff) { 234 safety++; 235 farptr += 2; 236 if (safety == 100) 237 return 0; 238 if (biosvbe_get_mode_info(mode, &mi) != 0x004f) 239 continue; 240 /* we only care about linear modes here */ 241 if (vbe_mode_is_supported(&mi) == 0) 242 continue; 243 safety = 0; 244 if (mi.XResolution == x && 245 mi.YResolution == y && 246 mi.BitsPerPixel == bpp) 247 return mode; 248 } 249 250 printf("VESA VBE BIOS does not support %s\n", str); 251 return 0; 252 } 253 254 static void 255 vbe_dump_mode(int modenum, struct modeinfoblock *mi) 256 { 257 printf("0x%x=%dx%dx%d", modenum, 258 mi->XResolution, mi->YResolution, mi->BitsPerPixel); 259 } 260 261 void 262 vbe_modelist(void) 263 { 264 struct vbeinfoblock vbe; 265 struct modeinfoblock mi; 266 uint32_t farptr; 267 uint16_t mode; 268 int nmodes = 0, safety = 0; 269 270 if (!vbestate.available) { 271 printf("VESA BIOS extensions not available\n"); 272 return; 273 } 274 275 printf("Modes: "); 276 memset(&vbe, 0, sizeof(vbe)); 277 memcpy(vbe.VbeSignature, "VBE2", 4); 278 if (biosvbe_info(&vbe) != 0x004f) 279 goto done; 280 if (memcmp(vbe.VbeSignature, "VESA", 4) != 0) 281 goto done; 282 farptr = vbe.VideoModePtr; 283 if (farptr == 0) 284 goto done; 285 286 while ((mode = *(uint16_t *)vbe_farptr(farptr)) != 0xffff) { 287 safety++; 288 farptr += 2; 289 if (safety == 100) { 290 printf("[garbage] "); 291 break; 292 } 293 if (biosvbe_get_mode_info(mode, &mi) != 0x004f) 294 continue; 295 /* we only care about linear modes here */ 296 if (vbe_mode_is_supported(&mi) == 0) 297 continue; 298 safety = 0; 299 if (nmodes % 4 == 0) 300 printf("\n"); 301 else 302 printf(" "); 303 vbe_dump_mode(mode, &mi); 304 nmodes++; 305 } 306 307 done: 308 if (nmodes == 0) 309 printf("none found"); 310 printf("\n"); 311 } 312 313 void 314 command_vesa(char *cmd) 315 { 316 char arg[20]; 317 int modenum; 318 319 if (!vbe_available()) { 320 printf("VESA VBE not available\n"); 321 return; 322 } 323 324 strlcpy(arg, cmd, sizeof(arg)); 325 326 if (strcmp(arg, "list") == 0) { 327 vbe_modelist(); 328 return; 329 } 330 331 if (strcmp(arg, "disabled") == 0 || strcmp(arg, "off") == 0) { 332 framebuffer_configure(NULL); 333 biosvideomode(); 334 return; 335 } 336 337 if (strcmp(arg, "enabled") == 0 || strcmp(arg, "on") == 0) 338 modenum = VBE_DEFAULT_MODE; 339 else if (strncmp(arg, "0x", 2) == 0) 340 modenum = strtoul(arg, NULL, 0); 341 else if (strchr(arg, 'x') != NULL) { 342 modenum = vbe_find_mode(arg); 343 if (modenum == 0) 344 return; 345 } else 346 modenum = 0; 347 348 if (modenum >= 0x100) { 349 vbe_set_mode(modenum); 350 return; 351 } 352 353 printf("invalid flag, must be 'enabled', 'disabled', " 354 "a display mode, or a valid VESA VBE mode number.\n"); 355 } 356