]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/bootstrap/server/src/ARCH-x86/setup.S
update
[l4.git] / l4 / pkg / bootstrap / server / src / ARCH-x86 / setup.S
1 /*
2  *      setup.S         Copyright (C) 1991, 1992 Linus Torvalds
3  *
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.
7  *
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
12  * for buffer-blocks.
13  *
14  * Move PS/2 aux init code to psaux.c
15  * (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92
16  *
17  * some changes and additional features by Christoph Niemann,
18  * March 1993/June 1994 (Christoph.Niemann@linux.org)
19  *
20  * add APM BIOS checking by Stephen Rothwell, May 1994
21  * (sfr@canb.auug.org.au)
22  *
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>
26  *
27  * Video handling moved to video.S by Martin Mares, March 1996
28  * <mj@k332.feld.cvut.cz>
29  *
30  * Extended memory detection scheme retwiddled by orc@pell.chi.il.us (david
31  * parsons) to avoid loadlin confusion, July 1997
32  *
33  * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999.
34  * <stiker@northlink.com>
35  *
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>
44  *
45  * New A20 code ported from SYSLINUX by H. Peter Anvin. AMD Elan bugfixes
46  * by Robert Schwebel, December 2001 <robert@schwebel.de>
47  */
48
49 #define __BIG_KERNEL__ 1
50
51 //#include <linux/config.h>
52 //#include <asm/segment.h>
53 //#include <asm/boot.h>
54
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
60
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 */
65
66
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 */
71
72 #define E820_RAM        1
73 #define E820_RESERVED   2
74 #define E820_ACPI       3 /* usable as RAM once ACPI tables have been read
75 */
76 #define E820_NVS        4
77
78 #define HIGH_MEMORY     (1024*1024)
79
80 //#include <asm/page.h>
81         
82 /* Signature words to ensure LILO loaded us right */
83 #define SIG1    0xAA55
84 #define SIG2    0x5A5A
85
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
90
91 DELTA_INITSEG = SETUPSEG - INITSEG      # 0x0020
92
93 .code16
94 .globl begtext, begdata, begbss, endtext, enddata, endbss
95
96 .text
97 begtext:
98 .data
99 begdata:
100 .bss
101 begbss:
102 .text
103
104 start:
105         jmp     trampoline
106
107 # This is the setup header, and it must start at %cs:2 (old 0x9020:2)
108
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
117                                         # change it.
118
119 type_of_loader: .byte   0               # = 0, old one (LILO, Loadlin,
120                                         #      Bootlin, SYSLX, bootsect...)
121                                         # See Documentation/i386/boot.txt for
122                                         # assigned ids
123         
124 # flags, unused bits must be zero (RFU) bit within loadflags
125 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
130                                         # heap purposes.
131                                         # Only the loader knows what is free
132 #ifndef __BIG_KERNEL__
133                 .byte   0
134 #else
135                 .byte   LOADED_HIGH
136 #endif
137
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.
144
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
149 #else
150                 .long   0x100000        # 0x100000 = default for big kernel
151 #endif
152
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.
157
158 ramdisk_size:   .long   0               # its size in bytes
159
160 bootsect_kludge:
161                 .long   0               # obsolete
162
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.
167
168 pad1:           .word   0
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.
183
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
188
189 trampoline:     call    start_of_setup
190                 .align 16
191                                         # The offset at this point is 0x240
192                 .space  (0x7ff-0x240+1) # E820 & EDD space (ending at 0x7ff)
193 # End of setup header #####################################################
194
195 start_of_setup:
196 # Bootlin depends on this being done early
197         movw    $0x01500, %ax
198         movb    $0x81, %dl
199         int     $0x13
200
201 #ifdef SAFE_RESET_DISK_CONTROLLER
202 # Reset the disk controller.
203         movw    $0x0000, %ax
204         movb    $0x80, %dl
205         int     $0x13
206 #endif
207
208 # Set %ds = %cs, we know that SETUPSEG = %cs at this point
209         movw    %cs, %ax                # aka SETUPSEG
210         movw    %ax, %ds
211 # Check signature at end of setup
212         cmpw    $SIG1, setup_sig1
213         jne     bad_sig
214
215         cmpw    $SIG2, setup_sig2
216         jne     bad_sig
217
218         jmp     good_sig1
219
220 # Routine to print asciiz string at ds:si
221 prtstr:
222         lodsb
223         andb    %al, %al
224         jz      fin
225
226         call    prtchr
227         jmp     prtstr
228
229 fin:    ret
230
231 # Space printing
232 prtsp2: call    prtspc          # Print double space
233 prtspc: movb    $0x20, %al      # Print single space (note: fall-thru)
234
235 # Part of above routine, this one just prints ascii al
236 prtchr: pushw   %ax
237         pushw   %cx
238         movw    $7,%bx
239         movw    $0x01, %cx
240         movb    $0x0e, %ah
241         int     $0x10
242         popw    %cx
243         popw    %ax
244         ret
245
246 beep:   movb    $0x07, %al
247         jmp     prtchr
248         
249 no_sig_mess: .string    "No setup signature found ..."
250
251 good_sig1:
252         jmp     good_sig
253
254 # We now have to find the rest of the setup code/data
255 bad_sig:
256         movw    %cs, %ax                        # SETUPSEG
257         subw    $DELTA_INITSEG, %ax             # INITSEG
258         movw    %ax, %ds
259         xorb    %bh, %bh
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)
263         movw    %bx, %cx
264         shrw    $3, %bx                         # convert to segment
265         addw    $SYSSEG, %bx
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
269         subw    %si, %si
270         pushw   %cs
271         popw    %es
272         movw    $SYSSEG, %ax
273         movw    %ax, %ds
274         rep
275         movsw
276         movw    %cs, %ax                        # aka SETUPSEG
277         movw    %ax, %ds
278         cmpw    $SIG1, setup_sig1
279         jne     no_sig
280
281         cmpw    $SIG2, setup_sig2
282         jne     no_sig
283
284         jmp     good_sig
285
286 no_sig:
287         lea     no_sig_mess, %si
288         call    prtstr
289
290 no_sig_loop:
291         hlt
292         jmp     no_sig_loop
293
294 good_sig:
295         movw    %cs, %ax                        # aka SETUPSEG
296         subw    $DELTA_INITSEG, %ax             # aka INITSEG
297         movw    %ax, %ds
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.
301
302         cmpb    $0, %cs:type_of_loader          # Do we have a loader that
303                                                 # can deal with us?
304         jnz     loader_ok                       # Yes, continue.
305
306         pushw   %cs                             # No, we have an old loader,
307         popw    %ds                             # die. 
308         lea     loader_panic_mess, %si
309         call    prtstr
310
311         jmp     no_sig_loop
312
313 loader_panic_mess: .string "Wrong loader, giving up..."
314
315 loader_ok:
316 # Get memory size (extended mem, kB)
317
318         xorl    %eax, %eax
319         movl    %eax, (0x1e0)
320 #ifndef STANDARD_MEMORY_BIOS_CALL
321         movb    %al, (E820NR)
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
325 # returns 0-64m
326
327 # method E820H:
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.
333
334 #define SMAP  0x534d4150
335
336 meme820:
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.
341
342 jmpe820:
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.
347         popw    %es
348         int     $0x15                           # make the call
349         jc      bail820                         # fall to e801 if it fails
350
351         cmpl    $SMAP, %eax                     # check the return is `SMAP'
352         jne     bail820                         # fall to e801 if it fails
353
354 #       cmpl    $1, 16(%di)                     # is this usable memory?
355 #       jne     again820
356
357         # If this is usable memory, we save it by simply advancing %di by
358         # sizeof(e820rec).
359         #
360 good820:
361         movb    (E820NR), %al                   # up to 32 entries
362         cmpb    $E820MAX, %al
363         jnl     bail820
364
365         incb    (E820NR)
366         movw    %di, %ax
367         addw    $20, %ax
368         movw    %ax, %di
369 again820:
370         cmpl    $0, %ebx                        # check to see if
371         jne     jmpe820                         # %ebx is set to EOF
372 bail820:
373
374
375 # method E801H:
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.)
382
383 meme801:
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.
390         movw    $0xe801, %ax
391         int     $0x15
392         jc      mem88
393
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...
400
401 e801usecxdx:
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
407                                                 # total size.
408
409 # Ye Olde Traditional Methode.  Returns the memory size (up to 16mb or
410 # 64mb, depending on the bios) in ax.
411 mem88:
412
413 #endif
414         movb    $0x88, %ah
415         int     $0x15
416         movw    %ax, (2)
417
418 # Set the keyboard repeat rate to the max
419         movw    $0x0305, %ax
420         xorw    %bx, %bx
421         int     $0x16
422
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
426                                                 # to bootsector
427
428 # Get hd0 data...
429         xorw    %ax, %ax
430         movw    %ax, %ds
431         ldsw    (4 * 0x41), %si
432         movw    %cs, %ax                        # aka SETUPSEG
433         subw    $DELTA_INITSEG, %ax             # aka INITSEG
434         pushw   %ax
435         movw    %ax, %es
436         movw    $0x0080, %di
437         movw    $0x10, %cx
438         pushw   %cx
439         cld
440         rep
441         movsb
442 # Get hd1 data...
443         xorw    %ax, %ax
444         movw    %ax, %ds
445         ldsw    (4 * 0x46), %si
446         popw    %cx
447         popw    %es
448         movw    $0x0090, %di
449         rep
450         movsb
451 # Check that there IS a hd1 :-)
452         movw    $0x01500, %ax
453         movb    $0x81, %dl
454         int     $0x13
455         jc      no_disk1
456         
457         cmpb    $3, %ah
458         je      is_disk1
459
460 no_disk1:
461         movw    %cs, %ax                        # aka SETUPSEG
462         subw    $DELTA_INITSEG, %ax             # aka INITSEG
463         movw    %ax, %es
464         movw    $0x0090, %di
465         movw    $0x10, %cx
466         xorw    %ax, %ax
467         cld
468         rep
469         stosb
470 is_disk1:
471 # check for Micro Channel (MCA) bus
472         movw    %cs, %ax                        # aka SETUPSEG
473         subw    $DELTA_INITSEG, %ax             # aka INITSEG
474         movw    %ax, %ds
475         xorw    %ax, %ax
476         movw    %ax, (0xa0)                     # set table length to 0
477         movb    $0xc0, %ah
478         stc
479         int     $0x15                           # moves feature table to es:bx
480         jc      no_mca
481
482         pushw   %ds
483         movw    %es, %ax
484         movw    %ax, %ds
485         movw    %cs, %ax                        # aka SETUPSEG
486         subw    $DELTA_INITSEG, %ax             # aka INITSEG
487         movw    %ax, %es
488         movw    %bx, %si
489         movw    $0xa0, %di
490         movw    (%si), %cx
491         addw    $2, %cx                         # table length is a short
492         cmpw    $0x10, %cx
493         jc      sysdesc_ok
494
495         movw    $0x10, %cx                      # we keep only first 16 bytes
496 sysdesc_ok:
497         rep
498         movsb
499         popw    %ds
500 no_mca:
501 #ifdef CONFIG_X86_VOYAGER
502         movb    $0xff, 0x40     # flag on config found
503         movb    $0xc0, %al
504         mov     $0xff, %ah
505         int     $0x15           # put voyager config info at es:di
506         jc      no_voyager
507         movw    $0x40, %si      # place voyager info in apm table
508         cld
509         movw    $7, %cx
510 voyager_rep:
511         movb    %es:(%di), %al
512         movb    %al,(%si)
513         incw    %di
514         incw    %si
515         decw    %cx
516         jnz     voyager_rep
517 no_voyager:     
518 #endif
519 # Check for PS/2 pointing device
520         movw    %cs, %ax                        # aka SETUPSEG
521         subw    $DELTA_INITSEG, %ax             # aka INITSEG
522         movw    %ax, %ds
523         movw    $0, (0x1ff)                     # default is no pointing device
524         int     $0x11                           # int 0x11: equipment list
525         testb   $0x04, %al                      # check if mouse installed
526         jz      no_psmouse
527
528         movw    $0xAA, (0x1ff)                  # device present
529 no_psmouse:
530
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
534         int     $0x15
535
536         movl    %eax, (96)
537         movl    %ebx, (100)
538         movl    %ecx, (104)
539         movl    %edx, (108)
540 #endif
541
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
547         xorw    %bx, %bx
548         int     $0x15
549         jc      done_apm_bios                   # Nope, no APM BIOS
550         
551         cmpw    $0x0504d, %bx                   # Check for "PM" signature
552         jne     done_apm_bios                   # No signature, no APM BIOS
553
554         andw    $0x02, %cx                      # Is 32 bit supported?
555         je      done_apm_bios                   # No 32-bit, no (good) APM BIOS
556
557         movw    $0x05304, %ax                   # Disconnect first just in case
558         xorw    %bx, %bx
559         int     $0x15                           # ignore return code
560         movw    $0x05303, %ax                   # 32 bit connect
561         xorl    %ebx, %ebx
562         xorw    %cx, %cx                        # paranoia :-)
563         xorw    %dx, %dx                        #   ...
564         xorl    %esi, %esi                      #   ...
565         xorw    %di, %di                        #   ...
566         int     $0x15
567         jc      no_32_apm_bios                  # Ack, error. 
568
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
578         xorw    %bx, %bx
579         xorw    %cx, %cx                        # paranoia
580         int     $0x15
581         jc      apm_disconnect                  # error -> shouldn't happen
582
583         cmpw    $0x0504d, %bx                   # check for "PM" signature
584         jne     apm_disconnect                  # no sig -> shouldn't happen
585
586         movw    %ax, (64)                       # record the APM BIOS version
587         movw    %cx, (76)                       # and flags
588         jmp     done_apm_bios
589
590 apm_disconnect:                                 # Tidy up
591         movw    $0x05304, %ax                   # Disconnect
592         xorw    %bx, %bx
593         int     $0x15                           # ignore return code
594
595         jmp     done_apm_bios
596
597 no_32_apm_bios:
598         andw    $0xfffd, (76)                   # remove 32 bit support bit
599 done_apm_bios:
600 #endif
601
602 //#include "edd.S"
603
604 # Now we want to move to protected mode ...
605         cmpw    $0, %cs:realmode_swtch
606         jz      rmodeswtch_normal
607
608         lcall   *%cs:realmode_swtch
609
610         jmp     rmodeswtch_end
611
612 rmodeswtch_normal:
613         pushw   %cs
614         call    default_switch
615
616 rmodeswtch_end:
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
621
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
626                                                 # loaded zImage
627                                                 # .. or else we have a high
628                                                 # loaded bzImage
629         jmp     end_move                        # ... and we skip moving
630
631 do_move0:
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
636         cld
637 do_move:
638         movw    %ax, %es                        # destination segment
639         incb    %ah                             # instead of add ax,#0x100
640         movw    %bx, %ds                        # source segment
641         addw    $0x100, %bx
642         subw    %di, %di
643         subw    %si, %si
644         movw    $0x800, %cx
645         rep
646         movsw
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
653         jb      do_move
654
655 end_move:
656 # then we load the segment descriptors
657         movw    %cs, %ax                        # aka SETUPSEG
658         movw    %ax, %ds
659                 
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
665
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.
671         movw    %cs, %ax
672         cmpw    $SETUPSEG, %ax
673         je      end_move_self
674
675         cli                                     # make sure we really have
676                                                 # interrupts disabled !
677                                                 # because after this the stack
678                                                 # should not be used
679         subw    $DELTA_INITSEG, %ax             # aka INITSEG
680         movw    %ss, %dx
681         cmpw    %ax, %dx
682         jb      move_self_1
683
684         addw    $INITSEG, %dx
685         subw    %ax, %dx                        # this will go into %ss after
686                                                 # the move
687 move_self_1:
688         movw    %ax, %ds
689         movw    $INITSEG, %ax                   # real INITSEG
690         movw    %ax, %es
691         movw    %cs:setup_move_size, %cx
692         std                                     # we have to move up, so we use
693                                                 # direction down because the
694                                                 # areas may overlap
695         movw    %cx, %di
696         decw    %di
697         movw    %di, %si
698         subw    $move_self_here+0x200, %cx
699         rep
700         movsb
701         ljmp    $SETUPSEG, $move_self_here
702
703 move_self_here:
704         movw    $move_self_here+0x200, %cx
705         rep
706         movsb
707         movw    $SETUPSEG, %ax
708         movw    %ax, %ds
709         movw    %dx, %ss
710 end_move_self:                                  # now we are at the right place
711
712 #
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.
716 #
717
718 #if defined(CONFIG_X86_ELAN)
719         movb $0x02, %al                 # alternate A20 gate
720         outb %al, $0x92                 # this works on SC410/SC520
721 a20_elan_wait:
722         call a20_test
723         jz a20_elan_wait
724         jmp a20_done
725 #endif
726
727
728 A20_TEST_LOOPS          =  32           # Iterations per wait
729 A20_ENABLE_LOOPS        = 255           # Total loops to try            
730
731
732 #ifndef CONFIG_X86_VOYAGER
733 a20_try_loop:
734
735         # First, see if we are on a system with no A20 gate.
736 a20_none:
737         call    a20_test
738         jnz     a20_done
739
740         # Next, try the BIOS (INT 0x15, AX=0x2401)
741 a20_bios:
742         movw    $0x2401, %ax
743         pushfl                                  # Be paranoid about flags
744         int     $0x15
745         popfl
746
747         call    a20_test
748         jnz     a20_done
749
750         # Try enabling A20 through the keyboard controller
751 #endif /* CONFIG_X86_VOYAGER */
752 a20_kbc:
753         call    empty_8042
754
755 #ifndef CONFIG_X86_VOYAGER
756         call    a20_test                        # Just in case the BIOS worked
757         jnz     a20_done                        # but had a delayed reaction.
758 #endif
759
760         movb    $0xD1, %al                      # command write
761         outb    %al, $0x64
762         call    empty_8042
763
764         movb    $0xDF, %al                      # A20 on
765         outb    %al, $0x60
766         call    empty_8042
767
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
771         # problem.
772 a20_kbc_wait:
773         xorw    %cx, %cx
774 a20_kbc_wait_loop:
775         call    a20_test
776         jnz     a20_done
777         loop    a20_kbc_wait_loop
778
779         # Final attempt: use "configuration port A"
780 a20_fast:
781         inb     $0x92, %al                      # Configuration Port A
782         orb     $0x02, %al                      # "fast A20" version
783         andb    $0xFE, %al                      # don't accidentally reset
784         outb    %al, $0x92
785
786         # Wait for configuration port A to take effect
787 a20_fast_wait:
788         xorw    %cx, %cx
789 a20_fast_wait_loop:
790         call    a20_test
791         jnz     a20_done
792         loop    a20_fast_wait_loop
793
794         # A20 is still not responding.  Try frobbing it again.
795         # 
796         decb    (a20_tries)
797         jnz     a20_try_loop
798         
799         movw    $a20_err_msg, %si
800         call    prtstr
801
802 a20_die:
803         hlt
804         jmp     a20_die
805
806 a20_tries:
807         .byte   A20_ENABLE_LOOPS
808
809 a20_err_msg:
810         .ascii  "linux: fatal error: A20 gate not responding!"
811         .byte   13, 10, 0
812
813         # If we get here, all is good
814 a20_done:
815
816 #endif /* CONFIG_X86_VOYAGER */
817 # set up gdt and idt
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)
821         shll    $4, %eax
822         addl    $gdt, %eax
823         movl    %eax, (gdt_48+2)
824         lgdt    gdt_48                          # load gdt with whatever is
825                                                 # appropriate
826
827 # make sure any possible coprocessor is properly reset..
828         xorw    %ax, %ax
829         outb    %al, $0xf0
830         call    delay
831
832         outb    %al, $0xf1
833         call    delay
834
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
838         outb    %al, $0xA1
839         call    delay
840         
841         movb    $0xFB, %al                      # mask all irq's but irq2 which
842         outb    %al, $0x21                      # is cascaded
843
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.
848 #
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.
854 #
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!
859         jmp     flush_instr
860
861 flush_instr:
862         xorw    %bx, %bx                        # Flag to indicate a boot
863         xorl    %esi, %esi                      # Pointer to real-mode code
864         movw    %cs, %si
865         subw    $DELTA_INITSEG, %si
866         shll    $4, %esi                        # Convert to 32-bit pointer
867
868 # jump to startup_32 in arch/i386/boot/compressed/head.S
869 #       
870 # NOTE: For high loaded big kernels we need a
871 #       jmpi    0x100000,__BOOT_CS
872 #
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)
878
879         .byte 0x66, 0xea                        # prefix + jmpi-opcode
880 code32: .long   0x1000                          # will be set to 0x100000
881                                                 # for big kernels
882         .word   2 * 8
883
884 # Here's a bunch of information about your current kernel..
885 kernel_version: .ascii  "bootstrap"
886                 .byte   0
887
888 # This is the default real mode switch routine.
889 # to be called just before protected mode transition
890 default_switch:
891         cli                                     # no interrupts allowed !
892         movb    $0x80, %al                      # disable NMI for bootup
893                                                 # sequence
894         outb    %al, $0x70
895         lret
896
897
898 #ifndef CONFIG_X86_VOYAGER
899 # This routine tests whether or not A20 is enabled.  If so, it
900 # exits with zf = 0.
901 #
902 # The memory address used, 0x200, is the int $0x80 vector, which
903 # should be safe.
904
905 A20_TEST_ADDR = 4*0x80
906
907 a20_test:
908         pushw   %cx
909         pushw   %ax
910         xorw    %cx, %cx
911         movw    %cx, %fs                        # Low memory
912         decw    %cx
913         movw    %cx, %gs                        # High memory area
914         movw    $A20_TEST_LOOPS, %cx
915         movw    %fs:(A20_TEST_ADDR), %ax
916         pushw   %ax
917 a20_test_wait:
918         incw    %ax
919         movw    %ax, %fs:(A20_TEST_ADDR)
920         call    delay                           # Serialize and make delay constant
921         cmpw    %gs:(A20_TEST_ADDR+0x10), %ax
922         loope   a20_test_wait
923
924         popw    %fs:(A20_TEST_ADDR)
925         popw    %ax
926         popw    %cx
927         ret     
928
929 #endif /* CONFIG_X86_VOYAGER */
930
931 # This routine checks that the keyboard command queue is empty
932 # (after emptying the output buffers)
933 #
934 # Some machines have delusions that the keyboard buffer is always full
935 # with no keyboard attached...
936 #
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
942 # to empty.
943 #
944
945 empty_8042:
946         pushl   %ecx
947         movl    $100000, %ecx
948
949 empty_8042_loop:
950         decl    %ecx
951         jz      empty_8042_end_loop
952
953         call    delay
954
955         inb     $0x64, %al                      # 8042 status port
956         testb   $1, %al                         # output buffer?
957         jz      no_output
958
959         call    delay
960         inb     $0x60, %al                      # read it
961         jmp     empty_8042_loop
962
963 no_output:
964         testb   $2, %al                         # is input buffer full?
965         jnz     empty_8042_loop                 # yes - loop
966 empty_8042_end_loop:
967         popl    %ecx
968         ret
969
970 # Read the cmos clock. Return the seconds in al
971 gettime:
972         pushw   %cx
973         movb    $0x02, %ah
974         int     $0x1a
975         movb    %dh, %al                        # %dh contains the seconds
976         andb    $0x0f, %al
977         movb    %dh, %ah
978         movb    $0x04, %cl
979         shrb    %cl, %ah
980         aad
981         popw    %cx
982         ret
983
984 # Delay is needed after doing I/O
985 delay:
986         outb    %al,$0x80
987         ret
988
989 # Descriptor tables
990 #
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).
996 #
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.
1000 #
1001         .align 16
1002 gdt:
1003         .fill 2,8,0
1004
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)
1010
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)
1016 gdt_end:
1017         .align  4
1018         
1019         .word   0                               # alignment byte
1020 idt_48:
1021         .word   0                               # idt limit = 0
1022         .word   0, 0                            # idt base = 0L
1023
1024         .word   0                               # alignment byte
1025 gdt_48:
1026         .word   gdt_end - gdt - 1               # gdt limit
1027         .word   0, 0                            # gdt base (filled in later)
1028
1029 # Include video setup & detection code
1030
1031 /* Enable autodetection of SVGA adapters and modes. */
1032 #undef CONFIG_VIDEO_SVGA
1033
1034 /* Enable autodetection of VESA modes */
1035 #define CONFIG_VIDEO_VESA
1036
1037 /* Enable compacting of mode table */
1038 #define CONFIG_VIDEO_COMPACT
1039
1040 /* Retain screen contents when switching modes */
1041 #define CONFIG_VIDEO_RETAIN
1042
1043 /* Enable local mode list */
1044 #undef CONFIG_VIDEO_LOCAL
1045
1046 /* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */
1047 #undef CONFIG_VIDEO_400_HACK
1048
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 */
1054
1055 /* This code uses an extended set of video mode numbers. These include:
1056  * Aliases for standard modes
1057  *      NORMAL_VGA (-1)
1058  *      EXTENDED_VGA (-2)
1059  *      ASK_VGA (-3)
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.
1062  */
1063 #define VIDEO_FIRST_MENU 0x0000
1064
1065 /* Standard BIOS video modes (BIOS number + 0x0100) */
1066 #define VIDEO_FIRST_BIOS 0x0100
1067
1068 /* VESA BIOS video modes (VESA number + 0x0200) */
1069 #define VIDEO_FIRST_VESA 0x0200
1070
1071 /* Video7 special modes (BIOS number + 0x0900) */
1072 #define VIDEO_FIRST_V7 0x0900
1073
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
1086
1087 /* Video modes given by resolution */
1088 #define VIDEO_FIRST_RESOLUTION 0x1000
1089
1090 /* The "recalculate timings" flag */
1091 #define VIDEO_RECALC 0x8000
1092
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
1103
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
1115
1116 /* Define DO_STORE according to CONFIG_VIDEO_RETAIN */
1117 #ifdef CONFIG_VIDEO_RETAIN
1118 #define DO_STORE call store_screen
1119 #else
1120 #define DO_STORE
1121 #endif /* CONFIG_VIDEO_RETAIN */
1122
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
1127         popw    %fs
1128         pushw   %cs             # DS is equal to CS
1129         popw    %ds
1130         pushw   %cs             # ES is equal to CS
1131         popw    %es
1132         xorw    %ax, %ax
1133         movw    %ax, %gs        # GS is zero
1134         cld
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
1139         jz      vid2
1140
1141         call    mode_set                        # Set the mode
1142         jc      vid1
1143
1144         leaw    badmdt, %si                     # Invalid mode ID
1145         call    prtstr
1146 vid2:   call    mode_menu
1147 vid1:
1148 #ifdef CONFIG_VIDEO_RETAIN
1149         call    restore_screen                  # Restore screen contents
1150 #endif /* CONFIG_VIDEO_RETAIN */
1151         call    store_edid
1152 #endif /* CONFIG_VIDEO_SELECT */
1153         call    mode_params                     # Store mode parameters
1154         popw    %ds                             # Restore original DS
1155         ret
1156
1157 # Detect if we have CGA, MDA, EGA or VGA and pass it to the kernel.
1158 basic_detect:
1159         movb    $0, %fs:(PARAM_HAVE_VGA)
1160         movb    $0x12, %ah      # Check EGA/VGA
1161         movb    $0x10, %bl
1162         int     $0x10
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.
1165         je      basret
1166
1167         incb    adapter
1168         movw    $0x1a00, %ax                    # Check EGA or VGA?
1169         int     $0x10
1170         cmpb    $0x1a, %al                      # 1a means VGA...
1171         jne     basret                          # anything else is EGA.
1172         
1173         incb    %fs:(PARAM_HAVE_VGA)            # We've detected a VGA
1174         incb    adapter
1175 basret: ret
1176
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.
1181 mode_params:
1182 #ifdef CONFIG_VIDEO_SELECT
1183         cmpb    $0, graphic_mode
1184         jnz     mopar_gr
1185 #endif
1186         movb    $0x03, %ah                      # Read cursor position
1187         xorb    %bh, %bh
1188         int     $0x10
1189         movw    %dx, %fs:(PARAM_CURSOR_POS)
1190         movb    $0x0f, %ah                      # Read page/mode/width
1191         int     $0x10
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
1195         jnz     mopar0
1196
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?
1201         orw     %ax, %ax
1202         jz      mopar1
1203
1204         movb    %ah, %fs:(PARAM_VIDEO_COLS)
1205         movb    %al, %fs:(PARAM_VIDEO_LINES)
1206         ret
1207
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.
1211
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)
1215         ret
1216
1217 #ifdef CONFIG_VIDEO_SELECT
1218 # Fetching of VESA frame buffer parameters
1219 mopar_gr:
1220         leaw    modelist+1024, %di
1221         movb    $0x23, %fs:(PARAM_HAVE_VGA)
1222         movw    16(%di), %ax
1223         movw    %ax, %fs:(PARAM_LFB_LINELENGTH)
1224         movw    18(%di), %ax
1225         movw    %ax, %fs:(PARAM_LFB_WIDTH)
1226         movw    20(%di), %ax
1227         movw    %ax, %fs:(PARAM_LFB_HEIGHT)
1228         movb    25(%di), %al
1229         movb    $0, %ah
1230         movw    %ax, %fs:(PARAM_LFB_DEPTH)
1231         movb    29(%di), %al    
1232         movb    $0, %ah
1233         movw    %ax, %fs:(PARAM_LFB_PAGES)
1234         movl    40(%di), %eax
1235         movl    %eax, %fs:(PARAM_LFB_BASE)
1236         movl    31(%di), %eax
1237         movl    %eax, %fs:(PARAM_LFB_COLORS)
1238         movl    35(%di), %eax
1239         movl    %eax, %fs:(PARAM_LFB_COLORS+4)
1240         movw    0(%di), %ax
1241         movw    %ax, %fs:(PARAM_VESA_ATTRIB)
1242
1243 # get video mem size
1244         leaw    modelist+1024, %di
1245         movw    $0x4f00, %ax
1246         int     $0x10
1247         xorl    %eax, %eax
1248         movw    18(%di), %ax
1249         movl    %eax, %fs:(PARAM_LFB_SIZE)
1250
1251 # switching the DAC to 8-bit is for <= 8 bpp only
1252         movw    %fs:(PARAM_LFB_DEPTH), %ax
1253         cmpw    $8, %ax
1254         jg      dac_done
1255
1256 # get DAC switching capability
1257         xorl    %eax, %eax
1258         movb    10(%di), %al
1259         testb   $1, %al
1260         jz      dac_set
1261
1262 # attempt to switch DAC to 8-bit
1263         movw    $0x4f08, %ax
1264         movw    $0x0800, %bx
1265         int     $0x10
1266         cmpw    $0x004f, %ax
1267         jne     dac_set
1268         movb    %bh, dac_size           # store actual DAC size
1269
1270 dac_set:
1271 # set color size to DAC size
1272         movb    dac_size, %al
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)
1277
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)
1283
1284 dac_done:
1285 # get protected mode interface informations
1286         movw    $0x4f0a, %ax
1287         xorw    %bx, %bx
1288         xorw    %di, %di
1289         int     $0x10
1290         cmp     $0x004f, %ax
1291         jnz     no_pm
1292
1293         movw    %es, %fs:(PARAM_VESAPM_SEG)
1294         movw    %di, %fs:(PARAM_VESAPM_OFF)
1295 no_pm:  ret
1296
1297 # The video mode menu
1298 mode_menu:
1299         leaw    keymsg, %si                     # "Return/Space/Timeout" message
1300         call    prtstr
1301         call    flush
1302 nokey:  call    getkt
1303
1304         cmpb    $0x0d, %al                      # ENTER ?
1305         je      listm                           # yes - manual mode selection
1306
1307         cmpb    $0x20, %al                      # SPACE ?
1308         je      defmd1                          # no - repeat
1309
1310         call    beep
1311         jmp     nokey
1312
1313 defmd1: ret                                     # No mode chosen? Default 80x25
1314
1315 listm:  call    mode_table                      # List mode table
1316 listm0: leaw    name_bann, %si                  # Print adapter name
1317         call    prtstr
1318         movw    card_name, %si
1319         orw     %si, %si
1320         jnz     an2
1321
1322         movb    adapter, %al
1323         leaw    old_name, %si
1324         orb     %al, %al
1325         jz      an1
1326
1327         leaw    ega_name, %si
1328         decb    %al
1329         jz      an1
1330
1331         leaw    vga_name, %si
1332         jmp     an1
1333
1334 an2:    call    prtstr
1335         leaw    svga_name, %si
1336 an1:    call    prtstr
1337         leaw    listhdr, %si                    # Table header
1338         call    prtstr
1339         movb    $0x30, %dl                      # DL holds mode number
1340         leaw    modelist, %si
1341 lm1:    cmpw    $ASK_VGA, (%si)                 # End?
1342         jz      lm2
1343
1344         movb    %dl, %al                        # Menu selection number
1345         call    prtchr
1346         call    prtsp2
1347         lodsw
1348         call    prthw                           # Mode ID
1349         call    prtsp2
1350         movb    0x1(%si), %al
1351         call    prtdec                          # Rows
1352         movb    $0x78, %al                      # the letter 'x'
1353         call    prtchr
1354         lodsw
1355         call    prtdec                          # Columns
1356         movb    $0x0d, %al                      # New line
1357         call    prtchr
1358         movb    $0x0a, %al
1359         call    prtchr
1360         incb    %dl                             # Next character
1361         cmpb    $0x3a, %dl
1362         jnz     lm1
1363
1364         movb    $0x61, %dl
1365         jmp     lm1
1366
1367 lm2:    leaw    prompt, %si                     # Mode prompt
1368         call    prtstr
1369         leaw    edit_buf, %di                   # Editor buffer
1370 lm3:    call    getkey
1371         cmpb    $0x0d, %al                      # Enter?
1372         jz      lment
1373
1374         cmpb    $0x08, %al                      # Backspace?
1375         jz      lmbs
1376
1377         cmpb    $0x20, %al                      # Printable?
1378         jc      lm3
1379
1380         cmpw    $edit_buf+4, %di                # Enough space?
1381         jz      lm3
1382
1383         stosb
1384         call    prtchr
1385         jmp     lm3
1386
1387 lmbs:   cmpw    $edit_buf, %di                  # Backspace
1388         jz      lm3
1389
1390         decw    %di
1391         movb    $0x08, %al
1392         call    prtchr
1393         call    prtspc
1394         movb    $0x08, %al
1395         call    prtchr
1396         jmp     lm3
1397         
1398 lment:  movb    $0, (%di)
1399         leaw    crlft, %si
1400         call    prtstr
1401         leaw    edit_buf, %si
1402         cmpb    $0, (%si)                       # Empty string = default mode
1403         jz      lmdef
1404
1405         cmpb    $0, 1(%si)                      # One character = menu selection
1406         jz      mnusel
1407
1408         cmpw    $0x6373, (%si)                  # "scan" => mode scanning
1409         jnz     lmhx
1410
1411         cmpw    $0x6e61, 2(%si)
1412         jz      lmscan
1413
1414 lmhx:   xorw    %bx, %bx                        # Else => mode ID in hex
1415 lmhex:  lodsb
1416         orb     %al, %al
1417         jz      lmuse1
1418
1419         subb    $0x30, %al
1420         jc      lmbad
1421
1422         cmpb    $10, %al
1423         jc      lmhx1
1424
1425         subb    $7, %al
1426         andb    $0xdf, %al
1427         cmpb    $10, %al
1428         jc      lmbad
1429
1430         cmpb    $16, %al
1431         jnc     lmbad
1432
1433 lmhx1:  shlw    $4, %bx
1434         orb     %al, %bl
1435         jmp     lmhex
1436
1437 lmuse1: movw    %bx, %ax
1438         jmp     lmuse
1439
1440 mnusel: lodsb                                   # Menu selection
1441         xorb    %ah, %ah
1442         subb    $0x30, %al
1443         jc      lmbad
1444
1445         cmpb    $10, %al
1446         jc      lmuse
1447         
1448         cmpb    $0x61-0x30, %al
1449         jc      lmbad
1450         
1451         subb    $0x61-0x30-10, %al
1452         cmpb    $36, %al
1453         jnc     lmbad
1454
1455 lmuse:  call    mode_set
1456         jc      lmdef
1457
1458 lmbad:  leaw    unknt, %si
1459         call    prtstr
1460         jmp     lm2
1461 lmscan: cmpb    $0, adapter                     # Scanning only on EGA/VGA
1462         jz      lmbad
1463
1464         movw    $0, mt_end                      # Scanning of modes is
1465         movb    $1, scanning                    # done as new autodetection.
1466         call    mode_table
1467         jmp     listm0
1468 lmdef:  ret
1469
1470 # Additional parts of mode_set... (relative jumps, you know)
1471 setv7:                                          # Video7 extended modes
1472         DO_STORE
1473         subb    $VIDEO_FIRST_V7>>8, %bh
1474         movw    $0x6f05, %ax
1475         int     $0x10
1476         stc
1477         ret
1478
1479 _setrec:        jmp     setrec                  # Ugly...
1480 _set_80x25:     jmp     set_80x25
1481
1482 # Aliases for backward compatibility.
1483 setalias:
1484         movw    $VIDEO_80x25, %ax
1485         incw    %bx
1486         jz      mode_set
1487
1488         movb    $VIDEO_8POINT-VIDEO_FIRST_SPECIAL, %al
1489         incw    %bx
1490         jnz     setbad                          # Fall-through!
1491
1492 # Setting of user mode (AX=mode ID) => CF=success
1493 mode_set:
1494         movw    %ax, %fs:(0x01fa)               # Store mode for use in acpi_wakeup.S
1495         movw    %ax, %bx
1496         cmpb    $0xff, %ah
1497         jz      setalias
1498
1499         testb   $VIDEO_RECALC>>8, %ah
1500         jnz     _setrec
1501
1502         cmpb    $VIDEO_FIRST_RESOLUTION>>8, %ah
1503         jnc     setres
1504         
1505         cmpb    $VIDEO_FIRST_SPECIAL>>8, %ah
1506         jz      setspc
1507         
1508         cmpb    $VIDEO_FIRST_V7>>8, %ah
1509         jz      setv7
1510         
1511         cmpb    $VIDEO_FIRST_VESA>>8, %ah
1512         jnc     check_vesa
1513         
1514         orb     %ah, %ah
1515         jz      setmenu
1516         
1517         decb    %ah
1518         jz      setbios
1519
1520 setbad: clc
1521         movb    $0, do_restore                  # The screen needn't be restored
1522         ret
1523
1524 setvesa:
1525         DO_STORE
1526         subb    $VIDEO_FIRST_VESA>>8, %bh
1527         movw    $0x4f02, %ax                    # VESA BIOS mode set call
1528         int     $0x10
1529         cmpw    $0x004f, %ax                    # AL=4f if implemented
1530         jnz     setbad                          # AH=0 if OK
1531
1532         stc
1533         ret
1534
1535 setbios:
1536         DO_STORE
1537         int     $0x10                           # Standard BIOS mode set call
1538         pushw   %bx
1539         movb    $0x0f, %ah                      # Check if really set
1540         int     $0x10
1541         popw    %bx
1542         cmpb    %bl, %al
1543         jnz     setbad
1544         
1545         stc
1546         ret
1547
1548 setspc: xorb    %bh, %bh                        # Set special mode
1549         cmpb    $VIDEO_LAST_SPECIAL-VIDEO_FIRST_SPECIAL, %bl
1550         jnc     setbad
1551         
1552         addw    %bx, %bx
1553         jmp     *spec_inits(%bx)
1554
1555 setmenu:
1556         orb     %al, %al                        # 80x25 is an exception
1557         jz      _set_80x25
1558         
1559         pushw   %bx                             # Set mode chosen from menu
1560         call    mode_table                      # Build the mode table
1561         popw    %ax
1562         shlw    $2, %ax
1563         addw    %ax, %si
1564         cmpw    %di, %si
1565         jnc     setbad
1566         
1567         movw    (%si), %ax                      # Fetch mode ID
1568 _m_s:   jmp     mode_set
1569
1570 setres: pushw   %bx                             # Set mode chosen by resolution
1571         call    mode_table
1572         popw    %bx
1573         xchgb   %bl, %bh
1574 setr1:  lodsw
1575         cmpw    $ASK_VGA, %ax                   # End of the list?
1576         jz      setbad
1577         
1578         lodsw
1579         cmpw    %bx, %ax
1580         jnz     setr1
1581         
1582         movw    -4(%si), %ax                    # Fetch mode ID
1583         jmp     _m_s
1584
1585 check_vesa:
1586         leaw    modelist+1024, %di
1587         subb    $VIDEO_FIRST_VESA>>8, %bh
1588         movw    %bx, %cx                        # Get mode information structure
1589         movw    $0x4f01, %ax
1590         int     $0x10
1591         addb    $VIDEO_FIRST_VESA>>8, %bh
1592         cmpw    $0x004f, %ax
1593         jnz     setbad
1594
1595         movb    (%di), %al                      # Check capabilities.
1596         andb    $0x19, %al
1597         cmpb    $0x09, %al
1598         jz      setvesa                         # This is a text mode
1599
1600         movb    (%di), %al                      # Check capabilities.
1601         andb    $0x99, %al
1602         cmpb    $0x99, %al
1603         jnz     _setbad                         # Doh! No linear frame buffer.
1604
1605         subb    $VIDEO_FIRST_VESA>>8, %bh
1606         orw     $0x4000, %bx                    # Use linear frame buffer
1607         movw    $0x4f02, %ax                    # VESA BIOS mode set call
1608         int     $0x10
1609         cmpw    $0x004f, %ax                    # AL=4f if implemented
1610         jnz     _setbad                         # AH=0 if OK
1611
1612         movb    $1, graphic_mode                # flag graphic mode
1613         movb    $0, do_restore                  # no screen restore
1614         stc
1615         ret
1616
1617 _setbad:        jmp     setbad                  # Ugly...
1618
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.
1622
1623 setrec: subb    $VIDEO_RECALC>>8, %ah           # Set the base mode
1624         call    mode_set
1625         jnc     rct3
1626
1627         movw    %gs:(0x485), %ax                # Font size in pixels
1628         movb    %gs:(0x484), %bl                # Number of rows
1629         incb    %bl
1630         mulb    %bl                             # Number of visible
1631         decw    %ax                             # scan lines - 1
1632         movw    $0x3d4, %dx
1633         movw    %ax, %bx
1634         movb    $0x12, %al                      # Lower 8 bits
1635         movb    %bl, %ah
1636         outw    %ax, %dx
1637         movb    $0x07, %al              # Bits 8 and 9 in the overflow register
1638         call    inidx
1639         xchgb   %al, %ah
1640         andb    $0xbd, %ah
1641         shrb    %bh
1642         jnc     rct1
1643         orb     $0x02, %ah
1644 rct1:   shrb    %bh
1645         jnc     rct2
1646         orb     $0x40, %ah
1647 rct2:   movb    $0x07, %al
1648         outw    %ax, %dx
1649         stc
1650 rct3:   ret
1651
1652 # Table of routines for setting of the special modes.
1653 spec_inits:
1654         .word   set_80x25
1655         .word   set_8pixel
1656         .word   set_80x43
1657         .word   set_80x28
1658         .word   set_current
1659         .word   set_80x30
1660         .word   set_80x34
1661         .word   set_80x60
1662         .word   set_gfx
1663
1664 # Set the 80x25 mode. If already set, do nothing.
1665 set_80x25:
1666         movw    $0x5019, force_size             # Override possibly broken BIOS
1667 use_80x25:
1668 #ifdef CONFIG_VIDEO_400_HACK
1669         movw    $0x1202, %ax                    # Force 400 scan lines
1670         movb    $0x30, %bl
1671         int     $0x10
1672 #else
1673         movb    $0x0f, %ah                      # Get current mode ID
1674         int     $0x10
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
1677
1678         cmpw    $0x5003, %ax    # Unknown mode, force 80x25 color
1679         jnz     force3
1680
1681 st80:   cmpb    $0, adapter     # CGA/MDA/HGA => mode 3/7 is always 80x25
1682         jz      set80
1683
1684         movb    %gs:(0x0484), %al       # This is EGA+ -- beware of 80x50 etc.
1685         orb     %al, %al                # Some buggy BIOS'es set 0 rows
1686         jz      set80
1687         
1688         cmpb    $24, %al                # It's hopefully correct
1689         jz      set80
1690 #endif /* CONFIG_VIDEO_400_HACK */
1691 force3: DO_STORE
1692         movw    $0x0003, %ax                    # Forced set
1693         int     $0x10
1694 set80:  stc
1695         ret
1696
1697 # Set the 80x50/80x43 8-pixel mode. Simple BIOS calls.
1698 set_8pixel:
1699         DO_STORE
1700         call    use_80x25                       # The base is 80x25
1701 set_8pt:
1702         movw    $0x1112, %ax                    # Use 8x8 font
1703         xorb    %bl, %bl
1704         int     $0x10
1705         movw    $0x1200, %ax                    # Use alternate print screen
1706         movb    $0x20, %bl
1707         int     $0x10
1708         movw    $0x1201, %ax                    # Turn off cursor emulation
1709         movb    $0x34, %bl
1710         int     $0x10
1711         movb    $0x01, %ah                      # Define cursor scan lines 6-7
1712         movw    $0x0607, %cx
1713         int     $0x10
1714 set_current:
1715         stc
1716         ret
1717
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.
1720 set_80x28:
1721         DO_STORE
1722         call    use_80x25                       # The base is 80x25
1723 set14:  movw    $0x1111, %ax                    # Use 9x14 font
1724         xorb    %bl, %bl
1725         int     $0x10
1726         movb    $0x01, %ah                      # Define cursor scan lines 11-12
1727         movw    $0x0b0c, %cx
1728         int     $0x10
1729         stc
1730         ret
1731
1732 # Set the 80x43 mode. This mode is works on all VGA's.
1733 # It's a 350-scanline mode with 8-pixel font.
1734 set_80x43:
1735         DO_STORE
1736         movw    $0x1201, %ax                    # Set 350 scans
1737         movb    $0x30, %bl
1738         int     $0x10
1739         movw    $0x0003, %ax                    # Reset video mode
1740         int     $0x10
1741         jmp     set_8pt                         # Use 8-pixel font
1742
1743 # Set the 80x30 mode (all VGA's). 480 scanlines, 16-pixel font.
1744 set_80x30:
1745         call    use_80x25                       # Start with real 80x25
1746         DO_STORE
1747         movw    $0x3cc, %dx                     # Get CRTC port
1748         inb     %dx, %al
1749         movb    $0xd4, %dl
1750         rorb    %al                             # Mono or color?
1751         jc      set48a
1752
1753         movb    $0xb4, %dl
1754 set48a: movw    $0x0c11, %ax            # Vertical sync end (also unlocks CR0-7)
1755         call    outidx
1756         movw    $0x0b06, %ax                    # Vertical total
1757         call    outidx
1758         movw    $0x3e07, %ax                    # (Vertical) overflow
1759         call    outidx
1760         movw    $0xea10, %ax                    # Vertical sync start
1761         call    outidx
1762         movw    $0xdf12, %ax                    # Vertical display end
1763         call    outidx
1764         movw    $0xe715, %ax                    # Vertical blank start
1765         call    outidx
1766         movw    $0x0416, %ax                    # Vertical blank end
1767         call    outidx
1768         pushw   %dx
1769         movb    $0xcc, %dl                      # Misc output register (read)
1770         inb     %dx, %al
1771         movb    $0xc2, %dl                      # (write)
1772         andb    $0x0d, %al      # Preserve clock select bits and color bit
1773         orb     $0xe2, %al                      # Set correct sync polarity
1774         outb    %al, %dx
1775         popw    %dx
1776         movw    $0x501e, force_size
1777         stc                                     # That's all.
1778         ret
1779
1780 # Set the 80x34 mode (all VGA's). 480 scans, 14-pixel font.
1781 set_80x34:
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
1786 setvde: call    outidx
1787         stc
1788         ret
1789
1790 # Set the 80x60 mode (all VGA's). 480 scans, 8-pixel font.
1791 set_80x60:
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
1796         jmp     setvde
1797
1798 # Special hack for ThinkPad graphics
1799 set_gfx:
1800 #ifdef CONFIG_VIDEO_GFX_HACK
1801         movw    $VIDEO_GFX_BIOS_AX, %ax
1802         movw    $VIDEO_GFX_BIOS_BX, %bx
1803         int     $0x10
1804         movw    $VIDEO_GFX_DUMMY_RESOLUTION, force_size
1805         stc
1806 #endif
1807         ret
1808
1809 #ifdef CONFIG_VIDEO_RETAIN
1810
1811 # Store screen contents to temporary buffer.
1812 store_screen:
1813         cmpb    $0, do_restore                  # Already stored?
1814         jnz     stsr
1815
1816         testb   $CAN_USE_HEAP, loadflags        # Have we space for storing?
1817         jz      stsr
1818         
1819         pushw   %ax
1820         pushw   %bx
1821         pushw   force_size                      # Don't force specific size
1822         movw    $0, force_size
1823         call    mode_params                     # Obtain params of current mode
1824         popw    force_size
1825         movb    %fs:(PARAM_VIDEO_LINES), %ah
1826         movb    %fs:(PARAM_VIDEO_COLS), %al
1827         movw    %ax, %bx                        # BX=dimensions
1828         mulb    %ah
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
1834
1835         movw    %fs:(PARAM_CURSOR_POS), %ax     # Store mode params
1836         leaw    modelist+1024, %di
1837         stosw
1838         movw    %bx, %ax
1839         stosw
1840         pushw   %ds                             # Store the screen
1841         movw    video_segment, %ds
1842         xorw    %si, %si
1843         rep
1844         movsw
1845         popw    %ds
1846         incb    do_restore                      # Screen will be restored later
1847 sts1:   popw    %bx
1848         popw    %ax
1849 stsr:   ret
1850
1851 # Restore screen contents from temporary buffer.
1852 restore_screen:
1853         cmpb    $0, do_restore                  # Has the screen been stored?
1854         jz      res1
1855
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
1861         movw    %ax, %dx
1862         cmpb    %cl, %dh
1863         jc      res2
1864         
1865         movb    %cl, %dh
1866         decb    %dh
1867 res2:   cmpb    %ch, %dl
1868         jc      res3
1869         
1870         movb    %ch, %dl
1871         decb    %dl
1872 res3:   movb    $0x02, %ah
1873         movb    $0x00, %bh
1874         int     $0x10
1875         lodsw                                   # Display size
1876         movb    %ah, %dl                        # DL=number of lines
1877         movb    $0, %ah                         # BX=phys. length of orig. line
1878         movw    %ax, %bx
1879         cmpb    %cl, %dl                        # Too many?
1880         jc      res4
1881
1882         pushw   %ax
1883         movb    %dl, %al
1884         subb    %cl, %al
1885         mulb    %bl
1886         addw    %ax, %si
1887         addw    %ax, %si
1888         popw    %ax
1889         movb    %cl, %dl
1890 res4:   cmpb    %ch, %al                        # Too wide?
1891         jc      res5
1892         
1893         movb    %ch, %al                        # AX=width of src. line
1894 res5:   movb    $0, %cl
1895         xchgb   %ch, %cl
1896         movw    %cx, %bp                        # BP=width of dest. line
1897         pushw   %es
1898         movw    video_segment, %es
1899         xorw    %di, %di                        # Move the data
1900         addw    %bx, %bx                        # Convert BX and BP to _bytes_
1901         addw    %bp, %bp
1902 res6:   pushw   %si
1903         pushw   %di
1904         movw    %ax, %cx
1905         rep
1906         movsw
1907         popw    %di
1908         popw    %si
1909         addw    %bp, %di
1910         addw    %bx, %si
1911         decb    %dl
1912         jnz     res6
1913         
1914         popw    %es                             # Done
1915 res1:   ret
1916 #endif /* CONFIG_VIDEO_RETAIN */
1917
1918 # Write to indexed VGA register (AL=index, AH=data, DX=index reg. port)
1919 outidx: outb    %al, %dx
1920         pushw   %ax
1921         movb    %ah, %al
1922         incw    %dx
1923         outb    %al, %dx
1924         decw    %dx
1925         popw    %ax
1926         ret
1927
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.
1935 mode_table:
1936         movw    mt_end, %di                     # Already filled?
1937         orw     %di, %di
1938         jnz     mtab1x
1939         
1940         leaw    modelist, %di                   # Store standard modes:
1941         movl    $VIDEO_80x25 + 0x50190000, %eax # The 80x25 mode (ALL)
1942         stosl
1943         movb    adapter, %al                    # CGA/MDA/HGA -- no more modes
1944         orb     %al, %al
1945         jz      mtabe
1946         
1947         decb    %al
1948         jnz     mtabv
1949         
1950         movl    $VIDEO_8POINT + 0x502b0000, %eax        # The 80x43 EGA mode
1951         stosl
1952         jmp     mtabe
1953
1954 mtab1x: jmp     mtab1
1955
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.
1960
1961         cmpb    $0, scanning                    # Mode scan requested?
1962         jz      mscan1
1963         
1964         call    mode_scan
1965 mscan1:
1966
1967 #ifdef CONFIG_VIDEO_LOCAL
1968         call    local_modes
1969 #endif /* CONFIG_VIDEO_LOCAL */
1970
1971 #ifdef CONFIG_VIDEO_VESA
1972         call    vesa_modes                      # Detect VESA VGA modes
1973 #endif /* CONFIG_VIDEO_VESA */
1974
1975 #ifdef CONFIG_VIDEO_SVGA
1976         cmpb    $0, scanning                    # Bypass when scanning
1977         jnz     mscan2
1978         
1979         call    svga_modes                      # Detect SVGA cards & modes
1980 mscan2:
1981 #endif /* CONFIG_VIDEO_SVGA */
1982
1983 mtabe:
1984
1985 #ifdef CONFIG_VIDEO_COMPACT
1986         leaw    modelist, %si
1987         movw    %di, %dx
1988         movw    %si, %di
1989 cmt1:   cmpw    %dx, %si                        # Scan all modes
1990         jz      cmt2
1991
1992         leaw    modelist, %bx                   # Find in previous entries
1993         movw    2(%si), %cx
1994 cmt3:   cmpw    %bx, %si
1995         jz      cmt4
1996
1997         cmpw    2(%bx), %cx                     # Found => don't copy this entry
1998         jz      cmt5
1999
2000         addw    $4, %bx
2001         jmp     cmt3
2002
2003 cmt4:   movsl                                   # Copy entry
2004         jmp     cmt1
2005
2006 cmt5:   addw    $4, %si                         # Skip entry
2007         jmp     cmt1
2008
2009 cmt2:
2010 #endif  /* CONFIG_VIDEO_COMPACT */
2011
2012         movw    $ASK_VGA, (%di)                 # End marker
2013         movw    %di, mt_end
2014 mtab1:  leaw    modelist, %si                   # SI=mode list, DI=list end
2015 ret0:   ret
2016
2017 # Modes usable on all standard VGAs
2018 vga_modes:
2019         .word   VIDEO_8POINT
2020         .word   0x5032                          # 80x50
2021         .word   VIDEO_80x43
2022         .word   0x502b                          # 80x43
2023         .word   VIDEO_80x28
2024         .word   0x501c                          # 80x28
2025         .word   VIDEO_80x30
2026         .word   0x501e                          # 80x30
2027         .word   VIDEO_80x34
2028         .word   0x5022                          # 80x34
2029         .word   VIDEO_80x60
2030         .word   0x503c                          # 80x60
2031 #ifdef CONFIG_VIDEO_GFX_HACK
2032         .word   VIDEO_GFX_HACK
2033         .word   VIDEO_GFX_DUMMY_RESOLUTION
2034 #endif
2035
2036 vga_modes_end:
2037 # Detect VESA modes.
2038
2039 #ifdef CONFIG_VIDEO_VESA
2040 vesa_modes:
2041         cmpb    $2, adapter                     # VGA only
2042         jnz     ret0
2043
2044         movw    %di, %bp                        # BP=original mode table end
2045         addw    $0x200, %di                     # Buffer space
2046         movw    $0x4f00, %ax                    # VESA Get card info call
2047         int     $0x10
2048         movw    %bp, %di
2049         cmpw    $0x004f, %ax                    # Successful?
2050         jnz     ret0
2051         
2052         cmpw    $0x4556, 0x200(%di)
2053         jnz     ret0
2054         
2055         cmpw    $0x4153, 0x202(%di)
2056         jnz     ret0
2057         
2058         movw    $vesa_name, card_name           # Set name to "VESA VGA"
2059         pushw   %gs
2060         lgsw    0x20e(%di), %si                 # GS:SI=mode list
2061         movw    $128, %cx                       # Iteration limit
2062 vesa1:
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
2065         gs; lodsw
2066         cmpw    $0xffff, %ax                    # End of the table?
2067         jz      vesar
2068         
2069         cmpw    $0x0080, %ax                    # Check validity of mode ID
2070         jc      vesa2
2071         
2072         orb     %ah, %ah                # Valid IDs: 0x0000-0x007f/0x0100-0x07ff
2073         jz      vesan                   # Certain BIOSes report 0x80-0xff!
2074
2075         cmpw    $0x0800, %ax
2076         jnc     vesae
2077
2078 vesa2:  pushw   %cx
2079         movw    %ax, %cx                        # Get mode information structure
2080         movw    $0x4f01, %ax
2081         int     $0x10
2082         movw    %cx, %bx                        # BX=mode number
2083         addb    $VIDEO_FIRST_VESA>>8, %bh
2084         popw    %cx
2085         cmpw    $0x004f, %ax
2086         jnz     vesan                   # Don't report errors (buggy BIOSES)
2087
2088         movb    (%di), %al                      # Check capabilities. We require
2089         andb    $0x19, %al                      # a color text mode.
2090         cmpb    $0x09, %al
2091         jnz     vesan
2092         
2093         cmpw    $0xb800, 8(%di)         # Standard video memory address required
2094         jnz     vesan
2095
2096         testb   $2, (%di)                       # Mode characteristics supplied?
2097         movw    %bx, (%di)                      # Store mode number
2098         jz      vesa3
2099         
2100         xorw    %dx, %dx
2101         movw    0x12(%di), %bx                  # Width
2102         orb     %bh, %bh
2103         jnz     vesan
2104         
2105         movb    %bl, 0x3(%di)
2106         movw    0x14(%di), %ax                  # Height
2107         orb     %ah, %ah
2108         jnz     vesan
2109         
2110         movb    %al, 2(%di)
2111         mulb    %bl
2112         cmpw    $8193, %ax              # Small enough for Linux console driver?
2113         jnc     vesan
2114
2115         jmp     vesaok
2116
2117 vesa3:  subw    $0x8108, %bx    # This mode has no detailed info specified,
2118         jc      vesan           # so it must be a standard VESA mode.
2119
2120         cmpw    $5, %bx
2121         jnc     vesan
2122
2123         movw    vesa_text_mode_table(%bx), %ax
2124         movw    %ax, 2(%di)
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
2128         call    prtstr
2129         movw    %bp, %di                        # Discard already found modes.
2130 vesar:  popw    %gs
2131         ret
2132
2133 # Dimensions of standard VESA text modes
2134 vesa_text_mode_table:
2135         .byte   60, 80                          # 0108
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 */
2141
2142 # Scan for video modes. A bit dirty, but should work.
2143 mode_scan:
2144         movw    $0x0100, %cx                    # Start with mode 0
2145 scm1:   movb    $0, %ah                         # Test the mode
2146         movb    %cl, %al
2147         int     $0x10
2148         movb    $0x0f, %ah
2149         int     $0x10
2150         cmpb    %cl, %al
2151         jnz     scm2                            # Mode not set
2152
2153         movw    $0x3c0, %dx                     # Test if it's a text mode
2154         movb    $0x10, %al                      # Mode bits
2155         call    inidx
2156         andb    $0x03, %al
2157         jnz     scm2
2158         
2159         movb    $0xce, %dl                      # Another set of mode bits
2160         movb    $0x06, %al
2161         call    inidx
2162         shrb    %al
2163         jc      scm2
2164         
2165         movb    $0xd4, %dl                      # Cursor location
2166         movb    $0x0f, %al
2167         call    inidx
2168         orb     %al, %al
2169         jnz     scm2
2170         
2171         movw    %cx, %ax                        # Ok, store the mode
2172         stosw
2173         movb    %gs:(0x484), %al                # Number of rows
2174         incb    %al
2175         stosb
2176         movw    %gs:(0x44a), %ax                # Number of columns
2177         stosb
2178 scm2:   incb    %cl
2179         jns     scm1
2180         
2181         movw    $0x0003, %ax                    # Return back to mode 3
2182         int     $0x10
2183         ret
2184
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
2188         inb     %dx, %al
2189         decw    %dx
2190         ret
2191
2192 # Try to detect type of SVGA card and supply (usually approximate) video
2193 # mode table for it.
2194
2195 #ifdef CONFIG_VIDEO_SVGA
2196 svga_modes:
2197         leaw    svga_table, %si                 # Test all known SVGA adapters
2198 dosvga: lodsw
2199         movw    %ax, %bp                        # Default mode table
2200         orw     %ax, %ax
2201         jz      didsv1
2202
2203         lodsw                                   # Pointer to test routine
2204         pushw   %si
2205         pushw   %di
2206         pushw   %es
2207         movw    $0xc000, %bx
2208         movw    %bx, %es
2209         call    *%ax                            # Call test routine
2210         popw    %es
2211         popw    %di
2212         popw    %si
2213         orw     %bp, %bp
2214         jz      dosvga
2215         
2216         movw    %bp, %si                        # Found, copy the modes
2217         movb    svga_prefix, %ah
2218 cpsvga: lodsb
2219         orb     %al, %al
2220         jz      didsv
2221         
2222         stosw
2223         movsw
2224         jmp     cpsvga
2225
2226 didsv:  movw    %si, card_name                  # Store pointer to card name
2227 didsv1: ret
2228
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.
2233 svga_table:
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
2249         .word   0
2250
2251 # Test routines and mode tables:
2252
2253 # S3 - The test algorithm was taken from the SuperProbe package
2254 # for XFree86 1.2.1. Report bugs to Christoph.Niemann@linux.org
2255 s3_test:
2256         movw    $0x0f35, %cx    # we store some constants in cl/ch
2257         movw    $0x03d4, %dx
2258         movb    $0x38, %al
2259         call    inidx
2260         movb    %al, %bh        # store current CRT-register 0x38
2261         movw    $0x0038, %ax
2262         call    outidx          # disable writing to special regs
2263         movb    %cl, %al        # check whether we can write special reg 0x35
2264         call    inidx
2265         movb    %al, %bl        # save the current value of CRT reg 0x35
2266         andb    $0xf0, %al      # clear bits 0-3
2267         movb    %al, %ah
2268         movb    %cl, %al        # and write it to CRT reg 0x35
2269         call    outidx
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
2273
2274         movb    %bl, %ah        # second chance
2275         movb    %cl, %al
2276         call    outidx
2277         jmp     s3_1            # do the other tests
2278
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
2284         pushw   %ax
2285         movb    %bl, %ah        # restore old value in register 0x35
2286         movb    %cl, %al
2287         call    outidx
2288         popw    %ax
2289         cmpb    %ch, %al        # setting lower 4 bits was successful => bad
2290         je      no_s3           # writing is allowed => this is not an S3
2291
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
2295         call    inidx
2296         movb    %al, %bl
2297         andb    $0xf0, %al
2298         movb    %al, %ah
2299         movb    %cl, %al
2300         call    outidx
2301         call    inidx
2302         andb    %ch, %al
2303         jnz     no_s3           # no, we can't write => no S3
2304
2305         movw    %cx, %ax
2306         orb     %bl, %ah
2307         call    outidx
2308         call    inidx
2309         andb    %ch, %al
2310         pushw   %ax
2311         movb    %bl, %ah        # restore old value in register 0x35
2312         movb    %cl, %al
2313         call    outidx
2314         popw    %ax
2315         cmpb    %ch, %al
2316         jne     no_s31          # writing not possible => no S3
2317         movb    $0x30, %al
2318         call    inidx           # now get the S3 id ...
2319         leaw    idS3, %di
2320         movw    $0x10, %cx
2321         repne
2322         scasb
2323         je      no_s31
2324
2325         movb    %bh, %ah
2326         movb    $0x38, %al
2327         jmp     s3rest
2328
2329 no_s3:  movb    $0x35, %al      # restore CRT register 0x35
2330         movb    %bl, %ah
2331         call    outidx
2332 no_s31: xorw    %bp, %bp        # Detection failed
2333 s3rest: movb    %bh, %ah
2334         movb    $0x38, %al      # restore old value of CRT register 0x38
2335         jmp     outidx
2336
2337 idS3:   .byte   0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95
2338         .byte   0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0
2339
2340 s3_md:  .byte   0x54, 0x2b, 0x84
2341         .byte   0x55, 0x19, 0x84
2342         .byte   0
2343         .ascii  "S3"
2344         .byte   0
2345
2346 # ATI cards.
2347 ati_test:
2348         leaw    idati, %si
2349         movw    $0x31, %di
2350         movw    $0x09, %cx
2351         repe
2352         cmpsb
2353         je      atiok
2354
2355         xorw    %bp, %bp
2356 atiok:  ret
2357
2358 idati:  .ascii  "761295520"
2359
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
2366         .byte   0
2367         .ascii  "ATI"
2368         .byte   0
2369
2370 # AHEAD
2371 ahead_test:
2372         movw    $0x200f, %ax
2373         movw    $0x3ce, %dx
2374         outw    %ax, %dx
2375         incw    %dx
2376         inb     %dx, %al
2377         cmpb    $0x20, %al
2378         je      isahed
2379
2380         cmpb    $0x21, %al
2381         je      isahed
2382         
2383         xorw    %bp, %bp
2384 isahed: ret
2385
2386 ahead_md:
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
2393         .byte   0
2394         .ascii  "Ahead"
2395         .byte   0
2396
2397 # Chips & Tech.
2398 chips_test:
2399         movw    $0x3c3, %dx
2400         inb     %dx, %al
2401         orb     $0x10, %al
2402         outb    %al, %dx
2403         movw    $0x104, %dx
2404         inb     %dx, %al
2405         movb    %al, %bl
2406         movw    $0x3c3, %dx
2407         inb     %dx, %al
2408         andb    $0xef, %al
2409         outb    %al, %dx
2410         cmpb    $0xa5, %bl
2411         je      cantok
2412         
2413         xorw    %bp, %bp
2414 cantok: ret
2415
2416 chips_md:
2417         .byte   0x60, 0x19, 0x84
2418         .byte   0x61, 0x32, 0x84
2419         .byte   0
2420         .ascii  "Chips & Technologies"
2421         .byte   0
2422
2423 # Cirrus Logic 5X0
2424 cirrus1_test:
2425         movw    $0x3d4, %dx
2426         movb    $0x0c, %al
2427         outb    %al, %dx
2428         incw    %dx
2429         inb     %dx, %al
2430         movb    %al, %bl
2431         xorb    %al, %al
2432         outb    %al, %dx
2433         decw    %dx
2434         movb    $0x1f, %al
2435         outb    %al, %dx
2436         incw    %dx
2437         inb     %dx, %al
2438         movb    %al, %bh
2439         xorb    %ah, %ah
2440         shlb    $4, %al
2441         movw    %ax, %cx
2442         movb    %bh, %al
2443         shrb    $4, %al
2444         addw    %ax, %cx
2445         shlw    $8, %cx
2446         addw    $6, %cx
2447         movw    %cx, %ax
2448         movw    $0x3c4, %dx
2449         outw    %ax, %dx
2450         incw    %dx
2451         inb     %dx, %al
2452         andb    %al, %al
2453         jnz     nocirr
2454         
2455         movb    %bh, %al
2456         outb    %al, %dx
2457         inb     %dx, %al
2458         cmpb    $0x01, %al
2459         je      iscirr
2460
2461 nocirr: xorw    %bp, %bp
2462 iscirr: movw    $0x3d4, %dx
2463         movb    %bl, %al
2464         xorb    %ah, %ah
2465         shlw    $8, %ax
2466         addw    $0x0c, %ax
2467         outw    %ax, %dx
2468         ret
2469
2470 cirrus1_md:
2471         .byte   0x1f, 0x19, 0x84
2472         .byte   0x20, 0x2c, 0x84
2473         .byte   0x22, 0x1e, 0x84
2474         .byte   0x31, 0x25, 0x64
2475         .byte   0
2476         .ascii  "Cirrus Logic 5X0"
2477         .byte   0
2478
2479 # Cirrus Logic 54XX
2480 cirrus5_test:
2481         movw    $0x3c4, %dx
2482         movb    $6, %al
2483         call    inidx
2484         movb    %al, %bl                        # BL=backup
2485         movw    $6, %ax
2486         call    tstidx
2487         cmpb    $0x0f, %al
2488         jne     c5fail
2489         
2490         movw    $0x1206, %ax
2491         call    tstidx
2492         cmpb    $0x12, %al
2493         jne     c5fail
2494         
2495         movb    $0x1e, %al
2496         call    inidx
2497         movb    %al, %bh
2498         movb    %bh, %ah
2499         andb    $0xc0, %ah
2500         movb    $0x1e, %al
2501         call    tstidx
2502         andb    $0x3f, %al
2503         jne     c5xx
2504         
2505         movb    $0x1e, %al
2506         movb    %bh, %ah
2507         orb     $0x3f, %ah
2508         call    tstidx
2509         xorb    $0x3f, %al
2510         andb    $0x3f, %al
2511 c5xx:   pushf
2512         movb    $0x1e, %al
2513         movb    %bh, %ah
2514         outw    %ax, %dx
2515         popf
2516         je      c5done
2517
2518 c5fail: xorw    %bp, %bp
2519 c5done: movb    $6, %al
2520         movb    %bl, %ah
2521         outw    %ax, %dx
2522         ret
2523
2524 cirrus5_md:
2525         .byte   0x14, 0x19, 0x84
2526         .byte   0x54, 0x2b, 0x84
2527         .byte   0
2528         .ascii  "Cirrus Logic 54XX"
2529         .byte   0
2530
2531 # Cirrus Logic 64XX -- no known extra modes, but must be identified, because
2532 # it's misidentified by the Ahead test.
2533 cirrus6_test:
2534         movw    $0x3ce, %dx
2535         movb    $0x0a, %al
2536         call    inidx
2537         movb    %al, %bl        # BL=backup
2538         movw    $0xce0a, %ax
2539         call    tstidx
2540         orb     %al, %al
2541         jne     c2fail
2542         
2543         movw    $0xec0a, %ax
2544         call    tstidx
2545         cmpb    $0x01, %al
2546         jne     c2fail
2547         
2548         movb    $0xaa, %al
2549         call    inidx           # 4X, 5X, 7X and 8X are valid 64XX chip ID's. 
2550         shrb    $4, %al
2551         subb    $4, %al
2552         jz      c6done
2553         
2554         decb    %al
2555         jz      c6done
2556         
2557         subb    $2, %al
2558         jz      c6done
2559         
2560         decb    %al
2561         jz      c6done
2562         
2563 c2fail: xorw    %bp, %bp
2564 c6done: movb    $0x0a, %al
2565         movb    %bl, %ah
2566         outw    %ax, %dx
2567         ret
2568
2569 cirrus6_md:
2570         .byte   0
2571         .ascii  "Cirrus Logic 64XX"
2572         .byte   0
2573
2574 # Everex / Trident
2575 everex_test:
2576         movw    $0x7000, %ax
2577         xorw    %bx, %bx
2578         int     $0x10
2579         cmpb    $0x70, %al
2580         jne     noevrx
2581         
2582         shrw    $4, %dx
2583         cmpw    $0x678, %dx
2584         je      evtrid
2585         
2586         cmpw    $0x236, %dx
2587         jne     evrxok
2588
2589 evtrid: leaw    trident_md, %bp
2590 evrxok: ret
2591
2592 noevrx: xorw    %bp, %bp
2593         ret
2594
2595 everex_md:
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
2606         .byte   0
2607         .ascii  "Everex/Trident"
2608         .byte   0
2609
2610 # Genoa.
2611 genoa_test:
2612         leaw    idgenoa, %si                    # Check Genoa 'clues'
2613         xorw    %ax, %ax
2614         movb    %es:(0x37), %al
2615         movw    %ax, %di
2616         movw    $0x04, %cx
2617         decw    %si
2618         decw    %di
2619 l1:     incw    %si
2620         incw    %di
2621         movb    (%si), %al
2622         testb   %al, %al
2623         jz      l2
2624
2625         cmpb    %es:(%di), %al
2626 l2:     loope   l1
2627         orw     %cx, %cx
2628         je      isgen
2629         
2630         xorw    %bp, %bp
2631 isgen:  ret
2632
2633 idgenoa: .byte  0x77, 0x00, 0x99, 0x66
2634
2635 genoa_md:
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
2647         .byte   0
2648         .ascii  "Genoa"
2649         .byte   0
2650
2651 # OAK
2652 oak_test:
2653         leaw    idoakvga, %si
2654         movw    $0x08, %di
2655         movw    $0x08, %cx
2656         repe
2657         cmpsb
2658         je      isoak
2659         
2660         xorw    %bp, %bp
2661 isoak:  ret
2662
2663 idoakvga: .ascii  "OAK VGA "
2664
2665 oak_md: .byte   0x4e, 0x3c, 0x50
2666         .byte   0x4f, 0x3c, 0x84
2667         .byte   0x50, 0x19, 0x84
2668         .byte   0x51, 0x2b, 0x84
2669         .byte   0
2670         .ascii  "OAK"
2671         .byte   0
2672
2673 # WD Paradise.
2674 paradise_test:
2675         leaw    idparadise, %si
2676         movw    $0x7d, %di
2677         movw    $0x04, %cx
2678         repe
2679         cmpsb
2680         je      ispara
2681         
2682         xorw    %bp, %bp
2683 ispara: ret
2684
2685 idparadise:     .ascii  "VGA="
2686
2687 paradise_md:
2688         .byte   0x41, 0x22, 0x50
2689         .byte   0x47, 0x1c, 0x84
2690         .byte   0x55, 0x19, 0x84
2691         .byte   0x54, 0x2c, 0x84
2692         .byte   0
2693         .ascii  "Paradise"
2694         .byte   0
2695
2696 # Trident.
2697 trident_test:
2698         movw    $0x3c4, %dx
2699         movb    $0x0e, %al
2700         outb    %al, %dx
2701         incw    %dx
2702         inb     %dx, %al
2703         xchgb   %al, %ah
2704         xorb    %al, %al
2705         outb    %al, %dx
2706         inb     %dx, %al
2707         xchgb   %ah, %al
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
2711                                 # blurred ...
2712         andb    $0xfd, %al
2713         jmp     clrb2           
2714
2715 setb2:  orb     $0x02, %al      
2716 clrb2:  outb    %al, %dx
2717         andb    $0x0f, %ah
2718         cmpb    $0x02, %ah
2719         je      istrid
2720
2721         xorw    %bp, %bp
2722 istrid: ret
2723
2724 trident_md:
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
2732         .byte   0
2733         .ascii  "Trident"
2734         .byte   0
2735
2736 # Tseng.
2737 tseng_test:
2738         movw    $0x3cd, %dx
2739         inb     %dx, %al        # Could things be this simple ! :-)
2740         movb    %al, %bl
2741         movb    $0x55, %al
2742         outb    %al, %dx
2743         inb     %dx, %al
2744         movb    %al, %ah
2745         movb    %bl, %al
2746         outb    %al, %dx
2747         cmpb    $0x55, %ah
2748         je      istsen
2749
2750 isnot:  xorw    %bp, %bp
2751 istsen: ret
2752
2753 tseng_md:
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
2760         .byte   0
2761         .ascii  "Tseng"
2762         .byte   0
2763
2764 # Video7.
2765 video7_test:
2766         movw    $0x3cc, %dx
2767         inb     %dx, %al
2768         movw    $0x3b4, %dx
2769         andb    $0x01, %al
2770         jz      even7
2771
2772         movw    $0x3d4, %dx
2773 even7:  movb    $0x0c, %al
2774         outb    %al, %dx
2775         incw    %dx
2776         inb     %dx, %al
2777         movb    %al, %bl
2778         movb    $0x55, %al
2779         outb    %al, %dx
2780         inb     %dx, %al
2781         decw    %dx
2782         movb    $0x1f, %al
2783         outb    %al, %dx
2784         incw    %dx
2785         inb     %dx, %al
2786         movb    %al, %bh
2787         decw    %dx
2788         movb    $0x0c, %al
2789         outb    %al, %dx
2790         incw    %dx
2791         movb    %bl, %al
2792         outb    %al, %dx
2793         movb    $0x55, %al
2794         xorb    $0xea, %al
2795         cmpb    %bh, %al
2796         jne     isnot
2797         
2798         movb    $VIDEO_FIRST_V7>>8, svga_prefix # Use special mode switching
2799         ret
2800
2801 video7_md:
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
2808         .byte   0
2809         .ascii  "Video 7"
2810         .byte   0
2811
2812 # Realtek VGA
2813 realtek_test:
2814         leaw    idrtvga, %si
2815         movw    $0x45, %di
2816         movw    $0x0b, %cx
2817         repe
2818         cmpsb
2819         je      isrt
2820         
2821         xorw    %bp, %bp
2822 isrt:   ret
2823
2824 idrtvga:        .ascii  "REALTEK VGA"
2825
2826 realtek_md:
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
2832         .byte   0
2833         .ascii  "REALTEK"
2834         .byte   0
2835
2836 #endif  /* CONFIG_VIDEO_SVGA */
2837
2838 # User-defined local mode table (VGA only)
2839 #ifdef CONFIG_VIDEO_LOCAL
2840 local_modes:
2841         leaw    local_mode_table, %si
2842 locm1:  lodsw
2843         orw     %ax, %ax
2844         jz      locm2
2845         
2846         stosw
2847         movsw
2848         jmp     locm1
2849
2850 locm2:  ret
2851
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.
2858 local_mode_table:
2859         .word   0x0100                          # Example: 40x25
2860         .byte   25,40
2861         .word   0
2862         .ascii  "Local"
2863         .byte   0
2864 #endif  /* CONFIG_VIDEO_LOCAL */
2865
2866 # Read a key and return the ASCII code in al, scan code in ah
2867 getkey: xorb    %ah, %ah
2868         int     $0x16
2869         ret
2870
2871 # Read a key with a timeout of 30 seconds.
2872 # The hardware clock is used to get the time.
2873 getkt:  call    gettime
2874         addb    $30, %al                        # Wait 30 seconds
2875         cmpb    $60, %al
2876         jl      lminute
2877
2878         subb    $60, %al
2879 lminute:
2880         movb    %al, %cl
2881 again:  movb    $0x01, %ah
2882         int     $0x16
2883         jnz     getkey                          # key pressed, so get it
2884
2885         call    gettime
2886         cmpb    %cl, %al
2887         jne     again
2888
2889         movb    $0x20, %al                      # timeout, return `space'
2890         ret
2891
2892 # Flush the keyboard buffer
2893 flush:  movb    $0x01, %ah
2894         int     $0x16
2895         jz      empty
2896         
2897         xorb    %ah, %ah
2898         int     $0x16
2899         jmp     flush
2900
2901 empty:  ret
2902
2903 # Print hexadecimal number.
2904 prthw:  pushw   %ax
2905         movb    %ah, %al
2906         call    prthb
2907         popw    %ax
2908 prthb:  pushw   %ax
2909         shrb    $4, %al
2910         call    prthn
2911         popw    %ax
2912         andb    $0x0f, %al
2913 prthn:  cmpb    $0x0a, %al
2914         jc      prth1
2915
2916         addb    $0x07, %al
2917 prth1:  addb    $0x30, %al
2918         jmp     prtchr
2919
2920 # Print decimal number in al
2921 prtdec: pushw   %ax
2922         pushw   %cx
2923         xorb    %ah, %ah
2924         movb    $0x0a, %cl
2925         idivb   %cl
2926         cmpb    $0x09, %al
2927         jbe     lt100
2928
2929         call    prtdec
2930         jmp     skip10
2931
2932 lt100:  addb    $0x30, %al
2933         call    prtchr
2934 skip10: movb    %ah, %al
2935         addb    $0x30, %al
2936         call    prtchr  
2937         popw    %cx
2938         popw    %ax
2939         ret
2940
2941 store_edid:
2942         pushw   %es                             # just save all registers 
2943         pushw   %ax                             
2944         pushw   %bx
2945         pushw   %cx
2946         pushw   %dx
2947         pushw   %di
2948
2949         pushw   %fs                             
2950         popw    %es
2951
2952         movl    $0x13131313, %eax               # memset block with 0x13
2953         movw    $32, %cx
2954         movw    $0x140, %di
2955         cld
2956         rep 
2957         stosl  
2958
2959         movw    $0x4f15, %ax                    # do VBE/DDC 
2960         movw    $0x01, %bx
2961         movw    $0x00, %cx
2962         movw    $0x01, %dx
2963         movw    $0x140, %di
2964         int     $0x10   
2965
2966         popw    %di                             # restore all registers        
2967         popw    %dx
2968         popw    %cx
2969         popw    %bx
2970         popw    %ax
2971         popw    %es     
2972         ret
2973
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
2983
2984 # Status messages
2985 keymsg:         .ascii  "Press <RETURN> to see video modes available, "
2986                 .ascii  "<SPACE> to continue or wait 30 secs"
2987                 .byte   0x0d, 0x0a, 0
2988
2989 listhdr:        .byte   0x0d, 0x0a
2990                 .ascii  "Mode:    COLSxROWS:"
2991
2992 crlft:          .byte   0x0d, 0x0a, 0
2993
2994 prompt:         .byte   0x0d, 0x0a
2995                 .asciz  "Enter mode number or `scan': "
2996
2997 unknt:          .asciz  "Unknown mode ID. Try again."
2998
2999 badmdt:         .ascii  "You passed an undefined mode number."
3000                 .byte   0x0d, 0x0a, 0
3001
3002 vesaer:         .ascii  "Error: Scanning of VESA modes failed. Please "
3003                 .ascii  "report to <mj@ucw.cz>."
3004                 .byte   0x0d, 0x0a, 0
3005
3006 old_name:       .asciz  "CGA/MDA/HGA"
3007
3008 ega_name:       .asciz  "EGA"
3009
3010 svga_name:      .ascii  " "
3011
3012 vga_name:       .asciz  "VGA"
3013
3014 vesa_name:      .asciz  "VESA"
3015
3016 name_bann:      .asciz  "Video adapter: "
3017 #endif /* CONFIG_VIDEO_SELECT */
3018
3019 # Other variables:
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
3023
3024 # Setup signature -- must be last
3025 setup_sig1:     .word   SIG1
3026 setup_sig2:     .word   SIG2
3027
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).
3030
3031 modelist:
3032
3033 .text
3034 endtext:
3035 .data
3036 enddata:
3037 .bss
3038 endbss:
3039