summaryrefslogtreecommitdiffstats
path: root/arch/i386/boot
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/boot
parent908d4681a1dc3792ecafbe64265783a86c4cccb6 (diff)
Import of Linux/MIPS 2.1.14
Diffstat (limited to 'arch/i386/boot')
-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
14 files changed, 2709 insertions, 2278 deletions
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