|
|
1.1 root 1: // VGA bios implementation
2: //
3: // Copyright (C) 2009-2012 Kevin O'Connor <[email protected]>
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 "bregs.h" // struct bregs
9: #include "biosvar.h" // GET_BDA
10: #include "util.h" // memset
11: #include "vgabios.h" // calc_page_size
12: #include "optionroms.h" // struct pci_data
13: #include "config.h" // CONFIG_*
14: #include "stdvga.h" // stdvga_set_cursor_shape
15: #include "clext.h" // clext_1012
16: #include "vgahw.h" // vgahw_set_mode
17: #include "vbe.h" // VBE_RETURN_STATUS_FAILED
18: #include "pci.h" // pci_config_readw
19: #include "pci_regs.h" // PCI_VENDOR_ID
20:
21: // Standard Video Save Pointer Table
22: struct VideoSavePointer_s {
23: struct segoff_s videoparam;
24: struct segoff_s paramdynamicsave;
25: struct segoff_s textcharset;
26: struct segoff_s graphcharset;
27: struct segoff_s secsavepointer;
28: u8 reserved[8];
29: } PACKED;
30:
31: static struct VideoSavePointer_s video_save_pointer_table VAR16;
32:
33: struct VideoParam_s video_param_table[29] VAR16;
34:
35:
36: /****************************************************************
37: * PCI Data
38: ****************************************************************/
39:
40: struct pci_data rom_pci_data VAR16VISIBLE = {
41: .signature = PCI_ROM_SIGNATURE,
42: .vendor = CONFIG_VGA_VID,
43: .device = CONFIG_VGA_DID,
44: .dlen = 0x18,
45: .class_hi = 0x300,
46: .irevision = 1,
47: .type = PCIROM_CODETYPE_X86,
48: .indicator = 0x80,
49: };
50:
51:
52: /****************************************************************
53: * Helper functions
54: ****************************************************************/
55:
56: // Return the bits per pixel in system memory for a given mode.
57: int
58: vga_bpp(struct vgamode_s *vmode_g)
59: {
60: switch (GET_GLOBAL(vmode_g->memmodel)) {
61: case MM_TEXT:
62: return 16;
63: case MM_PLANAR:
64: return 1;
65: }
66: u8 depth = GET_GLOBAL(vmode_g->depth);
67: if (depth > 8)
68: return ALIGN(depth, 8);
69: return depth;
70: }
71:
72: u16
73: calc_page_size(u8 memmodel, u16 width, u16 height)
74: {
75: switch (memmodel) {
76: case MM_TEXT:
77: return ALIGN(width * height * 2, 2*1024);
78: case MM_CGA:
79: return 16*1024;
80: default:
81: return ALIGN(width * height / 8, 8*1024);
82: }
83: }
84:
85: static void
86: set_cursor_shape(u8 start, u8 end)
87: {
88: start &= 0x3f;
89: end &= 0x1f;
90:
91: u16 curs = (start << 8) + end;
92: SET_BDA(cursor_type, curs);
93:
94: u8 modeset_ctl = GET_BDA(modeset_ctl);
95: u16 cheight = GET_BDA(char_height);
96: if ((modeset_ctl & 0x01) && (cheight > 8) && (end < 8) && (start < 0x20)) {
97: if (end != (start + 1))
98: start = ((start + 1) * cheight / 8) - 1;
99: else
100: start = ((end + 1) * cheight / 8) - 2;
101: end = ((end + 1) * cheight / 8) - 1;
102: }
103: stdvga_set_cursor_shape(start, end);
104: }
105:
106: static u16
107: get_cursor_shape(u8 page)
108: {
109: if (page > 7)
110: return 0;
111: // FIXME should handle VGA 14/16 lines
112: return GET_BDA(cursor_type);
113: }
114:
115: static void
116: set_cursor_pos(struct cursorpos cp)
117: {
118: u8 page = cp.page, x = cp.x, y = cp.y;
119:
120: // Should not happen...
121: if (page > 7)
122: return;
123:
124: // Bios cursor pos
125: SET_BDA(cursor_pos[page], (y << 8) | x);
126:
127: // Set the hardware cursor
128: u8 current = GET_BDA(video_page);
129: if (cp.page != current)
130: return;
131:
132: // Calculate the memory address
133: int address = (GET_BDA(video_pagesize) * page
134: + (x + y * GET_BDA(video_cols)) * 2);
135: stdvga_set_cursor_pos(address);
136: }
137:
138: static struct cursorpos
139: get_cursor_pos(u8 page)
140: {
141: if (page == 0xff)
142: // special case - use current page
143: page = GET_BDA(video_page);
144: if (page > 7) {
145: struct cursorpos cp = { 0, 0, 0xfe };
146: return cp;
147: }
148: // FIXME should handle VGA 14/16 lines
149: u16 xy = GET_BDA(cursor_pos[page]);
150: struct cursorpos cp = {xy, xy>>8, page};
151: return cp;
152: }
153:
154: static void
155: set_active_page(u8 page)
156: {
157: if (page > 7)
158: return;
159:
160: // Get the mode
161: struct vgamode_s *vmode_g = get_current_mode();
162: if (!vmode_g)
163: return;
164:
165: // Get cursor pos for the given page
166: struct cursorpos cp = get_cursor_pos(page);
167:
168: // Calculate memory address of start of page
169: int address = GET_BDA(video_pagesize) * page;
170: vgahw_set_displaystart(vmode_g, address);
171:
172: // And change the BIOS page
173: SET_BDA(video_pagestart, address);
174: SET_BDA(video_page, page);
175:
176: dprintf(1, "Set active page %02x address %04x\n", page, address);
177:
178: // Display the cursor, now the page is active
179: set_cursor_pos(cp);
180: }
181:
182: static void
183: set_scan_lines(u8 lines)
184: {
185: stdvga_set_scan_lines(lines);
186: if (lines == 8)
187: set_cursor_shape(0x06, 0x07);
188: else
189: set_cursor_shape(lines - 4, lines - 3);
190: SET_BDA(char_height, lines);
191: u16 vde = stdvga_get_vde();
192: u8 rows = vde / lines;
193: SET_BDA(video_rows, rows - 1);
194: u16 cols = GET_BDA(video_cols);
195: SET_BDA(video_pagesize, calc_page_size(MM_TEXT, cols, rows));
196: }
197:
198:
199: /****************************************************************
200: * Character writing
201: ****************************************************************/
202:
203: // Scroll the screen one line. This function is designed to be called
204: // tail-recursive to reduce stack usage.
205: static void noinline
206: scroll_one(u16 nbrows, u16 nbcols, u8 page)
207: {
208: struct cursorpos ul = {0, 0, page};
209: struct cursorpos lr = {nbcols-1, nbrows-1, page};
210: vgafb_scroll(1, -1, ul, lr);
211: }
212:
213: // Write a character to the screen at a given position. Implement
214: // special characters and scroll the screen if necessary.
215: static void
216: write_teletype(struct cursorpos *pcp, struct carattr ca)
217: {
218: struct cursorpos cp = *pcp;
219:
220: // Get the dimensions
221: u16 nbrows = GET_BDA(video_rows) + 1;
222: u16 nbcols = GET_BDA(video_cols);
223:
224: switch (ca.car) {
225: case 7:
226: //FIXME should beep
227: break;
228: case 8:
229: if (cp.x > 0)
230: cp.x--;
231: break;
232: case '\r':
233: cp.x = 0;
234: break;
235: case '\n':
236: cp.y++;
237: break;
238: case '\t':
239: ca.car = ' ';
240: do {
241: vgafb_write_char(cp, ca);
242: cp.x++;
243: } while (cp.x < nbcols && cp.x % 8);
244: break;
245: default:
246: vgafb_write_char(cp, ca);
247: cp.x++;
248: }
249:
250: // Do we need to wrap ?
251: if (cp.x == nbcols) {
252: cp.x = 0;
253: cp.y++;
254: }
255: // Do we need to scroll ?
256: if (cp.y < nbrows) {
257: *pcp = cp;
258: return;
259: }
260: // Scroll screen
261: cp.y--;
262: *pcp = cp;
263: scroll_one(nbrows, nbcols, cp.page);
264: }
265:
266:
267: /****************************************************************
268: * Save and restore bda state
269: ****************************************************************/
270:
271: void
272: save_bda_state(u16 seg, struct saveBDAstate *info)
273: {
274: SET_FARVAR(seg, info->video_mode, GET_BDA(vbe_mode));
275: SET_FARVAR(seg, info->video_cols, GET_BDA(video_cols));
276: SET_FARVAR(seg, info->video_pagesize, GET_BDA(video_pagesize));
277: SET_FARVAR(seg, info->crtc_address, GET_BDA(crtc_address));
278: SET_FARVAR(seg, info->video_rows, GET_BDA(video_rows));
279: SET_FARVAR(seg, info->char_height, GET_BDA(char_height));
280: SET_FARVAR(seg, info->video_ctl, GET_BDA(video_ctl));
281: SET_FARVAR(seg, info->video_switches, GET_BDA(video_switches));
282: SET_FARVAR(seg, info->modeset_ctl, GET_BDA(modeset_ctl));
283: SET_FARVAR(seg, info->cursor_type, GET_BDA(cursor_type));
284: int i;
285: for (i=0; i<8; i++)
286: SET_FARVAR(seg, info->cursor_pos[i], GET_BDA(cursor_pos[i]));
287: SET_FARVAR(seg, info->video_pagestart, GET_BDA(video_pagestart));
288: SET_FARVAR(seg, info->video_page, GET_BDA(video_page));
289: /* current font */
290: SET_FARVAR(seg, info->font0, GET_IVT(0x1f));
291: SET_FARVAR(seg, info->font1, GET_IVT(0x43));
292: }
293:
294: void
295: restore_bda_state(u16 seg, struct saveBDAstate *info)
296: {
297: u16 mode = GET_FARVAR(seg, info->video_mode);
298: SET_BDA(vbe_mode, mode);
299: if (mode < 0x100)
300: SET_BDA(video_mode, mode);
301: else
302: SET_BDA(video_mode, 0xff);
303: SET_BDA(video_cols, GET_FARVAR(seg, info->video_cols));
304: SET_BDA(video_pagesize, GET_FARVAR(seg, info->video_pagesize));
305: SET_BDA(crtc_address, GET_FARVAR(seg, info->crtc_address));
306: SET_BDA(video_rows, GET_FARVAR(seg, info->video_rows));
307: SET_BDA(char_height, GET_FARVAR(seg, info->char_height));
308: SET_BDA(video_ctl, GET_FARVAR(seg, info->video_ctl));
309: SET_BDA(video_switches, GET_FARVAR(seg, info->video_switches));
310: SET_BDA(modeset_ctl, GET_FARVAR(seg, info->modeset_ctl));
311: SET_BDA(cursor_type, GET_FARVAR(seg, info->cursor_type));
312: int i;
313: for (i = 0; i < 8; i++)
314: SET_BDA(cursor_pos[i], GET_FARVAR(seg, info->cursor_pos[i]));
315: SET_BDA(video_pagestart, GET_FARVAR(seg, info->video_pagestart));
316: SET_BDA(video_page, GET_FARVAR(seg, info->video_page));
317: /* current font */
318: SET_IVT(0x1f, GET_FARVAR(seg, info->font0));
319: SET_IVT(0x43, GET_FARVAR(seg, info->font1));
320: }
321:
322:
323: /****************************************************************
324: * Mode setting
325: ****************************************************************/
326:
327: struct vgamode_s *
328: get_current_mode(void)
329: {
330: return vgahw_find_mode(GET_BDA(vbe_mode) & ~MF_VBEFLAGS);
331: }
332:
333: // Setup BDA after a mode switch.
334: int
335: vga_set_mode(int mode, int flags)
336: {
337: dprintf(1, "set VGA mode %x\n", mode);
338: struct vgamode_s *vmode_g = vgahw_find_mode(mode);
339: if (!vmode_g)
340: return VBE_RETURN_STATUS_FAILED;
341:
342: int ret = vgahw_set_mode(vmode_g, flags);
343: if (ret)
344: return ret;
345:
346: // Set the BIOS mem
347: int width = GET_GLOBAL(vmode_g->width);
348: int height = GET_GLOBAL(vmode_g->height);
349: u8 memmodel = GET_GLOBAL(vmode_g->memmodel);
350: int cheight = GET_GLOBAL(vmode_g->cheight);
351: if (mode < 0x100)
352: SET_BDA(video_mode, mode);
353: else
354: SET_BDA(video_mode, 0xff);
355: SET_BDA(vbe_mode, mode | (flags & MF_VBEFLAGS));
356: if (memmodel == MM_TEXT) {
357: SET_BDA(video_cols, width);
358: SET_BDA(video_rows, height-1);
359: SET_BDA(cursor_type, 0x0607);
360: } else {
361: int cwidth = GET_GLOBAL(vmode_g->cwidth);
362: SET_BDA(video_cols, width / cwidth);
363: SET_BDA(video_rows, (height / cheight) - 1);
364: SET_BDA(cursor_type, 0x0000);
365: }
366: SET_BDA(video_pagesize, calc_page_size(memmodel, width, height));
367: SET_BDA(crtc_address, stdvga_get_crtc());
368: SET_BDA(char_height, cheight);
369: SET_BDA(video_ctl, 0x60 | (flags & MF_NOCLEARMEM ? 0x80 : 0x00));
370: SET_BDA(video_switches, 0xF9);
371: SET_BDA(modeset_ctl, GET_BDA(modeset_ctl) & 0x7f);
372: int i;
373: for (i=0; i<8; i++)
374: SET_BDA(cursor_pos[i], 0x0000);
375: SET_BDA(video_pagestart, 0x0000);
376: SET_BDA(video_page, 0x00);
377:
378: // FIXME We nearly have the good tables. to be reworked
379: SET_BDA(dcc_index, 0x08); // 8 is VGA should be ok for now
380: SET_BDA(video_savetable
381: , SEGOFF(get_global_seg(), (u32)&video_save_pointer_table));
382:
383: // FIXME
384: SET_BDA(video_msr, 0x00); // Unavailable on vanilla vga, but...
385: SET_BDA(video_pal, 0x00); // Unavailable on vanilla vga, but...
386:
387: // Set the ints 0x1F and 0x43
388: SET_IVT(0x1f, SEGOFF(get_global_seg(), (u32)&vgafont8[128 * 8]));
389:
390: switch (cheight) {
391: case 8:
392: SET_IVT(0x43, SEGOFF(get_global_seg(), (u32)vgafont8));
393: break;
394: case 14:
395: SET_IVT(0x43, SEGOFF(get_global_seg(), (u32)vgafont14));
396: break;
397: case 16:
398: SET_IVT(0x43, SEGOFF(get_global_seg(), (u32)vgafont16));
399: break;
400: }
401:
402: return 0;
403: }
404:
405:
406: /****************************************************************
407: * VGA int 10 handler
408: ****************************************************************/
409:
410: static void
411: handle_1000(struct bregs *regs)
412: {
413: int mode = regs->al & 0x7f;
414:
415: // Set regs->al
416: if (mode > 7)
417: regs->al = 0x20;
418: else if (mode == 6)
419: regs->al = 0x3f;
420: else
421: regs->al = 0x30;
422:
423: int flags = GET_BDA(modeset_ctl) & (MF_NOPALETTE|MF_GRAYSUM);
424: if (regs->al & 0x80)
425: flags |= MF_NOCLEARMEM;
426:
427: vga_set_mode(mode, flags);
428: }
429:
430: static void
431: handle_1001(struct bregs *regs)
432: {
433: set_cursor_shape(regs->ch, regs->cl);
434: }
435:
436: static void
437: handle_1002(struct bregs *regs)
438: {
439: struct cursorpos cp = {regs->dl, regs->dh, regs->bh};
440: set_cursor_pos(cp);
441: }
442:
443: static void
444: handle_1003(struct bregs *regs)
445: {
446: regs->cx = get_cursor_shape(regs->bh);
447: struct cursorpos cp = get_cursor_pos(regs->bh);
448: regs->dl = cp.x;
449: regs->dh = cp.y;
450: }
451:
452: // Read light pen pos (unimplemented)
453: static void
454: handle_1004(struct bregs *regs)
455: {
456: debug_stub(regs);
457: regs->ax = regs->bx = regs->cx = regs->dx = 0;
458: }
459:
460: static void
461: handle_1005(struct bregs *regs)
462: {
463: set_active_page(regs->al);
464: }
465:
466: static void
467: verify_scroll(struct bregs *regs, int dir)
468: {
469: u8 ulx = regs->cl, uly = regs->ch, lrx = regs->dl, lry = regs->dh;
470: u16 nbrows = GET_BDA(video_rows) + 1;
471: if (lry >= nbrows)
472: lry = nbrows - 1;
473: u16 nbcols = GET_BDA(video_cols);
474: if (lrx >= nbcols)
475: lrx = nbcols - 1;
476:
477: if (ulx > lrx || uly > lry)
478: return;
479:
480: int nblines = regs->al;
481: if (!nblines || nblines > lry - uly + 1)
482: nblines = lry - uly + 1;
483:
484: u8 page = GET_BDA(video_page);
485: struct cursorpos ul = {ulx, uly, page};
486: struct cursorpos lr = {lrx, lry, page};
487: vgafb_scroll(dir * nblines, regs->bh, ul, lr);
488: }
489:
490: static void
491: handle_1006(struct bregs *regs)
492: {
493: verify_scroll(regs, 1);
494: }
495:
496: static void
497: handle_1007(struct bregs *regs)
498: {
499: verify_scroll(regs, -1);
500: }
501:
502: static void
503: handle_1008(struct bregs *regs)
504: {
505: struct carattr ca = vgafb_read_char(get_cursor_pos(regs->bh));
506: regs->al = ca.car;
507: regs->ah = ca.attr;
508: }
509:
510: static void noinline
511: write_chars(u8 page, struct carattr ca, u16 count)
512: {
513: u16 nbcols = GET_BDA(video_cols);
514: struct cursorpos cp = get_cursor_pos(page);
515: while (count--) {
516: vgafb_write_char(cp, ca);
517: cp.x++;
518: if (cp.x >= nbcols) {
519: cp.x -= nbcols;
520: cp.y++;
521: }
522: }
523: }
524:
525: static void
526: handle_1009(struct bregs *regs)
527: {
528: struct carattr ca = {regs->al, regs->bl, 1};
529: write_chars(regs->bh, ca, regs->cx);
530: }
531:
532: static void
533: handle_100a(struct bregs *regs)
534: {
535: struct carattr ca = {regs->al, regs->bl, 0};
536: write_chars(regs->bh, ca, regs->cx);
537: }
538:
539:
540: static void
541: handle_100b00(struct bregs *regs)
542: {
543: stdvga_set_border_color(regs->bl);
544: }
545:
546: static void
547: handle_100b01(struct bregs *regs)
548: {
549: stdvga_set_palette(regs->bl);
550: }
551:
552: static void
553: handle_100bXX(struct bregs *regs)
554: {
555: debug_stub(regs);
556: }
557:
558: static void
559: handle_100b(struct bregs *regs)
560: {
561: switch (regs->bh) {
562: case 0x00: handle_100b00(regs); break;
563: case 0x01: handle_100b01(regs); break;
564: default: handle_100bXX(regs); break;
565: }
566: }
567:
568:
569: static void
570: handle_100c(struct bregs *regs)
571: {
572: // XXX - page (regs->bh) is unused
573: vgafb_write_pixel(regs->al, regs->cx, regs->dx);
574: }
575:
576: static void
577: handle_100d(struct bregs *regs)
578: {
579: // XXX - page (regs->bh) is unused
580: regs->al = vgafb_read_pixel(regs->cx, regs->dx);
581: }
582:
583: static void noinline
584: handle_100e(struct bregs *regs)
585: {
586: // Ralf Brown Interrupt list is WRONG on bh(page)
587: // We do output only on the current page !
588: struct carattr ca = {regs->al, regs->bl, 0};
589: struct cursorpos cp = get_cursor_pos(0xff);
590: write_teletype(&cp, ca);
591: set_cursor_pos(cp);
592: }
593:
594: static void
595: handle_100f(struct bregs *regs)
596: {
597: regs->bh = GET_BDA(video_page);
598: regs->al = GET_BDA(video_mode) | (GET_BDA(video_ctl) & 0x80);
599: regs->ah = GET_BDA(video_cols);
600: }
601:
602:
603: static void
604: handle_101000(struct bregs *regs)
605: {
606: if (regs->bl > 0x14)
607: return;
608: stdvga_attr_write(regs->bl, regs->bh);
609: }
610:
611: static void
612: handle_101001(struct bregs *regs)
613: {
614: stdvga_set_overscan_border_color(regs->bh);
615: }
616:
617: static void
618: handle_101002(struct bregs *regs)
619: {
620: stdvga_set_all_palette_reg(regs->es, (u8*)(regs->dx + 0));
621: }
622:
623: static void
624: handle_101003(struct bregs *regs)
625: {
626: stdvga_toggle_intensity(regs->bl);
627: }
628:
629: static void
630: handle_101007(struct bregs *regs)
631: {
632: if (regs->bl > 0x14)
633: return;
634: regs->bh = stdvga_attr_read(regs->bl);
635: }
636:
637: static void
638: handle_101008(struct bregs *regs)
639: {
640: regs->bh = stdvga_get_overscan_border_color();
641: }
642:
643: static void
644: handle_101009(struct bregs *regs)
645: {
646: stdvga_get_all_palette_reg(regs->es, (u8*)(regs->dx + 0));
647: }
648:
649: static void noinline
650: handle_101010(struct bregs *regs)
651: {
652: u8 rgb[3] = {regs->dh, regs->ch, regs->cl};
653: stdvga_dac_write(GET_SEG(SS), rgb, regs->bx, 1);
654: }
655:
656: static void
657: handle_101012(struct bregs *regs)
658: {
659: stdvga_dac_write(regs->es, (u8*)(regs->dx + 0), regs->bx, regs->cx);
660: }
661:
662: static void
663: handle_101013(struct bregs *regs)
664: {
665: stdvga_select_video_dac_color_page(regs->bl, regs->bh);
666: }
667:
668: static void noinline
669: handle_101015(struct bregs *regs)
670: {
671: u8 rgb[3];
672: stdvga_dac_read(GET_SEG(SS), rgb, regs->bx, 1);
673: regs->dh = rgb[0];
674: regs->ch = rgb[1];
675: regs->cl = rgb[2];
676: }
677:
678: static void
679: handle_101017(struct bregs *regs)
680: {
681: stdvga_dac_read(regs->es, (u8*)(regs->dx + 0), regs->bx, regs->cx);
682: }
683:
684: static void
685: handle_101018(struct bregs *regs)
686: {
687: stdvga_pelmask_write(regs->bl);
688: }
689:
690: static void
691: handle_101019(struct bregs *regs)
692: {
693: regs->bl = stdvga_pelmask_read();
694: }
695:
696: static void
697: handle_10101a(struct bregs *regs)
698: {
699: stdvga_read_video_dac_state(®s->bl, ®s->bh);
700: }
701:
702: static void
703: handle_10101b(struct bregs *regs)
704: {
705: stdvga_perform_gray_scale_summing(regs->bx, regs->cx);
706: }
707:
708: static void
709: handle_1010XX(struct bregs *regs)
710: {
711: debug_stub(regs);
712: }
713:
714: static void
715: handle_1010(struct bregs *regs)
716: {
717: switch (regs->al) {
718: case 0x00: handle_101000(regs); break;
719: case 0x01: handle_101001(regs); break;
720: case 0x02: handle_101002(regs); break;
721: case 0x03: handle_101003(regs); break;
722: case 0x07: handle_101007(regs); break;
723: case 0x08: handle_101008(regs); break;
724: case 0x09: handle_101009(regs); break;
725: case 0x10: handle_101010(regs); break;
726: case 0x12: handle_101012(regs); break;
727: case 0x13: handle_101013(regs); break;
728: case 0x15: handle_101015(regs); break;
729: case 0x17: handle_101017(regs); break;
730: case 0x18: handle_101018(regs); break;
731: case 0x19: handle_101019(regs); break;
732: case 0x1a: handle_10101a(regs); break;
733: case 0x1b: handle_10101b(regs); break;
734: default: handle_1010XX(regs); break;
735: }
736: }
737:
738:
739: static void
740: handle_101100(struct bregs *regs)
741: {
742: stdvga_load_font(regs->es, (void*)(regs->bp+0), regs->cx
743: , regs->dx, regs->bl, regs->bh);
744: }
745:
746: static void
747: handle_101101(struct bregs *regs)
748: {
749: stdvga_load_font(get_global_seg(), vgafont14, 0x100, 0, regs->bl, 14);
750: }
751:
752: static void
753: handle_101102(struct bregs *regs)
754: {
755: stdvga_load_font(get_global_seg(), vgafont8, 0x100, 0, regs->bl, 8);
756: }
757:
758: static void
759: handle_101103(struct bregs *regs)
760: {
761: stdvga_set_text_block_specifier(regs->bl);
762: }
763:
764: static void
765: handle_101104(struct bregs *regs)
766: {
767: stdvga_load_font(get_global_seg(), vgafont16, 0x100, 0, regs->bl, 16);
768: }
769:
770: static void
771: handle_101110(struct bregs *regs)
772: {
773: stdvga_load_font(regs->es, (void*)(regs->bp+0), regs->cx
774: , regs->dx, regs->bl, regs->bh);
775: set_scan_lines(regs->bh);
776: }
777:
778: static void
779: handle_101111(struct bregs *regs)
780: {
781: stdvga_load_font(get_global_seg(), vgafont14, 0x100, 0, regs->bl, 14);
782: set_scan_lines(14);
783: }
784:
785: static void
786: handle_101112(struct bregs *regs)
787: {
788: stdvga_load_font(get_global_seg(), vgafont8, 0x100, 0, regs->bl, 8);
789: set_scan_lines(8);
790: }
791:
792: static void
793: handle_101114(struct bregs *regs)
794: {
795: stdvga_load_font(get_global_seg(), vgafont16, 0x100, 0, regs->bl, 16);
796: set_scan_lines(16);
797: }
798:
799: static void
800: handle_101130(struct bregs *regs)
801: {
802: switch (regs->bh) {
803: case 0x00: {
804: struct segoff_s so = GET_IVT(0x1f);
805: regs->es = so.seg;
806: regs->bp = so.offset;
807: break;
808: }
809: case 0x01: {
810: struct segoff_s so = GET_IVT(0x43);
811: regs->es = so.seg;
812: regs->bp = so.offset;
813: break;
814: }
815: case 0x02:
816: regs->es = get_global_seg();
817: regs->bp = (u32)vgafont14;
818: break;
819: case 0x03:
820: regs->es = get_global_seg();
821: regs->bp = (u32)vgafont8;
822: break;
823: case 0x04:
824: regs->es = get_global_seg();
825: regs->bp = (u32)vgafont8 + 128 * 8;
826: break;
827: case 0x05:
828: regs->es = get_global_seg();
829: regs->bp = (u32)vgafont14alt;
830: break;
831: case 0x06:
832: regs->es = get_global_seg();
833: regs->bp = (u32)vgafont16;
834: break;
835: case 0x07:
836: regs->es = get_global_seg();
837: regs->bp = (u32)vgafont16alt;
838: break;
839: default:
840: dprintf(1, "Get font info BH(%02x) was discarded\n", regs->bh);
841: return;
842: }
843: // Set byte/char of on screen font
844: regs->cx = GET_BDA(char_height) & 0xff;
845:
846: // Set Highest char row
847: regs->dl = GET_BDA(video_rows);
848: }
849:
850: static void
851: handle_1011XX(struct bregs *regs)
852: {
853: debug_stub(regs);
854: }
855:
856: static void
857: handle_1011(struct bregs *regs)
858: {
859: switch (regs->al) {
860: case 0x00: handle_101100(regs); break;
861: case 0x01: handle_101101(regs); break;
862: case 0x02: handle_101102(regs); break;
863: case 0x03: handle_101103(regs); break;
864: case 0x04: handle_101104(regs); break;
865: case 0x10: handle_101110(regs); break;
866: case 0x11: handle_101111(regs); break;
867: case 0x12: handle_101112(regs); break;
868: case 0x14: handle_101114(regs); break;
869: case 0x30: handle_101130(regs); break;
870: default: handle_1011XX(regs); break;
871: }
872: }
873:
874:
875: static void
876: handle_101210(struct bregs *regs)
877: {
878: u16 crtc_addr = GET_BDA(crtc_address);
879: if (crtc_addr == VGAREG_MDA_CRTC_ADDRESS)
880: regs->bx = 0x0103;
881: else
882: regs->bx = 0x0003;
883: regs->cx = GET_BDA(video_switches) & 0x0f;
884: }
885:
886: static void
887: handle_101230(struct bregs *regs)
888: {
889: u8 mctl = GET_BDA(modeset_ctl);
890: u8 vswt = GET_BDA(video_switches);
891: switch (regs->al) {
892: case 0x00:
893: // 200 lines
894: mctl = (mctl & ~0x10) | 0x80;
895: vswt = (vswt & ~0x0f) | 0x08;
896: break;
897: case 0x01:
898: // 350 lines
899: mctl &= ~0x90;
900: vswt = (vswt & ~0x0f) | 0x09;
901: break;
902: case 0x02:
903: // 400 lines
904: mctl = (mctl & ~0x80) | 0x10;
905: vswt = (vswt & ~0x0f) | 0x09;
906: break;
907: default:
908: dprintf(1, "Select vert res (%02x) was discarded\n", regs->al);
909: break;
910: }
911: SET_BDA(modeset_ctl, mctl);
912: SET_BDA(video_switches, vswt);
913: regs->al = 0x12;
914: }
915:
916: static void
917: handle_101231(struct bregs *regs)
918: {
919: u8 v = (regs->al & 0x01) << 3;
920: u8 mctl = GET_BDA(video_ctl) & ~0x08;
921: SET_BDA(video_ctl, mctl | v);
922: regs->al = 0x12;
923: }
924:
925: static void
926: handle_101232(struct bregs *regs)
927: {
928: stdvga_enable_video_addressing(regs->al);
929: regs->al = 0x12;
930: }
931:
932: static void
933: handle_101233(struct bregs *regs)
934: {
935: u8 v = ((regs->al << 1) & 0x02) ^ 0x02;
936: u8 v2 = GET_BDA(modeset_ctl) & ~0x02;
937: SET_BDA(modeset_ctl, v | v2);
938: regs->al = 0x12;
939: }
940:
941: static void
942: handle_101234(struct bregs *regs)
943: {
944: u8 v = (regs->al & 0x01) ^ 0x01;
945: u8 v2 = GET_BDA(modeset_ctl) & ~0x01;
946: SET_BDA(modeset_ctl, v | v2);
947: regs->al = 0x12;
948: }
949:
950: static void
951: handle_101235(struct bregs *regs)
952: {
953: debug_stub(regs);
954: regs->al = 0x12;
955: }
956:
957: static void
958: handle_101236(struct bregs *regs)
959: {
960: debug_stub(regs);
961: regs->al = 0x12;
962: }
963:
964: static void
965: handle_1012XX(struct bregs *regs)
966: {
967: debug_stub(regs);
968: }
969:
970: static void
971: handle_1012(struct bregs *regs)
972: {
973: if (CONFIG_VGA_CIRRUS && regs->bl >= 0x80) {
974: clext_1012(regs);
975: return;
976: }
977:
978: switch (regs->bl) {
979: case 0x10: handle_101210(regs); break;
980: case 0x30: handle_101230(regs); break;
981: case 0x31: handle_101231(regs); break;
982: case 0x32: handle_101232(regs); break;
983: case 0x33: handle_101233(regs); break;
984: case 0x34: handle_101234(regs); break;
985: case 0x35: handle_101235(regs); break;
986: case 0x36: handle_101236(regs); break;
987: default: handle_1012XX(regs); break;
988: }
989: }
990:
991:
992: // Write string
993: static void noinline
994: handle_1013(struct bregs *regs)
995: {
996: struct cursorpos cp;
997: if (regs->dh == 0xff)
998: // if row=0xff special case : use current cursor position
999: cp = get_cursor_pos(regs->bh);
1000: else
1001: cp = (struct cursorpos) {regs->dl, regs->dh, regs->bh};
1002:
1003: u16 count = regs->cx;
1004: u8 *offset_far = (void*)(regs->bp + 0);
1005: u8 attr = regs->bl;
1006: while (count--) {
1007: u8 car = GET_FARVAR(regs->es, *offset_far);
1008: offset_far++;
1009: if (regs->al & 2) {
1010: attr = GET_FARVAR(regs->es, *offset_far);
1011: offset_far++;
1012: }
1013:
1014: struct carattr ca = {car, attr, 1};
1015: write_teletype(&cp, ca);
1016: }
1017:
1018: if (regs->al & 1)
1019: set_cursor_pos(cp);
1020: }
1021:
1022:
1023: static void
1024: handle_101a00(struct bregs *regs)
1025: {
1026: regs->bx = GET_BDA(dcc_index);
1027: regs->al = 0x1a;
1028: }
1029:
1030: static void
1031: handle_101a01(struct bregs *regs)
1032: {
1033: SET_BDA(dcc_index, regs->bl);
1034: dprintf(1, "Alternate Display code (%02x) was discarded\n", regs->bh);
1035: regs->al = 0x1a;
1036: }
1037:
1038: static void
1039: handle_101aXX(struct bregs *regs)
1040: {
1041: debug_stub(regs);
1042: }
1043:
1044: static void
1045: handle_101a(struct bregs *regs)
1046: {
1047: switch (regs->al) {
1048: case 0x00: handle_101a00(regs); break;
1049: case 0x01: handle_101a01(regs); break;
1050: default: handle_101aXX(regs); break;
1051: }
1052: }
1053:
1054:
1055: static u8 static_functionality[0x10] VAR16 = {
1056: /* 0 */ 0xff, // All modes supported #1
1057: /* 1 */ 0xe0, // All modes supported #2
1058: /* 2 */ 0x0f, // All modes supported #3
1059: /* 3 */ 0x00, 0x00, 0x00, 0x00, // reserved
1060: /* 7 */ 0x07, // 200, 350, 400 scan lines
1061: /* 8 */ 0x02, // mamimum number of visible charsets in text mode
1062: /* 9 */ 0x08, // total number of charset blocks in text mode
1063: /* a */ 0xe7, // Change to add new functions
1064: /* b */ 0x0c, // Change to add new functions
1065: /* c */ 0x00, // reserved
1066: /* d */ 0x00, // reserved
1067: /* e */ 0x00, // Change to add new functions
1068: /* f */ 0x00 // reserved
1069: };
1070:
1071: struct funcInfo {
1072: struct segoff_s static_functionality;
1073: u8 bda_0x49[30];
1074: u8 bda_0x84[3];
1075: u8 dcc_index;
1076: u8 dcc_alt;
1077: u16 colors;
1078: u8 pages;
1079: u8 scan_lines;
1080: u8 primary_char;
1081: u8 secondar_char;
1082: u8 misc;
1083: u8 non_vga_mode;
1084: u8 reserved_2f[2];
1085: u8 video_mem;
1086: u8 save_flags;
1087: u8 disp_info;
1088: u8 reserved_34[12];
1089: };
1090:
1091: static void
1092: handle_101b(struct bregs *regs)
1093: {
1094: u16 seg = regs->es;
1095: struct funcInfo *info = (void*)(regs->di+0);
1096: memset_far(seg, info, 0, sizeof(*info));
1097: // Address of static functionality table
1098: SET_FARVAR(seg, info->static_functionality
1099: , SEGOFF(get_global_seg(), (u32)static_functionality));
1100:
1101: // Hard coded copy from BIOS area. Should it be cleaner ?
1102: memcpy_far(seg, info->bda_0x49, SEG_BDA, (void*)0x49
1103: , sizeof(info->bda_0x49));
1104: memcpy_far(seg, info->bda_0x84, SEG_BDA, (void*)0x84
1105: , sizeof(info->bda_0x84));
1106:
1107: SET_FARVAR(seg, info->dcc_index, GET_BDA(dcc_index));
1108: SET_FARVAR(seg, info->colors, 16);
1109: SET_FARVAR(seg, info->pages, 8);
1110: SET_FARVAR(seg, info->scan_lines, 2);
1111: SET_FARVAR(seg, info->video_mem, 3);
1112: regs->al = 0x1B;
1113: }
1114:
1115:
1116: static void
1117: handle_101c(struct bregs *regs)
1118: {
1119: u16 seg = regs->es;
1120: void *data = (void*)(regs->bx+0);
1121: u16 states = regs->cx;
1122: if (states & ~0x07)
1123: goto fail;
1124: int ret;
1125: switch (regs->al) {
1126: case 0x00:
1127: ret = vgahw_size_state(states);
1128: if (ret < 0)
1129: goto fail;
1130: regs->bx = ret / 64;
1131: break;
1132: case 0x01:
1133: ret = vgahw_save_state(seg, data, states);
1134: if (ret)
1135: goto fail;
1136: break;
1137: case 0x02:
1138: ret = vgahw_restore_state(seg, data, states);
1139: if (ret)
1140: goto fail;
1141: break;
1142: default:
1143: goto fail;
1144: }
1145: regs->al = 0x1c;
1146: fail:
1147: return;
1148: }
1149:
1150: static void
1151: handle_10XX(struct bregs *regs)
1152: {
1153: debug_stub(regs);
1154: }
1155:
1156: // INT 10h Video Support Service Entry Point
1157: void VISIBLE16
1158: handle_10(struct bregs *regs)
1159: {
1160: debug_enter(regs, DEBUG_VGA_10);
1161: switch (regs->ah) {
1162: case 0x00: handle_1000(regs); break;
1163: case 0x01: handle_1001(regs); break;
1164: case 0x02: handle_1002(regs); break;
1165: case 0x03: handle_1003(regs); break;
1166: case 0x04: handle_1004(regs); break;
1167: case 0x05: handle_1005(regs); break;
1168: case 0x06: handle_1006(regs); break;
1169: case 0x07: handle_1007(regs); break;
1170: case 0x08: handle_1008(regs); break;
1171: case 0x09: handle_1009(regs); break;
1172: case 0x0a: handle_100a(regs); break;
1173: case 0x0b: handle_100b(regs); break;
1174: case 0x0c: handle_100c(regs); break;
1175: case 0x0d: handle_100d(regs); break;
1176: case 0x0e: handle_100e(regs); break;
1177: case 0x0f: handle_100f(regs); break;
1178: case 0x10: handle_1010(regs); break;
1179: case 0x11: handle_1011(regs); break;
1180: case 0x12: handle_1012(regs); break;
1181: case 0x13: handle_1013(regs); break;
1182: case 0x1a: handle_101a(regs); break;
1183: case 0x1b: handle_101b(regs); break;
1184: case 0x1c: handle_101c(regs); break;
1185: case 0x4f: handle_104f(regs); break;
1186: default: handle_10XX(regs); break;
1187: }
1188: }
1189:
1190:
1191: /****************************************************************
1192: * VGA post
1193: ****************************************************************/
1194:
1195: static void
1196: init_bios_area(void)
1197: {
1198: // init detected hardware BIOS Area
1199: // set 80x25 color (not clear from RBIL but usual)
1200: u16 eqf = GET_BDA(equipment_list_flags);
1201: SET_BDA(equipment_list_flags, (eqf & 0xffcf) | 0x20);
1202:
1203: // Just for the first int10 find its children
1204:
1205: // the default char height
1206: SET_BDA(char_height, 0x10);
1207:
1208: // Clear the screen
1209: SET_BDA(video_ctl, 0x60);
1210:
1211: // Set the basic screen we have
1212: SET_BDA(video_switches, 0xf9);
1213:
1214: // Set the basic modeset options
1215: SET_BDA(modeset_ctl, 0x51);
1216:
1217: // Set the default MSR
1218: SET_BDA(video_msr, 0x09);
1219: }
1220:
1221: int VgaBDF VAR16 = -1;
1222: int HaveRunInit VAR16;
1223:
1224: void VISIBLE16
1225: vga_post(struct bregs *regs)
1226: {
1227: debug_serial_setup();
1228: dprintf(1, "Start SeaVGABIOS (version %s)\n", VERSION);
1229: debug_enter(regs, DEBUG_VGA_POST);
1230:
1231: if (CONFIG_VGA_PCI && !GET_GLOBAL(HaveRunInit)) {
1232: u16 bdf = regs->ax;
1233: if ((pci_config_readw(bdf, PCI_VENDOR_ID)
1234: == GET_GLOBAL(rom_pci_data.vendor))
1235: && (pci_config_readw(bdf, PCI_DEVICE_ID)
1236: == GET_GLOBAL(rom_pci_data.device)))
1237: SET_VGA(VgaBDF, bdf);
1238: }
1239:
1240: int ret = vgahw_init();
1241: if (ret) {
1242: dprintf(1, "Failed to initialize VGA hardware. Exiting.\n");
1243: return;
1244: }
1245:
1246: if (GET_GLOBAL(HaveRunInit))
1247: return;
1248:
1249: init_bios_area();
1250:
1251: SET_VGA(video_save_pointer_table.videoparam
1252: , SEGOFF(get_global_seg(), (u32)video_param_table));
1253: stdvga_build_video_param();
1254:
1255: extern void entry_10(void);
1256: SET_IVT(0x10, SEGOFF(get_global_seg(), (u32)entry_10));
1257:
1258: SET_VGA(HaveRunInit, 1);
1259:
1260: // Fixup checksum
1261: extern u8 _rom_header_size, _rom_header_checksum;
1262: SET_VGA(_rom_header_checksum, 0);
1263: u8 sum = -checksum_far(get_global_seg(), 0,
1264: GET_GLOBAL(_rom_header_size) * 512);
1265: SET_VGA(_rom_header_checksum, sum);
1266: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.