VirtualBox

source: vbox/trunk/src/VBox/Devices/Graphics/BIOS/vbe.c

Last change on this file was 85497, checked in by vboxsync, 4 years ago

VGABIOS: If LFB is disabled (BAR is zero), do not report any LFB modes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.8 KB
Line 
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)
51#define VBE_BYTEWISE_IO
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. */
78extern void __cdecl vga_compat_setup(void);
79extern void dispi_set_enable(uint16_t enable);
80extern void dispi_set_bank(uint16_t bank);
81extern uint16_t __cdecl dispi_get_max_bpp(void);
82extern 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?
88char vbebios_copyright[] = "VirtualBox VESA BIOS";
89char vbebios_vendor_name[] = VBOX_VENDOR;
90char vbebios_product_name[] = VBOX_PRODUCT " VBE Adapter";
91char vbebios_product_revision[] = VBOX_PRODUCT " Version " VBOX_VERSION_STRING;
92
93char vbebios_info_string[] = "VirtualBox VBE Display Adapter enabled\r\n\r\n";
94char no_vbebios_info_string[] = "No VirtualBox VBE support available!\r\n\r\n";
95
96#ifdef VGA_DEBUG
97char msg_vbe_init[] = "VirtualBox Version " VBOX_VERSION_STRING " VBE Display Adapter\r\n";
98#endif
99
100static 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
109static 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
118static 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
124static 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
133static 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
139static 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
148static 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
154static 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
160uint16_t in_word(uint16_t port, uint16_t addr)
161{
162 outw(port, addr);
163 return inw(port);
164}
165
166uint8_t in_byte(uint16_t port, uint16_t addr)
167{
168 outw(port, addr);
169 return inb(port);
170}
171
172/* Display "chip" identification helpers. */
173static 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}
178
179static 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 */
188void 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
201/* Find the offset of the desired mode, given its number. */
202static 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. */
206
207 /* Read and check the VBE Extra Data signature. */
208 sig = in_word(VBE_EXTRA_PORT, 0);
209 if (sig != VBEHEADER_MAGIC) {
210#ifdef DEBUG_VGA
211 printf("Signature NOT found! %x\n", sig);
212#endif
213 return 0;
214 }
215
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
230 cur_info_ofs = sizeof(VBEHeader);
231
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) );
236
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}
254
255#ifndef VBOX
256; VBE Display Info - Display information on screen about the VBE
257
258vbe_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
266no_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 */
284void 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;
302#ifdef DEBUG_VGA
303 printf("Signature NOT found\n");
304#endif
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 */
399void 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);
435 write_word(ES, DI + offsetof(ModeInfoBlock, PhysBasePtr) + 2, in_w(VBE_DISPI_IOPORT_DATA));
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 */
458void 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
530leave:
531 *AX = result;
532}
533
534uint16_t vbe_biosfn_read_video_state_size(void)
535{
536 return 9 * 2;
537}
538
539void 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
559void 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 */
604void vbe_biosfn_save_restore_state(uint16_t STACK_BASED *AX, uint16_t CX, uint16_t DX,
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}
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 */
665void 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;
672 uint16_t old_vw;
673
674 bpp = dispi_get_bpp();
675 bpp = bpp == 15 ? 16 : bpp;
676 old_vw = dispi_get_virt_width();
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. */
703 if (*DX < dispi_get_yres()) {
704 dispi_set_virt_width(old_vw);
705 result = 0x200;
706 }
707 break;
708 default:
709 // function failed
710 result = 0x100;
711 break;
712 }
713 *AX = result;
714}
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 */
721uint32_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 */
740void 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}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use