summaryrefslogtreecommitdiffstats
path: root/arch/i386
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1994-11-28 11:59:19 +0000
committer <ralf@linux-mips.org>1994-11-28 11:59:19 +0000
commit1513ff9b7899ab588401c89db0e99903dbf5f886 (patch)
treef69cc81a940a502ea23d664c3ffb2d215a479667 /arch/i386
Import of Linus's Linux 1.1.68
Diffstat (limited to 'arch/i386')
-rw-r--r--arch/i386/Makefile107
-rw-r--r--arch/i386/boot/bootsect.S460
-rw-r--r--arch/i386/boot/head.S349
-rw-r--r--arch/i386/boot/setup.S1011
-rw-r--r--arch/i386/config.in219
-rw-r--r--arch/i386/entry.S545
6 files changed, 2691 insertions, 0 deletions
diff --git a/arch/i386/Makefile b/arch/i386/Makefile
new file mode 100644
index 000000000..1b878067a
--- /dev/null
+++ b/arch/i386/Makefile
@@ -0,0 +1,107 @@
+#
+# i386/Makefile
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 1994 by Linus Torvalds
+#
+
+AS86 =as86 -0 -a
+LD86 =ld86 -0
+AS =as
+LD =ld
+HOSTCC =gcc -I$(TOPDIR)/include
+CC =gcc -D__KERNEL__ -I$(TOPDIR)/include
+MAKE =make
+CPP =$(CC) -E
+AR =ar
+STRIP =strip
+
+ifdef CONFIG_M486
+CFLAGS := $(CFLAGS) -m486
+else
+CFLAGS := $(CFLAGS) -m386
+endif
+
+zBoot/zSystem: zBoot/*.c zBoot/*.S tools/zSystem
+ $(MAKE) -C zBoot
+
+zImage: $(CONFIGURE) boot/bootsect boot/setup zBoot/zSystem tools/build
+ tools/build boot/bootsect boot/setup zBoot/zSystem $(ROOT_DEV) > zImage
+ sync
+
+zdisk: zImage
+ dd bs=8192 if=zImage of=/dev/fd0
+
+zlilo: $(CONFIGURE) zImage
+ if [ -f $(INSTALL_PATH)/vmlinuz ]; then mv $(INSTALL_PATH)/vmlinuz $(INSTALL_PATH)/vmlinuz.old; fi
+ if [ -f $(INSTALL_PATH)/zSystem.map ]; then mv $(INSTALL_PATH)/zSystem.map $(INSTALL_PATH)/zSystem.old; fi
+ cat zImage > $(INSTALL_PATH)/vmlinuz
+ cp zSystem.map $(INSTALL_PATH)/
+ if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
+
+#
+# Set these to indicate how to link it..
+#
+# -zmagic:
+#
+#LOWLDFLAGS = -Ttext 0x1000
+#HIGHLDFLAGS = -Ttext 0x100000
+#
+# -qmagic (we need to remove the 32 byte header for bootup purposes)
+#
+LOWLDFLAGS =-qmagic -Ttext 0xfe0
+HIGHLDFLAGS =-qmagic -Ttext 0xfffe0
+
+tools/system: boot/head.o init/main.o tools/version.o linuxsubdirs
+ $(LD) $(LOWLDFLAGS) boot/head.o init/main.o tools/version.o \
+ $(ARCHIVES) \
+ $(FILESYSTEMS) \
+ $(DRIVERS) \
+ $(LIBS) \
+ -o tools/system
+ nm tools/zSystem | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)' | \
+ sort > System.map
+
+boot/setup: boot/setup.o
+ $(LD86) -s -o $@ $<
+
+boot/setup.o: boot/setup.s
+ $(AS86) -o $@ $<
+
+boot/setup.s: boot/setup.S $(CONFIGURE) include/linux/config.h Makefile
+ $(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
+
+boot/bootsect: boot/bootsect.o
+ $(LD86) -s -o $@ $<
+
+boot/bootsect.o: boot/bootsect.s
+ $(AS86) -o $@ $<
+
+boot/bootsect.s: boot/bootsect.S $(CONFIGURE) include/linux/config.h Makefile
+ $(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
+
+tools/zSystem: boot/head.o init/main.o tools/version.o linuxsubdirs
+ $(LD) $(HIGHLDFLAGS) boot/head.o init/main.o tools/version.o \
+ $(ARCHIVES) \
+ $(FILESYSTEMS) \
+ $(DRIVERS) \
+ $(LIBS) \
+ -o tools/zSystem
+ nm tools/zSystem | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)' | \
+ sort > zSystem.map
+
+#
+# Leave these dummy entries for now to tell people that they are going away..
+#
+lilo:
+ @echo
+ @echo Uncompressed kernel images no longer supported. Use
+ @echo \"make zlilo\" instead.
+ @echo
+ @exit 1
+
+archclean:
+ rm -f boot/bootsect boot/setup
diff --git a/arch/i386/boot/bootsect.S b/arch/i386/boot/bootsect.S
new file mode 100644
index 000000000..f6a0d3158
--- /dev/null
+++ b/arch/i386/boot/bootsect.S
@@ -0,0 +1,460 @@
+!
+! SYS_SIZE is the number of clicks (16 bytes) to be loaded.
+! 0x7F00 is 0x7F000 bytes = 508kB, more than enough for current
+! versions of linux which compress the kernel
+!
+#include <linux/config.h>
+SYSSIZE = DEF_SYSSIZE
+!
+! bootsect.s Copyright (C) 1991, 1992 Linus Torvalds
+! modified by Drew Eckhardt
+! modified by Bruce Evans (bde)
+!
+! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
+! itself out of the way to address 0x90000, and jumps there.
+!
+! bde - should not jump blindly, there may be systems with only 512K low
+! memory. Use int 0x12 to get the top of memory, etc.
+!
+! It then loads 'setup' directly after itself (0x90200), and the system
+! at 0x10000, using BIOS interrupts.
+!
+! NOTE! currently system is at most (8*65536-4096) bytes long. This should
+! be no problem, even in the future. I want to keep it simple. This 508 kB
+! kernel size should be enough, especially as this doesn't contain the
+! buffer cache as in minix (and especially now that the kernel is
+! compressed :-)
+!
+! The loader has been made as simple as possible, and continuous
+! read errors will result in a unbreakable loop. Reboot by hand. It
+! loads pretty fast by getting whole tracks at a time whenever possible.
+
+.text
+
+SETUPSECS = 4 ! nr of setup-sectors
+BOOTSEG = 0x07C0 ! original address of boot-sector
+INITSEG = DEF_INITSEG ! we move boot here - out of the way
+SETUPSEG = DEF_SETUPSEG ! setup starts here
+SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536).
+
+! ROOT_DEV & SWAP_DEV are now written by "build".
+ROOT_DEV = 0
+SWAP_DEV = 0
+#ifndef SVGA_MODE
+#define SVGA_MODE ASK_VGA
+#endif
+#ifndef RAMDISK
+#define RAMDISK 0
+#endif
+#ifndef CONFIG_ROOT_RDONLY
+#define CONFIG_ROOT_RDONLY 0
+#endif
+
+! ld86 requires an entry symbol. This may as well be the usual one.
+.globl _main
+_main:
+#if 0 /* hook for debugger, harmless unless BIOS is fussy (old HP) */
+ int 3
+#endif
+ mov ax,#BOOTSEG
+ mov ds,ax
+ mov ax,#INITSEG
+ mov es,ax
+ mov cx,#256
+ sub si,si
+ sub di,di
+ cld
+ rep
+ movsw
+ jmpi go,INITSEG
+
+! ax and es already contain INITSEG
+
+go: mov di,#0x4000-12 ! 0x4000 is arbitrary value >= length of
+ ! bootsect + length of setup + room for stack
+ ! 12 is disk parm size
+
+! bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde). We
+! wouldn't have to worry about this if we checked the top of memory. Also
+! my BIOS can be configured to put the wini drive tables in high memory
+! instead of in the vector table. The old stack might have clobbered the
+! drive table.
+
+ mov ds,ax
+ mov ss,ax ! put stack at INITSEG:0x4000-12.
+ mov sp,di
+/*
+ * Many BIOS's default disk parameter tables will not
+ * recognize multi-sector reads beyond the maximum sector number
+ * specified in the default diskette parameter tables - this may
+ * mean 7 sectors in some cases.
+ *
+ * Since single sector reads are slow and out of the question,
+ * we must take care of this by creating new parameter tables
+ * (for the first disk) in RAM. We will set the maximum sector
+ * count to 36 - the most we will encounter on an ED 2.88.
+ *
+ * High doesn't hurt. Low does.
+ *
+ * Segments are as follows: ds=es=ss=cs - INITSEG,
+ * fs = 0, gs is unused.
+ */
+
+! cx contains 0 from rep movsw above
+
+ mov fs,cx
+ mov bx,#0x78 ! fs:bx is parameter table address
+ push ds
+ seg fs
+ lds si,(bx) ! ds:si is source
+
+ mov cl,#6 ! copy 12 bytes
+ cld
+ push di
+
+ rep
+ movsw
+
+ pop di
+ pop ds
+
+ movb 4(di),*36 ! patch sector count
+
+ seg fs
+ mov (bx),di
+ seg fs
+ mov 2(bx),es
+
+! load the setup-sectors directly after the bootblock.
+! Note that 'es' is already set up.
+! Also cx is 0 from rep movsw above.
+
+load_setup:
+ xor ah,ah ! reset FDC
+ xor dl,dl
+ int 0x13
+
+ xor dx, dx ! drive 0, head 0
+ mov cl,#0x02 ! sector 2, track 0
+ mov bx,#0x0200 ! address = 512, in INITSEG
+ mov ah,#0x02 ! service 2, nr of sectors
+ mov al,setup_sects ! (assume all on head 0, track 0)
+ int 0x13 ! read it
+ jnc ok_load_setup ! ok - continue
+
+ push ax ! dump error code
+ call print_nl
+ mov bp, sp
+ call print_hex
+ pop ax
+
+ jmp load_setup
+
+ok_load_setup:
+
+! Get disk drive parameters, specifically nr of sectors/track
+
+#if 0
+
+! bde - the Phoenix BIOS manual says function 0x08 only works for fixed
+! disks. It doesn't work for one of my BIOS's (1987 Award). It was
+! fatal not to check the error code.
+
+ xor dl,dl
+ mov ah,#0x08 ! AH=8 is get drive parameters
+ int 0x13
+ xor ch,ch
+#else
+
+! It seems that there is no BIOS call to get the number of sectors. Guess
+! 36 sectors if sector 36 can be read, 18 sectors if sector 18 can be read,
+! 15 if sector 15 can be read. Otherwise guess 9.
+
+ mov si,#disksizes ! table of sizes to try
+
+probe_loop:
+ lodsb
+ cbw ! extend to word
+ mov sectors, ax
+ cmp si,#disksizes+4
+ jae got_sectors ! if all else fails, try 9
+ xchg ax, cx ! cx = track and sector
+ xor dx, dx ! drive 0, head 0
+ xor bl, bl
+ mov bh,setup_sects
+ inc bh
+ shl bh,#1 ! address after setup (es = cs)
+ mov ax,#0x0201 ! service 2, 1 sector
+ int 0x13
+ jc probe_loop ! try next value
+
+#endif
+
+got_sectors:
+
+! Restore es
+
+ mov ax,#INITSEG
+ mov es,ax
+
+! Print some inane message
+
+ mov ah,#0x03 ! read cursor pos
+ xor bh,bh
+ int 0x10
+
+ mov cx,#9
+ mov bx,#0x0007 ! page 0, attribute 7 (normal)
+ mov bp,#msg1
+ mov ax,#0x1301 ! write string, move cursor
+ int 0x10
+
+! ok, we've written the message, now
+! we want to load the system (at 0x10000)
+
+ mov ax,#SYSSEG
+ mov es,ax ! segment of 0x010000
+ call read_it
+ call kill_motor
+ call print_nl
+
+! After that we check which root-device to use. If the device is
+! defined (!= 0), nothing is done and the given device is used.
+! Otherwise, one of /dev/fd0H2880 (2,32) or /dev/PS0 (2,28) or /dev/at0 (2,8),
+! depending on the number of sectors we pretend to know we have.
+
+ seg cs
+ mov ax,root_dev
+ or ax,ax
+ jne root_defined
+ seg cs
+ mov bx,sectors
+ mov ax,#0x0208 ! /dev/ps0 - 1.2Mb
+ cmp bx,#15
+ je root_defined
+ mov al,#0x1c ! /dev/PS0 - 1.44Mb
+ cmp bx,#18
+ je root_defined
+ mov al,#0x20 ! /dev/fd0H2880 - 2.88Mb
+ cmp bx,#36
+ je root_defined
+ mov al,#0 ! /dev/fd0 - autodetect
+root_defined:
+ seg cs
+ mov root_dev,ax
+
+! after that (everything loaded), we jump to
+! the setup-routine loaded directly after
+! the bootblock:
+
+ jmpi 0,SETUPSEG
+
+! This routine loads the system at address 0x10000, making sure
+! no 64kB boundaries are crossed. We try to load it as fast as
+! possible, loading whole tracks whenever we can.
+!
+! in: es - starting address segment (normally 0x1000)
+!
+sread: .word 0 ! sectors read of current track
+head: .word 0 ! current head
+track: .word 0 ! current track
+
+read_it:
+ mov al,setup_sects
+ inc al
+ mov sread,al
+ mov ax,es
+ test ax,#0x0fff
+die: jne die ! es must be at 64kB boundary
+ xor bx,bx ! bx is starting address within segment
+rp_read:
+ mov ax,es
+ sub ax,#SYSSEG
+ cmp ax,syssize ! have we loaded all yet?
+ jbe ok1_read
+ ret
+ok1_read:
+ mov ax,sectors
+ sub ax,sread
+ mov cx,ax
+ shl cx,#9
+ add cx,bx
+ jnc ok2_read
+ je ok2_read
+ xor ax,ax
+ sub ax,bx
+ shr ax,#9
+ok2_read:
+ call read_track
+ mov cx,ax
+ add ax,sread
+ cmp ax,sectors
+ jne ok3_read
+ mov ax,#1
+ sub ax,head
+ jne ok4_read
+ inc track
+ok4_read:
+ mov head,ax
+ xor ax,ax
+ok3_read:
+ mov sread,ax
+ shl cx,#9
+ add bx,cx
+ jnc rp_read
+ mov ax,es
+ add ah,#0x10
+ mov es,ax
+ xor bx,bx
+ jmp rp_read
+
+read_track:
+ pusha
+ pusha
+ mov ax, #0xe2e ! loading... message 2e = .
+ mov bx, #7
+ int 0x10
+ popa
+
+ mov dx,track
+ mov cx,sread
+ inc cx
+ mov ch,dl
+ mov dx,head
+ mov dh,dl
+ and dx,#0x0100
+ mov ah,#2
+
+ push dx ! save for error dump
+ push cx
+ push bx
+ push ax
+
+ int 0x13
+ jc bad_rt
+ add sp, #8
+ popa
+ ret
+
+bad_rt: push ax ! save error code
+ call print_all ! ah = error, al = read
+
+
+ xor ah,ah
+ xor dl,dl
+ int 0x13
+
+
+ add sp, #10
+ popa
+ jmp read_track
+
+/*
+ * print_all is for debugging purposes.
+ * It will print out all of the registers. The assumption is that this is
+ * called from a routine, with a stack frame like
+ * dx
+ * cx
+ * bx
+ * ax
+ * error
+ * ret <- sp
+ *
+*/
+
+print_all:
+ mov cx, #5 ! error code + 4 registers
+ mov bp, sp
+
+print_loop:
+ push cx ! save count left
+ call print_nl ! nl for readability
+
+ cmp cl, #5
+ jae no_reg ! see if register name is needed
+
+ mov ax, #0xe05 + 'A - 1
+ sub al, cl
+ int 0x10
+
+ mov al, #'X
+ int 0x10
+
+ mov al, #':
+ int 0x10
+
+no_reg:
+ add bp, #2 ! next register
+ call print_hex ! print it
+ pop cx
+ loop print_loop
+ ret
+
+print_nl:
+ mov ax, #0xe0d ! CR
+ int 0x10
+ mov al, #0xa ! LF
+ int 0x10
+ ret
+
+/*
+ * print_hex is for debugging purposes, and prints the word
+ * pointed to by ss:bp in hexadecimal.
+*/
+
+print_hex:
+ mov cx, #4 ! 4 hex digits
+ mov dx, (bp) ! load word into dx
+print_digit:
+ rol dx, #4 ! rotate so that lowest 4 bits are used
+ mov ax, #0xe0f ! ah = request, al = mask for nybble
+ and al, dl
+ add al, #0x90 ! convert al to ascii hex (four instructions)
+ daa
+ adc al, #0x40
+ daa
+ int 0x10
+ loop print_digit
+ ret
+
+
+/*
+ * This procedure turns off the floppy drive motor, so
+ * that we enter the kernel in a known state, and
+ * don't have to worry about it later.
+ */
+kill_motor:
+ push dx
+ mov dx,#0x3f2
+ xor al, al
+ outb
+ pop dx
+ ret
+
+sectors:
+ .word 0
+
+disksizes:
+ .byte 36,18,15,9
+
+msg1:
+ .byte 13,10
+ .ascii "Loading"
+
+.org 497
+setup_sects:
+ .byte SETUPSECS
+root_flags:
+ .word CONFIG_ROOT_RDONLY
+syssize:
+ .word SYSSIZE
+swap_dev:
+ .word SWAP_DEV
+ram_size:
+ .word RAMDISK
+vid_mode:
+ .word SVGA_MODE
+root_dev:
+ .word ROOT_DEV
+boot_flag:
+ .word 0xAA55
diff --git a/arch/i386/boot/head.S b/arch/i386/boot/head.S
new file mode 100644
index 000000000..896c62f18
--- /dev/null
+++ b/arch/i386/boot/head.S
@@ -0,0 +1,349 @@
+/*
+ * linux/boot/head.S
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+/*
+ * head.S contains the 32-bit startup code.
+ */
+
+.text
+.globl _idt,_gdt,
+.globl _swapper_pg_dir,_pg0
+.globl _empty_bad_page
+.globl _empty_bad_page_table
+.globl _empty_zero_page
+.globl _floppy_track_buffer
+
+#define __ASSEMBLY__
+#include <linux/tasks.h>
+#include <linux/fd.h>
+#include <asm/segment.h>
+
+#define CL_MAGIC_ADDR 0x90020
+#define CL_MAGIC 0xA33F
+#define CL_BASE_ADDR 0x90000
+#define CL_OFFSET 0x90022
+
+/*
+ * swapper_pg_dir is the main page directory, address 0x00001000 (or at
+ * address 0x00101000 for a compressed boot).
+ */
+startup_32:
+ cld
+ movl $(KERNEL_DS),%eax
+ mov %ax,%ds
+ mov %ax,%es
+ mov %ax,%fs
+ mov %ax,%gs
+ lss _stack_start,%esp
+/*
+ * Clear BSS first so that there are no surprises...
+ */
+ xorl %eax,%eax
+ movl $__edata,%edi
+ movl $__end,%ecx
+ subl %edi,%ecx
+ cld
+ rep
+ stosb
+/*
+ * start system 32-bit setup. We need to re-do some of the things done
+ * in 16-bit mode for the "real" operations.
+ */
+ call setup_idt
+ xorl %eax,%eax
+1: incl %eax # check that A20 really IS enabled
+ movl %eax,0x000000 # loop forever if it isn't
+ cmpl %eax,0x100000
+ je 1b
+/*
+ * Initialize eflags. Some BIOS's leave bits like NT set. This would
+ * confuse the debugger if this code is traced.
+ * XXX - best to initialize before switching to protected mode.
+ */
+ pushl $0
+ popfl
+/*
+ * Copy bootup parameters out of the way. First 2kB of
+ * _empty_zero_page is for boot parameters, second 2kB
+ * is for the command line.
+ */
+ movl $0x90000,%esi
+ movl $_empty_zero_page,%edi
+ movl $512,%ecx
+ cld
+ rep
+ movsl
+ xorl %eax,%eax
+ movl $512,%ecx
+ rep
+ stosl
+ cmpw $(CL_MAGIC),CL_MAGIC_ADDR
+ jne 1f
+ movl $_empty_zero_page+2048,%edi
+ movzwl CL_OFFSET,%esi
+ addl $(CL_BASE_ADDR),%esi
+ movl $2048,%ecx
+ rep
+ movsb
+1:
+/* check if it is 486 or 386. */
+/*
+ * XXX - this does a lot of unnecessary setup. Alignment checks don't
+ * apply at our cpl of 0 and the stack ought to be aligned already, and
+ * we don't need to preserve eflags.
+ */
+ movl %esp,%edi # save stack pointer
+ andl $0xfffffffc,%esp # align stack to avoid AC fault
+ movl $3,_x86
+ pushfl # push EFLAGS
+ popl %eax # get EFLAGS
+ movl %eax,%ecx # save original EFLAGS
+ xorl $0x40000,%eax # flip AC bit in EFLAGS
+ pushl %eax # copy to EFLAGS
+ popfl # set EFLAGS
+ pushfl # get new EFLAGS
+ popl %eax # put it in eax
+ xorl %ecx,%eax # change in flags
+ andl $0x40000,%eax # check if AC bit changed
+ je is386
+ movl $4,_x86
+ movl %ecx,%eax
+ xorl $0x200000,%eax # check ID flag
+ pushl %eax
+ popfl # if we are on a straight 486DX, SX, or
+ pushfl # 487SX we can't change it
+ popl %eax
+ xorl %ecx,%eax
+ andl $0x200000,%eax
+ je is486
+isnew: pushl %ecx # restore original EFLAGS
+ popfl
+ movl $1, %eax # Use the CPUID instruction to
+ .byte 0x0f, 0xa2 # check the processor type
+ andl $0xf00, %eax # Set _x86 with the family
+ shrl $8, %eax # returned.
+ movl %eax, _x86
+ movl %edi,%esp # restore esp
+ movl %cr0,%eax # 486+
+ andl $0x80000011,%eax # Save PG,PE,ET
+ orl $0x50022,%eax # set AM, WP, NE and MP
+ jmp 2f
+is486: pushl %ecx # restore original EFLAGS
+ popfl
+ movl %edi,%esp # restore esp
+ movl %cr0,%eax # 486
+ andl $0x80000011,%eax # Save PG,PE,ET
+ orl $0x50022,%eax # set AM, WP, NE and MP
+ jmp 2f
+is386: pushl %ecx # restore original EFLAGS
+ popfl
+ movl %edi,%esp # restore esp
+ movl %cr0,%eax # 386
+ andl $0x80000011,%eax # Save PG,PE,ET
+ orl $2,%eax # set MP
+2: movl %eax,%cr0
+ call check_x87
+ call setup_paging
+ lgdt gdt_descr
+ lidt idt_descr
+ ljmp $(KERNEL_CS),$1f
+1: movl $(KERNEL_DS),%eax # reload all the segment registers
+ mov %ax,%ds # after changing gdt.
+ mov %ax,%es
+ mov %ax,%fs
+ mov %ax,%gs
+ lss _stack_start,%esp
+ xorl %eax,%eax
+ lldt %ax
+ pushl %eax # These are the parameters to main :-)
+ pushl %eax
+ pushl %eax
+ cld # gcc2 wants the direction flag cleared at all times
+ call _start_kernel
+L6:
+ jmp L6 # main should never return here, but
+ # just in case, we know what happens.
+
+/*
+ * We depend on ET to be correct. This checks for 287/387.
+ */
+check_x87:
+ movl $0,_hard_math
+ clts
+ fninit
+ fstsw %ax
+ cmpb $0,%al
+ je 1f
+ movl %cr0,%eax /* no coprocessor: have to set bits */
+ xorl $4,%eax /* set EM */
+ movl %eax,%cr0
+ ret
+.align 2
+1: movl $1,_hard_math
+ .byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */
+ ret
+
+/*
+ * setup_idt
+ *
+ * sets up a idt with 256 entries pointing to
+ * ignore_int, interrupt gates. It doesn't actually load
+ * idt - that can be done only after paging has been enabled
+ * and the kernel moved to 0xC0000000. Interrupts
+ * are enabled elsewhere, when we can be relatively
+ * sure everything is ok.
+ */
+setup_idt:
+ lea ignore_int,%edx
+ movl $(KERNEL_CS << 16),%eax
+ movw %dx,%ax /* selector = 0x0010 = cs */
+ movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
+
+ lea _idt,%edi
+ mov $256,%ecx
+rp_sidt:
+ movl %eax,(%edi)
+ movl %edx,4(%edi)
+ addl $8,%edi
+ dec %ecx
+ jne rp_sidt
+ ret
+
+
+/*
+ * Setup_paging
+ *
+ * This routine sets up paging by setting the page bit
+ * in cr0. The page tables are set up, identity-mapping
+ * the first 4MB. The rest are initialized later.
+ *
+ * (ref: added support for up to 32mb, 17Apr92) -- Rik Faith
+ * (ref: update, 25Sept92) -- croutons@crunchy.uucp
+ * (ref: 92.10.11 - Linus Torvalds. Corrected 16M limit - no upper memory limit)
+ */
+.align 2
+setup_paging:
+ movl $1024*2,%ecx /* 2 pages - swapper_pg_dir+1 page table */
+ xorl %eax,%eax
+ movl $_swapper_pg_dir,%edi /* swapper_pg_dir is at 0x1000 */
+ cld;rep;stosl
+/* Identity-map the kernel in low 4MB memory for ease of transition */
+ movl $_pg0+7,_swapper_pg_dir /* set present bit/user r/w */
+/* But the real place is at 0xC0000000 */
+ movl $_pg0+7,_swapper_pg_dir+3072 /* set present bit/user r/w */
+ movl $_pg0+4092,%edi
+ movl $0x03ff007,%eax /* 4Mb - 4096 + 7 (r/w user,p) */
+ std
+1: stosl /* fill the page backwards - more efficient :-) */
+ subl $0x1000,%eax
+ jge 1b
+ cld
+ movl $_swapper_pg_dir,%eax
+ movl %eax,%cr3 /* cr3 - page directory start */
+ movl %cr0,%eax
+ orl $0x80000000,%eax
+ movl %eax,%cr0 /* set paging (PG) bit */
+ ret /* this also flushes the prefetch-queue */
+
+/*
+ * page 0 is made non-existent, so that kernel NULL pointer references get
+ * caught. Thus the swapper page directory has been moved to 0x1000
+ *
+ * XXX Actually, the swapper page directory is at 0x1000 plus 1 megabyte,
+ * with the introduction of the compressed boot code. Theoretically,
+ * the original design of overlaying the startup code with the swapper
+ * page directory is still possible --- it would reduce the size of the kernel
+ * by 2-3k. This would be a good thing to do at some point.....
+ */
+.org 0x1000
+_swapper_pg_dir:
+/*
+ * The page tables are initialized to only 4MB here - the final page
+ * tables are set up later depending on memory size.
+ */
+.org 0x2000
+_pg0:
+
+.org 0x3000
+_empty_bad_page:
+
+.org 0x4000
+_empty_bad_page_table:
+
+.org 0x5000
+_empty_zero_page:
+
+.org 0x6000
+/*
+ * floppy_track_buffer is used to buffer one track of floppy data: it
+ * has to be separate from the tmp_floppy area, as otherwise a single-
+ * sector read/write can mess it up. It can contain one full cylinder (sic) of
+ * data (36*2*512 bytes).
+ */
+_floppy_track_buffer:
+ .fill 512*2*MAX_BUFFER_SECTORS,1,0
+
+/* This is the default interrupt "handler" :-) */
+int_msg:
+ .asciz "Unknown interrupt\n"
+.align 2
+ignore_int:
+ cld
+ pushl %eax
+ pushl %ecx
+ pushl %edx
+ push %ds
+ push %es
+ push %fs
+ movl $(KERNEL_DS),%eax
+ mov %ax,%ds
+ mov %ax,%es
+ mov %ax,%fs
+ pushl $int_msg
+ call _printk
+ popl %eax
+ pop %fs
+ pop %es
+ pop %ds
+ popl %edx
+ popl %ecx
+ popl %eax
+ iret
+
+/*
+ * The interrupt descriptor table has room for 256 idt's
+ */
+.align 4
+.word 0
+idt_descr:
+ .word 256*8-1 # idt contains 256 entries
+ .long 0xc0000000+_idt
+
+.align 4
+_idt:
+ .fill 256,8,0 # idt is uninitialized
+
+.align 4
+.word 0
+gdt_descr:
+ .word (8+2*NR_TASKS)*8-1
+ .long 0xc0000000+_gdt
+
+/*
+ * This gdt setup gives the kernel a 1GB address space at virtual
+ * address 0xC0000000 - space enough for expansion, I hope.
+ */
+.align 4
+_gdt:
+ .quad 0x0000000000000000 /* NULL descriptor */
+ .quad 0x0000000000000000 /* not used */
+ .quad 0xc0c39a000000ffff /* 0x10 kernel 1GB code at 0xC0000000 */
+ .quad 0xc0c392000000ffff /* 0x18 kernel 1GB data at 0xC0000000 */
+ .quad 0x00cbfa000000ffff /* 0x23 user 3GB code at 0x00000000 */
+ .quad 0x00cbf2000000ffff /* 0x2b user 3GB data at 0x00000000 */
+ .quad 0x0000000000000000 /* not used */
+ .quad 0x0000000000000000 /* not used */
+ .fill 2*NR_TASKS,8,0 /* space for LDT's and TSS's etc */
diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S
new file mode 100644
index 000000000..d4f56ef2a
--- /dev/null
+++ b/arch/i386/boot/setup.S
@@ -0,0 +1,1011 @@
+!
+! setup.S Copyright (C) 1991, 1992 Linus Torvalds
+!
+! setup.s is responsible for getting the system data from the BIOS,
+! and putting them into the appropriate places in system memory.
+! both setup.s and system has been loaded by the bootblock.
+!
+! This code asks the bios for memory/disk/other parameters, and
+! puts them in a "safe" place: 0x90000-0x901FF, ie where the
+! boot-block used to be. It is then up to the protected mode
+! system to read them from there before the area is overwritten
+! for buffer-blocks.
+!
+! Move PS/2 aux init code to psaux.c
+! (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92
+!
+! some changes and additional features by Christoph Niemann,
+! March 1993/June 1994 (Christoph.Niemann@linux.org)
+!
+
+! NOTE! These had better be the same as in bootsect.s!
+#define __ASSEMBLY__
+#include <linux/config.h>
+#include <asm/segment.h>
+
+#ifndef SVGA_MODE
+#define SVGA_MODE ASK_VGA
+#endif
+
+! Signature words to ensure LILO loaded us right
+#define SIG1 0xAA55
+#define SIG2 0x5A5A
+
+INITSEG = DEF_INITSEG ! we move boot here - out of the way
+SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536).
+SETUPSEG = DEF_SETUPSEG ! this is the current segment
+
+.globl begtext, begdata, begbss, endtext, enddata, endbss
+.text
+begtext:
+.data
+begdata:
+.bss
+begbss:
+.text
+
+entry start
+start:
+! Bootlin depends on this being done early
+ mov ax,#0x01500
+ mov dl,#0x81
+ int 0x13
+
+! Check signature at end of setup
+ mov ax,#SETUPSEG
+ mov ds,ax
+ cmp setup_sig1,#SIG1
+ jne bad_sig
+ cmp setup_sig2,#SIG2
+ jne bad_sig
+ jmp good_sig1
+
+! Routine to print asciiz-string at DS:SI
+
+prtstr: lodsb
+ and al,al
+ jz fin
+ call prnt1
+ jmp prtstr
+fin: ret
+
+! Part of above routine, this one just prints ascii al
+
+prnt1: push ax
+ push cx
+ xor bh,bh
+ mov cx,#0x01
+ mov ah,#0x0e
+ int 0x10
+ pop cx
+ pop ax
+ ret
+
+beep: mov al,#0x07
+ jmp prnt1
+
+no_sig_mess: .ascii "No setup signature found ..."
+ db 0x00
+start_sys_seg: .word SYSSEG
+
+good_sig1:
+ jmp good_sig
+
+! We now have to find the rest of the setup code/data
+bad_sig:
+ mov ax,#INITSEG
+ mov ds,ax
+ xor bh,bh
+ mov bl,[497] ! get setup sects from boot sector
+ sub bx,#4 ! LILO loads 4 sectors of setup
+ shl bx,#8 ! convert to words
+ mov cx,bx
+ shr bx,#3 ! convert to segment
+ add bx,#SYSSEG
+ seg cs
+ mov start_sys_seg,bx
+
+! Move rest of setup code/data to here
+ mov di,#2048 ! four sectors loaded by LILO
+ sub si,si
+ mov ax,#SETUPSEG
+ mov es,ax
+ mov ax,#SYSSEG
+ mov ds,ax
+ rep
+ movsw
+
+ mov ax,#SETUPSEG
+ mov ds,ax
+ cmp setup_sig1,#SIG1
+ jne no_sig
+ cmp setup_sig2,#SIG2
+ jne no_sig
+ jmp good_sig
+
+no_sig:
+ lea si,no_sig_mess
+ call prtstr
+no_sig_loop:
+ jmp no_sig_loop
+
+good_sig:
+ mov ax,#INITSEG
+ mov ds,ax
+
+! Get memory size (extended mem, kB)
+
+ mov ah,#0x88
+ int 0x15
+ mov [2],ax
+
+! set the keyboard repeat rate to the max
+
+ mov ax,#0x0305
+ xor bx,bx ! clear bx
+ int 0x16
+
+! check for EGA/VGA and some config parameters
+
+ mov ah,#0x12
+ mov bl,#0x10
+ int 0x10
+ mov [8],ax
+ mov [10],bx
+ mov [12],cx
+ mov ax,#0x5019
+ cmp bl,#0x10
+ je novga
+ mov ax,#0x1a00 ! Added check for EGA/VGA discrimination
+ int 0x10
+ mov bx,ax
+ mov ax,#0x5019
+ cmp bl,#0x1a ! 1a means VGA, anything else EGA or lower
+ jne novga
+ call chsvga
+novga: mov [14],ax
+ mov ah,#0x03 ! read cursor pos
+ xor bh,bh ! clear bh
+ int 0x10 ! save it in known place, con_init fetches
+ mov [0],dx ! it from 0x90000.
+
+! Get video-card data:
+
+ mov ah,#0x0f
+ int 0x10
+ mov [4],bx ! bh = display page
+ mov [6],ax ! al = video mode, ah = window width
+
+! Get hd0 data
+
+ xor ax,ax ! clear ax
+ mov ds,ax
+ lds si,[4*0x41]
+ mov ax,#INITSEG
+ push ax
+ mov es,ax
+ mov di,#0x0080
+ mov cx,#0x10
+ push cx
+ cld
+ rep
+ movsb
+
+! Get hd1 data
+
+ xor ax,ax ! clear ax
+ mov ds,ax
+ lds si,[4*0x46]
+ pop cx
+ pop es
+ mov di,#0x0090
+ rep
+ movsb
+
+! Check that there IS a hd1 :-)
+
+ mov ax,#0x01500
+ mov dl,#0x81
+ int 0x13
+ jc no_disk1
+ cmp ah,#3
+ je is_disk1
+no_disk1:
+ mov ax,#INITSEG
+ mov es,ax
+ mov di,#0x0090
+ mov cx,#0x10
+ xor ax,ax ! clear ax
+ cld
+ rep
+ stosb
+is_disk1:
+
+! check for PS/2 pointing device
+
+ mov ax,#INITSEG
+ mov ds,ax
+ mov [0x1ff],#0 ! default is no pointing device
+ int 0x11 ! int 0x11: equipment determination
+ test al,#0x04 ! check if pointing device installed
+ jz no_psmouse
+ mov [0x1ff],#0xaa ! device present
+no_psmouse:
+! now we want to move to protected mode ...
+
+ cli ! no interrupts allowed !
+ mov al,#0x80 ! disable NMI for the bootup sequence
+ out #0x70,al
+
+! first we move the system to its rightful place
+
+ mov ax,#0x100 ! start of destination segment
+ seg cs
+ mov bx,start_sys_seg ! start of source segment
+ cld ! 'direction'=0, movs moves forward
+do_move:
+ mov es,ax ! destination segment
+ inc ah ! instead of add ax,#0x100
+ cmp ax,#0x9000
+ jz end_move
+ mov ds,bx ! source segment
+ add bx,#0x100
+ sub di,di
+ sub si,si
+ mov cx,#0x800
+ rep
+ movsw
+ jmp do_move
+
+! then we load the segment descriptors
+
+end_move:
+ mov ax,#SETUPSEG ! right, forgot this at first. didn't work :-)
+ mov ds,ax
+ lidt idt_48 ! load idt with 0,0
+ lgdt gdt_48 ! load gdt with whatever appropriate
+
+! that was painless, now we enable A20
+
+ call empty_8042
+ mov al,#0xD1 ! command write
+ out #0x64,al
+ call empty_8042
+ mov al,#0xDF ! A20 on
+ out #0x60,al
+ call empty_8042
+
+! make sure any possible coprocessor is properly reset..
+
+ xor ax,ax
+ out #0xf0,al
+ call delay
+ out #0xf1,al
+ call delay
+
+! well, that went ok, I hope. Now we have to reprogram the interrupts :-(
+! we put them right after the intel-reserved hardware interrupts, at
+! int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
+! messed this up with the original PC, and they haven't been able to
+! rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
+! which is used for the internal hardware interrupts as well. We just
+! have to reprogram the 8259's, and it isn't fun.
+
+ mov al,#0x11 ! initialization sequence
+ out #0x20,al ! send it to 8259A-1
+ call delay
+ out #0xA0,al ! and to 8259A-2
+ call delay
+ mov al,#0x20 ! start of hardware int's (0x20)
+ out #0x21,al
+ call delay
+ mov al,#0x28 ! start of hardware int's 2 (0x28)
+ out #0xA1,al
+ call delay
+ mov al,#0x04 ! 8259-1 is master
+ out #0x21,al
+ call delay
+ mov al,#0x02 ! 8259-2 is slave
+ out #0xA1,al
+ call delay
+ mov al,#0x01 ! 8086 mode for both
+ out #0x21,al
+ call delay
+ out #0xA1,al
+ call delay
+ mov al,#0xFF ! mask off all interrupts for now
+ out #0xA1,al
+ call delay
+ mov al,#0xFB ! mask all irq's but irq2 which
+ out #0x21,al ! is cascaded
+
+! well, that certainly wasn't fun :-(. Hopefully it works, and we don't
+! need no steenking BIOS anyway (except for the initial loading :-).
+! The BIOS-routine wants lots of unnecessary data, and it's less
+! "interesting" anyway. This is how REAL programmers do it.
+!
+! Well, now's the time to actually move into protected mode. To make
+! things as simple as possible, we do no register set-up or anything,
+! we let the gnu-compiled 32-bit programs do that. We just jump to
+! absolute address 0x00000, in 32-bit protected mode.
+!
+! Note that the short jump isn't strictly needed, although there are
+! reasons why it might be a good idea. It won't hurt in any case.
+!
+ xor ax,ax
+ inc ax ! protected mode (PE) bit
+ lmsw ax ! This is it!
+ jmp flush_instr
+flush_instr:
+ jmpi 0x1000,KERNEL_CS ! jmp offset 1000 of segment 0x10 (cs)
+
+! This routine checks that the keyboard command queue is empty
+! (after emptying the output buffers)
+!
+! No timeout is used - if this hangs there is something wrong with
+! the machine, and we probably couldn't proceed anyway.
+empty_8042:
+ call delay
+ in al,#0x64 ! 8042 status port
+ test al,#1 ! output buffer?
+ jz no_output
+ call delay
+ in al,#0x60 ! read it
+ jmp empty_8042
+no_output:
+ test al,#2 ! is input buffer full?
+ jnz empty_8042 ! yes - loop
+ ret
+!
+! Read a key and return the (US-)ascii code in al, scan code in ah
+!
+getkey:
+ xor ah,ah
+ int 0x16
+ ret
+
+!
+! Read a key with a timeout of 30 seconds. The cmos clock is used to get
+! the time.
+!
+getkt:
+ call gettime
+ add al,#30 ! wait 30 seconds
+ cmp al,#60
+ jl lminute
+ sub al,#60
+lminute:
+ mov cl,al
+again: mov ah,#0x01
+ int 0x16
+ jnz getkey ! key pressed, so get it
+ call gettime
+ cmp al,cl
+ jne again
+ mov al,#0x20 ! timeout, return default char `space'
+ ret
+
+!
+! Flush the keyboard buffer
+!
+flush: mov ah,#0x01
+ int 0x16
+ jz empty
+ xor ah,ah
+ int 0x16
+ jmp flush
+empty: ret
+
+!
+! Read the cmos clock. Return the seconds in al
+!
+gettime:
+ push cx
+ mov ah,#0x02
+ int 0x1a
+ mov al,dh ! dh contains the seconds
+ and al,#0x0f
+ mov ah,dh
+ mov cl,#0x04
+ shr ah,cl
+ aad
+ pop cx
+ ret
+
+!
+! Delay is needed after doing i/o
+!
+delay:
+ .word 0x00eb ! jmp $+2
+ ret
+
+! Routine trying to recognize type of SVGA-board present (if any)
+! and if it recognize one gives the choices of resolution it offers.
+! If one is found the resolution chosen is given by al,ah (rows,cols).
+
+chsvga: cld
+ push ds
+ push cs
+ mov ax,[0x01fa]
+ pop ds
+ mov modesave,ax
+ mov ax,#0xc000
+ mov es,ax
+ mov ax,modesave
+ cmp ax,#NORMAL_VGA
+ je defvga
+ cmp ax,#EXTENDED_VGA
+ je vga50
+ cmp ax,#ASK_VGA
+ jne svga
+ lea si,msg1
+ call prtstr
+ call flush
+nokey: call getkt
+ cmp al,#0x0d ! enter ?
+ je svga ! yes - svga selection
+ cmp al,#0x20 ! space ?
+ je defvga ! no - repeat
+ call beep
+ jmp nokey
+defvga: mov ax,#0x5019
+ pop ds
+ ret
+/* extended vga mode: 80x50 */
+vga50:
+ mov ax,#0x1112
+ xor bl,bl
+ int 0x10 ! use 8x8 font set (50 lines on VGA)
+ mov ax,#0x1200
+ mov bl,#0x20
+ int 0x10 ! use alternate print screen
+ mov ax,#0x1201
+ mov bl,#0x34
+ int 0x10 ! turn off cursor emulation
+ mov ah,#0x01
+ mov cx,#0x0607
+ int 0x10 ! turn on cursor (scan lines 6 to 7)
+ pop ds
+ mov ax,#0x5032 ! return 80x50
+ ret
+/* extended vga mode: 80x28 */
+vga28:
+ pop ax ! clean the stack
+ mov ax,#0x1111
+ xor bl,bl
+ int 0x10 ! use 9x14 fontset (28 lines on VGA)
+ mov ah, #0x01
+ mov cx,#0x0b0c
+ int 0x10 ! turn on cursor (scan lines 11 to 12)
+ pop ds
+ mov ax,#0x501c ! return 80x28
+ ret
+/* svga modes */
+!
+! test for presence of an S3 VGA chip. The algorithm was taken
+! from the SuperProbe package of XFree86 1.2.1
+! report bugs to Christoph.Niemann@linux.org
+!
+svga: cld
+ mov cx,#0x0f35 ! we store some constants in cl/ch
+ mov dx,#0x03d4
+ movb al,#0x38
+ call inidx
+ mov bh,al ! store current value of CRT-register 0x38
+ mov ax,#0x0038
+ call outidx ! disable writing to special regs
+ movb al,cl ! check whether we can write special reg 0x35
+ call inidx
+ movb bl,al ! save the current value of CRT reg 0x35
+ andb al,#0xf0 ! clear bits 0-3
+ movb ah,al
+ movb al,cl ! and write it to CRT reg 0x35
+ call outidx
+ call inidx ! now read it back
+ andb al,ch ! clear the upper 4 bits
+ jz s3_2 ! the first test failed. But we have a
+ movb ah,bl ! second chance
+ mov al,cl
+ call outidx
+ jmp s3_1 ! do the other tests
+s3_2: mov ax,cx ! load ah with 0xf and al with 0x35
+ orb ah,bl ! set the upper 4 bits of ah with the orig value
+ call outidx ! write ...
+ call inidx ! ... and reread
+ andb al,cl ! turn off the upper 4 bits
+ push ax
+ movb ah,bl ! restore old value in register 0x35
+ movb al,cl
+ call outidx
+ pop ax
+ cmp al,ch ! setting lower 4 bits was successful => bad
+ je no_s3 ! writing is allowed => this is not an S3
+s3_1: mov ax,#0x4838 ! allow writing to special regs by putting
+ call outidx ! magic number into CRT-register 0x38
+ movb al,cl ! check whether we can write special reg 0x35
+ call inidx
+ movb bl,al
+ andb al,#0xf0
+ movb ah,al
+ movb al,cl
+ call outidx
+ call inidx
+ andb al,ch
+ jnz no_s3 ! no, we can't write => no S3
+ mov ax,cx
+ orb ah,bl
+ call outidx
+ call inidx
+ andb al,ch
+ push ax
+ movb ah,bl ! restore old value in register 0x35
+ movb al,cl
+ call outidx
+ pop ax
+ cmp al,ch
+ jne no_s31 ! writing not possible => no S3
+ movb al,#0x30
+ call inidx ! now get the S3 id ...
+ lea di,idS3
+ mov cx,#0x10
+ repne
+ scasb
+ je no_s31
+ lea si,dsc_S3 ! table of descriptions of video modes for BIOS
+ lea di,mo_S3 ! table of sizes of video modes for my BIOS
+ movb ah,bh
+ movb al,#0x38
+ call outidx ! restore old value of CRT register 0x38
+ br selmod ! go ask for video mode
+no_s3: movb al,#0x35 ! restore CRT register 0x35
+ movb ah,bl
+ call outidx
+no_s31: movb ah,bh
+ movb al,#0x38
+ call outidx ! restore old value of CRT register 0x38
+
+ lea si,idati ! Check ATI 'clues'
+ mov di,#0x31
+ mov cx,#0x09
+ repe
+ cmpsb
+ jne noati
+ lea si,dscati
+ lea di,moati
+ br selmod
+noati: mov ax,#0x200f ! Check Ahead 'clues'
+ mov dx,#0x3ce
+ out dx,ax
+ inc dx
+ in al,dx
+ cmp al,#0x20
+ je isahed
+ cmp al,#0x21
+ jne noahed
+isahed: lea si,dscahead
+ lea di,moahead
+ br selmod
+noahed: mov dx,#0x3c3 ! Check Chips & Tech. 'clues'
+ in al,dx
+ or al,#0x10
+ out dx,al
+ mov dx,#0x104
+ in al,dx
+ mov bl,al
+ mov dx,#0x3c3
+ in al,dx
+ and al,#0xef
+ out dx,al
+ cmp bl,[idcandt]
+ jne nocant
+ lea si,dsccandt
+ lea di,mocandt
+ br selmod
+nocant: mov dx,#0x3d4 ! Check Cirrus 'clues'
+ mov al,#0x0c
+ out dx,al
+ inc dx
+ in al,dx
+ mov bl,al
+ xor al,al
+ out dx,al
+ dec dx
+ mov al,#0x1f
+ out dx,al
+ inc dx
+ in al,dx
+ mov bh,al
+ xor ah,ah
+ shl al,#4
+ mov cx,ax
+ mov al,bh
+ shr al,#4
+ add cx,ax
+ shl cx,#8
+ add cx,#6
+ mov ax,cx
+ mov dx,#0x3c4
+ out dx,ax
+ inc dx
+ in al,dx
+ and al,al
+ jnz nocirr
+ mov al,bh
+ out dx,al
+ in al,dx
+ cmp al,#0x01
+ jne nocirr
+ call rst3d4
+ lea si,dsccirrus
+ lea di,mocirrus
+ br selmod
+rst3d4: mov dx,#0x3d4
+ mov al,bl
+ xor ah,ah
+ shl ax,#8
+ add ax,#0x0c
+ out dx,ax
+ ret
+nocirr: call rst3d4 ! Check Everex 'clues'
+ mov ax,#0x7000
+ xor bx,bx
+ int 0x10
+ cmp al,#0x70
+ jne noevrx
+ shr dx,#4
+ cmp dx,#0x678
+ je istrid
+ cmp dx,#0x236
+ je istrid
+ lea si,dsceverex
+ lea di,moeverex
+ br selmod
+istrid: lea cx,ev2tri
+ jmp cx
+noevrx: lea si,idgenoa ! Check Genoa 'clues'
+ xor ax,ax
+ seg es
+ mov al,[0x37]
+ mov di,ax
+ mov cx,#0x04
+ dec si
+ dec di
+l1: inc si
+ inc di
+ mov al,(si)
+ test al,al
+ jz l2
+ seg es
+ cmp al,(di)
+l2: loope l1
+ cmp cx,#0x00
+ jne nogen
+ lea si,dscgenoa
+ lea di,mogenoa
+ br selmod
+nogen: cld
+ lea si,idoakvga
+ mov di,#0x08
+ mov cx,#0x08
+ repe
+ cmpsb
+ jne nooak
+ lea si,dscoakvga
+ lea di,mooakvga
+ br selmod
+nooak: cld
+ lea si,idparadise ! Check Paradise 'clues'
+ mov di,#0x7d
+ mov cx,#0x04
+ repe
+ cmpsb
+ jne nopara
+ lea si,dscparadise
+ lea di,moparadise
+ br selmod
+nopara: mov dx,#0x3c4 ! Check Trident 'clues'
+ mov al,#0x0e
+ out dx,al
+ inc dx
+ in al,dx
+ xchg ah,al
+ xor al,al
+ out dx,al
+ in al,dx
+ xchg al,ah
+ mov bl,al ! Strange thing ... in the book this wasn't
+ and bl,#0x02 ! necessary but it worked on my card which
+ jz setb2 ! is a trident. Without it the screen goes
+ and al,#0xfd ! blurred ...
+ jmp clrb2 !
+setb2: or al,#0x02 !
+clrb2: out dx,al
+ and ah,#0x0f
+ cmp ah,#0x02
+ jne notrid
+ev2tri: lea si,dsctrident
+ lea di,motrident
+ jmp selmod
+notrid: mov dx,#0x3cd ! Check Tseng 'clues'
+ in al,dx ! Could things be this simple ! :-)
+ mov bl,al
+ mov al,#0x55
+ out dx,al
+ in al,dx
+ mov ah,al
+ mov al,bl
+ out dx,al
+ cmp ah,#0x55
+ jne notsen
+ lea si,dsctseng
+ lea di,motseng
+ jmp selmod
+notsen: mov dx,#0x3cc ! Check Video7 'clues'
+ in al,dx
+ mov dx,#0x3b4
+ and al,#0x01
+ jz even7
+ mov dx,#0x3d4
+even7: mov al,#0x0c
+ out dx,al
+ inc dx
+ in al,dx
+ mov bl,al
+ mov al,#0x55
+ out dx,al
+ in al,dx
+ dec dx
+ mov al,#0x1f
+ out dx,al
+ inc dx
+ in al,dx
+ mov bh,al
+ dec dx
+ mov al,#0x0c
+ out dx,al
+ inc dx
+ mov al,bl
+ out dx,al
+ mov al,#0x55
+ xor al,#0xea
+ cmp al,bh
+ jne novid7
+ lea si,dscvideo7
+ lea di,movideo7
+ jmp selmod
+novid7: lea si,dsunknown
+ lea di,mounknown
+selmod: xor cx,cx
+ mov cl,(di)
+ mov ax,modesave
+ cmp ax,#ASK_VGA
+ je askmod
+ cmp ax,#NORMAL_VGA
+ je askmod
+ cmp al,cl
+ jl gotmode
+ push si
+ lea si,msg4
+ call prtstr
+ pop si
+askmod: push si
+ lea si,msg2
+ call prtstr
+ pop si
+ push si
+ push cx
+tbl: pop bx
+ push bx
+ mov al,bl
+ sub al,cl
+ call modepr
+ lodsw
+ xchg al,ah
+ call dprnt
+ xchg ah,al
+ push ax
+ mov al,#0x78
+ call prnt1
+ pop ax
+ call dprnt
+ push si
+ lea si,crlf ! print CR+LF
+ call prtstr
+ pop si
+ loop tbl
+ pop cx
+ lea si,msg3
+ call prtstr
+ pop si
+ add cl,#0x30
+ jmp nonum
+nonumb: call beep
+nonum: call getkey
+ cmp al,#0x30 ! ascii `0'
+ jb nonumb
+ cmp al,#0x3a ! ascii `9'
+ jbe number
+ cmp al,#0x61 ! ascii `a'
+ jb nonumb
+ cmp al,#0x7a ! ascii `z'
+ ja nonumb
+ sub al,#0x27
+ cmp al,cl
+ jae nonumb
+ sub al,#0x30
+ jmp gotmode
+number: cmp al,cl
+ jae nonumb
+ sub al,#0x30
+gotmode: xor ah,ah
+ or al,al
+ beq vga50
+ push ax
+ dec ax
+ beq vga28
+ add di,ax
+ mov al,(di)
+ int 0x10
+ pop ax
+ shl ax,#1
+ add si,ax
+ lodsw
+ pop ds
+ ret
+
+! Routine to write al into a VGA-register that is
+! accessed via an index register
+!
+! dx contains the address of the index register
+! al contains the index
+! ah contains the value to write to the data register (dx + 1)
+!
+! no registers are changed
+
+outidx: out dx,al
+ push ax
+ mov al,ah
+ inc dx
+ out dx,al
+ dec dx
+ pop ax
+ ret
+inidx: out dx,al
+ inc dx
+ in al,dx
+ dec dx
+ ret
+
+! Routine to print a decimal value on screen, the value to be
+! printed is put in al (i.e 0-255).
+
+dprnt: push ax
+ push cx
+ xor ah,ah ! Clear ah
+ mov cl,#0x0a
+ idiv cl
+ cmp al,#0x09
+ jbe lt100
+ call dprnt
+ jmp skip10
+lt100: add al,#0x30
+ call prnt1
+skip10: mov al,ah
+ add al,#0x30
+ call prnt1
+ pop cx
+ pop ax
+ ret
+
+!
+! Routine to print the mode number key on screen. Mode numbers
+! 0-9 print the ascii values `0' to '9', 10-35 are represented by
+! the letters `a' to `z'. This routine prints some spaces around the
+! mode no.
+!
+
+modepr: push ax
+ cmp al,#0x0a
+ jb digit ! Here is no check for number > 35
+ add al,#0x27
+digit: add al,#0x30
+ mov modenr, al
+ push si
+ lea si, modestring
+ call prtstr
+ pop si
+ pop ax
+ ret
+
+gdt:
+ .word 0,0,0,0 ! dummy
+
+ .word 0,0,0,0 ! unused
+
+ .word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb)
+ .word 0x0000 ! base address=0
+ .word 0x9A00 ! code read/exec
+ .word 0x00C0 ! granularity=4096, 386
+
+ .word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb)
+ .word 0x0000 ! base address=0
+ .word 0x9200 ! data read/write
+ .word 0x00C0 ! granularity=4096, 386
+
+idt_48:
+ .word 0 ! idt limit=0
+ .word 0,0 ! idt base=0L
+
+gdt_48:
+ .word 0x800 ! gdt limit=2048, 256 GDT entries
+ .word 512+gdt,0x9 ! gdt base = 0X9xxxx
+
+msg1: .ascii "Press <RETURN> to see SVGA-modes available, <SPACE> to continue or wait 30 secs."
+ db 0x0d, 0x0a, 0x0a, 0x00
+msg2: .ascii "Mode: COLSxROWS:"
+ db 0x0d, 0x0a, 0x0a, 0x00
+msg3: db 0x0d, 0x0a
+ .ascii "Choose mode by pressing the corresponding number or letter."
+crlf: db 0x0d, 0x0a, 0x00
+msg4: .ascii "You passed an undefined mode number to setup. Please choose a new mode."
+ db 0x0d, 0x0a, 0x0a, 0x07, 0x00
+modestring: .ascii " "
+modenr: db 0x00 ! mode number
+ .ascii ": "
+ db 0x00
+
+idati: .ascii "761295520"
+idcandt: .byte 0xa5
+idgenoa: .byte 0x77, 0x00, 0x99, 0x66
+idparadise: .ascii "VGA="
+idoakvga: .ascii "OAK VGA "
+idS3: .byte 0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95
+ .byte 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0
+
+! Manufacturer: Numofmodes+2: Mode:
+! Number of modes is the number of chip-specific svga modes plus the extended
+! modes available on any vga (currently 2)
+
+moati: .byte 0x06, 0x23, 0x33, 0x22, 0x21
+moahead: .byte 0x07, 0x22, 0x23, 0x24, 0x2f, 0x34
+mocandt: .byte 0x04, 0x60, 0x61
+mocirrus: .byte 0x06, 0x1f, 0x20, 0x22, 0x31
+moeverex: .byte 0x0c, 0x03, 0x04, 0x07, 0x08, 0x0a, 0x0b, 0x16, 0x18, 0x21, 0x40
+mogenoa: .byte 0x0c, 0x58, 0x5a, 0x60, 0x61, 0x62, 0x63, 0x64, 0x72, 0x74, 0x78
+moparadise: .byte 0x04, 0x55, 0x54
+motrident: .byte 0x09, 0x50, 0x51, 0x52, 0x57, 0x58, 0x59, 0x5a
+motseng: .byte 0x07, 0x26, 0x2a, 0x23, 0x24, 0x22
+movideo7: .byte 0x08, 0x40, 0x43, 0x44, 0x41, 0x42, 0x45
+mooakvga: .byte 0x08, 0x00, 0x07, 0x4e, 0x4f, 0x50, 0x51
+mo_S3: .byte 0x04, 0x54, 0x55
+mounknown: .byte 0x02
+
+! msb = Cols lsb = Rows:
+! The first two modes are standard vga modes available on any vga.
+! mode 0 is 80x50 and mode 1 is 80x28
+
+dscati: .word 0x5032, 0x501c, 0x8419, 0x842c, 0x641e, 0x6419
+dscahead: .word 0x5032, 0x501c, 0x842c, 0x8419, 0x841c, 0xa032, 0x5042
+dsccandt: .word 0x5032, 0x501c, 0x8419, 0x8432
+dsccirrus: .word 0x5032, 0x501c, 0x8419, 0x842c, 0x841e, 0x6425
+dsceverex: .word 0x5032, 0x501c, 0x5022, 0x503c, 0x642b, 0x644b, 0x8419, 0x842c, 0x501e, 0x641b, 0xa040, 0x841e
+dscgenoa: .word 0x5032, 0x501c, 0x5020, 0x642a, 0x8419, 0x841d, 0x8420, 0x842c, 0x843c, 0x503c, 0x5042, 0x644b
+dscparadise: .word 0x5032, 0x501c, 0x8419, 0x842c
+dsctrident: .word 0x5032, 0x501c, 0x501e, 0x502b, 0x503c, 0x8419, 0x841e, 0x842b, 0x843c
+dsctseng: .word 0x5032, 0x501c, 0x503c, 0x6428, 0x8419, 0x841c, 0x842c
+dscvideo7: .word 0x5032, 0x501c, 0x502b, 0x503c, 0x643c, 0x8419, 0x842c, 0x841c
+dscoakvga: .word 0x5032, 0x501c, 0x2819, 0x5019, 0x503c, 0x843c, 0x8419, 0x842b
+dsc_S3: .word 0x5032, 0x501c, 0x842b, 0x8419
+dsunknown: .word 0x5032, 0x501c
+modesave: .word SVGA_MODE
+
+! This must be last
+setup_sig1: .word SIG1
+setup_sig2: .word SIG2
+
+.text
+endtext:
+.data
+enddata:
+.bss
+endbss:
diff --git a/arch/i386/config.in b/arch/i386/config.in
new file mode 100644
index 000000000..2c4bc4ba5
--- /dev/null
+++ b/arch/i386/config.in
@@ -0,0 +1,219 @@
+#
+# For a description of the syntax of this configuration file,
+# see the Configure script.
+#
+
+comment 'General setup'
+
+bool 'Kernel math emulation' CONFIG_MATH_EMULATION n
+bool 'Normal floppy disk support' CONFIG_BLK_DEV_FD y
+bool 'Normal harddisk support' CONFIG_BLK_DEV_HD y
+bool 'XT harddisk support' CONFIG_BLK_DEV_XD n
+bool 'Networking support' CONFIG_NET y
+bool 'Limit memory to low 16MB' CONFIG_MAX_16M n
+bool 'System V IPC' CONFIG_SYSVIPC y
+bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF y
+bool 'Use -m486 flag for 486-specific optimizations' CONFIG_M486 y
+
+if [ "$CONFIG_NET" = "y" ]; then
+comment 'Networking options'
+bool 'TCP/IP networking' CONFIG_INET y
+if [ "$CONFIG_INET" "=" "y" ]; then
+bool 'IP forwarding/gatewaying' CONFIG_IP_FORWARD n
+comment '(it is safe to leave these untouched)'
+bool 'PC/TCP compatibility mode' CONFIG_INET_PCTCP n
+bool 'Reverse ARP' CONFIG_INET_RARP n
+bool 'Assume subnets are local' CONFIG_INET_SNARL y
+bool 'Disable NAGLE algorithm (normally enabled)' CONFIG_TCP_NAGLE_OFF n
+fi
+bool 'The IPX protocol' CONFIG_IPX n
+#bool 'Amateur Radio AX.25 Level 2' CONFIG_AX25 n
+fi
+
+comment 'SCSI support'
+
+bool 'SCSI support?' CONFIG_SCSI n
+
+if [ "$CONFIG_SCSI" = "n" ]; then
+
+comment 'Skipping SCSI configuration options...'
+
+else
+
+comment 'SCSI support type (disk, tape, CDrom)'
+
+bool 'Scsi disk support' CONFIG_BLK_DEV_SD y
+bool 'Scsi tape support' CONFIG_CHR_DEV_ST n
+bool 'Scsi CDROM support' CONFIG_BLK_DEV_SR n
+bool 'Scsi generic support' CONFIG_CHR_DEV_SG n
+
+comment 'SCSI low-level drivers'
+
+bool 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X n
+bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 y
+bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 n
+bool 'Adaptec AHA274X/284X support' CONFIG_SCSI_AHA274X n
+bool 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC n
+bool 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F n
+bool 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN n
+bool 'Generic NCR5380 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 n
+bool 'NCR53c7,8xx SCSI support' CONFIG_SCSI_NCR53C7xx n
+bool 'Always IN2000 SCSI support (test release)' CONFIG_SCSI_IN2000 n
+bool 'PAS16 SCSI support' CONFIG_SCSI_PAS16 n
+bool 'QLOGIC SCSI support' CONFIG_SCSI_QLOGIC n
+bool 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE n
+bool 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 n
+bool 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR n
+bool '7000FASST SCSI support' CONFIG_SCSI_7000FASST n
+bool 'EISA EATA support' CONFIG_SCSI_EATA n
+#bool 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG n
+fi
+
+
+if [ "$CONFIG_NET" = "y" ]; then
+
+comment 'Network device support'
+
+bool 'Network device support?' CONFIG_NETDEVICES y
+if [ "$CONFIG_NETDEVICES" = "n" ]; then
+
+comment 'Skipping network driver configuration options...'
+
+else
+bool 'Dummy net driver support' CONFIG_DUMMY n
+bool 'SLIP (serial line) support' CONFIG_SLIP n
+if [ "$CONFIG_SLIP" = "y" ]; then
+ bool ' CSLIP compressed headers' SL_COMPRESSED y
+# bool ' SLIP debugging on' SL_DUMP y
+fi
+bool 'PPP (point-to-point) support' CONFIG_PPP n
+bool 'PLIP (parallel port) support' CONFIG_PLIP n
+bool 'Load balancing support (experimental)' CONFIG_SLAVE_BALANCING n
+bool 'Do you want to be offered ALPHA test drivers' CONFIG_NET_ALPHA n
+bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC n
+if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then
+ bool 'WD80*3 support' CONFIG_WD80x3 n
+ bool 'SMC Ultra support' CONFIG_ULTRA n
+fi
+bool '3COM cards' CONFIG_NET_VENDOR_3COM y
+if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
+ bool '3c501 support' CONFIG_EL1 n
+ bool '3c503 support' CONFIG_EL2 n
+ if [ "$CONFIG_NET_ALPHA" = "y" ]; then
+ bool '3c505 support' CONFIG_ELPLUS n
+ bool '3c507 support' CONFIG_EL16 n
+ fi
+ bool '3c509/3c579 support' CONFIG_EL3 y
+fi
+bool 'Other ISA cards' CONFIG_NET_ISA n
+if [ "$CONFIG_NET_ISA" = "y" ]; then
+ bool 'AT1500 and NE2100 (LANCE and PCnet-ISA) support' CONFIG_LANCE n
+ bool 'Cabletron E21xx support (not recommended)' CONFIG_E2100 n
+ bool 'DEPCA support' CONFIG_DEPCA n
+ bool 'EtherWorks 3 support' CONFIG_EWRK3 n
+ if [ "$CONFIG_NET_ALPHA" = "y" ]; then
+ bool 'EtherExpress support' CONFIG_EEXPRESS n
+ bool 'AT1700 support' CONFIG_AT1700 n
+ bool 'NI5210 support' CONFIG_NI52 n
+ bool 'NI6510 support' CONFIG_NI65 n
+ fi
+ bool 'HP PCLAN support' CONFIG_HPLAN n
+ bool 'HP PCLAN PLUS support' CONFIG_HPLAN_PLUS n
+ bool 'NE2000/NE1000 support' CONFIG_NE2000 y
+ bool 'SK_G16 support' CONFIG_SK_G16 n
+fi
+bool 'EISA and on board controllers' CONFIG_NET_EISA n
+ if [ "$CONFIG_NET_ALPHA" = "y" ]; then
+ bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n
+ fi
+ bool 'Apricot Xen-II on board ethernet' CONFIG_APRICOT n
+bool 'Pocket and portable adaptors' CONFIG_NET_POCKET n
+if [ "$CONFIG_NET_POCKET" = "y" ]; then
+ bool 'D-Link DE600 pocket adaptor support' CONFIG_DE600 n
+ bool 'D-Link DE620 pocket adaptor support' CONFIG_DE620 n
+ bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP n
+ bool 'Zenith Z-Note support' CONFIG_ZNET n
+fi
+fi
+fi
+
+comment 'CD-ROM drivers'
+
+bool 'Sony CDU31A/CDU33A CDROM driver support' CONFIG_CDU31A n
+bool 'Mitsumi CDROM driver support' CONFIG_MCD n
+bool 'Matsushita/Panasonic CDROM driver support' CONFIG_SBPCD n
+if [ "$CONFIG_SBPCD" = "y" ]; then
+ bool 'Matsushita/Panasonic second CDROM controller support' CONFIG_SBPCD2 n
+ if [ "$CONFIG_SBPCD2" = "y" ]; then
+ bool 'Matsushita/Panasonic third CDROM controller support' CONFIG_SBPCD3 n
+ if [ "$CONFIG_SBPCD3" = "y" ]; then
+ bool 'Matsushita/Panasonic fourth CDROM controller support' CONFIG_SBPCD4 n
+ fi
+ fi
+fi
+
+comment 'Filesystems'
+
+bool 'Standard (minix) fs support' CONFIG_MINIX_FS y
+bool 'Extended fs support' CONFIG_EXT_FS n
+bool 'Second extended fs support' CONFIG_EXT2_FS y
+bool 'xiafs filesystem support' CONFIG_XIA_FS n
+bool 'msdos fs support' CONFIG_MSDOS_FS y
+if [ "$CONFIG_MSDOS_FS" = "y" ]; then
+bool 'umsdos: Unix like fs on top of std MSDOS FAT fs' CONFIG_UMSDOS_FS n
+fi
+bool '/proc filesystem support' CONFIG_PROC_FS y
+if [ "$CONFIG_INET" = "y" ]; then
+bool 'NFS filesystem support' CONFIG_NFS_FS y
+fi
+if [ "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_CDU31A" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_BLK_DEV_IDECD" = "y" ]; then
+ bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS y
+else
+ bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n
+fi
+bool 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS n
+bool 'System V and Coherent filesystem support' CONFIG_SYSV_FS n
+
+comment 'character devices'
+
+bool 'Parallel printer support' CONFIG_PRINTER n
+bool 'Logitech busmouse support' CONFIG_BUSMOUSE n
+bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE n
+if [ "$CONFIG_PSMOUSE" = "y" ]; then
+bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE y
+fi
+bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n
+bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n
+bool 'Selection (cut and paste for virtual consoles)' CONFIG_SELECTION n
+
+bool 'QIC-02 tape support' CONFIG_QIC02_TAPE n
+if [ "$CONFIG_QIC02_TAPE" = "y" ]; then
+bool 'Do you want runtime configuration for QIC-02' CONFIG_QIC02_DYNCONF y
+if [ "$CONFIG_QIC02_DYNCONF" != "y" ]; then
+
+comment '>>> Edit configuration parameters in ./include/linux/tpqic02.h!'
+
+else
+
+comment '>>> Setting runtime QIC-02 configuration is done with qic02conf'
+comment '>>> Which is available from ftp://ftp.funet.fi/pub/OS/Linux/BETA/QIC-02/'
+
+fi
+fi
+
+bool 'QIC-117 tape support' CONFIG_FTAPE n
+if [ "$CONFIG_FTAPE" = "y" ]; then
+int ' number of ftape buffers' NR_FTAPE_BUFFERS 3
+fi
+
+comment 'Sound'
+
+bool 'Sound card support' CONFIG_SOUND n
+
+comment 'Kernel hacking'
+
+#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC n
+bool 'Kernel profiling support' CONFIG_PROFILE n
+if [ "$CONFIG_SCSI" = "y" ]; then
+bool 'Verbose scsi error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS y
+fi
diff --git a/arch/i386/entry.S b/arch/i386/entry.S
new file mode 100644
index 000000000..d7008a74b
--- /dev/null
+++ b/arch/i386/entry.S
@@ -0,0 +1,545 @@
+/*
+ * linux/arch/i386/entry.S
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+/*
+ * entry.S contains the system-call and fault low-level handling routines.
+ * This also contains the timer-interrupt handler, as well as all interrupts
+ * and faults that can result in a task-switch.
+ *
+ * NOTE: This code handles signal-recognition, which happens every time
+ * after a timer-interrupt and after each system call.
+ *
+ * I changed all the .align's to 4 (16 byte alignment), as that's faster
+ * on a 486.
+ *
+ * Stack layout in 'ret_from_system_call':
+ * ptrace needs to have all regs on the stack.
+ * if the order here is changed, it needs to be
+ * updated in fork.c:copy_process, signal.c:do_signal,
+ * ptrace.c and ptrace.h
+ *
+ * 0(%esp) - %ebx
+ * 4(%esp) - %ecx
+ * 8(%esp) - %edx
+ * C(%esp) - %esi
+ * 10(%esp) - %edi
+ * 14(%esp) - %ebp
+ * 18(%esp) - %eax
+ * 1C(%esp) - %ds
+ * 20(%esp) - %es
+ * 24(%esp) - %fs
+ * 28(%esp) - %gs
+ * 2C(%esp) - orig_eax
+ * 30(%esp) - %eip
+ * 34(%esp) - %cs
+ * 38(%esp) - %eflags
+ * 3C(%esp) - %oldesp
+ * 40(%esp) - %oldss
+ */
+
+#define __ASSEMBLY__
+#include <linux/sys.h>
+#include <asm/segment.h>
+
+EBX = 0x00
+ECX = 0x04
+EDX = 0x08
+ESI = 0x0C
+EDI = 0x10
+EBP = 0x14
+EAX = 0x18
+DS = 0x1C
+ES = 0x20
+FS = 0x24
+GS = 0x28
+ORIG_EAX = 0x2C
+EIP = 0x30
+CS = 0x34
+EFLAGS = 0x38
+OLDESP = 0x3C
+OLDSS = 0x40
+
+CF_MASK = 0x00000001
+IF_MASK = 0x00000200
+NT_MASK = 0x00004000
+VM_MASK = 0x00020000
+
+/*
+ * these are offsets into the task-struct.
+ */
+state = 0
+counter = 4
+priority = 8
+signal = 12
+blocked = 16
+flags = 20
+errno = 24
+dbgreg6 = 52
+dbgreg7 = 56
+exec_domain = 60
+
+ENOSYS = 38
+
+.globl _system_call,_lcall7
+.globl _device_not_available, _coprocessor_error
+.globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op
+.globl _double_fault,_coprocessor_segment_overrun
+.globl _invalid_TSS,_segment_not_present,_stack_segment
+.globl _general_protection,_reserved
+.globl _alignment_check,_page_fault
+.globl ret_from_sys_call, _sys_call_table
+
+#define SAVE_ALL \
+ cld; \
+ push %gs; \
+ push %fs; \
+ push %es; \
+ push %ds; \
+ pushl %eax; \
+ pushl %ebp; \
+ pushl %edi; \
+ pushl %esi; \
+ pushl %edx; \
+ pushl %ecx; \
+ pushl %ebx; \
+ movl $(KERNEL_DS),%edx; \
+ mov %dx,%ds; \
+ mov %dx,%es; \
+ movl $(USER_DS),%edx; \
+ mov %dx,%fs;
+
+#define RESTORE_ALL \
+ cmpw $(KERNEL_CS),CS(%esp); \
+ je 1f; \
+ movl _current,%eax; \
+ movl dbgreg7(%eax),%ebx; \
+ movl %ebx,%db7; \
+1: popl %ebx; \
+ popl %ecx; \
+ popl %edx; \
+ popl %esi; \
+ popl %edi; \
+ popl %ebp; \
+ popl %eax; \
+ pop %ds; \
+ pop %es; \
+ pop %fs; \
+ pop %gs; \
+ addl $4,%esp; \
+ iret
+
+.align 4
+_lcall7:
+ pushfl # We get a different stack layout with call gates,
+ pushl %eax # which has to be cleaned up later..
+ SAVE_ALL
+ movl EIP(%esp),%eax # due to call gates, this is eflags, not eip..
+ movl CS(%esp),%edx # this is eip..
+ movl EFLAGS(%esp),%ecx # and this is cs..
+ movl %eax,EFLAGS(%esp) #
+ movl %edx,EIP(%esp) # Now we move them to their "normal" places
+ movl %ecx,CS(%esp) #
+ movl %esp,%eax
+ movl _current,%edx
+ pushl %eax
+ movl exec_domain(%edx),%edx # Get the execution domain
+ movl 4(%edx),%edx # Get the lcall7 handler for the domain
+ call *%edx
+ popl %eax
+ jmp ret_from_sys_call
+
+.align 4
+handle_bottom_half:
+ pushfl
+ incl _intr_count
+ sti
+ call _do_bottom_half
+ popfl
+ decl _intr_count
+ jmp 9f
+.align 4
+reschedule:
+ pushl $ret_from_sys_call
+ jmp _schedule
+.align 4
+_system_call:
+ pushl %eax # save orig_eax
+ SAVE_ALL
+ movl $-ENOSYS,EAX(%esp)
+ cmpl $(NR_syscalls),%eax
+ jae ret_from_sys_call
+ movl _sys_call_table(,%eax,4),%eax
+ testl %eax,%eax
+ je ret_from_sys_call
+ movl _current,%ebx
+ andl $~CF_MASK,EFLAGS(%esp) # clear carry - assume no errors
+ movl $0,errno(%ebx)
+ movl %db6,%edx
+ movl %edx,dbgreg6(%ebx) # save current hardware debugging status
+ testb $0x20,flags(%ebx) # PF_TRACESYS
+ jne 1f
+ call *%eax
+ movl %eax,EAX(%esp) # save the return value
+ movl errno(%ebx),%edx
+ negl %edx
+ je ret_from_sys_call
+ movl %edx,EAX(%esp)
+ orl $(CF_MASK),EFLAGS(%esp) # set carry to indicate error
+ jmp ret_from_sys_call
+.align 4
+1: call _syscall_trace
+ movl ORIG_EAX(%esp),%eax
+ call _sys_call_table(,%eax,4)
+ movl %eax,EAX(%esp) # save the return value
+ movl _current,%eax
+ movl errno(%eax),%edx
+ negl %edx
+ je 1f
+ movl %edx,EAX(%esp)
+ orl $(CF_MASK),EFLAGS(%esp) # set carry to indicate error
+1: call _syscall_trace
+
+ .align 4,0x90
+ret_from_sys_call:
+ cmpl $0,_intr_count
+ jne 2f
+9: movl _bh_mask,%eax
+ andl _bh_active,%eax
+ jne handle_bottom_half
+ movl EFLAGS(%esp),%eax # check VM86 flag: CS/SS are
+ testl $(VM_MASK),%eax # different then
+ jne 1f
+ cmpw $(KERNEL_CS),CS(%esp) # was old code segment supervisor ?
+ je 2f
+1: sti
+ orl $(IF_MASK),%eax # these just try to make sure
+ andl $~NT_MASK,%eax # the program doesn't do anything
+ movl %eax,EFLAGS(%esp) # stupid
+ cmpl $0,_need_resched
+ jne reschedule
+ movl _current,%eax
+ cmpl _task,%eax # task[0] cannot have signals
+ je 2f
+ cmpl $0,state(%eax) # state
+ jne reschedule
+ cmpl $0,counter(%eax) # counter
+ je reschedule
+ movl blocked(%eax),%ecx
+ movl %ecx,%ebx # save blocked in %ebx for signal handling
+ notl %ecx
+ andl signal(%eax),%ecx
+ jne signal_return
+2: RESTORE_ALL
+.align 4
+signal_return:
+ movl %esp,%ecx
+ pushl %ecx
+ testl $(VM_MASK),EFLAGS(%ecx)
+ jne v86_signal_return
+ pushl %ebx
+ call _do_signal
+ popl %ebx
+ popl %ebx
+ RESTORE_ALL
+.align 4
+v86_signal_return:
+ call _save_v86_state
+ movl %eax,%esp
+ pushl %eax
+ pushl %ebx
+ call _do_signal
+ popl %ebx
+ popl %ebx
+ RESTORE_ALL
+
+.align 4
+_divide_error:
+ pushl $0 # no error code
+ pushl $_do_divide_error
+.align 4,0x90
+error_code:
+ push %fs
+ push %es
+ push %ds
+ pushl %eax
+ pushl %ebp
+ pushl %edi
+ pushl %esi
+ pushl %edx
+ pushl %ecx
+ pushl %ebx
+ movl $0,%eax
+ movl %eax,%db7 # disable hardware debugging...
+ cld
+ movl $-1, %eax
+ xchgl %eax, ORIG_EAX(%esp) # orig_eax (get the error code. )
+ xorl %ebx,%ebx # zero ebx
+ mov %gs,%bx # get the lower order bits of gs
+ xchgl %ebx, GS(%esp) # get the address and save gs.
+ pushl %eax # push the error code
+ lea 4(%esp),%edx
+ pushl %edx
+ movl $(KERNEL_DS),%edx
+ mov %dx,%ds
+ mov %dx,%es
+ movl $(USER_DS),%edx
+ mov %dx,%fs
+ pushl %eax
+ movl _current,%eax
+ movl %db6,%edx
+ movl %edx,dbgreg6(%eax) # save current hardware debugging status
+ popl %eax
+ call *%ebx
+ addl $8,%esp
+ jmp ret_from_sys_call
+
+.align 4
+_coprocessor_error:
+ pushl $0
+ pushl $_do_coprocessor_error
+ jmp error_code
+
+.align 4
+_device_not_available:
+ pushl $-1 # mark this as an int
+ SAVE_ALL
+ pushl $ret_from_sys_call
+ movl %cr0,%eax
+ testl $0x4,%eax # EM (math emulation bit)
+ je _math_state_restore
+ pushl $0 # temporary storage for ORIG_EIP
+ call _math_emulate
+ addl $4,%esp
+ ret
+
+.align 4
+_debug:
+ pushl $0
+ pushl $_do_debug
+ jmp error_code
+
+.align 4
+_nmi:
+ pushl $0
+ pushl $_do_nmi
+ jmp error_code
+
+.align 4
+_int3:
+ pushl $0
+ pushl $_do_int3
+ jmp error_code
+
+.align 4
+_overflow:
+ pushl $0
+ pushl $_do_overflow
+ jmp error_code
+
+.align 4
+_bounds:
+ pushl $0
+ pushl $_do_bounds
+ jmp error_code
+
+.align 4
+_invalid_op:
+ pushl $0
+ pushl $_do_invalid_op
+ jmp error_code
+
+.align 4
+_coprocessor_segment_overrun:
+ pushl $0
+ pushl $_do_coprocessor_segment_overrun
+ jmp error_code
+
+.align 4
+_reserved:
+ pushl $0
+ pushl $_do_reserved
+ jmp error_code
+
+.align 4
+_double_fault:
+ pushl $_do_double_fault
+ jmp error_code
+
+.align 4
+_invalid_TSS:
+ pushl $_do_invalid_TSS
+ jmp error_code
+
+.align 4
+_segment_not_present:
+ pushl $_do_segment_not_present
+ jmp error_code
+
+.align 4
+_stack_segment:
+ pushl $_do_stack_segment
+ jmp error_code
+
+.align 4
+_general_protection:
+ pushl $_do_general_protection
+ jmp error_code
+
+.align 4
+_alignment_check:
+ pushl $_do_alignment_check
+ jmp error_code
+
+.align 4
+_page_fault:
+ pushl $_do_page_fault
+ jmp error_code
+
+.data
+.align 4
+_sys_call_table:
+ .long _sys_setup /* 0 */
+ .long _sys_exit
+ .long _sys_fork
+ .long _sys_read
+ .long _sys_write
+ .long _sys_open /* 5 */
+ .long _sys_close
+ .long _sys_waitpid
+ .long _sys_creat
+ .long _sys_link
+ .long _sys_unlink /* 10 */
+ .long _sys_execve
+ .long _sys_chdir
+ .long _sys_time
+ .long _sys_mknod
+ .long _sys_chmod /* 15 */
+ .long _sys_chown
+ .long _sys_break
+ .long _sys_stat
+ .long _sys_lseek
+ .long _sys_getpid /* 20 */
+ .long _sys_mount
+ .long _sys_umount
+ .long _sys_setuid
+ .long _sys_getuid
+ .long _sys_stime /* 25 */
+ .long _sys_ptrace
+ .long _sys_alarm
+ .long _sys_fstat
+ .long _sys_pause
+ .long _sys_utime /* 30 */
+ .long _sys_stty
+ .long _sys_gtty
+ .long _sys_access
+ .long _sys_nice
+ .long _sys_ftime /* 35 */
+ .long _sys_sync
+ .long _sys_kill
+ .long _sys_rename
+ .long _sys_mkdir
+ .long _sys_rmdir /* 40 */
+ .long _sys_dup
+ .long _sys_pipe
+ .long _sys_times
+ .long _sys_prof
+ .long _sys_brk /* 45 */
+ .long _sys_setgid
+ .long _sys_getgid
+ .long _sys_signal
+ .long _sys_geteuid
+ .long _sys_getegid /* 50 */
+ .long _sys_acct
+ .long _sys_phys
+ .long _sys_lock
+ .long _sys_ioctl
+ .long _sys_fcntl /* 55 */
+ .long _sys_mpx
+ .long _sys_setpgid
+ .long _sys_ulimit
+ .long _sys_olduname
+ .long _sys_umask /* 60 */
+ .long _sys_chroot
+ .long _sys_ustat
+ .long _sys_dup2
+ .long _sys_getppid
+ .long _sys_getpgrp /* 65 */
+ .long _sys_setsid
+ .long _sys_sigaction
+ .long _sys_sgetmask
+ .long _sys_ssetmask
+ .long _sys_setreuid /* 70 */
+ .long _sys_setregid
+ .long _sys_sigsuspend
+ .long _sys_sigpending
+ .long _sys_sethostname
+ .long _sys_setrlimit /* 75 */
+ .long _sys_getrlimit
+ .long _sys_getrusage
+ .long _sys_gettimeofday
+ .long _sys_settimeofday
+ .long _sys_getgroups /* 80 */
+ .long _sys_setgroups
+ .long _sys_select
+ .long _sys_symlink
+ .long _sys_lstat
+ .long _sys_readlink /* 85 */
+ .long _sys_uselib
+ .long _sys_swapon
+ .long _sys_reboot
+ .long _sys_readdir
+ .long _sys_mmap /* 90 */
+ .long _sys_munmap
+ .long _sys_truncate
+ .long _sys_ftruncate
+ .long _sys_fchmod
+ .long _sys_fchown /* 95 */
+ .long _sys_getpriority
+ .long _sys_setpriority
+ .long _sys_profil
+ .long _sys_statfs
+ .long _sys_fstatfs /* 100 */
+ .long _sys_ioperm
+ .long _sys_socketcall
+ .long _sys_syslog
+ .long _sys_setitimer
+ .long _sys_getitimer /* 105 */
+ .long _sys_newstat
+ .long _sys_newlstat
+ .long _sys_newfstat
+ .long _sys_uname
+ .long _sys_iopl /* 110 */
+ .long _sys_vhangup
+ .long _sys_idle
+ .long _sys_vm86
+ .long _sys_wait4
+ .long _sys_swapoff /* 115 */
+ .long _sys_sysinfo
+ .long _sys_ipc
+ .long _sys_fsync
+ .long _sys_sigreturn
+ .long _sys_clone /* 120 */
+ .long _sys_setdomainname
+ .long _sys_newuname
+ .long _sys_modify_ldt
+ .long _sys_adjtimex
+ .long _sys_mprotect /* 125 */
+ .long _sys_sigprocmask
+ .long _sys_create_module
+ .long _sys_init_module
+ .long _sys_delete_module
+ .long _sys_get_kernel_syms /* 130 */
+ .long _sys_quotactl
+ .long _sys_getpgid
+ .long _sys_fchdir
+ .long _sys_bdflush
+ .long _sys_sysfs /* 135 */
+ .long _sys_personality
+ .long 0 /* for afs_syscall */
+ .long _sys_setfsuid
+ .long _sys_setfsgid
+ .long _sys_llseek /* 140 */
+ .space (NR_syscalls-140)*4