2 * setup.S Copyright (C) 1991, 1992 Linus Torvalds
4 * setup.s is responsible for getting the system data from the BIOS,
5 * and putting them into the appropriate places in system memory.
6 * both setup.s and system has been loaded by the bootblock.
8 * This code asks the bios for memory/disk/other parameters, and
9 * puts them in a "safe" place: 0x90000-0x901FF, ie where the
10 * boot-block used to be. It is then up to the protected mode
11 * system to read them from there before the area is overwritten
14 * Move PS/2 aux init code to psaux.c
15 * (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92
17 * some changes and additional features by Christoph Niemann,
18 * March 1993/June 1994 (Christoph.Niemann@linux.org)
20 * add APM BIOS checking by Stephen Rothwell, May 1994
21 * (sfr@canb.auug.org.au)
23 * High load stuff, initrd support and position independency
24 * by Hans Lermen & Werner Almesberger, February 1996
25 * <lermen@elserv.ffm.fgan.de>, <almesber@lrc.epfl.ch>
27 * Video handling moved to video.S by Martin Mares, March 1996
28 * <mj@k332.feld.cvut.cz>
30 * Extended memory detection scheme retwiddled by orc@pell.chi.il.us (david
31 * parsons) to avoid loadlin confusion, July 1997
33 * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999.
34 * <stiker@northlink.com>
36 * Fix to work around buggy BIOSes which dont use carry bit correctly
37 * and/or report extended memory in CX/DX for e801h memory size detection
38 * call. As a result the kernel got wrong figures. The int15/e801h docs
39 * from Ralf Brown interrupt list seem to indicate AX/BX should be used
40 * anyway. So to avoid breaking many machines (presumably there was a reason
41 * to orginally use CX/DX instead of AX/BX), we do a kludge to see
42 * if CX/DX have been changed in the e801 call and if so use AX/BX .
43 * Michael Miller, April 2001 <michaelm@mjmm.org>
45 * New A20 code ported from SYSLINUX by H. Peter Anvin. AMD Elan bugfixes
46 * by Robert Schwebel, December 2001 <robert@schwebel.de>
49 #define __BIG_KERNEL__ 1
51 //#include <linux/config.h>
52 //#include <asm/segment.h>
53 //#include <asm/boot.h>
55 /* Don't touch these, unless you really know what you're doing. */
56 #define DEF_INITSEG 0x9000
57 #define DEF_SYSSEG 0x1000
58 #define DEF_SETUPSEG 0x9020
59 #define DEF_SYSSIZE 0x7F00
61 /* Internal svga startup constants */
62 #define NORMAL_VGA 0xffff /* 80x25 mode */
63 #define EXTENDED_VGA 0xfffe /* 80x50 mode */
64 #define ASK_VGA 0xfffd /* ask for it at bootup */
67 //#include <asm/e820.h>
68 #define E820MAP 0x2d0 /* our map */
69 #define E820MAX 32 /* number of entries in E820MAP */
70 #define E820NR 0x1e8 /* # entries in E820MAP */
73 #define E820_RESERVED 2
74 #define E820_ACPI 3 /* usable as RAM once ACPI tables have been read
78 #define HIGH_MEMORY (1024*1024)
80 //#include <asm/page.h>
82 /* Signature words to ensure LILO loaded us right */
86 INITSEG = DEF_INITSEG # 0x9000, we move boot here, out of the way
87 SYSSEG = DEF_SYSSEG # 0x1000, system loaded at 0x10000 (65536).
88 SETUPSEG = DEF_SETUPSEG # 0x9020, this is the current segment
89 # ... and the former contents of CS
91 DELTA_INITSEG = SETUPSEG - INITSEG # 0x0020
94 .globl begtext, begdata, begbss, endtext, enddata, endbss
107 # This is the setup header, and it must start at %cs:2 (old 0x9020:2)
109 .ascii "HdrS" # header signature
110 .word 0x0203 # header version number (>= 0x0105)
111 # or else old loadlin-1.5 will fail)
112 realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
113 start_sys_seg: .word SYSSEG
114 .word kernel_version # pointing to kernel version string
115 # above section of header is compatible
116 # with loadlin-1.5 (header v1.5). Don't
119 type_of_loader: .byte 0 # = 0, old one (LILO, Loadlin,
120 # Bootlin, SYSLX, bootsect...)
121 # See Documentation/i386/boot.txt for
124 # flags, unused bits must be zero (RFU) bit within loadflags
126 LOADED_HIGH = 1 # If set, the kernel is loaded high
127 CAN_USE_HEAP = 0x80 # If set, the loader also has set
128 # heap_end_ptr to tell how much
129 # space behind setup.S can be used for
131 # Only the loader knows what is free
132 #ifndef __BIG_KERNEL__
138 setup_move_size: .word 0x8000 # size to move, when setup is not
139 # loaded at 0x90000. We will move setup
140 # to 0x90000 then just before jumping
141 # into the kernel. However, only the
142 # loader knows how much data behind
143 # us also needs to be loaded.
145 code32_start: # here loaders can put a different
146 # start address for 32-bit code.
147 #ifndef __BIG_KERNEL__
148 .long 0x1000 # 0x1000 = default for zImage
150 .long 0x100000 # 0x100000 = default for big kernel
153 ramdisk_image: .long 0 # address of loaded ramdisk image
154 # Here the loader puts the 32-bit
155 # address where it loaded the image.
156 # This only will be read by the kernel.
158 ramdisk_size: .long 0 # its size in bytes
163 heap_end_ptr: .word modelist+1024 # (Header version 0x0201 or later)
164 # space from here (exclusive) down to
165 # end of setup code can be used by setup
166 # for local heap purposes.
169 cmd_line_ptr: .long 0 # (Header version 0x0202 or later)
170 # If nonzero, a 32-bit pointer
171 # to the kernel command line.
172 # The command line should be
173 # located between the start of
174 # setup and the end of low
175 # memory (0xa0000), or it may
176 # get overwritten before it
177 # gets read. If this field is
178 # used, there is no longer
179 # anything magical about the
180 # 0x90000 segment; the setup
181 # can be located anywhere in
182 # low memory 0x10000 or higher.
184 ramdisk_max: .long (-0xC0000000-(512 << 20)-1) & 0x7fffffff
185 # (Header version 0x0203 or later)
186 # The highest safe address for
187 # the contents of an initrd
189 trampoline: call start_of_setup
191 # The offset at this point is 0x240
192 .space (0x7ff-0x240+1) # E820 & EDD space (ending at 0x7ff)
193 # End of setup header #####################################################
196 # Bootlin depends on this being done early
201 #ifdef SAFE_RESET_DISK_CONTROLLER
202 # Reset the disk controller.
208 # Set %ds = %cs, we know that SETUPSEG = %cs at this point
209 movw %cs, %ax # aka SETUPSEG
211 # Check signature at end of setup
212 cmpw $SIG1, setup_sig1
215 cmpw $SIG2, setup_sig2
220 # Routine to print asciiz string at ds:si
232 prtsp2: call prtspc # Print double space
233 prtspc: movb $0x20, %al # Print single space (note: fall-thru)
235 # Part of above routine, this one just prints ascii al
246 beep: movb $0x07, %al
249 no_sig_mess: .string "No setup signature found ..."
254 # We now have to find the rest of the setup code/data
256 movw %cs, %ax # SETUPSEG
257 subw $DELTA_INITSEG, %ax # INITSEG
260 movb (497), %bl # get setup sect from bootsect
261 subw $4, %bx # LILO loads 4 sectors of setup
262 shlw $8, %bx # convert to words (1sect=2^8 words)
264 shrw $3, %bx # convert to segment
266 movw %bx, %cs:start_sys_seg
267 # Move rest of setup code/data to here
268 movw $2048, %di # four sectors loaded by LILO
276 movw %cs, %ax # aka SETUPSEG
278 cmpw $SIG1, setup_sig1
281 cmpw $SIG2, setup_sig2
295 movw %cs, %ax # aka SETUPSEG
296 subw $DELTA_INITSEG, %ax # aka INITSEG
298 # Check if an old loader tries to load a big-kernel
299 testb $LOADED_HIGH, %cs:loadflags # Do we have a big kernel?
300 jz loader_ok # No, no danger for old loaders.
302 cmpb $0, %cs:type_of_loader # Do we have a loader that
304 jnz loader_ok # Yes, continue.
306 pushw %cs # No, we have an old loader,
308 lea loader_panic_mess, %si
313 loader_panic_mess: .string "Wrong loader, giving up..."
316 # Get memory size (extended mem, kB)
320 #ifndef STANDARD_MEMORY_BIOS_CALL
322 # Try three different memory detection schemes. First, try
323 # e820h, which lets us assemble a memory map, then try e801h,
324 # which returns a 32-bit memory size, and finally 88h, which
328 # the memory map from hell. e820h returns memory classified into
329 # a whole bunch of different types, and allows memory holes and
330 # everything. We scan through this memory map and build a list
331 # of the first 32 memory areas, which we return at [E820MAP].
332 # This is documented at http://www.acpi.info/, in the ACPI 2.0 specification.
334 #define SMAP 0x534d4150
337 xorl %ebx, %ebx # continuation counter
338 movw $E820MAP, %di # point into the whitelist
339 # so we can have the bios
340 # directly write into it.
343 movl $0x0000e820, %eax # e820, upper word zeroed
344 movl $SMAP, %edx # ascii 'SMAP'
345 movl $20, %ecx # size of the e820rec
346 pushw %ds # data record.
348 int $0x15 # make the call
349 jc bail820 # fall to e801 if it fails
351 cmpl $SMAP, %eax # check the return is `SMAP'
352 jne bail820 # fall to e801 if it fails
354 # cmpl $1, 16(%di) # is this usable memory?
357 # If this is usable memory, we save it by simply advancing %di by
361 movb (E820NR), %al # up to 32 entries
370 cmpl $0, %ebx # check to see if
371 jne jmpe820 # %ebx is set to EOF
376 # memory size is in 1k chunksizes, to avoid confusing loadlin.
377 # we store the 0xe801 memory size in a completely different place,
378 # because it will most likely be longer than 16 bits.
379 # (use 1e0 because that's what Larry Augustine uses in his
380 # alternative new memory detection scheme, and it's sensible
381 # to write everything into the same place.)
384 stc # fix to work around buggy
385 xorw %cx,%cx # BIOSes which dont clear/set
386 xorw %dx,%dx # carry on pass/error of
387 # e801h memory size call
388 # or merely pass cx,dx though
389 # without changing them.
394 cmpw $0x0, %cx # Kludge to handle BIOSes
395 jne e801usecxdx # which report their extended
396 cmpw $0x0, %dx # memory in AX/BX rather than
397 jne e801usecxdx # CX/DX. The spec I have read
398 movw %ax, %cx # seems to indicate AX/BX
399 movw %bx, %dx # are more reasonable anyway...
402 andl $0xffff, %edx # clear sign extend
403 shll $6, %edx # and go from 64k to 1k chunks
404 movl %edx, (0x1e0) # store extended memory size
405 andl $0xffff, %ecx # clear sign extend
406 addl %ecx, (0x1e0) # and add lower memory into
409 # Ye Olde Traditional Methode. Returns the memory size (up to 16mb or
410 # 64mb, depending on the bios) in ax.
418 # Set the keyboard repeat rate to the max
423 # Check for video adapter and its parameters and allow the
424 # user to browse video modes.
425 call video # NOTE: we need %ds pointing
432 movw %cs, %ax # aka SETUPSEG
433 subw $DELTA_INITSEG, %ax # aka INITSEG
451 # Check that there IS a hd1 :-)
461 movw %cs, %ax # aka SETUPSEG
462 subw $DELTA_INITSEG, %ax # aka INITSEG
471 # check for Micro Channel (MCA) bus
472 movw %cs, %ax # aka SETUPSEG
473 subw $DELTA_INITSEG, %ax # aka INITSEG
476 movw %ax, (0xa0) # set table length to 0
479 int $0x15 # moves feature table to es:bx
485 movw %cs, %ax # aka SETUPSEG
486 subw $DELTA_INITSEG, %ax # aka INITSEG
491 addw $2, %cx # table length is a short
495 movw $0x10, %cx # we keep only first 16 bytes
501 #ifdef CONFIG_X86_VOYAGER
502 movb $0xff, 0x40 # flag on config found
505 int $0x15 # put voyager config info at es:di
507 movw $0x40, %si # place voyager info in apm table
519 # Check for PS/2 pointing device
520 movw %cs, %ax # aka SETUPSEG
521 subw $DELTA_INITSEG, %ax # aka INITSEG
523 movw $0, (0x1ff) # default is no pointing device
524 int $0x11 # int 0x11: equipment list
525 testb $0x04, %al # check if mouse installed
528 movw $0xAA, (0x1ff) # device present
531 #if defined(CONFIG_X86_SPEEDSTEP_SMI) || defined(CONFIG_X86_SPEEDSTEP_SMI_MODULE)
532 movl $0x0000E980, %eax # IST Support
533 movl $0x47534943, %edx # Request value
542 #if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
543 # Then check for an APM BIOS...
544 # %ds points to the bootsector
545 movw $0, 0x40 # version = 0 means no APM BIOS
546 movw $0x05300, %ax # APM BIOS installation check
549 jc done_apm_bios # Nope, no APM BIOS
551 cmpw $0x0504d, %bx # Check for "PM" signature
552 jne done_apm_bios # No signature, no APM BIOS
554 andw $0x02, %cx # Is 32 bit supported?
555 je done_apm_bios # No 32-bit, no (good) APM BIOS
557 movw $0x05304, %ax # Disconnect first just in case
559 int $0x15 # ignore return code
560 movw $0x05303, %ax # 32 bit connect
562 xorw %cx, %cx # paranoia :-)
564 xorl %esi, %esi # ...
567 jc no_32_apm_bios # Ack, error.
569 movw %ax, (66) # BIOS code segment
570 movl %ebx, (68) # BIOS entry point offset
571 movw %cx, (72) # BIOS 16 bit code segment
572 movw %dx, (74) # BIOS data segment
573 movl %esi, (78) # BIOS code segment lengths
574 movw %di, (82) # BIOS data segment length
575 # Redo the installation check as the 32 bit connect
576 # modifies the flags returned on some BIOSs
577 movw $0x05300, %ax # APM BIOS installation check
579 xorw %cx, %cx # paranoia
581 jc apm_disconnect # error -> shouldn't happen
583 cmpw $0x0504d, %bx # check for "PM" signature
584 jne apm_disconnect # no sig -> shouldn't happen
586 movw %ax, (64) # record the APM BIOS version
587 movw %cx, (76) # and flags
590 apm_disconnect: # Tidy up
591 movw $0x05304, %ax # Disconnect
593 int $0x15 # ignore return code
598 andw $0xfffd, (76) # remove 32 bit support bit
604 # Now we want to move to protected mode ...
605 cmpw $0, %cs:realmode_swtch
608 lcall *%cs:realmode_swtch
617 # we get the code32 start address and modify the below 'jmpi'
618 # (loader may have changed it)
619 movl %cs:code32_start, %eax
620 movl %eax, %cs:code32
622 # Now we move the system to its rightful place ... but we check if we have a
623 # big-kernel. In that case we *must* not move it ...
624 testb $LOADED_HIGH, %cs:loadflags
625 jz do_move0 # .. then we have a normal low
627 # .. or else we have a high
629 jmp end_move # ... and we skip moving
632 movw $0x100, %ax # start of destination segment
633 movw %cs, %bp # aka SETUPSEG
634 subw $DELTA_INITSEG, %bp # aka INITSEG
635 movw %cs:start_sys_seg, %bx # start of source segment
638 movw %ax, %es # destination segment
639 incb %ah # instead of add ax,#0x100
640 movw %bx, %ds # source segment
647 cmpw %bp, %bx # assume start_sys_seg > 0x200,
648 # so we will perhaps read one
649 # page more than needed, but
650 # never overwrite INITSEG
651 # because destination is a
652 # minimum one page below source
656 # then we load the segment descriptors
657 movw %cs, %ax # aka SETUPSEG
660 # Check whether we need to be downward compatible with version <=201
661 cmpl $0, cmd_line_ptr
662 jne end_move_self # loader uses version >=202 features
663 cmpb $0x20, type_of_loader
664 je end_move_self # bootsect loader, we know of it
666 # Boot loader doesnt support boot protocol version 2.02.
667 # If we have our code not at 0x90000, we need to move it there now.
668 # We also then need to move the params behind it (commandline)
669 # Because we would overwrite the code on the current IP, we move
670 # it in two steps, jumping high after the first one.
675 cli # make sure we really have
676 # interrupts disabled !
677 # because after this the stack
679 subw $DELTA_INITSEG, %ax # aka INITSEG
685 subw %ax, %dx # this will go into %ss after
689 movw $INITSEG, %ax # real INITSEG
691 movw %cs:setup_move_size, %cx
692 std # we have to move up, so we use
693 # direction down because the
698 subw $move_self_here+0x200, %cx
701 ljmp $SETUPSEG, $move_self_here
704 movw $move_self_here+0x200, %cx
710 end_move_self: # now we are at the right place
713 # Enable A20. This is at the very best an annoying procedure.
714 # A20 code ported from SYSLINUX 1.52-1.63 by H. Peter Anvin.
715 # AMD Elan bug fix by Robert Schwebel.
718 #if defined(CONFIG_X86_ELAN)
719 movb $0x02, %al # alternate A20 gate
720 outb %al, $0x92 # this works on SC410/SC520
728 A20_TEST_LOOPS = 32 # Iterations per wait
729 A20_ENABLE_LOOPS = 255 # Total loops to try
732 #ifndef CONFIG_X86_VOYAGER
735 # First, see if we are on a system with no A20 gate.
740 # Next, try the BIOS (INT 0x15, AX=0x2401)
743 pushfl # Be paranoid about flags
750 # Try enabling A20 through the keyboard controller
751 #endif /* CONFIG_X86_VOYAGER */
755 #ifndef CONFIG_X86_VOYAGER
756 call a20_test # Just in case the BIOS worked
757 jnz a20_done # but had a delayed reaction.
760 movb $0xD1, %al # command write
764 movb $0xDF, %al # A20 on
768 #ifndef CONFIG_X86_VOYAGER
769 # Wait until a20 really *is* enabled; it can take a fair amount of
770 # time on certain systems; Toshiba Tecras are known to have this
777 loop a20_kbc_wait_loop
779 # Final attempt: use "configuration port A"
781 inb $0x92, %al # Configuration Port A
782 orb $0x02, %al # "fast A20" version
783 andb $0xFE, %al # don't accidentally reset
786 # Wait for configuration port A to take effect
792 loop a20_fast_wait_loop
794 # A20 is still not responding. Try frobbing it again.
799 movw $a20_err_msg, %si
807 .byte A20_ENABLE_LOOPS
810 .ascii "linux: fatal error: A20 gate not responding!"
813 # If we get here, all is good
816 #endif /* CONFIG_X86_VOYAGER */
818 lidt idt_48 # load idt with 0,0
819 xorl %eax, %eax # Compute gdt_base
820 movw %ds, %ax # (Convert %ds:gdt to a linear ptr)
823 movl %eax, (gdt_48+2)
824 lgdt gdt_48 # load gdt with whatever is
827 # make sure any possible coprocessor is properly reset..
835 # well, that went ok, I hope. Now we mask all interrupts - the rest
836 # is done in init_IRQ().
837 movb $0xFF, %al # mask all interrupts for now
841 movb $0xFB, %al # mask all irq's but irq2 which
842 outb %al, $0x21 # is cascaded
844 # Well, that certainly wasn't fun :-(. Hopefully it works, and we don't
845 # need no steenking BIOS anyway (except for the initial loading :-).
846 # The BIOS-routine wants lots of unnecessary data, and it's less
847 # "interesting" anyway. This is how REAL programmers do it.
849 # Well, now's the time to actually move into protected mode. To make
850 # things as simple as possible, we do no register set-up or anything,
851 # we let the gnu-compiled 32-bit programs do that. We just jump to
852 # absolute address 0x1000 (or the loader supplied one),
853 # in 32-bit protected mode.
855 # Note that the short jump isn't strictly needed, although there are
856 # reasons why it might be a good idea. It won't hurt in any case.
857 movw $1, %ax # protected mode (PE) bit
858 lmsw %ax # This is it!
862 xorw %bx, %bx # Flag to indicate a boot
863 xorl %esi, %esi # Pointer to real-mode code
865 subw $DELTA_INITSEG, %si
866 shll $4, %esi # Convert to 32-bit pointer
868 # jump to startup_32 in arch/i386/boot/compressed/head.S
870 # NOTE: For high loaded big kernels we need a
871 # jmpi 0x100000,__BOOT_CS
873 # but we yet haven't reloaded the CS register, so the default size
874 # of the target offset still is 16 bit.
875 # However, using an operand prefix (0x66), the CPU will properly
876 # take our 48 bit far pointer. (INTeL 80386 Programmer's Reference
877 # Manual, Mixing 16-bit and 32-bit code, page 16-6)
879 .byte 0x66, 0xea # prefix + jmpi-opcode
880 code32: .long 0x1000 # will be set to 0x100000
884 # Here's a bunch of information about your current kernel..
885 kernel_version: .ascii "bootstrap"
888 # This is the default real mode switch routine.
889 # to be called just before protected mode transition
891 cli # no interrupts allowed !
892 movb $0x80, %al # disable NMI for bootup
898 #ifndef CONFIG_X86_VOYAGER
899 # This routine tests whether or not A20 is enabled. If so, it
902 # The memory address used, 0x200, is the int $0x80 vector, which
905 A20_TEST_ADDR = 4*0x80
911 movw %cx, %fs # Low memory
913 movw %cx, %gs # High memory area
914 movw $A20_TEST_LOOPS, %cx
915 movw %fs:(A20_TEST_ADDR), %ax
919 movw %ax, %fs:(A20_TEST_ADDR)
920 call delay # Serialize and make delay constant
921 cmpw %gs:(A20_TEST_ADDR+0x10), %ax
924 popw %fs:(A20_TEST_ADDR)
929 #endif /* CONFIG_X86_VOYAGER */
931 # This routine checks that the keyboard command queue is empty
932 # (after emptying the output buffers)
934 # Some machines have delusions that the keyboard buffer is always full
935 # with no keyboard attached...
937 # If there is no keyboard controller, we will usually get 0xff
938 # to all the reads. With each IO taking a microsecond and
939 # a timeout of 100,000 iterations, this can take about half a
940 # second ("delay" == outb to port 0x80). That should be ok,
941 # and should also be plenty of time for a real keyboard controller
951 jz empty_8042_end_loop
955 inb $0x64, %al # 8042 status port
956 testb $1, %al # output buffer?
960 inb $0x60, %al # read it
964 testb $2, %al # is input buffer full?
965 jnz empty_8042_loop # yes - loop
970 # Read the cmos clock. Return the seconds in al
975 movb %dh, %al # %dh contains the seconds
984 # Delay is needed after doing I/O
991 # NOTE: The intel manual says gdt should be sixteen bytes aligned for
992 # efficiency reasons. However, there are machines which are known not
993 # to boot with misaligned GDTs, so alter this at your peril! If you alter
994 # GDT_ENTRY_BOOT_CS (in asm/segment.h) remember to leave at least two
995 # empty GDT entries (one for NULL and one reserved).
997 # NOTE: On some CPUs, the GDT must be 8 byte aligned. This is
998 # true for the Voyager Quad CPU card which will not boot without
999 # This directive. 16 byte aligment is recommended by intel.
1005 .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
1006 .word 0 # base address = 0
1007 .word 0x9A00 # code read/exec
1008 .word 0x00CF # granularity = 4096, 386
1009 # (+5th nibble of limit)
1011 .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
1012 .word 0 # base address = 0
1013 .word 0x9200 # data read/write
1014 .word 0x00CF # granularity = 4096, 386
1015 # (+5th nibble of limit)
1019 .word 0 # alignment byte
1021 .word 0 # idt limit = 0
1022 .word 0, 0 # idt base = 0L
1024 .word 0 # alignment byte
1026 .word gdt_end - gdt - 1 # gdt limit
1027 .word 0, 0 # gdt base (filled in later)
1029 # Include video setup & detection code
1031 /* Enable autodetection of SVGA adapters and modes. */
1032 #undef CONFIG_VIDEO_SVGA
1034 /* Enable autodetection of VESA modes */
1035 #define CONFIG_VIDEO_VESA
1037 /* Enable compacting of mode table */
1038 #define CONFIG_VIDEO_COMPACT
1040 /* Retain screen contents when switching modes */
1041 #define CONFIG_VIDEO_RETAIN
1043 /* Enable local mode list */
1044 #undef CONFIG_VIDEO_LOCAL
1046 /* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */
1047 #undef CONFIG_VIDEO_400_HACK
1049 /* Hack that lets you force specific BIOS mode ID and specific dimensions */
1050 #undef CONFIG_VIDEO_GFX_HACK
1051 #define VIDEO_GFX_BIOS_AX 0x4f02 /* 800x600 on ThinkPad */
1052 #define VIDEO_GFX_BIOS_BX 0x0102
1053 #define VIDEO_GFX_DUMMY_RESOLUTION 0x6425 /* 100x37 */
1055 /* This code uses an extended set of video mode numbers. These include:
1056 * Aliases for standard modes
1060 * Video modes numbered by menu position -- NOT RECOMMENDED because of lack
1061 * of compatibility when extending the table. These are between 0x00 and 0xff.
1063 #define VIDEO_FIRST_MENU 0x0000
1065 /* Standard BIOS video modes (BIOS number + 0x0100) */
1066 #define VIDEO_FIRST_BIOS 0x0100
1068 /* VESA BIOS video modes (VESA number + 0x0200) */
1069 #define VIDEO_FIRST_VESA 0x0200
1071 /* Video7 special modes (BIOS number + 0x0900) */
1072 #define VIDEO_FIRST_V7 0x0900
1074 /* Special video modes */
1075 #define VIDEO_FIRST_SPECIAL 0x0f00
1076 #define VIDEO_80x25 0x0f00
1077 #define VIDEO_8POINT 0x0f01
1078 #define VIDEO_80x43 0x0f02
1079 #define VIDEO_80x28 0x0f03
1080 #define VIDEO_CURRENT_MODE 0x0f04
1081 #define VIDEO_80x30 0x0f05
1082 #define VIDEO_80x34 0x0f06
1083 #define VIDEO_80x60 0x0f07
1084 #define VIDEO_GFX_HACK 0x0f08
1085 #define VIDEO_LAST_SPECIAL 0x0f09
1087 /* Video modes given by resolution */
1088 #define VIDEO_FIRST_RESOLUTION 0x1000
1090 /* The "recalculate timings" flag */
1091 #define VIDEO_RECALC 0x8000
1093 /* Positions of various video parameters passed to the kernel */
1094 /* (see also include/linux/tty.h) */
1095 #define PARAM_CURSOR_POS 0x00
1096 #define PARAM_VIDEO_PAGE 0x04
1097 #define PARAM_VIDEO_MODE 0x06
1098 #define PARAM_VIDEO_COLS 0x07
1099 #define PARAM_VIDEO_EGA_BX 0x0a
1100 #define PARAM_VIDEO_LINES 0x0e
1101 #define PARAM_HAVE_VGA 0x0f
1102 #define PARAM_FONT_POINTS 0x10
1104 #define PARAM_LFB_WIDTH 0x12
1105 #define PARAM_LFB_HEIGHT 0x14
1106 #define PARAM_LFB_DEPTH 0x16
1107 #define PARAM_LFB_BASE 0x18
1108 #define PARAM_LFB_SIZE 0x1c
1109 #define PARAM_LFB_LINELENGTH 0x24
1110 #define PARAM_LFB_COLORS 0x26
1111 #define PARAM_VESAPM_SEG 0x2e
1112 #define PARAM_VESAPM_OFF 0x30
1113 #define PARAM_LFB_PAGES 0x32
1114 #define PARAM_VESA_ATTRIB 0x34
1116 /* Define DO_STORE according to CONFIG_VIDEO_RETAIN */
1117 #ifdef CONFIG_VIDEO_RETAIN
1118 #define DO_STORE call store_screen
1121 #endif /* CONFIG_VIDEO_RETAIN */
1123 # This is the main entry point called by setup.S
1124 # %ds *must* be pointing to the bootsector
1125 video: pushw %ds # We use different segments
1126 pushw %ds # FS contains original DS
1128 pushw %cs # DS is equal to CS
1130 pushw %cs # ES is equal to CS
1133 movw %ax, %gs # GS is zero
1135 call basic_detect # Basic adapter type testing (EGA/VGA/MDA/CGA)
1136 #ifdef CONFIG_VIDEO_SELECT
1137 movw %fs:(0x01fa), %ax # User selected video mode
1138 cmpw $ASK_VGA, %ax # Bring up the menu
1141 call mode_set # Set the mode
1144 leaw badmdt, %si # Invalid mode ID
1146 vid2: call mode_menu
1148 #ifdef CONFIG_VIDEO_RETAIN
1149 call restore_screen # Restore screen contents
1150 #endif /* CONFIG_VIDEO_RETAIN */
1152 #endif /* CONFIG_VIDEO_SELECT */
1153 call mode_params # Store mode parameters
1154 popw %ds # Restore original DS
1157 # Detect if we have CGA, MDA, EGA or VGA and pass it to the kernel.
1159 movb $0, %fs:(PARAM_HAVE_VGA)
1160 movb $0x12, %ah # Check EGA/VGA
1163 movw %bx, %fs:(PARAM_VIDEO_EGA_BX) # Identifies EGA to the kernel
1164 cmpb $0x10, %bl # No, it's a CGA/MDA/HGA card.
1168 movw $0x1a00, %ax # Check EGA or VGA?
1170 cmpb $0x1a, %al # 1a means VGA...
1171 jne basret # anything else is EGA.
1173 incb %fs:(PARAM_HAVE_VGA) # We've detected a VGA
1177 # Store the video mode parameters for later usage by the kernel.
1178 # This is done by asking the BIOS except for the rows/columns
1179 # parameters in the default 80x25 mode -- these are set directly,
1180 # because some very obscure BIOSes supply insane values.
1182 #ifdef CONFIG_VIDEO_SELECT
1183 cmpb $0, graphic_mode
1186 movb $0x03, %ah # Read cursor position
1189 movw %dx, %fs:(PARAM_CURSOR_POS)
1190 movb $0x0f, %ah # Read page/mode/width
1192 movw %bx, %fs:(PARAM_VIDEO_PAGE)
1193 movw %ax, %fs:(PARAM_VIDEO_MODE) # Video mode and screen width
1194 cmpb $0x7, %al # MDA/HGA => segment differs
1197 movw $0xb000, video_segment
1198 mopar0: movw %gs:(0x485), %ax # Font size
1199 movw %ax, %fs:(PARAM_FONT_POINTS) # (valid only on EGA/VGA)
1200 movw force_size, %ax # Forced size?
1204 movb %ah, %fs:(PARAM_VIDEO_COLS)
1205 movb %al, %fs:(PARAM_VIDEO_LINES)
1208 mopar1: movb $25, %al
1209 cmpb $0, adapter # If we are on CGA/MDA/HGA, the
1210 jz mopar2 # screen must have 25 lines.
1212 movb %gs:(0x484), %al # On EGA/VGA, use the EGA+ BIOS
1213 incb %al # location of max lines.
1214 mopar2: movb %al, %fs:(PARAM_VIDEO_LINES)
1217 #ifdef CONFIG_VIDEO_SELECT
1218 # Fetching of VESA frame buffer parameters
1220 leaw modelist+1024, %di
1221 movb $0x23, %fs:(PARAM_HAVE_VGA)
1223 movw %ax, %fs:(PARAM_LFB_LINELENGTH)
1225 movw %ax, %fs:(PARAM_LFB_WIDTH)
1227 movw %ax, %fs:(PARAM_LFB_HEIGHT)
1230 movw %ax, %fs:(PARAM_LFB_DEPTH)
1233 movw %ax, %fs:(PARAM_LFB_PAGES)
1235 movl %eax, %fs:(PARAM_LFB_BASE)
1237 movl %eax, %fs:(PARAM_LFB_COLORS)
1239 movl %eax, %fs:(PARAM_LFB_COLORS+4)
1241 movw %ax, %fs:(PARAM_VESA_ATTRIB)
1243 # get video mem size
1244 leaw modelist+1024, %di
1249 movl %eax, %fs:(PARAM_LFB_SIZE)
1251 # switching the DAC to 8-bit is for <= 8 bpp only
1252 movw %fs:(PARAM_LFB_DEPTH), %ax
1256 # get DAC switching capability
1262 # attempt to switch DAC to 8-bit
1268 movb %bh, dac_size # store actual DAC size
1271 # set color size to DAC size
1273 movb %al, %fs:(PARAM_LFB_COLORS+0)
1274 movb %al, %fs:(PARAM_LFB_COLORS+2)
1275 movb %al, %fs:(PARAM_LFB_COLORS+4)
1276 movb %al, %fs:(PARAM_LFB_COLORS+6)
1278 # set color offsets to 0
1279 movb $0, %fs:(PARAM_LFB_COLORS+1)
1280 movb $0, %fs:(PARAM_LFB_COLORS+3)
1281 movb $0, %fs:(PARAM_LFB_COLORS+5)
1282 movb $0, %fs:(PARAM_LFB_COLORS+7)
1285 # get protected mode interface informations
1293 movw %es, %fs:(PARAM_VESAPM_SEG)
1294 movw %di, %fs:(PARAM_VESAPM_OFF)
1297 # The video mode menu
1299 leaw keymsg, %si # "Return/Space/Timeout" message
1304 cmpb $0x0d, %al # ENTER ?
1305 je listm # yes - manual mode selection
1307 cmpb $0x20, %al # SPACE ?
1308 je defmd1 # no - repeat
1313 defmd1: ret # No mode chosen? Default 80x25
1315 listm: call mode_table # List mode table
1316 listm0: leaw name_bann, %si # Print adapter name
1337 leaw listhdr, %si # Table header
1339 movb $0x30, %dl # DL holds mode number
1341 lm1: cmpw $ASK_VGA, (%si) # End?
1344 movb %dl, %al # Menu selection number
1348 call prthw # Mode ID
1352 movb $0x78, %al # the letter 'x'
1355 call prtdec # Columns
1356 movb $0x0d, %al # New line
1360 incb %dl # Next character
1367 lm2: leaw prompt, %si # Mode prompt
1369 leaw edit_buf, %di # Editor buffer
1371 cmpb $0x0d, %al # Enter?
1374 cmpb $0x08, %al # Backspace?
1377 cmpb $0x20, %al # Printable?
1380 cmpw $edit_buf+4, %di # Enough space?
1387 lmbs: cmpw $edit_buf, %di # Backspace
1398 lment: movb $0, (%di)
1402 cmpb $0, (%si) # Empty string = default mode
1405 cmpb $0, 1(%si) # One character = menu selection
1408 cmpw $0x6373, (%si) # "scan" => mode scanning
1411 cmpw $0x6e61, 2(%si)
1414 lmhx: xorw %bx, %bx # Else => mode ID in hex
1437 lmuse1: movw %bx, %ax
1440 mnusel: lodsb # Menu selection
1448 cmpb $0x61-0x30, %al
1451 subb $0x61-0x30-10, %al
1455 lmuse: call mode_set
1458 lmbad: leaw unknt, %si
1461 lmscan: cmpb $0, adapter # Scanning only on EGA/VGA
1464 movw $0, mt_end # Scanning of modes is
1465 movb $1, scanning # done as new autodetection.
1470 # Additional parts of mode_set... (relative jumps, you know)
1471 setv7: # Video7 extended modes
1473 subb $VIDEO_FIRST_V7>>8, %bh
1479 _setrec: jmp setrec # Ugly...
1480 _set_80x25: jmp set_80x25
1482 # Aliases for backward compatibility.
1484 movw $VIDEO_80x25, %ax
1488 movb $VIDEO_8POINT-VIDEO_FIRST_SPECIAL, %al
1490 jnz setbad # Fall-through!
1492 # Setting of user mode (AX=mode ID) => CF=success
1494 movw %ax, %fs:(0x01fa) # Store mode for use in acpi_wakeup.S
1499 testb $VIDEO_RECALC>>8, %ah
1502 cmpb $VIDEO_FIRST_RESOLUTION>>8, %ah
1505 cmpb $VIDEO_FIRST_SPECIAL>>8, %ah
1508 cmpb $VIDEO_FIRST_V7>>8, %ah
1511 cmpb $VIDEO_FIRST_VESA>>8, %ah
1521 movb $0, do_restore # The screen needn't be restored
1526 subb $VIDEO_FIRST_VESA>>8, %bh
1527 movw $0x4f02, %ax # VESA BIOS mode set call
1529 cmpw $0x004f, %ax # AL=4f if implemented
1530 jnz setbad # AH=0 if OK
1537 int $0x10 # Standard BIOS mode set call
1539 movb $0x0f, %ah # Check if really set
1548 setspc: xorb %bh, %bh # Set special mode
1549 cmpb $VIDEO_LAST_SPECIAL-VIDEO_FIRST_SPECIAL, %bl
1553 jmp *spec_inits(%bx)
1556 orb %al, %al # 80x25 is an exception
1559 pushw %bx # Set mode chosen from menu
1560 call mode_table # Build the mode table
1567 movw (%si), %ax # Fetch mode ID
1570 setres: pushw %bx # Set mode chosen by resolution
1575 cmpw $ASK_VGA, %ax # End of the list?
1582 movw -4(%si), %ax # Fetch mode ID
1586 leaw modelist+1024, %di
1587 subb $VIDEO_FIRST_VESA>>8, %bh
1588 movw %bx, %cx # Get mode information structure
1591 addb $VIDEO_FIRST_VESA>>8, %bh
1595 movb (%di), %al # Check capabilities.
1598 jz setvesa # This is a text mode
1600 movb (%di), %al # Check capabilities.
1603 jnz _setbad # Doh! No linear frame buffer.
1605 subb $VIDEO_FIRST_VESA>>8, %bh
1606 orw $0x4000, %bx # Use linear frame buffer
1607 movw $0x4f02, %ax # VESA BIOS mode set call
1609 cmpw $0x004f, %ax # AL=4f if implemented
1610 jnz _setbad # AH=0 if OK
1612 movb $1, graphic_mode # flag graphic mode
1613 movb $0, do_restore # no screen restore
1617 _setbad: jmp setbad # Ugly...
1619 # Recalculate vertical display end registers -- this fixes various
1620 # inconsistencies of extended modes on many adapters. Called when
1621 # the VIDEO_RECALC flag is set in the mode ID.
1623 setrec: subb $VIDEO_RECALC>>8, %ah # Set the base mode
1627 movw %gs:(0x485), %ax # Font size in pixels
1628 movb %gs:(0x484), %bl # Number of rows
1630 mulb %bl # Number of visible
1631 decw %ax # scan lines - 1
1634 movb $0x12, %al # Lower 8 bits
1637 movb $0x07, %al # Bits 8 and 9 in the overflow register
1647 rct2: movb $0x07, %al
1652 # Table of routines for setting of the special modes.
1664 # Set the 80x25 mode. If already set, do nothing.
1666 movw $0x5019, force_size # Override possibly broken BIOS
1668 #ifdef CONFIG_VIDEO_400_HACK
1669 movw $0x1202, %ax # Force 400 scan lines
1673 movb $0x0f, %ah # Get current mode ID
1675 cmpw $0x5007, %ax # Mode 7 (80x25 mono) is the only one available
1676 jz st80 # on CGA/MDA/HGA and is also available on EGAM
1678 cmpw $0x5003, %ax # Unknown mode, force 80x25 color
1681 st80: cmpb $0, adapter # CGA/MDA/HGA => mode 3/7 is always 80x25
1684 movb %gs:(0x0484), %al # This is EGA+ -- beware of 80x50 etc.
1685 orb %al, %al # Some buggy BIOS'es set 0 rows
1688 cmpb $24, %al # It's hopefully correct
1690 #endif /* CONFIG_VIDEO_400_HACK */
1692 movw $0x0003, %ax # Forced set
1697 # Set the 80x50/80x43 8-pixel mode. Simple BIOS calls.
1700 call use_80x25 # The base is 80x25
1702 movw $0x1112, %ax # Use 8x8 font
1705 movw $0x1200, %ax # Use alternate print screen
1708 movw $0x1201, %ax # Turn off cursor emulation
1711 movb $0x01, %ah # Define cursor scan lines 6-7
1718 # Set the 80x28 mode. This mode works on all VGA's, because it's a standard
1719 # 80x25 mode with 14-point fonts instead of 16-point.
1722 call use_80x25 # The base is 80x25
1723 set14: movw $0x1111, %ax # Use 9x14 font
1726 movb $0x01, %ah # Define cursor scan lines 11-12
1732 # Set the 80x43 mode. This mode is works on all VGA's.
1733 # It's a 350-scanline mode with 8-pixel font.
1736 movw $0x1201, %ax # Set 350 scans
1739 movw $0x0003, %ax # Reset video mode
1741 jmp set_8pt # Use 8-pixel font
1743 # Set the 80x30 mode (all VGA's). 480 scanlines, 16-pixel font.
1745 call use_80x25 # Start with real 80x25
1747 movw $0x3cc, %dx # Get CRTC port
1750 rorb %al # Mono or color?
1754 set48a: movw $0x0c11, %ax # Vertical sync end (also unlocks CR0-7)
1756 movw $0x0b06, %ax # Vertical total
1758 movw $0x3e07, %ax # (Vertical) overflow
1760 movw $0xea10, %ax # Vertical sync start
1762 movw $0xdf12, %ax # Vertical display end
1764 movw $0xe715, %ax # Vertical blank start
1766 movw $0x0416, %ax # Vertical blank end
1769 movb $0xcc, %dl # Misc output register (read)
1771 movb $0xc2, %dl # (write)
1772 andb $0x0d, %al # Preserve clock select bits and color bit
1773 orb $0xe2, %al # Set correct sync polarity
1776 movw $0x501e, force_size
1780 # Set the 80x34 mode (all VGA's). 480 scans, 14-pixel font.
1782 call set_80x30 # Set 480 scans
1783 call set14 # And 14-pt font
1784 movw $0xdb12, %ax # VGA vertical display end
1785 movw $0x5022, force_size
1790 # Set the 80x60 mode (all VGA's). 480 scans, 8-pixel font.
1792 call set_80x30 # Set 480 scans
1793 call set_8pt # And 8-pt font
1794 movw $0xdf12, %ax # VGA vertical display end
1795 movw $0x503c, force_size
1798 # Special hack for ThinkPad graphics
1800 #ifdef CONFIG_VIDEO_GFX_HACK
1801 movw $VIDEO_GFX_BIOS_AX, %ax
1802 movw $VIDEO_GFX_BIOS_BX, %bx
1804 movw $VIDEO_GFX_DUMMY_RESOLUTION, force_size
1809 #ifdef CONFIG_VIDEO_RETAIN
1811 # Store screen contents to temporary buffer.
1813 cmpb $0, do_restore # Already stored?
1816 testb $CAN_USE_HEAP, loadflags # Have we space for storing?
1821 pushw force_size # Don't force specific size
1823 call mode_params # Obtain params of current mode
1825 movb %fs:(PARAM_VIDEO_LINES), %ah
1826 movb %fs:(PARAM_VIDEO_COLS), %al
1827 movw %ax, %bx # BX=dimensions
1829 movw %ax, %cx # CX=number of characters
1830 addw %ax, %ax # Calculate image size
1831 addw $modelist+1024+4, %ax
1832 cmpw heap_end_ptr, %ax
1833 jnc sts1 # Unfortunately, out of memory
1835 movw %fs:(PARAM_CURSOR_POS), %ax # Store mode params
1836 leaw modelist+1024, %di
1840 pushw %ds # Store the screen
1841 movw video_segment, %ds
1846 incb do_restore # Screen will be restored later
1851 # Restore screen contents from temporary buffer.
1853 cmpb $0, do_restore # Has the screen been stored?
1856 call mode_params # Get parameters of current mode
1857 movb %fs:(PARAM_VIDEO_LINES), %cl
1858 movb %fs:(PARAM_VIDEO_COLS), %ch
1859 leaw modelist+1024, %si # Screen buffer
1860 lodsw # Set cursor position
1872 res3: movb $0x02, %ah
1875 lodsw # Display size
1876 movb %ah, %dl # DL=number of lines
1877 movb $0, %ah # BX=phys. length of orig. line
1879 cmpb %cl, %dl # Too many?
1890 res4: cmpb %ch, %al # Too wide?
1893 movb %ch, %al # AX=width of src. line
1896 movw %cx, %bp # BP=width of dest. line
1898 movw video_segment, %es
1899 xorw %di, %di # Move the data
1900 addw %bx, %bx # Convert BX and BP to _bytes_
1916 #endif /* CONFIG_VIDEO_RETAIN */
1918 # Write to indexed VGA register (AL=index, AH=data, DX=index reg. port)
1919 outidx: outb %al, %dx
1928 # Build the table of video modes (stored after the setup.S code at the
1929 # `modelist' label. Each video mode record looks like:
1930 # .word MODE-ID (our special mode ID (see above))
1931 # .byte rows (number of rows)
1932 # .byte columns (number of columns)
1933 # Returns address of the end of the table in DI, the end is marked
1934 # with a ASK_VGA ID.
1936 movw mt_end, %di # Already filled?
1940 leaw modelist, %di # Store standard modes:
1941 movl $VIDEO_80x25 + 0x50190000, %eax # The 80x25 mode (ALL)
1943 movb adapter, %al # CGA/MDA/HGA -- no more modes
1950 movl $VIDEO_8POINT + 0x502b0000, %eax # The 80x43 EGA mode
1956 mtabv: leaw vga_modes, %si # All modes for std VGA
1957 movw $vga_modes_end-vga_modes, %cx
1958 rep # I'm unable to use movsw as I don't know how to store a half
1959 movsb # of the expression above to cx without using explicit shr.
1961 cmpb $0, scanning # Mode scan requested?
1967 #ifdef CONFIG_VIDEO_LOCAL
1969 #endif /* CONFIG_VIDEO_LOCAL */
1971 #ifdef CONFIG_VIDEO_VESA
1972 call vesa_modes # Detect VESA VGA modes
1973 #endif /* CONFIG_VIDEO_VESA */
1975 #ifdef CONFIG_VIDEO_SVGA
1976 cmpb $0, scanning # Bypass when scanning
1979 call svga_modes # Detect SVGA cards & modes
1981 #endif /* CONFIG_VIDEO_SVGA */
1985 #ifdef CONFIG_VIDEO_COMPACT
1989 cmt1: cmpw %dx, %si # Scan all modes
1992 leaw modelist, %bx # Find in previous entries
1997 cmpw 2(%bx), %cx # Found => don't copy this entry
2003 cmt4: movsl # Copy entry
2006 cmt5: addw $4, %si # Skip entry
2010 #endif /* CONFIG_VIDEO_COMPACT */
2012 movw $ASK_VGA, (%di) # End marker
2014 mtab1: leaw modelist, %si # SI=mode list, DI=list end
2017 # Modes usable on all standard VGAs
2020 .word 0x5032 # 80x50
2022 .word 0x502b # 80x43
2024 .word 0x501c # 80x28
2026 .word 0x501e # 80x30
2028 .word 0x5022 # 80x34
2030 .word 0x503c # 80x60
2031 #ifdef CONFIG_VIDEO_GFX_HACK
2032 .word VIDEO_GFX_HACK
2033 .word VIDEO_GFX_DUMMY_RESOLUTION
2037 # Detect VESA modes.
2039 #ifdef CONFIG_VIDEO_VESA
2041 cmpb $2, adapter # VGA only
2044 movw %di, %bp # BP=original mode table end
2045 addw $0x200, %di # Buffer space
2046 movw $0x4f00, %ax # VESA Get card info call
2049 cmpw $0x004f, %ax # Successful?
2052 cmpw $0x4556, 0x200(%di)
2055 cmpw $0x4153, 0x202(%di)
2058 movw $vesa_name, card_name # Set name to "VESA VGA"
2060 lgsw 0x20e(%di), %si # GS:SI=mode list
2061 movw $128, %cx # Iteration limit
2063 # gas version 2.9.1, using BFD version 2.9.1.0.23 buggers the next inst.
2064 # XXX: lodsw %gs:(%si), %ax # Get next mode in the list
2066 cmpw $0xffff, %ax # End of the table?
2069 cmpw $0x0080, %ax # Check validity of mode ID
2072 orb %ah, %ah # Valid IDs: 0x0000-0x007f/0x0100-0x07ff
2073 jz vesan # Certain BIOSes report 0x80-0xff!
2079 movw %ax, %cx # Get mode information structure
2082 movw %cx, %bx # BX=mode number
2083 addb $VIDEO_FIRST_VESA>>8, %bh
2086 jnz vesan # Don't report errors (buggy BIOSES)
2088 movb (%di), %al # Check capabilities. We require
2089 andb $0x19, %al # a color text mode.
2093 cmpw $0xb800, 8(%di) # Standard video memory address required
2096 testb $2, (%di) # Mode characteristics supplied?
2097 movw %bx, (%di) # Store mode number
2101 movw 0x12(%di), %bx # Width
2106 movw 0x14(%di), %ax # Height
2112 cmpw $8193, %ax # Small enough for Linux console driver?
2117 vesa3: subw $0x8108, %bx # This mode has no detailed info specified,
2118 jc vesan # so it must be a standard VESA mode.
2123 movw vesa_text_mode_table(%bx), %ax
2125 vesaok: addw $4, %di # The mode is valid. Store it.
2126 vesan: loop vesa1 # Next mode. Limit exceeded => error
2127 vesae: leaw vesaer, %si
2129 movw %bp, %di # Discard already found modes.
2133 # Dimensions of standard VESA text modes
2134 vesa_text_mode_table:
2136 .byte 25, 132 # 0109
2137 .byte 43, 132 # 010A
2138 .byte 50, 132 # 010B
2139 .byte 60, 132 # 010C
2140 #endif /* CONFIG_VIDEO_VESA */
2142 # Scan for video modes. A bit dirty, but should work.
2144 movw $0x0100, %cx # Start with mode 0
2145 scm1: movb $0, %ah # Test the mode
2151 jnz scm2 # Mode not set
2153 movw $0x3c0, %dx # Test if it's a text mode
2154 movb $0x10, %al # Mode bits
2159 movb $0xce, %dl # Another set of mode bits
2165 movb $0xd4, %dl # Cursor location
2171 movw %cx, %ax # Ok, store the mode
2173 movb %gs:(0x484), %al # Number of rows
2176 movw %gs:(0x44a), %ax # Number of columns
2181 movw $0x0003, %ax # Return back to mode 3
2185 tstidx: outw %ax, %dx # OUT DX,AX and inidx
2186 inidx: outb %al, %dx # Read from indexed VGA register
2187 incw %dx # AL=index, DX=index reg port -> AL=data
2192 # Try to detect type of SVGA card and supply (usually approximate) video
2193 # mode table for it.
2195 #ifdef CONFIG_VIDEO_SVGA
2197 leaw svga_table, %si # Test all known SVGA adapters
2199 movw %ax, %bp # Default mode table
2203 lodsw # Pointer to test routine
2209 call *%ax # Call test routine
2216 movw %bp, %si # Found, copy the modes
2217 movb svga_prefix, %ah
2226 didsv: movw %si, card_name # Store pointer to card name
2229 # Table of all known SVGA cards. For each card, we store a pointer to
2230 # a table of video modes supported by the card and a pointer to a routine
2231 # used for testing of presence of the card. The video mode table is always
2232 # followed by the name of the card or the chipset.
2234 .word ati_md, ati_test
2235 .word oak_md, oak_test
2236 .word paradise_md, paradise_test
2237 .word realtek_md, realtek_test
2238 .word s3_md, s3_test
2239 .word chips_md, chips_test
2240 .word video7_md, video7_test
2241 .word cirrus5_md, cirrus5_test
2242 .word cirrus6_md, cirrus6_test
2243 .word cirrus1_md, cirrus1_test
2244 .word ahead_md, ahead_test
2245 .word everex_md, everex_test
2246 .word genoa_md, genoa_test
2247 .word trident_md, trident_test
2248 .word tseng_md, tseng_test
2251 # Test routines and mode tables:
2253 # S3 - The test algorithm was taken from the SuperProbe package
2254 # for XFree86 1.2.1. Report bugs to Christoph.Niemann@linux.org
2256 movw $0x0f35, %cx # we store some constants in cl/ch
2260 movb %al, %bh # store current CRT-register 0x38
2262 call outidx # disable writing to special regs
2263 movb %cl, %al # check whether we can write special reg 0x35
2265 movb %al, %bl # save the current value of CRT reg 0x35
2266 andb $0xf0, %al # clear bits 0-3
2268 movb %cl, %al # and write it to CRT reg 0x35
2270 call inidx # now read it back
2271 andb %ch, %al # clear the upper 4 bits
2272 jz s3_2 # the first test failed. But we have a
2274 movb %bl, %ah # second chance
2277 jmp s3_1 # do the other tests
2279 s3_2: movw %cx, %ax # load ah with 0xf and al with 0x35
2280 orb %bl, %ah # set the upper 4 bits of ah with the orig value
2281 call outidx # write ...
2282 call inidx # ... and reread
2283 andb %cl, %al # turn off the upper 4 bits
2285 movb %bl, %ah # restore old value in register 0x35
2289 cmpb %ch, %al # setting lower 4 bits was successful => bad
2290 je no_s3 # writing is allowed => this is not an S3
2292 s3_1: movw $0x4838, %ax # allow writing to special regs by putting
2293 call outidx # magic number into CRT-register 0x38
2294 movb %cl, %al # check whether we can write special reg 0x35
2303 jnz no_s3 # no, we can't write => no S3
2311 movb %bl, %ah # restore old value in register 0x35
2316 jne no_s31 # writing not possible => no S3
2318 call inidx # now get the S3 id ...
2329 no_s3: movb $0x35, %al # restore CRT register 0x35
2332 no_s31: xorw %bp, %bp # Detection failed
2333 s3rest: movb %bh, %ah
2334 movb $0x38, %al # restore old value of CRT register 0x38
2337 idS3: .byte 0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95
2338 .byte 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0
2340 s3_md: .byte 0x54, 0x2b, 0x84
2341 .byte 0x55, 0x19, 0x84
2358 idati: .ascii "761295520"
2360 ati_md: .byte 0x23, 0x19, 0x84
2361 .byte 0x33, 0x2c, 0x84
2362 .byte 0x22, 0x1e, 0x64
2363 .byte 0x21, 0x19, 0x64
2364 .byte 0x58, 0x21, 0x50
2365 .byte 0x5b, 0x1e, 0x50
2387 .byte 0x22, 0x2c, 0x84
2388 .byte 0x23, 0x19, 0x84
2389 .byte 0x24, 0x1c, 0x84
2390 .byte 0x2f, 0x32, 0xa0
2391 .byte 0x32, 0x22, 0x50
2392 .byte 0x34, 0x42, 0x50
2417 .byte 0x60, 0x19, 0x84
2418 .byte 0x61, 0x32, 0x84
2420 .ascii "Chips & Technologies"
2461 nocirr: xorw %bp, %bp
2462 iscirr: movw $0x3d4, %dx
2471 .byte 0x1f, 0x19, 0x84
2472 .byte 0x20, 0x2c, 0x84
2473 .byte 0x22, 0x1e, 0x84
2474 .byte 0x31, 0x25, 0x64
2476 .ascii "Cirrus Logic 5X0"
2484 movb %al, %bl # BL=backup
2518 c5fail: xorw %bp, %bp
2519 c5done: movb $6, %al
2525 .byte 0x14, 0x19, 0x84
2526 .byte 0x54, 0x2b, 0x84
2528 .ascii "Cirrus Logic 54XX"
2531 # Cirrus Logic 64XX -- no known extra modes, but must be identified, because
2532 # it's misidentified by the Ahead test.
2537 movb %al, %bl # BL=backup
2549 call inidx # 4X, 5X, 7X and 8X are valid 64XX chip ID's.
2563 c2fail: xorw %bp, %bp
2564 c6done: movb $0x0a, %al
2571 .ascii "Cirrus Logic 64XX"
2589 evtrid: leaw trident_md, %bp
2592 noevrx: xorw %bp, %bp
2596 .byte 0x03, 0x22, 0x50
2597 .byte 0x04, 0x3c, 0x50
2598 .byte 0x07, 0x2b, 0x64
2599 .byte 0x08, 0x4b, 0x64
2600 .byte 0x0a, 0x19, 0x84
2601 .byte 0x0b, 0x2c, 0x84
2602 .byte 0x16, 0x1e, 0x50
2603 .byte 0x18, 0x1b, 0x64
2604 .byte 0x21, 0x40, 0xa0
2605 .byte 0x40, 0x1e, 0x84
2607 .ascii "Everex/Trident"
2612 leaw idgenoa, %si # Check Genoa 'clues'
2614 movb %es:(0x37), %al
2633 idgenoa: .byte 0x77, 0x00, 0x99, 0x66
2636 .byte 0x58, 0x20, 0x50
2637 .byte 0x5a, 0x2a, 0x64
2638 .byte 0x60, 0x19, 0x84
2639 .byte 0x61, 0x1d, 0x84
2640 .byte 0x62, 0x20, 0x84
2641 .byte 0x63, 0x2c, 0x84
2642 .byte 0x64, 0x3c, 0x84
2643 .byte 0x6b, 0x4f, 0x64
2644 .byte 0x72, 0x3c, 0x50
2645 .byte 0x74, 0x42, 0x50
2646 .byte 0x78, 0x4b, 0x64
2663 idoakvga: .ascii "OAK VGA "
2665 oak_md: .byte 0x4e, 0x3c, 0x50
2666 .byte 0x4f, 0x3c, 0x84
2667 .byte 0x50, 0x19, 0x84
2668 .byte 0x51, 0x2b, 0x84
2675 leaw idparadise, %si
2685 idparadise: .ascii "VGA="
2688 .byte 0x41, 0x22, 0x50
2689 .byte 0x47, 0x1c, 0x84
2690 .byte 0x55, 0x19, 0x84
2691 .byte 0x54, 0x2c, 0x84
2708 movb %al, %bl # Strange thing ... in the book this wasn't
2709 andb $0x02, %bl # necessary but it worked on my card which
2710 jz setb2 # is a trident. Without it the screen goes
2715 setb2: orb $0x02, %al
2716 clrb2: outb %al, %dx
2725 .byte 0x50, 0x1e, 0x50
2726 .byte 0x51, 0x2b, 0x50
2727 .byte 0x52, 0x3c, 0x50
2728 .byte 0x57, 0x19, 0x84
2729 .byte 0x58, 0x1e, 0x84
2730 .byte 0x59, 0x2b, 0x84
2731 .byte 0x5a, 0x3c, 0x84
2739 inb %dx, %al # Could things be this simple ! :-)
2750 isnot: xorw %bp, %bp
2754 .byte 0x26, 0x3c, 0x50
2755 .byte 0x2a, 0x28, 0x64
2756 .byte 0x23, 0x19, 0x84
2757 .byte 0x24, 0x1c, 0x84
2758 .byte 0x22, 0x2c, 0x84
2759 .byte 0x21, 0x3c, 0x84
2773 even7: movb $0x0c, %al
2798 movb $VIDEO_FIRST_V7>>8, svga_prefix # Use special mode switching
2802 .byte 0x40, 0x2b, 0x50
2803 .byte 0x43, 0x3c, 0x50
2804 .byte 0x44, 0x3c, 0x64
2805 .byte 0x41, 0x19, 0x84
2806 .byte 0x42, 0x2c, 0x84
2807 .byte 0x45, 0x1c, 0x84
2824 idrtvga: .ascii "REALTEK VGA"
2827 .byte 0x1a, 0x3c, 0x50
2828 .byte 0x1b, 0x19, 0x84
2829 .byte 0x1c, 0x1e, 0x84
2830 .byte 0x1d, 0x2b, 0x84
2831 .byte 0x1e, 0x3c, 0x84
2836 #endif /* CONFIG_VIDEO_SVGA */
2838 # User-defined local mode table (VGA only)
2839 #ifdef CONFIG_VIDEO_LOCAL
2841 leaw local_mode_table, %si
2852 # This is the table of local video modes which can be supplied manually
2853 # by the user. Each entry consists of mode ID (word) and dimensions
2854 # (byte for column count and another byte for row count). These modes
2855 # are placed before all SVGA and VESA modes and override them if table
2856 # compacting is enabled. The table must end with a zero word followed
2857 # by NUL-terminated video adapter name.
2859 .word 0x0100 # Example: 40x25
2864 #endif /* CONFIG_VIDEO_LOCAL */
2866 # Read a key and return the ASCII code in al, scan code in ah
2867 getkey: xorb %ah, %ah
2871 # Read a key with a timeout of 30 seconds.
2872 # The hardware clock is used to get the time.
2874 addb $30, %al # Wait 30 seconds
2881 again: movb $0x01, %ah
2883 jnz getkey # key pressed, so get it
2889 movb $0x20, %al # timeout, return `space'
2892 # Flush the keyboard buffer
2893 flush: movb $0x01, %ah
2903 # Print hexadecimal number.
2913 prthn: cmpb $0x0a, %al
2917 prth1: addb $0x30, %al
2920 # Print decimal number in al
2932 lt100: addb $0x30, %al
2934 skip10: movb %ah, %al
2942 pushw %es # just save all registers
2952 movl $0x13131313, %eax # memset block with 0x13
2959 movw $0x4f15, %ax # do VBE/DDC
2966 popw %di # restore all registers
2974 # VIDEO_SELECT-only variables
2975 mt_end: .word 0 # End of video mode table if built
2976 edit_buf: .space 6 # Line editor buffer
2977 card_name: .word 0 # Pointer to adapter name
2978 scanning: .byte 0 # Performing mode scan
2979 do_restore: .byte 0 # Screen contents altered during mode change
2980 svga_prefix: .byte VIDEO_FIRST_BIOS>>8 # Default prefix for BIOS modes
2981 graphic_mode: .byte 0 # Graphic mode with a linear frame buffer
2982 dac_size: .byte 6 # DAC bit depth
2985 keymsg: .ascii "Press <RETURN> to see video modes available, "
2986 .ascii "<SPACE> to continue or wait 30 secs"
2989 listhdr: .byte 0x0d, 0x0a
2990 .ascii "Mode: COLSxROWS:"
2992 crlft: .byte 0x0d, 0x0a, 0
2994 prompt: .byte 0x0d, 0x0a
2995 .asciz "Enter mode number or `scan': "
2997 unknt: .asciz "Unknown mode ID. Try again."
2999 badmdt: .ascii "You passed an undefined mode number."
3002 vesaer: .ascii "Error: Scanning of VESA modes failed. Please "
3003 .ascii "report to <mj@ucw.cz>."
3006 old_name: .asciz "CGA/MDA/HGA"
3008 ega_name: .asciz "EGA"
3010 svga_name: .ascii " "
3012 vga_name: .asciz "VGA"
3014 vesa_name: .asciz "VESA"
3016 name_bann: .asciz "Video adapter: "
3017 #endif /* CONFIG_VIDEO_SELECT */
3020 adapter: .byte 0 # Video adapter: 0=CGA/MDA/HGA,1=EGA,2=VGA
3021 video_segment: .word 0xb800 # Video memory segment
3022 force_size: .word 0 # Use this size instead of the one in BIOS vars
3024 # Setup signature -- must be last
3025 setup_sig1: .word SIG1
3026 setup_sig2: .word SIG2
3028 # After this point, there is some free space which is used by the video mode
3029 # handling code to store the temporary mode table (not used by the kernel).