Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Ported palacios to Kbuild
[palacios.git] / bios / vgabios / clext.c
diff --git a/bios/vgabios/clext.c b/bios/vgabios/clext.c
new file mode 100644 (file)
index 0000000..1eb3c69
--- /dev/null
@@ -0,0 +1,1633 @@
+//
+//  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