1 // ============================================================================================ 2 // 3 // Copyright (C) 2002 Jeroen Janssen 4 // 5 // This library is free software; you can redistribute it and/or 6 // modify it under the terms of the GNU Lesser General Public 7 // License as published by the Free Software Foundation; either 8 // version 2 of the License, or (at your option) any later version. 9 // 10 // This library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 // Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public 16 // License along with this library; if not, write to the Free Software 17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 // 19 // ============================================================================================ 20 // 21 // This VBE is part of the VGA Bios specific to the plex86/bochs Emulated VGA card. 22 // You can NOT drive any physical vga card with it. 23 // 24 // ============================================================================================ 25 // 26 // This VBE Bios is based on information taken from : 27 // - VESA BIOS EXTENSION (VBE) Core Functions Standard Version 3.0 located at www.vesa.org 28 // 29 // ============================================================================================ 30 31 32 // defines available 33 34 // disable VESA/VBE2 check in vbe info 35 //#define VBE2_NO_VESA_CHECK 36 37 38 #include "vbe.h" 39 #include "vbetables.h" 40 41 // The current OEM Software Revision of this VBE Bios 42 #define VBE_OEM_SOFTWARE_REV 0x0002; 43 44 extern char vbebios_copyright; 45 extern char vbebios_vendor_name; 46 extern char vbebios_product_name; 47 extern char vbebios_product_revision; 48 49 ASM_START 50 // FIXME: 'merge' these (c) etc strings with the vgabios.c strings? 51 _vbebios_copyright: 52 .ascii "Bochs/Plex86 VBE(C) 2003 http://savannah.nongnu.org/projects/vgabios/" 53 .byte 0x00 54 55 _vbebios_vendor_name: 56 .ascii "Bochs/Plex86 Developers" 57 .byte 0x00 58 59 _vbebios_product_name: 60 .ascii "Bochs/Plex86 VBE Adapter" 61 .byte 0x00 62 63 _vbebios_product_revision: 64 .ascii "$Id$" 65 .byte 0x00 66 67 _vbebios_info_string: 68 .ascii "Bochs VBE Display Adapter enabled" 69 .byte 0x0a,0x0d 70 .byte 0x0a,0x0d 71 .byte 0x00 72 73 _no_vbebios_info_string: 74 .ascii "NO Bochs VBE Support available!" 75 .byte 0x0a,0x0d 76 .byte 0x0a,0x0d 77 .byte 0x00 78 79 #if defined(USE_BX_INFO) || defined(DEBUG) 80 msg_vbe_init: 81 .ascii "VBE Bios $Id$" 82 .byte 0x0a,0x0d, 0x00 83 #endif 84 85 .align 2 86 vesa_pm_start: 87 dw vesa_pm_set_window - vesa_pm_start 88 dw vesa_pm_set_display_start - vesa_pm_start 89 dw vesa_pm_unimplemented - vesa_pm_start 90 dw vesa_pm_io_ports_table - vesa_pm_start 91 vesa_pm_io_ports_table: 92 dw VBE_DISPI_IOPORT_INDEX 93 dw VBE_DISPI_IOPORT_INDEX + 1 94 dw VBE_DISPI_IOPORT_DATA 95 dw VBE_DISPI_IOPORT_DATA + 1 96 dw 0xffff 97 dw 0xffff 98 99 USE32 100 vesa_pm_set_window: 101 cmp bx, #0x00 102 je vesa_pm_set_display_window1 103 mov ax, #0x0100 104 ret 105 vesa_pm_set_display_window1: 106 mov ax, dx 107 push dx 108 push ax 109 mov dx, # VBE_DISPI_IOPORT_INDEX 110 mov ax, # VBE_DISPI_INDEX_BANK 111 out dx, ax 112 pop ax 113 mov dx, # VBE_DISPI_IOPORT_DATA 114 out dx, ax 115 in ax, dx 116 pop dx 117 cmp dx, ax 118 jne illegal_window 119 mov ax, #0x004f 120 ret 121 illegal_window: 122 mov ax, #0x014f 123 ret 124 125 vesa_pm_set_display_start: 126 cmp bl, #0x80 127 je vesa_pm_set_display_start1 128 cmp bl, #0x00 129 je vesa_pm_set_display_start1 130 mov ax, #0x0100 131 ret 132 vesa_pm_set_display_start1: 133 ; convert offset to (X, Y) coordinate 134 ; (would be simpler to change Bochs VBE API...) 135 push eax 136 push ecx 137 push edx 138 push esi 139 push edi 140 shl edx, #16 141 and ecx, #0xffff 142 or ecx, edx 143 shl ecx, #2 144 mov eax, ecx 145 146 push eax 147 mov dx, # VBE_DISPI_IOPORT_INDEX 148 mov ax, # VBE_DISPI_INDEX_VIRT_WIDTH 149 out dx, ax 150 mov dx, # VBE_DISPI_IOPORT_DATA 151 in ax, dx 152 movzx ecx, ax 153 154 mov dx, # VBE_DISPI_IOPORT_INDEX 155 mov ax, # VBE_DISPI_INDEX_BPP 156 out dx, ax 157 mov dx, # VBE_DISPI_IOPORT_DATA 158 in ax, dx 159 movzx esi, ax 160 pop eax 161 162 cmp esi, #4 163 jz bpp4_mode 164 add esi, #7 165 shr esi, #3 166 imul ecx, esi 167 xor edx, edx 168 div ecx 169 mov edi, eax 170 mov eax, edx 171 xor edx, edx 172 div esi 173 jmp set_xy_regs 174 175 bpp4_mode: 176 shr ecx, #1 177 xor edx, edx 178 div ecx 179 mov edi, eax 180 mov eax, edx 181 shl eax, #1 182 183 set_xy_regs: 184 push dx 185 push ax 186 mov dx, # VBE_DISPI_IOPORT_INDEX 187 mov ax, # VBE_DISPI_INDEX_X_OFFSET 188 out dx, ax 189 pop ax 190 mov dx, # VBE_DISPI_IOPORT_DATA 191 out dx, ax 192 pop dx 193 194 mov ax, di 195 push dx 196 push ax 197 mov dx, # VBE_DISPI_IOPORT_INDEX 198 mov ax, # VBE_DISPI_INDEX_Y_OFFSET 199 out dx, ax 200 pop ax 201 mov dx, # VBE_DISPI_IOPORT_DATA 202 out dx, ax 203 pop dx 204 205 pop edi 206 pop esi 207 pop edx 208 pop ecx 209 pop eax 210 mov ax, #0x004f 211 ret 212 213 vesa_pm_unimplemented: 214 mov ax, #0x014f 215 ret 216 USE16 217 vesa_pm_end: 218 219 ; DISPI ioport functions 220 221 dispi_get_id: 222 push dx 223 mov dx, # VBE_DISPI_IOPORT_INDEX 224 mov ax, # VBE_DISPI_INDEX_ID 225 out dx, ax 226 mov dx, # VBE_DISPI_IOPORT_DATA 227 in ax, dx 228 pop dx 229 ret 230 231 dispi_set_id: 232 push dx 233 push ax 234 mov dx, # VBE_DISPI_IOPORT_INDEX 235 mov ax, # VBE_DISPI_INDEX_ID 236 out dx, ax 237 pop ax 238 mov dx, # VBE_DISPI_IOPORT_DATA 239 out dx, ax 240 pop dx 241 ret 242 ASM_END 243 244 static void dispi_set_xres(xres) 245 Bit16u xres; 246 { 247 ASM_START 248 push bp 249 mov bp, sp 250 push ax 251 push dx 252 253 mov dx, # VBE_DISPI_IOPORT_INDEX 254 mov ax, # VBE_DISPI_INDEX_XRES 255 out dx, ax 256 mov dx, # VBE_DISPI_IOPORT_DATA 257 mov ax, 4[bp] ; xres 258 out dx, ax 259 260 pop dx 261 pop ax 262 pop bp 263 ASM_END 264 } 265 266 static void dispi_set_yres(yres) 267 Bit16u yres; 268 { 269 outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_YRES); 270 outw(VBE_DISPI_IOPORT_DATA,yres); 271 } 272 273 static void dispi_set_bpp(bpp) 274 Bit16u bpp; 275 { 276 outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_BPP); 277 outw(VBE_DISPI_IOPORT_DATA,bpp); 278 } 279 280 ASM_START 281 ; AL = bits per pixel / AH = bytes per pixel 282 dispi_get_bpp: 283 push dx 284 mov dx, # VBE_DISPI_IOPORT_INDEX 285 mov ax, # VBE_DISPI_INDEX_BPP 286 out dx, ax 287 mov dx, # VBE_DISPI_IOPORT_DATA 288 in ax, dx 289 mov ah, al 290 shr ah, 3 291 test al, #0x07 292 jz get_bpp_noinc 293 inc ah 294 get_bpp_noinc: 295 pop dx 296 ret 297 298 ; get display capabilities 299 300 _dispi_get_max_xres: 301 push dx 302 push bx 303 call dispi_get_enable 304 mov bx, ax 305 or ax, # VBE_DISPI_GETCAPS 306 call _dispi_set_enable 307 mov dx, # VBE_DISPI_IOPORT_INDEX 308 mov ax, # VBE_DISPI_INDEX_XRES 309 out dx, ax 310 mov dx, # VBE_DISPI_IOPORT_DATA 311 in ax, dx 312 push ax 313 mov ax, bx 314 call _dispi_set_enable 315 pop ax 316 pop bx 317 pop dx 318 ret 319 320 _dispi_get_max_bpp: 321 push dx 322 push bx 323 call dispi_get_enable 324 mov bx, ax 325 or ax, # VBE_DISPI_GETCAPS 326 call _dispi_set_enable 327 mov dx, # VBE_DISPI_IOPORT_INDEX 328 mov ax, # VBE_DISPI_INDEX_BPP 329 out dx, ax 330 mov dx, # VBE_DISPI_IOPORT_DATA 331 in ax, dx 332 push ax 333 mov ax, bx 334 call _dispi_set_enable 335 pop ax 336 pop bx 337 pop dx 338 ret 339 340 _dispi_set_enable: 341 push dx 342 push ax 343 mov dx, # VBE_DISPI_IOPORT_INDEX 344 mov ax, # VBE_DISPI_INDEX_ENABLE 345 out dx, ax 346 pop ax 347 mov dx, # VBE_DISPI_IOPORT_DATA 348 out dx, ax 349 pop dx 350 ret 351 352 dispi_get_enable: 353 push dx 354 mov dx, # VBE_DISPI_IOPORT_INDEX 355 mov ax, # VBE_DISPI_INDEX_ENABLE 356 out dx, ax 357 mov dx, # VBE_DISPI_IOPORT_DATA 358 in ax, dx 359 pop dx 360 ret 361 362 _dispi_set_bank: 363 push dx 364 push ax 365 mov dx, # VBE_DISPI_IOPORT_INDEX 366 mov ax, # VBE_DISPI_INDEX_BANK 367 out dx, ax 368 pop ax 369 mov dx, # VBE_DISPI_IOPORT_DATA 370 out dx, ax 371 pop dx 372 ret 373 374 dispi_get_bank: 375 push dx 376 mov dx, # VBE_DISPI_IOPORT_INDEX 377 mov ax, # VBE_DISPI_INDEX_BANK 378 out dx, ax 379 mov dx, # VBE_DISPI_IOPORT_DATA 380 in ax, dx 381 pop dx 382 ret 383 ASM_END 384 385 static void dispi_set_bank_farcall() 386 { 387 ASM_START 388 cmp bx,#0x0100 389 je dispi_set_bank_farcall_get 390 or bx,bx 391 jnz dispi_set_bank_farcall_error 392 mov ax,dx 393 push dx 394 push ax 395 mov ax,# VBE_DISPI_INDEX_BANK 396 mov dx,# VBE_DISPI_IOPORT_INDEX 397 out dx,ax 398 pop ax 399 mov dx,# VBE_DISPI_IOPORT_DATA 400 out dx,ax 401 in ax,dx 402 pop dx 403 cmp dx,ax 404 jne dispi_set_bank_farcall_error 405 mov ax, #0x004f 406 retf 407 dispi_set_bank_farcall_get: 408 mov ax,# VBE_DISPI_INDEX_BANK 409 mov dx,# VBE_DISPI_IOPORT_INDEX 410 out dx,ax 411 mov dx,# VBE_DISPI_IOPORT_DATA 412 in ax,dx 413 mov dx,ax 414 retf 415 dispi_set_bank_farcall_error: 416 mov ax,#0x014F 417 retf 418 ASM_END 419 } 420 421 ASM_START 422 dispi_set_x_offset: 423 push dx 424 push ax 425 mov dx, # VBE_DISPI_IOPORT_INDEX 426 mov ax, # VBE_DISPI_INDEX_X_OFFSET 427 out dx, ax 428 pop ax 429 mov dx, # VBE_DISPI_IOPORT_DATA 430 out dx, ax 431 pop dx 432 ret 433 434 dispi_get_x_offset: 435 push dx 436 mov dx, # VBE_DISPI_IOPORT_INDEX 437 mov ax, # VBE_DISPI_INDEX_X_OFFSET 438 out dx, ax 439 mov dx, # VBE_DISPI_IOPORT_DATA 440 in ax, dx 441 pop dx 442 ret 443 444 dispi_set_y_offset: 445 push dx 446 push ax 447 mov dx, # VBE_DISPI_IOPORT_INDEX 448 mov ax, # VBE_DISPI_INDEX_Y_OFFSET 449 out dx, ax 450 pop ax 451 mov dx, # VBE_DISPI_IOPORT_DATA 452 out dx, ax 453 pop dx 454 ret 455 456 dispi_get_y_offset: 457 push dx 458 mov dx, # VBE_DISPI_IOPORT_INDEX 459 mov ax, # VBE_DISPI_INDEX_Y_OFFSET 460 out dx, ax 461 mov dx, # VBE_DISPI_IOPORT_DATA 462 in ax, dx 463 pop dx 464 ret 465 466 vga_set_virt_width: 467 push ax 468 push bx 469 push dx 470 mov bx, ax 471 call dispi_get_bpp 472 cmp al, #0x04 473 ja set_width_svga 474 shr bx, #1 475 set_width_svga: 476 shr bx, #3 477 mov dx, # VGAREG_VGA_CRTC_ADDRESS 478 mov ah, bl 479 mov al, #0x13 480 out dx, ax 481 pop dx 482 pop bx 483 pop ax 484 ret 485 486 dispi_set_virt_width: 487 call vga_set_virt_width 488 push dx 489 push ax 490 mov dx, # VBE_DISPI_IOPORT_INDEX 491 mov ax, # VBE_DISPI_INDEX_VIRT_WIDTH 492 out dx, ax 493 pop ax 494 mov dx, # VBE_DISPI_IOPORT_DATA 495 out dx, ax 496 pop dx 497 ret 498 499 dispi_get_virt_width: 500 push dx 501 mov dx, # VBE_DISPI_IOPORT_INDEX 502 mov ax, # VBE_DISPI_INDEX_VIRT_WIDTH 503 out dx, ax 504 mov dx, # VBE_DISPI_IOPORT_DATA 505 in ax, dx 506 pop dx 507 ret 508 509 dispi_get_virt_height: 510 push dx 511 mov dx, # VBE_DISPI_IOPORT_INDEX 512 mov ax, # VBE_DISPI_INDEX_VIRT_HEIGHT 513 out dx, ax 514 mov dx, # VBE_DISPI_IOPORT_DATA 515 in ax, dx 516 pop dx 517 ret 518 519 _vga_compat_setup: 520 push ax 521 push dx 522 523 ; set CRT X resolution 524 mov dx, # VBE_DISPI_IOPORT_INDEX 525 mov ax, # VBE_DISPI_INDEX_XRES 526 out dx, ax 527 mov dx, # VBE_DISPI_IOPORT_DATA 528 in ax, dx 529 push ax 530 mov dx, # VGAREG_VGA_CRTC_ADDRESS 531 mov ax, #0x0011 532 out dx, ax 533 pop ax 534 push ax 535 shr ax, #3 536 dec ax 537 mov ah, al 538 mov al, #0x01 539 out dx, ax 540 pop ax 541 call vga_set_virt_width 542 543 ; set CRT Y resolution 544 mov dx, # VBE_DISPI_IOPORT_INDEX 545 mov ax, # VBE_DISPI_INDEX_YRES 546 out dx, ax 547 mov dx, # VBE_DISPI_IOPORT_DATA 548 in ax, dx 549 dec ax 550 push ax 551 mov dx, # VGAREG_VGA_CRTC_ADDRESS 552 mov ah, al 553 mov al, #0x12 554 out dx, ax 555 pop ax 556 mov al, #0x07 557 out dx, al 558 inc dx 559 in al, dx 560 and al, #0xbd 561 test ah, #0x01 562 jz bit8_clear 563 or al, #0x02 564 bit8_clear: 565 test ah, #0x02 566 jz bit9_clear 567 or al, #0x40 568 bit9_clear: 569 out dx, al 570 571 ; other settings 572 mov dx, # VGAREG_VGA_CRTC_ADDRESS 573 mov ax, #0x0009 574 out dx, ax 575 mov al, #0x17 576 out dx, al 577 mov dx, # VGAREG_VGA_CRTC_DATA 578 in al, dx 579 or al, #0x03 580 out dx, al 581 mov dx, # VGAREG_ACTL_RESET 582 in al, dx 583 mov dx, # VGAREG_ACTL_ADDRESS 584 mov al, #0x10 585 out dx, al 586 mov dx, # VGAREG_ACTL_READ_DATA 587 in al, dx 588 or al, #0x01 589 mov dx, # VGAREG_ACTL_ADDRESS 590 out dx, al 591 mov al, #0x20 592 out dx, al 593 mov dx, # VGAREG_GRDC_ADDRESS 594 mov ax, #0x0506 595 out dx, ax 596 mov dx, # VGAREG_SEQU_ADDRESS 597 mov ax, #0x0f02 598 out dx, ax 599 600 ; settings for >= 8bpp 601 mov dx, # VBE_DISPI_IOPORT_INDEX 602 mov ax, # VBE_DISPI_INDEX_BPP 603 out dx, ax 604 mov dx, # VBE_DISPI_IOPORT_DATA 605 in ax, dx 606 cmp al, #0x08 607 jb vga_compat_end 608 mov dx, # VGAREG_VGA_CRTC_ADDRESS 609 mov al, #0x14 610 out dx, al 611 mov dx, # VGAREG_VGA_CRTC_DATA 612 in al, dx 613 or al, #0x40 614 out dx, al 615 mov dx, # VGAREG_ACTL_RESET 616 in al, dx 617 mov dx, # VGAREG_ACTL_ADDRESS 618 mov al, #0x10 619 out dx, al 620 mov dx, # VGAREG_ACTL_READ_DATA 621 in al, dx 622 or al, #0x40 623 mov dx, # VGAREG_ACTL_ADDRESS 624 out dx, al 625 mov al, #0x20 626 out dx, al 627 mov dx, # VGAREG_SEQU_ADDRESS 628 mov al, #0x04 629 out dx, al 630 mov dx, # VGAREG_SEQU_DATA 631 in al, dx 632 or al, #0x08 633 out dx, al 634 mov dx, # VGAREG_GRDC_ADDRESS 635 mov al, #0x05 636 out dx, al 637 mov dx, # VGAREG_GRDC_DATA 638 in al, dx 639 and al, #0x9f 640 or al, #0x40 641 out dx, al 642 643 vga_compat_end: 644 pop dx 645 pop ax 646 ASM_END 647 648 649 // ModeInfo helper function 650 static ModeInfoListItem* mode_info_find_mode(mode, using_lfb) 651 Bit16u mode; Boolean using_lfb; 652 { 653 ModeInfoListItem *cur_info=&mode_info_list; 654 655 while (cur_info->mode != VBE_VESA_MODE_END_OF_LIST) 656 { 657 if (cur_info->mode == mode) 658 { 659 if (!using_lfb) 660 { 661 return cur_info; 662 } 663 else if (cur_info->info.ModeAttributes & VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE) 664 { 665 return cur_info; 666 } 667 else 668 { 669 cur_info++; 670 } 671 } 672 else 673 { 674 cur_info++; 675 } 676 } 677 678 return 0; 679 } 680 681 ASM_START 682 683 ; Has VBE display - Returns true if VBE display detected 684 685 _vbe_has_vbe_display: 686 push ds 687 push bx 688 mov ax, # BIOSMEM_SEG 689 mov ds, ax 690 mov bx, # BIOSMEM_VBE_FLAG 691 mov al, [bx] 692 and al, #0x01 693 xor ah, ah 694 pop bx 695 pop ds 696 ret 697 698 ; VBE Init - Initialise the Vesa Bios Extension Code 699 ; This function does a sanity check on the host side display code interface. 700 701 vbe_init: 702 mov ax, # VBE_DISPI_ID0 703 call dispi_set_id 704 call dispi_get_id 705 cmp ax, # VBE_DISPI_ID0 706 jne no_vbe_interface 707 push ds 708 push bx 709 mov ax, # BIOSMEM_SEG 710 mov ds, ax 711 mov bx, # BIOSMEM_VBE_FLAG 712 mov al, #0x01 713 mov [bx], al 714 pop bx 715 pop ds 716 mov ax, # VBE_DISPI_ID5 717 call dispi_set_id 718 no_vbe_interface: 719 #if defined(USE_BX_INFO) || defined(DEBUG) 720 mov bx, #msg_vbe_init 721 push bx 722 call _printf 723 inc sp 724 inc sp 725 #endif 726 ret 727 728 ; VBE Display Info - Display information on screen about the VBE 729 730 vbe_display_info: 731 call _vbe_has_vbe_display 732 test ax, ax 733 jz no_vbe_flag 734 mov ax, #0xc000 735 mov ds, ax 736 mov si, #_vbebios_info_string 737 jmp _display_string 738 no_vbe_flag: 739 mov ax, #0xc000 740 mov ds, ax 741 mov si, #_no_vbebios_info_string 742 jmp _display_string 743 744 ; helper function for memory size calculation 745 746 lmulul: 747 and eax, #0x0000FFFF 748 shl ebx, #16 749 or eax, ebx 750 SEG SS 751 mul eax, dword ptr [di] 752 mov ebx, eax 753 shr ebx, #16 754 ret 755 ASM_END 756 757 /** Function 00h - Return VBE Controller Information 758 * 759 * Input: 760 * AX = 4F00h 761 * ES:DI = Pointer to buffer in which to place VbeInfoBlock structure 762 * (VbeSignature should be VBE2 when VBE 2.0 information is desired and 763 * the info block is 512 bytes in size) 764 * Output: 765 * AX = VBE Return Status 766 * 767 */ 768 void vbe_biosfn_return_controller_information(AX, ES, DI) 769 Bit16u *AX;Bit16u ES;Bit16u DI; 770 { 771 Bit16u ss=get_SS(); 772 VbeInfoBlock vbe_info_block; 773 Bit16u status; 774 Bit16u result; 775 Bit16u vbe2_info; 776 Bit16u cur_mode=0; 777 Bit16u cur_ptr=34; 778 Bit16u size_64k; 779 ModeInfoListItem *cur_info=&mode_info_list; 780 781 status = read_word(ss, AX); 782 783 #ifdef DEBUG 784 printf("VBE vbe_biosfn_return_vbe_info ES%x DI%x AX%x\n",ES,DI,status); 785 #endif 786 787 vbe2_info = 0; 788 #ifdef VBE2_NO_VESA_CHECK 789 #else 790 // get vbe_info_block into local variable 791 memcpyb(ss, &vbe_info_block, ES, DI, sizeof(vbe_info_block)); 792 793 // check for VBE2 signature 794 if (((vbe_info_block.VbeSignature[0] == 'V') && 795 (vbe_info_block.VbeSignature[1] == 'B') && 796 (vbe_info_block.VbeSignature[2] == 'E') && 797 (vbe_info_block.VbeSignature[3] == '2')) || 798 799 ((vbe_info_block.VbeSignature[0] == 'V') && 800 (vbe_info_block.VbeSignature[1] == 'E') && 801 (vbe_info_block.VbeSignature[2] == 'S') && 802 (vbe_info_block.VbeSignature[3] == 'A')) ) 803 { 804 vbe2_info = 1; 805 #ifdef DEBUG 806 printf("VBE correct VESA/VBE2 signature found\n"); 807 #endif 808 } 809 #endif 810 811 // VBE Signature 812 vbe_info_block.VbeSignature[0] = 'V'; 813 vbe_info_block.VbeSignature[1] = 'E'; 814 vbe_info_block.VbeSignature[2] = 'S'; 815 vbe_info_block.VbeSignature[3] = 'A'; 816 817 // VBE Version supported 818 vbe_info_block.VbeVersion = 0x0200; 819 820 // OEM String 821 vbe_info_block.OemStringPtr_Seg = 0xc000; 822 vbe_info_block.OemStringPtr_Off = &vbebios_copyright; 823 824 // Capabilities 825 vbe_info_block.Capabilities[0] = VBE_CAPABILITY_8BIT_DAC; 826 vbe_info_block.Capabilities[1] = 0; 827 vbe_info_block.Capabilities[2] = 0; 828 vbe_info_block.Capabilities[3] = 0; 829 830 // VBE Video Mode Pointer (dynamicly generated from the mode_info_list) 831 vbe_info_block.VideoModePtr_Seg= ES ; 832 vbe_info_block.VideoModePtr_Off= DI + 34; 833 834 // VBE Total Memory (in 64k blocks) 835 outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VIDEO_MEMORY_64K); 836 vbe_info_block.TotalMemory = inw(VBE_DISPI_IOPORT_DATA); 837 838 if (vbe2_info) 839 { 840 // OEM Stuff 841 vbe_info_block.OemSoftwareRev = VBE_OEM_SOFTWARE_REV; 842 vbe_info_block.OemVendorNamePtr_Seg = 0xc000; 843 vbe_info_block.OemVendorNamePtr_Off = &vbebios_vendor_name; 844 vbe_info_block.OemProductNamePtr_Seg = 0xc000; 845 vbe_info_block.OemProductNamePtr_Off = &vbebios_product_name; 846 vbe_info_block.OemProductRevPtr_Seg = 0xc000; 847 vbe_info_block.OemProductRevPtr_Off = &vbebios_product_revision; 848 849 // copy updates in vbe_info_block back 850 memcpyb(ES, DI, ss, &vbe_info_block, sizeof(vbe_info_block)); 851 } 852 else 853 { 854 // copy updates in vbe_info_block back (VBE 1.x compatibility) 855 memcpyb(ES, DI, ss, &vbe_info_block, 256); 856 } 857 858 do 859 { 860 size_64k = (Bit16u)((Bit32u)cur_info->info.XResolution * cur_info->info.XResolution * cur_info->info.BitsPerPixel) >> 19; 861 862 if ((cur_info->info.XResolution <= dispi_get_max_xres()) && 863 (cur_info->info.BitsPerPixel <= dispi_get_max_bpp()) && 864 (size_64k <= vbe_info_block.TotalMemory)) { 865 #ifdef DEBUG 866 printf("VBE found mode %x => %x\n", cur_info->mode,cur_mode); 867 #endif 868 write_word(ES, DI + cur_ptr, cur_info->mode); 869 cur_mode++; 870 cur_ptr+=2; 871 } else { 872 #ifdef DEBUG 873 printf("VBE mode %x (xres=%x / bpp=%02x) not supported \n", cur_info->mode,cur_info->info.XResolution,cur_info->info.BitsPerPixel); 874 #endif 875 } 876 cur_info++; 877 } while (cur_info->mode != VBE_VESA_MODE_END_OF_LIST); 878 879 // Add vesa mode list terminator 880 write_word(ES, DI + cur_ptr, cur_info->mode); 881 882 result = 0x4f; 883 884 write_word(ss, AX, result); 885 } 886 887 888 /** Function 01h - Return VBE Mode Information 889 * 890 * Input: 891 * AX = 4F01h 892 * CX = Mode Number 893 * ES:DI = Pointer to buffer in which to place ModeInfoBlock structure 894 * Output: 895 * AX = VBE Return Status 896 * 897 */ 898 void vbe_biosfn_return_mode_information(AX, CX, ES, DI) 899 Bit16u *AX;Bit16u CX; Bit16u ES;Bit16u DI; 900 { 901 Bit16u result=0x0100; 902 Bit16u ss=get_SS(); 903 ModeInfoBlock info; 904 ModeInfoListItem *cur_info; 905 Boolean using_lfb; 906 Bit16u lfb_addr; 907 908 #ifdef DEBUG 909 printf("VBE vbe_biosfn_return_mode_information ES%x DI%x CX%x\n",ES,DI,CX); 910 #endif 911 912 using_lfb=((CX & VBE_MODE_LINEAR_FRAME_BUFFER) == VBE_MODE_LINEAR_FRAME_BUFFER); 913 914 CX = (CX & 0x1ff); 915 916 cur_info = mode_info_find_mode(CX, using_lfb, &cur_info); 917 918 if (cur_info != 0) 919 { 920 #ifdef DEBUG 921 printf("VBE found mode %x\n",CX); 922 #endif 923 memsetb(ss, &info, 0, sizeof(ModeInfoBlock)); 924 memcpyb(ss, &info, 0xc000, &(cur_info->info), sizeof(ModeInfoBlockCompact)); 925 if (using_lfb) { 926 info.NumberOfBanks = 1; 927 } 928 lfb_addr = pci_get_lfb_addr(0x1234); // experimental vendor 929 if (lfb_addr > 0) { 930 info.PhysBasePtr = ((Bit32u)lfb_addr << 16); 931 } 932 if (info.WinAAttributes & VBE_WINDOW_ATTRIBUTE_RELOCATABLE) { 933 info.WinFuncPtr = 0xC0000000UL; 934 *(Bit16u *)&(info.WinFuncPtr) = (Bit16u)(dispi_set_bank_farcall); 935 } 936 937 result = 0x4f; 938 } 939 else 940 { 941 #ifdef DEBUG 942 printf("VBE *NOT* found mode %x\n",CX); 943 #endif 944 result = 0x100; 945 } 946 947 if (result == 0x4f) 948 { 949 // copy updates in mode_info_block back 950 memcpyb(ES, DI, ss, &info, sizeof(info)); 951 } 952 953 write_word(ss, AX, result); 954 } 955 956 /** Function 02h - Set VBE Mode 957 * 958 * Input: 959 * AX = 4F02h 960 * BX = Desired Mode to set 961 * ES:DI = Pointer to CRTCInfoBlock structure 962 * Output: 963 * AX = VBE Return Status 964 * 965 */ 966 void vbe_biosfn_set_mode(AX, BX, ES, DI) 967 Bit16u *AX;Bit16u BX; Bit16u ES;Bit16u DI; 968 { 969 Bit16u ss = get_SS(); 970 Bit16u result; 971 ModeInfoListItem *cur_info; 972 Boolean using_lfb; 973 Bit8u no_clear; 974 Bit8u lfb_flag; 975 976 using_lfb=((BX & VBE_MODE_LINEAR_FRAME_BUFFER) == VBE_MODE_LINEAR_FRAME_BUFFER); 977 lfb_flag=using_lfb?VBE_DISPI_LFB_ENABLED:0; 978 no_clear=((BX & VBE_MODE_PRESERVE_DISPLAY_MEMORY) == VBE_MODE_PRESERVE_DISPLAY_MEMORY)?VBE_DISPI_NOCLEARMEM:0; 979 980 BX = (BX & 0x1ff); 981 982 //result=read_word(ss,AX); 983 984 // check for non vesa mode 985 if (BX<VBE_MODE_VESA_DEFINED) 986 { 987 Bit8u mode; 988 989 dispi_set_enable(VBE_DISPI_DISABLED); 990 // call the vgabios in order to set the video mode 991 // this allows for going back to textmode with a VBE call (some applications expect that to work) 992 993 mode=(BX & 0xff); 994 biosfn_set_video_mode(mode); 995 result = 0x4f; 996 } 997 998 cur_info = mode_info_find_mode(BX, using_lfb, &cur_info); 999 1000 if (cur_info != 0) 1001 { 1002 #ifdef DEBUG 1003 printf("VBE found mode %x, setting:\n", BX); 1004 printf("\txres%x yres%x bpp%x\n", 1005 cur_info->info.XResolution, 1006 cur_info->info.YResolution, 1007 cur_info->info.BitsPerPixel); 1008 #endif 1009 1010 // first disable current mode (when switching between vesa modi) 1011 dispi_set_enable(VBE_DISPI_DISABLED); 1012 1013 if (cur_info->info.BitsPerPixel == 4) 1014 { 1015 biosfn_set_video_mode(0x6a); 1016 } 1017 1018 dispi_set_bpp(cur_info->info.BitsPerPixel); 1019 dispi_set_xres(cur_info->info.XResolution); 1020 dispi_set_yres(cur_info->info.YResolution); 1021 dispi_set_bank(0); 1022 dispi_set_enable(VBE_DISPI_ENABLED | no_clear | lfb_flag); 1023 vga_compat_setup(); 1024 1025 write_word(BIOSMEM_SEG,BIOSMEM_VBE_MODE,BX); 1026 write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60 | no_clear)); 1027 1028 result = 0x4f; 1029 } 1030 else 1031 { 1032 #ifdef DEBUG 1033 printf("VBE *NOT* found mode %x\n" , BX); 1034 #endif 1035 result = 0x100; 1036 1037 // FIXME: redirect non VBE modi to normal VGA bios operation 1038 // (switch back to VGA mode 1039 if (BX == 3) 1040 result = 0x4f; 1041 } 1042 1043 write_word(ss, AX, result); 1044 } 1045 1046 /** Function 03h - Return Current VBE Mode 1047 * 1048 * Input: 1049 * AX = 4F03h 1050 * Output: 1051 * AX = VBE Return Status 1052 * BX = Current VBE Mode 1053 * 1054 */ 1055 ASM_START 1056 vbe_biosfn_return_current_mode: 1057 push ds 1058 mov ax, # BIOSMEM_SEG 1059 mov ds, ax 1060 call dispi_get_enable 1061 and ax, # VBE_DISPI_ENABLED 1062 jz no_vbe_mode 1063 mov bx, # BIOSMEM_VBE_MODE 1064 mov ax, [bx] 1065 mov bx, ax 1066 jnz vbe_03_ok 1067 no_vbe_mode: 1068 mov bx, # BIOSMEM_CURRENT_MODE 1069 mov al, [bx] 1070 mov bl, al 1071 xor bh, bh 1072 vbe_03_ok: 1073 mov ax, #0x004f 1074 pop ds 1075 ret 1076 ASM_END 1077 1078 1079 Bit16u vbe_biosfn_read_video_state_size() 1080 { 1081 return 9 * 2; 1082 } 1083 1084 void vbe_biosfn_save_video_state(ES, BX) 1085 Bit16u ES; Bit16u BX; 1086 { 1087 Bit16u enable, i; 1088 1089 outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE); 1090 enable = inw(VBE_DISPI_IOPORT_DATA); 1091 write_word(ES, BX, enable); 1092 BX += 2; 1093 if (!(enable & VBE_DISPI_ENABLED)) 1094 return; 1095 for(i = VBE_DISPI_INDEX_XRES; i <= VBE_DISPI_INDEX_Y_OFFSET; i++) { 1096 if (i != VBE_DISPI_INDEX_ENABLE) { 1097 outw(VBE_DISPI_IOPORT_INDEX, i); 1098 write_word(ES, BX, inw(VBE_DISPI_IOPORT_DATA)); 1099 BX += 2; 1100 } 1101 } 1102 } 1103 1104 1105 void vbe_biosfn_restore_video_state(ES, BX) 1106 Bit16u ES; Bit16u BX; 1107 { 1108 Bit16u enable, i; 1109 1110 enable = read_word(ES, BX); 1111 BX += 2; 1112 1113 if (!(enable & VBE_DISPI_ENABLED)) { 1114 outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE); 1115 outw(VBE_DISPI_IOPORT_DATA, enable); 1116 } else { 1117 outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES); 1118 outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX)); 1119 BX += 2; 1120 outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES); 1121 outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX)); 1122 BX += 2; 1123 outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP); 1124 outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX)); 1125 BX += 2; 1126 outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE); 1127 outw(VBE_DISPI_IOPORT_DATA, enable); 1128 1129 for(i = VBE_DISPI_INDEX_BANK; i <= VBE_DISPI_INDEX_Y_OFFSET; i++) { 1130 outw(VBE_DISPI_IOPORT_INDEX, i); 1131 outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX)); 1132 BX += 2; 1133 } 1134 } 1135 } 1136 1137 /** Function 04h - Save/Restore State 1138 * 1139 * Input: 1140 * AX = 4F04h 1141 * DL = 00h Return Save/Restore State buffer size 1142 * 01h Save State 1143 * 02h Restore State 1144 * CX = Requested states 1145 * ES:BX = Pointer to buffer (if DL <> 00h) 1146 * Output: 1147 * AX = VBE Return Status 1148 * BX = Number of 64-byte blocks to hold the state buffer (if DL=00h) 1149 * 1150 */ 1151 void vbe_biosfn_save_restore_state(AX, CX, DX, ES, BX) 1152 Bit16u *AX; Bit16u CX; Bit16u DX; Bit16u ES; Bit16u *BX; 1153 { 1154 Bit16u ss=get_SS(); 1155 Bit16u result, val; 1156 1157 result = 0x4f; 1158 switch(GET_DL()) { 1159 case 0x00: 1160 val = biosfn_read_video_state_size2(CX); 1161 #ifdef DEBUG 1162 printf("VGA state size=%x\n", val); 1163 #endif 1164 if (CX & 8) 1165 val += vbe_biosfn_read_video_state_size(); 1166 write_word(ss, BX, val); 1167 break; 1168 case 0x01: 1169 val = read_word(ss, BX); 1170 val = biosfn_save_video_state(CX, ES, val); 1171 #ifdef DEBUG 1172 printf("VGA save_state offset=%x\n", val); 1173 #endif 1174 if (CX & 8) 1175 vbe_biosfn_save_video_state(ES, val); 1176 break; 1177 case 0x02: 1178 val = read_word(ss, BX); 1179 val = biosfn_restore_video_state(CX, ES, val); 1180 #ifdef DEBUG 1181 printf("VGA restore_state offset=%x\n", val); 1182 #endif 1183 if (CX & 8) 1184 vbe_biosfn_restore_video_state(ES, val); 1185 break; 1186 default: 1187 // function failed 1188 result = 0x100; 1189 break; 1190 } 1191 write_word(ss, AX, result); 1192 } 1193 1194 /** Function 05h - Display Window Control 1195 * 1196 * Input: 1197 * AX = 4F05h 1198 * (16-bit) BH = 00h Set memory window 1199 * = 01h Get memory window 1200 * BL = Window number 1201 * = 00h Window A 1202 * = 01h Window B 1203 * DX = Window number in video memory in window 1204 * granularity units (Set Memory Window only) 1205 * Note: 1206 * If this function is called while in a linear frame buffer mode, 1207 * this function must fail with completion code AH=03h 1208 * 1209 * Output: 1210 * AX = VBE Return Status 1211 * DX = Window number in window granularity units 1212 * (Get Memory Window only) 1213 */ 1214 ASM_START 1215 vbe_biosfn_display_window_control: 1216 cmp bl, #0x00 1217 jne vbe_05_failed 1218 cmp bh, #0x01 1219 je get_display_window 1220 jb set_display_window 1221 mov ax, #0x0100 1222 ret 1223 set_display_window: 1224 mov ax, dx 1225 call _dispi_set_bank 1226 call dispi_get_bank 1227 cmp ax, dx 1228 jne vbe_05_failed 1229 mov ax, #0x004f 1230 ret 1231 get_display_window: 1232 call dispi_get_bank 1233 mov dx, ax 1234 mov ax, #0x004f 1235 ret 1236 vbe_05_failed: 1237 mov ax, #0x014f 1238 ret 1239 ASM_END 1240 1241 1242 /** Function 06h - Set/Get Logical Scan Line Length 1243 * 1244 * Input: 1245 * AX = 4F06h 1246 * BL = 00h Set Scan Line Length in Pixels 1247 * = 01h Get Scan Line Length 1248 * = 02h Set Scan Line Length in Bytes 1249 * = 03h Get Maximum Scan Line Length 1250 * CX = If BL=00h Desired Width in Pixels 1251 * If BL=02h Desired Width in Bytes 1252 * (Ignored for Get Functions) 1253 * 1254 * Output: 1255 * AX = VBE Return Status 1256 * BX = Bytes Per Scan Line 1257 * CX = Actual Pixels Per Scan Line 1258 * (truncated to nearest complete pixel) 1259 * DX = Maximum Number of Scan Lines 1260 */ 1261 ASM_START 1262 vbe_biosfn_set_get_logical_scan_line_length: 1263 mov ax, cx 1264 cmp bl, #0x01 1265 je get_logical_scan_line_length 1266 cmp bl, #0x02 1267 je set_logical_scan_line_bytes 1268 jb set_logical_scan_line_pixels 1269 mov ax, #0x0100 1270 ret 1271 set_logical_scan_line_bytes: 1272 push ax 1273 call dispi_get_bpp 1274 xor bh, bh 1275 mov bl, ah 1276 or bl, bl 1277 jnz no_4bpp_1 1278 shl ax, #3 1279 mov bl, #1 1280 no_4bpp_1: 1281 xor dx, dx 1282 pop ax 1283 div bx 1284 set_logical_scan_line_pixels: 1285 call dispi_set_virt_width 1286 get_logical_scan_line_length: 1287 call dispi_get_bpp 1288 xor bh, bh 1289 mov bl, ah 1290 call dispi_get_virt_width 1291 mov cx, ax 1292 or bl, bl 1293 jnz no_4bpp_2 1294 shr ax, #3 1295 mov bl, #1 1296 no_4bpp_2: 1297 mul bx 1298 mov bx, ax 1299 call dispi_get_virt_height 1300 mov dx, ax 1301 mov ax, #0x004f 1302 ret 1303 ASM_END 1304 1305 1306 /** Function 07h - Set/Get Display Start 1307 * 1308 * Input(16-bit): 1309 * AX = 4F07h 1310 * BH = 00h Reserved and must be 00h 1311 * BL = 00h Set Display Start 1312 * = 01h Get Display Start 1313 * = 02h Schedule Display Start (Alternate) 1314 * = 03h Schedule Stereoscopic Display Start 1315 * = 04h Get Scheduled Display Start Status 1316 * = 05h Enable Stereoscopic Mode 1317 * = 06h Disable Stereoscopic Mode 1318 * = 80h Set Display Start during Vertical Retrace 1319 * = 82h Set Display Start during Vertical Retrace (Alternate) 1320 * = 83h Set Stereoscopic Display Start during Vertical Retrace 1321 * ECX = If BL=02h/82h Display Start Address in bytes 1322 * If BL=03h/83h Left Image Start Address in bytes 1323 * EDX = If BL=03h/83h Right Image Start Address in bytes 1324 * CX = If BL=00h/80h First Displayed Pixel In Scan Line 1325 * DX = If BL=00h/80h First Displayed Scan Line 1326 * 1327 * Output: 1328 * AX = VBE Return Status 1329 * BH = If BL=01h Reserved and will be 0 1330 * CX = If BL=01h First Displayed Pixel In Scan Line 1331 * If BL=04h 0 if flip has not occurred, not 0 if it has 1332 * DX = If BL=01h First Displayed Scan Line 1333 * 1334 * Input(32-bit): 1335 * BH = 00h Reserved and must be 00h 1336 * BL = 00h Set Display Start 1337 * = 80h Set Display Start during Vertical Retrace 1338 * CX = Bits 0-15 of display start address 1339 * DX = Bits 16-31 of display start address 1340 * ES = Selector for memory mapped registers 1341 */ 1342 ASM_START 1343 vbe_biosfn_set_get_display_start: 1344 cmp bl, #0x80 1345 je set_display_start 1346 cmp bl, #0x01 1347 je get_display_start 1348 jb set_display_start 1349 mov ax, #0x0100 1350 ret 1351 set_display_start: 1352 mov ax, cx 1353 call dispi_set_x_offset 1354 mov ax, dx 1355 call dispi_set_y_offset 1356 mov ax, #0x004f 1357 ret 1358 get_display_start: 1359 call dispi_get_x_offset 1360 mov cx, ax 1361 call dispi_get_y_offset 1362 mov dx, ax 1363 xor bh, bh 1364 mov ax, #0x004f 1365 ret 1366 ASM_END 1367 1368 1369 /** Function 08h - Set/Get Dac Palette Format 1370 * 1371 * Input: 1372 * AX = 4F08h 1373 * BL = 00h set DAC palette width 1374 * = 01h get DAC palette width 1375 * BH = If BL=00h: desired number of bits per primary color 1376 * Output: 1377 * AX = VBE Return Status 1378 * BH = current number of bits per primary color (06h = standard VGA) 1379 */ 1380 ASM_START 1381 vbe_biosfn_set_get_dac_palette_format: 1382 cmp bl, #0x01 1383 je get_dac_palette_format 1384 jb set_dac_palette_format 1385 mov ax, #0x0100 1386 ret 1387 set_dac_palette_format: 1388 call dispi_get_enable 1389 cmp bh, #0x06 1390 je set_normal_dac 1391 cmp bh, #0x08 1392 jne vbe_08_unsupported 1393 or ax, # VBE_DISPI_8BIT_DAC 1394 jnz set_dac_mode 1395 set_normal_dac: 1396 and ax, #~ VBE_DISPI_8BIT_DAC 1397 set_dac_mode: 1398 call _dispi_set_enable 1399 get_dac_palette_format: 1400 mov bh, #0x06 1401 call dispi_get_enable 1402 and ax, # VBE_DISPI_8BIT_DAC 1403 jz vbe_08_ok 1404 mov bh, #0x08 1405 vbe_08_ok: 1406 mov ax, #0x004f 1407 ret 1408 vbe_08_unsupported: 1409 mov ax, #0x014f 1410 ret 1411 ASM_END 1412 1413 1414 /** Function 09h - Set/Get Palette Data 1415 * 1416 * Input: 1417 * AX = 4F09h 1418 * Output: 1419 * AX = VBE Return Status 1420 * 1421 * FIXME: incomplete API description, Input & Output 1422 */ 1423 void vbe_biosfn_set_get_palette_data(AX) 1424 { 1425 } 1426 1427 /** Function 0Ah - Return VBE Protected Mode Interface 1428 * Input: AX = 4F0Ah VBE 2.0 Protected Mode Interface 1429 * BL = 00h Return protected mode table 1430 * 1431 * 1432 * Output: AX = Status 1433 * ES = Real Mode Segment of Table 1434 * DI = Offset of Table 1435 * CX = Length of Table including protected mode code 1436 * (for copying purposes) 1437 */ 1438 ASM_START 1439 vbe_biosfn_return_protected_mode_interface: 1440 test bl, bl 1441 jnz _fail 1442 mov di, #0xc000 1443 mov es, di 1444 mov di, # vesa_pm_start 1445 mov cx, # vesa_pm_end 1446 sub cx, di 1447 mov ax, #0x004f 1448 ret 1449 _fail: 1450 mov ax, #0x014f 1451 ret 1452 ASM_END 1453