Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


imported SEABIOS source tree
[palacios.git] / bios / seabios / vgasrc / vgafb.c
1 // Code for manipulating VGA framebuffers.
2 //
3 // Copyright (C) 2009  Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2001-2008 the LGPL VGABios developers Team
5 //
6 // This file may be distributed under the terms of the GNU LGPLv3 license.
7
8 #include "biosvar.h" // GET_BDA
9 #include "util.h" // memset_far
10 #include "vgatables.h" // find_vga_entry
11
12
13 /****************************************************************
14  * Screen scrolling
15  ****************************************************************/
16
17 static inline void *
18 memcpy_stride(u16 seg, void *dst, void *src, int copylen, int stride, int lines)
19 {
20     for (; lines; lines--, dst+=stride, src+=stride)
21         memcpy_far(seg, dst, seg, src, copylen);
22     return dst;
23 }
24
25 static inline void
26 memset_stride(u16 seg, void *dst, u8 val, int setlen, int stride, int lines)
27 {
28     for (; lines; lines--, dst+=stride)
29         memset_far(seg, dst, val, setlen);
30 }
31
32 static inline void
33 memset16_stride(u16 seg, void *dst, u16 val, int setlen, int stride, int lines)
34 {
35     for (; lines; lines--, dst+=stride)
36         memset16_far(seg, dst, val, setlen);
37 }
38
39 static void
40 scroll_pl4(struct vgamode_s *vmode_g, int nblines, int attr
41            , struct cursorpos ul, struct cursorpos lr)
42 {
43     struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
44     u8 cheight = GET_GLOBAL(vparam_g->cheight);
45     int stride = GET_BDA(video_cols);
46     void *src_far, *dest_far;
47     if (nblines >= 0) {
48         dest_far = (void*)(ul.y * cheight * stride + ul.x);
49         src_far = dest_far + nblines * cheight * stride;
50     } else {
51         // Scroll down
52         nblines = -nblines;
53         dest_far = (void*)(lr.y * cheight * stride + ul.x);
54         src_far = dest_far - nblines * cheight * stride;
55         stride = -stride;
56     }
57     int cols = lr.x - ul.x + 1;
58     int rows = lr.y - ul.y + 1;
59     if (nblines < rows) {
60         vgahw_grdc_write(0x05, 0x01);
61         dest_far = memcpy_stride(SEG_GRAPH, dest_far, src_far, cols, stride
62                                  , (rows - nblines) * cheight);
63     }
64     if (attr < 0)
65         attr = 0;
66     vgahw_grdc_write(0x05, 0x02);
67     memset_stride(SEG_GRAPH, dest_far, attr, cols, stride, nblines * cheight);
68     vgahw_grdc_write(0x05, 0x00);
69 }
70
71 static void
72 scroll_cga(struct vgamode_s *vmode_g, int nblines, int attr
73             , struct cursorpos ul, struct cursorpos lr)
74 {
75     struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
76     u8 cheight = GET_GLOBAL(vparam_g->cheight);
77     u8 bpp = GET_GLOBAL(vmode_g->pixbits);
78     int stride = GET_BDA(video_cols) * bpp;
79     void *src_far, *dest_far;
80     if (nblines >= 0) {
81         dest_far = (void*)(ul.y * cheight * stride + ul.x * bpp);
82         src_far = dest_far + nblines * cheight * stride;
83     } else {
84         // Scroll down
85         nblines = -nblines;
86         dest_far = (void*)(lr.y * cheight * stride + ul.x * bpp);
87         src_far = dest_far - nblines * cheight * stride;
88         stride = -stride;
89     }
90     int cols = (lr.x - ul.x + 1) * bpp;
91     int rows = lr.y - ul.y + 1;
92     if (nblines < rows) {
93         memcpy_stride(SEG_CTEXT, dest_far + 0x2000, src_far + 0x2000, cols
94                       , stride, (rows - nblines) * cheight / 2);
95         dest_far = memcpy_stride(SEG_CTEXT, dest_far, src_far, cols
96                                  , stride, (rows - nblines) * cheight / 2);
97     }
98     if (attr < 0)
99         attr = 0;
100     memset_stride(SEG_CTEXT, dest_far + 0x2000, attr, cols
101                   , stride, nblines * cheight / 2);
102     memset_stride(SEG_CTEXT, dest_far, attr, cols
103                   , stride, nblines * cheight / 2);
104 }
105
106 static void
107 scroll_text(struct vgamode_s *vmode_g, int nblines, int attr
108             , struct cursorpos ul, struct cursorpos lr)
109 {
110     u16 nbrows = GET_BDA(video_rows) + 1;
111     u16 nbcols = GET_BDA(video_cols);
112     void *src_far, *dest_far = (void*)SCREEN_MEM_START(nbcols, nbrows, ul.page);
113     int stride = nbcols * 2;
114     if (nblines >= 0) {
115         dest_far += ul.y * stride + ul.x * 2;
116         src_far = dest_far + nblines * stride;
117     } else {
118         // Scroll down
119         nblines = -nblines;
120         dest_far += lr.y * stride + ul.x * 2;
121         src_far = dest_far - nblines * stride;
122         stride = -stride;
123     }
124     int cols = (lr.x - ul.x + 1) * 2;
125     int rows = lr.y - ul.y + 1;
126     u16 seg = GET_GLOBAL(vmode_g->sstart);
127     if (nblines < rows)
128         dest_far = memcpy_stride(seg, dest_far, src_far, cols, stride
129                                  , (rows - nblines));
130     if (attr < 0)
131         attr = 0x07;
132     attr = (attr << 8) | ' ';
133     memset16_stride(seg, dest_far, attr, cols, stride, nblines);
134 }
135
136 void
137 vgafb_scroll(int nblines, int attr, struct cursorpos ul, struct cursorpos lr)
138 {
139     // Get the mode
140     struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
141     if (!vmode_g)
142         return;
143
144     // FIXME gfx mode not complete
145     switch (GET_GLOBAL(vmode_g->memmodel)) {
146     case CTEXT:
147     case MTEXT:
148         scroll_text(vmode_g, nblines, attr, ul, lr);
149         break;
150     case PLANAR4:
151     case PLANAR1:
152         scroll_pl4(vmode_g, nblines, attr, ul, lr);
153         break;
154     case CGA:
155         scroll_cga(vmode_g, nblines, attr, ul, lr);
156         break;
157     default:
158         dprintf(1, "Scroll in graphics mode\n");
159     }
160 }
161
162 void
163 clear_screen(struct vgamode_s *vmode_g)
164 {
165     switch (GET_GLOBAL(vmode_g->memmodel)) {
166     case CTEXT:
167     case MTEXT:
168         memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0720, 32*1024);
169         break;
170     case CGA:
171         memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 32*1024);
172         break;
173     default:
174         // XXX - old code gets/sets/restores sequ register 2 to 0xf -
175         // but it should always be 0xf anyway.
176         memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 64*1024);
177     }
178 }
179
180
181 /****************************************************************
182  * Read/write characters to screen
183  ****************************************************************/
184
185 static void
186 write_gfx_char_pl4(struct vgamode_s *vmode_g
187                    , struct cursorpos cp, struct carattr ca)
188 {
189     u16 nbcols = GET_BDA(video_cols);
190     if (cp.x >= nbcols)
191         return;
192
193     struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
194     u8 cheight = GET_GLOBAL(vparam_g->cheight);
195     u8 *fdata_g;
196     switch (cheight) {
197     case 14:
198         fdata_g = vgafont14;
199         break;
200     case 16:
201         fdata_g = vgafont16;
202         break;
203     default:
204         fdata_g = vgafont8;
205     }
206     u16 addr = cp.x + cp.y * cheight * nbcols;
207     u16 src = ca.car * cheight;
208     vgahw_sequ_write(0x02, 0x0f);
209     vgahw_grdc_write(0x05, 0x02);
210     if (ca.attr & 0x80)
211         vgahw_grdc_write(0x03, 0x18);
212     else
213         vgahw_grdc_write(0x03, 0x00);
214     u8 i;
215     for (i = 0; i < cheight; i++) {
216         u8 *dest_far = (void*)(addr + i * nbcols);
217         u8 j;
218         for (j = 0; j < 8; j++) {
219             u8 mask = 0x80 >> j;
220             vgahw_grdc_write(0x08, mask);
221             GET_FARVAR(SEG_GRAPH, *dest_far);
222             if (GET_GLOBAL(fdata_g[src + i]) & mask)
223                 SET_FARVAR(SEG_GRAPH, *dest_far, ca.attr & 0x0f);
224             else
225                 SET_FARVAR(SEG_GRAPH, *dest_far, 0x00);
226         }
227     }
228     vgahw_grdc_write(0x08, 0xff);
229     vgahw_grdc_write(0x05, 0x00);
230     vgahw_grdc_write(0x03, 0x00);
231 }
232
233 static void
234 write_gfx_char_cga(struct vgamode_s *vmode_g
235                    , struct cursorpos cp, struct carattr ca)
236 {
237     u16 nbcols = GET_BDA(video_cols);
238     if (cp.x >= nbcols)
239         return;
240
241     u8 *fdata_g = vgafont8;
242     u8 bpp = GET_GLOBAL(vmode_g->pixbits);
243     u16 addr = (cp.x * bpp) + cp.y * 320;
244     u16 src = ca.car * 8;
245     u8 i;
246     for (i = 0; i < 8; i++) {
247         u8 *dest_far = (void*)(addr + (i >> 1) * 80);
248         if (i & 1)
249             dest_far += 0x2000;
250         u8 mask = 0x80;
251         if (bpp == 1) {
252             u8 data = 0;
253             if (ca.attr & 0x80)
254                 data = GET_FARVAR(SEG_CTEXT, *dest_far);
255             u8 j;
256             for (j = 0; j < 8; j++) {
257                 if (GET_GLOBAL(fdata_g[src + i]) & mask) {
258                     if (ca.attr & 0x80)
259                         data ^= (ca.attr & 0x01) << (7 - j);
260                     else
261                         data |= (ca.attr & 0x01) << (7 - j);
262                 }
263                 mask >>= 1;
264             }
265             SET_FARVAR(SEG_CTEXT, *dest_far, data);
266         } else {
267             while (mask > 0) {
268                 u8 data = 0;
269                 if (ca.attr & 0x80)
270                     data = GET_FARVAR(SEG_CTEXT, *dest_far);
271                 u8 j;
272                 for (j = 0; j < 4; j++) {
273                     if (GET_GLOBAL(fdata_g[src + i]) & mask) {
274                         if (ca.attr & 0x80)
275                             data ^= (ca.attr & 0x03) << ((3 - j) * 2);
276                         else
277                             data |= (ca.attr & 0x03) << ((3 - j) * 2);
278                     }
279                     mask >>= 1;
280                 }
281                 SET_FARVAR(SEG_CTEXT, *dest_far, data);
282                 dest_far += 1;
283             }
284         }
285     }
286 }
287
288 static void
289 write_gfx_char_lin(struct vgamode_s *vmode_g
290                    , struct cursorpos cp, struct carattr ca)
291 {
292     // Get the dimensions
293     u16 nbcols = GET_BDA(video_cols);
294     if (cp.x >= nbcols)
295         return;
296
297     u8 *fdata_g = vgafont8;
298     u16 addr = cp.x * 8 + cp.y * nbcols * 64;
299     u16 src = ca.car * 8;
300     u8 i;
301     for (i = 0; i < 8; i++) {
302         u8 *dest_far = (void*)(addr + i * nbcols * 8);
303         u8 mask = 0x80;
304         u8 j;
305         for (j = 0; j < 8; j++) {
306             u8 data = 0x00;
307             if (GET_GLOBAL(fdata_g[src + i]) & mask)
308                 data = ca.attr;
309             SET_FARVAR(SEG_GRAPH, dest_far[j], data);
310             mask >>= 1;
311         }
312     }
313 }
314
315 static void
316 write_text_char(struct vgamode_s *vmode_g
317                 , struct cursorpos cp, struct carattr ca)
318 {
319     // Get the dimensions
320     u16 nbrows = GET_BDA(video_rows) + 1;
321     u16 nbcols = GET_BDA(video_cols);
322
323     // Compute the address
324     void *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, cp.page)
325                                 + (cp.x + cp.y * nbcols) * 2);
326
327     if (ca.use_attr) {
328         u16 dummy = (ca.attr << 8) | ca.car;
329         SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u16*)address_far, dummy);
330     } else {
331         SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)address_far, ca.car);
332     }
333 }
334
335 void
336 vgafb_write_char(struct cursorpos cp, struct carattr ca)
337 {
338     // Get the mode
339     struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
340     if (!vmode_g)
341         return;
342
343     // FIXME gfx mode not complete
344     switch (GET_GLOBAL(vmode_g->memmodel)) {
345     case CTEXT:
346     case MTEXT:
347         write_text_char(vmode_g, cp, ca);
348         break;
349     case PLANAR4:
350     case PLANAR1:
351         write_gfx_char_pl4(vmode_g, cp, ca);
352         break;
353     case CGA:
354         write_gfx_char_cga(vmode_g, cp, ca);
355         break;
356     case LINEAR8:
357         write_gfx_char_lin(vmode_g, cp, ca);
358         break;
359     }
360 }
361
362 struct carattr
363 vgafb_read_char(struct cursorpos cp)
364 {
365     // Get the mode
366     struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
367     if (!vmode_g)
368         goto fail;
369
370     if (!(GET_GLOBAL(vmode_g->memmodel) & TEXT)) {
371         // FIXME gfx mode
372         dprintf(1, "Read char in graphics mode\n");
373         goto fail;
374     }
375
376     // Get the dimensions
377     u16 nbrows = GET_BDA(video_rows) + 1;
378     u16 nbcols = GET_BDA(video_cols);
379
380     // Compute the address
381     u16 *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, cp.page)
382                                + (cp.x + cp.y * nbcols) * 2);
383     u16 v = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *address_far);
384     struct carattr ca = {v, v>>8, 0};
385     return ca;
386
387 fail: ;
388     struct carattr ca2 = {0, 0, 0};
389     return ca2;
390 }
391
392
393 /****************************************************************
394  * Read/write pixels
395  ****************************************************************/
396
397 void
398 vgafb_write_pixel(u8 color, u16 x, u16 y)
399 {
400     // Get the mode
401     struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
402     if (!vmode_g)
403         return;
404     if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
405         return;
406
407     u8 *addr_far, mask, attr, data;
408     switch (GET_GLOBAL(vmode_g->memmodel)) {
409     case PLANAR4:
410     case PLANAR1:
411         addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
412         mask = 0x80 >> (x & 0x07);
413         vgahw_grdc_write(0x08, mask);
414         vgahw_grdc_write(0x05, 0x02);
415         data = GET_FARVAR(SEG_GRAPH, *addr_far);
416         if (color & 0x80)
417             vgahw_grdc_write(0x03, 0x18);
418         SET_FARVAR(SEG_GRAPH, *addr_far, color);
419         vgahw_grdc_write(0x08, 0xff);
420         vgahw_grdc_write(0x05, 0x00);
421         vgahw_grdc_write(0x03, 0x00);
422         break;
423     case CGA:
424         if (GET_GLOBAL(vmode_g->pixbits) == 2)
425             addr_far = (void*)((x >> 2) + (y >> 1) * 80);
426         else
427             addr_far = (void*)((x >> 3) + (y >> 1) * 80);
428         if (y & 1)
429             addr_far += 0x2000;
430         data = GET_FARVAR(SEG_CTEXT, *addr_far);
431         if (GET_GLOBAL(vmode_g->pixbits) == 2) {
432             attr = (color & 0x03) << ((3 - (x & 0x03)) * 2);
433             mask = 0x03 << ((3 - (x & 0x03)) * 2);
434         } else {
435             attr = (color & 0x01) << (7 - (x & 0x07));
436             mask = 0x01 << (7 - (x & 0x07));
437         }
438         if (color & 0x80) {
439             data ^= attr;
440         } else {
441             data &= ~mask;
442             data |= attr;
443         }
444         SET_FARVAR(SEG_CTEXT, *addr_far, data);
445         break;
446     case LINEAR8:
447         addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
448         SET_FARVAR(SEG_GRAPH, *addr_far, color);
449         break;
450     }
451 }
452
453 u8
454 vgafb_read_pixel(u16 x, u16 y)
455 {
456     // Get the mode
457     struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
458     if (!vmode_g)
459         return 0;
460     if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
461         return 0;
462
463     u8 *addr_far, mask, attr=0, data, i;
464     switch (GET_GLOBAL(vmode_g->memmodel)) {
465     case PLANAR4:
466     case PLANAR1:
467         addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
468         mask = 0x80 >> (x & 0x07);
469         attr = 0x00;
470         for (i = 0; i < 4; i++) {
471             vgahw_grdc_write(0x04, i);
472             data = GET_FARVAR(SEG_GRAPH, *addr_far) & mask;
473             if (data > 0)
474                 attr |= (0x01 << i);
475         }
476         break;
477     case CGA:
478         addr_far = (void*)((x >> 2) + (y >> 1) * 80);
479         if (y & 1)
480             addr_far += 0x2000;
481         data = GET_FARVAR(SEG_CTEXT, *addr_far);
482         if (GET_GLOBAL(vmode_g->pixbits) == 2)
483             attr = (data >> ((3 - (x & 0x03)) * 2)) & 0x03;
484         else
485             attr = (data >> (7 - (x & 0x07))) & 0x01;
486         break;
487     case LINEAR8:
488         addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
489         attr = GET_FARVAR(SEG_GRAPH, *addr_far);
490         break;
491     }
492     return attr;
493 }
494
495
496 /****************************************************************
497  * Font loading
498  ****************************************************************/
499
500 void
501 vgafb_load_font(u16 seg, void *src_far, u16 count
502                 , u16 start, u8 destflags, u8 fontsize)
503 {
504     get_font_access();
505     u16 blockaddr = ((destflags & 0x03) << 14) + ((destflags & 0x04) << 11);
506     void *dest_far = (void*)(blockaddr + start*32);
507     u16 i;
508     for (i = 0; i < count; i++)
509         memcpy_far(SEG_GRAPH, dest_far + i*32
510                    , seg, src_far + i*fontsize, fontsize);
511     release_font_access();
512 }