aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/boot
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/i386/boot
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'arch/i386/boot')
-rw-r--r--arch/i386/boot/Makefile104
-rw-r--r--arch/i386/boot/bootsect.S98
-rw-r--r--arch/i386/boot/compressed/Makefile25
-rw-r--r--arch/i386/boot/compressed/head.S128
-rw-r--r--arch/i386/boot/compressed/misc.c382
-rw-r--r--arch/i386/boot/compressed/vmlinux.scr9
-rw-r--r--arch/i386/boot/edd.S176
-rw-r--r--arch/i386/boot/install.sh40
-rw-r--r--arch/i386/boot/mtools.conf.in17
-rw-r--r--arch/i386/boot/setup.S1028
-rw-r--r--arch/i386/boot/tools/build.c184
-rw-r--r--arch/i386/boot/video.S2007
12 files changed, 4198 insertions, 0 deletions
diff --git a/arch/i386/boot/Makefile b/arch/i386/boot/Makefile
new file mode 100644
index 00000000000..aa7064a75ee
--- /dev/null
+++ b/arch/i386/boot/Makefile
@@ -0,0 +1,104 @@
1#
2# arch/i386/boot/Makefile
3#
4# This file is subject to the terms and conditions of the GNU General Public
5# License. See the file "COPYING" in the main directory of this archive
6# for more details.
7#
8# Copyright (C) 1994 by Linus Torvalds
9#
10
11# ROOT_DEV specifies the default root-device when making the image.
12# This can be either FLOPPY, CURRENT, /dev/xxxx or empty, in which case
13# the default of FLOPPY is used by 'build'.
14
15ROOT_DEV := CURRENT
16
17# If you want to preset the SVGA mode, uncomment the next line and
18# set SVGA_MODE to whatever number you want.
19# Set it to -DSVGA_MODE=NORMAL_VGA if you just want the EGA/VGA mode.
20# The number is the same as you would ordinarily press at bootup.
21
22SVGA_MODE := -DSVGA_MODE=NORMAL_VGA
23
24# If you want the RAM disk device, define this to be the size in blocks.
25
26#RAMDISK := -DRAMDISK=512
27
28targets := vmlinux.bin bootsect bootsect.o setup setup.o \
29 zImage bzImage
30subdir- := compressed
31
32hostprogs-y := tools/build
33
34HOSTCFLAGS_build.o := $(LINUXINCLUDE)
35
36# ---------------------------------------------------------------------------
37
38$(obj)/zImage: IMAGE_OFFSET := 0x1000
39$(obj)/zImage: EXTRA_AFLAGS := -traditional $(SVGA_MODE) $(RAMDISK)
40$(obj)/bzImage: IMAGE_OFFSET := 0x100000
41$(obj)/bzImage: EXTRA_AFLAGS := -traditional $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__
42$(obj)/bzImage: BUILDFLAGS := -b
43
44quiet_cmd_image = BUILD $@
45cmd_image = $(obj)/tools/build $(BUILDFLAGS) $(obj)/bootsect $(obj)/setup \
46 $(obj)/vmlinux.bin $(ROOT_DEV) > $@
47
48$(obj)/zImage $(obj)/bzImage: $(obj)/bootsect $(obj)/setup \
49 $(obj)/vmlinux.bin $(obj)/tools/build FORCE
50 $(call if_changed,image)
51 @echo 'Kernel: $@ is ready'
52
53$(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
54 $(call if_changed,objcopy)
55
56LDFLAGS_bootsect := -Ttext 0x0 -s --oformat binary
57LDFLAGS_setup := -Ttext 0x0 -s --oformat binary -e begtext
58
59$(obj)/setup $(obj)/bootsect: %: %.o FORCE
60 $(call if_changed,ld)
61
62$(obj)/compressed/vmlinux: FORCE
63 $(Q)$(MAKE) $(build)=$(obj)/compressed IMAGE_OFFSET=$(IMAGE_OFFSET) $@
64
65# Set this if you want to pass append arguments to the zdisk/fdimage kernel
66FDARGS =
67
68$(obj)/mtools.conf: $(src)/mtools.conf.in
69 sed -e 's|@OBJ@|$(obj)|g' < $< > $@
70
71# This requires write access to /dev/fd0
72zdisk: $(BOOTIMAGE) $(obj)/mtools.conf
73 MTOOLSRC=$(obj)/mtools.conf mformat a: ; sync
74 syslinux /dev/fd0 ; sync
75 echo 'default linux $(FDARGS)' | \
76 MTOOLSRC=$(src)/mtools.conf mcopy - a:syslinux.cfg
77 MTOOLSRC=$(obj)/mtools.conf mcopy $(BOOTIMAGE) a:linux ; sync
78
79# These require being root or having syslinux 2.02 or higher installed
80fdimage fdimage144: $(BOOTIMAGE) $(obj)/mtools.conf
81 dd if=/dev/zero of=$(obj)/fdimage bs=1024 count=1440
82 MTOOLSRC=$(obj)/mtools.conf mformat v: ; sync
83 syslinux $(obj)/fdimage ; sync
84 echo 'default linux $(FDARGS)' | \
85 MTOOLSRC=$(obj)/mtools.conf mcopy - v:syslinux.cfg
86 MTOOLSRC=$(obj)/mtools.conf mcopy $(BOOTIMAGE) v:linux ; sync
87
88fdimage288: $(BOOTIMAGE) $(obj)/mtools.conf
89 dd if=/dev/zero of=$(obj)/fdimage bs=1024 count=2880
90 MTOOLSRC=$(obj)/mtools.conf mformat w: ; sync
91 syslinux $(obj)/fdimage ; sync
92 echo 'default linux $(FDARGS)' | \
93 MTOOLSRC=$(obj)/mtools.conf mcopy - w:syslinux.cfg
94 MTOOLSRC=$(obj)/mtools.conf mcopy $(BOOTIMAGE) w:linux ; sync
95
96zlilo: $(BOOTIMAGE)
97 if [ -f $(INSTALL_PATH)/vmlinuz ]; then mv $(INSTALL_PATH)/vmlinuz $(INSTALL_PATH)/vmlinuz.old; fi
98 if [ -f $(INSTALL_PATH)/System.map ]; then mv $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
99 cat $(BOOTIMAGE) > $(INSTALL_PATH)/vmlinuz
100 cp System.map $(INSTALL_PATH)/
101 if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
102
103install: $(BOOTIMAGE)
104 sh $(srctree)/$(src)/install.sh $(KERNELRELEASE) $< System.map "$(INSTALL_PATH)"
diff --git a/arch/i386/boot/bootsect.S b/arch/i386/boot/bootsect.S
new file mode 100644
index 00000000000..ba9fe14db6a
--- /dev/null
+++ b/arch/i386/boot/bootsect.S
@@ -0,0 +1,98 @@
1/*
2 * bootsect.S Copyright (C) 1991, 1992 Linus Torvalds
3 *
4 * modified by Drew Eckhardt
5 * modified by Bruce Evans (bde)
6 * modified by Chris Noe (May 1999) (as86 -> gas)
7 * gutted by H. Peter Anvin (Jan 2003)
8 *
9 * BIG FAT NOTE: We're in real mode using 64k segments. Therefore segment
10 * addresses must be multiplied by 16 to obtain their respective linear
11 * addresses. To avoid confusion, linear addresses are written using leading
12 * hex while segment addresses are written as segment:offset.
13 *
14 */
15
16#include <asm/boot.h>
17
18SETUPSECTS = 4 /* default nr of setup-sectors */
19BOOTSEG = 0x07C0 /* original address of boot-sector */
20INITSEG = DEF_INITSEG /* we move boot here - out of the way */
21SETUPSEG = DEF_SETUPSEG /* setup starts here */
22SYSSEG = DEF_SYSSEG /* system loaded at 0x10000 (65536) */
23SYSSIZE = DEF_SYSSIZE /* system size: # of 16-byte clicks */
24 /* to be loaded */
25ROOT_DEV = 0 /* ROOT_DEV is now written by "build" */
26SWAP_DEV = 0 /* SWAP_DEV is now written by "build" */
27
28#ifndef SVGA_MODE
29#define SVGA_MODE ASK_VGA
30#endif
31
32#ifndef RAMDISK
33#define RAMDISK 0
34#endif
35
36#ifndef ROOT_RDONLY
37#define ROOT_RDONLY 1
38#endif
39
40.code16
41.text
42
43.global _start
44_start:
45
46 # Normalize the start address
47 jmpl $BOOTSEG, $start2
48
49start2:
50 movw %cs, %ax
51 movw %ax, %ds
52 movw %ax, %es
53 movw %ax, %ss
54 movw $0x7c00, %sp
55 sti
56 cld
57
58 movw $bugger_off_msg, %si
59
60msg_loop:
61 lodsb
62 andb %al, %al
63 jz die
64 movb $0xe, %ah
65 movw $7, %bx
66 int $0x10
67 jmp msg_loop
68
69die:
70 # Allow the user to press a key, then reboot
71 xorw %ax, %ax
72 int $0x16
73 int $0x19
74
75 # int 0x19 should never return. In case it does anyway,
76 # invoke the BIOS reset code...
77 ljmp $0xf000,$0xfff0
78
79
80bugger_off_msg:
81 .ascii "Direct booting from floppy is no longer supported.\r\n"
82 .ascii "Please use a boot loader program instead.\r\n"
83 .ascii "\n"
84 .ascii "Remove disk and press any key to reboot . . .\r\n"
85 .byte 0
86
87
88 # Kernel attributes; used by setup
89
90 .org 497
91setup_sects: .byte SETUPSECTS
92root_flags: .word ROOT_RDONLY
93syssize: .word SYSSIZE
94swap_dev: .word SWAP_DEV
95ram_size: .word RAMDISK
96vid_mode: .word SVGA_MODE
97root_dev: .word ROOT_DEV
98boot_flag: .word 0xAA55
diff --git a/arch/i386/boot/compressed/Makefile b/arch/i386/boot/compressed/Makefile
new file mode 100644
index 00000000000..258ea95224f
--- /dev/null
+++ b/arch/i386/boot/compressed/Makefile
@@ -0,0 +1,25 @@
1#
2# linux/arch/i386/boot/compressed/Makefile
3#
4# create a compressed vmlinux image from the original vmlinux
5#
6
7targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o
8EXTRA_AFLAGS := -traditional
9
10LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup_32
11
12$(obj)/vmlinux: $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE
13 $(call if_changed,ld)
14 @:
15
16$(obj)/vmlinux.bin: vmlinux FORCE
17 $(call if_changed,objcopy)
18
19$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
20 $(call if_changed,gzip)
21
22LDFLAGS_piggy.o := -r --format binary --oformat elf32-i386 -T
23
24$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE
25 $(call if_changed,ld)
diff --git a/arch/i386/boot/compressed/head.S b/arch/i386/boot/compressed/head.S
new file mode 100644
index 00000000000..c5e80b69e7d
--- /dev/null
+++ b/arch/i386/boot/compressed/head.S
@@ -0,0 +1,128 @@
1/*
2 * linux/boot/head.S
3 *
4 * Copyright (C) 1991, 1992, 1993 Linus Torvalds
5 */
6
7/*
8 * head.S contains the 32-bit startup code.
9 *
10 * NOTE!!! Startup happens at absolute address 0x00001000, which is also where
11 * the page directory will exist. The startup code will be overwritten by
12 * the page directory. [According to comments etc elsewhere on a compressed
13 * kernel it will end up at 0x1000 + 1Mb I hope so as I assume this. - AC]
14 *
15 * Page 0 is deliberately kept safe, since System Management Mode code in
16 * laptops may need to access the BIOS data stored there. This is also
17 * useful for future device drivers that either access the BIOS via VM86
18 * mode.
19 */
20
21/*
22 * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
23 */
24.text
25
26#include <linux/linkage.h>
27#include <asm/segment.h>
28
29 .globl startup_32
30
31startup_32:
32 cld
33 cli
34 movl $(__BOOT_DS),%eax
35 movl %eax,%ds
36 movl %eax,%es
37 movl %eax,%fs
38 movl %eax,%gs
39
40 lss stack_start,%esp
41 xorl %eax,%eax
421: incl %eax # check that A20 really IS enabled
43 movl %eax,0x000000 # loop forever if it isn't
44 cmpl %eax,0x100000
45 je 1b
46
47/*
48 * Initialize eflags. Some BIOS's leave bits like NT set. This would
49 * confuse the debugger if this code is traced.
50 * XXX - best to initialize before switching to protected mode.
51 */
52 pushl $0
53 popfl
54/*
55 * Clear BSS
56 */
57 xorl %eax,%eax
58 movl $_edata,%edi
59 movl $_end,%ecx
60 subl %edi,%ecx
61 cld
62 rep
63 stosb
64/*
65 * Do the decompression, and jump to the new kernel..
66 */
67 subl $16,%esp # place for structure on the stack
68 movl %esp,%eax
69 pushl %esi # real mode pointer as second arg
70 pushl %eax # address of structure as first arg
71 call decompress_kernel
72 orl %eax,%eax
73 jnz 3f
74 popl %esi # discard address
75 popl %esi # real mode pointer
76 xorl %ebx,%ebx
77 ljmp $(__BOOT_CS), $0x100000
78
79/*
80 * We come here, if we were loaded high.
81 * We need to move the move-in-place routine down to 0x1000
82 * and then start it with the buffer addresses in registers,
83 * which we got from the stack.
84 */
853:
86 movl $move_routine_start,%esi
87 movl $0x1000,%edi
88 movl $move_routine_end,%ecx
89 subl %esi,%ecx
90 addl $3,%ecx
91 shrl $2,%ecx
92 cld
93 rep
94 movsl
95
96 popl %esi # discard the address
97 popl %ebx # real mode pointer
98 popl %esi # low_buffer_start
99 popl %ecx # lcount
100 popl %edx # high_buffer_start
101 popl %eax # hcount
102 movl $0x100000,%edi
103 cli # make sure we don't get interrupted
104 ljmp $(__BOOT_CS), $0x1000 # and jump to the move routine
105
106/*
107 * Routine (template) for moving the decompressed kernel in place,
108 * if we were high loaded. This _must_ PIC-code !
109 */
110move_routine_start:
111 movl %ecx,%ebp
112 shrl $2,%ecx
113 rep
114 movsl
115 movl %ebp,%ecx
116 andl $3,%ecx
117 rep
118 movsb
119 movl %edx,%esi
120 movl %eax,%ecx # NOTE: rep movsb won't move if %ecx == 0
121 addl $3,%ecx
122 shrl $2,%ecx
123 rep
124 movsl
125 movl %ebx,%esi # Restore setup pointer
126 xorl %ebx,%ebx
127 ljmp $(__BOOT_CS), $0x100000
128move_routine_end:
diff --git a/arch/i386/boot/compressed/misc.c b/arch/i386/boot/compressed/misc.c
new file mode 100644
index 00000000000..fa67045234a
--- /dev/null
+++ b/arch/i386/boot/compressed/misc.c
@@ -0,0 +1,382 @@
1/*
2 * misc.c
3 *
4 * This is a collection of several routines from gzip-1.0.3
5 * adapted for Linux.
6 *
7 * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
8 * puts by Nick Holloway 1993, better puts by Martin Mares 1995
9 * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
10 */
11
12#include <linux/linkage.h>
13#include <linux/vmalloc.h>
14#include <linux/tty.h>
15#include <video/edid.h>
16#include <asm/io.h>
17
18/*
19 * gzip declarations
20 */
21
22#define OF(args) args
23#define STATIC static
24
25#undef memset
26#undef memcpy
27
28/*
29 * Why do we do this? Don't ask me..
30 *
31 * Incomprehensible are the ways of bootloaders.
32 */
33static void* memset(void *, int, size_t);
34static void* memcpy(void *, __const void *, size_t);
35#define memzero(s, n) memset ((s), 0, (n))
36
37typedef unsigned char uch;
38typedef unsigned short ush;
39typedef unsigned long ulg;
40
41#define WSIZE 0x8000 /* Window size must be at least 32k, */
42 /* and a power of two */
43
44static uch *inbuf; /* input buffer */
45static uch window[WSIZE]; /* Sliding window buffer */
46
47static unsigned insize = 0; /* valid bytes in inbuf */
48static unsigned inptr = 0; /* index of next byte to be processed in inbuf */
49static unsigned outcnt = 0; /* bytes in output buffer */
50
51/* gzip flag byte */
52#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
53#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
54#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
55#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
56#define COMMENT 0x10 /* bit 4 set: file comment present */
57#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
58#define RESERVED 0xC0 /* bit 6,7: reserved */
59
60#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
61
62/* Diagnostic functions */
63#ifdef DEBUG
64# define Assert(cond,msg) {if(!(cond)) error(msg);}
65# define Trace(x) fprintf x
66# define Tracev(x) {if (verbose) fprintf x ;}
67# define Tracevv(x) {if (verbose>1) fprintf x ;}
68# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
69# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
70#else
71# define Assert(cond,msg)
72# define Trace(x)
73# define Tracev(x)
74# define Tracevv(x)
75# define Tracec(c,x)
76# define Tracecv(c,x)
77#endif
78
79static int fill_inbuf(void);
80static void flush_window(void);
81static void error(char *m);
82static void gzip_mark(void **);
83static void gzip_release(void **);
84
85/*
86 * This is set up by the setup-routine at boot-time
87 */
88static unsigned char *real_mode; /* Pointer to real-mode data */
89
90#define RM_EXT_MEM_K (*(unsigned short *)(real_mode + 0x2))
91#ifndef STANDARD_MEMORY_BIOS_CALL
92#define RM_ALT_MEM_K (*(unsigned long *)(real_mode + 0x1e0))
93#endif
94#define RM_SCREEN_INFO (*(struct screen_info *)(real_mode+0))
95
96extern char input_data[];
97extern int input_len;
98
99static long bytes_out = 0;
100static uch *output_data;
101static unsigned long output_ptr = 0;
102
103static void *malloc(int size);
104static void free(void *where);
105
106static void putstr(const char *);
107
108extern int end;
109static long free_mem_ptr = (long)&end;
110static long free_mem_end_ptr;
111
112#define INPLACE_MOVE_ROUTINE 0x1000
113#define LOW_BUFFER_START 0x2000
114#define LOW_BUFFER_MAX 0x90000
115#define HEAP_SIZE 0x3000
116static unsigned int low_buffer_end, low_buffer_size;
117static int high_loaded =0;
118static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/;
119
120static char *vidmem = (char *)0xb8000;
121static int vidport;
122static int lines, cols;
123
124#ifdef CONFIG_X86_NUMAQ
125static void * xquad_portio = NULL;
126#endif
127
128#include "../../../../lib/inflate.c"
129
130static void *malloc(int size)
131{
132 void *p;
133
134 if (size <0) error("Malloc error");
135 if (free_mem_ptr <= 0) error("Memory error");
136
137 free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */
138
139 p = (void *)free_mem_ptr;
140 free_mem_ptr += size;
141
142 if (free_mem_ptr >= free_mem_end_ptr)
143 error("Out of memory");
144
145 return p;
146}
147
148static void free(void *where)
149{ /* Don't care */
150}
151
152static void gzip_mark(void **ptr)
153{
154 *ptr = (void *) free_mem_ptr;
155}
156
157static void gzip_release(void **ptr)
158{
159 free_mem_ptr = (long) *ptr;
160}
161
162static void scroll(void)
163{
164 int i;
165
166 memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 );
167 for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 )
168 vidmem[i] = ' ';
169}
170
171static void putstr(const char *s)
172{
173 int x,y,pos;
174 char c;
175
176 x = RM_SCREEN_INFO.orig_x;
177 y = RM_SCREEN_INFO.orig_y;
178
179 while ( ( c = *s++ ) != '\0' ) {
180 if ( c == '\n' ) {
181 x = 0;
182 if ( ++y >= lines ) {
183 scroll();
184 y--;
185 }
186 } else {
187 vidmem [ ( x + cols * y ) * 2 ] = c;
188 if ( ++x >= cols ) {
189 x = 0;
190 if ( ++y >= lines ) {
191 scroll();
192 y--;
193 }
194 }
195 }
196 }
197
198 RM_SCREEN_INFO.orig_x = x;
199 RM_SCREEN_INFO.orig_y = y;
200
201 pos = (x + cols * y) * 2; /* Update cursor position */
202 outb_p(14, vidport);
203 outb_p(0xff & (pos >> 9), vidport+1);
204 outb_p(15, vidport);
205 outb_p(0xff & (pos >> 1), vidport+1);
206}
207
208static void* memset(void* s, int c, size_t n)
209{
210 int i;
211 char *ss = (char*)s;
212
213 for (i=0;i<n;i++) ss[i] = c;
214 return s;
215}
216
217static void* memcpy(void* __dest, __const void* __src,
218 size_t __n)
219{
220 int i;
221 char *d = (char *)__dest, *s = (char *)__src;
222
223 for (i=0;i<__n;i++) d[i] = s[i];
224 return __dest;
225}
226
227/* ===========================================================================
228 * Fill the input buffer. This is called only when the buffer is empty
229 * and at least one byte is really needed.
230 */
231static int fill_inbuf(void)
232{
233 if (insize != 0) {
234 error("ran out of input data");
235 }
236
237 inbuf = input_data;
238 insize = input_len;
239 inptr = 1;
240 return inbuf[0];
241}
242
243/* ===========================================================================
244 * Write the output window window[0..outcnt-1] and update crc and bytes_out.
245 * (Used for the decompressed data only.)
246 */
247static void flush_window_low(void)
248{
249 ulg c = crc; /* temporary variable */
250 unsigned n;
251 uch *in, *out, ch;
252
253 in = window;
254 out = &output_data[output_ptr];
255 for (n = 0; n < outcnt; n++) {
256 ch = *out++ = *in++;
257 c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
258 }
259 crc = c;
260 bytes_out += (ulg)outcnt;
261 output_ptr += (ulg)outcnt;
262 outcnt = 0;
263}
264
265static void flush_window_high(void)
266{
267 ulg c = crc; /* temporary variable */
268 unsigned n;
269 uch *in, ch;
270 in = window;
271 for (n = 0; n < outcnt; n++) {
272 ch = *output_data++ = *in++;
273 if ((ulg)output_data == low_buffer_end) output_data=high_buffer_start;
274 c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
275 }
276 crc = c;
277 bytes_out += (ulg)outcnt;
278 outcnt = 0;
279}
280
281static void flush_window(void)
282{
283 if (high_loaded) flush_window_high();
284 else flush_window_low();
285}
286
287static void error(char *x)
288{
289 putstr("\n\n");
290 putstr(x);
291 putstr("\n\n -- System halted");
292
293 while(1); /* Halt */
294}
295
296#define STACK_SIZE (4096)
297
298long user_stack [STACK_SIZE];
299
300struct {
301 long * a;
302 short b;
303 } stack_start = { & user_stack [STACK_SIZE] , __BOOT_DS };
304
305static void setup_normal_output_buffer(void)
306{
307#ifdef STANDARD_MEMORY_BIOS_CALL
308 if (RM_EXT_MEM_K < 1024) error("Less than 2MB of memory");
309#else
310 if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) < 1024) error("Less than 2MB of memory");
311#endif
312 output_data = (char *)0x100000; /* Points to 1M */
313 free_mem_end_ptr = (long)real_mode;
314}
315
316struct moveparams {
317 uch *low_buffer_start; int lcount;
318 uch *high_buffer_start; int hcount;
319};
320
321static void setup_output_buffer_if_we_run_high(struct moveparams *mv)
322{
323 high_buffer_start = (uch *)(((ulg)&end) + HEAP_SIZE);
324#ifdef STANDARD_MEMORY_BIOS_CALL
325 if (RM_EXT_MEM_K < (3*1024)) error("Less than 4MB of memory");
326#else
327 if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) <
328 (3*1024))
329 error("Less than 4MB of memory");
330#endif
331 mv->low_buffer_start = output_data = (char *)LOW_BUFFER_START;
332 low_buffer_end = ((unsigned int)real_mode > LOW_BUFFER_MAX
333 ? LOW_BUFFER_MAX : (unsigned int)real_mode) & ~0xfff;
334 low_buffer_size = low_buffer_end - LOW_BUFFER_START;
335 high_loaded = 1;
336 free_mem_end_ptr = (long)high_buffer_start;
337 if ( (0x100000 + low_buffer_size) > ((ulg)high_buffer_start)) {
338 high_buffer_start = (uch *)(0x100000 + low_buffer_size);
339 mv->hcount = 0; /* say: we need not to move high_buffer */
340 }
341 else mv->hcount = -1;
342 mv->high_buffer_start = high_buffer_start;
343}
344
345static void close_output_buffer_if_we_run_high(struct moveparams *mv)
346{
347 if (bytes_out > low_buffer_size) {
348 mv->lcount = low_buffer_size;
349 if (mv->hcount)
350 mv->hcount = bytes_out - low_buffer_size;
351 } else {
352 mv->lcount = bytes_out;
353 mv->hcount = 0;
354 }
355}
356
357
358asmlinkage int decompress_kernel(struct moveparams *mv, void *rmode)
359{
360 real_mode = rmode;
361
362 if (RM_SCREEN_INFO.orig_video_mode == 7) {
363 vidmem = (char *) 0xb0000;
364 vidport = 0x3b4;
365 } else {
366 vidmem = (char *) 0xb8000;
367 vidport = 0x3d4;
368 }
369
370 lines = RM_SCREEN_INFO.orig_video_lines;
371 cols = RM_SCREEN_INFO.orig_video_cols;
372
373 if (free_mem_ptr < 0x100000) setup_normal_output_buffer();
374 else setup_output_buffer_if_we_run_high(mv);
375
376 makecrc();
377 putstr("Uncompressing Linux... ");
378 gunzip();
379 putstr("Ok, booting the kernel.\n");
380 if (high_loaded) close_output_buffer_if_we_run_high(mv);
381 return high_loaded;
382}
diff --git a/arch/i386/boot/compressed/vmlinux.scr b/arch/i386/boot/compressed/vmlinux.scr
new file mode 100644
index 00000000000..1ed9d791f86
--- /dev/null
+++ b/arch/i386/boot/compressed/vmlinux.scr
@@ -0,0 +1,9 @@
1SECTIONS
2{
3 .data : {
4 input_len = .;
5 LONG(input_data_end - input_data) input_data = .;
6 *(.data)
7 input_data_end = .;
8 }
9}
diff --git a/arch/i386/boot/edd.S b/arch/i386/boot/edd.S
new file mode 100644
index 00000000000..027d6b354ff
--- /dev/null
+++ b/arch/i386/boot/edd.S
@@ -0,0 +1,176 @@
1/*
2 * BIOS Enhanced Disk Drive support
3 * Copyright (C) 2002, 2003, 2004 Dell, Inc.
4 * by Matt Domsch <Matt_Domsch@dell.com> October 2002
5 * conformant to T13 Committee www.t13.org
6 * projects 1572D, 1484D, 1386D, 1226DT
7 * disk signature read by Matt Domsch <Matt_Domsch@dell.com>
8 * and Andrew Wilks <Andrew_Wilks@dell.com> September 2003, June 2004
9 * legacy CHS retreival by Patrick J. LoPresti <patl@users.sourceforge.net>
10 * March 2004
11 * Command line option parsing, Matt Domsch, November 2004
12 */
13
14#include <linux/edd.h>
15#include <asm/setup.h>
16
17#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
18 movb $0, (EDD_MBR_SIG_NR_BUF)
19 movb $0, (EDDNR)
20
21# Check the command line for two options:
22# edd=of disables EDD completely (edd=off)
23# edd=sk skips the MBR test (edd=skipmbr)
24 pushl %esi
25 cmpl $0, %cs:cmd_line_ptr
26 jz done_cl
27 movl %cs:(cmd_line_ptr), %esi
28# ds:esi has the pointer to the command line now
29 movl $(COMMAND_LINE_SIZE-7), %ecx
30# loop through kernel command line one byte at a time
31cl_loop:
32 cmpl $EDD_CL_EQUALS, (%si)
33 jz found_edd_equals
34 incl %esi
35 loop cl_loop
36 jmp done_cl
37found_edd_equals:
38# only looking at first two characters after equals
39 addl $4, %esi
40 cmpw $EDD_CL_OFF, (%si) # edd=of
41 jz do_edd_off
42 cmpw $EDD_CL_SKIP, (%si) # edd=sk
43 jz do_edd_skipmbr
44 jmp done_cl
45do_edd_skipmbr:
46 popl %esi
47 jmp edd_start
48do_edd_off:
49 popl %esi
50 jmp edd_done
51done_cl:
52 popl %esi
53
54
55# Read the first sector of each BIOS disk device and store the 4-byte signature
56edd_mbr_sig_start:
57 movb $0x80, %dl # from device 80
58 movw $EDD_MBR_SIG_BUF, %bx # store buffer ptr in bx
59edd_mbr_sig_read:
60 movl $0xFFFFFFFF, %eax
61 movl %eax, (%bx) # assume failure
62 pushw %bx
63 movb $READ_SECTORS, %ah
64 movb $1, %al # read 1 sector
65 movb $0, %dh # at head 0
66 movw $1, %cx # cylinder 0, sector 0
67 pushw %es
68 pushw %ds
69 popw %es
70 movw $EDDBUF, %bx # disk's data goes into EDDBUF
71 pushw %dx # work around buggy BIOSes
72 stc # work around buggy BIOSes
73 int $0x13
74 sti # work around buggy BIOSes
75 popw %dx
76 popw %es
77 popw %bx
78 jc edd_mbr_sig_done # on failure, we're done.
79 movl (EDDBUF+EDD_MBR_SIG_OFFSET), %eax # read sig out of the MBR
80 movl %eax, (%bx) # store success
81 incb (EDD_MBR_SIG_NR_BUF) # note that we stored something
82 incb %dl # increment to next device
83 addw $4, %bx # increment sig buffer ptr
84 cmpb $EDD_MBR_SIG_MAX, (EDD_MBR_SIG_NR_BUF) # Out of space?
85 jb edd_mbr_sig_read # keep looping
86edd_mbr_sig_done:
87
88# Do the BIOS Enhanced Disk Drive calls
89# This consists of two calls:
90# int 13h ah=41h "Check Extensions Present"
91# int 13h ah=48h "Get Device Parameters"
92# int 13h ah=08h "Legacy Get Device Parameters"
93#
94# A buffer of size EDDMAXNR*(EDDEXTSIZE+EDDPARMSIZE) is reserved for our use
95# in the boot_params at EDDBUF. The first four bytes of which are
96# used to store the device number, interface support map and version
97# results from fn41. The next four bytes are used to store the legacy
98# cylinders, heads, and sectors from fn08. The following 74 bytes are used to
99# store the results from fn48. Starting from device 80h, fn41, then fn48
100# are called and their results stored in EDDBUF+n*(EDDEXTSIZE+EDDPARMIZE).
101# Then the pointer is incremented to store the data for the next call.
102# This repeats until either a device doesn't exist, or until EDDMAXNR
103# devices have been stored.
104# The one tricky part is that ds:si always points EDDEXTSIZE bytes into
105# the structure, and the fn41 and fn08 results are stored at offsets
106# from there. This removes the need to increment the pointer for
107# every store, and leaves it ready for the fn48 call.
108# A second one-byte buffer, EDDNR, in the boot_params stores
109# the number of BIOS devices which exist, up to EDDMAXNR.
110# In setup.c, copy_edd() stores both boot_params buffers away
111# for later use, as they would get overwritten otherwise.
112# This code is sensitive to the size of the structs in edd.h
113edd_start:
114 # %ds points to the bootsector
115 # result buffer for fn48
116 movw $EDDBUF+EDDEXTSIZE, %si # in ds:si, fn41 results
117 # kept just before that
118 movb $0x80, %dl # BIOS device 0x80
119
120edd_check_ext:
121 movb $CHECKEXTENSIONSPRESENT, %ah # Function 41
122 movw $EDDMAGIC1, %bx # magic
123 int $0x13 # make the call
124 jc edd_done # no more BIOS devices
125
126 cmpw $EDDMAGIC2, %bx # is magic right?
127 jne edd_next # nope, next...
128
129 movb %dl, %ds:-8(%si) # store device number
130 movb %ah, %ds:-7(%si) # store version
131 movw %cx, %ds:-6(%si) # store extensions
132 incb (EDDNR) # note that we stored something
133
134edd_get_device_params:
135 movw $EDDPARMSIZE, %ds:(%si) # put size
136 movw $0x0, %ds:2(%si) # work around buggy BIOSes
137 movb $GETDEVICEPARAMETERS, %ah # Function 48
138 int $0x13 # make the call
139 # Don't check for fail return
140 # it doesn't matter.
141edd_get_legacy_chs:
142 xorw %ax, %ax
143 movw %ax, %ds:-4(%si)
144 movw %ax, %ds:-2(%si)
145 # Ralf Brown's Interrupt List says to set ES:DI to
146 # 0000h:0000h "to guard against BIOS bugs"
147 pushw %es
148 movw %ax, %es
149 movw %ax, %di
150 pushw %dx # legacy call clobbers %dl
151 movb $LEGACYGETDEVICEPARAMETERS, %ah # Function 08
152 int $0x13 # make the call
153 jc edd_legacy_done # failed
154 movb %cl, %al # Low 6 bits are max
155 andb $0x3F, %al # sector number
156 movb %al, %ds:-1(%si) # Record max sect
157 movb %dh, %ds:-2(%si) # Record max head number
158 movb %ch, %al # Low 8 bits of max cyl
159 shr $6, %cl
160 movb %cl, %ah # High 2 bits of max cyl
161 movw %ax, %ds:-4(%si)
162
163edd_legacy_done:
164 popw %dx
165 popw %es
166 movw %si, %ax # increment si
167 addw $EDDPARMSIZE+EDDEXTSIZE, %ax
168 movw %ax, %si
169
170edd_next:
171 incb %dl # increment to next device
172 cmpb $EDDMAXNR, (EDDNR) # Out of space?
173 jb edd_check_ext # keep looping
174
175edd_done:
176#endif
diff --git a/arch/i386/boot/install.sh b/arch/i386/boot/install.sh
new file mode 100644
index 00000000000..90f2452b3b9
--- /dev/null
+++ b/arch/i386/boot/install.sh
@@ -0,0 +1,40 @@
1#!/bin/sh
2#
3# arch/i386/boot/install.sh
4#
5# This file is subject to the terms and conditions of the GNU General Public
6# License. See the file "COPYING" in the main directory of this archive
7# for more details.
8#
9# Copyright (C) 1995 by Linus Torvalds
10#
11# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin
12#
13# "make install" script for i386 architecture
14#
15# Arguments:
16# $1 - kernel version
17# $2 - kernel image file
18# $3 - kernel map file
19# $4 - default install path (blank if root directory)
20#
21
22# User may have a custom install script
23
24if [ -x ~/bin/installkernel ]; then exec ~/bin/installkernel "$@"; fi
25if [ -x /sbin/installkernel ]; then exec /sbin/installkernel "$@"; fi
26
27# Default install - same as make zlilo
28
29if [ -f $4/vmlinuz ]; then
30 mv $4/vmlinuz $4/vmlinuz.old
31fi
32
33if [ -f $4/System.map ]; then
34 mv $4/System.map $4/System.old
35fi
36
37cat $2 > $4/vmlinuz
38cp $3 $4/System.map
39
40if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
diff --git a/arch/i386/boot/mtools.conf.in b/arch/i386/boot/mtools.conf.in
new file mode 100644
index 00000000000..efd6d2490c1
--- /dev/null
+++ b/arch/i386/boot/mtools.conf.in
@@ -0,0 +1,17 @@
1#
2# mtools configuration file for "make (b)zdisk"
3#
4
5# Actual floppy drive
6drive a:
7 file="/dev/fd0"
8
9# 1.44 MB floppy disk image
10drive v:
11 file="@OBJ@/fdimage" cylinders=80 heads=2 sectors=18 filter
12
13# 2.88 MB floppy disk image (mostly for virtual uses)
14drive w:
15 file="@OBJ@/fdimage" cylinders=80 heads=2 sectors=36 filter
16
17
diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S
new file mode 100644
index 00000000000..a934ab32bf8
--- /dev/null
+++ b/arch/i386/boot/setup.S
@@ -0,0 +1,1028 @@
1/*
2 * setup.S Copyright (C) 1991, 1992 Linus Torvalds
3 *
4 * setup.s is responsible for getting the system data from the BIOS,
5 * and putting them into the appropriate places in system memory.
6 * both setup.s and system has been loaded by the bootblock.
7 *
8 * This code asks the bios for memory/disk/other parameters, and
9 * puts them in a "safe" place: 0x90000-0x901FF, ie where the
10 * boot-block used to be. It is then up to the protected mode
11 * system to read them from there before the area is overwritten
12 * for buffer-blocks.
13 *
14 * Move PS/2 aux init code to psaux.c
15 * (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92
16 *
17 * some changes and additional features by Christoph Niemann,
18 * March 1993/June 1994 (Christoph.Niemann@linux.org)
19 *
20 * add APM BIOS checking by Stephen Rothwell, May 1994
21 * (sfr@canb.auug.org.au)
22 *
23 * High load stuff, initrd support and position independency
24 * by Hans Lermen & Werner Almesberger, February 1996
25 * <lermen@elserv.ffm.fgan.de>, <almesber@lrc.epfl.ch>
26 *
27 * Video handling moved to video.S by Martin Mares, March 1996
28 * <mj@k332.feld.cvut.cz>
29 *
30 * Extended memory detection scheme retwiddled by orc@pell.chi.il.us (david
31 * parsons) to avoid loadlin confusion, July 1997
32 *
33 * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999.
34 * <stiker@northlink.com>
35 *
36 * Fix to work around buggy BIOSes which dont use carry bit correctly
37 * and/or report extended memory in CX/DX for e801h memory size detection
38 * call. As a result the kernel got wrong figures. The int15/e801h docs
39 * from Ralf Brown interrupt list seem to indicate AX/BX should be used
40 * anyway. So to avoid breaking many machines (presumably there was a reason
41 * to orginally use CX/DX instead of AX/BX), we do a kludge to see
42 * if CX/DX have been changed in the e801 call and if so use AX/BX .
43 * Michael Miller, April 2001 <michaelm@mjmm.org>
44 *
45 * New A20 code ported from SYSLINUX by H. Peter Anvin. AMD Elan bugfixes
46 * by Robert Schwebel, December 2001 <robert@schwebel.de>
47 */
48
49#include <linux/config.h>
50#include <asm/segment.h>
51#include <linux/version.h>
52#include <linux/compile.h>
53#include <asm/boot.h>
54#include <asm/e820.h>
55#include <asm/page.h>
56
57/* Signature words to ensure LILO loaded us right */
58#define SIG1 0xAA55
59#define SIG2 0x5A5A
60
61INITSEG = DEF_INITSEG # 0x9000, we move boot here, out of the way
62SYSSEG = DEF_SYSSEG # 0x1000, system loaded at 0x10000 (65536).
63SETUPSEG = DEF_SETUPSEG # 0x9020, this is the current segment
64 # ... and the former contents of CS
65
66DELTA_INITSEG = SETUPSEG - INITSEG # 0x0020
67
68.code16
69.globl begtext, begdata, begbss, endtext, enddata, endbss
70
71.text
72begtext:
73.data
74begdata:
75.bss
76begbss:
77.text
78
79start:
80 jmp trampoline
81
82# This is the setup header, and it must start at %cs:2 (old 0x9020:2)
83
84 .ascii "HdrS" # header signature
85 .word 0x0203 # header version number (>= 0x0105)
86 # or else old loadlin-1.5 will fail)
87realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
88start_sys_seg: .word SYSSEG
89 .word kernel_version # pointing to kernel version string
90 # above section of header is compatible
91 # with loadlin-1.5 (header v1.5). Don't
92 # change it.
93
94type_of_loader: .byte 0 # = 0, old one (LILO, Loadlin,
95 # Bootlin, SYSLX, bootsect...)
96 # See Documentation/i386/boot.txt for
97 # assigned ids
98
99# flags, unused bits must be zero (RFU) bit within loadflags
100loadflags:
101LOADED_HIGH = 1 # If set, the kernel is loaded high
102CAN_USE_HEAP = 0x80 # If set, the loader also has set
103 # heap_end_ptr to tell how much
104 # space behind setup.S can be used for
105 # heap purposes.
106 # Only the loader knows what is free
107#ifndef __BIG_KERNEL__
108 .byte 0
109#else
110 .byte LOADED_HIGH
111#endif
112
113setup_move_size: .word 0x8000 # size to move, when setup is not
114 # loaded at 0x90000. We will move setup
115 # to 0x90000 then just before jumping
116 # into the kernel. However, only the
117 # loader knows how much data behind
118 # us also needs to be loaded.
119
120code32_start: # here loaders can put a different
121 # start address for 32-bit code.
122#ifndef __BIG_KERNEL__
123 .long 0x1000 # 0x1000 = default for zImage
124#else
125 .long 0x100000 # 0x100000 = default for big kernel
126#endif
127
128ramdisk_image: .long 0 # address of loaded ramdisk image
129 # Here the loader puts the 32-bit
130 # address where it loaded the image.
131 # This only will be read by the kernel.
132
133ramdisk_size: .long 0 # its size in bytes
134
135bootsect_kludge:
136 .long 0 # obsolete
137
138heap_end_ptr: .word modelist+1024 # (Header version 0x0201 or later)
139 # space from here (exclusive) down to
140 # end of setup code can be used by setup
141 # for local heap purposes.
142
143pad1: .word 0
144cmd_line_ptr: .long 0 # (Header version 0x0202 or later)
145 # If nonzero, a 32-bit pointer
146 # to the kernel command line.
147 # The command line should be
148 # located between the start of
149 # setup and the end of low
150 # memory (0xa0000), or it may
151 # get overwritten before it
152 # gets read. If this field is
153 # used, there is no longer
154 # anything magical about the
155 # 0x90000 segment; the setup
156 # can be located anywhere in
157 # low memory 0x10000 or higher.
158
159ramdisk_max: .long (-__PAGE_OFFSET-(512 << 20)-1) & 0x7fffffff
160 # (Header version 0x0203 or later)
161 # The highest safe address for
162 # the contents of an initrd
163
164trampoline: call start_of_setup
165 .align 16
166 # The offset at this point is 0x240
167 .space (0x7ff-0x240+1) # E820 & EDD space (ending at 0x7ff)
168# End of setup header #####################################################
169
170start_of_setup:
171# Bootlin depends on this being done early
172 movw $0x01500, %ax
173 movb $0x81, %dl
174 int $0x13
175
176#ifdef SAFE_RESET_DISK_CONTROLLER
177# Reset the disk controller.
178 movw $0x0000, %ax
179 movb $0x80, %dl
180 int $0x13
181#endif
182
183# Set %ds = %cs, we know that SETUPSEG = %cs at this point
184 movw %cs, %ax # aka SETUPSEG
185 movw %ax, %ds
186# Check signature at end of setup
187 cmpw $SIG1, setup_sig1
188 jne bad_sig
189
190 cmpw $SIG2, setup_sig2
191 jne bad_sig
192
193 jmp good_sig1
194
195# Routine to print asciiz string at ds:si
196prtstr:
197 lodsb
198 andb %al, %al
199 jz fin
200
201 call prtchr
202 jmp prtstr
203
204fin: ret
205
206# Space printing
207prtsp2: call prtspc # Print double space
208prtspc: movb $0x20, %al # Print single space (note: fall-thru)
209
210# Part of above routine, this one just prints ascii al
211prtchr: pushw %ax
212 pushw %cx
213 movw $7,%bx
214 movw $0x01, %cx
215 movb $0x0e, %ah
216 int $0x10
217 popw %cx
218 popw %ax
219 ret
220
221beep: movb $0x07, %al
222 jmp prtchr
223
224no_sig_mess: .string "No setup signature found ..."
225
226good_sig1:
227 jmp good_sig
228
229# We now have to find the rest of the setup code/data
230bad_sig:
231 movw %cs, %ax # SETUPSEG
232 subw $DELTA_INITSEG, %ax # INITSEG
233 movw %ax, %ds
234 xorb %bh, %bh
235 movb (497), %bl # get setup sect from bootsect
236 subw $4, %bx # LILO loads 4 sectors of setup
237 shlw $8, %bx # convert to words (1sect=2^8 words)
238 movw %bx, %cx
239 shrw $3, %bx # convert to segment
240 addw $SYSSEG, %bx
241 movw %bx, %cs:start_sys_seg
242# Move rest of setup code/data to here
243 movw $2048, %di # four sectors loaded by LILO
244 subw %si, %si
245 pushw %cs
246 popw %es
247 movw $SYSSEG, %ax
248 movw %ax, %ds
249 rep
250 movsw
251 movw %cs, %ax # aka SETUPSEG
252 movw %ax, %ds
253 cmpw $SIG1, setup_sig1
254 jne no_sig
255
256 cmpw $SIG2, setup_sig2
257 jne no_sig
258
259 jmp good_sig
260
261no_sig:
262 lea no_sig_mess, %si
263 call prtstr
264
265no_sig_loop:
266 hlt
267 jmp no_sig_loop
268
269good_sig:
270 movw %cs, %ax # aka SETUPSEG
271 subw $DELTA_INITSEG, %ax # aka INITSEG
272 movw %ax, %ds
273# Check if an old loader tries to load a big-kernel
274 testb $LOADED_HIGH, %cs:loadflags # Do we have a big kernel?
275 jz loader_ok # No, no danger for old loaders.
276
277 cmpb $0, %cs:type_of_loader # Do we have a loader that
278 # can deal with us?
279 jnz loader_ok # Yes, continue.
280
281 pushw %cs # No, we have an old loader,
282 popw %ds # die.
283 lea loader_panic_mess, %si
284 call prtstr
285
286 jmp no_sig_loop
287
288loader_panic_mess: .string "Wrong loader, giving up..."
289
290loader_ok:
291# Get memory size (extended mem, kB)
292
293 xorl %eax, %eax
294 movl %eax, (0x1e0)
295#ifndef STANDARD_MEMORY_BIOS_CALL
296 movb %al, (E820NR)
297# Try three different memory detection schemes. First, try
298# e820h, which lets us assemble a memory map, then try e801h,
299# which returns a 32-bit memory size, and finally 88h, which
300# returns 0-64m
301
302# method E820H:
303# the memory map from hell. e820h returns memory classified into
304# a whole bunch of different types, and allows memory holes and
305# everything. We scan through this memory map and build a list
306# of the first 32 memory areas, which we return at [E820MAP].
307# This is documented at http://www.acpi.info/, in the ACPI 2.0 specification.
308
309#define SMAP 0x534d4150
310
311meme820:
312 xorl %ebx, %ebx # continuation counter
313 movw $E820MAP, %di # point into the whitelist
314 # so we can have the bios
315 # directly write into it.
316
317jmpe820:
318 movl $0x0000e820, %eax # e820, upper word zeroed
319 movl $SMAP, %edx # ascii 'SMAP'
320 movl $20, %ecx # size of the e820rec
321 pushw %ds # data record.
322 popw %es
323 int $0x15 # make the call
324 jc bail820 # fall to e801 if it fails
325
326 cmpl $SMAP, %eax # check the return is `SMAP'
327 jne bail820 # fall to e801 if it fails
328
329# cmpl $1, 16(%di) # is this usable memory?
330# jne again820
331
332 # If this is usable memory, we save it by simply advancing %di by
333 # sizeof(e820rec).
334 #
335good820:
336 movb (E820NR), %al # up to 32 entries
337 cmpb $E820MAX, %al
338 jnl bail820
339
340 incb (E820NR)
341 movw %di, %ax
342 addw $20, %ax
343 movw %ax, %di
344again820:
345 cmpl $0, %ebx # check to see if
346 jne jmpe820 # %ebx is set to EOF
347bail820:
348
349
350# method E801H:
351# memory size is in 1k chunksizes, to avoid confusing loadlin.
352# we store the 0xe801 memory size in a completely different place,
353# because it will most likely be longer than 16 bits.
354# (use 1e0 because that's what Larry Augustine uses in his
355# alternative new memory detection scheme, and it's sensible
356# to write everything into the same place.)
357
358meme801:
359 stc # fix to work around buggy
360 xorw %cx,%cx # BIOSes which dont clear/set
361 xorw %dx,%dx # carry on pass/error of
362 # e801h memory size call
363 # or merely pass cx,dx though
364 # without changing them.
365 movw $0xe801, %ax
366 int $0x15
367 jc mem88
368
369 cmpw $0x0, %cx # Kludge to handle BIOSes
370 jne e801usecxdx # which report their extended
371 cmpw $0x0, %dx # memory in AX/BX rather than
372 jne e801usecxdx # CX/DX. The spec I have read
373 movw %ax, %cx # seems to indicate AX/BX
374 movw %bx, %dx # are more reasonable anyway...
375
376e801usecxdx:
377 andl $0xffff, %edx # clear sign extend
378 shll $6, %edx # and go from 64k to 1k chunks
379 movl %edx, (0x1e0) # store extended memory size
380 andl $0xffff, %ecx # clear sign extend
381 addl %ecx, (0x1e0) # and add lower memory into
382 # total size.
383
384# Ye Olde Traditional Methode. Returns the memory size (up to 16mb or
385# 64mb, depending on the bios) in ax.
386mem88:
387
388#endif
389 movb $0x88, %ah
390 int $0x15
391 movw %ax, (2)
392
393# Set the keyboard repeat rate to the max
394 movw $0x0305, %ax
395 xorw %bx, %bx
396 int $0x16
397
398# Check for video adapter and its parameters and allow the
399# user to browse video modes.
400 call video # NOTE: we need %ds pointing
401 # to bootsector
402
403# Get hd0 data...
404 xorw %ax, %ax
405 movw %ax, %ds
406 ldsw (4 * 0x41), %si
407 movw %cs, %ax # aka SETUPSEG
408 subw $DELTA_INITSEG, %ax # aka INITSEG
409 pushw %ax
410 movw %ax, %es
411 movw $0x0080, %di
412 movw $0x10, %cx
413 pushw %cx
414 cld
415 rep
416 movsb
417# Get hd1 data...
418 xorw %ax, %ax
419 movw %ax, %ds
420 ldsw (4 * 0x46), %si
421 popw %cx
422 popw %es
423 movw $0x0090, %di
424 rep
425 movsb
426# Check that there IS a hd1 :-)
427 movw $0x01500, %ax
428 movb $0x81, %dl
429 int $0x13
430 jc no_disk1
431
432 cmpb $3, %ah
433 je is_disk1
434
435no_disk1:
436 movw %cs, %ax # aka SETUPSEG
437 subw $DELTA_INITSEG, %ax # aka INITSEG
438 movw %ax, %es
439 movw $0x0090, %di
440 movw $0x10, %cx
441 xorw %ax, %ax
442 cld
443 rep
444 stosb
445is_disk1:
446# check for Micro Channel (MCA) bus
447 movw %cs, %ax # aka SETUPSEG
448 subw $DELTA_INITSEG, %ax # aka INITSEG
449 movw %ax, %ds
450 xorw %ax, %ax
451 movw %ax, (0xa0) # set table length to 0
452 movb $0xc0, %ah
453 stc
454 int $0x15 # moves feature table to es:bx
455 jc no_mca
456
457 pushw %ds
458 movw %es, %ax
459 movw %ax, %ds
460 movw %cs, %ax # aka SETUPSEG
461 subw $DELTA_INITSEG, %ax # aka INITSEG
462 movw %ax, %es
463 movw %bx, %si
464 movw $0xa0, %di
465 movw (%si), %cx
466 addw $2, %cx # table length is a short
467 cmpw $0x10, %cx
468 jc sysdesc_ok
469
470 movw $0x10, %cx # we keep only first 16 bytes
471sysdesc_ok:
472 rep
473 movsb
474 popw %ds
475no_mca:
476#ifdef CONFIG_X86_VOYAGER
477 movb $0xff, 0x40 # flag on config found
478 movb $0xc0, %al
479 mov $0xff, %ah
480 int $0x15 # put voyager config info at es:di
481 jc no_voyager
482 movw $0x40, %si # place voyager info in apm table
483 cld
484 movw $7, %cx
485voyager_rep:
486 movb %es:(%di), %al
487 movb %al,(%si)
488 incw %di
489 incw %si
490 decw %cx
491 jnz voyager_rep
492no_voyager:
493#endif
494# Check for PS/2 pointing device
495 movw %cs, %ax # aka SETUPSEG
496 subw $DELTA_INITSEG, %ax # aka INITSEG
497 movw %ax, %ds
498 movw $0, (0x1ff) # default is no pointing device
499 int $0x11 # int 0x11: equipment list
500 testb $0x04, %al # check if mouse installed
501 jz no_psmouse
502
503 movw $0xAA, (0x1ff) # device present
504no_psmouse:
505
506#if defined(CONFIG_X86_SPEEDSTEP_SMI) || defined(CONFIG_X86_SPEEDSTEP_SMI_MODULE)
507 movl $0x0000E980, %eax # IST Support
508 movl $0x47534943, %edx # Request value
509 int $0x15
510
511 movl %eax, (96)
512 movl %ebx, (100)
513 movl %ecx, (104)
514 movl %edx, (108)
515#endif
516
517#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
518# Then check for an APM BIOS...
519 # %ds points to the bootsector
520 movw $0, 0x40 # version = 0 means no APM BIOS
521 movw $0x05300, %ax # APM BIOS installation check
522 xorw %bx, %bx
523 int $0x15
524 jc done_apm_bios # Nope, no APM BIOS
525
526 cmpw $0x0504d, %bx # Check for "PM" signature
527 jne done_apm_bios # No signature, no APM BIOS
528
529 andw $0x02, %cx # Is 32 bit supported?
530 je done_apm_bios # No 32-bit, no (good) APM BIOS
531
532 movw $0x05304, %ax # Disconnect first just in case
533 xorw %bx, %bx
534 int $0x15 # ignore return code
535 movw $0x05303, %ax # 32 bit connect
536 xorl %ebx, %ebx
537 xorw %cx, %cx # paranoia :-)
538 xorw %dx, %dx # ...
539 xorl %esi, %esi # ...
540 xorw %di, %di # ...
541 int $0x15
542 jc no_32_apm_bios # Ack, error.
543
544 movw %ax, (66) # BIOS code segment
545 movl %ebx, (68) # BIOS entry point offset
546 movw %cx, (72) # BIOS 16 bit code segment
547 movw %dx, (74) # BIOS data segment
548 movl %esi, (78) # BIOS code segment lengths
549 movw %di, (82) # BIOS data segment length
550# Redo the installation check as the 32 bit connect
551# modifies the flags returned on some BIOSs
552 movw $0x05300, %ax # APM BIOS installation check
553 xorw %bx, %bx
554 xorw %cx, %cx # paranoia
555 int $0x15
556 jc apm_disconnect # error -> shouldn't happen
557
558 cmpw $0x0504d, %bx # check for "PM" signature
559 jne apm_disconnect # no sig -> shouldn't happen
560
561 movw %ax, (64) # record the APM BIOS version
562 movw %cx, (76) # and flags
563 jmp done_apm_bios
564
565apm_disconnect: # Tidy up
566 movw $0x05304, %ax # Disconnect
567 xorw %bx, %bx
568 int $0x15 # ignore return code
569
570 jmp done_apm_bios
571
572no_32_apm_bios:
573 andw $0xfffd, (76) # remove 32 bit support bit
574done_apm_bios:
575#endif
576
577#include "edd.S"
578
579# Now we want to move to protected mode ...
580 cmpw $0, %cs:realmode_swtch
581 jz rmodeswtch_normal
582
583 lcall *%cs:realmode_swtch
584
585 jmp rmodeswtch_end
586
587rmodeswtch_normal:
588 pushw %cs
589 call default_switch
590
591rmodeswtch_end:
592# we get the code32 start address and modify the below 'jmpi'
593# (loader may have changed it)
594 movl %cs:code32_start, %eax
595 movl %eax, %cs:code32
596
597# Now we move the system to its rightful place ... but we check if we have a
598# big-kernel. In that case we *must* not move it ...
599 testb $LOADED_HIGH, %cs:loadflags
600 jz do_move0 # .. then we have a normal low
601 # loaded zImage
602 # .. or else we have a high
603 # loaded bzImage
604 jmp end_move # ... and we skip moving
605
606do_move0:
607 movw $0x100, %ax # start of destination segment
608 movw %cs, %bp # aka SETUPSEG
609 subw $DELTA_INITSEG, %bp # aka INITSEG
610 movw %cs:start_sys_seg, %bx # start of source segment
611 cld
612do_move:
613 movw %ax, %es # destination segment
614 incb %ah # instead of add ax,#0x100
615 movw %bx, %ds # source segment
616 addw $0x100, %bx
617 subw %di, %di
618 subw %si, %si
619 movw $0x800, %cx
620 rep
621 movsw
622 cmpw %bp, %bx # assume start_sys_seg > 0x200,
623 # so we will perhaps read one
624 # page more than needed, but
625 # never overwrite INITSEG
626 # because destination is a
627 # minimum one page below source
628 jb do_move
629
630end_move:
631# then we load the segment descriptors
632 movw %cs, %ax # aka SETUPSEG
633 movw %ax, %ds
634
635# Check whether we need to be downward compatible with version <=201
636 cmpl $0, cmd_line_ptr
637 jne end_move_self # loader uses version >=202 features
638 cmpb $0x20, type_of_loader
639 je end_move_self # bootsect loader, we know of it
640
641# Boot loader doesnt support boot protocol version 2.02.
642# If we have our code not at 0x90000, we need to move it there now.
643# We also then need to move the params behind it (commandline)
644# Because we would overwrite the code on the current IP, we move
645# it in two steps, jumping high after the first one.
646 movw %cs, %ax
647 cmpw $SETUPSEG, %ax
648 je end_move_self
649
650 cli # make sure we really have
651 # interrupts disabled !
652 # because after this the stack
653 # should not be used
654 subw $DELTA_INITSEG, %ax # aka INITSEG
655 movw %ss, %dx
656 cmpw %ax, %dx
657 jb move_self_1
658
659 addw $INITSEG, %dx
660 subw %ax, %dx # this will go into %ss after
661 # the move
662move_self_1:
663 movw %ax, %ds
664 movw $INITSEG, %ax # real INITSEG
665 movw %ax, %es
666 movw %cs:setup_move_size, %cx
667 std # we have to move up, so we use
668 # direction down because the
669 # areas may overlap
670 movw %cx, %di
671 decw %di
672 movw %di, %si
673 subw $move_self_here+0x200, %cx
674 rep
675 movsb
676 ljmp $SETUPSEG, $move_self_here
677
678move_self_here:
679 movw $move_self_here+0x200, %cx
680 rep
681 movsb
682 movw $SETUPSEG, %ax
683 movw %ax, %ds
684 movw %dx, %ss
685end_move_self: # now we are at the right place
686
687#
688# Enable A20. This is at the very best an annoying procedure.
689# A20 code ported from SYSLINUX 1.52-1.63 by H. Peter Anvin.
690# AMD Elan bug fix by Robert Schwebel.
691#
692
693#if defined(CONFIG_X86_ELAN)
694 movb $0x02, %al # alternate A20 gate
695 outb %al, $0x92 # this works on SC410/SC520
696a20_elan_wait:
697 call a20_test
698 jz a20_elan_wait
699 jmp a20_done
700#endif
701
702
703A20_TEST_LOOPS = 32 # Iterations per wait
704A20_ENABLE_LOOPS = 255 # Total loops to try
705
706
707#ifndef CONFIG_X86_VOYAGER
708a20_try_loop:
709
710 # First, see if we are on a system with no A20 gate.
711a20_none:
712 call a20_test
713 jnz a20_done
714
715 # Next, try the BIOS (INT 0x15, AX=0x2401)
716a20_bios:
717 movw $0x2401, %ax
718 pushfl # Be paranoid about flags
719 int $0x15
720 popfl
721
722 call a20_test
723 jnz a20_done
724
725 # Try enabling A20 through the keyboard controller
726#endif /* CONFIG_X86_VOYAGER */
727a20_kbc:
728 call empty_8042
729
730#ifndef CONFIG_X86_VOYAGER
731 call a20_test # Just in case the BIOS worked
732 jnz a20_done # but had a delayed reaction.
733#endif
734
735 movb $0xD1, %al # command write
736 outb %al, $0x64
737 call empty_8042
738
739 movb $0xDF, %al # A20 on
740 outb %al, $0x60
741 call empty_8042
742
743#ifndef CONFIG_X86_VOYAGER
744 # Wait until a20 really *is* enabled; it can take a fair amount of
745 # time on certain systems; Toshiba Tecras are known to have this
746 # problem.
747a20_kbc_wait:
748 xorw %cx, %cx
749a20_kbc_wait_loop:
750 call a20_test
751 jnz a20_done
752 loop a20_kbc_wait_loop
753
754 # Final attempt: use "configuration port A"
755a20_fast:
756 inb $0x92, %al # Configuration Port A
757 orb $0x02, %al # "fast A20" version
758 andb $0xFE, %al # don't accidentally reset
759 outb %al, $0x92
760
761 # Wait for configuration port A to take effect
762a20_fast_wait:
763 xorw %cx, %cx
764a20_fast_wait_loop:
765 call a20_test
766 jnz a20_done
767 loop a20_fast_wait_loop
768
769 # A20 is still not responding. Try frobbing it again.
770 #
771 decb (a20_tries)
772 jnz a20_try_loop
773
774 movw $a20_err_msg, %si
775 call prtstr
776
777a20_die:
778 hlt
779 jmp a20_die
780
781a20_tries:
782 .byte A20_ENABLE_LOOPS
783
784a20_err_msg:
785 .ascii "linux: fatal error: A20 gate not responding!"
786 .byte 13, 10, 0
787
788 # If we get here, all is good
789a20_done:
790
791#endif /* CONFIG_X86_VOYAGER */
792# set up gdt and idt
793 lidt idt_48 # load idt with 0,0
794 xorl %eax, %eax # Compute gdt_base
795 movw %ds, %ax # (Convert %ds:gdt to a linear ptr)
796 shll $4, %eax
797 addl $gdt, %eax
798 movl %eax, (gdt_48+2)
799 lgdt gdt_48 # load gdt with whatever is
800 # appropriate
801
802# make sure any possible coprocessor is properly reset..
803 xorw %ax, %ax
804 outb %al, $0xf0
805 call delay
806
807 outb %al, $0xf1
808 call delay
809
810# well, that went ok, I hope. Now we mask all interrupts - the rest
811# is done in init_IRQ().
812 movb $0xFF, %al # mask all interrupts for now
813 outb %al, $0xA1
814 call delay
815
816 movb $0xFB, %al # mask all irq's but irq2 which
817 outb %al, $0x21 # is cascaded
818
819# Well, that certainly wasn't fun :-(. Hopefully it works, and we don't
820# need no steenking BIOS anyway (except for the initial loading :-).
821# The BIOS-routine wants lots of unnecessary data, and it's less
822# "interesting" anyway. This is how REAL programmers do it.
823#
824# Well, now's the time to actually move into protected mode. To make
825# things as simple as possible, we do no register set-up or anything,
826# we let the gnu-compiled 32-bit programs do that. We just jump to
827# absolute address 0x1000 (or the loader supplied one),
828# in 32-bit protected mode.
829#
830# Note that the short jump isn't strictly needed, although there are
831# reasons why it might be a good idea. It won't hurt in any case.
832 movw $1, %ax # protected mode (PE) bit
833 lmsw %ax # This is it!
834 jmp flush_instr
835
836flush_instr:
837 xorw %bx, %bx # Flag to indicate a boot
838 xorl %esi, %esi # Pointer to real-mode code
839 movw %cs, %si
840 subw $DELTA_INITSEG, %si
841 shll $4, %esi # Convert to 32-bit pointer
842
843# jump to startup_32 in arch/i386/boot/compressed/head.S
844#
845# NOTE: For high loaded big kernels we need a
846# jmpi 0x100000,__BOOT_CS
847#
848# but we yet haven't reloaded the CS register, so the default size
849# of the target offset still is 16 bit.
850# However, using an operand prefix (0x66), the CPU will properly
851# take our 48 bit far pointer. (INTeL 80386 Programmer's Reference
852# Manual, Mixing 16-bit and 32-bit code, page 16-6)
853
854 .byte 0x66, 0xea # prefix + jmpi-opcode
855code32: .long 0x1000 # will be set to 0x100000
856 # for big kernels
857 .word __BOOT_CS
858
859# Here's a bunch of information about your current kernel..
860kernel_version: .ascii UTS_RELEASE
861 .ascii " ("
862 .ascii LINUX_COMPILE_BY
863 .ascii "@"
864 .ascii LINUX_COMPILE_HOST
865 .ascii ") "
866 .ascii UTS_VERSION
867 .byte 0
868
869# This is the default real mode switch routine.
870# to be called just before protected mode transition
871default_switch:
872 cli # no interrupts allowed !
873 movb $0x80, %al # disable NMI for bootup
874 # sequence
875 outb %al, $0x70
876 lret
877
878
879#ifndef CONFIG_X86_VOYAGER
880# This routine tests whether or not A20 is enabled. If so, it
881# exits with zf = 0.
882#
883# The memory address used, 0x200, is the int $0x80 vector, which
884# should be safe.
885
886A20_TEST_ADDR = 4*0x80
887
888a20_test:
889 pushw %cx
890 pushw %ax
891 xorw %cx, %cx
892 movw %cx, %fs # Low memory
893 decw %cx
894 movw %cx, %gs # High memory area
895 movw $A20_TEST_LOOPS, %cx
896 movw %fs:(A20_TEST_ADDR), %ax
897 pushw %ax
898a20_test_wait:
899 incw %ax
900 movw %ax, %fs:(A20_TEST_ADDR)
901 call delay # Serialize and make delay constant
902 cmpw %gs:(A20_TEST_ADDR+0x10), %ax
903 loope a20_test_wait
904
905 popw %fs:(A20_TEST_ADDR)
906 popw %ax
907 popw %cx
908 ret
909
910#endif /* CONFIG_X86_VOYAGER */
911
912# This routine checks that the keyboard command queue is empty
913# (after emptying the output buffers)
914#
915# Some machines have delusions that the keyboard buffer is always full
916# with no keyboard attached...
917#
918# If there is no keyboard controller, we will usually get 0xff
919# to all the reads. With each IO taking a microsecond and
920# a timeout of 100,000 iterations, this can take about half a
921# second ("delay" == outb to port 0x80). That should be ok,
922# and should also be plenty of time for a real keyboard controller
923# to empty.
924#
925
926empty_8042:
927 pushl %ecx
928 movl $100000, %ecx
929
930empty_8042_loop:
931 decl %ecx
932 jz empty_8042_end_loop
933
934 call delay
935
936 inb $0x64, %al # 8042 status port
937 testb $1, %al # output buffer?
938 jz no_output
939
940 call delay
941 inb $0x60, %al # read it
942 jmp empty_8042_loop
943
944no_output:
945 testb $2, %al # is input buffer full?
946 jnz empty_8042_loop # yes - loop
947empty_8042_end_loop:
948 popl %ecx
949 ret
950
951# Read the cmos clock. Return the seconds in al
952gettime:
953 pushw %cx
954 movb $0x02, %ah
955 int $0x1a
956 movb %dh, %al # %dh contains the seconds
957 andb $0x0f, %al
958 movb %dh, %ah
959 movb $0x04, %cl
960 shrb %cl, %ah
961 aad
962 popw %cx
963 ret
964
965# Delay is needed after doing I/O
966delay:
967 outb %al,$0x80
968 ret
969
970# Descriptor tables
971#
972# NOTE: The intel manual says gdt should be sixteen bytes aligned for
973# efficiency reasons. However, there are machines which are known not
974# to boot with misaligned GDTs, so alter this at your peril! If you alter
975# GDT_ENTRY_BOOT_CS (in asm/segment.h) remember to leave at least two
976# empty GDT entries (one for NULL and one reserved).
977#
978# NOTE: On some CPUs, the GDT must be 8 byte aligned. This is
979# true for the Voyager Quad CPU card which will not boot without
980# This directive. 16 byte aligment is recommended by intel.
981#
982 .align 16
983gdt:
984 .fill GDT_ENTRY_BOOT_CS,8,0
985
986 .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
987 .word 0 # base address = 0
988 .word 0x9A00 # code read/exec
989 .word 0x00CF # granularity = 4096, 386
990 # (+5th nibble of limit)
991
992 .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
993 .word 0 # base address = 0
994 .word 0x9200 # data read/write
995 .word 0x00CF # granularity = 4096, 386
996 # (+5th nibble of limit)
997gdt_end:
998 .align 4
999
1000 .word 0 # alignment byte
1001idt_48:
1002 .word 0 # idt limit = 0
1003 .word 0, 0 # idt base = 0L
1004
1005 .word 0 # alignment byte
1006gdt_48:
1007 .word gdt_end - gdt - 1 # gdt limit
1008 .word 0, 0 # gdt base (filled in later)
1009
1010# Include video setup & detection code
1011
1012#include "video.S"
1013
1014# Setup signature -- must be last
1015setup_sig1: .word SIG1
1016setup_sig2: .word SIG2
1017
1018# After this point, there is some free space which is used by the video mode
1019# handling code to store the temporary mode table (not used by the kernel).
1020
1021modelist:
1022
1023.text
1024endtext:
1025.data
1026enddata:
1027.bss
1028endbss:
diff --git a/arch/i386/boot/tools/build.c b/arch/i386/boot/tools/build.c
new file mode 100644
index 00000000000..26509b826ae
--- /dev/null
+++ b/arch/i386/boot/tools/build.c
@@ -0,0 +1,184 @@
1/*
2 * $Id: build.c,v 1.5 1997/05/19 12:29:58 mj Exp $
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 * Copyright (C) 1997 Martin Mares
6 */
7
8/*
9 * This file builds a disk-image from three different files:
10 *
11 * - bootsect: exactly 512 bytes of 8086 machine code, loads the rest
12 * - setup: 8086 machine code, sets up system parm
13 * - system: 80386 code for actual system
14 *
15 * It does some checking that all files are of the correct type, and
16 * just writes the result to stdout, removing headers and padding to
17 * the right amount. It also writes some system data to stderr.
18 */
19
20/*
21 * Changes by tytso to allow root device specification
22 * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
23 * Cross compiling fixes by Gertjan van Wingerde, July 1996
24 * Rewritten by Martin Mares, April 1997
25 */
26
27#include <stdio.h>
28#include <string.h>
29#include <stdlib.h>
30#include <stdarg.h>
31#include <sys/types.h>
32#include <sys/stat.h>
33#include <sys/sysmacros.h>
34#include <unistd.h>
35#include <fcntl.h>
36#include <asm/boot.h>
37
38typedef unsigned char byte;
39typedef unsigned short word;
40typedef unsigned long u32;
41
42#define DEFAULT_MAJOR_ROOT 0
43#define DEFAULT_MINOR_ROOT 0
44
45/* Minimal number of setup sectors (see also bootsect.S) */
46#define SETUP_SECTS 4
47
48byte buf[1024];
49int fd;
50int is_big_kernel;
51
52void die(const char * str, ...)
53{
54 va_list args;
55 va_start(args, str);
56 vfprintf(stderr, str, args);
57 fputc('\n', stderr);
58 exit(1);
59}
60
61void file_open(const char *name)
62{
63 if ((fd = open(name, O_RDONLY, 0)) < 0)
64 die("Unable to open `%s': %m", name);
65}
66
67void usage(void)
68{
69 die("Usage: build [-b] bootsect setup system [rootdev] [> image]");
70}
71
72int main(int argc, char ** argv)
73{
74 unsigned int i, c, sz, setup_sectors;
75 u32 sys_size;
76 byte major_root, minor_root;
77 struct stat sb;
78
79 if (argc > 2 && !strcmp(argv[1], "-b"))
80 {
81 is_big_kernel = 1;
82 argc--, argv++;
83 }
84 if ((argc < 4) || (argc > 5))
85 usage();
86 if (argc > 4) {
87 if (!strcmp(argv[4], "CURRENT")) {
88 if (stat("/", &sb)) {
89 perror("/");
90 die("Couldn't stat /");
91 }
92 major_root = major(sb.st_dev);
93 minor_root = minor(sb.st_dev);
94 } else if (strcmp(argv[4], "FLOPPY")) {
95 if (stat(argv[4], &sb)) {
96 perror(argv[4]);
97 die("Couldn't stat root device.");
98 }
99 major_root = major(sb.st_rdev);
100 minor_root = minor(sb.st_rdev);
101 } else {
102 major_root = 0;
103 minor_root = 0;
104 }
105 } else {
106 major_root = DEFAULT_MAJOR_ROOT;
107 minor_root = DEFAULT_MINOR_ROOT;
108 }
109 fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root);
110
111 file_open(argv[1]);
112 i = read(fd, buf, sizeof(buf));
113 fprintf(stderr,"Boot sector %d bytes.\n",i);
114 if (i != 512)
115 die("Boot block must be exactly 512 bytes");
116 if (buf[510] != 0x55 || buf[511] != 0xaa)
117 die("Boot block hasn't got boot flag (0xAA55)");
118 buf[508] = minor_root;
119 buf[509] = major_root;
120 if (write(1, buf, 512) != 512)
121 die("Write call failed");
122 close (fd);
123
124 file_open(argv[2]); /* Copy the setup code */
125 for (i=0 ; (c=read(fd, buf, sizeof(buf)))>0 ; i+=c )
126 if (write(1, buf, c) != c)
127 die("Write call failed");
128 if (c != 0)
129 die("read-error on `setup'");
130 close (fd);
131
132 setup_sectors = (i + 511) / 512; /* Pad unused space with zeros */
133 /* for compatibility with ancient versions of LILO. */
134 if (setup_sectors < SETUP_SECTS)
135 setup_sectors = SETUP_SECTS;
136 fprintf(stderr, "Setup is %d bytes.\n", i);
137 memset(buf, 0, sizeof(buf));
138 while (i < setup_sectors * 512) {
139 c = setup_sectors * 512 - i;
140 if (c > sizeof(buf))
141 c = sizeof(buf);
142 if (write(1, buf, c) != c)
143 die("Write call failed");
144 i += c;
145 }
146
147 file_open(argv[3]);
148 if (fstat (fd, &sb))
149 die("Unable to stat `%s': %m", argv[3]);
150 sz = sb.st_size;
151 fprintf (stderr, "System is %d kB\n", sz/1024);
152 sys_size = (sz + 15) / 16;
153 if (!is_big_kernel && sys_size > DEF_SYSSIZE)
154 die("System is too big. Try using bzImage or modules.");
155 while (sz > 0) {
156 int l, n;
157
158 l = (sz > sizeof(buf)) ? sizeof(buf) : sz;
159 if ((n=read(fd, buf, l)) != l) {
160 if (n < 0)
161 die("Error reading %s: %m", argv[3]);
162 else
163 die("%s: Unexpected EOF", argv[3]);
164 }
165 if (write(1, buf, l) != l)
166 die("Write failed");
167 sz -= l;
168 }
169 close(fd);
170
171 if (lseek(1, 497, SEEK_SET) != 497) /* Write sizes to the bootsector */
172 die("Output: seek failed");
173 buf[0] = setup_sectors;
174 if (write(1, buf, 1) != 1)
175 die("Write of setup sector count failed");
176 if (lseek(1, 500, SEEK_SET) != 500)
177 die("Output: seek failed");
178 buf[0] = (sys_size & 0xff);
179 buf[1] = ((sys_size >> 8) & 0xff);
180 if (write(1, buf, 2) != 2)
181 die("Write of image length failed");
182
183 return 0; /* Everything is OK */
184}
diff --git a/arch/i386/boot/video.S b/arch/i386/boot/video.S
new file mode 100644
index 00000000000..925d3f5a382
--- /dev/null
+++ b/arch/i386/boot/video.S
@@ -0,0 +1,2007 @@
1/* video.S
2 *
3 * Display adapter & video mode setup, version 2.13 (14-May-99)
4 *
5 * Copyright (C) 1995 -- 1998 Martin Mares <mj@ucw.cz>
6 * Based on the original setup.S code (C) Linus Torvalds and Mats Anderson
7 *
8 * Rewritten to use GNU 'as' by Chris Noe <stiker@northlink.com> May 1999
9 *
10 * For further information, look at Documentation/svga.txt.
11 *
12 */
13
14#include <linux/config.h> /* for CONFIG_VIDEO_* */
15
16/* Enable autodetection of SVGA adapters and modes. */
17#undef CONFIG_VIDEO_SVGA
18
19/* Enable autodetection of VESA modes */
20#define CONFIG_VIDEO_VESA
21
22/* Enable compacting of mode table */
23#define CONFIG_VIDEO_COMPACT
24
25/* Retain screen contents when switching modes */
26#define CONFIG_VIDEO_RETAIN
27
28/* Enable local mode list */
29#undef CONFIG_VIDEO_LOCAL
30
31/* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */
32#undef CONFIG_VIDEO_400_HACK
33
34/* Hack that lets you force specific BIOS mode ID and specific dimensions */
35#undef CONFIG_VIDEO_GFX_HACK
36#define VIDEO_GFX_BIOS_AX 0x4f02 /* 800x600 on ThinkPad */
37#define VIDEO_GFX_BIOS_BX 0x0102
38#define VIDEO_GFX_DUMMY_RESOLUTION 0x6425 /* 100x37 */
39
40/* This code uses an extended set of video mode numbers. These include:
41 * Aliases for standard modes
42 * NORMAL_VGA (-1)
43 * EXTENDED_VGA (-2)
44 * ASK_VGA (-3)
45 * Video modes numbered by menu position -- NOT RECOMMENDED because of lack
46 * of compatibility when extending the table. These are between 0x00 and 0xff.
47 */
48#define VIDEO_FIRST_MENU 0x0000
49
50/* Standard BIOS video modes (BIOS number + 0x0100) */
51#define VIDEO_FIRST_BIOS 0x0100
52
53/* VESA BIOS video modes (VESA number + 0x0200) */
54#define VIDEO_FIRST_VESA 0x0200
55
56/* Video7 special modes (BIOS number + 0x0900) */
57#define VIDEO_FIRST_V7 0x0900
58
59/* Special video modes */
60#define VIDEO_FIRST_SPECIAL 0x0f00
61#define VIDEO_80x25 0x0f00
62#define VIDEO_8POINT 0x0f01
63#define VIDEO_80x43 0x0f02
64#define VIDEO_80x28 0x0f03
65#define VIDEO_CURRENT_MODE 0x0f04
66#define VIDEO_80x30 0x0f05
67#define VIDEO_80x34 0x0f06
68#define VIDEO_80x60 0x0f07
69#define VIDEO_GFX_HACK 0x0f08
70#define VIDEO_LAST_SPECIAL 0x0f09
71
72/* Video modes given by resolution */
73#define VIDEO_FIRST_RESOLUTION 0x1000
74
75/* The "recalculate timings" flag */
76#define VIDEO_RECALC 0x8000
77
78/* Positions of various video parameters passed to the kernel */
79/* (see also include/linux/tty.h) */
80#define PARAM_CURSOR_POS 0x00
81#define PARAM_VIDEO_PAGE 0x04
82#define PARAM_VIDEO_MODE 0x06
83#define PARAM_VIDEO_COLS 0x07
84#define PARAM_VIDEO_EGA_BX 0x0a
85#define PARAM_VIDEO_LINES 0x0e
86#define PARAM_HAVE_VGA 0x0f
87#define PARAM_FONT_POINTS 0x10
88
89#define PARAM_LFB_WIDTH 0x12
90#define PARAM_LFB_HEIGHT 0x14
91#define PARAM_LFB_DEPTH 0x16
92#define PARAM_LFB_BASE 0x18
93#define PARAM_LFB_SIZE 0x1c
94#define PARAM_LFB_LINELENGTH 0x24
95#define PARAM_LFB_COLORS 0x26
96#define PARAM_VESAPM_SEG 0x2e
97#define PARAM_VESAPM_OFF 0x30
98#define PARAM_LFB_PAGES 0x32
99#define PARAM_VESA_ATTRIB 0x34
100
101/* Define DO_STORE according to CONFIG_VIDEO_RETAIN */
102#ifdef CONFIG_VIDEO_RETAIN
103#define DO_STORE call store_screen
104#else
105#define DO_STORE
106#endif /* CONFIG_VIDEO_RETAIN */
107
108# This is the main entry point called by setup.S
109# %ds *must* be pointing to the bootsector
110video: pushw %ds # We use different segments
111 pushw %ds # FS contains original DS
112 popw %fs
113 pushw %cs # DS is equal to CS
114 popw %ds
115 pushw %cs # ES is equal to CS
116 popw %es
117 xorw %ax, %ax
118 movw %ax, %gs # GS is zero
119 cld
120 call basic_detect # Basic adapter type testing (EGA/VGA/MDA/CGA)
121#ifdef CONFIG_VIDEO_SELECT
122 movw %fs:(0x01fa), %ax # User selected video mode
123 cmpw $ASK_VGA, %ax # Bring up the menu
124 jz vid2
125
126 call mode_set # Set the mode
127 jc vid1
128
129 leaw badmdt, %si # Invalid mode ID
130 call prtstr
131vid2: call mode_menu
132vid1:
133#ifdef CONFIG_VIDEO_RETAIN
134 call restore_screen # Restore screen contents
135#endif /* CONFIG_VIDEO_RETAIN */
136 call store_edid
137#endif /* CONFIG_VIDEO_SELECT */
138 call mode_params # Store mode parameters
139 popw %ds # Restore original DS
140 ret
141
142# Detect if we have CGA, MDA, EGA or VGA and pass it to the kernel.
143basic_detect:
144 movb $0, %fs:(PARAM_HAVE_VGA)
145 movb $0x12, %ah # Check EGA/VGA
146 movb $0x10, %bl
147 int $0x10
148 movw %bx, %fs:(PARAM_VIDEO_EGA_BX) # Identifies EGA to the kernel
149 cmpb $0x10, %bl # No, it's a CGA/MDA/HGA card.
150 je basret
151
152 incb adapter
153 movw $0x1a00, %ax # Check EGA or VGA?
154 int $0x10
155 cmpb $0x1a, %al # 1a means VGA...
156 jne basret # anything else is EGA.
157
158 incb %fs:(PARAM_HAVE_VGA) # We've detected a VGA
159 incb adapter
160basret: ret
161
162# Store the video mode parameters for later usage by the kernel.
163# This is done by asking the BIOS except for the rows/columns
164# parameters in the default 80x25 mode -- these are set directly,
165# because some very obscure BIOSes supply insane values.
166mode_params:
167#ifdef CONFIG_VIDEO_SELECT
168 cmpb $0, graphic_mode
169 jnz mopar_gr
170#endif
171 movb $0x03, %ah # Read cursor position
172 xorb %bh, %bh
173 int $0x10
174 movw %dx, %fs:(PARAM_CURSOR_POS)
175 movb $0x0f, %ah # Read page/mode/width
176 int $0x10
177 movw %bx, %fs:(PARAM_VIDEO_PAGE)
178 movw %ax, %fs:(PARAM_VIDEO_MODE) # Video mode and screen width
179 cmpb $0x7, %al # MDA/HGA => segment differs
180 jnz mopar0
181
182 movw $0xb000, video_segment
183mopar0: movw %gs:(0x485), %ax # Font size
184 movw %ax, %fs:(PARAM_FONT_POINTS) # (valid only on EGA/VGA)
185 movw force_size, %ax # Forced size?
186 orw %ax, %ax
187 jz mopar1
188
189 movb %ah, %fs:(PARAM_VIDEO_COLS)
190 movb %al, %fs:(PARAM_VIDEO_LINES)
191 ret
192
193mopar1: movb $25, %al
194 cmpb $0, adapter # If we are on CGA/MDA/HGA, the
195 jz mopar2 # screen must have 25 lines.
196
197 movb %gs:(0x484), %al # On EGA/VGA, use the EGA+ BIOS
198 incb %al # location of max lines.
199mopar2: movb %al, %fs:(PARAM_VIDEO_LINES)
200 ret
201
202#ifdef CONFIG_VIDEO_SELECT
203# Fetching of VESA frame buffer parameters
204mopar_gr:
205 leaw modelist+1024, %di
206 movb $0x23, %fs:(PARAM_HAVE_VGA)
207 movw 16(%di), %ax
208 movw %ax, %fs:(PARAM_LFB_LINELENGTH)
209 movw 18(%di), %ax
210 movw %ax, %fs:(PARAM_LFB_WIDTH)
211 movw 20(%di), %ax
212 movw %ax, %fs:(PARAM_LFB_HEIGHT)
213 movb 25(%di), %al
214 movb $0, %ah
215 movw %ax, %fs:(PARAM_LFB_DEPTH)
216 movb 29(%di), %al
217 movb $0, %ah
218 movw %ax, %fs:(PARAM_LFB_PAGES)
219 movl 40(%di), %eax
220 movl %eax, %fs:(PARAM_LFB_BASE)
221 movl 31(%di), %eax
222 movl %eax, %fs:(PARAM_LFB_COLORS)
223 movl 35(%di), %eax
224 movl %eax, %fs:(PARAM_LFB_COLORS+4)
225 movw 0(%di), %ax
226 movw %ax, %fs:(PARAM_VESA_ATTRIB)
227
228# get video mem size
229 leaw modelist+1024, %di
230 movw $0x4f00, %ax
231 int $0x10
232 xorl %eax, %eax
233 movw 18(%di), %ax
234 movl %eax, %fs:(PARAM_LFB_SIZE)
235
236# switching the DAC to 8-bit is for <= 8 bpp only
237 movw %fs:(PARAM_LFB_DEPTH), %ax
238 cmpw $8, %ax
239 jg dac_done
240
241# get DAC switching capability
242 xorl %eax, %eax
243 movb 10(%di), %al
244 testb $1, %al
245 jz dac_set
246
247# attempt to switch DAC to 8-bit
248 movw $0x4f08, %ax
249 movw $0x0800, %bx
250 int $0x10
251 cmpw $0x004f, %ax
252 jne dac_set
253 movb %bh, dac_size # store actual DAC size
254
255dac_set:
256# set color size to DAC size
257 movb dac_size, %al
258 movb %al, %fs:(PARAM_LFB_COLORS+0)
259 movb %al, %fs:(PARAM_LFB_COLORS+2)
260 movb %al, %fs:(PARAM_LFB_COLORS+4)
261 movb %al, %fs:(PARAM_LFB_COLORS+6)
262
263# set color offsets to 0
264 movb $0, %fs:(PARAM_LFB_COLORS+1)
265 movb $0, %fs:(PARAM_LFB_COLORS+3)
266 movb $0, %fs:(PARAM_LFB_COLORS+5)
267 movb $0, %fs:(PARAM_LFB_COLORS+7)
268
269dac_done:
270# get protected mode interface informations
271 movw $0x4f0a, %ax
272 xorw %bx, %bx
273 xorw %di, %di
274 int $0x10
275 cmp $0x004f, %ax
276 jnz no_pm
277
278 movw %es, %fs:(PARAM_VESAPM_SEG)
279 movw %di, %fs:(PARAM_VESAPM_OFF)
280no_pm: ret
281
282# The video mode menu
283mode_menu:
284 leaw keymsg, %si # "Return/Space/Timeout" message
285 call prtstr
286 call flush
287nokey: call getkt
288
289 cmpb $0x0d, %al # ENTER ?
290 je listm # yes - manual mode selection
291
292 cmpb $0x20, %al # SPACE ?
293 je defmd1 # no - repeat
294
295 call beep
296 jmp nokey
297
298defmd1: ret # No mode chosen? Default 80x25
299
300listm: call mode_table # List mode table
301listm0: leaw name_bann, %si # Print adapter name
302 call prtstr
303 movw card_name, %si
304 orw %si, %si
305 jnz an2
306
307 movb adapter, %al
308 leaw old_name, %si
309 orb %al, %al
310 jz an1
311
312 leaw ega_name, %si
313 decb %al
314 jz an1
315
316 leaw vga_name, %si
317 jmp an1
318
319an2: call prtstr
320 leaw svga_name, %si
321an1: call prtstr
322 leaw listhdr, %si # Table header
323 call prtstr
324 movb $0x30, %dl # DL holds mode number
325 leaw modelist, %si
326lm1: cmpw $ASK_VGA, (%si) # End?
327 jz lm2
328
329 movb %dl, %al # Menu selection number
330 call prtchr
331 call prtsp2
332 lodsw
333 call prthw # Mode ID
334 call prtsp2
335 movb 0x1(%si), %al
336 call prtdec # Rows
337 movb $0x78, %al # the letter 'x'
338 call prtchr
339 lodsw
340 call prtdec # Columns
341 movb $0x0d, %al # New line
342 call prtchr
343 movb $0x0a, %al
344 call prtchr
345 incb %dl # Next character
346 cmpb $0x3a, %dl
347 jnz lm1
348
349 movb $0x61, %dl
350 jmp lm1
351
352lm2: leaw prompt, %si # Mode prompt
353 call prtstr
354 leaw edit_buf, %di # Editor buffer
355lm3: call getkey
356 cmpb $0x0d, %al # Enter?
357 jz lment
358
359 cmpb $0x08, %al # Backspace?
360 jz lmbs
361
362 cmpb $0x20, %al # Printable?
363 jc lm3
364
365 cmpw $edit_buf+4, %di # Enough space?
366 jz lm3
367
368 stosb
369 call prtchr
370 jmp lm3
371
372lmbs: cmpw $edit_buf, %di # Backspace
373 jz lm3
374
375 decw %di
376 movb $0x08, %al
377 call prtchr
378 call prtspc
379 movb $0x08, %al
380 call prtchr
381 jmp lm3
382
383lment: movb $0, (%di)
384 leaw crlft, %si
385 call prtstr
386 leaw edit_buf, %si
387 cmpb $0, (%si) # Empty string = default mode
388 jz lmdef
389
390 cmpb $0, 1(%si) # One character = menu selection
391 jz mnusel
392
393 cmpw $0x6373, (%si) # "scan" => mode scanning
394 jnz lmhx
395
396 cmpw $0x6e61, 2(%si)
397 jz lmscan
398
399lmhx: xorw %bx, %bx # Else => mode ID in hex
400lmhex: lodsb
401 orb %al, %al
402 jz lmuse1
403
404 subb $0x30, %al
405 jc lmbad
406
407 cmpb $10, %al
408 jc lmhx1
409
410 subb $7, %al
411 andb $0xdf, %al
412 cmpb $10, %al
413 jc lmbad
414
415 cmpb $16, %al
416 jnc lmbad
417
418lmhx1: shlw $4, %bx
419 orb %al, %bl
420 jmp lmhex
421
422lmuse1: movw %bx, %ax
423 jmp lmuse
424
425mnusel: lodsb # Menu selection
426 xorb %ah, %ah
427 subb $0x30, %al
428 jc lmbad
429
430 cmpb $10, %al
431 jc lmuse
432
433 cmpb $0x61-0x30, %al
434 jc lmbad
435
436 subb $0x61-0x30-10, %al
437 cmpb $36, %al
438 jnc lmbad
439
440lmuse: call mode_set
441 jc lmdef
442
443lmbad: leaw unknt, %si
444 call prtstr
445 jmp lm2
446lmscan: cmpb $0, adapter # Scanning only on EGA/VGA
447 jz lmbad
448
449 movw $0, mt_end # Scanning of modes is
450 movb $1, scanning # done as new autodetection.
451 call mode_table
452 jmp listm0
453lmdef: ret
454
455# Additional parts of mode_set... (relative jumps, you know)
456setv7: # Video7 extended modes
457 DO_STORE
458 subb $VIDEO_FIRST_V7>>8, %bh
459 movw $0x6f05, %ax
460 int $0x10
461 stc
462 ret
463
464_setrec: jmp setrec # Ugly...
465_set_80x25: jmp set_80x25
466
467# Aliases for backward compatibility.
468setalias:
469 movw $VIDEO_80x25, %ax
470 incw %bx
471 jz mode_set
472
473 movb $VIDEO_8POINT-VIDEO_FIRST_SPECIAL, %al
474 incw %bx
475 jnz setbad # Fall-through!
476
477# Setting of user mode (AX=mode ID) => CF=success
478mode_set:
479 movw %ax, %fs:(0x01fa) # Store mode for use in acpi_wakeup.S
480 movw %ax, %bx
481 cmpb $0xff, %ah
482 jz setalias
483
484 testb $VIDEO_RECALC>>8, %ah
485 jnz _setrec
486
487 cmpb $VIDEO_FIRST_RESOLUTION>>8, %ah
488 jnc setres
489
490 cmpb $VIDEO_FIRST_SPECIAL>>8, %ah
491 jz setspc
492
493 cmpb $VIDEO_FIRST_V7>>8, %ah
494 jz setv7
495
496 cmpb $VIDEO_FIRST_VESA>>8, %ah
497 jnc check_vesa
498
499 orb %ah, %ah
500 jz setmenu
501
502 decb %ah
503 jz setbios
504
505setbad: clc
506 movb $0, do_restore # The screen needn't be restored
507 ret
508
509setvesa:
510 DO_STORE
511 subb $VIDEO_FIRST_VESA>>8, %bh
512 movw $0x4f02, %ax # VESA BIOS mode set call
513 int $0x10
514 cmpw $0x004f, %ax # AL=4f if implemented
515 jnz setbad # AH=0 if OK
516
517 stc
518 ret
519
520setbios:
521 DO_STORE
522 int $0x10 # Standard BIOS mode set call
523 pushw %bx
524 movb $0x0f, %ah # Check if really set
525 int $0x10
526 popw %bx
527 cmpb %bl, %al
528 jnz setbad
529
530 stc
531 ret
532
533setspc: xorb %bh, %bh # Set special mode
534 cmpb $VIDEO_LAST_SPECIAL-VIDEO_FIRST_SPECIAL, %bl
535 jnc setbad
536
537 addw %bx, %bx
538 jmp *spec_inits(%bx)
539
540setmenu:
541 orb %al, %al # 80x25 is an exception
542 jz _set_80x25
543
544 pushw %bx # Set mode chosen from menu
545 call mode_table # Build the mode table
546 popw %ax
547 shlw $2, %ax
548 addw %ax, %si
549 cmpw %di, %si
550 jnc setbad
551
552 movw (%si), %ax # Fetch mode ID
553_m_s: jmp mode_set
554
555setres: pushw %bx # Set mode chosen by resolution
556 call mode_table
557 popw %bx
558 xchgb %bl, %bh
559setr1: lodsw
560 cmpw $ASK_VGA, %ax # End of the list?
561 jz setbad
562
563 lodsw
564 cmpw %bx, %ax
565 jnz setr1
566
567 movw -4(%si), %ax # Fetch mode ID
568 jmp _m_s
569
570check_vesa:
571 leaw modelist+1024, %di
572 subb $VIDEO_FIRST_VESA>>8, %bh
573 movw %bx, %cx # Get mode information structure
574 movw $0x4f01, %ax
575 int $0x10
576 addb $VIDEO_FIRST_VESA>>8, %bh
577 cmpw $0x004f, %ax
578 jnz setbad
579
580 movb (%di), %al # Check capabilities.
581 andb $0x19, %al
582 cmpb $0x09, %al
583 jz setvesa # This is a text mode
584
585 movb (%di), %al # Check capabilities.
586 andb $0x99, %al
587 cmpb $0x99, %al
588 jnz _setbad # Doh! No linear frame buffer.
589
590 subb $VIDEO_FIRST_VESA>>8, %bh
591 orw $0x4000, %bx # Use linear frame buffer
592 movw $0x4f02, %ax # VESA BIOS mode set call
593 int $0x10
594 cmpw $0x004f, %ax # AL=4f if implemented
595 jnz _setbad # AH=0 if OK
596
597 movb $1, graphic_mode # flag graphic mode
598 movb $0, do_restore # no screen restore
599 stc
600 ret
601
602_setbad: jmp setbad # Ugly...
603
604# Recalculate vertical display end registers -- this fixes various
605# inconsistencies of extended modes on many adapters. Called when
606# the VIDEO_RECALC flag is set in the mode ID.
607
608setrec: subb $VIDEO_RECALC>>8, %ah # Set the base mode
609 call mode_set
610 jnc rct3
611
612 movw %gs:(0x485), %ax # Font size in pixels
613 movb %gs:(0x484), %bl # Number of rows
614 incb %bl
615 mulb %bl # Number of visible
616 decw %ax # scan lines - 1
617 movw $0x3d4, %dx
618 movw %ax, %bx
619 movb $0x12, %al # Lower 8 bits
620 movb %bl, %ah
621 outw %ax, %dx
622 movb $0x07, %al # Bits 8 and 9 in the overflow register
623 call inidx
624 xchgb %al, %ah
625 andb $0xbd, %ah
626 shrb %bh
627 jnc rct1
628 orb $0x02, %ah
629rct1: shrb %bh
630 jnc rct2
631 orb $0x40, %ah
632rct2: movb $0x07, %al
633 outw %ax, %dx
634 stc
635rct3: ret
636
637# Table of routines for setting of the special modes.
638spec_inits:
639 .word set_80x25
640 .word set_8pixel
641 .word set_80x43
642 .word set_80x28
643 .word set_current
644 .word set_80x30
645 .word set_80x34
646 .word set_80x60
647 .word set_gfx
648
649# Set the 80x25 mode. If already set, do nothing.
650set_80x25:
651 movw $0x5019, force_size # Override possibly broken BIOS
652use_80x25:
653#ifdef CONFIG_VIDEO_400_HACK
654 movw $0x1202, %ax # Force 400 scan lines
655 movb $0x30, %bl
656 int $0x10
657#else
658 movb $0x0f, %ah # Get current mode ID
659 int $0x10
660 cmpw $0x5007, %ax # Mode 7 (80x25 mono) is the only one available
661 jz st80 # on CGA/MDA/HGA and is also available on EGAM
662
663 cmpw $0x5003, %ax # Unknown mode, force 80x25 color
664 jnz force3
665
666st80: cmpb $0, adapter # CGA/MDA/HGA => mode 3/7 is always 80x25
667 jz set80
668
669 movb %gs:(0x0484), %al # This is EGA+ -- beware of 80x50 etc.
670 orb %al, %al # Some buggy BIOS'es set 0 rows
671 jz set80
672
673 cmpb $24, %al # It's hopefully correct
674 jz set80
675#endif /* CONFIG_VIDEO_400_HACK */
676force3: DO_STORE
677 movw $0x0003, %ax # Forced set
678 int $0x10
679set80: stc
680 ret
681
682# Set the 80x50/80x43 8-pixel mode. Simple BIOS calls.
683set_8pixel:
684 DO_STORE
685 call use_80x25 # The base is 80x25
686set_8pt:
687 movw $0x1112, %ax # Use 8x8 font
688 xorb %bl, %bl
689 int $0x10
690 movw $0x1200, %ax # Use alternate print screen
691 movb $0x20, %bl
692 int $0x10
693 movw $0x1201, %ax # Turn off cursor emulation
694 movb $0x34, %bl
695 int $0x10
696 movb $0x01, %ah # Define cursor scan lines 6-7
697 movw $0x0607, %cx
698 int $0x10
699set_current:
700 stc
701 ret
702
703# Set the 80x28 mode. This mode works on all VGA's, because it's a standard
704# 80x25 mode with 14-point fonts instead of 16-point.
705set_80x28:
706 DO_STORE
707 call use_80x25 # The base is 80x25
708set14: movw $0x1111, %ax # Use 9x14 font
709 xorb %bl, %bl
710 int $0x10
711 movb $0x01, %ah # Define cursor scan lines 11-12
712 movw $0x0b0c, %cx
713 int $0x10
714 stc
715 ret
716
717# Set the 80x43 mode. This mode is works on all VGA's.
718# It's a 350-scanline mode with 8-pixel font.
719set_80x43:
720 DO_STORE
721 movw $0x1201, %ax # Set 350 scans
722 movb $0x30, %bl
723 int $0x10
724 movw $0x0003, %ax # Reset video mode
725 int $0x10
726 jmp set_8pt # Use 8-pixel font
727
728# Set the 80x30 mode (all VGA's). 480 scanlines, 16-pixel font.
729set_80x30:
730 call use_80x25 # Start with real 80x25
731 DO_STORE
732 movw $0x3cc, %dx # Get CRTC port
733 inb %dx, %al
734 movb $0xd4, %dl
735 rorb %al # Mono or color?
736 jc set48a
737
738 movb $0xb4, %dl
739set48a: movw $0x0c11, %ax # Vertical sync end (also unlocks CR0-7)
740 call outidx
741 movw $0x0b06, %ax # Vertical total
742 call outidx
743 movw $0x3e07, %ax # (Vertical) overflow
744 call outidx
745 movw $0xea10, %ax # Vertical sync start
746 call outidx
747 movw $0xdf12, %ax # Vertical display end
748 call outidx
749 movw $0xe715, %ax # Vertical blank start
750 call outidx
751 movw $0x0416, %ax # Vertical blank end
752 call outidx
753 pushw %dx
754 movb $0xcc, %dl # Misc output register (read)
755 inb %dx, %al
756 movb $0xc2, %dl # (write)
757 andb $0x0d, %al # Preserve clock select bits and color bit
758 orb $0xe2, %al # Set correct sync polarity
759 outb %al, %dx
760 popw %dx
761 movw $0x501e, force_size
762 stc # That's all.
763 ret
764
765# Set the 80x34 mode (all VGA's). 480 scans, 14-pixel font.
766set_80x34:
767 call set_80x30 # Set 480 scans
768 call set14 # And 14-pt font
769 movw $0xdb12, %ax # VGA vertical display end
770 movw $0x5022, force_size
771setvde: call outidx
772 stc
773 ret
774
775# Set the 80x60 mode (all VGA's). 480 scans, 8-pixel font.
776set_80x60:
777 call set_80x30 # Set 480 scans
778 call set_8pt # And 8-pt font
779 movw $0xdf12, %ax # VGA vertical display end
780 movw $0x503c, force_size
781 jmp setvde
782
783# Special hack for ThinkPad graphics
784set_gfx:
785#ifdef CONFIG_VIDEO_GFX_HACK
786 movw $VIDEO_GFX_BIOS_AX, %ax
787 movw $VIDEO_GFX_BIOS_BX, %bx
788 int $0x10
789 movw $VIDEO_GFX_DUMMY_RESOLUTION, force_size
790 stc
791#endif
792 ret
793
794#ifdef CONFIG_VIDEO_RETAIN
795
796# Store screen contents to temporary buffer.
797store_screen:
798 cmpb $0, do_restore # Already stored?
799 jnz stsr
800
801 testb $CAN_USE_HEAP, loadflags # Have we space for storing?
802 jz stsr
803
804 pushw %ax
805 pushw %bx
806 pushw force_size # Don't force specific size
807 movw $0, force_size
808 call mode_params # Obtain params of current mode
809 popw force_size
810 movb %fs:(PARAM_VIDEO_LINES), %ah
811 movb %fs:(PARAM_VIDEO_COLS), %al
812 movw %ax, %bx # BX=dimensions
813 mulb %ah
814 movw %ax, %cx # CX=number of characters
815 addw %ax, %ax # Calculate image size
816 addw $modelist+1024+4, %ax
817 cmpw heap_end_ptr, %ax
818 jnc sts1 # Unfortunately, out of memory
819
820 movw %fs:(PARAM_CURSOR_POS), %ax # Store mode params
821 leaw modelist+1024, %di
822 stosw
823 movw %bx, %ax
824 stosw
825 pushw %ds # Store the screen
826 movw video_segment, %ds
827 xorw %si, %si
828 rep
829 movsw
830 popw %ds
831 incb do_restore # Screen will be restored later
832sts1: popw %bx
833 popw %ax
834stsr: ret
835
836# Restore screen contents from temporary buffer.
837restore_screen:
838 cmpb $0, do_restore # Has the screen been stored?
839 jz res1
840
841 call mode_params # Get parameters of current mode
842 movb %fs:(PARAM_VIDEO_LINES), %cl
843 movb %fs:(PARAM_VIDEO_COLS), %ch
844 leaw modelist+1024, %si # Screen buffer
845 lodsw # Set cursor position
846 movw %ax, %dx
847 cmpb %cl, %dh
848 jc res2
849
850 movb %cl, %dh
851 decb %dh
852res2: cmpb %ch, %dl
853 jc res3
854
855 movb %ch, %dl
856 decb %dl
857res3: movb $0x02, %ah
858 movb $0x00, %bh
859 int $0x10
860 lodsw # Display size
861 movb %ah, %dl # DL=number of lines
862 movb $0, %ah # BX=phys. length of orig. line
863 movw %ax, %bx
864 cmpb %cl, %dl # Too many?
865 jc res4
866
867 pushw %ax
868 movb %dl, %al
869 subb %cl, %al
870 mulb %bl
871 addw %ax, %si
872 addw %ax, %si
873 popw %ax
874 movb %cl, %dl
875res4: cmpb %ch, %al # Too wide?
876 jc res5
877
878 movb %ch, %al # AX=width of src. line
879res5: movb $0, %cl
880 xchgb %ch, %cl
881 movw %cx, %bp # BP=width of dest. line
882 pushw %es
883 movw video_segment, %es
884 xorw %di, %di # Move the data
885 addw %bx, %bx # Convert BX and BP to _bytes_
886 addw %bp, %bp
887res6: pushw %si
888 pushw %di
889 movw %ax, %cx
890 rep
891 movsw
892 popw %di
893 popw %si
894 addw %bp, %di
895 addw %bx, %si
896 decb %dl
897 jnz res6
898
899 popw %es # Done
900res1: ret
901#endif /* CONFIG_VIDEO_RETAIN */
902
903# Write to indexed VGA register (AL=index, AH=data, DX=index reg. port)
904outidx: outb %al, %dx
905 pushw %ax
906 movb %ah, %al
907 incw %dx
908 outb %al, %dx
909 decw %dx
910 popw %ax
911 ret
912
913# Build the table of video modes (stored after the setup.S code at the
914# `modelist' label. Each video mode record looks like:
915# .word MODE-ID (our special mode ID (see above))
916# .byte rows (number of rows)
917# .byte columns (number of columns)
918# Returns address of the end of the table in DI, the end is marked
919# with a ASK_VGA ID.
920mode_table:
921 movw mt_end, %di # Already filled?
922 orw %di, %di
923 jnz mtab1x
924
925 leaw modelist, %di # Store standard modes:
926 movl $VIDEO_80x25 + 0x50190000, %eax # The 80x25 mode (ALL)
927 stosl
928 movb adapter, %al # CGA/MDA/HGA -- no more modes
929 orb %al, %al
930 jz mtabe
931
932 decb %al
933 jnz mtabv
934
935 movl $VIDEO_8POINT + 0x502b0000, %eax # The 80x43 EGA mode
936 stosl
937 jmp mtabe
938
939mtab1x: jmp mtab1
940
941mtabv: leaw vga_modes, %si # All modes for std VGA
942 movw $vga_modes_end-vga_modes, %cx
943 rep # I'm unable to use movsw as I don't know how to store a half
944 movsb # of the expression above to cx without using explicit shr.
945
946 cmpb $0, scanning # Mode scan requested?
947 jz mscan1
948
949 call mode_scan
950mscan1:
951
952#ifdef CONFIG_VIDEO_LOCAL
953 call local_modes
954#endif /* CONFIG_VIDEO_LOCAL */
955
956#ifdef CONFIG_VIDEO_VESA
957 call vesa_modes # Detect VESA VGA modes
958#endif /* CONFIG_VIDEO_VESA */
959
960#ifdef CONFIG_VIDEO_SVGA
961 cmpb $0, scanning # Bypass when scanning
962 jnz mscan2
963
964 call svga_modes # Detect SVGA cards & modes
965mscan2:
966#endif /* CONFIG_VIDEO_SVGA */
967
968mtabe:
969
970#ifdef CONFIG_VIDEO_COMPACT
971 leaw modelist, %si
972 movw %di, %dx
973 movw %si, %di
974cmt1: cmpw %dx, %si # Scan all modes
975 jz cmt2
976
977 leaw modelist, %bx # Find in previous entries
978 movw 2(%si), %cx
979cmt3: cmpw %bx, %si
980 jz cmt4
981
982 cmpw 2(%bx), %cx # Found => don't copy this entry
983 jz cmt5
984
985 addw $4, %bx
986 jmp cmt3
987
988cmt4: movsl # Copy entry
989 jmp cmt1
990
991cmt5: addw $4, %si # Skip entry
992 jmp cmt1
993
994cmt2:
995#endif /* CONFIG_VIDEO_COMPACT */
996
997 movw $ASK_VGA, (%di) # End marker
998 movw %di, mt_end
999mtab1: leaw modelist, %si # SI=mode list, DI=list end
1000ret0: ret
1001
1002# Modes usable on all standard VGAs
1003vga_modes:
1004 .word VIDEO_8POINT
1005 .word 0x5032 # 80x50
1006 .word VIDEO_80x43
1007 .word 0x502b # 80x43
1008 .word VIDEO_80x28
1009 .word 0x501c # 80x28
1010 .word VIDEO_80x30
1011 .word 0x501e # 80x30
1012 .word VIDEO_80x34
1013 .word 0x5022 # 80x34
1014 .word VIDEO_80x60
1015 .word 0x503c # 80x60
1016#ifdef CONFIG_VIDEO_GFX_HACK
1017 .word VIDEO_GFX_HACK
1018 .word VIDEO_GFX_DUMMY_RESOLUTION
1019#endif
1020
1021vga_modes_end:
1022# Detect VESA modes.
1023
1024#ifdef CONFIG_VIDEO_VESA
1025vesa_modes:
1026 cmpb $2, adapter # VGA only
1027 jnz ret0
1028
1029 movw %di, %bp # BP=original mode table end
1030 addw $0x200, %di # Buffer space
1031 movw $0x4f00, %ax # VESA Get card info call
1032 int $0x10
1033 movw %bp, %di
1034 cmpw $0x004f, %ax # Successful?
1035 jnz ret0
1036
1037 cmpw $0x4556, 0x200(%di)
1038 jnz ret0
1039
1040 cmpw $0x4153, 0x202(%di)
1041 jnz ret0
1042
1043 movw $vesa_name, card_name # Set name to "VESA VGA"
1044 pushw %gs
1045 lgsw 0x20e(%di), %si # GS:SI=mode list
1046 movw $128, %cx # Iteration limit
1047vesa1:
1048# gas version 2.9.1, using BFD version 2.9.1.0.23 buggers the next inst.
1049# XXX: lodsw %gs:(%si), %ax # Get next mode in the list
1050 gs; lodsw
1051 cmpw $0xffff, %ax # End of the table?
1052 jz vesar
1053
1054 cmpw $0x0080, %ax # Check validity of mode ID
1055 jc vesa2
1056
1057 orb %ah, %ah # Valid IDs: 0x0000-0x007f/0x0100-0x07ff
1058 jz vesan # Certain BIOSes report 0x80-0xff!
1059
1060 cmpw $0x0800, %ax
1061 jnc vesae
1062
1063vesa2: pushw %cx
1064 movw %ax, %cx # Get mode information structure
1065 movw $0x4f01, %ax
1066 int $0x10
1067 movw %cx, %bx # BX=mode number
1068 addb $VIDEO_FIRST_VESA>>8, %bh
1069 popw %cx
1070 cmpw $0x004f, %ax
1071 jnz vesan # Don't report errors (buggy BIOSES)
1072
1073 movb (%di), %al # Check capabilities. We require
1074 andb $0x19, %al # a color text mode.
1075 cmpb $0x09, %al
1076 jnz vesan
1077
1078 cmpw $0xb800, 8(%di) # Standard video memory address required
1079 jnz vesan
1080
1081 testb $2, (%di) # Mode characteristics supplied?
1082 movw %bx, (%di) # Store mode number
1083 jz vesa3
1084
1085 xorw %dx, %dx
1086 movw 0x12(%di), %bx # Width
1087 orb %bh, %bh
1088 jnz vesan
1089
1090 movb %bl, 0x3(%di)
1091 movw 0x14(%di), %ax # Height
1092 orb %ah, %ah
1093 jnz vesan
1094
1095 movb %al, 2(%di)
1096 mulb %bl
1097 cmpw $8193, %ax # Small enough for Linux console driver?
1098 jnc vesan
1099
1100 jmp vesaok
1101
1102vesa3: subw $0x8108, %bx # This mode has no detailed info specified,
1103 jc vesan # so it must be a standard VESA mode.
1104
1105 cmpw $5, %bx
1106 jnc vesan
1107
1108 movw vesa_text_mode_table(%bx), %ax
1109 movw %ax, 2(%di)
1110vesaok: addw $4, %di # The mode is valid. Store it.
1111vesan: loop vesa1 # Next mode. Limit exceeded => error
1112vesae: leaw vesaer, %si
1113 call prtstr
1114 movw %bp, %di # Discard already found modes.
1115vesar: popw %gs
1116 ret
1117
1118# Dimensions of standard VESA text modes
1119vesa_text_mode_table:
1120 .byte 60, 80 # 0108
1121 .byte 25, 132 # 0109
1122 .byte 43, 132 # 010A
1123 .byte 50, 132 # 010B
1124 .byte 60, 132 # 010C
1125#endif /* CONFIG_VIDEO_VESA */
1126
1127# Scan for video modes. A bit dirty, but should work.
1128mode_scan:
1129 movw $0x0100, %cx # Start with mode 0
1130scm1: movb $0, %ah # Test the mode
1131 movb %cl, %al
1132 int $0x10
1133 movb $0x0f, %ah
1134 int $0x10
1135 cmpb %cl, %al
1136 jnz scm2 # Mode not set
1137
1138 movw $0x3c0, %dx # Test if it's a text mode
1139 movb $0x10, %al # Mode bits
1140 call inidx
1141 andb $0x03, %al
1142 jnz scm2
1143
1144 movb $0xce, %dl # Another set of mode bits
1145 movb $0x06, %al
1146 call inidx
1147 shrb %al
1148 jc scm2
1149
1150 movb $0xd4, %dl # Cursor location
1151 movb $0x0f, %al
1152 call inidx
1153 orb %al, %al
1154 jnz scm2
1155
1156 movw %cx, %ax # Ok, store the mode
1157 stosw
1158 movb %gs:(0x484), %al # Number of rows
1159 incb %al
1160 stosb
1161 movw %gs:(0x44a), %ax # Number of columns
1162 stosb
1163scm2: incb %cl
1164 jns scm1
1165
1166 movw $0x0003, %ax # Return back to mode 3
1167 int $0x10
1168 ret
1169
1170tstidx: outw %ax, %dx # OUT DX,AX and inidx
1171inidx: outb %al, %dx # Read from indexed VGA register
1172 incw %dx # AL=index, DX=index reg port -> AL=data
1173 inb %dx, %al
1174 decw %dx
1175 ret
1176
1177# Try to detect type of SVGA card and supply (usually approximate) video
1178# mode table for it.
1179
1180#ifdef CONFIG_VIDEO_SVGA
1181svga_modes:
1182 leaw svga_table, %si # Test all known SVGA adapters
1183dosvga: lodsw
1184 movw %ax, %bp # Default mode table
1185 orw %ax, %ax
1186 jz didsv1
1187
1188 lodsw # Pointer to test routine
1189 pushw %si
1190 pushw %di
1191 pushw %es
1192 movw $0xc000, %bx
1193 movw %bx, %es
1194 call *%ax # Call test routine
1195 popw %es
1196 popw %di
1197 popw %si
1198 orw %bp, %bp
1199 jz dosvga
1200
1201 movw %bp, %si # Found, copy the modes
1202 movb svga_prefix, %ah
1203cpsvga: lodsb
1204 orb %al, %al
1205 jz didsv
1206
1207 stosw
1208 movsw
1209 jmp cpsvga
1210
1211didsv: movw %si, card_name # Store pointer to card name
1212didsv1: ret
1213
1214# Table of all known SVGA cards. For each card, we store a pointer to
1215# a table of video modes supported by the card and a pointer to a routine
1216# used for testing of presence of the card. The video mode table is always
1217# followed by the name of the card or the chipset.
1218svga_table:
1219 .word ati_md, ati_test
1220 .word oak_md, oak_test
1221 .word paradise_md, paradise_test
1222 .word realtek_md, realtek_test
1223 .word s3_md, s3_test
1224 .word chips_md, chips_test
1225 .word video7_md, video7_test
1226 .word cirrus5_md, cirrus5_test
1227 .word cirrus6_md, cirrus6_test
1228 .word cirrus1_md, cirrus1_test
1229 .word ahead_md, ahead_test
1230 .word everex_md, everex_test
1231 .word genoa_md, genoa_test
1232 .word trident_md, trident_test
1233 .word tseng_md, tseng_test
1234 .word 0
1235
1236# Test routines and mode tables:
1237
1238# S3 - The test algorithm was taken from the SuperProbe package
1239# for XFree86 1.2.1. Report bugs to Christoph.Niemann@linux.org
1240s3_test:
1241 movw $0x0f35, %cx # we store some constants in cl/ch
1242 movw $0x03d4, %dx
1243 movb $0x38, %al
1244 call inidx
1245 movb %al, %bh # store current CRT-register 0x38
1246 movw $0x0038, %ax
1247 call outidx # disable writing to special regs
1248 movb %cl, %al # check whether we can write special reg 0x35
1249 call inidx
1250 movb %al, %bl # save the current value of CRT reg 0x35
1251 andb $0xf0, %al # clear bits 0-3
1252 movb %al, %ah
1253 movb %cl, %al # and write it to CRT reg 0x35
1254 call outidx
1255 call inidx # now read it back
1256 andb %ch, %al # clear the upper 4 bits
1257 jz s3_2 # the first test failed. But we have a
1258
1259 movb %bl, %ah # second chance
1260 movb %cl, %al
1261 call outidx
1262 jmp s3_1 # do the other tests
1263
1264s3_2: movw %cx, %ax # load ah with 0xf and al with 0x35
1265 orb %bl, %ah # set the upper 4 bits of ah with the orig value
1266 call outidx # write ...
1267 call inidx # ... and reread
1268 andb %cl, %al # turn off the upper 4 bits
1269 pushw %ax
1270 movb %bl, %ah # restore old value in register 0x35
1271 movb %cl, %al
1272 call outidx
1273 popw %ax
1274 cmpb %ch, %al # setting lower 4 bits was successful => bad
1275 je no_s3 # writing is allowed => this is not an S3
1276
1277s3_1: movw $0x4838, %ax # allow writing to special regs by putting
1278 call outidx # magic number into CRT-register 0x38
1279 movb %cl, %al # check whether we can write special reg 0x35
1280 call inidx
1281 movb %al, %bl
1282 andb $0xf0, %al
1283 movb %al, %ah
1284 movb %cl, %al
1285 call outidx
1286 call inidx
1287 andb %ch, %al
1288 jnz no_s3 # no, we can't write => no S3
1289
1290 movw %cx, %ax
1291 orb %bl, %ah
1292 call outidx
1293 call inidx
1294 andb %ch, %al
1295 pushw %ax
1296 movb %bl, %ah # restore old value in register 0x35
1297 movb %cl, %al
1298 call outidx
1299 popw %ax
1300 cmpb %ch, %al
1301 jne no_s31 # writing not possible => no S3
1302 movb $0x30, %al
1303 call inidx # now get the S3 id ...
1304 leaw idS3, %di
1305 movw $0x10, %cx
1306 repne
1307 scasb
1308 je no_s31
1309
1310 movb %bh, %ah
1311 movb $0x38, %al
1312 jmp s3rest
1313
1314no_s3: movb $0x35, %al # restore CRT register 0x35
1315 movb %bl, %ah
1316 call outidx
1317no_s31: xorw %bp, %bp # Detection failed
1318s3rest: movb %bh, %ah
1319 movb $0x38, %al # restore old value of CRT register 0x38
1320 jmp outidx
1321
1322idS3: .byte 0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95
1323 .byte 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0
1324
1325s3_md: .byte 0x54, 0x2b, 0x84
1326 .byte 0x55, 0x19, 0x84
1327 .byte 0
1328 .ascii "S3"
1329 .byte 0
1330
1331# ATI cards.
1332ati_test:
1333 leaw idati, %si
1334 movw $0x31, %di
1335 movw $0x09, %cx
1336 repe
1337 cmpsb
1338 je atiok
1339
1340 xorw %bp, %bp
1341atiok: ret
1342
1343idati: .ascii "761295520"
1344
1345ati_md: .byte 0x23, 0x19, 0x84
1346 .byte 0x33, 0x2c, 0x84
1347 .byte 0x22, 0x1e, 0x64
1348 .byte 0x21, 0x19, 0x64
1349 .byte 0x58, 0x21, 0x50
1350 .byte 0x5b, 0x1e, 0x50
1351 .byte 0
1352 .ascii "ATI"
1353 .byte 0
1354
1355# AHEAD
1356ahead_test:
1357 movw $0x200f, %ax
1358 movw $0x3ce, %dx
1359 outw %ax, %dx
1360 incw %dx
1361 inb %dx, %al
1362 cmpb $0x20, %al
1363 je isahed
1364
1365 cmpb $0x21, %al
1366 je isahed
1367
1368 xorw %bp, %bp
1369isahed: ret
1370
1371ahead_md:
1372 .byte 0x22, 0x2c, 0x84
1373 .byte 0x23, 0x19, 0x84
1374 .byte 0x24, 0x1c, 0x84
1375 .byte 0x2f, 0x32, 0xa0
1376 .byte 0x32, 0x22, 0x50
1377 .byte 0x34, 0x42, 0x50
1378 .byte 0
1379 .ascii "Ahead"
1380 .byte 0
1381
1382# Chips & Tech.
1383chips_test:
1384 movw $0x3c3, %dx
1385 inb %dx, %al
1386 orb $0x10, %al
1387 outb %al, %dx
1388 movw $0x104, %dx
1389 inb %dx, %al
1390 movb %al, %bl
1391 movw $0x3c3, %dx
1392 inb %dx, %al
1393 andb $0xef, %al
1394 outb %al, %dx
1395 cmpb $0xa5, %bl
1396 je cantok
1397
1398 xorw %bp, %bp
1399cantok: ret
1400
1401chips_md:
1402 .byte 0x60, 0x19, 0x84
1403 .byte 0x61, 0x32, 0x84
1404 .byte 0
1405 .ascii "Chips & Technologies"
1406 .byte 0
1407
1408# Cirrus Logic 5X0
1409cirrus1_test:
1410 movw $0x3d4, %dx
1411 movb $0x0c, %al
1412 outb %al, %dx
1413 incw %dx
1414 inb %dx, %al
1415 movb %al, %bl
1416 xorb %al, %al
1417 outb %al, %dx
1418 decw %dx
1419 movb $0x1f, %al
1420 outb %al, %dx
1421 incw %dx
1422 inb %dx, %al
1423 movb %al, %bh
1424 xorb %ah, %ah
1425 shlb $4, %al
1426 movw %ax, %cx
1427 movb %bh, %al
1428 shrb $4, %al
1429 addw %ax, %cx
1430 shlw $8, %cx
1431 addw $6, %cx
1432 movw %cx, %ax
1433 movw $0x3c4, %dx
1434 outw %ax, %dx
1435 incw %dx
1436 inb %dx, %al
1437 andb %al, %al
1438 jnz nocirr
1439
1440 movb %bh, %al
1441 outb %al, %dx
1442 inb %dx, %al
1443 cmpb $0x01, %al
1444 je iscirr
1445
1446nocirr: xorw %bp, %bp
1447iscirr: movw $0x3d4, %dx
1448 movb %bl, %al
1449 xorb %ah, %ah
1450 shlw $8, %ax
1451 addw $0x0c, %ax
1452 outw %ax, %dx
1453 ret
1454
1455cirrus1_md:
1456 .byte 0x1f, 0x19, 0x84
1457 .byte 0x20, 0x2c, 0x84
1458 .byte 0x22, 0x1e, 0x84
1459 .byte 0x31, 0x25, 0x64
1460 .byte 0
1461 .ascii "Cirrus Logic 5X0"
1462 .byte 0
1463
1464# Cirrus Logic 54XX
1465cirrus5_test:
1466 movw $0x3c4, %dx
1467 movb $6, %al
1468 call inidx
1469 movb %al, %bl # BL=backup
1470 movw $6, %ax
1471 call tstidx
1472 cmpb $0x0f, %al
1473 jne c5fail
1474
1475 movw $0x1206, %ax
1476 call tstidx
1477 cmpb $0x12, %al
1478 jne c5fail
1479
1480 movb $0x1e, %al
1481 call inidx
1482 movb %al, %bh
1483 movb %bh, %ah
1484 andb $0xc0, %ah
1485 movb $0x1e, %al
1486 call tstidx
1487 andb $0x3f, %al
1488 jne c5xx
1489
1490 movb $0x1e, %al
1491 movb %bh, %ah
1492 orb $0x3f, %ah
1493 call tstidx
1494 xorb $0x3f, %al
1495 andb $0x3f, %al
1496c5xx: pushf
1497 movb $0x1e, %al
1498 movb %bh, %ah
1499 outw %ax, %dx
1500 popf
1501 je c5done
1502
1503c5fail: xorw %bp, %bp
1504c5done: movb $6, %al
1505 movb %bl, %ah
1506 outw %ax, %dx
1507 ret
1508
1509cirrus5_md:
1510 .byte 0x14, 0x19, 0x84
1511 .byte 0x54, 0x2b, 0x84
1512 .byte 0
1513 .ascii "Cirrus Logic 54XX"
1514 .byte 0
1515
1516# Cirrus Logic 64XX -- no known extra modes, but must be identified, because
1517# it's misidentified by the Ahead test.
1518cirrus6_test:
1519 movw $0x3ce, %dx
1520 movb $0x0a, %al
1521 call inidx
1522 movb %al, %bl # BL=backup
1523 movw $0xce0a, %ax
1524 call tstidx
1525 orb %al, %al
1526 jne c2fail
1527
1528 movw $0xec0a, %ax
1529 call tstidx
1530 cmpb $0x01, %al
1531 jne c2fail
1532
1533 movb $0xaa, %al
1534 call inidx # 4X, 5X, 7X and 8X are valid 64XX chip ID's.
1535 shrb $4, %al
1536 subb $4, %al
1537 jz c6done
1538
1539 decb %al
1540 jz c6done
1541
1542 subb $2, %al
1543 jz c6done
1544
1545 decb %al
1546 jz c6done
1547
1548c2fail: xorw %bp, %bp
1549c6done: movb $0x0a, %al
1550 movb %bl, %ah
1551 outw %ax, %dx
1552 ret
1553
1554cirrus6_md:
1555 .byte 0
1556 .ascii "Cirrus Logic 64XX"
1557 .byte 0
1558
1559# Everex / Trident
1560everex_test:
1561 movw $0x7000, %ax
1562 xorw %bx, %bx
1563 int $0x10
1564 cmpb $0x70, %al
1565 jne noevrx
1566
1567 shrw $4, %dx
1568 cmpw $0x678, %dx
1569 je evtrid
1570
1571 cmpw $0x236, %dx
1572 jne evrxok
1573
1574evtrid: leaw trident_md, %bp
1575evrxok: ret
1576
1577noevrx: xorw %bp, %bp
1578 ret
1579
1580everex_md:
1581 .byte 0x03, 0x22, 0x50
1582 .byte 0x04, 0x3c, 0x50
1583 .byte 0x07, 0x2b, 0x64
1584 .byte 0x08, 0x4b, 0x64
1585 .byte 0x0a, 0x19, 0x84
1586 .byte 0x0b, 0x2c, 0x84
1587 .byte 0x16, 0x1e, 0x50
1588 .byte 0x18, 0x1b, 0x64
1589 .byte 0x21, 0x40, 0xa0
1590 .byte 0x40, 0x1e, 0x84
1591 .byte 0
1592 .ascii "Everex/Trident"
1593 .byte 0
1594
1595# Genoa.
1596genoa_test:
1597 leaw idgenoa, %si # Check Genoa 'clues'
1598 xorw %ax, %ax
1599 movb %es:(0x37), %al
1600 movw %ax, %di
1601 movw $0x04, %cx
1602 decw %si
1603 decw %di
1604l1: incw %si
1605 incw %di
1606 movb (%si), %al
1607 testb %al, %al
1608 jz l2
1609
1610 cmpb %es:(%di), %al
1611l2: loope l1
1612 orw %cx, %cx
1613 je isgen
1614
1615 xorw %bp, %bp
1616isgen: ret
1617
1618idgenoa: .byte 0x77, 0x00, 0x99, 0x66
1619
1620genoa_md:
1621 .byte 0x58, 0x20, 0x50
1622 .byte 0x5a, 0x2a, 0x64
1623 .byte 0x60, 0x19, 0x84
1624 .byte 0x61, 0x1d, 0x84
1625 .byte 0x62, 0x20, 0x84
1626 .byte 0x63, 0x2c, 0x84
1627 .byte 0x64, 0x3c, 0x84
1628 .byte 0x6b, 0x4f, 0x64
1629 .byte 0x72, 0x3c, 0x50
1630 .byte 0x74, 0x42, 0x50
1631 .byte 0x78, 0x4b, 0x64
1632 .byte 0
1633 .ascii "Genoa"
1634 .byte 0
1635
1636# OAK
1637oak_test:
1638 leaw idoakvga, %si
1639 movw $0x08, %di
1640 movw $0x08, %cx
1641 repe
1642 cmpsb
1643 je isoak
1644
1645 xorw %bp, %bp
1646isoak: ret
1647
1648idoakvga: .ascii "OAK VGA "
1649
1650oak_md: .byte 0x4e, 0x3c, 0x50
1651 .byte 0x4f, 0x3c, 0x84
1652 .byte 0x50, 0x19, 0x84
1653 .byte 0x51, 0x2b, 0x84
1654 .byte 0
1655 .ascii "OAK"
1656 .byte 0
1657
1658# WD Paradise.
1659paradise_test:
1660 leaw idparadise, %si
1661 movw $0x7d, %di
1662 movw $0x04, %cx
1663 repe
1664 cmpsb
1665 je ispara
1666
1667 xorw %bp, %bp
1668ispara: ret
1669
1670idparadise: .ascii "VGA="
1671
1672paradise_md:
1673 .byte 0x41, 0x22, 0x50
1674 .byte 0x47, 0x1c, 0x84
1675 .byte 0x55, 0x19, 0x84
1676 .byte 0x54, 0x2c, 0x84
1677 .byte 0
1678 .ascii "Paradise"
1679 .byte 0
1680
1681# Trident.
1682trident_test:
1683 movw $0x3c4, %dx
1684 movb $0x0e, %al
1685 outb %al, %dx
1686 incw %dx
1687 inb %dx, %al
1688 xchgb %al, %ah
1689 xorb %al, %al
1690 outb %al, %dx
1691 inb %dx, %al
1692 xchgb %ah, %al
1693 movb %al, %bl # Strange thing ... in the book this wasn't
1694 andb $0x02, %bl # necessary but it worked on my card which
1695 jz setb2 # is a trident. Without it the screen goes
1696 # blurred ...
1697 andb $0xfd, %al
1698 jmp clrb2
1699
1700setb2: orb $0x02, %al
1701clrb2: outb %al, %dx
1702 andb $0x0f, %ah
1703 cmpb $0x02, %ah
1704 je istrid
1705
1706 xorw %bp, %bp
1707istrid: ret
1708
1709trident_md:
1710 .byte 0x50, 0x1e, 0x50
1711 .byte 0x51, 0x2b, 0x50
1712 .byte 0x52, 0x3c, 0x50
1713 .byte 0x57, 0x19, 0x84
1714 .byte 0x58, 0x1e, 0x84
1715 .byte 0x59, 0x2b, 0x84
1716 .byte 0x5a, 0x3c, 0x84
1717 .byte 0
1718 .ascii "Trident"
1719 .byte 0
1720
1721# Tseng.
1722tseng_test:
1723 movw $0x3cd, %dx
1724 inb %dx, %al # Could things be this simple ! :-)
1725 movb %al, %bl
1726 movb $0x55, %al
1727 outb %al, %dx
1728 inb %dx, %al
1729 movb %al, %ah
1730 movb %bl, %al
1731 outb %al, %dx
1732 cmpb $0x55, %ah
1733 je istsen
1734
1735isnot: xorw %bp, %bp
1736istsen: ret
1737
1738tseng_md:
1739 .byte 0x26, 0x3c, 0x50
1740 .byte 0x2a, 0x28, 0x64
1741 .byte 0x23, 0x19, 0x84
1742 .byte 0x24, 0x1c, 0x84
1743 .byte 0x22, 0x2c, 0x84
1744 .byte 0x21, 0x3c, 0x84
1745 .byte 0
1746 .ascii "Tseng"
1747 .byte 0
1748
1749# Video7.
1750video7_test:
1751 movw $0x3cc, %dx
1752 inb %dx, %al
1753 movw $0x3b4, %dx
1754 andb $0x01, %al
1755 jz even7
1756
1757 movw $0x3d4, %dx
1758even7: movb $0x0c, %al
1759 outb %al, %dx
1760 incw %dx
1761 inb %dx, %al
1762 movb %al, %bl
1763 movb $0x55, %al
1764 outb %al, %dx
1765 inb %dx, %al
1766 decw %dx
1767 movb $0x1f, %al
1768 outb %al, %dx
1769 incw %dx
1770 inb %dx, %al
1771 movb %al, %bh
1772 decw %dx
1773 movb $0x0c, %al
1774 outb %al, %dx
1775 incw %dx
1776 movb %bl, %al
1777 outb %al, %dx
1778 movb $0x55, %al
1779 xorb $0xea, %al
1780 cmpb %bh, %al
1781 jne isnot
1782
1783 movb $VIDEO_FIRST_V7>>8, svga_prefix # Use special mode switching
1784 ret
1785
1786video7_md:
1787 .byte 0x40, 0x2b, 0x50
1788 .byte 0x43, 0x3c, 0x50
1789 .byte 0x44, 0x3c, 0x64
1790 .byte 0x41, 0x19, 0x84
1791 .byte 0x42, 0x2c, 0x84
1792 .byte 0x45, 0x1c, 0x84
1793 .byte 0
1794 .ascii "Video 7"
1795 .byte 0
1796
1797# Realtek VGA
1798realtek_test:
1799 leaw idrtvga, %si
1800 movw $0x45, %di
1801 movw $0x0b, %cx
1802 repe
1803 cmpsb
1804 je isrt
1805
1806 xorw %bp, %bp
1807isrt: ret
1808
1809idrtvga: .ascii "REALTEK VGA"
1810
1811realtek_md:
1812 .byte 0x1a, 0x3c, 0x50
1813 .byte 0x1b, 0x19, 0x84
1814 .byte 0x1c, 0x1e, 0x84
1815 .byte 0x1d, 0x2b, 0x84
1816 .byte 0x1e, 0x3c, 0x84
1817 .byte 0
1818 .ascii "REALTEK"
1819 .byte 0
1820
1821#endif /* CONFIG_VIDEO_SVGA */
1822
1823# User-defined local mode table (VGA only)
1824#ifdef CONFIG_VIDEO_LOCAL
1825local_modes:
1826 leaw local_mode_table, %si
1827locm1: lodsw
1828 orw %ax, %ax
1829 jz locm2
1830
1831 stosw
1832 movsw
1833 jmp locm1
1834
1835locm2: ret
1836
1837# This is the table of local video modes which can be supplied manually
1838# by the user. Each entry consists of mode ID (word) and dimensions
1839# (byte for column count and another byte for row count). These modes
1840# are placed before all SVGA and VESA modes and override them if table
1841# compacting is enabled. The table must end with a zero word followed
1842# by NUL-terminated video adapter name.
1843local_mode_table:
1844 .word 0x0100 # Example: 40x25
1845 .byte 25,40
1846 .word 0
1847 .ascii "Local"
1848 .byte 0
1849#endif /* CONFIG_VIDEO_LOCAL */
1850
1851# Read a key and return the ASCII code in al, scan code in ah
1852getkey: xorb %ah, %ah
1853 int $0x16
1854 ret
1855
1856# Read a key with a timeout of 30 seconds.
1857# The hardware clock is used to get the time.
1858getkt: call gettime
1859 addb $30, %al # Wait 30 seconds
1860 cmpb $60, %al
1861 jl lminute
1862
1863 subb $60, %al
1864lminute:
1865 movb %al, %cl
1866again: movb $0x01, %ah
1867 int $0x16
1868 jnz getkey # key pressed, so get it
1869
1870 call gettime
1871 cmpb %cl, %al
1872 jne again
1873
1874 movb $0x20, %al # timeout, return `space'
1875 ret
1876
1877# Flush the keyboard buffer
1878flush: movb $0x01, %ah
1879 int $0x16
1880 jz empty
1881
1882 xorb %ah, %ah
1883 int $0x16
1884 jmp flush
1885
1886empty: ret
1887
1888# Print hexadecimal number.
1889prthw: pushw %ax
1890 movb %ah, %al
1891 call prthb
1892 popw %ax
1893prthb: pushw %ax
1894 shrb $4, %al
1895 call prthn
1896 popw %ax
1897 andb $0x0f, %al
1898prthn: cmpb $0x0a, %al
1899 jc prth1
1900
1901 addb $0x07, %al
1902prth1: addb $0x30, %al
1903 jmp prtchr
1904
1905# Print decimal number in al
1906prtdec: pushw %ax
1907 pushw %cx
1908 xorb %ah, %ah
1909 movb $0x0a, %cl
1910 idivb %cl
1911 cmpb $0x09, %al
1912 jbe lt100
1913
1914 call prtdec
1915 jmp skip10
1916
1917lt100: addb $0x30, %al
1918 call prtchr
1919skip10: movb %ah, %al
1920 addb $0x30, %al
1921 call prtchr
1922 popw %cx
1923 popw %ax
1924 ret
1925
1926store_edid:
1927 pushw %es # just save all registers
1928 pushw %ax
1929 pushw %bx
1930 pushw %cx
1931 pushw %dx
1932 pushw %di
1933
1934 pushw %fs
1935 popw %es
1936
1937 movl $0x13131313, %eax # memset block with 0x13
1938 movw $32, %cx
1939 movw $0x140, %di
1940 cld
1941 rep
1942 stosl
1943
1944 movw $0x4f15, %ax # do VBE/DDC
1945 movw $0x01, %bx
1946 movw $0x00, %cx
1947 movw $0x01, %dx
1948 movw $0x140, %di
1949 int $0x10
1950
1951 popw %di # restore all registers
1952 popw %dx
1953 popw %cx
1954 popw %bx
1955 popw %ax
1956 popw %es
1957 ret
1958
1959# VIDEO_SELECT-only variables
1960mt_end: .word 0 # End of video mode table if built
1961edit_buf: .space 6 # Line editor buffer
1962card_name: .word 0 # Pointer to adapter name
1963scanning: .byte 0 # Performing mode scan
1964do_restore: .byte 0 # Screen contents altered during mode change
1965svga_prefix: .byte VIDEO_FIRST_BIOS>>8 # Default prefix for BIOS modes
1966graphic_mode: .byte 0 # Graphic mode with a linear frame buffer
1967dac_size: .byte 6 # DAC bit depth
1968
1969# Status messages
1970keymsg: .ascii "Press <RETURN> to see video modes available, "
1971 .ascii "<SPACE> to continue or wait 30 secs"
1972 .byte 0x0d, 0x0a, 0
1973
1974listhdr: .byte 0x0d, 0x0a
1975 .ascii "Mode: COLSxROWS:"
1976
1977crlft: .byte 0x0d, 0x0a, 0
1978
1979prompt: .byte 0x0d, 0x0a
1980 .asciz "Enter mode number or `scan': "
1981
1982unknt: .asciz "Unknown mode ID. Try again."
1983
1984badmdt: .ascii "You passed an undefined mode number."
1985 .byte 0x0d, 0x0a, 0
1986
1987vesaer: .ascii "Error: Scanning of VESA modes failed. Please "
1988 .ascii "report to <mj@ucw.cz>."
1989 .byte 0x0d, 0x0a, 0
1990
1991old_name: .asciz "CGA/MDA/HGA"
1992
1993ega_name: .asciz "EGA"
1994
1995svga_name: .ascii " "
1996
1997vga_name: .asciz "VGA"
1998
1999vesa_name: .asciz "VESA"
2000
2001name_bann: .asciz "Video adapter: "
2002#endif /* CONFIG_VIDEO_SELECT */
2003
2004# Other variables:
2005adapter: .byte 0 # Video adapter: 0=CGA/MDA/HGA,1=EGA,2=VGA
2006video_segment: .word 0xb800 # Video memory segment
2007force_size: .word 0 # Use this size instead of the one in BIOS vars