summaryrefslogtreecommitdiffstats
path: root/arch/i386
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-01-07 02:33:00 +0000
committer <ralf@linux-mips.org>1997-01-07 02:33:00 +0000
commitbeb116954b9b7f3bb56412b2494b562f02b864b1 (patch)
tree120e997879884e1b9d93b265221b939d2ef1ade1 /arch/i386
parent908d4681a1dc3792ecafbe64265783a86c4cccb6 (diff)
Import of Linux/MIPS 2.1.14
Diffstat (limited to 'arch/i386')
-rw-r--r--arch/i386/Makefile78
-rw-r--r--arch/i386/boot/Makefile54
-rw-r--r--arch/i386/boot/bootsect.S8
-rw-r--r--arch/i386/boot/compressed/Makefile60
-rw-r--r--arch/i386/boot/compressed/Makefile.debug21
-rw-r--r--arch/i386/boot/compressed/crypt.h12
-rw-r--r--arch/i386/boot/compressed/gzip.h284
-rw-r--r--arch/i386/boot/compressed/head.S91
-rw-r--r--arch/i386/boot/compressed/inflate.c810
-rw-r--r--arch/i386/boot/compressed/lzw.h42
-rw-r--r--arch/i386/boot/compressed/misc.c483
-rw-r--r--arch/i386/boot/compressed/unzip.c180
-rw-r--r--arch/i386/boot/setup.S1046
-rw-r--r--arch/i386/boot/tools/build.c57
-rw-r--r--arch/i386/boot/video.S1839
-rw-r--r--arch/i386/config.in326
-rw-r--r--arch/i386/defconfig176
-rw-r--r--arch/i386/ibcs/Makefile37
-rw-r--r--arch/i386/ibcs/binfmt_coff.c784
-rw-r--r--arch/i386/ibcs/binfmt_elf.c655
-rw-r--r--arch/i386/ibcs/emulate.c10
-rw-r--r--arch/i386/kernel/Makefile69
-rw-r--r--arch/i386/kernel/bios32.c29
-rw-r--r--arch/i386/kernel/entry.S773
-rw-r--r--arch/i386/kernel/head.S355
-rw-r--r--arch/i386/kernel/hexify.c31
-rw-r--r--arch/i386/kernel/ioport.c4
-rw-r--r--arch/i386/kernel/irq.c463
-rw-r--r--arch/i386/kernel/ksyms.c41
-rw-r--r--arch/i386/kernel/ldt.c44
-rw-r--r--arch/i386/kernel/process.c283
-rw-r--r--arch/i386/kernel/ptrace.c193
-rw-r--r--arch/i386/kernel/setup.c308
-rw-r--r--arch/i386/kernel/signal.c324
-rw-r--r--arch/i386/kernel/smp.c1204
-rw-r--r--arch/i386/kernel/sys_i386.c181
-rw-r--r--arch/i386/kernel/time.c500
-rw-r--r--arch/i386/kernel/trampoline.S74
-rw-r--r--arch/i386/kernel/trampoline32.S20
-rw-r--r--arch/i386/kernel/traps.c139
-rw-r--r--arch/i386/kernel/vm86.c130
-rw-r--r--arch/i386/lib/Makefile16
-rw-r--r--arch/i386/lib/checksum.c194
-rw-r--r--arch/i386/lib/semaphore.S35
-rw-r--r--arch/i386/math-emu/Makefile34
-rw-r--r--arch/i386/math-emu/README10
-rw-r--r--arch/i386/math-emu/control_w.h2
-rw-r--r--arch/i386/math-emu/div_Xsig.S12
-rw-r--r--arch/i386/math-emu/div_small.S13
-rw-r--r--arch/i386/math-emu/errors.c60
-rw-r--r--arch/i386/math-emu/exception.h10
-rw-r--r--arch/i386/math-emu/fpu_asm.h9
-rw-r--r--arch/i386/math-emu/fpu_emu.h22
-rw-r--r--arch/i386/math-emu/fpu_entry.c59
-rw-r--r--arch/i386/math-emu/fpu_proto.h2
-rw-r--r--arch/i386/math-emu/get_address.c48
-rw-r--r--arch/i386/math-emu/load_store.c8
-rw-r--r--arch/i386/math-emu/mul_Xsig.S18
-rw-r--r--arch/i386/math-emu/polynom_Xsig.S10
-rw-r--r--arch/i386/math-emu/reg_constant.c51
-rw-r--r--arch/i386/math-emu/reg_div.S35
-rw-r--r--arch/i386/math-emu/reg_ld_str.c198
-rw-r--r--arch/i386/math-emu/reg_norm.S25
-rw-r--r--arch/i386/math-emu/reg_round.S22
-rw-r--r--arch/i386/math-emu/reg_u_add.S14
-rw-r--r--arch/i386/math-emu/reg_u_div.S20
-rw-r--r--arch/i386/math-emu/reg_u_mul.S15
-rw-r--r--arch/i386/math-emu/reg_u_sub.S14
-rw-r--r--arch/i386/math-emu/round_Xsig.S17
-rw-r--r--arch/i386/math-emu/shr_Xsig.S11
-rw-r--r--arch/i386/math-emu/status_w.h6
-rw-r--r--arch/i386/math-emu/version.h8
-rw-r--r--arch/i386/math-emu/wm_shrx.S16
-rw-r--r--arch/i386/math-emu/wm_sqrt.S11
-rw-r--r--arch/i386/mm/Makefile25
-rw-r--r--arch/i386/mm/extable.c63
-rw-r--r--arch/i386/mm/fault.c153
-rw-r--r--arch/i386/mm/init.c180
-rw-r--r--arch/i386/mm/ioremap.c109
79 files changed, 8144 insertions, 5629 deletions
diff --git a/arch/i386/Makefile b/arch/i386/Makefile
index 0b296da44..429b2b2b4 100644
--- a/arch/i386/Makefile
+++ b/arch/i386/Makefile
@@ -13,39 +13,65 @@
# Copyright (C) 1994 by Linus Torvalds
#
+AS86 =$(CROSS_COMPILE)as86 -0 -a
+AS386 =$(CROSS_COMPILE)as86 -3
+LD86 =$(CROSS_COMPILE)ld86 -0
+
#
-# Set these to indicate how to link it..
-#
-# -zmagic:
+# ZIMAGE_OFFSET is the load offset of the compression loader
+# BZIMAGE_OFFSET is the load offset of the high loaded compression loader
#
-# ZLINKFLAGS = -Ttext 0x1000
-# LINKFLAGS = -Ttext 0x100000
+ZIMAGE_OFFSET=0x1000
+BZIMAGE_OFFSET=0x100000
+
#
-# -qmagic (we need to remove the 32 byte header for bootup purposes)
+# IMAGE_OFFSET is the load offset of the _real_ kernel, soon
+# to be offset by another 0xC0000000...
#
-ZLINKFLAGS =-qmagic -Ttext 0xfe0
-LINKFLAGS =-qmagic -Ttext 0xfffe0
+IMAGE_OFFSET=0xC0100000
+
+# This is used for ELF - it needs to migrate or be moved.
+LD_RFLAG = -m elf_i386
+
+LD=$(CROSS_COMPILE)ld -m elf_i386
+CPP=$(CC) -E -D__ELF__
+OBJDUMP=$(CROSS_COMPILE)objdump
+OBJDUMP_FLAGS=-k -q
+ENCAPS=$(CROSS_COMPILE)encaps
+OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -R .stab -R .stabstr
+ZLDFLAGS=-e startup_32
+LDFLAGS=-e stext
+ZLINKFLAGS =-Ttext $(ZIMAGE_OFFSET) $(ZLDFLAGS)
+BZLINKFLAGS =-Ttext $(BZIMAGE_OFFSET) $(ZLDFLAGS)
+LINKFLAGS =-Ttext $(IMAGE_OFFSET) $(LDFLAGS)
+
CFLAGS := $(CFLAGS) -pipe
+ifdef CONFIG_M386
+CFLAGS := $(CFLAGS) -m386 -DCPU=386
+endif
+
ifdef CONFIG_M486
-CFLAGS := $(CFLAGS) -m486
-else
+CFLAGS := $(CFLAGS) -m486 -DCPU=486
+endif
+
ifdef CONFIG_M586
-CFLAGS := $(CFLAGS) -mpentium
-else
-CFLAGS := $(CFLAGS) -m386
+CFLAGS := $(CFLAGS) -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=586
endif
+
+ifdef CONFIG_M686
+CFLAGS := $(CFLAGS) -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=686
+endif
+
+ifdef SMP
+CFLAGS := $(CFLAGS) -D__SMP__
endif
HEAD := arch/i386/kernel/head.o
-SUBDIRS := $(SUBDIRS) arch/i386/kernel arch/i386/mm
+SUBDIRS := $(SUBDIRS) arch/i386/kernel arch/i386/mm arch/i386/lib
ARCHIVES := arch/i386/kernel/kernel.o arch/i386/mm/mm.o $(ARCHIVES)
-
-ifdef CONFIG_IBCS
-SUBDIRS := $(SUBDIRS) arch/i386/ibcs
-DRIVERS := $(DRIVERS) arch/i386/ibcs/ibcs.o
-endif
+LIBS := $(TOPDIR)/arch/i386/lib/lib.a $(LIBS) $(TOPDIR)/arch/i386/lib/lib.a
ifdef CONFIG_MATH_EMULATION
SUBDIRS := $(SUBDIRS) arch/i386/math-emu
@@ -63,19 +89,29 @@ MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
zImage: vmlinux
@$(MAKEBOOT) zImage
+bzImage: vmlinux
+ @$(MAKEBOOT) bzImage
+
compressed: zImage
zlilo: vmlinux
- @$(MAKEBOOT) zlilo
+ @$(MAKEBOOT) BOOTIMAGE=zImage zlilo
+
+bzlilo: vmlinux
+ @$(MAKEBOOT) BOOTIMAGE=bzImage zlilo
zdisk: vmlinux
- @$(MAKEBOOT) zdisk
+ @$(MAKEBOOT) BOOTIMAGE=zImage zdisk
+
+bzdisk: vmlinux
+ @$(MAKEBOOT) BOOTIMAGE=bzImage zdisk
install: vmlinux
@$(MAKEBOOT) install
archclean:
@$(MAKEBOOT) clean
+ $(MAKE) -C arch/$(ARCH)/kernel clean
archdep:
@$(MAKEBOOT) dep
diff --git a/arch/i386/boot/Makefile b/arch/i386/boot/Makefile
index b6a5f1c15..503b0cce6 100644
--- a/arch/i386/boot/Makefile
+++ b/arch/i386/boot/Makefile
@@ -8,23 +8,43 @@
# Copyright (C) 1994 by Linus Torvalds
#
-AS86 =as86 -0 -a
-LD86 =ld86 -0
+HOSTCFLAGS := $(HOSTCFLAGS) -D__BFD__
+
+ifdef SMP
+HOSTCFLAGS := $(HOSTCFLAGS) -D__SMP__
+endif
zImage: $(CONFIGURE) bootsect setup compressed/vmlinux tools/build
- tools/build bootsect setup compressed/vmlinux $(ROOT_DEV) > zImage
+ if hash $(ENCAPS) 2> /dev/null; then \
+ $(OBJDUMP) $(OBJDUMP_FLAGS) -o $(ZIMAGE_OFFSET) compressed/vmlinux > compressed/vmlinux.out; \
+ else \
+ $(OBJCOPY) compressed/vmlinux compressed/vmlinux.out; \
+ fi
+ tools/build bootsect setup compressed/vmlinux.out $(ROOT_DEV) > zImage
+ sync
+
+bzImage: $(CONFIGURE) bbootsect setup compressed/bvmlinux tools/bbuild
+ if hash $(ENCAPS) 2> /dev/null; then \
+ $(OBJDUMP) $(OBJDUMP_FLAGS) -o $(BZIMAGE_OFFSET) compressed/bvmlinux > compressed/bvmlinux.out; \
+ else \
+ $(OBJCOPY) compressed/bvmlinux compressed/bvmlinux.out; \
+ fi
+ tools/bbuild bbootsect setup compressed/bvmlinux.out $(ROOT_DEV) > bzImage
sync
compressed/vmlinux: $(TOPDIR)/vmlinux
@$(MAKE) -C compressed vmlinux
-zdisk: zImage
- dd bs=8192 if=zImage of=/dev/fd0
+compressed/bvmlinux: $(TOPDIR)/vmlinux
+ @$(MAKE) -C compressed bvmlinux
-zlilo: $(CONFIGURE) zImage
+zdisk: $(BOOTIMAGE)
+ dd bs=8192 if=$(BOOTIMAGE) of=/dev/fd0
+
+zlilo: $(CONFIGURE) $(BOOTIMAGE)
if [ -f $(INSTALL_PATH)/vmlinuz ]; then mv $(INSTALL_PATH)/vmlinuz $(INSTALL_PATH)/vmlinuz.old; fi
if [ -f $(INSTALL_PATH)/System.map ]; then mv $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
- cat zImage > $(INSTALL_PATH)/vmlinuz
+ cat $(BOOTIMAGE) > $(INSTALL_PATH)/vmlinuz
cp $(TOPDIR)/System.map $(INSTALL_PATH)/
if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
@@ -32,7 +52,10 @@ install: $(CONFIGURE) zImage
sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) zImage $(TOPDIR)/System.map "$(INSTALL_PATH)"
tools/build: tools/build.c
- $(HOSTCC) $(CFLAGS) -o $@ $< -I$(TOPDIR)/include
+ $(HOSTCC) $(HOSTCFLAGS) -o $@ $< -I$(TOPDIR)/include
+
+tools/bbuild: tools/build.c
+ $(HOSTCC) $(HOSTCFLAGS) -D__BIG_KERNEL__ -o $@ $< -I$(TOPDIR)/include
setup: setup.o
$(LD86) -s -o $@ $<
@@ -40,7 +63,7 @@ setup: setup.o
setup.o: setup.s
$(AS86) -o $@ $<
-setup.s: setup.S $(CONFIGURE) $(TOPDIR)/include/linux/config.h Makefile
+setup.s: setup.S video.S $(CONFIGURE) $(TOPDIR)/include/linux/config.h Makefile
$(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
bootsect: bootsect.o
@@ -52,9 +75,20 @@ bootsect.o: bootsect.s
bootsect.s: bootsect.S $(CONFIGURE) $(TOPDIR)/include/linux/config.h Makefile
$(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
+bbootsect: bbootsect.o
+ $(LD86) -s -o $@ $<
+
+bbootsect.o: bbootsect.s
+ $(AS86) -o $@ $<
+
+bbootsect.s: bootsect.S $(CONFIGURE) $(TOPDIR)/include/linux/config.h Makefile
+ $(CPP) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
+
dep:
clean:
rm -f bootsect setup
- rm -f zImage tools/build
+ rm -f bbootsect
+ rm -f zImage tools/build compressed/vmlinux.out
+ rm -f bzImage tools/bbuild compressed/bvmlinux.out
@$(MAKE) -C compressed clean
diff --git a/arch/i386/boot/bootsect.S b/arch/i386/boot/bootsect.S
index f6a0d3158..88a04190d 100644
--- a/arch/i386/boot/bootsect.S
+++ b/arch/i386/boot/bootsect.S
@@ -47,7 +47,7 @@ SWAP_DEV = 0
#define RAMDISK 0
#endif
#ifndef CONFIG_ROOT_RDONLY
-#define CONFIG_ROOT_RDONLY 0
+#define CONFIG_ROOT_RDONLY 1
#endif
! ld86 requires an entry symbol. This may as well be the usual one.
@@ -268,8 +268,14 @@ read_it:
die: jne die ! es must be at 64kB boundary
xor bx,bx ! bx is starting address within segment
rp_read:
+#ifdef __BIG_KERNEL__
+#define CALL_HIGHLOAD_KLUDGE .word 0x1eff,0x220 ! call far * bootsect_kludge
+ ! NOTE: as86 can't assemble this
+ CALL_HIGHLOAD_KLUDGE ! this is within setup.S
+#else
mov ax,es
sub ax,#SYSSEG
+#endif
cmp ax,syssize ! have we loaded all yet?
jbe ok1_read
ret
diff --git a/arch/i386/boot/compressed/Makefile b/arch/i386/boot/compressed/Makefile
index b4e3f8482..d7f093e3f 100644
--- a/arch/i386/boot/compressed/Makefile
+++ b/arch/i386/boot/compressed/Makefile
@@ -7,35 +7,57 @@
HEAD = head.o
SYSTEM = $(TOPDIR)/vmlinux
-OBJECTS = $(HEAD) inflate.o unzip.o misc.o
+OBJECTS = $(HEAD) misc.o
CFLAGS = -O2 -DSTDC_HEADERS
-.c.s:
- $(CC) $(CFLAGS) -S $<
-.s.o:
- $(AS) -o $*.o $<
-.c.o:
- $(CC) $(CFLAGS) -c $<
+ifdef SMP
+CFLAGS := $(CFLAGS) -D__SMP__
+endif
+
+TARGET=--target elf32-i386
+INPUT_DATA=input_data
+INPUT_LEN=input_len
all: vmlinux
-vmlinux: piggy.o $(OBJECTS)
- $(LD) $(ZLINKFLAGS) -o vmlinux $(OBJECTS) piggy.o
+vmlinux: piggy.o $(OBJECTS)
+ $(LD) $(ZLINKFLAGS) -o vmlinux $(OBJECTS) piggy.o
+
+bvmlinux: piggy.o $(OBJECTS)
+ $(LD) $(BZLINKFLAGS) -o bvmlinux $(OBJECTS) piggy.o
+
+ifdef SMP
+
+head.o: head.S $(TOPDIR)/include/linux/tasks.h
+ $(CC) -D__SMP__ -traditional -c head.S
-head.o: head.s
+else
-head.s: head.S $(TOPDIR)/include/linux/tasks.h
- $(CPP) -traditional head.S -o head.s
+head.o: head.S $(TOPDIR)/include/linux/tasks.h
+ $(CC) -traditional -c head.S
-piggy.o: $(SYSTEM) xtract piggyback
- ./xtract $(SYSTEM) | gzip -9 | ./piggyback > piggy.o
+endif
-xtract: xtract.c
- $(HOSTCC) $(CFLAGS) -o xtract xtract.c
-piggyback: piggyback.c
- $(HOSTCC) $(CFLAGS) -o piggyback piggyback.c
+# You cannot compress a file and have the kernel uncompress it, it must
+# be stdin
+piggy.o: $(SYSTEM)
+ tmppiggy=/tmp/$$$$piggy; \
+ rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; \
+ if hash $(ENCAPS) 2> /dev/null; then \
+ $(OBJDUMP) $(OBJDUMP_FLAGS) -o $(IMAGE_OFFSET) $(SYSTEM) > $$tmppiggy; \
+ else \
+ $(OBJCOPY) $(SYSTEM) $$tmppiggy; \
+ fi; \
+ gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \
+ if hash $(ENCAPS) 2> /dev/null; then \
+ $(ENCAPS) $(TARGET) piggy.o $$tmppiggy.gz $(INPUT_DATA) $(INPUT_LEN); \
+ else \
+ echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \
+ $(LD) -m elf_i386 -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-i386 -T $$tmppiggy.lnk; \
+ fi; \
+ rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk
clean:
- rm -f xtract piggyback vmlinux
+ rm -f xtract piggyback vmlinux bvmlinux
diff --git a/arch/i386/boot/compressed/Makefile.debug b/arch/i386/boot/compressed/Makefile.debug
new file mode 100644
index 000000000..83714b505
--- /dev/null
+++ b/arch/i386/boot/compressed/Makefile.debug
@@ -0,0 +1,21 @@
+#
+# linux/arch/i386/boot/compressed/Makefile
+#
+# create a compressed vmlinux image from the original vmlinux
+#
+
+OBJECTS = misc.o
+
+CFLAGS = -g -O2 -DSTDC_HEADERS -DSTANDALONE_DEBUG -Wall
+
+test-gzip: piggy.o $(OBJECTS)
+ $(CC) -g -o test-gzip $(OBJECTS) piggy.o
+
+clean:
+ $(RM) inflate.o misc.o test-gzip
+
+inflate.o: inflate.c gzip.h
+
+misc.o: misc.c gzip.h
+
+
diff --git a/arch/i386/boot/compressed/crypt.h b/arch/i386/boot/compressed/crypt.h
deleted file mode 100644
index 2a4c203ca..000000000
--- a/arch/i386/boot/compressed/crypt.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* crypt.h (dummy version) -- do not perform encryption
- * Hardly worth copyrighting :-)
- */
-
-#ifdef CRYPT
-# undef CRYPT /* dummy version */
-#endif
-
-#define RAND_HEAD_LEN 12 /* length of encryption random header */
-
-#define zencode
-#define zdecode
diff --git a/arch/i386/boot/compressed/gzip.h b/arch/i386/boot/compressed/gzip.h
deleted file mode 100644
index 2f738b945..000000000
--- a/arch/i386/boot/compressed/gzip.h
+++ /dev/null
@@ -1,284 +0,0 @@
-/* gzip.h -- common declarations for all gzip modules
- * Copyright (C) 1992-1993 Jean-loup Gailly.
- * This is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License, see the file COPYING.
- */
-
-#if defined(__STDC__) || defined(PROTO)
-# define OF(args) args
-#else
-# define OF(args) ()
-#endif
-
-#ifdef __STDC__
- typedef void *voidp;
-#else
- typedef char *voidp;
-#endif
-
-/* I don't like nested includes, but the string functions are used too often */
-#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
-# include <string.h>
-# define memzero(s, n) memset ((s), 0, (n))
-#else
-# include <strings.h>
-# define strchr index
-# define strrchr rindex
-# define memcpy(d, s, n) bcopy((s), (d), (n))
-# define memcmp(s1, s2, n) bcmp((s1), (s2), (n))
-# define memzero(s, n) bzero((s), (n))
-#endif
-
-#if !defined(STDC_HEADERS) && defined(HAVE_MEMORY_H)
-# include <memory.h>
-#endif
-
-#ifndef RETSIGTYPE
-# define RETSIGTYPE void
-#endif
-
-#define local static
-
-typedef unsigned char uch;
-typedef unsigned short ush;
-typedef unsigned long ulg;
-
-/* Return codes from gzip */
-#define OK 0
-#define ERROR 1
-#define WARNING 2
-
-/* Compression methods (see algorithm.doc) */
-#define STORED 0
-#define COMPRESSED 1
-#define PACKED 2
-/* methods 3 to 7 reserved */
-#define DEFLATED 8
-extern int method; /* compression method */
-
-/* To save memory for 16 bit systems, some arrays are overlayed between
- * the various modules:
- * deflate: prev+head window d_buf l_buf outbuf
- * unlzw: tab_prefix tab_suffix stack inbuf outbuf
- * inflate: window inbuf
- * unpack: window inbuf
- * For compression, input is done in window[]. For decompression, output
- * is done in window except for unlzw.
- */
-
-#ifndef INBUFSIZ
-# define INBUFSIZ 0x8000 /* input buffer size */
-#endif
-#define INBUF_EXTRA 64 /* required by unlzw() */
-
-#ifndef OUTBUFSIZ
-# define OUTBUFSIZ 16384 /* output buffer size */
-#endif
-#define OUTBUF_EXTRA 2048 /* required by unlzw() */
-
-#define DIST_BUFSIZE 0x8000 /* buffer for distances, see trees.c */
-
-#ifdef DYN_ALLOC
-# define EXTERN(type, array) extern type * near array
-# define DECLARE(type, array, size) type * near array
-# define ALLOC(type, array, size) { \
- array = (type*)fcalloc((unsigned)(((size)+1L)/2), 2*sizeof(type)); \
- if (array == NULL) error("insufficient memory"); \
- }
-# define FREE(array) {if (array != NULL) fcfree(array), array=NULL;}
-#else
-# define EXTERN(type, array) extern type array[]
-# define DECLARE(type, array, size) type array[size]
-# define ALLOC(type, array, size)
-# define FREE(array)
-#endif
-
-EXTERN(uch, inbuf); /* input buffer */
-EXTERN(uch, outbuf); /* output buffer */
-EXTERN(ush, d_buf); /* buffer for distances, see trees.c */
-EXTERN(uch, window); /* Sliding window and suffix table (unlzw) */
-#define tab_suffix window
-#ifndef MAXSEG_64K
-# define tab_prefix prev /* hash link (see deflate.c) */
-# define head (prev+WSIZE) /* hash head (see deflate.c) */
- EXTERN(ush, tab_prefix); /* prefix code (see unlzw.c) */
-#else
-# define tab_prefix0 prev
-# define head tab_prefix1
- EXTERN(ush, tab_prefix0); /* prefix for even codes */
- EXTERN(ush, tab_prefix1); /* prefix for odd codes */
-#endif
-
-extern unsigned insize; /* valid bytes in inbuf */
-extern unsigned inptr; /* index of next byte to be processed in inbuf */
-extern unsigned outcnt; /* bytes in output buffer */
-
-extern long bytes_in; /* number of input bytes */
-extern long bytes_out; /* number of output bytes */
-extern long overhead; /* number of bytes in gzip header */
-
-#define isize bytes_in
-/* for compatibility with old zip sources (to be cleaned) */
-
-extern int ifd; /* input file descriptor */
-extern int ofd; /* output file descriptor */
-extern char ifname[]; /* input filename or "stdin" */
-extern char ofname[]; /* output filename or "stdout" */
-
-extern ulg time_stamp; /* original time stamp (modification time) */
-extern long ifile_size; /* input file size, -1 for devices (debug only) */
-
-extern int exit_code; /* program exit code */
-
-typedef int file_t; /* Do not use stdio */
-#define NO_FILE (-1) /* in memory compression */
-
-
-#define GZIP_MAGIC "\037\213" /* Magic header for gzip files, 1F 8B */
-#define OLD_GZIP_MAGIC "\037\236" /* Magic header for gzip 0.5 = freeze 1.x */
-#define PKZIP_MAGIC "PK\003\004" /* Magic header for pkzip files */
-#define PACK_MAGIC "\037\036" /* Magic header for packed files */
-
-/* gzip flag byte */
-#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
-#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
-#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
-#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
-#define COMMENT 0x10 /* bit 4 set: file comment present */
-#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
-#define RESERVED 0xC0 /* bit 6,7: reserved */
-
-/* internal file attribute */
-#define UNKNOWN (-1)
-#define BINARY 0
-#define ASCII 1
-
-#ifndef WSIZE
-# define WSIZE 0x8000 /* window size--must be a power of two, and */
-#endif /* at least 32K for zip's deflate method */
-
-#define MIN_MATCH 3
-#define MAX_MATCH 258
-/* The minimum and maximum match lengths */
-
-#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
-/* Minimum amount of lookahead, except at the end of the input file.
- * See deflate.c for comments about the MIN_MATCH+1.
- */
-
-#define MAX_DIST (WSIZE-MIN_LOOKAHEAD)
-/* In order to simplify the code, particularly on 16 bit machines, match
- * distances are limited to MAX_DIST instead of WSIZE.
- */
-
-extern int decrypt; /* flag to turn on decryption */
-extern int save_orig_name; /* set if original name must be saved */
-extern int verbose; /* be verbose (-v) */
-extern int level; /* compression level */
-extern int test; /* check .z file integrity */
-extern int to_stdout; /* output to stdout (-c) */
-
-#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
-
-/* put_byte is used for the compressed output, put_char for the
- * uncompressed output. However unlzw() uses window for its
- * suffix table instead of its output buffer, so it does not use put_char.
- * (to be cleaned up).
- */
-#define put_byte(c) {outbuf[outcnt++]=(uch)(c); if (outcnt==OUTBUFSIZ)\
- flush_outbuf();}
-#define put_char(c) {window[outcnt++]=(uch)(c); if (outcnt==WSIZE)\
- flush_window();}
-
-/* Output a 16 bit value, lsb first */
-#define put_short(w) \
-{ if (outcnt < OUTBUFSIZ-2) { \
- outbuf[outcnt++] = (uch) ((w) & 0xff); \
- outbuf[outcnt++] = (uch) ((ush)(w) >> 8); \
- } else { \
- put_byte((uch)((w) & 0xff)); \
- put_byte((uch)((ush)(w) >> 8)); \
- } \
-}
-
-/* Output a 32 bit value to the bit stream, lsb first */
-#define put_long(n) { \
- put_short((n) & 0xffff); \
- put_short(((ulg)(n)) >> 16); \
-}
-
-#define seekable() 0 /* force sequential output */
-#define translate_eol 0 /* no option -a yet */
-
-#define tolow(c) (isupper(c) ? (c)-'A'+'a' : (c)) /* force to lower case */
-
-/* Macros for getting two-byte and four-byte header values */
-#define SH(p) ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8))
-#define LG(p) ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16))
-
-/* Diagnostic functions */
-#ifdef DEBUG
-# define Assert(cond,msg) {if(!(cond)) error(msg);}
-# define Trace(x) fprintf x
-# define Tracev(x) {if (verbose) fprintf x ;}
-# define Tracevv(x) {if (verbose>1) fprintf x ;}
-# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
-# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
-#else
-# define Assert(cond,msg)
-# define Trace(x)
-# define Tracev(x)
-# define Tracevv(x)
-# define Tracec(c,x)
-# define Tracecv(c,x)
-#endif
-
- /* in zip.c: */
-extern void zip OF((int in, int out));
-extern int file_read OF((char *buf, unsigned size));
-
- /* in unzip.c */
-extern void unzip OF((int in, int out));
-extern int check_zipfile OF((int in));
-
- /* in unpack.c */
-extern void unpack OF((int in, int out));
-
- /* in gzip.c */
-RETSIGTYPE abort_gzip OF((void));
-
- /* in deflate.c */
-void lm_init OF((int pack_level, ush *flags));
-ulg deflate OF((void));
-
- /* in trees.c */
-void ct_init OF((ush *attr, int *method));
-int ct_tally OF((int dist, int lc));
-ulg flush_block OF((char *buf, ulg stored_len, int eof));
-
- /* in bits.c */
-void bi_init OF((file_t zipfile));
-void send_bits OF((int value, int length));
-unsigned bi_reverse OF((unsigned value, int length));
-void bi_windup OF((void));
-void copy_block OF((char *buf, unsigned len, int header));
-extern int (*read_buf) OF((char *buf, unsigned size));
-
- /* in util.c: */
-extern ulg updcrc OF((uch *s, unsigned n));
-extern void clear_bufs OF((void));
-extern int fill_inbuf OF((void));
-extern void flush_outbuf OF((void));
-extern void flush_window OF((void));
-extern char *strlwr OF((char *s));
-extern char *basename OF((char *fname));
-extern char *add_envopt OF((int *argcp, char ***argvp, char *env));
-extern void error OF((char *m));
-extern void warn OF((char *a, char *b));
-extern void read_error OF((void));
-extern void write_error OF((void));
-extern void display_ratio OF((long num, long den));
-extern voidp xmalloc OF((unsigned int size));
-
- /* in inflate.c */
-extern int inflate OF((void));
diff --git a/arch/i386/boot/compressed/head.S b/arch/i386/boot/compressed/head.S
index 6035cea85..6f68a92d4 100644
--- a/arch/i386/boot/compressed/head.S
+++ b/arch/i386/boot/compressed/head.S
@@ -9,18 +9,31 @@
*
* NOTE!!! Startup happens at absolute address 0x00001000, which is also where
* the page directory will exist. The startup code will be overwritten by
- * the page directory.
+ * the page directory. [According to comments etc elsewhere on a compressed
+ * kernel it will end up at 0x1000 + 1Mb I hope so as I assume this. - AC]
+ *
+ * In SMP mode we keep this page safe. Really we ought to shuffle things and
+ * put the trampoline here. - AC. An SMP trampoline enters with %cx holding
+ * the stack base.
*
* Page 0 is deliberately kept safe, since System Management Mode code in
* laptops may need to access the BIOS data stored there. This is also
* useful for future device drivers that either access the BIOS via VM86
* mode.
*/
+
+/*
+ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
+ */
.text
#define __ASSEMBLY__
+#include <linux/config.h>
+#include <linux/linkage.h>
#include <asm/segment.h>
+ .globl startup_32
+
startup_32:
cld
cli
@@ -29,7 +42,25 @@ startup_32:
mov %ax,%es
mov %ax,%fs
mov %ax,%gs
- lss _stack_start,%esp
+#ifdef __SMP__
+ orw %bx,%bx # What state are we in BX=1 for SMP
+ # 0 for boot
+ jz 2f # Initial boot
+
+/*
+ * We are trampolining an SMP processor
+ */
+ mov %ax,%ss
+ xorl %eax,%eax # Back to 0
+ mov %cx,%ax # SP low 16 bits
+ movl %eax,%esp
+ pushl 0 # Clear NT
+ popfl
+ ljmp $(KERNEL_CS), $0x100000 # Into C and sanity
+
+2:
+#endif
+ lss SYMBOL_NAME(stack_start),%esp
xorl %eax,%eax
1: incl %eax # check that A20 really IS enabled
movl %eax,0x000000 # loop forever if it isn't
@@ -46,8 +77,8 @@ startup_32:
* Clear BSS
*/
xorl %eax,%eax
- movl $__edata,%edi
- movl $__end,%ecx
+ movl $ SYMBOL_NAME(_edata),%edi
+ movl $ SYMBOL_NAME(_end),%ecx
subl %edi,%ecx
cld
rep
@@ -55,5 +86,55 @@ startup_32:
/*
* Do the decompression, and jump to the new kernel..
*/
- call _decompress_kernel
+ subl $16,%esp # place for structure on the stack
+ pushl %esp # address of structure as first arg
+ call SYMBOL_NAME(decompress_kernel)
+ orl %eax,%eax
+ jnz 3f
+ xorl %ebx,%ebx
+ ljmp $(KERNEL_CS), $0x100000
+
+/*
+ * We come here, if we were loaded high.
+ * We need to move the move-in-place routine down to 0x1000
+ * and then start it with the buffer addresses in registers,
+ * which we got from the stack.
+ */
+3:
+ movl $move_routine_start,%esi
+ movl $0x1000,%edi
+ movl $move_routine_end,%ecx
+ subl %esi,%ecx
+ cld
+ rep
+ movsb
+
+ popl %esi # discard the address
+ popl %esi # low_buffer_start
+ popl %ecx # lcount
+ popl %edx # high_buffer_start
+ popl %eax # hcount
+ movl $0x100000,%edi
+ cli # make sure we don't get interrupted
+ ljmp $(KERNEL_CS), $0x1000 # and jump to the move routine
+
+/*
+ * Routine (template) for moving the decompressed kernel in place,
+ * if we were high loaded. This _must_ PIC-code !
+ */
+move_routine_start:
+ rep
+ movsb
+ movl %edx,%esi
+ movl %eax,%ecx # NOTE: rep movsb won't move if %ecx == 0
+ rep
+ movsb
+ xorl %ebx,%ebx
+/*
+ * Well, the kernel relies on %esp pointing into low mem,
+ * with the decompressor loaded high this is no longer true,
+ * so we set esp here.
+ */
+ mov $0x90000,%esp
ljmp $(KERNEL_CS), $0x100000
+move_routine_end:
diff --git a/arch/i386/boot/compressed/inflate.c b/arch/i386/boot/compressed/inflate.c
deleted file mode 100644
index 848fef6ae..000000000
--- a/arch/i386/boot/compressed/inflate.c
+++ /dev/null
@@ -1,810 +0,0 @@
-#define DEBG(x)
-#define DEBG1(x)
-/* inflate.c -- Not copyrighted 1992 by Mark Adler
- version c10p1, 10 January 1993 */
-
-/*
- * Adapted for booting Linux by Hannu Savolainen 1993
- * based on gzip-1.0.3
- */
-
-#ifndef lint
-static char rcsid[] = "$Id: inflate.c,v 0.10 1993/02/04 13:21:06 jloup Exp $";
-#endif
-
-#include "gzip.h"
-#define slide window
-
-#if defined(STDC_HEADERS) || defined(HAVE_STDLIB_H)
-# include <sys/types.h>
-# include <stdlib.h>
-#endif
-
-struct huft {
- uch e; /* number of extra bits or operation */
- uch b; /* number of bits in this code or subcode */
- union {
- ush n; /* literal, length base, or distance base */
- struct huft *t; /* pointer to next level of table */
- } v;
-};
-
-
-/* Function prototypes */
-int huft_build OF((unsigned *, unsigned, unsigned, ush *, ush *,
- struct huft **, int *));
-int huft_free OF((struct huft *));
-int inflate_codes OF((struct huft *, struct huft *, int, int));
-int inflate_stored OF((void));
-int inflate_fixed OF((void));
-int inflate_dynamic OF((void));
-int inflate_block OF((int *));
-int inflate OF((void));
-
-
-#define wp outcnt
-#define flush_output(w) (wp=(w),flush_window())
-
-/* Tables for deflate from PKZIP's appnote.txt. */
-static unsigned border[] = { /* Order of the bit length code lengths */
- 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
-static ush cplens[] = { /* Copy lengths for literal codes 257..285 */
- 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
- 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
- /* note: see note #13 above about the 258 in this list. */
-static ush cplext[] = { /* Extra bits for literal codes 257..285 */
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
- 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */
-static ush cpdist[] = { /* Copy offsets for distance codes 0..29 */
- 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
- 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
- 8193, 12289, 16385, 24577};
-static ush cpdext[] = { /* Extra bits for distance codes */
- 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
- 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
- 12, 12, 13, 13};
-
-
-ulg bb; /* bit buffer */
-unsigned bk; /* bits in bit buffer */
-
-ush mask_bits[] = {
- 0x0000,
- 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
- 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
-};
-
-#ifdef CRYPT
- uch cc;
-# define NEXTBYTE() \
- (decrypt ? (cc = get_byte(), zdecode(cc), cc) : get_byte())
-#else
-# define NEXTBYTE() (uch)get_byte()
-#endif
-#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<<k;k+=8;}}
-#define DUMPBITS(n) {b>>=(n);k-=(n);}
-
-int lbits = 9; /* bits in base literal/length lookup table */
-int dbits = 6; /* bits in base distance lookup table */
-
-
-/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
-#define BMAX 16 /* maximum bit length of any code (16 for explode) */
-#define N_MAX 288 /* maximum number of codes in any set */
-
-
-unsigned hufts; /* track memory usage */
-
-
-int huft_build(b, n, s, d, e, t, m)
-unsigned *b; /* code lengths in bits (all assumed <= BMAX) */
-unsigned n; /* number of codes (assumed <= N_MAX) */
-unsigned s; /* number of simple-valued codes (0..s-1) */
-ush *d; /* list of base values for non-simple codes */
-ush *e; /* list of extra bits for non-simple codes */
-struct huft **t; /* result: starting table */
-int *m; /* maximum lookup bits, returns actual */
-/* Given a list of code lengths and a maximum table size, make a set of
- tables to decode that set of codes. Return zero on success, one if
- the given code set is incomplete (the tables are still built in this
- case), two if the input is invalid (all zero length codes or an
- oversubscribed set of lengths), and three if not enough memory. */
-{
- unsigned a; /* counter for codes of length k */
- unsigned c[BMAX+1]; /* bit length count table */
- unsigned f; /* i repeats in table every f entries */
- int g; /* maximum code length */
- int h; /* table level */
- register unsigned i; /* counter, current code */
- register unsigned j; /* counter */
- register int k; /* number of bits in current code */
- int l; /* bits per table (returned in m) */
- register unsigned *p; /* pointer into c[], b[], or v[] */
- register struct huft *q; /* points to current table */
- struct huft r; /* table entry for structure assignment */
- struct huft *u[BMAX]; /* table stack */
- unsigned v[N_MAX]; /* values in order of bit length */
- register int w; /* bits before this table == (l * h) */
- unsigned x[BMAX+1]; /* bit offsets, then code stack */
- unsigned *xp; /* pointer into x */
- int y; /* number of dummy codes added */
- unsigned z; /* number of entries in current table */
-
-DEBG("huft1 ");
-
- /* Generate counts for each bit length */
- memzero(c, sizeof(c));
- p = b; i = n;
- do {
- c[*p++]++; /* assume all entries <= BMAX */
- } while (--i);
- if (c[0] == n) /* null input--all zero length codes */
- {
- *t = (struct huft *)NULL;
- *m = 0;
- return 0;
- }
-
-DEBG("huft2 ");
-
- /* Find minimum and maximum length, bound *m by those */
- l = *m;
- for (j = 1; j <= BMAX; j++)
- if (c[j])
- break;
- k = j; /* minimum code length */
- if ((unsigned)l < j)
- l = j;
- for (i = BMAX; i; i--)
- if (c[i])
- break;
- g = i; /* maximum code length */
- if ((unsigned)l > i)
- l = i;
- *m = l;
-
-DEBG("huft3 ");
-
- /* Adjust last length count to fill out codes, if needed */
- for (y = 1 << j; j < i; j++, y <<= 1)
- if ((y -= c[j]) < 0)
- return 2; /* bad input: more codes than bits */
- if ((y -= c[i]) < 0)
- return 2;
- c[i] += y;
-
-DEBG("huft4 ");
-
- /* Generate starting offsets into the value table for each length */
- x[1] = j = 0;
- p = c + 1; xp = x + 2;
- while (--i) { /* note that i == g from above */
- *xp++ = (j += *p++);
- }
-
-DEBG("huft5 ");
-
- /* Make a table of values in order of bit lengths */
- p = b; i = 0;
- do {
- if ((j = *p++) != 0)
- v[x[j]++] = i;
- } while (++i < n);
-
-DEBG("h6 ");
-
- /* Generate the Huffman codes and for each, make the table entries */
- x[0] = i = 0; /* first Huffman code is zero */
- p = v; /* grab values in bit order */
- h = -1; /* no tables yet--level -1 */
- w = -l; /* bits decoded == (l * h) */
- u[0] = (struct huft *)NULL; /* just to keep compilers happy */
- q = (struct huft *)NULL; /* ditto */
- z = 0; /* ditto */
-DEBG("h6a ");
-
- /* go through the bit lengths (k already is bits in shortest code) */
- for (; k <= g; k++)
- {
-DEBG("h6b ");
- a = c[k];
- while (a--)
- {
-DEBG("h6b1 ");
- /* here i is the Huffman code of length k bits for value *p */
- /* make tables up to required level */
- while (k > w + l)
- {
-DEBG1("1 ");
- h++;
- w += l; /* previous table always l bits */
-
- /* compute minimum size table less than or equal to l bits */
- z = (z = g - w) > (unsigned)l ? l : z; /* upper limit on table size */
- if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
- { /* too few codes for k-w bit table */
-DEBG1("2 ");
- f -= a + 1; /* deduct codes from patterns left */
- xp = c + k;
- while (++j < z) /* try smaller tables up to z bits */
- {
- if ((f <<= 1) <= *++xp)
- break; /* enough codes to use up j bits */
- f -= *xp; /* else deduct codes from patterns */
- }
- }
-DEBG1("3 ");
- z = 1 << j; /* table entries for j-bit table */
-
- /* allocate and link in new table */
- q = (struct huft *)malloc((z + 1)*sizeof(struct huft));
-DEBG1("4 ");
- hufts += z + 1; /* track memory usage */
- *t = q + 1; /* link to list for huft_free() */
- *(t = &(q->v.t)) = (struct huft *)NULL;
- u[h] = ++q; /* table starts after link */
-
-DEBG1("5 ");
- /* connect to last table, if there is one */
- if (h)
- {
- x[h] = i; /* save pattern for backing up */
- r.b = (uch)l; /* bits to dump before this table */
- r.e = (uch)(16 + j); /* bits in this table */
- r.v.t = q; /* pointer to this table */
- j = i >> (w - l); /* (get around Turbo C bug) */
- u[h-1][j] = r; /* connect to last table */
- }
-DEBG1("6 ");
- }
-DEBG("h6c ");
-
- /* set up table entry in r */
- r.b = (uch)(k - w);
- if (p >= v + n)
- r.e = 99; /* out of values--invalid code */
- else if (*p < s)
- {
- r.e = (uch)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */
- r.v.n = *p++; /* simple code is just the value */
- }
- else
- {
- r.e = (uch)e[*p - s]; /* non-simple--look up in lists */
- r.v.n = d[*p++ - s];
- }
-DEBG("h6d ");
-
- /* fill code-like entries with r */
- f = 1 << (k - w);
- for (j = i >> w; j < z; j += f)
- q[j] = r;
-
- /* backwards increment the k-bit code i */
- for (j = 1 << (k - 1); i & j; j >>= 1)
- i ^= j;
- i ^= j;
-
- /* backup over finished tables */
- while ((i & ((1 << w) - 1)) != x[h])
- {
- h--; /* don't need to update q */
- w -= l;
- }
-DEBG("h6e ");
- }
-DEBG("h6f ");
- }
-
-DEBG("huft7 ");
-
- /* Return true (1) if we were given an incomplete table */
- return y != 0 && g != 1;
-}
-
-
-
-int huft_free(t)
-struct huft *t; /* table to free */
-/* Free the malloc'ed tables built by huft_build(), which makes a linked
- list of the tables it made, with the links in a dummy first entry of
- each table. */
-{
- register struct huft *p, *q;
-
-
- /* Go through linked list, freeing from the malloced (t[-1]) address. */
- p = t;
- while (p != (struct huft *)NULL)
- {
- q = (--p)->v.t;
- free(p);
- p = q;
- }
- return 0;
-}
-
-
-int inflate_codes(tl, td, bl, bd)
-struct huft *tl, *td; /* literal/length and distance decoder tables */
-int bl, bd; /* number of bits decoded by tl[] and td[] */
-/* inflate (decompress) the codes in a deflated (compressed) block.
- Return an error code or zero if it all goes ok. */
-{
- register unsigned e; /* table entry flag/number of extra bits */
- unsigned n, d; /* length and index for copy */
- unsigned w; /* current window position */
- struct huft *t; /* pointer to table entry */
- unsigned ml, md; /* masks for bl and bd bits */
- register ulg b; /* bit buffer */
- register unsigned k; /* number of bits in bit buffer */
-
-
- /* make local copies of globals */
- b = bb; /* initialize bit buffer */
- k = bk;
- w = wp; /* initialize window position */
-
- /* inflate the coded data */
- ml = mask_bits[bl]; /* precompute masks for speed */
- md = mask_bits[bd];
- for (;;) /* do until end of block */
- {
- NEEDBITS((unsigned)bl)
- if ((e = (t = tl + ((unsigned)b & ml))->e) > 16)
- do {
- if (e == 99)
- return 1;
- DUMPBITS(t->b)
- e -= 16;
- NEEDBITS(e)
- } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
- DUMPBITS(t->b)
- if (e == 16) /* then it's a literal */
- {
- slide[w++] = (uch)t->v.n;
- if (w == WSIZE)
- {
- flush_output(w);
- w = 0;
- }
- }
- else /* it's an EOB or a length */
- {
- /* exit if end of block */
- if (e == 15)
- break;
-
- /* get length of block to copy */
- NEEDBITS(e)
- n = t->v.n + ((unsigned)b & mask_bits[e]);
- DUMPBITS(e);
-
- /* decode distance of block to copy */
- NEEDBITS((unsigned)bd)
- if ((e = (t = td + ((unsigned)b & md))->e) > 16)
- do {
- if (e == 99)
- return 1;
- DUMPBITS(t->b)
- e -= 16;
- NEEDBITS(e)
- } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
- DUMPBITS(t->b)
- NEEDBITS(e)
- d = w - t->v.n - ((unsigned)b & mask_bits[e]);
- DUMPBITS(e)
-
- /* do the copy */
- do {
- n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e);
-#if !defined(NOMEMCPY) && !defined(DEBUG)
- if (w - d >= e) /* (this test assumes unsigned comparison) */
- {
- memcpy(slide + w, slide + d, e);
- w += e;
- d += e;
- }
- else /* do it slow to avoid memcpy() overlap */
-#endif /* !NOMEMCPY */
- do {
- slide[w++] = slide[d++];
- } while (--e);
- if (w == WSIZE)
- {
- flush_output(w);
- w = 0;
- }
- } while (n);
- }
- }
-
-
- /* restore the globals from the locals */
- wp = w; /* restore global window pointer */
- bb = b; /* restore global bit buffer */
- bk = k;
-
- /* done */
- return 0;
-}
-
-
-
-int inflate_stored()
-/* "decompress" an inflated type 0 (stored) block. */
-{
- unsigned n; /* number of bytes in block */
- unsigned w; /* current window position */
- register ulg b; /* bit buffer */
- register unsigned k; /* number of bits in bit buffer */
-
-DEBG("<stor");
-
- /* make local copies of globals */
- b = bb; /* initialize bit buffer */
- k = bk;
- w = wp; /* initialize window position */
-
-
- /* go to byte boundary */
- n = k & 7;
- DUMPBITS(n);
-
-
- /* get the length and its complement */
- NEEDBITS(16)
- n = ((unsigned)b & 0xffff);
- DUMPBITS(16)
- NEEDBITS(16)
- if (n != (unsigned)((~b) & 0xffff))
- return 1; /* error in compressed data */
- DUMPBITS(16)
-
-
- /* read and output the compressed data */
- while (n--)
- {
- NEEDBITS(8)
- slide[w++] = (uch)b;
- if (w == WSIZE)
- {
- flush_output(w);
- w = 0;
- }
- DUMPBITS(8)
- }
-
-
- /* restore the globals from the locals */
- wp = w; /* restore global window pointer */
- bb = b; /* restore global bit buffer */
- bk = k;
-
- DEBG(">");
- return 0;
-}
-
-
-
-int inflate_fixed()
-/* decompress an inflated type 1 (fixed Huffman codes) block. We should
- either replace this with a custom decoder, or at least precompute the
- Huffman tables. */
-{
- int i; /* temporary variable */
- struct huft *tl; /* literal/length code table */
- struct huft *td; /* distance code table */
- int bl; /* lookup bits for tl */
- int bd; /* lookup bits for td */
- unsigned l[288]; /* length list for huft_build */
-
-DEBG("<fix");
-
- /* set up literal table */
- for (i = 0; i < 144; i++)
- l[i] = 8;
- for (; i < 256; i++)
- l[i] = 9;
- for (; i < 280; i++)
- l[i] = 7;
- for (; i < 288; i++) /* make a complete, but wrong code set */
- l[i] = 8;
- bl = 7;
- if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0)
- return i;
-
-
- /* set up distance table */
- for (i = 0; i < 30; i++) /* make an incomplete code set */
- l[i] = 5;
- bd = 5;
- if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1)
- {
- huft_free(tl);
-
- DEBG(">");
- return i;
- }
-
-
- /* decompress until an end-of-block code */
- if (inflate_codes(tl, td, bl, bd))
- return 1;
-
-
- /* free the decoding tables, return */
- huft_free(tl);
- huft_free(td);
- return 0;
-}
-
-
-
-int inflate_dynamic()
-/* decompress an inflated type 2 (dynamic Huffman codes) block. */
-{
- int i; /* temporary variables */
- unsigned j;
- unsigned l; /* last length */
- unsigned m; /* mask for bit lengths table */
- unsigned n; /* number of lengths to get */
- struct huft *tl; /* literal/length code table */
- struct huft *td; /* distance code table */
- int bl; /* lookup bits for tl */
- int bd; /* lookup bits for td */
- unsigned nb; /* number of bit length codes */
- unsigned nl; /* number of literal/length codes */
- unsigned nd; /* number of distance codes */
-#ifdef PKZIP_BUG_WORKAROUND
- unsigned ll[288+32]; /* literal/length and distance code lengths */
-#else
- unsigned ll[286+30]; /* literal/length and distance code lengths */
-#endif
- register ulg b; /* bit buffer */
- register unsigned k; /* number of bits in bit buffer */
-
-DEBG("<dyn");
-
- /* make local bit buffer */
- b = bb;
- k = bk;
-
-
- /* read in table lengths */
- NEEDBITS(5)
- nl = 257 + ((unsigned)b & 0x1f); /* number of literal/length codes */
- DUMPBITS(5)
- NEEDBITS(5)
- nd = 1 + ((unsigned)b & 0x1f); /* number of distance codes */
- DUMPBITS(5)
- NEEDBITS(4)
- nb = 4 + ((unsigned)b & 0xf); /* number of bit length codes */
- DUMPBITS(4)
-#ifdef PKZIP_BUG_WORKAROUND
- if (nl > 288 || nd > 32)
-#else
- if (nl > 286 || nd > 30)
-#endif
- return 1; /* bad lengths */
-
-DEBG("dyn1 ");
-
- /* read in bit-length-code lengths */
- for (j = 0; j < nb; j++)
- {
- NEEDBITS(3)
- ll[border[j]] = (unsigned)b & 7;
- DUMPBITS(3)
- }
- for (; j < 19; j++)
- ll[border[j]] = 0;
-
-DEBG("dyn2 ");
-
- /* build decoding table for trees--single level, 7 bit lookup */
- bl = 7;
- if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0)
- {
- if (i == 1)
- huft_free(tl);
- return i; /* incomplete code set */
- }
-
-DEBG("dyn3 ");
-
- /* read in literal and distance code lengths */
- n = nl + nd;
- m = mask_bits[bl];
- i = l = 0;
- while ((unsigned)i < n)
- {
- NEEDBITS((unsigned)bl)
- j = (td = tl + ((unsigned)b & m))->b;
- DUMPBITS(j)
- j = td->v.n;
- if (j < 16) /* length of code in bits (0..15) */
- ll[i++] = l = j; /* save last length in l */
- else if (j == 16) /* repeat last length 3 to 6 times */
- {
- NEEDBITS(2)
- j = 3 + ((unsigned)b & 3);
- DUMPBITS(2)
- if ((unsigned)i + j > n)
- return 1;
- while (j--)
- ll[i++] = l;
- }
- else if (j == 17) /* 3 to 10 zero length codes */
- {
- NEEDBITS(3)
- j = 3 + ((unsigned)b & 7);
- DUMPBITS(3)
- if ((unsigned)i + j > n)
- return 1;
- while (j--)
- ll[i++] = 0;
- l = 0;
- }
- else /* j == 18: 11 to 138 zero length codes */
- {
- NEEDBITS(7)
- j = 11 + ((unsigned)b & 0x7f);
- DUMPBITS(7)
- if ((unsigned)i + j > n)
- return 1;
- while (j--)
- ll[i++] = 0;
- l = 0;
- }
- }
-
-DEBG("dyn4 ");
-
- /* free decoding table for trees */
- huft_free(tl);
-
-DEBG("dyn5 ");
-
- /* restore the global bit buffer */
- bb = b;
- bk = k;
-
-DEBG("dyn5a ");
-
- /* build the decoding tables for literal/length and distance codes */
- bl = lbits;
- if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0)
- {
-DEBG("dyn5b ");
- if (i == 1) {
- error(" incomplete literal tree\n");
- huft_free(tl);
- }
- return i; /* incomplete code set */
- }
-DEBG("dyn5c ");
- bd = dbits;
- if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0)
- {
-DEBG("dyn5d ");
- if (i == 1) {
- error(" incomplete distance tree\n");
-#ifdef PKZIP_BUG_WORKAROUND
- i = 0;
- }
-#else
- huft_free(td);
- }
- huft_free(tl);
- return i; /* incomplete code set */
-#endif
- }
-
-DEBG("dyn6 ");
-
- /* decompress until an end-of-block code */
- if (inflate_codes(tl, td, bl, bd))
- return 1;
-
-DEBG("dyn7 ");
-
- /* free the decoding tables, return */
- huft_free(tl);
- huft_free(td);
-
- DEBG(">");
- return 0;
-}
-
-
-
-int inflate_block(e)
-int *e; /* last block flag */
-/* decompress an inflated block */
-{
- unsigned t; /* block type */
- register ulg b; /* bit buffer */
- register unsigned k; /* number of bits in bit buffer */
-
- DEBG("<blk");
-
- /* make local bit buffer */
- b = bb;
- k = bk;
-
-
- /* read in last block bit */
- NEEDBITS(1)
- *e = (int)b & 1;
- DUMPBITS(1)
-
-
- /* read in block type */
- NEEDBITS(2)
- t = (unsigned)b & 3;
- DUMPBITS(2)
-
-
- /* restore the global bit buffer */
- bb = b;
- bk = k;
-
- /* inflate that block type */
- if (t == 2)
- return inflate_dynamic();
- if (t == 0)
- return inflate_stored();
- if (t == 1)
- return inflate_fixed();
-
- DEBG(">");
-
- /* bad block type */
- return 2;
-}
-
-
-
-int inflate()
-/* decompress an inflated entry */
-{
- int e; /* last block flag */
- int r; /* result code */
- unsigned h; /* maximum struct huft's malloc'ed */
-
-
- /* initialize window, bit buffer */
- wp = 0;
- bk = 0;
- bb = 0;
-
-
- /* decompress until the last block */
- h = 0;
- do {
- hufts = 0;
- if ((r = inflate_block(&e)) != 0)
- return r;
- if (hufts > h)
- h = hufts;
- } while (!e);
-
- /* Undo too much lookahead. The next read will be byte aligned so we
- * can discard unused bits in the last meaningful byte.
- */
- while (bk >= 8) {
- bk -= 8;
- inptr--;
- }
-
- /* flush out slide */
- flush_output(wp);
-
-
- /* return success */
-#ifdef DEBUG
- fprintf(stderr, "<%u> ", h);
-#endif /* DEBUG */
- return 0;
-}
diff --git a/arch/i386/boot/compressed/lzw.h b/arch/i386/boot/compressed/lzw.h
deleted file mode 100644
index 4e640f5a2..000000000
--- a/arch/i386/boot/compressed/lzw.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* lzw.h -- define the lzw functions.
- * Copyright (C) 1992-1993 Jean-loup Gailly.
- * This is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License, see the file COPYING.
- */
-
-#if !defined(OF) && defined(lint)
-# include "gzip.h"
-#endif
-
-#ifndef BITS
-# define BITS 16
-#endif
-#define INIT_BITS 9 /* Initial number of bits per code */
-
-#define LZW_MAGIC "\037\235" /* Magic header for lzw files, 1F 9D */
-
-#define BIT_MASK 0x1f /* Mask for 'number of compression bits' */
-/* Mask 0x20 is reserved to mean a fourth header byte, and 0x40 is free.
- * It's a pity that old uncompress does not check bit 0x20. That makes
- * extension of the format actually undesirable because old compress
- * would just crash on the new format instead of giving a meaningful
- * error message. It does check the number of bits, but it's more
- * helpful to say "unsupported format, get a new version" than
- * "can only handle 16 bits".
- */
-
-#define BLOCK_MODE 0x80
-/* Block compression: if table is full and compression rate is dropping,
- * clear the dictionary.
- */
-
-#define LZW_RESERVED 0x60 /* reserved bits */
-
-#define CLEAR 256 /* flush the dictionary */
-#define FIRST (CLEAR+1) /* first free entry */
-
-extern int maxbits; /* max bits per code for LZW */
-extern int block_mode; /* block compress mode -C compatible with 2.0 */
-
-extern void lzw OF((int in, int out));
-extern void unlzw OF((int in, int out));
diff --git a/arch/i386/boot/compressed/misc.c b/arch/i386/boot/compressed/misc.c
index 2623925c7..296517fee 100644
--- a/arch/i386/boot/compressed/misc.c
+++ b/arch/i386/boot/compressed/misc.c
@@ -5,15 +5,75 @@
* adapted for Linux.
*
* malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
- * puts by Nick Holloway 1993
+ * puts by Nick Holloway 1993, better puts by Martin Mares 1995
+ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
*/
-#include "gzip.h"
-#include "lzw.h"
+#include <string.h>
#include <asm/segment.h>
+#include <asm/io.h>
/*
+ * gzip declarations
+ */
+
+#define OF(args) args
+#define STATIC static
+
+#undef memset
+#undef memcpy
+#define memzero(s, n) memset ((s), 0, (n))
+
+typedef unsigned char uch;
+typedef unsigned short ush;
+typedef unsigned long ulg;
+
+#define WSIZE 0x8000 /* Window size must be at least 32k, */
+ /* and a power of two */
+
+static uch *inbuf; /* input buffer */
+static uch window[WSIZE]; /* Sliding window buffer */
+
+static unsigned insize = 0; /* valid bytes in inbuf */
+static unsigned inptr = 0; /* index of next byte to be processed in inbuf */
+static unsigned outcnt = 0; /* bytes in output buffer */
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
+#define RESERVED 0xC0 /* bit 6,7: reserved */
+
+#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# define Assert(cond,msg) {if(!(cond)) error(msg);}
+# define Trace(x) fprintf x
+# define Tracev(x) {if (verbose) fprintf x ;}
+# define Tracevv(x) {if (verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+static int fill_inbuf(void);
+static void flush_window(void);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+
+/*
* These are set up by the setup-routine at boot-time:
*/
@@ -24,10 +84,11 @@ struct screen_info {
unsigned short orig_video_page;
unsigned char orig_video_mode;
unsigned char orig_video_cols;
- unsigned short orig_video_ega_ax;
+ unsigned short unused2;
unsigned short orig_video_ega_bx;
- unsigned short orig_video_ega_cx;
+ unsigned short unused3;
unsigned char orig_video_lines;
+ unsigned char orig_video_isVGA;
};
/*
@@ -40,82 +101,73 @@ struct screen_info {
#define ORIG_ROOT_DEV (*(unsigned short *)0x901FC)
#define AUX_DEVICE_INFO (*(unsigned char *)0x901FF)
-#define EOF -1
-
-DECLARE(uch, inbuf, INBUFSIZ);
-DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
-DECLARE(uch, window, WSIZE);
-
-unsigned outcnt;
-unsigned insize;
-unsigned inptr;
-
extern char input_data[];
extern int input_len;
-int input_ptr;
-
-int method, exit_code, part_nb, last_member;
-int test = 0;
-int force = 0;
-int verbose = 1;
-long bytes_in, bytes_out;
-
-char *output_data;
-unsigned long output_ptr;
-
-extern int end;
-long free_mem_ptr = (long)&end;
-
-int to_stdout = 0;
-int hard_math = 0;
-
-void (*work)(int inf, int outf);
-void makecrc(void);
-
-local int get_method(int);
-
-char *vidmem = (char *)0xb8000;
-int lines, cols;
-
+static long bytes_out = 0;
+static uch *output_data;
+static unsigned long output_ptr = 0;
+
+
+static void *malloc(int size);
+static void free(void *where);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+
+#ifndef STANDALONE_DEBUG
static void puts(const char *);
-
-void *malloc(int size)
+
+extern int end;
+static long free_mem_ptr = (long)&end;
+static long free_mem_end_ptr = 0x90000;
+
+#define INPLACE_MOVE_ROUTINE 0x1000
+#define LOW_BUFFER_START 0x2000
+#define LOW_BUFFER_END 0x90000
+#define LOW_BUFFER_SIZE ( LOW_BUFFER_END - LOW_BUFFER_START )
+#define HEAP_SIZE 0x2000
+static int high_loaded =0;
+static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/;
+
+static char *vidmem = (char *)0xb8000;
+static int vidport;
+static int lines, cols;
+
+#include "../../../../lib/inflate.c"
+
+static void *malloc(int size)
{
void *p;
if (size <0) error("Malloc error\n");
if (free_mem_ptr <= 0) error("Memory error\n");
- while(1) {
free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */
p = (void *)free_mem_ptr;
free_mem_ptr += size;
- /*
- * The part of the compressed kernel which has already been expanded
- * is no longer needed. Therefore we can reuse it for malloc.
- * With bigger kernels, this is necessary.
- */
-
- if (free_mem_ptr < (long)&end) {
- if (free_mem_ptr > (long)&input_data[input_ptr])
- error("\nOut of memory\n");
-
- return p;
- }
- if (free_mem_ptr < 0x90000)
+ if (free_mem_ptr >= free_mem_end_ptr)
+ error("\nOut of memory\n");
+
return p;
- puts("large kernel, low 1M tight...");
- free_mem_ptr = (long)input_data;
- }
}
-void free(void *where)
+static void free(void *where)
{ /* Don't care */
}
+static void gzip_mark(void **ptr)
+{
+ *ptr = (void *) free_mem_ptr;
+}
+
+static void gzip_release(void **ptr)
+{
+ free_mem_ptr = (long) *ptr;
+}
+
static void scroll()
{
int i;
@@ -127,7 +179,7 @@ static void scroll()
static void puts(const char *s)
{
- int x,y;
+ int x,y,pos;
char c;
x = SCREEN_INFO.orig_x;
@@ -154,6 +206,12 @@ static void puts(const char *s)
SCREEN_INFO.orig_x = x;
SCREEN_INFO.orig_y = y;
+
+ pos = (x + cols * y) * 2; /* Update cursor position */
+ outb_p(14, vidport);
+ outb_p(0xff & (pos >> 9), vidport+1);
+ outb_p(15, vidport);
+ outb_p(0xff & (pos >> 1), vidport+1);
}
__ptr_t memset(__ptr_t s, int c, size_t n)
@@ -172,129 +230,69 @@ __ptr_t memcpy(__ptr_t __dest, __const __ptr_t __src,
for (i=0;i<__n;i++) d[i] = s[i];
}
-
-extern ulg crc_32_tab[]; /* crc table, defined below */
-
-/* ===========================================================================
- * Run a set of bytes through the crc shift register. If s is a NULL
- * pointer, then initialize the crc shift register contents instead.
- * Return the current crc in either case.
- */
-ulg updcrc(s, n)
- uch *s; /* pointer to bytes to pump through */
- unsigned n; /* number of bytes in s[] */
-{
- register ulg c; /* temporary variable */
-
- static ulg crc = (ulg)0xffffffffL; /* shift register contents */
-
- if (s == NULL) {
- c = 0xffffffffL;
- } else {
- c = crc;
- while (n--) {
- c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
- }
- }
- crc = c;
- return c ^ 0xffffffffL; /* (instead of ~c for 64-bit machines) */
-}
-
-/* ===========================================================================
- * Clear input and output buffers
- */
-void clear_bufs()
-{
- outcnt = 0;
- insize = inptr = 0;
- bytes_in = bytes_out = 0L;
-}
+#endif
/* ===========================================================================
* Fill the input buffer. This is called only when the buffer is empty
* and at least one byte is really needed.
*/
-int fill_inbuf()
+static int fill_inbuf()
{
- int len, i;
-
- /* Read as much as possible */
- insize = 0;
- do {
- len = INBUFSIZ-insize;
- if (len > (input_len-input_ptr+1)) len=input_len-input_ptr+1;
- if (len == 0 || len == EOF) break;
-
- for (i=0;i<len;i++) inbuf[insize+i] = input_data[input_ptr+i];
- insize += len;
- input_ptr += len;
- } while (insize < INBUFSIZ);
-
- if (insize == 0) {
- error("unable to fill buffer\n");
- }
- bytes_in += (ulg)insize;
- inptr = 1;
- return inbuf[0];
+ if (insize != 0) {
+ error("ran out of input data\n");
+ }
+
+ inbuf = input_data;
+ insize = input_len;
+ inptr = 1;
+ return inbuf[0];
}
/* ===========================================================================
* Write the output window window[0..outcnt-1] and update crc and bytes_out.
* (Used for the decompressed data only.)
*/
-void flush_window()
+static void flush_window_low()
{
- if (outcnt == 0) return;
- updcrc(window, outcnt);
-
- memcpy(&output_data[output_ptr], (char *)window, outcnt);
-
+ ulg c = crc; /* temporary variable */
+ unsigned n;
+ uch *in, *out, ch;
+
+ in = window;
+ out = &output_data[output_ptr];
+ for (n = 0; n < outcnt; n++) {
+ ch = *out++ = *in++;
+ c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
+ }
+ crc = c;
bytes_out += (ulg)outcnt;
output_ptr += (ulg)outcnt;
outcnt = 0;
}
-/*
- * Code to compute the CRC-32 table. Borrowed from
- * gzip-1.0.3/makecrc.c.
- */
-
-ulg crc_32_tab[256];
-
-void
-makecrc(void)
+static void flush_window_high()
{
-/* Not copyrighted 1990 Mark Adler */
-
- unsigned long c; /* crc shift register */
- unsigned long e; /* polynomial exclusive-or pattern */
- int i; /* counter for all possible eight bit values */
- int k; /* byte being shifted into crc apparatus */
-
- /* terms of polynomial defining this crc (except x^32): */
- static int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
-
- /* Make exclusive-or pattern from polynomial */
- e = 0;
- for (i = 0; i < sizeof(p)/sizeof(int); i++)
- e |= 1L << (31 - p[i]);
-
- crc_32_tab[0] = 0;
-
- for (i = 1; i < 256; i++)
- {
- c = 0;
- for (k = i | 256; k != 1; k >>= 1)
- {
- c = c & 1 ? (c >> 1) ^ e : c >> 1;
- if (k & 1)
- c ^= e;
+ ulg c = crc; /* temporary variable */
+ unsigned n;
+ uch *in, ch;
+ in = window;
+ for (n = 0; n < outcnt; n++) {
+ ch = *output_data++ = *in++;
+ if ((ulg)output_data == LOW_BUFFER_END) output_data=high_buffer_start;
+ c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
}
- crc_32_tab[i] = c;
- }
+ crc = c;
+ bytes_out += (ulg)outcnt;
+ outcnt = 0;
+}
+
+static void flush_window()
+{
+ if (high_loaded) flush_window_high();
+ else flush_window_low();
}
-void error(char *x)
+static void error(char *x)
{
puts("\n\n");
puts(x);
@@ -312,107 +310,96 @@ struct {
short b;
} stack_start = { & user_stack [STACK_SIZE] , KERNEL_DS };
-void decompress_kernel()
-{
- if (SCREEN_INFO.orig_video_mode == 7)
- vidmem = (char *) 0xb0000;
- else
- vidmem = (char *) 0xb8000;
+#ifdef STANDALONE_DEBUG
- lines = SCREEN_INFO.orig_video_lines;
- cols = SCREEN_INFO.orig_video_cols;
+static void gzip_mark(void **ptr)
+{
+}
- if (EXT_MEM_K < 1024) error("<2M of mem\n");
+static void gzip_release(void **ptr)
+{
+}
- output_data = (char *)0x100000; /* Points to 1M */
- output_ptr = 0;
+char output_buffer[1024 * 800];
- exit_code = 0;
- test = 0;
- input_ptr = 0;
- part_nb = 0;
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ output_data = output_buffer;
- clear_bufs();
makecrc();
-
puts("Uncompressing Linux...");
+ gunzip();
+ puts("done.\n");
+ return 0;
+}
- method = get_method(0);
+#else
- work(0, 0);
+void setup_normal_output_buffer()
+{
+ if (EXT_MEM_K < 1024) error("Less than 2MB of memory.\n");
+ output_data = (char *)0x100000; /* Points to 1M */
+}
- puts("done.\n");
+struct moveparams {
+ uch *low_buffer_start; int lcount;
+ uch *high_buffer_start; int hcount;
+};
- puts("Now booting the kernel\n");
+void setup_output_buffer_if_we_run_high(struct moveparams *mv)
+{
+ high_buffer_start = (uch *)(((ulg)&end) + HEAP_SIZE);
+ if (EXT_MEM_K < (3*1024)) error("Less than 4MB of memory.\n");
+ mv->low_buffer_start = output_data = (char *)LOW_BUFFER_START;
+ high_loaded = 1;
+ free_mem_end_ptr = (long)high_buffer_start;
+ if ( (0x100000 + LOW_BUFFER_SIZE) > ((ulg)high_buffer_start)) {
+ high_buffer_start = (uch *)(0x100000 + LOW_BUFFER_SIZE);
+ mv->hcount = 0; /* say: we need not to move high_buffer */
+ }
+ else mv->hcount = -1;
+ mv->high_buffer_start = high_buffer_start;
}
-/* ========================================================================
- * Check the magic number of the input file and update ofname if an
- * original name was given and to_stdout is not set.
- * Return the compression method, -1 for error, -2 for warning.
- * Set inptr to the offset of the next byte to be processed.
- * This function may be called repeatedly for an input file consisting
- * of several contiguous gzip'ed members.
- * IN assertions: there is at least one remaining compressed member.
- * If the member is a zip file, it must be the only one.
- */
-local int get_method(in)
- int in; /* input file descriptor */
+void close_output_buffer_if_we_run_high(struct moveparams *mv)
{
- uch flags;
- char magic[2]; /* magic header */
-
- magic[0] = (char)get_byte();
- magic[1] = (char)get_byte();
-
- method = -1; /* unknown yet */
- part_nb++; /* number of parts in gzip file */
- last_member = 0;
- /* assume multiple members in gzip file except for record oriented I/O */
-
- if (memcmp(magic, GZIP_MAGIC, 2) == 0
- || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
-
- work = unzip;
- method = (int)get_byte();
- flags = (uch)get_byte();
- if ((flags & ENCRYPTED) != 0)
- error("Input is encrypted\n");
- if ((flags & CONTINUATION) != 0)
- error("Multi part input\n");
- if ((flags & RESERVED) != 0) {
- error("Input has invalid flags\n");
- exit_code = ERROR;
- if (force <= 1) return -1;
- }
- (ulg)get_byte(); /* Get timestamp */
- ((ulg)get_byte()) << 8;
- ((ulg)get_byte()) << 16;
- ((ulg)get_byte()) << 24;
-
- (void)get_byte(); /* Ignore extra flags for the moment */
- (void)get_byte(); /* Ignore OS type for the moment */
-
- if ((flags & EXTRA_FIELD) != 0) {
- unsigned len = (unsigned)get_byte();
- len |= ((unsigned)get_byte())<<8;
- while (len--) (void)get_byte();
+ mv->lcount = bytes_out;
+ if (bytes_out > LOW_BUFFER_SIZE) {
+ mv->lcount = LOW_BUFFER_SIZE;
+ if (mv->hcount) mv->hcount = bytes_out - LOW_BUFFER_SIZE;
}
+ else mv->hcount = 0;
+}
- /* Get original file name if it was truncated */
- if ((flags & ORIG_NAME) != 0) {
- if (to_stdout || part_nb > 1) {
- /* Discard the old name */
- while (get_byte() != 0) /* null */ ;
- } else {
- } /* to_stdout */
- } /* orig_name */
-
- /* Discard file comment if any */
- if ((flags & COMMENT) != 0) {
- while (get_byte() != 0) /* null */ ;
+
+int decompress_kernel(struct moveparams *mv)
+{
+ if (SCREEN_INFO.orig_video_mode == 7) {
+ vidmem = (char *) 0xb0000;
+ vidport = 0x3b4;
+ } else {
+ vidmem = (char *) 0xb8000;
+ vidport = 0x3d4;
}
- } else
- error("unknown compression method");
- return method;
+
+ lines = SCREEN_INFO.orig_video_lines;
+ cols = SCREEN_INFO.orig_video_cols;
+
+ if (free_mem_ptr < 0x100000) setup_normal_output_buffer();
+ else setup_output_buffer_if_we_run_high(mv);
+
+ makecrc();
+ puts("Uncompressing Linux...");
+ gunzip();
+ puts("done.\nNow booting the kernel\n");
+ if (high_loaded) close_output_buffer_if_we_run_high(mv);
+ return high_loaded;
}
+#endif
+
+
+
+
diff --git a/arch/i386/boot/compressed/unzip.c b/arch/i386/boot/compressed/unzip.c
deleted file mode 100644
index d4a6617cd..000000000
--- a/arch/i386/boot/compressed/unzip.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/* unzip.c -- decompress files in gzip or pkzip format.
- * Copyright (C) 1992-1993 Jean-loup Gailly
- *
- * Adapted for Linux booting by Hannu Savolainen 1993
- *
- * This is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License, see the file COPYING.
- *
- * The code in this file is derived from the file funzip.c written
- * and put in the public domain by Mark Adler.
- */
-
-/*
- This version can extract files in gzip or pkzip format.
- For the latter, only the first entry is extracted, and it has to be
- either deflated or stored.
- */
-
-#ifndef lint
-static char rcsid[] = "$Id: unzip.c,v 0.9 1993/02/10 16:07:22 jloup Exp $";
-#endif
-
-#include "gzip.h"
-#include "crypt.h"
-
-#include <stdio.h>
-
-/* PKZIP header definitions */
-#define LOCSIG 0x04034b50L /* four-byte lead-in (lsb first) */
-#define LOCFLG 6 /* offset of bit flag */
-#define CRPFLG 1 /* bit for encrypted entry */
-#define EXTFLG 8 /* bit for extended local header */
-#define LOCHOW 8 /* offset of compression method */
-#define LOCTIM 10 /* file mod time (for decryption) */
-#define LOCCRC 14 /* offset of crc */
-#define LOCSIZ 18 /* offset of compressed size */
-#define LOCLEN 22 /* offset of uncompressed length */
-#define LOCFIL 26 /* offset of file name field length */
-#define LOCEXT 28 /* offset of extra field length */
-#define LOCHDR 30 /* size of local header, including sig */
-#define EXTHDR 16 /* size of extended local header, inc sig */
-
-
-/* Globals */
-
-int decrypt; /* flag to turn on decryption */
-char *key; /* not used--needed to link crypt.c */
-int pkzip = 0; /* set for a pkzip file */
-int extended = 0; /* set if extended local header */
-
-/* ===========================================================================
- * Check zip file and advance inptr to the start of the compressed data.
- * Get ofname from the local header if necessary.
- */
-int check_zipfile(in)
- int in; /* input file descriptors */
-{
- uch *h = inbuf + inptr; /* first local header */
-
- /* ifd = in; */
-
- /* Check validity of local header, and skip name and extra fields */
- inptr += LOCHDR + SH(h + LOCFIL) + SH(h + LOCEXT);
-
- if (inptr > insize || LG(h) != LOCSIG) {
- error("input not a zip");
- }
- method = h[LOCHOW];
- if (method != STORED && method != DEFLATED) {
- error("first entry not deflated or stored--can't extract");
- }
-
- /* If entry encrypted, decrypt and validate encryption header */
- if ((decrypt = h[LOCFLG] & CRPFLG) != 0) {
- error("encrypted file\n");
- exit_code = ERROR;
- return -1;
- }
-
- /* Save flags for unzip() */
- extended = (h[LOCFLG] & EXTFLG) != 0;
- pkzip = 1;
-
- /* Get ofname and time stamp from local header (to be done) */
- return 0;
-}
-
-/* ===========================================================================
- * Unzip in to out. This routine works on both gzip and pkzip files.
- *
- * IN assertions: the buffer inbuf contains already the beginning of
- * the compressed data, from offsets inptr to insize-1 included.
- * The magic header has already been checked. The output buffer is cleared.
- */
-void unzip(in, out)
- int in, out; /* input and output file descriptors */
-{
- ulg orig_crc = 0; /* original crc */
- ulg orig_len = 0; /* original uncompressed length */
- int n;
- uch buf[EXTHDR]; /* extended local header */
-
- /* ifd = in;
- ofd = out; */
-
- updcrc(NULL, 0); /* initialize crc */
-
- if (pkzip && !extended) { /* crc and length at the end otherwise */
- orig_crc = LG(inbuf + LOCCRC);
- orig_len = LG(inbuf + LOCLEN);
- }
-
- /* Decompress */
- if (method == DEFLATED) {
-
- int res = inflate();
-
- if (res == 3) {
- error("out of memory");
- } else if (res != 0) {
- error("invalid compressed format");
- }
-
- } else if (pkzip && method == STORED) {
-
- register ulg n = LG(inbuf + LOCLEN);
-
- if (n != LG(inbuf + LOCSIZ) - (decrypt ? RAND_HEAD_LEN : 0)) {
-
- error("length mismatch");
- }
- while (n--) {
- uch c = (uch)get_byte();
-#ifdef CRYPT
- if (decrypt) zdecode(c);
-#endif
- if (!test) put_char(c);
- }
- } else {
- error("internal error, invalid method");
- }
-
- /* Get the crc and original length */
- if (!pkzip) {
- /* crc32 (see algorithm.doc)
- * uncompressed input size modulo 2^32
- */
- for (n = 0; n < 8; n++) {
- buf[n] = (uch)get_byte(); /* may cause an error if EOF */
- }
- orig_crc = LG(buf);
- orig_len = LG(buf+4);
-
- } else if (extended) { /* If extended header, check it */
- /* signature - 4bytes: 0x50 0x4b 0x07 0x08
- * CRC-32 value
- * compressed size 4-bytes
- * uncompressed size 4-bytes
- */
- for (n = 0; n < EXTHDR; n++) {
- buf[n] = (uch)get_byte(); /* may cause an error if EOF */
- }
- orig_crc = LG(buf+4);
- orig_len = LG(buf+12);
- }
-
- /* Validate decompression */
- if (orig_crc != updcrc(outbuf, 0)) {
- error("crc error");
- }
- if (orig_len != bytes_out) {
- error("length error");
- }
-
- /* Check if there are more entries in a pkzip file */
- if (pkzip && inptr + 4 < insize && LG(inbuf+inptr) == LOCSIG) {
- error("zip file has more than one entry");
- }
- extended = pkzip = 0; /* for next file */
-}
diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S
index d4f56ef2a..201a2936b 100644
--- a/arch/i386/boot/setup.S
+++ b/arch/i386/boot/setup.S
@@ -17,23 +17,32 @@
! some changes and additional features by Christoph Niemann,
! March 1993/June 1994 (Christoph.Niemann@linux.org)
!
+! add APM BIOS checking by Stephen Rothwell, May 1994
+! (Stephen.Rothwell@pd.necisa.oz.au)
+!
+! High load stuff, initrd support and position independency
+! by Hans Lermen & Werner Almesberger, February 1996
+! <lermen@elserv.ffm.fgan.de>, <almesber@lrc.epfl.ch>
+!
+! Video handling moved to video.S by Martin Mares, March 1996
+! <mj@k332.feld.cvut.cz>
! 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
+#include <linux/version.h>
+#include <linux/compile.h>
! 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
+INITSEG = DEF_INITSEG ! 0x9000, we move boot here - out of the way
+SYSSEG = DEF_SYSSEG ! 0x1000, system loaded at 0x10000 (65536).
+SETUPSEG = DEF_SETUPSEG ! 0x9020, this is the current segment
+ ! ... and the former contents of CS
+DELTA_INITSEG = SETUPSEG - INITSEG ! 0x0020
.globl begtext, begdata, begbss, endtext, enddata, endbss
.text
@@ -46,14 +55,77 @@ begbss:
entry start
start:
+ jmp start_of_setup
+! ------------------------ start of header --------------------------------
+!
+! SETUP-header, must start at CS:2 (old 0x9020:2)
+!
+ .ascii "HdrS" ! Signature for SETUP-header
+ .word 0x0201 ! Version number of header format
+ ! (must be >= 0x0105
+ ! else old loadlin-1.5 will fail)
+realmode_swtch: .word 0,0 ! default_switch,SETUPSEG
+start_sys_seg: .word SYSSEG
+ .word kernel_version ! pointing to kernel version string
+ ! note: above part of header is compatible with loadlin-1.5 (header v1.5),
+ ! must not change it
+
+type_of_loader: .byte 0 ! = 0, old one (LILO, Loadlin,
+ ! Bootlin, SYSLX, bootsect...)
+ ! else it is set by the loader:
+ ! 0xTV: T=0 for LILO
+ ! T=1 for Loadlin
+ ! T=2 for bootsect-loader
+ ! T=3 for SYSLX
+ ! T=4 for ETHERBOOT
+ ! V = version
+loadflags: .byte 0 ! unused bits =0 (reserved for future development)
+LOADED_HIGH = 1 ! bit within loadflags,
+ ! if set, then the kernel is loaded high
+CAN_USE_HEAP = 0x80 ! if set, the loader also has set heap_end_ptr
+ ! to tell how much space behind setup.S
+ | can be used for heap purposes.
+ ! Only the loader knows what is free!
+setup_move_size: .word 0x8000 ! size to move, when we (setup) are not
+ ! loaded at 0x90000. We will move ourselves
+ ! to 0x90000 then just before jumping into
+ ! the kernel. However, only the loader
+ ! know how much of data behind us also needs
+ ! to be loaded.
+code32_start: .long 0x1000 ! here loaders can put a different
+ ! start address for 32-bit code.
+ ! 0x1000 = default for zImage
+ ! 0x100000 = default for big kernel
+ramdisk_image: .long 0 ! address of loaded ramdisk image
+ ! Here the loader (or kernel generator) puts
+ ! the 32-bit address were it loaded the image.
+ ! This only will be interpreted by the kernel.
+ramdisk_size: .long 0 ! its size in bytes
+bootsect_kludge:
+ .word bootsect_helper,SETUPSEG
+heap_end_ptr: .word modelist+1024 ! space from here (exclusive) down to
+ ! end of setup code can be used by setup
+ ! for local heap purposes.
+! ------------------------ end of header ----------------------------------
+
+start_of_setup:
! Bootlin depends on this being done early
mov ax,#0x01500
mov dl,#0x81
int 0x13
-! Check signature at end of setup
- mov ax,#SETUPSEG
+#ifdef SAFE_RESET_DISK_CONTROLLER
+! Reset the disk controller.
+ mov ax,#0x0000
+ mov dl,#0x80
+ int 0x13
+#endif
+
+! set DS=CS, we know that SETUPSEG == CS at this point
+ mov ax,cs ! aka #SETUPSEG
mov ds,ax
+
+! Check signature at end of setup
cmp setup_sig1,#SIG1
jne bad_sig
cmp setup_sig2,#SIG2
@@ -65,13 +137,18 @@ start:
prtstr: lodsb
and al,al
jz fin
- call prnt1
+ call prtchr
jmp prtstr
fin: ret
+! Space printing
+
+prtsp2: call prtspc ! Print double space
+prtspc: mov al,#0x20 ! Print single space (fall-thru!)
+
! Part of above routine, this one just prints ascii al
-prnt1: push ax
+prtchr: push ax
push cx
xor bh,bh
mov cx,#0x01
@@ -82,18 +159,18 @@ prnt1: push ax
ret
beep: mov al,#0x07
- jmp prnt1
+ jmp prtchr
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 ax,cs ! aka #SETUPSEG
+ sub ax,#DELTA_INITSEG ! aka #INITSEG
mov ds,ax
xor bh,bh
mov bl,[497] ! get setup sects from boot sector
@@ -108,14 +185,14 @@ bad_sig:
! Move rest of setup code/data to here
mov di,#2048 ! four sectors loaded by LILO
sub si,si
- mov ax,#SETUPSEG
+ mov ax,cs ! aka #SETUPSEG
mov es,ax
mov ax,#SYSSEG
mov ds,ax
rep
movsw
- mov ax,#SETUPSEG
+ mov ax,cs ! aka #SETUPSEG
mov ds,ax
cmp setup_sig1,#SIG1
jne no_sig
@@ -130,58 +207,53 @@ no_sig_loop:
jmp no_sig_loop
good_sig:
- mov ax,#INITSEG
+ mov ax,cs ! aka #SETUPSEG
+ sub ax,#DELTA_INITSEG ! aka #INITSEG
mov ds,ax
+! check if an old loader tries to load a big-kernel
+ seg cs
+ test byte ptr loadflags,#LOADED_HIGH ! have we a big kernel ?
+ jz loader_ok ! NO, no danger even for old loaders
+ ! YES, we have a big-kernel
+ seg cs
+ cmp byte ptr type_of_loader,#0 ! have we one of the new loaders ?
+ jnz loader_ok ! YES, ok
+ ! NO, we have an old loader, must give up
+ push cs
+ pop ds
+ lea si,loader_panic_mess
+ call prtstr
+ jmp no_sig_loop
+loader_panic_mess:
+ .ascii "Wrong loader, giving up..."
+ db 0
+
+loader_ok:
! Get memory size (extended mem, kB)
mov ah,#0x88
int 0x15
mov [2],ax
-! set the keyboard repeat rate to the max
+! 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
+! Check for video adapter and its parameters and allow the
+! user to browse video modes.
- 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
+ call video ! NOTE: we need DS pointing to bootsector
! Get hd0 data
xor ax,ax ! clear ax
mov ds,ax
lds si,[4*0x41]
- mov ax,#INITSEG
+ mov ax,cs ! aka #SETUPSEG
+ sub ax,#DELTA_INITSEG ! aka #INITSEG
push ax
mov es,ax
mov di,#0x0080
@@ -211,7 +283,8 @@ novga: mov [14],ax
cmp ah,#3
je is_disk1
no_disk1:
- mov ax,#INITSEG
+ mov ax,cs ! aka #SETUPSEG
+ sub ax,#DELTA_INITSEG ! aka #INITSEG
mov es,ax
mov di,#0x0090
mov cx,#0x10
@@ -221,9 +294,10 @@ no_disk1:
stosb
is_disk1:
-! check for PS/2 pointing device
+! Check for PS/2 pointing device
- mov ax,#INITSEG
+ mov ax,cs ! aka #SETUPSEG
+ sub ax,#DELTA_INITSEG ! aka #INITSEG
mov ds,ax
mov [0x1ff],#0 ! default is no pointing device
int 0x11 ! int 0x11: equipment determination
@@ -231,23 +305,88 @@ is_disk1:
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
+#ifdef CONFIG_APM
+! check for APM BIOS
+ ! NOTE: DS is pointing to the bootsector
+ !
+ mov [64],#0 ! version == 0 means no APM BIOS
+
+ mov ax,#0x05300 ! APM BIOS installation check
+ xor bx,bx
+ int 0x15
+ jc done_apm_bios ! error -> no APM BIOS
+
+ cmp bx,#0x0504d ! check for "PM" signature
+ jne done_apm_bios ! no signature -> no APM BIOS
+
+ mov [64],ax ! record the APM BIOS version
+ mov [76],cx ! and flags
+ and cx,#0x02 ! Is 32 bit supported?
+ je done_apm_bios ! no ...
+
+ mov ax,#0x05304 ! Disconnect first just in case
+ xor bx,bx
+ int 0x15 ! ignore return code
+
+ mov ax,#0x05303 ! 32 bit connect
+ xor bx,bx
+ int 0x15
+ jc no_32_apm_bios ! error
+
+ mov [66],ax ! BIOS code segment
+ mov [68],ebx ! BIOS entry point offset
+ mov [72],cx ! BIOS 16 bit code segment
+ mov [74],dx ! BIOS data segment
+ mov [78],si ! BIOS code segment length
+ mov [80],di ! BIOS data segment length
+ jmp done_apm_bios
+
+no_32_apm_bios:
+ and [76], #0xfffd ! remove 32 bit support bit
+
+done_apm_bios:
+#endif
+
+! Now we want to move to protected mode ...
+
+ seg cs
+ cmp realmode_swtch,#0
+ jz rmodeswtch_normal
+ seg cs
+ callf far * realmode_swtch
+ jmp rmodeswtch_end
+rmodeswtch_normal:
+ push cs
+ call default_switch
+rmodeswtch_end:
+
+! we get the code32 start address and modify the below 'jmpi'
+! (loader may have changed it)
+ seg cs
+ mov eax,code32_start
+ seg cs
+ mov code32,eax
-! first we move the system to its rightful place
+! Now we move the system to its rightful place
+! ...but we check, if we have a big-kernel.
+! in this case we *must* not move it ...
+ seg cs
+ test byte ptr loadflags,#LOADED_HIGH
+ jz do_move0 ! we have a normal low loaded zImage
+ ! we have a high loaded big kernel
+ jmp end_move ! ... and we skip moving
+do_move0:
mov ax,#0x100 ! start of destination segment
+ mov bp,cs ! aka #SETUPSEG
+ sub bp,#DELTA_INITSEG ! aka #INITSEG
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
@@ -255,13 +394,58 @@ do_move:
mov cx,#0x800
rep
movsw
- jmp do_move
+ cmp bx,bp ! we assume start_sys_seg > 0x200,
+ ! so we will perhaps read one page more then
+ ! needed, but never overwrite INITSEG because
+ ! destination is minimum one page below source
+ jb do_move
! then we load the segment descriptors
end_move:
- mov ax,#SETUPSEG ! right, forgot this at first. didn't work :-)
+ mov ax,cs ! aka #SETUPSEG ! right, forgot this at first. didn't work :-)
+ mov ds,ax
+
+! If we have our code not at 0x90000, we need to move it there now.
+! We also then need to move the params behind it (commandline)
+! Because we would overwrite the code on the current IP, we move
+! it in two steps, jumping high after the first one.
+ mov ax,cs
+ cmp ax,#SETUPSEG
+ je end_move_self
+ cli ! make sure we really have interrupts disabled !
+ ! because after this the stack should not be used
+ sub ax,#DELTA_INITSEG ! aka #INITSEG
+ mov dx,ss
+ cmp dx,ax
+ jb move_self_1
+ add dx,#INITSEG
+ sub dx,ax ! this will be SS after the move
+move_self_1:
mov ds,ax
+ mov ax,#INITSEG ! real INITSEG
+ mov es,ax
+ seg cs
+ mov cx,setup_move_size
+ std ! we have to move up, so we use direction down
+ ! because the areas may overlap
+ mov di,cx
+ dec di
+ mov si,di
+ sub cx,#move_self_here+0x200
+ rep
+ movsb
+ jmpi move_self_here,SETUPSEG ! jump to our final place
+move_self_here:
+ mov cx,#move_self_here+0x200
+ rep
+ movsb
+ mov ax,#SETUPSEG
+ mov ds,ax
+ mov ss,dx
+ ! now we are at the right place
+end_move_self:
+
lidt idt_48 ! load idt with 0,0
lgdt gdt_48 ! load gdt with whatever appropriate
@@ -319,7 +503,7 @@ end_move:
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
+! 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.
@@ -327,17 +511,127 @@ end_move:
! 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.
+! absolute address 0x1000 (or the loader supplied one),
+! 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
+ mov ax,#1 ! 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)
+ xor bx,bx ! Flag to indicate a boot
+
+! NOTE: For high loaded big kernels we need a
+! jmpi 0x100000,KERNEL_CS
+!
+! but we yet haven't reloaded the CS register, so the default size
+! of the target offset still is 16 bit.
+! However, using an operant prefix (0x66), the CPU will properly
+! take our 48 bit far pointer. (INTeL 80386 Programmer's Reference
+! Manual, Mixing 16-bit and 32-bit code, page 16-6)
+ db 0x66,0xea ! prefix + jmpi-opcode
+code32: dd 0x1000 ! will be set to 0x100000 for big kernels
+ dw KERNEL_CS
+
+
+kernel_version: .ascii UTS_RELEASE
+ .ascii " ("
+ .ascii LINUX_COMPILE_BY
+ .ascii "@"
+ .ascii LINUX_COMPILE_HOST
+ .ascii ") "
+ .ascii UTS_VERSION
+ db 0
+
+! This is the default real mode switch routine.
+! to be called just before protected mode transition
+
+default_switch:
+ cli ! no interrupts allowed !
+ mov al,#0x80 ! disable NMI for the bootup sequence
+ out #0x70,al
+ retf
+
+! This routine only gets called, if we get loaded by the simple
+! bootsect loader _and_ have a bzImage to load.
+! Because there is no place left in the 512 bytes of the boot sector,
+! we must emigrate to code space here.
+!
+bootsect_helper:
+ seg cs
+ cmp word ptr bootsect_es,#0
+ jnz bootsect_second
+ seg cs
+ mov byte ptr type_of_loader,#0x20
+ mov ax,es
+ shr ax,#4
+ seg cs
+ mov byte ptr bootsect_src_base+2,ah
+ mov ax,es
+ seg cs
+ mov bootsect_es,ax
+ sub ax,#SYSSEG
+ retf ! nothing else to do for now
+bootsect_second:
+ push cx
+ push si
+ push bx
+ test bx,bx ! 64K full ?
+ jne bootsect_ex
+ mov cx,#0x8000 ! full 64K move, INT15 moves words
+ push cs
+ pop es
+ mov si,#bootsect_gdt
+ mov ax,#0x8700
+ int 0x15
+ jc bootsect_panic ! this, if INT15 fails
+ seg cs
+ mov es,bootsect_es ! we reset es to always point to 0x10000
+ seg cs
+ inc byte ptr bootsect_dst_base+2
+bootsect_ex:
+ seg cs
+ mov ah, byte ptr bootsect_dst_base+2
+ shl ah,4 ! we now have the number of moved frames in ax
+ xor al,al
+ pop bx
+ pop si
+ pop cx
+ retf
+
+bootsect_gdt:
+ .word 0,0,0,0
+ .word 0,0,0,0
+bootsect_src:
+ .word 0xffff
+bootsect_src_base:
+ .byte 0,0,1 ! base = 0x010000
+ .byte 0x93 ! typbyte
+ .word 0 ! limit16,base24 =0
+bootsect_dst:
+ .word 0xffff
+bootsect_dst_base:
+ .byte 0,0,0x10 ! base = 0x100000
+ .byte 0x93 ! typbyte
+ .word 0 ! limit16,base24 =0
+ .word 0,0,0,0 ! BIOS CS
+ .word 0,0,0,0 ! BIOS DS
+bootsect_es:
+ .word 0
+
+bootsect_panic:
+ push cs
+ pop ds
+ cld
+ lea si,bootsect_panic_mess
+ call prtstr
+bootsect_panic_loop:
+ jmp bootsect_panic_loop
+bootsect_panic_mess:
+ .ascii "INT15 refuses to access high mem, giving up..."
+ db 0
! This routine checks that the keyboard command queue is empty
! (after emptying the output buffers)
@@ -356,45 +650,6 @@ 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
@@ -413,524 +668,30 @@ gettime:
ret
!
-! Delay is needed after doing i/o
+! 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
+! Descriptor tables
!
-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 0xFFFF ! 4Gb - (0x100000*0x1000 = 4Gb)
.word 0x0000 ! base address=0
.word 0x9A00 ! code read/exec
- .word 0x00C0 ! granularity=4096, 386
+ .word 0x00CF ! granularity=4096, 386 (+5th nibble of limit)
- .word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb)
+ .word 0xFFFF ! 4Gb - (0x100000*0x1000 = 4Gb)
.word 0x0000 ! base address=0
.word 0x9200 ! data read/write
- .word 0x00C0 ! granularity=4096, 386
+ .word 0x00CF ! granularity=4096, 386 (+5th nibble of limit)
idt_48:
.word 0 ! idt limit=0
@@ -940,69 +701,26 @@ 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
+!
+! Include video setup & detection code
+!
+
+#include "video.S"
+
+!
+! Setup signature -- must be last
+!
+
setup_sig1: .word SIG1
setup_sig2: .word SIG2
+!
+! After this point, there is some free space which is used by the video mode
+! handling code to store the temporary mode table (not used by the kernel).
+!
+
+modelist:
+
.text
endtext:
.data
diff --git a/arch/i386/boot/tools/build.c b/arch/i386/boot/tools/build.c
index 31277a019..a7e9d063f 100644
--- a/arch/i386/boot/tools/build.c
+++ b/arch/i386/boot/tools/build.c
@@ -18,6 +18,8 @@
/*
* Changes by tytso to allow root device specification
+ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
+ * Cross compiling fixes by Gertjan van Wingerde, July 1996
*/
#include <stdio.h> /* fprintf */
@@ -30,13 +32,20 @@
#include <fcntl.h>
#include <linux/a.out.h>
#include <linux/config.h>
+#include <errno.h>
#define MINIX_HEADER 32
#define N_MAGIC_OFFSET 1024
+#ifndef __BFD__
static int GCC_HEADER = sizeof(struct exec);
+#endif
+#ifdef __BIG_KERNEL__
+#define SYS_SIZE 0xffff
+#else
#define SYS_SIZE DEF_SYSSIZE
+#endif
#define DEFAULT_MAJOR_ROOT 0
#define DEFAULT_MINOR_ROOT 0
@@ -48,6 +57,7 @@ static int GCC_HEADER = sizeof(struct exec);
#define STRINGIFY(x) #x
typedef union {
+ int i;
long l;
short s[2];
char b[4];
@@ -64,6 +74,17 @@ long intel_long(long l)
return t.l;
}
+int intel_int(int i)
+{
+ conv t;
+
+ t.b[0] = i & 0xff; i >>= 8;
+ t.b[1] = i & 0xff; i >>= 8;
+ t.b[2] = i & 0xff; i >>= 8;
+ t.b[3] = i & 0xff; i >>= 8;
+ return t.i;
+}
+
short intel_short(short l)
{
conv t;
@@ -73,7 +94,7 @@ short intel_short(short l)
return t.s[0];
}
-void die(char * str)
+void die(const char * str)
{
fprintf(stderr,"%s\n",str);
exit(1);
@@ -86,10 +107,12 @@ void usage(void)
int main(int argc, char ** argv)
{
- int i,c,id, sz;
- unsigned long sys_size;
+ int i,c,id,sz,tmp_int;
+ unsigned long sys_size, tmp_long;
char buf[1024];
+#ifndef __BFD__
struct exec *ex = (struct exec *)buf;
+#endif
char major_root, minor_root;
struct stat sb;
unsigned char setup_sectors;
@@ -167,8 +190,27 @@ int main(int argc, char ** argv)
if (((long *) buf)[7] != 0)
die("Illegal symbol table in 'setup'");
for (i=0 ; (c=read(id,buf,sizeof buf))>0 ; i+=c )
+#ifdef __BIG_KERNEL__
+ {
+ if (!i) {
+ /* Working with memcpy because of alignment constraints
+ on Sparc - Gertjan */
+ memcpy(&tmp_long, &buf[2], sizeof(long));
+ if (tmp_long != intel_long(0x53726448) )
+ die("Wrong magic in loader header of 'setup'");
+ memcpy(&tmp_int, &buf[6], sizeof(int));
+ if (tmp_int < intel_int(0x200))
+ die("Wrong version of loader header of 'setup'");
+ buf[0x11] = 1; /* LOADED_HIGH */
+ tmp_long = intel_long(0x100000);
+ memcpy(&buf[0x14], &tmp_long, sizeof(long)); /* code32_start */
+ }
+#endif
if (write(1,buf,c)!=c)
die("Write call failed");
+#ifdef __BIG_KERNEL__
+ }
+#endif
if (c != 0)
die("read-error on 'setup'");
close (id);
@@ -190,6 +232,7 @@ int main(int argc, char ** argv)
if ((id=open(argv[3],O_RDONLY,0))<0)
die("Unable to open 'system'");
+#ifndef __BFD__
if (read(id,buf,GCC_HEADER) != GCC_HEADER)
die("Unable to read header of 'system'");
if (N_MAGIC(*ex) == ZMAGIC) {
@@ -203,6 +246,14 @@ int main(int argc, char ** argv)
ex->a_data /1024,
ex->a_bss /1024);
sz = N_SYMOFF(*ex) - GCC_HEADER + 4;
+#else
+ if (fstat (id, &sb)) {
+ perror ("fstat");
+ die ("Unable to stat 'system'");
+ }
+ sz = sb.st_size;
+ fprintf (stderr, "System is %d kB\n", sz/1024);
+#endif
sys_size = (sz + 15) / 16;
if (sys_size > SYS_SIZE)
die("System is too big");
diff --git a/arch/i386/boot/video.S b/arch/i386/boot/video.S
new file mode 100644
index 000000000..8507b7081
--- /dev/null
+++ b/arch/i386/boot/video.S
@@ -0,0 +1,1839 @@
+!
+! Display adapter & video mode setup, version 2.10 (11-Nov-96)
+!
+! Copyright (C) 1995, 1996 Martin Mares <mj@k332.feld.cvut.cz>
+! Based on the original setup.S code (C) Linus Torvalds and Mats Anderson
+!
+
+! Enable autodetection of SVGA adapters and modes
+#define CONFIG_VIDEO_SVGA
+
+! Enable autodetection of VESA modes
+#define CONFIG_VIDEO_VESA
+
+! Enable compacting of mode table
+#define CONFIG_VIDEO_COMPACT
+
+! Retain screen contents when switching modes
+#define CONFIG_VIDEO_RETAIN
+
+! Enable local mode list
+#undef CONFIG_VIDEO_LOCAL
+
+! Force 400 scan lines for standard modes (hack to fix bad behaviour
+! of certain broken BIOS'es -- don't use unless needed)
+#undef CONFIG_VIDEO_400_HACK
+
+! A special hack allowing to force specific BIOS mode ID along with specific
+! dimensions. Especially useful for certain X-Window graphics mode hacks
+! (e.g., 800x600 modes on IBM ThinkPad).
+#undef CONFIG_VIDEO_GFX_HACK
+#define VIDEO_GFX_BIOS_AX 0x4f02 /* 800x600 on ThinkPad */
+#define VIDEO_GFX_BIOS_BX 0x0102
+#define VIDEO_GFX_DUMMY_RESOLUTION 0x6425 /* 100x37 */
+
+! This code uses an extended set of video mode numbers. These include:
+! Aliases for standard modes
+! NORMAL_VGA (-1)
+! EXTENDED_VGA (-2)
+! ASK_VGA (-3)
+! Video modes numbered by menu position -- NOT RECOMMENDED because of lack
+! of compatibility when extending the table. These are between 0x00 and 0xff.
+#define VIDEO_FIRST_MENU 0x0000
+! Standard BIOS video modes (BIOS number + 0x0100)
+#define VIDEO_FIRST_BIOS 0x0100
+! VESA BIOS video modes (VESA number + 0x0200)
+#define VIDEO_FIRST_VESA 0x0200
+! Video7 special modes (BIOS number + 0x0900)
+#define VIDEO_FIRST_V7 0x0900
+! Special video modes
+#define VIDEO_FIRST_SPECIAL 0x0f00
+#define VIDEO_80x25 0x0f00
+#define VIDEO_8POINT 0x0f01
+#define VIDEO_80x43 0x0f02
+#define VIDEO_80x28 0x0f03
+#define VIDEO_CURRENT_MODE 0x0f04
+#define VIDEO_80x30 0x0f05
+#define VIDEO_80x34 0x0f06
+#define VIDEO_80x60 0x0f07
+#define VIDEO_GFX_HACK 0x0f08
+#define VIDEO_LAST_SPECIAL 0x0f09
+! Video modes given by resolution
+#define VIDEO_FIRST_RESOLUTION 0x1000
+
+! The "recalculate timings" flag
+#define VIDEO_RECALC 0x8000
+
+! Positions of various video parameters passed to the kernel
+#define PARAM_CURSOR_POS 0
+#define PARAM_VIDEO_PAGE 4
+#define PARAM_VIDEO_MODE 6
+#define PARAM_VIDEO_COLS 7
+#define PARAM_VIDEO_EGA_BX 10
+#define PARAM_VIDEO_LINES 14
+#define PARAM_HAVE_VGA 15
+#define PARAM_FONT_POINTS 16
+
+! Define DO_STORE according to CONFIG_VIDEO_RETAIN
+#ifdef CONFIG_VIDEO_RETAIN
+#define DO_STORE call store_screen
+#else
+#define DO_STORE
+#endif /* CONFIG_VIDEO_RETAIN */
+
+!
+! This is the main entry point called by setup.S
+!
+! Input:
+! DS pointing to the bootsector
+
+video: push ds ! We use different segments
+ push ds ! FS contains original DS
+ pop fs
+ push cs ! DS is equal to CS
+ pop ds
+ push cs ! ES is equal to CS
+ pop es
+ xor ax,ax
+ mov gs,ax ! GS is zero
+ cld
+ call basic_detect ! Basic adapter type testing (EGA/VGA/MDA/CGA)
+#ifdef CONFIG_VIDEO_SELECT
+ seg fs ! User-selected video mode
+ mov ax,[0x01fa]
+ cmp ax,#ASK_VGA ! Bring up the menu
+ jz vid2
+ call mode_set ! Set the mode
+ jc vid1
+ lea si,badmdt ! Invalid mode ID
+ call prtstr
+vid2: call mode_menu
+vid1:
+#ifdef CONFIG_VIDEO_RETAIN
+ call restore_screen ! Restore screen contents
+#endif /* CONFIG_VIDEO_RETAIN */
+#endif /* CONFIG_VIDEO_SELECT */
+ call mode_params ! Store mode parameters
+ pop ds ! Restore original DS
+ ret
+
+!
+! Detect if we have CGA, MDA, EGA or VGA and pass it to the kernel.
+!
+
+basic_detect:
+ seg fs ! Default is no VGA
+ movb [PARAM_HAVE_VGA],#0
+
+ mov ah,#0x12 ! Check EGA/VGA
+ mov bl,#0x10
+ int 0x10
+ seg fs
+ mov [PARAM_VIDEO_EGA_BX],bx ! Used for identification of EGA in the kernel
+ cmp bl,#0x10 ! No, this is a CGA/MDA/HGA card.
+ je basret
+ incb [adapter]
+
+ mov ax,#0x1a00 ! Check for EGA/VGA discrimination
+ int 0x10
+ cmp al,#0x1a ! 1a means VGA, anything else EGA
+ jne basret
+ seg fs
+ incb [PARAM_HAVE_VGA] ! We've detected a VGA
+ incb [adapter]
+
+basret: ret
+
+!
+! Store the video mode parameters for later usage by the kernel.
+! This is done by asking the BIOS except for the rows/columns
+! parameters in the default 80x25 mode -- these are set directly,
+! because some very obscure BIOSes supply insane values.
+!
+
+mode_params:
+ mov ah,#0x03 ! Read cursor position
+ xor bh,bh
+ int 0x10
+ seg fs
+ mov [PARAM_CURSOR_POS],dx
+
+ mov ah,#0x0f ! Read page/mode/width
+ int 0x10
+ seg fs
+ mov [PARAM_VIDEO_PAGE],bx
+ seg fs
+ mov [PARAM_VIDEO_MODE],ax ! Video mode and screen width
+ cmp al,#7 ! MDA/HGA => segment differs
+ jnz mopar0
+ mov [video_segment],#0xb000
+mopar0: seg gs ! Font size
+ mov ax,[0x485]
+ seg fs
+ mov [PARAM_FONT_POINTS],ax ! (valid only on EGA/VGA)
+
+ mov ax,[force_size] ! Forced size?
+ or ax,ax
+ jz mopar1
+ seg fs
+ mov [PARAM_VIDEO_COLS],ah
+ seg fs
+ mov [PARAM_VIDEO_LINES],al
+ ret
+
+mopar1: mov al,#25
+ cmpb [adapter],#0 ! If we are on CGA/MDA/HGA, the screen must
+ jz mopar2 ! have 25 lines.
+ seg gs ! On EGA/VGA, use the EGA+ BIOS variable
+ mov al,[0x484] ! containing maximal line number.
+ inc al
+mopar2: seg fs
+ movb [PARAM_VIDEO_LINES],al
+ ret
+
+#ifdef CONFIG_VIDEO_SELECT
+
+!
+! The video mode menu
+!
+
+mode_menu:
+ lea si,keymsg ! "Return/Space/Timeout" message
+ call prtstr
+ call flush
+nokey: call getkt
+ cmp al,#0x0d ! ENTER ?
+ je listm ! yes - manual mode selection
+ cmp al,#0x20 ! SPACE ?
+ je defmd1 ! no - repeat
+ call beep
+ jmp nokey
+defmd1: ret ! No mode selected => use the 80x25 default
+
+listm: call mode_table ! We need a mode table to be listed
+listm0: lea si,name_bann ! Print adapter name
+ call prtstr
+ mov si,[card_name]
+ or si,si
+ jnz an2
+ mov al,[adapter]
+ lea si,old_name
+ or al,al
+ jz an1
+ lea si,ega_name
+ dec al
+ jz an1
+ lea si,vga_name
+ jmp an1
+an2: call prtstr
+ lea si,svga_name
+an1: call prtstr
+ lea si,listhdr ! Table header
+ call prtstr
+ mov dl,#0x30 ! DL holds mode number
+ lea si,modelist
+lm1: cmp (si),#ASK_VGA ! End?
+ jz lm2
+ mov al,dl ! Menu selection number
+ call prtchr
+ call prtsp2
+ lodsw
+ call prthw ! Mode ID
+ call prtsp2
+ mov al,(si+1)
+ call prtdec ! Rows
+ mov al,#0x78 ! 'x'
+ call prtchr
+ lodsw
+ call prtdec ! Columns
+ mov al,#0x0d ! New line
+ call prtchr
+ mov al,#0x0a
+ call prtchr
+ inc dl ! Next character
+ cmp dl,#0x3a
+ jnz lm1
+ mov dl,#0x61
+ jmp lm1
+
+lm2: lea si,prompt ! Mode prompt
+ call prtstr
+ lea di,edit_buf ! Editor buffer
+lm3: call getkey
+ cmp al,#0x0d ! Enter?
+ jz lment
+ cmp al,#0x08 ! Backspace?
+ jz lmbs
+ cmp al,#0x20 ! Printable?
+ jc lm3
+ cmp di,#edit_buf+4 ! Enough space?
+ jz lm3
+ stosb
+ call prtchr
+ jmp lm3
+
+lmbs: cmp di,#edit_buf ! Backspace
+ jz lm3
+ dec di
+ mov al,#0x08
+ call prtchr
+ call prtspc
+ mov al,#0x08
+ call prtchr
+ jmp lm3
+
+lment: movb (di),#0
+ lea si,crlft
+ call prtstr
+ lea si,edit_buf
+ cmpb (si),#0 ! Empty string => use default mode
+ jz lmdef
+ cmpb (si+1),#0 ! One character => menu selection
+ jz mnusel
+ cmp (si),#0x6373 ! "scan" => mode scanning
+ jnz lmhx
+ cmp (si+2),#0x6e61
+ jz lmscan
+lmhx: xor bx,bx ! Else => mode ID in hex
+lmhex: lodsb
+ or al,al
+ jz lmuse1
+ sub al,#0x30
+ jc lmbad
+ cmp al,#10
+ jc lmhx1
+ sub al,#7
+ and al,#0xdf
+ cmp al,#10
+ jc lmbad
+ cmp al,#16
+ jnc lmbad
+lmhx1: shl bx,#4
+ or bl,al
+ jmp lmhex
+lmuse1: mov ax,bx
+ jmp lmuse
+
+mnusel: lodsb ! Menu selection
+ xor ah,ah
+ sub al,#0x30
+ jc lmbad
+ cmp al,#10
+ jc lmuse
+ cmp al,#0x61-0x30
+ jc lmbad
+ sub al,#0x61-0x30-10
+ cmp al,#36
+ jnc lmbad
+lmuse: call mode_set
+ jc lmdef
+lmbad: lea si,unknt
+ call prtstr
+ br lm2
+
+lmscan: cmpb [adapter],#0 ! Scanning supported only on EGA/VGA
+ jz lmbad
+ mov [mt_end],#0 ! Scanning of modes: done as new autodetection
+ movb [scanning],#1
+ call mode_table
+ br listm0
+
+lmdef: ret
+
+!
+! Additional parts of mode_set... (relative jumps, you know)
+!
+
+setv7: ! Video7 extended modes
+ DO_STORE
+ sub bh,#VIDEO_FIRST_V7>>8
+ mov ax,#0x6f05
+ int 0x10
+ stc
+ ret
+
+_setrec: br setrec ! Ugly...
+
+!
+! Aliases for backward compatibility.
+!
+
+setalias:
+ mov ax,#VIDEO_80x25
+ inc bx
+ jz mode_set
+ mov al,#VIDEO_8POINT-VIDEO_FIRST_SPECIAL
+ inc bx
+ jnz setbad
+
+ ! Fall-thru !
+
+!
+! Setting of user mode (AX=mode ID) => CF=success
+!
+
+mode_set:
+ mov bx,ax
+ cmp ah,#0xff
+ jz setalias
+ test ah,#VIDEO_RECALC>>8
+ jnz _setrec
+ cmp ah,#VIDEO_FIRST_RESOLUTION>>8
+ jnc setres
+ cmp ah,#VIDEO_FIRST_SPECIAL>>8
+ jz setspc
+ cmp ah,#VIDEO_FIRST_V7>>8
+ jz setv7
+ cmp ah,#VIDEO_FIRST_VESA>>8
+ jnc setvesa
+ or ah,ah
+ jz setmenu
+ dec ah
+ jz setbios
+setbad: clc
+ movb [do_restore],#0 ! The screen needn't be restored
+ ret
+
+setvesa:
+ DO_STORE
+ sub bh,#VIDEO_FIRST_VESA>>8
+ mov ax,#0x4f02 ! VESA BIOS mode set call
+ int 0x10
+ cmp ax,#0x004f ! AL=4f if implemented, AH=0 if OK
+ jnz setbad
+ stc
+ ret
+
+setbios:
+ DO_STORE
+ int 0x10 ! Standard BIOS mode set call
+ push bx
+ mov ah,#0x0f ! Check if really set
+ int 0x10
+ pop bx
+ cmp al,bl
+ jnz setbad
+ stc
+ ret
+
+setspc: xor bh,bh ! Set special mode
+ cmp bl,#VIDEO_LAST_SPECIAL-VIDEO_FIRST_SPECIAL
+ jnc setbad
+ add bx,bx
+ .word 0xa7ff, spec_inits ! JMP [BX+spec_inits]
+
+setmenu:
+ or al,al ! 80x25 is an exception
+ jz set_80x25
+ push bx ! Set mode chosen from menu
+ call mode_table ! Build the mode table
+ pop ax
+ shl ax,#2
+ add si,ax
+ cmp si,di
+ jnc setbad
+ mov ax,(si) ! Fetch mode ID
+_m_s: jmp mode_set
+
+setres:
+ push bx ! Set mode chosen by its resolution
+ call mode_table
+ pop bx
+ xchg bh,bl
+setr1: lodsw
+ cmp ax,#ASK_VGA ! End of the list?
+ jz setbad
+ lodsw
+ cmp ax,bx
+ jnz setr1
+ mov ax,(si-4) ! Fetch mode ID
+ jmp _m_s
+
+!
+! Recalculate vertical display end registers -- this fixes various
+! inconsistencies of extended modes on many adapters. Called when
+! the VIDEO_RECALC flag is set in the mode ID.
+!
+
+setrec: sub ah,#VIDEO_RECALC>>8 ! Set the base mode
+ call mode_set
+ jnc rct3
+ seg gs ! Font size in pixels
+ mov ax,[0x485]
+ seg gs ! Number of rows
+ mov bl,[0x484]
+ inc bl
+ mul bl ! Number of visible
+ dec ax ! scan lines - 1
+ mov dx,#0x3d4
+ mov bx,ax
+ mov al,#0x12 ! Lower 8 bits
+ mov ah,bl
+ out dx,ax
+ mov al,#0x07 ! Bits 8 and 9 in the overflow register
+ call inidx
+ xchg ah,al
+ and ah,#0xbd
+ shr bh,#1
+ jnc rct1
+ or ah,#0x02
+rct1: shr bh,#1
+ jnc rct2
+ or ah,#0x40
+rct2: mov al,#0x07
+ out dx,ax
+ stc
+rct3: ret
+
+!
+! Table of routines for setting of the special modes.
+!
+
+spec_inits:
+ .word set_80x25
+ .word set_8pixel
+ .word set_80x43
+ .word set_80x28
+ .word set_current
+ .word set_80x30
+ .word set_80x34
+ .word set_80x60
+ .word set_gfx
+
+!
+! Set the 80x25 mode. If already set, do nothing.
+!
+
+set_80x25:
+ mov [force_size],#0x5019 ! Override possibly broken BIOS vars
+use_80x25:
+#ifdef CONFIG_VIDEO_400_HACK
+ mov ax,#0x1202 ! Force 400 scan lines
+ mov bl,#0x30
+ int 0x10
+#else
+ mov ah,#0x0f ! Get current mode ID
+ int 0x10
+ cmp ax,#0x5007 ! Mode 7 (80x25 mono) is the only one available
+ jz st80 ! on CGA/MDA/HGA and is also available on EGAM
+ cmp ax,#0x5003 ! Unknown mode => force 80x25 color
+ jnz force3
+st80: cmpb [adapter],#0 ! CGA/MDA/HGA => mode 3/7 is always 80x25
+ jz set80
+ seg gs ! This is EGA+ -- beware of 80x50 etc.
+ mov al,[0x0484]
+ or al,al ! Some buggy BIOS'es set 0 rows
+ jz set80
+ cmp al,#24 ! It's hopefully correct
+ jz set80
+#endif /* CONFIG_VIDEO_400_HACK */
+force3: DO_STORE
+ mov ax,#0x0003 ! Forced set
+ int 0x10
+set80: stc
+ ret
+
+!
+! Set the 80x50/80x43 8-pixel mode. Simple BIOS calls.
+!
+
+set_8pixel:
+ DO_STORE
+ call use_80x25 ! The base is 80x25
+set_8pt:
+ mov ax,#0x1112 ! Use 8x8 font
+ xor bl,bl
+ int 0x10
+ mov ax,#0x1200 ! Use alternate print screen
+ mov bl,#0x20
+ int 0x10
+ mov ax,#0x1201 ! Turn off cursor emulation
+ mov bl,#0x34
+ int 0x10
+ mov ah,#0x01 ! Define cursor (scan lines 6 to 7)
+ mov cx,#0x0607
+ int 0x10
+set_current:
+ stc
+ ret
+
+!
+! Set the 80x28 mode. This mode works on all VGA's, because it's a standard
+! 80x25 mode with 14-point fonts instead of 16-point.
+!
+
+set_80x28:
+ DO_STORE
+ call use_80x25 ! The base is 80x25
+set14: mov ax,#0x1111 ! Use 9x14 font
+ xor bl,bl
+ int 0x10
+ mov ah,#0x01 ! Define cursor (scan lines 11 to 12)
+ mov cx,#0x0b0c
+ int 0x10
+ stc
+ ret
+
+!
+! Set the 80x43 mode. This mode is works on all VGA's.
+! It's a 350-scanline mode with 8-pixel font.
+!
+
+set_80x43:
+ DO_STORE
+ mov ax,#0x1201 ! Set 350 scans
+ mov bl,#0x30
+ int 0x10
+ mov ax,#0x0003 ! Reset video mode
+ int 0x10
+ jmp set_8pt ! Use 8-pixel font
+
+!
+! Set the 80x30 mode (all VGA's). 480 scanlines, 16-pixel font.
+!
+
+set_80x30:
+ call use_80x25 ! Start with real 80x25
+ DO_STORE
+ mov dx,#0x3cc ! Get CRTC port
+ in al,dx
+ mov dl,#0xd4
+ ror al,#1 ! Mono or color?
+ jc set48a
+ mov dl,#0xb4
+set48a: mov ax,#0x0c11 ! Vertical sync end (also unlocks CR0-7)
+ call outidx
+ mov ax,#0x0b06 ! Vertical total
+ call outidx
+ mov ax,#0x3e07 ! (Vertical) overflow
+ call outidx
+ mov ax,#0xea10 ! Vertical sync start
+ call outidx
+ mov ax,#0xdf12 ! Vertical display end
+ call outidx
+ mov ax,#0xe715 ! Vertical blank start
+ call outidx
+ mov ax,#0x0416 ! Vertical blank end
+ call outidx
+ push dx
+ mov dl,#0xcc ! Misc output register (read)
+ in al,dx
+ mov dl,#0xc2 ! (write)
+ and al,#0x0d ! Preserve clock select bits and color bit
+ or al,#0xe2 ! Set correct sync polarity
+ out dx,al
+ pop dx
+ mov [force_size],#0x501e
+ stc ! That's all.
+ ret
+
+!
+! Set the 80x34 mode (all VGA's). 480 scans, 14-pixel font.
+!
+
+set_80x34:
+ call set_80x30 ! Set 480 scans
+ call set14 ! And 14-pt font
+ mov ax,#0xdb12 ! VGA vertical display end
+ mov [force_size],#0x5022
+setvde: call outidx
+ stc
+ ret
+
+!
+! Set the 80x60 mode (all VGA's). 480 scans, 8-pixel font.
+!
+
+set_80x60:
+ call set_80x30 ! Set 480 scans
+ call set_8pt ! And 8-pt font
+ mov ax,#0xdf12 ! VGA vertical display end
+ mov [force_size],#0x503c
+ jmp setvde
+
+!
+! Special hack for ThinkPad graphics
+!
+
+set_gfx:
+#ifdef CONFIG_VIDEO_GFX_HACK
+ mov ax,# VIDEO_GFX_BIOS_AX
+ mov bx,# VIDEO_GFX_BIOS_BX
+ int 0x10
+ mov [force_size],# VIDEO_GFX_DUMMY_RESOLUTION
+ stc
+#endif
+ ret
+
+#ifdef CONFIG_VIDEO_RETAIN
+
+!
+! Store screen contents to temporary buffer.
+!
+
+store_screen:
+ cmpb [do_restore],#0 ! Already stored?
+ jnz stsr
+ testb [loadflags],#CAN_USE_HEAP ! Have we space for storing?
+ jz stsr
+ push ax
+ push bx
+ push [force_size] ! Don't force specific size
+ mov [force_size],#0
+ call mode_params ! Obtain params of current mode
+ pop [force_size]
+
+ seg fs
+ mov ah,[PARAM_VIDEO_LINES]
+ seg fs
+ mov al,[PARAM_VIDEO_COLS]
+ mov bx,ax ! BX=dimensions
+ mul ah
+ mov cx,ax ! CX=number of characters to store
+ add ax,ax ! Calculate image size
+ add ax,#modelist+1024+4
+ cmp ax,[heap_end_ptr]
+ jnc sts1 ! Unfortunately, out of memory
+
+ seg fs ! Store mode params
+ mov ax,[PARAM_CURSOR_POS]
+ lea di,modelist+1024
+ stosw
+ mov ax,bx
+ stosw
+
+ push ds ! Store the screen
+ mov ds,[video_segment]
+ xor si,si
+ rep
+ movsw
+ pop ds
+ incb [do_restore] ! Screen will be restored later
+sts1: pop bx
+ pop ax
+stsr: ret
+
+!
+! Restore screen contents from temporary buffer.
+!
+
+restore_screen:
+ cmpb [do_restore],#0 ! Has the screen been stored?
+ jz res1
+ call mode_params ! Get parameters of current mode
+ seg fs
+ mov cl,[PARAM_VIDEO_LINES]
+ seg fs
+ mov ch,[PARAM_VIDEO_COLS]
+ lea si,modelist+1024 ! Screen buffer
+ lodsw ! Set cursor position
+ mov dx,ax
+ cmp dh,cl
+ jc res2
+ mov dh,cl
+ dec dh
+res2: cmp dl,ch
+ jc res3
+ mov dl,ch
+ dec dl
+res3: mov ah,#0x02
+ mov bh,#0x00
+ int 0x10
+ lodsw ! Display size
+ mov dl,ah ! DL=number of lines
+ mov ah,#0 ! BX=physical length of orig. line
+ mov bx,ax
+ cmp dl,cl ! Too many?
+ jc res4
+ push ax
+ mov al,dl
+ sub al,cl
+ mul bl
+ add si,ax
+ add si,ax
+ pop ax
+ mov dl,cl
+res4: cmp al,ch ! Too wide?
+ jc res5
+ mov al,ch ! AX=width of src. line
+res5: mov cl,#0
+ xchg cl,ch
+ mov bp,cx ! BP=width of dest. line
+ push es
+ mov es,[video_segment]
+ xor di,di ! Move the data
+ add bx,bx ! Convert BX and BP to _bytes_
+ add bp,bp
+res6: push si
+ push di
+ mov cx,ax
+ rep
+ movsw
+ pop di
+ pop si
+ add di,bp
+ add si,bx
+ dec dl
+ jnz res6
+ pop es ! Done
+res1: ret
+
+#endif /* CONFIG_VIDEO_RETAIN */
+
+!
+! Write to indexed VGA register (AL=index, AH=data, DX=index reg. port)
+!
+
+outidx: out dx,al
+ push ax
+ mov al,ah
+ inc dx
+ out dx,al
+ dec dx
+ pop ax
+ ret
+
+!
+! Build the table of video modes (stored after the setup.S code at the
+! `modelist' label. Each video mode record looks like:
+! .word MODE-ID (our special mode ID (see above))
+! .byte rows (number of rows)
+! .byte columns (number of columns)
+! Returns address of the end of the table in DI, the end is marked
+! with a ASK_VGA ID.
+!
+
+mode_table:
+ mov di,[mt_end] ! Already filled?
+ or di,di
+ jnz mtab1x
+ lea di,modelist ! Store standard modes:
+
+ mov eax,#VIDEO_80x25 + 0x50190000 ! The 80x25 mode (ALL)
+ stosd
+ mov al,[adapter] ! CGA/MDA/HGA -- no more modes
+ or al,al
+ jz mtabe
+ dec al
+ jnz mtabv
+ mov eax,#VIDEO_8POINT + 0x502b0000 ! The 80x43 EGA mode
+ stosd
+ jmp mtabe
+mtab1x: jmp mtab1
+
+mtabv: lea si,vga_modes ! All modes for std VGA
+ mov cx,#vga_modes_end-vga_modes
+ rep ! I'm unable to use movsw as I don't know how to store a half
+ movsb ! of the expression above to cx without using explicit shr.
+
+ cmpb [scanning],#0 ! Mode scan requested?
+ jz mscan1
+ call mode_scan
+mscan1:
+
+#ifdef CONFIG_VIDEO_LOCAL
+ call local_modes
+#endif /* CONFIG_VIDEO_LOCAL */
+#ifdef CONFIG_VIDEO_VESA
+ call vesa_modes ! Detect VESA VGA modes
+#endif /* CONFIG_VIDEO_VESA */
+#ifdef CONFIG_VIDEO_SVGA
+ cmpb [scanning],#0 ! Bypass when scanning
+ jnz mscan2
+ call svga_modes ! Detect SVGA cards & modes
+mscan2:
+#endif /* CONFIG_VIDEO_SVGA */
+
+mtabe:
+
+#ifdef CONFIG_VIDEO_COMPACT
+ lea si,modelist ! Compact video mode list if requested.
+ mov dx,di
+ mov di,si
+cmt1: cmp si,dx ! Scan all modes
+ jz cmt2
+ lea bx,modelist ! Find in previous entries
+ mov cx,(si+2)
+cmt3: cmp si,bx
+ jz cmt4
+ cmp cx,(bx+2) ! Found => don't copy this entry
+ jz cmt5
+ add bx,#4
+ jmp cmt3
+
+cmt4: movsd ! Copy entry
+ jmp cmt1
+
+cmt5: add si,#4 ! Skip entry
+ jmp cmt1
+
+cmt2:
+#endif /* CONFIG_VIDEO_COMPACT */
+
+ mov (di),#ASK_VGA ! End marker
+ mov [mt_end],di
+mtab1: lea si,modelist ! Returning: SI=mode list, DI=list end
+ret0: ret
+
+! Modes usable on all standard VGAs
+
+vga_modes:
+ .word VIDEO_8POINT
+ .word 0x5032 ! 80x50
+ .word VIDEO_80x43
+ .word 0x502b ! 80x43
+ .word VIDEO_80x28
+ .word 0x501c ! 80x28
+ .word VIDEO_80x30
+ .word 0x501e ! 80x30
+ .word VIDEO_80x34
+ .word 0x5022 ! 80x34
+ .word VIDEO_80x60
+ .word 0x503c ! 80x60
+#ifdef CONFIG_VIDEO_GFX_HACK
+ .word VIDEO_GFX_HACK
+ .word VIDEO_GFX_DUMMY_RESOLUTION
+#endif
+vga_modes_end:
+
+!
+! Detect VESA modes.
+!
+
+#ifdef CONFIG_VIDEO_VESA
+
+vesa_modes:
+ cmpb [adapter],#2 ! VGA only
+ jnz ret0
+ mov bp,di ! BP=original mode table end
+ add di,#0x200 ! Buffer space
+ mov ax,#0x4f00 ! VESA Get card info call
+ int #0x10
+ mov di,bp
+ cmp ax,#0x004f ! Successful?
+ jnz ret0
+ cmp (di+0x200),#0x4556
+ jnz ret0
+ cmp (di+0x202),#0x4153
+ jnz ret0
+ mov [card_name],#vesa_name ! Set name to "VESA VGA"
+ push gs
+ lgs si,(di+0x20e) ! GS:SI=mode list
+ mov cx,#128 ! Iteration limit
+vesa1: seg gs ! Get next mode in the list
+ lodsw
+ cmp ax,#0xffff ! End of the table?
+ jz vesar
+ cmp ax,#0x0080 ! Check validity of mode ID
+ jc vesa2
+ or ah,ah ! Valid ID's are 0x0000-0x007f and 0x0100-0x07ff
+ jz vesan ! [Certain BIOSes erroneously report 0x80-0xff]
+ cmp ax,#0x0800
+ jnc vesae
+vesa2: push cx
+ mov cx,ax ! Get mode information structure
+ mov ax,#0x4f01
+ int 0x10
+ mov bx,cx ! BX=mode number
+ add bh,#VIDEO_FIRST_VESA>>8
+ pop cx
+ cmp ax,#0x004f
+ jnz vesan ! Don't report errors (buggy BIOSES :-[ )
+ mov al,(di) ! Check capabilities. We require
+ and al,#0x19 ! a color text mode.
+ cmp al,#0x09
+ jnz vesan
+ cmp (di+8),#0xb800 ! Standard video memory address required
+ jnz vesan
+ testb (di),#2 ! Mode characteristics supplied?
+ mov (di),bx ! Store mode number
+ jz vesa3
+ xor dx,dx
+ mov bx,(di+0x12) ! Width
+ or bh,bh
+ jnz vesan
+ mov (di+3),bl
+ mov ax,(di+0x14) ! Height
+ or ah,ah
+ jnz vesan
+ mov (di+2),al
+ mul bl
+ cmp ax,#8193 ! Small enough for Linux console driver?
+ jnc vesan
+ jmp vesaok
+
+vesa3: sub bx,#0x8108 ! This mode has no detailed info specified,
+ jc vesan ! so it must be a standard VESA mode.
+ cmp bx,#5
+ jnc vesan
+ mov ax,(bx+vesa_text_mode_table)
+ mov (di+2),ax
+vesaok: add di,#4 ! The mode is valid. Store it.
+vesan: loop vesa1 ! Next mode. Limit exceeded => error
+vesae: lea si,vesaer
+ call prtstr
+ mov di,bp ! Discard already found modes.
+vesar: pop gs
+ ret
+
+!
+! Dimensions of standard VESA text modes
+!
+
+vesa_text_mode_table:
+ db 60, 80 ! 0108
+ db 25, 132 ! 0109
+ db 43, 132 ! 010A
+ db 50, 132 ! 010B
+ db 60, 132 ! 010C
+
+#endif /* CONFIG_VIDEO_VESA */
+
+!
+! Scan for video modes. A bit dirty, but should work.
+!
+
+mode_scan:
+ mov cx,#0x0100 ! Start with mode 0
+scm1: mov ah,#0 ! Test the mode
+ mov al,cl
+ int 0x10
+ mov ah,#0x0f
+ int 0x10
+ cmp al,cl
+ jnz scm2 ! Mode not set
+ mov dx,#0x3c0 ! Test if it's a text mode
+ mov al,#0x10 ! Mode bits
+ call inidx
+ and al,#0x03
+ jnz scm2
+ mov dl,#0xce ! Another set of mode bits
+ mov al,#0x06
+ call inidx
+ shr al,#1
+ jc scm2
+ mov dl,#0xd4 ! Cursor location
+ mov al,#0x0f
+ call inidx
+ or al,al
+ jnz scm2
+ mov ax,cx ! OK, store the mode
+ stosw
+ seg gs ! Number of rows
+ mov al,[0x484]
+ inc al
+ stosb
+ seg gs ! Number of columns
+ mov ax,[0x44a]
+ stosb
+scm2: inc cl
+ jns scm1
+ mov ax,#0x0003 ! Return back to mode 3
+ int 0x10
+ ret
+
+tstidx: out dx,ax ! OUT DX,AX and inidx
+inidx: out dx,al ! Read from indexed VGA register
+ inc dx ! AL=index, DX=index reg port -> AL=data
+ in al,dx
+ dec dx
+ ret
+
+!
+! Try to detect type of SVGA card and supply (usually approximate) video
+! mode table for it.
+!
+
+#ifdef CONFIG_VIDEO_SVGA
+
+svga_modes:
+ lea si,svga_table ! Test all known SVGA adapters
+dosvga: lodsw
+ mov bp,ax ! Default mode table
+ or ax,ax
+ jz didsv1
+ lodsw ! Pointer to test routine
+ push si
+ push di
+ push es
+ mov bx,#0xc000
+ mov es,bx
+ call ax ! Call test routine
+ pop es
+ pop di
+ pop si
+ or bp,bp
+ jz dosvga
+ mov si,bp ! Found, copy the modes
+ mov ah,[svga_prefix]
+cpsvga: lodsb
+ or al,al
+ jz didsv
+ stosw
+ movsw
+ jmp cpsvga
+
+didsv: mov [card_name],si ! Store pointer to card name
+didsv1: ret
+
+!
+! Table of all known SVGA cards. For each card, we store a pointer to
+! a table of video modes supported by the card and a pointer to a routine
+! used for testing of presence of the card. The video mode table is always
+! followed by the name of the card or the chipset.
+!
+
+svga_table:
+ .word ati_md, ati_test
+ .word oak_md, oak_test
+ .word paradise_md, paradise_test
+ .word realtek_md, realtek_test
+ .word s3_md, s3_test
+ .word chips_md, chips_test
+ .word video7_md, video7_test
+ .word cirrus5_md, cirrus5_test
+ .word cirrus6_md, cirrus6_test
+ .word cirrus1_md, cirrus1_test
+ .word ahead_md, ahead_test
+ .word everex_md, everex_test
+ .word genoa_md, genoa_test
+ .word trident_md, trident_test
+ .word tseng_md, tseng_test
+ .word 0
+
+!
+! Test routines and mode tables:
+!
+
+! S3 - The test algorithm was taken from the SuperProbe package
+! for XFree86 1.2.1. Report bugs to Christoph.Niemann@linux.org
+
+s3_test:
+ 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
+ movb ah,bh
+ movb al,#0x38
+ jmp s3rest
+no_s3: movb al,#0x35 ! restore CRT register 0x35
+ movb ah,bl
+ call outidx
+no_s31: xor bp,bp ! Detection failed
+s3rest: movb ah,bh
+ movb al,#0x38 ! restore old value of CRT register 0x38
+ br outidx
+
+idS3: .byte 0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95
+ .byte 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0
+
+s3_md: .byte 0x54, 0x2b, 0x84
+ .byte 0x55, 0x19, 0x84
+ .byte 0
+ .ascii "S3"
+ .byte 0
+
+! ATI cards.
+
+ati_test:
+ lea si,idati
+ mov di,#0x31
+ mov cx,#0x09
+ repe
+ cmpsb
+ je atiok
+ xor bp,bp
+atiok: ret
+
+idati: .ascii "761295520"
+
+ati_md: .byte 0x23, 0x19, 0x84
+ .byte 0x33, 0x2c, 0x84
+ .byte 0x22, 0x1e, 0x64
+ .byte 0x21, 0x19, 0x64
+ .byte 0x58, 0x21, 0x50
+ .byte 0x5b, 0x1e, 0x50
+ .byte 0
+ .ascii "ATI"
+ .byte 0
+
+! AHEAD
+
+ahead_test:
+ mov ax,#0x200f
+ mov dx,#0x3ce
+ out dx,ax
+ inc dx
+ in al,dx
+ cmp al,#0x20
+ je isahed
+ cmp al,#0x21
+ je isahed
+ xor bp,bp
+isahed: ret
+
+ahead_md:
+ .byte 0x22, 0x2c, 0x84
+ .byte 0x23, 0x19, 0x84
+ .byte 0x24, 0x1c, 0x84
+ .byte 0x2f, 0x32, 0xa0
+ .byte 0x32, 0x22, 0x50
+ .byte 0x34, 0x42, 0x50
+ .byte 0
+ .ascii "Ahead"
+ .byte 0
+
+! Chips & Tech.
+
+chips_test:
+ mov dx,#0x3c3
+ 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,#0xa5
+ je cantok
+ xor bp,bp
+cantok: ret
+
+chips_md:
+ .byte 0x60, 0x19, 0x84
+ .byte 0x61, 0x32, 0x84
+ .byte 0
+ .ascii "Chips & Technologies"
+ .byte 0
+
+! Cirrus Logic 5X0
+
+cirrus1_test:
+ mov dx,#0x3d4
+ 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
+ je iscirr
+nocirr: xor bp,bp
+iscirr: mov dx,#0x3d4
+ mov al,bl
+ xor ah,ah
+ shl ax,#8
+ add ax,#0x0c
+ out dx,ax
+ ret
+
+cirrus1_md:
+ .byte 0x1f, 0x19, 0x84
+ .byte 0x20, 0x2c, 0x84
+ .byte 0x22, 0x1e, 0x84
+ .byte 0x31, 0x25, 0x64
+ .byte 0
+ .ascii "Cirrus Logic 5X0"
+ .byte 0
+
+! Cirrus Logic 54XX
+
+cirrus5_test:
+ mov dx,#0x3c4
+ mov al,#6
+ call inidx
+ mov bl,al ! BL=backup
+ mov ax,#6
+ call tstidx
+ cmp al,#0x0f
+ jne c5fail
+ mov ax,#0x1206
+ call tstidx
+ cmp al,#0x12
+ jne c5fail
+ mov al,#0x1e
+ call inidx
+ mov bh,al
+ mov ah,bh
+ and ah,#0xc0
+ mov al,#0x1e
+ call tstidx
+ and al,#0x3f
+ jne c5xx
+ mov al,#0x1e
+ mov ah,bh
+ or ah,#0x3f
+ call tstidx
+ xor al,#0x3f
+ and al,#0x3f
+c5xx: pushf
+ mov al,#0x1e
+ mov ah,bh
+ out dx,ax
+ popf
+ je c5done
+c5fail: xor bp,bp
+c5done: mov al,#6
+ mov ah,bl
+ out dx,ax
+ ret
+
+cirrus5_md:
+ .byte 0x14, 0x19, 0x84
+ .byte 0x54, 0x2b, 0x84
+ .byte 0
+ .ascii "Cirrus Logic 54XX"
+ .byte 0
+
+! Cirrus Logic 64XX -- no known extra modes, but must be identified, because
+! it's misidentified by the Ahead test.
+
+cirrus6_test:
+ mov dx,#0x3ce
+ mov al,#0x0a
+ call inidx
+ mov bl,al ! BL=backup
+ mov ax,#0xce0a
+ call tstidx
+ or al,al
+ jne c2fail
+ mov ax,#0xec0a
+ call tstidx
+ cmp al,#0x01
+ jne c2fail
+ mov al,#0xaa
+ call inidx ! 4X, 5X, 7X and 8X are valid 64XX chip ID's
+ shr al,#4
+ sub al,#4
+ jz c6done
+ dec al
+ jz c6done
+ sub al,#2
+ jz c6done
+ dec al
+ jz c6done
+c2fail: xor bp,bp
+c6done: mov al,#0x0a
+ mov ah,bl
+ out dx,ax
+ ret
+
+cirrus6_md:
+ .byte 0
+ .ascii "Cirrus Logic 64XX"
+ .byte 0
+
+! Everex / Trident
+
+everex_test:
+ mov ax,#0x7000
+ xor bx,bx
+ int 0x10
+ cmp al,#0x70
+ jne noevrx
+ shr dx,#4
+ cmp dx,#0x678
+ je evtrid
+ cmp dx,#0x236
+ jne evrxok
+evtrid: lea bp,trident_md
+evrxok: ret
+
+noevrx: xor bp,bp
+ ret
+
+everex_md:
+ .byte 0x03, 0x22, 0x50
+ .byte 0x04, 0x3c, 0x50
+ .byte 0x07, 0x2b, 0x64
+ .byte 0x08, 0x4b, 0x64
+ .byte 0x0a, 0x19, 0x84
+ .byte 0x0b, 0x2c, 0x84
+ .byte 0x16, 0x1e, 0x50
+ .byte 0x18, 0x1b, 0x64
+ .byte 0x21, 0x40, 0xa0
+ .byte 0x40, 0x1e, 0x84
+ .byte 0
+ .ascii "Everex/Trident"
+ .byte 0
+
+! Genoa.
+
+genoa_test:
+ 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
+ or cx,cx
+ je isgen
+ xor bp,bp
+isgen: ret
+
+idgenoa: .byte 0x77, 0x00, 0x99, 0x66
+
+genoa_md:
+ .byte 0x58, 0x20, 0x50
+ .byte 0x5a, 0x2a, 0x64
+ .byte 0x60, 0x19, 0x84
+ .byte 0x61, 0x1d, 0x84
+ .byte 0x62, 0x20, 0x84
+ .byte 0x63, 0x2c, 0x84
+ .byte 0x64, 0x3c, 0x84
+ .byte 0x6b, 0x4f, 0x64
+ .byte 0x72, 0x3c, 0x50
+ .byte 0x74, 0x42, 0x50
+ .byte 0x78, 0x4b, 0x64
+ .byte 0
+ .ascii "Genoa"
+ .byte 0
+
+! OAK
+
+oak_test:
+ lea si,idoakvga
+ mov di,#0x08
+ mov cx,#0x08
+ repe
+ cmpsb
+ je isoak
+ xor bp,bp
+isoak: ret
+
+idoakvga: .ascii "OAK VGA "
+
+oak_md: .byte 0x4e, 0x3c, 0x50
+ .byte 0x4f, 0x3c, 0x84
+ .byte 0x50, 0x19, 0x84
+ .byte 0x51, 0x2b, 0x84
+ .byte 0
+ .ascii "OAK"
+ .byte 0
+
+! WD Paradise.
+
+paradise_test:
+ lea si,idparadise
+ mov di,#0x7d
+ mov cx,#0x04
+ repe
+ cmpsb
+ je ispara
+ xor bp,bp
+ispara: ret
+
+idparadise: .ascii "VGA="
+
+paradise_md:
+ .byte 0x41, 0x22, 0x50
+ .byte 0x47, 0x1c, 0x84
+ .byte 0x55, 0x19, 0x84
+ .byte 0x54, 0x2c, 0x84
+ .byte 0
+ .ascii "Paradise"
+ .byte 0
+
+! Trident.
+
+trident_test:
+ mov dx,#0x3c4
+ 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
+ je istrid
+ xor bp,bp
+istrid: ret
+
+trident_md:
+ .byte 0x50, 0x1e, 0x50
+ .byte 0x51, 0x2b, 0x50
+ .byte 0x52, 0x3c, 0x50
+ .byte 0x57, 0x19, 0x84
+ .byte 0x58, 0x1e, 0x84
+ .byte 0x59, 0x2b, 0x84
+ .byte 0x5a, 0x3c, 0x84
+ .byte 0
+ .ascii "Trident"
+ .byte 0
+
+! Tseng.
+
+tseng_test:
+ mov dx,#0x3cd
+ 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
+ je istsen
+isnot: xor bp,bp
+istsen: ret
+
+tseng_md:
+ .byte 0x26, 0x3c, 0x50
+ .byte 0x2a, 0x28, 0x64
+ .byte 0x23, 0x19, 0x84
+ .byte 0x24, 0x1c, 0x84
+ .byte 0x22, 0x2c, 0x84
+ .byte 0x21, 0x3c, 0x84
+ .byte 0
+ .ascii "Tseng"
+ .byte 0
+
+! Video7.
+
+video7_test:
+ mov dx,#0x3cc
+ 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 isnot
+ movb [svga_prefix],#VIDEO_FIRST_V7>>8 ! Use special mode switching
+ ret
+
+video7_md:
+ .byte 0x40, 0x2b, 0x50
+ .byte 0x43, 0x3c, 0x50
+ .byte 0x44, 0x3c, 0x64
+ .byte 0x41, 0x19, 0x84
+ .byte 0x42, 0x2c, 0x84
+ .byte 0x45, 0x1c, 0x84
+ .byte 0
+ .ascii "Video 7"
+ .byte 0
+
+! Realtek VGA
+
+realtek_test:
+ lea si,idrtvga
+ mov di,#0x45
+ mov cx,#0x0b
+ repe
+ cmpsb
+ je isrt
+ xor bp,bp
+isrt: ret
+
+idrtvga: .ascii "REALTEK VGA"
+
+realtek_md:
+ .byte 0x1a, 0x3c, 0x50
+ .byte 0x1b, 0x19, 0x84
+ .byte 0x1c, 0x1e, 0x84
+ .byte 0x1d, 0x2b, 0x84
+ .byte 0x1e, 0x3c, 0x84
+ .byte 0
+ .ascii "REALTEK"
+ .byte 0
+
+#endif /* CONFIG_VIDEO_SVGA */
+
+!
+! User-defined local mode table (VGA only)
+!
+
+#ifdef CONFIG_VIDEO_LOCAL
+
+local_modes:
+ lea si,local_mode_table
+locm1: lodsw
+ or ax,ax
+ jz locm2
+ stosw
+ movsw
+ jmp locm1
+locm2: ret
+
+! This is the table of local video modes which can be supplied manually
+! by the user. Each entry consists of mode ID (word) and dimensions
+! (byte for column count and another byte for row count). These modes
+! are placed before all SVGA and VESA modes and override them if table
+! compacting is enabled. The table must end with a zero word followed
+! by NUL-terminated video adapter name.
+
+local_mode_table:
+ .word 0x0100 ! Example: 40x25
+ .byte 25,40
+ .word 0
+ .ascii "Local"
+ .byte 0
+
+#endif /* CONFIG_VIDEO_LOCAL */
+
+!
+! Read a key and return the 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 hardware 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
+
+!
+! Print hexadecimal number.
+!
+
+prthw: push ax
+ mov al,ah
+ call prthb
+ pop ax
+prthb: push ax
+ shr al,#4
+ call prthn
+ pop ax
+ and al,#0x0f
+prthn: cmp al,#0x0a
+ jc prth1
+ add al,#0x07
+prth1: add al,#0x30
+ br prtchr
+
+!
+! Print decimal number (AL).
+!
+
+prtdec: push ax
+ push cx
+ xor ah,ah ! Clear ah
+ mov cl,#0x0a
+ idiv cl
+ cmp al,#0x09
+ jbe lt100
+ call prtdec
+ jmp skip10
+lt100: add al,#0x30
+ call prtchr
+skip10: mov al,ah
+ add al,#0x30
+ call prtchr
+ pop cx
+ pop ax
+ ret
+
+!
+! VIDEO_SELECT-only variables
+!
+
+mt_end: .word 0 ! End of video mode table if built
+edit_buf: .space 6 ! Line editor buffer
+card_name: .word 0 ! Pointer to adapter name
+scanning: .byte 0 ! Performing mode scan
+do_restore: .byte 0 ! Screen contents altered during mode change
+svga_prefix: .byte VIDEO_FIRST_BIOS>>8 ! Default prefix for BIOS modes
+
+!
+! Messages:
+!
+
+keymsg: .ascii "Press <RETURN> to see video modes available, "
+ .ascii "<SPACE> to continue or wait 30 secs"
+ db 0x0d, 0x0a, 0
+listhdr: db 0x0d, 0x0a
+ .ascii "Mode: COLSxROWS:"
+crlft: db 0x0d, 0x0a, 0
+prompt: db 0x0d, 0x0a
+ .ascii "Enter mode number: "
+ db 0
+unknt: .ascii "Unknown mode ID. Try again."
+ db 0
+badmdt: .ascii "You passed an undefined mode number to setup."
+ db 0x0d, 0x0a, 0
+vesaer: .ascii "Error: Scanning of VESA modes failed. Please "
+ .ascii "report to <mj@k332.feld.cvut.cz>."
+ db 0x0d, 0x0a, 0
+old_name: .ascii "CGA/MDA/HGA"
+ db 0
+ega_name: .ascii "EGA"
+ db 0
+svga_name: .ascii " "
+vga_name: .ascii "VGA"
+ db 0
+vesa_name: .ascii "VESA"
+ db 0
+name_bann: .ascii "Video adapter: "
+ db 0
+
+#endif /* CONFIG_VIDEO_SELECT */
+
+!
+! Other variables:
+!
+
+adapter: .byte 0 ! Video adapter: 0=CGA/MDA/HGA,1=EGA,2=VGA
+video_segment: .word 0xb800 ! Video memory segment
+force_size: .word 0 ! Use this size instead of the one in BIOS vars
diff --git a/arch/i386/config.in b/arch/i386/config.in
index bfbf42acb..a5b72a4d0 100644
--- a/arch/i386/config.in
+++ b/arch/i386/config.in
@@ -2,293 +2,113 @@
# For a description of the syntax of this configuration file,
# see the Configure script.
#
+mainmenu_name "Linux Kernel Configuration"
-comment 'General setup'
-
-bool 'Kernel math emulation' CONFIG_MATH_EMULATION n
-bool 'Normal floppy disk support' CONFIG_BLK_DEV_FD y
-bool 'Normal (MFM/RLL) disk and IDE disk/cdrom support' CONFIG_ST506 y
-if [ "$CONFIG_ST506" = "y" ]; then
- comment 'Please see drivers/block/README.ide for help/info on IDE drives'
- bool ' Use old disk-only driver for primary i/f' CONFIG_BLK_DEV_HD n
- if [ "$CONFIG_BLK_DEV_HD" = "y" ]; then
- bool ' Include new IDE driver for secondary i/f support' CONFIG_BLK_DEV_IDE n
- else
- bool ' Use new IDE driver for primary/secondary i/f' CONFIG_BLK_DEV_IDE y
- fi
- if [ "$CONFIG_BLK_DEV_IDE" = "y" ]; then
- bool ' Include support for IDE/ATAPI CDROMs' CONFIG_BLK_DEV_IDECD n
- fi
-fi
-
-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 'PCI bios support' CONFIG_PCI y
-if [ "$CONFIG_PCI" = "y" ]; then
- bool ' PCI bridge optimisation (experimental)' CONFIG_PCI_OPTIMIZE y
-fi
-bool 'System V IPC' CONFIG_SYSVIPC y
-bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF y
-#bool 'Use -mpentium flag for Pentium-specific optimizations' CONFIG_M586 n
-#if [ "$CONFIG_M586" = "n" ]; then
-bool 'Use -m486 flag for 486-specific optimizations' CONFIG_M486 y
-#fi
+mainmenu_option next_comment
+comment 'Code maturity level options'
+bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
+endmenu
+mainmenu_option next_comment
comment 'Loadable module support'
-bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS n
-
-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
-bool 'IP: multicasting' CONFIG_IP_MULTICAST n
-bool 'IP: firewalling' CONFIG_IP_FIREWALL n
-bool 'IP: accounting' CONFIG_IP_ACCT n
-bool 'IP: tunneling' CONFIG_NET_IPIP n
-if [ "$CONFIG_IP_FORWARD" = "y" -a "$CONFIG_IP_FIREWALL" = "y" ]; then
- bool 'IP: firewall packet logging' CONFIG_IP_FIREWALL_VERBOSE y
- bool 'IP: masquerading (ALPHA)' CONFIG_IP_MASQUERADE n
-fi
-comment '(it is safe to leave these untouched)'
-bool 'IP: PC/TCP compatibility mode' CONFIG_INET_PCTCP n
-bool 'IP: Reverse ARP' CONFIG_INET_RARP n
-bool 'IP: Assume subnets are local' CONFIG_INET_SNARL y
-bool 'IP: Disable NAGLE algorithm (normally enabled)' CONFIG_TCP_NAGLE_OFF n
-bool 'IP: Drop source routed frames' CONFIG_IP_NOSR y
-fi
-bool 'The IPX protocol' CONFIG_IPX n
-bool 'Appletalk DDP' CONFIG_ATALK n
-bool 'Amateur Radio AX.25 Level 2' CONFIG_AX25 n
-if [ "$CONFIG_AX25" = "y" ]; then
- bool 'Amateur Radio NET/ROM' CONFIG_NETROM n
-fi
+bool 'Enable loadable module support' CONFIG_MODULES
+if [ "$CONFIG_MODULES" = "y" ]; then
+ bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
+ bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD
fi
+endmenu
-comment 'SCSI support'
-
-bool 'SCSI support?' CONFIG_SCSI y
-
-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 y
-bool 'SCSI generic support' CONFIG_CHR_DEV_SG n
-
-comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs'
-
-bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN n
-
-comment 'SCSI low-level drivers'
+mainmenu_option next_comment
+comment 'General setup'
-bool 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X y
-bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 n
-bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 y
-bool 'Adaptec AHA274X/284X support' CONFIG_SCSI_AHA274X n
-bool 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC n
-bool 'EATA-DMA (DPT,NEC&ATT for ISA,EISA,PCI) support' CONFIG_SCSI_EATA_DMA 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 'Kernel math emulation' CONFIG_MATH_EMULATION
+bool 'Networking support' CONFIG_NET
+bool 'Limit memory to low 16MB' CONFIG_MAX_16M
+bool 'PCI bios support' CONFIG_PCI
if [ "$CONFIG_PCI" = "y" ]; then
- bool 'NCR53c7,8xx SCSI support' CONFIG_SCSI_NCR53C7xx n
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool ' PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
+ fi
fi
-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 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA n
-#bool 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG n
+bool 'System V IPC' CONFIG_SYSVIPC
+tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
+tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
fi
+choice 'Processor type' \
+ "386 CONFIG_M386 \
+ 486 CONFIG_M486 \
+ Pentium CONFIG_M586 \
+ PPro CONFIG_M686" Pentium
+bool 'Video mode selection support' CONFIG_VIDEO_SELECT
+endmenu
-if [ "$CONFIG_NET" = "y" ]; then
+source drivers/block/Config.in
-comment 'Network device support'
+if [ "$CONFIG_NET" = "y" ]; then
+ source net/Config.in
+fi
-bool 'Network device support?' CONFIG_NETDEVICES y
-if [ "$CONFIG_NETDEVICES" = "n" ]; then
+mainmenu_option next_comment
+comment 'SCSI support'
-comment 'Skipping network driver configuration options...'
+tristate 'SCSI support' CONFIG_SCSI
-else
-bool 'Dummy net driver support' CONFIG_DUMMY y
-bool 'SLIP (serial line) support' CONFIG_SLIP n
-if [ "$CONFIG_SLIP" = "y" ]; then
- bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED y
- bool ' 16 channels instead of 4' SL_SLIP_LOTS n
-fi
-bool 'PPP (point-to-point) support' CONFIG_PPP n
-if [ "$CONFIG_PPP" = "y" ]; then
- bool ' 16 channels instead of 4' CONFIG_PPP_LOTS n
-fi
-if [ "$CONFIG_AX25" = "y" ]; then
- bool 'Z8530 SCC kiss emulation driver for AX.25' CONFIG_SCC y
-fi
-bool 'PLIP (parallel port) support' CONFIG_PLIP n
-bool 'EQL (serial line load balancing) support' CONFIG_EQUALIZER 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 'AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE n
-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 'Arcnet support' CONFIG_ARCNET n
- bool 'Cabletron E21xx support' CONFIG_E2100 n
- bool 'DEPCA support' CONFIG_DEPCA n
- bool 'EtherWorks 3 support' CONFIG_EWRK3 n
- if [ "$CONFIG_NET_ALPHA" = "y" ]; then
- bool 'AT1700 support' CONFIG_AT1700 n
-# bool 'EtherExpressPro support' CONFIG_EEXPRESS_PRO n
- bool 'EtherExpress support' CONFIG_EEXPRESS n
- bool 'NI5210 support' CONFIG_NI52 n
- bool 'NI6510 support' CONFIG_NI65 n
- bool 'WaveLAN support' CONFIG_WAVELAN n
- fi
- bool 'HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS n
- bool 'HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN n
- bool 'NE2000/NE1000 support' CONFIG_NE2000 y
- if [ "$CONFIG_AX25" = "y" ]; then
- bool 'Ottawa PI and PI/2 support' CONFIG_PI y
- fi
- bool 'SK_G16 support' CONFIG_SK_G16 n
-fi
-bool 'EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA n
-if [ "$CONFIG_NET_EISA" = "y" ]; then
- 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 'DE425, DE434, DE435 support' CONFIG_DE4X5 n
-# bool 'DEC 21040 PCI support' CONFIG_DEC_ELCP n
-# bool 'LPL T100V 100Mbs support' CONFIG_LPL_T100 n
-# bool 'PCnet32 (32 bit VLB and PCI LANCE) support' CONFIG_PCNET32 n
- bool 'Zenith Z-Note support' CONFIG_ZNET y
-fi
-bool 'Pocket and portable adaptors' CONFIG_NET_POCKET n
-if [ "$CONFIG_NET_POCKET" = "y" ]; then
- bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP n
- bool 'D-Link DE600 pocket adaptor support' CONFIG_DE600 n
- bool 'D-Link DE620 pocket adaptor support' CONFIG_DE620 n
-# bool 'Silicom pocket adaptor support' CONFIG_SILICOM_PEA n
-# bool 'WaveLAN PCMCIA support' CONFIG_WaveLAN n
-# bool '3 Com 3c589 PCMCIA support' CONFIG_3C589 n
-fi
-bool 'Token Ring driver support' CONFIG_TR n
-if [ "$CONFIG_TR" = "y" ]; then
- bool 'IBM Tropic chipset based adaptor support' CONFIG_IBMTR y
-fi
-fi
+if [ "$CONFIG_SCSI" != "n" ]; then
+ source drivers/scsi/Config.in
fi
+endmenu
-comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
+if [ "$CONFIG_NET" = "y" ]; then
+ mainmenu_option next_comment
+ comment 'Network device support'
-bool 'Sony CDU31A/CDU33A CDROM driver support' CONFIG_CDU31A n
-bool 'Mitsumi (not IDE/ATAPI) 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
+ bool 'Network device support' CONFIG_NETDEVICES
+ if [ "$CONFIG_NETDEVICES" = "y" ]; then
+ source drivers/net/Config.in
fi
+ endmenu
fi
-bool 'Aztech/Orchid/Okano/Wearnes (non IDE) CDROM support' CONFIG_AZTCD n
-bool 'Sony CDU535 CDROM driver support' CONFIG_CDU535 n
-comment 'Filesystems'
+mainmenu_option next_comment
+comment 'ISDN subsystem'
-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
-comment 'Umsdos is not supported in 1.3.0: wait for 1.3.1'
+tristate 'ISDN support' CONFIG_ISDN
+if [ "$CONFIG_ISDN" != "n" ]; then
+ source drivers/isdn/Config.in
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" -o "$CONFIG_AZTCD" = "y" -o "$CONFIG_CDU535" = "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
+endmenu
-comment 'character devices'
+mainmenu_option next_comment
+comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
-bool 'Cyclades async mux support' CONFIG_CYCLADES n
-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
+bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI
+if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
+ source drivers/cdrom/Config.in
fi
-bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n
-bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n
-
+endmenu
-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
+source fs/Config.in
-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
+source drivers/char/Config.in
+mainmenu_option next_comment
comment 'Sound'
-bool 'Sound card support' CONFIG_SOUND n
+tristate 'Sound card support' CONFIG_SOUND
+if [ "$CONFIG_SOUND" != "n" ]; then
+ source drivers/sound/Config.in
+fi
+endmenu
+mainmenu_option next_comment
comment 'Kernel hacking'
-#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC n
-bool 'Kernel profiling support' CONFIG_PROFILE y
+#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
+bool 'Kernel profiling support' CONFIG_PROFILE
if [ "$CONFIG_PROFILE" = "y" ]; then
int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
fi
-if [ "$CONFIG_SCSI" = "y" ]; then
-bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS y
-fi
+endmenu
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
new file mode 100644
index 000000000..0e30c600a
--- /dev/null
+++ b/arch/i386/defconfig
@@ -0,0 +1,176 @@
+#
+# Automatically generated make config: don't edit
+#
+
+#
+# Code maturity level options
+#
+# CONFIG_EXPERIMENTAL is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KERNELD is not set
+
+#
+# General setup
+#
+# CONFIG_MATH_EMULATION is not set
+CONFIG_NET=y
+# CONFIG_MAX_16M is not set
+CONFIG_PCI=y
+CONFIG_SYSVIPC=y
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_M386 is not set
+# CONFIG_M486 is not set
+CONFIG_M586=y
+# CONFIG_M686 is not set
+# CONFIG_VIDEO_SELECT is not set
+
+#
+# Floppy, IDE, and other block devices
+#
+CONFIG_BLK_DEV_FD=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+CONFIG_BLK_DEV_CMD640=y
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+CONFIG_BLK_DEV_RZ1000=y
+# CONFIG_BLK_DEV_TRITON is not set
+# CONFIG_IDE_CHIPSETS is not set
+
+#
+# Additional Block Devices
+#
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# Networking options
+#
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+# CONFIG_NET_ALIAS is not set
+CONFIG_INET=y
+# CONFIG_IP_FORWARD is not set
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ACCT is not set
+
+#
+# (it is safe to leave these untouched)
+#
+# CONFIG_INET_PCTCP is not set
+# CONFIG_INET_RARP is not set
+# CONFIG_NO_PATH_MTU_DISCOVERY is not set
+CONFIG_IP_NOSR=y
+CONFIG_SKB_LARGE=y
+
+#
+#
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_AX25 is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+CONFIG_DUMMY=m
+# CONFIG_EQUALIZER is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_VENDOR_3COM=y
+# CONFIG_EL1 is not set
+# CONFIG_EL2 is not set
+CONFIG_EL3=y
+# CONFIG_VORTEX is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_EISA is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_FDDI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_NET_RADIO is not set
+# CONFIG_SLIP is not set
+# CONFIG_TR is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+CONFIG_MINIX_FS=y
+# CONFIG_EXT_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_XIA_FS is not set
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_VFAT_FS is not set
+# CONFIG_UMSDOS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_NFS_FS=y
+# CONFIG_ROOT_NFS is not set
+# CONFIG_SMB_FS is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_HPFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Character devices
+#
+CONFIG_SERIAL=y
+# CONFIG_DIGI is not set
+# CONFIG_CYCLADES is not set
+# CONFIG_STALDRV is not set
+# CONFIG_RISCOM8 is not set
+# CONFIG_PRINTER is not set
+# CONFIG_MOUSE is not set
+# CONFIG_UMISC is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_FTAPE is not set
+# CONFIG_APM is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PROFILE is not set
diff --git a/arch/i386/ibcs/Makefile b/arch/i386/ibcs/Makefile
deleted file mode 100644
index 7b81ff2bc..000000000
--- a/arch/i386/ibcs/Makefile
+++ /dev/null
@@ -1,37 +0,0 @@
-#
-# Makefile for the iBCS emulator files
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
-
-.S.s:
- $(CPP) -traditional $< -o $*.s
-.c.s:
- $(CC) $(CFLAGS) -S $<
-.s.o:
- $(AS) -c -o $*.o $<
-.c.o:
- $(CC) $(CFLAGS) -c $<
-
-SUBDIRS =
-
-OBJS = emulate.o
-
-ibcs.o: $(OBJS)
- $(LD) -r -o ibcs.o $(OBJS)
- sync
-
-dep:
- $(CPP) -M *.c > .depend
-
-dummy:
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
diff --git a/arch/i386/ibcs/binfmt_coff.c b/arch/i386/ibcs/binfmt_coff.c
deleted file mode 100644
index 1a7c760cd..000000000
--- a/arch/i386/ibcs/binfmt_coff.c
+++ /dev/null
@@ -1,784 +0,0 @@
-/*
- * These are the functions used to load COFF IBSC style executables.
- * Information on COFF format may be obtained in either the Intel Binary
- * Compatibility Specification 2 or O'Rilley's book on COFF. The shared
- * libraries are defined only the in the Intel book.
- *
- * This file is based upon code written by Eric Youngdale for the ELF object
- * file format.
- *
- * Author: Al Longyear (longyear@sii.com)
- *
- * Latest Revision:
- * 3 February 1994
- * Al Longyear (longyear@sii.com)
- * Cleared first page of bss section using put_fs_byte.
- */
-
-#include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/a.out.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/binfmts.h>
-#include <asm/segment.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/coff.h>
-#include <linux/malloc.h>
-
-asmlinkage int sys_exit (int exit_code);
-asmlinkage int sys_close (unsigned fd);
-asmlinkage int sys_open (const char *, int, int);
-asmlinkage int sys_uselib(const char * library);
-
-static int preload_library (struct linux_binprm *exe_bprm,
- COFF_SCNHDR * sect,
- struct file *fp);
-
-static int load_object (struct linux_binprm *bprm,
- struct pt_regs *regs,
- int lib_ok);
-
-/*
- * Small procedure to test for the proper file alignment.
- */
-
-static inline int
-is_properly_aligned (COFF_SCNHDR *sect)
-{
- long scnptr = COFF_LONG (sect->s_scnptr);
- long vaddr = COFF_LONG (sect->s_vaddr);
-/*
- * Print the section information if needed
- */
-
-#ifdef COFF_DEBUG
- printk ("%s, scnptr = %d, vaddr = %d\n",
- sect->s_name,
- scnptr, vaddr);
-#endif
-
-/*
- * Return the error code if the section is not properly aligned.
- */
-
-#ifdef COFF_DEBUG
- if (((vaddr - scnptr) & ~PAGE_MASK) != 0)
- printk ("bad alignment in %s\n", sect->s_name);
-#endif
- return ((((vaddr - scnptr) & ~PAGE_MASK) != 0) ? -ENOEXEC : 0);
-}
-
-/*
- * Clear the bytes in the last page of data.
- */
-
-static
-int clear_memory (unsigned long addr, unsigned long size)
-{
- int status;
-
- size = (PAGE_SIZE - (addr & ~PAGE_MASK)) & ~PAGE_MASK;
- if (size == 0)
- status = 0;
- else {
-
-#ifdef COFF_DEBUG
- printk ("un-initialized storage in last page %d\n", size);
-#endif
-
- status = verify_area (VERIFY_WRITE,
- (void *) addr, size);
-#ifdef COFF_DEBUG
- printk ("result from verify_area = %d\n", status);
-#endif
-
- if (status >= 0)
- while (size-- != 0)
- put_fs_byte (0, addr++);
- }
- return status;
-}
-
-/*
- * Helper function to process the load operation.
- */
-
-static int
-load_object (struct linux_binprm * bprm, struct pt_regs *regs, int lib_ok)
-{
- COFF_FILHDR *coff_hdr = (COFF_FILHDR *) bprm->buf; /* COFF Header */
- COFF_SCNHDR *sect_bufr; /* Pointer to section table */
- COFF_SCNHDR *text_sect; /* Pointer to the text section */
- COFF_SCNHDR *data_sect; /* Pointer to the data section */
- COFF_SCNHDR *bss_sect; /* Pointer to the bss section */
- int text_count; /* Number of text sections */
- int data_count; /* Number of data sections */
- int bss_count; /* Number of bss sections */
- int lib_count; /* Number of lib sections */
- unsigned int start_addr = 0;/* Starting location for program */
- int status = 0; /* Result status register */
- int fd = -1; /* Open file descriptor */
- struct file *fp = NULL; /* Pointer to the file at "fd" */
- short int sections = 0; /* Number of sections in the file */
- short int aout_size = 0; /* Size of the a.out header area */
- short int flags; /* Flag bits from the COFF header */
-
-#ifdef COFF_DEBUG
- printk ("binfmt_coff entry: %s\n", bprm->filename);
-#endif
-
-/*
- * Validate the magic value for the object file.
- */
- do {
- if (COFF_I386BADMAG (*coff_hdr)) {
-#ifdef COFF_DEBUG
- printk ("bad filehdr magic\n");
-#endif
- status = -ENOEXEC;
- break;
- }
-/*
- * The object file should have 32 BIT little endian format. Do not allow
- * it to have the 16 bit object file flag set as Linux is not able to run
- * on the 80286/80186/8086.
- */
- flags = COFF_SHORT (coff_hdr->f_flags);
- if ((flags & (COFF_F_AR32WR | COFF_F_AR16WR)) != COFF_F_AR32WR) {
-#ifdef COFF_DEBUG
- printk ("invalid f_flags bits\n");
-#endif
- status = -ENOEXEC;
- break;
- }
-/*
- * Extract the header information which we need.
- */
- sections = COFF_SHORT (coff_hdr->f_nscns); /* Number of sections */
- aout_size = COFF_SHORT (coff_hdr->f_opthdr); /* Size of opt. headr */
-/*
- * If the file is not executable then reject the execution. This means
- * that there must not be external references.
- */
- if ((flags & COFF_F_EXEC) == 0) {
-#ifdef COFF_DEBUG
- printk ("not executable bit\n");
-#endif
- status = -ENOEXEC;
- break;
- }
-/*
- * There must be at least one section.
- */
- if (sections == 0) {
-#ifdef COFF_DEBUG
- printk ("no sections\n");
-#endif
- status = -ENOEXEC;
- break;
- }
-/*
- * Do some additional consistency checks.
- * The system requires mapping for this loader. If you try
- * to use a file system with no mapping, the format is not valid.
- */
- if (!bprm->inode->i_op ||
- !bprm->inode->i_op->default_file_ops->mmap) {
-#ifdef COFF_DEBUG
- printk ("no mmap in fs\n");
-#endif
- status = -ENOEXEC;
- }
- }
- while (0);
-/*
- * Allocate a buffer to hold the entire coff section list.
- */
- if (status >= 0) {
- int nbytes = sections * COFF_SCNHSZ;
-
- sect_bufr = (COFF_SCNHDR *) kmalloc (nbytes, GFP_KERNEL);
- if (0 == sect_bufr) {
-#ifdef COFF_DEBUG
- printk ("kmalloc failed\n");
-#endif
- status = -ENOEXEC;
- }
-/*
- * Read the section list from the disk file.
- */
- else {
- int old_fs = get_fs ();
- set_fs (get_ds ()); /* Make it point to the proper location */
- status = read_exec (bprm->inode, /* INODE for file */
- aout_size + COFF_FILHSZ, /* Offset in the file */
- (char *) sect_bufr, /* Buffer for read */
- nbytes); /* Byte count reqd. */
- set_fs (old_fs); /* Restore the selector */
-#ifdef COFF_DEBUG
- if (status < 0)
- printk ("read aout hdr, status = %d\n", status);
-#endif
- }
- }
- else
- sect_bufr = NULL; /* Errors do not have a section buffer */
-/*
- * Count the number of sections for the required types and store the location
- * of the last section for the three primary types.
- */
- text_count = 0;
- data_count = 0;
- bss_count = 0;
- lib_count = 0;
-
- text_sect = NULL;
- data_sect = NULL;
- bss_sect = NULL;
-/*
- * Loop through the sections and find the various types
- */
- if (status >= 0) {
- int nIndex;
- COFF_SCNHDR *sect_ptr = sect_bufr;
-
- for (nIndex = 0; nIndex < sections; ++nIndex) {
- long int sect_flags = COFF_LONG (sect_ptr->s_flags);
-
- switch (sect_flags) {
- case COFF_STYP_TEXT:
- text_sect = sect_ptr;
- ++text_count;
- status = is_properly_aligned (sect_ptr);
- break;
-
- case COFF_STYP_DATA:
- data_sect = sect_ptr;
- ++data_count;
- status = is_properly_aligned (sect_ptr);
- break;
-
- case COFF_STYP_BSS:
- bss_sect = sect_ptr;
- ++bss_count;
- break;
-
- case COFF_STYP_LIB:
-#ifdef COFF_DEBUG
- printk (".lib section found\n");
-#endif
- ++lib_count;
- break;
-
- default:
- break;
- }
- sect_ptr = (COFF_SCNHDR *) & ((char *) sect_ptr)[COFF_SCNHSZ];
- }
-/*
- * Ensure that there are the required sections. There must be one text
- * sections and one each of the data and bss sections for an executable.
- * A library may or may not have a data / bss section.
- */
- if (text_count != 1) {
- status = -ENOEXEC;
-#ifdef COFF_DEBUG
- printk ("no text sections\n");
-#endif
- }
- else {
- if (lib_ok) {
- if (data_count != 1 || bss_count != 1) {
- status = -ENOEXEC;
-#ifdef COFF_DEBUG
- printk ("no .data nor .bss sections\n");
-#endif
- }
- }
- }
- }
-/*
- * If there is no additional header then assume the file starts at
- * the first byte of the text section. This may not be the proper place,
- * so the best solution is to include the optional header. A shared library
- * __MUST__ have an optional header to indicate that it is a shared library.
- */
- if (status >= 0) {
- if (aout_size == 0) {
- if (!lib_ok) {
- status = -ENOEXEC;
-#ifdef COFF_DEBUG
- printk ("no header in library\n");
-#endif
- }
- start_addr = COFF_LONG (text_sect->s_vaddr);
- }
-/*
- * There is some header. Ensure that it is sufficient.
- */
- else {
- if (aout_size < COFF_AOUTSZ) {
- status = -ENOEXEC;
-#ifdef COFF_DEBUG
- printk ("header too small\n");
-#endif
- }
- else {
- COFF_AOUTHDR *aout_hdr = /* Pointer to a.out header */
- (COFF_AOUTHDR *) & ((char *) coff_hdr)[COFF_FILHSZ];
- short int aout_magic = COFF_SHORT (aout_hdr->magic); /* id */
-/*
- * Validate the magic number in the a.out header. If it is valid then
- * update the starting symbol location. Do not accept these file formats
- * when loading a shared library.
- */
- switch (aout_magic) {
- case COFF_OMAGIC:
- case COFF_ZMAGIC:
- case COFF_STMAGIC:
- if (!lib_ok) {
- status = -ENOEXEC;
-#ifdef COFF_DEBUG
- printk ("wrong a.out header magic\n");
-#endif
- }
- start_addr = (unsigned int) COFF_LONG (aout_hdr->entry);
- break;
-/*
- * Magic value for a shared library. This is valid only when loading a
- * shared library. (There is no need for a start_addr. It won't be used.)
- */
- case COFF_SHMAGIC:
- if (lib_ok) {
-#ifdef COFF_DEBUG
- printk ("wrong a.out header magic\n");
-#endif
- status = -ENOEXEC;
- }
- break;
-
- default:
-#ifdef COFF_DEBUG
- printk ("wrong a.out header magic\n");
-#endif
- status = -ENOEXEC;
- break;
- }
- }
- }
- }
-/*
- * Fetch a file pointer to the executable.
- */
- if (status >= 0) {
- fd = open_inode (bprm->inode, O_RDONLY);
- if (fd < 0) {
-#ifdef COFF_DEBUG
- printk ("can not open inode, result = %d\n", fd);
-#endif
- status = fd;
- }
- else
- fp = current->files->fd[fd];
- }
- else
- fd = -1; /* Invalidate the open file descriptor */
-/*
- * Generate the proper values for the text fields
- *
- * THIS IS THE POINT OF NO RETURN. THE NEW PROCESS WILL TRAP OUT SHOULD
- * SOMETHING FAIL IN THE LOAD SEQUENCE FROM THIS POINT ONWARD.
- */
- if (status >= 0) {
- long text_scnptr = COFF_LONG (text_sect->s_scnptr);
- long text_size = COFF_LONG (text_sect->s_size);
- long text_vaddr = COFF_LONG (text_sect->s_vaddr);
-
- long data_scnptr;
- long data_size;
- long data_vaddr;
-
- long bss_size;
- long bss_vaddr;
-/*
- * Generate the proper values for the data fields
- */
- if (data_sect != NULL) {
- data_scnptr = COFF_LONG (data_sect->s_scnptr);
- data_size = COFF_LONG (data_sect->s_size);
- data_vaddr = COFF_LONG (data_sect->s_vaddr);
- }
- else {
- data_scnptr = 0;
- data_size = 0;
- data_vaddr = 0;
- }
-/*
- * Generate the proper values for the bss fields
- */
- if (bss_sect != NULL) {
- bss_size = COFF_LONG (bss_sect->s_size);
- bss_vaddr = COFF_LONG (bss_sect->s_vaddr);
- }
- else {
- bss_size = 0;
- bss_vaddr = 0;
- }
-/*
- * Flush the executable from memory. At this point the executable is
- * committed to being defined or a segmentation violation will occur.
- */
- if (lib_ok) {
-#ifdef COFF_DEBUG
- printk ("flushing executable\n");
-#endif
- flush_old_exec (bprm);
-/*
- * Define the initial locations for the various items in the new process
- */
- current->mm->mmap = NULL;
- current->mm->rss = 0;
-/*
- * Construct the parameter and environment string table entries.
- */
- bprm->p += change_ldt (0, bprm->page);
- bprm->p -= MAX_ARG_PAGES*PAGE_SIZE;
- bprm->p = (unsigned long) create_tables ((char *) bprm->p,
- bprm->argc,
- bprm->envc,
- 1);
-/*
- * Do the end processing once the stack has been constructed
- */
- current->mm->start_code = text_vaddr & PAGE_MASK;
- current->mm->end_code = text_vaddr + text_size;
- current->mm->end_data = data_vaddr + data_size;
- current->mm->start_brk =
- current->mm->brk = bss_vaddr + bss_size;
- current->suid =
- current->euid = bprm->e_uid;
- current->sgid =
- current->egid = bprm->e_gid;
- current->executable = bprm->inode; /* Store inode for file */
- ++bprm->inode->i_count; /* Count the open inode */
- regs->eip = start_addr; /* Current EIP register */
- regs->esp =
- current->mm->start_stack = bprm->p;
- }
-/*
- * Map the text pages
- */
-
-#ifdef COFF_DEBUG
- printk (".text: vaddr = %d, size = %d, scnptr = %d\n",
- text_vaddr,
- text_size,
- text_scnptr);
-#endif
- status = do_mmap (fp,
- text_vaddr & PAGE_MASK,
- text_size + (text_vaddr & ~PAGE_MASK),
- PROT_READ | PROT_EXEC,
- MAP_FIXED | MAP_SHARED,
- text_scnptr & PAGE_MASK);
-
- status = (status == (text_vaddr & PAGE_MASK)) ? 0 : -ENOEXEC;
-/*
- * Map the data pages
- */
- if (status >= 0 && data_size != 0) {
-#ifdef COFF_DEBUG
- printk (".data: vaddr = %d, size = %d, scnptr = %d\n",
- data_vaddr,
- data_size,
- data_scnptr);
-#endif
- status = do_mmap (fp,
- data_vaddr & PAGE_MASK,
- data_size + (data_vaddr & ~PAGE_MASK),
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE,
- data_scnptr & PAGE_MASK);
-
- status = (status == (data_vaddr & PAGE_MASK)) ? 0 : -ENOEXEC;
- }
-/*
- * Construct the bss data for the process. The bss ranges from the
- * end of the data (which may not be on a page boundary) to the end
- * of the bss section. Allocate any necessary pages for the data.
- */
- if (status >= 0 && bss_size != 0) {
-#ifdef COFF_DEBUG
- printk (".bss: vaddr = %d, size = %d\n",
- bss_vaddr,
- bss_size);
-#endif
- zeromap_page_range (PAGE_ALIGN (bss_vaddr),
- PAGE_ALIGN (bss_size),
- PAGE_COPY);
-
- status = clear_memory (bss_vaddr, bss_size);
- }
-/*
- * Load any shared library for the executable.
- */
- if (status >= 0 && lib_ok && lib_count != 0) {
- int nIndex;
- COFF_SCNHDR *sect_ptr = sect_bufr;
-/*
- * Find the library sections. (There should be at least one. It was counted
- * earlier.) This will eventually recurse to our code and load the shared
- * library with our own procedures.
- */
- for (nIndex = 0; nIndex < sections; ++nIndex) {
- long int sect_flags = COFF_LONG (sect_ptr->s_flags);
- if (sect_flags == COFF_STYP_LIB) {
- status = preload_library (bprm, sect_ptr, fp);
- if (status != 0)
- break;
- }
- sect_ptr = (COFF_SCNHDR *) &((char *) sect_ptr) [COFF_SCNHSZ];
- }
- }
-/*
- * Generate any needed trap for this process. If an error occurred then
- * generate a segmentation violation. If the process is being debugged
- * then generate the load trap. (Note: If this is a library load then
- * do not generate the trap here. Pass the error to the caller who
- * will do it for the process in the outer lay of this procedure call.)
- */
- if (lib_ok) {
- if (status < 0)
- send_sig (SIGSEGV, current, 0); /* Generate the error trap */
- else {
- if (current->flags & PF_PTRACED)
- send_sig (SIGTRAP, current, 0);
- }
- status = 0; /* We are committed. It can't fail */
- }
- }
-/*
- * Do any cleanup processing
- */
- if (fd >= 0)
- sys_close (fd); /* Close unused code file */
-
- if (sect_bufr != NULL)
- kfree (sect_bufr); /* Release section list buffer */
-/*
- * Return the completion status.
- */
-#ifdef COFF_DEBUG
- printk ("binfmt_coff: result = %d\n", status);
-#endif
- return (status);
-}
-
-/*
- * This procedure will load the library listed in the file name given
- * as the parameter. The result will be non-zero should something fail
- * to load.
- */
-
-static int
-preload_this_library (struct linux_binprm *exe_bprm, char *lib_name)
-{
- int status;
- int old_fs = get_fs();
-/*
- * If debugging then print "we have arrived"
- */
-#ifdef COFF_DEBUG
- printk ("%s loading shared library %s\n",
- exe_bprm->filename,
- lib_name);
-#endif
-/*
- * Change the FS register to the proper kernel address space and attempt
- * to load the library. The library name is allocated from the kernel
- * pool.
- */
- set_fs (get_ds ());
- status = sys_uselib (lib_name);
- set_fs (old_fs);
-/*
- * Return the success/failure to the caller.
- */
- return (status);
-}
-
-/*
- * This procedure is called to load a library section. The various
- * libraries are loaded from the list given in the section data.
- */
-
-static int
-preload_library (struct linux_binprm *exe_bprm,
- COFF_SCNHDR * sect, struct file *fp)
-{
- int status = 0; /* Completion status */
- long nbytes; /* Count of bytes in the header area */
-/*
- * Fetch the size of the section. There must be enough room for at least
- * one entry.
- */
- nbytes = COFF_LONG (sect->s_size);
- if (nbytes < COFF_SLIBSZ) {
- status = -ENOEXEC;
-#ifdef COFF_DEBUG
- printk ("library section too small\n");
-#endif
- }
-/*
- * Allocate a buffer to hold the section data
- */
- else {
- COFF_SLIBHD *phdr;
- char *buffer = (char *) kmalloc (nbytes, GFP_KERNEL);
-
- if (0 == buffer) {
- status = -ENOEXEC;
-#ifdef COFF_DEBUG
- printk ("kmalloc failed\n");
-#endif
- }
- else {
- int old_fs = get_fs ();
-/*
- * Read the section data from the disk file.
- */
- set_fs (get_ds ()); /* Make it point to the proper location */
- status = read_exec (exe_bprm->inode, /* INODE for file */
- COFF_LONG (sect->s_scnptr), /* Disk location */
- buffer, /* Buffer for read */
- nbytes); /* Byte count reqd. */
- set_fs (old_fs); /* Restore the selector */
-/*
- * Check the result. The value returned is the byte count actually read.
- */
- if (status >= 0 && status != nbytes) {
-#ifdef COFF_DEBUG
- printk ("read of lib section was short\n");
-#endif
- status = -ENOEXEC;
- }
- }
-/*
- * At this point, go through the list of libraries in the data area.
- */
- phdr = (COFF_SLIBHD *) buffer;
- while (status >= 0 && nbytes > COFF_SLIBSZ) {
- int entry_size = COFF_LONG (phdr->sl_entsz) * sizeof (long);
- int header_size = COFF_LONG (phdr->sl_pathndx) * sizeof (long);
-/*
- * Validate the sizes of the various items. I don't trust the linker!!
- */
- if ((unsigned) header_size >= (unsigned) nbytes ||
- entry_size <= 0 ||
- (unsigned) entry_size <= (unsigned) header_size) {
- status = -ENOEXEC;
-#ifdef COFF_DEBUG
- printk ("header count is invalid\n");
-#endif
- }
-/*
- * Load the library. Stop the load process on the first error.
- */
- else {
- status = preload_this_library (exe_bprm,
- &((char *) phdr)[header_size]);
-#ifdef COFF_DEBUG
- printk ("preload_this_library result = %d\n", status);
-#endif
- }
-/*
- * Point to the next library in the section data.
- */
- nbytes -= entry_size;
- phdr = (COFF_SLIBHD *) &((char *) phdr)[entry_size];
- }
-/*
- * Release the space for the library list.
- */
- if (buffer != NULL)
- kfree (buffer);
- }
-/*
- * Return the resulting status to the caller.
- */
- return (status);
-}
-
-/*
- * This procedure is called by the main load sequence. It will load
- * the executable and prepare it for execution. It provides the additional
- * parameters used by the recursive coff loader and tells the loader that
- * this is the main executable. How simple it is . . . .
- */
-
-int
-load_coff_binary (struct linux_binprm *bprm, struct pt_regs *regs)
-{
- return (load_object (bprm, regs, 1));
-}
-
-/*
- * Load the image for any shared library.
- *
- * This is called when we need to load a library based upon a file name.
- */
-
-int
-load_coff_library (int fd)
-{
- struct linux_binprm *bprm; /* Parameters for the load operation */
- int status; /* Status of the request */
-/*
- * Read the first portion of the file.
- */
- bprm = (struct linux_binprm *) kmalloc (sizeof (struct linux_binprm),
- GFP_KERNEL);
- if (0 == bprm) {
-#ifdef COFF_DEBUG
- printk ("kmalloc failed\n");
-#endif
- status = -ENOEXEC;
- }
- else {
- struct file *file; /* Pointer to the file table */
- struct pt_regs regs; /* Register work area */
- int old_fs = get_fs (); /* Previous FS register value */
-
- memset (bprm, '\0', sizeof (struct linux_binprm));
-
- file = current->files->fd[fd];
- bprm->inode = file->f_inode; /* The only item _really_ needed */
- bprm->filename = ""; /* Make it a legal string */
-/*
- * Read the section list from the disk file.
- */
- set_fs (get_ds ()); /* Make it point to the proper location */
- status = read_exec (bprm->inode, /* INODE for file */
- 0L, /* Offset in the file */
- bprm->buf, /* Buffer for read */
- sizeof (bprm->buf)); /* Size of the buffer */
- set_fs (old_fs); /* Restore the selector */
-/*
- * Try to load the library.
- */
- status = load_object (bprm, &regs, 0);
-/*
- * Release the work buffer and return the result.
- */
- kfree (bprm); /* Release the buffer area */
- }
-/*
- * Return the result of the load operation
- */
- return (status);
-}
diff --git a/arch/i386/ibcs/binfmt_elf.c b/arch/i386/ibcs/binfmt_elf.c
deleted file mode 100644
index ab6d36915..000000000
--- a/arch/i386/ibcs/binfmt_elf.c
+++ /dev/null
@@ -1,655 +0,0 @@
-/*
- * linux/fs/binfmt_elf.c
- *
- * These are the functions used to load ELF format executables as used
- * on SVr4 machines. Information on the format may be found in the book
- * "UNIX SYSTEM V RELEASE 4 Programmers Guide: Ansi C and Programming Support
- * Tools".
- *
- * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com).
- */
-#include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/a.out.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/binfmts.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/malloc.h>
-#include <linux/shm.h>
-#include <linux/personality.h>
-
-#include <asm/segment.h>
-
-asmlinkage int sys_exit(int exit_code);
-asmlinkage int sys_close(unsigned fd);
-asmlinkage int sys_open(const char *, int, int);
-asmlinkage int sys_brk(unsigned long);
-
-#define DLINFO_ITEMS 8
-
-#include <linux/elf.h>
-
-/* We need to explicitly zero any fractional pages
- after the data section (i.e. bss). This would
- contain the junk from the file that should not
- be in memory */
-
-static void padzero(int elf_bss){
- unsigned int fpnt, nbyte;
-
- if(elf_bss & 0xfff) {
-
- nbyte = (PAGE_SIZE - (elf_bss & 0xfff)) & 0xfff;
- if(nbyte){
- verify_area(VERIFY_WRITE, (void *) elf_bss, nbyte);
-
- fpnt = elf_bss;
- while(fpnt & 0xfff) put_fs_byte(0, fpnt++);
- };
- };
-}
-
-unsigned long * create_elf_tables(char * p,int argc,int envc,struct elfhdr * exec, unsigned int load_addr, int ibcs)
-{
- unsigned long *argv,*envp, *dlinfo;
- unsigned long * sp;
- struct vm_area_struct *mpnt;
-
- mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL);
- if (mpnt) {
- mpnt->vm_task = current;
- mpnt->vm_start = PAGE_MASK & (unsigned long) p;
- mpnt->vm_end = TASK_SIZE;
- mpnt->vm_page_prot = PAGE_COPY;
- mpnt->vm_flags = VM_STACK_FLAGS;
- mpnt->vm_ops = NULL;
- mpnt->vm_inode = NULL;
- mpnt->vm_offset = 0;
- mpnt->vm_pte = 0;
- insert_vm_struct(current, mpnt);
- }
- sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
- if(exec) sp -= DLINFO_ITEMS*2;
- dlinfo = sp;
- sp -= envc+1;
- envp = sp;
- sp -= argc+1;
- argv = sp;
- if (!ibcs) {
- put_fs_long((unsigned long)envp,--sp);
- put_fs_long((unsigned long)argv,--sp);
- }
-
- /* The constant numbers (0-9) that we are writing here are
- described in the header file sys/auxv.h on at least
- some versions of SVr4 */
- if(exec) { /* Put this here for an ELF program interpreter */
- struct elf_phdr * eppnt;
- eppnt = (struct elf_phdr *) exec->e_phoff;
- put_fs_long(3,dlinfo++); put_fs_long(load_addr + exec->e_phoff,dlinfo++);
- put_fs_long(4,dlinfo++); put_fs_long(sizeof(struct elf_phdr),dlinfo++);
- put_fs_long(5,dlinfo++); put_fs_long(exec->e_phnum,dlinfo++);
- put_fs_long(9,dlinfo++); put_fs_long((unsigned long) exec->e_entry,dlinfo++);
- put_fs_long(7,dlinfo++); put_fs_long(SHM_RANGE_START,dlinfo++);
- put_fs_long(8,dlinfo++); put_fs_long(0,dlinfo++);
- put_fs_long(6,dlinfo++); put_fs_long(PAGE_SIZE,dlinfo++);
- put_fs_long(0,dlinfo++); put_fs_long(0,dlinfo++);
- };
-
- put_fs_long((unsigned long)argc,--sp);
- current->mm->arg_start = (unsigned long) p;
- while (argc-->0) {
- put_fs_long((unsigned long) p,argv++);
- while (get_fs_byte(p++)) /* nothing */ ;
- }
- put_fs_long(0,argv);
- current->mm->arg_end = current->mm->env_start = (unsigned long) p;
- while (envc-->0) {
- put_fs_long((unsigned long) p,envp++);
- while (get_fs_byte(p++)) /* nothing */ ;
- }
- put_fs_long(0,envp);
- current->mm->env_end = (unsigned long) p;
- return sp;
-}
-
-
-/* This is much more generalized than the library routine read function,
- so we keep this separate. Technically the library read function
- is only provided so that we can read a.out libraries that have
- an ELF header */
-
-static unsigned int load_elf_interp(struct elfhdr * interp_elf_ex,
- struct inode * interpreter_inode)
-{
- struct file * file;
- struct elf_phdr *elf_phdata = NULL;
- struct elf_phdr *eppnt;
- unsigned int len;
- unsigned int load_addr;
- int elf_exec_fileno;
- int elf_bss;
- int old_fs, retval;
- unsigned int last_bss;
- int error;
- int i, k;
-
- elf_bss = 0;
- last_bss = 0;
- error = load_addr = 0;
-
- /* First of all, some simple consistency checks */
- if((interp_elf_ex->e_type != ET_EXEC &&
- interp_elf_ex->e_type != ET_DYN) ||
- (interp_elf_ex->e_machine != EM_386 && interp_elf_ex->e_machine != EM_486) ||
- (!interpreter_inode->i_op ||
- !interpreter_inode->i_op->default_file_ops->mmap)){
- return 0xffffffff;
- };
-
- /* Now read in all of the header information */
-
- if(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE)
- return 0xffffffff;
-
- elf_phdata = (struct elf_phdr *)
- kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, GFP_KERNEL);
- if(!elf_phdata) return 0xffffffff;
-
- old_fs = get_fs();
- set_fs(get_ds());
- retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff, (char *) elf_phdata,
- sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
- set_fs(old_fs);
-
- elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY);
- if (elf_exec_fileno < 0) return 0xffffffff;
- file = current->files->fd[elf_exec_fileno];
-
- eppnt = elf_phdata;
- for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
- if(eppnt->p_type == PT_LOAD) {
- error = do_mmap(file,
- eppnt->p_vaddr & 0xfffff000,
- eppnt->p_filesz + (eppnt->p_vaddr & 0xfff),
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE | (interp_elf_ex->e_type == ET_EXEC ? MAP_FIXED : 0),
- eppnt->p_offset & 0xfffff000);
-
- if(!load_addr && interp_elf_ex->e_type == ET_DYN)
- load_addr = error;
- k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
- if(k > elf_bss) elf_bss = k;
- if(error < 0 && error > -1024) break; /* Real error */
- k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
- if(k > last_bss) last_bss = k;
- }
-
- /* Now use mmap to map the library into memory. */
-
-
- sys_close(elf_exec_fileno);
- if(error < 0 && error > -1024) {
- kfree(elf_phdata);
- return 0xffffffff;
- }
-
- padzero(elf_bss);
- len = (elf_bss + 0xfff) & 0xfffff000; /* What we have mapped so far */
-
- /* Map the last of the bss segment */
- if (last_bss > len)
- do_mmap(NULL, len, last_bss-len,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE, 0);
- kfree(elf_phdata);
-
- return ((unsigned int) interp_elf_ex->e_entry) + load_addr;
-}
-
-static unsigned int load_aout_interp(struct exec * interp_ex,
- struct inode * interpreter_inode)
-{
- int retval;
- unsigned int elf_entry;
-
- current->mm->brk = interp_ex->a_bss +
- (current->mm->end_data = interp_ex->a_data +
- (current->mm->end_code = interp_ex->a_text));
- elf_entry = interp_ex->a_entry;
-
-
- if (N_MAGIC(*interp_ex) == OMAGIC) {
- do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE, 0);
- retval = read_exec(interpreter_inode, 32, (char *) 0,
- interp_ex->a_text+interp_ex->a_data);
- } else if (N_MAGIC(*interp_ex) == ZMAGIC || N_MAGIC(*interp_ex) == QMAGIC) {
- do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE, 0);
- retval = read_exec(interpreter_inode,
- N_TXTOFF(*interp_ex) ,
- (char *) N_TXTADDR(*interp_ex),
- interp_ex->a_text+interp_ex->a_data);
- } else
- retval = -1;
-
- if(retval >= 0)
- do_mmap(NULL, (interp_ex->a_text + interp_ex->a_data + 0xfff) &
- 0xfffff000, interp_ex->a_bss,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE, 0);
- if(retval < 0) return 0xffffffff;
- return elf_entry;
-}
-
-/*
- * These are the functions used to load ELF style executables and shared
- * libraries. There is no binary dependent code anywhere else.
- */
-
-#define INTERPRETER_NONE 0
-#define INTERPRETER_AOUT 1
-#define INTERPRETER_ELF 2
-
-static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
-{
- struct elfhdr elf_ex;
- struct elfhdr interp_elf_ex;
- struct file * file;
- struct exec interp_ex;
- struct inode *interpreter_inode;
- unsigned int load_addr;
- unsigned int interpreter_type = INTERPRETER_NONE;
- int i;
- int old_fs;
- int error;
- struct elf_phdr * elf_ppnt, *elf_phdata;
- int elf_exec_fileno;
- unsigned int elf_bss, k, elf_brk;
- int retval;
- char * elf_interpreter;
- unsigned int elf_entry;
- int status;
- unsigned int start_code, end_code, end_data;
- unsigned int elf_stack;
- char passed_fileno[6];
-
- status = 0;
- load_addr = 0;
- elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
-
- if (elf_ex.e_ident[0] != 0x7f ||
- strncmp(&elf_ex.e_ident[1], "ELF",3) != 0)
- return -ENOEXEC;
-
-
- /* First of all, some simple consistency checks */
- if(elf_ex.e_type != ET_EXEC ||
- (elf_ex.e_machine != EM_386 && elf_ex.e_machine != EM_486) ||
- (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
- !bprm->inode->i_op->default_file_ops->mmap)){
- return -ENOEXEC;
- };
-
- /* Now read in all of the header information */
-
- elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize *
- elf_ex.e_phnum, GFP_KERNEL);
-
- old_fs = get_fs();
- set_fs(get_ds());
- retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata,
- elf_ex.e_phentsize * elf_ex.e_phnum);
- set_fs(old_fs);
- if (retval < 0) {
- kfree (elf_phdata);
- return retval;
- }
-
- elf_ppnt = elf_phdata;
-
- elf_bss = 0;
- elf_brk = 0;
-
- elf_exec_fileno = open_inode(bprm->inode, O_RDONLY);
-
- if (elf_exec_fileno < 0) {
- kfree (elf_phdata);
- return elf_exec_fileno;
- }
-
- file = current->files->fd[elf_exec_fileno];
-
- elf_stack = 0xffffffff;
- elf_interpreter = NULL;
- start_code = 0;
- end_code = 0;
- end_data = 0;
-
- old_fs = get_fs();
- set_fs(get_ds());
-
- for(i=0;i < elf_ex.e_phnum; i++){
- if(elf_ppnt->p_type == PT_INTERP) {
- /* This is the program interpreter used for shared libraries -
- for now assume that this is an a.out format binary */
-
- elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz,
- GFP_KERNEL);
-
- retval = read_exec(bprm->inode,elf_ppnt->p_offset,elf_interpreter,
- elf_ppnt->p_filesz);
-#if 0
- printk("Using ELF interpreter %s\n", elf_interpreter);
-#endif
- if(retval >= 0)
- retval = namei(elf_interpreter, &interpreter_inode);
- if(retval >= 0)
- retval = read_exec(interpreter_inode,0,bprm->buf,128);
-
- if(retval >= 0){
- interp_ex = *((struct exec *) bprm->buf); /* exec-header */
- interp_elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
-
- };
- if(retval < 0) {
- kfree (elf_phdata);
- kfree(elf_interpreter);
- return retval;
- };
- };
- elf_ppnt++;
- };
-
- set_fs(old_fs);
-
- /* Some simple consistency checks for the interpreter */
- if(elf_interpreter){
- interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
- if(retval < 0) {
- kfree(elf_interpreter);
- kfree(elf_phdata);
- return -ELIBACC;
- };
- /* Now figure out which format our binary is */
- if((N_MAGIC(interp_ex) != OMAGIC) &&
- (N_MAGIC(interp_ex) != ZMAGIC) &&
- (N_MAGIC(interp_ex) != QMAGIC))
- interpreter_type = INTERPRETER_ELF;
-
- if (interp_elf_ex.e_ident[0] != 0x7f ||
- strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0)
- interpreter_type &= ~INTERPRETER_ELF;
-
- if(!interpreter_type)
- {
- kfree(elf_interpreter);
- kfree(elf_phdata);
- return -ELIBBAD;
- };
- }
-
- /* OK, we are done with that, now set up the arg stuff,
- and then start this sucker up */
-
- if (!bprm->sh_bang) {
- char * passed_p;
-
- if(interpreter_type == INTERPRETER_AOUT) {
- sprintf(passed_fileno, "%d", elf_exec_fileno);
- passed_p = passed_fileno;
-
- if(elf_interpreter) {
- bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2);
- bprm->argc++;
- };
- };
- if (!bprm->p) {
- if(elf_interpreter) {
- kfree(elf_interpreter);
- }
- kfree (elf_phdata);
- return -E2BIG;
- }
- }
-
- /* OK, This is the point of no return */
- flush_old_exec(bprm);
-
- current->mm->end_data = 0;
- current->mm->end_code = 0;
- current->mm->start_mmap = ELF_START_MMAP;
- current->mm->mmap = NULL;
- elf_entry = (unsigned int) elf_ex.e_entry;
-
- /* Do this so that we can load the interpreter, if need be. We will
- change some of these later */
- current->mm->rss = 0;
- bprm->p += change_ldt(0, bprm->page);
- current->mm->start_stack = bprm->p;
-
- /* Now we do a little grungy work by mmaping the ELF image into
- the correct location in memory. At this point, we assume that
- the image should be loaded at fixed address, not at a variable
- address. */
-
- old_fs = get_fs();
- set_fs(get_ds());
-
- elf_ppnt = elf_phdata;
- for(i=0;i < elf_ex.e_phnum; i++){
-
- if(elf_ppnt->p_type == PT_INTERP) {
- /* Set these up so that we are able to load the interpreter */
- /* Now load the interpreter into user address space */
- set_fs(old_fs);
-
- if(interpreter_type & 1) elf_entry =
- load_aout_interp(&interp_ex, interpreter_inode);
-
- if(interpreter_type & 2) elf_entry =
- load_elf_interp(&interp_elf_ex, interpreter_inode);
-
- old_fs = get_fs();
- set_fs(get_ds());
-
- iput(interpreter_inode);
- kfree(elf_interpreter);
-
- if(elf_entry == 0xffffffff) {
- printk("Unable to load interpreter\n");
- kfree(elf_phdata);
- send_sig(SIGSEGV, current, 0);
- return 0;
- };
- };
-
-
- if(elf_ppnt->p_type == PT_LOAD) {
- error = do_mmap(file,
- elf_ppnt->p_vaddr & 0xfffff000,
- elf_ppnt->p_filesz + (elf_ppnt->p_vaddr & 0xfff),
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE,
- elf_ppnt->p_offset & 0xfffff000);
-
-#ifdef LOW_ELF_STACK
- if(elf_ppnt->p_vaddr & 0xfffff000 < elf_stack)
- elf_stack = elf_ppnt->p_vaddr & 0xfffff000;
-#endif
-
- if(!load_addr)
- load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
- k = elf_ppnt->p_vaddr;
- if(k > start_code) start_code = k;
- k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
- if(k > elf_bss) elf_bss = k;
- if((elf_ppnt->p_flags | PROT_WRITE) && end_code < k)
- end_code = k;
- if(end_data < k) end_data = k;
- k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
- if(k > elf_brk) elf_brk = k;
- };
- elf_ppnt++;
- };
- set_fs(old_fs);
-
- kfree(elf_phdata);
-
- if(interpreter_type != INTERPRETER_AOUT) sys_close(elf_exec_fileno);
-
- /* The following 3 lines need a little bit of work if we are loading
- an iBCS2 binary. We should initially load it this way, and if
- we get a lcall7, then we should look to see if the iBCS2 execution
- profile is present. If it is, then switch to that, otherwise
- bomb. */
- current->personality = PER_LINUX;
- current->lcall7 = no_lcall7;
- current->signal_map = current->signal_invmap = ident_map;
-
- current->executable = bprm->inode;
- bprm->inode->i_count++;
-#ifdef LOW_ELF_STACK
- current->start_stack = p = elf_stack - 4;
-#endif
- bprm->p -= MAX_ARG_PAGES*PAGE_SIZE;
- bprm->p = (unsigned long)
- create_elf_tables((char *)bprm->p,
- bprm->argc,
- bprm->envc,
- (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
- load_addr,
- (interpreter_type == INTERPRETER_AOUT ? 0 : 1));
- if(interpreter_type == INTERPRETER_AOUT)
- current->mm->arg_start += strlen(passed_fileno) + 1;
- current->mm->start_brk = current->mm->brk = elf_brk;
- current->mm->end_code = end_code;
- current->mm->start_code = start_code;
- current->mm->end_data = end_data;
- current->mm->start_stack = bprm->p;
- current->suid = current->euid = bprm->e_uid;
- current->sgid = current->egid = bprm->e_gid;
-
- /* Calling sys_brk effectively mmaps the pages that we need for the bss and break
- sections */
- current->mm->brk = (elf_bss + 0xfff) & 0xfffff000;
- sys_brk((elf_brk + 0xfff) & 0xfffff000);
-
- padzero(elf_bss);
-
- /* Why this, you ask??? Well SVr4 maps page 0 as read-only,
- and some applications "depend" upon this behavior.
- Since we do not have the power to recompile these, we
- emulate the SVr4 behavior. Sigh. */
- error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE, 0);
-
- regs->eip = elf_entry; /* eip, magic happens :-) */
- regs->esp = bprm->p; /* stack pointer */
- if (current->flags & PF_PTRACED)
- send_sig(SIGTRAP, current, 0);
- return 0;
-}
-
-/* This is really simpleminded and specialized - we are loading an
- a.out library that is given an ELF header. */
-
-static int load_elf_library(int fd){
- struct file * file;
- struct elfhdr elf_ex;
- struct elf_phdr *elf_phdata = NULL;
- struct inode * inode;
- unsigned int len;
- int elf_bss;
- int old_fs, retval;
- unsigned int bss;
- int error;
- int i,j, k;
-
- len = 0;
- file = current->files->fd[fd];
- inode = file->f_inode;
- elf_bss = 0;
-
- set_fs(KERNEL_DS);
- if (file->f_op->read(inode, file, (char *) &elf_ex, sizeof(elf_ex)) != sizeof(elf_ex)) {
- sys_close(fd);
- return -EACCES;
- }
- set_fs(USER_DS);
-
- if (elf_ex.e_ident[0] != 0x7f ||
- strncmp(&elf_ex.e_ident[1], "ELF",3) != 0)
- return -ENOEXEC;
-
- /* First of all, some simple consistency checks */
- if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
- (elf_ex.e_machine != EM_386 && elf_ex.e_machine != EM_486) ||
- (!inode->i_op ||
- !inode->i_op->default_file_ops->mmap)){
- return -ENOEXEC;
- };
-
- /* Now read in all of the header information */
-
- if(sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE)
- return -ENOEXEC;
-
- elf_phdata = (struct elf_phdr *)
- kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL);
-
- old_fs = get_fs();
- set_fs(get_ds());
- retval = read_exec(inode, elf_ex.e_phoff, (char *) elf_phdata,
- sizeof(struct elf_phdr) * elf_ex.e_phnum);
- set_fs(old_fs);
-
- j = 0;
- for(i=0; i<elf_ex.e_phnum; i++)
- if((elf_phdata + i)->p_type == PT_LOAD) j++;
-
- if(j != 1) {
- kfree(elf_phdata);
- return -ENOEXEC;
- };
-
- while(elf_phdata->p_type != PT_LOAD) elf_phdata++;
-
- /* Now use mmap to map the library into memory. */
- error = do_mmap(file,
- elf_phdata->p_vaddr & 0xfffff000,
- elf_phdata->p_filesz + (elf_phdata->p_vaddr & 0xfff),
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE,
- elf_phdata->p_offset & 0xfffff000);
-
- k = elf_phdata->p_vaddr + elf_phdata->p_filesz;
- if(k > elf_bss) elf_bss = k;
-
- sys_close(fd);
- if (error != elf_phdata->p_vaddr & 0xfffff000) {
- kfree(elf_phdata);
- return error;
- }
-
- padzero(elf_bss);
-
- len = (elf_phdata->p_filesz + elf_phdata->p_vaddr+ 0xfff) & 0xfffff000;
- bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
- if (bss > len)
- do_mmap(NULL, len, bss-len,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE, 0);
- kfree(elf_phdata);
- return 0;
-}
-
-struct linux_binfmt elf_format = { NULL, load_elf_binary, load_elf_library };
diff --git a/arch/i386/ibcs/emulate.c b/arch/i386/ibcs/emulate.c
deleted file mode 100644
index dc3b3d576..000000000
--- a/arch/i386/ibcs/emulate.c
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * linux/abi/emulate.c
- *
- * Copyright (C) 1993 Linus Torvalds
- */
-
-/*
- * Yes, sir, this file is completely empty, waiting for some real code..
- * I still copyright it, silly me.
- */
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
index 701926d26..123dd1207 100644
--- a/arch/i386/kernel/Makefile
+++ b/arch/i386/kernel/Makefile
@@ -7,42 +7,61 @@
#
# Note 2! The CFLAGS definitions are now in the main makefile...
-.c.s:
- $(CC) $(CFLAGS) -S $<
-.s.o:
- $(AS) -o $*.o $<
-.c.o:
- $(CC) $(CFLAGS) -c $<
-.S.s:
- $(CPP) -D__ASSEMBLY__ -traditional $< -o $*.s
+#.S.s:
+# $(CPP) -D__ASSEMBLY__ -traditional $< -o $*.s
+
+ifdef SMP
+.S.o:
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+else
.S.o:
$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
-
-OBJS = process.o signal.o entry.o traps.o irq.o vm86.o bios32.o ptrace.o ioport.o ldt.o setup.o
+endif
all: kernel.o head.o
-head.o: head.s
+O_TARGET := kernel.o
+O_OBJS := process.o signal.o entry.o traps.o irq.o vm86.o bios32.o \
+ ptrace.o ioport.o ldt.o setup.o time.o sys_i386.o ksyms.o
-head.s: head.S $(TOPDIR)/include/linux/tasks.h
- $(CPP) -traditional -o $*.s $<
+ifdef SMP
-kernel.o: $(OBJS)
- $(LD) -r -o kernel.o $(OBJS)
- sync
+O_OBJS += smp.o
-dep:
- $(CPP) -M *.c > .depend
+head.o: head.S $(TOPDIR)/include/linux/tasks.h
+ $(CC) -D__ASSEMBLY__ -D__SMP__ -traditional -c $*.S -o $*.o
-modules:
+else
-dummy:
+head.o: head.S $(TOPDIR)/include/linux/tasks.h
+ $(CC) -D__ASSEMBLY__ -traditional -c $*.S -o $*.o
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
endif
+hexify:
+ $(HOSTCC) hexify.c -o hexify
+
+smp.c: trampoline.hex
+
+trampoline.hex: trampoline hexify
+ (dd if=trampoline bs=1 skip=32 | ./hexify >trampoline.hex )
+
+trampoline: trampoline.o trampoline32.o
+ $(LD86) -s -o $@ trampoline.o trampoline32.o
+
+trampoline.o: trampoline.s
+ $(AS86) -o $@ $<
+
+trampoline32.o: trampoline32.s
+ $(AS386) -o $@ $<
+
+trampoline.s: trampoline.S $(CONFIGURE) $(TOPDIR)/include/linux/config.h Makefile
+ $(CPP) -D__SMP__ -traditional $< -o $@
+
+trampoline32.s: trampoline32.S $(CONFIGURE) $(TOPDIR)/include/linux/config.h Makefile
+ $(CPP) -D__SMP__ -traditional $< -o $@
+
+clean:
+ rm -f trampoline hexify
+include $(TOPDIR)/Rules.make
diff --git a/arch/i386/kernel/bios32.c b/arch/i386/kernel/bios32.c
index 8cc3d76fa..a1b49a3ae 100644
--- a/arch/i386/kernel/bios32.c
+++ b/arch/i386/kernel/bios32.c
@@ -55,6 +55,7 @@
#include <linux/bios32.h>
#include <linux/pci.h>
+#include <asm/page.h>
#include <asm/segment.h>
#define PCIBIOS_PCI_FUNCTION_ID 0xb1XX
@@ -164,7 +165,7 @@ extern unsigned long check_pcibios(unsigned long memory_start, unsigned long mem
int pack;
if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
- pci_indirect.address = pcibios_entry;
+ pci_indirect.address = pcibios_entry | PAGE_OFFSET;
__asm__("lcall (%%edi)\n\t"
"jc 1f\n\t"
@@ -363,7 +364,7 @@ int pcibios_write_config_dword (unsigned char bus,
return (int) (ret & 0xff00) >> 8;
}
-char *pcibios_strerror (int error)
+const char *pcibios_strerror (int error)
{
static char buf[80];
@@ -383,6 +384,12 @@ char *pcibios_strerror (int error)
case PCIBIOS_BAD_REGISTER_NUMBER:
return "BAD_REGISTER_NUMBER";
+ case PCIBIOS_SET_FAILED:
+ return "SET_FAILED";
+
+ case PCIBIOS_BUFFER_TOO_SMALL:
+ return "BUFFER_TOO_SMALL";
+
default:
sprintf (buf, "UNKNOWN RETURN 0x%x", error);
return buf;
@@ -411,7 +418,9 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
*
*/
- for (check = (union bios32 *) 0xe0000; check <= (union bios32 *) 0xffff0; ++check) {
+ for (check = (union bios32 *) __va(0xe0000);
+ check <= (union bios32 *) __va(0xffff0);
+ ++check) {
if (check->fields.signature != BIOS32_SIGNATURE)
continue;
length = check->fields.length * 16;
@@ -432,17 +441,10 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
if (check->fields.entry >= 0x100000) {
printk("pcibios_init: entry in high memory, unable to access\n");
} else {
- bios32_indirect.address = bios32_entry = check->fields.entry;
+ bios32_entry = check->fields.entry;
printk ("pcibios_init : BIOS32 Service Directory entry at 0x%lx\n", bios32_entry);
+ bios32_indirect.address = bios32_entry + PAGE_OFFSET;
}
- } else {
- printk ("pcibios_init : multiple entries, mail drew@colorado.edu\n");
- /*
- * Jeremy Fitzhardinge reports at least one PCI BIOS
- * with two different service directories, and as both
- * worked for him, we'll just mention the fact, and
- * not actually disallow it..
- */
}
}
#ifdef CONFIG_PCI
@@ -452,6 +454,3 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
#endif
return memory_start;
}
-
-
-
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
index 1bdf062c8..d421f45f1 100644
--- a/arch/i386/kernel/entry.S
+++ b/arch/i386/kernel/entry.S
@@ -30,18 +30,21 @@
* 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
+ * 24(%esp) - orig_eax
+ * 28(%esp) - %eip
+ * 2C(%esp) - %cs
+ * 30(%esp) - %eflags
+ * 34(%esp) - %oldesp
+ * 38(%esp) - %oldss
+ *
+ * "current" is in register %ebx during any slow entries.
*/
#include <linux/sys.h>
+#include <linux/linkage.h>
#include <asm/segment.h>
+#define ASSEMBLY
+#include <asm/smp.h>
EBX = 0x00
ECX = 0x04
@@ -52,14 +55,12 @@ 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
+ORIG_EAX = 0x24
+EIP = 0x28
+CS = 0x2C
+EFLAGS = 0x30
+OLDESP = 0x34
+OLDSS = 0x38
CF_MASK = 0x00000001
IF_MASK = 0x00000200
@@ -75,26 +76,14 @@ 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; \
@@ -106,17 +95,123 @@ ENOSYS = 38
pushl %ebx; \
movl $(KERNEL_DS),%edx; \
mov %dx,%ds; \
- mov %dx,%es; \
- movl $(USER_DS),%edx; \
- mov %dx,%fs;
+ mov %dx,%es;
+
+#ifdef __SMP__
+
+#define GET_PROCESSOR_ID \
+ movl SYMBOL_NAME(apic_reg), %edx; \
+ movl 32(%edx), %eax;\
+ movl %eax,SYMBOL_NAME(apic_retval); \
+ shrl $24,%eax; \
+ andb $0x0F,%al;
+
+/*
+ * Get the processor ID multiplied by 4
+ */
+
+#define GET_PROCESSOR_OFFSET(x) \
+ movl SYMBOL_NAME(apic_reg), x ; \
+ movl 32( x ), x ; \
+ shrl $22, x ; \
+ andl $0x3C, x ;
+
+/* macro LEAVE_KERNEL decrements kernel_counter and resets kernel_flag and
+ saves processor variables if zero */
+#define LEAVE_KERNEL \
+ pushfl; \
+ cli; \
+ GET_PROCESSOR_ID \
+ btrl $ SMP_FROM_SYSCALL,SYMBOL_NAME(smp_proc_in_lock)(,%eax,4); \
+ decl SYMBOL_NAME(syscall_count); \
+ decl SYMBOL_NAME(kernel_counter); \
+ jnz 1f; \
+ movb $(NO_PROC_ID), SYMBOL_NAME(active_kernel_processor); \
+ lock; \
+ btrl $0, SYMBOL_NAME(kernel_flag); \
+1: popfl;
+
+/* macro ENTER_KERNEL waits for entering the kernel, increments
+ kernel_counter, and reloads the processor variables if necessary
+ uses : %eax, %edx (pushed and popped)
+
+ Note: We go to great pains to minimise the number of locked operations.
+ We want to spin without locking, and lock when we attempt an update.
+ The pentium has a MESI cache so the spin without lock will exit when
+ another CPU write invalidates our cache, and the lock is avoided when
+ possible so we don't play ping-pong games with the cache line.
+
+*/
+
+#ifndef __SMP_PROF__
+
+#define SMP_PROF_A
+#define SMP_PROF_B
+
+#else
+
+#define SMP_PROF_A movl $0,SYMBOL_NAME(smp_spins_syscall_cur)(,%eax,4);
+#define SMP_PROF_B incl SYMBOL_NAME(smp_spins_syscall)(,%eax,4); \
+ incl SYMBOL_NAME(smp_spins_syscall_cur)(,%eax,4);
+#endif
+
+#define ENTER_KERNEL \
+ pushl %eax; \
+ pushl %edx; \
+ pushfl; \
+ cli; \
+ GET_PROCESSOR_ID \
+ btsl $ SMP_FROM_SYSCALL,SYMBOL_NAME(smp_proc_in_lock)(,%eax,4); \
+ SMP_PROF_A \
+1: lock; \
+ btsl $0, SYMBOL_NAME(kernel_flag); \
+ jnc 3f; \
+ cmpb SYMBOL_NAME(active_kernel_processor), %al; \
+ je 4f; \
+2: SMP_PROF_B \
+ btl %al, SYMBOL_NAME(smp_invalidate_needed); \
+ jnc 5f; \
+ lock; \
+ btrl %al, SYMBOL_NAME(smp_invalidate_needed); \
+ jnc 5f; \
+ movl %cr3,%edx; \
+ movl %edx,%cr3; \
+5: btl $0, SYMBOL_NAME(kernel_flag); \
+ jc 2b; \
+ jmp 1b; \
+3: movb %al, SYMBOL_NAME(active_kernel_processor); \
+4: incl SYMBOL_NAME(kernel_counter); \
+ incl SYMBOL_NAME(syscall_count); \
+ popfl; \
+ popl %edx; \
+ popl %eax;
+
+
+#define RESTORE_ALL \
+ LEAVE_KERNEL \
+ popl %ebx; \
+ popl %ecx; \
+ popl %edx; \
+ popl %esi; \
+ popl %edi; \
+ popl %ebp; \
+ popl %eax; \
+ pop %ds; \
+ pop %es; \
+ addl $4,%esp; \
+ iret
+
+#define GET_CURRENT \
+ GET_PROCESSOR_OFFSET(%ebx) \
+ movl SYMBOL_NAME(current_set)(%ebx),%ebx
+
+#else
+
+#define GET_CURRENT \
+ movl SYMBOL_NAME(current_set),%ebx
#define RESTORE_ALL \
- cmpw $(KERNEL_CS),CS(%esp); \
- je 1f; \
- movl _current,%eax; \
- movl dbgreg7(%eax),%ebx; \
- movl %ebx,%db7; \
-1: popl %ebx; \
+ popl %ebx; \
popl %ecx; \
popl %edx; \
popl %esi; \
@@ -125,16 +220,19 @@ ENOSYS = 38
popl %eax; \
pop %ds; \
pop %es; \
- pop %fs; \
- pop %gs; \
addl $4,%esp; \
iret
+#endif
+
-.align 4
-_lcall7:
+ENTRY(lcall7)
pushfl # We get a different stack layout with call gates,
pushl %eax # which has to be cleaned up later..
SAVE_ALL
+ GET_CURRENT
+#ifdef __SMP__
+ ENTER_KERNEL
+#endif
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..
@@ -142,7 +240,12 @@ _lcall7:
movl %edx,EIP(%esp) # Now we move them to their "normal" places
movl %ecx,CS(%esp) #
movl %esp,%eax
- movl _current,%edx
+#ifdef __SMP__
+ GET_PROCESSOR_OFFSET(%edx) # Processor offset into edx
+ movl SYMBOL_NAME(current_set)(,%edx),%edx
+#else
+ movl SYMBOL_NAME(current_set),%edx
+#endif
pushl %eax
movl exec_domain(%edx),%edx # Get the execution domain
movl 4(%edx),%edx # Get the lcall7 handler for the domain
@@ -150,398 +253,378 @@ _lcall7:
popl %eax
jmp ret_from_sys_call
-.align 4
+ ALIGN
handle_bottom_half:
- pushfl
- incl _intr_count
- sti
- call _do_bottom_half
- popfl
- decl _intr_count
+ incl SYMBOL_NAME(intr_count)
+ call SYMBOL_NAME(do_bottom_half)
+ decl SYMBOL_NAME(intr_count)
jmp 9f
-.align 4
+ ALIGN
reschedule:
pushl $ret_from_sys_call
- jmp _schedule
-.align 4
-_system_call:
+ jmp SYMBOL_NAME(schedule) # test
+
+ENTRY(system_call)
pushl %eax # save orig_eax
SAVE_ALL
- movl $-ENOSYS,EAX(%esp)
+ GET_CURRENT
+#ifdef __SMP__
+ ENTER_KERNEL
+#endif
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
+ jae badsys
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)
+ jne tracesys
+ call SYMBOL_NAME(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
+ ALIGN
+ .globl ret_from_sys_call
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
+ cmpl $0,SYMBOL_NAME(intr_count)
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
+9: movl SYMBOL_NAME(bh_mask),%eax
+ andl SYMBOL_NAME(bh_active),%eax
+ jne handle_bottom_half
+ movl EFLAGS(%esp),%eax # mix EFLAGS and CS
+ movb CS(%esp),%al
+ testl $(VM_MASK | 3),%eax # return to VM86 mode or non-supervisor?
+ je 1f
+ cmpl $0,SYMBOL_NAME(need_resched)
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
+ movl blocked(%ebx),%eax
+ movl %eax,%esi # save blocked in %esi for signal handling
+ notl %eax
+ andl signal(%ebx),%eax
jne signal_return
-2: RESTORE_ALL
-.align 4
+1: RESTORE_ALL
+ ALIGN
signal_return:
- movl %esp,%ecx
- pushl %ecx
- testl $(VM_MASK),EFLAGS(%ecx)
+ testl $(VM_MASK),EFLAGS(%esp)
+ pushl %esp
jne v86_signal_return
- pushl %ebx
- call _do_signal
- popl %ebx
- popl %ebx
+ pushl %esi
+ call SYMBOL_NAME(do_signal)
+ addl $8,%esp
RESTORE_ALL
-.align 4
+ ALIGN
v86_signal_return:
- call _save_v86_state
+ call SYMBOL_NAME(save_v86_state)
movl %eax,%esp
pushl %eax
- pushl %ebx
- call _do_signal
- popl %ebx
- popl %ebx
+ pushl %esi
+ call SYMBOL_NAME(do_signal)
+ addl $8,%esp
RESTORE_ALL
+ ALIGN
+tracesys:
+ movl $-ENOSYS,EAX(%esp)
+ call SYMBOL_NAME(syscall_trace)
+ movl ORIG_EAX(%esp),%eax
+ call SYMBOL_NAME(sys_call_table)(,%eax,4)
+ movl %eax,EAX(%esp) # save the return value
+ call SYMBOL_NAME(syscall_trace)
+ jmp ret_from_sys_call
+badsys:
+ movl $-ENOSYS,EAX(%esp)
+ jmp ret_from_sys_call
-.align 4
-_divide_error:
+
+ENTRY(divide_error)
pushl $0 # no error code
- pushl $_do_divide_error
-.align 4,0x90
+ pushl $ SYMBOL_NAME(do_divide_error)
+ ALIGN
error_code:
- push %fs
- push %es
push %ds
pushl %eax
+ xorl %eax,%eax
pushl %ebp
pushl %edi
pushl %esi
pushl %edx
+ decl %eax # eax = -1
pushl %ecx
pushl %ebx
- movl $0,%eax
- movl %eax,%db7 # disable hardware debugging...
+ xorl %ecx,%ecx # zero ecx
cld
- movl $-1, %eax
+ mov %es,%cx # get the lower order bits of es
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.
+ movl %esp,%edx
+ xchgl %ecx, ES(%esp) # get the address and save es.
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
+ GET_CURRENT
+#ifdef __SMP__
+ ENTER_KERNEL
+#endif
+ call *%ecx
addl $8,%esp
jmp ret_from_sys_call
-.align 4
-_coprocessor_error:
+ENTRY(coprocessor_error)
pushl $0
- pushl $_do_coprocessor_error
+ pushl $ SYMBOL_NAME(do_coprocessor_error)
jmp error_code
-.align 4
-_device_not_available:
+ENTRY(device_not_available)
pushl $-1 # mark this as an int
SAVE_ALL
+ GET_CURRENT
+#ifdef __SMP__
+ ENTER_KERNEL
+#endif
pushl $ret_from_sys_call
movl %cr0,%eax
testl $0x4,%eax # EM (math emulation bit)
- je _math_state_restore
+ je SYMBOL_NAME(math_state_restore)
pushl $0 # temporary storage for ORIG_EIP
- call _math_emulate
+ call SYMBOL_NAME(math_emulate)
addl $4,%esp
ret
-.align 4
-_debug:
+ENTRY(debug)
pushl $0
- pushl $_do_debug
+ pushl $ SYMBOL_NAME(do_debug)
jmp error_code
-.align 4
-_nmi:
+ENTRY(nmi)
pushl $0
- pushl $_do_nmi
+ pushl $ SYMBOL_NAME(do_nmi)
jmp error_code
-.align 4
-_int3:
+ENTRY(int3)
pushl $0
- pushl $_do_int3
+ pushl $ SYMBOL_NAME(do_int3)
jmp error_code
-.align 4
-_overflow:
+ENTRY(overflow)
pushl $0
- pushl $_do_overflow
+ pushl $ SYMBOL_NAME(do_overflow)
jmp error_code
-.align 4
-_bounds:
+ENTRY(bounds)
pushl $0
- pushl $_do_bounds
+ pushl $ SYMBOL_NAME(do_bounds)
jmp error_code
-.align 4
-_invalid_op:
+ENTRY(invalid_op)
pushl $0
- pushl $_do_invalid_op
+ pushl $ SYMBOL_NAME(do_invalid_op)
jmp error_code
-.align 4
-_coprocessor_segment_overrun:
+ENTRY(coprocessor_segment_overrun)
pushl $0
- pushl $_do_coprocessor_segment_overrun
+ pushl $ SYMBOL_NAME(do_coprocessor_segment_overrun)
jmp error_code
-.align 4
-_reserved:
+ENTRY(reserved)
pushl $0
- pushl $_do_reserved
+ pushl $ SYMBOL_NAME(do_reserved)
+ jmp error_code
+
+ENTRY(double_fault)
+ pushl $ SYMBOL_NAME(do_double_fault)
jmp error_code
-.align 4
-_double_fault:
- pushl $_do_double_fault
+ENTRY(invalid_TSS)
+ pushl $ SYMBOL_NAME(do_invalid_TSS)
jmp error_code
-.align 4
-_invalid_TSS:
- pushl $_do_invalid_TSS
+ENTRY(segment_not_present)
+ pushl $ SYMBOL_NAME(do_segment_not_present)
jmp error_code
-.align 4
-_segment_not_present:
- pushl $_do_segment_not_present
+ENTRY(stack_segment)
+ pushl $ SYMBOL_NAME(do_stack_segment)
jmp error_code
-.align 4
-_stack_segment:
- pushl $_do_stack_segment
+ENTRY(general_protection)
+ pushl $ SYMBOL_NAME(do_general_protection)
jmp error_code
-.align 4
-_general_protection:
- pushl $_do_general_protection
+ENTRY(alignment_check)
+ pushl $ SYMBOL_NAME(do_alignment_check)
jmp error_code
-.align 4
-_alignment_check:
- pushl $_do_alignment_check
+ENTRY(page_fault)
+ pushl $ SYMBOL_NAME(do_page_fault)
jmp error_code
-.align 4
-_page_fault:
- pushl $_do_page_fault
+ENTRY(spurious_interrupt_bug)
+ pushl $0
+ pushl $ SYMBOL_NAME(do_spurious_interrupt_bug)
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 _old_select
- .long _sys_symlink
- .long _sys_lstat
- .long _sys_readlink /* 85 */
- .long _sys_uselib
- .long _sys_swapon
- .long _sys_reboot
- .long _old_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 */
- .long _sys_getdents
- .long _sys_select
- .long _sys_flock
- .space (NR_syscalls-140)*4
+ENTRY(sys_call_table)
+ .long SYMBOL_NAME(sys_setup) /* 0 */
+ .long SYMBOL_NAME(sys_exit)
+ .long SYMBOL_NAME(sys_fork)
+ .long SYMBOL_NAME(sys_read)
+ .long SYMBOL_NAME(sys_write)
+ .long SYMBOL_NAME(sys_open) /* 5 */
+ .long SYMBOL_NAME(sys_close)
+ .long SYMBOL_NAME(sys_waitpid)
+ .long SYMBOL_NAME(sys_creat)
+ .long SYMBOL_NAME(sys_link)
+ .long SYMBOL_NAME(sys_unlink) /* 10 */
+ .long SYMBOL_NAME(sys_execve)
+ .long SYMBOL_NAME(sys_chdir)
+ .long SYMBOL_NAME(sys_time)
+ .long SYMBOL_NAME(sys_mknod)
+ .long SYMBOL_NAME(sys_chmod) /* 15 */
+ .long SYMBOL_NAME(sys_chown)
+ .long SYMBOL_NAME(sys_break)
+ .long SYMBOL_NAME(sys_stat)
+ .long SYMBOL_NAME(sys_lseek)
+ .long SYMBOL_NAME(sys_getpid) /* 20 */
+ .long SYMBOL_NAME(sys_mount)
+ .long SYMBOL_NAME(sys_umount)
+ .long SYMBOL_NAME(sys_setuid)
+ .long SYMBOL_NAME(sys_getuid)
+ .long SYMBOL_NAME(sys_stime) /* 25 */
+ .long SYMBOL_NAME(sys_ptrace)
+ .long SYMBOL_NAME(sys_alarm)
+ .long SYMBOL_NAME(sys_fstat)
+ .long SYMBOL_NAME(sys_pause)
+ .long SYMBOL_NAME(sys_utime) /* 30 */
+ .long SYMBOL_NAME(sys_stty)
+ .long SYMBOL_NAME(sys_gtty)
+ .long SYMBOL_NAME(sys_access)
+ .long SYMBOL_NAME(sys_nice)
+ .long SYMBOL_NAME(sys_ftime) /* 35 */
+ .long SYMBOL_NAME(sys_sync)
+ .long SYMBOL_NAME(sys_kill)
+ .long SYMBOL_NAME(sys_rename)
+ .long SYMBOL_NAME(sys_mkdir)
+ .long SYMBOL_NAME(sys_rmdir) /* 40 */
+ .long SYMBOL_NAME(sys_dup)
+ .long SYMBOL_NAME(sys_pipe)
+ .long SYMBOL_NAME(sys_times)
+ .long SYMBOL_NAME(sys_prof)
+ .long SYMBOL_NAME(sys_brk) /* 45 */
+ .long SYMBOL_NAME(sys_setgid)
+ .long SYMBOL_NAME(sys_getgid)
+ .long SYMBOL_NAME(sys_signal)
+ .long SYMBOL_NAME(sys_geteuid)
+ .long SYMBOL_NAME(sys_getegid) /* 50 */
+ .long SYMBOL_NAME(sys_acct)
+ .long SYMBOL_NAME(sys_phys)
+ .long SYMBOL_NAME(sys_lock)
+ .long SYMBOL_NAME(sys_ioctl)
+ .long SYMBOL_NAME(sys_fcntl) /* 55 */
+ .long SYMBOL_NAME(sys_mpx)
+ .long SYMBOL_NAME(sys_setpgid)
+ .long SYMBOL_NAME(sys_ulimit)
+ .long SYMBOL_NAME(sys_olduname)
+ .long SYMBOL_NAME(sys_umask) /* 60 */
+ .long SYMBOL_NAME(sys_chroot)
+ .long SYMBOL_NAME(sys_ustat)
+ .long SYMBOL_NAME(sys_dup2)
+ .long SYMBOL_NAME(sys_getppid)
+ .long SYMBOL_NAME(sys_getpgrp) /* 65 */
+ .long SYMBOL_NAME(sys_setsid)
+ .long SYMBOL_NAME(sys_sigaction)
+ .long SYMBOL_NAME(sys_sgetmask)
+ .long SYMBOL_NAME(sys_ssetmask)
+ .long SYMBOL_NAME(sys_setreuid) /* 70 */
+ .long SYMBOL_NAME(sys_setregid)
+ .long SYMBOL_NAME(sys_sigsuspend)
+ .long SYMBOL_NAME(sys_sigpending)
+ .long SYMBOL_NAME(sys_sethostname)
+ .long SYMBOL_NAME(sys_setrlimit) /* 75 */
+ .long SYMBOL_NAME(sys_getrlimit)
+ .long SYMBOL_NAME(sys_getrusage)
+ .long SYMBOL_NAME(sys_gettimeofday)
+ .long SYMBOL_NAME(sys_settimeofday)
+ .long SYMBOL_NAME(sys_getgroups) /* 80 */
+ .long SYMBOL_NAME(sys_setgroups)
+ .long SYMBOL_NAME(old_select)
+ .long SYMBOL_NAME(sys_symlink)
+ .long SYMBOL_NAME(sys_lstat)
+ .long SYMBOL_NAME(sys_readlink) /* 85 */
+ .long SYMBOL_NAME(sys_uselib)
+ .long SYMBOL_NAME(sys_swapon)
+ .long SYMBOL_NAME(sys_reboot)
+ .long SYMBOL_NAME(old_readdir)
+ .long SYMBOL_NAME(old_mmap) /* 90 */
+ .long SYMBOL_NAME(sys_munmap)
+ .long SYMBOL_NAME(sys_truncate)
+ .long SYMBOL_NAME(sys_ftruncate)
+ .long SYMBOL_NAME(sys_fchmod)
+ .long SYMBOL_NAME(sys_fchown) /* 95 */
+ .long SYMBOL_NAME(sys_getpriority)
+ .long SYMBOL_NAME(sys_setpriority)
+ .long SYMBOL_NAME(sys_profil)
+ .long SYMBOL_NAME(sys_statfs)
+ .long SYMBOL_NAME(sys_fstatfs) /* 100 */
+ .long SYMBOL_NAME(sys_ioperm)
+ .long SYMBOL_NAME(sys_socketcall)
+ .long SYMBOL_NAME(sys_syslog)
+ .long SYMBOL_NAME(sys_setitimer)
+ .long SYMBOL_NAME(sys_getitimer) /* 105 */
+ .long SYMBOL_NAME(sys_newstat)
+ .long SYMBOL_NAME(sys_newlstat)
+ .long SYMBOL_NAME(sys_newfstat)
+ .long SYMBOL_NAME(sys_uname)
+ .long SYMBOL_NAME(sys_iopl) /* 110 */
+ .long SYMBOL_NAME(sys_vhangup)
+ .long SYMBOL_NAME(sys_idle)
+ .long SYMBOL_NAME(sys_vm86)
+ .long SYMBOL_NAME(sys_wait4)
+ .long SYMBOL_NAME(sys_swapoff) /* 115 */
+ .long SYMBOL_NAME(sys_sysinfo)
+ .long SYMBOL_NAME(sys_ipc)
+ .long SYMBOL_NAME(sys_fsync)
+ .long SYMBOL_NAME(sys_sigreturn)
+ .long SYMBOL_NAME(sys_clone) /* 120 */
+ .long SYMBOL_NAME(sys_setdomainname)
+ .long SYMBOL_NAME(sys_newuname)
+ .long SYMBOL_NAME(sys_modify_ldt)
+ .long SYMBOL_NAME(sys_adjtimex)
+ .long SYMBOL_NAME(sys_mprotect) /* 125 */
+ .long SYMBOL_NAME(sys_sigprocmask)
+ .long SYMBOL_NAME(sys_create_module)
+ .long SYMBOL_NAME(sys_init_module)
+ .long SYMBOL_NAME(sys_delete_module)
+ .long SYMBOL_NAME(sys_get_kernel_syms) /* 130 */
+ .long SYMBOL_NAME(sys_quotactl)
+ .long SYMBOL_NAME(sys_getpgid)
+ .long SYMBOL_NAME(sys_fchdir)
+ .long SYMBOL_NAME(sys_bdflush)
+ .long SYMBOL_NAME(sys_sysfs) /* 135 */
+ .long SYMBOL_NAME(sys_personality)
+ .long SYMBOL_NAME(sys_ni_syscall) /* for afs_syscall */
+ .long SYMBOL_NAME(sys_setfsuid)
+ .long SYMBOL_NAME(sys_setfsgid)
+ .long SYMBOL_NAME(sys_llseek) /* 140 */
+ .long SYMBOL_NAME(sys_getdents)
+ .long SYMBOL_NAME(sys_select)
+ .long SYMBOL_NAME(sys_flock)
+ .long SYMBOL_NAME(sys_msync)
+ .long SYMBOL_NAME(sys_readv) /* 145 */
+ .long SYMBOL_NAME(sys_writev)
+ .long SYMBOL_NAME(sys_getsid)
+ .long SYMBOL_NAME(sys_fdatasync)
+ .long SYMBOL_NAME(sys_sysctl)
+ .long SYMBOL_NAME(sys_mlock) /* 150 */
+ .long SYMBOL_NAME(sys_munlock)
+ .long SYMBOL_NAME(sys_mlockall)
+ .long SYMBOL_NAME(sys_munlockall)
+ .long SYMBOL_NAME(sys_sched_setparam)
+ .long SYMBOL_NAME(sys_sched_getparam) /* 155 */
+ .long SYMBOL_NAME(sys_sched_setscheduler)
+ .long SYMBOL_NAME(sys_sched_getscheduler)
+ .long SYMBOL_NAME(sys_sched_yield)
+ .long SYMBOL_NAME(sys_sched_get_priority_max)
+ .long SYMBOL_NAME(sys_sched_get_priority_min) /* 160 */
+ .long SYMBOL_NAME(sys_sched_rr_get_interval)
+ .long SYMBOL_NAME(sys_nanosleep)
+ .long SYMBOL_NAME(sys_mremap)
+ .long SYMBOL_NAME(sys_setresuid)
+ .long SYMBOL_NAME(sys_getresuid)
+ .rept NR_syscalls-165
+ .long SYMBOL_NAME(sys_ni_syscall)
+ .endr
diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
index a3e0df213..fdf38c818 100644
--- a/arch/i386/kernel/head.S
+++ b/arch/i386/kernel/head.S
@@ -9,17 +9,10 @@
*/
.text
-.globl _idt,_gdt,_stext,__stext
-.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 <linux/linkage.h>
#include <asm/segment.h>
+#include <linux/config.h>
#define CL_MAGIC_ADDR 0x90020
#define CL_MAGIC 0xA33F
@@ -27,25 +20,56 @@
#define CL_OFFSET 0x90022
/*
- * swapper_pg_dir is the main page directory, address 0x00001000 (or at
- * address 0x00101000 for a compressed boot).
+ * swapper_pg_dir is the main page directory, address 0x00101000
*/
-_stext:
-__stext:
+ENTRY(stext)
+ENTRY(_stext)
startup_32:
+/*
+ * Set segments to known values
+ */
cld
movl $(KERNEL_DS),%eax
mov %ax,%ds
mov %ax,%es
mov %ax,%fs
mov %ax,%gs
+/*
+ * Setup paging (the tables are already set up, just switch them on)
+ */
+ movl $0x101000,%eax
+ movl %eax,%cr3 /* set the page table pointer.. */
+ movl %cr0,%eax
+ orl $0x80000000,%eax
+ movl %eax,%cr0 /* ..and set paging (PG) bit */
+ jmp 1f /* flush the prefetch-queue */
+1:
+ movl $1f,%eax
+ jmp *%eax /* make sure eip is relocated */
+1:
+
+#ifdef __SMP__
+ orw %bx,%bx
+ jz 1f /* Initial CPU cleans BSS */
+/*
+ * Set up the stack
+ */
+ mov %ax,%ss
+ xorl %eax,%eax
+ movw %cx, %ax
+ movl %eax,%esp
+ pushl $0
+ popfl
+ jmp checkCPUtype
+1:
lss stack_start,%esp
+#endif __SMP__
/*
* Clear BSS first so that there are no surprises...
*/
xorl %eax,%eax
- movl $__edata,%edi
- movl $__end,%ecx
+ movl $ SYMBOL_NAME(_edata),%edi
+ movl $ SYMBOL_NAME(_end),%ecx
subl %edi,%ecx
cld
rep
@@ -73,7 +97,7 @@ startup_32:
* is for the command line.
*/
movl $0x90000,%esi
- movl $_empty_zero_page,%edi
+ movl $ SYMBOL_NAME(empty_zero_page),%edi
movl $512,%ecx
cld
rep
@@ -84,20 +108,24 @@ startup_32:
stosl
cmpw $(CL_MAGIC),CL_MAGIC_ADDR
jne 1f
- movl $_empty_zero_page+2048,%edi
+ movl $ SYMBOL_NAME(empty_zero_page)+2048,%edi
movzwl CL_OFFSET,%esi
addl $(CL_BASE_ADDR),%esi
movl $2048,%ecx
rep
movsb
1:
+#ifdef __SMP__
+checkCPUtype:
+#endif
+
/* 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 $3,_x86
+ movl $3, SYMBOL_NAME(x86)
pushfl # push EFLAGS
popl %eax # get EFLAGS
movl %eax,%ecx # save original EFLAGS
@@ -109,7 +137,7 @@ startup_32:
xorl %ecx,%eax # change in flags
andl $0x40000,%eax # check if AC bit changed
je is386
- movl $4,_x86
+ movl $4,SYMBOL_NAME(x86)
movl %ecx,%eax
xorl $0x200000,%eax # check ID flag
pushl %eax
@@ -121,24 +149,25 @@ startup_32:
je is486
isnew: pushl %ecx # restore original EFLAGS
popfl
+ incl SYMBOL_NAME(have_cpuid) # we have CPUID
/* get processor type */
movl $1, %eax # Use the CPUID instruction to
.byte 0x0f, 0xa2 # check the processor type
movb %al, %cl # save reg for future use
andb $0x0f,%ah # mask processor family
- movb %ah, _x86
+ movb %ah,SYMBOL_NAME(x86)
andb $0xf0, %eax # mask model
shrb $4, %al
- movb %al, _x86_model
+ movb %al,SYMBOL_NAME(x86_model)
andb $0x0f, %cl # mask mask revision
- movb %cl, _x86_mask
- movl %edx, _x86_capability
+ movb %cl,SYMBOL_NAME(x86_mask)
+ movl %edx,SYMBOL_NAME(x86_capability)
/* get vendor info */
xorl %eax, %eax # call CPUID with 0 -> return vendor ID
.byte 0x0f, 0xa2 # CPUID
- movl %ebx, _x86_vendor_id # lo 4 chars
- movl %edx, _x86_vendor_id+4 # next 4 chars
- movl %ecx, _x86_vendor_id+8 # last 4 chars
+ movl %ebx,SYMBOL_NAME(x86_vendor_id) # lo 4 chars
+ movl %edx,SYMBOL_NAME(x86_vendor_id)+4 # next 4 chars
+ movl %ecx,SYMBOL_NAME(x86_vendor_id)+8 # last 4 chars
movl %cr0,%eax # 486+
andl $0x80000011,%eax # Save PG,PE,ET
@@ -157,7 +186,26 @@ is386: pushl %ecx # restore original EFLAGS
orl $2,%eax # set MP
2: movl %eax,%cr0
call check_x87
- call setup_paging
+#ifdef __SMP__
+ movb ready,%eax
+ orb %eax,%eax
+ jz 3f
+#ifdef GAS_KNOWS_CR4
+ movl %cr4,%eax
+ orl $16,%eax
+ movl %eax,%cr4
+#else
+ .byte 0x0f,0x20,0xe0
+ orl $16,%eax
+ .byte 0x0f,0x22,0xe0
+#endif
+ jmp 4f
+#endif
+3:
+#ifdef __SMP__
+ incb ready
+#endif
+4:
lgdt gdt_descr
lidt idt_descr
ljmp $(KERNEL_CS),$1f
@@ -166,23 +214,32 @@ is386: pushl %ecx # restore original EFLAGS
mov %ax,%es
mov %ax,%fs
mov %ax,%gs
- lss stack_start,%esp
+#ifdef __SMP__
+ movl $(KERNEL_DS), %eax
+ mov %ax,%ss # Reload the stack pointer (segment only)
+#else
+ lss stack_start,%esp # Load processor stack
+#endif
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
+ call SYMBOL_NAME(start_kernel)
L6:
jmp L6 # main should never return here, but
# just in case, we know what happens.
+#ifdef __SMP__
+ready: .byte 0
+#endif
+
/*
* We depend on ET to be correct. This checks for 287/387.
*/
check_x87:
- movb $0,_hard_math
+ movb $0,SYMBOL_NAME(hard_math)
clts
fninit
fstsw %ax
@@ -192,8 +249,8 @@ check_x87:
xorl $4,%eax /* set EM */
movl %eax,%cr0
ret
-.align 2
-1: movb $1,_hard_math
+ ALIGN
+1: movb $1,SYMBOL_NAME(hard_math)
.byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */
ret
@@ -213,7 +270,7 @@ setup_idt:
movw %dx,%ax /* selector = 0x0010 = cs */
movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
- lea _idt,%edi
+ lea SYMBOL_NAME(idt),%edi
mov $256,%ecx
rp_sidt:
movl %eax,(%edi)
@@ -225,86 +282,179 @@ rp_sidt:
/*
- * 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,
+ * caught. Thus the swapper page directory has been moved to 0x101000
* 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.....
+ *
+ * This is initialized to create a identity-mapping at 0-4M (for bootup
+ * purposes) and another mapping of the 0-4M area at virtual address
+ * 0xC0000000.
*/
.org 0x1000
-_swapper_pg_dir:
+ENTRY(swapper_pg_dir)
+ .long 0x00102007
+ .fill 767,4,0
+ .long 0x00102007
+ .fill 127,4,0
+
/*
* The page tables are initialized to only 4MB here - the final page
- * tables are set up later depending on memory size.
+ * tables are set up later depending on memory size. The "007" at the
+ * end doesn't mean with right to kill, but PRESENT+RW+USER
*/
.org 0x2000
-_pg0:
+ENTRY(pg0)
+ .long 0x000007,0x001007,0x002007,0x003007,0x004007,0x005007,0x006007,0x007007
+ .long 0x008007,0x009007,0x00a007,0x00b007,0x00c007,0x00d007,0x00e007,0x00f007
+ .long 0x010007,0x011007,0x012007,0x013007,0x014007,0x015007,0x016007,0x017007
+ .long 0x018007,0x019007,0x01a007,0x01b007,0x01c007,0x01d007,0x01e007,0x01f007
+ .long 0x020007,0x021007,0x022007,0x023007,0x024007,0x025007,0x026007,0x027007
+ .long 0x028007,0x029007,0x02a007,0x02b007,0x02c007,0x02d007,0x02e007,0x02f007
+ .long 0x030007,0x031007,0x032007,0x033007,0x034007,0x035007,0x036007,0x037007
+ .long 0x038007,0x039007,0x03a007,0x03b007,0x03c007,0x03d007,0x03e007,0x03f007
+ .long 0x040007,0x041007,0x042007,0x043007,0x044007,0x045007,0x046007,0x047007
+ .long 0x048007,0x049007,0x04a007,0x04b007,0x04c007,0x04d007,0x04e007,0x04f007
+ .long 0x050007,0x051007,0x052007,0x053007,0x054007,0x055007,0x056007,0x057007
+ .long 0x058007,0x059007,0x05a007,0x05b007,0x05c007,0x05d007,0x05e007,0x05f007
+ .long 0x060007,0x061007,0x062007,0x063007,0x064007,0x065007,0x066007,0x067007
+ .long 0x068007,0x069007,0x06a007,0x06b007,0x06c007,0x06d007,0x06e007,0x06f007
+ .long 0x070007,0x071007,0x072007,0x073007,0x074007,0x075007,0x076007,0x077007
+ .long 0x078007,0x079007,0x07a007,0x07b007,0x07c007,0x07d007,0x07e007,0x07f007
+ .long 0x080007,0x081007,0x082007,0x083007,0x084007,0x085007,0x086007,0x087007
+ .long 0x088007,0x089007,0x08a007,0x08b007,0x08c007,0x08d007,0x08e007,0x08f007
+ .long 0x090007,0x091007,0x092007,0x093007,0x094007,0x095007,0x096007,0x097007
+ .long 0x098007,0x099007,0x09a007,0x09b007,0x09c007,0x09d007,0x09e007,0x09f007
+ .long 0x0a0007,0x0a1007,0x0a2007,0x0a3007,0x0a4007,0x0a5007,0x0a6007,0x0a7007
+ .long 0x0a8007,0x0a9007,0x0aa007,0x0ab007,0x0ac007,0x0ad007,0x0ae007,0x0af007
+ .long 0x0b0007,0x0b1007,0x0b2007,0x0b3007,0x0b4007,0x0b5007,0x0b6007,0x0b7007
+ .long 0x0b8007,0x0b9007,0x0ba007,0x0bb007,0x0bc007,0x0bd007,0x0be007,0x0bf007
+ .long 0x0c0007,0x0c1007,0x0c2007,0x0c3007,0x0c4007,0x0c5007,0x0c6007,0x0c7007
+ .long 0x0c8007,0x0c9007,0x0ca007,0x0cb007,0x0cc007,0x0cd007,0x0ce007,0x0cf007
+ .long 0x0d0007,0x0d1007,0x0d2007,0x0d3007,0x0d4007,0x0d5007,0x0d6007,0x0d7007
+ .long 0x0d8007,0x0d9007,0x0da007,0x0db007,0x0dc007,0x0dd007,0x0de007,0x0df007
+ .long 0x0e0007,0x0e1007,0x0e2007,0x0e3007,0x0e4007,0x0e5007,0x0e6007,0x0e7007
+ .long 0x0e8007,0x0e9007,0x0ea007,0x0eb007,0x0ec007,0x0ed007,0x0ee007,0x0ef007
+ .long 0x0f0007,0x0f1007,0x0f2007,0x0f3007,0x0f4007,0x0f5007,0x0f6007,0x0f7007
+ .long 0x0f8007,0x0f9007,0x0fa007,0x0fb007,0x0fc007,0x0fd007,0x0fe007,0x0ff007
+ .long 0x100007,0x101007,0x102007,0x103007,0x104007,0x105007,0x106007,0x107007
+ .long 0x108007,0x109007,0x10a007,0x10b007,0x10c007,0x10d007,0x10e007,0x10f007
+ .long 0x110007,0x111007,0x112007,0x113007,0x114007,0x115007,0x116007,0x117007
+ .long 0x118007,0x119007,0x11a007,0x11b007,0x11c007,0x11d007,0x11e007,0x11f007
+ .long 0x120007,0x121007,0x122007,0x123007,0x124007,0x125007,0x126007,0x127007
+ .long 0x128007,0x129007,0x12a007,0x12b007,0x12c007,0x12d007,0x12e007,0x12f007
+ .long 0x130007,0x131007,0x132007,0x133007,0x134007,0x135007,0x136007,0x137007
+ .long 0x138007,0x139007,0x13a007,0x13b007,0x13c007,0x13d007,0x13e007,0x13f007
+ .long 0x140007,0x141007,0x142007,0x143007,0x144007,0x145007,0x146007,0x147007
+ .long 0x148007,0x149007,0x14a007,0x14b007,0x14c007,0x14d007,0x14e007,0x14f007
+ .long 0x150007,0x151007,0x152007,0x153007,0x154007,0x155007,0x156007,0x157007
+ .long 0x158007,0x159007,0x15a007,0x15b007,0x15c007,0x15d007,0x15e007,0x15f007
+ .long 0x160007,0x161007,0x162007,0x163007,0x164007,0x165007,0x166007,0x167007
+ .long 0x168007,0x169007,0x16a007,0x16b007,0x16c007,0x16d007,0x16e007,0x16f007
+ .long 0x170007,0x171007,0x172007,0x173007,0x174007,0x175007,0x176007,0x177007
+ .long 0x178007,0x179007,0x17a007,0x17b007,0x17c007,0x17d007,0x17e007,0x17f007
+ .long 0x180007,0x181007,0x182007,0x183007,0x184007,0x185007,0x186007,0x187007
+ .long 0x188007,0x189007,0x18a007,0x18b007,0x18c007,0x18d007,0x18e007,0x18f007
+ .long 0x190007,0x191007,0x192007,0x193007,0x194007,0x195007,0x196007,0x197007
+ .long 0x198007,0x199007,0x19a007,0x19b007,0x19c007,0x19d007,0x19e007,0x19f007
+ .long 0x1a0007,0x1a1007,0x1a2007,0x1a3007,0x1a4007,0x1a5007,0x1a6007,0x1a7007
+ .long 0x1a8007,0x1a9007,0x1aa007,0x1ab007,0x1ac007,0x1ad007,0x1ae007,0x1af007
+ .long 0x1b0007,0x1b1007,0x1b2007,0x1b3007,0x1b4007,0x1b5007,0x1b6007,0x1b7007
+ .long 0x1b8007,0x1b9007,0x1ba007,0x1bb007,0x1bc007,0x1bd007,0x1be007,0x1bf007
+ .long 0x1c0007,0x1c1007,0x1c2007,0x1c3007,0x1c4007,0x1c5007,0x1c6007,0x1c7007
+ .long 0x1c8007,0x1c9007,0x1ca007,0x1cb007,0x1cc007,0x1cd007,0x1ce007,0x1cf007
+ .long 0x1d0007,0x1d1007,0x1d2007,0x1d3007,0x1d4007,0x1d5007,0x1d6007,0x1d7007
+ .long 0x1d8007,0x1d9007,0x1da007,0x1db007,0x1dc007,0x1dd007,0x1de007,0x1df007
+ .long 0x1e0007,0x1e1007,0x1e2007,0x1e3007,0x1e4007,0x1e5007,0x1e6007,0x1e7007
+ .long 0x1e8007,0x1e9007,0x1ea007,0x1eb007,0x1ec007,0x1ed007,0x1ee007,0x1ef007
+ .long 0x1f0007,0x1f1007,0x1f2007,0x1f3007,0x1f4007,0x1f5007,0x1f6007,0x1f7007
+ .long 0x1f8007,0x1f9007,0x1fa007,0x1fb007,0x1fc007,0x1fd007,0x1fe007,0x1ff007
+ .long 0x200007,0x201007,0x202007,0x203007,0x204007,0x205007,0x206007,0x207007
+ .long 0x208007,0x209007,0x20a007,0x20b007,0x20c007,0x20d007,0x20e007,0x20f007
+ .long 0x210007,0x211007,0x212007,0x213007,0x214007,0x215007,0x216007,0x217007
+ .long 0x218007,0x219007,0x21a007,0x21b007,0x21c007,0x21d007,0x21e007,0x21f007
+ .long 0x220007,0x221007,0x222007,0x223007,0x224007,0x225007,0x226007,0x227007
+ .long 0x228007,0x229007,0x22a007,0x22b007,0x22c007,0x22d007,0x22e007,0x22f007
+ .long 0x230007,0x231007,0x232007,0x233007,0x234007,0x235007,0x236007,0x237007
+ .long 0x238007,0x239007,0x23a007,0x23b007,0x23c007,0x23d007,0x23e007,0x23f007
+ .long 0x240007,0x241007,0x242007,0x243007,0x244007,0x245007,0x246007,0x247007
+ .long 0x248007,0x249007,0x24a007,0x24b007,0x24c007,0x24d007,0x24e007,0x24f007
+ .long 0x250007,0x251007,0x252007,0x253007,0x254007,0x255007,0x256007,0x257007
+ .long 0x258007,0x259007,0x25a007,0x25b007,0x25c007,0x25d007,0x25e007,0x25f007
+ .long 0x260007,0x261007,0x262007,0x263007,0x264007,0x265007,0x266007,0x267007
+ .long 0x268007,0x269007,0x26a007,0x26b007,0x26c007,0x26d007,0x26e007,0x26f007
+ .long 0x270007,0x271007,0x272007,0x273007,0x274007,0x275007,0x276007,0x277007
+ .long 0x278007,0x279007,0x27a007,0x27b007,0x27c007,0x27d007,0x27e007,0x27f007
+ .long 0x280007,0x281007,0x282007,0x283007,0x284007,0x285007,0x286007,0x287007
+ .long 0x288007,0x289007,0x28a007,0x28b007,0x28c007,0x28d007,0x28e007,0x28f007
+ .long 0x290007,0x291007,0x292007,0x293007,0x294007,0x295007,0x296007,0x297007
+ .long 0x298007,0x299007,0x29a007,0x29b007,0x29c007,0x29d007,0x29e007,0x29f007
+ .long 0x2a0007,0x2a1007,0x2a2007,0x2a3007,0x2a4007,0x2a5007,0x2a6007,0x2a7007
+ .long 0x2a8007,0x2a9007,0x2aa007,0x2ab007,0x2ac007,0x2ad007,0x2ae007,0x2af007
+ .long 0x2b0007,0x2b1007,0x2b2007,0x2b3007,0x2b4007,0x2b5007,0x2b6007,0x2b7007
+ .long 0x2b8007,0x2b9007,0x2ba007,0x2bb007,0x2bc007,0x2bd007,0x2be007,0x2bf007
+ .long 0x2c0007,0x2c1007,0x2c2007,0x2c3007,0x2c4007,0x2c5007,0x2c6007,0x2c7007
+ .long 0x2c8007,0x2c9007,0x2ca007,0x2cb007,0x2cc007,0x2cd007,0x2ce007,0x2cf007
+ .long 0x2d0007,0x2d1007,0x2d2007,0x2d3007,0x2d4007,0x2d5007,0x2d6007,0x2d7007
+ .long 0x2d8007,0x2d9007,0x2da007,0x2db007,0x2dc007,0x2dd007,0x2de007,0x2df007
+ .long 0x2e0007,0x2e1007,0x2e2007,0x2e3007,0x2e4007,0x2e5007,0x2e6007,0x2e7007
+ .long 0x2e8007,0x2e9007,0x2ea007,0x2eb007,0x2ec007,0x2ed007,0x2ee007,0x2ef007
+ .long 0x2f0007,0x2f1007,0x2f2007,0x2f3007,0x2f4007,0x2f5007,0x2f6007,0x2f7007
+ .long 0x2f8007,0x2f9007,0x2fa007,0x2fb007,0x2fc007,0x2fd007,0x2fe007,0x2ff007
+ .long 0x300007,0x301007,0x302007,0x303007,0x304007,0x305007,0x306007,0x307007
+ .long 0x308007,0x309007,0x30a007,0x30b007,0x30c007,0x30d007,0x30e007,0x30f007
+ .long 0x310007,0x311007,0x312007,0x313007,0x314007,0x315007,0x316007,0x317007
+ .long 0x318007,0x319007,0x31a007,0x31b007,0x31c007,0x31d007,0x31e007,0x31f007
+ .long 0x320007,0x321007,0x322007,0x323007,0x324007,0x325007,0x326007,0x327007
+ .long 0x328007,0x329007,0x32a007,0x32b007,0x32c007,0x32d007,0x32e007,0x32f007
+ .long 0x330007,0x331007,0x332007,0x333007,0x334007,0x335007,0x336007,0x337007
+ .long 0x338007,0x339007,0x33a007,0x33b007,0x33c007,0x33d007,0x33e007,0x33f007
+ .long 0x340007,0x341007,0x342007,0x343007,0x344007,0x345007,0x346007,0x347007
+ .long 0x348007,0x349007,0x34a007,0x34b007,0x34c007,0x34d007,0x34e007,0x34f007
+ .long 0x350007,0x351007,0x352007,0x353007,0x354007,0x355007,0x356007,0x357007
+ .long 0x358007,0x359007,0x35a007,0x35b007,0x35c007,0x35d007,0x35e007,0x35f007
+ .long 0x360007,0x361007,0x362007,0x363007,0x364007,0x365007,0x366007,0x367007
+ .long 0x368007,0x369007,0x36a007,0x36b007,0x36c007,0x36d007,0x36e007,0x36f007
+ .long 0x370007,0x371007,0x372007,0x373007,0x374007,0x375007,0x376007,0x377007
+ .long 0x378007,0x379007,0x37a007,0x37b007,0x37c007,0x37d007,0x37e007,0x37f007
+ .long 0x380007,0x381007,0x382007,0x383007,0x384007,0x385007,0x386007,0x387007
+ .long 0x388007,0x389007,0x38a007,0x38b007,0x38c007,0x38d007,0x38e007,0x38f007
+ .long 0x390007,0x391007,0x392007,0x393007,0x394007,0x395007,0x396007,0x397007
+ .long 0x398007,0x399007,0x39a007,0x39b007,0x39c007,0x39d007,0x39e007,0x39f007
+ .long 0x3a0007,0x3a1007,0x3a2007,0x3a3007,0x3a4007,0x3a5007,0x3a6007,0x3a7007
+ .long 0x3a8007,0x3a9007,0x3aa007,0x3ab007,0x3ac007,0x3ad007,0x3ae007,0x3af007
+ .long 0x3b0007,0x3b1007,0x3b2007,0x3b3007,0x3b4007,0x3b5007,0x3b6007,0x3b7007
+ .long 0x3b8007,0x3b9007,0x3ba007,0x3bb007,0x3bc007,0x3bd007,0x3be007,0x3bf007
+ .long 0x3c0007,0x3c1007,0x3c2007,0x3c3007,0x3c4007,0x3c5007,0x3c6007,0x3c7007
+ .long 0x3c8007,0x3c9007,0x3ca007,0x3cb007,0x3cc007,0x3cd007,0x3ce007,0x3cf007
+ .long 0x3d0007,0x3d1007,0x3d2007,0x3d3007,0x3d4007,0x3d5007,0x3d6007,0x3d7007
+ .long 0x3d8007,0x3d9007,0x3da007,0x3db007,0x3dc007,0x3dd007,0x3de007,0x3df007
+ .long 0x3e0007,0x3e1007,0x3e2007,0x3e3007,0x3e4007,0x3e5007,0x3e6007,0x3e7007
+ .long 0x3e8007,0x3e9007,0x3ea007,0x3eb007,0x3ec007,0x3ed007,0x3ee007,0x3ef007
+ .long 0x3f0007,0x3f1007,0x3f2007,0x3f3007,0x3f4007,0x3f5007,0x3f6007,0x3f7007
+ .long 0x3f8007,0x3f9007,0x3fa007,0x3fb007,0x3fc007,0x3fd007,0x3fe007,0x3ff007
.org 0x3000
-_empty_bad_page:
+ENTRY(empty_bad_page)
.org 0x4000
-_empty_bad_page_table:
+ENTRY(empty_bad_page_table)
.org 0x5000
-_empty_zero_page:
+ENTRY(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
-
+
stack_start:
- .long _init_user_stack+4096
+ .long SYMBOL_NAME(init_user_stack)+4096
.long KERNEL_DS
/* This is the default interrupt "handler" :-) */
int_msg:
.asciz "Unknown interrupt\n"
-.align 2
+ ALIGN
ignore_int:
cld
pushl %eax
@@ -318,7 +468,7 @@ ignore_int:
mov %ax,%es
mov %ax,%fs
pushl $int_msg
- call _printk
+ call SYMBOL_NAME(printk)
popl %eax
pop %fs
pop %es
@@ -331,34 +481,41 @@ ignore_int:
/*
* The interrupt descriptor table has room for 256 idt's
*/
-.align 4
+ ALIGN
.word 0
idt_descr:
.word 256*8-1 # idt contains 256 entries
- .long 0xc0000000+_idt
+ .long SYMBOL_NAME(idt)
-.align 4
-_idt:
+ENTRY(idt)
.fill 256,8,0 # idt is uninitialized
-.align 4
+ ALIGN
.word 0
gdt_descr:
+#ifdef CONFIG_APM
+ .word (11+2*NR_TASKS)*8-1
+#else
.word (8+2*NR_TASKS)*8-1
- .long 0xc0000000+_gdt
+#endif
+ .long SYMBOL_NAME(gdt)
/*
* This gdt setup gives the kernel a 1GB address space at virtual
* address 0xC0000000 - space enough for expansion, I hope.
*/
-.align 4
-_gdt:
+ENTRY(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 0x00cf9a000000ffff /* 0x10 kernel 4GB code at 0x00000000 */
+ .quad 0x00cf92000000ffff /* 0x18 kernel 4GB data at 0x00000000 */
.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 */
+#ifdef CONFIG_APM
+ .quad 0x00c09a0000000000 /* APM CS code */
+ .quad 0x00809a0000000000 /* APM CS 16 code (16 bit) */
+ .quad 0x00c0920000000000 /* APM DS data */
+#endif
diff --git a/arch/i386/kernel/hexify.c b/arch/i386/kernel/hexify.c
new file mode 100644
index 000000000..daa331fec
--- /dev/null
+++ b/arch/i386/kernel/hexify.c
@@ -0,0 +1,31 @@
+#include <stdio.h>
+
+
+void main()
+{
+ int c;
+ int comma=0;
+ int count=0;
+ while((c=getchar())!=EOF)
+ {
+ unsigned char x=c;
+ if(comma)
+ printf(",");
+ else
+ comma=1;
+ if(count==8)
+ {
+ count=0;
+ printf("\n");
+ }
+ if(count==0)
+ printf("\t");
+ printf("0x%02X",c);
+ count++;
+ }
+ if(count)
+ printf("\n");
+ exit(0);
+}
+
+
diff --git a/arch/i386/kernel/ioport.c b/arch/i386/kernel/ioport.c
index c949f70cd..bcefeef9b 100644
--- a/arch/i386/kernel/ioport.c
+++ b/arch/i386/kernel/ioport.c
@@ -75,8 +75,8 @@ unsigned int *stack;
*/
asmlinkage int sys_iopl(long ebx,long ecx,long edx,
long esi, long edi, long ebp, long eax, long ds,
- long es, long fs, long gs, long orig_eax,
- long eip,long cs,long eflags,long esp,long ss)
+ long es, long orig_eax, long eip, long cs,
+ long eflags, long esp, long ss)
{
unsigned int level = ebx;
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index 23085dc6c..e131e5a45 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -23,54 +23,68 @@
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
+#include <linux/malloc.h>
+#include <linux/random.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/bitops.h>
+#include <asm/smp.h>
#define CR0_NE 32
static unsigned char cache_21 = 0xff;
static unsigned char cache_A1 = 0xff;
-void disable_irq(unsigned int irq_nr)
+#ifdef __SMP_PROF__
+static unsigned int int_count[NR_CPUS][NR_IRQS] = {{0},};
+#endif
+
+static inline void mask_irq(unsigned int irq_nr)
{
- unsigned long flags;
unsigned char mask;
mask = 1 << (irq_nr & 7);
- save_flags(flags);
if (irq_nr < 8) {
- cli();
cache_21 |= mask;
outb(cache_21,0x21);
- restore_flags(flags);
- return;
+ } else {
+ cache_A1 |= mask;
+ outb(cache_A1,0xA1);
}
- cli();
- cache_A1 |= mask;
- outb(cache_A1,0xA1);
- restore_flags(flags);
}
-void enable_irq(unsigned int irq_nr)
+static inline void unmask_irq(unsigned int irq_nr)
{
- unsigned long flags;
unsigned char mask;
mask = ~(1 << (irq_nr & 7));
- save_flags(flags);
if (irq_nr < 8) {
- cli();
cache_21 &= mask;
outb(cache_21,0x21);
- restore_flags(flags);
- return;
+ } else {
+ cache_A1 &= mask;
+ outb(cache_A1,0xA1);
}
+}
+
+void disable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ mask_irq(irq_nr);
+ restore_flags(flags);
+}
+
+void enable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+ save_flags(flags);
cli();
- cache_A1 &= mask;
- outb(cache_A1,0xA1);
+ unmask_irq(irq_nr);
restore_flags(flags);
}
@@ -88,8 +102,16 @@ void enable_irq(unsigned int irq_nr)
* atomic. The specific handler is chosen depending on the SA_INTERRUPT
* flag when installing a handler. Finally, one "bad interrupt" handler, that
* is used when no handler is present.
+ *
+ * The timer interrupt is handled specially to insure that the jiffies
+ * variable is updated at all times. Specifically, the timer interrupt is
+ * just like the complete handlers except that it is invoked with interrupts
+ * disabled and should never re-enable them. If other interrupts were
+ * allowed to be processed while the timer interrupt is active, then the
+ * other interrupts would have to avoid using the jiffies variable for delay
+ * and interval timing operations to avoid hanging the system.
*/
-BUILD_IRQ(FIRST,0,0x01)
+BUILD_TIMER_IRQ(FIRST,0,0x01)
BUILD_IRQ(FIRST,1,0x02)
BUILD_IRQ(FIRST,2,0x04)
BUILD_IRQ(FIRST,3,0x08)
@@ -102,19 +124,29 @@ BUILD_IRQ(SECOND,9,0x02)
BUILD_IRQ(SECOND,10,0x04)
BUILD_IRQ(SECOND,11,0x08)
BUILD_IRQ(SECOND,12,0x10)
+#ifdef __SMP__
+BUILD_MSGIRQ(SECOND,13,0x20)
+#else
BUILD_IRQ(SECOND,13,0x20)
+#endif
BUILD_IRQ(SECOND,14,0x40)
BUILD_IRQ(SECOND,15,0x80)
+#ifdef __SMP__
+BUILD_RESCHEDIRQ(16)
+#endif
/*
* Pointers to the low-level handlers: first the general ones, then the
* fast ones, then the bad ones.
*/
-static void (*interrupt[16])(void) = {
+static void (*interrupt[17])(void) = {
IRQ0_interrupt, IRQ1_interrupt, IRQ2_interrupt, IRQ3_interrupt,
IRQ4_interrupt, IRQ5_interrupt, IRQ6_interrupt, IRQ7_interrupt,
IRQ8_interrupt, IRQ9_interrupt, IRQ10_interrupt, IRQ11_interrupt,
- IRQ12_interrupt, IRQ13_interrupt, IRQ14_interrupt, IRQ15_interrupt
+ IRQ12_interrupt, IRQ13_interrupt, IRQ14_interrupt, IRQ15_interrupt
+#ifdef __SMP__
+ ,IRQ16_interrupt
+#endif
};
static void (*fast_interrupt[16])(void) = {
@@ -142,39 +174,164 @@ static void (*bad_interrupt[16])(void) = {
/*
* Initial irq handlers.
*/
-struct irqaction {
- void (*handler)(int, struct pt_regs *);
- unsigned long flags;
- unsigned long mask;
- const char *name;
-};
-static struct irqaction irq_action[16] = {
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }
+static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
+
+#ifdef __SMP__
+
+/*
+ * On SMP boards, irq13 is used for interprocessor interrupts (IPI's).
+ */
+static struct irqaction irq13 = { smp_message_irq, SA_INTERRUPT, 0, "IPI", NULL, NULL };
+
+#else
+
+/*
+ * Note that on a 486, we don't want to do a SIGFPE on an irq13
+ * as the irq is unreliable, and exception 16 works correctly
+ * (ie as explained in the intel literature). On a 386, you
+ * can't use exception 16 due to bad IBM design, so we have to
+ * rely on the less exact irq13.
+ *
+ * Careful.. Not only is IRQ13 unreliable, but it is also
+ * leads to races. IBM designers who came up with it should
+ * be shot.
+ */
+
+
+static void math_error_irq(int cpl, void *dev_id, struct pt_regs *regs)
+{
+ outb(0,0xF0);
+ if (ignore_irq13 || !hard_math)
+ return;
+ math_error();
+}
+
+static struct irqaction irq13 = { math_error_irq, 0, 0, "math error", NULL, NULL };
+
+#endif
+
+/*
+ * IRQ2 is cascade interrupt to second interrupt controller
+ */
+static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL};
+
+static struct irqaction *irq_action[16] = {
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL
};
int get_irq_list(char *buf)
{
int i, len = 0;
- struct irqaction * action = irq_action;
+ struct irqaction * action;
- for (i = 0 ; i < 16 ; i++, action++) {
- if (!action->handler)
+ for (i = 0 ; i < 16 ; i++) {
+ action = irq_action[i];
+ if (!action)
continue;
- len += sprintf(buf+len, "%2d: %8d %c %s\n",
+ len += sprintf(buf+len, "%2d: %10u %c %s",
i, kstat.interrupts[i],
(action->flags & SA_INTERRUPT) ? '+' : ' ',
action->name);
+ for (action=action->next; action; action = action->next) {
+ len += sprintf(buf+len, ",%s %s",
+ (action->flags & SA_INTERRUPT) ? " +" : "",
+ action->name);
+ }
+ len += sprintf(buf+len, "\n");
+ }
+/*
+ * Linus - should you add NMI counts here ?????
+ */
+#ifdef __SMP_PROF__
+ len+=sprintf(buf+len, "IPI: %8lu received\n",
+ ipi_count);
+#endif
+ return len;
+}
+
+#ifdef __SMP_PROF__
+
+int get_smp_prof_list(char *buf) {
+ int i,j, len = 0;
+ struct irqaction * action;
+ unsigned long sum_spins = 0;
+ unsigned long sum_spins_syscall = 0;
+ unsigned long sum_spins_sys_idle = 0;
+ unsigned long sum_smp_idle_count = 0;
+
+ for (i=0;i<smp_num_cpus;i++) {
+ int cpunum = cpu_logical_map[i];
+ sum_spins+=smp_spins[cpunum];
+ sum_spins_syscall+=smp_spins_syscall[cpunum];
+ sum_spins_sys_idle+=smp_spins_sys_idle[cpunum];
+ sum_smp_idle_count+=smp_idle_count[cpunum];
+ }
+
+ len += sprintf(buf+len,"CPUS: %10i \n", smp_num_cpus);
+ len += sprintf(buf+len," SUM ");
+ for (i=0;i<smp_num_cpus;i++)
+ len += sprintf(buf+len," P%1d ",cpu_logical_map[i]);
+ len += sprintf(buf+len,"\n");
+ for (i = 0 ; i < NR_IRQS ; i++) {
+ action = *(i + irq_action);
+ if (!action || !action->handler)
+ continue;
+ len += sprintf(buf+len, "%3d: %10d ",
+ i, kstat.interrupts[i]);
+ for (j=0;j<smp_num_cpus;j++)
+ len+=sprintf(buf+len, "%10d ",
+ int_count[cpu_logical_map[j]][i]);
+ len += sprintf(buf+len, "%c %s\n",
+ (action->flags & SA_INTERRUPT) ? '+' : ' ',
+ action->name);
+ for (action=action->next; action; action = action->next) {
+ len += sprintf(buf+len, ",%s %s",
+ (action->flags & SA_INTERRUPT) ? " +" : "",
+ action->name);
+ }
}
+ len+=sprintf(buf+len, "LCK: %10lu",
+ sum_spins);
+
+ for (i=0;i<smp_num_cpus;i++)
+ len+=sprintf(buf+len," %10lu",smp_spins[cpu_logical_map[i]]);
+
+ len +=sprintf(buf+len," spins from int\n");
+
+ len+=sprintf(buf+len, "LCK: %10lu",
+ sum_spins_syscall);
+
+ for (i=0;i<smp_num_cpus;i++)
+ len+=sprintf(buf+len," %10lu",smp_spins_syscall[cpu_logical_map[i]]);
+
+ len +=sprintf(buf+len," spins from syscall\n");
+
+ len+=sprintf(buf+len, "LCK: %10lu",
+ sum_spins_sys_idle);
+
+ for (i=0;i<smp_num_cpus;i++)
+ len+=sprintf(buf+len," %10lu",smp_spins_sys_idle[cpu_logical_map[i]]);
+
+ len +=sprintf(buf+len," spins from sysidle\n");
+ len+=sprintf(buf+len,"IDLE %10lu",sum_smp_idle_count);
+
+ for (i=0;i<smp_num_cpus;i++)
+ len+=sprintf(buf+len," %10lu",smp_idle_count[cpu_logical_map[i]]);
+
+ len +=sprintf(buf+len," idle ticks\n");
+
+ len+=sprintf(buf+len, "IPI: %10lu received\n",
+ ipi_count);
+
return len;
}
+#endif
+
+
/*
* do_IRQ handles IRQ's that have been installed without the
@@ -185,10 +342,25 @@ int get_irq_list(char *buf)
*/
asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
{
- struct irqaction * action = irq + irq_action;
+ struct irqaction * action = *(irq + irq_action);
+ int do_random = 0;
+
+#ifdef __SMP__
+ if(smp_threads_ready && active_kernel_processor!=smp_processor_id())
+ panic("IRQ %d: active processor set wrongly(%d not %d).\n", irq, active_kernel_processor, smp_processor_id());
+#endif
kstat.interrupts[irq]++;
- action->handler(irq, regs);
+#ifdef __SMP_PROF__
+ int_count[smp_processor_id()][irq]++;
+#endif
+ while (action) {
+ do_random |= action->flags;
+ action->handler(irq, action->dev_id, regs);
+ action = action->next;
+ }
+ if (do_random & SA_SAMPLE_RANDOM)
+ add_interrupt_randomness(irq);
}
/*
@@ -198,145 +370,159 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
*/
asmlinkage void do_fast_IRQ(int irq)
{
- struct irqaction * action = irq + irq_action;
+ struct irqaction * action = *(irq + irq_action);
+ int do_random = 0;
+
+#ifdef __SMP__
+ /* IRQ 13 is allowed - that's a flush tlb */
+ if(smp_threads_ready && active_kernel_processor!=smp_processor_id() && irq!=13)
+ panic("fast_IRQ %d: active processor set wrongly(%d not %d).\n", irq, active_kernel_processor, smp_processor_id());
+#endif
kstat.interrupts[irq]++;
- action->handler(irq, NULL);
+#ifdef __SMP_PROF__
+ int_count[smp_processor_id()][irq]++;
+#endif
+ while (action) {
+ do_random |= action->flags;
+ action->handler(irq, action->dev_id, NULL);
+ action = action->next;
+ }
+ if (do_random & SA_SAMPLE_RANDOM)
+ add_interrupt_randomness(irq);
}
-#define SA_PROBE SA_ONESHOT
+int setup_x86_irq(int irq, struct irqaction * new)
+{
+ int shared = 0;
+ struct irqaction *old, **p;
+ unsigned long flags;
+
+ p = irq_action + irq;
+ if ((old = *p) != NULL) {
+ /* Can't share interrupts unless both agree to */
+ if (!(old->flags & new->flags & SA_SHIRQ))
+ return -EBUSY;
+
+ /* Can't share interrupts unless both are same type */
+ if ((old->flags ^ new->flags) & SA_INTERRUPT)
+ return -EBUSY;
+
+ /* add new interrupt at end of irq queue */
+ do {
+ p = &old->next;
+ old = *p;
+ } while (old);
+ shared = 1;
+ }
+
+ if (new->flags & SA_SAMPLE_RANDOM)
+ rand_initialize_irq(irq);
+
+ save_flags(flags);
+ cli();
+ *p = new;
+
+ if (!shared) {
+ if (new->flags & SA_INTERRUPT)
+ set_intr_gate(0x20+irq,fast_interrupt[irq]);
+ else
+ set_intr_gate(0x20+irq,interrupt[irq]);
+ unmask_irq(irq);
+ }
+ restore_flags(flags);
+ return 0;
+}
-int request_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
- unsigned long irqflags, const char * devname)
+int request_irq(unsigned int irq,
+ void (*handler)(int, void *, struct pt_regs *),
+ unsigned long irqflags,
+ const char * devname,
+ void *dev_id)
{
+ int retval;
struct irqaction * action;
- unsigned long flags;
if (irq > 15)
return -EINVAL;
- action = irq + irq_action;
- if (action->handler)
- return -EBUSY;
if (!handler)
return -EINVAL;
- save_flags(flags);
- cli();
+
+ action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+ if (!action)
+ return -ENOMEM;
+
action->handler = handler;
action->flags = irqflags;
action->mask = 0;
action->name = devname;
- if (!(action->flags & SA_PROBE)) { /* SA_ONESHOT is used by probing */
- if (action->flags & SA_INTERRUPT)
- set_intr_gate(0x20+irq,fast_interrupt[irq]);
- else
- set_intr_gate(0x20+irq,interrupt[irq]);
- }
- if (irq < 8) {
- cache_21 &= ~(1<<irq);
- outb(cache_21,0x21);
- } else {
- cache_21 &= ~(1<<2);
- cache_A1 &= ~(1<<(irq-8));
- outb(cache_21,0x21);
- outb(cache_A1,0xA1);
- }
- restore_flags(flags);
- return 0;
+ action->next = NULL;
+ action->dev_id = dev_id;
+
+ retval = setup_x86_irq(irq, action);
+
+ if (retval)
+ kfree(action);
+ return retval;
}
-void free_irq(unsigned int irq)
+void free_irq(unsigned int irq, void *dev_id)
{
- struct irqaction * action = irq + irq_action;
+ struct irqaction * action, **p;
unsigned long flags;
if (irq > 15) {
printk("Trying to free IRQ%d\n",irq);
return;
}
- if (!action->handler) {
- printk("Trying to free free IRQ%d\n",irq);
- return;
- }
- save_flags(flags);
- cli();
- if (irq < 8) {
- cache_21 |= 1 << irq;
- outb(cache_21,0x21);
- } else {
- cache_A1 |= 1 << (irq-8);
- outb(cache_A1,0xA1);
- }
- set_intr_gate(0x20+irq,bad_interrupt[irq]);
- action->handler = NULL;
- action->flags = 0;
- action->mask = 0;
- action->name = NULL;
- restore_flags(flags);
-}
+ for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) {
+ if (action->dev_id != dev_id)
+ continue;
-/*
- * Note that on a 486, we don't want to do a SIGFPE on a irq13
- * as the irq is unreliable, and exception 16 works correctly
- * (ie as explained in the intel literature). On a 386, you
- * can't use exception 16 due to bad IBM design, so we have to
- * rely on the less exact irq13.
- *
- * Careful.. Not only is IRQ13 unreliable, but it is also
- * leads to races. IBM designers who came up with it should
- * be shot.
- */
-static void math_error_irq(int cpl, struct pt_regs *regs)
-{
- outb(0,0xF0);
- if (ignore_irq13 || !hard_math)
+ /* Found it - now free it */
+ save_flags(flags);
+ cli();
+ *p = action->next;
+ if (!irq[irq_action]) {
+ mask_irq(irq);
+ set_intr_gate(0x20+irq,bad_interrupt[irq]);
+ }
+ restore_flags(flags);
+ kfree(action);
return;
- math_error();
+ }
+ printk("Trying to free free IRQ%d\n",irq);
}
-static void no_action(int cpl, struct pt_regs * regs) { }
-
-unsigned int probe_irq_on (void)
+unsigned long probe_irq_on (void)
{
unsigned int i, irqs = 0, irqmask;
unsigned long delay;
- /* first, snaffle up any unassigned irqs */
+ /* first, enable any unassigned irqs */
for (i = 15; i > 0; i--) {
- if (!request_irq(i, no_action, SA_PROBE, "probe")) {
+ if (!irq_action[i]) {
enable_irq(i);
irqs |= (1 << i);
}
}
/* wait for spurious interrupts to mask themselves out again */
- for (delay = jiffies + 2; delay > jiffies; ); /* min 10ms delay */
+ for (delay = jiffies + HZ/10; delay > jiffies; )
+ /* about 100ms delay */;
/* now filter out any obviously spurious interrupts */
irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
- for (i = 15; i > 0; i--) {
- if (irqs & (1 << i) & irqmask) {
- irqs ^= (1 << i);
- free_irq(i);
- }
- }
-#ifdef DEBUG
- printk("probe_irq_on: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
-#endif
- return irqs;
+ return irqs & ~irqmask;
}
-int probe_irq_off (unsigned int irqs)
+int probe_irq_off (unsigned long irqs)
{
unsigned int i, irqmask;
irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
- for (i = 15; i > 0; i--) {
- if (irqs & (1 << i)) {
- free_irq(i);
- }
- }
#ifdef DEBUG
- printk("probe_irq_off: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
+ printk("probe_irq_off: irqs=0x%04lx irqmask=0x%04x\n", irqs, irqmask);
#endif
irqs &= irqmask;
if (!irqs)
@@ -350,6 +536,10 @@ int probe_irq_off (unsigned int irqs)
void init_IRQ(void)
{
int i;
+ static unsigned char smptrap=0;
+ if(smptrap)
+ return;
+ smptrap=1;
/* set the clock to 100 Hz */
outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
@@ -357,10 +547,13 @@ void init_IRQ(void)
outb(LATCH >> 8 , 0x40); /* MSB */
for (i = 0; i < 16 ; i++)
set_intr_gate(0x20+i,bad_interrupt[i]);
- if (request_irq(2, no_action, SA_INTERRUPT, "cascade"))
- printk("Unable to get IRQ2 for cascade\n");
- if (request_irq(13,math_error_irq, 0, "math error"))
- printk("Unable to get IRQ13 for math-error handler\n");
+ /* This bit is a hack because we don't send timer messages to all processors yet */
+ /* It has to be here .. it doesn't work if you put it down the bottom - assembler explodes 8) */
+#ifdef __SMP__
+ set_intr_gate(0x20+i, interrupt[i]); /* IRQ '16' - IPI for rescheduling */
+#endif
request_region(0x20,0x20,"pic1");
request_region(0xa0,0x20,"pic2");
+ setup_x86_irq(2, &irq2);
+ setup_x86_irq(13, &irq13);
}
diff --git a/arch/i386/kernel/ksyms.c b/arch/i386/kernel/ksyms.c
new file mode 100644
index 000000000..bdb6e8005
--- /dev/null
+++ b/arch/i386/kernel/ksyms.c
@@ -0,0 +1,41 @@
+#include <linux/module.h>
+#include <linux/smp.h>
+#include <linux/user.h>
+#include <linux/elfcore.h>
+
+#include <asm/semaphore.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+extern void dump_thread(struct pt_regs *, struct user *);
+extern int dump_fpu(elf_fpregset_t *);
+
+static struct symbol_table arch_symbol_table = {
+#include <linux/symtab_begin.h>
+ /* platform dependent support */
+ X(EISA_bus),
+ X(wp_works_ok),
+ X(__verify_write),
+ X(dump_thread),
+ X(dump_fpu),
+ X(ioremap),
+ X(iounmap),
+ XNOVERS(__down_failed),
+ XNOVERS(__up_wakeup),
+#ifdef __SMP__
+ X(apic_reg), /* Needed internally for the I386 inlines */
+ X(cpu_data),
+ X(syscall_count),
+ X(kernel_flag),
+ X(kernel_counter),
+ X(active_kernel_processor),
+ X(smp_invalidate_needed),
+#endif
+#include <linux/symtab_end.h>
+};
+
+void arch_syms_export(void)
+{
+ register_symtab(&arch_symbol_table);
+}
diff --git a/arch/i386/kernel/ldt.c b/arch/i386/kernel/ldt.c
index bace95f4e..9e2f5e0cd 100644
--- a/arch/i386/kernel/ldt.c
+++ b/arch/i386/kernel/ldt.c
@@ -8,9 +8,11 @@
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <asm/segment.h>
+#include <linux/vmalloc.h>
+
+#include <asm/uaccess.h>
#include <asm/system.h>
-#include <linux/ldt.h>
+#include <asm/ldt.h>
static int read_ldt(void * ptr, unsigned long bytecount)
{
@@ -30,15 +32,39 @@ static int read_ldt(void * ptr, unsigned long bytecount)
error = verify_area(VERIFY_WRITE, ptr, size);
if (error)
return error;
- memcpy_tofs(ptr, address, size);
+ copy_to_user(ptr, address, size);
return size;
}
+static inline int limits_ok(struct modify_ldt_ldt_s *ldt_info)
+{
+ unsigned long base, limit;
+ /* linear address of first and last accessible byte */
+ unsigned long first, last;
+
+ base = ldt_info->base_addr;
+ limit = ldt_info->limit;
+ if (ldt_info->limit_in_pages)
+ limit = limit * PAGE_SIZE + PAGE_SIZE - 1;
+
+ first = base;
+ last = limit + base;
+
+ /* segment grows down? */
+ if (ldt_info->contents == 1) {
+ /* data segment grows down */
+ first = base+limit+1;
+ last = base+65535;
+ if (ldt_info->seg_32bit)
+ last = base-1;
+ }
+ return (last >= first && last < TASK_SIZE);
+}
+
static int write_ldt(void * ptr, unsigned long bytecount)
{
struct modify_ldt_ldt_s ldt_info;
unsigned long *lp;
- unsigned long base, limit;
int error, i;
if (bytecount != sizeof(ldt_info))
@@ -47,18 +73,12 @@ static int write_ldt(void * ptr, unsigned long bytecount)
if (error)
return error;
- memcpy_fromfs(&ldt_info, ptr, sizeof(ldt_info));
+ copy_from_user(&ldt_info, ptr, sizeof(ldt_info));
if (ldt_info.contents == 3 || ldt_info.entry_number >= LDT_ENTRIES)
return -EINVAL;
- limit = ldt_info.limit;
- base = ldt_info.base_addr;
- if (ldt_info.limit_in_pages)
- limit *= PAGE_SIZE;
-
- limit += base;
- if (limit < base || limit >= 0xC0000000)
+ if (!limits_ok(&ldt_info))
return -EINVAL;
if (!current->ldt) {
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index a5e8777bf..a26a2c6a3 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -8,6 +8,9 @@
* This file handles the architecture-dependent parts of process handling..
*/
+#define __KERNEL_SYSCALLS__
+#include <stdarg.h>
+
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -16,19 +19,32 @@
#include <linux/unistd.h>
#include <linux/ptrace.h>
#include <linux/malloc.h>
-#include <linux/ldt.h>
+#include <linux/vmalloc.h>
#include <linux/user.h>
#include <linux/a.out.h>
+#include <linux/interrupt.h>
+#include <linux/config.h>
+#include <linux/unistd.h>
+#include <linux/delay.h>
+#include <linux/smp.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/ldt.h>
asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call");
+#ifdef CONFIG_APM
+extern int apm_do_idle(void);
+extern void apm_do_busy(void);
+#endif
+
static int hlt_counter=0;
+#define HARD_IDLE_TIMEOUT (HZ / 3)
+
void disable_hlt(void)
{
hlt_counter++;
@@ -39,53 +55,145 @@ void enable_hlt(void)
hlt_counter--;
}
-asmlinkage int sys_pipe(unsigned long * fildes)
-{
- int fd[2];
- int error;
+#ifndef __SMP__
- error = verify_area(VERIFY_WRITE,fildes,8);
- if (error)
- return error;
- error = do_pipe(fd);
- if (error)
- return error;
- put_fs_long(fd[0],0+fildes);
- put_fs_long(fd[1],1+fildes);
- return 0;
+static void hard_idle(void)
+{
+ while (!need_resched) {
+ if (hlt_works_ok && !hlt_counter) {
+#ifdef CONFIG_APM
+ /* If the APM BIOS is not enabled, or there
+ is an error calling the idle routine, we
+ should hlt if possible. We need to check
+ need_resched again because an interrupt
+ may have occurred in apm_do_idle(). */
+ start_bh_atomic();
+ if (!apm_do_idle() && !need_resched)
+ __asm__("hlt");
+ end_bh_atomic();
+#else
+ __asm__("hlt");
+#endif
+ }
+ if (need_resched)
+ break;
+ schedule();
+ }
+#ifdef CONFIG_APM
+ apm_do_busy();
+#endif
}
/*
- * The idle loop on a i386..
+ * The idle loop on a uniprocessor i386..
*/
+
asmlinkage int sys_idle(void)
{
- int i;
- pmd_t * pmd;
+ unsigned long start_idle = 0;
if (current->pid != 0)
return -EPERM;
-
- /* Map out the low memory: it's no longer needed */
- pmd = pmd_offset(swapper_pg_dir, 0);
- for (i = 0 ; i < 768 ; i++)
- pmd_clear(pmd++);
-
/* endless idle loop with no priority at all */
current->counter = -100;
- for (;;) {
- if (hlt_works_ok && !hlt_counter && !need_resched)
- __asm__("hlt");
+ for (;;)
+ {
+ /*
+ * We are locked at this point. So we can safely call
+ * the APM bios knowing only one CPU at a time will do
+ * so.
+ */
+ if (!start_idle)
+ start_idle = jiffies;
+ if (jiffies - start_idle > HARD_IDLE_TIMEOUT)
+ {
+ hard_idle();
+ }
+ else
+ {
+ if (hlt_works_ok && !hlt_counter && !need_resched)
+ __asm__("hlt");
+ }
+ if (need_resched)
+ start_idle = 0;
schedule();
}
}
+#else
+
+/*
+ * In the SMP world we hlt outside of kernel syscall rather than within
+ * so as to get the right locking semantics.
+ */
+
+asmlinkage int sys_idle(void)
+{
+ if(current->pid != 0)
+ return -EPERM;
+#ifdef __SMP_PROF__
+ smp_spins_sys_idle[smp_processor_id()]+=
+ smp_spins_syscall_cur[smp_processor_id()];
+#endif
+ current->counter= -100;
+ schedule();
+ return 0;
+}
+
+/*
+ * This is being executed in task 0 'user space'.
+ */
+
+int cpu_idle(void *unused)
+{
+ while(1)
+ {
+ if(cpu_data[smp_processor_id()].hlt_works_ok && !hlt_counter && !need_resched)
+ __asm("hlt");
+ if(0==(0x7fffffff & smp_process_available))
+ continue;
+ while(0x80000000 & smp_process_available);
+ cli();
+ while(set_bit(31,&smp_process_available))
+ while(test_bit(31,&smp_process_available))
+ {
+ /*
+ * Oops.. This is kind of important in some cases...
+ */
+ if(clear_bit(smp_processor_id(), &smp_invalidate_needed))
+ local_flush_tlb();
+ }
+ if (0==(0x7fffffff & smp_process_available)){
+ clear_bit(31,&smp_process_available);
+ sti();
+ continue;
+ }
+ smp_process_available--;
+ clear_bit(31,&smp_process_available);
+ sti();
+ idle();
+ }
+}
+
+#endif
+
/*
* This routine reboots the machine by asking the keyboard
* controller to pulse the reset-line low. We try that for a while,
* and if it doesn't work, we do some other stupid things.
*/
static long no_idt[2] = {0, 0};
+static int reboot_mode = 0;
+
+void reboot_setup(char *str, int *ints)
+{
+ int mode = 0;
+
+ /* "w" for "warm" reboot (no memory testing etc) */
+ if (str[0] == 'w')
+ mode = 0x1234;
+ reboot_mode = mode;
+}
static inline void kb_wait(void)
{
@@ -101,15 +209,14 @@ void hard_reset_now(void)
int i, j;
sti();
-/* rebooting needs to touch the page at absolute addr 0 */
- pg0[0] = 7;
- *((unsigned short *)0x472) = 0x1234;
+ *((unsigned short *)__va(0x472)) = reboot_mode;
for (;;) {
for (i=0; i<100; i++) {
kb_wait();
for(j = 0; j < 100000 ; j++)
/* nothing */;
outb(0xfe,0x64); /* pulse reset low */
+ udelay(100);
}
__asm__ __volatile__("\tlidt %0": "=m" (no_idt));
}
@@ -118,24 +225,27 @@ void hard_reset_now(void)
void show_regs(struct pt_regs * regs)
{
printk("\n");
- printk("EIP: %04x:%08lx",0xffff & regs->cs,regs->eip);
- if (regs->cs & 3)
- printk(" ESP: %04x:%08lx",0xffff & regs->ss,regs->esp);
+ printk("EIP: %04x:[<%08lx>]",0xffff & regs->xcs,regs->eip);
+ if (regs->xcs & 3)
+ printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp);
printk(" EFLAGS: %08lx\n",regs->eflags);
printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
regs->eax,regs->ebx,regs->ecx,regs->edx);
printk("ESI: %08lx EDI: %08lx EBP: %08lx",
regs->esi, regs->edi, regs->ebp);
- printk(" DS: %04x ES: %04x FS: %04x GS: %04x\n",
- 0xffff & regs->ds,0xffff & regs->es,
- 0xffff & regs->fs,0xffff & regs->gs);
+ printk(" DS: %04x ES: %04x\n",
+ 0xffff & regs->xds,0xffff & regs->xes);
}
/*
* Free current thread data structures etc..
*/
+
void exit_thread(void)
{
+ /* forget lazy i387 state */
+ if (last_task_used_math == current)
+ last_task_used_math = NULL;
/* forget local segments */
__asm__ __volatile__("mov %w0,%%fs ; mov %w0,%%gs ; lldt %w0"
: /* no outputs */
@@ -166,6 +276,26 @@ void flush_thread(void)
for (i=0 ; i<8 ; i++)
current->debugreg[i] = 0;
+
+ /*
+ * Forget coprocessor state..
+ */
+#ifdef __SMP__
+ if (current->flags & PF_USEDFPU) {
+ stts();
+ }
+#else
+ if (last_task_used_math == current) {
+ last_task_used_math = NULL;
+ stts();
+ }
+#endif
+ current->used_math = 0;
+ current->flags &= ~PF_USEDFPU;
+}
+
+void release_thread(struct task_struct *dead_task)
+{
}
void copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
@@ -186,6 +316,7 @@ void copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1;
p->tss.esp = (unsigned long) childregs;
p->tss.eip = (unsigned long) ret_from_sys_call;
+ p->tss.ebx = (unsigned long) p;
*childregs = *regs;
childregs->eax = 0;
childregs->esp = esp;
@@ -210,6 +341,31 @@ void copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
}
/*
+ * fill in the fpu structure for a core dump..
+ */
+int dump_fpu (struct pt_regs * regs, struct user_i387_struct* fpu)
+{
+ int fpvalid;
+
+/* Flag indicating the math stuff is valid. We don't support this for the
+ soft-float routines yet */
+ if (hard_math) {
+ if ((fpvalid = current->used_math) != 0) {
+ if (last_task_used_math == current)
+ __asm__("clts ; fnsave %0": :"m" (*fpu));
+ else
+ memcpy(fpu,&current->tss.i387.hard,sizeof(*fpu));
+ }
+ } else {
+ /* we should dump the emulator state here, but we need to
+ convert it into standard 387 format first.. */
+ fpvalid = 0;
+ }
+
+ return fpvalid;
+}
+
+/*
* fill in the user structure for a core dump..
*/
void dump_thread(struct pt_regs * regs, struct user * dump)
@@ -220,55 +376,52 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
dump->magic = CMAGIC;
dump->start_code = 0;
dump->start_stack = regs->esp & ~(PAGE_SIZE - 1);
- dump->u_tsize = ((unsigned long) current->mm->end_code) >> 12;
- dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> 12;
+ dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT;
+ dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT;
dump->u_dsize -= dump->u_tsize;
dump->u_ssize = 0;
for (i = 0; i < 8; i++)
dump->u_debugreg[i] = current->debugreg[i];
if (dump->start_stack < TASK_SIZE)
- dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> 12;
-
- dump->regs = *regs;
-
-/* Flag indicating the math stuff is valid. We don't support this for the
- soft-float routines yet */
- if (hard_math) {
- if ((dump->u_fpvalid = current->used_math) != 0) {
- if (last_task_used_math == current)
- __asm__("clts ; fnsave %0": :"m" (dump->i387));
- else
- memcpy(&dump->i387,&current->tss.i387.hard,sizeof(dump->i387));
- }
- } else {
- /* we should dump the emulator state here, but we need to
- convert it into standard 387 format first.. */
- dump->u_fpvalid = 0;
- }
+ dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT;
+
+ dump->regs.ebx = regs->ebx;
+ dump->regs.ecx = regs->ecx;
+ dump->regs.edx = regs->edx;
+ dump->regs.esi = regs->esi;
+ dump->regs.edi = regs->edi;
+ dump->regs.ebp = regs->ebp;
+ dump->regs.eax = regs->eax;
+ dump->regs.ds = regs->xds;
+ dump->regs.es = regs->xes;
+ __asm__("mov %%fs,%0":"=r" (dump->regs.fs));
+ __asm__("mov %%gs,%0":"=r" (dump->regs.gs));
+ dump->regs.orig_eax = regs->orig_eax;
+ dump->regs.eip = regs->eip;
+ dump->regs.cs = regs->xcs;
+ dump->regs.eflags = regs->eflags;
+ dump->regs.esp = regs->esp;
+ dump->regs.ss = regs->xss;
+
+ dump->u_fpvalid = dump_fpu (regs, &dump->i387);
}
asmlinkage int sys_fork(struct pt_regs regs)
{
- return do_fork(COPYVM | SIGCHLD, regs.esp, &regs);
+ return do_fork(SIGCHLD, regs.esp, &regs);
}
asmlinkage int sys_clone(struct pt_regs regs)
{
-#ifdef CLONE_ACTUALLY_WORKS_OK
unsigned long clone_flags;
unsigned long newsp;
- newsp = regs.ebx;
- clone_flags = regs.ecx;
+ clone_flags = regs.ebx;
+ newsp = regs.ecx;
if (!newsp)
newsp = regs.esp;
- if (newsp == regs.esp)
- clone_flags |= COPYVM;
return do_fork(clone_flags, newsp, &regs);
-#else
- return -ENOSYS;
-#endif
}
/*
diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c
index f32035edc..5ea636092 100644
--- a/arch/i386/kernel/ptrace.c
+++ b/arch/i386/kernel/ptrace.c
@@ -11,7 +11,7 @@
#include <linux/user.h>
#include <linux/debugreg.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/system.h>
@@ -28,10 +28,9 @@
#define TRAP_FLAG 0x100
/*
- * this is the number to subtract from the top of the stack. To find
- * the local frame.
+ * Offset of eflags on child stack..
*/
-#define MAGICNUMBER 68
+#define EFL_OFFSET ((EFL-2)*4-sizeof(struct pt_regs))
/* change a pid into a task struct. */
static inline struct task_struct * get_task(int pid)
@@ -83,7 +82,8 @@ static inline int put_stack_long(struct task_struct *task, int offset,
* and that it is in the task area before calling this: this routine does
* no checking.
*/
-static unsigned long get_long(struct vm_area_struct * vma, unsigned long addr)
+static unsigned long get_long(struct task_struct * tsk,
+ struct vm_area_struct * vma, unsigned long addr)
{
pgd_t * pgdir;
pmd_t * pgmiddle;
@@ -91,9 +91,9 @@ static unsigned long get_long(struct vm_area_struct * vma, unsigned long addr)
unsigned long page;
repeat:
- pgdir = pgd_offset(vma->vm_task, addr);
+ pgdir = pgd_offset(vma->vm_mm, addr);
if (pgd_none(*pgdir)) {
- do_no_page(vma, addr, 0);
+ do_no_page(tsk, vma, addr, 0);
goto repeat;
}
if (pgd_bad(*pgdir)) {
@@ -103,7 +103,7 @@ repeat:
}
pgmiddle = pmd_offset(pgdir, addr);
if (pmd_none(*pgmiddle)) {
- do_no_page(vma, addr, 0);
+ do_no_page(tsk, vma, addr, 0);
goto repeat;
}
if (pmd_bad(*pgmiddle)) {
@@ -113,12 +113,12 @@ repeat:
}
pgtable = pte_offset(pgmiddle, addr);
if (!pte_present(*pgtable)) {
- do_no_page(vma, addr, 0);
+ do_no_page(tsk, vma, addr, 0);
goto repeat;
}
page = pte_page(*pgtable);
/* this is a hack for non-kernel-mapped video buffers and similar */
- if (page >= high_memory)
+ if (MAP_NR(page) >= max_mapnr)
return 0;
page += addr & ~PAGE_MASK;
return *(unsigned long *) page;
@@ -133,7 +133,7 @@ repeat:
* Now keeps R/W state of page so that a text page stays readonly
* even if a debugger scribbles breakpoints into it. -M.U-
*/
-static void put_long(struct vm_area_struct * vma, unsigned long addr,
+static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long addr,
unsigned long data)
{
pgd_t *pgdir;
@@ -142,9 +142,9 @@ static void put_long(struct vm_area_struct * vma, unsigned long addr,
unsigned long page;
repeat:
- pgdir = pgd_offset(vma->vm_task, addr);
+ pgdir = pgd_offset(vma->vm_mm, addr);
if (!pgd_present(*pgdir)) {
- do_no_page(vma, addr, 1);
+ do_no_page(tsk, vma, addr, 1);
goto repeat;
}
if (pgd_bad(*pgdir)) {
@@ -154,7 +154,7 @@ repeat:
}
pgmiddle = pmd_offset(pgdir, addr);
if (pmd_none(*pgmiddle)) {
- do_no_page(vma, addr, 1);
+ do_no_page(tsk, vma, addr, 1);
goto repeat;
}
if (pmd_bad(*pgmiddle)) {
@@ -164,23 +164,21 @@ repeat:
}
pgtable = pte_offset(pgmiddle, addr);
if (!pte_present(*pgtable)) {
- do_no_page(vma, addr, 1);
+ do_no_page(tsk, vma, addr, 1);
goto repeat;
}
page = pte_page(*pgtable);
if (!pte_write(*pgtable)) {
- do_wp_page(vma, addr, 1);
+ do_wp_page(tsk, vma, addr, 1);
goto repeat;
}
/* this is a hack for non-kernel-mapped video buffers and similar */
- if (page < high_memory) {
- page += addr & ~PAGE_MASK;
- *(unsigned long *) page = data;
- }
+ if (MAP_NR(page) < max_mapnr)
+ *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
/* we're bypassing pagetables, so we have to set the dirty bit ourselves */
/* this should also re-instate whatever read-only mode there was before */
- *pgtable = pte_mkdirty(mk_pte(page, vma->vm_page_prot));
- invalidate();
+ set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
+ flush_tlb();
}
static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigned long addr)
@@ -188,7 +186,7 @@ static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigne
struct vm_area_struct * vma;
addr &= PAGE_MASK;
- vma = find_vma(tsk,addr);
+ vma = find_vma(tsk->mm,addr);
if (!vma)
return NULL;
if (vma->vm_start <= addr)
@@ -222,8 +220,8 @@ static int read_long(struct task_struct * tsk, unsigned long addr,
if (!vma_high || vma_high->vm_start != vma->vm_end)
return -EIO;
}
- low = get_long(vma, addr & ~(sizeof(long)-1));
- high = get_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
+ low = get_long(tsk, vma, addr & ~(sizeof(long)-1));
+ high = get_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
switch (addr & (sizeof(long)-1)) {
case 1:
low >>= 8;
@@ -240,7 +238,7 @@ static int read_long(struct task_struct * tsk, unsigned long addr,
}
*result = low;
} else
- *result = get_long(vma, addr);
+ *result = get_long(tsk, vma, addr);
return 0;
}
@@ -264,8 +262,8 @@ static int write_long(struct task_struct * tsk, unsigned long addr,
if (!vma_high || vma_high->vm_start != vma->vm_end)
return -EIO;
}
- low = get_long(vma, addr & ~(sizeof(long)-1));
- high = get_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
+ low = get_long(tsk, vma, addr & ~(sizeof(long)-1));
+ high = get_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
switch (addr & (sizeof(long)-1)) {
case 0: /* shouldn't happen, but safety first */
low = data;
@@ -289,13 +287,78 @@ static int write_long(struct task_struct * tsk, unsigned long addr,
high |= data >> 8;
break;
}
- put_long(vma, addr & ~(sizeof(long)-1),low);
- put_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1),high);
+ put_long(tsk, vma, addr & ~(sizeof(long)-1),low);
+ put_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1),high);
} else
- put_long(vma, addr, data);
+ put_long(tsk, vma, addr, data);
+ return 0;
+}
+
+static int putreg(struct task_struct *child,
+ unsigned long regno, unsigned long value)
+{
+ switch (regno >> 2) {
+ case ORIG_EAX:
+ return -EIO;
+ case FS:
+ if (value && (value & 3) != 3)
+ return -EIO;
+ child->tss.fs = value;
+ return 0;
+ case GS:
+ if (value && (value & 3) != 3)
+ return -EIO;
+ child->tss.gs = value;
+ return 0;
+ case DS:
+ case ES:
+ if (value && (value & 3) != 3)
+ return -EIO;
+ value &= 0xffff;
+ break;
+ case SS:
+ case CS:
+ if ((value & 3) != 3)
+ return -EIO;
+ value &= 0xffff;
+ break;
+ case EFL:
+ value &= FLAG_MASK;
+ value |= get_stack_long(child, EFL_OFFSET) & ~FLAG_MASK;
+ }
+ if (regno > GS*4)
+ regno -= 2*4;
+ put_stack_long(child, regno - sizeof(struct pt_regs), value);
return 0;
}
+static unsigned long getreg(struct task_struct *child,
+ unsigned long regno)
+{
+ unsigned long retval = ~0UL;
+
+ switch (regno >> 2) {
+ case FS:
+ retval = child->tss.fs;
+ break;
+ case GS:
+ retval = child->tss.gs;
+ break;
+ case DS:
+ case ES:
+ case SS:
+ case CS:
+ retval = 0xffff;
+ /* fall through */
+ default:
+ if (regno > GS*4)
+ regno -= 2*4;
+ regno = regno - sizeof(struct pt_regs);
+ retval &= get_stack_long(child, regno);
+ }
+ return retval;
+}
+
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
{
struct task_struct *child;
@@ -321,8 +384,10 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
return -EPERM;
if ((!child->dumpable ||
(current->uid != child->euid) ||
+ (current->uid != child->suid) ||
(current->uid != child->uid) ||
(current->gid != child->egid) ||
+ (current->gid != child->sgid) ||
(current->gid != child->gid)) && !suser())
return -EPERM;
/* the same process cannot be attached many times */
@@ -358,7 +423,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
return res;
res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long));
if (!res)
- put_fs_long(tmp,(unsigned long *) data);
+ put_user(tmp,(unsigned long *) data);
return res;
}
@@ -375,22 +440,15 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
if (res)
return res;
tmp = 0; /* Default return condition */
- if(addr < 17*sizeof(long)) {
- addr = addr >> 2; /* temporary hack. */
-
- tmp = get_stack_long(child, sizeof(long)*addr - MAGICNUMBER);
- if (addr == DS || addr == ES ||
- addr == FS || addr == GS ||
- addr == CS || addr == SS)
- tmp &= 0xffff;
- };
+ if(addr < 17*sizeof(long))
+ tmp = getreg(child, addr);
if(addr >= (long) &dummy->u_debugreg[0] &&
addr <= (long) &dummy->u_debugreg[7]){
addr -= (long) &dummy->u_debugreg[0];
addr = addr >> 2;
tmp = child->debugreg[addr];
};
- put_fs_long(tmp,(unsigned long *) data);
+ put_user(tmp,(unsigned long *) data);
return 0;
}
@@ -404,35 +462,14 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
addr > sizeof(struct user) - 3)
return -EIO;
- addr = addr >> 2; /* temporary hack. */
-
- if (addr == ORIG_EAX)
- return -EIO;
- if (addr == DS || addr == ES ||
- addr == FS || addr == GS ||
- addr == CS || addr == SS) {
- data &= 0xffff;
- if (data && (data & 3) != 3)
- return -EIO;
- }
- if (addr == EFL) { /* flags. */
- data &= FLAG_MASK;
- data |= get_stack_long(child, EFL*sizeof(long)-MAGICNUMBER) & ~FLAG_MASK;
- }
- /* Do not allow the user to set the debug register for kernel
- address space */
- if(addr < 17){
- if (put_stack_long(child, sizeof(long)*addr-MAGICNUMBER, data))
- return -EIO;
- return 0;
- };
+ if (addr < 17*sizeof(long))
+ return putreg(child, addr, data);
/* We need to be very careful here. We implicitly
want to modify a portion of the task_struct, and we
have to be selective about what portions we allow someone
to modify. */
- addr = addr << 2; /* Convert back again */
if(addr >= (long) &dummy->u_debugreg[0] &&
addr <= (long) &dummy->u_debugreg[7]){
@@ -466,10 +503,10 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
else
child->flags &= ~PF_TRACESYS;
child->exit_code = data;
- child->state = TASK_RUNNING;
+ wake_up_process(child);
/* make sure the single step bit is not set. */
- tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG;
- put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp);
+ tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
+ put_stack_long(child, EFL_OFFSET,tmp);
return 0;
}
@@ -481,11 +518,13 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
case PTRACE_KILL: {
long tmp;
- child->state = TASK_RUNNING;
+ if (child->state == TASK_ZOMBIE) /* already dead */
+ return 0;
+ wake_up_process(child);
child->exit_code = SIGKILL;
/* make sure the single step bit is not set. */
- tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG;
- put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp);
+ tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
+ put_stack_long(child, EFL_OFFSET, tmp);
return 0;
}
@@ -495,9 +534,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
if ((unsigned long) data > NSIG)
return -EIO;
child->flags &= ~PF_TRACESYS;
- tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) | TRAP_FLAG;
- put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp);
- child->state = TASK_RUNNING;
+ tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG;
+ put_stack_long(child, EFL_OFFSET, tmp);
+ wake_up_process(child);
child->exit_code = data;
/* give it a chance to run. */
return 0;
@@ -509,14 +548,14 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
if ((unsigned long) data > NSIG)
return -EIO;
child->flags &= ~(PF_PTRACED|PF_TRACESYS);
- child->state = TASK_RUNNING;
+ wake_up_process(child);
child->exit_code = data;
REMOVE_LINKS(child);
child->p_pptr = child->p_opptr;
SET_LINKS(child);
/* make sure the single step bit is not set. */
- tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG;
- put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp);
+ tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
+ put_stack_long(child, EFL_OFFSET, tmp);
return 0;
}
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index 5cc4c5d7d..3dae50628 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -5,7 +5,7 @@
*/
/*
- * This file handles the architecture-dependent parts of process handling..
+ * This file handles the architecture-dependent parts of initialization
*/
#include <linux/errno.h>
@@ -16,30 +16,37 @@
#include <linux/unistd.h>
#include <linux/ptrace.h>
#include <linux/malloc.h>
-#include <linux/ldt.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/delay.h>
-
-#include <asm/segment.h>
+#include <linux/config.h>
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+#endif
+#ifdef CONFIG_BLK_DEV_RAM
+#include <linux/blk.h>
+#endif
+#include <asm/uaccess.h>
#include <asm/system.h>
+#include <asm/smp.h>
/*
* Tell us the machine setup..
*/
-char hard_math = 0; /* set by boot/head.S */
-char x86 = 0; /* set by boot/head.S to 3 or 4 */
-char x86_model = 0; /* set by boot/head.S */
-char x86_mask = 0; /* set by boot/head.S */
-int x86_capability = 0; /* set by boot/head.S */
+char hard_math = 0; /* set by kernel/head.S */
+char x86 = 0; /* set by kernel/head.S to 3..6 */
+char x86_model = 0; /* set by kernel/head.S */
+char x86_mask = 0; /* set by kernel/head.S */
+int x86_capability = 0; /* set by kernel/head.S */
int fdiv_bug = 0; /* set if Pentium(TM) with FP bug */
+int have_cpuid = 0; /* set if CPUID instruction works */
-char x86_vendor_id[13] = "Unknown";
+char x86_vendor_id[13] = "unknown";
char ignore_irq13 = 0; /* set if exception 16 works */
-char wp_works_ok = 0; /* set if paging hardware honours WP */
+char wp_works_ok = -1; /* set if paging hardware honours WP */
char hlt_works_ok = 1; /* set if the "hlt" instruction works */
/*
@@ -52,11 +59,20 @@ int EISA_bus = 0;
*/
struct drive_info_struct { char dummy[32]; } drive_info;
struct screen_info screen_info;
+#ifdef CONFIG_APM
+struct apm_bios_info apm_bios_info;
+#endif
unsigned char aux_device_present;
-extern int ramdisk_size;
+
+#ifdef CONFIG_BLK_DEV_RAM
+extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */
+extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */
+extern int rd_image_start; /* starting block # of image */
+#endif
+
extern int root_mountflags;
-extern int etext, edata, end;
+extern int _etext, _edata, _end;
extern char empty_zero_page[PAGE_SIZE];
@@ -65,16 +81,28 @@ extern char empty_zero_page[PAGE_SIZE];
*/
#define PARAM empty_zero_page
#define EXT_MEM_K (*(unsigned short *) (PARAM+2))
+#ifdef CONFIG_APM
+#define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+64))
+#endif
#define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
#define SCREEN_INFO (*(struct screen_info *) (PARAM+0))
#define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
-#define RAMDISK_SIZE (*(unsigned short *) (PARAM+0x1F8))
+#define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8))
#define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC))
#define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF))
+#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210))
+#define KERNEL_START (*(unsigned long *) (PARAM+0x214))
+#define INITRD_START (*(unsigned long *) (PARAM+0x218))
+#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c))
#define COMMAND_LINE ((char *) (PARAM+2048))
#define COMMAND_LINE_SIZE 256
+#define RAMDISK_IMAGE_START_MASK 0x07FF
+#define RAMDISK_PROMPT_FLAG 0x8000
+#define RAMDISK_LOAD_FLAG 0x4000
+
static char command_line[COMMAND_LINE_SIZE] = { 0, };
+ char saved_command_line[COMMAND_LINE_SIZE];
void setup_arch(char **cmdline_p,
unsigned long * memory_start_p, unsigned long * memory_end_p)
@@ -82,35 +110,64 @@ void setup_arch(char **cmdline_p,
unsigned long memory_start, memory_end;
char c = ' ', *to = command_line, *from = COMMAND_LINE;
int len = 0;
+ static unsigned char smptrap=0;
+
+ if(smptrap==1)
+ {
+ return;
+ }
+ smptrap=1;
- ROOT_DEV = ORIG_ROOT_DEV;
+ ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
drive_info = DRIVE_INFO;
screen_info = SCREEN_INFO;
+#ifdef CONFIG_APM
+ apm_bios_info = APM_BIOS_INFO;
+#endif
aux_device_present = AUX_DEVICE_INFO;
memory_end = (1<<20) + (EXT_MEM_K<<10);
memory_end &= PAGE_MASK;
- ramdisk_size = RAMDISK_SIZE;
+#ifdef CONFIG_BLK_DEV_RAM
+ rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
+ rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
+ rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
+#endif
#ifdef CONFIG_MAX_16M
if (memory_end > 16*1024*1024)
memory_end = 16*1024*1024;
#endif
- if (MOUNT_ROOT_RDONLY)
- root_mountflags |= MS_RDONLY;
- memory_start = (unsigned long) &end;
- init_task.mm->start_code = TASK_SIZE;
- init_task.mm->end_code = TASK_SIZE + (unsigned long) &etext;
- init_task.mm->end_data = TASK_SIZE + (unsigned long) &edata;
- init_task.mm->brk = TASK_SIZE + (unsigned long) &end;
+ if (!MOUNT_ROOT_RDONLY)
+ root_mountflags &= ~MS_RDONLY;
+ memory_start = (unsigned long) &_end;
+ init_task.mm->start_code = PAGE_OFFSET;
+ init_task.mm->end_code = (unsigned long) &_etext;
+ init_task.mm->end_data = (unsigned long) &_edata;
+ init_task.mm->brk = (unsigned long) &_end;
+
+ /* Save unparsed command line copy for /proc/cmdline */
+ memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
+ saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
for (;;) {
- if (c == ' ' && *(unsigned long *)from == *(unsigned long *)"mem=") {
- memory_end = simple_strtoul(from+4, &from, 0);
- if ( *from == 'K' || *from == 'k' ) {
- memory_end = memory_end << 10;
- from++;
- } else if ( *from == 'M' || *from == 'm' ) {
- memory_end = memory_end << 20;
- from++;
+ /*
+ * "mem=nopentium" disables the 4MB page tables.
+ * "mem=XXX[kKmM]" overrides the BIOS-reported
+ * memory size
+ */
+ if (c == ' ' && *(const unsigned long *)from == *(const unsigned long *)"mem=") {
+ if (to != command_line) to--;
+ if (!memcmp(from+4, "nopentium", 9)) {
+ from += 9+4;
+ x86_capability &= ~8;
+ } else {
+ memory_end = simple_strtoul(from+4, &from, 0);
+ if ( *from == 'K' || *from == 'k' ) {
+ memory_end = memory_end << 10;
+ from++;
+ } else if ( *from == 'M' || *from == 'm' ) {
+ memory_end = memory_end << 20;
+ from++;
+ }
}
}
c = *(from++);
@@ -122,60 +179,159 @@ void setup_arch(char **cmdline_p,
}
*to = '\0';
*cmdline_p = command_line;
+ memory_end += PAGE_OFFSET;
*memory_start_p = memory_start;
*memory_end_p = memory_end;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (LOADER_TYPE) {
+ initrd_start = INITRD_START ? INITRD_START + PAGE_OFFSET : 0;
+ initrd_end = initrd_start+INITRD_SIZE;
+ if (initrd_end > memory_end) {
+ printk("initrd extends beyond end of memory "
+ "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+ initrd_end,memory_end);
+ initrd_start = 0;
+ }
+ }
+#endif
+
/* request io space for devices used on all i[345]86 PC'S */
request_region(0x00,0x20,"dma1");
request_region(0x40,0x20,"timer");
- request_region(0x70,0x10,"rtc");
request_region(0x80,0x20,"dma page reg");
request_region(0xc0,0x20,"dma2");
- request_region(0xf0,0x2,"npu");
- request_region(0xf8,0x8,"npu");
+ request_region(0xf0,0x10,"npu");
+}
+
+static const char * i486model(unsigned int nr)
+{
+ static const char *model[] = {
+ "0","DX","SX","DX/2","4","SX/2","6","DX/2-WB","DX/4","DX/4-WB",
+ "10","11","12","13","Am5x86-WT","Am5x86-WB"
+ };
+ if (nr < sizeof(model)/sizeof(char *))
+ return model[nr];
+ return NULL;
+}
+
+static const char * i586model(unsigned int nr)
+{
+ static const char *model[] = {
+ "0", "Pentium 60/66","Pentium 75+","OverDrive PODP5V83"
+ };
+ if (nr < sizeof(model)/sizeof(char *))
+ return model[nr];
+ return NULL;
+}
+
+static const char * i686model(unsigned int nr)
+{
+ static const char *model[] = {
+ "PPro A-step", "Pentium Pro"
+ };
+ if (nr < sizeof(model)/sizeof(char *))
+ return model[nr];
+ return NULL;
+}
+
+static const char * getmodel(int x86, int model)
+{
+ const char *p = NULL;
+ static char nbuf[12];
+ switch (x86) {
+ case 4:
+ p = i486model(model);
+ break;
+ case 5:
+ p = i586model(model);
+ break;
+ case 6:
+ p = i686model(model);
+ break;
+ }
+ if (p)
+ return p;
+
+ sprintf(nbuf, "%d", model);
+ return nbuf;
}
int get_cpuinfo(char * buffer)
{
- char *model[2][9]={{"DX","SX","DX/2","4","SX/2","6",
- "DX/2-WB","DX/4"},
- {"Pentium 60/66","Pentium 90/100","3",
- "4","5","6","7","8"}};
- char mask[2];
- mask[0] = x86_mask+'@';
- mask[1] = '\0';
- return sprintf(buffer,"cpu\t\t: %c86\n"
- "model\t\t: %s\n"
- "mask\t\t: %s\n"
- "vid\t\t: %s\n"
- "fdiv_bug\t: %s\n"
- "math\t\t: %s\n"
- "hlt\t\t: %s\n"
- "wp\t\t: %s\n"
- "Integrated NPU\t: %s\n"
- "Enhanced VM86\t: %s\n"
- "IO Breakpoints\t: %s\n"
- "4MB Pages\t: %s\n"
- "TS Counters\t: %s\n"
- "Pentium MSR\t: %s\n"
- "Mach. Ch. Exep.\t: %s\n"
- "CMPXCHGB8B\t: %s\n"
- "BogoMips\t: %lu.%02lu\n",
- x86+'0',
- x86_model ? model[x86-4][x86_model-1] : "Unknown",
- x86_mask ? mask : "Unknown",
- x86_vendor_id,
- fdiv_bug ? "yes" : "no",
- hard_math ? "yes" : "no",
- hlt_works_ok ? "yes" : "no",
- wp_works_ok ? "yes" : "no",
- x86_capability & 1 ? "yes" : "no",
- x86_capability & 2 ? "yes" : "no",
- x86_capability & 4 ? "yes" : "no",
- x86_capability & 8 ? "yes" : "no",
- x86_capability & 16 ? "yes" : "no",
- x86_capability & 32 ? "yes" : "no",
- x86_capability & 128 ? "yes" : "no",
- x86_capability & 256 ? "yes" : "no",
- loops_per_sec/500000, (loops_per_sec/5000) % 100
- );
+ int i, len = 0;
+ static const char *x86_cap_flags[] = {
+ "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
+ "cx8", "apic", "10", "11", "mtrr", "pge", "mca", "cmov",
+ "16", "17", "18", "19", "20", "21", "22", "mmx",
+ "24", "25", "26", "27", "28", "29", "30", "31"
+ };
+
+#ifdef __SMP__
+ int n;
+
+#define CD(X) (cpu_data[n].X)
+/* SMP has the wrong name for loops_per_sec */
+#define loops_per_sec udelay_val
+#define CPUN n
+
+ for ( n = 0 ; n < 32 ; n++ ) {
+ if ( cpu_present_map & (1<<n) ) {
+ if (len) buffer[len++] = '\n';
+
+#else
+#define CD(X) (X)
+#define CPUN 0
+#endif
+
+ len += sprintf(buffer+len,"processor\t: %d\n"
+ "cpu\t\t: %c86\n"
+ "model\t\t: %s\n"
+ "vendor_id\t: %s\n",
+ CPUN,
+ CD(x86)+'0',
+ CD(have_cpuid) ?
+ getmodel(CD(x86), CD(x86_model)) :
+ "unknown",
+ CD(x86_vendor_id));
+
+ if (CD(x86_mask))
+ len += sprintf(buffer+len,
+ "stepping\t: %d\n",
+ CD(x86_mask));
+ else
+ len += sprintf(buffer+len,
+ "stepping\t: unknown\n");
+
+ len += sprintf(buffer+len,
+ "fdiv_bug\t: %s\n"
+ "hlt_bug\t\t: %s\n"
+ "fpu\t\t: %s\n"
+ "fpu_exception\t: %s\n"
+ "cpuid\t\t: %s\n"
+ "wp\t\t: %s\n"
+ "flags\t\t:",
+ CD(fdiv_bug) ? "yes" : "no",
+ CD(hlt_works_ok) ? "no" : "yes",
+ CD(hard_math) ? "yes" : "no",
+ (CD(hard_math) && ignore_irq13)
+ ? "yes" : "no",
+ CD(have_cpuid) ? "yes" : "no",
+ CD(wp_works_ok) ? "yes" : "no");
+
+ for ( i = 0 ; i < 32 ; i++ ) {
+ if ( CD(x86_capability) & (1 << i) ) {
+ len += sprintf(buffer+len, " %s",
+ x86_cap_flags[i]);
+ }
+ }
+ len += sprintf(buffer+len,
+ "\nbogomips\t: %lu.%02lu\n",
+ CD(loops_per_sec+2500)/500000,
+ (CD(loops_per_sec+2500)/5000) % 100);
+#ifdef __SMP__
+ }
+ }
+#endif
+ return len;
}
diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
index 3db1a6985..c53a40e16 100644
--- a/arch/i386/kernel/signal.c
+++ b/arch/i386/kernel/signal.c
@@ -4,6 +4,8 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*/
+#include <linux/config.h>
+
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/kernel.h>
@@ -13,13 +15,14 @@
#include <linux/ptrace.h>
#include <linux/unistd.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#define _S(nr) (1<<((nr)-1))
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
+asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs);
/*
* atomically swap in the new signal mask, and wait for a signal.
@@ -40,28 +43,67 @@ asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long
}
}
+static inline void restore_i387_hard(struct _fpstate *buf)
+{
+#ifdef __SMP__
+ if (current->flags & PF_USEDFPU) {
+ stts();
+ }
+#else
+ if (current == last_task_used_math) {
+ last_task_used_math = NULL;
+ stts();
+ }
+#endif
+ current->used_math = 1;
+ current->flags &= ~PF_USEDFPU;
+ copy_from_user(&current->tss.i387.hard, buf, sizeof(*buf));
+}
+
+static void restore_i387(struct _fpstate *buf)
+{
+#ifndef CONFIG_MATH_EMULATION
+ restore_i387_hard(buf);
+#else
+ if (hard_math) {
+ restore_i387_hard(buf);
+ return;
+ }
+ restore_i387_soft(buf);
+#endif
+}
+
+
/*
* This sets regs->esp even though we don't actually use sigstacks yet..
*/
asmlinkage int sys_sigreturn(unsigned long __unused)
{
-#define COPY(x) regs->x = context.x
-#define COPY_SEG(x) \
-if ((context.x & 0xfffc) && (context.x & 3) != 3) goto badframe; COPY(x);
-#define COPY_SEG_STRICT(x) \
-if (!(context.x & 0xfffc) || (context.x & 3) != 3) goto badframe; COPY(x);
- struct sigcontext_struct context;
+#define COPY(x) regs->x = context->x
+#define COPY_SEG(seg) \
+{ unsigned int tmp = context->seg; \
+if ((tmp & 0xfffc) && (tmp & 3) != 3) goto badframe; \
+regs->x##seg = tmp; }
+#define COPY_SEG_STRICT(seg) \
+{ unsigned int tmp = context->seg; \
+if ((tmp & 0xfffc) && (tmp & 3) != 3) goto badframe; \
+regs->x##seg = tmp; }
+#define GET_SEG(seg) \
+{ unsigned int tmp = context->seg; \
+if ((tmp & 0xfffc) && (tmp & 3) != 3) goto badframe; \
+__asm__("mov %w0,%%" #seg: :"r" (tmp)); }
+ struct sigcontext * context;
struct pt_regs * regs;
regs = (struct pt_regs *) &__unused;
- if (verify_area(VERIFY_READ, (void *) regs->esp, sizeof(context)))
+ context = (struct sigcontext *) regs->esp;
+ if (verify_area(VERIFY_READ, context, sizeof(*context)))
goto badframe;
- memcpy_fromfs(&context,(void *) regs->esp, sizeof(context));
- current->blocked = context.oldmask & _BLOCKABLE;
+ current->blocked = context->oldmask & _BLOCKABLE;
COPY_SEG(ds);
COPY_SEG(es);
- COPY_SEG(fs);
- COPY_SEG(gs);
+ GET_SEG(fs);
+ GET_SEG(gs);
COPY_SEG_STRICT(ss);
COPY_SEG_STRICT(cs);
COPY(eip);
@@ -70,66 +112,164 @@ if (!(context.x & 0xfffc) || (context.x & 3) != 3) goto badframe; COPY(x);
COPY(esp); COPY(ebp);
COPY(edi); COPY(esi);
regs->eflags &= ~0x40DD5;
- regs->eflags |= context.eflags & 0x40DD5;
+ regs->eflags |= context->eflags & 0x40DD5;
regs->orig_eax = -1; /* disable syscall checks */
- return context.eax;
+ if (context->fpstate) {
+ struct _fpstate * buf = context->fpstate;
+ if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
+ goto badframe;
+ restore_i387(buf);
+ }
+ return context->eax;
badframe:
do_exit(SIGSEGV);
}
+static inline struct _fpstate * save_i387_hard(struct _fpstate * buf)
+{
+#ifdef __SMP__
+ if (current->flags & PF_USEDFPU) {
+ __asm__ __volatile__("fnsave %0":"=m" (current->tss.i387.hard));
+ stts();
+ current->flags &= ~PF_USEDFPU;
+ }
+#else
+ if (current == last_task_used_math) {
+ __asm__ __volatile__("fnsave %0":"=m" (current->tss.i387.hard));
+ last_task_used_math = NULL;
+ __asm__ __volatile__("fwait"); /* not needed on 486+ */
+ stts();
+ }
+#endif
+ current->tss.i387.hard.status = current->tss.i387.hard.swd;
+ copy_to_user(buf, &current->tss.i387.hard, sizeof(*buf));
+ current->used_math = 0;
+ return buf;
+}
+
+static struct _fpstate * save_i387(struct _fpstate * buf)
+{
+ if (!current->used_math)
+ return NULL;
+
+#ifndef CONFIG_MATH_EMULATION
+ return save_i387_hard(buf);
+#else
+ if (hard_math)
+ return save_i387_hard(buf);
+ return save_i387_soft(buf);
+#endif
+}
+
/*
* Set up a signal frame... Make the stack look the way iBCS2 expects
* it to look.
*/
-void setup_frame(struct sigaction * sa, unsigned long ** fp, unsigned long eip,
- struct pt_regs * regs, int signr, unsigned long oldmask)
+static void setup_frame(struct sigaction * sa,
+ struct pt_regs * regs, int signr,
+ unsigned long oldmask)
{
unsigned long * frame;
-#define __CODE ((unsigned long)(frame+24))
-#define CODE(x) ((unsigned long *) ((x)+__CODE))
- frame = *fp;
- if (regs->ss != USER_DS)
+ frame = (unsigned long *) regs->esp;
+ if ((regs->xss & 0xffff) != USER_DS && sa->sa_restorer)
frame = (unsigned long *) sa->sa_restorer;
- frame -= 32;
- if (verify_area(VERIFY_WRITE,frame,32*4))
+ frame -= 64;
+ if (verify_area(VERIFY_WRITE,frame,64*4))
do_exit(SIGSEGV);
+
/* set up the "normal" stack seen by the signal handler (iBCS2) */
- put_fs_long(__CODE,frame);
+#define __CODE ((unsigned long)(frame+24))
+#define CODE(x) ((unsigned long *) ((x)+__CODE))
+ if (put_user(__CODE,frame))
+ do_exit(SIGSEGV);
if (current->exec_domain && current->exec_domain->signal_invmap)
- put_fs_long(current->exec_domain->signal_invmap[signr], frame+1);
+ put_user(current->exec_domain->signal_invmap[signr], frame+1);
else
- put_fs_long(signr, frame+1);
- put_fs_long(regs->gs, frame+2);
- put_fs_long(regs->fs, frame+3);
- put_fs_long(regs->es, frame+4);
- put_fs_long(regs->ds, frame+5);
- put_fs_long(regs->edi, frame+6);
- put_fs_long(regs->esi, frame+7);
- put_fs_long(regs->ebp, frame+8);
- put_fs_long((long)*fp, frame+9);
- put_fs_long(regs->ebx, frame+10);
- put_fs_long(regs->edx, frame+11);
- put_fs_long(regs->ecx, frame+12);
- put_fs_long(regs->eax, frame+13);
- put_fs_long(current->tss.trap_no, frame+14);
- put_fs_long(current->tss.error_code, frame+15);
- put_fs_long(eip, frame+16);
- put_fs_long(regs->cs, frame+17);
- put_fs_long(regs->eflags, frame+18);
- put_fs_long(regs->esp, frame+19);
- put_fs_long(regs->ss, frame+20);
- put_fs_long(0,frame+21); /* 387 state pointer - not implemented*/
+ put_user(signr, frame+1);
+ {
+ unsigned int tmp = 0;
+#define PUT_SEG(seg, mem) \
+__asm__("mov %%" #seg",%w0":"=r" (tmp):"0" (tmp)); put_user(tmp,mem);
+ PUT_SEG(gs, frame+2);
+ PUT_SEG(fs, frame+3);
+ }
+ put_user(regs->xes, frame+4);
+ put_user(regs->xds, frame+5);
+ put_user(regs->edi, frame+6);
+ put_user(regs->esi, frame+7);
+ put_user(regs->ebp, frame+8);
+ put_user(regs->esp, frame+9);
+ put_user(regs->ebx, frame+10);
+ put_user(regs->edx, frame+11);
+ put_user(regs->ecx, frame+12);
+ put_user(regs->eax, frame+13);
+ put_user(current->tss.trap_no, frame+14);
+ put_user(current->tss.error_code, frame+15);
+ put_user(regs->eip, frame+16);
+ put_user(regs->xcs, frame+17);
+ put_user(regs->eflags, frame+18);
+ put_user(regs->esp, frame+19);
+ put_user(regs->xss, frame+20);
+ put_user((unsigned long) save_i387((struct _fpstate *)(frame+32)),frame+21);
/* non-iBCS2 extensions.. */
- put_fs_long(oldmask, frame+22);
- put_fs_long(current->tss.cr2, frame+23);
+ put_user(oldmask, frame+22);
+ put_user(current->tss.cr2, frame+23);
/* set up the return code... */
- put_fs_long(0x0000b858, CODE(0)); /* popl %eax ; movl $,%eax */
- put_fs_long(0x80cd0000, CODE(4)); /* int $0x80 */
- put_fs_long(__NR_sigreturn, CODE(2));
- *fp = frame;
+ put_user(0x0000b858, CODE(0)); /* popl %eax ; movl $,%eax */
+ put_user(0x80cd0000, CODE(4)); /* int $0x80 */
+ put_user(__NR_sigreturn, CODE(2));
#undef __CODE
#undef CODE
+
+ /* Set up registers for signal handler */
+ regs->esp = (unsigned long) frame;
+ regs->eip = (unsigned long) sa->sa_handler;
+ {
+ unsigned long seg = USER_DS;
+ __asm__("mov %w0,%%fs ; mov %w0,%%gs":"=r" (seg) :"0" (seg));
+ set_fs(seg);
+ regs->xds = seg;
+ regs->xes = seg;
+ regs->xss = seg;
+ regs->xcs = USER_CS;
+ }
+ regs->eflags &= ~TF_MASK;
+}
+
+/*
+ * OK, we're invoking a handler
+ */
+static void handle_signal(unsigned long signr, struct sigaction *sa,
+ unsigned long oldmask, struct pt_regs * regs)
+{
+ /* are we from a system call? */
+ if (regs->orig_eax >= 0) {
+ /* If so, check system call restarting.. */
+ switch (regs->eax) {
+ case -ERESTARTNOHAND:
+ regs->eax = -EINTR;
+ break;
+
+ case -ERESTARTSYS:
+ if (!(sa->sa_flags & SA_RESTART)) {
+ regs->eax = -EINTR;
+ break;
+ }
+ /* fallthrough */
+ case -ERESTARTNOINTR:
+ regs->eax = regs->orig_eax;
+ regs->eip -= 2;
+ }
+ }
+
+ /* set up the stack frame */
+ setup_frame(sa, regs, signr, oldmask);
+
+ if (sa->sa_flags & SA_ONESHOT)
+ sa->sa_handler = NULL;
+ if (!(sa->sa_flags & SA_NOMASK))
+ current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE;
}
/*
@@ -144,18 +284,21 @@ void setup_frame(struct sigaction * sa, unsigned long ** fp, unsigned long eip,
asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
{
unsigned long mask = ~current->blocked;
- unsigned long handler_signal = 0;
- unsigned long *frame = NULL;
- unsigned long eip = 0;
unsigned long signr;
struct sigaction * sa;
while ((signr = current->signal & mask)) {
+ /*
+ * This stops gcc flipping out. Otherwise the assembler
+ * including volatiles for the inline function to get
+ * current combined with this gets it confused.
+ */
+ struct task_struct *t=current;
__asm__("bsf %3,%1\n\t"
"btrl %1,%0"
- :"=m" (current->signal),"=r" (signr)
- :"0" (current->signal), "1" (signr));
- sa = current->sigaction + signr;
+ :"=m" (t->signal),"=r" (signr)
+ :"0" (t->signal), "1" (signr));
+ sa = current->sig->action + signr;
signr++;
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
current->exit_code = signr;
@@ -171,7 +314,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
current->signal |= _S(signr);
continue;
}
- sa = current->sigaction + signr - 1;
+ sa = current->sig->action + signr - 1;
}
if (sa->sa_handler == SIG_IGN) {
if (signr != SIGCHLD)
@@ -188,12 +331,15 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
case SIGCONT: case SIGCHLD: case SIGWINCH:
continue;
- case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
+ case SIGTSTP: case SIGTTIN: case SIGTTOU:
+ if (is_orphaned_pgrp(current->pgrp))
+ continue;
+ case SIGSTOP:
if (current->flags & PF_PTRACED)
continue;
current->state = TASK_STOPPED;
current->exit_code = signr;
- if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags &
+ if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
SA_NOCLDSTOP))
notify_parent(current);
schedule();
@@ -208,53 +354,23 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
/* fall through */
default:
current->signal |= _S(signr & 0x7f);
+ current->flags |= PF_SIGNALED;
do_exit(signr);
}
}
- /*
- * OK, we're invoking a handler
- */
- if (regs->orig_eax >= 0) {
- if (regs->eax == -ERESTARTNOHAND ||
- (regs->eax == -ERESTARTSYS && !(sa->sa_flags & SA_RESTART)))
- regs->eax = -EINTR;
- }
- handler_signal |= 1 << (signr-1);
- mask &= ~sa->sa_mask;
+ handle_signal(signr, sa, oldmask, regs);
+ return 1;
}
- if (regs->orig_eax >= 0 &&
- (regs->eax == -ERESTARTNOHAND ||
- regs->eax == -ERESTARTSYS ||
- regs->eax == -ERESTARTNOINTR)) {
- regs->eax = regs->orig_eax;
- regs->eip -= 2;
- }
- if (!handler_signal) /* no handler will be called - return 0 */
- return 0;
- eip = regs->eip;
- frame = (unsigned long *) regs->esp;
- signr = 1;
- sa = current->sigaction;
- for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
- if (mask > handler_signal)
- break;
- if (!(mask & handler_signal))
- continue;
- setup_frame(sa,&frame,eip,regs,signr,oldmask);
- eip = (unsigned long) sa->sa_handler;
- if (sa->sa_flags & SA_ONESHOT)
- sa->sa_handler = NULL;
-/* force a supervisor-mode page-in of the signal handler to reduce races */
- __asm__("testb $0,%%fs:%0": :"m" (*(char *) eip));
- regs->cs = USER_CS; regs->ss = USER_DS;
- regs->ds = USER_DS; regs->es = USER_DS;
- regs->gs = USER_DS; regs->fs = USER_DS;
- current->blocked |= sa->sa_mask;
- oldmask |= sa->sa_mask;
+
+ /* Did we come from a system call? */
+ if (regs->orig_eax >= 0) {
+ /* Restart the system call - no handlers present */
+ if (regs->eax == -ERESTARTNOHAND ||
+ regs->eax == -ERESTARTSYS ||
+ regs->eax == -ERESTARTNOINTR) {
+ regs->eax = regs->orig_eax;
+ regs->eip -= 2;
+ }
}
- regs->esp = (unsigned long) frame;
- regs->eip = eip; /* "return" to the first handler */
- regs->eflags &= ~TF_MASK;
- current->tss.trap_no = current->tss.error_code = 0;
- return 1;
+ return 0;
}
diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
new file mode 100644
index 000000000..05c80b711
--- /dev/null
+++ b/arch/i386/kernel/smp.c
@@ -0,0 +1,1204 @@
+/*
+ * Intel MP v1.1/v1.4 specification support routines for multi-pentium
+ * hosts.
+ *
+ * (c) 1995 Alan Cox, CymruNET Ltd <alan@cymru.net>
+ * Supported by Caldera http://www.caldera.com.
+ * Much of the core SMP work is based on previous work by Thomas Radke, to
+ * whom a great many thanks are extended.
+ *
+ * Thanks to Intel for making available several different Pentium and
+ * Pentium Pro MP machines.
+ *
+ * This code is released under the GNU public license version 2 or
+ * later.
+ *
+ * Fixes
+ * Felix Koop : NR_CPUS used properly
+ * Jose Renau : Handle single CPU case.
+ * Alan Cox : By repeated request 8) - Total BogoMIP report.
+ * Greg Wright : Fix for kernel stacks panic.
+ * Erich Boleyn : MP v1.4 and additional changes.
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/kernel_stat.h>
+#include <linux/delay.h>
+#include <linux/mc146818rtc.h>
+#include <asm/i82489.h>
+#include <linux/smp.h>
+#include <asm/pgtable.h>
+#include <asm/bitops.h>
+#include <asm/pgtable.h>
+#include <asm/smp.h>
+
+/*
+ * Why isn't this somewhere standard ??
+ */
+
+extern __inline int max(int a,int b)
+{
+ if(a>b)
+ return a;
+ return b;
+}
+
+
+int smp_found_config=0; /* Have we found an SMP box */
+
+unsigned long cpu_present_map = 0; /* Bitmask of existing CPU's */
+int smp_num_cpus = 1; /* Total count of live CPU's */
+int smp_threads_ready=0; /* Set when the idlers are all forked */
+volatile int cpu_number_map[NR_CPUS]; /* which CPU maps to which logical number */
+volatile int cpu_logical_map[NR_CPUS]; /* which logical number maps to which CPU */
+volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; /* We always use 0 the rest is ready for parallel delivery */
+volatile unsigned long smp_invalidate_needed; /* Used for the invalidate map that's also checked in the spinlock */
+struct cpuinfo_x86 cpu_data[NR_CPUS]; /* Per cpu bogomips and other parameters */
+static unsigned int num_processors = 1; /* Internal processor count */
+static unsigned long io_apic_addr = 0xFEC00000; /* Address of the I/O apic (not yet used) */
+unsigned char boot_cpu_id = 0; /* Processor that is doing the boot up */
+static unsigned char *kstack_base,*kstack_end; /* Kernel stack list pointers */
+static int smp_activated = 0; /* Tripped once we need to start cross invalidating */
+int apic_version[NR_CPUS]; /* APIC version number */
+static volatile int smp_commenced=0; /* Tripped when we start scheduling */
+unsigned long apic_addr=0xFEE00000; /* Address of APIC (defaults to 0xFEE00000) */
+unsigned long nlong = 0; /* dummy used for apic_reg address + 0x20 */
+unsigned char *apic_reg=((unsigned char *)(&nlong))-0x20;/* Later set to the ioremap() of the APIC */
+unsigned long apic_retval; /* Just debugging the assembler.. */
+unsigned char *kernel_stacks[NR_CPUS]; /* Kernel stack pointers for CPU's (debugging) */
+
+static volatile unsigned char smp_cpu_in_msg[NR_CPUS]; /* True if this processor is sending an IPI */
+static volatile unsigned long smp_msg_data; /* IPI data pointer */
+static volatile int smp_src_cpu; /* IPI sender processor */
+static volatile int smp_msg_id; /* Message being sent */
+
+volatile unsigned long kernel_flag=0; /* Kernel spinlock */
+volatile unsigned char active_kernel_processor = NO_PROC_ID; /* Processor holding kernel spinlock */
+volatile unsigned long kernel_counter=0; /* Number of times the processor holds the lock */
+volatile unsigned long syscall_count=0; /* Number of times the processor holds the syscall lock */
+
+volatile unsigned long ipi_count; /* Number of IPI's delivered */
+#ifdef __SMP_PROF__
+volatile unsigned long smp_spins[NR_CPUS]={0}; /* Count interrupt spins */
+volatile unsigned long smp_spins_syscall[NR_CPUS]={0}; /* Count syscall spins */
+volatile unsigned long smp_spins_syscall_cur[NR_CPUS]={0};/* Count spins for the actual syscall */
+volatile unsigned long smp_spins_sys_idle[NR_CPUS]={0}; /* Count spins for sys_idle */
+volatile unsigned long smp_idle_count[1+NR_CPUS]={0,}; /* Count idle ticks */
+#endif
+#if defined (__SMP_PROF__)
+volatile unsigned long smp_idle_map=0; /* Map for idle processors */
+#endif
+
+volatile unsigned long smp_proc_in_lock[NR_CPUS] = {0,};/* for computing process time */
+volatile unsigned long smp_process_available=0;
+
+/*#define SMP_DEBUG*/
+
+#ifdef SMP_DEBUG
+#define SMP_PRINTK(x) printk x
+#else
+#define SMP_PRINTK(x)
+#endif
+
+
+/*
+ * Checksum an MP configuration block.
+ */
+
+static int mpf_checksum(unsigned char *mp, int len)
+{
+ int sum=0;
+ while(len--)
+ sum+=*mp++;
+ return sum&0xFF;
+}
+
+/*
+ * Processor encoding in an MP configuration block
+ */
+
+static char *mpc_family(int family,int model)
+{
+ static char n[32];
+ static char *model_defs[]=
+ {
+ "80486DX","80486DX",
+ "80486SX","80486DX/2 or 80487",
+ "80486SL","Intel5X2(tm)",
+ "Unknown","Unknown",
+ "80486DX/4"
+ };
+ if(family==0x6)
+ return("Pentium(tm) Pro");
+ if(family==0x5)
+ return("Pentium(tm)");
+ if(family==0x0F && model==0x0F)
+ return("Special controller");
+ if(family==0x04 && model<9)
+ return model_defs[model];
+ sprintf(n,"Unknown CPU [%d:%d]",family, model);
+ return n;
+}
+
+/*
+ * Read the MPC
+ */
+
+static int smp_read_mpc(struct mp_config_table *mpc)
+{
+ char str[16];
+ int count=sizeof(*mpc);
+ int apics=0;
+ unsigned char *mpt=((unsigned char *)mpc)+count;
+
+ if(memcmp(mpc->mpc_signature,MPC_SIGNATURE,4))
+ {
+ printk("Bad signature [%c%c%c%c].\n",
+ mpc->mpc_signature[0],
+ mpc->mpc_signature[1],
+ mpc->mpc_signature[2],
+ mpc->mpc_signature[3]);
+ return 1;
+ }
+ if(mpf_checksum((unsigned char *)mpc,mpc->mpc_length))
+ {
+ printk("Checksum error.\n");
+ return 1;
+ }
+ if(mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04)
+ {
+ printk("Bad Config Table version (%d)!!\n",mpc->mpc_spec);
+ return 1;
+ }
+ memcpy(str,mpc->mpc_oem,8);
+ str[8]=0;
+ printk("OEM ID: %s ",str);
+ memcpy(str,mpc->mpc_productid,12);
+ str[12]=0;
+ printk("Product ID: %s ",str);
+ printk("APIC at: 0x%lX\n",mpc->mpc_lapic);
+
+ /* set the local APIC address */
+ apic_addr = mpc->mpc_lapic;
+
+ /*
+ * Now process the configuration blocks.
+ */
+
+ while(count<mpc->mpc_length)
+ {
+ switch(*mpt)
+ {
+ case MP_PROCESSOR:
+ {
+ struct mpc_config_processor *m=
+ (struct mpc_config_processor *)mpt;
+ if(m->mpc_cpuflag&CPU_ENABLED)
+ {
+ printk("Processor #%d %s APIC version %d\n",
+ m->mpc_apicid,
+ mpc_family((m->mpc_cpufeature&
+ CPU_FAMILY_MASK)>>8,
+ (m->mpc_cpufeature&
+ CPU_MODEL_MASK)>>4),
+ m->mpc_apicver);
+#ifdef SMP_DEBUG
+ if(m->mpc_featureflag&(1<<0))
+ printk(" Floating point unit present.\n");
+ if(m->mpc_featureflag&(1<<7))
+ printk(" Machine Exception supported.\n");
+ if(m->mpc_featureflag&(1<<8))
+ printk(" 64 bit compare & exchange supported.\n");
+ if(m->mpc_featureflag&(1<<9))
+ printk(" Internal APIC present.\n");
+#endif
+ if(m->mpc_cpuflag&CPU_BOOTPROCESSOR)
+ {
+ SMP_PRINTK((" Bootup CPU\n"));
+ boot_cpu_id=m->mpc_apicid;
+ }
+ else /* Boot CPU already counted */
+ num_processors++;
+
+ if(m->mpc_apicid>NR_CPUS)
+ printk("Processor #%d unused. (Max %d processors).\n",m->mpc_apicid, NR_CPUS);
+ else
+ {
+ cpu_present_map|=(1<<m->mpc_apicid);
+ apic_version[m->mpc_apicid]=m->mpc_apicver;
+ }
+ }
+ mpt+=sizeof(*m);
+ count+=sizeof(*m);
+ break;
+ }
+ case MP_BUS:
+ {
+ struct mpc_config_bus *m=
+ (struct mpc_config_bus *)mpt;
+ memcpy(str,m->mpc_bustype,6);
+ str[6]=0;
+ SMP_PRINTK(("Bus #%d is %s\n",
+ m->mpc_busid,
+ str));
+ mpt+=sizeof(*m);
+ count+=sizeof(*m);
+ break;
+ }
+ case MP_IOAPIC:
+ {
+ struct mpc_config_ioapic *m=
+ (struct mpc_config_ioapic *)mpt;
+ if(m->mpc_flags&MPC_APIC_USABLE)
+ {
+ apics++;
+ printk("I/O APIC #%d Version %d at 0x%lX.\n",
+ m->mpc_apicid,m->mpc_apicver,
+ m->mpc_apicaddr);
+ io_apic_addr = m->mpc_apicaddr;
+ }
+ mpt+=sizeof(*m);
+ count+=sizeof(*m);
+ break;
+ }
+ case MP_INTSRC:
+ {
+ struct mpc_config_intsrc *m=
+ (struct mpc_config_intsrc *)mpt;
+
+ mpt+=sizeof(*m);
+ count+=sizeof(*m);
+ break;
+ }
+ case MP_LINTSRC:
+ {
+ struct mpc_config_intlocal *m=
+ (struct mpc_config_intlocal *)mpt;
+ mpt+=sizeof(*m);
+ count+=sizeof(*m);
+ break;
+ }
+ }
+ }
+ if(apics>1)
+ printk("Warning: Multiple APIC's not supported.\n");
+ return num_processors;
+}
+
+/*
+ * Scan the memory blocks for an SMP configuration block.
+ */
+
+int smp_scan_config(unsigned long base, unsigned long length)
+{
+ unsigned long *bp=(unsigned long *)base;
+ struct intel_mp_floating *mpf;
+
+ SMP_PRINTK(("Scan SMP from %p for %ld bytes.\n",
+ bp,length));
+ if(sizeof(*mpf)!=16)
+ printk("Error: MPF size\n");
+
+ while(length>0)
+ {
+ if(*bp==SMP_MAGIC_IDENT)
+ {
+ mpf=(struct intel_mp_floating *)bp;
+ if(mpf->mpf_length==1 &&
+ !mpf_checksum((unsigned char *)bp,16) &&
+ (mpf->mpf_specification == 1
+ || mpf->mpf_specification == 4) )
+ {
+ printk("Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification);
+ if(mpf->mpf_feature2&(1<<7))
+ printk(" IMCR and PIC compatibility mode.\n");
+ else
+ printk(" Virtual Wire compatibility mode.\n");
+ smp_found_config=1;
+ /*
+ * Now see if we need to read further.
+ */
+ if(mpf->mpf_feature1!=0)
+ {
+ unsigned long cfg;
+
+ /*
+ * We need to know what the local
+ * APIC id of the boot CPU is!
+ */
+
+/*
+ *
+ * HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK
+ *
+ * It's not just a crazy hack... ;-)
+ */
+ /*
+ * Standard page mapping
+ * functions don't work yet.
+ * We know that page 0 is not
+ * used. Steal it for now!
+ */
+
+ cfg=pg0[0];
+ pg0[0] = (apic_addr | 7);
+ local_flush_tlb();
+
+ boot_cpu_id = GET_APIC_ID(*((volatile unsigned long *) APIC_ID));
+
+ /*
+ * Give it back
+ */
+
+ pg0[0]= cfg;
+ local_flush_tlb();
+
+/*
+ *
+ * END OF HACK END OF HACK END OF HACK END OF HACK END OF HACK
+ *
+ */
+ /*
+ * 2 CPUs, numbered 0 & 1.
+ */
+ cpu_present_map=3;
+ num_processors=2;
+ printk("I/O APIC at 0xFEC00000.\n");
+ printk("Bus#0 is ");
+ }
+ switch(mpf->mpf_feature1)
+ {
+ case 1:
+ case 5:
+ printk("ISA\n");
+ break;
+ case 2:
+ printk("EISA with no IRQ8 chaining\n");
+ break;
+ case 6:
+ case 3:
+ printk("EISA\n");
+ break;
+ case 4:
+ case 7:
+ printk("MCA\n");
+ break;
+ case 0:
+ break;
+ default:
+ printk("???\nUnknown standard configuration %d\n",
+ mpf->mpf_feature1);
+ return 1;
+ }
+ if(mpf->mpf_feature1>4)
+ {
+ printk("Bus #1 is PCI\n");
+
+ /*
+ * Set local APIC version to
+ * the integrated form.
+ * It's initialized to zero
+ * otherwise, representing
+ * a discrete 82489DX.
+ */
+ apic_version[0] = 0x10;
+ apic_version[1] = 0x10;
+ }
+ /*
+ * Read the physical hardware table.
+ * Anything here will override the
+ * defaults.
+ */
+ if(mpf->mpf_physptr)
+ smp_read_mpc((void *)mpf->mpf_physptr);
+
+ /*
+ * Now that the boot CPU id is known,
+ * set some other information about it.
+ */
+ nlong = boot_cpu_id<<24; /* Dummy 'self' for bootup */
+ cpu_logical_map[0] = boot_cpu_id;
+
+ printk("Processors: %d\n", num_processors);
+ /*
+ * Only use the first configuration found.
+ */
+ return 1;
+ }
+ }
+ bp+=4;
+ length-=16;
+ }
+
+ return 0;
+}
+
+/*
+ * Trampoline 80x86 program as an array.
+ */
+
+static unsigned char trampoline_data[]={
+#include "trampoline.hex"
+};
+
+/*
+ * Currently trivial. Write the real->protected mode
+ * bootstrap into the page concerned. The caller
+ * has made sure it's suitably aligned.
+ */
+
+static void install_trampoline(unsigned char *mp)
+{
+ memcpy(mp,trampoline_data,sizeof(trampoline_data));
+}
+
+/*
+ * We are called very early to get the low memory for the trampoline/kernel stacks
+ * This has to be done by mm/init.c to parcel us out nice low memory. We allocate
+ * the kernel stacks at 4K, 8K, 12K... currently (0-03FF is preserved for SMM and
+ * other things).
+ */
+
+unsigned long smp_alloc_memory(unsigned long mem_base)
+{
+ int size=(num_processors-1)*PAGE_SIZE; /* Number of stacks needed */
+ /*
+ * Our stacks have to be below the 1Mb line, and mem_base on entry
+ * is 4K aligned.
+ */
+
+ if(mem_base+size>=0x9F000)
+ panic("smp_alloc_memory: Insufficient low memory for kernel stacks.\n");
+ kstack_base=(void *)mem_base;
+ mem_base+=size;
+ kstack_end=(void *)mem_base;
+ return mem_base;
+}
+
+/*
+ * Hand out stacks one at a time.
+ */
+
+static void *get_kernel_stack(void)
+{
+ void *stack=kstack_base;
+ if(kstack_base>=kstack_end)
+ return NULL;
+ kstack_base+=PAGE_SIZE;
+ return stack;
+}
+
+
+/*
+ * The bootstrap kernel entry code has set these up. Save them for
+ * a given CPU
+ */
+
+void smp_store_cpu_info(int id)
+{
+ struct cpuinfo_x86 *c=&cpu_data[id];
+ c->hard_math=hard_math; /* Always assumed same currently */
+ c->x86=x86;
+ c->x86_model=x86_model;
+ c->x86_mask=x86_mask;
+ c->x86_capability=x86_capability;
+ c->fdiv_bug=fdiv_bug;
+ c->wp_works_ok=wp_works_ok; /* Always assumed the same currently */
+ c->hlt_works_ok=hlt_works_ok;
+ c->have_cpuid=have_cpuid;
+ c->udelay_val=loops_per_sec;
+ strcpy(c->x86_vendor_id, x86_vendor_id);
+}
+
+/*
+ * Architecture specific routine called by the kernel just before init is
+ * fired off. This allows the BP to have everything in order [we hope].
+ * At the end of this all the AP's will hit the system scheduling and off
+ * we go. Each AP will load the system gdt's and jump through the kernel
+ * init into idle(). At this point the scheduler will one day take over
+ * and give them jobs to do. smp_callin is a standard routine
+ * we use to track CPU's as they power up.
+ */
+
+void smp_commence(void)
+{
+ /*
+ * Lets the callin's below out of their loop.
+ */
+ smp_commenced=1;
+}
+
+void smp_callin(void)
+{
+ extern void calibrate_delay(void);
+ int cpuid=GET_APIC_ID(apic_read(APIC_ID));
+ unsigned long l;
+
+ /*
+ * Activate our APIC
+ */
+
+ SMP_PRINTK(("CALLIN %d\n",smp_processor_id()));
+ l=apic_read(APIC_SPIV);
+ l|=(1<<8); /* Enable */
+ apic_write(APIC_SPIV,l);
+ sti();
+ /*
+ * Get our bogomips.
+ */
+ calibrate_delay();
+ /*
+ * Save our processor parameters
+ */
+ smp_store_cpu_info(cpuid);
+ /*
+ * Allow the master to continue.
+ */
+ set_bit(cpuid, (unsigned long *)&cpu_callin_map[0]);
+ /*
+ * Until we are ready for SMP scheduling
+ */
+ load_ldt(0);
+/* printk("Testing faulting...\n");
+ *(long *)0=1; OOPS... */
+ local_flush_tlb();
+ while(!smp_commenced);
+ if (cpu_number_map[cpuid] == -1)
+ while(1);
+ local_flush_tlb();
+ SMP_PRINTK(("Commenced..\n"));
+
+ load_TR(cpu_number_map[cpuid]);
+/* while(1);*/
+}
+
+/*
+ * Cycle through the processors sending pentium IPI's to boot each.
+ */
+
+void smp_boot_cpus(void)
+{
+ int i;
+ int cpucount=0;
+ unsigned long cfg;
+ void *stack;
+ extern unsigned long init_user_stack[];
+
+ /*
+ * Initialize the logical to physical cpu number mapping
+ */
+
+ for (i = 0; i < NR_CPUS; i++)
+ cpu_number_map[i] = -1;
+
+ /*
+ * Setup boot CPU information
+ */
+
+ kernel_stacks[boot_cpu_id]=(void *)init_user_stack; /* Set up for boot processor first */
+
+ smp_store_cpu_info(boot_cpu_id); /* Final full version of the data */
+
+ cpu_present_map |= (1 << smp_processor_id());
+ cpu_number_map[boot_cpu_id] = 0;
+ active_kernel_processor=boot_cpu_id;
+
+ /*
+ * If we don't conform to the Intel MPS standard, get out
+ * of here now!
+ */
+
+ if (!smp_found_config)
+ return;
+
+ /*
+ * Map the local APIC into kernel space
+ */
+
+ apic_reg = ioremap(apic_addr,4096);
+
+ if(apic_reg == NULL)
+ panic("Unable to map local apic.\n");
+
+#ifdef SMP_DEBUG
+ {
+ int reg;
+
+ /*
+ * This is to verify that we're looking at
+ * a real local APIC. Check these against
+ * your board if the CPUs aren't getting
+ * started for no apparent reason.
+ */
+
+ reg = apic_read(APIC_VERSION);
+ SMP_PRINTK(("Getting VERSION: %x\n", reg));
+
+ apic_write(APIC_VERSION, 0);
+ reg = apic_read(APIC_VERSION);
+ SMP_PRINTK(("Getting VERSION: %x\n", reg));
+
+ /*
+ * The two version reads above should print the same
+ * NON-ZERO!!! numbers. If the second one is zero,
+ * there is a problem with the APIC write/read
+ * definitions.
+ *
+ * The next two are just to see if we have sane values.
+ * They're only really relevant if we're in Virtual Wire
+ * compatibility mode, but most boxes are anymore.
+ */
+
+
+ reg = apic_read(APIC_LVT0);
+ SMP_PRINTK(("Getting LVT0: %x\n", reg));
+
+ reg = apic_read(APIC_LVT1);
+ SMP_PRINTK(("Getting LVT1: %x\n", reg));
+ }
+#endif
+
+ /*
+ * Enable the local APIC
+ */
+
+ cfg=apic_read(APIC_SPIV);
+ cfg|=(1<<8); /* Enable APIC */
+ apic_write(APIC_SPIV,cfg);
+
+ udelay(10);
+
+ /*
+ * Now scan the cpu present map and fire up the other CPUs.
+ */
+
+ SMP_PRINTK(("CPU map: %lx\n", cpu_present_map));
+
+ for(i=0;i<NR_CPUS;i++)
+ {
+ /*
+ * Don't even attempt to start the boot CPU!
+ */
+ if (i == boot_cpu_id)
+ continue;
+
+ if (cpu_present_map & (1 << i))
+ {
+ unsigned long send_status, accept_status;
+ int timeout, num_starts, j;
+
+ /*
+ * We need a kernel stack for each processor.
+ */
+
+ stack=get_kernel_stack(); /* We allocated these earlier */
+ if(stack==NULL)
+ panic("No memory for processor stacks.\n");
+ kernel_stacks[i]=stack;
+ install_trampoline(stack);
+
+ printk("Booting processor %d stack %p: ",i,stack); /* So we set what's up */
+
+ /*
+ * This grunge runs the startup process for
+ * the targeted processor.
+ */
+
+ SMP_PRINTK(("Setting warm reset code and vector.\n"));
+
+ /*
+ * Install a writable page 0 entry.
+ */
+
+ cfg=pg0[0];
+
+ CMOS_WRITE(0xa, 0xf);
+ pg0[0]=7;
+ local_flush_tlb();
+ *((volatile unsigned short *) 0x469) = ((unsigned long)stack)>>4;
+ *((volatile unsigned short *) 0x467) = 0;
+
+ /*
+ * Protect it again
+ */
+
+ pg0[0]= cfg;
+ local_flush_tlb();
+
+ /*
+ * Be paranoid about clearing APIC errors.
+ */
+
+ if ( apic_version[i] & 0xF0 )
+ {
+ apic_write(APIC_ESR, 0);
+ accept_status = (apic_read(APIC_ESR) & 0xEF);
+ }
+
+ /*
+ * Status is now clean
+ */
+
+ send_status = 0;
+ accept_status = 0;
+
+ /*
+ * Starting actual IPI sequence...
+ */
+
+ SMP_PRINTK(("Asserting INIT.\n"));
+
+ /*
+ * Turn INIT on
+ */
+
+ cfg=apic_read(APIC_ICR2);
+ cfg&=0x00FFFFFF;
+ apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */
+ cfg=apic_read(APIC_ICR);
+ cfg&=~0xCDFFF; /* Clear bits */
+ cfg |= (APIC_DEST_FIELD | APIC_DEST_LEVELTRIG
+ | APIC_DEST_ASSERT | APIC_DEST_DM_INIT);
+ apic_write(APIC_ICR, cfg); /* Send IPI */
+
+ udelay(200);
+ SMP_PRINTK(("Deasserting INIT.\n"));
+
+ cfg=apic_read(APIC_ICR2);
+ cfg&=0x00FFFFFF;
+ apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */
+ cfg=apic_read(APIC_ICR);
+ cfg&=~0xCDFFF; /* Clear bits */
+ cfg |= (APIC_DEST_FIELD | APIC_DEST_LEVELTRIG
+ | APIC_DEST_DM_INIT);
+ apic_write(APIC_ICR, cfg); /* Send IPI */
+
+ /*
+ * Should we send STARTUP IPIs ?
+ *
+ * Determine this based on the APIC version.
+ * If we don't have an integrated APIC, don't
+ * send the STARTUP IPIs.
+ */
+
+ if ( apic_version[i] & 0xF0 )
+ num_starts = 2;
+ else
+ num_starts = 0;
+
+ /*
+ * Run STARTUP IPI loop.
+ */
+
+ for (j = 1; !(send_status || accept_status)
+ && (j <= num_starts) ; j++)
+ {
+ SMP_PRINTK(("Sending STARTUP #%d.\n",j));
+
+ apic_write(APIC_ESR, 0);
+
+ /*
+ * STARTUP IPI
+ */
+
+ cfg=apic_read(APIC_ICR2);
+ cfg&=0x00FFFFFF;
+ apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */
+ cfg=apic_read(APIC_ICR);
+ cfg&=~0xCDFFF; /* Clear bits */
+ cfg |= (APIC_DEST_FIELD
+ | APIC_DEST_DM_STARTUP
+ | (((int) stack) >> 12) ); /* Boot on the stack */
+ apic_write(APIC_ICR, cfg); /* Kick the second */
+
+ timeout = 0;
+ do {
+ udelay(10);
+ } while ( (send_status = (apic_read(APIC_ICR) & 0x1000))
+ && (timeout++ < 1000));
+ udelay(200);
+
+ accept_status = (apic_read(APIC_ESR) & 0xEF);
+ }
+
+ if (send_status) /* APIC never delivered?? */
+ printk("APIC never delivered???\n");
+ if (accept_status) /* Send accept error */
+ printk("APIC delivery error (%lx).\n", accept_status);
+
+ if( !(send_status || accept_status) )
+ {
+ for(timeout=0;timeout<50000;timeout++)
+ {
+ if(cpu_callin_map[0]&(1<<i))
+ break; /* It has booted */
+ udelay(100); /* Wait 5s total for a response */
+ }
+ if(cpu_callin_map[0]&(1<<i))
+ {
+ cpucount++;
+ /* number CPUs logically, starting from 1 (BSP is 0) */
+ cpu_number_map[i] = cpucount;
+ cpu_logical_map[cpucount] = i;
+ }
+ else
+ {
+ if(*((volatile unsigned char *)8192)==0xA5)
+ printk("Stuck ??\n");
+ else
+ printk("Not responding.\n");
+ }
+ }
+
+ /* mark "stuck" area as not stuck */
+ *((volatile unsigned long *)8192) = 0;
+ }
+
+ /*
+ * Make sure we unmap all failed CPUs
+ */
+
+ if (cpu_number_map[i] == -1)
+ cpu_present_map &= ~(1 << i);
+ }
+
+ /*
+ * Cleanup possible dangling ends...
+ */
+
+ /*
+ * Install writable page 0 entry.
+ */
+
+ cfg = pg0[0];
+ pg0[0] = 3; /* writeable, present, addr 0 */
+ local_flush_tlb();
+
+ /*
+ * Paranoid: Set warm reset code and vector here back
+ * to default values.
+ */
+
+ CMOS_WRITE(0, 0xf);
+
+ *((volatile long *) 0x467) = 0;
+
+ /*
+ * Restore old page 0 entry.
+ */
+
+ pg0[0] = cfg;
+ local_flush_tlb();
+
+ /*
+ * Allow the user to impress friends.
+ */
+
+ if(cpucount==0)
+ {
+ printk("Error: only one processor found.\n");
+ cpu_present_map=(1<<smp_processor_id());
+ }
+ else
+ {
+ unsigned long bogosum=0;
+ for(i=0;i<32;i++)
+ {
+ if(cpu_present_map&(1<<i))
+ bogosum+=cpu_data[i].udelay_val;
+ }
+ printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
+ cpucount+1,
+ (bogosum+2500)/500000,
+ ((bogosum+2500)/5000)%100);
+ smp_activated=1;
+ smp_num_cpus=cpucount+1;
+ }
+}
+
+
+/*
+ * A non wait message cannot pass data or cpu source info. This current setup
+ * is only safe because the kernel lock owner is the only person who can send a message.
+ *
+ * Wrapping this whole block in a spinlock is not the safe answer either. A processor may
+ * get stuck with irq's off waiting to send a message and thus not replying to the person
+ * spinning for a reply....
+ *
+ * In the end flush tlb ought to be the NMI and a very very short function (to avoid the old
+ * IDE disk problems), and other messages sent with IRQ's enabled in a civilised fashion. That
+ * will also boost performance.
+ */
+
+void smp_message_pass(int target, int msg, unsigned long data, int wait)
+{
+ unsigned long cfg;
+ unsigned long target_map;
+ int p=smp_processor_id();
+ int irq=0x2d; /* IRQ 13 */
+ int ct=0;
+ static volatile int message_cpu = NO_PROC_ID;
+
+ /*
+ * During boot up send no messages
+ */
+
+ if(!smp_activated || !smp_commenced)
+ return;
+
+
+ /*
+ * Skip the reschedule if we are waiting to clear a
+ * message at this time. The reschedule cannot wait
+ * but is not critical.
+ */
+
+ if(msg==MSG_RESCHEDULE) /* Reschedules we do via trap 0x30 */
+ {
+ irq=0x30;
+ if(smp_cpu_in_msg[p])
+ return;
+ }
+
+ /*
+ * Sanity check we don't re-enter this across CPU's. Only the kernel
+ * lock holder may send messages. For a STOP_CPU we are bringing the
+ * entire box to the fastest halt we can.. A reschedule carries
+ * no data and can occur during a flush.. guess what panic
+ * I got to notice this bug...
+ */
+
+ if(message_cpu!=NO_PROC_ID && msg!=MSG_STOP_CPU && msg!=MSG_RESCHEDULE)
+ {
+ panic("CPU #%d: Message pass %d but pass in progress by %d of %d\n",
+ smp_processor_id(),msg,message_cpu, smp_msg_id);
+ }
+ message_cpu=smp_processor_id();
+
+
+ /*
+ * We are busy
+ */
+
+ smp_cpu_in_msg[p]++;
+
+ /*
+ * Reschedule is currently special
+ */
+
+ if(msg!=MSG_RESCHEDULE)
+ {
+ smp_src_cpu=p;
+ smp_msg_id=msg;
+ smp_msg_data=data;
+ }
+
+/* printk("SMP message pass #%d to %d of %d\n",
+ p, msg, target);*/
+
+ /*
+ * Wait for the APIC to become ready - this should never occur. Its
+ * a debugging check really.
+ */
+
+ while(ct<1000)
+ {
+ cfg=apic_read(APIC_ICR);
+ if(!(cfg&(1<<12)))
+ break;
+ ct++;
+ udelay(10);
+ }
+
+ /*
+ * Just pray... there is nothing more we can do
+ */
+
+ if(ct==1000)
+ printk("CPU #%d: previous IPI still not cleared after 10mS", smp_processor_id());
+
+ /*
+ * Program the APIC to deliver the IPI
+ */
+
+ cfg=apic_read(APIC_ICR2);
+ cfg&=0x00FFFFFF;
+ apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(target)); /* Target chip */
+ cfg=apic_read(APIC_ICR);
+ cfg&=~0xFDFFF; /* Clear bits */
+ cfg|=APIC_DEST_FIELD|APIC_DEST_DM_FIXED|irq; /* Send an IRQ 13 */
+
+ /*
+ * Set the target requirement
+ */
+
+ if(target==MSG_ALL_BUT_SELF)
+ {
+ cfg|=APIC_DEST_ALLBUT;
+ target_map=cpu_present_map;
+ cpu_callin_map[0]=(1<<smp_src_cpu);
+ }
+ else if(target==MSG_ALL)
+ {
+ cfg|=APIC_DEST_ALLINC;
+ target_map=cpu_present_map;
+ cpu_callin_map[0]=0;
+ }
+ else
+ {
+ target_map=(1<<target);
+ cpu_callin_map[0]=0;
+ }
+
+ /*
+ * Send the IPI. The write to APIC_ICR fires this off.
+ */
+
+ apic_write(APIC_ICR, cfg);
+
+ /*
+ * Spin waiting for completion
+ */
+
+ switch(wait)
+ {
+ case 1:
+ while(cpu_callin_map[0]!=target_map); /* Spin on the pass */
+ break;
+ case 2:
+ while(smp_invalidate_needed); /* Wait for invalidate map to clear */
+ break;
+ }
+
+ /*
+ * Record our completion
+ */
+
+ smp_cpu_in_msg[p]--;
+ message_cpu=NO_PROC_ID;
+}
+
+/*
+ * This is fraught with deadlocks. Linus does a flush tlb at a whim
+ * even with IRQ's off. We have to avoid a pair of crossing flushes
+ * or we are doomed. See the notes about smp_message_pass.
+ */
+
+void smp_flush_tlb(void)
+{
+ unsigned long flags;
+ if(smp_activated && smp_processor_id()!=active_kernel_processor)
+ panic("CPU #%d:Attempted flush tlb IPI when not AKP(=%d)\n",smp_processor_id(),active_kernel_processor);
+/* printk("SMI-");*/
+
+ /*
+ * The assignment is safe because it's volatile so the compiler cannot reorder it,
+ * because the i586 has strict memory ordering and because only the kernel lock holder
+ * may issue a tlb flush. If you break any one of those three change this to an atomic
+ * bus locked or.
+ */
+
+ smp_invalidate_needed=cpu_present_map&~(1<<smp_processor_id());
+
+ /*
+ * Processors spinning on the lock will see this IRQ late. The smp_invalidate_needed map will
+ * ensure they don't do a spurious flush tlb or miss one.
+ */
+
+ save_flags(flags);
+ cli();
+ smp_message_pass(MSG_ALL_BUT_SELF, MSG_INVALIDATE_TLB, 0L, 2);
+
+ /*
+ * Flush the local TLB
+ */
+
+ local_flush_tlb();
+
+ restore_flags(flags);
+
+ /*
+ * Completed.
+ */
+
+/* printk("SMID\n");*/
+}
+
+/*
+ * Reschedule call back
+ */
+
+void smp_reschedule_irq(int cpl, struct pt_regs *regs)
+{
+#ifdef DEBUGGING_SMP_RESCHED
+ static int ct=0;
+ if(ct==0)
+ {
+ printk("Beginning scheduling on CPU#%d\n",smp_processor_id());
+ ct=1;
+ }
+#endif
+ if(smp_processor_id()!=active_kernel_processor)
+ panic("SMP Reschedule on CPU #%d, but #%d is active.\n",
+ smp_processor_id(), active_kernel_processor);
+
+ need_resched=1;
+
+ /*
+ * Clear the IPI
+ */
+ apic_read(APIC_SPIV); /* Dummy read */
+ apic_write(APIC_EOI, 0); /* Docs say use 0 for future compatibility */
+}
+
+/*
+ * Message call back.
+ */
+
+void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs)
+{
+ int i=smp_processor_id();
+/* static int n=0;
+ if(n++<NR_CPUS)
+ printk("IPI %d->%d(%d,%ld)\n",smp_src_cpu,i,smp_msg_id,smp_msg_data);*/
+ switch(smp_msg_id)
+ {
+ case 0: /* IRQ 13 testing - boring */
+ return;
+
+ /*
+ * A TLB flush is needed.
+ */
+
+ case MSG_INVALIDATE_TLB:
+ if(clear_bit(i,(unsigned long *)&smp_invalidate_needed))
+ local_flush_tlb();
+ set_bit(i, (unsigned long *)&cpu_callin_map[0]);
+ /* cpu_callin_map[0]|=1<<smp_processor_id();*/
+ break;
+
+ /*
+ * Halt other CPU's for a panic or reboot
+ */
+ case MSG_STOP_CPU:
+ while(1)
+ {
+ if(cpu_data[smp_processor_id()].hlt_works_ok)
+ __asm__("hlt");
+ }
+ default:
+ printk("CPU #%d sent invalid cross CPU message to CPU #%d: %X(%lX).\n",
+ smp_src_cpu,smp_processor_id(),smp_msg_id,smp_msg_data);
+ break;
+ }
+ /*
+ * Clear the IPI, so we can receive future IPI's
+ */
+
+ apic_read(APIC_SPIV); /* Dummy read */
+ apic_write(APIC_EOI, 0); /* Docs say use 0 for future compatibility */
+}
diff --git a/arch/i386/kernel/sys_i386.c b/arch/i386/kernel/sys_i386.c
new file mode 100644
index 000000000..619b372d8
--- /dev/null
+++ b/arch/i386/kernel/sys_i386.c
@@ -0,0 +1,181 @@
+/*
+ * linux/arch/i386/kernel/sys_i386.c
+ *
+ * This file contains various random system calls that
+ * have a non-standard calling sequence on the Linux/i386
+ * platform.
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/stat.h>
+#include <linux/mman.h>
+#include <linux/file.h>
+
+#include <asm/uaccess.h>
+#include <asm/ipc.h>
+
+/*
+ * sys_pipe() is the normal C calling standard for creating
+ * a pipe. It's not the way unix traditionally does this, though.
+ */
+asmlinkage int sys_pipe(unsigned long * fildes)
+{
+ int fd[2];
+ int error;
+
+ error = verify_area(VERIFY_WRITE,fildes,8);
+ if (error)
+ return error;
+ error = do_pipe(fd);
+ if (error)
+ return error;
+ put_user(fd[0],0+fildes);
+ put_user(fd[1],1+fildes);
+ return 0;
+}
+
+/*
+ * Perform the select(nd, in, out, ex, tv) and mmap() system
+ * calls. Linux/i386 didn't use to be able to handle more than
+ * 4 system call parameters, so these system calls used a memory
+ * block for parameter passing..
+ */
+struct mmap_arg_struct {
+ unsigned long addr;
+ unsigned long len;
+ unsigned long prot;
+ unsigned long flags;
+ unsigned long fd;
+ unsigned long offset;
+};
+
+asmlinkage int old_mmap(struct mmap_arg_struct *arg)
+{
+ int error;
+ struct file * file = NULL;
+ struct mmap_arg_struct a;
+
+ error = verify_area(VERIFY_READ, arg, sizeof(*arg));
+ if (error)
+ return error;
+ copy_from_user(&a, arg, sizeof(a));
+ if (!(a.flags & MAP_ANONYMOUS)) {
+ if (a.fd >= NR_OPEN || !(file = current->files->fd[a.fd]))
+ return -EBADF;
+ }
+ a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset);
+ return error;
+}
+
+extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+
+struct sel_arg_struct {
+ unsigned long n;
+ fd_set *inp, *outp, *exp;
+ struct timeval *tvp;
+};
+
+asmlinkage int old_select(struct sel_arg_struct *arg)
+{
+ struct sel_arg_struct a;
+
+ if (copy_from_user(&a, arg, sizeof(a)))
+ return -EFAULT;
+ return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
+}
+
+/*
+ * sys_ipc() is the de-multiplexer for the SysV IPC calls..
+ *
+ * This is really horribly ugly.
+ */
+asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
+{
+ int version;
+
+ version = call >> 16; /* hack for backward compatibility */
+ call &= 0xffff;
+
+ if (call <= SEMCTL)
+ switch (call) {
+ case SEMOP:
+ return sys_semop (first, (struct sembuf *)ptr, second);
+ case SEMGET:
+ return sys_semget (first, second, third);
+ case SEMCTL: {
+ union semun fourth;
+ int err;
+ if (!ptr)
+ return -EINVAL;
+ if ((err = verify_area (VERIFY_READ, ptr, sizeof(long))))
+ return err;
+ get_user(fourth.__pad, (void **) ptr);
+ return sys_semctl (first, second, third, fourth);
+ }
+ default:
+ return -EINVAL;
+ }
+ if (call <= MSGCTL)
+ switch (call) {
+ case MSGSND:
+ return sys_msgsnd (first, (struct msgbuf *) ptr,
+ second, third);
+ case MSGRCV:
+ switch (version) {
+ case 0: {
+ struct ipc_kludge tmp;
+ int err;
+ if (!ptr)
+ return -EINVAL;
+ if ((err = verify_area (VERIFY_READ, ptr, sizeof(tmp))))
+ return err;
+ copy_from_user(&tmp,(struct ipc_kludge *) ptr, sizeof (tmp));
+ return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
+ }
+ case 1: default:
+ return sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
+ }
+ case MSGGET:
+ return sys_msgget ((key_t) first, second);
+ case MSGCTL:
+ return sys_msgctl (first, second, (struct msqid_ds *) ptr);
+ default:
+ return -EINVAL;
+ }
+ if (call <= SHMCTL)
+ switch (call) {
+ case SHMAT:
+ switch (version) {
+ case 0: default: {
+ ulong raddr;
+ int err;
+ if ((err = verify_area(VERIFY_WRITE, (ulong*) third, sizeof(ulong))))
+ return err;
+ err = sys_shmat (first, (char *) ptr, second, &raddr);
+ if (err)
+ return err;
+ put_user (raddr, (ulong *) third);
+ return 0;
+ }
+ case 1: /* iBCS2 emulator entry point */
+ if (get_fs() != get_ds())
+ return -EINVAL;
+ return sys_shmat (first, (char *) ptr, second, (ulong *) third);
+ }
+ case SHMDT:
+ return sys_shmdt ((char *)ptr);
+ case SHMGET:
+ return sys_shmget (first, second, third);
+ case SHMCTL:
+ return sys_shmctl (first, second, (struct shmid_ds *) ptr);
+ default:
+ return -EINVAL;
+ }
+ return -EINVAL;
+}
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
new file mode 100644
index 000000000..0eddd66e5
--- /dev/null
+++ b/arch/i386/kernel/time.c
@@ -0,0 +1,500 @@
+/*
+ * linux/arch/i386/kernel/time.c
+ *
+ * Copyright (C) 1991, 1992, 1995 Linus Torvalds
+ *
+ * This file contains the PC-specific time handling details:
+ * reading the RTC at bootup, etc..
+ * 1994-07-02 Alan Modra
+ * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
+ * 1995-03-26 Markus Kuhn
+ * fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887
+ * precision CMOS clock update
+ * 1996-05-03 Ingo Molnar
+ * fixed time warps in do_[slow|fast]_gettimeoffset()
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/delay.h>
+
+#include <linux/mc146818rtc.h>
+#include <linux/timex.h>
+#include <linux/config.h>
+
+extern int setup_x86_irq(int, struct irqaction *);
+
+#ifndef CONFIG_APM /* cycle counter may be unreliable */
+/* Cycle counter value at the previous timer interrupt.. */
+static struct {
+ unsigned long low;
+ unsigned long high;
+} init_timer_cc, last_timer_cc;
+
+/*
+ * This is more assembly than C, but it's also rather
+ * timing-critical and we have to use assembler to get
+ * reasonable 64-bit arithmetic
+ */
+static unsigned long do_fast_gettimeoffset(void)
+{
+ register unsigned long eax asm("ax");
+ register unsigned long edx asm("dx");
+ unsigned long tmp, quotient, low_timer, missing_time;
+
+ /* Last jiffy when do_fast_gettimeoffset() was called.. */
+ static unsigned long last_jiffies=0;
+
+ /* Cached "clocks per usec" value.. */
+ static unsigned long cached_quotient=0;
+
+ /* The "clocks per usec" value is calculated once each jiffy */
+ tmp = jiffies;
+ quotient = cached_quotient;
+ low_timer = last_timer_cc.low;
+ missing_time = 0;
+ if (last_jiffies != tmp) {
+ last_jiffies = tmp;
+ /*
+ * test for hanging bottom handler (this means xtime is not
+ * updated yet)
+ */
+ if (test_bit(TIMER_BH, &bh_active) )
+ {
+ missing_time = 1000020/HZ;
+ }
+
+ /* Get last timer tick in absolute kernel time */
+ eax = low_timer;
+ edx = last_timer_cc.high;
+ __asm__("subl "SYMBOL_NAME_STR(init_timer_cc)",%0\n\t"
+ "sbbl "SYMBOL_NAME_STR(init_timer_cc)"+4,%1"
+ :"=a" (eax), "=d" (edx)
+ :"0" (eax), "1" (edx));
+
+ /*
+ * Divide the 64-bit time with the 32-bit jiffy counter,
+ * getting the quotient in clocks.
+ *
+ * Giving quotient = "average internal clocks per usec"
+ */
+ __asm__("divl %2"
+ :"=a" (eax), "=d" (edx)
+ :"r" (tmp),
+ "0" (eax), "1" (edx));
+
+ edx = 1000020/HZ;
+ tmp = eax;
+ eax = 0;
+
+ __asm__("divl %2"
+ :"=a" (eax), "=d" (edx)
+ :"r" (tmp),
+ "0" (eax), "1" (edx));
+ cached_quotient = eax;
+ quotient = eax;
+ }
+
+ /* Read the time counter */
+ __asm__(".byte 0x0f,0x31"
+ :"=a" (eax), "=d" (edx));
+
+ /* .. relative to previous jiffy (32 bits is enough) */
+ edx = 0;
+ eax -= low_timer;
+
+ /*
+ * Time offset = (1000020/HZ * time_low) / quotient.
+ */
+
+ __asm__("mull %2"
+ :"=a" (eax), "=d" (edx)
+ :"r" (quotient),
+ "0" (eax), "1" (edx));
+
+ /*
+ * Due to rounding errors (and jiffies inconsistencies),
+ * we need to check the result so that we'll get a timer
+ * that is monotonic.
+ */
+ if (edx >= 1000020/HZ)
+ edx = 1000020/HZ-1;
+
+ eax = edx + missing_time;
+ return eax;
+}
+#endif
+
+/* This function must be called with interrupts disabled
+ * It was inspired by Steve McCanne's microtime-i386 for BSD. -- jrs
+ *
+ * However, the pc-audio speaker driver changes the divisor so that
+ * it gets interrupted rather more often - it loads 64 into the
+ * counter rather than 11932! This has an adverse impact on
+ * do_gettimeoffset() -- it stops working! What is also not
+ * good is that the interval that our timer function gets called
+ * is no longer 10.0002 ms, but 9.9767 ms. To get around this
+ * would require using a different timing source. Maybe someone
+ * could use the RTC - I know that this can interrupt at frequencies
+ * ranging from 8192Hz to 2Hz. If I had the energy, I'd somehow fix
+ * it so that at startup, the timer code in sched.c would select
+ * using either the RTC or the 8253 timer. The decision would be
+ * based on whether there was any other device around that needed
+ * to trample on the 8253. I'd set up the RTC to interrupt at 1024 Hz,
+ * and then do some jiggery to have a version of do_timer that
+ * advanced the clock by 1/1024 s. Every time that reached over 1/100
+ * of a second, then do all the old code. If the time was kept correct
+ * then do_gettimeoffset could just return 0 - there is no low order
+ * divider that can be accessed.
+ *
+ * Ideally, you would be able to use the RTC for the speaker driver,
+ * but it appears that the speaker driver really needs interrupt more
+ * often than every 120 us or so.
+ *
+ * Anyway, this needs more thought.... pjsg (1993-08-28)
+ *
+ * If you are really that interested, you should be reading
+ * comp.protocols.time.ntp!
+ */
+
+#define TICK_SIZE tick
+
+static unsigned long do_slow_gettimeoffset(void)
+{
+ int count;
+ static int count_p = 0;
+ unsigned long offset = 0;
+ static unsigned long jiffies_p = 0;
+
+ /*
+ * cache volatile jiffies temporarily; we have IRQs turned off.
+ */
+ unsigned long jiffies_t;
+
+ /* timer count may underflow right here */
+ outb_p(0x00, 0x43); /* latch the count ASAP */
+ count = inb_p(0x40); /* read the latched count */
+ count |= inb(0x40) << 8;
+
+ jiffies_t = jiffies;
+
+ /*
+ * avoiding timer inconsistencies (they are rare, but they happen)...
+ * there are three kinds of problems that must be avoided here:
+ * 1. the timer counter underflows
+ * 2. hardware problem with the timer, not giving us continuous time,
+ * the counter does small "jumps" upwards on some Pentium systems,
+ * thus causes time warps
+ * 3. we are after the timer interrupt, but the bottom half handler
+ * hasn't executed yet.
+ */
+ if( count > count_p ) {
+ if( jiffies_t == jiffies_p ) {
+ if( count > LATCH-LATCH/100 )
+ offset = TICK_SIZE;
+ else
+ /*
+ * argh, the timer is bugging we cant do nothing
+ * but to give the previous clock value.
+ */
+ count = count_p;
+ } else {
+ if( test_bit(TIMER_BH, &bh_active) ) {
+ /*
+ * we have detected a counter underflow.
+ */
+ offset = TICK_SIZE;
+ count_p = count;
+ } else {
+ count_p = count;
+ jiffies_p = jiffies_t;
+ }
+ }
+ } else {
+ count_p = count;
+ jiffies_p = jiffies_t;
+ }
+
+
+ count = ((LATCH-1) - count) * TICK_SIZE;
+ count = (count + LATCH/2) / LATCH;
+
+ return offset + count;
+}
+
+/*
+ * this is only used if we have fast gettimeoffset:
+ */
+void do_x86_get_fast_time(struct timeval * tv)
+{
+ do_gettimeofday(tv);
+}
+
+static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
+
+/*
+ * This version of gettimeofday has near microsecond resolution.
+ */
+void do_gettimeofday(struct timeval *tv)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ *tv = xtime;
+ tv->tv_usec += do_gettimeoffset();
+ if (tv->tv_usec >= 1000000) {
+ tv->tv_usec -= 1000000;
+ tv->tv_sec++;
+ }
+ restore_flags(flags);
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+ cli();
+ /* This is revolting. We need to set the xtime.tv_usec
+ * correctly. However, the value in this location is
+ * is value at the last tick.
+ * Discover what correction gettimeofday
+ * would have done, and then undo it!
+ */
+ tv->tv_usec -= do_gettimeoffset();
+
+ if (tv->tv_usec < 0) {
+ tv->tv_usec += 1000000;
+ tv->tv_sec--;
+ }
+
+ xtime = *tv;
+ time_state = TIME_BAD;
+ time_maxerror = MAXPHASE;
+ time_esterror = MAXPHASE;
+ sti();
+}
+
+
+/*
+ * In order to set the CMOS clock precisely, set_rtc_mmss has to be
+ * called 500 ms after the second nowtime has started, because when
+ * nowtime is written into the registers of the CMOS clock, it will
+ * jump to the next second precisely 500 ms later. Check the Motorola
+ * MC146818A or Dallas DS12887 data sheet for details.
+ */
+static int set_rtc_mmss(unsigned long nowtime)
+{
+ int retval = 0;
+ int real_seconds, real_minutes, cmos_minutes;
+ unsigned char save_control, save_freq_select;
+
+ save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
+ CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+
+ save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
+ CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+ cmos_minutes = CMOS_READ(RTC_MINUTES);
+ if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+ BCD_TO_BIN(cmos_minutes);
+
+ /*
+ * since we're only adjusting minutes and seconds,
+ * don't interfere with hour overflow. This avoids
+ * messing with unknown time zones but requires your
+ * RTC not to be off by more than 15 minutes
+ */
+ real_seconds = nowtime % 60;
+ real_minutes = nowtime / 60;
+ if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
+ real_minutes += 30; /* correct for half hour time zone */
+ real_minutes %= 60;
+
+ if (abs(real_minutes - cmos_minutes) < 30) {
+ if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+ BIN_TO_BCD(real_seconds);
+ BIN_TO_BCD(real_minutes);
+ }
+ CMOS_WRITE(real_seconds,RTC_SECONDS);
+ CMOS_WRITE(real_minutes,RTC_MINUTES);
+ } else
+ retval = -1;
+
+ /* The following flags have to be released exactly in this order,
+ * otherwise the DS12887 (popular MC146818A clone with integrated
+ * battery and quartz) will not reset the oscillator and will not
+ * update precisely 500 ms later. You won't find this mentioned in
+ * the Dallas Semiconductor data sheets, but who believes data
+ * sheets anyway ... -- Markus Kuhn
+ */
+ CMOS_WRITE(save_control, RTC_CONTROL);
+ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+
+ return retval;
+}
+
+/* last time the cmos clock got updated */
+static long last_rtc_update = 0;
+
+/*
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+static inline void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ do_timer(regs);
+
+ /*
+ * If we have an externally synchronized Linux clock, then update
+ * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+ * called as close as possible to 500 ms before the new second starts.
+ */
+ if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
+ xtime.tv_usec > 500000 - (tick >> 1) &&
+ xtime.tv_usec < 500000 + (tick >> 1))
+ if (set_rtc_mmss(xtime.tv_sec) == 0)
+ last_rtc_update = xtime.tv_sec;
+ else
+ last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+ /* As we return to user mode fire off the other CPU schedulers.. this is
+ basically because we don't yet share IRQ's around. This message is
+ rigged to be safe on the 386 - basically it's a hack, so don't look
+ closely for now.. */
+ /*smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0); */
+
+}
+
+#ifndef CONFIG_APM /* cycle counter may be unreliable */
+/*
+ * This is the same as the above, except we _also_ save the current
+ * cycle counter value at the time of the timer interrupt, so that
+ * we later on can estimate the time of day more exactly.
+ */
+static void pentium_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ /* read Pentium cycle counter */
+ __asm__(".byte 0x0f,0x31"
+ :"=a" (last_timer_cc.low),
+ "=d" (last_timer_cc.high));
+ timer_interrupt(irq, NULL, regs);
+}
+#endif
+
+/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
+ * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
+ * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
+ *
+ * [For the Julian calendar (which was used in Russia before 1917,
+ * Britain & colonies before 1752, anywhere else before 1582,
+ * and is still in use by some communities) leave out the
+ * -year/100+year/400 terms, and add 10.]
+ *
+ * This algorithm was first published by Gauss (I think).
+ *
+ * WARNING: this function will overflow on 2106-02-07 06:28:16 on
+ * machines were long is 32-bit! (However, as time_t is signed, we
+ * will already get problems at other places on 2038-01-19 03:14:08)
+ */
+static inline unsigned long mktime(unsigned int year, unsigned int mon,
+ unsigned int day, unsigned int hour,
+ unsigned int min, unsigned int sec)
+{
+ if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */
+ mon += 12; /* Puts Feb last since it has leap day */
+ year -= 1;
+ }
+ return (((
+ (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
+ year*365 - 719499
+ )*24 + hour /* now have hours */
+ )*60 + min /* now have minutes */
+ )*60 + sec; /* finally seconds */
+}
+
+unsigned long get_cmos_time(void)
+{
+ unsigned int year, mon, day, hour, min, sec;
+ int i;
+
+ /* The Linux interpretation of the CMOS clock register contents:
+ * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
+ * RTC registers show the second which has precisely just started.
+ * Let's hope other operating systems interpret the RTC the same way.
+ */
+ /* read RTC exactly on falling edge of update flag */
+ for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
+ if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
+ break;
+ for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
+ if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
+ break;
+ do { /* Isn't this overkill ? UIP above should guarantee consistency */
+ sec = CMOS_READ(RTC_SECONDS);
+ min = CMOS_READ(RTC_MINUTES);
+ hour = CMOS_READ(RTC_HOURS);
+ day = CMOS_READ(RTC_DAY_OF_MONTH);
+ mon = CMOS_READ(RTC_MONTH);
+ year = CMOS_READ(RTC_YEAR);
+ } while (sec != CMOS_READ(RTC_SECONDS));
+ if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+ {
+ BCD_TO_BIN(sec);
+ BCD_TO_BIN(min);
+ BCD_TO_BIN(hour);
+ BCD_TO_BIN(day);
+ BCD_TO_BIN(mon);
+ BCD_TO_BIN(year);
+ }
+ if ((year += 1900) < 1970)
+ year += 100;
+ return mktime(year, mon, day, hour, min, sec);
+}
+
+static struct irqaction irq0 = { timer_interrupt, 0, 0, "timer", NULL, NULL};
+
+void time_init(void)
+{
+ xtime.tv_sec = get_cmos_time();
+ xtime.tv_usec = 0;
+
+ /* If we have the CPU hardware time counters, use them */
+#ifndef CONFIG_APM
+ /* Don't use them if a suspend/resume could
+ corrupt the timer value. This problem
+ needs more debugging. */
+ if (x86_capability & 16) {
+ do_gettimeoffset = do_fast_gettimeoffset;
+ do_get_fast_time = do_x86_get_fast_time;
+
+ if( strcmp( x86_vendor_id, "AuthenticAMD" ) == 0 ) {
+ if( x86 == 5 ) {
+ if( x86_model == 0 ) {
+ /* turn on cycle counters during power down */
+ __asm__ __volatile__ (" movl $0x83, %%ecx \n \
+ .byte 0x0f,0x32 \n \
+ orl $1,%%eax \n \
+ .byte 0x0f,0x30 \n "
+ : : : "ax", "cx", "dx" );
+ udelay(500);
+ }
+ }
+ }
+
+ /* read Pentium cycle counter */
+ __asm__(".byte 0x0f,0x31"
+ :"=a" (init_timer_cc.low),
+ "=d" (init_timer_cc.high));
+ irq0.handler = pentium_timer_interrupt;
+ }
+#endif
+ setup_x86_irq(0, &irq0);
+}
diff --git a/arch/i386/kernel/trampoline.S b/arch/i386/kernel/trampoline.S
new file mode 100644
index 000000000..29bcc9040
--- /dev/null
+++ b/arch/i386/kernel/trampoline.S
@@ -0,0 +1,74 @@
+!
+! Trampoline.S Derived from Setup.S by Linus Torvalds
+!
+! Entry: CS:IP point to the start of our code, we are
+! in real mode with no stack, but the rest of the
+! trampoline page to make our stack and everything else
+! is a mystery.
+!
+! In fact we don't actually need a stack so we don't
+! set one up.
+!
+! We jump into the boot/compressed/head.S code. So you'd
+! better be running a compressed kernel image or you
+! won't get very far.
+!
+#define __ASSEMBLY__
+#include <asm/segment.h>
+
+.text
+ extrn startup32
+
+entry start
+start:
+! nop
+! jmp start ! Test
+ mov ax,cs ! Code and data in the same place
+ mov ds,ax !
+ mov cx,ax ! Pass stack info to the 32bit boot
+ add cx,cx
+ add cx,cx
+ add cx,cx
+ add cx,cx ! Segment -> Offset
+ add cx, #4096 ! End of page is wanted
+ mov bx,#1 ! Flag an SMP trampoline
+ cli ! We should be safe anyway
+
+ lidt idt_48 ! load idt with 0,0
+ lgdt gdt_48 ! load gdt with whatever is appropriate
+
+ xor ax,ax
+ inc ax ! protected mode (PE) bit
+ lmsw ax ! Into protected mode
+ jmp flush_instr
+flush_instr:
+ jmpi 8192+startup32,KERNEL_CS ! Jump to the 32bit trampoline code
+! jmpi 0x100000,KERNEL_CS ! Jump into the 32bit startup
+! .byte 0x66,0x67 ! 32bit
+! .byte 0xea,0x00,0x00,0x10,0x00,0x10,0x00 !jmpi .0x100000,KERNEL_CS
+
+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 8192+gdt,0x0 ! gdt base = 8192+gdt (first SMP CPU)
+ ! we load the others with the first table
+ ! saves rewriting gdt_48 for each
+
diff --git a/arch/i386/kernel/trampoline32.S b/arch/i386/kernel/trampoline32.S
new file mode 100644
index 000000000..fafa972a0
--- /dev/null
+++ b/arch/i386/kernel/trampoline32.S
@@ -0,0 +1,20 @@
+!
+! 32bit side of the trampoline code
+!
+#define __ASSEMBLY__
+#include <asm/segment.h>
+!
+!
+! Anything but a relative address here will be wrong by 8K...
+!
+ .globl startup32
+.text
+startup32:
+! Run the kernel
+ mov eax,#KERNEL_DS
+ mov ds,ax
+ mov eax,#0xA5A5A5A5
+ mov [8192],eax
+ jmpi 0x100000,KERNEL_CS
+l1:
+ .byte 0xEA,0x00,0x00,0x10,0x00,0x10,0x00
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 6dd7fc65b..8dfab81c5 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -10,6 +10,7 @@
* to mainly kill the offending process (probably by giving it a signal,
* but possibly by killing it outright if necessary).
*/
+#include <linux/config.h>
#include <linux/head.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -21,12 +22,12 @@
#include <linux/mm.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/io.h>
asmlinkage int system_call(void);
asmlinkage void lcall7(void);
-struct desc_struct default_ldt;
+struct desc_struct default_ldt = { 0, 0 };
static inline void console_verbose(void)
{
@@ -39,9 +40,7 @@ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
{ \
tsk->tss.error_code = error_code; \
tsk->tss.trap_no = trapnr; \
- if (signr == SIGTRAP && current->flags & PF_PTRACED) \
- current->blocked &= ~(1 << (SIGTRAP-1)); \
- send_sig(signr, tsk, 1); \
+ force_sig(signr, tsk); \
die_if_kernel(str,regs,error_code); \
}
@@ -82,6 +81,7 @@ asmlinkage void page_fault(void);
asmlinkage void coprocessor_error(void);
asmlinkage void reserved(void);
asmlinkage void alignment_check(void);
+asmlinkage void spurious_interrupt_bug(void);
int kstack_depth_to_print = 24;
@@ -93,31 +93,32 @@ int kstack_depth_to_print = 24;
#define VMALLOC_OFFSET (8*1024*1024)
#define MODULE_RANGE (8*1024*1024)
-/*static*/ void die_if_kernel(char * str, struct pt_regs * regs, long err)
+/*static*/ void die_if_kernel(const char * str, struct pt_regs * regs, long err)
{
int i;
unsigned long esp;
unsigned short ss;
unsigned long *stack, addr, module_start, module_end;
- extern char start_kernel, etext;
+ extern char start_kernel, _etext;
esp = (unsigned long) &regs->esp;
ss = KERNEL_DS;
- if ((regs->eflags & VM_MASK) || (3 & regs->cs) == 3)
+ if ((regs->eflags & VM_MASK) || (3 & regs->xcs) == 3)
return;
- if (regs->cs & 3) {
+ if (regs->xcs & 3) {
esp = regs->esp;
- ss = regs->ss;
+ ss = regs->xss & 0xffff;
}
console_verbose();
printk("%s: %04lx\n", str, err & 0xffff);
- printk("EIP: %04x:%08lx\nEFLAGS: %08lx\n", 0xffff & regs->cs,regs->eip,regs->eflags);
+ printk("CPU: %d\n", smp_processor_id());
+ printk("EIP: %04x:[<%08lx>]\nEFLAGS: %08lx\n", 0xffff & regs->xcs,regs->eip,regs->eflags);
printk("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n",
regs->eax, regs->ebx, regs->ecx, regs->edx);
printk("esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n",
regs->esi, regs->edi, regs->ebp, esp);
- printk("ds: %04x es: %04x fs: %04x gs: %04x ss: %04x\n",
- regs->ds, regs->es, regs->fs, regs->gs, ss);
+ printk("ds: %04x es: %04x ss: %04x\n",
+ regs->xds & 0xffff, regs->xes & 0xffff, ss);
store_TR(i);
if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page)
printk("Corrupted stack page\n");
@@ -134,7 +135,8 @@ int kstack_depth_to_print = 24;
printk("\nCall Trace: ");
stack = (unsigned long *) esp;
i = 1;
- module_start = ((high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1));
+ module_start = PAGE_OFFSET + (max_mapnr << PAGE_SHIFT);
+ module_start = ((module_start + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1));
module_end = module_start + MODULE_RANGE;
while (((long) stack & 4095) != 0) {
addr = get_seg_long(ss, stack++);
@@ -147,17 +149,17 @@ int kstack_depth_to_print = 24;
* out the call path that was taken.
*/
if (((addr >= (unsigned long) &start_kernel) &&
- (addr <= (unsigned long) &etext)) ||
+ (addr <= (unsigned long) &_etext)) ||
((addr >= module_start) && (addr <= module_end))) {
if (i && ((i % 8) == 0))
printk("\n ");
- printk("%08lx ", addr);
+ printk("[<%08lx>] ", addr);
i++;
}
}
printk("\nCode: ");
for(i=0;i<20;i++)
- printk("%02x ",0xff & get_seg_byte(regs->cs,(i+(char *)regs->eip)));
+ printk("%02x ",0xff & get_seg_byte(regs->xcs & 0xffff,(i+(char *)regs->eip)));
printk("\n");
do_exit(SIGSEGV);
}
@@ -173,8 +175,8 @@ DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun
DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS, current)
DO_ERROR(11, SIGBUS, "segment not present", segment_not_present, current)
DO_ERROR(12, SIGBUS, "stack segment", stack_segment, current)
-DO_ERROR(15, SIGSEGV, "reserved", reserved, current)
DO_ERROR(17, SIGSEGV, "alignment check", alignment_check, current)
+DO_ERROR(18, SIGSEGV, "reserved", reserved, current)
asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
{
@@ -185,16 +187,20 @@ asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
die_if_kernel("general protection",regs,error_code);
current->tss.error_code = error_code;
current->tss.trap_no = 13;
- send_sig(SIGSEGV, current, 1);
+ force_sig(SIGSEGV, current);
}
asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
{
+#ifdef CONFIG_SMP_NMI_INVAL
+ smp_flush_tlb_rcv();
+#else
#ifndef CONFIG_IGNORE_NMI
printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n");
printk("You probably have a hardware problem with your RAM chips or a\n");
printk("power saving mode enabled.\n");
#endif
+#endif
}
asmlinkage void do_debug(struct pt_regs * regs, long error_code)
@@ -203,12 +209,10 @@ asmlinkage void do_debug(struct pt_regs * regs, long error_code)
handle_vm86_debug((struct vm86_regs *) regs, error_code);
return;
}
- if (current->flags & PF_PTRACED)
- current->blocked &= ~(1 << (SIGTRAP-1));
- send_sig(SIGTRAP, current, 1);
+ force_sig(SIGTRAP, current);
current->tss.trap_no = 1;
current->tss.error_code = error_code;
- if ((regs->cs & 3) == 0) {
+ if ((regs->xcs & 3) == 0) {
/* If this is a kernel mode trap, then reset db7 and allow us to continue */
__asm__("movl %0,%%db7"
: /* no output */
@@ -219,40 +223,35 @@ asmlinkage void do_debug(struct pt_regs * regs, long error_code)
}
/*
- * Allow the process which triggered the interrupt to recover the error
- * condition.
- * - the status word is saved in the cs selector.
- * - the tag word is saved in the operand selector.
- * - the status word is then cleared and the tags all set to Empty.
- *
- * This will give sufficient information for complete recovery provided that
- * the affected process knows or can deduce the code and data segments
- * which were in force when the exception condition arose.
- *
* Note that we play around with the 'TS' bit to hopefully get
* the correct behaviour even in the presence of the asynchronous
* IRQ13 behaviour
*/
void math_error(void)
{
- struct i387_hard_struct * env;
+ struct task_struct * task;
clts();
- if (!last_task_used_math) {
+#ifdef __SMP__
+ task = current;
+#else
+ task = last_task_used_math;
+ last_task_used_math = NULL;
+ if (!task) {
__asm__("fnclex");
return;
}
- env = &last_task_used_math->tss.i387.hard;
- send_sig(SIGFPE, last_task_used_math, 1);
- last_task_used_math->tss.trap_no = 16;
- last_task_used_math->tss.error_code = 0;
- __asm__ __volatile__("fnsave %0":"=m" (*env));
- last_task_used_math = NULL;
+#endif
+ /*
+ * Save the info for the exception handler
+ */
+ __asm__ __volatile__("fnsave %0":"=m" (task->tss.i387.hard));
+ task->flags&=~PF_USEDFPU;
stts();
- env->fcs = (env->swd & 0x0000ffff) | (env->fcs & 0xffff0000);
- env->fos = env->twd;
- env->swd &= 0xffff3800;
- env->twd = 0xffffffff;
+
+ force_sig(SIGFPE, task);
+ task->tss.trap_no = 16;
+ task->tss.error_code = 0;
}
asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code)
@@ -261,6 +260,12 @@ asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code)
math_error();
}
+asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs,
+ long error_code)
+{
+ printk("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
+}
+
/*
* 'math_state_restore()' saves the current math information in the
* old math state array, and gets the new ones from the current task
@@ -270,23 +275,37 @@ asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code)
*/
asmlinkage void math_state_restore(void)
{
- __asm__ __volatile__("clts");
+ __asm__ __volatile__("clts"); /* Allow maths ops (or we recurse) */
+
+/*
+ * SMP is actually simpler than uniprocessor for once. Because
+ * we can't pull the delayed FPU switching trick Linus does
+ * we simply have to do the restore each context switch and
+ * set the flag. switch_to() will always save the state in
+ * case we swap processors. We also don't use the coprocessor
+ * timer - IRQ 13 mode isn't used with SMP machines (thank god).
+ */
+#ifndef __SMP__
if (last_task_used_math == current)
return;
- timer_table[COPRO_TIMER].expires = jiffies+50;
- timer_active |= 1<<COPRO_TIMER;
if (last_task_used_math)
__asm__("fnsave %0":"=m" (last_task_used_math->tss.i387));
else
__asm__("fnclex");
last_task_used_math = current;
- if (current->used_math) {
+#endif
+
+ if(current->used_math)
__asm__("frstor %0": :"m" (current->tss.i387));
- } else {
+ else
+ {
+ /*
+ * Our first FPU usage, clean the chip.
+ */
__asm__("fninit");
- current->used_math=1;
+ current->used_math = 1;
}
- timer_active &= ~(1<<COPRO_TIMER);
+ current->flags|=PF_USEDFPU; /* So we fnsave on switch_to() */
}
#ifndef CONFIG_MATH_EMULATION
@@ -295,7 +314,7 @@ asmlinkage void math_emulate(long arg)
{
printk("math-emulation not enabled and no coprocessor found.\n");
printk("killing %s.\n",current->comm);
- send_sig(SIGFPE,current,1);
+ force_sig(SIGFPE,current);
schedule();
}
@@ -305,8 +324,16 @@ void trap_init(void)
{
int i;
struct desc_struct * p;
-
- if (strncmp((char*)0x0FFFD9, "EISA", 4) == 0)
+ static int smptrap=0;
+
+ if(smptrap)
+ {
+ __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");
+ load_ldt(0);
+ return;
+ }
+ smptrap++;
+ if (readl(0x0FFFD9) == 'E' + ('I'<<8) + ('S'<<16) + ('A'<<24))
EISA_bus = 1;
set_call_gate(&default_ldt,lcall7);
set_trap_gate(0,&divide_error);
@@ -324,7 +351,7 @@ void trap_init(void)
set_trap_gate(12,&stack_segment);
set_trap_gate(13,&general_protection);
set_trap_gate(14,&page_fault);
- set_trap_gate(15,&reserved);
+ set_trap_gate(15,&spurious_interrupt_bug);
set_trap_gate(16,&coprocessor_error);
set_trap_gate(17,&alignment_check);
for (i=18;i<48;i++)
diff --git a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c
index d55f8248f..6cceba36c 100644
--- a/arch/i386/kernel/vm86.c
+++ b/arch/i386/kernel/vm86.c
@@ -11,7 +11,7 @@
#include <linux/ptrace.h>
#include <linux/mm.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/io.h>
@@ -59,8 +59,12 @@ asmlinkage struct pt_regs * save_v86_state(struct vm86_regs * regs)
do_exit(SIGSEGV);
}
set_flags(regs->eflags, VEFLAGS, VIF_MASK | current->tss.v86mask);
- memcpy_tofs(&current->tss.vm86_info->regs,regs,sizeof(*regs));
- put_fs_long(current->tss.screen_bitmap,&current->tss.vm86_info->screen_bitmap);
+ tmp = copy_to_user(&current->tss.vm86_info->regs,regs,sizeof(*regs));
+ tmp += put_user(current->tss.screen_bitmap,&current->tss.vm86_info->screen_bitmap);
+ if (tmp) {
+ printk("vm86: could not access userspace vm86_info\n");
+ do_exit(SIGSEGV);
+ }
tmp = current->tss.esp0;
current->tss.esp0 = current->saved_kernel_stack;
current->saved_kernel_stack = 0;
@@ -74,7 +78,7 @@ static void mark_screen_rdonly(struct task_struct * tsk)
pte_t *pte;
int i;
- pgd = pgd_offset(tsk, 0xA0000);
+ pgd = pgd_offset(tsk->mm, 0xA0000);
if (pgd_none(*pgd))
return;
if (pgd_bad(*pgd)) {
@@ -93,32 +97,32 @@ static void mark_screen_rdonly(struct task_struct * tsk)
pte = pte_offset(pmd, 0xA0000);
for (i = 0; i < 32; i++) {
if (pte_present(*pte))
- *pte = pte_wrprotect(*pte);
+ set_pte(pte, pte_wrprotect(*pte));
pte++;
}
- invalidate();
+ flush_tlb();
}
asmlinkage int sys_vm86(struct vm86_struct * v86)
{
struct vm86_struct info;
+ struct task_struct *tsk = current;
struct pt_regs * pt_regs = (struct pt_regs *) &v86;
- int error;
- if (current->saved_kernel_stack)
+ if (tsk->saved_kernel_stack)
return -EPERM;
- /* v86 must be readable (now) and writable (for save_v86_state) */
- error = verify_area(VERIFY_WRITE,v86,sizeof(*v86));
- if (error)
- return error;
- memcpy_fromfs(&info,v86,sizeof(info));
+ if (copy_from_user(&info,v86,sizeof(info)))
+ return -EFAULT;
/*
* make sure the vm86() system call doesn't try to do anything silly
*/
info.regs.__null_ds = 0;
info.regs.__null_es = 0;
- info.regs.__null_fs = 0;
- info.regs.__null_gs = 0;
+
+/* we are clearing fs,gs later just before "jmp ret_from_sys_call",
+ * because starting with Linux 2.1.x they aren't no longer saved/restored
+ */
+
/*
* The eflags register is also special: we cannot trust that the user
* has set it up safely, so this makes sure interrupt etc flags are
@@ -131,16 +135,16 @@ asmlinkage int sys_vm86(struct vm86_struct * v86)
switch (info.cpu_type) {
case CPU_286:
- current->tss.v86mask = 0;
+ tsk->tss.v86mask = 0;
break;
case CPU_386:
- current->tss.v86mask = NT_MASK | IOPL_MASK;
+ tsk->tss.v86mask = NT_MASK | IOPL_MASK;
break;
case CPU_486:
- current->tss.v86mask = AC_MASK | NT_MASK | IOPL_MASK;
+ tsk->tss.v86mask = AC_MASK | NT_MASK | IOPL_MASK;
break;
default:
- current->tss.v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK;
+ tsk->tss.v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK;
break;
}
@@ -148,17 +152,19 @@ asmlinkage int sys_vm86(struct vm86_struct * v86)
* Save old state, set default return value (%eax) to 0
*/
pt_regs->eax = 0;
- current->saved_kernel_stack = current->tss.esp0;
- current->tss.esp0 = (unsigned long) pt_regs;
- current->tss.vm86_info = v86;
+ tsk->saved_kernel_stack = tsk->tss.esp0;
+ tsk->tss.esp0 = (unsigned long) pt_regs;
+ tsk->tss.vm86_info = v86;
- current->tss.screen_bitmap = info.screen_bitmap;
+ tsk->tss.screen_bitmap = info.screen_bitmap;
if (info.flags & VM86_SCREEN_BITMAP)
- mark_screen_rdonly(current);
- __asm__ __volatile__("movl %0,%%esp\n\t"
+ mark_screen_rdonly(tsk);
+ __asm__ __volatile__(
+ "xorl %%eax,%%eax; mov %%ax,%%fs; mov %%ax,%%gs\n\t"
+ "movl %0,%%esp\n\t"
"jmp ret_from_sys_call"
: /* no outputs */
- :"r" (&info.regs));
+ :"r" (&info.regs), "b" (tsk) : "ax");
return 0;
}
@@ -170,7 +176,7 @@ static inline void return_to_32bit(struct vm86_regs * regs16, int retval)
regs32->eax = retval;
__asm__ __volatile__("movl %0,%%esp\n\t"
"jmp ret_from_sys_call"
- : : "r" (regs32));
+ : : "r" (regs32), "b" (current));
}
static inline void set_IF(struct vm86_regs * regs)
@@ -217,10 +223,10 @@ static inline unsigned long get_vflags(struct vm86_regs * regs)
static inline int is_revectored(int nr, struct revectored_struct * bitmap)
{
- __asm__ __volatile__("btl %2,%%fs:%1\n\tsbbl %0,%0"
- :"=r" (nr)
- :"m" (*bitmap),"r" (nr));
- return nr;
+ unsigned long map;
+ if (get_user(map, bitmap->__map + (nr >> 5)))
+ return 1;
+ return test_bit(nr & ((1 << 5)-1), &map);
}
/*
@@ -231,16 +237,16 @@ static inline int is_revectored(int nr, struct revectored_struct * bitmap)
#define pushb(base, ptr, val) \
__asm__ __volatile__( \
"decw %w0\n\t" \
- "movb %2,%%fs:0(%1,%0)" \
+ "movb %2,0(%1,%0)" \
: "=r" (ptr) \
: "r" (base), "q" (val), "0" (ptr))
#define pushw(base, ptr, val) \
__asm__ __volatile__( \
"decw %w0\n\t" \
- "movb %h2,%%fs:0(%1,%0)\n\t" \
+ "movb %h2,0(%1,%0)\n\t" \
"decw %w0\n\t" \
- "movb %b2,%%fs:0(%1,%0)" \
+ "movb %b2,0(%1,%0)" \
: "=r" (ptr) \
: "r" (base), "q" (val), "0" (ptr))
@@ -248,21 +254,21 @@ __asm__ __volatile__( \
__asm__ __volatile__( \
"decw %w0\n\t" \
"rorl $16,%2\n\t" \
- "movb %h2,%%fs:0(%1,%0)\n\t" \
+ "movb %h2,0(%1,%0)\n\t" \
"decw %w0\n\t" \
- "movb %b2,%%fs:0(%1,%0)\n\t" \
+ "movb %b2,0(%1,%0)\n\t" \
"decw %w0\n\t" \
"rorl $16,%2\n\t" \
- "movb %h2,%%fs:0(%1,%0)\n\t" \
+ "movb %h2,0(%1,%0)\n\t" \
"decw %w0\n\t" \
- "movb %b2,%%fs:0(%1,%0)" \
+ "movb %b2,0(%1,%0)" \
: "=r" (ptr) \
: "r" (base), "q" (val), "0" (ptr))
#define popb(base, ptr) \
({ unsigned long __res; \
__asm__ __volatile__( \
- "movb %%fs:0(%1,%0),%b2\n\t" \
+ "movb 0(%1,%0),%b2\n\t" \
"incw %w0" \
: "=r" (ptr), "=r" (base), "=q" (__res) \
: "0" (ptr), "1" (base), "2" (0)); \
@@ -271,9 +277,9 @@ __res; })
#define popw(base, ptr) \
({ unsigned long __res; \
__asm__ __volatile__( \
- "movb %%fs:0(%1,%0),%b2\n\t" \
+ "movb 0(%1,%0),%b2\n\t" \
"incw %w0\n\t" \
- "movb %%fs:0(%1,%0),%h2\n\t" \
+ "movb 0(%1,%0),%h2\n\t" \
"incw %w0" \
: "=r" (ptr), "=r" (base), "=q" (__res) \
: "0" (ptr), "1" (base), "2" (0)); \
@@ -282,14 +288,14 @@ __res; })
#define popl(base, ptr) \
({ unsigned long __res; \
__asm__ __volatile__( \
- "movb %%fs:0(%1,%0),%b2\n\t" \
+ "movb 0(%1,%0),%b2\n\t" \
"incw %w0\n\t" \
- "movb %%fs:0(%1,%0),%h2\n\t" \
+ "movb 0(%1,%0),%h2\n\t" \
"incw %w0\n\t" \
"rorl $16,%2\n\t" \
- "movb %%fs:0(%1,%0),%b2\n\t" \
+ "movb 0(%1,%0),%b2\n\t" \
"incw %w0\n\t" \
- "movb %%fs:0(%1,%0),%h2\n\t" \
+ "movb 0(%1,%0),%h2\n\t" \
"incw %w0\n\t" \
"rorl $16,%2" \
: "=r" (ptr), "=r" (base), "=q" (__res) \
@@ -298,22 +304,31 @@ __res; })
static void do_int(struct vm86_regs *regs, int i, unsigned char * ssp, unsigned long sp)
{
- unsigned short seg = get_fs_word((void *) ((i<<2)+2));
-
- if (seg == BIOSSEG || regs->cs == BIOSSEG ||
- is_revectored(i, &current->tss.vm86_info->int_revectored))
- return_to_32bit(regs, VM86_INTx + (i << 8));
+ unsigned long *intr_ptr, segoffs;
+
+ if (regs->cs == BIOSSEG)
+ goto cannot_handle;
+ if (is_revectored(i, &current->tss.vm86_info->int_revectored))
+ goto cannot_handle;
if (i==0x21 && is_revectored(AH(regs),&current->tss.vm86_info->int21_revectored))
- return_to_32bit(regs, VM86_INTx + (i << 8));
+ goto cannot_handle;
+ intr_ptr = (unsigned long *) (i << 2);
+ if (get_user(segoffs, intr_ptr))
+ goto cannot_handle;
+ if ((segoffs >> 16) == BIOSSEG)
+ goto cannot_handle;
pushw(ssp, sp, get_vflags(regs));
pushw(ssp, sp, regs->cs);
pushw(ssp, sp, IP(regs));
- regs->cs = seg;
+ regs->cs = segoffs >> 16;
SP(regs) -= 6;
- IP(regs) = get_fs_word((void *) (i<<2));
+ IP(regs) = segoffs & 0xffff;
clear_TF(regs);
clear_IF(regs);
return;
+
+cannot_handle:
+ return_to_32bit(regs, VM86_INTx + (i << 8));
}
void handle_vm86_debug(struct vm86_regs * regs, long error_code)
@@ -367,6 +382,7 @@ void handle_vm86_fault(struct vm86_regs * regs, long error_code)
set_vflags_long(popl(ssp, sp), regs);
return;
}
+ break;
/* pushf */
case 0x9c:
@@ -413,8 +429,10 @@ void handle_vm86_fault(struct vm86_regs * regs, long error_code)
IP(regs)++;
set_IF(regs);
return;
-
- default:
- return_to_32bit(regs, VM86_UNKNOWN);
}
+
+ /*
+ * We didn't recognize it, let the emulator take care of it..
+ */
+ return_to_32bit(regs, VM86_UNKNOWN);
}
diff --git a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile
new file mode 100644
index 000000000..cf54dd7df
--- /dev/null
+++ b/arch/i386/lib/Makefile
@@ -0,0 +1,16 @@
+#
+# Makefile for i386-specific library files..
+#
+
+ifdef SMP
+.S.o:
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+else
+.S.o:
+ $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
+endif
+
+L_TARGET = lib.a
+L_OBJS = checksum.o semaphore.o
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/i386/lib/checksum.c b/arch/i386/lib/checksum.c
new file mode 100644
index 000000000..d2bf48b08
--- /dev/null
+++ b/arch/i386/lib/checksum.c
@@ -0,0 +1,194 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * IP/TCP/UDP checksumming routines
+ *
+ * Authors: Jorge Cwik, <jorge@laser.satlink.net>
+ * Arnt Gulbrandsen, <agulbra@nvg.unit.no>
+ * Tom May, <ftom@netcom.com>
+ * Lots of code moved from tcp.c and ip.c; see those files
+ * for more names.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <net/checksum.h>
+
+/*
+ * computes a partial checksum, e.g. for TCP/UDP fragments
+ */
+
+unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) {
+ /*
+ * Experiments with ethernet and slip connections show that buff
+ * is aligned on either a 2-byte or 4-byte boundary. We get at
+ * least a 2x speedup on 486 and Pentium if it is 4-byte aligned.
+ * Fortunately, it is easy to convert 2-byte alignment to 4-byte
+ * alignment for the unrolled loop.
+ */
+ __asm__("
+ testl $2, %%esi # Check alignment.
+ jz 2f # Jump if alignment is ok.
+ subl $2, %%ecx # Alignment uses up two bytes.
+ jae 1f # Jump if we had at least two bytes.
+ addl $2, %%ecx # ecx was < 2. Deal with it.
+ jmp 4f
+1: movw (%%esi), %%bx
+ addl $2, %%esi
+ addw %%bx, %%ax
+ adcl $0, %%eax
+2:
+ movl %%ecx, %%edx
+ shrl $5, %%ecx
+ jz 2f
+ testl %%esi, %%esi
+1: movl (%%esi), %%ebx
+ adcl %%ebx, %%eax
+ movl 4(%%esi), %%ebx
+ adcl %%ebx, %%eax
+ movl 8(%%esi), %%ebx
+ adcl %%ebx, %%eax
+ movl 12(%%esi), %%ebx
+ adcl %%ebx, %%eax
+ movl 16(%%esi), %%ebx
+ adcl %%ebx, %%eax
+ movl 20(%%esi), %%ebx
+ adcl %%ebx, %%eax
+ movl 24(%%esi), %%ebx
+ adcl %%ebx, %%eax
+ movl 28(%%esi), %%ebx
+ adcl %%ebx, %%eax
+ lea 32(%%esi), %%esi
+ dec %%ecx
+ jne 1b
+ adcl $0, %%eax
+2: movl %%edx, %%ecx
+ andl $0x1c, %%edx
+ je 4f
+ shrl $2, %%edx
+ testl %%esi, %%esi
+3: adcl (%%esi), %%eax
+ lea 4(%%esi), %%esi
+ dec %%edx
+ jne 3b
+ adcl $0, %%eax
+4: andl $3, %%ecx
+ jz 7f
+ cmpl $2, %%ecx
+ jb 5f
+ movw (%%esi),%%cx
+ leal 2(%%esi),%%esi
+ je 6f
+ shll $16,%%ecx
+5: movb (%%esi),%%cl
+6: addl %%ecx,%%eax
+ adcl $0, %%eax
+7: "
+ : "=a"(sum)
+ : "0"(sum), "c"(len), "S"(buff)
+ : "bx", "cx", "dx", "si");
+ return(sum);
+}
+
+
+
+/*
+ * copy from ds while checksumming, otherwise like csum_partial
+ */
+
+unsigned int csum_partial_copy(const char *src, char *dst,
+ int len, int sum) {
+ __asm__("
+ testl $2, %%edi # Check alignment.
+ jz 2f # Jump if alignment is ok.
+ subl $2, %%ecx # Alignment uses up two bytes.
+ jae 1f # Jump if we had at least two bytes.
+ addl $2, %%ecx # ecx was < 2. Deal with it.
+ jmp 4f
+1: movw (%%esi), %%bx
+ addl $2, %%esi
+ movw %%bx, (%%edi)
+ addl $2, %%edi
+ addw %%bx, %%ax
+ adcl $0, %%eax
+2:
+ movl %%ecx, %%edx
+ shrl $5, %%ecx
+ jz 2f
+ testl %%esi, %%esi
+1: movl (%%esi), %%ebx
+ adcl %%ebx, %%eax
+ movl %%ebx, (%%edi)
+
+ movl 4(%%esi), %%ebx
+ adcl %%ebx, %%eax
+ movl %%ebx, 4(%%edi)
+
+ movl 8(%%esi), %%ebx
+ adcl %%ebx, %%eax
+ movl %%ebx, 8(%%edi)
+
+ movl 12(%%esi), %%ebx
+ adcl %%ebx, %%eax
+ movl %%ebx, 12(%%edi)
+
+ movl 16(%%esi), %%ebx
+ adcl %%ebx, %%eax
+ movl %%ebx, 16(%%edi)
+
+ movl 20(%%esi), %%ebx
+ adcl %%ebx, %%eax
+ movl %%ebx, 20(%%edi)
+
+ movl 24(%%esi), %%ebx
+ adcl %%ebx, %%eax
+ movl %%ebx, 24(%%edi)
+
+ movl 28(%%esi), %%ebx
+ adcl %%ebx, %%eax
+ movl %%ebx, 28(%%edi)
+
+ lea 32(%%esi), %%esi
+ lea 32(%%edi), %%edi
+ dec %%ecx
+ jne 1b
+ adcl $0, %%eax
+2: movl %%edx, %%ecx
+ andl $28, %%edx
+ je 4f
+ shrl $2, %%edx
+ testl %%esi, %%esi
+3: movl (%%esi), %%ebx
+ adcl %%ebx, %%eax
+ movl %%ebx, (%%edi)
+ lea 4(%%esi), %%esi
+ lea 4(%%edi), %%edi
+ dec %%edx
+ jne 3b
+ adcl $0, %%eax
+4: andl $3, %%ecx
+ jz 7f
+ cmpl $2, %%ecx
+ jb 5f
+ movw (%%esi), %%cx
+ leal 2(%%esi), %%esi
+ movw %%cx, (%%edi)
+ leal 2(%%edi), %%edi
+ je 6f
+ shll $16,%%ecx
+5: movb (%%esi), %%cl
+ movb %%cl, (%%edi)
+6: addl %%ecx, %%eax
+ adcl $0, %%eax
+7:
+ "
+ : "=a" (sum)
+ : "0"(sum), "c"(len), "S"(src), "D" (dst)
+ : "bx", "cx", "dx", "si", "di" );
+ return(sum);
+}
diff --git a/arch/i386/lib/semaphore.S b/arch/i386/lib/semaphore.S
new file mode 100644
index 000000000..f2d11099f
--- /dev/null
+++ b/arch/i386/lib/semaphore.S
@@ -0,0 +1,35 @@
+/*
+ * linux/arch/i386/lib/semaphore.S
+ *
+ * Copyright (C) 1996 Linus Torvalds
+ */
+
+#include <linux/linkage.h>
+
+/*
+ * "down_failed" is called with the eventual return address
+ * in %eax, and the address of the semaphore in %ecx. We need
+ * to call "__down()", and then re-try until we succeed..
+ */
+ENTRY(__down_failed)
+ pushl %eax /* return address */
+ pushl %edx /* save %edx */
+1: pushl %ecx /* save %ecx (and argument) */
+ call SYMBOL_NAME(__down)
+ popl %ecx /* restore %ecx (count on __down not changing it) */
+#ifdef __SMP__
+ lock
+#endif
+ decl (%ecx)
+ js 1b
+ popl %edx /* restore %edx */
+ ret
+
+ENTRY(__up_wakeup)
+ pushl %eax /* return address */
+ pushl %edx /* save %edx */
+ pushl %ecx /* save %ecx (and argument) */
+ call SYMBOL_NAME(__up)
+ popl %ecx /* restore %ecx (count on __up not changing it) */
+ popl %edx /* restore %edx */
+ ret
diff --git a/arch/i386/math-emu/Makefile b/arch/i386/math-emu/Makefile
index 2d391a9e6..1bd2cb40d 100644
--- a/arch/i386/math-emu/Makefile
+++ b/arch/i386/math-emu/Makefile
@@ -2,21 +2,17 @@
# Makefile for wm-FPU-emu
#
+L_TARGET := math.a
+
#DEBUG = -DDEBUGGING
DEBUG =
PARANOID = -DPARANOID
-CFLAGS := $(CFLAGS) $(PARANOID) $(DEBUG) -fno-builtin
-
-.c.o:
- $(CC) $(CFLAGS) $(MATH_EMULATION) -c $<
+CFLAGS := $(CFLAGS) $(PARANOID) $(DEBUG) -fno-builtin $(MATH_EMULATION)
.S.o:
- $(CC) -D__ASSEMBLER__ $(PARANOID) -c $<
-
-.s.o:
- $(CC) -c $<
+ $(CC) -D__ASSEMBLY__ $(PARANOID) -c $<
-OBJS = fpu_entry.o div_small.o errors.o \
+L_OBJS =fpu_entry.o div_small.o errors.o \
fpu_arith.o fpu_aux.o fpu_etc.o fpu_trig.o \
load_store.o get_address.o \
poly_atan.o poly_l2.o poly_2xm1.o poly_sin.o poly_tan.o \
@@ -28,25 +24,7 @@ OBJS = fpu_entry.o div_small.o errors.o \
div_Xsig.o polynom_Xsig.o round_Xsig.o \
shr_Xsig.o mul_Xsig.o
-math.a: $(OBJS)
- rm -f math.a
- $(AR) rcs math.a $(OBJS)
- sync
-
-dep:
- $(CPP) -M *.c > .depend
- $(CPP) -D__ASSEMBLER__ -M *.S >> .depend
+include $(TOPDIR)/Rules.make
proto:
cproto -e -DMAKING_PROTO *.c >fpu_proto.h
-
-modules:
-
-dummy:
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
diff --git a/arch/i386/math-emu/README b/arch/i386/math-emu/README
index 2c0acb423..5158b4b81 100644
--- a/arch/i386/math-emu/README
+++ b/arch/i386/math-emu/README
@@ -1,9 +1,9 @@
+---------------------------------------------------------------------------+
| wm-FPU-emu an FPU emulator for 80386 and 80486SX microprocessors. |
| |
- | Copyright (C) 1992,1993,1994 |
+ | Copyright (C) 1992,1993,1994,1995,1996 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Australia. E-mail billm@suburbia.net |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License version 2 as |
@@ -42,13 +42,11 @@ but is very close. See "Limitations" later in this file for a list of
some differences.
Please report bugs, etc to me at:
- billm@vaxc.cc.monash.edu.au
- or at:
- billm@jacobi.maths.monash.edu.au
+ billm@suburbia.net
--Bill Metzenthen
- August 1994
+ October 1996
----------------------- Internals of wm-FPU-emu -----------------------
diff --git a/arch/i386/math-emu/control_w.h b/arch/i386/math-emu/control_w.h
index ef5fced39..6bd7654b7 100644
--- a/arch/i386/math-emu/control_w.h
+++ b/arch/i386/math-emu/control_w.h
@@ -10,7 +10,7 @@
#ifndef _CONTROLW_H_
#define _CONTROLW_H_
-#ifdef __ASSEMBLER__
+#ifdef __ASSEMBLY__
#define _Const_(x) $##x
#else
#define _Const_(x) x
diff --git a/arch/i386/math-emu/div_Xsig.S b/arch/i386/math-emu/div_Xsig.S
index 67d8be964..fd83732fc 100644
--- a/arch/i386/math-emu/div_Xsig.S
+++ b/arch/i386/math-emu/div_Xsig.S
@@ -4,9 +4,9 @@
| |
| Division subroutine for 96 bit quantities |
| |
- | Copyright (C) 1994 |
+ | Copyright (C) 1994,1995 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Australia. E-mail billm@jacobi.maths.monash.edu.au |
| |
| |
+---------------------------------------------------------------------------*/
@@ -28,7 +28,7 @@
+---------------------------------------------------------------------------*/
#include "exception.h"
-#include "fpu_asm.h"
+#include "fpu_emu.h"
#define XsigLL(x) (x)
@@ -74,11 +74,7 @@ FPU_result_1:
.text
- .align 2,144
-
-.globl _div_Xsig
-
-_div_Xsig:
+ENTRY(div_Xsig)
pushl %ebp
movl %esp,%ebp
#ifndef NON_REENTRANT_FPU
diff --git a/arch/i386/math-emu/div_small.S b/arch/i386/math-emu/div_small.S
index 0225a96d4..13ab2b7ae 100644
--- a/arch/i386/math-emu/div_small.S
+++ b/arch/i386/math-emu/div_small.S
@@ -4,8 +4,9 @@
| |
| Divide a 64 bit integer by a 32 bit integer & return remainder. |
| |
- | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Copyright (C) 1992,1995 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@jacobi.maths.monash.edu.au |
| |
| |
+---------------------------------------------------------------------------*/
@@ -14,14 +15,10 @@
| unsigned long div_small(unsigned long long *x, unsigned long y) |
+---------------------------------------------------------------------------*/
-#include "fpu_asm.h"
+#include "fpu_emu.h"
.text
- .align 2,144
-
-.globl _div_small
-
-_div_small:
+ENTRY(div_small)
pushl %ebp
movl %esp,%ebp
diff --git a/arch/i386/math-emu/errors.c b/arch/i386/math-emu/errors.c
index e34eec942..f76020d1f 100644
--- a/arch/i386/math-emu/errors.c
+++ b/arch/i386/math-emu/errors.c
@@ -3,9 +3,9 @@
| |
| The error handling functions for wm-FPU-emu |
| |
- | Copyright (C) 1992,1993,1994 |
- | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Copyright (C) 1992,1993,1994,1996 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@jacobi.maths.monash.edu.au |
| |
| |
+---------------------------------------------------------------------------*/
@@ -19,7 +19,7 @@
#include <linux/signal.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include "fpu_system.h"
#include "exception.h"
@@ -46,13 +46,13 @@ void Un_impl(void)
{
while ( 1 )
{
- byte1 = get_fs_byte((unsigned char *) address);
+ get_user(byte1, (unsigned char *) address);
if ( (byte1 & 0xf8) == 0xd8 ) break;
printk("[%02x]", byte1);
address++;
}
printk("%02x ", byte1);
- FPU_modrm = get_fs_byte(1 + (unsigned char *) address);
+ get_user(FPU_modrm, 1 + (unsigned char *) address);
if (FPU_modrm >= 0300)
printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
@@ -82,10 +82,10 @@ void FPU_illegal(void)
-void emu_printall()
+void emu_printall(void)
{
int i;
- static char *tag_desc[] = { "Valid", "Zero", "ERROR", "ERROR",
+ static const char *tag_desc[] = { "Valid", "Zero", "ERROR", "ERROR",
"DeNorm", "Inf", "NaN", "Empty" };
unsigned char byte1, FPU_modrm;
unsigned long address = FPU_ORIG_EIP;
@@ -98,7 +98,7 @@ void emu_printall()
#define MAX_PRINTED_BYTES 20
for ( i = 0; i < MAX_PRINTED_BYTES; i++ )
{
- byte1 = get_fs_byte((unsigned char *) address);
+ get_user(byte1, (unsigned char *) address);
if ( (byte1 & 0xf8) == 0xd8 )
{
printk(" %02x", byte1);
@@ -111,7 +111,7 @@ void emu_printall()
printk(" [more..]\n");
else
{
- FPU_modrm = get_fs_byte(1 + (unsigned char *) address);
+ get_user(FPU_modrm, 1 + (unsigned char *) address);
if (FPU_modrm >= 0300)
printk(" %02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
@@ -166,7 +166,8 @@ printk(" CW: ic=%d rc=%ld%ld pc=%ld%ld iem=%d ef=%d%d%d%d%d%d\n",
for ( i = 0; i < 8; i++ )
{
FPU_REG *r = &st(i);
- switch (r->tag)
+ char tagi = r->tag;
+ switch (tagi)
{
case TW_Empty:
continue;
@@ -190,29 +191,20 @@ printk(" CW: ic=%d rc=%ld%ld pc=%ld%ld iem=%d ef=%d%d%d%d%d%d\n",
r->exp - EXP_BIAS + 1);
break;
default:
- printk("Whoops! Error in errors.c ");
+ printk("Whoops! Error in errors.c: tag%d is %d ", i, tagi);
+ continue;
break;
}
- printk("%s\n", tag_desc[(int) (unsigned) r->tag]);
+ printk("%s\n", tag_desc[(int) (unsigned) tagi]);
}
-#ifdef OBSOLETE
- printk("[data] %c .%04lx %04lx %04lx %04lx e%+-6ld ",
- FPU_loaded_data.sign ? '-' : '+',
- (long)(FPU_loaded_data.sigh >> 16),
- (long)(FPU_loaded_data.sigh & 0xFFFF),
- (long)(FPU_loaded_data.sigl >> 16),
- (long)(FPU_loaded_data.sigl & 0xFFFF),
- FPU_loaded_data.exp - EXP_BIAS + 1);
- printk("%s\n", tag_desc[(int) (unsigned) FPU_loaded_data.tag]);
-#endif OBSOLETE
RE_ENTRANT_CHECK_ON;
}
static struct {
int type;
- char *name;
+ const char *name;
} exception_names[] = {
{ EX_StackOver, "stack overflow" },
{ EX_StackUnder, "stack underflow" },
@@ -300,7 +292,7 @@ static struct {
0x242 in div_Xsig.S
*/
-void exception(int n)
+void FPU_exception(int n)
{
int i, int_type;
@@ -365,12 +357,8 @@ void exception(int n)
/*
* The 80486 generates an interrupt on the next non-control FPU
* instruction. So we need some means of flagging it.
- * We use the ES (Error Summary) bit for this, assuming that
- * this is the way a real FPU does it (until I can check it out),
- * if not, then some method such as the following kludge might
- * be needed.
+ * We use the ES (Error Summary) bit for this.
*/
-/* regs[0].tag |= TW_FPU_Interrupt; */
}
RE_ENTRANT_CHECK_ON;
@@ -494,7 +482,7 @@ int set_precision_flag(int flags)
}
else
{
- exception(flags);
+ EXCEPTION(flags);
return 1;
}
}
@@ -506,7 +494,7 @@ asmlinkage void set_precision_flag_up(void)
if ( control_word & CW_Precision )
partial_status |= (SW_Precision | SW_C1); /* The masked response */
else
- exception(EX_Precision | SW_C1);
+ EXCEPTION(EX_Precision | SW_C1);
}
@@ -520,7 +508,7 @@ asmlinkage void set_precision_flag_down(void)
partial_status |= SW_Precision;
}
else
- exception(EX_Precision);
+ EXCEPTION(EX_Precision);
}
@@ -533,7 +521,7 @@ asmlinkage int denormal_operand(void)
}
else
{
- exception(EX_Denormal);
+ EXCEPTION(EX_Denormal);
return 1;
}
}
@@ -568,7 +556,7 @@ asmlinkage int arith_overflow(FPU_REG *dest)
return !(control_word & CW_Precision);
}
- return !(control_word & CW_Overflow);
+ return 0;
}
@@ -599,7 +587,7 @@ asmlinkage int arith_underflow(FPU_REG *dest)
return !(control_word & CW_Precision);
}
- return !(control_word & CW_Underflow);
+ return 0;
}
diff --git a/arch/i386/math-emu/exception.h b/arch/i386/math-emu/exception.h
index 2e629a30c..b90e5e9c3 100644
--- a/arch/i386/math-emu/exception.h
+++ b/arch/i386/math-emu/exception.h
@@ -10,7 +10,7 @@
#define _EXCEPTION_H_
-#ifdef __ASSEMBLER__
+#ifdef __ASSEMBLY__
#define Const_(x) $##x
#else
#define Const_(x) x
@@ -39,15 +39,15 @@
#define PRECISION_LOST_DOWN Const_(EX_Precision)
-#ifndef __ASSEMBLER__
+#ifndef __ASSEMBLY__
#ifdef DEBUG
#define EXCEPTION(x) { printk("exception in %s at line %d\n", \
- __FILE__, __LINE__); exception(x); }
+ __FILE__, __LINE__); FPU_exception(x); }
#else
-#define EXCEPTION(x) exception(x)
+#define EXCEPTION(x) FPU_exception(x)
#endif
-#endif __ASSEMBLER__
+#endif __ASSEMBLY__
#endif _EXCEPTION_H_
diff --git a/arch/i386/math-emu/fpu_asm.h b/arch/i386/math-emu/fpu_asm.h
index 8eb60148d..d08fbc874 100644
--- a/arch/i386/math-emu/fpu_asm.h
+++ b/arch/i386/math-emu/fpu_asm.h
@@ -1,17 +1,18 @@
/*---------------------------------------------------------------------------+
| fpu_asm.h |
| |
- | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Copyright (C) 1992,1995 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@jacobi.maths.monash.edu.au |
| |
+---------------------------------------------------------------------------*/
#ifndef _FPU_ASM_H_
#define _FPU_ASM_H_
-#include "fpu_emu.h"
+#include <linux/linkage.h>
-#define EXCEPTION _exception
+#define EXCEPTION SYMBOL_NAME(FPU_exception)
#define PARAM1 8(%ebp)
diff --git a/arch/i386/math-emu/fpu_emu.h b/arch/i386/math-emu/fpu_emu.h
index 9d2c5dd13..b8385db1f 100644
--- a/arch/i386/math-emu/fpu_emu.h
+++ b/arch/i386/math-emu/fpu_emu.h
@@ -28,7 +28,7 @@
*/
#define PECULIAR_486
-#ifdef __ASSEMBLER__
+#ifdef __ASSEMBLY__
#include "fpu_asm.h"
#define Const(x) $##x
#else
@@ -55,9 +55,11 @@
#define TW_Empty Const(7) /* empty */
-#ifndef __ASSEMBLER__
+#ifndef __ASSEMBLY__
+
+#include <asm/sigcontext.h> /* for struct _fpstate */
+#include <asm/math_emu.h>
-#include <linux/math_emu.h>
#include <linux/linkage.h>
/*
@@ -95,9 +97,9 @@ extern char emulating;
struct address {
unsigned int offset;
- unsigned int selector:16;
- unsigned int opcode:11;
- unsigned int empty:5;
+ unsigned short selector;
+ unsigned short opcode:11,
+ empty:5;
};
typedef void (*FUNC)(void);
typedef struct fpu_reg FPU_REG;
@@ -133,9 +135,9 @@ extern unsigned char const data_sizes_16[32];
#define reg_move(x, y) { \
- *(short *)&((y)->sign) = *(short *)&((x)->sign); \
- *(long *)&((y)->exp) = *(long *)&((x)->exp); \
- *(long long *)&((y)->sigl) = *(long long *)&((x)->sigl); }
+ *(short *)&((y)->sign) = *(const short *)&((x)->sign); \
+ *(long *)&((y)->exp) = *(const long *)&((x)->exp); \
+ *(long long *)&((y)->sigl) = *(const long long *)&((x)->sigl); }
#define significand(x) ( ((unsigned long long *)&((x)->sigl))[0] )
@@ -166,6 +168,6 @@ asmlinkage void round_reg(FPU_REG *arg, unsigned int extent,
#include "fpu_proto.h"
#endif
-#endif __ASSEMBLER__
+#endif __ASSEMBLY__
#endif _FPU_EMU_H_
diff --git a/arch/i386/math-emu/fpu_entry.c b/arch/i386/math-emu/fpu_entry.c
index b2777a722..07c32db9a 100644
--- a/arch/i386/math-emu/fpu_entry.c
+++ b/arch/i386/math-emu/fpu_entry.c
@@ -1,11 +1,11 @@
/*---------------------------------------------------------------------------+
| fpu_entry.c |
| |
- | The entry function for wm-FPU-emu |
+ | The entry functions for wm-FPU-emu |
| |
- | Copyright (C) 1992,1993,1994 |
- | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Copyright (C) 1992,1993,1994,1996 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@jacobi.maths.monash.edu.au |
| |
| See the files "README" and "COPYING" for further copyright and warranty |
| information. |
@@ -20,12 +20,13 @@
+---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------+
- | math_emulate() is the sole entry point for wm-FPU-emu |
+ | math_emulate(), restore_i387_soft() and save_i387_soft() are the only |
+ | entry points for wm-FPU-emu. |
+---------------------------------------------------------------------------*/
#include <linux/signal.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include "fpu_system.h"
#include "fpu_emu.h"
@@ -159,8 +160,9 @@ asmlinkage void math_emulate(long arg)
{
/* Make sure that the registers are compatible
with the assumptions of the emulator. */
- regs[i].exp = 0;
- regs[i].sigh = 0x80000000;
+ if ( !((regs[i].exp == EXP_UNDER) && (regs[i].sigh == 0)
+ && (regs[i].sigl == 0)) )
+ regs[i].sigh |= 0x80000000;
}
finit();
current->used_math = 1;
@@ -262,7 +264,7 @@ do_another_FPU_instruction:
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1);
- FPU_modrm = get_fs_byte((unsigned char *) FPU_EIP);
+ get_user(FPU_modrm, (unsigned char *) FPU_EIP);
RE_ENTRANT_CHECK_ON;
FPU_EIP++;
@@ -283,24 +285,8 @@ do_another_FPU_instruction:
/*
* We need to simulate the action of the kernel to FPU
* interrupts here.
- * Currently, the "real FPU" part of the kernel (0.99.10)
- * clears the exception flags, sets the registers to empty,
- * and passes information back to the interrupted process
- * via the cs selector and operand selector, so we do the same.
*/
do_the_FPU_interrupt:
- instruction_address.selector = status_word();
- operand_address.selector = tag_word();
- partial_status = 0;
- top = 0;
- {
- int r;
- for (r = 0; r < 8; r++)
- {
- regs[r].tag = TW_Empty;
- }
- }
-
FPU_EIP = FPU_ORIG_EIP; /* Point to current FPU instruction. */
RE_ENTRANT_CHECK_OFF;
@@ -605,7 +591,7 @@ static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip,
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1);
- byte = get_fs_byte(ip);
+ get_user(byte, ip);
RE_ENTRANT_CHECK_ON;
while ( 1 )
@@ -651,7 +637,7 @@ static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip,
ip++;
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1);
- byte = get_fs_byte(ip);
+ get_user(byte, ip);
RE_ENTRANT_CHECK_ON;
break;
case FWAIT_OPCODE:
@@ -688,3 +674,22 @@ void math_abort(struct info * info, unsigned int signal)
printk("ERROR: wm-FPU-emu math_abort failed!\n");
#endif PARANOID
}
+
+
+
+void restore_i387_soft(struct _fpstate *buf)
+{
+ fpu_addr_modes addr_modes = {{ 0, 0, PREFIX_DEFAULT }, 0};
+
+ frstor(addr_modes, (char *)buf);
+}
+
+
+struct _fpstate * save_i387_soft(struct _fpstate * buf)
+{
+ fpu_addr_modes addr_modes = {{ 0, 0, PREFIX_DEFAULT }, 0};
+
+ fsave(addr_modes, (char *)buf);
+
+ return buf;
+}
diff --git a/arch/i386/math-emu/fpu_proto.h b/arch/i386/math-emu/fpu_proto.h
index b4392fe57..d0e58ed0e 100644
--- a/arch/i386/math-emu/fpu_proto.h
+++ b/arch/i386/math-emu/fpu_proto.h
@@ -7,7 +7,7 @@ extern void stack_underflow(void);
extern void stack_underflow_i(int i);
extern void stack_underflow_pop(int i);
extern int set_precision_flag(int flags);
-asmlinkage void exception(int n);
+asmlinkage void FPU_exception(int n);
asmlinkage int real_2op_NaN(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest);
asmlinkage int arith_invalid(FPU_REG *dest);
asmlinkage int divide_by_zero(int sign, FPU_REG *dest);
diff --git a/arch/i386/math-emu/get_address.c b/arch/i386/math-emu/get_address.c
index 6f3270ae3..0749cdc70 100644
--- a/arch/i386/math-emu/get_address.c
+++ b/arch/i386/math-emu/get_address.c
@@ -21,7 +21,7 @@
#include <linux/stddef.h>
#include <linux/head.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include "fpu_system.h"
#include "exception.h"
@@ -56,12 +56,16 @@ static int reg_offset_vm86[] = {
#define VM86_REG_(x) (*(unsigned short *) \
(reg_offset_vm86[((unsigned)x)]+(char *) FPU_info))
+/* These are dummy, fs and gs are not saved on the stack. */
+#define ___FS ___ds
+#define ___GS ___ds
+
static int reg_offset_pm[] = {
offsetof(struct info,___cs),
offsetof(struct info,___ds),
offsetof(struct info,___es),
- offsetof(struct info,___fs),
- offsetof(struct info,___gs),
+ offsetof(struct info,___FS),
+ offsetof(struct info,___GS),
offsetof(struct info,___ss),
offsetof(struct info,___ds)
};
@@ -78,7 +82,7 @@ static int sib(int mod, unsigned long *fpu_eip)
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1);
- base = get_fs_byte((char *) (*fpu_eip)); /* The SIB byte */
+ get_user(base, (unsigned char *) (*fpu_eip)); /* The SIB byte */
RE_ENTRANT_CHECK_ON;
(*fpu_eip)++;
ss = base >> 6;
@@ -105,18 +109,22 @@ static int sib(int mod, unsigned long *fpu_eip)
if (mod == 1)
{
/* 8 bit signed displacement */
+ long displacement;
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1);
- offset += (signed char) get_fs_byte((char *) (*fpu_eip));
+ get_user(displacement, (signed char *) (*fpu_eip));
+ offset += displacement;
RE_ENTRANT_CHECK_ON;
(*fpu_eip)++;
}
else if (mod == 2 || base == 5) /* The second condition also has mod==0 */
{
/* 32 bit displacement */
+ long displacement;
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(4);
- offset += (signed) get_fs_long((unsigned long *) (*fpu_eip));
+ get_user(displacement, (signed long *) (*fpu_eip));
+ offset += displacement;
RE_ENTRANT_CHECK_ON;
(*fpu_eip) += 4;
}
@@ -149,7 +157,9 @@ static long pm_address(unsigned char FPU_modrm, unsigned char segment,
unsigned long base_address, limit, address, seg_top;
segment--;
+
#ifdef PARANOID
+ /* segment is unsigned, so this also detects if segment was 0: */
if ( segment > PREFIX_SS_ )
{
EXCEPTION(EX_INTERNAL|0x132);
@@ -157,7 +167,19 @@ static long pm_address(unsigned char FPU_modrm, unsigned char segment,
}
#endif PARANOID
- *selector = PM_REG_(segment);
+ switch ( segment )
+ {
+ /* fs and gs aren't used by the kernel, so they still have their
+ user-space values. */
+ case PREFIX_FS_-1:
+ __asm__("mov %%fs,%0":"=r" (*selector));
+ break;
+ case PREFIX_GS_-1:
+ __asm__("mov %%gs,%0":"=r" (*selector));
+ break;
+ default:
+ *selector = PM_REG_(segment);
+ }
descriptor = LDT_DESCRIPTOR(PM_REG_(segment));
base_address = SEG_BASE_ADDR(descriptor);
@@ -248,7 +270,7 @@ void *get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
/* Special case: disp32 */
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(4);
- address = get_fs_long((unsigned long *) (*fpu_eip));
+ get_user(address, (unsigned long *) (*fpu_eip));
(*fpu_eip) += 4;
RE_ENTRANT_CHECK_ON;
addr->offset = address;
@@ -265,7 +287,7 @@ void *get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
/* 8 bit signed displacement */
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1);
- address = (signed char) get_fs_byte((char *) (*fpu_eip));
+ get_user(address, (signed char *) (*fpu_eip));
RE_ENTRANT_CHECK_ON;
(*fpu_eip)++;
break;
@@ -273,7 +295,7 @@ void *get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
/* 32 bit displacement */
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(4);
- address = (signed) get_fs_long((unsigned long *) (*fpu_eip));
+ get_user(address, (long *) (*fpu_eip));
(*fpu_eip) += 4;
RE_ENTRANT_CHECK_ON;
break;
@@ -336,7 +358,7 @@ void *get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
/* Special case: disp16 */
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(2);
- address = (unsigned short)get_fs_word((unsigned short *) (*fpu_eip));
+ get_user(address, (unsigned short *) (*fpu_eip));
(*fpu_eip) += 2;
RE_ENTRANT_CHECK_ON;
goto add_segment;
@@ -346,7 +368,7 @@ void *get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
/* 8 bit signed displacement */
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(1);
- address = (signed char) get_fs_byte((signed char *) (*fpu_eip));
+ get_user(address, (signed char *) (*fpu_eip));
RE_ENTRANT_CHECK_ON;
(*fpu_eip)++;
break;
@@ -354,7 +376,7 @@ void *get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
/* 16 bit displacement */
RE_ENTRANT_CHECK_OFF;
FPU_code_verify_area(2);
- address = (unsigned) get_fs_word((unsigned short *) (*fpu_eip));
+ get_user(address, (unsigned short *) (*fpu_eip));
(*fpu_eip) += 2;
RE_ENTRANT_CHECK_ON;
break;
diff --git a/arch/i386/math-emu/load_store.c b/arch/i386/math-emu/load_store.c
index 6f0e167d6..cc288a9ab 100644
--- a/arch/i386/math-emu/load_store.c
+++ b/arch/i386/math-emu/load_store.c
@@ -18,7 +18,7 @@
| other processes using the emulator while swapping is in progress. |
+---------------------------------------------------------------------------*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include "fpu_system.h"
#include "exception.h"
@@ -201,7 +201,7 @@ int load_store_instr(unsigned char type, fpu_addr_modes addr_modes,
case 024: /* fldcw */
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, data_address, 2);
- control_word = get_fs_word((unsigned short *) data_address);
+ get_user(control_word, (unsigned short *) data_address);
RE_ENTRANT_CHECK_ON;
if ( partial_status & ~control_word & CW_Exceptions )
partial_status |= (SW_Summary | SW_Backward);
@@ -234,7 +234,7 @@ int load_store_instr(unsigned char type, fpu_addr_modes addr_modes,
case 034: /* fstcw m16int */
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,data_address,2);
- put_fs_word(control_word, (short *) data_address);
+ put_user(control_word, (unsigned short *) data_address);
RE_ENTRANT_CHECK_ON;
return 1;
case 035: /* fstp m80real */
@@ -246,7 +246,7 @@ int load_store_instr(unsigned char type, fpu_addr_modes addr_modes,
case 036: /* fstsw m2byte */
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,data_address,2);
- put_fs_word(status_word(),(short *) data_address);
+ put_user(status_word(),(unsigned short *) data_address);
RE_ENTRANT_CHECK_ON;
return 1;
case 037: /* fistp m64int */
diff --git a/arch/i386/math-emu/mul_Xsig.S b/arch/i386/math-emu/mul_Xsig.S
index 1d88d4466..717785a53 100644
--- a/arch/i386/math-emu/mul_Xsig.S
+++ b/arch/i386/math-emu/mul_Xsig.S
@@ -3,9 +3,9 @@
| |
| Multiply a 12 byte fixed point number by another fixed point number. |
| |
- | Copyright (C) 1992,1994 |
+ | Copyright (C) 1992,1994,1995 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Australia. E-mail billm@jacobi.maths.monash.edu.au |
| |
| Call from C as: |
| void mul32_Xsig(Xsig *x, unsigned b) |
@@ -21,12 +21,10 @@
.file "mul_Xsig.S"
-#include "fpu_asm.h"
+#include "fpu_emu.h"
.text
- .align 2,144
-.globl _mul32_Xsig
-_mul32_Xsig:
+ENTRY(mul32_Xsig)
pushl %ebp
movl %esp,%ebp
subl $16,%esp
@@ -66,9 +64,7 @@ _mul32_Xsig:
ret
- .align 2,144
-.globl _mul64_Xsig
-_mul64_Xsig:
+ENTRY(mul64_Xsig)
pushl %ebp
movl %esp,%ebp
subl $16,%esp
@@ -121,9 +117,7 @@ _mul64_Xsig:
- .align 2,144
-.globl _mul_Xsig_Xsig
-_mul_Xsig_Xsig:
+ENTRY(mul_Xsig_Xsig)
pushl %ebp
movl %esp,%ebp
subl $16,%esp
diff --git a/arch/i386/math-emu/polynom_Xsig.S b/arch/i386/math-emu/polynom_Xsig.S
index 585221f96..17315c89f 100644
--- a/arch/i386/math-emu/polynom_Xsig.S
+++ b/arch/i386/math-emu/polynom_Xsig.S
@@ -3,9 +3,9 @@
| |
| Fixed point arithmetic polynomial evaluation. |
| |
- | Copyright (C) 1992,1993,1994 |
+ | Copyright (C) 1992,1993,1994,1995 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Australia. E-mail billm@jacobi.maths.monash.edu.au |
| |
| Call from C as: |
| void polynomial_Xsig(Xsig *accum, unsigned long long x, |
@@ -23,7 +23,7 @@
+---------------------------------------------------------------------------*/
.file "polynomial_Xsig.S"
-#include "fpu_asm.h"
+#include "fpu_emu.h"
#define TERM_SIZE $8
@@ -36,9 +36,7 @@
#define OVERFLOWED -16(%ebp) /* addition overflow flag */
.text
- .align 2,144
-.globl _polynomial_Xsig
-_polynomial_Xsig:
+ENTRY(polynomial_Xsig)
pushl %ebp
movl %esp,%ebp
subl $32,%esp
diff --git a/arch/i386/math-emu/reg_constant.c b/arch/i386/math-emu/reg_constant.c
index c1981ce24..1b2458eea 100644
--- a/arch/i386/math-emu/reg_constant.c
+++ b/arch/i386/math-emu/reg_constant.c
@@ -3,9 +3,9 @@
| |
| All of the constant FPU_REGs |
| |
- | Copyright (C) 1992,1993,1994 |
- | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Copyright (C) 1992,1993,1994,1996 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@jacobi.maths.monash.edu.au |
| |
| |
+---------------------------------------------------------------------------*/
@@ -14,6 +14,7 @@
#include "fpu_emu.h"
#include "status_w.h"
#include "reg_constant.h"
+#include "control_w.h"
FPU_REG const CONST_1 = { SIGN_POS, TW_Valid, EXP_BIAS,
@@ -56,7 +57,7 @@ FPU_REG const CONST_INF = { SIGN_POS, TW_Infinity, EXP_OVER, 0x00000000, 0x8000
-static void fld_const(FPU_REG const *c)
+static void fld_const(FPU_REG const *c, int adj)
{
FPU_REG *st_new_ptr;
@@ -67,50 +68,58 @@ static void fld_const(FPU_REG const *c)
}
push();
reg_move(c, st_new_ptr);
+ st_new_ptr->sigl += adj; /* For all our fldxxx constants, we don't need to
+ borrow or carry. */
clear_C1();
}
+/* A fast way to find out whether x is one of RC_DOWN or RC_CHOP
+ (and not one of RC_RND or RC_UP).
+ */
+#define DOWN_OR_CHOP(x) (x & RC_DOWN)
-static void fld1(void)
+static void fld1(int rc)
{
- fld_const(&CONST_1);
+ fld_const(&CONST_1, 0);
}
-static void fldl2t(void)
+static void fldl2t(int rc)
{
- fld_const(&CONST_L2T);
+ fld_const(&CONST_L2T, (rc == RC_UP) ? 1 : 0);
}
-static void fldl2e(void)
+static void fldl2e(int rc)
{
- fld_const(&CONST_L2E);
+ fld_const(&CONST_L2E, DOWN_OR_CHOP(rc) ? -1 : 0);
}
-static void fldpi(void)
+static void fldpi(int rc)
{
- fld_const(&CONST_PI);
+ fld_const(&CONST_PI, DOWN_OR_CHOP(rc) ? -1 : 0);
}
-static void fldlg2(void)
+static void fldlg2(int rc)
{
- fld_const(&CONST_LG2);
+ fld_const(&CONST_LG2, DOWN_OR_CHOP(rc) ? -1 : 0);
}
-static void fldln2(void)
+static void fldln2(int rc)
{
- fld_const(&CONST_LN2);
+ fld_const(&CONST_LN2, DOWN_OR_CHOP(rc) ? -1 : 0);
}
-static void fldz(void)
+static void fldz(int rc)
{
- fld_const(&CONST_Z);
+ fld_const(&CONST_Z, 0);
}
-static FUNC constants_table[] = {
- fld1, fldl2t, fldl2e, fldpi, fldlg2, fldln2, fldz, FPU_illegal
+typedef void (*FUNC_RC)(int);
+
+static FUNC_RC constants_table[] = {
+ fld1, fldl2t, fldl2e, fldpi, fldlg2, fldln2, fldz, (FUNC_RC)FPU_illegal
};
void fconst(void)
{
- (constants_table[FPU_rm])();
+ (constants_table[FPU_rm])(control_word & CW_RC);
}
diff --git a/arch/i386/math-emu/reg_div.S b/arch/i386/math-emu/reg_div.S
index 2fbc5f7c4..24d44ac6c 100644
--- a/arch/i386/math-emu/reg_div.S
+++ b/arch/i386/math-emu/reg_div.S
@@ -4,9 +4,9 @@
| |
| Divide one FPU_REG by another and put the result in a destination FPU_REG.|
| |
- | Copyright (C) 1992,1993,1994 |
+ | Copyright (C) 1992,1993,1994,1995 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Australia. E-mail billm@jacobi.maths.monash.edu.au |
| |
| Call from C as: |
| void reg_div(FPU_REG *a, FPU_REG *b, FPU_REG *dest, |
@@ -15,14 +15,11 @@
+---------------------------------------------------------------------------*/
#include "exception.h"
-#include "fpu_asm.h"
+#include "fpu_emu.h"
.text
- .align 2
-
-.globl _reg_div
-_reg_div:
+ENTRY(reg_div)
pushl %ebp
movl %esp,%ebp
#ifndef NON_REENTRANT_FPU
@@ -47,7 +44,7 @@ _reg_div:
cmpl EXP_UNDER,EXP(%esi)
jg xL_arg1_not_denormal
- call _denormal_operand
+ call SYMBOL_NAME(denormal_operand)
orl %eax,%eax
jnz fpu_Arith_exit
@@ -55,7 +52,7 @@ xL_arg1_not_denormal:
cmpl EXP_UNDER,EXP(%ebx)
jg xL_arg2_not_denormal
- call _denormal_operand
+ call SYMBOL_NAME(denormal_operand)
orl %eax,%eax
jnz fpu_Arith_exit
@@ -75,7 +72,7 @@ xL_arg2_not_denormal:
addl EXP_BIAS,%edx
movl %edx,EXP(%edi)
- jmp _divide_kernel
+ jmp SYMBOL_NAME(divide_kernel)
/*-----------------------------------------------------------------------*/
@@ -92,14 +89,14 @@ L_arg2_NaN:
pushl %edi /* Destination */
pushl %esi
pushl %ebx /* Ordering is important here */
- call _real_2op_NaN
+ call SYMBOL_NAME(real_2op_NaN)
jmp LDiv_exit
/* Invalid operations */
L_zero_zero:
L_inf_inf:
pushl %edi /* Destination */
- call _arith_invalid /* 0/0 or Infinity/Infinity */
+ call SYMBOL_NAME(arith_invalid) /* 0/0 or Infinity/Infinity */
jmp LDiv_exit
L_no_NaN_arg:
@@ -126,7 +123,7 @@ L_inf_valid:
cmpl EXP_UNDER,EXP(%ebx)
jg L_copy_arg1 /* Answer is Inf */
- call _denormal_operand
+ call SYMBOL_NAME(denormal_operand)
orl %eax,%eax
jnz fpu_Arith_exit
#endif DENORM_OPERAND
@@ -151,7 +148,7 @@ L_arg1_not_inf:
movb SIGN(%esi),%al
xorb SIGN(%ebx),%al
pushl %eax /* lower 8 bits have the sign */
- call _divide_by_zero
+ call SYMBOL_NAME(divide_by_zero)
jmp LDiv_exit
L_arg2_not_zero:
@@ -165,7 +162,7 @@ L_arg2_not_zero:
cmpl EXP_UNDER,EXP(%esi)
jg L_return_zero /* Answer is zero */
- call _denormal_operand
+ call SYMBOL_NAME(denormal_operand)
orl %eax,%eax
jnz fpu_Arith_exit
#endif DENORM_OPERAND
@@ -185,7 +182,7 @@ L_arg2_not_inf:
cmpl EXP_UNDER,EXP(%ebx)
jg L_copy_arg1 /* Answer is zero */
- call _denormal_operand
+ call SYMBOL_NAME(denormal_operand)
orl %eax,%eax
jnz fpu_Arith_exit
#endif DENORM_OPERAND
@@ -241,11 +238,11 @@ L_unknown_tags:
call EXCEPTION
/* Generate a NaN for unknown tags */
- movl _CONST_QNaN,%eax
+ movl SYMBOL_NAME(CONST_QNaN),%eax
movl %eax,(%edi)
- movl _CONST_QNaN+4,%eax
+ movl SYMBOL_NAME(CONST_QNaN)+4,%eax
movl %eax,SIGL(%edi)
- movl _CONST_QNaN+8,%eax
+ movl SYMBOL_NAME(CONST_QNaN)+8,%eax
movl %eax,SIGH(%edi)
jmp LDiv_exit /* %eax is nz */
#endif PARANOID
diff --git a/arch/i386/math-emu/reg_ld_str.c b/arch/i386/math-emu/reg_ld_str.c
index efec9e010..3e258a0c6 100644
--- a/arch/i386/math-emu/reg_ld_str.c
+++ b/arch/i386/math-emu/reg_ld_str.c
@@ -3,9 +3,9 @@
| |
| All of the functions which transfer data between user memory and FPU_REGs.|
| |
- | Copyright (C) 1992,1993,1994 |
- | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Copyright (C) 1992,1993,1994,1996 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@jacobi.maths.monash.edu.au |
| |
| |
+---------------------------------------------------------------------------*/
@@ -17,7 +17,7 @@
| other processes using the emulator while swapping is in progress. |
+---------------------------------------------------------------------------*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include "fpu_system.h"
#include "exception.h"
@@ -48,9 +48,9 @@ int reg_load_extended(long double *s, FPU_REG *loaded_data)
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, s, 10);
- sigl = get_fs_long((unsigned long *) s);
- sigh = get_fs_long(1 + (unsigned long *) s);
- exp = get_fs_word(4 + (unsigned short *) s);
+ get_user(sigl, (unsigned long *) s);
+ get_user(sigh, 1 + (unsigned long *) s);
+ get_user(exp, 4 + (unsigned short *) s);
RE_ENTRANT_CHECK_ON;
loaded_data->tag = TW_Valid; /* Default */
@@ -144,8 +144,8 @@ int reg_load_double(double *dfloat, FPU_REG *loaded_data)
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, dfloat, 8);
- m64 = get_fs_long(1 + (unsigned long *) dfloat);
- l64 = get_fs_long((unsigned long *) dfloat);
+ get_user(m64, 1 + (unsigned long *) dfloat);
+ get_user(l64, (unsigned long *) dfloat);
RE_ENTRANT_CHECK_ON;
if (m64 & 0x80000000)
@@ -221,7 +221,7 @@ int reg_load_single(float *single, FPU_REG *loaded_data)
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, single, 4);
- m32 = get_fs_long((unsigned long *) single);
+ get_user(m32, (unsigned long *) single);
RE_ENTRANT_CHECK_ON;
if (m32 & 0x80000000)
@@ -289,8 +289,7 @@ void reg_load_int64(long long *_s, FPU_REG *loaded_data)
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, _s, 8);
- ((unsigned long *)&s)[0] = get_fs_long((unsigned long *) _s);
- ((unsigned long *)&s)[1] = get_fs_long(1 + (unsigned long *) _s);
+ copy_from_user(&s,_s,8);
RE_ENTRANT_CHECK_ON;
if (s == 0)
@@ -320,7 +319,7 @@ void reg_load_int32(long *_s, FPU_REG *loaded_data)
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, _s, 4);
- s = (long)get_fs_long((unsigned long *) _s);
+ get_user(s, _s);
RE_ENTRANT_CHECK_ON;
if (s == 0)
@@ -351,7 +350,7 @@ void reg_load_int16(short *_s, FPU_REG *loaded_data)
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, _s, 2);
/* Cast as short to get the sign extended. */
- s = (short)get_fs_word((unsigned short *) _s);
+ get_user(s, _s);
RE_ENTRANT_CHECK_ON;
if (s == 0)
@@ -389,7 +388,7 @@ void reg_load_bcd(char *s, FPU_REG *loaded_data)
{
l *= 10;
RE_ENTRANT_CHECK_OFF;
- bcd = (unsigned char)get_fs_byte((unsigned char *) s+pos);
+ get_user(bcd, (unsigned char *) s+pos);
RE_ENTRANT_CHECK_ON;
l += bcd >> 4;
l *= 10;
@@ -397,9 +396,11 @@ void reg_load_bcd(char *s, FPU_REG *loaded_data)
}
RE_ENTRANT_CHECK_OFF;
- loaded_data->sign =
- ((unsigned char)get_fs_byte((unsigned char *) s+9)) & 0x80 ?
- SIGN_NEG : SIGN_POS;
+ {
+ unsigned char sign;
+ get_user(sign, (unsigned char *) s+9);
+ loaded_data->sign = (sign & 0x80) ? SIGN_NEG : SIGN_POS;
+ }
RE_ENTRANT_CHECK_ON;
if (l == 0)
@@ -445,9 +446,9 @@ int reg_store_extended(long double *d, FPU_REG *st0_ptr)
/* Put out the QNaN indefinite */
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,d,10);
- put_fs_long(0, (unsigned long *) d);
- put_fs_long(0xc0000000, 1 + (unsigned long *) d);
- put_fs_word(0xffff, 4 + (short *) d);
+ put_user(0, (unsigned long *) d);
+ put_user(0xc0000000, 1 + (unsigned long *) d);
+ put_user(0xffff, 4 + (short *) d);
RE_ENTRANT_CHECK_ON;
return 1;
}
@@ -466,6 +467,7 @@ int reg_store_double(double *dfloat, FPU_REG *st0_ptr)
if (st0_tag == TW_Valid)
{
+ int precision_loss;
int exp;
FPU_REG tmp;
@@ -474,8 +476,6 @@ int reg_store_double(double *dfloat, FPU_REG *st0_ptr)
if ( exp < DOUBLE_Emin ) /* It may be a denormal */
{
- int precision_loss;
-
/* A denormal will always underflow. */
#ifndef PECULIAR_486
/* An 80486 is supposed to be able to generate
@@ -518,6 +518,7 @@ int reg_store_double(double *dfloat, FPU_REG *st0_ptr)
{
if ( tmp.sigl & 0x000007ff )
{
+ precision_loss = 1;
switch (control_word & CW_RC)
{
case RC_RND:
@@ -541,8 +542,6 @@ int reg_store_double(double *dfloat, FPU_REG *st0_ptr)
if ( increment )
{
- set_precision_flag_up();
-
if ( tmp.sigl >= 0xfffff800 )
{
/* the sigl part overflows */
@@ -566,9 +565,9 @@ int reg_store_double(double *dfloat, FPU_REG *st0_ptr)
tmp.sigl += 0x00000800;
}
}
- else
- set_precision_flag_down();
}
+ else
+ precision_loss = 0;
l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21);
l[1] = ((tmp.sigh >> 11) & 0xfffff);
@@ -590,6 +589,13 @@ int reg_store_double(double *dfloat, FPU_REG *st0_ptr)
}
else
{
+ if ( precision_loss )
+ {
+ if ( increment )
+ set_precision_flag_up();
+ else
+ set_precision_flag_down();
+ }
/* Add the exponent */
l[1] |= (((exp+DOUBLE_Ebias) & 0x7ff) << 20);
}
@@ -631,8 +637,8 @@ int reg_store_double(double *dfloat, FPU_REG *st0_ptr)
/* Put out the QNaN indefinite */
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8);
- put_fs_long(0, (unsigned long *) dfloat);
- put_fs_long(0xfff80000, 1 + (unsigned long *) dfloat);
+ put_user(0, (unsigned long *) dfloat);
+ put_user(0xfff80000, 1 + (unsigned long *) dfloat);
RE_ENTRANT_CHECK_ON;
return 1;
}
@@ -644,8 +650,8 @@ int reg_store_double(double *dfloat, FPU_REG *st0_ptr)
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8);
- put_fs_long(l[0], (unsigned long *)dfloat);
- put_fs_long(l[1], 1 + (unsigned long *)dfloat);
+ put_user(l[0], (unsigned long *)dfloat);
+ put_user(l[1], 1 + (unsigned long *)dfloat);
RE_ENTRANT_CHECK_ON;
return 1;
@@ -661,6 +667,7 @@ int reg_store_single(float *single, FPU_REG *st0_ptr)
if (st0_tag == TW_Valid)
{
+ int precision_loss;
int exp;
FPU_REG tmp;
@@ -669,8 +676,6 @@ int reg_store_single(float *single, FPU_REG *st0_ptr)
if ( exp < SINGLE_Emin )
{
- int precision_loss;
-
/* A denormal will always underflow. */
#ifndef PECULIAR_486
/* An 80486 is supposed to be able to generate
@@ -715,6 +720,7 @@ int reg_store_single(float *single, FPU_REG *st0_ptr)
unsigned long sigh = tmp.sigh;
unsigned long sigl = tmp.sigl;
+ precision_loss = 1;
switch (control_word & CW_RC)
{
case RC_RND:
@@ -740,8 +746,6 @@ int reg_store_single(float *single, FPU_REG *st0_ptr)
if (increment)
{
- set_precision_flag_up();
-
if ( sigh >= 0xffffff00 )
{
/* The sigh part overflows */
@@ -758,10 +762,11 @@ int reg_store_single(float *single, FPU_REG *st0_ptr)
}
else
{
- set_precision_flag_down();
tmp.sigh &= 0xffffff00; /* Finish the truncation */
}
}
+ else
+ precision_loss = 0;
templ = (tmp.sigh >> 8) & 0x007fffff;
@@ -780,7 +785,17 @@ int reg_store_single(float *single, FPU_REG *st0_ptr)
templ = 0x7f800000;
}
else
- templ |= ((exp+SINGLE_Ebias) & 0xff) << 23;
+ {
+ if ( precision_loss )
+ {
+ if ( increment )
+ set_precision_flag_up();
+ else
+ set_precision_flag_down();
+ }
+ /* Add the exponent */
+ templ |= ((exp+SINGLE_Ebias) & 0xff) << 23;
+ }
}
}
else if (st0_tag == TW_Zero)
@@ -815,7 +830,7 @@ int reg_store_single(float *single, FPU_REG *st0_ptr)
/* Put out the QNaN indefinite */
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,(void *)single,4);
- put_fs_long(0xffc00000, (unsigned long *) single);
+ put_user(0xffc00000, (unsigned long *) single);
RE_ENTRANT_CHECK_ON;
return 1;
}
@@ -834,7 +849,7 @@ int reg_store_single(float *single, FPU_REG *st0_ptr)
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,(void *)single,4);
- put_fs_long(templ,(unsigned long *) single);
+ put_user(templ,(unsigned long *) single);
RE_ENTRANT_CHECK_ON;
return 1;
@@ -892,8 +907,7 @@ int reg_store_int64(long long *d, FPU_REG *st0_ptr)
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,(void *)d,8);
- put_fs_long(((long *)&tll)[0],(unsigned long *) d);
- put_fs_long(((long *)&tll)[1],1 + (unsigned long *) d);
+ copy_to_user(d, &tll, 8);
RE_ENTRANT_CHECK_ON;
return 1;
@@ -947,7 +961,7 @@ int reg_store_int32(long *d, FPU_REG *st0_ptr)
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,d,4);
- put_fs_long(t.sigl, (unsigned long *) d);
+ put_user(t.sigl, (unsigned long *) d);
RE_ENTRANT_CHECK_ON;
return 1;
@@ -1001,7 +1015,7 @@ int reg_store_int16(short *d, FPU_REG *st0_ptr)
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,d,2);
- put_fs_word((short)t.sigl,(short *) d);
+ put_user((short)t.sigl,(short *) d);
RE_ENTRANT_CHECK_ON;
return 1;
@@ -1042,10 +1056,10 @@ int reg_store_bcd(char *d, FPU_REG *st0_ptr)
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,d,10);
for ( i = 0; i < 7; i++)
- put_fs_byte(0, (unsigned char *) d+i); /* These bytes "undefined" */
- put_fs_byte(0xc0, (unsigned char *) d+7); /* This byte "undefined" */
- put_fs_byte(0xff, (unsigned char *) d+8);
- put_fs_byte(0xff, (unsigned char *) d+9);
+ put_user(0, (unsigned char *) d+i); /* These bytes "undefined" */
+ put_user(0xc0, (unsigned char *) d+7); /* This byte "undefined" */
+ put_user(0xff, (unsigned char *) d+8);
+ put_user(0xff, (unsigned char *) d+9);
RE_ENTRANT_CHECK_ON;
return 1;
}
@@ -1066,11 +1080,11 @@ int reg_store_bcd(char *d, FPU_REG *st0_ptr)
b = div_small(&ll, 10);
b |= (div_small(&ll, 10)) << 4;
RE_ENTRANT_CHECK_OFF;
- put_fs_byte(b,(unsigned char *) d+i);
+ put_user(b,(unsigned char *) d+i);
RE_ENTRANT_CHECK_ON;
}
RE_ENTRANT_CHECK_OFF;
- put_fs_byte(sign,(unsigned char *) d+9);
+ put_user(sign,(unsigned char *) d+9);
RE_ENTRANT_CHECK_ON;
return 1;
@@ -1158,13 +1172,13 @@ char *fldenv(fpu_addr_modes addr_modes, char *s)
{
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, s, 0x0e);
- control_word = get_fs_word((unsigned short *) s);
- partial_status = get_fs_word((unsigned short *) (s+2));
- tag_word = get_fs_word((unsigned short *) (s+4));
- instruction_address.offset = get_fs_word((unsigned short *) (s+6));
- instruction_address.selector = get_fs_word((unsigned short *) (s+8));
- operand_address.offset = get_fs_word((unsigned short *) (s+0x0a));
- operand_address.selector = get_fs_word((unsigned short *) (s+0x0c));
+ get_user(control_word, (unsigned short *) s);
+ get_user(partial_status, (unsigned short *) (s+2));
+ get_user(tag_word, (unsigned short *) (s+4));
+ get_user(instruction_address.offset, (unsigned short *) (s+6));
+ get_user(instruction_address.selector, (unsigned short *) (s+8));
+ get_user(operand_address.offset, (unsigned short *) (s+0x0a));
+ get_user(operand_address.selector, (unsigned short *) (s+0x0c));
RE_ENTRANT_CHECK_ON;
s += 0x0e;
if ( addr_modes.default_mode == VM86 )
@@ -1178,14 +1192,14 @@ char *fldenv(fpu_addr_modes addr_modes, char *s)
{
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_READ, s, 0x1c);
- control_word = get_fs_word((unsigned short *) s);
- partial_status = get_fs_word((unsigned short *) (s+4));
- tag_word = get_fs_word((unsigned short *) (s+8));
- instruction_address.offset = get_fs_long((unsigned long *) (s+0x0c));
- instruction_address.selector = get_fs_word((unsigned short *) (s+0x10));
- instruction_address.opcode = get_fs_word((unsigned short *) (s+0x12));
- operand_address.offset = get_fs_long((unsigned long *) (s+0x14));
- operand_address.selector = get_fs_long((unsigned long *) (s+0x18));
+ get_user(control_word, (unsigned short *) s);
+ get_user(partial_status, (unsigned short *) (s+4));
+ get_user(tag_word, (unsigned short *) (s+8));
+ get_user(instruction_address.offset, (unsigned long *) (s+0x0c));
+ get_user(instruction_address.selector, (unsigned short *) (s+0x10));
+ get_user(instruction_address.opcode, (unsigned short *) (s+0x12));
+ get_user(operand_address.offset, (unsigned long *) (s+0x14));
+ get_user(operand_address.selector, (unsigned long *) (s+0x18));
RE_ENTRANT_CHECK_ON;
s += 0x1c;
}
@@ -1296,25 +1310,25 @@ char *fstenv(fpu_addr_modes addr_modes, char *d)
RE_ENTRANT_CHECK_OFF;
FPU_verify_area(VERIFY_WRITE,d,14);
#ifdef PECULIAR_486
- put_fs_long(control_word & ~0xe080, (unsigned short *) d);
+ put_user(control_word & ~0xe080, (unsigned long *) d);
#else
- put_fs_word(control_word, (unsigned short *) d);
+ put_user(control_word, (unsigned short *) d);
#endif PECULIAR_486
- put_fs_word(status_word(), (unsigned short *) (d+2));
- put_fs_word(tag_word(), (unsigned short *) (d+4));
- put_fs_word(instruction_address.offset, (unsigned short *) (d+6));
- put_fs_word(operand_address.offset, (unsigned short *) (d+0x0a));
+ put_user(status_word(), (unsigned short *) (d+2));
+ put_user(tag_word(), (unsigned short *) (d+4));
+ put_user(instruction_address.offset, (unsigned short *) (d+6));
+ put_user(operand_address.offset, (unsigned short *) (d+0x0a));
if ( addr_modes.default_mode == VM86 )
{
- put_fs_word((instruction_address.offset & 0xf0000) >> 4,
+ put_user((instruction_address.offset & 0xf0000) >> 4,
(unsigned short *) (d+8));
- put_fs_word((operand_address.offset & 0xf0000) >> 4,
+ put_user((operand_address.offset & 0xf0000) >> 4,
(unsigned short *) (d+0x0c));
}
else
{
- put_fs_word(instruction_address.selector, (unsigned short *) (d+8));
- put_fs_word(operand_address.selector, (unsigned short *) (d+0x0c));
+ put_user(instruction_address.selector, (unsigned short *) (d+8));
+ put_user(operand_address.selector, (unsigned short *) (d+0x0c));
}
RE_ENTRANT_CHECK_ON;
d += 0x0e;
@@ -1325,24 +1339,24 @@ char *fstenv(fpu_addr_modes addr_modes, char *d)
FPU_verify_area(VERIFY_WRITE,d,28);
#ifdef PECULIAR_486
/* An 80486 sets all the reserved bits to 1. */
- put_fs_long(0xffff0040 | (control_word & ~0xe080), (unsigned long *) d);
- put_fs_long(0xffff0000 | status_word(), (unsigned long *) (d+4));
- put_fs_long(0xffff0000 | tag_word(), (unsigned long *) (d+8));
+ put_user(0xffff0040 | (control_word & ~0xe080), (unsigned long *) d);
+ put_user(0xffff0000 | status_word(), (unsigned long *) (d+4));
+ put_user(0xffff0000 | tag_word(), (unsigned long *) (d+8));
#else
- put_fs_word(control_word, (unsigned short *) d);
- put_fs_word(status_word(), (unsigned short *) (d+4));
- put_fs_word(tag_word(), (unsigned short *) (d+8));
+ put_user(control_word, (unsigned short *) d);
+ put_user(status_word(), (unsigned short *) (d+4));
+ put_user(tag_word(), (unsigned short *) (d+8));
#endif PECULIAR_486
- put_fs_long(instruction_address.offset, (unsigned long *) (d+0x0c));
- put_fs_word(instruction_address.selector, (unsigned short *) (d+0x10));
- put_fs_word(instruction_address.opcode, (unsigned short *) (d+0x12));
- put_fs_long(operand_address.offset, (unsigned long *) (d+0x14));
+ put_user(instruction_address.offset, (unsigned long *) (d+0x0c));
+ put_user(instruction_address.selector, (unsigned short *) (d+0x10));
+ put_user(instruction_address.opcode, (unsigned short *) (d+0x12));
+ put_user(operand_address.offset, (unsigned long *) (d+0x14));
#ifdef PECULIAR_486
/* An 80486 sets all the reserved bits to 1. */
- put_fs_word(operand_address.selector, (unsigned short *) (d+0x18));
- put_fs_word(0xffff, (unsigned short *) (d+0x1a));
+ put_user(operand_address.selector, (unsigned short *) (d+0x18));
+ put_user(0xffff, (unsigned short *) (d+0x1a));
#else
- put_fs_long(operand_address.selector, (unsigned long *) (d+0x18));
+ put_user(operand_address.selector, (unsigned long *) (d+0x18));
#endif PECULIAR_486
RE_ENTRANT_CHECK_ON;
d += 0x1c;
@@ -1411,8 +1425,8 @@ static void write_to_extended(FPU_REG *rp, char *d)
{
/* just copy the reg */
RE_ENTRANT_CHECK_OFF;
- put_fs_long(rp->sigl, (unsigned long *) d);
- put_fs_long(rp->sigh, (unsigned long *) (d + 4));
+ put_user(rp->sigl, (unsigned long *) d);
+ put_user(rp->sigh, (unsigned long *) (d + 4));
RE_ENTRANT_CHECK_ON;
}
else
@@ -1427,12 +1441,12 @@ static void write_to_extended(FPU_REG *rp, char *d)
round_to_int(&tmp);
e = 0;
RE_ENTRANT_CHECK_OFF;
- put_fs_long(tmp.sigl, (unsigned long *) d);
- put_fs_long(tmp.sigh, (unsigned long *) (d + 4));
+ put_user(tmp.sigl, (unsigned long *) d);
+ put_user(tmp.sigh, (unsigned long *) (d + 4));
RE_ENTRANT_CHECK_ON;
}
e |= rp->sign == SIGN_POS ? 0 : 0x8000;
RE_ENTRANT_CHECK_OFF;
- put_fs_word(e, (unsigned short *) (d + 8));
+ put_user(e, (unsigned short *) (d + 8));
RE_ENTRANT_CHECK_ON;
}
diff --git a/arch/i386/math-emu/reg_norm.S b/arch/i386/math-emu/reg_norm.S
index 9b7a9d77d..781a2d466 100644
--- a/arch/i386/math-emu/reg_norm.S
+++ b/arch/i386/math-emu/reg_norm.S
@@ -1,9 +1,9 @@
/*---------------------------------------------------------------------------+
| reg_norm.S |
| |
- | Copyright (C) 1992,1993,1994 |
+ | Copyright (C) 1992,1993,1994,1995 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Australia. E-mail billm@jacobi.maths.monash.edu.au |
| |
| Normalize the value in a FPU_REG. |
| |
@@ -14,15 +14,11 @@
| |
+---------------------------------------------------------------------------*/
-#include "fpu_asm.h"
+#include "fpu_emu.h"
.text
-
- .align 2,144
-.globl _normalize
-
-_normalize:
+ENTRY(normalize)
pushl %ebp
movl %esp,%ebp
pushl %ebx
@@ -34,7 +30,7 @@ _normalize:
je L_ok
pushl $0x220
- call _exception
+ call SYMBOL_NAME(FPU_exception)
addl $4,%esp
L_ok:
@@ -86,23 +82,20 @@ L_zero:
L_underflow:
push %ebx
- call _arith_underflow
+ call SYMBOL_NAME(arith_underflow)
pop %ebx
jmp L_exit
L_overflow:
push %ebx
- call _arith_overflow
+ call SYMBOL_NAME(arith_overflow)
pop %ebx
jmp L_exit
/* Normalise without reporting underflow or overflow */
- .align 2,144
-.globl _normalize_nuo
-
-_normalize_nuo:
+ENTRY(normalize_nuo)
pushl %ebp
movl %esp,%ebp
pushl %ebx
@@ -114,7 +107,7 @@ _normalize_nuo:
je L_ok_nuo
pushl $0x221
- call _exception
+ call SYMBOL_NAME(FPU_exception)
addl $4,%esp
L_ok_nuo:
diff --git a/arch/i386/math-emu/reg_round.S b/arch/i386/math-emu/reg_round.S
index bd8a40dc4..4aac507a1 100644
--- a/arch/i386/math-emu/reg_round.S
+++ b/arch/i386/math-emu/reg_round.S
@@ -4,9 +4,9 @@
| |
| Rounding/truncation/etc for FPU basic arithmetic functions. |
| |
- | Copyright (C) 1993 |
+ | Copyright (C) 1993,1995 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Australia. E-mail billm@jacobi.maths.monash.edu.au |
| |
| This code has four possible entry points. |
| The following must be entered by a jmp instruction: |
@@ -69,7 +69,7 @@
+---------------------------------------------------------------------------*/
-#include "fpu_asm.h"
+#include "fpu_emu.h"
#include "exception.h"
#include "control_w.h"
@@ -101,14 +101,12 @@ FPU_denormal:
.text
- .align 2,144
.globl fpu_reg_round
.globl fpu_reg_round_sqrt
.globl fpu_Arith_exit
-.globl _round_reg
/* Entry point when called from C */
-_round_reg:
+ENTRY(round_reg)
pushl %ebp
movl %esp,%ebp
pushl %esi
@@ -435,7 +433,7 @@ fpu_Arith_exit:
*/
xL_precision_lost_up:
push %eax
- call _set_precision_flag_up
+ call SYMBOL_NAME(set_precision_flag_up)
popl %eax
jmp xL_no_precision_loss
@@ -445,7 +443,7 @@ xL_precision_lost_up:
*/
xL_precision_lost_down:
push %eax
- call _set_precision_flag_down
+ call SYMBOL_NAME(set_precision_flag_down)
popl %eax
jmp xL_no_precision_loss
@@ -598,7 +596,7 @@ LNormalise_shift_done:
/* There must be a masked underflow */
push %eax
pushl EX_Underflow
- call _exception
+ call SYMBOL_NAME(FPU_exception)
popl %eax
popl %eax
jmp xL_Normalised
@@ -610,12 +608,12 @@ LNormalise_shift_done:
*/
L_underflow_to_zero:
push %eax
- call _set_precision_flag_down
+ call SYMBOL_NAME(set_precision_flag_down)
popl %eax
push %eax
pushl EX_Underflow
- call _exception
+ call SYMBOL_NAME(FPU_exception)
popl %eax
popl %eax
@@ -628,7 +626,7 @@ L_underflow_to_zero:
/* The operations resulted in a number too large to represent. */
L_overflow:
push %edi
- call _arith_overflow
+ call SYMBOL_NAME(arith_overflow)
pop %edi
jmp fpu_reg_round_exit
diff --git a/arch/i386/math-emu/reg_u_add.S b/arch/i386/math-emu/reg_u_add.S
index 4410f8fd4..1dc0d41df 100644
--- a/arch/i386/math-emu/reg_u_add.S
+++ b/arch/i386/math-emu/reg_u_add.S
@@ -5,9 +5,9 @@
| Add two valid (TW_Valid) FPU_REG numbers, of the same sign, and put the |
| result in a destination FPU_REG. |
| |
- | Copyright (C) 1992,1993 |
+ | Copyright (C) 1992,1993,1995 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Australia. E-mail billm@jacobi.maths.monash.edu.au |
| |
| Call from C as: |
| void reg_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, |
@@ -25,13 +25,11 @@
*/
#include "exception.h"
-#include "fpu_asm.h"
+#include "fpu_emu.h"
#include "control_w.h"
.text
- .align 2,144
-.globl _reg_u_add
-_reg_u_add:
+ENTRY(reg_u_add)
pushl %ebp
movl %esp,%ebp
pushl %esi
@@ -45,7 +43,7 @@ _reg_u_add:
cmpl EXP_UNDER,EXP(%esi)
jg xOp1_not_denorm
- call _denormal_operand
+ call SYMBOL_NAME(denormal_operand)
orl %eax,%eax
jnz fpu_Arith_exit
@@ -53,7 +51,7 @@ xOp1_not_denorm:
cmpl EXP_UNDER,EXP(%edi)
jg xOp2_not_denorm
- call _denormal_operand
+ call SYMBOL_NAME(denormal_operand)
orl %eax,%eax
jnz fpu_Arith_exit
diff --git a/arch/i386/math-emu/reg_u_div.S b/arch/i386/math-emu/reg_u_div.S
index 328e9116e..5bba98dd8 100644
--- a/arch/i386/math-emu/reg_u_div.S
+++ b/arch/i386/math-emu/reg_u_div.S
@@ -4,9 +4,9 @@
| |
| Core division routines |
| |
- | Copyright (C) 1992,1993 |
+ | Copyright (C) 1992,1993,1995 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Australia. E-mail billm@jacobi.maths.monash.edu.au |
| |
| |
+---------------------------------------------------------------------------*/
@@ -21,7 +21,7 @@
+---------------------------------------------------------------------------*/
#include "exception.h"
-#include "fpu_asm.h"
+#include "fpu_emu.h"
#include "control_w.h"
@@ -69,13 +69,7 @@ FPU_ovfl_flag:
.text
- .align 2,144
-
-.globl _reg_u_div
-
-.globl _divide_kernel
-
-_reg_u_div:
+ENTRY(reg_u_div)
pushl %ebp
movl %esp,%ebp
#ifndef NON_REENTRANT_FPU
@@ -95,7 +89,7 @@ _reg_u_div:
cmpl EXP_UNDER,%eax
jg xOp1_not_denorm
- call _denormal_operand
+ call SYMBOL_NAME(denormal_operand)
orl %eax,%eax
jnz fpu_Arith_exit
@@ -104,14 +98,14 @@ xOp1_not_denorm:
cmpl EXP_UNDER,%eax
jg xOp2_not_denorm
- call _denormal_operand
+ call SYMBOL_NAME(denormal_operand)
orl %eax,%eax
jnz fpu_Arith_exit
xOp2_not_denorm:
#endif DENORM_OPERAND
-_divide_kernel:
+ENTRY(divide_kernel)
#ifdef PARANOID
/* testl $0x80000000, SIGH(%esi) // Dividend */
/* je L_bugged */
diff --git a/arch/i386/math-emu/reg_u_mul.S b/arch/i386/math-emu/reg_u_mul.S
index 8250666bd..682fbec15 100644
--- a/arch/i386/math-emu/reg_u_mul.S
+++ b/arch/i386/math-emu/reg_u_mul.S
@@ -4,9 +4,9 @@
| |
| Core multiplication routine |
| |
- | Copyright (C) 1992,1993 |
+ | Copyright (C) 1992,1993,1995 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Australia. E-mail billm@jacobi.maths.monash.edu.au |
| |
| |
+---------------------------------------------------------------------------*/
@@ -22,7 +22,7 @@
+---------------------------------------------------------------------------*/
#include "exception.h"
-#include "fpu_asm.h"
+#include "fpu_emu.h"
#include "control_w.h"
@@ -44,10 +44,7 @@ FPU_accum_1:
.text
- .align 2,144
-
-.globl _reg_u_mul
-_reg_u_mul:
+ENTRY(reg_u_mul)
pushl %ebp
movl %esp,%ebp
#ifndef NON_REENTRANT_FPU
@@ -73,7 +70,7 @@ _reg_u_mul:
cmpl EXP_UNDER,%eax
jg xOp1_not_denorm
- call _denormal_operand
+ call SYMBOL_NAME(denormal_operand)
orl %eax,%eax
jnz fpu_Arith_exit
@@ -82,7 +79,7 @@ xOp1_not_denorm:
cmpl EXP_UNDER,%eax
jg xOp2_not_denorm
- call _denormal_operand
+ call SYMBOL_NAME(denormal_operand)
orl %eax,%eax
jnz fpu_Arith_exit
diff --git a/arch/i386/math-emu/reg_u_sub.S b/arch/i386/math-emu/reg_u_sub.S
index fbec17dfb..891670260 100644
--- a/arch/i386/math-emu/reg_u_sub.S
+++ b/arch/i386/math-emu/reg_u_sub.S
@@ -4,9 +4,9 @@
| |
| Core floating point subtraction routine. |
| |
- | Copyright (C) 1992,1993 |
+ | Copyright (C) 1992,1993,1995 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Australia. E-mail billm@jacobi.maths.monash.edu.au |
| |
| Call from C as: |
| void reg_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, |
@@ -26,13 +26,11 @@
*/
#include "exception.h"
-#include "fpu_asm.h"
+#include "fpu_emu.h"
#include "control_w.h"
.text
- .align 2,144
-.globl _reg_u_sub
-_reg_u_sub:
+ENTRY(reg_u_sub)
pushl %ebp
movl %esp,%ebp
pushl %esi
@@ -46,7 +44,7 @@ _reg_u_sub:
cmpl EXP_UNDER,EXP(%esi)
jg xOp1_not_denorm
- call _denormal_operand
+ call SYMBOL_NAME(denormal_operand)
orl %eax,%eax
jnz fpu_Arith_exit
@@ -54,7 +52,7 @@ xOp1_not_denorm:
cmpl EXP_UNDER,EXP(%edi)
jg xOp2_not_denorm
- call _denormal_operand
+ call SYMBOL_NAME(denormal_operand)
orl %eax,%eax
jnz fpu_Arith_exit
diff --git a/arch/i386/math-emu/round_Xsig.S b/arch/i386/math-emu/round_Xsig.S
index 163755878..bbe0e8771 100644
--- a/arch/i386/math-emu/round_Xsig.S
+++ b/arch/i386/math-emu/round_Xsig.S
@@ -1,9 +1,9 @@
/*---------------------------------------------------------------------------+
| round_Xsig.S |
| |
- | Copyright (C) 1992,1993,1994 |
+ | Copyright (C) 1992,1993,1994,1995 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Australia. E-mail billm@jacobi.maths.monash.edu.au |
| |
| Normalize and round a 12 byte quantity. |
| Call from C as: |
@@ -18,15 +18,11 @@
+---------------------------------------------------------------------------*/
.file "round_Xsig.S"
-#include "fpu_asm.h"
+#include "fpu_emu.h"
.text
-
- .align 2,144
-.globl _round_Xsig
-
-_round_Xsig:
+ENTRY(round_Xsig)
pushl %ebp
movl %esp,%ebp
pushl %ebx /* Reserve some space */
@@ -86,10 +82,7 @@ L_exit:
- .align 2,144
-.globl _norm_Xsig
-
-_norm_Xsig:
+ENTRY(norm_Xsig)
pushl %ebp
movl %esp,%ebp
pushl %ebx /* Reserve some space */
diff --git a/arch/i386/math-emu/shr_Xsig.S b/arch/i386/math-emu/shr_Xsig.S
index d6724a204..31cdd118e 100644
--- a/arch/i386/math-emu/shr_Xsig.S
+++ b/arch/i386/math-emu/shr_Xsig.S
@@ -4,9 +4,9 @@
| |
| 12 byte right shift function |
| |
- | Copyright (C) 1992,1994 |
+ | Copyright (C) 1992,1994,1995 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Australia. E-mail billm@jacobi.maths.monash.edu.au |
| |
| Call from C as: |
| void shr_Xsig(Xsig *arg, unsigned nr) |
@@ -18,13 +18,10 @@
| |
+---------------------------------------------------------------------------*/
-#include "fpu_asm.h"
+#include "fpu_emu.h"
.text
- .align 2,144
-
- .globl _shr_Xsig
-_shr_Xsig:
+ENTRY(shr_Xsig)
push %ebp
movl %esp,%ebp
pushl %esi
diff --git a/arch/i386/math-emu/status_w.h b/arch/i386/math-emu/status_w.h
index 96607d0e1..57d1ae6bb 100644
--- a/arch/i386/math-emu/status_w.h
+++ b/arch/i386/math-emu/status_w.h
@@ -12,7 +12,7 @@
#include "fpu_emu.h" /* for definition of PECULIAR_486 */
-#ifdef __ASSEMBLER__
+#ifdef __ASSEMBLY__
#define Const__(x) $##x
#else
#define Const__(x) x
@@ -36,7 +36,7 @@
#define SW_Exc_Mask Const__(0x27f) /* Status word exception bit mask */
-#ifndef __ASSEMBLER__
+#ifndef __ASSEMBLY__
#define COMP_A_gt_B 1
#define COMP_A_eq_B 2
@@ -60,6 +60,6 @@
# define clear_C1()
#endif PECULIAR_486
-#endif __ASSEMBLER__
+#endif __ASSEMBLY__
#endif _STATUS_H_
diff --git a/arch/i386/math-emu/version.h b/arch/i386/math-emu/version.h
index 4c75a4792..d966ab193 100644
--- a/arch/i386/math-emu/version.h
+++ b/arch/i386/math-emu/version.h
@@ -2,11 +2,11 @@
| version.h |
| |
| |
- | Copyright (C) 1992,1993,1994 |
- | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Copyright (C) 1992,1993,1994,1996 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@jacobi.maths.monash.edu.au |
| |
| |
+---------------------------------------------------------------------------*/
-#define FPU_VERSION "wm-FPU-emu version 1.20"
+#define FPU_VERSION "wm-FPU-emu version 1.22"
diff --git a/arch/i386/math-emu/wm_shrx.S b/arch/i386/math-emu/wm_shrx.S
index bef0e1963..1ea7ff7da 100644
--- a/arch/i386/math-emu/wm_shrx.S
+++ b/arch/i386/math-emu/wm_shrx.S
@@ -4,8 +4,9 @@
| |
| 64 bit right shift functions |
| |
- | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Copyright (C) 1992,1995 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@jacobi.maths.monash.edu.au |
| |
| Call from C as: |
| unsigned shrx(void *arg1, unsigned arg2) |
@@ -14,11 +15,9 @@
| |
+---------------------------------------------------------------------------*/
-#include "fpu_asm.h"
+#include "fpu_emu.h"
.text
- .align 2,144
-
/*---------------------------------------------------------------------------+
| unsigned shrx(void *arg1, unsigned arg2) |
| |
@@ -33,9 +32,7 @@
| Results returned in the 64 bit arg and eax. |
+---------------------------------------------------------------------------*/
- .globl _shrx
-
-_shrx:
+ENTRY(shrx)
push %ebp
movl %esp,%ebp
pushl %esi
@@ -113,8 +110,7 @@ L_more_than_95:
| part which has been shifted out of the arg. |
| Results returned in the 64 bit arg and eax. |
+---------------------------------------------------------------------------*/
- .globl _shrxs
-_shrxs:
+ENTRY(shrxs)
push %ebp
movl %esp,%ebp
pushl %esi
diff --git a/arch/i386/math-emu/wm_sqrt.S b/arch/i386/math-emu/wm_sqrt.S
index 4e028cb80..848796188 100644
--- a/arch/i386/math-emu/wm_sqrt.S
+++ b/arch/i386/math-emu/wm_sqrt.S
@@ -4,9 +4,9 @@
| |
| Fixed point arithmetic square root evaluation. |
| |
- | Copyright (C) 1992,1993 |
+ | Copyright (C) 1992,1993,1995 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Australia. E-mail billm@jacobi.maths.monash.edu.au |
| |
| Call from C as: |
| void wm_sqrt(FPU_REG *n, unsigned int control_word) |
@@ -26,7 +26,7 @@
+---------------------------------------------------------------------------*/
#include "exception.h"
-#include "fpu_asm.h"
+#include "fpu_emu.h"
#ifndef NON_REENTRANT_FPU
@@ -74,10 +74,7 @@ FPU_fsqrt_arg_0:
.text
- .align 2,144
-
-.globl _wm_sqrt
-_wm_sqrt:
+ENTRY(wm_sqrt)
pushl %ebp
movl %esp,%ebp
#ifndef NON_REENTRANT_FPU
diff --git a/arch/i386/mm/Makefile b/arch/i386/mm/Makefile
index af75a20a4..cee7d4e6d 100644
--- a/arch/i386/mm/Makefile
+++ b/arch/i386/mm/Makefile
@@ -7,26 +7,7 @@
#
# Note 2! The CFLAGS definition is now in the main makefile...
-.c.o:
- $(CC) $(CFLAGS) -c $<
-.s.o:
- $(AS) -o $*.o $<
-.c.s:
- $(CC) $(CFLAGS) -S $<
+O_TARGET := mm.o
+O_OBJS := init.o fault.o ioremap.o extable.o
-OBJS = init.o fault.o
-
-mm.o: $(OBJS)
- $(LD) -r -o mm.o $(OBJS)
-
-modules:
-
-dep:
- $(CPP) -M *.c > .depend
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff --git a/arch/i386/mm/extable.c b/arch/i386/mm/extable.c
new file mode 100644
index 000000000..c43a8d43d
--- /dev/null
+++ b/arch/i386/mm/extable.c
@@ -0,0 +1,63 @@
+/*
+ * linux/arch/i386/mm/extable.c
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+
+extern const struct exception_table_entry __start___ex_table[];
+extern const struct exception_table_entry __stop___ex_table[];
+
+static inline unsigned long
+search_one_table(const struct exception_table_entry *first,
+ const struct exception_table_entry *last,
+ unsigned long value)
+{
+ /* Some versions of the linker are buggy and do not align the
+ __start pointer along with the section, thus we may be low. */
+ if ((long)first & 3)
+ (long)first = ((long)first | 3) + 1;
+
+ while (first <= last) {
+ const struct exception_table_entry *mid;
+ long diff;
+
+ mid = (last - first) / 2 + first;
+ diff = mid->insn - value;
+ if (diff == 0)
+ return mid->fixup;
+ else if (diff < 0)
+ first = mid+1;
+ else
+ last = mid-1;
+ }
+ return 0;
+}
+
+unsigned long
+search_exception_table(unsigned long addr)
+{
+ unsigned long ret;
+#ifdef CONFIG_MODULES
+ struct module *mp;
+#endif
+
+ /* Search the kernel's table first. */
+ ret = search_one_table(__start___ex_table,
+ __stop___ex_table-1, addr);
+ if (ret)
+ return ret;
+
+#ifdef CONFIG_MODULES
+ for (mp = module_list; mp != NULL; mp = mp->next) {
+ if (mp->exceptinfo.start != NULL) {
+ ret = search_one_table(mp->exceptinfo.start,
+ mp->exceptinfo.stop-1, addr);
+ if (ret)
+ return ret;
+ }
+ }
+#endif
+ return 0;
+}
diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
index 01c259f0f..50dcd0735 100644
--- a/arch/i386/mm/fault.c
+++ b/arch/i386/mm/fault.c
@@ -4,7 +4,6 @@
* Copyright (C) 1995 Linus Torvalds
*/
-#include <linux/config.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/head.h>
@@ -17,10 +16,61 @@
#include <linux/mm.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/pgtable.h>
-extern void die_if_kernel(char *,struct pt_regs *,long);
+extern void die_if_kernel(const char *,struct pt_regs *,long);
+
+/*
+ * Ugly, ugly, but the goto's result in better assembly..
+ */
+int __verify_write(const void * addr, unsigned long size)
+{
+ struct vm_area_struct * vma;
+ unsigned long start = (unsigned long) addr;
+
+ if (!size)
+ return 1;
+
+ vma = find_vma(current->mm, start);
+ if (!vma)
+ goto bad_area;
+ if (vma->vm_start > start)
+ goto check_stack;
+
+good_area:
+ if (!(vma->vm_flags & VM_WRITE))
+ goto bad_area;
+ size--;
+ size += start & ~PAGE_MASK;
+ size >>= PAGE_SHIFT;
+ start &= PAGE_MASK;
+
+ for (;;) {
+ do_wp_page(current, vma, start, 1);
+ if (!size)
+ break;
+ size--;
+ start += PAGE_SIZE;
+ if (start < vma->vm_end)
+ continue;
+ vma = vma->vm_next;
+ if (!vma || vma->vm_start != start)
+ goto bad_area;
+ if (!(vma->vm_flags & VM_WRITE))
+ goto bad_area;;
+ }
+ return 1;
+
+check_stack:
+ if (!(vma->vm_flags & VM_GROWSDOWN))
+ goto bad_area;
+ if (expand_stack(vma, start) == 0)
+ goto good_area;
+
+bad_area:
+ return 0;
+}
/*
* This routine handles page faults. It determines the address,
@@ -34,58 +84,76 @@ extern void die_if_kernel(char *,struct pt_regs *,long);
*/
asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
{
+ void (*handler)(struct task_struct *,
+ struct vm_area_struct *,
+ unsigned long,
+ int);
+ struct task_struct *tsk = current;
+ struct mm_struct *mm = tsk->mm;
struct vm_area_struct * vma;
unsigned long address;
unsigned long page;
+ unsigned long fixup;
+ int write;
/* get the address */
__asm__("movl %%cr2,%0":"=r" (address));
- vma = find_vma(current, address);
+ down(&mm->mmap_sem);
+ vma = find_vma(mm, address);
if (!vma)
goto bad_area;
if (vma->vm_start <= address)
goto good_area;
if (!(vma->vm_flags & VM_GROWSDOWN))
goto bad_area;
- if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur)
+ if (error_code & 4) {
+ /*
+ * accessing the stack below %esp is always a bug.
+ * The "+ 32" is there due to some instructions (like
+ * pusha) doing pre-decrement on the stack and that
+ * doesn't show up until later..
+ */
+ if (address + 32 < regs->esp)
+ goto bad_area;
+ }
+ if (expand_stack(vma, address))
goto bad_area;
- vma->vm_offset -= vma->vm_start - (address & PAGE_MASK);
- vma->vm_start = (address & PAGE_MASK);
/*
* Ok, we have a good vm_area for this memory access, so
* we can handle it..
*/
good_area:
- /*
- * was it a write?
- */
- if (error_code & 2) {
- if (!(vma->vm_flags & VM_WRITE))
- goto bad_area;
- } else {
- /* read with protection fault? */
- if (error_code & 1)
- goto bad_area;
- if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+ write = 0;
+ handler = do_no_page;
+ switch (error_code & 3) {
+ default: /* 3: write, present */
+ handler = do_wp_page;
+#ifdef TEST_VERIFY_AREA
+ if (regs->cs == KERNEL_CS)
+ printk("WP fault at %08lx\n", regs->eip);
+#endif
+ /* fall through */
+ case 2: /* write, not present */
+ if (!(vma->vm_flags & VM_WRITE))
+ goto bad_area;
+ write++;
+ break;
+ case 1: /* read, present */
goto bad_area;
+ case 0: /* read, not present */
+ if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+ goto bad_area;
}
+ handler(tsk, vma, address, write);
+ up(&mm->mmap_sem);
/*
* Did it hit the DOS screen memory VA from vm86 mode?
*/
if (regs->eflags & VM_MASK) {
unsigned long bit = (address - 0xA0000) >> PAGE_SHIFT;
if (bit < 32)
- current->tss.screen_bitmap |= 1 << bit;
- }
- if (error_code & 1) {
-#ifdef CONFIG_TEST_VERIFY_AREA
- if (regs->cs == KERNEL_CS)
- printk("WP fault at %08x\n", regs->eip);
-#endif
- do_wp_page(vma, address, error_code & 2);
- return;
+ tsk->tss.screen_bitmap |= 1 << bit;
}
- do_no_page(vma, address, error_code & 2);
return;
/*
@@ -93,11 +161,20 @@ good_area:
* Fix it, but check if it's kernel or user first..
*/
bad_area:
+ up(&mm->mmap_sem);
+
+ /* Are we prepared to handle this fault? */
+ if ((fixup = search_exception_table(regs->eip)) != 0) {
+ printk("Exception at %lx (%lx)\n", regs->eip, fixup);
+ regs->eip = fixup;
+ return;
+ }
+
if (error_code & 4) {
- current->tss.cr2 = address;
- current->tss.error_code = error_code;
- current->tss.trap_no = 14;
- send_sig(SIGSEGV, current, 1);
+ tsk->tss.cr2 = address;
+ tsk->tss.error_code = error_code;
+ tsk->tss.trap_no = 14;
+ force_sig(SIGSEGV, tsk);
return;
}
/*
@@ -106,14 +183,14 @@ bad_area:
*
* First we check if it was the bootup rw-test, though..
*/
- if (wp_works_ok < 0 && address == TASK_SIZE && (error_code & 1)) {
+ if (wp_works_ok < 0 && !address && (error_code & 1)) {
wp_works_ok = 1;
pg0[0] = pte_val(mk_pte(0, PAGE_SHARED));
- invalidate();
+ flush_tlb();
printk("This processor honours the WP bit even when in supervisor mode. Good.\n");
return;
}
- if ((unsigned long) (address-TASK_SIZE) < PAGE_SIZE) {
+ if (address < PAGE_SIZE) {
printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
pg0[0] = pte_val(mk_pte(0, PAGE_SHARED));
} else
@@ -121,13 +198,13 @@ bad_area:
printk(" at virtual address %08lx\n",address);
__asm__("movl %%cr3,%0" : "=r" (page));
printk(KERN_ALERT "current->tss.cr3 = %08lx, %%cr3 = %08lx\n",
- current->tss.cr3, page);
- page = ((unsigned long *) page)[address >> 22];
+ tsk->tss.cr3, page);
+ page = ((unsigned long *) __va(page))[address >> 22];
printk(KERN_ALERT "*pde = %08lx\n", page);
if (page & 1) {
page &= PAGE_MASK;
address &= 0x003ff000;
- page = ((unsigned long *) page)[address >> PAGE_SHIFT];
+ page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT];
printk(KERN_ALERT "*pte = %08lx\n", page);
}
die_if_kernel("Oops", regs, error_code);
diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c
index 296595644..cf258d6de 100644
--- a/arch/i386/mm/init.c
+++ b/arch/i386/mm/init.c
@@ -15,13 +15,17 @@
#include <linux/ptrace.h>
#include <linux/mman.h>
#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/smp.h>
+#ifdef CONFIG_BLK_DEV_INITRD
+#include <linux/blk.h>
+#endif
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/pgtable.h>
+#include <asm/dma.h>
-extern void scsi_mem_init(unsigned long);
-extern void sound_mem_init(void);
extern void die_if_kernel(char *,struct pt_regs *,long);
extern void show_net_buffers(void);
@@ -29,7 +33,7 @@ extern void show_net_buffers(void);
* BAD_PAGE is the page that is used for page faults when linux
* is out-of-memory. Older versions of linux just did a
* do_exit(), but using this instead means there is less risk
- * for a process dying in kernel mode, possibly leaving a inode
+ * for a process dying in kernel mode, possibly leaving an inode
* unused etc..
*
* BAD_PAGETABLE is the accompanying page-table: it is initialized
@@ -70,15 +74,15 @@ void show_mem(void)
printk("Mem-info:\n");
show_free_areas();
printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
- i = high_memory >> PAGE_SHIFT;
+ i = max_mapnr;
while (i-- > 0) {
total++;
- if (mem_map[i] & MAP_PAGE_RESERVED)
+ if (PageReserved(mem_map+i))
reserved++;
- else if (!mem_map[i])
+ else if (!mem_map[i].count)
free++;
else
- shared += mem_map[i]-1;
+ shared += mem_map[i].count-1;
}
printk("%d pages of RAM\n",total);
printk("%d free pages\n",free);
@@ -111,34 +115,90 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
* and SMM (for laptops with [34]86/SL chips) may need it. It is read
* and write protected to detect null pointer references in the
* kernel.
+ * It may also hold the MP configuration table when we are booting SMP.
*/
#if 0
memset((void *) 0, 0, PAGE_SIZE);
#endif
+#ifdef __SMP__
+ if (!smp_scan_config(0x0,0x400)) /* Scan the bottom 1K for a signature */
+ {
+ /*
+ * FIXME: Linux assumes you have 640K of base ram.. this continues
+ * the error...
+ */
+ if (!smp_scan_config(639*0x400,0x400)) /* Scan the top 1K of base RAM */
+ smp_scan_config(0xF0000,0x10000); /* Scan the 64K of bios */
+ }
+ /*
+ * If it is an SMP machine we should know now, unless the configuration
+ * is in an EISA/MCA bus machine with an extended bios data area. I don't
+ * have such a machine so someone else can fill in the check of the EBDA
+ * here.
+ */
+/* smp_alloc_memory(8192); */
+#endif
+#ifdef TEST_VERIFY_AREA
+ wp_works_ok = 0;
+#endif
start_mem = PAGE_ALIGN(start_mem);
- address = 0;
+ address = PAGE_OFFSET;
pg_dir = swapper_pg_dir;
+ /* unmap the original low memory mappings */
+ pgd_val(pg_dir[0]) = 0;
while (address < end_mem) {
+ /*
+ * The following code enabled 4MB page tables for the
+ * Intel Pentium cpu, unfortunately the SMP kernel can't
+ * handle the 4MB page table optimizations yet
+ */
+#ifndef __SMP__
+ /*
+ * This will create page tables that
+ * span up to the next 4MB virtual
+ * memory boundary, but that's ok,
+ * we won't use that memory anyway.
+ */
+ if (x86_capability & 8) {
+#ifdef GAS_KNOWS_CR4
+ __asm__("movl %%cr4,%%eax\n\t"
+ "orl $16,%%eax\n\t"
+ "movl %%eax,%%cr4"
+ : : :"ax");
+#else
+ __asm__(".byte 0x0f,0x20,0xe0\n\t"
+ "orl $16,%%eax\n\t"
+ ".byte 0x0f,0x22,0xe0"
+ : : :"ax");
+#endif
+ wp_works_ok = 1;
+ pgd_val(pg_dir[768]) = _PAGE_TABLE + _PAGE_4M + __pa(address);
+ pg_dir++;
+ address += 4*1024*1024;
+ continue;
+ }
+#endif
/* map the memory at virtual addr 0xC0000000 */
+ /* pg_table is physical at this point */
pg_table = (pte_t *) (PAGE_MASK & pgd_val(pg_dir[768]));
if (!pg_table) {
- pg_table = (pte_t *) start_mem;
+ pg_table = (pte_t *) __pa(start_mem);
start_mem += PAGE_SIZE;
}
- /* also map it temporarily at 0x0000000 for init */
- pgd_val(pg_dir[0]) = _PAGE_TABLE | (unsigned long) pg_table;
pgd_val(pg_dir[768]) = _PAGE_TABLE | (unsigned long) pg_table;
pg_dir++;
+ /* now change pg_table to kernel virtual addresses */
+ pg_table = (pte_t *) __va(pg_table);
for (tmp = 0 ; tmp < PTRS_PER_PTE ; tmp++,pg_table++) {
- if (address < end_mem)
- *pg_table = mk_pte(address, PAGE_SHARED);
- else
- pte_clear(pg_table);
+ pte_t pte = mk_pte(address, PAGE_KERNEL);
+ if (address >= end_mem)
+ pte_val(pte) = 0;
+ set_pte(pg_table, pte);
address += PAGE_SIZE;
}
}
- invalidate();
+ local_flush_tlb();
return free_area_init(start_mem, end_mem);
}
@@ -149,16 +209,25 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
int reservedpages = 0;
int datapages = 0;
unsigned long tmp;
- extern int etext;
+ extern int _etext;
end_mem &= PAGE_MASK;
- high_memory = end_mem;
+ high_memory = (void *) end_mem;
+ max_mapnr = MAP_NR(end_mem);
/* clear the zero-page */
memset(empty_zero_page, 0, PAGE_SIZE);
/* mark usable pages in the mem_map[] */
- start_low_mem = PAGE_ALIGN(start_low_mem);
+ start_low_mem = PAGE_ALIGN(start_low_mem)+PAGE_OFFSET;
+
+#ifdef __SMP__
+ /*
+ * But first pinch a few for the stack/trampoline stuff
+ */
+ start_low_mem += PAGE_SIZE; /* 32bit startup code */
+ start_low_mem = smp_alloc_memory(start_low_mem); /* AP processor stacks */
+#endif
start_mem = PAGE_ALIGN(start_mem);
/*
@@ -166,53 +235,56 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
* They seem to have done something stupid with the floppy
* controller as well..
*/
- while (start_low_mem < 0x9f000) {
- mem_map[MAP_NR(start_low_mem)] = 0;
+ while (start_low_mem < 0x9f000+PAGE_OFFSET) {
+ clear_bit(PG_reserved, &mem_map[MAP_NR(start_low_mem)].flags);
start_low_mem += PAGE_SIZE;
}
- while (start_mem < high_memory) {
- mem_map[MAP_NR(start_mem)] = 0;
+ while (start_mem < end_mem) {
+ clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags);
start_mem += PAGE_SIZE;
}
-#ifdef CONFIG_SCSI
- scsi_mem_init(high_memory);
-#endif
-#ifdef CONFIG_SOUND
- sound_mem_init();
-#endif
- for (tmp = 0 ; tmp < high_memory ; tmp += PAGE_SIZE) {
- if (mem_map[MAP_NR(tmp)]) {
- if (tmp >= 0xA0000 && tmp < 0x100000)
+ for (tmp = PAGE_OFFSET ; tmp < end_mem ; tmp += PAGE_SIZE) {
+ if (tmp >= MAX_DMA_ADDRESS)
+ clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags);
+ if (PageReserved(mem_map+MAP_NR(tmp))) {
+ if (tmp >= 0xA0000+PAGE_OFFSET && tmp < 0x100000+PAGE_OFFSET)
reservedpages++;
- else if (tmp < (unsigned long) &etext)
+ else if (tmp < (unsigned long) &_etext)
codepages++;
else
datapages++;
continue;
}
- mem_map[MAP_NR(tmp)] = 1;
- free_page(tmp);
+ mem_map[MAP_NR(tmp)].count = 1;
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (!initrd_start || (tmp < initrd_start || tmp >=
+ initrd_end))
+#endif
+ free_page(tmp);
}
- tmp = nr_free_pages << PAGE_SHIFT;
printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data)\n",
- tmp >> 10,
- high_memory >> 10,
+ (unsigned long) nr_free_pages << (PAGE_SHIFT-10),
+ max_mapnr << (PAGE_SHIFT-10),
codepages << (PAGE_SHIFT-10),
reservedpages << (PAGE_SHIFT-10),
datapages << (PAGE_SHIFT-10));
/* test if the WP bit is honoured in supervisor mode */
- wp_works_ok = -1;
- pg0[0] = pte_val(mk_pte(0, PAGE_READONLY));
- invalidate();
- __asm__ __volatile__("movb 0,%%al ; movb %%al,0": : :"ax", "memory");
- pg0[0] = 0;
- invalidate();
- if (wp_works_ok < 0)
- wp_works_ok = 0;
-#ifdef CONFIG_TEST_VERIFY_AREA
- wp_works_ok = 0;
-#endif
+ if (wp_works_ok < 0) {
+ unsigned char tmp_reg;
+ pg0[0] = pte_val(mk_pte(PAGE_OFFSET, PAGE_READONLY));
+ local_flush_tlb();
+ __asm__ __volatile__(
+ "movb %0,%1 ; movb %1,%0"
+ :"=m" (*(char *) __va(0)),
+ "=q" (tmp_reg)
+ :/* no inputs */
+ :"memory");
+ pg0[0] = pte_val(mk_pte(PAGE_OFFSET, PAGE_KERNEL));
+ local_flush_tlb();
+ if (wp_works_ok < 0)
+ wp_works_ok = 0;
+ }
return;
}
@@ -220,18 +292,18 @@ void si_meminfo(struct sysinfo *val)
{
int i;
- i = high_memory >> PAGE_SHIFT;
+ i = max_mapnr;
val->totalram = 0;
val->sharedram = 0;
val->freeram = nr_free_pages << PAGE_SHIFT;
val->bufferram = buffermem;
while (i-- > 0) {
- if (mem_map[i] & MAP_PAGE_RESERVED)
+ if (PageReserved(mem_map+i))
continue;
val->totalram++;
- if (!mem_map[i])
+ if (!mem_map[i].count)
continue;
- val->sharedram += mem_map[i]-1;
+ val->sharedram += mem_map[i].count-1;
}
val->totalram <<= PAGE_SHIFT;
val->sharedram <<= PAGE_SHIFT;
diff --git a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c
new file mode 100644
index 000000000..42b386c1c
--- /dev/null
+++ b/arch/i386/mm/ioremap.c
@@ -0,0 +1,109 @@
+/*
+ * arch/i386/mm/ioremap.c
+ *
+ * Re-map IO memory to kernel address space so that we can access it.
+ * This is needed for high PCI addresses that aren't mapped in the
+ * 640k-1MB IO memory area on PC's
+ *
+ * (C) Copyright 1995 1996 Linus Torvalds
+ */
+
+#include <linux/vmalloc.h>
+
+#include <asm/io.h>
+
+static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
+ unsigned long phys_addr)
+{
+ unsigned long end;
+
+ address &= ~PMD_MASK;
+ end = address + size;
+ if (end > PMD_SIZE)
+ end = PMD_SIZE;
+ do {
+ if (!pte_none(*pte))
+ printk("remap_area_pte: page already exists\n");
+ set_pte(pte, mk_pte_phys(phys_addr, PAGE_KERNEL));
+ address += PAGE_SIZE;
+ phys_addr += PAGE_SIZE;
+ pte++;
+ } while (address < end);
+}
+
+static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
+ unsigned long phys_addr)
+{
+ unsigned long end;
+
+ address &= ~PGDIR_MASK;
+ end = address + size;
+ if (end > PGDIR_SIZE)
+ end = PGDIR_SIZE;
+ phys_addr -= address;
+ do {
+ pte_t * pte = pte_alloc_kernel(pmd, address);
+ if (!pte)
+ return -ENOMEM;
+ remap_area_pte(pte, address, end - address, address + phys_addr);
+ address = (address + PMD_SIZE) & PMD_MASK;
+ pmd++;
+ } while (address < end);
+ return 0;
+}
+
+static int remap_area_pages(unsigned long address, unsigned long phys_addr, unsigned long size)
+{
+ pgd_t * dir;
+ unsigned long end = address + size;
+
+ phys_addr -= address;
+ dir = pgd_offset(&init_mm, address);
+ flush_cache_all();
+ while (address < end) {
+ pmd_t *pmd = pmd_alloc_kernel(dir, address);
+ if (!pmd)
+ return -ENOMEM;
+ if (remap_area_pmd(pmd, address, end - address, phys_addr + address))
+ return -ENOMEM;
+ set_pgdir(address, *dir);
+ address = (address + PGDIR_SIZE) & PGDIR_MASK;
+ dir++;
+ }
+ flush_tlb_all();
+ return 0;
+}
+
+/*
+ * Remap an arbitrary physical address space into the kernel virtual
+ * address space. Needed when the kernel wants to access high addresses
+ * directly.
+ */
+void * ioremap(unsigned long phys_addr, unsigned long size)
+{
+ void * addr;
+ struct vm_struct * area;
+
+ if (phys_addr < virt_to_phys(high_memory))
+ return phys_to_virt(phys_addr);
+ if (phys_addr & ~PAGE_MASK)
+ return NULL;
+ size = PAGE_ALIGN(size);
+ if (!size || size > phys_addr + size)
+ return NULL;
+ area = get_vm_area(size);
+ if (!area)
+ return NULL;
+ addr = area->addr;
+ if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size)) {
+ vfree(addr);
+ return NULL;
+ }
+ return addr;
+}
+
+void iounmap(void *addr)
+{
+ if (addr > high_memory)
+ return vfree(addr);
+}