PageRenderTime 65ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/roms/seabios/vgasrc/vgabios.c

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