diff options
Diffstat (limited to 'arch/x86/boot')
28 files changed, 850 insertions, 655 deletions
diff --git a/arch/x86/boot/.gitignore b/arch/x86/boot/.gitignore index 172cf8a98bdd..851fe936d242 100644 --- a/arch/x86/boot/.gitignore +++ b/arch/x86/boot/.gitignore | |||
@@ -3,6 +3,8 @@ bzImage | |||
3 | cpustr.h | 3 | cpustr.h |
4 | mkcpustr | 4 | mkcpustr |
5 | offsets.h | 5 | offsets.h |
6 | voffset.h | ||
7 | zoffset.h | ||
6 | setup | 8 | setup |
7 | setup.bin | 9 | setup.bin |
8 | setup.elf | 10 | setup.elf |
diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile index 6633b6e7505a..8d16ada25048 100644 --- a/arch/x86/boot/Makefile +++ b/arch/x86/boot/Makefile | |||
@@ -26,9 +26,10 @@ targets := vmlinux.bin setup.bin setup.elf bzImage | |||
26 | targets += fdimage fdimage144 fdimage288 image.iso mtools.conf | 26 | targets += fdimage fdimage144 fdimage288 image.iso mtools.conf |
27 | subdir- := compressed | 27 | subdir- := compressed |
28 | 28 | ||
29 | setup-y += a20.o cmdline.o copy.o cpu.o cpucheck.o edd.o | 29 | setup-y += a20.o bioscall.o cmdline.o copy.o cpu.o cpucheck.o edd.o |
30 | setup-y += header.o main.o mca.o memory.o pm.o pmjump.o | 30 | setup-y += header.o main.o mca.o memory.o pm.o pmjump.o |
31 | setup-y += printf.o string.o tty.o video.o video-mode.o version.o | 31 | setup-y += printf.o regs.o string.o tty.o video.o video-mode.o |
32 | setup-y += version.o | ||
32 | setup-$(CONFIG_X86_APM_BOOT) += apm.o | 33 | setup-$(CONFIG_X86_APM_BOOT) += apm.o |
33 | 34 | ||
34 | # The link order of the video-*.o modules can matter. In particular, | 35 | # The link order of the video-*.o modules can matter. In particular, |
@@ -86,19 +87,27 @@ $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE | |||
86 | 87 | ||
87 | SETUP_OBJS = $(addprefix $(obj)/,$(setup-y)) | 88 | SETUP_OBJS = $(addprefix $(obj)/,$(setup-y)) |
88 | 89 | ||
89 | sed-offsets := -e 's/^00*/0/' \ | 90 | sed-voffset := -e 's/^\([0-9a-fA-F]*\) . \(_text\|_end\)$$/\#define VO_\2 0x\1/p' |
90 | -e 's/^\([0-9a-fA-F]*\) . \(input_data\|input_data_end\)$$/\#define \2 0x\1/p' | ||
91 | 91 | ||
92 | quiet_cmd_offsets = OFFSETS $@ | 92 | quiet_cmd_voffset = VOFFSET $@ |
93 | cmd_offsets = $(NM) $< | sed -n $(sed-offsets) > $@ | 93 | cmd_voffset = $(NM) $< | sed -n $(sed-voffset) > $@ |
94 | 94 | ||
95 | $(obj)/offsets.h: $(obj)/compressed/vmlinux FORCE | 95 | targets += voffset.h |
96 | $(call if_changed,offsets) | 96 | $(obj)/voffset.h: vmlinux FORCE |
97 | $(call if_changed,voffset) | ||
98 | |||
99 | sed-zoffset := -e 's/^\([0-9a-fA-F]*\) . \(startup_32\|input_data\|_end\|z_.*\)$$/\#define ZO_\2 0x\1/p' | ||
100 | |||
101 | quiet_cmd_zoffset = ZOFFSET $@ | ||
102 | cmd_zoffset = $(NM) $< | sed -n $(sed-zoffset) > $@ | ||
103 | |||
104 | targets += zoffset.h | ||
105 | $(obj)/zoffset.h: $(obj)/compressed/vmlinux FORCE | ||
106 | $(call if_changed,zoffset) | ||
97 | 107 | ||
98 | targets += offsets.h | ||
99 | 108 | ||
100 | AFLAGS_header.o += -I$(obj) | 109 | AFLAGS_header.o += -I$(obj) |
101 | $(obj)/header.o: $(obj)/offsets.h | 110 | $(obj)/header.o: $(obj)/voffset.h $(obj)/zoffset.h |
102 | 111 | ||
103 | LDFLAGS_setup.elf := -T | 112 | LDFLAGS_setup.elf := -T |
104 | $(obj)/setup.elf: $(src)/setup.ld $(SETUP_OBJS) FORCE | 113 | $(obj)/setup.elf: $(src)/setup.ld $(SETUP_OBJS) FORCE |
diff --git a/arch/x86/boot/a20.c b/arch/x86/boot/a20.c index 7c19ce8c2442..64a31a6d751a 100644 --- a/arch/x86/boot/a20.c +++ b/arch/x86/boot/a20.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * | 2 | * |
3 | * Copyright (C) 1991, 1992 Linus Torvalds | 3 | * Copyright (C) 1991, 1992 Linus Torvalds |
4 | * Copyright 2007-2008 rPath, Inc. - All Rights Reserved | 4 | * Copyright 2007-2008 rPath, Inc. - All Rights Reserved |
5 | * Copyright 2009 Intel Corporation | 5 | * Copyright 2009 Intel Corporation; author H. Peter Anvin |
6 | * | 6 | * |
7 | * This file is part of the Linux kernel, and is made available under | 7 | * This file is part of the Linux kernel, and is made available under |
8 | * the terms of the GNU General Public License version 2. | 8 | * the terms of the GNU General Public License version 2. |
@@ -90,8 +90,11 @@ static int a20_test_long(void) | |||
90 | 90 | ||
91 | static void enable_a20_bios(void) | 91 | static void enable_a20_bios(void) |
92 | { | 92 | { |
93 | asm volatile("pushfl; int $0x15; popfl" | 93 | struct biosregs ireg; |
94 | : : "a" ((u16)0x2401)); | 94 | |
95 | initregs(&ireg); | ||
96 | ireg.ax = 0x2401; | ||
97 | intcall(0x15, &ireg, NULL); | ||
95 | } | 98 | } |
96 | 99 | ||
97 | static void enable_a20_kbc(void) | 100 | static void enable_a20_kbc(void) |
diff --git a/arch/x86/boot/apm.c b/arch/x86/boot/apm.c index 7aa6033001f9..ee274834ea8b 100644 --- a/arch/x86/boot/apm.c +++ b/arch/x86/boot/apm.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * | 2 | * |
3 | * Copyright (C) 1991, 1992 Linus Torvalds | 3 | * Copyright (C) 1991, 1992 Linus Torvalds |
4 | * Copyright 2007 rPath, Inc. - All Rights Reserved | 4 | * Copyright 2007 rPath, Inc. - All Rights Reserved |
5 | * Copyright 2009 Intel Corporation; author H. Peter Anvin | ||
5 | * | 6 | * |
6 | * Original APM BIOS checking by Stephen Rothwell, May 1994 | 7 | * Original APM BIOS checking by Stephen Rothwell, May 1994 |
7 | * (sfr@canb.auug.org.au) | 8 | * (sfr@canb.auug.org.au) |
@@ -19,75 +20,56 @@ | |||
19 | 20 | ||
20 | int query_apm_bios(void) | 21 | int query_apm_bios(void) |
21 | { | 22 | { |
22 | u16 ax, bx, cx, dx, di; | 23 | struct biosregs ireg, oreg; |
23 | u32 ebx, esi; | ||
24 | u8 err; | ||
25 | 24 | ||
26 | /* APM BIOS installation check */ | 25 | /* APM BIOS installation check */ |
27 | ax = 0x5300; | 26 | initregs(&ireg); |
28 | bx = cx = 0; | 27 | ireg.ah = 0x53; |
29 | asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %0" | 28 | intcall(0x15, &ireg, &oreg); |
30 | : "=d" (err), "+a" (ax), "+b" (bx), "+c" (cx) | ||
31 | : : "esi", "edi"); | ||
32 | 29 | ||
33 | if (err) | 30 | if (oreg.flags & X86_EFLAGS_CF) |
34 | return -1; /* No APM BIOS */ | 31 | return -1; /* No APM BIOS */ |
35 | 32 | ||
36 | if (bx != 0x504d) /* "PM" signature */ | 33 | if (oreg.bx != 0x504d) /* "PM" signature */ |
37 | return -1; | 34 | return -1; |
38 | 35 | ||
39 | if (!(cx & 0x02)) /* 32 bits supported? */ | 36 | if (!(oreg.cx & 0x02)) /* 32 bits supported? */ |
40 | return -1; | 37 | return -1; |
41 | 38 | ||
42 | /* Disconnect first, just in case */ | 39 | /* Disconnect first, just in case */ |
43 | ax = 0x5304; | 40 | ireg.al = 0x04; |
44 | bx = 0; | 41 | intcall(0x15, &ireg, NULL); |
45 | asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp" | ||
46 | : "+a" (ax), "+b" (bx) | ||
47 | : : "ecx", "edx", "esi", "edi"); | ||
48 | |||
49 | /* Paranoia */ | ||
50 | ebx = esi = 0; | ||
51 | cx = dx = di = 0; | ||
52 | 42 | ||
53 | /* 32-bit connect */ | 43 | /* 32-bit connect */ |
54 | asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %6" | 44 | ireg.al = 0x03; |
55 | : "=a" (ax), "+b" (ebx), "+c" (cx), "+d" (dx), | 45 | intcall(0x15, &ireg, &oreg); |
56 | "+S" (esi), "+D" (di), "=m" (err) | 46 | |
57 | : "a" (0x5303)); | 47 | boot_params.apm_bios_info.cseg = oreg.ax; |
58 | 48 | boot_params.apm_bios_info.offset = oreg.ebx; | |
59 | boot_params.apm_bios_info.cseg = ax; | 49 | boot_params.apm_bios_info.cseg_16 = oreg.cx; |
60 | boot_params.apm_bios_info.offset = ebx; | 50 | boot_params.apm_bios_info.dseg = oreg.dx; |
61 | boot_params.apm_bios_info.cseg_16 = cx; | 51 | boot_params.apm_bios_info.cseg_len = oreg.si; |
62 | boot_params.apm_bios_info.dseg = dx; | 52 | boot_params.apm_bios_info.cseg_16_len = oreg.hsi; |
63 | boot_params.apm_bios_info.cseg_len = (u16)esi; | 53 | boot_params.apm_bios_info.dseg_len = oreg.di; |
64 | boot_params.apm_bios_info.cseg_16_len = esi >> 16; | 54 | |
65 | boot_params.apm_bios_info.dseg_len = di; | 55 | if (oreg.flags & X86_EFLAGS_CF) |
66 | |||
67 | if (err) | ||
68 | return -1; | 56 | return -1; |
69 | 57 | ||
70 | /* Redo the installation check as the 32-bit connect; | 58 | /* Redo the installation check as the 32-bit connect; |
71 | some BIOSes return different flags this way... */ | 59 | some BIOSes return different flags this way... */ |
72 | 60 | ||
73 | ax = 0x5300; | 61 | ireg.al = 0x00; |
74 | bx = cx = 0; | 62 | intcall(0x15, &ireg, &oreg); |
75 | asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %0" | ||
76 | : "=d" (err), "+a" (ax), "+b" (bx), "+c" (cx) | ||
77 | : : "esi", "edi"); | ||
78 | 63 | ||
79 | if (err || bx != 0x504d) { | 64 | if ((oreg.eflags & X86_EFLAGS_CF) || oreg.bx != 0x504d) { |
80 | /* Failure with 32-bit connect, try to disconect and ignore */ | 65 | /* Failure with 32-bit connect, try to disconect and ignore */ |
81 | ax = 0x5304; | 66 | ireg.al = 0x04; |
82 | bx = 0; | 67 | intcall(0x15, &ireg, NULL); |
83 | asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp" | ||
84 | : "+a" (ax), "+b" (bx) | ||
85 | : : "ecx", "edx", "esi", "edi"); | ||
86 | return -1; | 68 | return -1; |
87 | } | 69 | } |
88 | 70 | ||
89 | boot_params.apm_bios_info.version = ax; | 71 | boot_params.apm_bios_info.version = oreg.ax; |
90 | boot_params.apm_bios_info.flags = cx; | 72 | boot_params.apm_bios_info.flags = oreg.cx; |
91 | return 0; | 73 | return 0; |
92 | } | 74 | } |
93 | 75 | ||
diff --git a/arch/x86/boot/bioscall.S b/arch/x86/boot/bioscall.S new file mode 100644 index 000000000000..507793739ea5 --- /dev/null +++ b/arch/x86/boot/bioscall.S | |||
@@ -0,0 +1,82 @@ | |||
1 | /* ----------------------------------------------------------------------- | ||
2 | * | ||
3 | * Copyright 2009 Intel Corporation; author H. Peter Anvin | ||
4 | * | ||
5 | * This file is part of the Linux kernel, and is made available under | ||
6 | * the terms of the GNU General Public License version 2 or (at your | ||
7 | * option) any later version; incorporated herein by reference. | ||
8 | * | ||
9 | * ----------------------------------------------------------------------- */ | ||
10 | |||
11 | /* | ||
12 | * "Glove box" for BIOS calls. Avoids the constant problems with BIOSes | ||
13 | * touching registers they shouldn't be. | ||
14 | */ | ||
15 | |||
16 | .code16 | ||
17 | .text | ||
18 | .globl intcall | ||
19 | .type intcall, @function | ||
20 | intcall: | ||
21 | /* Self-modify the INT instruction. Ugly, but works. */ | ||
22 | cmpb %al, 3f | ||
23 | je 1f | ||
24 | movb %al, 3f | ||
25 | jmp 1f /* Synchronize pipeline */ | ||
26 | 1: | ||
27 | /* Save state */ | ||
28 | pushfl | ||
29 | pushw %fs | ||
30 | pushw %gs | ||
31 | pushal | ||
32 | |||
33 | /* Copy input state to stack frame */ | ||
34 | subw $44, %sp | ||
35 | movw %dx, %si | ||
36 | movw %sp, %di | ||
37 | movw $11, %cx | ||
38 | rep; movsd | ||
39 | |||
40 | /* Pop full state from the stack */ | ||
41 | popal | ||
42 | popw %gs | ||
43 | popw %fs | ||
44 | popw %es | ||
45 | popw %ds | ||
46 | popfl | ||
47 | |||
48 | /* Actual INT */ | ||
49 | .byte 0xcd /* INT opcode */ | ||
50 | 3: .byte 0 | ||
51 | |||
52 | /* Push full state to the stack */ | ||
53 | pushfl | ||
54 | pushw %ds | ||
55 | pushw %es | ||
56 | pushw %fs | ||
57 | pushw %gs | ||
58 | pushal | ||
59 | |||
60 | /* Re-establish C environment invariants */ | ||
61 | cld | ||
62 | movzwl %sp, %esp | ||
63 | movw %cs, %ax | ||
64 | movw %ax, %ds | ||
65 | movw %ax, %es | ||
66 | |||
67 | /* Copy output state from stack frame */ | ||
68 | movw 68(%esp), %di /* Original %cx == 3rd argument */ | ||
69 | andw %di, %di | ||
70 | jz 4f | ||
71 | movw %sp, %si | ||
72 | movw $11, %cx | ||
73 | rep; movsd | ||
74 | 4: addw $44, %sp | ||
75 | |||
76 | /* Restore state and return */ | ||
77 | popal | ||
78 | popw %gs | ||
79 | popw %fs | ||
80 | popfl | ||
81 | retl | ||
82 | .size intcall, .-intcall | ||
diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h index 7b2692e897e5..98239d2658f2 100644 --- a/arch/x86/boot/boot.h +++ b/arch/x86/boot/boot.h | |||
@@ -2,6 +2,7 @@ | |||
2 | * | 2 | * |
3 | * Copyright (C) 1991, 1992 Linus Torvalds | 3 | * Copyright (C) 1991, 1992 Linus Torvalds |
4 | * Copyright 2007 rPath, Inc. - All Rights Reserved | 4 | * Copyright 2007 rPath, Inc. - All Rights Reserved |
5 | * Copyright 2009 Intel Corporation; author H. Peter Anvin | ||
5 | * | 6 | * |
6 | * This file is part of the Linux kernel, and is made available under | 7 | * 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 | * the terms of the GNU General Public License version 2. |
@@ -26,6 +27,7 @@ | |||
26 | #include <asm/setup.h> | 27 | #include <asm/setup.h> |
27 | #include "bitops.h" | 28 | #include "bitops.h" |
28 | #include <asm/cpufeature.h> | 29 | #include <asm/cpufeature.h> |
30 | #include <asm/processor-flags.h> | ||
29 | 31 | ||
30 | /* Useful macros */ | 32 | /* Useful macros */ |
31 | #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) | 33 | #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) |
@@ -241,6 +243,49 @@ int enable_a20(void); | |||
241 | /* apm.c */ | 243 | /* apm.c */ |
242 | int query_apm_bios(void); | 244 | int query_apm_bios(void); |
243 | 245 | ||
246 | /* bioscall.c */ | ||
247 | struct biosregs { | ||
248 | union { | ||
249 | struct { | ||
250 | u32 edi; | ||
251 | u32 esi; | ||
252 | u32 ebp; | ||
253 | u32 _esp; | ||
254 | u32 ebx; | ||
255 | u32 edx; | ||
256 | u32 ecx; | ||
257 | u32 eax; | ||
258 | u32 _fsgs; | ||
259 | u32 _dses; | ||
260 | u32 eflags; | ||
261 | }; | ||
262 | struct { | ||
263 | u16 di, hdi; | ||
264 | u16 si, hsi; | ||
265 | u16 bp, hbp; | ||
266 | u16 _sp, _hsp; | ||
267 | u16 bx, hbx; | ||
268 | u16 dx, hdx; | ||
269 | u16 cx, hcx; | ||
270 | u16 ax, hax; | ||
271 | u16 gs, fs; | ||
272 | u16 es, ds; | ||
273 | u16 flags, hflags; | ||
274 | }; | ||
275 | struct { | ||
276 | u8 dil, dih, edi2, edi3; | ||
277 | u8 sil, sih, esi2, esi3; | ||
278 | u8 bpl, bph, ebp2, ebp3; | ||
279 | u8 _spl, _sph, _esp2, _esp3; | ||
280 | u8 bl, bh, ebx2, ebx3; | ||
281 | u8 dl, dh, edx2, edx3; | ||
282 | u8 cl, ch, ecx2, ecx3; | ||
283 | u8 al, ah, eax2, eax3; | ||
284 | }; | ||
285 | }; | ||
286 | }; | ||
287 | void intcall(u8 int_no, const struct biosregs *ireg, struct biosregs *oreg); | ||
288 | |||
244 | /* cmdline.c */ | 289 | /* cmdline.c */ |
245 | int cmdline_find_option(const char *option, char *buffer, int bufsize); | 290 | int cmdline_find_option(const char *option, char *buffer, int bufsize); |
246 | int cmdline_find_option_bool(const char *option); | 291 | int cmdline_find_option_bool(const char *option); |
@@ -279,6 +324,9 @@ int sprintf(char *buf, const char *fmt, ...); | |||
279 | int vsprintf(char *buf, const char *fmt, va_list args); | 324 | int vsprintf(char *buf, const char *fmt, va_list args); |
280 | int printf(const char *fmt, ...); | 325 | int printf(const char *fmt, ...); |
281 | 326 | ||
327 | /* regs.c */ | ||
328 | void initregs(struct biosregs *regs); | ||
329 | |||
282 | /* string.c */ | 330 | /* string.c */ |
283 | int strcmp(const char *str1, const char *str2); | 331 | int strcmp(const char *str1, const char *str2); |
284 | size_t strnlen(const char *s, size_t maxlen); | 332 | size_t strnlen(const char *s, size_t maxlen); |
diff --git a/arch/x86/boot/compressed/.gitignore b/arch/x86/boot/compressed/.gitignore index 63eff3b04d01..4a46fab7162e 100644 --- a/arch/x86/boot/compressed/.gitignore +++ b/arch/x86/boot/compressed/.gitignore | |||
@@ -1,3 +1,6 @@ | |||
1 | relocs | 1 | relocs |
2 | vmlinux.bin.all | 2 | vmlinux.bin.all |
3 | vmlinux.relocs | 3 | vmlinux.relocs |
4 | vmlinux.lds | ||
5 | mkpiggy | ||
6 | piggy.S | ||
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index 65551c9f8571..49c8a4c37d7c 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile | |||
@@ -19,7 +19,9 @@ KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__ | |||
19 | LDFLAGS := -m elf_$(UTS_MACHINE) | 19 | LDFLAGS := -m elf_$(UTS_MACHINE) |
20 | LDFLAGS_vmlinux := -T | 20 | LDFLAGS_vmlinux := -T |
21 | 21 | ||
22 | $(obj)/vmlinux: $(src)/vmlinux_$(BITS).lds $(obj)/head_$(BITS).o $(obj)/misc.o $(obj)/piggy.o FORCE | 22 | hostprogs-y := mkpiggy |
23 | |||
24 | $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o $(obj)/piggy.o FORCE | ||
23 | $(call if_changed,ld) | 25 | $(call if_changed,ld) |
24 | @: | 26 | @: |
25 | 27 | ||
@@ -29,7 +31,7 @@ $(obj)/vmlinux.bin: vmlinux FORCE | |||
29 | 31 | ||
30 | 32 | ||
31 | targets += vmlinux.bin.all vmlinux.relocs relocs | 33 | targets += vmlinux.bin.all vmlinux.relocs relocs |
32 | hostprogs-$(CONFIG_X86_32) += relocs | 34 | hostprogs-$(CONFIG_X86_NEED_RELOCS) += relocs |
33 | 35 | ||
34 | quiet_cmd_relocs = RELOCS $@ | 36 | quiet_cmd_relocs = RELOCS $@ |
35 | cmd_relocs = $(obj)/relocs $< > $@;$(obj)/relocs --abs-relocs $< | 37 | cmd_relocs = $(obj)/relocs $< > $@;$(obj)/relocs --abs-relocs $< |
@@ -37,46 +39,22 @@ $(obj)/vmlinux.relocs: vmlinux $(obj)/relocs FORCE | |||
37 | $(call if_changed,relocs) | 39 | $(call if_changed,relocs) |
38 | 40 | ||
39 | vmlinux.bin.all-y := $(obj)/vmlinux.bin | 41 | vmlinux.bin.all-y := $(obj)/vmlinux.bin |
40 | vmlinux.bin.all-$(CONFIG_RELOCATABLE) += $(obj)/vmlinux.relocs | 42 | vmlinux.bin.all-$(CONFIG_X86_NEED_RELOCS) += $(obj)/vmlinux.relocs |
41 | quiet_cmd_relocbin = BUILD $@ | ||
42 | cmd_relocbin = cat $(filter-out FORCE,$^) > $@ | ||
43 | $(obj)/vmlinux.bin.all: $(vmlinux.bin.all-y) FORCE | ||
44 | $(call if_changed,relocbin) | ||
45 | |||
46 | ifeq ($(CONFIG_X86_32),y) | ||
47 | 43 | ||
48 | ifdef CONFIG_RELOCATABLE | 44 | $(obj)/vmlinux.bin.gz: $(vmlinux.bin.all-y) FORCE |
49 | $(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin.all FORCE | ||
50 | $(call if_changed,gzip) | ||
51 | $(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin.all FORCE | ||
52 | $(call if_changed,bzip2) | ||
53 | $(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin.all FORCE | ||
54 | $(call if_changed,lzma) | ||
55 | else | ||
56 | $(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE | ||
57 | $(call if_changed,gzip) | 45 | $(call if_changed,gzip) |
58 | $(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE | 46 | $(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y) FORCE |
59 | $(call if_changed,bzip2) | 47 | $(call if_changed,bzip2) |
60 | $(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE | 48 | $(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y) FORCE |
61 | $(call if_changed,lzma) | 49 | $(call if_changed,lzma) |
62 | endif | ||
63 | LDFLAGS_piggy.o := -r --format binary --oformat elf32-i386 -T | ||
64 | 50 | ||
65 | else | 51 | suffix-$(CONFIG_KERNEL_GZIP) := gz |
52 | suffix-$(CONFIG_KERNEL_BZIP2) := bz2 | ||
53 | suffix-$(CONFIG_KERNEL_LZMA) := lzma | ||
66 | 54 | ||
67 | $(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE | 55 | quiet_cmd_mkpiggy = MKPIGGY $@ |
68 | $(call if_changed,gzip) | 56 | cmd_mkpiggy = $(obj)/mkpiggy $< > $@ || ( rm -f $@ ; false ) |
69 | $(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE | ||
70 | $(call if_changed,bzip2) | ||
71 | $(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE | ||
72 | $(call if_changed,lzma) | ||
73 | |||
74 | LDFLAGS_piggy.o := -r --format binary --oformat elf64-x86-64 -T | ||
75 | endif | ||
76 | 57 | ||
77 | suffix_$(CONFIG_KERNEL_GZIP) = gz | 58 | targets += piggy.S |
78 | suffix_$(CONFIG_KERNEL_BZIP2) = bz2 | 59 | $(obj)/piggy.S: $(obj)/vmlinux.bin.$(suffix-y) $(obj)/mkpiggy FORCE |
79 | suffix_$(CONFIG_KERNEL_LZMA) = lzma | 60 | $(call if_changed,mkpiggy) |
80 | |||
81 | $(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.$(suffix_y) FORCE | ||
82 | $(call if_changed,ld) | ||
diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S index 3a8a866fb2e2..75e4f001e706 100644 --- a/arch/x86/boot/compressed/head_32.S +++ b/arch/x86/boot/compressed/head_32.S | |||
@@ -12,16 +12,16 @@ | |||
12 | * the page directory. [According to comments etc elsewhere on a compressed | 12 | * the page directory. [According to comments etc elsewhere on a compressed |
13 | * kernel it will end up at 0x1000 + 1Mb I hope so as I assume this. - AC] | 13 | * kernel it will end up at 0x1000 + 1Mb I hope so as I assume this. - AC] |
14 | * | 14 | * |
15 | * Page 0 is deliberately kept safe, since System Management Mode code in | 15 | * Page 0 is deliberately kept safe, since System Management Mode code in |
16 | * laptops may need to access the BIOS data stored there. This is also | 16 | * laptops may need to access the BIOS data stored there. This is also |
17 | * useful for future device drivers that either access the BIOS via VM86 | 17 | * useful for future device drivers that either access the BIOS via VM86 |
18 | * mode. | 18 | * mode. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | /* | 21 | /* |
22 | * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 | 22 | * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 |
23 | */ | 23 | */ |
24 | .text | 24 | .text |
25 | 25 | ||
26 | #include <linux/linkage.h> | 26 | #include <linux/linkage.h> |
27 | #include <asm/segment.h> | 27 | #include <asm/segment.h> |
@@ -29,161 +29,151 @@ | |||
29 | #include <asm/boot.h> | 29 | #include <asm/boot.h> |
30 | #include <asm/asm-offsets.h> | 30 | #include <asm/asm-offsets.h> |
31 | 31 | ||
32 | .section ".text.head","ax",@progbits | 32 | .section ".text.head","ax",@progbits |
33 | ENTRY(startup_32) | 33 | ENTRY(startup_32) |
34 | cld | 34 | cld |
35 | /* test KEEP_SEGMENTS flag to see if the bootloader is asking | 35 | /* |
36 | * us to not reload segments */ | 36 | * Test KEEP_SEGMENTS flag to see if the bootloader is asking |
37 | testb $(1<<6), BP_loadflags(%esi) | 37 | * us to not reload segments |
38 | jnz 1f | 38 | */ |
39 | testb $(1<<6), BP_loadflags(%esi) | ||
40 | jnz 1f | ||
39 | 41 | ||
40 | cli | 42 | cli |
41 | movl $(__BOOT_DS),%eax | 43 | movl $__BOOT_DS, %eax |
42 | movl %eax,%ds | 44 | movl %eax, %ds |
43 | movl %eax,%es | 45 | movl %eax, %es |
44 | movl %eax,%fs | 46 | movl %eax, %fs |
45 | movl %eax,%gs | 47 | movl %eax, %gs |
46 | movl %eax,%ss | 48 | movl %eax, %ss |
47 | 1: | 49 | 1: |
48 | 50 | ||
49 | /* Calculate the delta between where we were compiled to run | 51 | /* |
52 | * Calculate the delta between where we were compiled to run | ||
50 | * at and where we were actually loaded at. This can only be done | 53 | * at and where we were actually loaded at. This can only be done |
51 | * with a short local call on x86. Nothing else will tell us what | 54 | * with a short local call on x86. Nothing else will tell us what |
52 | * address we are running at. The reserved chunk of the real-mode | 55 | * address we are running at. The reserved chunk of the real-mode |
53 | * data at 0x1e4 (defined as a scratch field) are used as the stack | 56 | * data at 0x1e4 (defined as a scratch field) are used as the stack |
54 | * for this calculation. Only 4 bytes are needed. | 57 | * for this calculation. Only 4 bytes are needed. |
55 | */ | 58 | */ |
56 | leal (0x1e4+4)(%esi), %esp | 59 | leal (BP_scratch+4)(%esi), %esp |
57 | call 1f | 60 | call 1f |
58 | 1: popl %ebp | 61 | 1: popl %ebp |
59 | subl $1b, %ebp | 62 | subl $1b, %ebp |
60 | 63 | ||
61 | /* %ebp contains the address we are loaded at by the boot loader and %ebx | 64 | /* |
65 | * %ebp contains the address we are loaded at by the boot loader and %ebx | ||
62 | * contains the address where we should move the kernel image temporarily | 66 | * contains the address where we should move the kernel image temporarily |
63 | * for safe in-place decompression. | 67 | * for safe in-place decompression. |
64 | */ | 68 | */ |
65 | 69 | ||
66 | #ifdef CONFIG_RELOCATABLE | 70 | #ifdef CONFIG_RELOCATABLE |
67 | movl %ebp, %ebx | 71 | movl %ebp, %ebx |
68 | addl $(CONFIG_PHYSICAL_ALIGN - 1), %ebx | 72 | movl BP_kernel_alignment(%esi), %eax |
69 | andl $(~(CONFIG_PHYSICAL_ALIGN - 1)), %ebx | 73 | decl %eax |
74 | addl %eax, %ebx | ||
75 | notl %eax | ||
76 | andl %eax, %ebx | ||
70 | #else | 77 | #else |
71 | movl $LOAD_PHYSICAL_ADDR, %ebx | 78 | movl $LOAD_PHYSICAL_ADDR, %ebx |
72 | #endif | 79 | #endif |
73 | 80 | ||
74 | /* Replace the compressed data size with the uncompressed size */ | 81 | /* Target address to relocate to for decompression */ |
75 | subl input_len(%ebp), %ebx | 82 | addl $z_extract_offset, %ebx |
76 | movl output_len(%ebp), %eax | 83 | |
77 | addl %eax, %ebx | 84 | /* Set up the stack */ |
78 | /* Add 8 bytes for every 32K input block */ | 85 | leal boot_stack_end(%ebx), %esp |
79 | shrl $12, %eax | 86 | |
80 | addl %eax, %ebx | 87 | /* Zero EFLAGS */ |
81 | /* Add 32K + 18 bytes of extra slack */ | 88 | pushl $0 |
82 | addl $(32768 + 18), %ebx | 89 | popfl |
83 | /* Align on a 4K boundary */ | 90 | |
84 | addl $4095, %ebx | 91 | /* |
85 | andl $~4095, %ebx | 92 | * Copy the compressed kernel to the end of our buffer |
86 | |||
87 | /* Copy the compressed kernel to the end of our buffer | ||
88 | * where decompression in place becomes safe. | 93 | * where decompression in place becomes safe. |
89 | */ | 94 | */ |
90 | pushl %esi | 95 | pushl %esi |
91 | leal _end(%ebp), %esi | 96 | leal (_bss-4)(%ebp), %esi |
92 | leal _end(%ebx), %edi | 97 | leal (_bss-4)(%ebx), %edi |
93 | movl $(_end - startup_32), %ecx | 98 | movl $(_bss - startup_32), %ecx |
99 | shrl $2, %ecx | ||
94 | std | 100 | std |
95 | rep | 101 | rep movsl |
96 | movsb | ||
97 | cld | 102 | cld |
98 | popl %esi | 103 | popl %esi |
99 | |||
100 | /* Compute the kernel start address. | ||
101 | */ | ||
102 | #ifdef CONFIG_RELOCATABLE | ||
103 | addl $(CONFIG_PHYSICAL_ALIGN - 1), %ebp | ||
104 | andl $(~(CONFIG_PHYSICAL_ALIGN - 1)), %ebp | ||
105 | #else | ||
106 | movl $LOAD_PHYSICAL_ADDR, %ebp | ||
107 | #endif | ||
108 | 104 | ||
109 | /* | 105 | /* |
110 | * Jump to the relocated address. | 106 | * Jump to the relocated address. |
111 | */ | 107 | */ |
112 | leal relocated(%ebx), %eax | 108 | leal relocated(%ebx), %eax |
113 | jmp *%eax | 109 | jmp *%eax |
114 | ENDPROC(startup_32) | 110 | ENDPROC(startup_32) |
115 | 111 | ||
116 | .section ".text" | 112 | .text |
117 | relocated: | 113 | relocated: |
118 | 114 | ||
119 | /* | 115 | /* |
120 | * Clear BSS | 116 | * Clear BSS (stack is currently empty) |
121 | */ | ||
122 | xorl %eax,%eax | ||
123 | leal _edata(%ebx),%edi | ||
124 | leal _end(%ebx), %ecx | ||
125 | subl %edi,%ecx | ||
126 | cld | ||
127 | rep | ||
128 | stosb | ||
129 | |||
130 | /* | ||
131 | * Setup the stack for the decompressor | ||
132 | */ | 117 | */ |
133 | leal boot_stack_end(%ebx), %esp | 118 | xorl %eax, %eax |
119 | leal _bss(%ebx), %edi | ||
120 | leal _ebss(%ebx), %ecx | ||
121 | subl %edi, %ecx | ||
122 | shrl $2, %ecx | ||
123 | rep stosl | ||
134 | 124 | ||
135 | /* | 125 | /* |
136 | * Do the decompression, and jump to the new kernel.. | 126 | * Do the decompression, and jump to the new kernel.. |
137 | */ | 127 | */ |
138 | movl output_len(%ebx), %eax | 128 | leal z_extract_offset_negative(%ebx), %ebp |
139 | pushl %eax | 129 | /* push arguments for decompress_kernel: */ |
140 | # push arguments for decompress_kernel: | 130 | pushl %ebp /* output address */ |
141 | pushl %ebp # output address | 131 | pushl $z_input_len /* input_len */ |
142 | movl input_len(%ebx), %eax | 132 | leal input_data(%ebx), %eax |
143 | pushl %eax # input_len | 133 | pushl %eax /* input_data */ |
144 | leal input_data(%ebx), %eax | 134 | leal boot_heap(%ebx), %eax |
145 | pushl %eax # input_data | 135 | pushl %eax /* heap area */ |
146 | leal boot_heap(%ebx), %eax | 136 | pushl %esi /* real mode pointer */ |
147 | pushl %eax # heap area | 137 | call decompress_kernel |
148 | pushl %esi # real mode pointer | 138 | addl $20, %esp |
149 | call decompress_kernel | ||
150 | addl $20, %esp | ||
151 | popl %ecx | ||
152 | 139 | ||
153 | #if CONFIG_RELOCATABLE | 140 | #if CONFIG_RELOCATABLE |
154 | /* Find the address of the relocations. | 141 | /* |
142 | * Find the address of the relocations. | ||
155 | */ | 143 | */ |
156 | movl %ebp, %edi | 144 | leal z_output_len(%ebp), %edi |
157 | addl %ecx, %edi | ||
158 | 145 | ||
159 | /* Calculate the delta between where vmlinux was compiled to run | 146 | /* |
147 | * Calculate the delta between where vmlinux was compiled to run | ||
160 | * and where it was actually loaded. | 148 | * and where it was actually loaded. |
161 | */ | 149 | */ |
162 | movl %ebp, %ebx | 150 | movl %ebp, %ebx |
163 | subl $LOAD_PHYSICAL_ADDR, %ebx | 151 | subl $LOAD_PHYSICAL_ADDR, %ebx |
164 | jz 2f /* Nothing to be done if loaded at compiled addr. */ | 152 | jz 2f /* Nothing to be done if loaded at compiled addr. */ |
165 | /* | 153 | /* |
166 | * Process relocations. | 154 | * Process relocations. |
167 | */ | 155 | */ |
168 | 156 | ||
169 | 1: subl $4, %edi | 157 | 1: subl $4, %edi |
170 | movl 0(%edi), %ecx | 158 | movl (%edi), %ecx |
171 | testl %ecx, %ecx | 159 | testl %ecx, %ecx |
172 | jz 2f | 160 | jz 2f |
173 | addl %ebx, -__PAGE_OFFSET(%ebx, %ecx) | 161 | addl %ebx, -__PAGE_OFFSET(%ebx, %ecx) |
174 | jmp 1b | 162 | jmp 1b |
175 | 2: | 163 | 2: |
176 | #endif | 164 | #endif |
177 | 165 | ||
178 | /* | 166 | /* |
179 | * Jump to the decompressed kernel. | 167 | * Jump to the decompressed kernel. |
180 | */ | 168 | */ |
181 | xorl %ebx,%ebx | 169 | xorl %ebx, %ebx |
182 | jmp *%ebp | 170 | jmp *%ebp |
183 | 171 | ||
184 | .bss | 172 | /* |
185 | /* Stack and heap for uncompression */ | 173 | * Stack and heap for uncompression |
186 | .balign 4 | 174 | */ |
175 | .bss | ||
176 | .balign 4 | ||
187 | boot_heap: | 177 | boot_heap: |
188 | .fill BOOT_HEAP_SIZE, 1, 0 | 178 | .fill BOOT_HEAP_SIZE, 1, 0 |
189 | boot_stack: | 179 | boot_stack: |
diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S index ed4a82948002..f62c284db9eb 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S | |||
@@ -21,8 +21,8 @@ | |||
21 | /* | 21 | /* |
22 | * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 | 22 | * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 |
23 | */ | 23 | */ |
24 | .code32 | 24 | .code32 |
25 | .text | 25 | .text |
26 | 26 | ||
27 | #include <linux/linkage.h> | 27 | #include <linux/linkage.h> |
28 | #include <asm/segment.h> | 28 | #include <asm/segment.h> |
@@ -33,12 +33,14 @@ | |||
33 | #include <asm/processor-flags.h> | 33 | #include <asm/processor-flags.h> |
34 | #include <asm/asm-offsets.h> | 34 | #include <asm/asm-offsets.h> |
35 | 35 | ||
36 | .section ".text.head" | 36 | .section ".text.head" |
37 | .code32 | 37 | .code32 |
38 | ENTRY(startup_32) | 38 | ENTRY(startup_32) |
39 | cld | 39 | cld |
40 | /* test KEEP_SEGMENTS flag to see if the bootloader is asking | 40 | /* |
41 | * us to not reload segments */ | 41 | * Test KEEP_SEGMENTS flag to see if the bootloader is asking |
42 | * us to not reload segments | ||
43 | */ | ||
42 | testb $(1<<6), BP_loadflags(%esi) | 44 | testb $(1<<6), BP_loadflags(%esi) |
43 | jnz 1f | 45 | jnz 1f |
44 | 46 | ||
@@ -49,14 +51,15 @@ ENTRY(startup_32) | |||
49 | movl %eax, %ss | 51 | movl %eax, %ss |
50 | 1: | 52 | 1: |
51 | 53 | ||
52 | /* Calculate the delta between where we were compiled to run | 54 | /* |
55 | * Calculate the delta between where we were compiled to run | ||
53 | * at and where we were actually loaded at. This can only be done | 56 | * at and where we were actually loaded at. This can only be done |
54 | * with a short local call on x86. Nothing else will tell us what | 57 | * with a short local call on x86. Nothing else will tell us what |
55 | * address we are running at. The reserved chunk of the real-mode | 58 | * address we are running at. The reserved chunk of the real-mode |
56 | * data at 0x1e4 (defined as a scratch field) are used as the stack | 59 | * data at 0x1e4 (defined as a scratch field) are used as the stack |
57 | * for this calculation. Only 4 bytes are needed. | 60 | * for this calculation. Only 4 bytes are needed. |
58 | */ | 61 | */ |
59 | leal (0x1e4+4)(%esi), %esp | 62 | leal (BP_scratch+4)(%esi), %esp |
60 | call 1f | 63 | call 1f |
61 | 1: popl %ebp | 64 | 1: popl %ebp |
62 | subl $1b, %ebp | 65 | subl $1b, %ebp |
@@ -70,32 +73,28 @@ ENTRY(startup_32) | |||
70 | testl %eax, %eax | 73 | testl %eax, %eax |
71 | jnz no_longmode | 74 | jnz no_longmode |
72 | 75 | ||
73 | /* Compute the delta between where we were compiled to run at | 76 | /* |
77 | * Compute the delta between where we were compiled to run at | ||
74 | * and where the code will actually run at. | 78 | * and where the code will actually run at. |
75 | */ | 79 | * |
76 | /* %ebp contains the address we are loaded at by the boot loader and %ebx | 80 | * %ebp contains the address we are loaded at by the boot loader and %ebx |
77 | * contains the address where we should move the kernel image temporarily | 81 | * contains the address where we should move the kernel image temporarily |
78 | * for safe in-place decompression. | 82 | * for safe in-place decompression. |
79 | */ | 83 | */ |
80 | 84 | ||
81 | #ifdef CONFIG_RELOCATABLE | 85 | #ifdef CONFIG_RELOCATABLE |
82 | movl %ebp, %ebx | 86 | movl %ebp, %ebx |
83 | addl $(PMD_PAGE_SIZE -1), %ebx | 87 | movl BP_kernel_alignment(%esi), %eax |
84 | andl $PMD_PAGE_MASK, %ebx | 88 | decl %eax |
89 | addl %eax, %ebx | ||
90 | notl %eax | ||
91 | andl %eax, %ebx | ||
85 | #else | 92 | #else |
86 | movl $CONFIG_PHYSICAL_START, %ebx | 93 | movl $LOAD_PHYSICAL_ADDR, %ebx |
87 | #endif | 94 | #endif |
88 | 95 | ||
89 | /* Replace the compressed data size with the uncompressed size */ | 96 | /* Target address to relocate to for decompression */ |
90 | subl input_len(%ebp), %ebx | 97 | addl $z_extract_offset, %ebx |
91 | movl output_len(%ebp), %eax | ||
92 | addl %eax, %ebx | ||
93 | /* Add 8 bytes for every 32K input block */ | ||
94 | shrl $12, %eax | ||
95 | addl %eax, %ebx | ||
96 | /* Add 32K + 18 bytes of extra slack and align on a 4K boundary */ | ||
97 | addl $(32768 + 18 + 4095), %ebx | ||
98 | andl $~4095, %ebx | ||
99 | 98 | ||
100 | /* | 99 | /* |
101 | * Prepare for entering 64 bit mode | 100 | * Prepare for entering 64 bit mode |
@@ -114,7 +113,7 @@ ENTRY(startup_32) | |||
114 | /* | 113 | /* |
115 | * Build early 4G boot pagetable | 114 | * Build early 4G boot pagetable |
116 | */ | 115 | */ |
117 | /* Initialize Page tables to 0*/ | 116 | /* Initialize Page tables to 0 */ |
118 | leal pgtable(%ebx), %edi | 117 | leal pgtable(%ebx), %edi |
119 | xorl %eax, %eax | 118 | xorl %eax, %eax |
120 | movl $((4096*6)/4), %ecx | 119 | movl $((4096*6)/4), %ecx |
@@ -155,7 +154,8 @@ ENTRY(startup_32) | |||
155 | btsl $_EFER_LME, %eax | 154 | btsl $_EFER_LME, %eax |
156 | wrmsr | 155 | wrmsr |
157 | 156 | ||
158 | /* Setup for the jump to 64bit mode | 157 | /* |
158 | * Setup for the jump to 64bit mode | ||
159 | * | 159 | * |
160 | * When the jump is performend we will be in long mode but | 160 | * When the jump is performend we will be in long mode but |
161 | * in 32bit compatibility mode with EFER.LME = 1, CS.L = 0, CS.D = 1 | 161 | * in 32bit compatibility mode with EFER.LME = 1, CS.L = 0, CS.D = 1 |
@@ -184,7 +184,8 @@ no_longmode: | |||
184 | 184 | ||
185 | #include "../../kernel/verify_cpu_64.S" | 185 | #include "../../kernel/verify_cpu_64.S" |
186 | 186 | ||
187 | /* Be careful here startup_64 needs to be at a predictable | 187 | /* |
188 | * Be careful here startup_64 needs to be at a predictable | ||
188 | * address so I can export it in an ELF header. Bootloaders | 189 | * address so I can export it in an ELF header. Bootloaders |
189 | * should look at the ELF header to find this address, as | 190 | * should look at the ELF header to find this address, as |
190 | * it may change in the future. | 191 | * it may change in the future. |
@@ -192,7 +193,8 @@ no_longmode: | |||
192 | .code64 | 193 | .code64 |
193 | .org 0x200 | 194 | .org 0x200 |
194 | ENTRY(startup_64) | 195 | ENTRY(startup_64) |
195 | /* We come here either from startup_32 or directly from a | 196 | /* |
197 | * We come here either from startup_32 or directly from a | ||
196 | * 64bit bootloader. If we come here from a bootloader we depend on | 198 | * 64bit bootloader. If we come here from a bootloader we depend on |
197 | * an identity mapped page table being provied that maps our | 199 | * an identity mapped page table being provied that maps our |
198 | * entire text+data+bss and hopefully all of memory. | 200 | * entire text+data+bss and hopefully all of memory. |
@@ -209,50 +211,54 @@ ENTRY(startup_64) | |||
209 | movl $0x20, %eax | 211 | movl $0x20, %eax |
210 | ltr %ax | 212 | ltr %ax |
211 | 213 | ||
212 | /* Compute the decompressed kernel start address. It is where | 214 | /* |
215 | * Compute the decompressed kernel start address. It is where | ||
213 | * we were loaded at aligned to a 2M boundary. %rbp contains the | 216 | * we were loaded at aligned to a 2M boundary. %rbp contains the |
214 | * decompressed kernel start address. | 217 | * decompressed kernel start address. |
215 | * | 218 | * |
216 | * If it is a relocatable kernel then decompress and run the kernel | 219 | * If it is a relocatable kernel then decompress and run the kernel |
217 | * from load address aligned to 2MB addr, otherwise decompress and | 220 | * from load address aligned to 2MB addr, otherwise decompress and |
218 | * run the kernel from CONFIG_PHYSICAL_START | 221 | * run the kernel from LOAD_PHYSICAL_ADDR |
222 | * | ||
223 | * We cannot rely on the calculation done in 32-bit mode, since we | ||
224 | * may have been invoked via the 64-bit entry point. | ||
219 | */ | 225 | */ |
220 | 226 | ||
221 | /* Start with the delta to where the kernel will run at. */ | 227 | /* Start with the delta to where the kernel will run at. */ |
222 | #ifdef CONFIG_RELOCATABLE | 228 | #ifdef CONFIG_RELOCATABLE |
223 | leaq startup_32(%rip) /* - $startup_32 */, %rbp | 229 | leaq startup_32(%rip) /* - $startup_32 */, %rbp |
224 | addq $(PMD_PAGE_SIZE - 1), %rbp | 230 | movl BP_kernel_alignment(%rsi), %eax |
225 | andq $PMD_PAGE_MASK, %rbp | 231 | decl %eax |
226 | movq %rbp, %rbx | 232 | addq %rax, %rbp |
233 | notq %rax | ||
234 | andq %rax, %rbp | ||
227 | #else | 235 | #else |
228 | movq $CONFIG_PHYSICAL_START, %rbp | 236 | movq $LOAD_PHYSICAL_ADDR, %rbp |
229 | movq %rbp, %rbx | ||
230 | #endif | 237 | #endif |
231 | 238 | ||
232 | /* Replace the compressed data size with the uncompressed size */ | 239 | /* Target address to relocate to for decompression */ |
233 | movl input_len(%rip), %eax | 240 | leaq z_extract_offset(%rbp), %rbx |
234 | subq %rax, %rbx | 241 | |
235 | movl output_len(%rip), %eax | 242 | /* Set up the stack */ |
236 | addq %rax, %rbx | 243 | leaq boot_stack_end(%rbx), %rsp |
237 | /* Add 8 bytes for every 32K input block */ | 244 | |
238 | shrq $12, %rax | 245 | /* Zero EFLAGS */ |
239 | addq %rax, %rbx | 246 | pushq $0 |
240 | /* Add 32K + 18 bytes of extra slack and align on a 4K boundary */ | 247 | popfq |
241 | addq $(32768 + 18 + 4095), %rbx | 248 | |
242 | andq $~4095, %rbx | 249 | /* |
243 | 250 | * Copy the compressed kernel to the end of our buffer | |
244 | /* Copy the compressed kernel to the end of our buffer | ||
245 | * where decompression in place becomes safe. | 251 | * where decompression in place becomes safe. |
246 | */ | 252 | */ |
247 | leaq _end_before_pgt(%rip), %r8 | 253 | pushq %rsi |
248 | leaq _end_before_pgt(%rbx), %r9 | 254 | leaq (_bss-8)(%rip), %rsi |
249 | movq $_end_before_pgt /* - $startup_32 */, %rcx | 255 | leaq (_bss-8)(%rbx), %rdi |
250 | 1: subq $8, %r8 | 256 | movq $_bss /* - $startup_32 */, %rcx |
251 | subq $8, %r9 | 257 | shrq $3, %rcx |
252 | movq 0(%r8), %rax | 258 | std |
253 | movq %rax, 0(%r9) | 259 | rep movsq |
254 | subq $8, %rcx | 260 | cld |
255 | jnz 1b | 261 | popq %rsi |
256 | 262 | ||
257 | /* | 263 | /* |
258 | * Jump to the relocated address. | 264 | * Jump to the relocated address. |
@@ -260,37 +266,28 @@ ENTRY(startup_64) | |||
260 | leaq relocated(%rbx), %rax | 266 | leaq relocated(%rbx), %rax |
261 | jmp *%rax | 267 | jmp *%rax |
262 | 268 | ||
263 | .section ".text" | 269 | .text |
264 | relocated: | 270 | relocated: |
265 | 271 | ||
266 | /* | 272 | /* |
267 | * Clear BSS | 273 | * Clear BSS (stack is currently empty) |
268 | */ | 274 | */ |
269 | xorq %rax, %rax | 275 | xorl %eax, %eax |
270 | leaq _edata(%rbx), %rdi | 276 | leaq _bss(%rip), %rdi |
271 | leaq _end_before_pgt(%rbx), %rcx | 277 | leaq _ebss(%rip), %rcx |
272 | subq %rdi, %rcx | 278 | subq %rdi, %rcx |
273 | cld | 279 | shrq $3, %rcx |
274 | rep | 280 | rep stosq |
275 | stosb | ||
276 | |||
277 | /* Setup the stack */ | ||
278 | leaq boot_stack_end(%rip), %rsp | ||
279 | |||
280 | /* zero EFLAGS after setting rsp */ | ||
281 | pushq $0 | ||
282 | popfq | ||
283 | 281 | ||
284 | /* | 282 | /* |
285 | * Do the decompression, and jump to the new kernel.. | 283 | * Do the decompression, and jump to the new kernel.. |
286 | */ | 284 | */ |
287 | pushq %rsi # Save the real mode argument | 285 | pushq %rsi /* Save the real mode argument */ |
288 | movq %rsi, %rdi # real mode address | 286 | movq %rsi, %rdi /* real mode address */ |
289 | leaq boot_heap(%rip), %rsi # malloc area for uncompression | 287 | leaq boot_heap(%rip), %rsi /* malloc area for uncompression */ |
290 | leaq input_data(%rip), %rdx # input_data | 288 | leaq input_data(%rip), %rdx /* input_data */ |
291 | movl input_len(%rip), %eax | 289 | movl $z_input_len, %ecx /* input_len */ |
292 | movq %rax, %rcx # input_len | 290 | movq %rbp, %r8 /* output target address */ |
293 | movq %rbp, %r8 # output | ||
294 | call decompress_kernel | 291 | call decompress_kernel |
295 | popq %rsi | 292 | popq %rsi |
296 | 293 | ||
@@ -311,11 +308,21 @@ gdt: | |||
311 | .quad 0x0000000000000000 /* TS continued */ | 308 | .quad 0x0000000000000000 /* TS continued */ |
312 | gdt_end: | 309 | gdt_end: |
313 | 310 | ||
314 | .bss | 311 | /* |
315 | /* Stack and heap for uncompression */ | 312 | * Stack and heap for uncompression |
316 | .balign 4 | 313 | */ |
314 | .bss | ||
315 | .balign 4 | ||
317 | boot_heap: | 316 | boot_heap: |
318 | .fill BOOT_HEAP_SIZE, 1, 0 | 317 | .fill BOOT_HEAP_SIZE, 1, 0 |
319 | boot_stack: | 318 | boot_stack: |
320 | .fill BOOT_STACK_SIZE, 1, 0 | 319 | .fill BOOT_STACK_SIZE, 1, 0 |
321 | boot_stack_end: | 320 | boot_stack_end: |
321 | |||
322 | /* | ||
323 | * Space for page tables (not in .bss so not zeroed) | ||
324 | */ | ||
325 | .section ".pgtable","a",@nobits | ||
326 | .balign 4096 | ||
327 | pgtable: | ||
328 | .fill 6*4096, 1, 0 | ||
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c index e45be73684ff..842b2a36174a 100644 --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c | |||
@@ -325,21 +325,19 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap, | |||
325 | free_mem_ptr = heap; /* Heap */ | 325 | free_mem_ptr = heap; /* Heap */ |
326 | free_mem_end_ptr = heap + BOOT_HEAP_SIZE; | 326 | free_mem_end_ptr = heap + BOOT_HEAP_SIZE; |
327 | 327 | ||
328 | if ((unsigned long)output & (MIN_KERNEL_ALIGN - 1)) | ||
329 | error("Destination address inappropriately aligned"); | ||
328 | #ifdef CONFIG_X86_64 | 330 | #ifdef CONFIG_X86_64 |
329 | if ((unsigned long)output & (__KERNEL_ALIGN - 1)) | 331 | if (heap > 0x3fffffffffffUL) |
330 | error("Destination address not 2M aligned"); | ||
331 | if ((unsigned long)output >= 0xffffffffffUL) | ||
332 | error("Destination address too large"); | 332 | error("Destination address too large"); |
333 | #else | 333 | #else |
334 | if ((u32)output & (CONFIG_PHYSICAL_ALIGN - 1)) | ||
335 | error("Destination address not CONFIG_PHYSICAL_ALIGN aligned"); | ||
336 | if (heap > ((-__PAGE_OFFSET-(512<<20)-1) & 0x7fffffff)) | 334 | if (heap > ((-__PAGE_OFFSET-(512<<20)-1) & 0x7fffffff)) |
337 | error("Destination address too large"); | 335 | error("Destination address too large"); |
336 | #endif | ||
338 | #ifndef CONFIG_RELOCATABLE | 337 | #ifndef CONFIG_RELOCATABLE |
339 | if ((u32)output != LOAD_PHYSICAL_ADDR) | 338 | if ((unsigned long)output != LOAD_PHYSICAL_ADDR) |
340 | error("Wrong destination address"); | 339 | error("Wrong destination address"); |
341 | #endif | 340 | #endif |
342 | #endif | ||
343 | 341 | ||
344 | if (!quiet) | 342 | if (!quiet) |
345 | putstr("\nDecompressing Linux... "); | 343 | putstr("\nDecompressing Linux... "); |
diff --git a/arch/x86/boot/compressed/mkpiggy.c b/arch/x86/boot/compressed/mkpiggy.c new file mode 100644 index 000000000000..bcbd36c41432 --- /dev/null +++ b/arch/x86/boot/compressed/mkpiggy.c | |||
@@ -0,0 +1,97 @@ | |||
1 | /* ----------------------------------------------------------------------- * | ||
2 | * | ||
3 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License version | ||
7 | * 2 as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
17 | * 02110-1301, USA. | ||
18 | * | ||
19 | * H. Peter Anvin <hpa@linux.intel.com> | ||
20 | * | ||
21 | * ----------------------------------------------------------------------- */ | ||
22 | |||
23 | /* | ||
24 | * Compute the desired load offset from a compressed program; outputs | ||
25 | * a small assembly wrapper with the appropriate symbols defined. | ||
26 | */ | ||
27 | |||
28 | #include <stdlib.h> | ||
29 | #include <stdio.h> | ||
30 | #include <string.h> | ||
31 | #include <inttypes.h> | ||
32 | |||
33 | static uint32_t getle32(const void *p) | ||
34 | { | ||
35 | const uint8_t *cp = p; | ||
36 | |||
37 | return (uint32_t)cp[0] + ((uint32_t)cp[1] << 8) + | ||
38 | ((uint32_t)cp[2] << 16) + ((uint32_t)cp[3] << 24); | ||
39 | } | ||
40 | |||
41 | int main(int argc, char *argv[]) | ||
42 | { | ||
43 | uint32_t olen; | ||
44 | long ilen; | ||
45 | unsigned long offs; | ||
46 | FILE *f; | ||
47 | |||
48 | if (argc < 2) { | ||
49 | fprintf(stderr, "Usage: %s compressed_file\n", argv[0]); | ||
50 | return 1; | ||
51 | } | ||
52 | |||
53 | /* Get the information for the compressed kernel image first */ | ||
54 | |||
55 | f = fopen(argv[1], "r"); | ||
56 | if (!f) { | ||
57 | perror(argv[1]); | ||
58 | return 1; | ||
59 | } | ||
60 | |||
61 | |||
62 | if (fseek(f, -4L, SEEK_END)) { | ||
63 | perror(argv[1]); | ||
64 | } | ||
65 | fread(&olen, sizeof olen, 1, f); | ||
66 | ilen = ftell(f); | ||
67 | olen = getle32(&olen); | ||
68 | fclose(f); | ||
69 | |||
70 | /* | ||
71 | * Now we have the input (compressed) and output (uncompressed) | ||
72 | * sizes, compute the necessary decompression offset... | ||
73 | */ | ||
74 | |||
75 | offs = (olen > ilen) ? olen - ilen : 0; | ||
76 | offs += olen >> 12; /* Add 8 bytes for each 32K block */ | ||
77 | offs += 32*1024 + 18; /* Add 32K + 18 bytes slack */ | ||
78 | offs = (offs+4095) & ~4095; /* Round to a 4K boundary */ | ||
79 | |||
80 | printf(".section \".rodata.compressed\",\"a\",@progbits\n"); | ||
81 | printf(".globl z_input_len\n"); | ||
82 | printf("z_input_len = %lu\n", ilen); | ||
83 | printf(".globl z_output_len\n"); | ||
84 | printf("z_output_len = %lu\n", (unsigned long)olen); | ||
85 | printf(".globl z_extract_offset\n"); | ||
86 | printf("z_extract_offset = 0x%lx\n", offs); | ||
87 | /* z_extract_offset_negative allows simplification of head_32.S */ | ||
88 | printf(".globl z_extract_offset_negative\n"); | ||
89 | printf("z_extract_offset_negative = -0x%lx\n", offs); | ||
90 | |||
91 | printf(".globl input_data, input_data_end\n"); | ||
92 | printf("input_data:\n"); | ||
93 | printf(".incbin \"%s\"\n", argv[1]); | ||
94 | printf("input_data_end:\n"); | ||
95 | |||
96 | return 0; | ||
97 | } | ||
diff --git a/arch/x86/boot/compressed/vmlinux_64.lds b/arch/x86/boot/compressed/vmlinux.lds.S index bef1ac891bce..cc353e1b3ffd 100644 --- a/arch/x86/boot/compressed/vmlinux_64.lds +++ b/arch/x86/boot/compressed/vmlinux.lds.S | |||
@@ -1,6 +1,17 @@ | |||
1 | OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") | 1 | OUTPUT_FORMAT(CONFIG_OUTPUT_FORMAT, CONFIG_OUTPUT_FORMAT, CONFIG_OUTPUT_FORMAT) |
2 | |||
3 | #undef i386 | ||
4 | |||
5 | #include <asm/page_types.h> | ||
6 | |||
7 | #ifdef CONFIG_X86_64 | ||
2 | OUTPUT_ARCH(i386:x86-64) | 8 | OUTPUT_ARCH(i386:x86-64) |
3 | ENTRY(startup_64) | 9 | ENTRY(startup_64) |
10 | #else | ||
11 | OUTPUT_ARCH(i386) | ||
12 | ENTRY(startup_32) | ||
13 | #endif | ||
14 | |||
4 | SECTIONS | 15 | SECTIONS |
5 | { | 16 | { |
6 | /* Be careful parts of head_64.S assume startup_32 is at | 17 | /* Be careful parts of head_64.S assume startup_32 is at |
@@ -33,16 +44,22 @@ SECTIONS | |||
33 | *(.data.*) | 44 | *(.data.*) |
34 | _edata = . ; | 45 | _edata = . ; |
35 | } | 46 | } |
47 | . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); | ||
36 | .bss : { | 48 | .bss : { |
37 | _bss = . ; | 49 | _bss = . ; |
38 | *(.bss) | 50 | *(.bss) |
39 | *(.bss.*) | 51 | *(.bss.*) |
40 | *(COMMON) | 52 | *(COMMON) |
41 | . = ALIGN(8); | 53 | . = ALIGN(8); /* For convenience during zeroing */ |
42 | _end_before_pgt = . ; | ||
43 | . = ALIGN(4096); | ||
44 | pgtable = . ; | ||
45 | . = . + 4096 * 6; | ||
46 | _ebss = .; | 54 | _ebss = .; |
47 | } | 55 | } |
56 | #ifdef CONFIG_X86_64 | ||
57 | . = ALIGN(PAGE_SIZE); | ||
58 | .pgtable : { | ||
59 | _pgtable = . ; | ||
60 | *(.pgtable) | ||
61 | _epgtable = . ; | ||
62 | } | ||
63 | #endif | ||
64 | _end = .; | ||
48 | } | 65 | } |
diff --git a/arch/x86/boot/compressed/vmlinux.scr b/arch/x86/boot/compressed/vmlinux.scr deleted file mode 100644 index f02382ae5c48..000000000000 --- a/arch/x86/boot/compressed/vmlinux.scr +++ /dev/null | |||
@@ -1,10 +0,0 @@ | |||
1 | SECTIONS | ||
2 | { | ||
3 | .rodata.compressed : { | ||
4 | input_len = .; | ||
5 | LONG(input_data_end - input_data) input_data = .; | ||
6 | *(.data) | ||
7 | output_len = . - 4; | ||
8 | input_data_end = .; | ||
9 | } | ||
10 | } | ||
diff --git a/arch/x86/boot/compressed/vmlinux_32.lds b/arch/x86/boot/compressed/vmlinux_32.lds deleted file mode 100644 index bb3c48379c40..000000000000 --- a/arch/x86/boot/compressed/vmlinux_32.lds +++ /dev/null | |||
@@ -1,43 +0,0 @@ | |||
1 | OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") | ||
2 | OUTPUT_ARCH(i386) | ||
3 | ENTRY(startup_32) | ||
4 | SECTIONS | ||
5 | { | ||
6 | /* Be careful parts of head_32.S assume startup_32 is at | ||
7 | * address 0. | ||
8 | */ | ||
9 | . = 0; | ||
10 | .text.head : { | ||
11 | _head = . ; | ||
12 | *(.text.head) | ||
13 | _ehead = . ; | ||
14 | } | ||
15 | .rodata.compressed : { | ||
16 | *(.rodata.compressed) | ||
17 | } | ||
18 | .text : { | ||
19 | _text = .; /* Text */ | ||
20 | *(.text) | ||
21 | *(.text.*) | ||
22 | _etext = . ; | ||
23 | } | ||
24 | .rodata : { | ||
25 | _rodata = . ; | ||
26 | *(.rodata) /* read-only data */ | ||
27 | *(.rodata.*) | ||
28 | _erodata = . ; | ||
29 | } | ||
30 | .data : { | ||
31 | _data = . ; | ||
32 | *(.data) | ||
33 | *(.data.*) | ||
34 | _edata = . ; | ||
35 | } | ||
36 | .bss : { | ||
37 | _bss = . ; | ||
38 | *(.bss) | ||
39 | *(.bss.*) | ||
40 | *(COMMON) | ||
41 | _end = . ; | ||
42 | } | ||
43 | } | ||
diff --git a/arch/x86/boot/edd.c b/arch/x86/boot/edd.c index 1aae8f3e5ca1..c501a5b466f8 100644 --- a/arch/x86/boot/edd.c +++ b/arch/x86/boot/edd.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * | 2 | * |
3 | * Copyright (C) 1991, 1992 Linus Torvalds | 3 | * Copyright (C) 1991, 1992 Linus Torvalds |
4 | * Copyright 2007 rPath, Inc. - All Rights Reserved | 4 | * Copyright 2007 rPath, Inc. - All Rights Reserved |
5 | * Copyright 2009 Intel Corporation; author H. Peter Anvin | ||
5 | * | 6 | * |
6 | * This file is part of the Linux kernel, and is made available under | 7 | * 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 | * the terms of the GNU General Public License version 2. |
@@ -22,17 +23,17 @@ | |||
22 | */ | 23 | */ |
23 | static int read_mbr(u8 devno, void *buf) | 24 | static int read_mbr(u8 devno, void *buf) |
24 | { | 25 | { |
25 | u16 ax, bx, cx, dx; | 26 | struct biosregs ireg, oreg; |
26 | 27 | ||
27 | ax = 0x0201; /* Legacy Read, one sector */ | 28 | initregs(&ireg); |
28 | cx = 0x0001; /* Sector 0-0-1 */ | 29 | ireg.ax = 0x0201; /* Legacy Read, one sector */ |
29 | dx = devno; | 30 | ireg.cx = 0x0001; /* Sector 0-0-1 */ |
30 | bx = (size_t)buf; | 31 | ireg.dl = devno; |
31 | asm volatile("pushfl; stc; int $0x13; setc %%al; popfl" | 32 | ireg.bx = (size_t)buf; |
32 | : "+a" (ax), "+c" (cx), "+d" (dx), "+b" (bx) | ||
33 | : : "esi", "edi", "memory"); | ||
34 | 33 | ||
35 | return -(u8)ax; /* 0 or -1 */ | 34 | intcall(0x13, &ireg, &oreg); |
35 | |||
36 | return -(oreg.eflags & X86_EFLAGS_CF); /* 0 or -1 */ | ||
36 | } | 37 | } |
37 | 38 | ||
38 | static u32 read_mbr_sig(u8 devno, struct edd_info *ei, u32 *mbrsig) | 39 | static u32 read_mbr_sig(u8 devno, struct edd_info *ei, u32 *mbrsig) |
@@ -72,56 +73,46 @@ static u32 read_mbr_sig(u8 devno, struct edd_info *ei, u32 *mbrsig) | |||
72 | 73 | ||
73 | static int get_edd_info(u8 devno, struct edd_info *ei) | 74 | static int get_edd_info(u8 devno, struct edd_info *ei) |
74 | { | 75 | { |
75 | u16 ax, bx, cx, dx, di; | 76 | struct biosregs ireg, oreg; |
76 | 77 | ||
77 | memset(ei, 0, sizeof *ei); | 78 | memset(ei, 0, sizeof *ei); |
78 | 79 | ||
79 | /* Check Extensions Present */ | 80 | /* Check Extensions Present */ |
80 | 81 | ||
81 | ax = 0x4100; | 82 | initregs(&ireg); |
82 | bx = EDDMAGIC1; | 83 | ireg.ah = 0x41; |
83 | dx = devno; | 84 | ireg.bx = EDDMAGIC1; |
84 | asm("pushfl; stc; int $0x13; setc %%al; popfl" | 85 | ireg.dl = devno; |
85 | : "+a" (ax), "+b" (bx), "=c" (cx), "+d" (dx) | 86 | intcall(0x13, &ireg, &oreg); |
86 | : : "esi", "edi"); | ||
87 | 87 | ||
88 | if ((u8)ax) | 88 | if (oreg.eflags & X86_EFLAGS_CF) |
89 | return -1; /* No extended information */ | 89 | return -1; /* No extended information */ |
90 | 90 | ||
91 | if (bx != EDDMAGIC2) | 91 | if (oreg.bx != EDDMAGIC2) |
92 | return -1; | 92 | return -1; |
93 | 93 | ||
94 | ei->device = devno; | 94 | ei->device = devno; |
95 | ei->version = ax >> 8; /* EDD version number */ | 95 | ei->version = oreg.ah; /* EDD version number */ |
96 | ei->interface_support = cx; /* EDD functionality subsets */ | 96 | ei->interface_support = oreg.cx; /* EDD functionality subsets */ |
97 | 97 | ||
98 | /* Extended Get Device Parameters */ | 98 | /* Extended Get Device Parameters */ |
99 | 99 | ||
100 | ei->params.length = sizeof(ei->params); | 100 | ei->params.length = sizeof(ei->params); |
101 | ax = 0x4800; | 101 | ireg.ah = 0x48; |
102 | dx = devno; | 102 | ireg.si = (size_t)&ei->params; |
103 | asm("pushfl; int $0x13; popfl" | 103 | intcall(0x13, &ireg, &oreg); |
104 | : "+a" (ax), "+d" (dx), "=m" (ei->params) | ||
105 | : "S" (&ei->params) | ||
106 | : "ebx", "ecx", "edi"); | ||
107 | 104 | ||
108 | /* Get legacy CHS parameters */ | 105 | /* Get legacy CHS parameters */ |
109 | 106 | ||
110 | /* Ralf Brown recommends setting ES:DI to 0:0 */ | 107 | /* Ralf Brown recommends setting ES:DI to 0:0 */ |
111 | ax = 0x0800; | 108 | ireg.ah = 0x08; |
112 | dx = devno; | 109 | ireg.es = 0; |
113 | di = 0; | 110 | intcall(0x13, &ireg, &oreg); |
114 | asm("pushw %%es; " | 111 | |
115 | "movw %%di,%%es; " | 112 | if (!(oreg.eflags & X86_EFLAGS_CF)) { |
116 | "pushfl; stc; int $0x13; setc %%al; popfl; " | 113 | ei->legacy_max_cylinder = oreg.ch + ((oreg.cl & 0xc0) << 2); |
117 | "popw %%es" | 114 | ei->legacy_max_head = oreg.dh; |
118 | : "+a" (ax), "=b" (bx), "=c" (cx), "+d" (dx), "+D" (di) | 115 | ei->legacy_sectors_per_track = oreg.cl & 0x3f; |
119 | : : "esi"); | ||
120 | |||
121 | if ((u8)ax == 0) { | ||
122 | ei->legacy_max_cylinder = (cx >> 8) + ((cx & 0xc0) << 2); | ||
123 | ei->legacy_max_head = dx >> 8; | ||
124 | ei->legacy_sectors_per_track = cx & 0x3f; | ||
125 | } | 116 | } |
126 | 117 | ||
127 | return 0; | 118 | return 0; |
diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S index 5d84d1c74e4c..b31cc54b4641 100644 --- a/arch/x86/boot/header.S +++ b/arch/x86/boot/header.S | |||
@@ -22,7 +22,8 @@ | |||
22 | #include <asm/page_types.h> | 22 | #include <asm/page_types.h> |
23 | #include <asm/setup.h> | 23 | #include <asm/setup.h> |
24 | #include "boot.h" | 24 | #include "boot.h" |
25 | #include "offsets.h" | 25 | #include "voffset.h" |
26 | #include "zoffset.h" | ||
26 | 27 | ||
27 | BOOTSEG = 0x07C0 /* original address of boot-sector */ | 28 | BOOTSEG = 0x07C0 /* original address of boot-sector */ |
28 | SYSSEG = 0x1000 /* historical load address >> 4 */ | 29 | SYSSEG = 0x1000 /* historical load address >> 4 */ |
@@ -115,7 +116,7 @@ _start: | |||
115 | # Part 2 of the header, from the old setup.S | 116 | # Part 2 of the header, from the old setup.S |
116 | 117 | ||
117 | .ascii "HdrS" # header signature | 118 | .ascii "HdrS" # header signature |
118 | .word 0x0209 # header version number (>= 0x0105) | 119 | .word 0x020a # header version number (>= 0x0105) |
119 | # or else old loadlin-1.5 will fail) | 120 | # or else old loadlin-1.5 will fail) |
120 | .globl realmode_swtch | 121 | .globl realmode_swtch |
121 | realmode_swtch: .word 0, 0 # default_switch, SETUPSEG | 122 | realmode_swtch: .word 0, 0 # default_switch, SETUPSEG |
@@ -168,7 +169,11 @@ heap_end_ptr: .word _end+STACK_SIZE-512 | |||
168 | # end of setup code can be used by setup | 169 | # end of setup code can be used by setup |
169 | # for local heap purposes. | 170 | # for local heap purposes. |
170 | 171 | ||
171 | pad1: .word 0 | 172 | ext_loader_ver: |
173 | .byte 0 # Extended boot loader version | ||
174 | ext_loader_type: | ||
175 | .byte 0 # Extended boot loader type | ||
176 | |||
172 | cmd_line_ptr: .long 0 # (Header version 0x0202 or later) | 177 | cmd_line_ptr: .long 0 # (Header version 0x0202 or later) |
173 | # If nonzero, a 32-bit pointer | 178 | # If nonzero, a 32-bit pointer |
174 | # to the kernel command line. | 179 | # to the kernel command line. |
@@ -200,7 +205,7 @@ relocatable_kernel: .byte 1 | |||
200 | #else | 205 | #else |
201 | relocatable_kernel: .byte 0 | 206 | relocatable_kernel: .byte 0 |
202 | #endif | 207 | #endif |
203 | pad2: .byte 0 | 208 | min_alignment: .byte MIN_KERNEL_ALIGN_LG2 # minimum alignment |
204 | pad3: .word 0 | 209 | pad3: .word 0 |
205 | 210 | ||
206 | cmdline_size: .long COMMAND_LINE_SIZE-1 #length of the command line, | 211 | cmdline_size: .long COMMAND_LINE_SIZE-1 #length of the command line, |
@@ -212,16 +217,27 @@ hardware_subarch: .long 0 # subarchitecture, added with 2.07 | |||
212 | 217 | ||
213 | hardware_subarch_data: .quad 0 | 218 | hardware_subarch_data: .quad 0 |
214 | 219 | ||
215 | payload_offset: .long input_data | 220 | payload_offset: .long ZO_input_data |
216 | payload_length: .long input_data_end-input_data | 221 | payload_length: .long ZO_z_input_len |
217 | 222 | ||
218 | setup_data: .quad 0 # 64-bit physical pointer to | 223 | setup_data: .quad 0 # 64-bit physical pointer to |
219 | # single linked list of | 224 | # single linked list of |
220 | # struct setup_data | 225 | # struct setup_data |
221 | 226 | ||
227 | pref_address: .quad LOAD_PHYSICAL_ADDR # preferred load addr | ||
228 | |||
229 | #define ZO_INIT_SIZE (ZO__end - ZO_startup_32 + ZO_z_extract_offset) | ||
230 | #define VO_INIT_SIZE (VO__end - VO__text) | ||
231 | #if ZO_INIT_SIZE > VO_INIT_SIZE | ||
232 | #define INIT_SIZE ZO_INIT_SIZE | ||
233 | #else | ||
234 | #define INIT_SIZE VO_INIT_SIZE | ||
235 | #endif | ||
236 | init_size: .long INIT_SIZE # kernel initialization size | ||
237 | |||
222 | # End of setup header ##################################################### | 238 | # End of setup header ##################################################### |
223 | 239 | ||
224 | .section ".inittext", "ax" | 240 | .section ".entrytext", "ax" |
225 | start_of_setup: | 241 | start_of_setup: |
226 | #ifdef SAFE_RESET_DISK_CONTROLLER | 242 | #ifdef SAFE_RESET_DISK_CONTROLLER |
227 | # Reset the disk controller. | 243 | # Reset the disk controller. |
diff --git a/arch/x86/boot/main.c b/arch/x86/boot/main.c index 58f0415d3ae0..140172b895bd 100644 --- a/arch/x86/boot/main.c +++ b/arch/x86/boot/main.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * | 2 | * |
3 | * Copyright (C) 1991, 1992 Linus Torvalds | 3 | * Copyright (C) 1991, 1992 Linus Torvalds |
4 | * Copyright 2007 rPath, Inc. - All Rights Reserved | 4 | * Copyright 2007 rPath, Inc. - All Rights Reserved |
5 | * Copyright 2009 Intel Corporation; author H. Peter Anvin | ||
5 | * | 6 | * |
6 | * This file is part of the Linux kernel, and is made available under | 7 | * 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 | * the terms of the GNU General Public License version 2. |
@@ -61,11 +62,10 @@ static void copy_boot_params(void) | |||
61 | */ | 62 | */ |
62 | static void keyboard_set_repeat(void) | 63 | static void keyboard_set_repeat(void) |
63 | { | 64 | { |
64 | u16 ax = 0x0305; | 65 | struct biosregs ireg; |
65 | u16 bx = 0; | 66 | initregs(&ireg); |
66 | asm volatile("int $0x16" | 67 | ireg.ax = 0x0305; |
67 | : "+a" (ax), "+b" (bx) | 68 | intcall(0x16, &ireg, NULL); |
68 | : : "ecx", "edx", "esi", "edi"); | ||
69 | } | 69 | } |
70 | 70 | ||
71 | /* | 71 | /* |
@@ -73,18 +73,22 @@ static void keyboard_set_repeat(void) | |||
73 | */ | 73 | */ |
74 | static void query_ist(void) | 74 | static void query_ist(void) |
75 | { | 75 | { |
76 | struct biosregs ireg, oreg; | ||
77 | |||
76 | /* Some older BIOSes apparently crash on this call, so filter | 78 | /* Some older BIOSes apparently crash on this call, so filter |
77 | it from machines too old to have SpeedStep at all. */ | 79 | it from machines too old to have SpeedStep at all. */ |
78 | if (cpu.level < 6) | 80 | if (cpu.level < 6) |
79 | return; | 81 | return; |
80 | 82 | ||
81 | asm("int $0x15" | 83 | initregs(&ireg); |
82 | : "=a" (boot_params.ist_info.signature), | 84 | ireg.ax = 0xe980; /* IST Support */ |
83 | "=b" (boot_params.ist_info.command), | 85 | ireg.edx = 0x47534943; /* Request value */ |
84 | "=c" (boot_params.ist_info.event), | 86 | intcall(0x15, &ireg, &oreg); |
85 | "=d" (boot_params.ist_info.perf_level) | 87 | |
86 | : "a" (0x0000e980), /* IST Support */ | 88 | boot_params.ist_info.signature = oreg.eax; |
87 | "d" (0x47534943)); /* Request value */ | 89 | boot_params.ist_info.command = oreg.ebx; |
90 | boot_params.ist_info.event = oreg.ecx; | ||
91 | boot_params.ist_info.perf_level = oreg.edx; | ||
88 | } | 92 | } |
89 | 93 | ||
90 | /* | 94 | /* |
@@ -93,13 +97,12 @@ static void query_ist(void) | |||
93 | static void set_bios_mode(void) | 97 | static void set_bios_mode(void) |
94 | { | 98 | { |
95 | #ifdef CONFIG_X86_64 | 99 | #ifdef CONFIG_X86_64 |
96 | u32 eax, ebx; | 100 | struct biosregs ireg; |
97 | 101 | ||
98 | eax = 0xec00; | 102 | initregs(&ireg); |
99 | ebx = 2; | 103 | ireg.ax = 0xec00; |
100 | asm volatile("int $0x15" | 104 | ireg.bx = 2; |
101 | : "+a" (eax), "+b" (ebx) | 105 | intcall(0x15, &ireg, NULL); |
102 | : : "ecx", "edx", "esi", "edi"); | ||
103 | #endif | 106 | #endif |
104 | } | 107 | } |
105 | 108 | ||
diff --git a/arch/x86/boot/mca.c b/arch/x86/boot/mca.c index 911eaae5d696..a95a531148ef 100644 --- a/arch/x86/boot/mca.c +++ b/arch/x86/boot/mca.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * | 2 | * |
3 | * Copyright (C) 1991, 1992 Linus Torvalds | 3 | * Copyright (C) 1991, 1992 Linus Torvalds |
4 | * Copyright 2007 rPath, Inc. - All Rights Reserved | 4 | * Copyright 2007 rPath, Inc. - All Rights Reserved |
5 | * Copyright 2009 Intel Corporation; author H. Peter Anvin | ||
5 | * | 6 | * |
6 | * This file is part of the Linux kernel, and is made available under | 7 | * 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 | * the terms of the GNU General Public License version 2. |
@@ -16,26 +17,22 @@ | |||
16 | 17 | ||
17 | int query_mca(void) | 18 | int query_mca(void) |
18 | { | 19 | { |
19 | u8 err; | 20 | struct biosregs ireg, oreg; |
20 | u16 es, bx, len; | 21 | u16 len; |
21 | 22 | ||
22 | asm("pushw %%es ; " | 23 | initregs(&ireg); |
23 | "int $0x15 ; " | 24 | ireg.ah = 0xc0; |
24 | "setc %0 ; " | 25 | intcall(0x15, &ireg, &oreg); |
25 | "movw %%es, %1 ; " | 26 | |
26 | "popw %%es" | 27 | if (oreg.eflags & X86_EFLAGS_CF) |
27 | : "=acd" (err), "=acdSD" (es), "=b" (bx) | ||
28 | : "a" (0xc000)); | ||
29 | |||
30 | if (err) | ||
31 | return -1; /* No MCA present */ | 28 | return -1; /* No MCA present */ |
32 | 29 | ||
33 | set_fs(es); | 30 | set_fs(oreg.es); |
34 | len = rdfs16(bx); | 31 | len = rdfs16(oreg.bx); |
35 | 32 | ||
36 | if (len > sizeof(boot_params.sys_desc_table)) | 33 | if (len > sizeof(boot_params.sys_desc_table)) |
37 | len = sizeof(boot_params.sys_desc_table); | 34 | len = sizeof(boot_params.sys_desc_table); |
38 | 35 | ||
39 | copy_from_fs(&boot_params.sys_desc_table, bx, len); | 36 | copy_from_fs(&boot_params.sys_desc_table, oreg.bx, len); |
40 | return 0; | 37 | return 0; |
41 | } | 38 | } |
diff --git a/arch/x86/boot/memory.c b/arch/x86/boot/memory.c index 74b3d2ba84e9..cae3feb1035e 100644 --- a/arch/x86/boot/memory.c +++ b/arch/x86/boot/memory.c | |||
@@ -20,12 +20,16 @@ | |||
20 | static int detect_memory_e820(void) | 20 | static int detect_memory_e820(void) |
21 | { | 21 | { |
22 | int count = 0; | 22 | int count = 0; |
23 | u32 next = 0; | 23 | struct biosregs ireg, oreg; |
24 | u32 size, id, edi; | ||
25 | u8 err; | ||
26 | struct e820entry *desc = boot_params.e820_map; | 24 | struct e820entry *desc = boot_params.e820_map; |
27 | static struct e820entry buf; /* static so it is zeroed */ | 25 | static struct e820entry buf; /* static so it is zeroed */ |
28 | 26 | ||
27 | initregs(&ireg); | ||
28 | ireg.ax = 0xe820; | ||
29 | ireg.cx = sizeof buf; | ||
30 | ireg.edx = SMAP; | ||
31 | ireg.di = (size_t)&buf; | ||
32 | |||
29 | /* | 33 | /* |
30 | * Note: at least one BIOS is known which assumes that the | 34 | * Note: at least one BIOS is known which assumes that the |
31 | * buffer pointed to by one e820 call is the same one as | 35 | * buffer pointed to by one e820 call is the same one as |
@@ -41,22 +45,13 @@ static int detect_memory_e820(void) | |||
41 | */ | 45 | */ |
42 | 46 | ||
43 | do { | 47 | do { |
44 | size = sizeof buf; | 48 | intcall(0x15, &ireg, &oreg); |
45 | 49 | ireg.ebx = oreg.ebx; /* for next iteration... */ | |
46 | /* Important: %edx and %esi are clobbered by some BIOSes, | ||
47 | so they must be either used for the error output | ||
48 | or explicitly marked clobbered. Given that, assume there | ||
49 | is something out there clobbering %ebp and %edi, too. */ | ||
50 | asm("pushl %%ebp; int $0x15; popl %%ebp; setc %0" | ||
51 | : "=d" (err), "+b" (next), "=a" (id), "+c" (size), | ||
52 | "=D" (edi), "+m" (buf) | ||
53 | : "D" (&buf), "d" (SMAP), "a" (0xe820) | ||
54 | : "esi"); | ||
55 | 50 | ||
56 | /* BIOSes which terminate the chain with CF = 1 as opposed | 51 | /* BIOSes which terminate the chain with CF = 1 as opposed |
57 | to %ebx = 0 don't always report the SMAP signature on | 52 | to %ebx = 0 don't always report the SMAP signature on |
58 | the final, failing, probe. */ | 53 | the final, failing, probe. */ |
59 | if (err) | 54 | if (oreg.eflags & X86_EFLAGS_CF) |
60 | break; | 55 | break; |
61 | 56 | ||
62 | /* Some BIOSes stop returning SMAP in the middle of | 57 | /* Some BIOSes stop returning SMAP in the middle of |
@@ -64,60 +59,64 @@ static int detect_memory_e820(void) | |||
64 | screwed up the map at that point, we might have a | 59 | screwed up the map at that point, we might have a |
65 | partial map, the full map, or complete garbage, so | 60 | partial map, the full map, or complete garbage, so |
66 | just return failure. */ | 61 | just return failure. */ |
67 | if (id != SMAP) { | 62 | if (oreg.eax != SMAP) { |
68 | count = 0; | 63 | count = 0; |
69 | break; | 64 | break; |
70 | } | 65 | } |
71 | 66 | ||
72 | *desc++ = buf; | 67 | *desc++ = buf; |
73 | count++; | 68 | count++; |
74 | } while (next && count < ARRAY_SIZE(boot_params.e820_map)); | 69 | } while (ireg.ebx && count < ARRAY_SIZE(boot_params.e820_map)); |
75 | 70 | ||
76 | return boot_params.e820_entries = count; | 71 | return boot_params.e820_entries = count; |
77 | } | 72 | } |
78 | 73 | ||
79 | static int detect_memory_e801(void) | 74 | static int detect_memory_e801(void) |
80 | { | 75 | { |
81 | u16 ax, bx, cx, dx; | 76 | struct biosregs ireg, oreg; |
82 | u8 err; | ||
83 | 77 | ||
84 | bx = cx = dx = 0; | 78 | initregs(&ireg); |
85 | ax = 0xe801; | 79 | ireg.ax = 0xe801; |
86 | asm("stc; int $0x15; setc %0" | 80 | intcall(0x15, &ireg, &oreg); |
87 | : "=m" (err), "+a" (ax), "+b" (bx), "+c" (cx), "+d" (dx)); | ||
88 | 81 | ||
89 | if (err) | 82 | if (oreg.eflags & X86_EFLAGS_CF) |
90 | return -1; | 83 | return -1; |
91 | 84 | ||
92 | /* Do we really need to do this? */ | 85 | /* Do we really need to do this? */ |
93 | if (cx || dx) { | 86 | if (oreg.cx || oreg.dx) { |
94 | ax = cx; | 87 | oreg.ax = oreg.cx; |
95 | bx = dx; | 88 | oreg.bx = oreg.dx; |
96 | } | 89 | } |
97 | 90 | ||
98 | if (ax > 15*1024) | 91 | if (oreg.ax > 15*1024) { |
99 | return -1; /* Bogus! */ | 92 | return -1; /* Bogus! */ |
100 | 93 | } else if (oreg.ax == 15*1024) { | |
101 | /* This ignores memory above 16MB if we have a memory hole | 94 | boot_params.alt_mem_k = (oreg.dx << 6) + oreg.ax; |
102 | there. If someone actually finds a machine with a memory | 95 | } else { |
103 | hole at 16MB and no support for 0E820h they should probably | 96 | /* |
104 | generate a fake e820 map. */ | 97 | * This ignores memory above 16MB if we have a memory |
105 | boot_params.alt_mem_k = (ax == 15*1024) ? (dx << 6)+ax : ax; | 98 | * hole there. If someone actually finds a machine |
99 | * with a memory hole at 16MB and no support for | ||
100 | * 0E820h they should probably generate a fake e820 | ||
101 | * map. | ||
102 | */ | ||
103 | boot_params.alt_mem_k = oreg.ax; | ||
104 | } | ||
106 | 105 | ||
107 | return 0; | 106 | return 0; |
108 | } | 107 | } |
109 | 108 | ||
110 | static int detect_memory_88(void) | 109 | static int detect_memory_88(void) |
111 | { | 110 | { |
112 | u16 ax; | 111 | struct biosregs ireg, oreg; |
113 | u8 err; | ||
114 | 112 | ||
115 | ax = 0x8800; | 113 | initregs(&ireg); |
116 | asm("stc; int $0x15; setc %0" : "=bcdm" (err), "+a" (ax)); | 114 | ireg.ah = 0x88; |
115 | intcall(0x15, &ireg, &oreg); | ||
117 | 116 | ||
118 | boot_params.screen_info.ext_mem_k = ax; | 117 | boot_params.screen_info.ext_mem_k = oreg.ax; |
119 | 118 | ||
120 | return -err; | 119 | return -(oreg.eflags & X86_EFLAGS_CF); /* 0 or -1 */ |
121 | } | 120 | } |
122 | 121 | ||
123 | int detect_memory(void) | 122 | int detect_memory(void) |
diff --git a/arch/x86/boot/regs.c b/arch/x86/boot/regs.c new file mode 100644 index 000000000000..958019b1cfa5 --- /dev/null +++ b/arch/x86/boot/regs.c | |||
@@ -0,0 +1,29 @@ | |||
1 | /* ----------------------------------------------------------------------- | ||
2 | * | ||
3 | * Copyright 2009 Intel Corporation; author H. Peter Anvin | ||
4 | * | ||
5 | * This file is part of the Linux kernel, and is made available under | ||
6 | * the terms of the GNU General Public License version 2 or (at your | ||
7 | * option) any later version; incorporated herein by reference. | ||
8 | * | ||
9 | * ----------------------------------------------------------------------- */ | ||
10 | |||
11 | /* | ||
12 | * Simple helper function for initializing a register set. | ||
13 | * | ||
14 | * Note that this sets EFLAGS_CF in the input register set; this | ||
15 | * makes it easier to catch functions which do nothing but don't | ||
16 | * explicitly set CF. | ||
17 | */ | ||
18 | |||
19 | #include "boot.h" | ||
20 | |||
21 | void initregs(struct biosregs *reg) | ||
22 | { | ||
23 | memset(reg, 0, sizeof *reg); | ||
24 | reg->eflags |= X86_EFLAGS_CF; | ||
25 | reg->ds = ds(); | ||
26 | reg->es = ds(); | ||
27 | reg->fs = fs(); | ||
28 | reg->gs = gs(); | ||
29 | } | ||
diff --git a/arch/x86/boot/setup.ld b/arch/x86/boot/setup.ld index bb8dc2de7969..0f6ec455a2b1 100644 --- a/arch/x86/boot/setup.ld +++ b/arch/x86/boot/setup.ld | |||
@@ -15,8 +15,11 @@ SECTIONS | |||
15 | 15 | ||
16 | . = 497; | 16 | . = 497; |
17 | .header : { *(.header) } | 17 | .header : { *(.header) } |
18 | .entrytext : { *(.entrytext) } | ||
18 | .inittext : { *(.inittext) } | 19 | .inittext : { *(.inittext) } |
19 | .initdata : { *(.initdata) } | 20 | .initdata : { *(.initdata) } |
21 | __end_init = .; | ||
22 | |||
20 | .text : { *(.text) } | 23 | .text : { *(.text) } |
21 | .text32 : { *(.text32) } | 24 | .text32 : { *(.text32) } |
22 | 25 | ||
@@ -52,4 +55,7 @@ SECTIONS | |||
52 | 55 | ||
53 | . = ASSERT(_end <= 0x8000, "Setup too big!"); | 56 | . = ASSERT(_end <= 0x8000, "Setup too big!"); |
54 | . = ASSERT(hdr == 0x1f1, "The setup header has the wrong offset!"); | 57 | . = ASSERT(hdr == 0x1f1, "The setup header has the wrong offset!"); |
58 | /* Necessary for the very-old-loader check to work... */ | ||
59 | . = ASSERT(__end_init <= 5*512, "init sections too big!"); | ||
60 | |||
55 | } | 61 | } |
diff --git a/arch/x86/boot/tty.c b/arch/x86/boot/tty.c index 7e8e8b25f5f6..01ec69c901c7 100644 --- a/arch/x86/boot/tty.c +++ b/arch/x86/boot/tty.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * | 2 | * |
3 | * Copyright (C) 1991, 1992 Linus Torvalds | 3 | * Copyright (C) 1991, 1992 Linus Torvalds |
4 | * Copyright 2007 rPath, Inc. - All Rights Reserved | 4 | * Copyright 2007 rPath, Inc. - All Rights Reserved |
5 | * Copyright 2009 Intel Corporation; author H. Peter Anvin | ||
5 | * | 6 | * |
6 | * This file is part of the Linux kernel, and is made available under | 7 | * 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 | * the terms of the GNU General Public License version 2. |
@@ -22,24 +23,23 @@ | |||
22 | 23 | ||
23 | void __attribute__((section(".inittext"))) putchar(int ch) | 24 | void __attribute__((section(".inittext"))) putchar(int ch) |
24 | { | 25 | { |
25 | unsigned char c = ch; | 26 | struct biosregs ireg; |
26 | 27 | ||
27 | if (c == '\n') | 28 | if (ch == '\n') |
28 | putchar('\r'); /* \n -> \r\n */ | 29 | putchar('\r'); /* \n -> \r\n */ |
29 | 30 | ||
30 | /* int $0x10 is known to have bugs involving touching registers | 31 | initregs(&ireg); |
31 | it shouldn't. Be extra conservative... */ | 32 | ireg.bx = 0x0007; |
32 | asm volatile("pushal; pushw %%ds; int $0x10; popw %%ds; popal" | 33 | ireg.cx = 0x0001; |
33 | : : "b" (0x0007), "c" (0x0001), "a" (0x0e00|ch)); | 34 | ireg.ah = 0x0e; |
35 | ireg.al = ch; | ||
36 | intcall(0x10, &ireg, NULL); | ||
34 | } | 37 | } |
35 | 38 | ||
36 | void __attribute__((section(".inittext"))) puts(const char *str) | 39 | void __attribute__((section(".inittext"))) puts(const char *str) |
37 | { | 40 | { |
38 | int n = 0; | 41 | while (*str) |
39 | while (*str) { | ||
40 | putchar(*str++); | 42 | putchar(*str++); |
41 | n++; | ||
42 | } | ||
43 | } | 43 | } |
44 | 44 | ||
45 | /* | 45 | /* |
@@ -49,14 +49,13 @@ void __attribute__((section(".inittext"))) puts(const char *str) | |||
49 | 49 | ||
50 | static u8 gettime(void) | 50 | static u8 gettime(void) |
51 | { | 51 | { |
52 | u16 ax = 0x0200; | 52 | struct biosregs ireg, oreg; |
53 | u16 cx, dx; | ||
54 | 53 | ||
55 | asm volatile("int $0x1a" | 54 | initregs(&ireg); |
56 | : "+a" (ax), "=c" (cx), "=d" (dx) | 55 | ireg.ah = 0x02; |
57 | : : "ebx", "esi", "edi"); | 56 | intcall(0x1a, &ireg, &oreg); |
58 | 57 | ||
59 | return dx >> 8; | 58 | return oreg.dh; |
60 | } | 59 | } |
61 | 60 | ||
62 | /* | 61 | /* |
@@ -64,19 +63,24 @@ static u8 gettime(void) | |||
64 | */ | 63 | */ |
65 | int getchar(void) | 64 | int getchar(void) |
66 | { | 65 | { |
67 | u16 ax = 0; | 66 | struct biosregs ireg, oreg; |
68 | asm volatile("int $0x16" : "+a" (ax)); | 67 | |
68 | initregs(&ireg); | ||
69 | /* ireg.ah = 0x00; */ | ||
70 | intcall(0x16, &ireg, &oreg); | ||
69 | 71 | ||
70 | return ax & 0xff; | 72 | return oreg.al; |
71 | } | 73 | } |
72 | 74 | ||
73 | static int kbd_pending(void) | 75 | static int kbd_pending(void) |
74 | { | 76 | { |
75 | u8 pending; | 77 | struct biosregs ireg, oreg; |
76 | asm volatile("int $0x16; setnz %0" | 78 | |
77 | : "=qm" (pending) | 79 | initregs(&ireg); |
78 | : "a" (0x0100)); | 80 | ireg.ah = 0x01; |
79 | return pending; | 81 | intcall(0x16, &ireg, &oreg); |
82 | |||
83 | return !(oreg.eflags & X86_EFLAGS_ZF); | ||
80 | } | 84 | } |
81 | 85 | ||
82 | void kbd_flush(void) | 86 | void kbd_flush(void) |
diff --git a/arch/x86/boot/video-bios.c b/arch/x86/boot/video-bios.c index 3fa979c9c363..d660be492363 100644 --- a/arch/x86/boot/video-bios.c +++ b/arch/x86/boot/video-bios.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * | 2 | * |
3 | * Copyright (C) 1991, 1992 Linus Torvalds | 3 | * Copyright (C) 1991, 1992 Linus Torvalds |
4 | * Copyright 2007 rPath, Inc. - All Rights Reserved | 4 | * Copyright 2007 rPath, Inc. - All Rights Reserved |
5 | * Copyright 2009 Intel Corporation; author H. Peter Anvin | ||
5 | * | 6 | * |
6 | * This file is part of the Linux kernel, and is made available under | 7 | * 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 | * the terms of the GNU General Public License version 2. |
@@ -29,21 +30,21 @@ static int bios_set_mode(struct mode_info *mi) | |||
29 | 30 | ||
30 | static int set_bios_mode(u8 mode) | 31 | static int set_bios_mode(u8 mode) |
31 | { | 32 | { |
32 | u16 ax; | 33 | struct biosregs ireg, oreg; |
33 | u8 new_mode; | 34 | u8 new_mode; |
34 | 35 | ||
35 | ax = mode; /* AH=0x00 Set Video Mode */ | 36 | initregs(&ireg); |
36 | asm volatile(INT10 | 37 | ireg.al = mode; /* AH=0x00 Set Video Mode */ |
37 | : "+a" (ax) | 38 | intcall(0x10, &ireg, NULL); |
38 | : : "ebx", "ecx", "edx", "esi", "edi"); | ||
39 | 39 | ||
40 | ax = 0x0f00; /* Get Current Video Mode */ | 40 | |
41 | asm volatile(INT10 | 41 | ireg.ah = 0x0f; /* Get Current Video Mode */ |
42 | : "+a" (ax) | 42 | intcall(0x10, &ireg, &oreg); |
43 | : : "ebx", "ecx", "edx", "esi", "edi"); | ||
44 | 43 | ||
45 | do_restore = 1; /* Assume video contents were lost */ | 44 | do_restore = 1; /* Assume video contents were lost */ |
46 | new_mode = ax & 0x7f; /* Not all BIOSes are clean with the top bit */ | 45 | |
46 | /* Not all BIOSes are clean with the top bit */ | ||
47 | new_mode = ireg.al & 0x7f; | ||
47 | 48 | ||
48 | if (new_mode == mode) | 49 | if (new_mode == mode) |
49 | return 0; /* Mode change OK */ | 50 | return 0; /* Mode change OK */ |
@@ -53,10 +54,8 @@ static int set_bios_mode(u8 mode) | |||
53 | /* Mode setting failed, but we didn't end up where we | 54 | /* Mode setting failed, but we didn't end up where we |
54 | started. That's bad. Try to revert to the original | 55 | started. That's bad. Try to revert to the original |
55 | video mode. */ | 56 | video mode. */ |
56 | ax = boot_params.screen_info.orig_video_mode; | 57 | ireg.ax = boot_params.screen_info.orig_video_mode; |
57 | asm volatile(INT10 | 58 | intcall(0x10, &ireg, NULL); |
58 | : "+a" (ax) | ||
59 | : : "ebx", "ecx", "edx", "esi", "edi"); | ||
60 | } | 59 | } |
61 | #endif | 60 | #endif |
62 | return -1; | 61 | return -1; |
diff --git a/arch/x86/boot/video-vesa.c b/arch/x86/boot/video-vesa.c index 4a58c8ce3f69..c700147d6ffb 100644 --- a/arch/x86/boot/video-vesa.c +++ b/arch/x86/boot/video-vesa.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * | 2 | * |
3 | * Copyright (C) 1991, 1992 Linus Torvalds | 3 | * Copyright (C) 1991, 1992 Linus Torvalds |
4 | * Copyright 2007 rPath, Inc. - All Rights Reserved | 4 | * Copyright 2007 rPath, Inc. - All Rights Reserved |
5 | * Copyright 2009 Intel Corporation; author H. Peter Anvin | ||
5 | * | 6 | * |
6 | * This file is part of the Linux kernel, and is made available under | 7 | * 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 | * the terms of the GNU General Public License version 2. |
@@ -31,7 +32,7 @@ static inline void vesa_store_mode_params_graphics(void) {} | |||
31 | static int vesa_probe(void) | 32 | static int vesa_probe(void) |
32 | { | 33 | { |
33 | #if defined(CONFIG_VIDEO_VESA) || defined(CONFIG_FIRMWARE_EDID) | 34 | #if defined(CONFIG_VIDEO_VESA) || defined(CONFIG_FIRMWARE_EDID) |
34 | u16 ax, cx, di; | 35 | struct biosregs ireg, oreg; |
35 | u16 mode; | 36 | u16 mode; |
36 | addr_t mode_ptr; | 37 | addr_t mode_ptr; |
37 | struct mode_info *mi; | 38 | struct mode_info *mi; |
@@ -39,13 +40,12 @@ static int vesa_probe(void) | |||
39 | 40 | ||
40 | video_vesa.modes = GET_HEAP(struct mode_info, 0); | 41 | video_vesa.modes = GET_HEAP(struct mode_info, 0); |
41 | 42 | ||
42 | ax = 0x4f00; | 43 | initregs(&ireg); |
43 | di = (size_t)&vginfo; | 44 | ireg.ax = 0x4f00; |
44 | asm(INT10 | 45 | ireg.di = (size_t)&vginfo; |
45 | : "+a" (ax), "+D" (di), "=m" (vginfo) | 46 | intcall(0x10, &ireg, &oreg); |
46 | : : "ebx", "ecx", "edx", "esi"); | ||
47 | 47 | ||
48 | if (ax != 0x004f || | 48 | if (ireg.ax != 0x004f || |
49 | vginfo.signature != VESA_MAGIC || | 49 | vginfo.signature != VESA_MAGIC || |
50 | vginfo.version < 0x0102) | 50 | vginfo.version < 0x0102) |
51 | return 0; /* Not present */ | 51 | return 0; /* Not present */ |
@@ -65,14 +65,12 @@ static int vesa_probe(void) | |||
65 | 65 | ||
66 | memset(&vminfo, 0, sizeof vminfo); /* Just in case... */ | 66 | memset(&vminfo, 0, sizeof vminfo); /* Just in case... */ |
67 | 67 | ||
68 | ax = 0x4f01; | 68 | ireg.ax = 0x4f01; |
69 | cx = mode; | 69 | ireg.cx = mode; |
70 | di = (size_t)&vminfo; | 70 | ireg.di = (size_t)&vminfo; |
71 | asm(INT10 | 71 | intcall(0x10, &ireg, &oreg); |
72 | : "+a" (ax), "+c" (cx), "+D" (di), "=m" (vminfo) | ||
73 | : : "ebx", "edx", "esi"); | ||
74 | 72 | ||
75 | if (ax != 0x004f) | 73 | if (ireg.ax != 0x004f) |
76 | continue; | 74 | continue; |
77 | 75 | ||
78 | if ((vminfo.mode_attr & 0x15) == 0x05) { | 76 | if ((vminfo.mode_attr & 0x15) == 0x05) { |
@@ -111,20 +109,19 @@ static int vesa_probe(void) | |||
111 | 109 | ||
112 | static int vesa_set_mode(struct mode_info *mode) | 110 | static int vesa_set_mode(struct mode_info *mode) |
113 | { | 111 | { |
114 | u16 ax, bx, cx, di; | 112 | struct biosregs ireg, oreg; |
115 | int is_graphic; | 113 | int is_graphic; |
116 | u16 vesa_mode = mode->mode - VIDEO_FIRST_VESA; | 114 | u16 vesa_mode = mode->mode - VIDEO_FIRST_VESA; |
117 | 115 | ||
118 | memset(&vminfo, 0, sizeof vminfo); /* Just in case... */ | 116 | memset(&vminfo, 0, sizeof vminfo); /* Just in case... */ |
119 | 117 | ||
120 | ax = 0x4f01; | 118 | initregs(&ireg); |
121 | cx = vesa_mode; | 119 | ireg.ax = 0x4f01; |
122 | di = (size_t)&vminfo; | 120 | ireg.cx = vesa_mode; |
123 | asm(INT10 | 121 | ireg.di = (size_t)&vminfo; |
124 | : "+a" (ax), "+c" (cx), "+D" (di), "=m" (vminfo) | 122 | intcall(0x10, &ireg, &oreg); |
125 | : : "ebx", "edx", "esi"); | ||
126 | 123 | ||
127 | if (ax != 0x004f) | 124 | if (oreg.ax != 0x004f) |
128 | return -1; | 125 | return -1; |
129 | 126 | ||
130 | if ((vminfo.mode_attr & 0x15) == 0x05) { | 127 | if ((vminfo.mode_attr & 0x15) == 0x05) { |
@@ -141,14 +138,12 @@ static int vesa_set_mode(struct mode_info *mode) | |||
141 | } | 138 | } |
142 | 139 | ||
143 | 140 | ||
144 | ax = 0x4f02; | 141 | initregs(&ireg); |
145 | bx = vesa_mode; | 142 | ireg.ax = 0x4f02; |
146 | di = 0; | 143 | ireg.bx = vesa_mode; |
147 | asm volatile(INT10 | 144 | intcall(0x10, &ireg, &oreg); |
148 | : "+a" (ax), "+b" (bx), "+D" (di) | ||
149 | : : "ecx", "edx", "esi"); | ||
150 | 145 | ||
151 | if (ax != 0x004f) | 146 | if (oreg.ax != 0x004f) |
152 | return -1; | 147 | return -1; |
153 | 148 | ||
154 | graphic_mode = is_graphic; | 149 | graphic_mode = is_graphic; |
@@ -171,50 +166,45 @@ static int vesa_set_mode(struct mode_info *mode) | |||
171 | /* Switch DAC to 8-bit mode */ | 166 | /* Switch DAC to 8-bit mode */ |
172 | static void vesa_dac_set_8bits(void) | 167 | static void vesa_dac_set_8bits(void) |
173 | { | 168 | { |
169 | struct biosregs ireg, oreg; | ||
174 | u8 dac_size = 6; | 170 | u8 dac_size = 6; |
175 | 171 | ||
176 | /* If possible, switch the DAC to 8-bit mode */ | 172 | /* If possible, switch the DAC to 8-bit mode */ |
177 | if (vginfo.capabilities & 1) { | 173 | if (vginfo.capabilities & 1) { |
178 | u16 ax, bx; | 174 | initregs(&ireg); |
179 | 175 | ireg.ax = 0x4f08; | |
180 | ax = 0x4f08; | 176 | ireg.bh = 0x08; |
181 | bx = 0x0800; | 177 | intcall(0x10, &ireg, &oreg); |
182 | asm volatile(INT10 | 178 | if (oreg.ax == 0x004f) |
183 | : "+a" (ax), "+b" (bx) | 179 | dac_size = oreg.bh; |
184 | : : "ecx", "edx", "esi", "edi"); | ||
185 | |||
186 | if (ax == 0x004f) | ||
187 | dac_size = bx >> 8; | ||
188 | } | 180 | } |
189 | 181 | ||
190 | /* Set the color sizes to the DAC size, and offsets to 0 */ | 182 | /* Set the color sizes to the DAC size, and offsets to 0 */ |
191 | boot_params.screen_info.red_size = dac_size; | 183 | boot_params.screen_info.red_size = dac_size; |
192 | boot_params.screen_info.green_size = dac_size; | 184 | boot_params.screen_info.green_size = dac_size; |
193 | boot_params.screen_info.blue_size = dac_size; | 185 | boot_params.screen_info.blue_size = dac_size; |
194 | boot_params.screen_info.rsvd_size = dac_size; | 186 | boot_params.screen_info.rsvd_size = dac_size; |
195 | 187 | ||
196 | boot_params.screen_info.red_pos = 0; | 188 | boot_params.screen_info.red_pos = 0; |
197 | boot_params.screen_info.green_pos = 0; | 189 | boot_params.screen_info.green_pos = 0; |
198 | boot_params.screen_info.blue_pos = 0; | 190 | boot_params.screen_info.blue_pos = 0; |
199 | boot_params.screen_info.rsvd_pos = 0; | 191 | boot_params.screen_info.rsvd_pos = 0; |
200 | } | 192 | } |
201 | 193 | ||
202 | /* Save the VESA protected mode info */ | 194 | /* Save the VESA protected mode info */ |
203 | static void vesa_store_pm_info(void) | 195 | static void vesa_store_pm_info(void) |
204 | { | 196 | { |
205 | u16 ax, bx, di, es; | 197 | struct biosregs ireg, oreg; |
206 | 198 | ||
207 | ax = 0x4f0a; | 199 | initregs(&ireg); |
208 | bx = di = 0; | 200 | ireg.ax = 0x4f0a; |
209 | asm("pushw %%es; "INT10"; movw %%es,%0; popw %%es" | 201 | intcall(0x10, &ireg, &oreg); |
210 | : "=d" (es), "+a" (ax), "+b" (bx), "+D" (di) | ||
211 | : : "ecx", "esi"); | ||
212 | 202 | ||
213 | if (ax != 0x004f) | 203 | if (oreg.ax != 0x004f) |
214 | return; | 204 | return; |
215 | 205 | ||
216 | boot_params.screen_info.vesapm_seg = es; | 206 | boot_params.screen_info.vesapm_seg = oreg.es; |
217 | boot_params.screen_info.vesapm_off = di; | 207 | boot_params.screen_info.vesapm_off = oreg.di; |
218 | } | 208 | } |
219 | 209 | ||
220 | /* | 210 | /* |
@@ -252,7 +242,7 @@ static void vesa_store_mode_params_graphics(void) | |||
252 | void vesa_store_edid(void) | 242 | void vesa_store_edid(void) |
253 | { | 243 | { |
254 | #ifdef CONFIG_FIRMWARE_EDID | 244 | #ifdef CONFIG_FIRMWARE_EDID |
255 | u16 ax, bx, cx, dx, di; | 245 | struct biosregs ireg, oreg; |
256 | 246 | ||
257 | /* Apparently used as a nonsense token... */ | 247 | /* Apparently used as a nonsense token... */ |
258 | memset(&boot_params.edid_info, 0x13, sizeof boot_params.edid_info); | 248 | memset(&boot_params.edid_info, 0x13, sizeof boot_params.edid_info); |
@@ -260,33 +250,26 @@ void vesa_store_edid(void) | |||
260 | if (vginfo.version < 0x0200) | 250 | if (vginfo.version < 0x0200) |
261 | return; /* EDID requires VBE 2.0+ */ | 251 | return; /* EDID requires VBE 2.0+ */ |
262 | 252 | ||
263 | ax = 0x4f15; /* VBE DDC */ | 253 | initregs(&ireg); |
264 | bx = 0x0000; /* Report DDC capabilities */ | 254 | ireg.ax = 0x4f15; /* VBE DDC */ |
265 | cx = 0; /* Controller 0 */ | 255 | /* ireg.bx = 0x0000; */ /* Report DDC capabilities */ |
266 | di = 0; /* ES:DI must be 0 by spec */ | 256 | /* ireg.cx = 0; */ /* Controller 0 */ |
267 | 257 | ireg.es = 0; /* ES:DI must be 0 by spec */ | |
268 | /* Note: The VBE DDC spec is different from the main VESA spec; | 258 | intcall(0x10, &ireg, &oreg); |
269 | we genuinely have to assume all registers are destroyed here. */ | ||
270 | |||
271 | asm("pushw %%es; movw %2,%%es; "INT10"; popw %%es" | ||
272 | : "+a" (ax), "+b" (bx), "+c" (cx), "+D" (di) | ||
273 | : : "esi", "edx"); | ||
274 | 259 | ||
275 | if (ax != 0x004f) | 260 | if (oreg.ax != 0x004f) |
276 | return; /* No EDID */ | 261 | return; /* No EDID */ |
277 | 262 | ||
278 | /* BH = time in seconds to transfer EDD information */ | 263 | /* BH = time in seconds to transfer EDD information */ |
279 | /* BL = DDC level supported */ | 264 | /* BL = DDC level supported */ |
280 | 265 | ||
281 | ax = 0x4f15; /* VBE DDC */ | 266 | ireg.ax = 0x4f15; /* VBE DDC */ |
282 | bx = 0x0001; /* Read EDID */ | 267 | ireg.bx = 0x0001; /* Read EDID */ |
283 | cx = 0; /* Controller 0 */ | 268 | /* ireg.cx = 0; */ /* Controller 0 */ |
284 | dx = 0; /* EDID block number */ | 269 | /* ireg.dx = 0; */ /* EDID block number */ |
285 | di =(size_t) &boot_params.edid_info; /* (ES:)Pointer to block */ | 270 | ireg.es = ds(); |
286 | asm(INT10 | 271 | ireg.di =(size_t)&boot_params.edid_info; /* (ES:)Pointer to block */ |
287 | : "+a" (ax), "+b" (bx), "+d" (dx), "=m" (boot_params.edid_info), | 272 | intcall(0x10, &ireg, &oreg); |
288 | "+c" (cx), "+D" (di) | ||
289 | : : "esi"); | ||
290 | #endif /* CONFIG_FIRMWARE_EDID */ | 273 | #endif /* CONFIG_FIRMWARE_EDID */ |
291 | } | 274 | } |
292 | 275 | ||
diff --git a/arch/x86/boot/video-vga.c b/arch/x86/boot/video-vga.c index 9e0587a37768..8f8d827e254d 100644 --- a/arch/x86/boot/video-vga.c +++ b/arch/x86/boot/video-vga.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * | 2 | * |
3 | * Copyright (C) 1991, 1992 Linus Torvalds | 3 | * Copyright (C) 1991, 1992 Linus Torvalds |
4 | * Copyright 2007 rPath, Inc. - All Rights Reserved | 4 | * Copyright 2007 rPath, Inc. - All Rights Reserved |
5 | * Copyright 2009 Intel Corporation; author H. Peter Anvin | ||
5 | * | 6 | * |
6 | * This file is part of the Linux kernel, and is made available under | 7 | * 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 | * the terms of the GNU General Public License version 2. |
@@ -39,30 +40,30 @@ static __videocard video_vga; | |||
39 | /* Set basic 80x25 mode */ | 40 | /* Set basic 80x25 mode */ |
40 | static u8 vga_set_basic_mode(void) | 41 | static u8 vga_set_basic_mode(void) |
41 | { | 42 | { |
43 | struct biosregs ireg, oreg; | ||
42 | u16 ax; | 44 | u16 ax; |
43 | u8 rows; | 45 | u8 rows; |
44 | u8 mode; | 46 | u8 mode; |
45 | 47 | ||
48 | initregs(&ireg); | ||
49 | |||
46 | #ifdef CONFIG_VIDEO_400_HACK | 50 | #ifdef CONFIG_VIDEO_400_HACK |
47 | if (adapter >= ADAPTER_VGA) { | 51 | if (adapter >= ADAPTER_VGA) { |
48 | asm volatile(INT10 | 52 | ireg.ax = 0x1202; |
49 | : : "a" (0x1202), "b" (0x0030) | 53 | ireg.bx = 0x0030; |
50 | : "ecx", "edx", "esi", "edi"); | 54 | intcall(0x10, &ireg, NULL); |
51 | } | 55 | } |
52 | #endif | 56 | #endif |
53 | 57 | ||
54 | ax = 0x0f00; | 58 | ax = 0x0f00; |
55 | asm volatile(INT10 | 59 | intcall(0x10, &ireg, &oreg); |
56 | : "+a" (ax) | 60 | mode = oreg.al; |
57 | : : "ebx", "ecx", "edx", "esi", "edi"); | ||
58 | |||
59 | mode = (u8)ax; | ||
60 | 61 | ||
61 | set_fs(0); | 62 | set_fs(0); |
62 | rows = rdfs8(0x484); /* rows minus one */ | 63 | rows = rdfs8(0x484); /* rows minus one */ |
63 | 64 | ||
64 | #ifndef CONFIG_VIDEO_400_HACK | 65 | #ifndef CONFIG_VIDEO_400_HACK |
65 | if ((ax == 0x5003 || ax == 0x5007) && | 66 | if ((oreg.ax == 0x5003 || oreg.ax == 0x5007) && |
66 | (rows == 0 || rows == 24)) | 67 | (rows == 0 || rows == 24)) |
67 | return mode; | 68 | return mode; |
68 | #endif | 69 | #endif |
@@ -71,10 +72,8 @@ static u8 vga_set_basic_mode(void) | |||
71 | mode = 3; | 72 | mode = 3; |
72 | 73 | ||
73 | /* Set the mode */ | 74 | /* Set the mode */ |
74 | ax = mode; | 75 | ireg.ax = mode; /* AH=0: set mode */ |
75 | asm volatile(INT10 | 76 | intcall(0x10, &ireg, NULL); |
76 | : "+a" (ax) | ||
77 | : : "ebx", "ecx", "edx", "esi", "edi"); | ||
78 | do_restore = 1; | 77 | do_restore = 1; |
79 | return mode; | 78 | return mode; |
80 | } | 79 | } |
@@ -82,43 +81,69 @@ static u8 vga_set_basic_mode(void) | |||
82 | static void vga_set_8font(void) | 81 | static void vga_set_8font(void) |
83 | { | 82 | { |
84 | /* Set 8x8 font - 80x43 on EGA, 80x50 on VGA */ | 83 | /* Set 8x8 font - 80x43 on EGA, 80x50 on VGA */ |
84 | struct biosregs ireg; | ||
85 | |||
86 | initregs(&ireg); | ||
85 | 87 | ||
86 | /* Set 8x8 font */ | 88 | /* Set 8x8 font */ |
87 | asm volatile(INT10 : : "a" (0x1112), "b" (0)); | 89 | ireg.ax = 0x1112; |
90 | /* ireg.bl = 0; */ | ||
91 | intcall(0x10, &ireg, NULL); | ||
88 | 92 | ||
89 | /* Use alternate print screen */ | 93 | /* Use alternate print screen */ |
90 | asm volatile(INT10 : : "a" (0x1200), "b" (0x20)); | 94 | ireg.ax = 0x1200; |
95 | ireg.bl = 0x20; | ||
96 | intcall(0x10, &ireg, NULL); | ||
91 | 97 | ||
92 | /* Turn off cursor emulation */ | 98 | /* Turn off cursor emulation */ |
93 | asm volatile(INT10 : : "a" (0x1201), "b" (0x34)); | 99 | ireg.ax = 0x1201; |
100 | ireg.bl = 0x34; | ||
101 | intcall(0x10, &ireg, NULL); | ||
94 | 102 | ||
95 | /* Cursor is scan lines 6-7 */ | 103 | /* Cursor is scan lines 6-7 */ |
96 | asm volatile(INT10 : : "a" (0x0100), "c" (0x0607)); | 104 | ireg.ax = 0x0100; |
105 | ireg.cx = 0x0607; | ||
106 | intcall(0x10, &ireg, NULL); | ||
97 | } | 107 | } |
98 | 108 | ||
99 | static void vga_set_14font(void) | 109 | static void vga_set_14font(void) |
100 | { | 110 | { |
101 | /* Set 9x14 font - 80x28 on VGA */ | 111 | /* Set 9x14 font - 80x28 on VGA */ |
112 | struct biosregs ireg; | ||
113 | |||
114 | initregs(&ireg); | ||
102 | 115 | ||
103 | /* Set 9x14 font */ | 116 | /* Set 9x14 font */ |
104 | asm volatile(INT10 : : "a" (0x1111), "b" (0)); | 117 | ireg.ax = 0x1111; |
118 | /* ireg.bl = 0; */ | ||
119 | intcall(0x10, &ireg, NULL); | ||
105 | 120 | ||
106 | /* Turn off cursor emulation */ | 121 | /* Turn off cursor emulation */ |
107 | asm volatile(INT10 : : "a" (0x1201), "b" (0x34)); | 122 | ireg.ax = 0x1201; |
123 | ireg.bl = 0x34; | ||
124 | intcall(0x10, &ireg, NULL); | ||
108 | 125 | ||
109 | /* Cursor is scan lines 11-12 */ | 126 | /* Cursor is scan lines 11-12 */ |
110 | asm volatile(INT10 : : "a" (0x0100), "c" (0x0b0c)); | 127 | ireg.ax = 0x0100; |
128 | ireg.cx = 0x0b0c; | ||
129 | intcall(0x10, &ireg, NULL); | ||
111 | } | 130 | } |
112 | 131 | ||
113 | static void vga_set_80x43(void) | 132 | static void vga_set_80x43(void) |
114 | { | 133 | { |
115 | /* Set 80x43 mode on VGA (not EGA) */ | 134 | /* Set 80x43 mode on VGA (not EGA) */ |
135 | struct biosregs ireg; | ||
136 | |||
137 | initregs(&ireg); | ||
116 | 138 | ||
117 | /* Set 350 scans */ | 139 | /* Set 350 scans */ |
118 | asm volatile(INT10 : : "a" (0x1201), "b" (0x30)); | 140 | ireg.ax = 0x1201; |
141 | ireg.bl = 0x30; | ||
142 | intcall(0x10, &ireg, NULL); | ||
119 | 143 | ||
120 | /* Reset video mode */ | 144 | /* Reset video mode */ |
121 | asm volatile(INT10 : : "a" (0x0003)); | 145 | ireg.ax = 0x0003; |
146 | intcall(0x10, &ireg, NULL); | ||
122 | 147 | ||
123 | vga_set_8font(); | 148 | vga_set_8font(); |
124 | } | 149 | } |
@@ -225,8 +250,6 @@ static int vga_set_mode(struct mode_info *mode) | |||
225 | */ | 250 | */ |
226 | static int vga_probe(void) | 251 | static int vga_probe(void) |
227 | { | 252 | { |
228 | u16 ega_bx; | ||
229 | |||
230 | static const char *card_name[] = { | 253 | static const char *card_name[] = { |
231 | "CGA/MDA/HGC", "EGA", "VGA" | 254 | "CGA/MDA/HGC", "EGA", "VGA" |
232 | }; | 255 | }; |
@@ -240,26 +263,26 @@ static int vga_probe(void) | |||
240 | sizeof(ega_modes)/sizeof(struct mode_info), | 263 | sizeof(ega_modes)/sizeof(struct mode_info), |
241 | sizeof(vga_modes)/sizeof(struct mode_info), | 264 | sizeof(vga_modes)/sizeof(struct mode_info), |
242 | }; | 265 | }; |
243 | u8 vga_flag; | ||
244 | 266 | ||
245 | asm(INT10 | 267 | struct biosregs ireg, oreg; |
246 | : "=b" (ega_bx) | 268 | |
247 | : "a" (0x1200), "b" (0x10) /* Check EGA/VGA */ | 269 | initregs(&ireg); |
248 | : "ecx", "edx", "esi", "edi"); | 270 | |
271 | ireg.ax = 0x1200; | ||
272 | ireg.bl = 0x10; /* Check EGA/VGA */ | ||
273 | intcall(0x10, &ireg, &oreg); | ||
249 | 274 | ||
250 | #ifndef _WAKEUP | 275 | #ifndef _WAKEUP |
251 | boot_params.screen_info.orig_video_ega_bx = ega_bx; | 276 | boot_params.screen_info.orig_video_ega_bx = oreg.bx; |
252 | #endif | 277 | #endif |
253 | 278 | ||
254 | /* If we have MDA/CGA/HGC then BL will be unchanged at 0x10 */ | 279 | /* If we have MDA/CGA/HGC then BL will be unchanged at 0x10 */ |
255 | if ((u8)ega_bx != 0x10) { | 280 | if (oreg.bl != 0x10) { |
256 | /* EGA/VGA */ | 281 | /* EGA/VGA */ |
257 | asm(INT10 | 282 | ireg.ax = 0x1a00; |
258 | : "=a" (vga_flag) | 283 | intcall(0x10, &ireg, &oreg); |
259 | : "a" (0x1a00) | ||
260 | : "ebx", "ecx", "edx", "esi", "edi"); | ||
261 | 284 | ||
262 | if (vga_flag == 0x1a) { | 285 | if (oreg.al == 0x1a) { |
263 | adapter = ADAPTER_VGA; | 286 | adapter = ADAPTER_VGA; |
264 | #ifndef _WAKEUP | 287 | #ifndef _WAKEUP |
265 | boot_params.screen_info.orig_video_isVGA = 1; | 288 | boot_params.screen_info.orig_video_isVGA = 1; |
diff --git a/arch/x86/boot/video.c b/arch/x86/boot/video.c index 3bef2c1febe9..bad728b76fc2 100644 --- a/arch/x86/boot/video.c +++ b/arch/x86/boot/video.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * | 2 | * |
3 | * Copyright (C) 1991, 1992 Linus Torvalds | 3 | * Copyright (C) 1991, 1992 Linus Torvalds |
4 | * Copyright 2007 rPath, Inc. - All Rights Reserved | 4 | * Copyright 2007 rPath, Inc. - All Rights Reserved |
5 | * Copyright 2009 Intel Corporation; author H. Peter Anvin | ||
5 | * | 6 | * |
6 | * This file is part of the Linux kernel, and is made available under | 7 | * 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 | * the terms of the GNU General Public License version 2. |
@@ -18,33 +19,29 @@ | |||
18 | 19 | ||
19 | static void store_cursor_position(void) | 20 | static void store_cursor_position(void) |
20 | { | 21 | { |
21 | u16 curpos; | 22 | struct biosregs ireg, oreg; |
22 | u16 ax, bx; | ||
23 | 23 | ||
24 | ax = 0x0300; | 24 | initregs(&ireg); |
25 | bx = 0; | 25 | ireg.ah = 0x03; |
26 | asm(INT10 | 26 | intcall(0x10, &ireg, &oreg); |
27 | : "=d" (curpos), "+a" (ax), "+b" (bx) | ||
28 | : : "ecx", "esi", "edi"); | ||
29 | 27 | ||
30 | boot_params.screen_info.orig_x = curpos; | 28 | boot_params.screen_info.orig_x = oreg.dl; |
31 | boot_params.screen_info.orig_y = curpos >> 8; | 29 | boot_params.screen_info.orig_y = oreg.dh; |
32 | } | 30 | } |
33 | 31 | ||
34 | static void store_video_mode(void) | 32 | static void store_video_mode(void) |
35 | { | 33 | { |
36 | u16 ax, page; | 34 | struct biosregs ireg, oreg; |
37 | 35 | ||
38 | /* N.B.: the saving of the video page here is a bit silly, | 36 | /* N.B.: the saving of the video page here is a bit silly, |
39 | since we pretty much assume page 0 everywhere. */ | 37 | since we pretty much assume page 0 everywhere. */ |
40 | ax = 0x0f00; | 38 | initregs(&ireg); |
41 | asm(INT10 | 39 | ireg.ah = 0x0f; |
42 | : "+a" (ax), "=b" (page) | 40 | intcall(0x10, &ireg, &oreg); |
43 | : : "ecx", "edx", "esi", "edi"); | ||
44 | 41 | ||
45 | /* Not all BIOSes are clean with respect to the top bit */ | 42 | /* Not all BIOSes are clean with respect to the top bit */ |
46 | boot_params.screen_info.orig_video_mode = ax & 0x7f; | 43 | boot_params.screen_info.orig_video_mode = oreg.al & 0x7f; |
47 | boot_params.screen_info.orig_video_page = page >> 8; | 44 | boot_params.screen_info.orig_video_page = oreg.bh; |
48 | } | 45 | } |
49 | 46 | ||
50 | /* | 47 | /* |
@@ -257,7 +254,7 @@ static void restore_screen(void) | |||
257 | int y; | 254 | int y; |
258 | addr_t dst = 0; | 255 | addr_t dst = 0; |
259 | u16 *src = saved.data; | 256 | u16 *src = saved.data; |
260 | u16 ax, bx, dx; | 257 | struct biosregs ireg; |
261 | 258 | ||
262 | if (graphic_mode) | 259 | if (graphic_mode) |
263 | return; /* Can't restore onto a graphic mode */ | 260 | return; /* Can't restore onto a graphic mode */ |
@@ -296,12 +293,11 @@ static void restore_screen(void) | |||
296 | } | 293 | } |
297 | 294 | ||
298 | /* Restore cursor position */ | 295 | /* Restore cursor position */ |
299 | ax = 0x0200; /* Set cursor position */ | 296 | initregs(&ireg); |
300 | bx = 0; /* Page number (<< 8) */ | 297 | ireg.ah = 0x02; /* Set cursor position */ |
301 | dx = (saved.cury << 8)+saved.curx; | 298 | ireg.dh = saved.cury; |
302 | asm volatile(INT10 | 299 | ireg.dl = saved.curx; |
303 | : "+a" (ax), "+b" (bx), "+d" (dx) | 300 | intcall(0x10, &ireg, NULL); |
304 | : : "ecx", "esi", "edi"); | ||
305 | } | 301 | } |
306 | #else | 302 | #else |
307 | #define save_screen() ((void)0) | 303 | #define save_screen() ((void)0) |
diff --git a/arch/x86/boot/video.h b/arch/x86/boot/video.h index ee63f5d14461..5bb174a997fc 100644 --- a/arch/x86/boot/video.h +++ b/arch/x86/boot/video.h | |||
@@ -112,20 +112,6 @@ extern int force_x, force_y; /* Don't query the BIOS for cols/rows */ | |||
112 | extern int do_restore; /* Restore screen contents */ | 112 | extern int do_restore; /* Restore screen contents */ |
113 | extern int graphic_mode; /* Graphics mode with linear frame buffer */ | 113 | extern int graphic_mode; /* Graphics mode with linear frame buffer */ |
114 | 114 | ||
115 | /* | ||
116 | * int $0x10 is notorious for touching registers it shouldn't. | ||
117 | * gcc doesn't like %ebp being clobbered, so define it as a push/pop | ||
118 | * sequence here. | ||
119 | * | ||
120 | * A number of systems, including the original PC can clobber %bp in | ||
121 | * certain circumstances, like when scrolling. There exists at least | ||
122 | * one Trident video card which could clobber DS under a set of | ||
123 | * circumstances that we are unlikely to encounter (scrolling when | ||
124 | * using an extended graphics mode of more than 800x600 pixels), but | ||
125 | * it's cheap insurance to deal with that here. | ||
126 | */ | ||
127 | #define INT10 "pushl %%ebp; pushw %%ds; int $0x10; popw %%ds; popl %%ebp" | ||
128 | |||
129 | /* Accessing VGA indexed registers */ | 115 | /* Accessing VGA indexed registers */ |
130 | static inline u8 in_idx(u16 port, u8 index) | 116 | static inline u8 in_idx(u16 port, u8 index) |
131 | { | 117 | { |