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