2 * setup.S Copyright (C) 1991, 1992 Linus Torvalds
4 * setup.s is responsible for getting the system data from the BIOS,
5 * and putting them into the appropriate places in system memory.
6 * both setup.s and system has been loaded by the bootblock.
8 * This code asks the bios for memory/disk/other parameters, and
9 * puts them in a "safe" place: 0x90000-0x901FF, ie where the
10 * boot-block used to be. It is then up to the protected mode
11 * system to read them from there before the area is overwritten
14 * Move PS/2 aux init code to psaux.c
15 * (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92
17 * some changes and additional features by Christoph Niemann,
18 * March 1993/June 1994 (Christoph.Niemann@linux.org)
20 * add APM BIOS checking by Stephen Rothwell, May 1994
21 * (sfr@canb.auug.org.au)
23 * High load stuff, initrd support and position independency
24 * by Hans Lermen & Werner Almesberger, February 1996
25 * <lermen@elserv.ffm.fgan.de>, <almesber@lrc.epfl.ch>
27 * Video handling moved to video.S by Martin Mares, March 1996
28 * <mj@k332.feld.cvut.cz>
30 * Extended memory detection scheme retwiddled by orc@pell.chi.il.us (david
31 * parsons) to avoid loadlin confusion, July 1997
33 * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999.
34 * <stiker@northlink.com>
36 * Fix to work around buggy BIOSes which dont use carry bit correctly
37 * and/or report extended memory in CX/DX for e801h memory size detection
38 * call. As a result the kernel got wrong figures. The int15/e801h docs
39 * from Ralf Brown interrupt list seem to indicate AX/BX should be used
40 * anyway. So to avoid breaking many machines (presumably there was a reason
41 * to orginally use CX/DX instead of AX/BX), we do a kludge to see
42 * if CX/DX have been changed in the e801 call and if so use AX/BX .
43 * Michael Miller, April 2001 <michaelm@mjmm.org>
45 * New A20 code ported from SYSLINUX by H. Peter Anvin. AMD Elan bugfixes
46 * by Robert Schwebel, December 2001 <robert@schwebel.de>
48 * Heavily modified for NEC PC-9800 series by Kyoto University Microcomputer
49 * Club (KMC) Linux/98 project <seraphim@kmc.kyoto-u.ac.jp>, 1997-1999
52 #include <linux/config.h>
53 #include <asm/segment.h>
54 #include <linux/version.h>
55 #include <linux/compile.h>
60 /* Signature words to ensure LILO loaded us right */
64 #define HIRESO_TEXT 0xe000
65 #define NORMAL_TEXT 0xa000
67 #define BIOS_FLAG2 0x0400
68 #define BIOS_FLAG5 0x0458
69 #define RDISK_EQUIP 0x0488
70 #define BIOS_FLAG 0x0501
71 #define KB_SHFT_STS 0x053a
72 #define DISK_EQUIP 0x055c
74 INITSEG = DEF_INITSEG # 0x9000, we move boot here, out of the way
75 SYSSEG = DEF_SYSSEG # 0x1000, system loaded at 0x10000 (65536).
76 SETUPSEG = DEF_SETUPSEG # 0x9020, this is the current segment
77 # ... and the former contents of CS
79 DELTA_INITSEG = SETUPSEG - INITSEG # 0x0020
82 .globl begtext, begdata, begbss, endtext, enddata, endbss
95 # This is the setup header, and it must start at %cs:2 (old 0x9020:2)
97 .ascii "HdrS" # header signature
98 .word 0x0203 # header version number (>= 0x0105)
99 # or else old loadlin-1.5 will fail)
100 realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
101 start_sys_seg: .word SYSSEG
102 .word kernel_version # pointing to kernel version string
103 # above section of header is compatible
104 # with loadlin-1.5 (header v1.5). Don't
107 type_of_loader: .byte 0 # = 0, old one (LILO, Loadlin,
108 # Bootlin, SYSLX, bootsect...)
109 # See Documentation/i386/boot.txt for
112 # flags, unused bits must be zero (RFU) bit within loadflags
114 LOADED_HIGH = 1 # If set, the kernel is loaded high
115 CAN_USE_HEAP = 0x80 # If set, the loader also has set
116 # heap_end_ptr to tell how much
117 # space behind setup.S can be used for
119 # Only the loader knows what is free
120 #ifndef __BIG_KERNEL__
126 setup_move_size: .word 0x8000 # size to move, when setup is not
127 # loaded at 0x90000. We will move setup
128 # to 0x90000 then just before jumping
129 # into the kernel. However, only the
130 # loader knows how much data behind
131 # us also needs to be loaded.
133 code32_start: # here loaders can put a different
134 # start address for 32-bit code.
135 #ifndef __BIG_KERNEL__
136 .long 0x1000 # 0x1000 = default for zImage
138 .long 0x100000 # 0x100000 = default for big kernel
141 ramdisk_image: .long 0 # address of loaded ramdisk image
142 # Here the loader puts the 32-bit
143 # address where it loaded the image.
144 # This only will be read by the kernel.
146 ramdisk_size: .long 0 # its size in bytes
151 heap_end_ptr: .word modelist+1024 # (Header version 0x0201 or later)
152 # space from here (exclusive) down to
153 # end of setup code can be used by setup
154 # for local heap purposes.
157 cmd_line_ptr: .long 0 # (Header version 0x0202 or later)
158 # If nonzero, a 32-bit pointer
159 # to the kernel command line.
160 # The command line should be
161 # located between the start of
162 # setup and the end of low
163 # memory (0xa0000), or it may
164 # get overwritten before it
165 # gets read. If this field is
166 # used, there is no longer
167 # anything magical about the
168 # 0x90000 segment; the setup
169 # can be located anywhere in
170 # low memory 0x10000 or higher.
172 ramdisk_max: .long MAXMEM-1 # (Header version 0x0203 or later)
173 # The highest safe address for
174 # the contents of an initrd
176 trampoline: call start_of_setup
178 # End of setup header #####################################################
181 # Set %ds = %cs, we know that SETUPSEG = %cs at this point
182 movw %cs, %ax # aka SETUPSEG
184 # Check signature at end of setup
185 cmpw $SIG1, setup_sig1
188 cmpw $SIG2, setup_sig2
193 # Routine to print asciiz string at ds:si
204 no_sig_mess: .string "No setup signature found ..."
209 # We now have to find the rest of the setup code/data
211 movw %cs, %ax # SETUPSEG
212 subw $DELTA_INITSEG, %ax # INITSEG
215 movb (497), %bl # get setup sect from bootsect
216 subw $4, %bx # LILO loads 4 sectors of setup
217 shlw $8, %bx # convert to words (1sect=2^8 words)
219 shrw $3, %bx # convert to segment
221 movw %bx, %cs:start_sys_seg
222 # Move rest of setup code/data to here
223 movw $2048, %di # four sectors loaded by LILO
231 movw %cs, %ax # aka SETUPSEG
233 cmpw $SIG1, setup_sig1
236 cmpw $SIG2, setup_sig2
250 movw %cs, %ax # aka SETUPSEG
251 subw $DELTA_INITSEG, %ax # aka INITSEG
253 # Check if an old loader tries to load a big-kernel
254 testb $LOADED_HIGH, %cs:loadflags # Do we have a big kernel?
255 jz loader_ok # No, no danger for old loaders.
257 cmpb $0, %cs:type_of_loader # Do we have a loader that
259 jnz loader_ok # Yes, continue.
261 pushw %cs # No, we have an old loader,
263 lea loader_panic_mess, %si
268 loader_panic_mess: .string "Wrong loader, giving up..."
271 # Get memory size (extended mem, kB)
273 # On PC-9800, memory size detection is done completely in 32-bit
274 # kernel initialize code (kernel/setup.c).
278 movb %al, (E820NR) # PC-9800 has no E820
279 movb %es:(0x401), %al
284 movw %es:(0x594), %ax
289 # Check for video adapter and its parameters and allow the
290 # user to browse video modes.
291 call video # NOTE: we need %ds pointing
294 # Get text video mode
296 int $0x18 # CRT mode sense
297 movw $(20 << 8) + 40, %cx
305 3: # If bit 4 was 1, it means either 1) 31 lines for hi-reso mode,
306 # or 2) 30 lines for PC-9821.
307 movb $31, %ch # hireso mode value
310 testb $0x08, %es:BIOS_FLAG
313 1: # Now we got # of rows in %ch
319 2: # Now we got # of columns in %cl
322 # Next, get horizontal frequency if supported
324 int $0x18 # Call CRT bios
325 movb %al, (6) # If 31h is unsupported, %al remains 0
328 pushw %ds # aka INITSEG
334 movb DISK_EQUIP+1, %ah
344 1: xorw %cx, %cx # `0 cylinders' means no drive
345 2: # Attention! Work area (drive_info) is arranged for PC-9800.
346 movw %cx, %ax # # of cylinders
348 movw %dx, %ax # # of sectors / # of heads
350 movw %bx, %ax # sector size in bytes
361 movb RDISK_EQUIP, %al
363 andb %al, %ah # ignore all `RAM drive'
374 andb $4, %al # 1.44MB support flag
376 addb $2, %al # %al = 2 (1.2MB) or 4 (1.44MB)
378 1: movb $0, %al # no drive
385 addb $(0xb0 - 0x34), %al
386 jnc get_fd_info # check FDs on 640KB I/F
389 popw %ds # %ds got bootsector again
391 mov $0, (0x1ff) # default is no pointing device
394 #if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
395 # Then check for an APM BIOS...
396 # %ds points to the bootsector
397 movw $0, 0x40 # version = 0 means no APM BIOS
398 movw $0x09a00, %ax # APM BIOS installation check
401 jc done_apm_bios # Nope, no APM BIOS
403 cmpw $0x0504d, %bx # Check for "PM" signature
404 jne done_apm_bios # No signature, no APM BIOS
406 testb $0x02, %cl # Is 32 bit supported?
407 je done_apm_bios # No 32-bit, no (good) APM BIOS
409 movw $0x09a04, %ax # Disconnect first just in case
411 int $0x1f # ignore return code
412 movw $0x09a03, %ax # 32 bit connect
415 jc no_32_apm_bios # Ack, error.
417 movw %ax, (66) # BIOS code segment
418 movl %ebx, (68) # BIOS entry point offset
419 movw %cx, (72) # BIOS 16 bit code segment
420 movw %dx, (74) # BIOS data segment
421 movl %esi, (78) # BIOS code segment length
422 movw %di, (82) # BIOS data segment length
423 # Redo the installation check as the 32 bit connect
424 # modifies the flags returned on some BIOSs
425 movw $0x09a00, %ax # APM BIOS installation check
428 jc apm_disconnect # error -> shouldn't happen
430 cmpw $0x0504d, %bx # check for "PM" signature
431 jne apm_disconnect # no sig -> shouldn't happen
433 movw %ax, (64) # record the APM BIOS version
434 movw %cx, (76) # and flags
437 apm_disconnect: # Tidy up
438 movw $0x09a04, %ax # Disconnect
440 int $0x1f # ignore return code
445 andw $0xfffd, (76) # remove 32 bit support bit
449 # Pass cursor position to kernel...
450 movw %cs:cursor_address, %ax
451 shrw %ax # cursor_address is 2 bytes unit
454 xchgb %al, %ah # (0) = %al = X, (1) = %ah = Y
469 .section .rodata, "a"
470 msg_cpos: .string "Cursor position: 0x"
476 # Now we want to move to protected mode ...
477 cmpw $0, %cs:realmode_swtch
480 lcall *%cs:realmode_swtch
489 # we get the code32 start address and modify the below 'jmpi'
490 # (loader may have changed it)
491 movl %cs:code32_start, %eax
492 movl %eax, %cs:code32
494 # Now we move the system to its rightful place ... but we check if we have a
495 # big-kernel. In that case we *must* not move it ...
496 testb $LOADED_HIGH, %cs:loadflags
497 jz do_move0 # .. then we have a normal low
499 # .. or else we have a high
501 jmp end_move # ... and we skip moving
504 movw $0x100, %ax # start of destination segment
505 movw %cs, %bp # aka SETUPSEG
506 subw $DELTA_INITSEG, %bp # aka INITSEG
507 movw %cs:start_sys_seg, %bx # start of source segment
510 movw %ax, %es # destination segment
511 incb %ah # instead of add ax,#0x100
512 movw %bx, %ds # source segment
519 cmpw %bp, %bx # assume start_sys_seg > 0x200,
520 # so we will perhaps read one
521 # page more than needed, but
522 # never overwrite INITSEG
523 # because destination is a
524 # minimum one page below source
528 # then we load the segment descriptors
529 movw %cs, %ax # aka SETUPSEG
532 # Check whether we need to be downward compatible with version <=201
533 cmpl $0, cmd_line_ptr
534 jne end_move_self # loader uses version >=202 features
535 cmpb $0x20, type_of_loader
536 je end_move_self # bootsect loader, we know of it
538 # Boot loader does not support boot protocol version 2.02.
539 # If we have our code not at 0x90000, we need to move it there now.
540 # We also then need to move the params behind it (commandline)
541 # Because we would overwrite the code on the current IP, we move
542 # it in two steps, jumping high after the first one.
547 cli # make sure we really have
548 # interrupts disabled !
549 # because after this the stack
551 subw $DELTA_INITSEG, %ax # aka INITSEG
557 subw %ax, %dx # this will go into %ss after
561 movw $INITSEG, %ax # real INITSEG
563 movw %cs:setup_move_size, %cx
564 std # we have to move up, so we use
565 # direction down because the
570 subw $move_self_here+0x200, %cx
573 ljmp $SETUPSEG, $move_self_here
576 movw $move_self_here+0x200, %cx
583 end_move_self: # now we are at the right place
584 lidt idt_48 # load idt with 0,0
585 xorl %eax, %eax # Compute gdt_base
586 movw %ds, %ax # (Convert %ds:gdt to a linear ptr)
589 movl %eax, (gdt_48+2)
590 lgdt gdt_48 # load gdt with whatever is
593 # that was painless, now we enable A20
595 outb %al, $0xf2 # A20 on
597 outb %al, $0xf6 # also A20 on; making ITF's
600 # PC-9800 seems to enable A20 at the moment of `outb';
601 # so we don't wait unlike IBM PCs (see ../setup.S).
603 # enable DMA to access memory over 0x100000 (1MB).
610 # Set DMA to increment its bank address automatically at 16MB boundary.
611 # Initial setting is 64KB boundary mode so that we can't run DMA crossing
612 # physical address 0xXXXXFFFF.
615 outb %al, $0x29 # ch. 0
617 outb %al, $0x29 # ch. 1
619 outb %al, $0x29 # ch. 2
621 outb %al, $0x29 # ch. 3
623 outb %al, $0x11 # reinitialize DMAC
625 # make sure any possible coprocessor is properly reset..
628 outb %al, $0x5f # delay
630 # well, that went ok, I hope. Now we mask all interrupts - the rest
631 # is done in init_IRQ().
632 movb $0xFF, %al # mask all interrupts for now
634 outb %al, $0x5f # delay
636 movb $0x7F, %al # mask all irq's but irq7 which
637 outb %al, $0x02 # is cascaded
639 # Well, that certainly wasn't fun :-(. Hopefully it works, and we don't
640 # need no steenking BIOS anyway (except for the initial loading :-).
641 # The BIOS-routine wants lots of unnecessary data, and it's less
642 # "interesting" anyway. This is how REAL programmers do it.
644 # Well, now's the time to actually move into protected mode. To make
645 # things as simple as possible, we do no register set-up or anything,
646 # we let the gnu-compiled 32-bit programs do that. We just jump to
647 # absolute address 0x1000 (or the loader supplied one),
648 # in 32-bit protected mode.
650 # Note that the short jump isn't strictly needed, although there are
651 # reasons why it might be a good idea. It won't hurt in any case.
652 movw $1, %ax # protected mode (PE) bit
653 lmsw %ax # This is it!
657 xorw %bx, %bx # Flag to indicate a boot
658 xorl %esi, %esi # Pointer to real-mode code
660 subw $DELTA_INITSEG, %si
661 shll $4, %esi # Convert to 32-bit pointer
662 # NOTE: For high loaded big kernels we need a
663 # jmpi 0x100000,__BOOT_CS
665 # but we yet haven't reloaded the CS register, so the default size
666 # of the target offset still is 16 bit.
667 # However, using an operand prefix (0x66), the CPU will properly
668 # take our 48 bit far pointer. (INTeL 80386 Programmer's Reference
669 # Manual, Mixing 16-bit and 32-bit code, page 16-6)
671 .byte 0x66, 0xea # prefix + jmpi-opcode
672 code32: .long 0x1000 # will be set to 0x100000
676 # Here's a bunch of information about your current kernel..
677 kernel_version: .ascii UTS_RELEASE
679 .ascii LINUX_COMPILE_BY
681 .ascii LINUX_COMPILE_HOST
686 # This is the default real mode switch routine.
687 # to be called just before protected mode transition
689 cli # no interrupts allowed !
690 outb %al, $0x50 # disable NMI for bootup
695 # This routine prints one character (in %al) on console.
696 # PC-9800 doesn't have BIOS-function to do it like IBM PC's INT 10h - 0Eh,
697 # so we hardcode `prtchr' subroutine here.
701 cmpb $0, %cs:prtchr_initialized
705 testb $0x8, %es:BIOS_FLAG
707 movb $(HIRESO_TEXT >> 8), %cs:cursor_address+3
708 movw $(80 * 31 * 2), %cs:max_cursor_offset
710 call get_cursor_position
711 movw %ax, %cs:cursor_address
713 movb $1, %cs:prtchr_initialized
715 lesw %cs:cursor_address, %di
723 # normal (printable) character
725 movb $0xe1, %es:0x2000-2(%di)
729 divb %bl # %al = Y, %ah = X * 2
735 1: movw %cs:max_cursor_offset, %cx
739 # cursor reaches bottom of screen; scroll it
748 movb $32, %al # clear bottom line characters
755 movb $0xe1, %al # clear bottom line attributes
758 2: movw %dx, %cs:cursor_address
759 movb $0x13, %ah # move cursor to right position
769 .word 80 * 25 * 2 # for normal 80x25 mode
771 # putstr may called without running through start_of_setup (via bootsect_panic)
772 # so we should initialize ourselves on demand.
776 # This routine queries GDC (graphic display controller) for current cursor
777 # position. Cursor position is returned in %ax (CPU offset address).
780 outb %al, $0x5f # delay
781 outb %al, $0x5f # delay
782 testb $0x04, %al # Is FIFO empty?
783 jz 1b # no -> wait until empty
785 movb $0xe0, %al # CSRR command
786 outb %al, $0x62 # command write
787 outb %al, $0x5f # delay
788 outb %al, $0x5f # delay
791 outb %al, $0x5f # delay
792 outb %al, $0x5f # delay
793 testb $0x01, %al # Is DATA READY?
794 jz 2b # no -> wait until ready
796 inb $0x62, %al # read xAD (L)
797 outb %al, $0x5f # delay
798 outb %al, $0x5f # delay
800 inb $0x62, %al # read xAD (H)
801 outb %al, $0x5f # delay
802 outb %al, $0x5f # delay
803 xchgb %al, %ah # correct byte order
805 inb $0x62, %al # read yAD (L)
806 outb %al, $0x5f # delay
807 outb %al, $0x5f # delay
808 inb $0x62, %al # read yAD (M)
809 outb %al, $0x5f # delay
810 outb %al, $0x5f # delay
811 inb $0x62, %al # read yAD (H)
812 # yAD is not our interest,
815 addw %ax, %ax # convert to CPU address
820 # NOTE: The intel manual says gdt should be sixteen bytes aligned for
821 # efficiency reasons. However, there are machines which are known not
822 # to boot with misaligned GDTs, so alter this at your peril! If you alter
823 # GDT_ENTRY_BOOT_CS (in asm/segment.h) remember to leave at least two
824 # empty GDT entries (one for NULL and one reserved).
826 # NOTE: On some CPUs, the GDT must be 8 byte aligned. This is
827 # true for the Voyager Quad CPU card which will not boot without
828 # This directive. 16 byte aligment is recommended by intel.
832 .fill GDT_ENTRY_BOOT_CS,8,0
834 .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
835 .word 0 # base address = 0
836 .word 0x9A00 # code read/exec
837 .word 0x00CF # granularity = 4096, 386
838 # (+5th nibble of limit)
840 .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
841 .word 0 # base address = 0
842 .word 0x9200 # data read/write
843 .word 0x00CF # granularity = 4096, 386
844 # (+5th nibble of limit)
848 .word 0 # alignment byte
850 .word 0 # idt limit = 0
851 .word 0, 0 # idt base = 0L
853 .word 0 # alignment byte
855 .word gdt_end - gdt - 1 # gdt limit
856 .word 0, 0 # gdt base (filled in later)
858 # Include video setup & detection code
862 # Setup signature -- must be last
863 setup_sig1: .word SIG1
864 setup_sig2: .word SIG2
866 # After this point, there is some free space which is used by the video mode
867 # handling code to store the temporary mode table (not used by the kernel).