vbe.c revision 1.3 1 /* $NetBSD: vbe.c,v 1.3 2009/08/24 02:15:46 jmcneill Exp $ */
2
3 /*-
4 * Copyright (c) 2009 Jared D. McNeill <jmcneill (at) 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 fb.vbemode = modenum;
170
171 framebuffer_configure(&fb);
172
173 return 0;
174 }
175
176 static void *
177 vbe_farptr(uint32_t farptr)
178 {
179 return VBEPHYPTR((((farptr & 0xffff0000) >> 12) + (farptr & 0xffff)));
180 }
181
182 static int
183 vbe_parse_mode_str(char *str, int *x, int *y, int *bpp)
184 {
185 char *p;
186
187 p = str;
188 *x = strtoul(p, NULL, 0);
189 if (*x == 0)
190 return 0;
191 p = strchr(p, 'x');
192 if (!p)
193 return 0;
194 ++p;
195 *y = strtoul(p, NULL, 0);
196 if (*y == 0)
197 return 0;
198 p = strchr(p, 'x');
199 if (!p)
200 *bpp = 8;
201 else {
202 ++p;
203 *bpp = strtoul(p, NULL, 0);
204 if (*bpp == 0)
205 return 0;
206 }
207
208 return 1;
209 }
210
211 static int
212 vbe_find_mode(char *str)
213 {
214 struct vbeinfoblock vbe;
215 struct modeinfoblock mi;
216 uint32_t farptr;
217 uint16_t mode;
218 int x, y, bpp;
219 int safety = 0;
220
221 if (!vbe_parse_mode_str(str, &x, &y, &bpp))
222 return 0;
223
224 memset(&vbe, 0, sizeof(vbe));
225 memcpy(vbe.VbeSignature, "VBE2", 4);
226 if (biosvbe_info(&vbe) != 0x004f)
227 return 0;
228 if (memcmp(vbe.VbeSignature, "VESA", 4) != 0)
229 return 0;
230 farptr = vbe.VideoModePtr;
231 if (farptr == 0)
232 return 0;
233
234 while ((mode = *(uint16_t *)vbe_farptr(farptr)) != 0xffff) {
235 safety++;
236 farptr += 2;
237 if (safety == 100)
238 return 0;
239 if (biosvbe_get_mode_info(mode, &mi) != 0x004f)
240 continue;
241 /* we only care about linear modes here */
242 if (vbe_mode_is_supported(&mi) == 0)
243 continue;
244 safety = 0;
245 if (mi.XResolution == x &&
246 mi.YResolution == y &&
247 mi.BitsPerPixel == bpp)
248 return mode;
249 }
250
251 printf("VESA VBE BIOS does not support %s\n", str);
252 return 0;
253 }
254
255 static void
256 vbe_dump_mode(int modenum, struct modeinfoblock *mi)
257 {
258 printf("0x%x=%dx%dx%d", modenum,
259 mi->XResolution, mi->YResolution, mi->BitsPerPixel);
260 }
261
262 void
263 vbe_modelist(void)
264 {
265 struct vbeinfoblock vbe;
266 struct modeinfoblock mi;
267 uint32_t farptr;
268 uint16_t mode;
269 int nmodes = 0, safety = 0;
270
271 if (!vbestate.available) {
272 printf("VESA BIOS extensions not available\n");
273 return;
274 }
275
276 printf("Modes: ");
277 memset(&vbe, 0, sizeof(vbe));
278 memcpy(vbe.VbeSignature, "VBE2", 4);
279 if (biosvbe_info(&vbe) != 0x004f)
280 goto done;
281 if (memcmp(vbe.VbeSignature, "VESA", 4) != 0)
282 goto done;
283 farptr = vbe.VideoModePtr;
284 if (farptr == 0)
285 goto done;
286
287 while ((mode = *(uint16_t *)vbe_farptr(farptr)) != 0xffff) {
288 safety++;
289 farptr += 2;
290 if (safety == 100) {
291 printf("[garbage] ");
292 break;
293 }
294 if (biosvbe_get_mode_info(mode, &mi) != 0x004f)
295 continue;
296 /* we only care about linear modes here */
297 if (vbe_mode_is_supported(&mi) == 0)
298 continue;
299 safety = 0;
300 if (nmodes % 4 == 0)
301 printf("\n");
302 else
303 printf(" ");
304 vbe_dump_mode(mode, &mi);
305 nmodes++;
306 }
307
308 done:
309 if (nmodes == 0)
310 printf("none found");
311 printf("\n");
312 }
313
314 void
315 command_vesa(char *cmd)
316 {
317 char arg[20];
318 int modenum;
319
320 if (!vbe_available()) {
321 printf("VESA VBE not available\n");
322 return;
323 }
324
325 strlcpy(arg, cmd, sizeof(arg));
326
327 if (strcmp(arg, "list") == 0) {
328 vbe_modelist();
329 return;
330 }
331
332 if (strcmp(arg, "disabled") == 0 || strcmp(arg, "off") == 0) {
333 framebuffer_configure(NULL);
334 biosvideomode();
335 return;
336 }
337
338 if (strcmp(arg, "enabled") == 0 || strcmp(arg, "on") == 0)
339 modenum = VBE_DEFAULT_MODE;
340 else if (strncmp(arg, "0x", 2) == 0)
341 modenum = strtoul(arg, NULL, 0);
342 else if (strchr(arg, 'x') != NULL) {
343 modenum = vbe_find_mode(arg);
344 if (modenum == 0)
345 return;
346 } else
347 modenum = 0;
348
349 if (modenum >= 0x100) {
350 vbe_set_mode(modenum);
351 return;
352 }
353
354 printf("invalid flag, must be 'enabled', 'disabled', "
355 "a display mode, or a valid VESA VBE mode number.\n");
356 }
357