aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/boot/.gitignore5
-rw-r--r--arch/x86/boot/Makefile171
-rw-r--r--arch/x86/boot/a20.c161
-rw-r--r--arch/x86/boot/apm.c98
-rw-r--r--arch/x86/boot/bitops.h45
-rw-r--r--arch/x86/boot/boot.h296
-rw-r--r--arch/x86/boot/cmdline.c97
-rw-r--r--arch/x86/boot/code16gcc.h15
-rw-r--r--arch/x86/boot/copy.S101
-rw-r--r--arch/x86/boot/cpu.c69
-rw-r--r--arch/x86/boot/cpucheck.c268
-rw-r--r--arch/x86/boot/edd.c167
-rw-r--r--arch/x86/boot/header.S283
-rw-r--r--arch/x86/boot/install.sh61
-rw-r--r--arch/x86/boot/main.c161
-rw-r--r--arch/x86/boot/mca.c43
-rw-r--r--arch/x86/boot/memory.c118
-rw-r--r--arch/x86/boot/mtools.conf.in17
-rw-r--r--arch/x86/boot/pm.c174
-rw-r--r--arch/x86/boot/pmjump.S54
-rw-r--r--arch/x86/boot/printf.c307
-rw-r--r--arch/x86/boot/setup.ld54
-rw-r--r--arch/x86/boot/string.c52
-rw-r--r--arch/x86/boot/tty.c112
-rw-r--r--arch/x86/boot/version.c23
-rw-r--r--arch/x86/boot/vesa.h79
-rw-r--r--arch/x86/boot/video-bios.c125
-rw-r--r--arch/x86/boot/video-vesa.c292
-rw-r--r--arch/x86/boot/video-vga.c261
-rw-r--r--arch/x86/boot/video.c467
-rw-r--r--arch/x86/boot/video.h152
-rw-r--r--arch/x86/boot/voyager.c46
32 files changed, 4374 insertions, 0 deletions
diff --git a/arch/x86/boot/.gitignore b/arch/x86/boot/.gitignore
new file mode 100644
index 000000000000..18465143cfa2
--- /dev/null
+++ b/arch/x86/boot/.gitignore
@@ -0,0 +1,5 @@
1bootsect
2bzImage
3setup
4setup.bin
5setup.elf
diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile
new file mode 100644
index 000000000000..cb1035f2b7e9
--- /dev/null
+++ b/arch/x86/boot/Makefile
@@ -0,0 +1,171 @@
1#
2# arch/x86/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 setup.bin setup.elf zImage bzImage
29subdir- := compressed
30
31setup-y += a20.o apm.o cmdline.o copy.o cpu.o cpucheck.o edd.o
32setup-y += header.o main.o mca.o memory.o pm.o pmjump.o
33setup-y += printf.o string.o tty.o video.o version.o voyager.o
34
35# The link order of the video-*.o modules can matter. In particular,
36# video-vga.o *must* be listed first, followed by video-vesa.o.
37# Hardware-specific drivers should follow in the order they should be
38# probed, and video-bios.o should typically be last.
39setup-y += video-vga.o
40setup-y += video-vesa.o
41setup-y += video-bios.o
42targets += $(setup-y)
43hostprogs-y := tools/build
44
45HOSTCFLAGS_build.o := $(LINUXINCLUDE)
46
47# ---------------------------------------------------------------------------
48
49# How to compile the 16-bit code. Note we always compile for -march=i386,
50# that way we can complain to the user if the CPU is insufficient.
51cflags-i386 :=
52cflags-x86_64 := -m32
53CFLAGS := $(LINUXINCLUDE) -g -Os -D_SETUP -D__KERNEL__ \
54 $(cflags-$(ARCH)) \
55 -Wall -Wstrict-prototypes \
56 -march=i386 -mregparm=3 \
57 -include $(srctree)/$(src)/code16gcc.h \
58 -fno-strict-aliasing -fomit-frame-pointer \
59 $(call cc-option, -ffreestanding) \
60 $(call cc-option, -fno-toplevel-reorder,\
61 $(call cc-option, -fno-unit-at-a-time)) \
62 $(call cc-option, -fno-stack-protector) \
63 $(call cc-option, -mpreferred-stack-boundary=2)
64AFLAGS := $(CFLAGS) -D__ASSEMBLY__
65
66$(obj)/zImage: IMAGE_OFFSET := 0x1000
67$(obj)/zImage: EXTRA_AFLAGS := $(SVGA_MODE) $(RAMDISK)
68$(obj)/bzImage: IMAGE_OFFSET := 0x100000
69$(obj)/bzImage: EXTRA_CFLAGS := -D__BIG_KERNEL__
70$(obj)/bzImage: EXTRA_AFLAGS := $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__
71$(obj)/bzImage: BUILDFLAGS := -b
72
73quiet_cmd_image = BUILD $@
74cmd_image = $(obj)/tools/build $(BUILDFLAGS) $(obj)/setup.bin \
75 $(obj)/vmlinux.bin $(ROOT_DEV) > $@
76
77$(obj)/zImage $(obj)/bzImage: $(obj)/setup.bin \
78 $(obj)/vmlinux.bin $(obj)/tools/build FORCE
79 $(call if_changed,image)
80 @echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
81
82$(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
83 $(call if_changed,objcopy)
84
85SETUP_OBJS = $(addprefix $(obj)/,$(setup-y))
86
87LDFLAGS_setup.elf := -T
88$(obj)/setup.elf: $(src)/setup.ld $(SETUP_OBJS) FORCE
89 $(call if_changed,ld)
90
91OBJCOPYFLAGS_setup.bin := -O binary
92
93$(obj)/setup.bin: $(obj)/setup.elf FORCE
94 $(call if_changed,objcopy)
95
96$(obj)/compressed/vmlinux: FORCE
97 $(Q)$(MAKE) $(build)=$(obj)/compressed IMAGE_OFFSET=$(IMAGE_OFFSET) $@
98
99# Set this if you want to pass append arguments to the zdisk/fdimage/isoimage kernel
100FDARGS =
101# Set this if you want an initrd included with the zdisk/fdimage/isoimage kernel
102FDINITRD =
103
104image_cmdline = default linux $(FDARGS) $(if $(FDINITRD),initrd=initrd.img,)
105
106$(obj)/mtools.conf: $(src)/mtools.conf.in
107 sed -e 's|@OBJ@|$(obj)|g' < $< > $@
108
109# This requires write access to /dev/fd0
110zdisk: $(BOOTIMAGE) $(obj)/mtools.conf
111 MTOOLSRC=$(obj)/mtools.conf mformat a: ; sync
112 syslinux /dev/fd0 ; sync
113 echo '$(image_cmdline)' | \
114 MTOOLSRC=$(src)/mtools.conf mcopy - a:syslinux.cfg
115 if [ -f '$(FDINITRD)' ] ; then \
116 MTOOLSRC=$(obj)/mtools.conf mcopy '$(FDINITRD)' a:initrd.img ; \
117 fi
118 MTOOLSRC=$(obj)/mtools.conf mcopy $(BOOTIMAGE) a:linux ; sync
119
120# These require being root or having syslinux 2.02 or higher installed
121fdimage fdimage144: $(BOOTIMAGE) $(obj)/mtools.conf
122 dd if=/dev/zero of=$(obj)/fdimage bs=1024 count=1440
123 MTOOLSRC=$(obj)/mtools.conf mformat v: ; sync
124 syslinux $(obj)/fdimage ; sync
125 echo '$(image_cmdline)' | \
126 MTOOLSRC=$(obj)/mtools.conf mcopy - v:syslinux.cfg
127 if [ -f '$(FDINITRD)' ] ; then \
128 MTOOLSRC=$(obj)/mtools.conf mcopy '$(FDINITRD)' v:initrd.img ; \
129 fi
130 MTOOLSRC=$(obj)/mtools.conf mcopy $(BOOTIMAGE) v:linux ; sync
131
132fdimage288: $(BOOTIMAGE) $(obj)/mtools.conf
133 dd if=/dev/zero of=$(obj)/fdimage bs=1024 count=2880
134 MTOOLSRC=$(obj)/mtools.conf mformat w: ; sync
135 syslinux $(obj)/fdimage ; sync
136 echo '$(image_cmdline)' | \
137 MTOOLSRC=$(obj)/mtools.conf mcopy - w:syslinux.cfg
138 if [ -f '$(FDINITRD)' ] ; then \
139 MTOOLSRC=$(obj)/mtools.conf mcopy '$(FDINITRD)' w:initrd.img ; \
140 fi
141 MTOOLSRC=$(obj)/mtools.conf mcopy $(BOOTIMAGE) w:linux ; sync
142
143isoimage: $(BOOTIMAGE)
144 -rm -rf $(obj)/isoimage
145 mkdir $(obj)/isoimage
146 for i in lib lib64 share end ; do \
147 if [ -f /usr/$$i/syslinux/isolinux.bin ] ; then \
148 cp /usr/$$i/syslinux/isolinux.bin $(obj)/isoimage ; \
149 break ; \
150 fi ; \
151 if [ $$i = end ] ; then exit 1 ; fi ; \
152 done
153 cp $(BOOTIMAGE) $(obj)/isoimage/linux
154 echo '$(image_cmdline)' > $(obj)/isoimage/isolinux.cfg
155 if [ -f '$(FDINITRD)' ] ; then \
156 cp '$(FDINITRD)' $(obj)/isoimage/initrd.img ; \
157 fi
158 mkisofs -J -r -o $(obj)/image.iso -b isolinux.bin -c boot.cat \
159 -no-emul-boot -boot-load-size 4 -boot-info-table \
160 $(obj)/isoimage
161 rm -rf $(obj)/isoimage
162
163zlilo: $(BOOTIMAGE)
164 if [ -f $(INSTALL_PATH)/vmlinuz ]; then mv $(INSTALL_PATH)/vmlinuz $(INSTALL_PATH)/vmlinuz.old; fi
165 if [ -f $(INSTALL_PATH)/System.map ]; then mv $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
166 cat $(BOOTIMAGE) > $(INSTALL_PATH)/vmlinuz
167 cp System.map $(INSTALL_PATH)/
168 if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
169
170install:
171 sh $(srctree)/$(src)/install.sh $(KERNELRELEASE) $(BOOTIMAGE) System.map "$(INSTALL_PATH)"
diff --git a/arch/x86/boot/a20.c b/arch/x86/boot/a20.c
new file mode 100644
index 000000000000..31348d054fca
--- /dev/null
+++ b/arch/x86/boot/a20.c
@@ -0,0 +1,161 @@
1/* -*- linux-c -*- ------------------------------------------------------- *
2 *
3 * Copyright (C) 1991, 1992 Linus Torvalds
4 * Copyright 2007 rPath, Inc. - All Rights Reserved
5 *
6 * This file is part of the Linux kernel, and is made available under
7 * the terms of the GNU General Public License version 2.
8 *
9 * ----------------------------------------------------------------------- */
10
11/*
12 * arch/i386/boot/a20.c
13 *
14 * Enable A20 gate (return -1 on failure)
15 */
16
17#include "boot.h"
18
19#define MAX_8042_LOOPS 100000
20
21static int empty_8042(void)
22{
23 u8 status;
24 int loops = MAX_8042_LOOPS;
25
26 while (loops--) {
27 io_delay();
28
29 status = inb(0x64);
30 if (status & 1) {
31 /* Read and discard input data */
32 io_delay();
33 (void)inb(0x60);
34 } else if (!(status & 2)) {
35 /* Buffers empty, finished! */
36 return 0;
37 }
38 }
39
40 return -1;
41}
42
43/* Returns nonzero if the A20 line is enabled. The memory address
44 used as a test is the int $0x80 vector, which should be safe. */
45
46#define A20_TEST_ADDR (4*0x80)
47#define A20_TEST_SHORT 32
48#define A20_TEST_LONG 2097152 /* 2^21 */
49
50static int a20_test(int loops)
51{
52 int ok = 0;
53 int saved, ctr;
54
55 set_fs(0x0000);
56 set_gs(0xffff);
57
58 saved = ctr = rdfs32(A20_TEST_ADDR);
59
60 while (loops--) {
61 wrfs32(++ctr, A20_TEST_ADDR);
62 io_delay(); /* Serialize and make delay constant */
63 ok = rdgs32(A20_TEST_ADDR+0x10) ^ ctr;
64 if (ok)
65 break;
66 }
67
68 wrfs32(saved, A20_TEST_ADDR);
69 return ok;
70}
71
72/* Quick test to see if A20 is already enabled */
73static int a20_test_short(void)
74{
75 return a20_test(A20_TEST_SHORT);
76}
77
78/* Longer test that actually waits for A20 to come on line; this
79 is useful when dealing with the KBC or other slow external circuitry. */
80static int a20_test_long(void)
81{
82 return a20_test(A20_TEST_LONG);
83}
84
85static void enable_a20_bios(void)
86{
87 asm volatile("pushfl; int $0x15; popfl"
88 : : "a" ((u16)0x2401));
89}
90
91static void enable_a20_kbc(void)
92{
93 empty_8042();
94
95 outb(0xd1, 0x64); /* Command write */
96 empty_8042();
97
98 outb(0xdf, 0x60); /* A20 on */
99 empty_8042();
100}
101
102static void enable_a20_fast(void)
103{
104 u8 port_a;
105
106 port_a = inb(0x92); /* Configuration port A */
107 port_a |= 0x02; /* Enable A20 */
108 port_a &= ~0x01; /* Do not reset machine */
109 outb(port_a, 0x92);
110}
111
112/*
113 * Actual routine to enable A20; return 0 on ok, -1 on failure
114 */
115
116#define A20_ENABLE_LOOPS 255 /* Number of times to try */
117
118int enable_a20(void)
119{
120 int loops = A20_ENABLE_LOOPS;
121
122#if defined(CONFIG_X86_ELAN)
123 /* Elan croaks if we try to touch the KBC */
124 enable_a20_fast();
125 while (!a20_test_long())
126 ;
127 return 0;
128#elif defined(CONFIG_X86_VOYAGER)
129 /* On Voyager, a20_test() is unsafe? */
130 enable_a20_kbc();
131 return 0;
132#else
133 while (loops--) {
134 /* First, check to see if A20 is already enabled
135 (legacy free, etc.) */
136 if (a20_test_short())
137 return 0;
138
139 /* Next, try the BIOS (INT 0x15, AX=0x2401) */
140 enable_a20_bios();
141 if (a20_test_short())
142 return 0;
143
144 /* Try enabling A20 through the keyboard controller */
145 empty_8042();
146 if (a20_test_short())
147 return 0; /* BIOS worked, but with delayed reaction */
148
149 enable_a20_kbc();
150 if (a20_test_long())
151 return 0;
152
153 /* Finally, try enabling the "fast A20 gate" */
154 enable_a20_fast();
155 if (a20_test_long())
156 return 0;
157 }
158
159 return -1;
160#endif
161}
diff --git a/arch/x86/boot/apm.c b/arch/x86/boot/apm.c
new file mode 100644
index 000000000000..eab50c55a3a5
--- /dev/null
+++ b/arch/x86/boot/apm.c
@@ -0,0 +1,98 @@
1/* -*- linux-c -*- ------------------------------------------------------- *
2 *
3 * Copyright (C) 1991, 1992 Linus Torvalds
4 * Copyright 2007 rPath, Inc. - All Rights Reserved
5 *
6 * Original APM BIOS checking by Stephen Rothwell, May 1994
7 * (sfr@canb.auug.org.au)
8 *
9 * This file is part of the Linux kernel, and is made available under
10 * the terms of the GNU General Public License version 2.
11 *
12 * ----------------------------------------------------------------------- */
13
14/*
15 * arch/i386/boot/apm.c
16 *
17 * Get APM BIOS information
18 */
19
20#include "boot.h"
21
22#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
23
24int query_apm_bios(void)
25{
26 u16 ax, bx, cx, dx, di;
27 u32 ebx, esi;
28 u8 err;
29
30 /* APM BIOS installation check */
31 ax = 0x5300;
32 bx = cx = 0;
33 asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %0"
34 : "=d" (err), "+a" (ax), "+b" (bx), "+c" (cx)
35 : : "esi", "edi");
36
37 if (err)
38 return -1; /* No APM BIOS */
39
40 if (bx != 0x504d) /* "PM" signature */
41 return -1;
42
43 if (!(cx & 0x02)) /* 32 bits supported? */
44 return -1;
45
46 /* Disconnect first, just in case */
47 ax = 0x5304;
48 bx = 0;
49 asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp"
50 : "+a" (ax), "+b" (bx)
51 : : "ecx", "edx", "esi", "edi");
52
53 /* Paranoia */
54 ebx = esi = 0;
55 cx = dx = di = 0;
56
57 /* 32-bit connect */
58 asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %6"
59 : "=a" (ax), "+b" (ebx), "+c" (cx), "+d" (dx),
60 "+S" (esi), "+D" (di), "=m" (err)
61 : "a" (0x5303));
62
63 boot_params.apm_bios_info.cseg = ax;
64 boot_params.apm_bios_info.offset = ebx;
65 boot_params.apm_bios_info.cseg_16 = cx;
66 boot_params.apm_bios_info.dseg = dx;
67 boot_params.apm_bios_info.cseg_len = (u16)esi;
68 boot_params.apm_bios_info.cseg_16_len = esi >> 16;
69 boot_params.apm_bios_info.dseg_len = di;
70
71 if (err)
72 return -1;
73
74 /* Redo the installation check as the 32-bit connect;
75 some BIOSes return different flags this way... */
76
77 ax = 0x5300;
78 bx = cx = 0;
79 asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %0"
80 : "=d" (err), "+a" (ax), "+b" (bx), "+c" (cx)
81 : : "esi", "edi");
82
83 if (err || bx != 0x504d) {
84 /* Failure with 32-bit connect, try to disconect and ignore */
85 ax = 0x5304;
86 bx = 0;
87 asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp"
88 : "+a" (ax), "+b" (bx)
89 : : "ecx", "edx", "esi", "edi");
90 return -1;
91 }
92
93 boot_params.apm_bios_info.version = ax;
94 boot_params.apm_bios_info.flags = cx;
95 return 0;
96}
97
98#endif
diff --git a/arch/x86/boot/bitops.h b/arch/x86/boot/bitops.h
new file mode 100644
index 000000000000..8dcc8dc7db88
--- /dev/null
+++ b/arch/x86/boot/bitops.h
@@ -0,0 +1,45 @@
1/* -*- linux-c -*- ------------------------------------------------------- *
2 *
3 * Copyright (C) 1991, 1992 Linus Torvalds
4 * Copyright 2007 rPath, Inc. - All Rights Reserved
5 *
6 * This file is part of the Linux kernel, and is made available under
7 * the terms of the GNU General Public License version 2.
8 *
9 * ----------------------------------------------------------------------- */
10
11/*
12 * arch/i386/boot/bitops.h
13 *
14 * Very simple bitops for the boot code.
15 */
16
17#ifndef BOOT_BITOPS_H
18#define BOOT_BITOPS_H
19#define _LINUX_BITOPS_H /* Inhibit inclusion of <linux/bitops.h> */
20
21static inline int constant_test_bit(int nr, const void *addr)
22{
23 const u32 *p = (const u32 *)addr;
24 return ((1UL << (nr & 31)) & (p[nr >> 5])) != 0;
25}
26static inline int variable_test_bit(int nr, const void *addr)
27{
28 u8 v;
29 const u32 *p = (const u32 *)addr;
30
31 asm("btl %2,%1; setc %0" : "=qm" (v) : "m" (*p), "Ir" (nr));
32 return v;
33}
34
35#define test_bit(nr,addr) \
36(__builtin_constant_p(nr) ? \
37 constant_test_bit((nr),(addr)) : \
38 variable_test_bit((nr),(addr)))
39
40static inline void set_bit(int nr, void *addr)
41{
42 asm("btsl %1,%0" : "+m" (*(u32 *)addr) : "Ir" (nr));
43}
44
45#endif /* BOOT_BITOPS_H */
diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h
new file mode 100644
index 000000000000..20bab9431acb
--- /dev/null
+++ b/arch/x86/boot/boot.h
@@ -0,0 +1,296 @@
1/* -*- linux-c -*- ------------------------------------------------------- *
2 *
3 * Copyright (C) 1991, 1992 Linus Torvalds
4 * Copyright 2007 rPath, Inc. - All Rights Reserved
5 *
6 * This file is part of the Linux kernel, and is made available under
7 * the terms of the GNU General Public License version 2.
8 *
9 * ----------------------------------------------------------------------- */
10
11/*
12 * arch/i386/boot/boot.h
13 *
14 * Header file for the real-mode kernel code
15 */
16
17#ifndef BOOT_BOOT_H
18#define BOOT_BOOT_H
19
20#ifndef __ASSEMBLY__
21
22#include <stdarg.h>
23#include <linux/types.h>
24#include <linux/edd.h>
25#include <asm/boot.h>
26#include <asm/bootparam.h>
27
28/* Useful macros */
29#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
30
31extern struct setup_header hdr;
32extern struct boot_params boot_params;
33
34/* Basic port I/O */
35static inline void outb(u8 v, u16 port)
36{
37 asm volatile("outb %0,%1" : : "a" (v), "dN" (port));
38}
39static inline u8 inb(u16 port)
40{
41 u8 v;
42 asm volatile("inb %1,%0" : "=a" (v) : "dN" (port));
43 return v;
44}
45
46static inline void outw(u16 v, u16 port)
47{
48 asm volatile("outw %0,%1" : : "a" (v), "dN" (port));
49}
50static inline u16 inw(u16 port)
51{
52 u16 v;
53 asm volatile("inw %1,%0" : "=a" (v) : "dN" (port));
54 return v;
55}
56
57static inline void outl(u32 v, u16 port)
58{
59 asm volatile("outl %0,%1" : : "a" (v), "dN" (port));
60}
61static inline u32 inl(u32 port)
62{
63 u32 v;
64 asm volatile("inl %1,%0" : "=a" (v) : "dN" (port));
65 return v;
66}
67
68static inline void io_delay(void)
69{
70 const u16 DELAY_PORT = 0x80;
71 asm volatile("outb %%al,%0" : : "dN" (DELAY_PORT));
72}
73
74/* These functions are used to reference data in other segments. */
75
76static inline u16 ds(void)
77{
78 u16 seg;
79 asm("movw %%ds,%0" : "=rm" (seg));
80 return seg;
81}
82
83static inline void set_fs(u16 seg)
84{
85 asm volatile("movw %0,%%fs" : : "rm" (seg));
86}
87static inline u16 fs(void)
88{
89 u16 seg;
90 asm volatile("movw %%fs,%0" : "=rm" (seg));
91 return seg;
92}
93
94static inline void set_gs(u16 seg)
95{
96 asm volatile("movw %0,%%gs" : : "rm" (seg));
97}
98static inline u16 gs(void)
99{
100 u16 seg;
101 asm volatile("movw %%gs,%0" : "=rm" (seg));
102 return seg;
103}
104
105typedef unsigned int addr_t;
106
107static inline u8 rdfs8(addr_t addr)
108{
109 u8 v;
110 asm volatile("movb %%fs:%1,%0" : "=r" (v) : "m" (*(u8 *)addr));
111 return v;
112}
113static inline u16 rdfs16(addr_t addr)
114{
115 u16 v;
116 asm volatile("movw %%fs:%1,%0" : "=r" (v) : "m" (*(u16 *)addr));
117 return v;
118}
119static inline u32 rdfs32(addr_t addr)
120{
121 u32 v;
122 asm volatile("movl %%fs:%1,%0" : "=r" (v) : "m" (*(u32 *)addr));
123 return v;
124}
125
126static inline void wrfs8(u8 v, addr_t addr)
127{
128 asm volatile("movb %1,%%fs:%0" : "+m" (*(u8 *)addr) : "r" (v));
129}
130static inline void wrfs16(u16 v, addr_t addr)
131{
132 asm volatile("movw %1,%%fs:%0" : "+m" (*(u16 *)addr) : "r" (v));
133}
134static inline void wrfs32(u32 v, addr_t addr)
135{
136 asm volatile("movl %1,%%fs:%0" : "+m" (*(u32 *)addr) : "r" (v));
137}
138
139static inline u8 rdgs8(addr_t addr)
140{
141 u8 v;
142 asm volatile("movb %%gs:%1,%0" : "=r" (v) : "m" (*(u8 *)addr));
143 return v;
144}
145static inline u16 rdgs16(addr_t addr)
146{
147 u16 v;
148 asm volatile("movw %%gs:%1,%0" : "=r" (v) : "m" (*(u16 *)addr));
149 return v;
150}
151static inline u32 rdgs32(addr_t addr)
152{
153 u32 v;
154 asm volatile("movl %%gs:%1,%0" : "=r" (v) : "m" (*(u32 *)addr));
155 return v;
156}
157
158static inline void wrgs8(u8 v, addr_t addr)
159{
160 asm volatile("movb %1,%%gs:%0" : "+m" (*(u8 *)addr) : "r" (v));
161}
162static inline void wrgs16(u16 v, addr_t addr)
163{
164 asm volatile("movw %1,%%gs:%0" : "+m" (*(u16 *)addr) : "r" (v));
165}
166static inline void wrgs32(u32 v, addr_t addr)
167{
168 asm volatile("movl %1,%%gs:%0" : "+m" (*(u32 *)addr) : "r" (v));
169}
170
171/* Note: these only return true/false, not a signed return value! */
172static inline int memcmp(const void *s1, const void *s2, size_t len)
173{
174 u8 diff;
175 asm("repe; cmpsb; setnz %0"
176 : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len));
177 return diff;
178}
179
180static inline int memcmp_fs(const void *s1, addr_t s2, size_t len)
181{
182 u8 diff;
183 asm volatile("fs; repe; cmpsb; setnz %0"
184 : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len));
185 return diff;
186}
187static inline int memcmp_gs(const void *s1, addr_t s2, size_t len)
188{
189 u8 diff;
190 asm volatile("gs; repe; cmpsb; setnz %0"
191 : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len));
192 return diff;
193}
194
195static inline int isdigit(int ch)
196{
197 return (ch >= '0') && (ch <= '9');
198}
199
200/* Heap -- available for dynamic lists. */
201#define STACK_SIZE 512 /* Minimum number of bytes for stack */
202
203extern char _end[];
204extern char *HEAP;
205extern char *heap_end;
206#define RESET_HEAP() ((void *)( HEAP = _end ))
207static inline char *__get_heap(size_t s, size_t a, size_t n)
208{
209 char *tmp;
210
211 HEAP = (char *)(((size_t)HEAP+(a-1)) & ~(a-1));
212 tmp = HEAP;
213 HEAP += s*n;
214 return tmp;
215}
216#define GET_HEAP(type, n) \
217 ((type *)__get_heap(sizeof(type),__alignof__(type),(n)))
218
219static inline int heap_free(void)
220{
221 return heap_end-HEAP;
222}
223
224/* copy.S */
225
226void copy_to_fs(addr_t dst, void *src, size_t len);
227void *copy_from_fs(void *dst, addr_t src, size_t len);
228void copy_to_gs(addr_t dst, void *src, size_t len);
229void *copy_from_gs(void *dst, addr_t src, size_t len);
230void *memcpy(void *dst, void *src, size_t len);
231void *memset(void *dst, int c, size_t len);
232
233#define memcpy(d,s,l) __builtin_memcpy(d,s,l)
234#define memset(d,c,l) __builtin_memset(d,c,l)
235
236/* a20.c */
237int enable_a20(void);
238
239/* apm.c */
240int query_apm_bios(void);
241
242/* cmdline.c */
243int cmdline_find_option(const char *option, char *buffer, int bufsize);
244
245/* cpu.c, cpucheck.c */
246int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr);
247int validate_cpu(void);
248
249/* edd.c */
250void query_edd(void);
251
252/* header.S */
253void __attribute__((noreturn)) die(void);
254
255/* mca.c */
256int query_mca(void);
257
258/* memory.c */
259int detect_memory(void);
260
261/* pm.c */
262void __attribute__((noreturn)) go_to_protected_mode(void);
263
264/* pmjump.S */
265void __attribute__((noreturn))
266 protected_mode_jump(u32 entrypoint, u32 bootparams);
267
268/* printf.c */
269int sprintf(char *buf, const char *fmt, ...);
270int vsprintf(char *buf, const char *fmt, va_list args);
271int printf(const char *fmt, ...);
272
273/* string.c */
274int strcmp(const char *str1, const char *str2);
275size_t strnlen(const char *s, size_t maxlen);
276unsigned int atou(const char *s);
277
278/* tty.c */
279void puts(const char *);
280void putchar(int);
281int getchar(void);
282void kbd_flush(void);
283int getchar_timeout(void);
284
285/* video.c */
286void set_video(void);
287
288/* video-vesa.c */
289void vesa_store_edid(void);
290
291/* voyager.c */
292int query_voyager(void);
293
294#endif /* __ASSEMBLY__ */
295
296#endif /* BOOT_BOOT_H */
diff --git a/arch/x86/boot/cmdline.c b/arch/x86/boot/cmdline.c
new file mode 100644
index 000000000000..34bb778c4357
--- /dev/null
+++ b/arch/x86/boot/cmdline.c
@@ -0,0 +1,97 @@
1/* -*- linux-c -*- ------------------------------------------------------- *
2 *
3 * Copyright (C) 1991, 1992 Linus Torvalds
4 * Copyright 2007 rPath, Inc. - All Rights Reserved
5 *
6 * This file is part of the Linux kernel, and is made available under
7 * the terms of the GNU General Public License version 2.
8 *
9 * ----------------------------------------------------------------------- */
10
11/*
12 * arch/i386/boot/cmdline.c
13 *
14 * Simple command-line parser for early boot.
15 */
16
17#include "boot.h"
18
19static inline int myisspace(u8 c)
20{
21 return c <= ' '; /* Close enough approximation */
22}
23
24/*
25 * Find a non-boolean option, that is, "option=argument". In accordance
26 * with standard Linux practice, if this option is repeated, this returns
27 * the last instance on the command line.
28 *
29 * Returns the length of the argument (regardless of if it was
30 * truncated to fit in the buffer), or -1 on not found.
31 */
32int cmdline_find_option(const char *option, char *buffer, int bufsize)
33{
34 u32 cmdline_ptr = boot_params.hdr.cmd_line_ptr;
35 addr_t cptr;
36 char c;
37 int len = -1;
38 const char *opptr = NULL;
39 char *bufptr = buffer;
40 enum {
41 st_wordstart, /* Start of word/after whitespace */
42 st_wordcmp, /* Comparing this word */
43 st_wordskip, /* Miscompare, skip */
44 st_bufcpy /* Copying this to buffer */
45 } state = st_wordstart;
46
47 if (!cmdline_ptr || cmdline_ptr >= 0x100000)
48 return -1; /* No command line, or inaccessible */
49
50 cptr = cmdline_ptr & 0xf;
51 set_fs(cmdline_ptr >> 4);
52
53 while (cptr < 0x10000 && (c = rdfs8(cptr++))) {
54 switch (state) {
55 case st_wordstart:
56 if (myisspace(c))
57 break;
58
59 /* else */
60 state = st_wordcmp;
61 opptr = option;
62 /* fall through */
63
64 case st_wordcmp:
65 if (c == '=' && !*opptr) {
66 len = 0;
67 bufptr = buffer;
68 state = st_bufcpy;
69 } else if (myisspace(c)) {
70 state = st_wordstart;
71 } else if (c != *opptr++) {
72 state = st_wordskip;
73 }
74 break;
75
76 case st_wordskip:
77 if (myisspace(c))
78 state = st_wordstart;
79 break;
80
81 case st_bufcpy:
82 if (myisspace(c)) {
83 state = st_wordstart;
84 } else {
85 if (len < bufsize-1)
86 *bufptr++ = c;
87 len++;
88 }
89 break;
90 }
91 }
92
93 if (bufsize)
94 *bufptr = '\0';
95
96 return len;
97}
diff --git a/arch/x86/boot/code16gcc.h b/arch/x86/boot/code16gcc.h
new file mode 100644
index 000000000000..d93e48010b61
--- /dev/null
+++ b/arch/x86/boot/code16gcc.h
@@ -0,0 +1,15 @@
1/*
2 * code16gcc.h
3 *
4 * This file is -include'd when compiling 16-bit C code.
5 * Note: this asm() needs to be emitted before gcc emits any code.
6 * Depending on gcc version, this requires -fno-unit-at-a-time or
7 * -fno-toplevel-reorder.
8 *
9 * Hopefully gcc will eventually have a real -m16 option so we can
10 * drop this hack long term.
11 */
12
13#ifndef __ASSEMBLY__
14asm(".code16gcc");
15#endif
diff --git a/arch/x86/boot/copy.S b/arch/x86/boot/copy.S
new file mode 100644
index 000000000000..ef127e56a3cf
--- /dev/null
+++ b/arch/x86/boot/copy.S
@@ -0,0 +1,101 @@
1/* ----------------------------------------------------------------------- *
2 *
3 * Copyright (C) 1991, 1992 Linus Torvalds
4 * Copyright 2007 rPath, Inc. - All Rights Reserved
5 *
6 * This file is part of the Linux kernel, and is made available under
7 * the terms of the GNU General Public License version 2.
8 *
9 * ----------------------------------------------------------------------- */
10
11/*
12 * arch/i386/boot/copy.S
13 *
14 * Memory copy routines
15 */
16
17 .code16gcc
18 .text
19
20 .globl memcpy
21 .type memcpy, @function
22memcpy:
23 pushw %si
24 pushw %di
25 movw %ax, %di
26 movw %dx, %si
27 pushw %cx
28 shrw $2, %cx
29 rep; movsl
30 popw %cx
31 andw $3, %cx
32 rep; movsb
33 popw %di
34 popw %si
35 ret
36 .size memcpy, .-memcpy
37
38 .globl memset
39 .type memset, @function
40memset:
41 pushw %di
42 movw %ax, %di
43 movzbl %dl, %eax
44 imull $0x01010101,%eax
45 pushw %cx
46 shrw $2, %cx
47 rep; stosl
48 popw %cx
49 andw $3, %cx
50 rep; stosb
51 popw %di
52 ret
53 .size memset, .-memset
54
55 .globl copy_from_fs
56 .type copy_from_fs, @function
57copy_from_fs:
58 pushw %ds
59 pushw %fs
60 popw %ds
61 call memcpy
62 popw %ds
63 ret
64 .size copy_from_fs, .-copy_from_fs
65
66 .globl copy_to_fs
67 .type copy_to_fs, @function
68copy_to_fs:
69 pushw %es
70 pushw %fs
71 popw %es
72 call memcpy
73 popw %es
74 ret
75 .size copy_to_fs, .-copy_to_fs
76
77#if 0 /* Not currently used, but can be enabled as needed */
78
79 .globl copy_from_gs
80 .type copy_from_gs, @function
81copy_from_gs:
82 pushw %ds
83 pushw %gs
84 popw %ds
85 call memcpy
86 popw %ds
87 ret
88 .size copy_from_gs, .-copy_from_gs
89 .globl copy_to_gs
90
91 .type copy_to_gs, @function
92copy_to_gs:
93 pushw %es
94 pushw %gs
95 popw %es
96 call memcpy
97 popw %es
98 ret
99 .size copy_to_gs, .-copy_to_gs
100
101#endif
diff --git a/arch/x86/boot/cpu.c b/arch/x86/boot/cpu.c
new file mode 100644
index 000000000000..2a5c32da5852
--- /dev/null
+++ b/arch/x86/boot/cpu.c
@@ -0,0 +1,69 @@
1/* -*- linux-c -*- ------------------------------------------------------- *
2 *
3 * Copyright (C) 1991, 1992 Linus Torvalds
4 * Copyright 2007 rPath, Inc. - All Rights Reserved
5 *
6 * This file is part of the Linux kernel, and is made available under
7 * the terms of the GNU General Public License version 2.
8 *
9 * ----------------------------------------------------------------------- */
10
11/*
12 * arch/i386/boot/cpu.c
13 *
14 * Check for obligatory CPU features and abort if the features are not
15 * present.
16 */
17
18#include "boot.h"
19#include "bitops.h"
20#include <asm/cpufeature.h>
21
22static char *cpu_name(int level)
23{
24 static char buf[6];
25
26 if (level == 64) {
27 return "x86-64";
28 } else {
29 sprintf(buf, "i%d86", level);
30 return buf;
31 }
32}
33
34int validate_cpu(void)
35{
36 u32 *err_flags;
37 int cpu_level, req_level;
38
39 check_cpu(&cpu_level, &req_level, &err_flags);
40
41 if (cpu_level < req_level) {
42 printf("This kernel requires an %s CPU, ",
43 cpu_name(req_level));
44 printf("but only detected an %s CPU.\n",
45 cpu_name(cpu_level));
46 return -1;
47 }
48
49 if (err_flags) {
50 int i, j;
51 puts("This kernel requires the following features "
52 "not present on the CPU:\n");
53
54 for (i = 0; i < NCAPINTS; i++) {
55 u32 e = err_flags[i];
56
57 for (j = 0; j < 32; j++) {
58 if (e & 1)
59 printf("%d:%d ", i, j);
60
61 e >>= 1;
62 }
63 }
64 putchar('\n');
65 return -1;
66 } else {
67 return 0;
68 }
69}
diff --git a/arch/x86/boot/cpucheck.c b/arch/x86/boot/cpucheck.c
new file mode 100644
index 000000000000..e655a89c5510
--- /dev/null
+++ b/arch/x86/boot/cpucheck.c
@@ -0,0 +1,268 @@
1/* -*- linux-c -*- ------------------------------------------------------- *
2 *
3 * Copyright (C) 1991, 1992 Linus Torvalds
4 * Copyright 2007 rPath, Inc. - All Rights Reserved
5 *
6 * This file is part of the Linux kernel, and is made available under
7 * the terms of the GNU General Public License version 2.
8 *
9 * ----------------------------------------------------------------------- */
10
11/*
12 * arch/i386/boot/cpucheck.c
13 *
14 * Check for obligatory CPU features and abort if the features are not
15 * present. This code should be compilable as 16-, 32- or 64-bit
16 * code, so be very careful with types and inline assembly.
17 *
18 * This code should not contain any messages; that requires an
19 * additional wrapper.
20 *
21 * As written, this code is not safe for inclusion into the kernel
22 * proper (after FPU initialization, in particular).
23 */
24
25#ifdef _SETUP
26# include "boot.h"
27# include "bitops.h"
28#endif
29#include <linux/types.h>
30#include <asm/cpufeature.h>
31#include <asm/processor-flags.h>
32#include <asm/required-features.h>
33#include <asm/msr-index.h>
34
35struct cpu_features {
36 int level; /* Family, or 64 for x86-64 */
37 int model;
38 u32 flags[NCAPINTS];
39};
40
41static struct cpu_features cpu;
42static u32 cpu_vendor[3];
43static u32 err_flags[NCAPINTS];
44
45#ifdef CONFIG_X86_64
46static const int req_level = 64;
47#elif defined(CONFIG_X86_MINIMUM_CPU_FAMILY)
48static const int req_level = CONFIG_X86_MINIMUM_CPU_FAMILY;
49#else
50static const int req_level = 3;
51#endif
52
53static const u32 req_flags[NCAPINTS] =
54{
55 REQUIRED_MASK0,
56 REQUIRED_MASK1,
57 REQUIRED_MASK2,
58 REQUIRED_MASK3,
59 REQUIRED_MASK4,
60 REQUIRED_MASK5,
61 REQUIRED_MASK6,
62 REQUIRED_MASK7,
63};
64
65#define A32(a,b,c,d) (((d) << 24)+((c) << 16)+((b) << 8)+(a))
66
67static int is_amd(void)
68{
69 return cpu_vendor[0] == A32('A','u','t','h') &&
70 cpu_vendor[1] == A32('e','n','t','i') &&
71 cpu_vendor[2] == A32('c','A','M','D');
72}
73
74static int is_centaur(void)
75{
76 return cpu_vendor[0] == A32('C','e','n','t') &&
77 cpu_vendor[1] == A32('a','u','r','H') &&
78 cpu_vendor[2] == A32('a','u','l','s');
79}
80
81static int is_transmeta(void)
82{
83 return cpu_vendor[0] == A32('G','e','n','u') &&
84 cpu_vendor[1] == A32('i','n','e','T') &&
85 cpu_vendor[2] == A32('M','x','8','6');
86}
87
88static int has_fpu(void)
89{
90 u16 fcw = -1, fsw = -1;
91 u32 cr0;
92
93 asm("movl %%cr0,%0" : "=r" (cr0));
94 if (cr0 & (X86_CR0_EM|X86_CR0_TS)) {
95 cr0 &= ~(X86_CR0_EM|X86_CR0_TS);
96 asm volatile("movl %0,%%cr0" : : "r" (cr0));
97 }
98
99 asm volatile("fninit ; fnstsw %0 ; fnstcw %1"
100 : "+m" (fsw), "+m" (fcw));
101
102 return fsw == 0 && (fcw & 0x103f) == 0x003f;
103}
104
105static int has_eflag(u32 mask)
106{
107 u32 f0, f1;
108
109 asm("pushfl ; "
110 "pushfl ; "
111 "popl %0 ; "
112 "movl %0,%1 ; "
113 "xorl %2,%1 ; "
114 "pushl %1 ; "
115 "popfl ; "
116 "pushfl ; "
117 "popl %1 ; "
118 "popfl"
119 : "=&r" (f0), "=&r" (f1)
120 : "ri" (mask));
121
122 return !!((f0^f1) & mask);
123}
124
125static void get_flags(void)
126{
127 u32 max_intel_level, max_amd_level;
128 u32 tfms;
129
130 if (has_fpu())
131 set_bit(X86_FEATURE_FPU, cpu.flags);
132
133 if (has_eflag(X86_EFLAGS_ID)) {
134 asm("cpuid"
135 : "=a" (max_intel_level),
136 "=b" (cpu_vendor[0]),
137 "=d" (cpu_vendor[1]),
138 "=c" (cpu_vendor[2])
139 : "a" (0));
140
141 if (max_intel_level >= 0x00000001 &&
142 max_intel_level <= 0x0000ffff) {
143 asm("cpuid"
144 : "=a" (tfms),
145 "=c" (cpu.flags[4]),
146 "=d" (cpu.flags[0])
147 : "a" (0x00000001)
148 : "ebx");
149 cpu.level = (tfms >> 8) & 15;
150 cpu.model = (tfms >> 4) & 15;
151 if (cpu.level >= 6)
152 cpu.model += ((tfms >> 16) & 0xf) << 4;
153 }
154
155 asm("cpuid"
156 : "=a" (max_amd_level)
157 : "a" (0x80000000)
158 : "ebx", "ecx", "edx");
159
160 if (max_amd_level >= 0x80000001 &&
161 max_amd_level <= 0x8000ffff) {
162 u32 eax = 0x80000001;
163 asm("cpuid"
164 : "+a" (eax),
165 "=c" (cpu.flags[6]),
166 "=d" (cpu.flags[1])
167 : : "ebx");
168 }
169 }
170}
171
172/* Returns a bitmask of which words we have error bits in */
173static int check_flags(void)
174{
175 u32 err;
176 int i;
177
178 err = 0;
179 for (i = 0; i < NCAPINTS; i++) {
180 err_flags[i] = req_flags[i] & ~cpu.flags[i];
181 if (err_flags[i])
182 err |= 1 << i;
183 }
184
185 return err;
186}
187
188/*
189 * Returns -1 on error.
190 *
191 * *cpu_level is set to the current CPU level; *req_level to the required
192 * level. x86-64 is considered level 64 for this purpose.
193 *
194 * *err_flags_ptr is set to the flags error array if there are flags missing.
195 */
196int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr)
197{
198 int err;
199
200 memset(&cpu.flags, 0, sizeof cpu.flags);
201 cpu.level = 3;
202
203 if (has_eflag(X86_EFLAGS_AC))
204 cpu.level = 4;
205
206 get_flags();
207 err = check_flags();
208
209 if (test_bit(X86_FEATURE_LM, cpu.flags))
210 cpu.level = 64;
211
212 if (err == 0x01 &&
213 !(err_flags[0] &
214 ~((1 << X86_FEATURE_XMM)|(1 << X86_FEATURE_XMM2))) &&
215 is_amd()) {
216 /* If this is an AMD and we're only missing SSE+SSE2, try to
217 turn them on */
218
219 u32 ecx = MSR_K7_HWCR;
220 u32 eax, edx;
221
222 asm("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx));
223 eax &= ~(1 << 15);
224 asm("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx));
225
226 get_flags(); /* Make sure it really did something */
227 err = check_flags();
228 } else if (err == 0x01 &&
229 !(err_flags[0] & ~(1 << X86_FEATURE_CX8)) &&
230 is_centaur() && cpu.model >= 6) {
231 /* If this is a VIA C3, we might have to enable CX8
232 explicitly */
233
234 u32 ecx = MSR_VIA_FCR;
235 u32 eax, edx;
236
237 asm("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx));
238 eax |= (1<<1)|(1<<7);
239 asm("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx));
240
241 set_bit(X86_FEATURE_CX8, cpu.flags);
242 err = check_flags();
243 } else if (err == 0x01 && is_transmeta()) {
244 /* Transmeta might have masked feature bits in word 0 */
245
246 u32 ecx = 0x80860004;
247 u32 eax, edx;
248 u32 level = 1;
249
250 asm("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx));
251 asm("wrmsr" : : "a" (~0), "d" (edx), "c" (ecx));
252 asm("cpuid"
253 : "+a" (level), "=d" (cpu.flags[0])
254 : : "ecx", "ebx");
255 asm("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx));
256
257 err = check_flags();
258 }
259
260 if (err_flags_ptr)
261 *err_flags_ptr = err ? err_flags : NULL;
262 if (cpu_level_ptr)
263 *cpu_level_ptr = cpu.level;
264 if (req_level_ptr)
265 *req_level_ptr = req_level;
266
267 return (cpu.level < req_level || err) ? -1 : 0;
268}
diff --git a/arch/x86/boot/edd.c b/arch/x86/boot/edd.c
new file mode 100644
index 000000000000..bd138e442ec2
--- /dev/null
+++ b/arch/x86/boot/edd.c
@@ -0,0 +1,167 @@
1/* -*- linux-c -*- ------------------------------------------------------- *
2 *
3 * Copyright (C) 1991, 1992 Linus Torvalds
4 * Copyright 2007 rPath, Inc. - All Rights Reserved
5 *
6 * This file is part of the Linux kernel, and is made available under
7 * the terms of the GNU General Public License version 2.
8 *
9 * ----------------------------------------------------------------------- */
10
11/*
12 * arch/i386/boot/edd.c
13 *
14 * Get EDD BIOS disk information
15 */
16
17#include "boot.h"
18#include <linux/edd.h>
19
20#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
21
22/*
23 * Read the MBR (first sector) from a specific device.
24 */
25static int read_mbr(u8 devno, void *buf)
26{
27 u16 ax, bx, cx, dx;
28
29 ax = 0x0201; /* Legacy Read, one sector */
30 cx = 0x0001; /* Sector 0-0-1 */
31 dx = devno;
32 bx = (size_t)buf;
33 asm volatile("pushfl; stc; int $0x13; setc %%al; popfl"
34 : "+a" (ax), "+c" (cx), "+d" (dx), "+b" (bx)
35 : : "esi", "edi", "memory");
36
37 return -(u8)ax; /* 0 or -1 */
38}
39
40static u32 read_mbr_sig(u8 devno, struct edd_info *ei, u32 *mbrsig)
41{
42 int sector_size;
43 char *mbrbuf_ptr, *mbrbuf_end;
44 u32 buf_base, mbr_base;
45 extern char _end[];
46
47 sector_size = ei->params.bytes_per_sector;
48 if (!sector_size)
49 sector_size = 512; /* Best available guess */
50
51 /* Produce a naturally aligned buffer on the heap */
52 buf_base = (ds() << 4) + (u32)&_end;
53 mbr_base = (buf_base+sector_size-1) & ~(sector_size-1);
54 mbrbuf_ptr = _end + (mbr_base-buf_base);
55 mbrbuf_end = mbrbuf_ptr + sector_size;
56
57 /* Make sure we actually have space on the heap... */
58 if (!(boot_params.hdr.loadflags & CAN_USE_HEAP))
59 return -1;
60 if (mbrbuf_end > (char *)(size_t)boot_params.hdr.heap_end_ptr)
61 return -1;
62
63 if (read_mbr(devno, mbrbuf_ptr))
64 return -1;
65
66 *mbrsig = *(u32 *)&mbrbuf_ptr[EDD_MBR_SIG_OFFSET];
67 return 0;
68}
69
70static int get_edd_info(u8 devno, struct edd_info *ei)
71{
72 u16 ax, bx, cx, dx, di;
73
74 memset(ei, 0, sizeof *ei);
75
76 /* Check Extensions Present */
77
78 ax = 0x4100;
79 bx = EDDMAGIC1;
80 dx = devno;
81 asm("pushfl; stc; int $0x13; setc %%al; popfl"
82 : "+a" (ax), "+b" (bx), "=c" (cx), "+d" (dx)
83 : : "esi", "edi");
84
85 if ((u8)ax)
86 return -1; /* No extended information */
87
88 if (bx != EDDMAGIC2)
89 return -1;
90
91 ei->device = devno;
92 ei->version = ax >> 8; /* EDD version number */
93 ei->interface_support = cx; /* EDD functionality subsets */
94
95 /* Extended Get Device Parameters */
96
97 ei->params.length = sizeof(ei->params);
98 ax = 0x4800;
99 dx = devno;
100 asm("pushfl; int $0x13; popfl"
101 : "+a" (ax), "+d" (dx), "=m" (ei->params)
102 : "S" (&ei->params)
103 : "ebx", "ecx", "edi");
104
105 /* Get legacy CHS parameters */
106
107 /* Ralf Brown recommends setting ES:DI to 0:0 */
108 ax = 0x0800;
109 dx = devno;
110 di = 0;
111 asm("pushw %%es; "
112 "movw %%di,%%es; "
113 "pushfl; stc; int $0x13; setc %%al; popfl; "
114 "popw %%es"
115 : "+a" (ax), "=b" (bx), "=c" (cx), "+d" (dx), "+D" (di)
116 : : "esi");
117
118 if ((u8)ax == 0) {
119 ei->legacy_max_cylinder = (cx >> 8) + ((cx & 0xc0) << 2);
120 ei->legacy_max_head = dx >> 8;
121 ei->legacy_sectors_per_track = cx & 0x3f;
122 }
123
124 return 0;
125}
126
127void query_edd(void)
128{
129 char eddarg[8];
130 int do_mbr = 1;
131 int do_edd = 1;
132 int devno;
133 struct edd_info ei, *edp;
134 u32 *mbrptr;
135
136 if (cmdline_find_option("edd", eddarg, sizeof eddarg) > 0) {
137 if (!strcmp(eddarg, "skipmbr") || !strcmp(eddarg, "skip"))
138 do_mbr = 0;
139 else if (!strcmp(eddarg, "off"))
140 do_edd = 0;
141 }
142
143 edp = boot_params.eddbuf;
144 mbrptr = boot_params.edd_mbr_sig_buffer;
145
146 if (!do_edd)
147 return;
148
149 for (devno = 0x80; devno < 0x80+EDD_MBR_SIG_MAX; devno++) {
150 /*
151 * Scan the BIOS-supported hard disks and query EDD
152 * information...
153 */
154 get_edd_info(devno, &ei);
155
156 if (boot_params.eddbuf_entries < EDDMAXNR) {
157 memcpy(edp, &ei, sizeof ei);
158 edp++;
159 boot_params.eddbuf_entries++;
160 }
161
162 if (do_mbr && !read_mbr_sig(devno, &ei, mbrptr++))
163 boot_params.edd_mbr_sig_buf_entries = devno-0x80+1;
164 }
165}
166
167#endif
diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
new file mode 100644
index 000000000000..f3140e596d40
--- /dev/null
+++ b/arch/x86/boot/header.S
@@ -0,0 +1,283 @@
1/*
2 * header.S
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 *
6 * Based on bootsect.S and setup.S
7 * modified by more people than can be counted
8 *
9 * Rewritten as a common file by H. Peter Anvin (Apr 2007)
10 *
11 * BIG FAT NOTE: We're in real mode using 64k segments. Therefore segment
12 * addresses must be multiplied by 16 to obtain their respective linear
13 * addresses. To avoid confusion, linear addresses are written using leading
14 * hex while segment addresses are written as segment:offset.
15 *
16 */
17
18#include <asm/segment.h>
19#include <linux/utsrelease.h>
20#include <asm/boot.h>
21#include <asm/e820.h>
22#include <asm/page.h>
23#include <asm/setup.h>
24#include "boot.h"
25
26SETUPSECTS = 4 /* default nr of setup-sectors */
27BOOTSEG = 0x07C0 /* original address of boot-sector */
28SYSSEG = DEF_SYSSEG /* system loaded at 0x10000 (65536) */
29SYSSIZE = DEF_SYSSIZE /* system size: # of 16-byte clicks */
30 /* to be loaded */
31ROOT_DEV = 0 /* ROOT_DEV is now written by "build" */
32SWAP_DEV = 0 /* SWAP_DEV is now written by "build" */
33
34#ifndef SVGA_MODE
35#define SVGA_MODE ASK_VGA
36#endif
37
38#ifndef RAMDISK
39#define RAMDISK 0
40#endif
41
42#ifndef ROOT_RDONLY
43#define ROOT_RDONLY 1
44#endif
45
46 .code16
47 .section ".bstext", "ax"
48
49 .global bootsect_start
50bootsect_start:
51
52 # Normalize the start address
53 ljmp $BOOTSEG, $start2
54
55start2:
56 movw %cs, %ax
57 movw %ax, %ds
58 movw %ax, %es
59 movw %ax, %ss
60 xorw %sp, %sp
61 sti
62 cld
63
64 movw $bugger_off_msg, %si
65
66msg_loop:
67 lodsb
68 andb %al, %al
69 jz bs_die
70 movb $0xe, %ah
71 movw $7, %bx
72 int $0x10
73 jmp msg_loop
74
75bs_die:
76 # Allow the user to press a key, then reboot
77 xorw %ax, %ax
78 int $0x16
79 int $0x19
80
81 # int 0x19 should never return. In case it does anyway,
82 # invoke the BIOS reset code...
83 ljmp $0xf000,$0xfff0
84
85 .section ".bsdata", "a"
86bugger_off_msg:
87 .ascii "Direct booting from floppy is no longer supported.\r\n"
88 .ascii "Please use a boot loader program instead.\r\n"
89 .ascii "\n"
90 .ascii "Remove disk and press any key to reboot . . .\r\n"
91 .byte 0
92
93
94 # Kernel attributes; used by setup. This is part 1 of the
95 # header, from the old boot sector.
96
97 .section ".header", "a"
98 .globl hdr
99hdr:
100setup_sects: .byte SETUPSECTS
101root_flags: .word ROOT_RDONLY
102syssize: .long SYSSIZE
103ram_size: .word RAMDISK
104vid_mode: .word SVGA_MODE
105root_dev: .word ROOT_DEV
106boot_flag: .word 0xAA55
107
108 # offset 512, entry point
109
110 .globl _start
111_start:
112 # Explicitly enter this as bytes, or the assembler
113 # tries to generate a 3-byte jump here, which causes
114 # everything else to push off to the wrong offset.
115 .byte 0xeb # short (2-byte) jump
116 .byte start_of_setup-1f
1171:
118
119 # Part 2 of the header, from the old setup.S
120
121 .ascii "HdrS" # header signature
122 .word 0x0206 # header version number (>= 0x0105)
123 # or else old loadlin-1.5 will fail)
124 .globl realmode_swtch
125realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
126start_sys_seg: .word SYSSEG
127 .word kernel_version-512 # pointing to kernel version string
128 # above section of header is compatible
129 # with loadlin-1.5 (header v1.5). Don't
130 # change it.
131
132type_of_loader: .byte 0 # = 0, old one (LILO, Loadlin,
133 # Bootlin, SYSLX, bootsect...)
134 # See Documentation/i386/boot.txt for
135 # assigned ids
136
137# flags, unused bits must be zero (RFU) bit within loadflags
138loadflags:
139LOADED_HIGH = 1 # If set, the kernel is loaded high
140CAN_USE_HEAP = 0x80 # If set, the loader also has set
141 # heap_end_ptr to tell how much
142 # space behind setup.S can be used for
143 # heap purposes.
144 # Only the loader knows what is free
145#ifndef __BIG_KERNEL__
146 .byte 0
147#else
148 .byte LOADED_HIGH
149#endif
150
151setup_move_size: .word 0x8000 # size to move, when setup is not
152 # loaded at 0x90000. We will move setup
153 # to 0x90000 then just before jumping
154 # into the kernel. However, only the
155 # loader knows how much data behind
156 # us also needs to be loaded.
157
158code32_start: # here loaders can put a different
159 # start address for 32-bit code.
160#ifndef __BIG_KERNEL__
161 .long 0x1000 # 0x1000 = default for zImage
162#else
163 .long 0x100000 # 0x100000 = default for big kernel
164#endif
165
166ramdisk_image: .long 0 # address of loaded ramdisk image
167 # Here the loader puts the 32-bit
168 # address where it loaded the image.
169 # This only will be read by the kernel.
170
171ramdisk_size: .long 0 # its size in bytes
172
173bootsect_kludge:
174 .long 0 # obsolete
175
176heap_end_ptr: .word _end+1024 # (Header version 0x0201 or later)
177 # space from here (exclusive) down to
178 # end of setup code can be used by setup
179 # for local heap purposes.
180
181pad1: .word 0
182cmd_line_ptr: .long 0 # (Header version 0x0202 or later)
183 # If nonzero, a 32-bit pointer
184 # to the kernel command line.
185 # The command line should be
186 # located between the start of
187 # setup and the end of low
188 # memory (0xa0000), or it may
189 # get overwritten before it
190 # gets read. If this field is
191 # used, there is no longer
192 # anything magical about the
193 # 0x90000 segment; the setup
194 # can be located anywhere in
195 # low memory 0x10000 or higher.
196
197ramdisk_max: .long (-__PAGE_OFFSET-(512 << 20)-1) & 0x7fffffff
198 # (Header version 0x0203 or later)
199 # The highest safe address for
200 # the contents of an initrd
201
202kernel_alignment: .long CONFIG_PHYSICAL_ALIGN #physical addr alignment
203 #required for protected mode
204 #kernel
205#ifdef CONFIG_RELOCATABLE
206relocatable_kernel: .byte 1
207#else
208relocatable_kernel: .byte 0
209#endif
210pad2: .byte 0
211pad3: .word 0
212
213cmdline_size: .long COMMAND_LINE_SIZE-1 #length of the command line,
214 #added with boot protocol
215 #version 2.06
216
217# End of setup header #####################################################
218
219 .section ".inittext", "ax"
220start_of_setup:
221#ifdef SAFE_RESET_DISK_CONTROLLER
222# Reset the disk controller.
223 movw $0x0000, %ax # Reset disk controller
224 movb $0x80, %dl # All disks
225 int $0x13
226#endif
227
228# We will have entered with %cs = %ds+0x20, normalize %cs so
229# it is on par with the other segments.
230 pushw %ds
231 pushw $setup2
232 lretw
233
234setup2:
235# Force %es = %ds
236 movw %ds, %ax
237 movw %ax, %es
238 cld
239
240# Stack paranoia: align the stack and make sure it is good
241# for both 16- and 32-bit references. In particular, if we
242# were meant to have been using the full 16-bit segment, the
243# caller might have set %sp to zero, which breaks %esp-based
244# references.
245 andw $~3, %sp # dword align (might as well...)
246 jnz 1f
247 movw $0xfffc, %sp # Make sure we're not zero
2481: movzwl %sp, %esp # Clear upper half of %esp
249 sti
250
251# Check signature at end of setup
252 cmpl $0x5a5aaa55, setup_sig
253 jne setup_bad
254
255# Zero the bss
256 movw $__bss_start, %di
257 movw $_end+3, %cx
258 xorl %eax, %eax
259 subw %di, %cx
260 shrw $2, %cx
261 rep; stosl
262
263# Jump to C code (should not return)
264 calll main
265
266# Setup corrupt somehow...
267setup_bad:
268 movl $setup_corrupt, %eax
269 calll puts
270 # Fall through...
271
272 .globl die
273 .type die, @function
274die:
275 hlt
276 jmp die
277
278 .size die, .-die
279
280 .section ".initdata", "a"
281setup_corrupt:
282 .byte 7
283 .string "No setup signature found...\n"
diff --git a/arch/x86/boot/install.sh b/arch/x86/boot/install.sh
new file mode 100644
index 000000000000..88d77761d01b
--- /dev/null
+++ b/arch/x86/boot/install.sh
@@ -0,0 +1,61 @@
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
22verify () {
23 if [ ! -f "$1" ]; then
24 echo "" 1>&2
25 echo " *** Missing file: $1" 1>&2
26 echo ' *** You need to run "make" before "make install".' 1>&2
27 echo "" 1>&2
28 exit 1
29 fi
30}
31
32# Make sure the files actually exist
33verify "$2"
34verify "$3"
35
36# User may have a custom install script
37
38if [ -x ~/bin/${CROSS_COMPILE}installkernel ]; then exec ~/bin/${CROSS_COMPILE}installkernel "$@"; fi
39if [ -x /sbin/${CROSS_COMPILE}installkernel ]; then exec /sbin/${CROSS_COMPILE}installkernel "$@"; fi
40
41# Default install - same as make zlilo
42
43if [ -f $4/vmlinuz ]; then
44 mv $4/vmlinuz $4/vmlinuz.old
45fi
46
47if [ -f $4/System.map ]; then
48 mv $4/System.map $4/System.old
49fi
50
51cat $2 > $4/vmlinuz
52cp $3 $4/System.map
53
54if [ -x /sbin/lilo ]; then
55 /sbin/lilo
56elif [ -x /etc/lilo/install ]; then
57 /etc/lilo/install
58else
59 sync
60 echo "Cannot find LILO."
61fi
diff --git a/arch/x86/boot/main.c b/arch/x86/boot/main.c
new file mode 100644
index 000000000000..0eeef3989a17
--- /dev/null
+++ b/arch/x86/boot/main.c
@@ -0,0 +1,161 @@
1/* -*- linux-c -*- ------------------------------------------------------- *
2 *
3 * Copyright (C) 1991, 1992 Linus Torvalds
4 * Copyright 2007 rPath, Inc. - All Rights Reserved
5 *
6 * This file is part of the Linux kernel, and is made available under
7 * the terms of the GNU General Public License version 2.
8 *
9 * ----------------------------------------------------------------------- */
10
11/*
12 * arch/i386/boot/main.c
13 *
14 * Main module for the real-mode kernel code
15 */
16
17#include "boot.h"
18
19struct boot_params boot_params __attribute__((aligned(16)));
20
21char *HEAP = _end;
22char *heap_end = _end; /* Default end of heap = no heap */
23
24/*
25 * Copy the header into the boot parameter block. Since this
26 * screws up the old-style command line protocol, adjust by
27 * filling in the new-style command line pointer instead.
28 */
29#define OLD_CL_MAGIC 0xA33F
30#define OLD_CL_ADDRESS 0x20
31
32static void copy_boot_params(void)
33{
34 struct old_cmdline {
35 u16 cl_magic;
36 u16 cl_offset;
37 };
38 const struct old_cmdline * const oldcmd =
39 (const struct old_cmdline *)OLD_CL_ADDRESS;
40
41 BUILD_BUG_ON(sizeof boot_params != 4096);
42 memcpy(&boot_params.hdr, &hdr, sizeof hdr);
43
44 if (!boot_params.hdr.cmd_line_ptr &&
45 oldcmd->cl_magic == OLD_CL_MAGIC) {
46 /* Old-style command line protocol. */
47 u16 cmdline_seg;
48
49 /* Figure out if the command line falls in the region
50 of memory that an old kernel would have copied up
51 to 0x90000... */
52 if (oldcmd->cl_offset < boot_params.hdr.setup_move_size)
53 cmdline_seg = ds();
54 else
55 cmdline_seg = 0x9000;
56
57 boot_params.hdr.cmd_line_ptr =
58 (cmdline_seg << 4) + oldcmd->cl_offset;
59 }
60}
61
62/*
63 * Set the keyboard repeat rate to maximum. Unclear why this
64 * is done here; this might be possible to kill off as stale code.
65 */
66static void keyboard_set_repeat(void)
67{
68 u16 ax = 0x0305;
69 u16 bx = 0;
70 asm volatile("int $0x16"
71 : "+a" (ax), "+b" (bx)
72 : : "ecx", "edx", "esi", "edi");
73}
74
75/*
76 * Get Intel SpeedStep (IST) information.
77 */
78static void query_ist(void)
79{
80 asm("int $0x15"
81 : "=a" (boot_params.ist_info.signature),
82 "=b" (boot_params.ist_info.command),
83 "=c" (boot_params.ist_info.event),
84 "=d" (boot_params.ist_info.perf_level)
85 : "a" (0x0000e980), /* IST Support */
86 "d" (0x47534943)); /* Request value */
87}
88
89/*
90 * Tell the BIOS what CPU mode we intend to run in.
91 */
92static void set_bios_mode(void)
93{
94#ifdef CONFIG_X86_64
95 u32 eax, ebx;
96
97 eax = 0xec00;
98 ebx = 2;
99 asm volatile("int $0x15"
100 : "+a" (eax), "+b" (ebx)
101 : : "ecx", "edx", "esi", "edi");
102#endif
103}
104
105void main(void)
106{
107 /* First, copy the boot header into the "zeropage" */
108 copy_boot_params();
109
110 /* End of heap check */
111 if (boot_params.hdr.loadflags & CAN_USE_HEAP) {
112 heap_end = (char *)(boot_params.hdr.heap_end_ptr
113 +0x200-STACK_SIZE);
114 } else {
115 /* Boot protocol 2.00 only, no heap available */
116 puts("WARNING: Ancient bootloader, some functionality "
117 "may be limited!\n");
118 }
119
120 /* Make sure we have all the proper CPU support */
121 if (validate_cpu()) {
122 puts("Unable to boot - please use a kernel appropriate "
123 "for your CPU.\n");
124 die();
125 }
126
127 /* Tell the BIOS what CPU mode we intend to run in. */
128 set_bios_mode();
129
130 /* Detect memory layout */
131 detect_memory();
132
133 /* Set keyboard repeat rate (why?) */
134 keyboard_set_repeat();
135
136 /* Set the video mode */
137 set_video();
138
139 /* Query MCA information */
140 query_mca();
141
142 /* Voyager */
143#ifdef CONFIG_X86_VOYAGER
144 query_voyager();
145#endif
146
147 /* Query Intel SpeedStep (IST) information */
148 query_ist();
149
150 /* Query APM information */
151#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
152 query_apm_bios();
153#endif
154
155 /* Query EDD information */
156#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
157 query_edd();
158#endif
159 /* Do the last things and invoke protected mode */
160 go_to_protected_mode();
161}
diff --git a/arch/x86/boot/mca.c b/arch/x86/boot/mca.c
new file mode 100644
index 000000000000..68222f2d4b67
--- /dev/null
+++ b/arch/x86/boot/mca.c
@@ -0,0 +1,43 @@
1/* -*- linux-c -*- ------------------------------------------------------- *
2 *
3 * Copyright (C) 1991, 1992 Linus Torvalds
4 * Copyright 2007 rPath, Inc. - All Rights Reserved
5 *
6 * This file is part of the Linux kernel, and is made available under
7 * the terms of the GNU General Public License version 2.
8 *
9 * ----------------------------------------------------------------------- */
10
11/*
12 * arch/i386/boot/mca.c
13 *
14 * Get the MCA system description table
15 */
16
17#include "boot.h"
18
19int query_mca(void)
20{
21 u8 err;
22 u16 es, bx, len;
23
24 asm("pushw %%es ; "
25 "int $0x15 ; "
26 "setc %0 ; "
27 "movw %%es, %1 ; "
28 "popw %%es"
29 : "=acd" (err), "=acdSD" (es), "=b" (bx)
30 : "a" (0xc000));
31
32 if (err)
33 return -1; /* No MCA present */
34
35 set_fs(es);
36 len = rdfs16(bx);
37
38 if (len > sizeof(boot_params.sys_desc_table))
39 len = sizeof(boot_params.sys_desc_table);
40
41 copy_from_fs(&boot_params.sys_desc_table, bx, len);
42 return 0;
43}
diff --git a/arch/x86/boot/memory.c b/arch/x86/boot/memory.c
new file mode 100644
index 000000000000..378353956b5d
--- /dev/null
+++ b/arch/x86/boot/memory.c
@@ -0,0 +1,118 @@
1/* -*- linux-c -*- ------------------------------------------------------- *
2 *
3 * Copyright (C) 1991, 1992 Linus Torvalds
4 * Copyright 2007 rPath, Inc. - All Rights Reserved
5 *
6 * This file is part of the Linux kernel, and is made available under
7 * the terms of the GNU General Public License version 2.
8 *
9 * ----------------------------------------------------------------------- */
10
11/*
12 * arch/i386/boot/memory.c
13 *
14 * Memory detection code
15 */
16
17#include "boot.h"
18
19#define SMAP 0x534d4150 /* ASCII "SMAP" */
20
21static int detect_memory_e820(void)
22{
23 int count = 0;
24 u32 next = 0;
25 u32 size, id;
26 u8 err;
27 struct e820entry *desc = boot_params.e820_map;
28
29 do {
30 size = sizeof(struct e820entry);
31
32 /* Important: %edx is clobbered by some BIOSes,
33 so it must be either used for the error output
34 or explicitly marked clobbered. */
35 asm("int $0x15; setc %0"
36 : "=d" (err), "+b" (next), "=a" (id), "+c" (size),
37 "=m" (*desc)
38 : "D" (desc), "d" (SMAP), "a" (0xe820));
39
40 /* Some BIOSes stop returning SMAP in the middle of
41 the search loop. We don't know exactly how the BIOS
42 screwed up the map at that point, we might have a
43 partial map, the full map, or complete garbage, so
44 just return failure. */
45 if (id != SMAP) {
46 count = 0;
47 break;
48 }
49
50 if (err)
51 break;
52
53 count++;
54 desc++;
55 } while (next && count < E820MAX);
56
57 return boot_params.e820_entries = count;
58}
59
60static int detect_memory_e801(void)
61{
62 u16 ax, bx, cx, dx;
63 u8 err;
64
65 bx = cx = dx = 0;
66 ax = 0xe801;
67 asm("stc; int $0x15; setc %0"
68 : "=m" (err), "+a" (ax), "+b" (bx), "+c" (cx), "+d" (dx));
69
70 if (err)
71 return -1;
72
73 /* Do we really need to do this? */
74 if (cx || dx) {
75 ax = cx;
76 bx = dx;
77 }
78
79 if (ax > 15*1024)
80 return -1; /* Bogus! */
81
82 /* This ignores memory above 16MB if we have a memory hole
83 there. If someone actually finds a machine with a memory
84 hole at 16MB and no support for 0E820h they should probably
85 generate a fake e820 map. */
86 boot_params.alt_mem_k = (ax == 15*1024) ? (dx << 6)+ax : ax;
87
88 return 0;
89}
90
91static int detect_memory_88(void)
92{
93 u16 ax;
94 u8 err;
95
96 ax = 0x8800;
97 asm("stc; int $0x15; setc %0" : "=bcdm" (err), "+a" (ax));
98
99 boot_params.screen_info.ext_mem_k = ax;
100
101 return -err;
102}
103
104int detect_memory(void)
105{
106 int err = -1;
107
108 if (detect_memory_e820() > 0)
109 err = 0;
110
111 if (!detect_memory_e801())
112 err = 0;
113
114 if (!detect_memory_88())
115 err = 0;
116
117 return err;
118}
diff --git a/arch/x86/boot/mtools.conf.in b/arch/x86/boot/mtools.conf.in
new file mode 100644
index 000000000000..efd6d2490c1d
--- /dev/null
+++ b/arch/x86/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/boot/pm.c b/arch/x86/boot/pm.c
new file mode 100644
index 000000000000..09fb342cc62e
--- /dev/null
+++ b/arch/x86/boot/pm.c
@@ -0,0 +1,174 @@
1/* -*- linux-c -*- ------------------------------------------------------- *
2 *
3 * Copyright (C) 1991, 1992 Linus Torvalds
4 * Copyright 2007 rPath, Inc. - All Rights Reserved
5 *
6 * This file is part of the Linux kernel, and is made available under
7 * the terms of the GNU General Public License version 2.
8 *
9 * ----------------------------------------------------------------------- */
10
11/*
12 * arch/i386/boot/pm.c
13 *
14 * Prepare the machine for transition to protected mode.
15 */
16
17#include "boot.h"
18#include <asm/segment.h>
19
20/*
21 * Invoke the realmode switch hook if present; otherwise
22 * disable all interrupts.
23 */
24static void realmode_switch_hook(void)
25{
26 if (boot_params.hdr.realmode_swtch) {
27 asm volatile("lcallw *%0"
28 : : "m" (boot_params.hdr.realmode_swtch)
29 : "eax", "ebx", "ecx", "edx");
30 } else {
31 asm volatile("cli");
32 outb(0x80, 0x70); /* Disable NMI */
33 io_delay();
34 }
35}
36
37/*
38 * A zImage kernel is loaded at 0x10000 but wants to run at 0x1000.
39 * A bzImage kernel is loaded and runs at 0x100000.
40 */
41static void move_kernel_around(void)
42{
43 /* Note: rely on the compile-time option here rather than
44 the LOADED_HIGH flag. The Qemu kernel loader unconditionally
45 sets the loadflags to zero. */
46#ifndef __BIG_KERNEL__
47 u16 dst_seg, src_seg;
48 u32 syssize;
49
50 dst_seg = 0x1000 >> 4;
51 src_seg = 0x10000 >> 4;
52 syssize = boot_params.hdr.syssize; /* Size in 16-byte paragraphs */
53
54 while (syssize) {
55 int paras = (syssize >= 0x1000) ? 0x1000 : syssize;
56 int dwords = paras << 2;
57
58 asm volatile("pushw %%es ; "
59 "pushw %%ds ; "
60 "movw %1,%%es ; "
61 "movw %2,%%ds ; "
62 "xorw %%di,%%di ; "
63 "xorw %%si,%%si ; "
64 "rep;movsl ; "
65 "popw %%ds ; "
66 "popw %%es"
67 : "+c" (dwords)
68 : "r" (dst_seg), "r" (src_seg)
69 : "esi", "edi");
70
71 syssize -= paras;
72 dst_seg += paras;
73 src_seg += paras;
74 }
75#endif
76}
77
78/*
79 * Disable all interrupts at the legacy PIC.
80 */
81static void mask_all_interrupts(void)
82{
83 outb(0xff, 0xa1); /* Mask all interrupts on the secondary PIC */
84 io_delay();
85 outb(0xfb, 0x21); /* Mask all but cascade on the primary PIC */
86 io_delay();
87}
88
89/*
90 * Reset IGNNE# if asserted in the FPU.
91 */
92static void reset_coprocessor(void)
93{
94 outb(0, 0xf0);
95 io_delay();
96 outb(0, 0xf1);
97 io_delay();
98}
99
100/*
101 * Set up the GDT
102 */
103#define GDT_ENTRY(flags,base,limit) \
104 (((u64)(base & 0xff000000) << 32) | \
105 ((u64)flags << 40) | \
106 ((u64)(limit & 0x00ff0000) << 32) | \
107 ((u64)(base & 0x00ffff00) << 16) | \
108 ((u64)(limit & 0x0000ffff)))
109
110struct gdt_ptr {
111 u16 len;
112 u32 ptr;
113} __attribute__((packed));
114
115static void setup_gdt(void)
116{
117 /* There are machines which are known to not boot with the GDT
118 being 8-byte unaligned. Intel recommends 16 byte alignment. */
119 static const u64 boot_gdt[] __attribute__((aligned(16))) = {
120 /* CS: code, read/execute, 4 GB, base 0 */
121 [GDT_ENTRY_BOOT_CS] = GDT_ENTRY(0xc09b, 0, 0xfffff),
122 /* DS: data, read/write, 4 GB, base 0 */
123 [GDT_ENTRY_BOOT_DS] = GDT_ENTRY(0xc093, 0, 0xfffff),
124 };
125 /* Xen HVM incorrectly stores a pointer to the gdt_ptr, instead
126 of the gdt_ptr contents. Thus, make it static so it will
127 stay in memory, at least long enough that we switch to the
128 proper kernel GDT. */
129 static struct gdt_ptr gdt;
130
131 gdt.len = sizeof(boot_gdt)-1;
132 gdt.ptr = (u32)&boot_gdt + (ds() << 4);
133
134 asm volatile("lgdtl %0" : : "m" (gdt));
135}
136
137/*
138 * Set up the IDT
139 */
140static void setup_idt(void)
141{
142 static const struct gdt_ptr null_idt = {0, 0};
143 asm volatile("lidtl %0" : : "m" (null_idt));
144}
145
146/*
147 * Actual invocation sequence
148 */
149void go_to_protected_mode(void)
150{
151 /* Hook before leaving real mode, also disables interrupts */
152 realmode_switch_hook();
153
154 /* Move the kernel/setup to their final resting places */
155 move_kernel_around();
156
157 /* Enable the A20 gate */
158 if (enable_a20()) {
159 puts("A20 gate not responding, unable to boot...\n");
160 die();
161 }
162
163 /* Reset coprocessor (IGNNE#) */
164 reset_coprocessor();
165
166 /* Mask all interrupts in the PIC */
167 mask_all_interrupts();
168
169 /* Actual transition to protected mode... */
170 setup_idt();
171 setup_gdt();
172 protected_mode_jump(boot_params.hdr.code32_start,
173 (u32)&boot_params + (ds() << 4));
174}
diff --git a/arch/x86/boot/pmjump.S b/arch/x86/boot/pmjump.S
new file mode 100644
index 000000000000..2e559233725a
--- /dev/null
+++ b/arch/x86/boot/pmjump.S
@@ -0,0 +1,54 @@
1/* ----------------------------------------------------------------------- *
2 *
3 * Copyright (C) 1991, 1992 Linus Torvalds
4 * Copyright 2007 rPath, Inc. - All Rights Reserved
5 *
6 * This file is part of the Linux kernel, and is made available under
7 * the terms of the GNU General Public License version 2.
8 *
9 * ----------------------------------------------------------------------- */
10
11/*
12 * arch/i386/boot/pmjump.S
13 *
14 * The actual transition into protected mode
15 */
16
17#include <asm/boot.h>
18#include <asm/segment.h>
19
20 .text
21
22 .globl protected_mode_jump
23 .type protected_mode_jump, @function
24
25 .code16
26
27/*
28 * void protected_mode_jump(u32 entrypoint, u32 bootparams);
29 */
30protected_mode_jump:
31 xorl %ebx, %ebx # Flag to indicate this is a boot
32 movl %edx, %esi # Pointer to boot_params table
33 movl %eax, 2f # Patch ljmpl instruction
34 jmp 1f # Short jump to flush instruction q.
35
361:
37 movw $__BOOT_DS, %cx
38
39 movl %cr0, %edx
40 orb $1, %dl # Protected mode (PE) bit
41 movl %edx, %cr0
42
43 movw %cx, %ds
44 movw %cx, %es
45 movw %cx, %fs
46 movw %cx, %gs
47 movw %cx, %ss
48
49 # Jump to the 32-bit entrypoint
50 .byte 0x66, 0xea # ljmpl opcode
512: .long 0 # offset
52 .word __BOOT_CS # segment
53
54 .size protected_mode_jump, .-protected_mode_jump
diff --git a/arch/x86/boot/printf.c b/arch/x86/boot/printf.c
new file mode 100644
index 000000000000..1a09f9309d3c
--- /dev/null
+++ b/arch/x86/boot/printf.c
@@ -0,0 +1,307 @@
1/* -*- linux-c -*- ------------------------------------------------------- *
2 *
3 * Copyright (C) 1991, 1992 Linus Torvalds
4 * Copyright 2007 rPath, Inc. - All Rights Reserved
5 *
6 * This file is part of the Linux kernel, and is made available under
7 * the terms of the GNU General Public License version 2.
8 *
9 * ----------------------------------------------------------------------- */
10
11/*
12 * arch/i386/boot/printf.c
13 *
14 * Oh, it's a waste of space, but oh-so-yummy for debugging. This
15 * version of printf() does not include 64-bit support. "Live with
16 * it."
17 *
18 */
19
20#include "boot.h"
21
22static int skip_atoi(const char **s)
23{
24 int i = 0;
25
26 while (isdigit(**s))
27 i = i * 10 + *((*s)++) - '0';
28 return i;
29}
30
31#define ZEROPAD 1 /* pad with zero */
32#define SIGN 2 /* unsigned/signed long */
33#define PLUS 4 /* show plus */
34#define SPACE 8 /* space if plus */
35#define LEFT 16 /* left justified */
36#define SPECIAL 32 /* 0x */
37#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
38
39#define do_div(n,base) ({ \
40int __res; \
41__res = ((unsigned long) n) % (unsigned) base; \
42n = ((unsigned long) n) / (unsigned) base; \
43__res; })
44
45static char *number(char *str, long num, int base, int size, int precision,
46 int type)
47{
48 char c, sign, tmp[66];
49 const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz";
50 int i;
51
52 if (type & LARGE)
53 digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
54 if (type & LEFT)
55 type &= ~ZEROPAD;
56 if (base < 2 || base > 36)
57 return 0;
58 c = (type & ZEROPAD) ? '0' : ' ';
59 sign = 0;
60 if (type & SIGN) {
61 if (num < 0) {
62 sign = '-';
63 num = -num;
64 size--;
65 } else if (type & PLUS) {
66 sign = '+';
67 size--;
68 } else if (type & SPACE) {
69 sign = ' ';
70 size--;
71 }
72 }
73 if (type & SPECIAL) {
74 if (base == 16)
75 size -= 2;
76 else if (base == 8)
77 size--;
78 }
79 i = 0;
80 if (num == 0)
81 tmp[i++] = '0';
82 else
83 while (num != 0)
84 tmp[i++] = digits[do_div(num, base)];
85 if (i > precision)
86 precision = i;
87 size -= precision;
88 if (!(type & (ZEROPAD + LEFT)))
89 while (size-- > 0)
90 *str++ = ' ';
91 if (sign)
92 *str++ = sign;
93 if (type & SPECIAL) {
94 if (base == 8)
95 *str++ = '0';
96 else if (base == 16) {
97 *str++ = '0';
98 *str++ = digits[33];
99 }
100 }
101 if (!(type & LEFT))
102 while (size-- > 0)
103 *str++ = c;
104 while (i < precision--)
105 *str++ = '0';
106 while (i-- > 0)
107 *str++ = tmp[i];
108 while (size-- > 0)
109 *str++ = ' ';
110 return str;
111}
112
113int vsprintf(char *buf, const char *fmt, va_list args)
114{
115 int len;
116 unsigned long num;
117 int i, base;
118 char *str;
119 const char *s;
120
121 int flags; /* flags to number() */
122
123 int field_width; /* width of output field */
124 int precision; /* min. # of digits for integers; max
125 number of chars for from string */
126 int qualifier; /* 'h', 'l', or 'L' for integer fields */
127
128 for (str = buf; *fmt; ++fmt) {
129 if (*fmt != '%') {
130 *str++ = *fmt;
131 continue;
132 }
133
134 /* process flags */
135 flags = 0;
136 repeat:
137 ++fmt; /* this also skips first '%' */
138 switch (*fmt) {
139 case '-':
140 flags |= LEFT;
141 goto repeat;
142 case '+':
143 flags |= PLUS;
144 goto repeat;
145 case ' ':
146 flags |= SPACE;
147 goto repeat;
148 case '#':
149 flags |= SPECIAL;
150 goto repeat;
151 case '0':
152 flags |= ZEROPAD;
153 goto repeat;
154 }
155
156 /* get field width */
157 field_width = -1;
158 if (isdigit(*fmt))
159 field_width = skip_atoi(&fmt);
160 else if (*fmt == '*') {
161 ++fmt;
162 /* it's the next argument */
163 field_width = va_arg(args, int);
164 if (field_width < 0) {
165 field_width = -field_width;
166 flags |= LEFT;
167 }
168 }
169
170 /* get the precision */
171 precision = -1;
172 if (*fmt == '.') {
173 ++fmt;
174 if (isdigit(*fmt))
175 precision = skip_atoi(&fmt);
176 else if (*fmt == '*') {
177 ++fmt;
178 /* it's the next argument */
179 precision = va_arg(args, int);
180 }
181 if (precision < 0)
182 precision = 0;
183 }
184
185 /* get the conversion qualifier */
186 qualifier = -1;
187 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
188 qualifier = *fmt;
189 ++fmt;
190 }
191
192 /* default base */
193 base = 10;
194
195 switch (*fmt) {
196 case 'c':
197 if (!(flags & LEFT))
198 while (--field_width > 0)
199 *str++ = ' ';
200 *str++ = (unsigned char)va_arg(args, int);
201 while (--field_width > 0)
202 *str++ = ' ';
203 continue;
204
205 case 's':
206 s = va_arg(args, char *);
207 len = strnlen(s, precision);
208
209 if (!(flags & LEFT))
210 while (len < field_width--)
211 *str++ = ' ';
212 for (i = 0; i < len; ++i)
213 *str++ = *s++;
214 while (len < field_width--)
215 *str++ = ' ';
216 continue;
217
218 case 'p':
219 if (field_width == -1) {
220 field_width = 2 * sizeof(void *);
221 flags |= ZEROPAD;
222 }
223 str = number(str,
224 (unsigned long)va_arg(args, void *), 16,
225 field_width, precision, flags);
226 continue;
227
228 case 'n':
229 if (qualifier == 'l') {
230 long *ip = va_arg(args, long *);
231 *ip = (str - buf);
232 } else {
233 int *ip = va_arg(args, int *);
234 *ip = (str - buf);
235 }
236 continue;
237
238 case '%':
239 *str++ = '%';
240 continue;
241
242 /* integer number formats - set up the flags and "break" */
243 case 'o':
244 base = 8;
245 break;
246
247 case 'X':
248 flags |= LARGE;
249 case 'x':
250 base = 16;
251 break;
252
253 case 'd':
254 case 'i':
255 flags |= SIGN;
256 case 'u':
257 break;
258
259 default:
260 *str++ = '%';
261 if (*fmt)
262 *str++ = *fmt;
263 else
264 --fmt;
265 continue;
266 }
267 if (qualifier == 'l')
268 num = va_arg(args, unsigned long);
269 else if (qualifier == 'h') {
270 num = (unsigned short)va_arg(args, int);
271 if (flags & SIGN)
272 num = (short)num;
273 } else if (flags & SIGN)
274 num = va_arg(args, int);
275 else
276 num = va_arg(args, unsigned int);
277 str = number(str, num, base, field_width, precision, flags);
278 }
279 *str = '\0';
280 return str - buf;
281}
282
283int sprintf(char *buf, const char *fmt, ...)
284{
285 va_list args;
286 int i;
287
288 va_start(args, fmt);
289 i = vsprintf(buf, fmt, args);
290 va_end(args);
291 return i;
292}
293
294int printf(const char *fmt, ...)
295{
296 char printf_buf[1024];
297 va_list args;
298 int printed;
299
300 va_start(args, fmt);
301 printed = vsprintf(printf_buf, fmt, args);
302 va_end(args);
303
304 puts(printf_buf);
305
306 return printed;
307}
diff --git a/arch/x86/boot/setup.ld b/arch/x86/boot/setup.ld
new file mode 100644
index 000000000000..df9234b3a5e0
--- /dev/null
+++ b/arch/x86/boot/setup.ld
@@ -0,0 +1,54 @@
1/*
2 * setup.ld
3 *
4 * Linker script for the i386 setup code
5 */
6OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
7OUTPUT_ARCH(i386)
8ENTRY(_start)
9
10SECTIONS
11{
12 . = 0;
13 .bstext : { *(.bstext) }
14 .bsdata : { *(.bsdata) }
15
16 . = 497;
17 .header : { *(.header) }
18 .inittext : { *(.inittext) }
19 .initdata : { *(.initdata) }
20 .text : { *(.text*) }
21
22 . = ALIGN(16);
23 .rodata : { *(.rodata*) }
24
25 .videocards : {
26 video_cards = .;
27 *(.videocards)
28 video_cards_end = .;
29 }
30
31 . = ALIGN(16);
32 .data : { *(.data*) }
33
34 .signature : {
35 setup_sig = .;
36 LONG(0x5a5aaa55)
37 }
38
39
40 . = ALIGN(16);
41 .bss :
42 {
43 __bss_start = .;
44 *(.bss)
45 __bss_end = .;
46 }
47 . = ALIGN(16);
48 _end = .;
49
50 /DISCARD/ : { *(.note*) }
51
52 . = ASSERT(_end <= 0x8000, "Setup too big!");
53 . = ASSERT(hdr == 0x1f1, "The setup header has the wrong offset!");
54}
diff --git a/arch/x86/boot/string.c b/arch/x86/boot/string.c
new file mode 100644
index 000000000000..481a22097781
--- /dev/null
+++ b/arch/x86/boot/string.c
@@ -0,0 +1,52 @@
1/* -*- linux-c -*- ------------------------------------------------------- *
2 *
3 * Copyright (C) 1991, 1992 Linus Torvalds
4 * Copyright 2007 rPath, Inc. - All Rights Reserved
5 *
6 * This file is part of the Linux kernel, and is made available under
7 * the terms of the GNU General Public License version 2.
8 *
9 * ----------------------------------------------------------------------- */
10
11/*
12 * arch/i386/boot/string.c
13 *
14 * Very basic string functions
15 */
16
17#include "boot.h"
18
19int strcmp(const char *str1, const char *str2)
20{
21 const unsigned char *s1 = (const unsigned char *)str1;
22 const unsigned char *s2 = (const unsigned char *)str2;
23 int delta = 0;
24
25 while (*s1 || *s2) {
26 delta = *s2 - *s1;
27 if (delta)
28 return delta;
29 s1++;
30 s2++;
31 }
32 return 0;
33}
34
35size_t strnlen(const char *s, size_t maxlen)
36{
37 const char *es = s;
38 while (*es && maxlen) {
39 es++;
40 maxlen--;
41 }
42
43 return (es - s);
44}
45
46unsigned int atou(const char *s)
47{
48 unsigned int i = 0;
49 while (isdigit(*s))
50 i = i * 10 + (*s++ - '0');
51 return i;
52}
diff --git a/arch/x86/boot/tty.c b/arch/x86/boot/tty.c
new file mode 100644
index 000000000000..f3f14bd26371
--- /dev/null
+++ b/arch/x86/boot/tty.c
@@ -0,0 +1,112 @@
1/* -*- linux-c -*- ------------------------------------------------------- *
2 *
3 * Copyright (C) 1991, 1992 Linus Torvalds
4 * Copyright 2007 rPath, Inc. - All Rights Reserved
5 *
6 * This file is part of the Linux kernel, and is made available under
7 * the terms of the GNU General Public License version 2.
8 *
9 * ----------------------------------------------------------------------- */
10
11/*
12 * arch/i386/boot/tty.c
13 *
14 * Very simple screen I/O
15 * XXX: Probably should add very simple serial I/O?
16 */
17
18#include "boot.h"
19
20/*
21 * These functions are in .inittext so they can be used to signal
22 * error during initialization.
23 */
24
25void __attribute__((section(".inittext"))) putchar(int ch)
26{
27 unsigned char c = ch;
28
29 if (c == '\n')
30 putchar('\r'); /* \n -> \r\n */
31
32 /* int $0x10 is known to have bugs involving touching registers
33 it shouldn't. Be extra conservative... */
34 asm volatile("pushal; pushw %%ds; int $0x10; popw %%ds; popal"
35 : : "b" (0x0007), "c" (0x0001), "a" (0x0e00|ch));
36}
37
38void __attribute__((section(".inittext"))) puts(const char *str)
39{
40 int n = 0;
41 while (*str) {
42 putchar(*str++);
43 n++;
44 }
45}
46
47/*
48 * Read the CMOS clock through the BIOS, and return the
49 * seconds in BCD.
50 */
51
52static u8 gettime(void)
53{
54 u16 ax = 0x0200;
55 u16 cx, dx;
56
57 asm volatile("int $0x1a"
58 : "+a" (ax), "=c" (cx), "=d" (dx)
59 : : "ebx", "esi", "edi");
60
61 return dx >> 8;
62}
63
64/*
65 * Read from the keyboard
66 */
67int getchar(void)
68{
69 u16 ax = 0;
70 asm volatile("int $0x16" : "+a" (ax));
71
72 return ax & 0xff;
73}
74
75static int kbd_pending(void)
76{
77 u8 pending;
78 asm volatile("int $0x16; setnz %0"
79 : "=rm" (pending)
80 : "a" (0x0100));
81 return pending;
82}
83
84void kbd_flush(void)
85{
86 for (;;) {
87 if (!kbd_pending())
88 break;
89 getchar();
90 }
91}
92
93int getchar_timeout(void)
94{
95 int cnt = 30;
96 int t0, t1;
97
98 t0 = gettime();
99
100 while (cnt) {
101 if (kbd_pending())
102 return getchar();
103
104 t1 = gettime();
105 if (t0 != t1) {
106 cnt--;
107 t0 = t1;
108 }
109 }
110
111 return 0; /* Timeout! */
112}
diff --git a/arch/x86/boot/version.c b/arch/x86/boot/version.c
new file mode 100644
index 000000000000..c61462f7d9a7
--- /dev/null
+++ b/arch/x86/boot/version.c
@@ -0,0 +1,23 @@
1/* -*- linux-c -*- ------------------------------------------------------- *
2 *
3 * Copyright (C) 1991, 1992 Linus Torvalds
4 * Copyright 2007 rPath, Inc. - All Rights Reserved
5 *
6 * This file is part of the Linux kernel, and is made available under
7 * the terms of the GNU General Public License version 2.
8 *
9 * ----------------------------------------------------------------------- */
10
11/*
12 * arch/i386/boot/version.c
13 *
14 * Kernel version string
15 */
16
17#include "boot.h"
18#include <linux/utsrelease.h>
19#include <linux/compile.h>
20
21const char kernel_version[] =
22 UTS_RELEASE " (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ") "
23 UTS_VERSION;
diff --git a/arch/x86/boot/vesa.h b/arch/x86/boot/vesa.h
new file mode 100644
index 000000000000..ff5b73cd406f
--- /dev/null
+++ b/arch/x86/boot/vesa.h
@@ -0,0 +1,79 @@
1/* ----------------------------------------------------------------------- *
2 *
3 * Copyright 1999-2007 H. Peter Anvin - All Rights Reserved
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
8 * Boston MA 02111-1307, USA; either version 2 of the License, or
9 * (at your option) any later version; incorporated herein by reference.
10 *
11 * ----------------------------------------------------------------------- */
12
13#ifndef BOOT_VESA_H
14#define BOOT_VESA_H
15
16typedef struct {
17 u16 off, seg;
18} far_ptr;
19
20/* VESA General Information table */
21struct vesa_general_info {
22 u32 signature; /* 0 Magic number = "VESA" */
23 u16 version; /* 4 */
24 far_ptr vendor_string; /* 6 */
25 u32 capabilities; /* 10 */
26 far_ptr video_mode_ptr; /* 14 */
27 u16 total_memory; /* 18 */
28
29 u16 oem_software_rev; /* 20 */
30 far_ptr oem_vendor_name_ptr; /* 22 */
31 far_ptr oem_product_name_ptr; /* 26 */
32 far_ptr oem_product_rev_ptr; /* 30 */
33
34 u8 reserved[222]; /* 34 */
35 u8 oem_data[256]; /* 256 */
36} __attribute__ ((packed));
37
38#define VESA_MAGIC ('V' + ('E' << 8) + ('S' << 16) + ('A' << 24))
39#define VBE2_MAGIC ('V' + ('B' << 8) + ('E' << 16) + ('2' << 24))
40
41struct vesa_mode_info {
42 u16 mode_attr; /* 0 */
43 u8 win_attr[2]; /* 2 */
44 u16 win_grain; /* 4 */
45 u16 win_size; /* 6 */
46 u16 win_seg[2]; /* 8 */
47 far_ptr win_scheme; /* 12 */
48 u16 logical_scan; /* 16 */
49
50 u16 h_res; /* 18 */
51 u16 v_res; /* 20 */
52 u8 char_width; /* 22 */
53 u8 char_height; /* 23 */
54 u8 memory_planes; /* 24 */
55 u8 bpp; /* 25 */
56 u8 banks; /* 26 */
57 u8 memory_layout; /* 27 */
58 u8 bank_size; /* 28 */
59 u8 image_planes; /* 29 */
60 u8 page_function; /* 30 */
61
62 u8 rmask; /* 31 */
63 u8 rpos; /* 32 */
64 u8 gmask; /* 33 */
65 u8 gpos; /* 34 */
66 u8 bmask; /* 35 */
67 u8 bpos; /* 36 */
68 u8 resv_mask; /* 37 */
69 u8 resv_pos; /* 38 */
70 u8 dcm_info; /* 39 */
71
72 u32 lfb_ptr; /* 40 Linear frame buffer address */
73 u32 offscreen_ptr; /* 44 Offscreen memory address */
74 u16 offscreen_size; /* 48 */
75
76 u8 reserved[206]; /* 50 */
77} __attribute__ ((packed));
78
79#endif /* LIB_SYS_VESA_H */
diff --git a/arch/x86/boot/video-bios.c b/arch/x86/boot/video-bios.c
new file mode 100644
index 000000000000..68e65d95cdfd
--- /dev/null
+++ b/arch/x86/boot/video-bios.c
@@ -0,0 +1,125 @@
1/* -*- linux-c -*- ------------------------------------------------------- *
2 *
3 * Copyright (C) 1991, 1992 Linus Torvalds
4 * Copyright 2007 rPath, Inc. - All Rights Reserved
5 *
6 * This file is part of the Linux kernel, and is made available under
7 * the terms of the GNU General Public License version 2.
8 *
9 * ----------------------------------------------------------------------- */
10
11/*
12 * arch/i386/boot/video-bios.c
13 *
14 * Standard video BIOS modes
15 *
16 * We have two options for this; silent and scanned.
17 */
18
19#include "boot.h"
20#include "video.h"
21
22__videocard video_bios;
23
24/* Set a conventional BIOS mode */
25static int set_bios_mode(u8 mode);
26
27static int bios_set_mode(struct mode_info *mi)
28{
29 return set_bios_mode(mi->mode - VIDEO_FIRST_BIOS);
30}
31
32static int set_bios_mode(u8 mode)
33{
34 u16 ax;
35 u8 new_mode;
36
37 ax = mode; /* AH=0x00 Set Video Mode */
38 asm volatile(INT10
39 : "+a" (ax)
40 : : "ebx", "ecx", "edx", "esi", "edi");
41
42 ax = 0x0f00; /* Get Current Video Mode */
43 asm volatile(INT10
44 : "+a" (ax)
45 : : "ebx", "ecx", "edx", "esi", "edi");
46
47 do_restore = 1; /* Assume video contents were lost */
48 new_mode = ax & 0x7f; /* Not all BIOSes are clean with the top bit */
49
50 if (new_mode == mode)
51 return 0; /* Mode change OK */
52
53 if (new_mode != boot_params.screen_info.orig_video_mode) {
54 /* Mode setting failed, but we didn't end up where we
55 started. That's bad. Try to revert to the original
56 video mode. */
57 ax = boot_params.screen_info.orig_video_mode;
58 asm volatile(INT10
59 : "+a" (ax)
60 : : "ebx", "ecx", "edx", "esi", "edi");
61 }
62 return -1;
63}
64
65static int bios_probe(void)
66{
67 u8 mode;
68 u8 saved_mode = boot_params.screen_info.orig_video_mode;
69 u16 crtc;
70 struct mode_info *mi;
71 int nmodes = 0;
72
73 if (adapter != ADAPTER_EGA && adapter != ADAPTER_VGA)
74 return 0;
75
76 set_fs(0);
77 crtc = vga_crtc();
78
79 video_bios.modes = GET_HEAP(struct mode_info, 0);
80
81 for (mode = 0x14; mode <= 0x7f; mode++) {
82 if (heap_free() < sizeof(struct mode_info))
83 break;
84
85 if (mode_defined(VIDEO_FIRST_BIOS+mode))
86 continue;
87
88 if (set_bios_mode(mode))
89 continue;
90
91 /* Try to verify that it's a text mode. */
92
93 /* Attribute Controller: make graphics controller disabled */
94 if (in_idx(0x3c0, 0x10) & 0x01)
95 continue;
96
97 /* Graphics Controller: verify Alpha addressing enabled */
98 if (in_idx(0x3ce, 0x06) & 0x01)
99 continue;
100
101 /* CRTC cursor location low should be zero(?) */
102 if (in_idx(crtc, 0x0f))
103 continue;
104
105 mi = GET_HEAP(struct mode_info, 1);
106 mi->mode = VIDEO_FIRST_BIOS+mode;
107 mi->x = rdfs16(0x44a);
108 mi->y = rdfs8(0x484)+1;
109 nmodes++;
110 }
111
112 set_bios_mode(saved_mode);
113
114 return nmodes;
115}
116
117__videocard video_bios =
118{
119 .card_name = "BIOS (scanned)",
120 .probe = bios_probe,
121 .set_mode = bios_set_mode,
122 .unsafe = 1,
123 .xmode_first = VIDEO_FIRST_BIOS,
124 .xmode_n = 0x80,
125};
diff --git a/arch/x86/boot/video-vesa.c b/arch/x86/boot/video-vesa.c
new file mode 100644
index 000000000000..192190710710
--- /dev/null
+++ b/arch/x86/boot/video-vesa.c
@@ -0,0 +1,292 @@
1/* -*- linux-c -*- ------------------------------------------------------- *
2 *
3 * Copyright (C) 1991, 1992 Linus Torvalds
4 * Copyright 2007 rPath, Inc. - All Rights Reserved
5 *
6 * This file is part of the Linux kernel, and is made available under
7 * the terms of the GNU General Public License version 2.
8 *
9 * ----------------------------------------------------------------------- */
10
11/*
12 * arch/i386/boot/video-vesa.c
13 *
14 * VESA text modes
15 */
16
17#include "boot.h"
18#include "video.h"
19#include "vesa.h"
20
21/* VESA information */
22static struct vesa_general_info vginfo;
23static struct vesa_mode_info vminfo;
24
25__videocard video_vesa;
26
27static void vesa_store_mode_params_graphics(void);
28
29static int vesa_probe(void)
30{
31#if defined(CONFIG_VIDEO_VESA) || defined(CONFIG_FIRMWARE_EDID)
32 u16 ax, cx, di;
33 u16 mode;
34 addr_t mode_ptr;
35 struct mode_info *mi;
36 int nmodes = 0;
37
38 video_vesa.modes = GET_HEAP(struct mode_info, 0);
39
40 vginfo.signature = VBE2_MAGIC;
41
42 ax = 0x4f00;
43 di = (size_t)&vginfo;
44 asm(INT10
45 : "+a" (ax), "+D" (di), "=m" (vginfo)
46 : : "ebx", "ecx", "edx", "esi");
47
48 if (ax != 0x004f ||
49 vginfo.signature != VESA_MAGIC ||
50 vginfo.version < 0x0102)
51 return 0; /* Not present */
52#endif /* CONFIG_VIDEO_VESA || CONFIG_FIRMWARE_EDID */
53#ifdef CONFIG_VIDEO_VESA
54 set_fs(vginfo.video_mode_ptr.seg);
55 mode_ptr = vginfo.video_mode_ptr.off;
56
57 while ((mode = rdfs16(mode_ptr)) != 0xffff) {
58 mode_ptr += 2;
59
60 if (heap_free() < sizeof(struct mode_info))
61 break; /* Heap full, can't save mode info */
62
63 if (mode & ~0x1ff)
64 continue;
65
66 memset(&vminfo, 0, sizeof vminfo); /* Just in case... */
67
68 ax = 0x4f01;
69 cx = mode;
70 di = (size_t)&vminfo;
71 asm(INT10
72 : "+a" (ax), "+c" (cx), "+D" (di), "=m" (vminfo)
73 : : "ebx", "edx", "esi");
74
75 if (ax != 0x004f)
76 continue;
77
78 if ((vminfo.mode_attr & 0x15) == 0x05) {
79 /* Text Mode, TTY BIOS supported,
80 supported by hardware */
81 mi = GET_HEAP(struct mode_info, 1);
82 mi->mode = mode + VIDEO_FIRST_VESA;
83 mi->x = vminfo.h_res;
84 mi->y = vminfo.v_res;
85 nmodes++;
86 } else if ((vminfo.mode_attr & 0x99) == 0x99) {
87#ifdef CONFIG_FB
88 /* Graphics mode, color, linear frame buffer
89 supported -- register the mode but hide from
90 the menu. Only do this if framebuffer is
91 configured, however, otherwise the user will
92 be left without a screen. */
93 mi = GET_HEAP(struct mode_info, 1);
94 mi->mode = mode + VIDEO_FIRST_VESA;
95 mi->x = mi->y = 0;
96 nmodes++;
97#endif
98 }
99 }
100
101 return nmodes;
102#else
103 return 0;
104#endif /* CONFIG_VIDEO_VESA */
105}
106
107static int vesa_set_mode(struct mode_info *mode)
108{
109 u16 ax, bx, cx, di;
110 int is_graphic;
111 u16 vesa_mode = mode->mode - VIDEO_FIRST_VESA;
112
113 memset(&vminfo, 0, sizeof vminfo); /* Just in case... */
114
115 ax = 0x4f01;
116 cx = vesa_mode;
117 di = (size_t)&vminfo;
118 asm(INT10
119 : "+a" (ax), "+c" (cx), "+D" (di), "=m" (vminfo)
120 : : "ebx", "edx", "esi");
121
122 if (ax != 0x004f)
123 return -1;
124
125 if ((vminfo.mode_attr & 0x15) == 0x05) {
126 /* It's a supported text mode */
127 is_graphic = 0;
128 } else if ((vminfo.mode_attr & 0x99) == 0x99) {
129 /* It's a graphics mode with linear frame buffer */
130 is_graphic = 1;
131 vesa_mode |= 0x4000; /* Request linear frame buffer */
132 } else {
133 return -1; /* Invalid mode */
134 }
135
136
137 ax = 0x4f02;
138 bx = vesa_mode;
139 di = 0;
140 asm volatile(INT10
141 : "+a" (ax), "+b" (bx), "+D" (di)
142 : : "ecx", "edx", "esi");
143
144 if (ax != 0x004f)
145 return -1;
146
147 graphic_mode = is_graphic;
148 if (!is_graphic) {
149 /* Text mode */
150 force_x = mode->x;
151 force_y = mode->y;
152 do_restore = 1;
153 } else {
154 /* Graphics mode */
155 vesa_store_mode_params_graphics();
156 }
157
158 return 0;
159}
160
161
162/* Switch DAC to 8-bit mode */
163static void vesa_dac_set_8bits(void)
164{
165 u8 dac_size = 6;
166
167 /* If possible, switch the DAC to 8-bit mode */
168 if (vginfo.capabilities & 1) {
169 u16 ax, bx;
170
171 ax = 0x4f08;
172 bx = 0x0800;
173 asm volatile(INT10
174 : "+a" (ax), "+b" (bx)
175 : : "ecx", "edx", "esi", "edi");
176
177 if (ax == 0x004f)
178 dac_size = bx >> 8;
179 }
180
181 /* Set the color sizes to the DAC size, and offsets to 0 */
182 boot_params.screen_info.red_size = dac_size;
183 boot_params.screen_info.green_size = dac_size;
184 boot_params.screen_info.blue_size = dac_size;
185 boot_params.screen_info.rsvd_size = dac_size;
186
187 boot_params.screen_info.red_pos = 0;
188 boot_params.screen_info.green_pos = 0;
189 boot_params.screen_info.blue_pos = 0;
190 boot_params.screen_info.rsvd_pos = 0;
191}
192
193/* Save the VESA protected mode info */
194static void vesa_store_pm_info(void)
195{
196 u16 ax, bx, di, es;
197
198 ax = 0x4f0a;
199 bx = di = 0;
200 asm("pushw %%es; "INT10"; movw %%es,%0; popw %%es"
201 : "=d" (es), "+a" (ax), "+b" (bx), "+D" (di)
202 : : "ecx", "esi");
203
204 if (ax != 0x004f)
205 return;
206
207 boot_params.screen_info.vesapm_seg = es;
208 boot_params.screen_info.vesapm_off = di;
209}
210
211/*
212 * Save video mode parameters for graphics mode
213 */
214static void vesa_store_mode_params_graphics(void)
215{
216 /* Tell the kernel we're in VESA graphics mode */
217 boot_params.screen_info.orig_video_isVGA = 0x23;
218
219 /* Mode parameters */
220 boot_params.screen_info.vesa_attributes = vminfo.mode_attr;
221 boot_params.screen_info.lfb_linelength = vminfo.logical_scan;
222 boot_params.screen_info.lfb_width = vminfo.h_res;
223 boot_params.screen_info.lfb_height = vminfo.v_res;
224 boot_params.screen_info.lfb_depth = vminfo.bpp;
225 boot_params.screen_info.pages = vminfo.image_planes;
226 boot_params.screen_info.lfb_base = vminfo.lfb_ptr;
227 memcpy(&boot_params.screen_info.red_size,
228 &vminfo.rmask, 8);
229
230 /* General parameters */
231 boot_params.screen_info.lfb_size = vginfo.total_memory;
232
233 if (vminfo.bpp <= 8)
234 vesa_dac_set_8bits();
235
236 vesa_store_pm_info();
237}
238
239/*
240 * Save EDID information for the kernel; this is invoked, separately,
241 * after mode-setting.
242 */
243void vesa_store_edid(void)
244{
245#ifdef CONFIG_FIRMWARE_EDID
246 u16 ax, bx, cx, dx, di;
247
248 /* Apparently used as a nonsense token... */
249 memset(&boot_params.edid_info, 0x13, sizeof boot_params.edid_info);
250
251 if (vginfo.version < 0x0200)
252 return; /* EDID requires VBE 2.0+ */
253
254 ax = 0x4f15; /* VBE DDC */
255 bx = 0x0000; /* Report DDC capabilities */
256 cx = 0; /* Controller 0 */
257 di = 0; /* ES:DI must be 0 by spec */
258
259 /* Note: The VBE DDC spec is different from the main VESA spec;
260 we genuinely have to assume all registers are destroyed here. */
261
262 asm("pushw %%es; movw %2,%%es; "INT10"; popw %%es"
263 : "+a" (ax), "+b" (bx)
264 : "c" (cx), "D" (di)
265 : "esi");
266
267 if (ax != 0x004f)
268 return; /* No EDID */
269
270 /* BH = time in seconds to transfer EDD information */
271 /* BL = DDC level supported */
272
273 ax = 0x4f15; /* VBE DDC */
274 bx = 0x0001; /* Read EDID */
275 cx = 0; /* Controller 0 */
276 dx = 0; /* EDID block number */
277 di =(size_t) &boot_params.edid_info; /* (ES:)Pointer to block */
278 asm(INT10
279 : "+a" (ax), "+b" (bx), "+d" (dx), "=m" (boot_params.edid_info)
280 : "c" (cx), "D" (di)
281 : "esi");
282#endif /* CONFIG_FIRMWARE_EDID */
283}
284
285__videocard video_vesa =
286{
287 .card_name = "VESA",
288 .probe = vesa_probe,
289 .set_mode = vesa_set_mode,
290 .xmode_first = VIDEO_FIRST_VESA,
291 .xmode_n = 0x200,
292};
diff --git a/arch/x86/boot/video-vga.c b/arch/x86/boot/video-vga.c
new file mode 100644
index 000000000000..aef02f9ec0c1
--- /dev/null
+++ b/arch/x86/boot/video-vga.c
@@ -0,0 +1,261 @@
1/* -*- linux-c -*- ------------------------------------------------------- *
2 *
3 * Copyright (C) 1991, 1992 Linus Torvalds
4 * Copyright 2007 rPath, Inc. - All Rights Reserved
5 *
6 * This file is part of the Linux kernel, and is made available under
7 * the terms of the GNU General Public License version 2.
8 *
9 * ----------------------------------------------------------------------- */
10
11/*
12 * arch/i386/boot/video-vga.c
13 *
14 * Common all-VGA modes
15 */
16
17#include "boot.h"
18#include "video.h"
19
20static struct mode_info vga_modes[] = {
21 { VIDEO_80x25, 80, 25 },
22 { VIDEO_8POINT, 80, 50 },
23 { VIDEO_80x43, 80, 43 },
24 { VIDEO_80x28, 80, 28 },
25 { VIDEO_80x30, 80, 30 },
26 { VIDEO_80x34, 80, 34 },
27 { VIDEO_80x60, 80, 60 },
28};
29
30static struct mode_info ega_modes[] = {
31 { VIDEO_80x25, 80, 25 },
32 { VIDEO_8POINT, 80, 43 },
33};
34
35static struct mode_info cga_modes[] = {
36 { VIDEO_80x25, 80, 25 },
37};
38
39__videocard video_vga;
40
41/* Set basic 80x25 mode */
42static u8 vga_set_basic_mode(void)
43{
44 u16 ax;
45 u8 rows;
46 u8 mode;
47
48#ifdef CONFIG_VIDEO_400_HACK
49 if (adapter >= ADAPTER_VGA) {
50 asm volatile(INT10
51 : : "a" (0x1202), "b" (0x0030)
52 : "ecx", "edx", "esi", "edi");
53 }
54#endif
55
56 ax = 0x0f00;
57 asm volatile(INT10
58 : "+a" (ax)
59 : : "ebx", "ecx", "edx", "esi", "edi");
60
61 mode = (u8)ax;
62
63 set_fs(0);
64 rows = rdfs8(0x484); /* rows minus one */
65
66#ifndef CONFIG_VIDEO_400_HACK
67 if ((ax == 0x5003 || ax == 0x5007) &&
68 (rows == 0 || rows == 24))
69 return mode;
70#endif
71
72 if (mode != 3 && mode != 7)
73 mode = 3;
74
75 /* Set the mode */
76 ax = mode;
77 asm volatile(INT10
78 : "+a" (ax)
79 : : "ebx", "ecx", "edx", "esi", "edi");
80 do_restore = 1;
81 return mode;
82}
83
84static void vga_set_8font(void)
85{
86 /* Set 8x8 font - 80x43 on EGA, 80x50 on VGA */
87
88 /* Set 8x8 font */
89 asm volatile(INT10 : : "a" (0x1112), "b" (0));
90
91 /* Use alternate print screen */
92 asm volatile(INT10 : : "a" (0x1200), "b" (0x20));
93
94 /* Turn off cursor emulation */
95 asm volatile(INT10 : : "a" (0x1201), "b" (0x34));
96
97 /* Cursor is scan lines 6-7 */
98 asm volatile(INT10 : : "a" (0x0100), "c" (0x0607));
99}
100
101static void vga_set_14font(void)
102{
103 /* Set 9x14 font - 80x28 on VGA */
104
105 /* Set 9x14 font */
106 asm volatile(INT10 : : "a" (0x1111), "b" (0));
107
108 /* Turn off cursor emulation */
109 asm volatile(INT10 : : "a" (0x1201), "b" (0x34));
110
111 /* Cursor is scan lines 11-12 */
112 asm volatile(INT10 : : "a" (0x0100), "c" (0x0b0c));
113}
114
115static void vga_set_80x43(void)
116{
117 /* Set 80x43 mode on VGA (not EGA) */
118
119 /* Set 350 scans */
120 asm volatile(INT10 : : "a" (0x1201), "b" (0x30));
121
122 /* Reset video mode */
123 asm volatile(INT10 : : "a" (0x0003));
124
125 vga_set_8font();
126}
127
128/* I/O address of the VGA CRTC */
129u16 vga_crtc(void)
130{
131 return (inb(0x3cc) & 1) ? 0x3d4 : 0x3b4;
132}
133
134static void vga_set_480_scanlines(int end)
135{
136 u16 crtc;
137 u8 csel;
138
139 crtc = vga_crtc();
140
141 out_idx(0x0c, crtc, 0x11); /* Vertical sync end, unlock CR0-7 */
142 out_idx(0x0b, crtc, 0x06); /* Vertical total */
143 out_idx(0x3e, crtc, 0x07); /* Vertical overflow */
144 out_idx(0xea, crtc, 0x10); /* Vertical sync start */
145 out_idx(end, crtc, 0x12); /* Vertical display end */
146 out_idx(0xe7, crtc, 0x15); /* Vertical blank start */
147 out_idx(0x04, crtc, 0x16); /* Vertical blank end */
148 csel = inb(0x3cc);
149 csel &= 0x0d;
150 csel |= 0xe2;
151 outb(csel, 0x3cc);
152}
153
154static void vga_set_80x30(void)
155{
156 vga_set_480_scanlines(0xdf);
157}
158
159static void vga_set_80x34(void)
160{
161 vga_set_14font();
162 vga_set_480_scanlines(0xdb);
163}
164
165static void vga_set_80x60(void)
166{
167 vga_set_8font();
168 vga_set_480_scanlines(0xdf);
169}
170
171static int vga_set_mode(struct mode_info *mode)
172{
173 /* Set the basic mode */
174 vga_set_basic_mode();
175
176 /* Override a possibly broken BIOS */
177 force_x = mode->x;
178 force_y = mode->y;
179
180 switch (mode->mode) {
181 case VIDEO_80x25:
182 break;
183 case VIDEO_8POINT:
184 vga_set_8font();
185 break;
186 case VIDEO_80x43:
187 vga_set_80x43();
188 break;
189 case VIDEO_80x28:
190 vga_set_14font();
191 break;
192 case VIDEO_80x30:
193 vga_set_80x30();
194 break;
195 case VIDEO_80x34:
196 vga_set_80x34();
197 break;
198 case VIDEO_80x60:
199 vga_set_80x60();
200 break;
201 }
202
203 return 0;
204}
205
206/*
207 * Note: this probe includes basic information required by all
208 * systems. It should be executed first, by making sure
209 * video-vga.c is listed first in the Makefile.
210 */
211static int vga_probe(void)
212{
213 static const char *card_name[] = {
214 "CGA/MDA/HGC", "EGA", "VGA"
215 };
216 static struct mode_info *mode_lists[] = {
217 cga_modes,
218 ega_modes,
219 vga_modes,
220 };
221 static int mode_count[] = {
222 sizeof(cga_modes)/sizeof(struct mode_info),
223 sizeof(ega_modes)/sizeof(struct mode_info),
224 sizeof(vga_modes)/sizeof(struct mode_info),
225 };
226 u8 vga_flag;
227
228 asm(INT10
229 : "=b" (boot_params.screen_info.orig_video_ega_bx)
230 : "a" (0x1200), "b" (0x10) /* Check EGA/VGA */
231 : "ecx", "edx", "esi", "edi");
232
233 /* If we have MDA/CGA/HGC then BL will be unchanged at 0x10 */
234 if ((u8)boot_params.screen_info.orig_video_ega_bx != 0x10) {
235 /* EGA/VGA */
236 asm(INT10
237 : "=a" (vga_flag)
238 : "a" (0x1a00)
239 : "ebx", "ecx", "edx", "esi", "edi");
240
241 if (vga_flag == 0x1a) {
242 adapter = ADAPTER_VGA;
243 boot_params.screen_info.orig_video_isVGA = 1;
244 } else {
245 adapter = ADAPTER_EGA;
246 }
247 } else {
248 adapter = ADAPTER_CGA;
249 }
250
251 video_vga.modes = mode_lists[adapter];
252 video_vga.card_name = card_name[adapter];
253 return mode_count[adapter];
254}
255
256__videocard video_vga =
257{
258 .card_name = "VGA",
259 .probe = vga_probe,
260 .set_mode = vga_set_mode,
261};
diff --git a/arch/x86/boot/video.c b/arch/x86/boot/video.c
new file mode 100644
index 000000000000..e4ba897bf9a3
--- /dev/null
+++ b/arch/x86/boot/video.c
@@ -0,0 +1,467 @@
1/* -*- linux-c -*- ------------------------------------------------------- *
2 *
3 * Copyright (C) 1991, 1992 Linus Torvalds
4 * Copyright 2007 rPath, Inc. - All Rights Reserved
5 *
6 * This file is part of the Linux kernel, and is made available under
7 * the terms of the GNU General Public License version 2.
8 *
9 * ----------------------------------------------------------------------- */
10
11/*
12 * arch/i386/boot/video.c
13 *
14 * Select video mode
15 */
16
17#include "boot.h"
18#include "video.h"
19#include "vesa.h"
20
21/*
22 * Mode list variables
23 */
24static struct card_info cards[]; /* List of cards to probe for */
25
26/*
27 * Common variables
28 */
29int adapter; /* 0=CGA/MDA/HGC, 1=EGA, 2=VGA+ */
30u16 video_segment;
31int force_x, force_y; /* Don't query the BIOS for cols/rows */
32
33int do_restore = 0; /* Screen contents changed during mode flip */
34int graphic_mode; /* Graphic mode with linear frame buffer */
35
36static void store_cursor_position(void)
37{
38 u16 curpos;
39 u16 ax, bx;
40
41 ax = 0x0300;
42 bx = 0;
43 asm(INT10
44 : "=d" (curpos), "+a" (ax), "+b" (bx)
45 : : "ecx", "esi", "edi");
46
47 boot_params.screen_info.orig_x = curpos;
48 boot_params.screen_info.orig_y = curpos >> 8;
49}
50
51static void store_video_mode(void)
52{
53 u16 ax, page;
54
55 /* N.B.: the saving of the video page here is a bit silly,
56 since we pretty much assume page 0 everywhere. */
57 ax = 0x0f00;
58 asm(INT10
59 : "+a" (ax), "=b" (page)
60 : : "ecx", "edx", "esi", "edi");
61
62 /* Not all BIOSes are clean with respect to the top bit */
63 boot_params.screen_info.orig_video_mode = ax & 0x7f;
64 boot_params.screen_info.orig_video_page = page >> 8;
65}
66
67/*
68 * Store the video mode parameters for later usage by the kernel.
69 * This is done by asking the BIOS except for the rows/columns
70 * parameters in the default 80x25 mode -- these are set directly,
71 * because some very obscure BIOSes supply insane values.
72 */
73static void store_mode_params(void)
74{
75 u16 font_size;
76 int x, y;
77
78 /* For graphics mode, it is up to the mode-setting driver
79 (currently only video-vesa.c) to store the parameters */
80 if (graphic_mode)
81 return;
82
83 store_cursor_position();
84 store_video_mode();
85
86 if (boot_params.screen_info.orig_video_mode == 0x07) {
87 /* MDA, HGC, or VGA in monochrome mode */
88 video_segment = 0xb000;
89 } else {
90 /* CGA, EGA, VGA and so forth */
91 video_segment = 0xb800;
92 }
93
94 set_fs(0);
95 font_size = rdfs16(0x485); /* Font size, BIOS area */
96 boot_params.screen_info.orig_video_points = font_size;
97
98 x = rdfs16(0x44a);
99 y = (adapter == ADAPTER_CGA) ? 25 : rdfs8(0x484)+1;
100
101 if (force_x)
102 x = force_x;
103 if (force_y)
104 y = force_y;
105
106 boot_params.screen_info.orig_video_cols = x;
107 boot_params.screen_info.orig_video_lines = y;
108}
109
110/* Probe the video drivers and have them generate their mode lists. */
111static void probe_cards(int unsafe)
112{
113 struct card_info *card;
114 static u8 probed[2];
115
116 if (probed[unsafe])
117 return;
118
119 probed[unsafe] = 1;
120
121 for (card = video_cards; card < video_cards_end; card++) {
122 if (card->unsafe == unsafe) {
123 if (card->probe)
124 card->nmodes = card->probe();
125 else
126 card->nmodes = 0;
127 }
128 }
129}
130
131/* Test if a mode is defined */
132int mode_defined(u16 mode)
133{
134 struct card_info *card;
135 struct mode_info *mi;
136 int i;
137
138 for (card = video_cards; card < video_cards_end; card++) {
139 mi = card->modes;
140 for (i = 0; i < card->nmodes; i++, mi++) {
141 if (mi->mode == mode)
142 return 1;
143 }
144 }
145
146 return 0;
147}
148
149/* Set mode (without recalc) */
150static int raw_set_mode(u16 mode, u16 *real_mode)
151{
152 int nmode, i;
153 struct card_info *card;
154 struct mode_info *mi;
155
156 /* Drop the recalc bit if set */
157 mode &= ~VIDEO_RECALC;
158
159 /* Scan for mode based on fixed ID, position, or resolution */
160 nmode = 0;
161 for (card = video_cards; card < video_cards_end; card++) {
162 mi = card->modes;
163 for (i = 0; i < card->nmodes; i++, mi++) {
164 int visible = mi->x || mi->y;
165
166 if ((mode == nmode && visible) ||
167 mode == mi->mode ||
168 mode == (mi->y << 8)+mi->x) {
169 *real_mode = mi->mode;
170 return card->set_mode(mi);
171 }
172
173 if (visible)
174 nmode++;
175 }
176 }
177
178 /* Nothing found? Is it an "exceptional" (unprobed) mode? */
179 for (card = video_cards; card < video_cards_end; card++) {
180 if (mode >= card->xmode_first &&
181 mode < card->xmode_first+card->xmode_n) {
182 struct mode_info mix;
183 *real_mode = mix.mode = mode;
184 mix.x = mix.y = 0;
185 return card->set_mode(&mix);
186 }
187 }
188
189 /* Otherwise, failure... */
190 return -1;
191}
192
193/*
194 * Recalculate the vertical video cutoff (hack!)
195 */
196static void vga_recalc_vertical(void)
197{
198 unsigned int font_size, rows;
199 u16 crtc;
200 u8 pt, ov;
201
202 set_fs(0);
203 font_size = rdfs8(0x485); /* BIOS: font size (pixels) */
204 rows = force_y ? force_y : rdfs8(0x484)+1; /* Text rows */
205
206 rows *= font_size; /* Visible scan lines */
207 rows--; /* ... minus one */
208
209 crtc = vga_crtc();
210
211 pt = in_idx(crtc, 0x11);
212 pt &= ~0x80; /* Unlock CR0-7 */
213 out_idx(pt, crtc, 0x11);
214
215 out_idx((u8)rows, crtc, 0x12); /* Lower height register */
216
217 ov = in_idx(crtc, 0x07); /* Overflow register */
218 ov &= 0xbd;
219 ov |= (rows >> (8-1)) & 0x02;
220 ov |= (rows >> (9-6)) & 0x40;
221 out_idx(ov, crtc, 0x07);
222}
223
224/* Set mode (with recalc if specified) */
225static int set_mode(u16 mode)
226{
227 int rv;
228 u16 real_mode;
229
230 /* Very special mode numbers... */
231 if (mode == VIDEO_CURRENT_MODE)
232 return 0; /* Nothing to do... */
233 else if (mode == NORMAL_VGA)
234 mode = VIDEO_80x25;
235 else if (mode == EXTENDED_VGA)
236 mode = VIDEO_8POINT;
237
238 rv = raw_set_mode(mode, &real_mode);
239 if (rv)
240 return rv;
241
242 if (mode & VIDEO_RECALC)
243 vga_recalc_vertical();
244
245 /* Save the canonical mode number for the kernel, not
246 an alias, size specification or menu position */
247 boot_params.hdr.vid_mode = real_mode;
248 return 0;
249}
250
251static unsigned int get_entry(void)
252{
253 char entry_buf[4];
254 int i, len = 0;
255 int key;
256 unsigned int v;
257
258 do {
259 key = getchar();
260
261 if (key == '\b') {
262 if (len > 0) {
263 puts("\b \b");
264 len--;
265 }
266 } else if ((key >= '0' && key <= '9') ||
267 (key >= 'A' && key <= 'Z') ||
268 (key >= 'a' && key <= 'z')) {
269 if (len < sizeof entry_buf) {
270 entry_buf[len++] = key;
271 putchar(key);
272 }
273 }
274 } while (key != '\r');
275 putchar('\n');
276
277 if (len == 0)
278 return VIDEO_CURRENT_MODE; /* Default */
279
280 v = 0;
281 for (i = 0; i < len; i++) {
282 v <<= 4;
283 key = entry_buf[i] | 0x20;
284 v += (key > '9') ? key-'a'+10 : key-'0';
285 }
286
287 return v;
288}
289
290static void display_menu(void)
291{
292 struct card_info *card;
293 struct mode_info *mi;
294 char ch;
295 int i;
296
297 puts("Mode: COLSxROWS:\n");
298
299 ch = '0';
300 for (card = video_cards; card < video_cards_end; card++) {
301 mi = card->modes;
302 for (i = 0; i < card->nmodes; i++, mi++) {
303 int visible = mi->x && mi->y;
304 u16 mode_id = mi->mode ? mi->mode :
305 (mi->y << 8)+mi->x;
306
307 if (!visible)
308 continue; /* Hidden mode */
309
310 printf("%c %04X %3dx%-3d %s\n",
311 ch, mode_id, mi->x, mi->y, card->card_name);
312
313 if (ch == '9')
314 ch = 'a';
315 else if (ch == 'z' || ch == ' ')
316 ch = ' '; /* Out of keys... */
317 else
318 ch++;
319 }
320 }
321}
322
323#define H(x) ((x)-'a'+10)
324#define SCAN ((H('s')<<12)+(H('c')<<8)+(H('a')<<4)+H('n'))
325
326static unsigned int mode_menu(void)
327{
328 int key;
329 unsigned int sel;
330
331 puts("Press <ENTER> to see video modes available, "
332 "<SPACE> to continue, or wait 30 sec\n");
333
334 kbd_flush();
335 while (1) {
336 key = getchar_timeout();
337 if (key == ' ' || key == 0)
338 return VIDEO_CURRENT_MODE; /* Default */
339 if (key == '\r')
340 break;
341 putchar('\a'); /* Beep! */
342 }
343
344
345 for (;;) {
346 display_menu();
347
348 puts("Enter a video mode or \"scan\" to scan for "
349 "additional modes: ");
350 sel = get_entry();
351 if (sel != SCAN)
352 return sel;
353
354 probe_cards(1);
355 }
356}
357
358#ifdef CONFIG_VIDEO_RETAIN
359/* Save screen content to the heap */
360struct saved_screen {
361 int x, y;
362 int curx, cury;
363 u16 *data;
364} saved;
365
366static void save_screen(void)
367{
368 /* Should be called after store_mode_params() */
369 saved.x = boot_params.screen_info.orig_video_cols;
370 saved.y = boot_params.screen_info.orig_video_lines;
371 saved.curx = boot_params.screen_info.orig_x;
372 saved.cury = boot_params.screen_info.orig_y;
373
374 if (heap_free() < saved.x*saved.y*sizeof(u16)+512)
375 return; /* Not enough heap to save the screen */
376
377 saved.data = GET_HEAP(u16, saved.x*saved.y);
378
379 set_fs(video_segment);
380 copy_from_fs(saved.data, 0, saved.x*saved.y*sizeof(u16));
381}
382
383static void restore_screen(void)
384{
385 /* Should be called after store_mode_params() */
386 int xs = boot_params.screen_info.orig_video_cols;
387 int ys = boot_params.screen_info.orig_video_lines;
388 int y;
389 addr_t dst = 0;
390 u16 *src = saved.data;
391 u16 ax, bx, dx;
392
393 if (graphic_mode)
394 return; /* Can't restore onto a graphic mode */
395
396 if (!src)
397 return; /* No saved screen contents */
398
399 /* Restore screen contents */
400
401 set_fs(video_segment);
402 for (y = 0; y < ys; y++) {
403 int npad;
404
405 if (y < saved.y) {
406 int copy = (xs < saved.x) ? xs : saved.x;
407 copy_to_fs(dst, src, copy*sizeof(u16));
408 dst += copy*sizeof(u16);
409 src += saved.x;
410 npad = (xs < saved.x) ? 0 : xs-saved.x;
411 } else {
412 npad = xs;
413 }
414
415 /* Writes "npad" blank characters to
416 video_segment:dst and advances dst */
417 asm volatile("pushw %%es ; "
418 "movw %2,%%es ; "
419 "shrw %%cx ; "
420 "jnc 1f ; "
421 "stosw \n\t"
422 "1: rep;stosl ; "
423 "popw %%es"
424 : "+D" (dst), "+c" (npad)
425 : "bdS" (video_segment),
426 "a" (0x07200720));
427 }
428
429 /* Restore cursor position */
430 ax = 0x0200; /* Set cursor position */
431 bx = 0; /* Page number (<< 8) */
432 dx = (saved.cury << 8)+saved.curx;
433 asm volatile(INT10
434 : "+a" (ax), "+b" (bx), "+d" (dx)
435 : : "ecx", "esi", "edi");
436}
437#else
438#define save_screen() ((void)0)
439#define restore_screen() ((void)0)
440#endif
441
442void set_video(void)
443{
444 u16 mode = boot_params.hdr.vid_mode;
445
446 RESET_HEAP();
447
448 store_mode_params();
449 save_screen();
450 probe_cards(0);
451
452 for (;;) {
453 if (mode == ASK_VGA)
454 mode = mode_menu();
455
456 if (!set_mode(mode))
457 break;
458
459 printf("Undefined video mode number: %x\n", mode);
460 mode = ASK_VGA;
461 }
462 vesa_store_edid();
463 store_mode_params();
464
465 if (do_restore)
466 restore_screen();
467}
diff --git a/arch/x86/boot/video.h b/arch/x86/boot/video.h
new file mode 100644
index 000000000000..b92447d51213
--- /dev/null
+++ b/arch/x86/boot/video.h
@@ -0,0 +1,152 @@
1/* -*- linux-c -*- ------------------------------------------------------- *
2 *
3 * Copyright (C) 1991, 1992 Linus Torvalds
4 * Copyright 2007 rPath, Inc. - All Rights Reserved
5 *
6 * This file is part of the Linux kernel, and is made available under
7 * the terms of the GNU General Public License version 2.
8 *
9 * ----------------------------------------------------------------------- */
10
11/*
12 * arch/i386/boot/video.h
13 *
14 * Header file for the real-mode video probing code
15 */
16
17#ifndef BOOT_VIDEO_H
18#define BOOT_VIDEO_H
19
20#include <linux/types.h>
21
22/* Enable autodetection of SVGA adapters and modes. */
23#undef CONFIG_VIDEO_SVGA
24
25/* Enable autodetection of VESA modes */
26#define CONFIG_VIDEO_VESA
27
28/* Retain screen contents when switching modes */
29#define CONFIG_VIDEO_RETAIN
30
31/* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */
32#undef CONFIG_VIDEO_400_HACK
33
34/* This code uses an extended set of video mode numbers. These include:
35 * Aliases for standard modes
36 * NORMAL_VGA (-1)
37 * EXTENDED_VGA (-2)
38 * ASK_VGA (-3)
39 * Video modes numbered by menu position -- NOT RECOMMENDED because of lack
40 * of compatibility when extending the table. These are between 0x00 and 0xff.
41 */
42#define VIDEO_FIRST_MENU 0x0000
43
44/* Standard BIOS video modes (BIOS number + 0x0100) */
45#define VIDEO_FIRST_BIOS 0x0100
46
47/* VESA BIOS video modes (VESA number + 0x0200) */
48#define VIDEO_FIRST_VESA 0x0200
49
50/* Video7 special modes (BIOS number + 0x0900) */
51#define VIDEO_FIRST_V7 0x0900
52
53/* Special video modes */
54#define VIDEO_FIRST_SPECIAL 0x0f00
55#define VIDEO_80x25 0x0f00
56#define VIDEO_8POINT 0x0f01
57#define VIDEO_80x43 0x0f02
58#define VIDEO_80x28 0x0f03
59#define VIDEO_CURRENT_MODE 0x0f04
60#define VIDEO_80x30 0x0f05
61#define VIDEO_80x34 0x0f06
62#define VIDEO_80x60 0x0f07
63#define VIDEO_GFX_HACK 0x0f08
64#define VIDEO_LAST_SPECIAL 0x0f09
65
66/* Video modes given by resolution */
67#define VIDEO_FIRST_RESOLUTION 0x1000
68
69/* The "recalculate timings" flag */
70#define VIDEO_RECALC 0x8000
71
72/* Define DO_STORE according to CONFIG_VIDEO_RETAIN */
73#ifdef CONFIG_VIDEO_RETAIN
74void store_screen(void);
75#define DO_STORE() store_screen()
76#else
77#define DO_STORE() ((void)0)
78#endif /* CONFIG_VIDEO_RETAIN */
79
80/*
81 * Mode table structures
82 */
83
84struct mode_info {
85 u16 mode; /* Mode number (vga= style) */
86 u8 x, y; /* Width, height */
87};
88
89struct card_info {
90 const char *card_name;
91 int (*set_mode)(struct mode_info *mode);
92 int (*probe)(void);
93 struct mode_info *modes;
94 int nmodes; /* Number of probed modes so far */
95 int unsafe; /* Probing is unsafe, only do after "scan" */
96 u16 xmode_first; /* Unprobed modes to try to call anyway */
97 u16 xmode_n; /* Size of unprobed mode range */
98};
99
100#define __videocard struct card_info __attribute__((section(".videocards")))
101extern struct card_info video_cards[], video_cards_end[];
102
103int mode_defined(u16 mode); /* video.c */
104
105/* Basic video information */
106#define ADAPTER_CGA 0 /* CGA/MDA/HGC */
107#define ADAPTER_EGA 1
108#define ADAPTER_VGA 2
109
110extern int adapter;
111extern u16 video_segment;
112extern int force_x, force_y; /* Don't query the BIOS for cols/rows */
113extern int do_restore; /* Restore screen contents */
114extern int graphic_mode; /* Graphics mode with linear frame buffer */
115
116/*
117 * int $0x10 is notorious for touching registers it shouldn't.
118 * gcc doesn't like %ebp being clobbered, so define it as a push/pop
119 * sequence here.
120 *
121 * A number of systems, including the original PC can clobber %bp in
122 * certain circumstances, like when scrolling. There exists at least
123 * one Trident video card which could clobber DS under a set of
124 * circumstances that we are unlikely to encounter (scrolling when
125 * using an extended graphics mode of more than 800x600 pixels), but
126 * it's cheap insurance to deal with that here.
127 */
128#define INT10 "pushl %%ebp; pushw %%ds; int $0x10; popw %%ds; popl %%ebp"
129
130/* Accessing VGA indexed registers */
131static inline u8 in_idx(u16 port, u8 index)
132{
133 outb(index, port);
134 return inb(port+1);
135}
136
137static inline void out_idx(u8 v, u16 port, u8 index)
138{
139 outw(index+(v << 8), port);
140}
141
142/* Writes a value to an indexed port and then reads the port again */
143static inline u8 tst_idx(u8 v, u16 port, u8 index)
144{
145 out_idx(port, index, v);
146 return in_idx(port, index);
147}
148
149/* Get the I/O port of the VGA CRTC */
150u16 vga_crtc(void); /* video-vga.c */
151
152#endif /* BOOT_VIDEO_H */
diff --git a/arch/x86/boot/voyager.c b/arch/x86/boot/voyager.c
new file mode 100644
index 000000000000..61c8fe0453be
--- /dev/null
+++ b/arch/x86/boot/voyager.c
@@ -0,0 +1,46 @@
1/* -*- linux-c -*- ------------------------------------------------------- *
2 *
3 * Copyright (C) 1991, 1992 Linus Torvalds
4 * Copyright 2007 rPath, Inc. - All Rights Reserved
5 *
6 * This file is part of the Linux kernel, and is made available under
7 * the terms of the GNU General Public License version 2.
8 *
9 * ----------------------------------------------------------------------- */
10
11/*
12 * arch/i386/boot/voyager.c
13 *
14 * Get the Voyager config information
15 */
16
17#include "boot.h"
18
19#ifdef CONFIG_X86_VOYAGER
20
21int query_voyager(void)
22{
23 u8 err;
24 u16 es, di;
25 /* Abuse the apm_bios_info area for this */
26 u8 *data_ptr = (u8 *)&boot_params.apm_bios_info;
27
28 data_ptr[0] = 0xff; /* Flag on config not found(?) */
29
30 asm("pushw %%es ; "
31 "int $0x15 ; "
32 "setc %0 ; "
33 "movw %%es, %1 ; "
34 "popw %%es"
35 : "=q" (err), "=r" (es), "=D" (di)
36 : "a" (0xffc0));
37
38 if (err)
39 return -1; /* Not Voyager */
40
41 set_fs(es);
42 copy_from_fs(data_ptr, di, 7); /* Table is 7 bytes apparently */
43 return 0;
44}
45
46#endif /* CONFIG_X86_VOYAGER */