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