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.


Avoid strict-aliasing related issues when compiling with optimization
[palacios.git] / bios / seabios / vgasrc / vga.c
1 // VGA bios implementation
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
9 // TODO:
10 //  * review correctness of converted asm by comparing with RBIL
11 //
12 //  * convert vbe/clext code
13
14 #include "bregs.h" // struct bregs
15 #include "biosvar.h" // GET_BDA
16 #include "util.h" // memset
17 #include "vgatables.h" // find_vga_entry
18
19 // XXX
20 #define CONFIG_VBE 0
21 #define CONFIG_CIRRUS 0
22
23 // XXX
24 #define DEBUG_VGA_POST 1
25 #define DEBUG_VGA_10 3
26
27 #define SET_VGA(var, val) SET_FARVAR(get_global_seg(), (var), (val))
28
29
30 /****************************************************************
31  * Helper functions
32  ****************************************************************/
33
34 static inline void
35 call16_vgaint(u32 eax, u32 ebx)
36 {
37     asm volatile(
38         "int $0x10\n"
39         "cli\n"
40         "cld"
41         :
42         : "a"(eax), "b"(ebx)
43         : "cc", "memory");
44 }
45
46 static void
47 perform_gray_scale_summing(u16 start, u16 count)
48 {
49     vgahw_screen_disable();
50     int i;
51     for (i = start; i < start+count; i++) {
52         u8 rgb[3];
53         vgahw_get_dac_regs(GET_SEG(SS), rgb, i, 1);
54
55         // intensity = ( 0.3 * Red ) + ( 0.59 * Green ) + ( 0.11 * Blue )
56         u16 intensity = ((77 * rgb[0] + 151 * rgb[1] + 28 * rgb[2]) + 0x80) >> 8;
57         if (intensity > 0x3f)
58             intensity = 0x3f;
59
60         vgahw_set_dac_regs(GET_SEG(SS), rgb, i, 1);
61     }
62     vgahw_screen_enable();
63 }
64
65 static void
66 set_cursor_shape(u8 start, u8 end)
67 {
68     start &= 0x3f;
69     end &= 0x1f;
70
71     u16 curs = (start << 8) + end;
72     SET_BDA(cursor_type, curs);
73
74     u8 modeset_ctl = GET_BDA(modeset_ctl);
75     u16 cheight = GET_BDA(char_height);
76     if ((modeset_ctl & 0x01) && (cheight > 8) && (end < 8) && (start < 0x20)) {
77         if (end != (start + 1))
78             start = ((start + 1) * cheight / 8) - 1;
79         else
80             start = ((end + 1) * cheight / 8) - 2;
81         end = ((end + 1) * cheight / 8) - 1;
82     }
83     vgahw_set_cursor_shape(start, end);
84 }
85
86 static u16
87 get_cursor_shape(u8 page)
88 {
89     if (page > 7)
90         return 0;
91     // FIXME should handle VGA 14/16 lines
92     return GET_BDA(cursor_type);
93 }
94
95 static void
96 set_cursor_pos(struct cursorpos cp)
97 {
98     // Should not happen...
99     if (cp.page > 7)
100         return;
101
102     // Bios cursor pos
103     SET_BDA(cursor_pos[cp.page], (cp.y << 8) | cp.x);
104
105     // Set the hardware cursor
106     u8 current = GET_BDA(video_page);
107     if (cp.page != current)
108         return;
109
110     // Get the dimensions
111     u16 nbcols = GET_BDA(video_cols);
112     u16 nbrows = GET_BDA(video_rows) + 1;
113
114     // Calculate the address knowing nbcols nbrows and page num
115     u16 address = (SCREEN_IO_START(nbcols, nbrows, cp.page)
116                    + cp.x + cp.y * nbcols);
117
118     vgahw_set_cursor_pos(address);
119 }
120
121 static struct cursorpos
122 get_cursor_pos(u8 page)
123 {
124     if (page == 0xff)
125         // special case - use current page
126         page = GET_BDA(video_page);
127     if (page > 7) {
128         struct cursorpos cp = { 0, 0, 0xfe };
129         return cp;
130     }
131     // FIXME should handle VGA 14/16 lines
132     u16 xy = GET_BDA(cursor_pos[page]);
133     struct cursorpos cp = {xy, xy>>8, page};
134     return cp;
135 }
136
137 static void
138 set_active_page(u8 page)
139 {
140     if (page > 7)
141         return;
142
143     // Get the mode
144     struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
145     if (!vmode_g)
146         return;
147
148     // Get pos curs pos for the right page
149     struct cursorpos cp = get_cursor_pos(page);
150
151     u16 address;
152     if (GET_GLOBAL(vmode_g->memmodel) & TEXT) {
153         // Get the dimensions
154         u16 nbcols = GET_BDA(video_cols);
155         u16 nbrows = GET_BDA(video_rows) + 1;
156
157         // Calculate the address knowing nbcols nbrows and page num
158         address = SCREEN_MEM_START(nbcols, nbrows, page);
159         SET_BDA(video_pagestart, address);
160
161         // Start address
162         address = SCREEN_IO_START(nbcols, nbrows, page);
163     } else {
164         struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
165         address = page * GET_GLOBAL(vparam_g->slength);
166     }
167
168     vgahw_set_active_page(address);
169
170     // And change the BIOS page
171     SET_BDA(video_page, page);
172
173     dprintf(1, "Set active page %02x address %04x\n", page, address);
174
175     // Display the cursor, now the page is active
176     set_cursor_pos(cp);
177 }
178
179 static void
180 set_scan_lines(u8 lines)
181 {
182     vgahw_set_scan_lines(lines);
183     if (lines == 8)
184         set_cursor_shape(0x06, 0x07);
185     else
186         set_cursor_shape(lines - 4, lines - 3);
187     SET_BDA(char_height, lines);
188     u16 vde = vgahw_get_vde();
189     u8 rows = vde / lines;
190     SET_BDA(video_rows, rows - 1);
191     u16 cols = GET_BDA(video_cols);
192     SET_BDA(video_pagesize, rows * cols * 2);
193 }
194
195
196 /****************************************************************
197  * Character writing
198  ****************************************************************/
199
200 // Scroll the screen one line.  This function is designed to be called
201 // tail-recursive to reduce stack usage.
202 static void noinline
203 scroll_one(u16 nbrows, u16 nbcols, u8 page)
204 {
205     struct cursorpos ul = {0, 0, page};
206     struct cursorpos lr = {nbcols-1, nbrows-1, page};
207     vgafb_scroll(1, -1, ul, lr);
208 }
209
210 // Write a character to the screen at a given position.  Implement
211 // special characters and scroll the screen if necessary.
212 static void
213 write_teletype(struct cursorpos *pcp, struct carattr ca)
214 {
215     struct cursorpos cp = *pcp;
216
217     // Get the dimensions
218     u16 nbrows = GET_BDA(video_rows) + 1;
219     u16 nbcols = GET_BDA(video_cols);
220
221     switch (ca.car) {
222     case 7:
223         //FIXME should beep
224         break;
225     case 8:
226         if (cp.x > 0)
227             cp.x--;
228         break;
229     case '\r':
230         cp.x = 0;
231         break;
232     case '\n':
233         cp.y++;
234         break;
235     case '\t':
236         do {
237             struct carattr dummyca = {' ', ca.attr, ca.use_attr};
238             vgafb_write_char(cp, dummyca);
239             cp.x++;
240         } while (cp.x < nbcols && cp.x % 8);
241         break;
242     default:
243         vgafb_write_char(cp, ca);
244         cp.x++;
245     }
246
247     // Do we need to wrap ?
248     if (cp.x == nbcols) {
249         cp.x = 0;
250         cp.y++;
251     }
252     // Do we need to scroll ?
253     if (cp.y < nbrows) {
254         *pcp = cp;
255         return;
256     }
257     // Scroll screen
258     cp.y--;
259     *pcp = cp;
260     scroll_one(nbrows, nbcols, cp.page);
261 }
262
263 // Write out a buffer of alternating characters and attributes.
264 static void
265 write_attr_string(struct cursorpos *pcp, u16 count, u16 seg, u8 *offset_far)
266 {
267     while (count--) {
268         u8 car = GET_FARVAR(seg, *offset_far);
269         offset_far++;
270         u8 attr = GET_FARVAR(seg, *offset_far);
271         offset_far++;
272
273         struct carattr ca = {car, attr, 1};
274         write_teletype(pcp, ca);
275     }
276 }
277
278 // Write out a buffer of characters.
279 static void
280 write_string(struct cursorpos *pcp, u8 attr, u16 count, u16 seg, u8 *offset_far)
281 {
282     while (count--) {
283         u8 car = GET_FARVAR(seg, *offset_far);
284         offset_far++;
285
286         struct carattr ca = {car, attr, 1};
287         write_teletype(pcp, ca);
288     }
289 }
290
291
292 /****************************************************************
293  * Save and restore bda state
294  ****************************************************************/
295
296 static void
297 save_bda_state(u16 seg, struct saveBDAstate *info)
298 {
299     SET_FARVAR(seg, info->video_mode, GET_BDA(video_mode));
300     SET_FARVAR(seg, info->video_cols, GET_BDA(video_cols));
301     SET_FARVAR(seg, info->video_pagesize, GET_BDA(video_pagesize));
302     SET_FARVAR(seg, info->crtc_address, GET_BDA(crtc_address));
303     SET_FARVAR(seg, info->video_rows, GET_BDA(video_rows));
304     SET_FARVAR(seg, info->char_height, GET_BDA(char_height));
305     SET_FARVAR(seg, info->video_ctl, GET_BDA(video_ctl));
306     SET_FARVAR(seg, info->video_switches, GET_BDA(video_switches));
307     SET_FARVAR(seg, info->modeset_ctl, GET_BDA(modeset_ctl));
308     SET_FARVAR(seg, info->cursor_type, GET_BDA(cursor_type));
309     u16 i;
310     for (i=0; i<8; i++)
311         SET_FARVAR(seg, info->cursor_pos[i], GET_BDA(cursor_pos[i]));
312     SET_FARVAR(seg, info->video_pagestart, GET_BDA(video_pagestart));
313     SET_FARVAR(seg, info->video_page, GET_BDA(video_page));
314     /* current font */
315     SET_FARVAR(seg, info->font0, GET_IVT(0x1f));
316     SET_FARVAR(seg, info->font1, GET_IVT(0x43));
317 }
318
319 static void
320 restore_bda_state(u16 seg, struct saveBDAstate *info)
321 {
322     SET_BDA(video_mode, GET_FARVAR(seg, info->video_mode));
323     SET_BDA(video_cols, GET_FARVAR(seg, info->video_cols));
324     SET_BDA(video_pagesize, GET_FARVAR(seg, info->video_pagesize));
325     SET_BDA(crtc_address, GET_FARVAR(seg, info->crtc_address));
326     SET_BDA(video_rows, GET_FARVAR(seg, info->video_rows));
327     SET_BDA(char_height, GET_FARVAR(seg, info->char_height));
328     SET_BDA(video_ctl, GET_FARVAR(seg, info->video_ctl));
329     SET_BDA(video_switches, GET_FARVAR(seg, info->video_switches));
330     SET_BDA(modeset_ctl, GET_FARVAR(seg, info->modeset_ctl));
331     SET_BDA(cursor_type, GET_FARVAR(seg, info->cursor_type));
332     u16 i;
333     for (i = 0; i < 8; i++)
334         SET_BDA(cursor_pos[i], GET_FARVAR(seg, info->cursor_pos[i]));
335     SET_BDA(video_pagestart, GET_FARVAR(seg, info->video_pagestart));
336     SET_BDA(video_page, GET_FARVAR(seg, info->video_page));
337     /* current font */
338     SET_IVT(0x1f, GET_FARVAR(seg, info->font0));
339     SET_IVT(0x43, GET_FARVAR(seg, info->font1));
340 }
341
342
343 /****************************************************************
344  * VGA int 10 handler
345  ****************************************************************/
346
347 // set video mode
348 static void
349 handle_1000(struct bregs *regs)
350 {
351     u8 noclearmem = regs->al & 0x80;
352     u8 mode = regs->al & 0x7f;
353
354     // Set regs->al
355     if (mode > 7)
356         regs->al = 0x20;
357     else if (mode == 6)
358         regs->al = 0x3f;
359     else
360         regs->al = 0x30;
361
362     if (CONFIG_CIRRUS)
363         cirrus_set_video_mode(mode);
364
365     if (CONFIG_VBE)
366         if (vbe_has_vbe_display())
367             dispi_set_enable(VBE_DISPI_DISABLED);
368
369     // find the entry in the video modes
370     struct vgamode_s *vmode_g = find_vga_entry(mode);
371     dprintf(1, "mode search %02x found %p\n", mode, vmode_g);
372     if (!vmode_g)
373         return;
374
375     // Read the bios mode set control
376     u8 modeset_ctl = GET_BDA(modeset_ctl);
377
378     // Then we know the number of lines
379 // FIXME
380
381     // if palette loading (bit 3 of modeset ctl = 0)
382     if ((modeset_ctl & 0x08) == 0) {    // Set the PEL mask
383         vgahw_set_pel_mask(GET_GLOBAL(vmode_g->pelmask));
384
385         // From which palette
386         u8 *palette_g = GET_GLOBAL(vmode_g->dac);
387         u16 palsize = GET_GLOBAL(vmode_g->dacsize) / 3;
388
389         // Always 256*3 values
390         vgahw_set_dac_regs(get_global_seg(), palette_g, 0, palsize);
391         u16 i;
392         for (i = palsize; i < 0x0100; i++) {
393             static u8 rgb[3] VAR16;
394             vgahw_set_dac_regs(get_global_seg(), rgb, i, 1);
395         }
396
397         if ((modeset_ctl & 0x02) == 0x02)
398             perform_gray_scale_summing(0x00, 0x100);
399     }
400
401     struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
402     vgahw_set_mode(vparam_g);
403
404     if (noclearmem == 0x00)
405         clear_screen(vmode_g);
406
407     // Set CRTC address VGA or MDA
408     u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS;
409     if (GET_GLOBAL(vmode_g->memmodel) == MTEXT)
410         crtc_addr = VGAREG_MDA_CRTC_ADDRESS;
411
412     // Set the BIOS mem
413     u16 cheight = GET_GLOBAL(vparam_g->cheight);
414     SET_BDA(video_mode, mode);
415     SET_BDA(video_cols, GET_GLOBAL(vparam_g->twidth));
416     SET_BDA(video_pagesize, GET_GLOBAL(vparam_g->slength));
417     SET_BDA(crtc_address, crtc_addr);
418     SET_BDA(video_rows, GET_GLOBAL(vparam_g->theightm1));
419     SET_BDA(char_height, cheight);
420     SET_BDA(video_ctl, (0x60 | noclearmem));
421     SET_BDA(video_switches, 0xF9);
422     SET_BDA(modeset_ctl, GET_BDA(modeset_ctl) & 0x7f);
423
424     // FIXME We nearly have the good tables. to be reworked
425     SET_BDA(dcc_index, 0x08);   // 8 is VGA should be ok for now
426     SET_BDA(video_savetable
427             , SEGOFF(get_global_seg(), (u32)video_save_pointer_table));
428
429     // FIXME
430     SET_BDA(video_msr, 0x00); // Unavailable on vanilla vga, but...
431     SET_BDA(video_pal, 0x00); // Unavailable on vanilla vga, but...
432
433     // Set cursor shape
434     if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
435         set_cursor_shape(0x06, 0x07);
436     // Set cursor pos for page 0..7
437     int i;
438     for (i = 0; i < 8; i++) {
439         struct cursorpos cp = {0, 0, i};
440         set_cursor_pos(cp);
441     }
442
443     // Set active page 0
444     set_active_page(0x00);
445
446     // Write the fonts in memory
447     if (GET_GLOBAL(vmode_g->memmodel) & TEXT) {
448         call16_vgaint(0x1104, 0);
449         call16_vgaint(0x1103, 0);
450     }
451     // Set the ints 0x1F and 0x43
452     SET_IVT(0x1f, SEGOFF(get_global_seg(), (u32)&vgafont8[128 * 8]));
453
454     switch (cheight) {
455     case 8:
456         SET_IVT(0x43, SEGOFF(get_global_seg(), (u32)vgafont8));
457         break;
458     case 14:
459         SET_IVT(0x43, SEGOFF(get_global_seg(), (u32)vgafont14));
460         break;
461     case 16:
462         SET_IVT(0x43, SEGOFF(get_global_seg(), (u32)vgafont16));
463         break;
464     }
465 }
466
467 static void
468 handle_1001(struct bregs *regs)
469 {
470     set_cursor_shape(regs->ch, regs->cl);
471 }
472
473 static void
474 handle_1002(struct bregs *regs)
475 {
476     struct cursorpos cp = {regs->dl, regs->dh, regs->bh};
477     set_cursor_pos(cp);
478 }
479
480 static void
481 handle_1003(struct bregs *regs)
482 {
483     regs->cx = get_cursor_shape(regs->bh);
484     struct cursorpos cp = get_cursor_pos(regs->bh);
485     regs->dl = cp.x;
486     regs->dh = cp.y;
487 }
488
489 // Read light pen pos (unimplemented)
490 static void
491 handle_1004(struct bregs *regs)
492 {
493     debug_stub(regs);
494     regs->ax = regs->bx = regs->cx = regs->dx = 0;
495 }
496
497 static void
498 handle_1005(struct bregs *regs)
499 {
500     set_active_page(regs->al);
501 }
502
503 static void
504 verify_scroll(struct bregs *regs, int dir)
505 {
506     u8 page = GET_BDA(video_page);
507     struct cursorpos ul = {regs->cl, regs->ch, page};
508     struct cursorpos lr = {regs->dl, regs->dh, page};
509
510     u16 nbrows = GET_BDA(video_rows) + 1;
511     if (lr.y >= nbrows)
512         lr.y = nbrows - 1;
513     u16 nbcols = GET_BDA(video_cols);
514     if (lr.x >= nbcols)
515         lr.x = nbcols - 1;
516
517     if (ul.x > lr.x || ul.y > lr.y)
518         return;
519
520     u16 nblines = regs->al;
521     if (!nblines || nblines > lr.y - ul.y + 1)
522         nblines = lr.y - ul.y + 1;
523
524     vgafb_scroll(dir * nblines, regs->bh, ul, lr);
525 }
526
527 static void
528 handle_1006(struct bregs *regs)
529 {
530     verify_scroll(regs, 1);
531 }
532
533 static void
534 handle_1007(struct bregs *regs)
535 {
536     verify_scroll(regs, -1);
537 }
538
539 static void
540 handle_1008(struct bregs *regs)
541 {
542     struct carattr ca = vgafb_read_char(get_cursor_pos(regs->bh));
543     regs->al = ca.car;
544     regs->ah = ca.attr;
545 }
546
547 static void noinline
548 write_chars(u8 page, struct carattr ca, u16 count)
549 {
550     struct cursorpos cp = get_cursor_pos(page);
551     while (count--) {
552         vgafb_write_char(cp, ca);
553         cp.x++;
554     }
555 }
556
557 static void
558 handle_1009(struct bregs *regs)
559 {
560     struct carattr ca = {regs->al, regs->bl, 1};
561     write_chars(regs->bh, ca, regs->cx);
562 }
563
564 static void
565 handle_100a(struct bregs *regs)
566 {
567     struct carattr ca = {regs->al, regs->bl, 0};
568     write_chars(regs->bh, ca, regs->cx);
569 }
570
571
572 static void
573 handle_100b00(struct bregs *regs)
574 {
575     vgahw_set_border_color(regs->bl);
576 }
577
578 static void
579 handle_100b01(struct bregs *regs)
580 {
581     vgahw_set_palette(regs->bl);
582 }
583
584 static void
585 handle_100bXX(struct bregs *regs)
586 {
587     debug_stub(regs);
588 }
589
590 static void
591 handle_100b(struct bregs *regs)
592 {
593     switch (regs->bh) {
594     case 0x00: handle_100b00(regs); break;
595     case 0x01: handle_100b01(regs); break;
596     default:   handle_100bXX(regs); break;
597     }
598 }
599
600
601 static void
602 handle_100c(struct bregs *regs)
603 {
604     // XXX - page (regs->bh) is unused
605     vgafb_write_pixel(regs->al, regs->cx, regs->dx);
606 }
607
608 static void
609 handle_100d(struct bregs *regs)
610 {
611     // XXX - page (regs->bh) is unused
612     regs->al = vgafb_read_pixel(regs->cx, regs->dx);
613 }
614
615 static void noinline
616 handle_100e(struct bregs *regs)
617 {
618     // Ralf Brown Interrupt list is WRONG on bh(page)
619     // We do output only on the current page !
620     struct carattr ca = {regs->al, regs->bl, 0};
621     struct cursorpos cp = get_cursor_pos(0xff);
622     write_teletype(&cp, ca);
623     set_cursor_pos(cp);
624 }
625
626 static void
627 handle_100f(struct bregs *regs)
628 {
629     regs->bh = GET_BDA(video_page);
630     regs->al = GET_BDA(video_mode) | (GET_BDA(video_ctl) & 0x80);
631     regs->ah = GET_BDA(video_cols);
632 }
633
634
635 static void
636 handle_101000(struct bregs *regs)
637 {
638     if (regs->bl > 0x14)
639         return;
640     vgahw_set_single_palette_reg(regs->bl, regs->bh);
641 }
642
643 static void
644 handle_101001(struct bregs *regs)
645 {
646     vgahw_set_overscan_border_color(regs->bh);
647 }
648
649 static void
650 handle_101002(struct bregs *regs)
651 {
652     vgahw_set_all_palette_reg(regs->es, (u8*)(regs->dx + 0));
653 }
654
655 static void
656 handle_101003(struct bregs *regs)
657 {
658     vgahw_toggle_intensity(regs->bl);
659 }
660
661 static void
662 handle_101007(struct bregs *regs)
663 {
664     if (regs->bl > 0x14)
665         return;
666     regs->bh = vgahw_get_single_palette_reg(regs->bl);
667 }
668
669 static void
670 handle_101008(struct bregs *regs)
671 {
672     regs->bh = vgahw_get_overscan_border_color();
673 }
674
675 static void
676 handle_101009(struct bregs *regs)
677 {
678     vgahw_get_all_palette_reg(regs->es, (u8*)(regs->dx + 0));
679 }
680
681 static void noinline
682 handle_101010(struct bregs *regs)
683 {
684     u8 rgb[3] = {regs->dh, regs->ch, regs->cl};
685     vgahw_set_dac_regs(GET_SEG(SS), rgb, regs->bx, 1);
686 }
687
688 static void
689 handle_101012(struct bregs *regs)
690 {
691     vgahw_set_dac_regs(regs->es, (u8*)(regs->dx + 0), regs->bx, regs->cx);
692 }
693
694 static void
695 handle_101013(struct bregs *regs)
696 {
697     vgahw_select_video_dac_color_page(regs->bl, regs->bh);
698 }
699
700 static void noinline
701 handle_101015(struct bregs *regs)
702 {
703     u8 rgb[3];
704     vgahw_get_dac_regs(GET_SEG(SS), rgb, regs->bx, 1);
705     regs->dh = rgb[0];
706     regs->ch = rgb[1];
707     regs->cl = rgb[2];
708 }
709
710 static void
711 handle_101017(struct bregs *regs)
712 {
713     vgahw_get_dac_regs(regs->es, (u8*)(regs->dx + 0), regs->bx, regs->cx);
714 }
715
716 static void
717 handle_101018(struct bregs *regs)
718 {
719     vgahw_set_pel_mask(regs->bl);
720 }
721
722 static void
723 handle_101019(struct bregs *regs)
724 {
725     regs->bl = vgahw_get_pel_mask();
726 }
727
728 static void
729 handle_10101a(struct bregs *regs)
730 {
731     vgahw_read_video_dac_state(&regs->bl, &regs->bh);
732 }
733
734 static void
735 handle_10101b(struct bregs *regs)
736 {
737     perform_gray_scale_summing(regs->bx, regs->cx);
738 }
739
740 static void
741 handle_1010XX(struct bregs *regs)
742 {
743     debug_stub(regs);
744 }
745
746 static void
747 handle_1010(struct bregs *regs)
748 {
749     switch (regs->al) {
750     case 0x00: handle_101000(regs); break;
751     case 0x01: handle_101001(regs); break;
752     case 0x02: handle_101002(regs); break;
753     case 0x03: handle_101003(regs); break;
754     case 0x07: handle_101007(regs); break;
755     case 0x08: handle_101008(regs); break;
756     case 0x09: handle_101009(regs); break;
757     case 0x10: handle_101010(regs); break;
758     case 0x12: handle_101012(regs); break;
759     case 0x13: handle_101013(regs); break;
760     case 0x15: handle_101015(regs); break;
761     case 0x17: handle_101017(regs); break;
762     case 0x18: handle_101018(regs); break;
763     case 0x19: handle_101019(regs); break;
764     case 0x1a: handle_10101a(regs); break;
765     case 0x1b: handle_10101b(regs); break;
766     default:   handle_1010XX(regs); break;
767     }
768 }
769
770
771 static void
772 handle_101100(struct bregs *regs)
773 {
774     vgafb_load_font(regs->es, (void*)(regs->bp+0), regs->cx
775                     , regs->dx, regs->bl, regs->bh);
776 }
777
778 static void
779 handle_101101(struct bregs *regs)
780 {
781     vgafb_load_font(get_global_seg(), vgafont14, 0x100, 0, regs->bl, 14);
782 }
783
784 static void
785 handle_101102(struct bregs *regs)
786 {
787     vgafb_load_font(get_global_seg(), vgafont8, 0x100, 0, regs->bl, 8);
788 }
789
790 static void
791 handle_101103(struct bregs *regs)
792 {
793     vgahw_set_text_block_specifier(regs->bl);
794 }
795
796 static void
797 handle_101104(struct bregs *regs)
798 {
799     vgafb_load_font(get_global_seg(), vgafont16, 0x100, 0, regs->bl, 16);
800 }
801
802 static void
803 handle_101110(struct bregs *regs)
804 {
805     vgafb_load_font(regs->es, (void*)(regs->bp+0), regs->cx
806                     , regs->dx, regs->bl, regs->bh);
807     set_scan_lines(regs->bh);
808 }
809
810 static void
811 handle_101111(struct bregs *regs)
812 {
813     vgafb_load_font(get_global_seg(), vgafont14, 0x100, 0, regs->bl, 14);
814     set_scan_lines(14);
815 }
816
817 static void
818 handle_101112(struct bregs *regs)
819 {
820     vgafb_load_font(get_global_seg(), vgafont8, 0x100, 0, regs->bl, 8);
821     set_scan_lines(8);
822 }
823
824 static void
825 handle_101114(struct bregs *regs)
826 {
827     vgafb_load_font(get_global_seg(), vgafont16, 0x100, 0, regs->bl, 16);
828     set_scan_lines(16);
829 }
830
831 static void
832 handle_101130(struct bregs *regs)
833 {
834     switch (regs->bh) {
835     case 0x00: {
836         struct segoff_s so = GET_IVT(0x1f);
837         regs->es = so.seg;
838         regs->bp = so.offset;
839         break;
840     }
841     case 0x01: {
842         struct segoff_s so = GET_IVT(0x43);
843         regs->es = so.seg;
844         regs->bp = so.offset;
845         break;
846     }
847     case 0x02:
848         regs->es = get_global_seg();
849         regs->bp = (u32)vgafont14;
850         break;
851     case 0x03:
852         regs->es = get_global_seg();
853         regs->bp = (u32)vgafont8;
854         break;
855     case 0x04:
856         regs->es = get_global_seg();
857         regs->bp = (u32)vgafont8 + 128 * 8;
858         break;
859     case 0x05:
860         regs->es = get_global_seg();
861         regs->bp = (u32)vgafont14alt;
862         break;
863     case 0x06:
864         regs->es = get_global_seg();
865         regs->bp = (u32)vgafont16;
866         break;
867     case 0x07:
868         regs->es = get_global_seg();
869         regs->bp = (u32)vgafont16alt;
870         break;
871     default:
872         dprintf(1, "Get font info BH(%02x) was discarded\n", regs->bh);
873         return;
874     }
875     // Set byte/char of on screen font
876     regs->cx = GET_BDA(char_height) & 0xff;
877
878     // Set Highest char row
879     regs->dx = GET_BDA(video_rows);
880 }
881
882 static void
883 handle_1011XX(struct bregs *regs)
884 {
885     debug_stub(regs);
886 }
887
888 static void
889 handle_1011(struct bregs *regs)
890 {
891     switch (regs->al) {
892     case 0x00: handle_101100(regs); break;
893     case 0x01: handle_101101(regs); break;
894     case 0x02: handle_101102(regs); break;
895     case 0x03: handle_101103(regs); break;
896     case 0x04: handle_101104(regs); break;
897     case 0x10: handle_101110(regs); break;
898     case 0x11: handle_101111(regs); break;
899     case 0x12: handle_101112(regs); break;
900     case 0x14: handle_101114(regs); break;
901     case 0x30: handle_101130(regs); break;
902     default:   handle_1011XX(regs); break;
903     }
904 }
905
906
907 static void
908 handle_101210(struct bregs *regs)
909 {
910     u16 crtc_addr = GET_BDA(crtc_address);
911     if (crtc_addr == VGAREG_MDA_CRTC_ADDRESS)
912         regs->bx = 0x0103;
913     else
914         regs->bx = 0x0003;
915     regs->cx = GET_BDA(video_switches) & 0x0f;
916 }
917
918 static void
919 handle_101230(struct bregs *regs)
920 {
921     u8 mctl = GET_BDA(modeset_ctl);
922     u8 vswt = GET_BDA(video_switches);
923     switch (regs->al) {
924     case 0x00:
925         // 200 lines
926         mctl = (mctl & ~0x10) | 0x80;
927         vswt = (vswt & ~0x0f) | 0x08;
928         break;
929     case 0x01:
930         // 350 lines
931         mctl &= ~0x90;
932         vswt = (vswt & ~0x0f) | 0x09;
933         break;
934     case 0x02:
935         // 400 lines
936         mctl = (mctl & ~0x80) | 0x10;
937         vswt = (vswt & ~0x0f) | 0x09;
938         break;
939     default:
940         dprintf(1, "Select vert res (%02x) was discarded\n", regs->al);
941         break;
942     }
943     SET_BDA(modeset_ctl, mctl);
944     SET_BDA(video_switches, vswt);
945     regs->al = 0x12;
946 }
947
948 static void
949 handle_101231(struct bregs *regs)
950 {
951     u8 v = (regs->al & 0x01) << 3;
952     u8 mctl = GET_BDA(video_ctl) & ~0x08;
953     SET_BDA(video_ctl, mctl | v);
954     regs->al = 0x12;
955 }
956
957 static void
958 handle_101232(struct bregs *regs)
959 {
960     vgahw_enable_video_addressing(regs->al);
961     regs->al = 0x12;
962 }
963
964 static void
965 handle_101233(struct bregs *regs)
966 {
967     u8 v = ((regs->al << 1) & 0x02) ^ 0x02;
968     u8 v2 = GET_BDA(modeset_ctl) & ~0x02;
969     SET_BDA(modeset_ctl, v | v2);
970     regs->al = 0x12;
971 }
972
973 static void
974 handle_101234(struct bregs *regs)
975 {
976     u8 v = (regs->al & 0x01) ^ 0x01;
977     u8 v2 = GET_BDA(modeset_ctl) & ~0x01;
978     SET_BDA(modeset_ctl, v | v2);
979     regs->al = 0x12;
980 }
981
982 static void
983 handle_101235(struct bregs *regs)
984 {
985     debug_stub(regs);
986     regs->al = 0x12;
987 }
988
989 static void
990 handle_101236(struct bregs *regs)
991 {
992     debug_stub(regs);
993     regs->al = 0x12;
994 }
995
996 static void
997 handle_1012XX(struct bregs *regs)
998 {
999     debug_stub(regs);
1000 }
1001
1002 static void
1003 handle_1012(struct bregs *regs)
1004 {
1005     switch (regs->bl) {
1006     case 0x10: handle_101210(regs); break;
1007     case 0x30: handle_101230(regs); break;
1008     case 0x31: handle_101231(regs); break;
1009     case 0x32: handle_101232(regs); break;
1010     case 0x33: handle_101233(regs); break;
1011     case 0x34: handle_101234(regs); break;
1012     case 0x35: handle_101235(regs); break;
1013     case 0x36: handle_101236(regs); break;
1014     default:   handle_1012XX(regs); break;
1015     }
1016
1017     // XXX - cirrus has 1280, 1281, 1282, 1285, 129a, 12a0, 12a1, 12a2, 12ae
1018 }
1019
1020
1021 // Write string
1022 static void noinline
1023 handle_1013(struct bregs *regs)
1024 {
1025     struct cursorpos cp = {regs->dl, regs->dh, regs->bh};
1026     // if row=0xff special case : use current cursor position
1027     if (cp.y == 0xff)
1028         cp = get_cursor_pos(cp.page);
1029     u8 flag = regs->al;
1030     if (flag & 2)
1031         write_attr_string(&cp, regs->cx, regs->es, (void*)(regs->bp + 0));
1032     else
1033         write_string(&cp, regs->bl, regs->cx, regs->es, (void*)(regs->bp + 0));
1034
1035     if (flag & 1)
1036         set_cursor_pos(cp);
1037 }
1038
1039
1040 static void
1041 handle_101a00(struct bregs *regs)
1042 {
1043     regs->bx = GET_BDA(dcc_index);
1044     regs->al = 0x1a;
1045 }
1046
1047 static void
1048 handle_101a01(struct bregs *regs)
1049 {
1050     SET_BDA(dcc_index, regs->bl);
1051     dprintf(1, "Alternate Display code (%02x) was discarded\n", regs->bh);
1052     regs->al = 0x1a;
1053 }
1054
1055 static void
1056 handle_101aXX(struct bregs *regs)
1057 {
1058     debug_stub(regs);
1059 }
1060
1061 static void
1062 handle_101a(struct bregs *regs)
1063 {
1064     switch (regs->al) {
1065     case 0x00: handle_101a00(regs); break;
1066     case 0x01: handle_101a01(regs); break;
1067     default:   handle_101aXX(regs); break;
1068     }
1069 }
1070
1071
1072 struct funcInfo {
1073     u16 static_functionality_off;
1074     u16 static_functionality_seg;
1075     u8 bda_0x49[30];
1076     u8 bda_0x84[3];
1077     u8 dcc_index;
1078     u8 dcc_alt;
1079     u16 colors;
1080     u8 pages;
1081     u8 scan_lines;
1082     u8 primary_char;
1083     u8 secondar_char;
1084     u8 misc;
1085     u8 non_vga_mode;
1086     u8 reserved_2f[2];
1087     u8 video_mem;
1088     u8 save_flags;
1089     u8 disp_info;
1090     u8 reserved_34[12];
1091 };
1092
1093 static void
1094 handle_101b(struct bregs *regs)
1095 {
1096     u16 seg = regs->es;
1097     struct funcInfo *info = (void*)(regs->di+0);
1098     memset_far(seg, info, 0, sizeof(*info));
1099     // Address of static functionality table
1100     SET_FARVAR(seg, info->static_functionality_off, (u32)static_functionality);
1101     SET_FARVAR(seg, info->static_functionality_seg, get_global_seg());
1102
1103     // Hard coded copy from BIOS area. Should it be cleaner ?
1104     memcpy_far(seg, info->bda_0x49, SEG_BDA, (void*)0x49
1105                , sizeof(info->bda_0x49));
1106     memcpy_far(seg, info->bda_0x84, SEG_BDA, (void*)0x84
1107                , sizeof(info->bda_0x84));
1108
1109     SET_FARVAR(seg, info->dcc_index, GET_BDA(dcc_index));
1110     SET_FARVAR(seg, info->colors, 16);
1111     SET_FARVAR(seg, info->pages, 8);
1112     SET_FARVAR(seg, info->scan_lines, 2);
1113     SET_FARVAR(seg, info->video_mem, 3);
1114     regs->al = 0x1B;
1115 }
1116
1117
1118 static void
1119 handle_101c00(struct bregs *regs)
1120 {
1121     u16 flags = regs->cx;
1122     u16 size = 0;
1123     if (flags & 1)
1124         size += sizeof(struct saveVideoHardware);
1125     if (flags & 2)
1126         size += sizeof(struct saveBDAstate);
1127     if (flags & 4)
1128         size += sizeof(struct saveDACcolors);
1129     regs->bx = size;
1130     regs->al = 0x1c;
1131 }
1132
1133 static void
1134 handle_101c01(struct bregs *regs)
1135 {
1136     u16 flags = regs->cx;
1137     u16 seg = regs->es;
1138     void *data = (void*)(regs->bx+0);
1139     if (flags & 1) {
1140         vgahw_save_state(seg, data);
1141         data += sizeof(struct saveVideoHardware);
1142     }
1143     if (flags & 2) {
1144         save_bda_state(seg, data);
1145         data += sizeof(struct saveBDAstate);
1146     }
1147     if (flags & 4)
1148         vgahw_save_dac_state(seg, data);
1149     regs->al = 0x1c;
1150 }
1151
1152 static void
1153 handle_101c02(struct bregs *regs)
1154 {
1155     u16 flags = regs->cx;
1156     u16 seg = regs->es;
1157     void *data = (void*)(regs->bx+0);
1158     if (flags & 1) {
1159         vgahw_restore_state(seg, data);
1160         data += sizeof(struct saveVideoHardware);
1161     }
1162     if (flags & 2) {
1163         restore_bda_state(seg, data);
1164         data += sizeof(struct saveBDAstate);
1165     }
1166     if (flags & 4)
1167         vgahw_restore_dac_state(seg, data);
1168     regs->al = 0x1c;
1169 }
1170
1171 static void
1172 handle_101cXX(struct bregs *regs)
1173 {
1174     debug_stub(regs);
1175 }
1176
1177 static void
1178 handle_101c(struct bregs *regs)
1179 {
1180     switch (regs->al) {
1181     case 0x00: handle_101c00(regs); break;
1182     case 0x01: handle_101c01(regs); break;
1183     case 0x02: handle_101c02(regs); break;
1184     default:   handle_101cXX(regs); break;
1185     }
1186 }
1187
1188
1189 static void
1190 handle_104f00(struct bregs *regs)
1191 {
1192     // XXX - vbe_biosfn_return_controller_information(&AX,ES,DI);
1193     // XXX - OR cirrus_vesa_00h
1194 }
1195
1196 static void
1197 handle_104f01(struct bregs *regs)
1198 {
1199     // XXX - vbe_biosfn_return_mode_information(&AX,CX,ES,DI);
1200     // XXX - OR cirrus_vesa_01h
1201 }
1202
1203 static void
1204 handle_104f02(struct bregs *regs)
1205 {
1206     // XXX - vbe_biosfn_set_mode(&AX,BX,ES,DI);
1207     // XXX - OR cirrus_vesa_02h
1208 }
1209
1210 static void
1211 handle_104f03(struct bregs *regs)
1212 {
1213     // XXX - vbe_biosfn_return_current_mode
1214     // XXX - OR cirrus_vesa_03h
1215 }
1216
1217 static void
1218 handle_104f04(struct bregs *regs)
1219 {
1220     // XXX - vbe_biosfn_save_restore_state(&AX, CX, DX, ES, &BX);
1221 }
1222
1223 static void
1224 handle_104f05(struct bregs *regs)
1225 {
1226     // XXX - vbe_biosfn_display_window_control
1227     // XXX - OR cirrus_vesa_05h
1228 }
1229
1230 static void
1231 handle_104f06(struct bregs *regs)
1232 {
1233     // XXX - vbe_biosfn_set_get_logical_scan_line_length
1234     // XXX - OR cirrus_vesa_06h
1235 }
1236
1237 static void
1238 handle_104f07(struct bregs *regs)
1239 {
1240     // XXX - vbe_biosfn_set_get_display_start
1241     // XXX - OR cirrus_vesa_07h
1242 }
1243
1244 static void
1245 handle_104f08(struct bregs *regs)
1246 {
1247     // XXX - vbe_biosfn_set_get_dac_palette_format
1248 }
1249
1250 static void
1251 handle_104f0a(struct bregs *regs)
1252 {
1253     // XXX - vbe_biosfn_return_protected_mode_interface
1254 }
1255
1256 static void
1257 handle_104fXX(struct bregs *regs)
1258 {
1259     debug_stub(regs);
1260     regs->ax = 0x0100;
1261 }
1262
1263 static void
1264 handle_104f(struct bregs *regs)
1265 {
1266     if (! CONFIG_VBE || !vbe_has_vbe_display()) {
1267         handle_104fXX(regs);
1268         return;
1269     }
1270
1271     switch (regs->al) {
1272     case 0x00: handle_104f00(regs); break;
1273     case 0x01: handle_104f01(regs); break;
1274     case 0x02: handle_104f02(regs); break;
1275     case 0x03: handle_104f03(regs); break;
1276     case 0x04: handle_104f04(regs); break;
1277     case 0x05: handle_104f05(regs); break;
1278     case 0x06: handle_104f06(regs); break;
1279     case 0x07: handle_104f07(regs); break;
1280     case 0x08: handle_104f08(regs); break;
1281     case 0x0a: handle_104f0a(regs); break;
1282     default:   handle_104fXX(regs); break;
1283     }
1284 }
1285
1286
1287 static void
1288 handle_10XX(struct bregs *regs)
1289 {
1290     debug_stub(regs);
1291 }
1292
1293 // INT 10h Video Support Service Entry Point
1294 void VISIBLE16
1295 handle_10(struct bregs *regs)
1296 {
1297     debug_enter(regs, DEBUG_VGA_10);
1298     switch (regs->ah) {
1299     case 0x00: handle_1000(regs); break;
1300     case 0x01: handle_1001(regs); break;
1301     case 0x02: handle_1002(regs); break;
1302     case 0x03: handle_1003(regs); break;
1303     case 0x04: handle_1004(regs); break;
1304     case 0x05: handle_1005(regs); break;
1305     case 0x06: handle_1006(regs); break;
1306     case 0x07: handle_1007(regs); break;
1307     case 0x08: handle_1008(regs); break;
1308     case 0x09: handle_1009(regs); break;
1309     case 0x0a: handle_100a(regs); break;
1310     case 0x0b: handle_100b(regs); break;
1311     case 0x0c: handle_100c(regs); break;
1312     case 0x0d: handle_100d(regs); break;
1313     case 0x0e: handle_100e(regs); break;
1314     case 0x0f: handle_100f(regs); break;
1315     case 0x10: handle_1010(regs); break;
1316     case 0x11: handle_1011(regs); break;
1317     case 0x12: handle_1012(regs); break;
1318     case 0x13: handle_1013(regs); break;
1319     case 0x1a: handle_101a(regs); break;
1320     case 0x1b: handle_101b(regs); break;
1321     case 0x1c: handle_101c(regs); break;
1322     case 0x4f: handle_104f(regs); break;
1323     default:   handle_10XX(regs); break;
1324     }
1325 }
1326
1327
1328 /****************************************************************
1329  * VGA post
1330  ****************************************************************/
1331
1332 static void
1333 init_bios_area(void)
1334 {
1335     // init detected hardware BIOS Area
1336     // set 80x25 color (not clear from RBIL but usual)
1337     u16 eqf = GET_BDA(equipment_list_flags);
1338     SET_BDA(equipment_list_flags, (eqf & 0xffcf) | 0x20);
1339
1340     // Just for the first int10 find its children
1341
1342     // the default char height
1343     SET_BDA(char_height, 0x10);
1344
1345     // Clear the screen
1346     SET_BDA(video_ctl, 0x60);
1347
1348     // Set the basic screen we have
1349     SET_BDA(video_switches, 0xf9);
1350
1351     // Set the basic modeset options
1352     SET_BDA(modeset_ctl, 0x51);
1353
1354     // Set the  default MSR
1355     SET_BDA(video_msr, 0x09);
1356 }
1357
1358 void VISIBLE16
1359 vga_post(struct bregs *regs)
1360 {
1361     debug_enter(regs, DEBUG_VGA_POST);
1362
1363     vgahw_init();
1364
1365     init_bios_area();
1366
1367     if (CONFIG_VBE)
1368         vbe_init();
1369
1370     extern void entry_10(void);
1371     SET_IVT(0x10, SEGOFF(get_global_seg(), (u32)entry_10));
1372
1373     if (CONFIG_CIRRUS)
1374         cirrus_init();
1375
1376     // XXX - clear screen and display info
1377
1378     // XXX: fill it
1379     SET_VGA(video_save_pointer_table[0], (u32)video_param_table);
1380     SET_VGA(video_save_pointer_table[1], get_global_seg());
1381
1382     // Fixup checksum
1383     extern u8 _rom_header_size, _rom_header_checksum;
1384     SET_VGA(_rom_header_checksum, 0);
1385     u8 sum = -checksum_far(get_global_seg(), 0, _rom_header_size * 512);
1386     SET_VGA(_rom_header_checksum, sum);
1387 }