ia64/xen-unstable

view xen/arch/x86/boot/video.S @ 16192:118a21c66fd5

x86: small boot-time changes:
* use memory 0x8c000-0x90000 to avoid trampling the area above
0x90000 -- some bootloaders may leave droppings in that region
* reserve 2kB for vga mode table -- limit of 128 VESA modes could
overflow the original 1kB allocation
* remove unnecessary alignment of trampoline GDT
author Keir Fraser <keir@xensource.com>
date Mon Oct 22 21:06:11 2007 +0100 (2007-10-22)
parents ef4119637f52
children 207ad1afe9bb
line source
1 /******************************************************************************
2 * video.S
3 *
4 * Display adapter & video mode setup, version 2.13 (14-May-99)
5 *
6 * Copyright (C) 1995 -- 1998 Martin Mares <mj@ucw.cz>
7 * Based on the original setup.S code (C) Linus Torvalds and Mats Anderson
8 *
9 * Rewritten to use GNU 'as' by Chris Noe <stiker@northlink.com> May 1999
10 *
11 * Updated and ported for Xen by Keir Fraser <keir@xensource.com> June 2007
12 */
14 .code16
16 #include "video.h"
18 /* Scratch space layout: +0x3000 to +0x4000. */
19 #define modelist (0x3000) /* 2kB (256 entries) */
20 #define vesa_glob_info (modelist + 0x800) /* 1kB */
21 #define vesa_mode_info (vesa_glob_info + 0x400) /* 1kB */
23 /* Retrieve Extended Display Identification Data. */
24 #define CONFIG_FIRMWARE_EDID
26 /* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */
27 #undef CONFIG_VIDEO_400_HACK
29 /* Positions of various video parameters passed to the kernel */
30 /* (see also include/linux/tty.h) */
31 #define PARAM_CURSOR_POS 0x00
32 #define PARAM_VIDEO_MODE 0x02
33 #define PARAM_VIDEO_COLS 0x03
34 #define PARAM_VIDEO_LINES 0x04
35 #define PARAM_HAVE_VGA 0x05
36 #define PARAM_FONT_POINTS 0x06
37 #define PARAM_CAPABILITIES 0x08
38 #define PARAM_LFB_LINELENGTH 0x0c
39 #define PARAM_LFB_WIDTH 0x0e
40 #define PARAM_LFB_HEIGHT 0x10
41 #define PARAM_LFB_DEPTH 0x12
42 #define PARAM_LFB_BASE 0x14
43 #define PARAM_LFB_SIZE 0x18
44 #define PARAM_LFB_COLORS 0x1c
45 #define PARAM_VESAPM_SEG 0x24
46 #define PARAM_VESAPM_OFF 0x26
47 #define PARAM_VESA_ATTRIB 0x28
48 #define _param(param) bootsym(boot_vid_info)+(param)
50 video: xorw %ax, %ax
51 movw %ax, %gs # GS is zero
52 cld
53 call basic_detect # Basic adapter type testing (EGA/VGA/MDA/CGA)
54 cmpb $0,_param(PARAM_HAVE_VGA)
55 je 1f # Bail if there's no VGA
56 movw bootsym(boot_vid_mode), %ax # User selected video mode
57 cmpw $ASK_VGA, %ax # Bring up the menu
58 jz vid2
60 call mode_set # Set the mode
61 jc vid1
63 leaw bootsym(badmdt), %si # Invalid mode ID
64 call prtstr
65 vid2: call mode_menu
66 vid1: call store_edid
67 call mode_params # Store mode parameters
68 1: ret
70 # Detect if we have CGA, MDA, EGA or VGA and pass it to the kernel.
71 basic_detect:
72 movb $0, _param(PARAM_HAVE_VGA)
73 movb $0x12, %ah # Check EGA/VGA
74 movb $0x10, %bl
75 int $0x10
76 cmpb $0x10, %bl # No, it's a CGA/MDA/HGA card.
77 je basret
78 movw $0x1a00, %ax # Check EGA or VGA?
79 int $0x10
80 cmpb $0x1a, %al # 1a means VGA...
81 jne basret # anything else is EGA.
82 incb _param(PARAM_HAVE_VGA) # We've detected a VGA
83 basret: ret
85 # Store the video mode parameters for later usage by the kernel.
86 # This is done by asking the BIOS except for the rows/columns
87 # parameters in the default 80x25 mode -- these are set directly,
88 # because some very obscure BIOSes supply insane values.
89 mode_params:
90 cmpb $0, bootsym(graphic_mode)
91 jnz mopar_gr
92 movb $0x03, %ah # Read cursor position
93 xorb %bh, %bh
94 int $0x10
95 movw %dx, _param(PARAM_CURSOR_POS)
96 movb $0x0f, %ah # Read page/mode/width
97 int $0x10
98 movw %ax, _param(PARAM_VIDEO_MODE) # Video mode and screen width
99 movw %gs:(0x485), %ax # Font size
100 movw %ax, _param(PARAM_FONT_POINTS) # (valid only on EGA/VGA)
101 movw bootsym(force_size), %ax # Forced size?
102 orw %ax, %ax
103 jz mopar1
105 movb %ah, _param(PARAM_VIDEO_COLS)
106 movb %al, _param(PARAM_VIDEO_LINES)
107 ret
109 mopar1: movb %gs:(0x484), %al # On EGA/VGA, use the EGA+ BIOS
110 incb %al # location of max lines.
111 mopar2: movb %al, _param(PARAM_VIDEO_LINES)
112 ret
114 # Fetching of VESA frame buffer parameters
115 mopar_gr:
116 leaw vesa_mode_info, %di
117 movb $0x23, _param(PARAM_HAVE_VGA)
118 movw 16(%di), %ax
119 movw %ax, _param(PARAM_LFB_LINELENGTH)
120 movw 18(%di), %ax
121 movw %ax, _param(PARAM_LFB_WIDTH)
122 movw 20(%di), %ax
123 movw %ax, _param(PARAM_LFB_HEIGHT)
124 movb 25(%di), %al
125 movb $0, %ah
126 movw %ax, _param(PARAM_LFB_DEPTH)
127 movl 40(%di), %eax
128 movl %eax, _param(PARAM_LFB_BASE)
129 movl 31(%di), %eax
130 movl %eax, _param(PARAM_LFB_COLORS)
131 movl 35(%di), %eax
132 movl %eax, _param(PARAM_LFB_COLORS+4)
133 movw 0(%di), %ax
134 movw %ax, _param(PARAM_VESA_ATTRIB)
136 # get video mem size
137 leaw vesa_glob_info, %di
138 xorl %eax, %eax
139 movw 18(%di), %ax
140 movl %eax, _param(PARAM_LFB_SIZE)
142 # store mode capabilities
143 movl 10(%di), %eax
144 movl %eax, _param(PARAM_CAPABILITIES)
146 # switching the DAC to 8-bit is for <= 8 bpp only
147 movw _param(PARAM_LFB_DEPTH), %ax
148 cmpw $8, %ax
149 jg dac_done
151 # get DAC switching capability
152 xorl %eax, %eax
153 movb 10(%di), %al
154 testb $1, %al
155 jz dac_set
157 # attempt to switch DAC to 8-bit
158 movw $0x4f08, %ax
159 movw $0x0800, %bx
160 int $0x10
161 cmpw $0x004f, %ax
162 jne dac_set
163 movb %bh, bootsym(dac_size) # store actual DAC size
165 dac_set:
166 # set color size to DAC size
167 movb bootsym(dac_size), %al
168 movb %al, _param(PARAM_LFB_COLORS+0)
169 movb %al, _param(PARAM_LFB_COLORS+2)
170 movb %al, _param(PARAM_LFB_COLORS+4)
171 movb %al, _param(PARAM_LFB_COLORS+6)
173 # set color offsets to 0
174 movb $0, _param(PARAM_LFB_COLORS+1)
175 movb $0, _param(PARAM_LFB_COLORS+3)
176 movb $0, _param(PARAM_LFB_COLORS+5)
177 movb $0, _param(PARAM_LFB_COLORS+7)
179 dac_done:
180 # get protected mode interface informations
181 movw $0x4f0a, %ax
182 xorw %bx, %bx
183 xorw %di, %di
184 int $0x10
185 cmp $0x004f, %ax
186 jnz no_pm
188 movw %es, _param(PARAM_VESAPM_SEG)
189 movw %di, _param(PARAM_VESAPM_OFF)
191 no_pm: pushw %ds
192 popw %es
193 ret
195 # The video mode menu
196 mode_menu:
197 leaw bootsym(keymsg), %si # "Return/Space/Timeout" message
198 call prtstr
199 call flush
200 nokey: call getkt
202 cmpb $0x0d, %al # ENTER ?
203 je listm # yes - manual mode selection
205 cmpb $0x20, %al # SPACE ?
206 je defmd1 # no - repeat
208 call beep
209 jmp nokey
211 defmd1: ret # No mode chosen? Default 80x25
213 listm: call mode_table # List mode table
214 listm0: leaw bootsym(name_bann), %si # Print adapter name
215 call prtstr
216 movw bootsym(card_name), %si
217 orw %si, %si
218 jnz an2
220 leaw bootsym(vga_name), %si
221 jmp an1
223 an2: call prtstr
224 leaw bootsym(svga_name), %si
225 an1: call prtstr
226 leaw bootsym(listhdr), %si # Table header
227 call prtstr
228 movb $0x30, %dl # DL holds mode number
229 leaw modelist, %si
230 lm1: cmpw $ASK_VGA, (%si) # End?
231 jz lm2
233 movb %dl, %al # Menu selection number
234 call prtchr
235 call prtsp2
236 lodsw
237 call prthw # Mode ID
238 call prtsp2
239 lodsw
240 call prtdec # Width
241 movb $0x78, %al # the letter 'x'
242 call prtchr
243 lodsw
244 call prtdec # Height
245 testb $0xff,(%si)
246 jnz 1f
247 push %si
248 leaw bootsym(textmode), %si
249 call prtstr
250 pop %si
251 lodsw
252 jmp 2f
253 1: movb $0x78, %al # the letter 'x'
254 call prtchr
255 lodsw
256 call prtdec # Depth
257 2: movb $0x0d, %al # New line
258 call prtchr
259 movb $0x0a, %al
260 call prtchr
261 incb %dl # Next character
263 cmpb $'z'+1, %dl
264 jnz skip_bail
265 leaw bootsym(menu_bail_msg), %si
266 call prtstr
267 jmp lm2
269 skip_bail:
270 cmpb $'i', %dl
271 jnz skip_pause
272 push %si
273 push %dx
274 leaw bootsym(menu_more_msg), %si # '<press space>'
275 call prtstr
276 call flush
277 1: call getkey
278 cmpb $0x20, %al # SPACE ?
279 jne 1b # yes - manual mode selection
280 leaw bootsym(crlft), %si
281 call prtstr
282 pop %dx
283 pop %si
285 skip_pause:
286 cmpb $'9'+1, %dl
287 jnz lm1
288 movb $'a', %dl
289 jmp lm1
291 lm2: leaw bootsym(prompt), %si # Mode prompt
292 call prtstr
293 leaw bootsym(edit_buf), %di # Editor buffer
294 lm3: call getkey
295 cmpb $0x0d, %al # Enter?
296 jz lment
298 cmpb $0x08, %al # Backspace?
299 jz lmbs
301 cmpb $0x20, %al # Printable?
302 jc lm3
304 cmpw $bootsym(edit_buf)+4, %di # Enough space?
305 jz lm3
307 stosb
308 call prtchr
309 jmp lm3
311 lmbs: cmpw $bootsym(edit_buf), %di # Backspace
312 jz lm3
314 decw %di
315 movb $0x08, %al
316 call prtchr
317 call prtspc
318 movb $0x08, %al
319 call prtchr
320 jmp lm3
322 lment: movb $0, (%di)
323 leaw bootsym(crlft), %si
324 call prtstr
325 leaw bootsym(edit_buf), %si
326 cmpb $0, (%si) # Empty string = default mode
327 jz lmdef
329 cmpb $0, 1(%si) # One character = menu selection
330 jz mnusel
332 cmpw $0x656d, (%si) # 'me'
333 jnz lmhx
334 cmpw $0x756e, 2(%si) # 'nu'
335 jnz lmhx
336 jmp listm
338 lmhx: xorw %bx, %bx # Else => mode ID in hex
339 lmhex: lodsb
340 orb %al, %al
341 jz lmuse1
343 subb $0x30, %al
344 jc lmbad
346 cmpb $10, %al
347 jc lmhx1
349 subb $7, %al
350 andb $0xdf, %al
351 cmpb $10, %al
352 jc lmbad
354 cmpb $16, %al
355 jnc lmbad
357 lmhx1: shlw $4, %bx
358 orb %al, %bl
359 jmp lmhex
361 lmuse1: movw %bx, %ax
362 jmp lmuse
364 mnusel: lodsb # Menu selection
365 xorb %ah, %ah
366 subb $0x30, %al
367 jc lmbad
369 cmpb $10, %al
370 jc lmuse
372 cmpb $0x61-0x30, %al
373 jc lmbad
375 subb $0x61-0x30-10, %al
376 cmpb $36, %al
377 jnc lmbad
379 lmuse: call mode_set
380 jc lmdef
382 lmbad: leaw bootsym(unknt), %si
383 call prtstr
384 jmp mode_menu
385 lmdef: ret
387 _setrec: jmp setrec # Ugly...
388 _set_80x25: jmp set_80x25
390 # Setting of user mode (AX=mode ID) => CF=success
391 mode_set:
392 movw %ax, bootsym(boot_vid_mode)
393 movw %ax, %bx
395 cmpw $VIDEO_VESA_BY_SIZE, %ax
396 je setvesabysize
398 testb $VIDEO_RECALC>>8, %ah
399 jnz _setrec
401 cmpb $VIDEO_FIRST_SPECIAL>>8, %ah
402 jz setspc
404 cmpb $VIDEO_FIRST_VESA>>8, %ah
405 jnc check_vesa
407 orb %ah, %ah
408 jnz setbad
410 jmp setmenu
412 setbad: clc
413 ret
415 setspc: xorb %bh, %bh # Set special mode
416 cmpb $VIDEO_LAST_SPECIAL-VIDEO_FIRST_SPECIAL, %bl
417 jnc setbad
419 addw %bx, %bx
420 jmp *bootsym(spec_inits)(%bx)
422 setmenu:
423 orb %al, %al # 80x25 is an exception
424 jz _set_80x25
426 pushw %bx # Set mode chosen from menu
427 call mode_table # Build the mode table
428 popw %ax
429 shlw $3, %ax
430 addw %ax, %si
431 cmpw %di, %si
432 jnc setbad
434 movw (%si), %ax # Fetch mode ID
435 jmp mode_set
437 check_vesa:
438 leaw vesa_glob_info, %di
439 movw $0x4f00, %ax
440 int $0x10
441 cmpw $0x004f, %ax
442 jnz setbad
444 leaw vesa_mode_info, %di
445 subb $VIDEO_FIRST_VESA>>8, %bh
446 movw %bx, %cx # Get mode information structure
447 movw $0x4f01, %ax
448 int $0x10
449 addb $VIDEO_FIRST_VESA>>8, %bh
450 cmpw $0x004f, %ax
451 jnz setbad
453 movb (%di), %al # Check mode attributes.
454 andb $0x99, %al
455 cmpb $0x99, %al
456 jnz _setbad # Doh! No linear frame buffer.
458 subb $VIDEO_FIRST_VESA>>8, %bh
459 orw $0x4000, %bx # Use linear frame buffer
460 movw $0x4f02, %ax # VESA BIOS mode set call
461 int $0x10
462 cmpw $0x004f, %ax # AL=4f if implemented
463 jnz _setbad # AH=0 if OK
465 movb $1, bootsym(graphic_mode) # flag graphic mode
466 stc
467 ret
469 _setbad: jmp setbad # Ugly...
471 # Recalculate vertical display end registers -- this fixes various
472 # inconsistencies of extended modes on many adapters. Called when
473 # the VIDEO_RECALC flag is set in the mode ID.
475 setrec: subb $VIDEO_RECALC>>8, %ah # Set the base mode
476 call mode_set
477 jnc rct3
479 movw %gs:(0x485), %ax # Font size in pixels
480 movb %gs:(0x484), %bl # Number of rows
481 incb %bl
482 mulb %bl # Number of visible
483 decw %ax # scan lines - 1
484 movw $0x3d4, %dx
485 movw %ax, %bx
486 movb $0x12, %al # Lower 8 bits
487 movb %bl, %ah
488 outw %ax, %dx
489 movb $0x07, %al # Bits 8 and 9 in the overflow register
490 call inidx
491 xchgb %al, %ah
492 andb $0xbd, %ah
493 shrb %bh
494 jnc rct1
495 orb $0x02, %ah
496 rct1: shrb %bh
497 jnc rct2
498 orb $0x40, %ah
499 rct2: movb $0x07, %al
500 outw %ax, %dx
501 stc
502 rct3: ret
504 inidx: outb %al, %dx # Read from indexed VGA register
505 incw %dx # AL=index, DX=index reg port -> AL=data
506 inb %dx, %al
507 decw %dx
508 ret
510 setvesabysize:
511 call mode_table
512 leaw modelist,%si
513 1: add $8,%si
514 cmpw $ASK_VGA,-8(%si) # End?
515 je _setbad
516 movw -6(%si),%ax
517 cmpw %ax,bootsym(vesa_size)+0
518 jne 1b
519 movw -4(%si),%ax
520 cmpw %ax,bootsym(vesa_size)+2
521 jne 1b
522 movw -2(%si),%ax
523 cmpw %ax,bootsym(vesa_size)+4
524 jne 1b
525 movw -8(%si),%ax
526 movw %ax,%bx
527 movw %ax,bootsym(boot_vid_mode)
528 jmp check_vesa
530 # Table of routines for setting of the special modes.
531 spec_inits:
532 .word bootsym(set_80x25)
533 .word bootsym(set_8pixel)
534 .word bootsym(set_80x43)
535 .word bootsym(set_80x28)
536 .word bootsym(set_current)
537 .word bootsym(set_80x30)
538 .word bootsym(set_80x34)
539 .word bootsym(set_80x60)
541 # Set the 80x25 mode. If already set, do nothing.
542 set_80x25:
543 movw $0x5019, bootsym(force_size) # Override possibly broken BIOS
544 use_80x25:
545 movw $0x1202, %ax # Force 400 scan lines
546 movb $0x30, %bl
547 int $0x10
548 movw $0x0003, %ax # Mode 3
549 int $0x10
550 stc
551 ret
553 # Set the 80x50/80x43 8-pixel mode. Simple BIOS calls.
554 set_8pixel:
555 call use_80x25 # The base is 80x25
556 set_8pt:
557 movw $0x1112, %ax # Use 8x8 font
558 xorb %bl, %bl
559 int $0x10
560 movw $0x1200, %ax # Use alternate print screen
561 movb $0x20, %bl
562 int $0x10
563 movw $0x1201, %ax # Turn off cursor emulation
564 movb $0x34, %bl
565 int $0x10
566 movb $0x01, %ah # Define cursor scan lines 6-7
567 movw $0x0607, %cx
568 int $0x10
569 stc
570 ret
572 # Set the 80x28 mode. This mode works on all VGA's, because it's a standard
573 # 80x25 mode with 14-point fonts instead of 16-point.
574 set_80x28:
575 call use_80x25 # The base is 80x25
576 set14: movw $0x1111, %ax # Use 9x14 font
577 xorb %bl, %bl
578 int $0x10
579 movb $0x01, %ah # Define cursor scan lines 11-12
580 movw $0x0b0c, %cx
581 int $0x10
582 set_current:
583 stc
584 ret
586 # Set the 80x43 mode. This mode is works on all VGA's.
587 # It's a 350-scanline mode with 8-pixel font.
588 set_80x43:
589 movw $0x1201, %ax # Set 350 scans
590 movb $0x30, %bl
591 int $0x10
592 movw $0x0003, %ax # Reset video mode
593 int $0x10
594 jmp set_8pt # Use 8-pixel font
596 # Set the 80x30 mode (all VGA's). 480 scanlines, 16-pixel font.
597 set_80x30:
598 call use_80x25 # Start with real 80x25
599 movw $0x3cc, %dx # Get CRTC port
600 inb %dx, %al
601 movb $0xd4, %dl
602 rorb %al # Mono or color?
603 jc set48a
605 movb $0xb4, %dl
606 set48a: movw $0x0c11, %ax # Vertical sync end (also unlocks CR0-7)
607 call outidx
608 movw $0x0b06, %ax # Vertical total
609 call outidx
610 movw $0x3e07, %ax # (Vertical) overflow
611 call outidx
612 movw $0xea10, %ax # Vertical sync start
613 call outidx
614 movw $0xdf12, %ax # Vertical display end
615 call outidx
616 movw $0xe715, %ax # Vertical blank start
617 call outidx
618 movw $0x0416, %ax # Vertical blank end
619 call outidx
620 pushw %dx
621 movb $0xcc, %dl # Misc output register (read)
622 inb %dx, %al
623 movb $0xc2, %dl # (write)
624 andb $0x0d, %al # Preserve clock select bits and color bit
625 orb $0xe2, %al # Set correct sync polarity
626 outb %al, %dx
627 popw %dx
628 movw $0x501e, bootsym(force_size)
629 stc # That's all.
630 ret
632 # Set the 80x34 mode (all VGA's). 480 scans, 14-pixel font.
633 set_80x34:
634 call set_80x30 # Set 480 scans
635 call set14 # And 14-pt font
636 movw $0xdb12, %ax # VGA vertical display end
637 movw $0x5022, bootsym(force_size)
638 setvde: call outidx
639 stc
640 ret
642 # Set the 80x60 mode (all VGA's). 480 scans, 8-pixel font.
643 set_80x60:
644 call set_80x30 # Set 480 scans
645 call set_8pt # And 8-pt font
646 movw $0xdf12, %ax # VGA vertical display end
647 movw $0x503c, bootsym(force_size)
648 jmp setvde
650 # Write to indexed VGA register (AL=index, AH=data, DX=index reg. port)
651 outidx: outb %al, %dx
652 pushw %ax
653 movb %ah, %al
654 incw %dx
655 outb %al, %dx
656 decw %dx
657 popw %ax
658 ret
660 # Build the table of video modes (stored after the setup.S code at the
661 # `modelist' label. Each video mode record looks like:
662 # .word MODE-ID (our special mode ID (see above))
663 # .byte rows (number of rows)
664 # .byte columns (number of columns)
665 # Returns address of the end of the table in DI, the end is marked
666 # with a ASK_VGA ID.
667 mode_table:
668 movw bootsym(mt_end), %di # Already filled?
669 orw %di, %di
670 jnz mtab1
672 leaw modelist, %di # Store standard modes:
673 movw $VIDEO_80x25,(%di) # The 80x25 mode (ALL)
674 movw $0x50,2(%di)
675 movw $0x19,4(%di)
676 movw $0x00,6(%di)
677 addw $8,%di
679 leaw bootsym(vga_modes), %si # All modes for std VGA
680 movw $vga_modes_end-vga_modes, %cx
681 rep movsb
683 call vesa_modes # Detect VESA VGA modes
685 movw $ASK_VGA, (%di) # End marker
686 movw %di, bootsym(mt_end)
687 mtab1: leaw modelist, %si # SI=mode list, DI=list end
688 ret0: ret
690 # Modes usable on all standard VGAs
691 vga_modes:
692 .word VIDEO_80x50, 0x50,0x32,0 # 80x50
693 .word VIDEO_80x43, 0x50,0x2b,0 # 80x43
694 .word VIDEO_80x28, 0x50,0x1c,0 # 80x28
695 .word VIDEO_80x30, 0x50,0x1e,0 # 80x30
696 .word VIDEO_80x34, 0x50,0x22,0 # 80x34
697 .word VIDEO_80x60, 0x50,0x3c,0 # 80x60
698 vga_modes_end:
700 # Detect VESA modes.
701 vesa_modes:
702 movw %di, %bp # BP=original mode table end
703 leaw vesa_glob_info, %di
704 movw $0x4f00, %ax # VESA Get card info call
705 int $0x10
706 movw %di, %si
707 movw %bp, %di
708 cmpw $0x004f, %ax # Successful?
709 jnz ret0
711 cmpw $0x4556, (%si) # 'VE'
712 jnz ret0
714 cmpw $0x4153, 2(%si) # 'SA'
715 jnz ret0
717 movw $bootsym(vesa_name), bootsym(card_name) # Set name to "VESA VGA"
718 pushw %gs
719 lgsw 0xe(%si), %si # GS:SI=mode list
720 movw $128, %cx # Iteration limit
721 vesa1:
722 gs; lodsw
723 cmpw $0xffff, %ax # End of the table?
724 jz vesar
726 cmpw $0x0080, %ax # Check validity of mode ID
727 jc vesa2
729 orb %ah, %ah # Valid IDs 0x0000-0x007f/0x0100-0x07ff
730 jz vesan # Certain BIOSes report 0x80-0xff!
732 cmpw $0x0800, %ax
733 jnc vesae
735 vesa2: pushw %cx
736 movw %ax, %cx # Get mode information structure
737 movw $0x4f01, %ax
738 int $0x10
739 movw %cx, %bx # BX=mode number
740 addb $VIDEO_FIRST_VESA>>8, %bh
741 popw %cx
742 cmpw $0x004f, %ax
743 jnz vesan # Don't report errors (buggy BIOSES)
745 movb (%di), %al # Check capabilities.
746 andb $0x9b, %al # LFB gfx mode in color?
747 cmpb $0x9b, %al
748 jnz vesan
750 movw %bx, (%di) # Store mode number
751 movw 0x12(%di), %bx # Width
752 movw %bx, 2(%di)
753 movw 0x14(%di), %bx # Height
754 movw %bx, 4(%di)
755 xorw %bx, %bx
756 movb 0x19(%di), %bl # Depth
757 movw %bx, 6(%di)
759 addw $8, %di # The mode is valid. Store it.
760 vesan: loop vesa1 # Next mode. Limit exceeded => error
761 vesae: leaw bootsym(vesaer), %si
762 call prtstr
763 movw %bp, %di # Discard already found modes.
764 vesar: popw %gs
765 ret
767 # Read a key and return the ASCII code in al, scan code in ah
768 getkey: xorb %ah, %ah
769 int $0x16
770 ret
772 # Read a key with a timeout of 30 seconds.
773 # The hardware clock is used to get the time.
774 getkt: call gettime
775 addb $30, %al # Wait 30 seconds
776 cmpb $60, %al
777 jl lminute
779 subb $60, %al
780 lminute:
781 movb %al, %cl
782 again: movb $0x01, %ah
783 int $0x16
784 jnz getkey # key pressed, so get it
786 call gettime
787 cmpb %cl, %al
788 jne again
790 movb $0x20, %al # timeout, return `space'
791 ret
793 # Flush the keyboard buffer
794 flush: movb $0x01, %ah
795 int $0x16
796 jz empty
798 xorb %ah, %ah
799 int $0x16
800 jmp flush
802 empty: ret
804 # Print hexadecimal number.
805 prthw: pushw %ax
806 movb %ah, %al
807 call prthb
808 popw %ax
809 prthb: pushw %ax
810 shrb $4, %al
811 call prthn
812 popw %ax
813 andb $0x0f, %al
814 prthn: cmpb $0x0a, %al
815 jc prth1
817 addb $0x07, %al
818 prth1: addb $0x30, %al
819 jmp prtchr
821 # Print decimal number in ax
822 prtdec: pushw %ax
823 pushw %cx
824 pushw %dx
825 xorw %dx, %dx
826 movw $0x0a, %cx
827 divw %cx
828 testw %ax, %ax
829 jz skip10
830 cmpw $0x09, %ax
831 jbe lt100
833 call prtdec
834 jmp skip10
836 lt100: addb $0x30, %al
837 call prtchr
838 skip10: movb %dl, %al
839 addb $0x30, %al
840 call prtchr
841 popw %dx
842 popw %cx
843 popw %ax
844 ret
846 # Routine to print asciiz string at ds:si
847 prtstr:
848 lodsb
849 andb %al, %al
850 jz fin
852 call prtchr
853 jmp prtstr
855 fin: ret
857 # Space printing
858 prtsp2: call prtspc # Print double space
859 prtspc: movb $0x20, %al # Print single space (note: fall-thru)
861 # Part of above routine, this one just prints ascii al
862 prtchr: pushw %ax
863 pushw %cx
864 movw $7,%bx
865 movw $0x01, %cx
866 movb $0x0e, %ah
867 int $0x10
868 popw %cx
869 popw %ax
870 ret
872 beep: movb $0x07, %al
873 jmp prtchr
875 # Read the cmos clock. Return the seconds in al
876 gettime:
877 pushw %cx
878 movb $0x02, %ah
879 int $0x1a
880 movb %dh, %al # %dh contains the seconds
881 andb $0x0f, %al
882 movb %dh, %ah
883 movb $0x04, %cl
884 shrb %cl, %ah
885 aad
886 popw %cx
887 ret
889 store_edid:
890 #ifdef CONFIG_FIRMWARE_EDID
891 pushw %ax
892 pushw %bx
893 pushw %cx
894 pushw %dx
895 pushw %di
897 cmpb $1, bootsym(opt_edid) # EDID disabled on cmdline (edid=no)?
898 je .Lno_edid
900 leaw vesa_glob_info, %di
901 movw $0x4f00, %ax
902 int $0x10
903 cmpw $0x004f, %ax
904 jne .Lno_edid
905 cmpw $0x0200, 4(%di) # only do EDID on >= VBE2.0
906 jb .Lno_edid
908 xorw %di, %di # Report Capability
909 pushw %di
910 popw %es # ES:DI must be 0:0
911 movw $0x4f15, %ax
912 xorw %bx, %bx
913 xorw %cx, %cx
914 int $0x10
915 pushw %ds
916 popw %es
917 cmpw $0x004f, %ax # Call failed?
918 jne .Lno_edid
920 movw %bx, bootsym(boot_edid_caps)
922 cmpb $2, bootsym(opt_edid) # EDID forced on cmdline (edid=force)?
923 je .Lforce_edid
925 /* EDID not forced on cmdline, so perform further sanity checks. */
926 testb $3,%bl # No DDC capabilities?
927 jz .Lno_edid
928 cmpb $5,%bh # Longer than 5s to read EDID?
929 ja .Lno_edid
931 .Lforce_edid:
932 movw $0x4f15, %ax # do VBE/DDC
933 movw $0x01, %bx
934 movw $0x00, %cx
935 movw $0x00, %dx
936 movw $bootsym(boot_edid_info), %di
937 int $0x10
939 .Lno_edid:
940 popw %di # restore all registers
941 popw %dx
942 popw %cx
943 popw %bx
944 popw %ax
945 #endif
946 ret
948 opt_edid: .byte 0 # EDID parsing option (force/no/default)
949 mt_end: .word 0 # End of video mode table if built
950 edit_buf: .space 6 # Line editor buffer
951 card_name: .word 0 # Pointer to adapter name
952 graphic_mode: .byte 0 # Graphic mode with a linear frame buffer
953 dac_size: .byte 6 # DAC bit depth
955 # Status messages
956 keymsg: .ascii "Press <RETURN> to see video modes available,"
957 .byte 0x0d, 0x0a
958 .ascii "<SPACE> to continue or wait 30 secs"
959 .byte 0x0d, 0x0a, 0
961 listhdr: .byte 0x0d, 0x0a
962 .ascii "MODE-KEY MODE-ID WIDTHxHEIGHTxDEPTH"
964 crlft: .byte 0x0d, 0x0a, 0
966 prompt: .byte 0x0d, 0x0a
967 .asciz "Enter mode number or 'menu': "
969 unknt: .ascii "Unknown mode ID. Try again."
970 .byte 0x0d, 0x0a, 0
972 badmdt: .ascii "You passed an undefined mode number."
973 .byte 0x0d, 0x0a, 0
975 vesaer: .ascii "Error: Scanning of VESA modes failed. Please "
976 .ascii "report to <mj@ucw.cz>."
977 .byte 0x0d, 0x0a, 0
979 textmode: .asciz " (text)"
980 menu_more_msg: .asciz "<press SPACE for more>"
981 menu_bail_msg: .ascii "<menu truncated>"
982 .byte 0x0d, 0x0a, 0
984 svga_name: .ascii " "
986 vga_name: .asciz "VGA"
988 vesa_name: .asciz "VESA"
990 name_bann: .asciz "Video adapter: "
992 force_size: .word 0 # Use this size instead of the one in BIOS vars
994 vesa_size: .word 0,0,0 # width x depth x height
996 .globl boot_vid_info, boot_edid_info, boot_edid_caps
997 /* If we don't run at all, assume basic video mode 3 at 80x25. */
998 boot_vid_mode: .word VIDEO_80x25
999 boot_vid_info: .byte 0, 0 /* orig_x, orig_y */
1000 .byte 3 /* text mode 3 */
1001 .byte 80, 25 /* 80x25 */
1002 .byte 1 /* isVGA */
1003 .word 16 /* 8x16 font */
1004 .fill 0x28,1,0
1005 boot_edid_info: .fill 128,1,0x13
1006 boot_edid_caps: .word 0x1313