// // QEMU Cirrus CLGD 54xx VGABIOS Extension. // // Copyright (c) 2004 Makoto Suzuki (suzu) // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //#define CIRRUS_VESA3_PMINFO #ifdef VBE #undef CIRRUS_VESA3_PMINFO #endif #define PM_BIOSMEM_CURRENT_MODE 0x449 #define PM_BIOSMEM_CRTC_ADDRESS 0x463 #define PM_BIOSMEM_VBE_MODE 0x4BA typedef struct { /* + 0 */ unsigned short mode; unsigned short width; unsigned short height; unsigned short depth; /* + 8 */ unsigned short hidden_dac; /* 0x3c6 */ unsigned short *seq; /* 0x3c4 */ unsigned short *graph; /* 0x3ce */ unsigned short *crtc; /* 0x3d4 */ /* +16 */ unsigned char bitsperpixel; unsigned char vesacolortype; unsigned char vesaredmask; unsigned char vesaredpos; unsigned char vesagreenmask; unsigned char vesagreenpos; unsigned char vesabluemask; unsigned char vesabluepos; /* +24 */ unsigned char vesareservedmask; unsigned char vesareservedpos; } cirrus_mode_t; #define CIRRUS_MODE_SIZE 26 /* For VESA BIOS 3.0 */ #define CIRRUS_PM16INFO_SIZE 20 /* VGA */ unsigned short cseq_vga[] = {0x0007,0xffff}; unsigned short cgraph_vga[] = {0x0009,0x000a,0x000b,0xffff}; unsigned short ccrtc_vga[] = {0x001a,0x001b,0x001d,0xffff}; /* extensions */ unsigned short cgraph_svgacolor[] = { 0x0000,0x0001,0x0002,0x0003,0x0004,0x4005,0x0506,0x0f07,0xff08, 0x0009,0x000a,0x000b, 0xffff }; /* 640x480x8 */ unsigned short cseq_640x480x8[] = { 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107, 0x580b,0x580c,0x580d,0x580e, 0x0412,0x0013,0x2017, 0x331b,0x331c,0x331d,0x331e, 0xffff }; unsigned short ccrtc_640x480x8[] = { 0x2c11, 0x5f00,0x4f01,0x4f02,0x8003,0x5204,0x1e05,0x0b06,0x3e07, 0x4009,0x000c,0x000d, 0xea10,0xdf12,0x5013,0x4014,0xdf15,0x0b16,0xc317,0xff18, 0x001a,0x221b,0x001d, 0xffff }; /* 640x480x16 */ unsigned short cseq_640x480x16[] = { 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707, 0x580b,0x580c,0x580d,0x580e, 0x0412,0x0013,0x2017, 0x331b,0x331c,0x331d,0x331e, 0xffff }; unsigned short ccrtc_640x480x16[] = { 0x2c11, 0x5f00,0x4f01,0x4f02,0x8003,0x5204,0x1e05,0x0b06,0x3e07, 0x4009,0x000c,0x000d, 0xea10,0xdf12,0xa013,0x4014,0xdf15,0x0b16,0xc317,0xff18, 0x001a,0x221b,0x001d, 0xffff }; /* 640x480x24 */ unsigned short cseq_640x480x24[] = { 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1507, 0x580b,0x580c,0x580d,0x580e, 0x0412,0x0013,0x2017, 0x331b,0x331c,0x331d,0x331e, 0xffff }; unsigned short ccrtc_640x480x24[] = { 0x2c11, 0x5f00,0x4f01,0x4f02,0x8003,0x5204,0x1e05,0x0b06,0x3e07, 0x4009,0x000c,0x000d, 0xea10,0xdf12,0x0013,0x4014,0xdf15,0x0b16,0xc317,0xff18, 0x001a,0x321b,0x001d, 0xffff }; /* 800x600x8 */ unsigned short cseq_800x600x8[] = { 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107, 0x230b,0x230c,0x230d,0x230e, 0x0412,0x0013,0x2017, 0x141b,0x141c,0x141d,0x141e, 0xffff }; unsigned short ccrtc_800x600x8[] = { 0x2311,0x7d00,0x6301,0x6302,0x8003,0x6b04,0x1a05,0x9806,0xf007, 0x6009,0x000c,0x000d, 0x7d10,0x5712,0x6413,0x4014,0x5715,0x9816,0xc317,0xff18, 0x001a,0x221b,0x001d, 0xffff }; /* 800x600x16 */ unsigned short cseq_800x600x16[] = { 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707, 0x230b,0x230c,0x230d,0x230e, 0x0412,0x0013,0x2017, 0x141b,0x141c,0x141d,0x141e, 0xffff }; unsigned short ccrtc_800x600x16[] = { 0x2311,0x7d00,0x6301,0x6302,0x8003,0x6b04,0x1a05,0x9806,0xf007, 0x6009,0x000c,0x000d, 0x7d10,0x5712,0xc813,0x4014,0x5715,0x9816,0xc317,0xff18, 0x001a,0x221b,0x001d, 0xffff }; /* 800x600x24 */ unsigned short cseq_800x600x24[] = { 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1507, 0x230b,0x230c,0x230d,0x230e, 0x0412,0x0013,0x2017, 0x141b,0x141c,0x141d,0x141e, 0xffff }; unsigned short ccrtc_800x600x24[] = { 0x2311,0x7d00,0x6301,0x6302,0x8003,0x6b04,0x1a05,0x9806,0xf007, 0x6009,0x000c,0x000d, 0x7d10,0x5712,0x2c13,0x4014,0x5715,0x9816,0xc317,0xff18, 0x001a,0x321b,0x001d, 0xffff }; /* 1024x768x8 */ unsigned short cseq_1024x768x8[] = { 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107, 0x760b,0x760c,0x760d,0x760e, 0x0412,0x0013,0x2017, 0x341b,0x341c,0x341d,0x341e, 0xffff }; unsigned short ccrtc_1024x768x8[] = { 0x2911,0xa300,0x7f01,0x7f02,0x8603,0x8304,0x9405,0x2406,0xf507, 0x6009,0x000c,0x000d, 0x0310,0xff12,0x8013,0x4014,0xff15,0x2416,0xc317,0xff18, 0x001a,0x221b,0x001d, 0xffff }; /* 1024x768x16 */ unsigned short cseq_1024x768x16[] = { 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707, 0x760b,0x760c,0x760d,0x760e, 0x0412,0x0013,0x2017, 0x341b,0x341c,0x341d,0x341e, 0xffff }; unsigned short ccrtc_1024x768x16[] = { 0x2911,0xa300,0x7f01,0x7f02,0x8603,0x8304,0x9405,0x2406,0xf507, 0x6009,0x000c,0x000d, 0x0310,0xff12,0x0013,0x4014,0xff15,0x2416,0xc317,0xff18, 0x001a,0x321b,0x001d, 0xffff }; /* 1024x768x24 */ unsigned short cseq_1024x768x24[] = { 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1507, 0x760b,0x760c,0x760d,0x760e, 0x0412,0x0013,0x2017, 0x341b,0x341c,0x341d,0x341e, 0xffff }; unsigned short ccrtc_1024x768x24[] = { 0x2911,0xa300,0x7f01,0x7f02,0x8603,0x8304,0x9405,0x2406,0xf507, 0x6009,0x000c,0x000d, 0x0310,0xff12,0x8013,0x4014,0xff15,0x2416,0xc317,0xff18, 0x001a,0x321b,0x001d, 0xffff }; /* 1280x1024x8 */ unsigned short cseq_1280x1024x8[] = { 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107, 0x760b,0x760c,0x760d,0x760e, 0x0412,0x0013,0x2017, 0x341b,0x341c,0x341d,0x341e, 0xffff }; unsigned short ccrtc_1280x1024x8[] = { 0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707, 0x6009,0x000c,0x000d, 0x0310,0xff12,0xa013,0x4014,0xff15,0x2416,0xc317,0xff18, 0x001a,0x221b,0x001d, 0xffff }; /* 1280x1024x16 */ unsigned short cseq_1280x1024x16[] = { 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707, 0x760b,0x760c,0x760d,0x760e, 0x0412,0x0013,0x2017, 0x341b,0x341c,0x341d,0x341e, 0xffff }; unsigned short ccrtc_1280x1024x16[] = { 0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707, 0x6009,0x000c,0x000d, 0x0310,0xff12,0x4013,0x4014,0xff15,0x2416,0xc317,0xff18, 0x001a,0x321b,0x001d, 0xffff }; cirrus_mode_t cirrus_modes[] = { {0x5f,640,480,8,0x00, cseq_640x480x8,cgraph_svgacolor,ccrtc_640x480x8,8, 4,0,0,0,0,0,0,0,0}, {0x64,640,480,16,0xe1, cseq_640x480x16,cgraph_svgacolor,ccrtc_640x480x16,16, 6,5,11,6,5,5,0,0,0}, {0x66,640,480,15,0xf0, cseq_640x480x16,cgraph_svgacolor,ccrtc_640x480x16,16, 6,5,10,5,5,5,0,1,15}, {0x71,640,480,24,0xe5, cseq_640x480x24,cgraph_svgacolor,ccrtc_640x480x24,24, 6,8,16,8,8,8,0,0,0}, {0x5c,800,600,8,0x00, cseq_800x600x8,cgraph_svgacolor,ccrtc_800x600x8,8, 4,0,0,0,0,0,0,0,0}, {0x65,800,600,16,0xe1, cseq_800x600x16,cgraph_svgacolor,ccrtc_800x600x16,16, 6,5,11,6,5,5,0,0,0}, {0x67,800,600,15,0xf0, cseq_800x600x16,cgraph_svgacolor,ccrtc_800x600x16,16, 6,5,10,5,5,5,0,1,15}, {0x60,1024,768,8,0x00, cseq_1024x768x8,cgraph_svgacolor,ccrtc_1024x768x8,8, 4,0,0,0,0,0,0,0,0}, {0x74,1024,768,16,0xe1, cseq_1024x768x16,cgraph_svgacolor,ccrtc_1024x768x16,16, 6,5,11,6,5,5,0,0,0}, {0x68,1024,768,15,0xf0, cseq_1024x768x16,cgraph_svgacolor,ccrtc_1024x768x16,16, 6,5,10,5,5,5,0,1,15}, {0x78,800,600,24,0xe5, cseq_800x600x24,cgraph_svgacolor,ccrtc_800x600x24,24, 6,8,16,8,8,8,0,0,0}, {0x79,1024,768,24,0xe5, cseq_1024x768x24,cgraph_svgacolor,ccrtc_1024x768x24,24, 6,8,16,8,8,8,0,0,0}, {0x6d,1280,1024,8,0x00, cseq_1280x1024x8,cgraph_svgacolor,ccrtc_1280x1024x8,8, 4,0,0,0,0,0,0,0,0}, {0x69,1280,1024,15,0xf0, cseq_1280x1024x16,cgraph_svgacolor,ccrtc_1280x1024x16,16, 6,5,10,5,5,5,0,1,15}, {0x75,1280,1024,16,0xe1, cseq_1280x1024x16,cgraph_svgacolor,ccrtc_1280x1024x16,16, 6,5,11,6,5,5,0,0,0}, {0xfe,0,0,0,0,cseq_vga,cgraph_vga,ccrtc_vga,0, 0xff,0,0,0,0,0,0,0,0}, {0xff,0,0,0,0,0,0,0,0, 0xff,0,0,0,0,0,0,0,0}, }; unsigned char cirrus_id_table[] = { // 5430 0xA0, 0x32, // 5446 0xB8, 0x39, 0xff, 0xff }; unsigned short cirrus_vesa_modelist[] = { // 640x480x8 0x101, 0x5f, // 640x480x15 0x110, 0x66, // 640x480x16 0x111, 0x64, // 640x480x24 0x112, 0x71, // 800x600x8 0x103, 0x5c, // 800x600x15 0x113, 0x67, // 800x600x16 0x114, 0x65, // 800x600x24 0x115, 0x78, // 1024x768x8 0x105, 0x60, // 1024x768x15 0x116, 0x68, // 1024x768x16 0x117, 0x74, // 1024x768x24 0x118, 0x79, // 1280x1024x8 0x107, 0x6d, // 1280x1024x15 0x119, 0x69, // 1280x1024x16 0x11a, 0x75, // invalid 0xffff,0xffff }; ASM_START cirrus_installed: .ascii "cirrus-compatible VGA is detected" .byte 0x0d,0x0a .byte 0x0d,0x0a,0x00 cirrus_not_installed: .ascii "cirrus-compatible VGA is not detected" .byte 0x0d,0x0a .byte 0x0d,0x0a,0x00 cirrus_vesa_vendorname: cirrus_vesa_productname: cirrus_vesa_oemname: .ascii "VGABIOS Cirrus extension" .byte 0 cirrus_vesa_productrevision: .ascii "1.0" .byte 0 cirrus_init: call cirrus_check jnz no_cirrus SET_INT_VECTOR(0x10, #0xC000, #cirrus_int10_handler) mov al, #0x0f ; memory setup mov dx, #0x3C4 out dx, al inc dx in al, dx and al, #0x18 mov ah, al mov al, #0x0a dec dx out dx, ax mov ax, #0x0007 ; set vga mode out dx, ax mov ax, #0x0431 ; reset bitblt mov dx, #0x3CE out dx, ax mov ax, #0x0031 out dx, ax no_cirrus: ret cirrus_display_info: push ds push si push cs pop ds call cirrus_check mov si, #cirrus_not_installed jnz cirrus_msgnotinstalled mov si, #cirrus_installed cirrus_msgnotinstalled: call _display_string pop si pop ds ret cirrus_check: push ax push dx mov ax, #0x9206 mov dx, #0x3C4 out dx, ax inc dx in al, dx cmp al, #0x12 pop dx pop ax ret cirrus_int10_handler: pushf push bp cmp ah, #0x00 ;; set video mode jz cirrus_set_video_mode cmp ah, #0x12 ;; cirrus extension jz cirrus_extbios cmp ah, #0x4F ;; VESA extension jz cirrus_vesa cirrus_unhandled: pop bp popf jmp vgabios_int10_handler cirrus_return: #ifdef CIRRUS_DEBUG call cirrus_debug_dump #endif pop bp popf iret cirrus_set_video_mode: #ifdef CIRRUS_DEBUG call cirrus_debug_dump #endif push si push ax push bx push ds #ifdef CIRRUS_VESA3_PMINFO db 0x2e ;; cs: mov si, [cirrus_vesa_sel0000_data] #else xor si, si #endif mov ds, si xor bx, bx mov [PM_BIOSMEM_VBE_MODE], bx pop ds pop bx call cirrus_get_modeentry jnc cirrus_set_video_mode_extended mov al, #0xfe call cirrus_get_modeentry_nomask call cirrus_switch_mode pop ax pop si jmp cirrus_unhandled cirrus_extbios: #ifdef CIRRUS_DEBUG call cirrus_debug_dump #endif cmp bl, #0x80 jb cirrus_unhandled cmp bl, #0xAF ja cirrus_unhandled push bx and bx, #0x7F shl bx, 1 db 0x2e ;; cs: mov bp, cirrus_extbios_handlers[bx] pop bx push #cirrus_return push bp ret cirrus_vesa: #ifdef CIRRUS_DEBUG call cirrus_debug_dump #endif cmp al, #0x0F ja cirrus_vesa_not_handled push bx xor bx, bx mov bl, al shl bx, 1 db 0x2e ;; cs: mov bp, cirrus_vesa_handlers[bx] pop bx push #cirrus_return push bp ret cirrus_vesa_not_handled: mov ax, #0x014F ;; not implemented jmp cirrus_return #ifdef CIRRUS_DEBUG cirrus_debug_dump: push es push ds pusha push cs pop ds call _cirrus_debugmsg popa pop ds pop es ret #endif cirrus_set_video_mode_extended: call cirrus_switch_mode pop ax ;; mode test al, #0x80 jnz cirrus_set_video_mode_extended_1 push ax mov ax, #0xffff ; set to 0xff to keep win 2K happy call cirrus_clear_vram pop ax cirrus_set_video_mode_extended_1: and al, #0x7f push ds #ifdef CIRRUS_VESA3_PMINFO db 0x2e ;; cs: mov si, [cirrus_vesa_sel0000_data] #else xor si, si #endif mov ds, si mov [PM_BIOSMEM_CURRENT_MODE], al pop ds mov al, #0x20 pop si jmp cirrus_return cirrus_vesa_pmbios_init: retf cirrus_vesa_pmbios_entry: pushf push bp cmp ah, #0x4F jnz cirrus_vesa_pmbios_unimplemented cmp al, #0x0F ja cirrus_vesa_pmbios_unimplemented push bx xor bx, bx mov bl, al shl bx, 1 db 0x2e ;; cs: mov bp, cirrus_vesa_handlers[bx] pop bx push #cirrus_vesa_pmbios_return push bp ret cirrus_vesa_pmbios_unimplemented: mov ax, #0x014F cirrus_vesa_pmbios_return: pop bp popf retf ; in si:mode table cirrus_switch_mode: push ds push bx push dx push cs pop ds mov bx, [si+10] ;; seq mov dx, #0x3c4 mov ax, #0x1206 out dx, ax ;; Unlock cirrus special call cirrus_switch_mode_setregs mov bx, [si+12] ;; graph mov dx, #0x3ce call cirrus_switch_mode_setregs mov bx, [si+14] ;; crtc call cirrus_get_crtc call cirrus_switch_mode_setregs mov dx, #0x3c6 mov al, #0x00 out dx, al in al, dx in al, dx in al, dx in al, dx mov al, [si+8] ;; hidden dac out dx, al mov al, #0xff out dx, al mov al, #0x00 mov bl, [si+17] ;; memory model or bl, bl jz is_text_mode mov al, #0x01 cmp bl, #0x03 jnz is_text_mode or al, #0x40 is_text_mode: mov bl, #0x10 call biosfn_get_single_palette_reg and bh, #0xfe or bh, al call biosfn_set_single_palette_reg pop dx pop bx pop ds ret cirrus_enable_16k_granularity: push ax push dx mov dx, #0x3ce mov al, #0x0b out dx, al inc dx in al, dx or al, #0x20 ;; enable 16k out dx, al pop dx pop ax ret cirrus_switch_mode_setregs: csms_1: mov ax, [bx] cmp ax, #0xffff jz csms_2 out dx, ax add bx, #0x2 jmp csms_1 csms_2: ret cirrus_extbios_80h: push dx call cirrus_get_crtc mov al, #0x27 out dx, al inc dx in al, dx mov bx, #_cirrus_id_table c80h_1: db 0x2e ;; cs: mov ah, [bx] cmp ah, al jz c80h_2 cmp ah, #0xff jz c80h_2 inc bx inc bx jmp c80h_1 c80h_2: db 0x2e ;; cs: mov al, 0x1[bx] pop dx mov ah, #0x00 xor bx, bx ret cirrus_extbios_81h: mov ax, #0x100 ;; XXX ret cirrus_extbios_82h: push dx call cirrus_get_crtc xor ax, ax mov al, #0x27 out dx, al inc dx in al, dx and al, #0x03 mov ah, #0xAF pop dx ret cirrus_extbios_85h: push cx push dx mov dx, #0x3C4 mov al, #0x0f ;; get DRAM band width out dx, al inc dx in al, dx ;; al = 4 << bandwidth mov cl, al shr cl, #0x03 and cl, #0x03 cmp cl, #0x03 je c85h2 mov al, #0x04 shl al, cl jmp c85h3 c85h2: ;; 4MB or 2MB and al, #0x80 mov al, #0x20 ;; 2 MB je c85h3 mov al, #0x40 ;; 4 MB c85h3: pop dx pop cx ret cirrus_extbios_9Ah: mov ax, #0x4060 mov cx, #0x1132 ret cirrus_extbios_A0h: call cirrus_get_modeentry mov ah, #0x01 sbb ah, #0x00 mov bx, cirrus_extbios_A0h_callback mov si, #0xffff mov di, bx mov ds, bx mov es, bx ret cirrus_extbios_A0h_callback: ;; fatal: not implemented yet cli hlt retf cirrus_extbios_A1h: mov bx, #0x0E00 ;; IBM 8512/8513, color ret cirrus_extbios_A2h: mov al, #0x07 ;; HSync 31.5 - 64.0 kHz ret cirrus_extbios_AEh: mov al, #0x01 ;; High Refresh 75Hz ret cirrus_extbios_unimplemented: ret cirrus_vesa_00h: push ds push si mov bp, di push es pop ds cld mov ax, [di] cmp ax, #0x4256 ;; VB jnz cv00_1 mov ax, [di+2] cmp ax, #0x3245 ;; E2 jnz cv00_1 ;; VBE2 lea di, 0x14[bp] mov ax, #0x0100 ;; soft ver. stosw mov ax, # cirrus_vesa_vendorname stosw mov ax, cs stosw mov ax, # cirrus_vesa_productname stosw mov ax, cs stosw mov ax, # cirrus_vesa_productrevision stosw mov ax, cs stosw cv00_1: mov di, bp mov ax, #0x4556 ;; VE stosw mov ax, #0x4153 ;; SA stosw mov ax, #0x0200 ;; v2.00 stosw mov ax, # cirrus_vesa_oemname stosw mov ax, cs stosw xor ax, ax ;; caps stosw stosw lea ax, 0x40[bp] stosw mov ax, es stosw call cirrus_extbios_85h ;; vram in 64k mov ah, #0x00 stosw push cs pop ds lea di, 0x40[bp] mov si, #_cirrus_vesa_modelist cv00_2: lodsw stosw add si, #2 cmp ax, #0xffff jnz cv00_2 mov ax, #0x004F mov di, bp pop si pop ds ret cirrus_vesa_01h: mov ax, cx and ax, #0x3fff call cirrus_vesamode_to_mode cmp ax, #0xffff jnz cirrus_vesa_01h_1 jmp cirrus_vesa_unimplemented cirrus_vesa_01h_1: push ds push si push cx push dx push bx mov bp, di cld push cs pop ds call cirrus_get_modeentry_nomask push di xor ax, ax mov cx, #0x80 rep stosw ;; clear buffer pop di mov ax, #0x003b ;; mode stosw mov ax, #0x0007 ;; attr stosw mov ax, #0x0010 ;; granularity =16K stosw mov ax, #0x0040 ;; size =64K stosw mov ax, #0xA000 ;; segment A stosw xor ax, ax ;; no segment B stosw mov ax, #cirrus_vesa_05h_farentry stosw mov ax, cs stosw call cirrus_get_line_offset_entry stosw ;; bytes per scan line mov ax, [si+2] ;; width stosw mov ax, [si+4] ;; height stosw mov ax, #0x08 stosb mov ax, #0x10 stosb mov al, #1 ;; count of planes stosb mov al, [si+6] ;; bpp stosb mov al, #0x1 ;; XXX number of banks stosb mov al, [si+17] stosb ;; memory model mov al, #0x0 ;; XXX size of bank in K stosb call cirrus_get_line_offset_entry mov bx, [si+4] mul bx ;; dx:ax=vramdisp or ax, ax jz cirrus_vesa_01h_3 inc dx cirrus_vesa_01h_3: call cirrus_extbios_85h ;; al=vram in 64k mov ah, #0x00 mov cx, dx xor dx, dx div cx dec ax stosb ;; number of image pages = vramtotal/vramdisp-1 mov al, #0x00 stosb ;; v1.2+ stuffs push si add si, #18 movsw movsw movsw movsw pop si mov ah, [si+16] mov al, #0x0 sub ah, #9 rcl al, #1 ; bit 0=palette flag stosb ;; direct screen mode info ;; v2.0+ stuffs ;; 32-bit LFB address xor ax, ax stosw call cirrus_get_lfb_addr stosw or ax, ax jz cirrus_vesa_01h_4 push di mov di, bp db 0x26 ;; es: mov ax, [di] or ax, #0x0080 ;; mode bit 7:LFB stosw pop di cirrus_vesa_01h_4: xor ax, ax stosw ; reserved stosw ; reserved stosw ; reserved mov ax, #0x004F mov di, bp pop bx pop dx pop cx pop si pop ds test cx, #0x4000 ;; LFB flag jz cirrus_vesa_01h_5 push cx db 0x26 ;; es: mov cx, [di] cmp cx, #0x0080 ;; is LFB supported? jnz cirrus_vesa_01h_6 mov ax, #0x014F ;; error - no LFB cirrus_vesa_01h_6: pop cx cirrus_vesa_01h_5: ret cirrus_vesa_02h: ;; XXX support CRTC registers test bx, #0x3e00 jnz cirrus_vesa_02h_2 ;; unknown flags mov ax, bx and ax, #0x1ff ;; bit 8-0 mode cmp ax, #0x100 ;; legacy VGA mode jb cirrus_vesa_02h_legacy call cirrus_vesamode_to_mode cmp ax, #0xffff jnz cirrus_vesa_02h_1 cirrus_vesa_02h_2: jmp cirrus_vesa_unimplemented cirrus_vesa_02h_legacy: #ifdef CIRRUS_VESA3_PMINFO db 0x2e ;; cs: cmp byte ptr [cirrus_vesa_is_protected_mode], #0 jnz cirrus_vesa_02h_2 #endif // CIRRUS_VESA3_PMINFO int #0x10 mov ax, #0x004F ret cirrus_vesa_02h_1: push si push ax call cirrus_get_modeentry_nomask call cirrus_switch_mode test bx, #0x4000 ;; LFB jnz cirrus_vesa_02h_3 call cirrus_enable_16k_granularity cirrus_vesa_02h_3: test bx, #0x8000 ;; no clear jnz cirrus_vesa_02h_4 push ax xor ax,ax call cirrus_clear_vram pop ax cirrus_vesa_02h_4: pop ax push ds #ifdef CIRRUS_VESA3_PMINFO db 0x2e ;; cs: mov si, [cirrus_vesa_sel0000_data] #else xor si, si #endif mov ds, si mov [PM_BIOSMEM_CURRENT_MODE], al mov [PM_BIOSMEM_VBE_MODE], bx pop ds pop si mov ax, #0x004F ret cirrus_vesa_03h: push ds #ifdef CIRRUS_VESA3_PMINFO db 0x2e ;; cs: mov ax, [cirrus_vesa_sel0000_data] #else xor ax, ax #endif mov ds, ax mov bx, # PM_BIOSMEM_VBE_MODE mov ax, [bx] mov bx, ax test bx, bx jnz cirrus_vesa_03h_1 mov bx, # PM_BIOSMEM_CURRENT_MODE mov al, [bx] mov bl, al xor bh, bh cirrus_vesa_03h_1: mov ax, #0x004f pop ds ret cirrus_vesa_05h_farentry: call cirrus_vesa_05h retf cirrus_vesa_05h: cmp bl, #0x01 ja cirrus_vesa_05h_1 cmp bh, #0x00 jz cirrus_vesa_05h_setmempage cmp bh, #0x01 jz cirrus_vesa_05h_getmempage cirrus_vesa_05h_1: jmp cirrus_vesa_unimplemented cirrus_vesa_05h_setmempage: or dh, dh ; address must be < 0x100 jnz cirrus_vesa_05h_1 push dx mov al, bl ;; bl=bank number add al, #0x09 mov ah, dl ;; dx=window address in granularity mov dx, #0x3ce out dx, ax pop dx mov ax, #0x004F ret cirrus_vesa_05h_getmempage: mov al, bl ;; bl=bank number add al, #0x09 mov dx, #0x3ce out dx, al inc dx in al, dx xor dx, dx mov dl, al ;; dx=window address in granularity mov ax, #0x004F ret cirrus_vesa_06h: mov ax, cx cmp bl, #0x01 je cirrus_vesa_06h_3 cmp bl, #0x02 je cirrus_vesa_06h_2 jb cirrus_vesa_06h_1 mov ax, #0x0100 ret cirrus_vesa_06h_1: call cirrus_get_bpp_bytes mov bl, al xor bh, bh mov ax, cx mul bx cirrus_vesa_06h_2: call cirrus_set_line_offset cirrus_vesa_06h_3: call cirrus_get_bpp_bytes mov bl, al xor bh, bh xor dx, dx call cirrus_get_line_offset push ax div bx mov cx, ax pop bx call cirrus_extbios_85h ;; al=vram in 64k xor dx, dx mov dl, al xor ax, ax div bx mov dx, ax mov ax, #0x004f ret cirrus_vesa_07h: cmp bl, #0x80 je cirrus_vesa_07h_1 cmp bl, #0x01 je cirrus_vesa_07h_2 jb cirrus_vesa_07h_1 mov ax, #0x0100 ret cirrus_vesa_07h_1: push dx call cirrus_get_bpp_bytes mov bl, al xor bh, bh mov ax, cx mul bx pop bx push ax call cirrus_get_line_offset mul bx pop bx add ax, bx jnc cirrus_vesa_07h_3 inc dx cirrus_vesa_07h_3: push dx and dx, #0x0003 mov bx, #0x04 div bx pop dx shr dx, #2 call cirrus_set_start_addr mov ax, #0x004f ret cirrus_vesa_07h_2: call cirrus_get_start_addr shl dx, #2 push dx mov bx, #0x04 mul bx pop bx or dx, bx push ax call cirrus_get_line_offset mov bx, ax pop ax div bx push ax push dx call cirrus_get_bpp_bytes mov bl, al xor bh, bh pop ax xor dx, dx div bx mov cx, ax pop dx mov ax, #0x004f ret cirrus_vesa_unimplemented: mov ax, #0x014F ;; not implemented ret ;; in ax:vesamode, out ax:cirrusmode cirrus_vesamode_to_mode: push ds push cx push si push cs pop ds mov cx, #0xffff mov si, #_cirrus_vesa_modelist cvtm_1: cmp [si],ax jz cvtm_2 cmp [si],cx jz cvtm_2 add si, #4 jmp cvtm_1 cvtm_2: mov ax,[si+2] pop si pop cx pop ds ret ; cirrus_get_crtc ;; NOTE - may be called in protected mode cirrus_get_crtc: push ds push ax mov dx, #0x3cc in al, dx and al, #0x01 shl al, #5 mov dx, #0x3b4 add dl, al pop ax pop ds ret ;; in - al:mode, out - cflag:result, si:table, ax:destroyed cirrus_get_modeentry: and al, #0x7f cirrus_get_modeentry_nomask: mov si, #_cirrus_modes cgm_1: db 0x2e ;; cs: mov ah, [si] cmp al, ah jz cgm_2 cmp ah, #0xff jz cgm_4 add si, # CIRRUS_MODE_SIZE jmp cgm_1 cgm_4: xor si, si stc ;; video mode is not supported jmp cgm_3 cgm_2: clc ;; video mode is supported cgm_3: ret ; get LFB address ; out - ax:LFB address (high 16 bit) ;; NOTE - may be called in protected mode cirrus_get_lfb_addr: push cx push dx push eax xor cx, cx mov dl, #0x00 call cirrus_pci_read cmp ax, #0xffff jz cirrus_get_lfb_addr_5 cirrus_get_lfb_addr_3: mov dl, #0x00 call cirrus_pci_read cmp ax, #0x1013 ;; cirrus jz cirrus_get_lfb_addr_4 add cx, #0x8 cmp cx, #0x200 ;; search bus #0 and #1 jb cirrus_get_lfb_addr_3 cirrus_get_lfb_addr_5: xor dx, dx ;; no LFB jmp cirrus_get_lfb_addr_6 cirrus_get_lfb_addr_4: mov dl, #0x10 ;; I/O space #0 call cirrus_pci_read test ax, #0xfff1 jnz cirrus_get_lfb_addr_5 shr eax, #16 mov dx, ax ;; LFB address cirrus_get_lfb_addr_6: pop eax mov ax, dx pop dx pop cx ret cirrus_pci_read: mov eax, #0x00800000 mov ax, cx shl eax, #8 mov al, dl mov dx, #0xcf8 out dx, eax add dl, #4 in eax, dx ret ;; out - al:bytes per pixel cirrus_get_bpp_bytes: push dx mov dx, #0x03c4 mov al, #0x07 out dx, al inc dx in al, dx and al, #0x0e cmp al, #0x06 jne cirrus_get_bpp_bytes_1 and al, #0x02 cirrus_get_bpp_bytes_1: shr al, #1 cmp al, #0x04 je cirrus_get_bpp_bytes_2 inc al cirrus_get_bpp_bytes_2: pop dx ret ;; in - ax: new line offset cirrus_set_line_offset: shr ax, #3 push ax call cirrus_get_crtc mov al, #0x13 out dx, al inc dx pop ax out dx, al dec dx mov al, #0x1b out dx, al inc dx shl ah, #4 in al, dx and al, #ef or al, ah out dx, al ret ;; out - ax: active line offset cirrus_get_line_offset: push dx push bx call cirrus_get_crtc mov al, #0x13 out dx, al inc dx in al, dx mov bl, al dec dx mov al, #0x1b out dx, al inc dx in al, dx mov ah, al shr ah, #4 and ah, #0x01 mov al, bl shl ax, #3 pop bx pop dx ret ;; in - si: table ;; out - ax: line offset for mode cirrus_get_line_offset_entry: push bx mov bx, [si+14] ;; crtc table push bx offset_loop1: mov ax, [bx] cmp al, #0x13 je offset_found1 inc bx inc bx jnz offset_loop1 offset_found1: xor al, al shr ax, #5 pop bx push ax offset_loop2: mov ax, [bx] cmp al, #0x1b je offset_found2 inc bx inc bx jnz offset_loop2 offset_found2: pop bx and ax, #0x1000 shr ax, #1 or ax, bx pop bx ret ;; in - new address in DX:AX cirrus_set_start_addr: push bx push dx push ax call cirrus_get_crtc mov al, #0x0d out dx, al inc dx pop ax out dx, al dec dx mov al, #0x0c out dx, al inc dx mov al, ah out dx, al dec dx mov al, #0x1d out dx, al inc dx in al, dx and al, #0x7f pop bx mov ah, bl shl bl, #4 and bl, #0x80 or al, bl out dx, al dec dx mov bl, ah and ah, #0x01 shl bl, #1 and bl, #0x0c or ah, bl mov al, #0x1b out dx, al inc dx in al, dx and al, #0xf2 or al, ah out dx, al pop bx ret ;; out - current address in DX:AX cirrus_get_start_addr: push bx call cirrus_get_crtc mov al, #0x0c out dx, al inc dx in al, dx mov ah, al dec dx mov al, #0x0d out dx, al inc dx in al, dx push ax dec dx mov al, #0x1b out dx, al inc dx in al, dx dec dx mov bl, al and al, #0x01 and bl, #0x0c shr bl, #1 or bl, al mov al, #0x1d out dx, al inc dx in al, dx and al, #0x80 shr al, #4 or bl, al mov dl, bl xor dh, dh pop ax pop bx ret cirrus_clear_vram: pusha push es mov si, ax call cirrus_enable_16k_granularity call cirrus_extbios_85h shl al, #2 mov bl, al xor ah,ah cirrus_clear_vram_1: mov al, #0x09 mov dx, #0x3ce out dx, ax push ax mov cx, #0xa000 mov es, cx xor di, di mov ax, si mov cx, #8192 cld rep stosw pop ax inc ah cmp ah, bl jne cirrus_clear_vram_1 pop es popa ret cirrus_extbios_handlers: ;; 80h dw cirrus_extbios_80h dw cirrus_extbios_81h dw cirrus_extbios_82h dw cirrus_extbios_unimplemented ;; 84h dw cirrus_extbios_unimplemented dw cirrus_extbios_85h dw cirrus_extbios_unimplemented dw cirrus_extbios_unimplemented ;; 88h dw cirrus_extbios_unimplemented dw cirrus_extbios_unimplemented dw cirrus_extbios_unimplemented dw cirrus_extbios_unimplemented ;; 8Ch dw cirrus_extbios_unimplemented dw cirrus_extbios_unimplemented dw cirrus_extbios_unimplemented dw cirrus_extbios_unimplemented ;; 90h dw cirrus_extbios_unimplemented dw cirrus_extbios_unimplemented dw cirrus_extbios_unimplemented dw cirrus_extbios_unimplemented ;; 94h dw cirrus_extbios_unimplemented dw cirrus_extbios_unimplemented dw cirrus_extbios_unimplemented dw cirrus_extbios_unimplemented ;; 98h dw cirrus_extbios_unimplemented dw cirrus_extbios_unimplemented dw cirrus_extbios_9Ah dw cirrus_extbios_unimplemented ;; 9Ch dw cirrus_extbios_unimplemented dw cirrus_extbios_unimplemented dw cirrus_extbios_unimplemented dw cirrus_extbios_unimplemented ;; A0h dw cirrus_extbios_A0h dw cirrus_extbios_A1h dw cirrus_extbios_A2h dw cirrus_extbios_unimplemented ;; A4h dw cirrus_extbios_unimplemented dw cirrus_extbios_unimplemented dw cirrus_extbios_unimplemented dw cirrus_extbios_unimplemented ;; A8h dw cirrus_extbios_unimplemented dw cirrus_extbios_unimplemented dw cirrus_extbios_unimplemented dw cirrus_extbios_unimplemented ;; ACh dw cirrus_extbios_unimplemented dw cirrus_extbios_unimplemented dw cirrus_extbios_AEh dw cirrus_extbios_unimplemented cirrus_vesa_handlers: ;; 00h dw cirrus_vesa_00h dw cirrus_vesa_01h dw cirrus_vesa_02h dw cirrus_vesa_03h ;; 04h dw cirrus_vesa_unimplemented dw cirrus_vesa_05h dw cirrus_vesa_06h dw cirrus_vesa_07h ;; 08h dw cirrus_vesa_unimplemented dw cirrus_vesa_unimplemented dw cirrus_vesa_unimplemented dw cirrus_vesa_unimplemented ;; 0Ch dw cirrus_vesa_unimplemented dw cirrus_vesa_unimplemented dw cirrus_vesa_unimplemented dw cirrus_vesa_unimplemented ASM_END #ifdef CIRRUS_VESA3_PMINFO ASM_START cirrus_vesa_pminfo: /* + 0 */ .byte 0x50,0x4d,0x49,0x44 ;; signature[4] /* + 4 */ dw cirrus_vesa_pmbios_entry ;; entry_bios dw cirrus_vesa_pmbios_init ;; entry_init /* + 8 */ cirrus_vesa_sel0000_data: dw 0x0000 ;; sel_00000 cirrus_vesa_selA000_data: dw 0xA000 ;; sel_A0000 /* +12 */ cirrus_vesa_selB000_data: dw 0xB000 ;; sel_B0000 cirrus_vesa_selB800_data: dw 0xB800 ;; sel_B8000 /* +16 */ cirrus_vesa_selC000_data: dw 0xC000 ;; sel_C0000 cirrus_vesa_is_protected_mode: ;; protected mode flag and checksum dw (~((0xf2 + (cirrus_vesa_pmbios_entry >> 8) + (cirrus_vesa_pmbios_entry) \ + (cirrus_vesa_pmbios_init >> 8) + (cirrus_vesa_pmbios_init)) & 0xff) << 8) + 0x01 ASM_END #endif // CIRRUS_VESA3_PMINFO #ifdef CIRRUS_DEBUG static void cirrus_debugmsg(DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS) Bit16u DI, SI, BP, SP, BX, DX, CX, AX, ES, DS, FLAGS; { if((GET_AH()!=0x0E)&&(GET_AH()!=0x02)&&(GET_AH()!=0x09)&&(AX!=0x4F05)) printf("vgabios call ah%02x al%02x bx%04x cx%04x dx%04x\n",GET_AH(),GET_AL(),BX,CX,DX); } #endif