1 /*
2 * Copyright (c) 2004-2005 Fabrice Bellard
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License V2
6 * as published by the Free Software Foundation
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
17
18 #include <stdlib.h>
19 #include "bios.h"
20
21 /* VGA init. We use the Bochs VESA VBE extensions */
22 #define VBE_DISPI_INDEX_ID 0x0
23 #define VBE_DISPI_INDEX_XRES 0x1
24 #define VBE_DISPI_INDEX_YRES 0x2
25 #define VBE_DISPI_INDEX_BPP 0x3
26 #define VBE_DISPI_INDEX_ENABLE 0x4
27 #define VBE_DISPI_INDEX_BANK 0x5
28 #define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
29 #define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
30 #define VBE_DISPI_INDEX_X_OFFSET 0x8
31 #define VBE_DISPI_INDEX_Y_OFFSET 0x9
32 #define VBE_DISPI_INDEX_NB 0xa
33
34 #define VBE_DISPI_ID0 0xB0C0
35 #define VBE_DISPI_ID1 0xB0C1
36 #define VBE_DISPI_ID2 0xB0C2
37
38 #define VBE_DISPI_DISABLED 0x00
39 #define VBE_DISPI_ENABLED 0x01
40 #define VBE_DISPI_LFB_ENABLED 0x40
41 #define VBE_DISPI_NOCLEARMEM 0x80
42
43 #define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000
44
45 static void vga_text_init(void);
46
47 unsigned long vga_fb_phys_addr;
48 int vga_fb_width;
49 int vga_fb_height;
50 int vga_fb_linesize;
51 int vga_fb_bpp;
52 int vga_fb_depth;
53 uint8_t rgb_to_index[256];
54
vbe_outw(int index,int val)55 static void vbe_outw(int index, int val)
56 {
57 outw(0x1ce, index);
58 outw(0x1d0, val);
59 }
60
61 /* init VGA in standard state for PREP boot */
vga_prep_init(void)62 void vga_prep_init(void)
63 {
64 outb(0x3c0, 0x00); /* set blanking */
65 vbe_outw(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED);
66 }
67
68 /* build standard RGB palette */
vga_build_rgb_palette(void)69 void vga_build_rgb_palette(void)
70 {
71 static const uint8_t pal_value[6] = { 0x00, 0x33, 0x66, 0x99, 0xcc, 0xff };
72 int i, r, g, b;
73
74 i = 0;
75 for(r = 0; r < 6; r++) {
76 for(g = 0; g < 6; g++) {
77 for(b = 0; b < 6; b++) {
78 vga_set_palette(i, RGB(pal_value[r], pal_value[g],
79 pal_value[b]));
80 i++;
81 }
82 }
83 }
84 for(i = 0; i < 256; i++) {
85 rgb_to_index[i] = ((i * 5) + 128) / 255;
86 }
87 }
88
vga_set_address(uint32_t address)89 void vga_set_address (uint32_t address)
90 {
91 vga_fb_phys_addr = address;
92 }
93
94 /* depth = 8, 15, 16 or 32 */
vga_set_mode(int width,int height,int depth)95 void vga_set_mode(int width, int height, int depth)
96 {
97 vbe_outw(VBE_DISPI_INDEX_XRES, width);
98 vbe_outw(VBE_DISPI_INDEX_YRES, height);
99 vbe_outw(VBE_DISPI_INDEX_BPP, depth);
100 vbe_outw(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED);
101 outb(0x3c0, 0x20); /* disable blanking */
102
103 if (vga_fb_phys_addr == 0x00000000)
104 vga_fb_phys_addr = VBE_DISPI_LFB_PHYSICAL_ADDRESS;
105 vga_fb_width = width;
106 vga_fb_height = height;
107 vga_fb_depth = depth;
108 vga_fb_bpp = (depth + 7) >> 3;
109 vga_fb_linesize = width * vga_fb_bpp;
110
111 if (depth == 8)
112 vga_build_rgb_palette();
113 vga_text_init();
114 }
115
116 /* for depth = 8 mode, set a hardware palette entry */
vga_set_palette(int i,unsigned int rgba)117 void vga_set_palette(int i, unsigned int rgba)
118 {
119 unsigned int r, g, b;
120
121 r = (rgba >> 16) & 0xff;
122 g = (rgba >> 8) & 0xff;
123 b = (rgba) & 0xff;
124 outb(0x3c8, i);
125 outb(0x3c9, r >> 2);
126 outb(0x3c9, g >> 2);
127 outb(0x3c9, b >> 2);
128 }
129
130 /* convert a RGBA color to a color index usable in graphic primitives */
vga_get_color(unsigned int rgba)131 unsigned int vga_get_color(unsigned int rgba)
132 {
133 unsigned int r, g, b, color;
134
135 switch(vga_fb_depth) {
136 case 8:
137 r = (rgba >> 16) & 0xff;
138 g = (rgba >> 8) & 0xff;
139 b = (rgba) & 0xff;
140 color = (rgb_to_index[r] * 6 * 6) +
141 (rgb_to_index[g] * 6) +
142 (rgb_to_index[b]);
143 break;
144 case 15:
145 r = (rgba >> 16) & 0xff;
146 g = (rgba >> 8) & 0xff;
147 b = (rgba) & 0xff;
148 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
149 break;
150 case 16:
151 r = (rgba >> 16) & 0xff;
152 g = (rgba >> 8) & 0xff;
153 b = (rgba) & 0xff;
154 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
155 break;
156 case 32:
157 default:
158 color = rgba;
159 break;
160 }
161 return color;
162 }
163
vga_draw_buf(const void * buf,int buf_linesize,int posx,int posy,int width,int height)164 void vga_draw_buf (const void *buf, int buf_linesize,
165 int posx, int posy, int width, int height)
166 {
167 const uint8_t *s;
168 uint8_t *d;
169 int y, wb;
170
171 s = buf;
172 d = (uint8_t *)vga_fb_phys_addr +
173 vga_fb_linesize * posy + vga_fb_bpp * posx;
174 wb = width * vga_fb_bpp;
175 for (y = 0; y < height; y++) {
176 memcpy(d, s, wb);
177 s += buf_linesize;
178 d += vga_fb_linesize;
179 }
180 }
181
vga_fill_rect(int posx,int posy,int width,int height,uint32_t color)182 void vga_fill_rect (int posx, int posy, int width, int height, uint32_t color)
183 {
184 uint8_t *d, *d1;
185 int x, y;
186
187 d1 = (uint8_t *)vga_fb_phys_addr +
188 vga_fb_linesize * posy + vga_fb_bpp * posx;
189 for (y = 0; y < height; y++) {
190 d = d1;
191 switch(vga_fb_bpp) {
192 case 1:
193 for (x = 0; x < width; x++) {
194 *((uint8_t *)d) = color;
195 d++;
196 }
197 break;
198 case 2:
199 for (x = 0; x < width; x++) {
200 *((uint16_t *)d) = color;
201 d += 2;
202 }
203 break;
204 case 4:
205 for (x = 0; x < width; x++) {
206 *((uint32_t *)d) = color;
207 d += 4;
208 }
209 break;
210 }
211 d1 += vga_fb_linesize;
212 }
213 }
214
215 /* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
vga_bitblt(int xs,int ys,int xd,int yd,int w,int h)216 void vga_bitblt(int xs, int ys, int xd, int yd, int w, int h)
217 {
218 const uint8_t *s;
219 uint8_t *d;
220 int wb, y;
221
222 wb = w * vga_fb_bpp;
223 if (yd <= ys) {
224 s = (uint8_t *)vga_fb_phys_addr +
225 vga_fb_linesize * ys + vga_fb_bpp * xs;
226 d = (uint8_t *)vga_fb_phys_addr +
227 vga_fb_linesize * yd + vga_fb_bpp * xd;
228 for (y = 0; y < h; y++) {
229 memmove(d, s, wb);
230 d += vga_fb_linesize;
231 s += vga_fb_linesize;
232 }
233 } else {
234 s = (uint8_t *)vga_fb_phys_addr +
235 vga_fb_linesize * (ys + h - 1) + vga_fb_bpp * xs;
236 d = (uint8_t *)vga_fb_phys_addr +
237 vga_fb_linesize * (yd + h - 1) + vga_fb_bpp * xd;
238 for (y = 0; y < h; y++) {
239 memmove(d, s, wb);
240 d -= vga_fb_linesize;
241 s -= vga_fb_linesize;
242 }
243 }
244 }
245
246 /***********************************************************/
247 /* basic char display */
248
249 #define FONT_HEIGHT 16
250 #define FONT_WIDTH 8
251
252 #include "vgafont.h"
253
254 #define cbswap_32(__x) \
255 ((uint32_t)( \
256 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
257 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
258 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
259 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
260
261 /* XXX: endianness */
262 #if 0
263 #define PAT(x) cbswap_32(x)
264 #else
265 #define PAT(x) x
266 #endif
267
268 static const uint32_t dmask16[16] = {
269 PAT(0x00000000),
270 PAT(0x000000ff),
271 PAT(0x0000ff00),
272 PAT(0x0000ffff),
273 PAT(0x00ff0000),
274 PAT(0x00ff00ff),
275 PAT(0x00ffff00),
276 PAT(0x00ffffff),
277 PAT(0xff000000),
278 PAT(0xff0000ff),
279 PAT(0xff00ff00),
280 PAT(0xff00ffff),
281 PAT(0xffff0000),
282 PAT(0xffff00ff),
283 PAT(0xffffff00),
284 PAT(0xffffffff),
285 };
286
287 static const uint32_t dmask4[4] = {
288 PAT(0x00000000),
289 PAT(0x0000ffff),
290 PAT(0xffff0000),
291 PAT(0xffffffff),
292 };
293
294 int text_width, text_height, text_fgcol, text_bgcol, text_x, text_y;
295
vga_text_init(void)296 static void vga_text_init(void)
297 {
298 text_width = vga_fb_width / FONT_WIDTH;
299 text_height = vga_fb_height / FONT_HEIGHT;
300 text_x = 0;
301 text_y = 0;
302 vga_text_set_fgcol(RGB(0xff, 0xff, 0xff));
303 vga_text_set_bgcol(RGB(0x00, 0x00, 0x00));
304 }
305
col_expand(unsigned int col)306 static inline unsigned int col_expand(unsigned int col)
307 {
308 switch(vga_fb_bpp) {
309 case 1:
310 col |= col << 8;
311 col |= col << 16;
312 break;
313 case 2:
314 col |= col << 16;
315 break;
316 default:
317 text_fgcol = 0xffffff;
318 break;
319 }
320
321 return col;
322 }
323
vga_text_set_fgcol(unsigned int rgba)324 void vga_text_set_fgcol(unsigned int rgba)
325 {
326 text_fgcol = col_expand(vga_get_color(rgba));
327 }
328
vga_text_set_bgcol(unsigned int rgba)329 void vga_text_set_bgcol(unsigned int rgba)
330 {
331 text_bgcol = col_expand(vga_get_color(rgba));
332 }
333
vga_putcharxy(int x,int y,int ch,unsigned int fgcol,unsigned int bgcol)334 void vga_putcharxy(int x, int y, int ch,
335 unsigned int fgcol, unsigned int bgcol)
336 {
337 uint8_t *d;
338 const uint8_t *font_ptr;
339 unsigned int font_data, linesize, xorcol;
340 int i;
341
342 d = (uint8_t *)vga_fb_phys_addr +
343 vga_fb_linesize * y * FONT_HEIGHT + vga_fb_bpp * x * FONT_WIDTH;
344 linesize = vga_fb_linesize;
345 font_ptr = vgafont16 + FONT_HEIGHT * ch;
346 xorcol = bgcol ^ fgcol;
347 switch(vga_fb_depth) {
348 case 8:
349 for(i = 0; i < FONT_HEIGHT; i++) {
350 font_data = *font_ptr++;
351 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
352 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
353 d += linesize;
354 }
355 break;
356 case 16:
357 case 15:
358 for(i = 0; i < FONT_HEIGHT; i++) {
359 font_data = *font_ptr++;
360 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
361 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
362 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
363 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
364 d += linesize;
365 }
366 break;
367 case 32:
368 for(i = 0; i < FONT_HEIGHT; i++) {
369 font_data = *font_ptr++;
370 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
371 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
372 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
373 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
374 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
375 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
376 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
377 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
378 d += linesize;
379 }
380 break;
381 }
382 }
383
vga_put_lf(void)384 static void vga_put_lf(void)
385 {
386 text_x = 0;
387 text_y++;
388 if (text_y >= text_height) {
389 text_y = text_height - 1;
390 vga_bitblt(0, FONT_HEIGHT, 0, 0,
391 text_width * FONT_WIDTH,
392 (text_height - 1) * FONT_HEIGHT);
393 vga_fill_rect(0, (text_height - 1) * FONT_HEIGHT,
394 text_width * FONT_WIDTH, FONT_HEIGHT, text_bgcol);
395 }
396 }
397
vga_putchar(int ch)398 void vga_putchar(int ch)
399 {
400 if (ch == '\r') {
401 text_x = 0;
402 } else if (ch == '\n') {
403 vga_put_lf();
404 } else if (ch == '\b') {
405 if (text_x == 0) {
406 if (text_y != 0) {
407 text_x = text_width;
408 text_y--;
409 goto eat_char;
410 }
411 } else {
412 eat_char:
413 vga_putcharxy(--text_x, text_y, ' ', text_fgcol, text_bgcol);
414 }
415 } else {
416 vga_putcharxy(text_x, text_y, ch, text_fgcol, text_bgcol);
417 text_x++;
418 if (text_x >= text_width)
419 vga_put_lf();
420 }
421 }
422
vga_puts(const char * s)423 void vga_puts(const char *s)
424 {
425 while (*s) {
426 vga_putchar(*(uint8_t *)s);
427 s++;
428 }
429 }
430