[43115] | 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 | /*
|
---|
| 33 | * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
|
---|
| 34 | * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
|
---|
| 35 | * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
|
---|
| 36 | * a choice of LGPL license versions is made available with the language indicating
|
---|
| 37 | * that LGPLv2 or any later version may be used, or where a choice of which version
|
---|
| 38 | * of the LGPL is applied is otherwise unspecified.
|
---|
| 39 | */
|
---|
| 40 |
|
---|
| 41 | #include <inttypes.h>
|
---|
| 42 | #include <stddef.h>
|
---|
| 43 | #include "vbe.h"
|
---|
| 44 | #include "vgadefs.h"
|
---|
| 45 | #include "inlines.h"
|
---|
| 46 |
|
---|
| 47 | // disable VESA/VBE2 check in vbe info
|
---|
| 48 | //#define VBE2_NO_VESA_CHECK
|
---|
| 49 |
|
---|
| 50 | // use bytewise i/o (Longhorn beta issue, not in released Vista)
|
---|
[53100] | 51 | #define VBE_BYTEWISE_IO
|
---|
[43115] | 52 |
|
---|
| 53 | #ifdef VBE_BYTEWISE_IO
|
---|
| 54 | extern void do_out_dx_ax();
|
---|
| 55 | #pragma aux do_out_dx_ax "*";
|
---|
| 56 | extern void out_w(uint16_t port, uint16_t value);
|
---|
| 57 | #pragma aux out_w = \
|
---|
| 58 | "call do_out_dx_ax" \
|
---|
| 59 | parm [dx] [ax] modify nomemory;
|
---|
| 60 | extern void do_in_ax_dx();
|
---|
| 61 | #pragma aux do_in_ax_dx "*";
|
---|
| 62 | extern uint16_t in_w(uint16_t port);
|
---|
| 63 | #pragma aux in_w = \
|
---|
| 64 | "call do_in_ax_dx" \
|
---|
| 65 | parm [dx] value [ax] modify nomemory;
|
---|
| 66 | #else
|
---|
| 67 | #define out_w outw
|
---|
| 68 | #define in_w inw
|
---|
| 69 | #endif
|
---|
| 70 |
|
---|
| 71 |
|
---|
| 72 | /* VESA signatures as integer constants. */
|
---|
| 73 | #define SIG_VBE2 0x32454256 /* 'VBE2' */
|
---|
| 74 | #define SIG_VESA 0x41534556 /* 'VESA' */
|
---|
| 75 |
|
---|
| 76 |
|
---|
| 77 | /* Implemented in assembler. */
|
---|
| 78 | extern void __cdecl vga_compat_setup(void);
|
---|
| 79 | extern void dispi_set_enable(uint16_t enable);
|
---|
| 80 | extern void dispi_set_bank(uint16_t bank);
|
---|
| 81 | extern uint16_t __cdecl dispi_get_max_bpp(void);
|
---|
| 82 | extern void __cdecl dispi_set_bank_farcall(void);
|
---|
| 83 |
|
---|
| 84 | // The current OEM Software Revision of this VBE Bios
|
---|
| 85 | #define VBE_OEM_SOFTWARE_REV 0x0003
|
---|
| 86 |
|
---|
| 87 | // FIXME: 'merge' these (c) etc strings with the vgabios.c strings?
|
---|
| 88 | char vbebios_copyright[] = "VirtualBox VESA BIOS";
|
---|
| 89 | char vbebios_vendor_name[] = VBOX_VENDOR;
|
---|
| 90 | char vbebios_product_name[] = VBOX_PRODUCT " VBE Adapter";
|
---|
| 91 | char vbebios_product_revision[] = VBOX_PRODUCT " Version " VBOX_VERSION_STRING;
|
---|
| 92 |
|
---|
| 93 | char vbebios_info_string[] = "VirtualBox VBE Display Adapter enabled\r\n\r\n";
|
---|
| 94 | char no_vbebios_info_string[] = "No VirtualBox VBE support available!\r\n\r\n";
|
---|
| 95 |
|
---|
| 96 | #ifdef VGA_DEBUG
|
---|
| 97 | char msg_vbe_init[] = "VirtualBox Version " VBOX_VERSION_STRING " VBE Display Adapter\r\n";
|
---|
| 98 | #endif
|
---|
| 99 |
|
---|
| 100 | static void dispi_set_xres(uint16_t xres)
|
---|
| 101 | {
|
---|
| 102 | #ifdef VGA_DEBUG
|
---|
| 103 | printf("vbe_set_xres: %04x\n", xres);
|
---|
| 104 | #endif
|
---|
| 105 | out_w(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
|
---|
| 106 | out_w(VBE_DISPI_IOPORT_DATA, xres);
|
---|
| 107 | }
|
---|
| 108 |
|
---|
| 109 | static void dispi_set_yres(uint16_t yres)
|
---|
| 110 | {
|
---|
| 111 | #ifdef VGA_DEBUG
|
---|
| 112 | printf("vbe_set_yres: %04x\n", yres);
|
---|
| 113 | #endif
|
---|
| 114 | out_w(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
|
---|
| 115 | out_w(VBE_DISPI_IOPORT_DATA, yres);
|
---|
| 116 | }
|
---|
| 117 |
|
---|
[67812] | 118 | static uint16_t dispi_get_yres(void)
|
---|
| 119 | {
|
---|
| 120 | out_w(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
|
---|
| 121 | return in_w(VBE_DISPI_IOPORT_DATA);
|
---|
| 122 | }
|
---|
| 123 |
|
---|
[43115] | 124 | static void dispi_set_bpp(uint16_t bpp)
|
---|
| 125 | {
|
---|
| 126 | #ifdef VGA_DEBUG
|
---|
| 127 | printf("vbe_set_bpp: %02x\n", bpp);
|
---|
| 128 | #endif
|
---|
| 129 | out_w(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
|
---|
| 130 | out_w(VBE_DISPI_IOPORT_DATA, bpp);
|
---|
| 131 | }
|
---|
| 132 |
|
---|
[67548] | 133 | static uint16_t dispi_get_bpp(void)
|
---|
| 134 | {
|
---|
| 135 | out_w(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
|
---|
| 136 | return in_w(VBE_DISPI_IOPORT_DATA);
|
---|
| 137 | }
|
---|
| 138 |
|
---|
| 139 | static void dispi_set_virt_width(uint16_t vwidth)
|
---|
| 140 | {
|
---|
| 141 | #ifdef VGA_DEBUG
|
---|
| 142 | printf("vbe_set_virt_width: %04x\n", vwidth);
|
---|
| 143 | #endif
|
---|
| 144 | out_w(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VIRT_WIDTH);
|
---|
| 145 | out_w(VBE_DISPI_IOPORT_DATA, vwidth);
|
---|
| 146 | }
|
---|
| 147 |
|
---|
| 148 | static uint16_t dispi_get_virt_width(void)
|
---|
| 149 | {
|
---|
| 150 | out_w(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VIRT_WIDTH);
|
---|
| 151 | return in_w(VBE_DISPI_IOPORT_DATA);
|
---|
| 152 | }
|
---|
| 153 |
|
---|
| 154 | static uint16_t dispi_get_virt_height(void)
|
---|
| 155 | {
|
---|
| 156 | out_w(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VIRT_HEIGHT);
|
---|
| 157 | return in_w(VBE_DISPI_IOPORT_DATA);
|
---|
| 158 | }
|
---|
| 159 |
|
---|
[43115] | 160 | uint16_t in_word(uint16_t port, uint16_t addr)
|
---|
| 161 | {
|
---|
| 162 | outw(port, addr);
|
---|
| 163 | return inw(port);
|
---|
| 164 | }
|
---|
| 165 |
|
---|
| 166 | uint8_t in_byte(uint16_t port, uint16_t addr)
|
---|
| 167 | {
|
---|
| 168 | outw(port, addr);
|
---|
| 169 | return inb(port);
|
---|
| 170 | }
|
---|
| 171 |
|
---|
[43152] | 172 | /* Display "chip" identification helpers. */
|
---|
| 173 | static uint16_t dispi_get_id(void)
|
---|
| 174 | {
|
---|
| 175 | outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
|
---|
| 176 | return inw(VBE_DISPI_IOPORT_DATA);
|
---|
| 177 | }
|
---|
[43115] | 178 |
|
---|
[43152] | 179 | static void dispi_set_id(uint16_t chip_id)
|
---|
| 180 | {
|
---|
| 181 | outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
|
---|
| 182 | outw(VBE_DISPI_IOPORT_DATA, chip_id);
|
---|
| 183 | }
|
---|
| 184 |
|
---|
| 185 | /* VBE Init - Initialise the VESA BIOS Extension (VBE) support
|
---|
| 186 | * This function does a sanity check on the host side display code interface.
|
---|
| 187 | */
|
---|
| 188 | void vbe_init(void)
|
---|
| 189 | {
|
---|
| 190 | dispi_set_id(VBE_DISPI_ID0);
|
---|
| 191 | if (dispi_get_id() == VBE_DISPI_ID0) {
|
---|
| 192 | /* VBE support was detected. */
|
---|
| 193 | write_byte(BIOSMEM_SEG, BIOSMEM_VBE_FLAG, 1);
|
---|
| 194 | dispi_set_id(VBE_DISPI_ID4);
|
---|
| 195 | }
|
---|
| 196 | #ifdef DEBUG_VGA
|
---|
| 197 | printf(msg_vbe_init);
|
---|
| 198 | #endif
|
---|
| 199 | }
|
---|
| 200 |
|
---|
[43115] | 201 | /* Find the offset of the desired mode, given its number. */
|
---|
| 202 | static uint16_t mode_info_find_mode(uint16_t mode, Boolean using_lfb)
|
---|
| 203 | {
|
---|
| 204 | uint16_t sig, vmode, attrs;
|
---|
| 205 | uint16_t cur_info_ofs; /* Current offset in mode list. */
|
---|
[48947] | 206 |
|
---|
[43115] | 207 | /* Read and check the VBE Extra Data signature. */
|
---|
| 208 | sig = in_word(VBE_EXTRA_PORT, 0);
|
---|
| 209 | if (sig != VBEHEADER_MAGIC) {
|
---|
[43152] | 210 | #ifdef DEBUG_VGA
|
---|
[43115] | 211 | printf("Signature NOT found! %x\n", sig);
|
---|
[43152] | 212 | #endif
|
---|
[43115] | 213 | return 0;
|
---|
| 214 | }
|
---|
[48947] | 215 |
|
---|
[85497] | 216 | /* The LFB may be disabled. If so, LFB modes must not be reported. */
|
---|
| 217 | if (using_lfb) {
|
---|
| 218 | uint16_t lfb_addr_hi;
|
---|
| 219 |
|
---|
| 220 | out_w(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_FB_BASE_HI);
|
---|
| 221 | lfb_addr_hi = in_w(VBE_DISPI_IOPORT_DATA);
|
---|
| 222 | if (!lfb_addr_hi) {
|
---|
| 223 | #ifdef DEBUG_VGA
|
---|
| 224 | printf("LFB disabled, LFB modes unavailable!\n");
|
---|
| 225 | #endif
|
---|
| 226 | return 0;
|
---|
| 227 | }
|
---|
| 228 | }
|
---|
| 229 |
|
---|
[43115] | 230 | cur_info_ofs = sizeof(VBEHeader);
|
---|
[48947] | 231 |
|
---|
[43115] | 232 | vmode = in_word(VBE_EXTRA_PORT, cur_info_ofs + offsetof(ModeInfoListItem, mode)/*&cur_info->mode*/);
|
---|
| 233 | while (vmode != VBE_VESA_MODE_END_OF_LIST)
|
---|
| 234 | {
|
---|
| 235 | attrs = in_word(VBE_EXTRA_PORT, /*&cur_info->info.ModeAttributes*/cur_info_ofs + offsetof(ModeInfoListItem, info.ModeAttributes) );
|
---|
[48947] | 236 |
|
---|
[43115] | 237 | if (vmode == mode)
|
---|
| 238 | {
|
---|
| 239 | if (!using_lfb)
|
---|
| 240 | return cur_info_ofs;
|
---|
| 241 | else if (attrs & VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE)
|
---|
| 242 | return cur_info_ofs;
|
---|
| 243 | else {
|
---|
| 244 | cur_info_ofs += sizeof(ModeInfoListItem);
|
---|
| 245 | vmode = in_word(VBE_EXTRA_PORT, /*&cur_info->mode*/cur_info_ofs + offsetof(ModeInfoListItem, mode));
|
---|
| 246 | }
|
---|
| 247 | } else {
|
---|
| 248 | cur_info_ofs += sizeof(ModeInfoListItem);
|
---|
| 249 | vmode = in_word(VBE_EXTRA_PORT, /*&cur_info->mode*/cur_info_ofs + offsetof(ModeInfoListItem, mode));
|
---|
| 250 | }
|
---|
| 251 | }
|
---|
| 252 | return 0;
|
---|
| 253 | }
|
---|
[48947] | 254 |
|
---|
[43115] | 255 | #ifndef VBOX
|
---|
| 256 | ; VBE Display Info - Display information on screen about the VBE
|
---|
| 257 |
|
---|
| 258 | vbe_display_info:
|
---|
| 259 | call _vbe_has_vbe_display
|
---|
| 260 | test ax, ax
|
---|
| 261 | jz no_vbe_flag
|
---|
| 262 | mov ax, #0xc000
|
---|
| 263 | mov ds, ax
|
---|
| 264 | mov si, #_vbebios_info_string
|
---|
| 265 | jmp _display_string
|
---|
| 266 | no_vbe_flag:
|
---|
| 267 | mov ax, #0xc000
|
---|
| 268 | mov ds, ax
|
---|
| 269 | mov si, #_no_vbebios_info_string
|
---|
| 270 | jmp _display_string
|
---|
| 271 | #endif
|
---|
| 272 |
|
---|
| 273 | /** Function 00h - Return VBE Controller Information
|
---|
| 274 | *
|
---|
| 275 | * Input:
|
---|
| 276 | * AX = 4F00h
|
---|
| 277 | * ES:DI = Pointer to buffer in which to place VbeInfoBlock structure
|
---|
| 278 | * (VbeSignature should be VBE2 when VBE 2.0 information is desired and
|
---|
| 279 | * the info block is 512 bytes in size)
|
---|
| 280 | * Output:
|
---|
| 281 | * AX = VBE Return Status
|
---|
| 282 | *
|
---|
| 283 | */
|
---|
| 284 | void vbe_biosfn_return_controller_information(uint16_t STACK_BASED *AX, uint16_t ES, uint16_t DI)
|
---|
| 285 | {
|
---|
| 286 | uint16_t status;
|
---|
| 287 | uint16_t vbe2_info;
|
---|
| 288 | uint16_t cur_mode = 0;
|
---|
| 289 | uint16_t cur_ptr=34;
|
---|
| 290 | uint16_t cur_info_ofs;
|
---|
| 291 | uint16_t sig, vmode;
|
---|
| 292 | uint16_t max_bpp = dispi_get_max_bpp();
|
---|
| 293 | VbeInfoBlock __far *info_block;
|
---|
| 294 |
|
---|
| 295 | info_block = ES :> (VbeInfoBlock *)DI;
|
---|
| 296 |
|
---|
| 297 | /* Read VBE Extra Data signature */
|
---|
| 298 | sig = in_word(VBE_EXTRA_PORT, 0);
|
---|
| 299 | if (sig != VBEHEADER_MAGIC)
|
---|
| 300 | {
|
---|
| 301 | *AX = 0x0100;
|
---|
[43152] | 302 | #ifdef DEBUG_VGA
|
---|
[43115] | 303 | printf("Signature NOT found\n");
|
---|
[43152] | 304 | #endif
|
---|
[43115] | 305 | return;
|
---|
| 306 | }
|
---|
| 307 | cur_info_ofs = sizeof(VBEHeader);
|
---|
| 308 | status = *AX;
|
---|
| 309 |
|
---|
| 310 | #ifdef VGA_DEBUG
|
---|
| 311 | printf("VBE vbe_biosfn_return_vbe_info ES%x DI%x AX%x\n",ES,DI,status);
|
---|
| 312 | #endif
|
---|
| 313 |
|
---|
| 314 | vbe2_info = 0;
|
---|
| 315 |
|
---|
| 316 | /* Don't use a local copy of VbeInfoBlock on the stack; it's too big.
|
---|
| 317 | * The Ubuntu 8.04 64 bits splash screen emulator can't handle this.
|
---|
| 318 | */
|
---|
| 319 | #ifdef VBE2_NO_VESA_CHECK
|
---|
| 320 | #else /* !VBE2_NO_VESA_CHECK */
|
---|
| 321 | // check for VBE2 signature
|
---|
| 322 | if (info_block->VbeSignature.Sig32 == SIG_VBE2 || info_block->VbeSignature.Sig32 == SIG_VESA)
|
---|
| 323 | {
|
---|
| 324 | vbe2_info = 1;
|
---|
| 325 | #ifdef VGA_DEBUG
|
---|
| 326 | printf("VBE correct VESA/VBE2 signature found\n");
|
---|
| 327 | #endif
|
---|
| 328 | }
|
---|
| 329 | #endif /* !VBE2_NO_VESA_CHECK */
|
---|
| 330 |
|
---|
| 331 | /* VBE Signature - the compiler will optimize this into something sane. */
|
---|
| 332 | info_block->VbeSignature.SigChr[0] = 'V';
|
---|
| 333 | info_block->VbeSignature.SigChr[1] = 'E';
|
---|
| 334 | info_block->VbeSignature.SigChr[2] = 'S';
|
---|
| 335 | info_block->VbeSignature.SigChr[3] = 'A';
|
---|
| 336 |
|
---|
| 337 | /* VBE Version supported. */
|
---|
| 338 | info_block->VbeVersion = 0x0200; /* Version 2.0. */
|
---|
| 339 |
|
---|
| 340 | /* OEM String. */
|
---|
| 341 | info_block->OemString.Ptr = &vbebios_copyright;
|
---|
| 342 |
|
---|
| 343 | /* Capabilities if this implementation. */
|
---|
| 344 | info_block->Capabilities[0] = VBE_CAPABILITY_8BIT_DAC;
|
---|
| 345 | info_block->Capabilities[1] = 0;
|
---|
| 346 | info_block->Capabilities[2] = 0;
|
---|
| 347 | info_block->Capabilities[3] = 0;
|
---|
| 348 |
|
---|
| 349 | /* Video mode list pointer (dynamically generated). */
|
---|
| 350 | info_block->VideoModePtr_Seg = ES;
|
---|
| 351 | info_block->VideoModePtr_Off = DI + 34;
|
---|
| 352 |
|
---|
| 353 | /* Total controller memory in 64K units. */
|
---|
| 354 | info_block->TotalMemory = in_word(VBE_EXTRA_PORT, 0xffff);
|
---|
| 355 |
|
---|
| 356 | if (vbe2_info)
|
---|
| 357 | {
|
---|
| 358 | /* OEM information. */
|
---|
| 359 | info_block->OemSoftwareRev = VBE_OEM_SOFTWARE_REV;
|
---|
| 360 | info_block->OemVendorName.Ptr = &vbebios_vendor_name;
|
---|
| 361 | info_block->OemProductName.Ptr = &vbebios_product_name;
|
---|
| 362 | info_block->OemProductRev.Ptr = &vbebios_product_revision;
|
---|
| 363 | }
|
---|
| 364 |
|
---|
| 365 | do
|
---|
| 366 | {
|
---|
| 367 | uint8_t data_b;
|
---|
| 368 |
|
---|
| 369 | data_b = in_byte(VBE_EXTRA_PORT, cur_info_ofs + offsetof(ModeInfoListItem, info.BitsPerPixel) /*&cur_info->info.BitsPerPixel*/);
|
---|
| 370 | if (data_b <= max_bpp)
|
---|
| 371 | {
|
---|
| 372 | vmode = in_word(VBE_EXTRA_PORT, cur_info_ofs + offsetof(ModeInfoListItem, mode)/*&cur_info->mode*/);
|
---|
| 373 | #ifdef VGA_DEBUG
|
---|
| 374 | printf("VBE found mode %x => %x\n", vmode, cur_mode);
|
---|
| 375 | #endif
|
---|
| 376 | write_word(ES, DI + cur_ptr, vmode);
|
---|
| 377 | cur_mode++;
|
---|
| 378 | cur_ptr+=2;
|
---|
| 379 | }
|
---|
| 380 | cur_info_ofs += sizeof(ModeInfoListItem);
|
---|
| 381 | vmode = in_word(VBE_EXTRA_PORT, cur_info_ofs + offsetof(ModeInfoListItem, mode)/*&cur_info->mode*/);
|
---|
| 382 | } while (vmode != VBE_VESA_MODE_END_OF_LIST);
|
---|
| 383 |
|
---|
| 384 | // Add vesa mode list terminator
|
---|
| 385 | write_word(ES, DI + cur_ptr, vmode);
|
---|
| 386 | *AX = 0x004F;
|
---|
| 387 | }
|
---|
| 388 |
|
---|
| 389 | /** Function 01h - Return VBE Mode Information
|
---|
| 390 | *
|
---|
| 391 | * Input:
|
---|
| 392 | * AX = 4F01h
|
---|
| 393 | * CX = Mode Number
|
---|
| 394 | * ES:DI = Pointer to buffer in which to place ModeInfoBlock structure
|
---|
| 395 | * Output:
|
---|
| 396 | * AX = VBE Return Status
|
---|
| 397 | *
|
---|
| 398 | */
|
---|
| 399 | void vbe_biosfn_return_mode_information(uint16_t STACK_BASED *AX, uint16_t CX, uint16_t ES, uint16_t DI)
|
---|
| 400 | {
|
---|
| 401 | uint16_t result = 0x0100;
|
---|
| 402 | uint16_t cur_info_ofs;
|
---|
| 403 | Boolean using_lfb;
|
---|
| 404 | uint8_t win_attr;
|
---|
| 405 |
|
---|
| 406 | #ifdef VGA_DEBUG
|
---|
| 407 | printf("VBE vbe_biosfn_return_mode_information ES%x DI%x CX%x\n",ES,DI,CX);
|
---|
| 408 | #endif
|
---|
| 409 |
|
---|
| 410 | using_lfb = ((CX & VBE_MODE_LINEAR_FRAME_BUFFER) == VBE_MODE_LINEAR_FRAME_BUFFER);
|
---|
| 411 | CX = (CX & 0x1ff);
|
---|
| 412 |
|
---|
| 413 | cur_info_ofs = mode_info_find_mode(CX, using_lfb);
|
---|
| 414 |
|
---|
| 415 | if (cur_info_ofs) {
|
---|
| 416 | uint16_t i;
|
---|
| 417 | #ifdef VGA_DEBUG
|
---|
| 418 | printf("VBE found mode %x\n",CX);
|
---|
| 419 | #endif
|
---|
| 420 | memsetb(ES, DI, 0, 256); // The mode info size is fixed
|
---|
| 421 | for (i = 0; i < sizeof(ModeInfoBlockCompact); i++) {
|
---|
| 422 | uint8_t b;
|
---|
| 423 |
|
---|
| 424 | b = in_byte(VBE_EXTRA_PORT, cur_info_ofs + offsetof(ModeInfoListItem, info) + i/*(char *)(&(cur_info->info)) + i*/);
|
---|
| 425 | write_byte(ES, DI + i, b);
|
---|
| 426 | }
|
---|
| 427 | win_attr = read_byte(ES, DI + offsetof(ModeInfoBlock, WinAAttributes));
|
---|
| 428 | if (win_attr & VBE_WINDOW_ATTRIBUTE_RELOCATABLE) {
|
---|
| 429 | write_word(ES, DI + offsetof(ModeInfoBlock, WinFuncPtr), (uint16_t)(dispi_set_bank_farcall));
|
---|
| 430 | // If BIOS not at 0xC000 -> boom
|
---|
| 431 | write_word(ES, DI + offsetof(ModeInfoBlock, WinFuncPtr) + 2, 0xC000);
|
---|
| 432 | }
|
---|
| 433 | // Update the LFB physical address which may change at runtime
|
---|
| 434 | out_w(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_FB_BASE_HI);
|
---|
[63595] | 435 | write_word(ES, DI + offsetof(ModeInfoBlock, PhysBasePtr) + 2, in_w(VBE_DISPI_IOPORT_DATA));
|
---|
[43115] | 436 |
|
---|
| 437 | result = 0x4f;
|
---|
| 438 | } else {
|
---|
| 439 | #ifdef VGA_DEBUG
|
---|
| 440 | printf("VBE *NOT* found mode %x\n",CX);
|
---|
| 441 | #endif
|
---|
| 442 | result = 0x100;
|
---|
| 443 | }
|
---|
| 444 |
|
---|
| 445 | *AX = result;
|
---|
| 446 | }
|
---|
| 447 |
|
---|
| 448 | /** Function 02h - Set VBE Mode
|
---|
| 449 | *
|
---|
| 450 | * Input:
|
---|
| 451 | * AX = 4F02h
|
---|
| 452 | * BX = Desired Mode to set
|
---|
| 453 | * ES:DI = Pointer to CRTCInfoBlock structure
|
---|
| 454 | * Output:
|
---|
| 455 | * AX = VBE Return Status
|
---|
| 456 | *
|
---|
| 457 | */
|
---|
| 458 | void vbe_biosfn_set_mode(uint16_t STACK_BASED *AX, uint16_t BX, uint16_t ES, uint16_t DI)
|
---|
| 459 | {
|
---|
| 460 | uint16_t result;
|
---|
| 461 | uint16_t cur_info_ofs;
|
---|
| 462 | Boolean using_lfb;
|
---|
| 463 | uint8_t no_clear;
|
---|
| 464 | uint8_t lfb_flag;
|
---|
| 465 |
|
---|
| 466 | using_lfb = ((BX & VBE_MODE_LINEAR_FRAME_BUFFER) == VBE_MODE_LINEAR_FRAME_BUFFER);
|
---|
| 467 | lfb_flag = using_lfb ? VBE_DISPI_LFB_ENABLED : 0;
|
---|
| 468 | no_clear = ((BX & VBE_MODE_PRESERVE_DISPLAY_MEMORY) == VBE_MODE_PRESERVE_DISPLAY_MEMORY) ? VBE_DISPI_NOCLEARMEM : 0;
|
---|
| 469 |
|
---|
| 470 | BX = (BX & 0x1ff);
|
---|
| 471 |
|
---|
| 472 | // check for non vesa mode
|
---|
| 473 | if (BX < VBE_MODE_VESA_DEFINED)
|
---|
| 474 | {
|
---|
| 475 | uint8_t mode;
|
---|
| 476 |
|
---|
| 477 | dispi_set_enable(VBE_DISPI_DISABLED);
|
---|
| 478 | // call the vgabios in order to set the video mode
|
---|
| 479 | // this allows for going back to textmode with a VBE call (some applications expect that to work)
|
---|
| 480 | mode = (BX & 0xff);
|
---|
| 481 | biosfn_set_video_mode(mode);
|
---|
| 482 | result = 0x4f;
|
---|
| 483 | goto leave;
|
---|
| 484 | }
|
---|
| 485 |
|
---|
| 486 | cur_info_ofs = mode_info_find_mode(BX, using_lfb);
|
---|
| 487 |
|
---|
| 488 | if (cur_info_ofs != 0)
|
---|
| 489 | {
|
---|
| 490 | uint16_t xres, yres;
|
---|
| 491 | uint8_t bpp;
|
---|
| 492 |
|
---|
| 493 | xres = in_word(VBE_EXTRA_PORT, cur_info_ofs + offsetof(ModeInfoListItem, info.XResolution) /*&cur_info->info.XResolution*/);
|
---|
| 494 | yres = in_word(VBE_EXTRA_PORT, cur_info_ofs + offsetof(ModeInfoListItem, info.YResolution) /*&cur_info->info.YResolution*/);
|
---|
| 495 | bpp = in_byte(VBE_EXTRA_PORT, cur_info_ofs + offsetof(ModeInfoListItem, info.BitsPerPixel) /*&cur_info->info.BitsPerPixel*/);
|
---|
| 496 |
|
---|
| 497 | #ifdef VGA_DEBUG
|
---|
| 498 | printf("VBE found mode %x, setting:\n", BX);
|
---|
| 499 | printf("\txres%x yres%x bpp%x\n", xres, yres, bpp);
|
---|
| 500 | #endif
|
---|
| 501 |
|
---|
| 502 | // first disable current mode (when switching between vesa modi)
|
---|
| 503 | dispi_set_enable(VBE_DISPI_DISABLED);
|
---|
| 504 |
|
---|
| 505 | if (bpp == 4)
|
---|
| 506 | {
|
---|
| 507 | biosfn_set_video_mode(0x6a);
|
---|
| 508 | }
|
---|
| 509 |
|
---|
| 510 | dispi_set_bpp(bpp);
|
---|
| 511 | dispi_set_xres(xres);
|
---|
| 512 | dispi_set_yres(yres);
|
---|
| 513 | dispi_set_bank(0);
|
---|
| 514 | dispi_set_enable(VBE_DISPI_ENABLED | no_clear | lfb_flag);
|
---|
| 515 | vga_compat_setup();
|
---|
| 516 |
|
---|
| 517 | write_word(BIOSMEM_SEG,BIOSMEM_VBE_MODE,BX);
|
---|
| 518 | write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60 | no_clear));
|
---|
| 519 |
|
---|
| 520 | result = 0x4f;
|
---|
| 521 | }
|
---|
| 522 | else
|
---|
| 523 | {
|
---|
| 524 | #ifdef VGA_DEBUG
|
---|
| 525 | printf("VBE *NOT* found mode %x\n" , BX);
|
---|
| 526 | #endif
|
---|
| 527 | result = 0x100;
|
---|
| 528 | }
|
---|
| 529 |
|
---|
| 530 | leave:
|
---|
| 531 | *AX = result;
|
---|
| 532 | }
|
---|
| 533 |
|
---|
| 534 | uint16_t vbe_biosfn_read_video_state_size(void)
|
---|
| 535 | {
|
---|
| 536 | return 9 * 2;
|
---|
| 537 | }
|
---|
| 538 |
|
---|
| 539 | void vbe_biosfn_save_video_state(uint16_t ES, uint16_t BX)
|
---|
| 540 | {
|
---|
| 541 | uint16_t enable, i;
|
---|
| 542 |
|
---|
| 543 | outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE);
|
---|
| 544 | enable = inw(VBE_DISPI_IOPORT_DATA);
|
---|
| 545 | write_word(ES, BX, enable);
|
---|
| 546 | BX += 2;
|
---|
| 547 | if (!(enable & VBE_DISPI_ENABLED))
|
---|
| 548 | return;
|
---|
| 549 | for(i = VBE_DISPI_INDEX_XRES; i <= VBE_DISPI_INDEX_Y_OFFSET; i++) {
|
---|
| 550 | if (i != VBE_DISPI_INDEX_ENABLE) {
|
---|
| 551 | outw(VBE_DISPI_IOPORT_INDEX, i);
|
---|
| 552 | write_word(ES, BX, inw(VBE_DISPI_IOPORT_DATA));
|
---|
| 553 | BX += 2;
|
---|
| 554 | }
|
---|
| 555 | }
|
---|
| 556 | }
|
---|
| 557 |
|
---|
| 558 |
|
---|
| 559 | void vbe_biosfn_restore_video_state(uint16_t ES, uint16_t BX)
|
---|
| 560 | {
|
---|
| 561 | uint16_t enable, i;
|
---|
| 562 |
|
---|
| 563 | enable = read_word(ES, BX);
|
---|
| 564 | BX += 2;
|
---|
| 565 |
|
---|
| 566 | if (!(enable & VBE_DISPI_ENABLED)) {
|
---|
| 567 | outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE);
|
---|
| 568 | outw(VBE_DISPI_IOPORT_DATA, enable);
|
---|
| 569 | } else {
|
---|
| 570 | outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
|
---|
| 571 | outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
|
---|
| 572 | BX += 2;
|
---|
| 573 | outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
|
---|
| 574 | outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
|
---|
| 575 | BX += 2;
|
---|
| 576 | outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
|
---|
| 577 | outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
|
---|
| 578 | BX += 2;
|
---|
| 579 | outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE);
|
---|
| 580 | outw(VBE_DISPI_IOPORT_DATA, enable);
|
---|
| 581 |
|
---|
| 582 | for(i = VBE_DISPI_INDEX_BANK; i <= VBE_DISPI_INDEX_Y_OFFSET; i++) {
|
---|
| 583 | outw(VBE_DISPI_IOPORT_INDEX, i);
|
---|
| 584 | outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
|
---|
| 585 | BX += 2;
|
---|
| 586 | }
|
---|
| 587 | }
|
---|
| 588 | }
|
---|
| 589 |
|
---|
| 590 | /** Function 04h - Save/Restore State
|
---|
| 591 | *
|
---|
| 592 | * Input:
|
---|
| 593 | * AX = 4F04h
|
---|
| 594 | * DL = 00h Return Save/Restore State buffer size
|
---|
| 595 | * 01h Save State
|
---|
| 596 | * 02h Restore State
|
---|
| 597 | * CX = Requested states
|
---|
| 598 | * ES:BX = Pointer to buffer (if DL <> 00h)
|
---|
| 599 | * Output:
|
---|
| 600 | * AX = VBE Return Status
|
---|
| 601 | * BX = Number of 64-byte blocks to hold the state buffer (if DL=00h)
|
---|
| 602 | *
|
---|
| 603 | */
|
---|
[48947] | 604 | void vbe_biosfn_save_restore_state(uint16_t STACK_BASED *AX, uint16_t CX, uint16_t DX,
|
---|
[43115] | 605 | uint16_t ES, uint16_t STACK_BASED *BX)
|
---|
| 606 | {
|
---|
| 607 | uint16_t result, val;
|
---|
| 608 |
|
---|
| 609 | result = 0x004F;
|
---|
| 610 | switch(GET_DL()) {
|
---|
| 611 | case 0x00:
|
---|
| 612 | val = biosfn_read_video_state_size2(CX);
|
---|
| 613 | #ifdef VGA_DEBUG
|
---|
| 614 | printf("VGA state size=%x\n", val);
|
---|
| 615 | #endif
|
---|
| 616 | if (CX & 8)
|
---|
| 617 | val += vbe_biosfn_read_video_state_size();
|
---|
| 618 | *BX = (val + 63) / 64;
|
---|
| 619 | break;
|
---|
| 620 | case 0x01:
|
---|
| 621 | val = *BX;
|
---|
| 622 | val = biosfn_save_video_state(CX, ES, val);
|
---|
| 623 | #ifdef VGA_DEBUG
|
---|
| 624 | printf("VGA save_state offset=%x\n", val);
|
---|
| 625 | #endif
|
---|
| 626 | if (CX & 8)
|
---|
| 627 | vbe_biosfn_save_video_state(ES, val);
|
---|
| 628 | break;
|
---|
| 629 | case 0x02:
|
---|
| 630 | val = *BX;
|
---|
| 631 | val = biosfn_restore_video_state(CX, ES, val);
|
---|
| 632 | #ifdef VGA_DEBUG
|
---|
| 633 | printf("VGA restore_state offset=%x\n", val);
|
---|
| 634 | #endif
|
---|
| 635 | if (CX & 8)
|
---|
| 636 | vbe_biosfn_restore_video_state(ES, val);
|
---|
| 637 | break;
|
---|
| 638 | default:
|
---|
| 639 | // function failed
|
---|
| 640 | result = 0x100;
|
---|
| 641 | break;
|
---|
| 642 | }
|
---|
| 643 | *AX = result;
|
---|
| 644 | }
|
---|
[67548] | 645 |
|
---|
| 646 | /** Function 06h - Set/Get Logical Scan Line Length
|
---|
| 647 | *
|
---|
| 648 | * Input:
|
---|
| 649 | * AX = 4F06h
|
---|
| 650 | * BL = 00h Set Scan Line Length in Pixels
|
---|
| 651 | * = 01h Get Scan Line Length
|
---|
| 652 | * = 02h Set Scan Line Length in Bytes
|
---|
| 653 | * = 03h Get Maximum Scan Line Length
|
---|
| 654 | * CX = If BL=00h Desired Width in Pixels
|
---|
| 655 | * If BL=02h Desired Width in Bytes
|
---|
| 656 | * (Ignored for Get Functions)
|
---|
| 657 | *
|
---|
| 658 | * Output:
|
---|
| 659 | * AX = VBE Return Status
|
---|
| 660 | * BX = Bytes Per Scan Line
|
---|
| 661 | * CX = Actual Pixels Per Scan Line (truncated to
|
---|
| 662 | * nearest complete pixel)
|
---|
| 663 | * DX = Maximum Number of Scan Lines
|
---|
| 664 | */
|
---|
| 665 | void vbe_biosfn_get_set_scanline_length(uint16_t STACK_BASED *AX, uint16_t STACK_BASED *BX,
|
---|
| 666 | uint16_t STACK_BASED *CX, uint16_t STACK_BASED *DX)
|
---|
| 667 | {
|
---|
| 668 | uint16_t val;
|
---|
| 669 | uint16_t result;
|
---|
| 670 | uint8_t bpp;
|
---|
| 671 | uint8_t subfn;
|
---|
[67812] | 672 | uint16_t old_vw;
|
---|
[67548] | 673 |
|
---|
| 674 | bpp = dispi_get_bpp();
|
---|
[67813] | 675 | bpp = bpp == 15 ? 16 : bpp;
|
---|
[67812] | 676 | old_vw = dispi_get_virt_width();
|
---|
[67548] | 677 | result = 0x004F;
|
---|
| 678 | val = *CX;
|
---|
| 679 | subfn = *BX & 0xFF;
|
---|
| 680 | #ifdef VGA_DEBUG
|
---|
| 681 | printf("VBE get/set scanline len fn=%x, CX=%x\n", subfn, *CX);
|
---|
| 682 | #endif
|
---|
| 683 | switch(subfn) {
|
---|
| 684 | case 0x02:
|
---|
| 685 | if (bpp == 4)
|
---|
| 686 | val = val * 8;
|
---|
| 687 | else
|
---|
| 688 | val = val / (bpp / 8);
|
---|
| 689 | /* fall through */
|
---|
| 690 | case 0x00:
|
---|
| 691 | dispi_set_virt_width(val);
|
---|
| 692 | /* fall through */
|
---|
| 693 | case 0x01:
|
---|
| 694 | val = dispi_get_virt_width();
|
---|
| 695 | *CX = val; /* Width in pixels. */
|
---|
| 696 | if (bpp == 4)
|
---|
| 697 | val = val / 8;
|
---|
| 698 | else
|
---|
| 699 | val = val * (bpp / 8);
|
---|
| 700 | val = (val + 3) & ~3;
|
---|
| 701 | *BX = val; /* Bytes per scanline. */
|
---|
| 702 | *DX = dispi_get_virt_height(); /* Height in lines. */
|
---|
[67812] | 703 | if (*DX < dispi_get_yres()) {
|
---|
| 704 | dispi_set_virt_width(old_vw);
|
---|
| 705 | result = 0x200;
|
---|
| 706 | }
|
---|
[67548] | 707 | break;
|
---|
| 708 | default:
|
---|
| 709 | // function failed
|
---|
| 710 | result = 0x100;
|
---|
| 711 | break;
|
---|
| 712 | }
|
---|
| 713 | *AX = result;
|
---|
| 714 | }
|
---|
[75149] | 715 |
|
---|
| 716 |
|
---|
| 717 | /* We would very much like to avoid dragging in the long multiply library
|
---|
| 718 | * routine, and we really just need to multiply two 16-bit numbers to
|
---|
| 719 | * obtain a 32-bit result, so...
|
---|
| 720 | */
|
---|
| 721 | uint32_t mul32_16x16(uint16_t a, uint16_t b);
|
---|
| 722 | #pragma aux mul32_16x16 = \
|
---|
| 723 | "mul dx" \
|
---|
| 724 | parm [ax] [dx] modify nomemory;
|
---|
| 725 |
|
---|
| 726 |
|
---|
| 727 | /** Private INT 10h function 5642h - Manage custom video modes using X/Y
|
---|
| 728 | * resolution and bit depth rather than mode number
|
---|
| 729 | *
|
---|
| 730 | * Input:
|
---|
| 731 | * AX = 5642h ('VB')
|
---|
| 732 | * BL = 00h Set video mode
|
---|
| 733 | * BH = If BL=00h Desired bit depth in pixels
|
---|
| 734 | * CX = If BL=00h Desired width in pixels
|
---|
| 735 | * DX = If BL=00h Desired height in pixels
|
---|
| 736 | *
|
---|
| 737 | * Output:
|
---|
| 738 | * AX = VBE style return status
|
---|
| 739 | */
|
---|
| 740 | void private_biosfn_custom_mode(uint16_t STACK_BASED *AX, uint16_t STACK_BASED *BX,
|
---|
| 741 | uint16_t STACK_BASED *CX, uint16_t STACK_BASED *DX)
|
---|
| 742 | {
|
---|
| 743 | uint16_t result;
|
---|
| 744 | uint8_t subfn;
|
---|
| 745 | uint8_t bpp;
|
---|
| 746 | uint8_t lfb_flag;
|
---|
| 747 | uint16_t xres;
|
---|
| 748 | uint16_t yres;
|
---|
| 749 | uint16_t line_size;
|
---|
| 750 | uint32_t vram_size;
|
---|
| 751 | uint32_t mode_size;
|
---|
| 752 |
|
---|
| 753 | result = 0x004F;
|
---|
| 754 | subfn = *BX & 0xFF;
|
---|
| 755 | switch (subfn) {
|
---|
| 756 | case 0x00:
|
---|
| 757 | xres = *CX;
|
---|
| 758 | yres = *DX;
|
---|
| 759 | bpp = (*BX >> 8) & 0x7F;
|
---|
| 760 | #ifdef VGA_DEBUG
|
---|
| 761 | printf("Set custom mode %04x by %04x %xbpp\n", xres, yres, bpp);
|
---|
| 762 | #endif
|
---|
| 763 | /* Only allow 32/16/8bpp. */
|
---|
| 764 | if (bpp != 8 && bpp != 16 && bpp != 32) {
|
---|
| 765 | result = 0x100;
|
---|
| 766 | break;
|
---|
| 767 | }
|
---|
| 768 |
|
---|
| 769 | /* Determine the LFB flag. */
|
---|
| 770 | lfb_flag = *BX & 0x8000 ? VBE_DISPI_LFB_ENABLED : 0;
|
---|
| 771 |
|
---|
| 772 | /* Cap the resolution to something not insanely high or low. */
|
---|
| 773 | if (xres < 640)
|
---|
| 774 | xres = 640;
|
---|
| 775 | else if (xres > 2560)
|
---|
| 776 | xres = 2560;
|
---|
| 777 | if (yres < 480)
|
---|
| 778 | yres = 480;
|
---|
| 779 | else if (yres > 1920)
|
---|
| 780 | yres = 1920;
|
---|
| 781 | #ifdef VGA_DEBUG
|
---|
| 782 | printf("Adjusted resolution %04x by %04x\n", xres, yres);
|
---|
| 783 | #endif
|
---|
| 784 |
|
---|
| 785 | /* Calculate the VRAM size in bytes. */
|
---|
| 786 | vram_size = (uint32_t)in_word(VBE_EXTRA_PORT, 0xffff) << 16;
|
---|
| 787 |
|
---|
| 788 | /* Calculate the scanline size in bytes. */
|
---|
| 789 | line_size = xres * (bpp / 8);
|
---|
| 790 | line_size = (line_size + 3) & ~3;
|
---|
| 791 | /* And now the memory required for the mode. */
|
---|
| 792 | mode_size = mul32_16x16(line_size, yres);
|
---|
| 793 |
|
---|
| 794 | if (mode_size > vram_size) {
|
---|
| 795 | /* No can do. Don't have that much VRAM. */
|
---|
| 796 | result = 0x200;
|
---|
| 797 | break;
|
---|
| 798 | }
|
---|
| 799 |
|
---|
| 800 | /* Mode looks valid, let's get cracking. */
|
---|
| 801 | dispi_set_enable(VBE_DISPI_DISABLED);
|
---|
| 802 | dispi_set_bpp(bpp);
|
---|
| 803 | dispi_set_xres(xres);
|
---|
| 804 | dispi_set_yres(yres);
|
---|
| 805 | dispi_set_bank(0);
|
---|
| 806 | dispi_set_enable(VBE_DISPI_ENABLED | lfb_flag);
|
---|
| 807 | vga_compat_setup();
|
---|
| 808 | break;
|
---|
| 809 |
|
---|
| 810 | default:
|
---|
| 811 | // unsupported sub-function
|
---|
| 812 | result = 0x100;
|
---|
| 813 | break;
|
---|
| 814 | }
|
---|
| 815 | *AX = result;
|
---|
| 816 | }
|
---|