aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/boot
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64/boot')
-rw-r--r--arch/x86_64/boot/Makefile102
-rw-r--r--arch/x86_64/boot/bootsect.S98
-rw-r--r--arch/x86_64/boot/compressed/Makefile32
-rw-r--r--arch/x86_64/boot/compressed/head.S142
-rw-r--r--arch/x86_64/boot/compressed/misc.c354
-rw-r--r--arch/x86_64/boot/compressed/miscsetup.h39
-rw-r--r--arch/x86_64/boot/compressed/vmlinux.scr9
-rw-r--r--arch/x86_64/boot/install.sh40
-rw-r--r--arch/x86_64/boot/mtools.conf.in17
-rw-r--r--arch/x86_64/boot/setup.S867
-rw-r--r--arch/x86_64/boot/tools/build.c186
-rw-r--r--arch/x86_64/boot/video.S2007
12 files changed, 3893 insertions, 0 deletions
diff --git a/arch/x86_64/boot/Makefile b/arch/x86_64/boot/Makefile
new file mode 100644
index 000000000000..f4399c701b77
--- /dev/null
+++ b/arch/x86_64/boot/Makefile
@@ -0,0 +1,102 @@
1#
2# arch/x86_64/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 \
29 setup setup.o bzImage mtools.conf
30
31EXTRA_CFLAGS := -m32
32
33hostprogs-y := tools/build
34HOST_EXTRACFLAGS += $(LINUXINCLUDE)
35subdir- := compressed/ #Let make clean descend in compressed/
36# ---------------------------------------------------------------------------
37
38$(obj)/bzImage: IMAGE_OFFSET := 0x100000
39$(obj)/bzImage: EXTRA_AFLAGS := -traditional $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__
40$(obj)/bzImage: BUILDFLAGS := -b
41
42quiet_cmd_image = BUILD $@
43cmd_image = $(obj)/tools/build $(BUILDFLAGS) $(obj)/bootsect $(obj)/setup \
44 $(obj)/vmlinux.bin $(ROOT_DEV) > $@
45
46$(obj)/bzImage: $(obj)/bootsect $(obj)/setup \
47 $(obj)/vmlinux.bin $(obj)/tools/build FORCE
48 $(call if_changed,image)
49 @echo 'Kernel: $@ is ready'
50
51$(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
52 $(call if_changed,objcopy)
53
54LDFLAGS_bootsect := -Ttext 0x0 -s --oformat binary
55LDFLAGS_setup := -Ttext 0x0 -s --oformat binary -e begtext
56
57$(obj)/setup $(obj)/bootsect: %: %.o FORCE
58 $(call if_changed,ld)
59
60$(obj)/compressed/vmlinux: FORCE
61 $(Q)$(MAKE) $(build)=$(obj)/compressed IMAGE_OFFSET=$(IMAGE_OFFSET) $@
62
63# Set this if you want to pass append arguments to the zdisk/fdimage kernel
64FDARGS =
65
66$(obj)/mtools.conf: $(src)/mtools.conf.in
67 sed -e 's|@OBJ@|$(obj)|g' < $< > $@
68
69# This requires write access to /dev/fd0
70zdisk: $(BOOTIMAGE) $(obj)/mtools.conf
71 MTOOLSRC=$(obj)/mtools.conf mformat a: ; sync
72 syslinux /dev/fd0 ; sync
73 echo 'default linux $(FDARGS)' | \
74 MTOOLSRC=$(obj)/mtools.conf mcopy - a:syslinux.cfg
75 MTOOLSRC=$(obj)/mtools.conf mcopy $(BOOTIMAGE) a:linux ; sync
76
77# These require being root or having syslinux 2.02 or higher installed
78fdimage fdimage144: $(BOOTIMAGE) $(obj)/mtools.conf
79 dd if=/dev/zero of=$(obj)/fdimage bs=1024 count=1440
80 MTOOLSRC=$(obj)/mtools.conf mformat v: ; sync
81 syslinux $(obj)/fdimage ; sync
82 echo 'default linux $(FDARGS)' | \
83 MTOOLSRC=$(obj)/mtools.conf mcopy - v:syslinux.cfg
84 MTOOLSRC=$(obj)/mtools.conf mcopy $(BOOTIMAGE) v:linux ; sync
85
86fdimage288: $(BOOTIMAGE) $(obj)/mtools.conf
87 dd if=/dev/zero of=$(obj)/fdimage bs=1024 count=2880
88 MTOOLSRC=$(obj)/mtools.conf mformat w: ; sync
89 syslinux $(obj)/fdimage ; sync
90 echo 'default linux $(FDARGS)' | \
91 MTOOLSRC=$(obj)/mtools.conf mcopy - w:syslinux.cfg
92 MTOOLSRC=$(obj)/mtools.conf mcopy $(BOOTIMAGE) w:linux ; sync
93
94zlilo: $(BOOTIMAGE)
95 if [ -f $(INSTALL_PATH)/vmlinuz ]; then mv $(INSTALL_PATH)/vmlinuz $(INSTALL_PATH)/vmlinuz.old; fi
96 if [ -f $(INSTALL_PATH)/System.map ]; then mv $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
97 cat $(BOOTIMAGE) > $(INSTALL_PATH)/vmlinuz
98 cp System.map $(INSTALL_PATH)/
99 if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
100
101install: $(BOOTIMAGE)
102 sh $(srctree)/$(src)/install.sh $(KERNELRELEASE) $(BOOTIMAGE) System.map "$(INSTALL_PATH)"
diff --git a/arch/x86_64/boot/bootsect.S b/arch/x86_64/boot/bootsect.S
new file mode 100644
index 000000000000..bb15d406ee95
--- /dev/null
+++ b/arch/x86_64/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/x86_64/boot/compressed/Makefile b/arch/x86_64/boot/compressed/Makefile
new file mode 100644
index 000000000000..f89d96f11a9f
--- /dev/null
+++ b/arch/x86_64/boot/compressed/Makefile
@@ -0,0 +1,32 @@
1#
2# linux/arch/x86_64/boot/compressed/Makefile
3#
4# create a compressed vmlinux image from the original vmlinux
5#
6# Note all the files here are compiled/linked as 32bit executables.
7#
8
9targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o
10EXTRA_AFLAGS := -traditional -m32
11
12# cannot use EXTRA_CFLAGS because base CFLAGS contains -mkernel which conflicts with
13# -m32
14CFLAGS := -m32 -D__KERNEL__ -Iinclude -O2 -fno-strict-aliasing
15LDFLAGS := -m elf_i386
16
17LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup_32 -m elf_i386
18
19$(obj)/vmlinux: $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE
20 $(call if_changed,ld)
21 @:
22
23$(obj)/vmlinux.bin: vmlinux FORCE
24 $(call if_changed,objcopy)
25
26$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
27 $(call if_changed,gzip)
28
29LDFLAGS_piggy.o := -r --format binary --oformat elf32-i386 -T
30
31$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE
32 $(call if_changed,ld)
diff --git a/arch/x86_64/boot/compressed/head.S b/arch/x86_64/boot/compressed/head.S
new file mode 100644
index 000000000000..27264dbd575c
--- /dev/null
+++ b/arch/x86_64/boot/compressed/head.S
@@ -0,0 +1,142 @@
1/*
2 * linux/boot/head.S
3 *
4 * Copyright (C) 1991, 1992, 1993 Linus Torvalds
5 *
6 * $Id: head.S,v 1.3 2001/04/20 00:59:28 ak Exp $
7 */
8
9/*
10 * head.S contains the 32-bit startup code.
11 *
12 * NOTE!!! Startup happens at absolute address 0x00001000, which is also where
13 * the page directory will exist. The startup code will be overwritten by
14 * the page directory. [According to comments etc elsewhere on a compressed
15 * kernel it will end up at 0x1000 + 1Mb I hope so as I assume this. - AC]
16 *
17 * Page 0 is deliberately kept safe, since System Management Mode code in
18 * laptops may need to access the BIOS data stored there. This is also
19 * useful for future device drivers that either access the BIOS via VM86
20 * mode.
21 */
22
23/*
24 * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
25 */
26.code32
27.text
28
29#include <linux/linkage.h>
30#include <asm/segment.h>
31
32 .code32
33 .globl startup_32
34
35startup_32:
36 cld
37 cli
38 movl $(__KERNEL_DS),%eax
39 movl %eax,%ds
40 movl %eax,%es
41 movl %eax,%fs
42 movl %eax,%gs
43
44 lss stack_start,%esp
45 xorl %eax,%eax
461: incl %eax # check that A20 really IS enabled
47 movl %eax,0x000000 # loop forever if it isn't
48 cmpl %eax,0x100000
49 je 1b
50
51/*
52 * Initialize eflags. Some BIOS's leave bits like NT set. This would
53 * confuse the debugger if this code is traced.
54 * XXX - best to initialize before switching to protected mode.
55 */
56 pushl $0
57 popfl
58/*
59 * Clear BSS
60 */
61 xorl %eax,%eax
62 movl $_edata,%edi
63 movl $_end,%ecx
64 subl %edi,%ecx
65 cld
66 rep
67 stosb
68/*
69 * Do the decompression, and jump to the new kernel..
70 */
71 subl $16,%esp # place for structure on the stack
72 movl %esp,%eax
73 pushl %esi # real mode pointer as second arg
74 pushl %eax # address of structure as first arg
75 call decompress_kernel
76 orl %eax,%eax
77 jnz 3f
78 addl $8,%esp
79 xorl %ebx,%ebx
80 ljmp $(__KERNEL_CS), $0x100000
81
82/*
83 * We come here, if we were loaded high.
84 * We need to move the move-in-place routine down to 0x1000
85 * and then start it with the buffer addresses in registers,
86 * which we got from the stack.
87 */
883:
89 movl %esi,%ebx
90 movl $move_routine_start,%esi
91 movl $0x1000,%edi
92 movl $move_routine_end,%ecx
93 subl %esi,%ecx
94 addl $3,%ecx
95 shrl $2,%ecx
96 cld
97 rep
98 movsl
99
100 popl %esi # discard the address
101 addl $4,%esp # real mode pointer
102 popl %esi # low_buffer_start
103 popl %ecx # lcount
104 popl %edx # high_buffer_start
105 popl %eax # hcount
106 movl $0x100000,%edi
107 cli # make sure we don't get interrupted
108 ljmp $(__KERNEL_CS), $0x1000 # and jump to the move routine
109
110/*
111 * Routine (template) for moving the decompressed kernel in place,
112 * if we were high loaded. This _must_ PIC-code !
113 */
114move_routine_start:
115 movl %ecx,%ebp
116 shrl $2,%ecx
117 rep
118 movsl
119 movl %ebp,%ecx
120 andl $3,%ecx
121 rep
122 movsb
123 movl %edx,%esi
124 movl %eax,%ecx # NOTE: rep movsb won't move if %ecx == 0
125 addl $3,%ecx
126 shrl $2,%ecx
127 rep
128 movsl
129 movl %ebx,%esi # Restore setup pointer
130 xorl %ebx,%ebx
131 ljmp $(__KERNEL_CS), $0x100000
132move_routine_end:
133
134
135/* Stack for uncompression */
136 .align 32
137user_stack:
138 .fill 4096,4,0
139stack_start:
140 .long user_stack+4096
141 .word __KERNEL_DS
142
diff --git a/arch/x86_64/boot/compressed/misc.c b/arch/x86_64/boot/compressed/misc.c
new file mode 100644
index 000000000000..c8b9216f9e63
--- /dev/null
+++ b/arch/x86_64/boot/compressed/misc.c
@@ -0,0 +1,354 @@
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 "miscsetup.h"
13#include <asm/io.h>
14
15/*
16 * gzip declarations
17 */
18
19#define OF(args) args
20#define STATIC static
21
22#undef memset
23#undef memcpy
24#define memzero(s, n) memset ((s), 0, (n))
25
26typedef unsigned char uch;
27typedef unsigned short ush;
28typedef unsigned long ulg;
29
30#define WSIZE 0x8000 /* Window size must be at least 32k, */
31 /* and a power of two */
32
33static uch *inbuf; /* input buffer */
34static uch window[WSIZE]; /* Sliding window buffer */
35
36static unsigned insize = 0; /* valid bytes in inbuf */
37static unsigned inptr = 0; /* index of next byte to be processed in inbuf */
38static unsigned outcnt = 0; /* bytes in output buffer */
39
40/* gzip flag byte */
41#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
42#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
43#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
44#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
45#define COMMENT 0x10 /* bit 4 set: file comment present */
46#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
47#define RESERVED 0xC0 /* bit 6,7: reserved */
48
49#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
50
51/* Diagnostic functions */
52#ifdef DEBUG
53# define Assert(cond,msg) {if(!(cond)) error(msg);}
54# define Trace(x) fprintf x
55# define Tracev(x) {if (verbose) fprintf x ;}
56# define Tracevv(x) {if (verbose>1) fprintf x ;}
57# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
58# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
59#else
60# define Assert(cond,msg)
61# define Trace(x)
62# define Tracev(x)
63# define Tracevv(x)
64# define Tracec(c,x)
65# define Tracecv(c,x)
66#endif
67
68static int fill_inbuf(void);
69static void flush_window(void);
70static void error(char *m);
71static void gzip_mark(void **);
72static void gzip_release(void **);
73
74/*
75 * This is set up by the setup-routine at boot-time
76 */
77static unsigned char *real_mode; /* Pointer to real-mode data */
78
79#define EXT_MEM_K (*(unsigned short *)(real_mode + 0x2))
80#ifndef STANDARD_MEMORY_BIOS_CALL
81#define ALT_MEM_K (*(unsigned long *)(real_mode + 0x1e0))
82#endif
83#define SCREEN_INFO (*(struct screen_info *)(real_mode+0))
84
85extern char input_data[];
86extern int input_len;
87
88static long bytes_out = 0;
89static uch *output_data;
90static unsigned long output_ptr = 0;
91
92static void *malloc(int size);
93static void free(void *where);
94
95static void putstr(const char *);
96
97extern int end;
98static long free_mem_ptr = (long)&end;
99static long free_mem_end_ptr;
100
101#define INPLACE_MOVE_ROUTINE 0x1000
102#define LOW_BUFFER_START 0x2000
103#define LOW_BUFFER_MAX 0x90000
104#define HEAP_SIZE 0x3000
105static unsigned int low_buffer_end, low_buffer_size;
106static int high_loaded =0;
107static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/;
108
109static char *vidmem = (char *)0xb8000;
110static int vidport;
111static int lines, cols;
112
113#include "../../../../lib/inflate.c"
114
115static void *malloc(int size)
116{
117 void *p;
118
119 if (size <0) error("Malloc error");
120 if (free_mem_ptr <= 0) error("Memory error");
121
122 free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */
123
124 p = (void *)free_mem_ptr;
125 free_mem_ptr += size;
126
127 if (free_mem_ptr >= free_mem_end_ptr)
128 error("Out of memory");
129
130 return p;
131}
132
133static void free(void *where)
134{ /* Don't care */
135}
136
137static void gzip_mark(void **ptr)
138{
139 *ptr = (void *) free_mem_ptr;
140}
141
142static void gzip_release(void **ptr)
143{
144 free_mem_ptr = (long) *ptr;
145}
146
147static void scroll(void)
148{
149 int i;
150
151 memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 );
152 for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 )
153 vidmem[i] = ' ';
154}
155
156static void putstr(const char *s)
157{
158 int x,y,pos;
159 char c;
160
161 x = SCREEN_INFO.orig_x;
162 y = SCREEN_INFO.orig_y;
163
164 while ( ( c = *s++ ) != '\0' ) {
165 if ( c == '\n' ) {
166 x = 0;
167 if ( ++y >= lines ) {
168 scroll();
169 y--;
170 }
171 } else {
172 vidmem [ ( x + cols * y ) * 2 ] = c;
173 if ( ++x >= cols ) {
174 x = 0;
175 if ( ++y >= lines ) {
176 scroll();
177 y--;
178 }
179 }
180 }
181 }
182
183 SCREEN_INFO.orig_x = x;
184 SCREEN_INFO.orig_y = y;
185
186 pos = (x + cols * y) * 2; /* Update cursor position */
187 outb_p(14, vidport);
188 outb_p(0xff & (pos >> 9), vidport+1);
189 outb_p(15, vidport);
190 outb_p(0xff & (pos >> 1), vidport+1);
191}
192
193void* memset(void* s, int c, unsigned n)
194{
195 int i;
196 char *ss = (char*)s;
197
198 for (i=0;i<n;i++) ss[i] = c;
199 return s;
200}
201
202void* memcpy(void* dest, const void* src, unsigned n)
203{
204 int i;
205 char *d = (char *)dest, *s = (char *)src;
206
207 for (i=0;i<n;i++) d[i] = s[i];
208 return dest;
209}
210
211/* ===========================================================================
212 * Fill the input buffer. This is called only when the buffer is empty
213 * and at least one byte is really needed.
214 */
215static int fill_inbuf(void)
216{
217 if (insize != 0) {
218 error("ran out of input data");
219 }
220
221 inbuf = input_data;
222 insize = input_len;
223 inptr = 1;
224 return inbuf[0];
225}
226
227/* ===========================================================================
228 * Write the output window window[0..outcnt-1] and update crc and bytes_out.
229 * (Used for the decompressed data only.)
230 */
231static void flush_window_low(void)
232{
233 ulg c = crc; /* temporary variable */
234 unsigned n;
235 uch *in, *out, ch;
236
237 in = window;
238 out = &output_data[output_ptr];
239 for (n = 0; n < outcnt; n++) {
240 ch = *out++ = *in++;
241 c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
242 }
243 crc = c;
244 bytes_out += (ulg)outcnt;
245 output_ptr += (ulg)outcnt;
246 outcnt = 0;
247}
248
249static void flush_window_high(void)
250{
251 ulg c = crc; /* temporary variable */
252 unsigned n;
253 uch *in, ch;
254 in = window;
255 for (n = 0; n < outcnt; n++) {
256 ch = *output_data++ = *in++;
257 if ((ulg)output_data == low_buffer_end) output_data=high_buffer_start;
258 c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
259 }
260 crc = c;
261 bytes_out += (ulg)outcnt;
262 outcnt = 0;
263}
264
265static void flush_window(void)
266{
267 if (high_loaded) flush_window_high();
268 else flush_window_low();
269}
270
271static void error(char *x)
272{
273 putstr("\n\n");
274 putstr(x);
275 putstr("\n\n -- System halted");
276
277 while(1);
278}
279
280void setup_normal_output_buffer(void)
281{
282#ifdef STANDARD_MEMORY_BIOS_CALL
283 if (EXT_MEM_K < 1024) error("Less than 2MB of memory");
284#else
285 if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < 1024) error("Less than 2MB of memory");
286#endif
287 output_data = (char *)0x100000; /* Points to 1M */
288 free_mem_end_ptr = (long)real_mode;
289}
290
291struct moveparams {
292 uch *low_buffer_start; int lcount;
293 uch *high_buffer_start; int hcount;
294};
295
296void setup_output_buffer_if_we_run_high(struct moveparams *mv)
297{
298 high_buffer_start = (uch *)(((ulg)&end) + HEAP_SIZE);
299#ifdef STANDARD_MEMORY_BIOS_CALL
300 if (EXT_MEM_K < (3*1024)) error("Less than 4MB of memory");
301#else
302 if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < (3*1024)) error("Less than 4MB of memory");
303#endif
304 mv->low_buffer_start = output_data = (char *)LOW_BUFFER_START;
305 low_buffer_end = ((unsigned int)real_mode > LOW_BUFFER_MAX
306 ? LOW_BUFFER_MAX : (unsigned int)real_mode) & ~0xfff;
307 low_buffer_size = low_buffer_end - LOW_BUFFER_START;
308 high_loaded = 1;
309 free_mem_end_ptr = (long)high_buffer_start;
310 if ( (0x100000 + low_buffer_size) > ((ulg)high_buffer_start)) {
311 high_buffer_start = (uch *)(0x100000 + low_buffer_size);
312 mv->hcount = 0; /* say: we need not to move high_buffer */
313 }
314 else mv->hcount = -1;
315 mv->high_buffer_start = high_buffer_start;
316}
317
318void close_output_buffer_if_we_run_high(struct moveparams *mv)
319{
320 if (bytes_out > low_buffer_size) {
321 mv->lcount = low_buffer_size;
322 if (mv->hcount)
323 mv->hcount = bytes_out - low_buffer_size;
324 } else {
325 mv->lcount = bytes_out;
326 mv->hcount = 0;
327 }
328}
329
330int decompress_kernel(struct moveparams *mv, void *rmode)
331{
332 real_mode = rmode;
333
334 if (SCREEN_INFO.orig_video_mode == 7) {
335 vidmem = (char *) 0xb0000;
336 vidport = 0x3b4;
337 } else {
338 vidmem = (char *) 0xb8000;
339 vidport = 0x3d4;
340 }
341
342 lines = SCREEN_INFO.orig_video_lines;
343 cols = SCREEN_INFO.orig_video_cols;
344
345 if (free_mem_ptr < 0x100000) setup_normal_output_buffer();
346 else setup_output_buffer_if_we_run_high(mv);
347
348 makecrc();
349 putstr(".\nDecompressing Linux...");
350 gunzip();
351 putstr("done.\nBooting the kernel.\n");
352 if (high_loaded) close_output_buffer_if_we_run_high(mv);
353 return high_loaded;
354}
diff --git a/arch/x86_64/boot/compressed/miscsetup.h b/arch/x86_64/boot/compressed/miscsetup.h
new file mode 100644
index 000000000000..bb1620531703
--- /dev/null
+++ b/arch/x86_64/boot/compressed/miscsetup.h
@@ -0,0 +1,39 @@
1#define NULL 0
2//typedef unsigned int size_t;
3
4
5struct screen_info {
6 unsigned char orig_x; /* 0x00 */
7 unsigned char orig_y; /* 0x01 */
8 unsigned short dontuse1; /* 0x02 -- EXT_MEM_K sits here */
9 unsigned short orig_video_page; /* 0x04 */
10 unsigned char orig_video_mode; /* 0x06 */
11 unsigned char orig_video_cols; /* 0x07 */
12 unsigned short unused2; /* 0x08 */
13 unsigned short orig_video_ega_bx; /* 0x0a */
14 unsigned short unused3; /* 0x0c */
15 unsigned char orig_video_lines; /* 0x0e */
16 unsigned char orig_video_isVGA; /* 0x0f */
17 unsigned short orig_video_points; /* 0x10 */
18
19 /* VESA graphic mode -- linear frame buffer */
20 unsigned short lfb_width; /* 0x12 */
21 unsigned short lfb_height; /* 0x14 */
22 unsigned short lfb_depth; /* 0x16 */
23 unsigned long lfb_base; /* 0x18 */
24 unsigned long lfb_size; /* 0x1c */
25 unsigned short dontuse2, dontuse3; /* 0x20 -- CL_MAGIC and CL_OFFSET here */
26 unsigned short lfb_linelength; /* 0x24 */
27 unsigned char red_size; /* 0x26 */
28 unsigned char red_pos; /* 0x27 */
29 unsigned char green_size; /* 0x28 */
30 unsigned char green_pos; /* 0x29 */
31 unsigned char blue_size; /* 0x2a */
32 unsigned char blue_pos; /* 0x2b */
33 unsigned char rsvd_size; /* 0x2c */
34 unsigned char rsvd_pos; /* 0x2d */
35 unsigned short vesapm_seg; /* 0x2e */
36 unsigned short vesapm_off; /* 0x30 */
37 unsigned short pages; /* 0x32 */
38 /* 0x34 -- 0x3f reserved for future expansion */
39};
diff --git a/arch/x86_64/boot/compressed/vmlinux.scr b/arch/x86_64/boot/compressed/vmlinux.scr
new file mode 100644
index 000000000000..1ed9d791f863
--- /dev/null
+++ b/arch/x86_64/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/x86_64/boot/install.sh b/arch/x86_64/boot/install.sh
new file mode 100644
index 000000000000..90f2452b3b9e
--- /dev/null
+++ b/arch/x86_64/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/x86_64/boot/mtools.conf.in b/arch/x86_64/boot/mtools.conf.in
new file mode 100644
index 000000000000..efd6d2490c1d
--- /dev/null
+++ b/arch/x86_64/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/x86_64/boot/setup.S b/arch/x86_64/boot/setup.S
new file mode 100644
index 000000000000..3e838be9dbe7
--- /dev/null
+++ b/arch/x86_64/boot/setup.S
@@ -0,0 +1,867 @@
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 * Added long mode checking and SSE force. March 2003, Andi Kleen.
46 */
47
48#include <linux/config.h>
49#include <asm/segment.h>
50#include <linux/version.h>
51#include <linux/compile.h>
52#include <asm/boot.h>
53#include <asm/e820.h>
54#include <asm/page.h>
55
56/* Signature words to ensure LILO loaded us right */
57#define SIG1 0xAA55
58#define SIG2 0x5A5A
59
60INITSEG = DEF_INITSEG # 0x9000, we move boot here, out of the way
61SYSSEG = DEF_SYSSEG # 0x1000, system loaded at 0x10000 (65536).
62SETUPSEG = DEF_SETUPSEG # 0x9020, this is the current segment
63 # ... and the former contents of CS
64
65DELTA_INITSEG = SETUPSEG - INITSEG # 0x0020
66
67.code16
68.globl begtext, begdata, begbss, endtext, enddata, endbss
69
70.text
71begtext:
72.data
73begdata:
74.bss
75begbss:
76.text
77
78start:
79 jmp trampoline
80
81# This is the setup header, and it must start at %cs:2 (old 0x9020:2)
82
83 .ascii "HdrS" # header signature
84 .word 0x0203 # header version number (>= 0x0105)
85 # or else old loadlin-1.5 will fail)
86realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
87start_sys_seg: .word SYSSEG
88 .word kernel_version # pointing to kernel version string
89 # above section of header is compatible
90 # with loadlin-1.5 (header v1.5). Don't
91 # change it.
92
93type_of_loader: .byte 0 # = 0, old one (LILO, Loadlin,
94 # Bootlin, SYSLX, bootsect...)
95 # See Documentation/i386/boot.txt for
96 # assigned ids
97
98# flags, unused bits must be zero (RFU) bit within loadflags
99loadflags:
100LOADED_HIGH = 1 # If set, the kernel is loaded high
101CAN_USE_HEAP = 0x80 # If set, the loader also has set
102 # heap_end_ptr to tell how much
103 # space behind setup.S can be used for
104 # heap purposes.
105 # Only the loader knows what is free
106#ifndef __BIG_KERNEL__
107 .byte 0
108#else
109 .byte LOADED_HIGH
110#endif
111
112setup_move_size: .word 0x8000 # size to move, when setup is not
113 # loaded at 0x90000. We will move setup
114 # to 0x90000 then just before jumping
115 # into the kernel. However, only the
116 # loader knows how much data behind
117 # us also needs to be loaded.
118
119code32_start: # here loaders can put a different
120 # start address for 32-bit code.
121#ifndef __BIG_KERNEL__
122 .long 0x1000 # 0x1000 = default for zImage
123#else
124 .long 0x100000 # 0x100000 = default for big kernel
125#endif
126
127ramdisk_image: .long 0 # address of loaded ramdisk image
128 # Here the loader puts the 32-bit
129 # address where it loaded the image.
130 # This only will be read by the kernel.
131
132ramdisk_size: .long 0 # its size in bytes
133
134bootsect_kludge:
135 .long 0 # obsolete
136
137heap_end_ptr: .word modelist+1024 # (Header version 0x0201 or later)
138 # space from here (exclusive) down to
139 # end of setup code can be used by setup
140 # for local heap purposes.
141
142pad1: .word 0
143cmd_line_ptr: .long 0 # (Header version 0x0202 or later)
144 # If nonzero, a 32-bit pointer
145 # to the kernel command line.
146 # The command line should be
147 # located between the start of
148 # setup and the end of low
149 # memory (0xa0000), or it may
150 # get overwritten before it
151 # gets read. If this field is
152 # used, there is no longer
153 # anything magical about the
154 # 0x90000 segment; the setup
155 # can be located anywhere in
156 # low memory 0x10000 or higher.
157
158ramdisk_max: .long 0xffffffff
159
160trampoline: call start_of_setup
161 .align 16
162 # The offset at this point is 0x240
163 .space (0x7ff-0x240+1) # E820 & EDD space (ending at 0x7ff)
164# End of setup header #####################################################
165
166start_of_setup:
167# Bootlin depends on this being done early
168 movw $0x01500, %ax
169 movb $0x81, %dl
170 int $0x13
171
172#ifdef SAFE_RESET_DISK_CONTROLLER
173# Reset the disk controller.
174 movw $0x0000, %ax
175 movb $0x80, %dl
176 int $0x13
177#endif
178
179# Set %ds = %cs, we know that SETUPSEG = %cs at this point
180 movw %cs, %ax # aka SETUPSEG
181 movw %ax, %ds
182# Check signature at end of setup
183 cmpw $SIG1, setup_sig1
184 jne bad_sig
185
186 cmpw $SIG2, setup_sig2
187 jne bad_sig
188
189 jmp good_sig1
190
191# Routine to print asciiz string at ds:si
192prtstr:
193 lodsb
194 andb %al, %al
195 jz fin
196
197 call prtchr
198 jmp prtstr
199
200fin: ret
201
202# Space printing
203prtsp2: call prtspc # Print double space
204prtspc: movb $0x20, %al # Print single space (note: fall-thru)
205
206prtchr:
207 pushw %ax
208 pushw %cx
209 movw $0007,%bx
210 movw $0x01, %cx
211 movb $0x0e, %ah
212 int $0x10
213 popw %cx
214 popw %ax
215 ret
216
217beep: movb $0x07, %al
218 jmp prtchr
219
220no_sig_mess: .string "No setup signature found ..."
221
222good_sig1:
223 jmp good_sig
224
225# We now have to find the rest of the setup code/data
226bad_sig:
227 movw %cs, %ax # SETUPSEG
228 subw $DELTA_INITSEG, %ax # INITSEG
229 movw %ax, %ds
230 xorb %bh, %bh
231 movb (497), %bl # get setup sect from bootsect
232 subw $4, %bx # LILO loads 4 sectors of setup
233 shlw $8, %bx # convert to words (1sect=2^8 words)
234 movw %bx, %cx
235 shrw $3, %bx # convert to segment
236 addw $SYSSEG, %bx
237 movw %bx, %cs:start_sys_seg
238# Move rest of setup code/data to here
239 movw $2048, %di # four sectors loaded by LILO
240 subw %si, %si
241 movw %cs, %ax # aka SETUPSEG
242 movw %ax, %es
243 movw $SYSSEG, %ax
244 movw %ax, %ds
245 rep
246 movsw
247 movw %cs, %ax # aka SETUPSEG
248 movw %ax, %ds
249 cmpw $SIG1, setup_sig1
250 jne no_sig
251
252 cmpw $SIG2, setup_sig2
253 jne no_sig
254
255 jmp good_sig
256
257no_sig:
258 lea no_sig_mess, %si
259 call prtstr
260
261no_sig_loop:
262 jmp no_sig_loop
263
264good_sig:
265 movw %cs, %ax # aka SETUPSEG
266 subw $DELTA_INITSEG, %ax # aka INITSEG
267 movw %ax, %ds
268# Check if an old loader tries to load a big-kernel
269 testb $LOADED_HIGH, %cs:loadflags # Do we have a big kernel?
270 jz loader_ok # No, no danger for old loaders.
271
272 cmpb $0, %cs:type_of_loader # Do we have a loader that
273 # can deal with us?
274 jnz loader_ok # Yes, continue.
275
276 pushw %cs # No, we have an old loader,
277 popw %ds # die.
278 lea loader_panic_mess, %si
279 call prtstr
280
281 jmp no_sig_loop
282
283loader_panic_mess: .string "Wrong loader, giving up..."
284
285loader_ok:
286 /* check for long mode. */
287 /* we have to do this before the VESA setup, otherwise the user
288 can't see the error message. */
289
290 pushw %ds
291 movw %cs,%ax
292 movw %ax,%ds
293
294 /* minimum CPUID flags for x86-64 */
295 /* see http://www.x86-64.org/lists/discuss/msg02971.html */
296#define SSE_MASK ((1<<25)|(1<<26))
297#define REQUIRED_MASK1 ((1<<0)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<8)|\
298 (1<<13)|(1<<15)|(1<<24))
299#define REQUIRED_MASK2 (1<<29)
300
301 pushfl /* standard way to check for cpuid */
302 popl %eax
303 movl %eax,%ebx
304 xorl $0x200000,%eax
305 pushl %eax
306 popfl
307 pushfl
308 popl %eax
309 cmpl %eax,%ebx
310 jz no_longmode /* cpu has no cpuid */
311 movl $0x0,%eax
312 cpuid
313 cmpl $0x1,%eax
314 jb no_longmode /* no cpuid 1 */
315 xor %di,%di
316 cmpl $0x68747541,%ebx /* AuthenticAMD */
317 jnz noamd
318 cmpl $0x69746e65,%edx
319 jnz noamd
320 cmpl $0x444d4163,%ecx
321 jnz noamd
322 mov $1,%di /* cpu is from AMD */
323noamd:
324 movl $0x1,%eax
325 cpuid
326 andl $REQUIRED_MASK1,%edx
327 xorl $REQUIRED_MASK1,%edx
328 jnz no_longmode
329 movl $0x80000000,%eax
330 cpuid
331 cmpl $0x80000001,%eax
332 jb no_longmode /* no extended cpuid */
333 movl $0x80000001,%eax
334 cpuid
335 andl $REQUIRED_MASK2,%edx
336 xorl $REQUIRED_MASK2,%edx
337 jnz no_longmode
338sse_test:
339 movl $1,%eax
340 cpuid
341 andl $SSE_MASK,%edx
342 cmpl $SSE_MASK,%edx
343 je sse_ok
344 test %di,%di
345 jz no_longmode /* only try to force SSE on AMD */
346 movl $0xc0010015,%ecx /* HWCR */
347 rdmsr
348 btr $15,%eax /* enable SSE */
349 wrmsr
350 xor %di,%di /* don't loop */
351 jmp sse_test /* try again */
352no_longmode:
353 call beep
354 lea long_mode_panic,%si
355 call prtstr
356no_longmode_loop:
357 jmp no_longmode_loop
358long_mode_panic:
359 .string "Your CPU does not support long mode. Use a 32bit distribution."
360 .byte 0
361
362sse_ok:
363 popw %ds
364
365# tell BIOS we want to go to long mode
366 movl $0xec00,%eax # declare target operating mode
367 movl $2,%ebx # long mode
368 int $0x15
369
370# Get memory size (extended mem, kB)
371
372 xorl %eax, %eax
373 movl %eax, (0x1e0)
374#ifndef STANDARD_MEMORY_BIOS_CALL
375 movb %al, (E820NR)
376# Try three different memory detection schemes. First, try
377# e820h, which lets us assemble a memory map, then try e801h,
378# which returns a 32-bit memory size, and finally 88h, which
379# returns 0-64m
380
381# method E820H:
382# the memory map from hell. e820h returns memory classified into
383# a whole bunch of different types, and allows memory holes and
384# everything. We scan through this memory map and build a list
385# of the first 32 memory areas, which we return at [E820MAP].
386# This is documented at http://www.teleport.com/~acpi/acpihtml/topic245.htm
387
388#define SMAP 0x534d4150
389
390meme820:
391 xorl %ebx, %ebx # continuation counter
392 movw $E820MAP, %di # point into the whitelist
393 # so we can have the bios
394 # directly write into it.
395
396jmpe820:
397 movl $0x0000e820, %eax # e820, upper word zeroed
398 movl $SMAP, %edx # ascii 'SMAP'
399 movl $20, %ecx # size of the e820rec
400 pushw %ds # data record.
401 popw %es
402 int $0x15 # make the call
403 jc bail820 # fall to e801 if it fails
404
405 cmpl $SMAP, %eax # check the return is `SMAP'
406 jne bail820 # fall to e801 if it fails
407
408# cmpl $1, 16(%di) # is this usable memory?
409# jne again820
410
411 # If this is usable memory, we save it by simply advancing %di by
412 # sizeof(e820rec).
413 #
414good820:
415 movb (E820NR), %al # up to 32 entries
416 cmpb $E820MAX, %al
417 jnl bail820
418
419 incb (E820NR)
420 movw %di, %ax
421 addw $20, %ax
422 movw %ax, %di
423again820:
424 cmpl $0, %ebx # check to see if
425 jne jmpe820 # %ebx is set to EOF
426bail820:
427
428
429# method E801H:
430# memory size is in 1k chunksizes, to avoid confusing loadlin.
431# we store the 0xe801 memory size in a completely different place,
432# because it will most likely be longer than 16 bits.
433# (use 1e0 because that's what Larry Augustine uses in his
434# alternative new memory detection scheme, and it's sensible
435# to write everything into the same place.)
436
437meme801:
438 stc # fix to work around buggy
439 xorw %cx,%cx # BIOSes which dont clear/set
440 xorw %dx,%dx # carry on pass/error of
441 # e801h memory size call
442 # or merely pass cx,dx though
443 # without changing them.
444 movw $0xe801, %ax
445 int $0x15
446 jc mem88
447
448 cmpw $0x0, %cx # Kludge to handle BIOSes
449 jne e801usecxdx # which report their extended
450 cmpw $0x0, %dx # memory in AX/BX rather than
451 jne e801usecxdx # CX/DX. The spec I have read
452 movw %ax, %cx # seems to indicate AX/BX
453 movw %bx, %dx # are more reasonable anyway...
454
455e801usecxdx:
456 andl $0xffff, %edx # clear sign extend
457 shll $6, %edx # and go from 64k to 1k chunks
458 movl %edx, (0x1e0) # store extended memory size
459 andl $0xffff, %ecx # clear sign extend
460 addl %ecx, (0x1e0) # and add lower memory into
461 # total size.
462
463# Ye Olde Traditional Methode. Returns the memory size (up to 16mb or
464# 64mb, depending on the bios) in ax.
465mem88:
466
467#endif
468 movb $0x88, %ah
469 int $0x15
470 movw %ax, (2)
471
472# Set the keyboard repeat rate to the max
473 movw $0x0305, %ax
474 xorw %bx, %bx
475 int $0x16
476
477# Check for video adapter and its parameters and allow the
478# user to browse video modes.
479 call video # NOTE: we need %ds pointing
480 # to bootsector
481
482# Get hd0 data...
483 xorw %ax, %ax
484 movw %ax, %ds
485 ldsw (4 * 0x41), %si
486 movw %cs, %ax # aka SETUPSEG
487 subw $DELTA_INITSEG, %ax # aka INITSEG
488 pushw %ax
489 movw %ax, %es
490 movw $0x0080, %di
491 movw $0x10, %cx
492 pushw %cx
493 cld
494 rep
495 movsb
496# Get hd1 data...
497 xorw %ax, %ax
498 movw %ax, %ds
499 ldsw (4 * 0x46), %si
500 popw %cx
501 popw %es
502 movw $0x0090, %di
503 rep
504 movsb
505# Check that there IS a hd1 :-)
506 movw $0x01500, %ax
507 movb $0x81, %dl
508 int $0x13
509 jc no_disk1
510
511 cmpb $3, %ah
512 je is_disk1
513
514no_disk1:
515 movw %cs, %ax # aka SETUPSEG
516 subw $DELTA_INITSEG, %ax # aka INITSEG
517 movw %ax, %es
518 movw $0x0090, %di
519 movw $0x10, %cx
520 xorw %ax, %ax
521 cld
522 rep
523 stosb
524is_disk1:
525
526# Check for PS/2 pointing device
527 movw %cs, %ax # aka SETUPSEG
528 subw $DELTA_INITSEG, %ax # aka INITSEG
529 movw %ax, %ds
530 movw $0, (0x1ff) # default is no pointing device
531 int $0x11 # int 0x11: equipment list
532 testb $0x04, %al # check if mouse installed
533 jz no_psmouse
534
535 movw $0xAA, (0x1ff) # device present
536no_psmouse:
537
538#include "../../i386/boot/edd.S"
539
540# Now we want to move to protected mode ...
541 cmpw $0, %cs:realmode_swtch
542 jz rmodeswtch_normal
543
544 lcall *%cs:realmode_swtch
545
546 jmp rmodeswtch_end
547
548rmodeswtch_normal:
549 pushw %cs
550 call default_switch
551
552rmodeswtch_end:
553# we get the code32 start address and modify the below 'jmpi'
554# (loader may have changed it)
555 movl %cs:code32_start, %eax
556 movl %eax, %cs:code32
557
558# Now we move the system to its rightful place ... but we check if we have a
559# big-kernel. In that case we *must* not move it ...
560 testb $LOADED_HIGH, %cs:loadflags
561 jz do_move0 # .. then we have a normal low
562 # loaded zImage
563 # .. or else we have a high
564 # loaded bzImage
565 jmp end_move # ... and we skip moving
566
567do_move0:
568 movw $0x100, %ax # start of destination segment
569 movw %cs, %bp # aka SETUPSEG
570 subw $DELTA_INITSEG, %bp # aka INITSEG
571 movw %cs:start_sys_seg, %bx # start of source segment
572 cld
573do_move:
574 movw %ax, %es # destination segment
575 incb %ah # instead of add ax,#0x100
576 movw %bx, %ds # source segment
577 addw $0x100, %bx
578 subw %di, %di
579 subw %si, %si
580 movw $0x800, %cx
581 rep
582 movsw
583 cmpw %bp, %bx # assume start_sys_seg > 0x200,
584 # so we will perhaps read one
585 # page more than needed, but
586 # never overwrite INITSEG
587 # because destination is a
588 # minimum one page below source
589 jb do_move
590
591end_move:
592# then we load the segment descriptors
593 movw %cs, %ax # aka SETUPSEG
594 movw %ax, %ds
595
596# Check whether we need to be downward compatible with version <=201
597 cmpl $0, cmd_line_ptr
598 jne end_move_self # loader uses version >=202 features
599 cmpb $0x20, type_of_loader
600 je end_move_self # bootsect loader, we know of it
601
602# Boot loader doesnt support boot protocol version 2.02.
603# If we have our code not at 0x90000, we need to move it there now.
604# We also then need to move the params behind it (commandline)
605# Because we would overwrite the code on the current IP, we move
606# it in two steps, jumping high after the first one.
607 movw %cs, %ax
608 cmpw $SETUPSEG, %ax
609 je end_move_self
610
611 cli # make sure we really have
612 # interrupts disabled !
613 # because after this the stack
614 # should not be used
615 subw $DELTA_INITSEG, %ax # aka INITSEG
616 movw %ss, %dx
617 cmpw %ax, %dx
618 jb move_self_1
619
620 addw $INITSEG, %dx
621 subw %ax, %dx # this will go into %ss after
622 # the move
623move_self_1:
624 movw %ax, %ds
625 movw $INITSEG, %ax # real INITSEG
626 movw %ax, %es
627 movw %cs:setup_move_size, %cx
628 std # we have to move up, so we use
629 # direction down because the
630 # areas may overlap
631 movw %cx, %di
632 decw %di
633 movw %di, %si
634 subw $move_self_here+0x200, %cx
635 rep
636 movsb
637 ljmp $SETUPSEG, $move_self_here
638
639move_self_here:
640 movw $move_self_here+0x200, %cx
641 rep
642 movsb
643 movw $SETUPSEG, %ax
644 movw %ax, %ds
645 movw %dx, %ss
646end_move_self: # now we are at the right place
647 lidt idt_48 # load idt with 0,0
648 xorl %eax, %eax # Compute gdt_base
649 movw %ds, %ax # (Convert %ds:gdt to a linear ptr)
650 shll $4, %eax
651 addl $gdt, %eax
652 movl %eax, (gdt_48+2)
653 lgdt gdt_48 # load gdt with whatever is
654 # appropriate
655
656# that was painless, now we enable a20
657 call empty_8042
658
659 movb $0xD1, %al # command write
660 outb %al, $0x64
661 call empty_8042
662
663 movb $0xDF, %al # A20 on
664 outb %al, $0x60
665 call empty_8042
666
667#
668# You must preserve the other bits here. Otherwise embarrasing things
669# like laptops powering off on boot happen. Corrected version by Kira
670# Brown from Linux 2.2
671#
672 inb $0x92, %al #
673 orb $02, %al # "fast A20" version
674 outb %al, $0x92 # some chips have only this
675
676# wait until a20 really *is* enabled; it can take a fair amount of
677# time on certain systems; Toshiba Tecras are known to have this
678# problem. The memory location used here (0x200) is the int 0x80
679# vector, which should be safe to use.
680
681 xorw %ax, %ax # segment 0x0000
682 movw %ax, %fs
683 decw %ax # segment 0xffff (HMA)
684 movw %ax, %gs
685a20_wait:
686 incw %ax # unused memory location <0xfff0
687 movw %ax, %fs:(0x200) # we use the "int 0x80" vector
688 cmpw %gs:(0x210), %ax # and its corresponding HMA addr
689 je a20_wait # loop until no longer aliased
690
691# make sure any possible coprocessor is properly reset..
692 xorw %ax, %ax
693 outb %al, $0xf0
694 call delay
695
696 outb %al, $0xf1
697 call delay
698
699# well, that went ok, I hope. Now we mask all interrupts - the rest
700# is done in init_IRQ().
701 movb $0xFF, %al # mask all interrupts for now
702 outb %al, $0xA1
703 call delay
704
705 movb $0xFB, %al # mask all irq's but irq2 which
706 outb %al, $0x21 # is cascaded
707
708# Well, that certainly wasn't fun :-(. Hopefully it works, and we don't
709# need no steenking BIOS anyway (except for the initial loading :-).
710# The BIOS-routine wants lots of unnecessary data, and it's less
711# "interesting" anyway. This is how REAL programmers do it.
712#
713# Well, now's the time to actually move into protected mode. To make
714# things as simple as possible, we do no register set-up or anything,
715# we let the gnu-compiled 32-bit programs do that. We just jump to
716# absolute address 0x1000 (or the loader supplied one),
717# in 32-bit protected mode.
718#
719# Note that the short jump isn't strictly needed, although there are
720# reasons why it might be a good idea. It won't hurt in any case.
721 movw $1, %ax # protected mode (PE) bit
722 lmsw %ax # This is it!
723 jmp flush_instr
724
725flush_instr:
726 xorw %bx, %bx # Flag to indicate a boot
727 xorl %esi, %esi # Pointer to real-mode code
728 movw %cs, %si
729 subw $DELTA_INITSEG, %si
730 shll $4, %esi # Convert to 32-bit pointer
731# NOTE: For high loaded big kernels we need a
732# jmpi 0x100000,__KERNEL_CS
733#
734# but we yet haven't reloaded the CS register, so the default size
735# of the target offset still is 16 bit.
736# However, using an operant prefix (0x66), the CPU will properly
737# take our 48 bit far pointer. (INTeL 80386 Programmer's Reference
738# Manual, Mixing 16-bit and 32-bit code, page 16-6)
739
740 .byte 0x66, 0xea # prefix + jmpi-opcode
741code32: .long 0x1000 # will be set to 0x100000
742 # for big kernels
743 .word __KERNEL_CS
744
745# Here's a bunch of information about your current kernel..
746kernel_version: .ascii UTS_RELEASE
747 .ascii " ("
748 .ascii LINUX_COMPILE_BY
749 .ascii "@"
750 .ascii LINUX_COMPILE_HOST
751 .ascii ") "
752 .ascii UTS_VERSION
753 .byte 0
754
755# This is the default real mode switch routine.
756# to be called just before protected mode transition
757default_switch:
758 cli # no interrupts allowed !
759 movb $0x80, %al # disable NMI for bootup
760 # sequence
761 outb %al, $0x70
762 lret
763
764
765# This routine checks that the keyboard command queue is empty
766# (after emptying the output buffers)
767#
768# Some machines have delusions that the keyboard buffer is always full
769# with no keyboard attached...
770#
771# If there is no keyboard controller, we will usually get 0xff
772# to all the reads. With each IO taking a microsecond and
773# a timeout of 100,000 iterations, this can take about half a
774# second ("delay" == outb to port 0x80). That should be ok,
775# and should also be plenty of time for a real keyboard controller
776# to empty.
777#
778
779empty_8042:
780 pushl %ecx
781 movl $100000, %ecx
782
783empty_8042_loop:
784 decl %ecx
785 jz empty_8042_end_loop
786
787 call delay
788
789 inb $0x64, %al # 8042 status port
790 testb $1, %al # output buffer?
791 jz no_output
792
793 call delay
794 inb $0x60, %al # read it
795 jmp empty_8042_loop
796
797no_output:
798 testb $2, %al # is input buffer full?
799 jnz empty_8042_loop # yes - loop
800empty_8042_end_loop:
801 popl %ecx
802 ret
803
804# Read the cmos clock. Return the seconds in al
805gettime:
806 pushw %cx
807 movb $0x02, %ah
808 int $0x1a
809 movb %dh, %al # %dh contains the seconds
810 andb $0x0f, %al
811 movb %dh, %ah
812 movb $0x04, %cl
813 shrb %cl, %ah
814 aad
815 popw %cx
816 ret
817
818# Delay is needed after doing I/O
819delay:
820 outb %al,$0x80
821 ret
822
823# Descriptor tables
824gdt:
825 .word 0, 0, 0, 0 # dummy
826
827 .word 0, 0, 0, 0 # unused
828
829 .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
830 .word 0 # base address = 0
831 .word 0x9A00 # code read/exec
832 .word 0x00CF # granularity = 4096, 386
833 # (+5th nibble of limit)
834
835 .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
836 .word 0 # base address = 0
837 .word 0x9200 # data read/write
838 .word 0x00CF # granularity = 4096, 386
839 # (+5th nibble of limit)
840idt_48:
841 .word 0 # idt limit = 0
842 .word 0, 0 # idt base = 0L
843gdt_48:
844 .word 0x8000 # gdt limit=2048,
845 # 256 GDT entries
846
847 .word 0, 0 # gdt base (filled in later)
848
849# Include video setup & detection code
850
851#include "video.S"
852
853# Setup signature -- must be last
854setup_sig1: .word SIG1
855setup_sig2: .word SIG2
856
857# After this point, there is some free space which is used by the video mode
858# handling code to store the temporary mode table (not used by the kernel).
859
860modelist:
861
862.text
863endtext:
864.data
865enddata:
866.bss
867endbss:
diff --git a/arch/x86_64/boot/tools/build.c b/arch/x86_64/boot/tools/build.c
new file mode 100644
index 000000000000..c2fa66313170
--- /dev/null
+++ b/arch/x86_64/boot/tools/build.c
@@ -0,0 +1,186 @@
1/*
2 * $Id: build.c,v 1.3 2001/06/26 15:14:50 pavel 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 /* 0x40000*16 = 4.0 MB, reasonable estimate for the current maximum */
154 if (sys_size > (is_big_kernel ? 0x40000 : DEF_SYSSIZE))
155 die("System is too big. Try using %smodules.",
156 is_big_kernel ? "" : "bzImage or ");
157 while (sz > 0) {
158 int l, n;
159
160 l = (sz > sizeof(buf)) ? sizeof(buf) : sz;
161 if ((n=read(fd, buf, l)) != l) {
162 if (n < 0)
163 die("Error reading %s: %m", argv[3]);
164 else
165 die("%s: Unexpected EOF", argv[3]);
166 }
167 if (write(1, buf, l) != l)
168 die("Write failed");
169 sz -= l;
170 }
171 close(fd);
172
173 if (lseek(1, 497, SEEK_SET) != 497) /* Write sizes to the bootsector */
174 die("Output: seek failed");
175 buf[0] = setup_sectors;
176 if (write(1, buf, 1) != 1)
177 die("Write of setup sector count failed");
178 if (lseek(1, 500, SEEK_SET) != 500)
179 die("Output: seek failed");
180 buf[0] = (sys_size & 0xff);
181 buf[1] = ((sys_size >> 8) & 0xff);
182 if (write(1, buf, 2) != 2)
183 die("Write of image length failed");
184
185 return 0; /* Everything is OK */
186}
diff --git a/arch/x86_64/boot/video.S b/arch/x86_64/boot/video.S
new file mode 100644
index 000000000000..0587477c99f2
--- /dev/null
+++ b/arch/x86_64/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