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