diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-01-07 02:33:00 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1997-01-07 02:33:00 +0000 |
commit | beb116954b9b7f3bb56412b2494b562f02b864b1 (patch) | |
tree | 120e997879884e1b9d93b265221b939d2ef1ade1 /arch/i386/boot | |
parent | 908d4681a1dc3792ecafbe64265783a86c4cccb6 (diff) |
Import of Linux/MIPS 2.1.14
Diffstat (limited to 'arch/i386/boot')
-rw-r--r-- | arch/i386/boot/Makefile | 54 | ||||
-rw-r--r-- | arch/i386/boot/bootsect.S | 8 | ||||
-rw-r--r-- | arch/i386/boot/compressed/Makefile | 60 | ||||
-rw-r--r-- | arch/i386/boot/compressed/Makefile.debug | 21 | ||||
-rw-r--r-- | arch/i386/boot/compressed/crypt.h | 12 | ||||
-rw-r--r-- | arch/i386/boot/compressed/gzip.h | 284 | ||||
-rw-r--r-- | arch/i386/boot/compressed/head.S | 91 | ||||
-rw-r--r-- | arch/i386/boot/compressed/inflate.c | 810 | ||||
-rw-r--r-- | arch/i386/boot/compressed/lzw.h | 42 | ||||
-rw-r--r-- | arch/i386/boot/compressed/misc.c | 483 | ||||
-rw-r--r-- | arch/i386/boot/compressed/unzip.c | 180 | ||||
-rw-r--r-- | arch/i386/boot/setup.S | 1046 | ||||
-rw-r--r-- | arch/i386/boot/tools/build.c | 57 | ||||
-rw-r--r-- | arch/i386/boot/video.S | 1839 |
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 |