vbe.c revision 1.1 1 /* $NetBSD: vbe.c,v 1.1 2009/02/16 22:39:30 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
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 (strchr(arg, 'x') != NULL) {
340 modenum = vbe_find_mode(arg);
341 if (modenum == 0)
342 return;
343 } else
344 modenum = strtoul(arg, NULL, 0);
345 if (modenum >= 0x100) {
346 vbe_set_mode(modenum);
347 return;
348 }
349
350 printf("invalid flag, must be 'enabled', 'disabled', "
351 "or a valid VESA VBE mode number.\n");
352 }
353