diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-06 13:20:47 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-06 13:20:47 -0400 |
commit | a417fb99dea8ee47e72060fb36e5f3ff4ea54a5b (patch) | |
tree | 788cf90966768c270db150f06917728937150da4 | |
parent | 9faa1e5942fd647b0dd2fbbdcc04988841cacaf3 (diff) | |
parent | 6238b47b58480cd9c092600c05338dbe261b71ce (diff) |
Merge branch 'x86-setup-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'x86-setup-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
x86, setup: move isdigit.h to ctype.h, header files on top.
x86, setup: enable early console output from the decompressor
x86, setup: reorganize the early console setup
x86, setup: Allow global variables and functions in the decompressor
x86, setup: Only set early_serial_base after port is initialized
x86, setup: Make the setup code also accept console=uart8250
x86, setup: Early-boot serial I/O support
-rw-r--r-- | arch/x86/boot/Makefile | 8 | ||||
-rw-r--r-- | arch/x86/boot/boot.h | 28 | ||||
-rw-r--r-- | arch/x86/boot/cmdline.c | 6 | ||||
-rw-r--r-- | arch/x86/boot/compressed/Makefile | 4 | ||||
-rw-r--r-- | arch/x86/boot/compressed/cmdline.c | 21 | ||||
-rw-r--r-- | arch/x86/boot/compressed/early_serial_console.c | 5 | ||||
-rw-r--r-- | arch/x86/boot/compressed/head_32.S | 13 | ||||
-rw-r--r-- | arch/x86/boot/compressed/head_64.S | 13 | ||||
-rw-r--r-- | arch/x86/boot/compressed/misc.c | 56 | ||||
-rw-r--r-- | arch/x86/boot/compressed/misc.h | 39 | ||||
-rw-r--r-- | arch/x86/boot/compressed/string.c | 2 | ||||
-rw-r--r-- | arch/x86/boot/compressed/vmlinux.lds.S | 6 | ||||
-rw-r--r-- | arch/x86/boot/ctype.h | 21 | ||||
-rw-r--r-- | arch/x86/boot/early_serial_console.c | 139 | ||||
-rw-r--r-- | arch/x86/boot/main.c | 9 | ||||
-rw-r--r-- | arch/x86/boot/printf.c | 4 | ||||
-rw-r--r-- | arch/x86/boot/string.c | 63 | ||||
-rw-r--r-- | arch/x86/boot/tty.c | 37 |
18 files changed, 422 insertions, 52 deletions
diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile index ec749c2bfdd7..f7cb086b4add 100644 --- a/arch/x86/boot/Makefile +++ b/arch/x86/boot/Makefile | |||
@@ -26,10 +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 bioscall.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 |
30 | setup-y += header.o main.o mca.o memory.o pm.o pmjump.o | 30 | setup-y += early_serial_console.o edd.o header.o main.o mca.o memory.o |
31 | setup-y += printf.o regs.o string.o tty.o video.o video-mode.o | 31 | setup-y += pm.o pmjump.o printf.o regs.o string.o tty.o video.o |
32 | setup-y += version.o | 32 | setup-y += video-mode.o version.o |
33 | setup-$(CONFIG_X86_APM_BOOT) += apm.o | 33 | setup-$(CONFIG_X86_APM_BOOT) += apm.o |
34 | 34 | ||
35 | # 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, |
diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h index 98239d2658f2..c7093bd9f2d3 100644 --- a/arch/x86/boot/boot.h +++ b/arch/x86/boot/boot.h | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "bitops.h" | 28 | #include "bitops.h" |
29 | #include <asm/cpufeature.h> | 29 | #include <asm/cpufeature.h> |
30 | #include <asm/processor-flags.h> | 30 | #include <asm/processor-flags.h> |
31 | #include "ctype.h" | ||
31 | 32 | ||
32 | /* Useful macros */ | 33 | /* Useful macros */ |
33 | #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) | 34 | #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) |
@@ -37,6 +38,8 @@ | |||
37 | extern struct setup_header hdr; | 38 | extern struct setup_header hdr; |
38 | extern struct boot_params boot_params; | 39 | extern struct boot_params boot_params; |
39 | 40 | ||
41 | #define cpu_relax() asm volatile("rep; nop") | ||
42 | |||
40 | /* Basic port I/O */ | 43 | /* Basic port I/O */ |
41 | static inline void outb(u8 v, u16 port) | 44 | static inline void outb(u8 v, u16 port) |
42 | { | 45 | { |
@@ -198,11 +201,6 @@ static inline int memcmp_gs(const void *s1, addr_t s2, size_t len) | |||
198 | return diff; | 201 | return diff; |
199 | } | 202 | } |
200 | 203 | ||
201 | static inline int isdigit(int ch) | ||
202 | { | ||
203 | return (ch >= '0') && (ch <= '9'); | ||
204 | } | ||
205 | |||
206 | /* Heap -- available for dynamic lists. */ | 204 | /* Heap -- available for dynamic lists. */ |
207 | extern char _end[]; | 205 | extern char _end[]; |
208 | extern char *HEAP; | 206 | extern char *HEAP; |
@@ -287,8 +285,18 @@ struct biosregs { | |||
287 | void intcall(u8 int_no, const struct biosregs *ireg, struct biosregs *oreg); | 285 | void intcall(u8 int_no, const struct biosregs *ireg, struct biosregs *oreg); |
288 | 286 | ||
289 | /* cmdline.c */ | 287 | /* cmdline.c */ |
290 | int cmdline_find_option(const char *option, char *buffer, int bufsize); | 288 | int __cmdline_find_option(u32 cmdline_ptr, const char *option, char *buffer, int bufsize); |
291 | int cmdline_find_option_bool(const char *option); | 289 | int __cmdline_find_option_bool(u32 cmdline_ptr, const char *option); |
290 | static inline int cmdline_find_option(const char *option, char *buffer, int bufsize) | ||
291 | { | ||
292 | return __cmdline_find_option(boot_params.hdr.cmd_line_ptr, option, buffer, bufsize); | ||
293 | } | ||
294 | |||
295 | static inline int cmdline_find_option_bool(const char *option) | ||
296 | { | ||
297 | return __cmdline_find_option_bool(boot_params.hdr.cmd_line_ptr, option); | ||
298 | } | ||
299 | |||
292 | 300 | ||
293 | /* cpu.c, cpucheck.c */ | 301 | /* cpu.c, cpucheck.c */ |
294 | struct cpu_features { | 302 | struct cpu_features { |
@@ -300,6 +308,10 @@ extern struct cpu_features cpu; | |||
300 | int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr); | 308 | int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr); |
301 | int validate_cpu(void); | 309 | int validate_cpu(void); |
302 | 310 | ||
311 | /* early_serial_console.c */ | ||
312 | extern int early_serial_base; | ||
313 | void console_init(void); | ||
314 | |||
303 | /* edd.c */ | 315 | /* edd.c */ |
304 | void query_edd(void); | 316 | void query_edd(void); |
305 | 317 | ||
@@ -329,8 +341,10 @@ void initregs(struct biosregs *regs); | |||
329 | 341 | ||
330 | /* string.c */ | 342 | /* string.c */ |
331 | int strcmp(const char *str1, const char *str2); | 343 | int strcmp(const char *str1, const char *str2); |
344 | int strncmp(const char *cs, const char *ct, size_t count); | ||
332 | size_t strnlen(const char *s, size_t maxlen); | 345 | size_t strnlen(const char *s, size_t maxlen); |
333 | unsigned int atou(const char *s); | 346 | unsigned int atou(const char *s); |
347 | unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base); | ||
334 | 348 | ||
335 | /* tty.c */ | 349 | /* tty.c */ |
336 | void puts(const char *); | 350 | void puts(const char *); |
diff --git a/arch/x86/boot/cmdline.c b/arch/x86/boot/cmdline.c index a1d35634bce0..6b3b6f708c04 100644 --- a/arch/x86/boot/cmdline.c +++ b/arch/x86/boot/cmdline.c | |||
@@ -27,9 +27,8 @@ static inline int myisspace(u8 c) | |||
27 | * Returns the length of the argument (regardless of if it was | 27 | * Returns the length of the argument (regardless of if it was |
28 | * truncated to fit in the buffer), or -1 on not found. | 28 | * truncated to fit in the buffer), or -1 on not found. |
29 | */ | 29 | */ |
30 | int cmdline_find_option(const char *option, char *buffer, int bufsize) | 30 | int __cmdline_find_option(u32 cmdline_ptr, const char *option, char *buffer, int bufsize) |
31 | { | 31 | { |
32 | u32 cmdline_ptr = boot_params.hdr.cmd_line_ptr; | ||
33 | addr_t cptr; | 32 | addr_t cptr; |
34 | char c; | 33 | char c; |
35 | int len = -1; | 34 | int len = -1; |
@@ -100,9 +99,8 @@ int cmdline_find_option(const char *option, char *buffer, int bufsize) | |||
100 | * Returns the position of that option (starts counting with 1) | 99 | * Returns the position of that option (starts counting with 1) |
101 | * or 0 on not found | 100 | * or 0 on not found |
102 | */ | 101 | */ |
103 | int cmdline_find_option_bool(const char *option) | 102 | int __cmdline_find_option_bool(u32 cmdline_ptr, const char *option) |
104 | { | 103 | { |
105 | u32 cmdline_ptr = boot_params.hdr.cmd_line_ptr; | ||
106 | addr_t cptr; | 104 | addr_t cptr; |
107 | char c; | 105 | char c; |
108 | int pos = 0, wstart = 0; | 106 | int pos = 0, wstart = 0; |
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index fbb47daf2459..0c229551eead 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile | |||
@@ -4,7 +4,7 @@ | |||
4 | # create a compressed vmlinux image from the original vmlinux | 4 | # create a compressed vmlinux image from the original vmlinux |
5 | # | 5 | # |
6 | 6 | ||
7 | targets := vmlinux.lds vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma vmlinux.bin.lzo head_$(BITS).o misc.o piggy.o | 7 | targets := vmlinux.lds vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma vmlinux.bin.lzo head_$(BITS).o misc.o string.o cmdline.o early_serial_console.o piggy.o |
8 | 8 | ||
9 | KBUILD_CFLAGS := -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2 | 9 | KBUILD_CFLAGS := -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2 |
10 | KBUILD_CFLAGS += -fno-strict-aliasing -fPIC | 10 | KBUILD_CFLAGS += -fno-strict-aliasing -fPIC |
@@ -23,7 +23,7 @@ LDFLAGS_vmlinux := -T | |||
23 | 23 | ||
24 | hostprogs-y := mkpiggy | 24 | hostprogs-y := mkpiggy |
25 | 25 | ||
26 | $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o $(obj)/piggy.o FORCE | 26 | $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o $(obj)/string.o $(obj)/cmdline.o $(obj)/early_serial_console.o $(obj)/piggy.o FORCE |
27 | $(call if_changed,ld) | 27 | $(call if_changed,ld) |
28 | @: | 28 | @: |
29 | 29 | ||
diff --git a/arch/x86/boot/compressed/cmdline.c b/arch/x86/boot/compressed/cmdline.c new file mode 100644 index 000000000000..cb62f786990d --- /dev/null +++ b/arch/x86/boot/compressed/cmdline.c | |||
@@ -0,0 +1,21 @@ | |||
1 | #include "misc.h" | ||
2 | |||
3 | static unsigned long fs; | ||
4 | static inline void set_fs(unsigned long seg) | ||
5 | { | ||
6 | fs = seg << 4; /* shift it back */ | ||
7 | } | ||
8 | typedef unsigned long addr_t; | ||
9 | static inline char rdfs8(addr_t addr) | ||
10 | { | ||
11 | return *((char *)(fs + addr)); | ||
12 | } | ||
13 | #include "../cmdline.c" | ||
14 | int cmdline_find_option(const char *option, char *buffer, int bufsize) | ||
15 | { | ||
16 | return __cmdline_find_option(real_mode->hdr.cmd_line_ptr, option, buffer, bufsize); | ||
17 | } | ||
18 | int cmdline_find_option_bool(const char *option) | ||
19 | { | ||
20 | return __cmdline_find_option_bool(real_mode->hdr.cmd_line_ptr, option); | ||
21 | } | ||
diff --git a/arch/x86/boot/compressed/early_serial_console.c b/arch/x86/boot/compressed/early_serial_console.c new file mode 100644 index 000000000000..261e81fb9582 --- /dev/null +++ b/arch/x86/boot/compressed/early_serial_console.c | |||
@@ -0,0 +1,5 @@ | |||
1 | #include "misc.h" | ||
2 | |||
3 | int early_serial_base; | ||
4 | |||
5 | #include "../early_serial_console.c" | ||
diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S index f543b70ffae2..67a655a39ce4 100644 --- a/arch/x86/boot/compressed/head_32.S +++ b/arch/x86/boot/compressed/head_32.S | |||
@@ -124,6 +124,19 @@ relocated: | |||
124 | rep stosl | 124 | rep stosl |
125 | 125 | ||
126 | /* | 126 | /* |
127 | * Adjust our own GOT | ||
128 | */ | ||
129 | leal _got(%ebx), %edx | ||
130 | leal _egot(%ebx), %ecx | ||
131 | 1: | ||
132 | cmpl %ecx, %edx | ||
133 | jae 2f | ||
134 | addl %ebx, (%edx) | ||
135 | addl $4, %edx | ||
136 | jmp 1b | ||
137 | 2: | ||
138 | |||
139 | /* | ||
127 | * Do the decompression, and jump to the new kernel.. | 140 | * Do the decompression, and jump to the new kernel.. |
128 | */ | 141 | */ |
129 | leal z_extract_offset_negative(%ebx), %ebp | 142 | leal z_extract_offset_negative(%ebx), %ebp |
diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S index faff0dc9c06a..52f85a196fa0 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S | |||
@@ -280,6 +280,19 @@ relocated: | |||
280 | rep stosq | 280 | rep stosq |
281 | 281 | ||
282 | /* | 282 | /* |
283 | * Adjust our own GOT | ||
284 | */ | ||
285 | leaq _got(%rip), %rdx | ||
286 | leaq _egot(%rip), %rcx | ||
287 | 1: | ||
288 | cmpq %rcx, %rdx | ||
289 | jae 2f | ||
290 | addq %rbx, (%rdx) | ||
291 | addq $8, %rdx | ||
292 | jmp 1b | ||
293 | 2: | ||
294 | |||
295 | /* | ||
283 | * Do the decompression, and jump to the new kernel.. | 296 | * Do the decompression, and jump to the new kernel.. |
284 | */ | 297 | */ |
285 | pushq %rsi /* Save the real mode argument */ | 298 | pushq %rsi /* Save the real mode argument */ |
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c index 51e240779a44..8f7bef8e9fff 100644 --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c | |||
@@ -9,23 +9,7 @@ | |||
9 | * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 | 9 | * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 |
10 | */ | 10 | */ |
11 | 11 | ||
12 | /* | 12 | #include "misc.h" |
13 | * we have to be careful, because no indirections are allowed here, and | ||
14 | * paravirt_ops is a kind of one. As it will only run in baremetal anyway, | ||
15 | * we just keep it from happening | ||
16 | */ | ||
17 | #undef CONFIG_PARAVIRT | ||
18 | #ifdef CONFIG_X86_32 | ||
19 | #define _ASM_X86_DESC_H 1 | ||
20 | #endif | ||
21 | |||
22 | #include <linux/linkage.h> | ||
23 | #include <linux/screen_info.h> | ||
24 | #include <linux/elf.h> | ||
25 | #include <linux/io.h> | ||
26 | #include <asm/page.h> | ||
27 | #include <asm/boot.h> | ||
28 | #include <asm/bootparam.h> | ||
29 | 13 | ||
30 | /* WARNING!! | 14 | /* WARNING!! |
31 | * This code is compiled with -fPIC and it is relocated dynamically | 15 | * This code is compiled with -fPIC and it is relocated dynamically |
@@ -123,15 +107,13 @@ static void error(char *m); | |||
123 | /* | 107 | /* |
124 | * This is set up by the setup-routine at boot-time | 108 | * This is set up by the setup-routine at boot-time |
125 | */ | 109 | */ |
126 | static struct boot_params *real_mode; /* Pointer to real-mode data */ | 110 | struct boot_params *real_mode; /* Pointer to real-mode data */ |
127 | static int quiet; | 111 | static int quiet; |
112 | static int debug; | ||
128 | 113 | ||
129 | void *memset(void *s, int c, size_t n); | 114 | void *memset(void *s, int c, size_t n); |
130 | void *memcpy(void *dest, const void *src, size_t n); | 115 | void *memcpy(void *dest, const void *src, size_t n); |
131 | 116 | ||
132 | static void __putstr(int, const char *); | ||
133 | #define putstr(__x) __putstr(0, __x) | ||
134 | |||
135 | #ifdef CONFIG_X86_64 | 117 | #ifdef CONFIG_X86_64 |
136 | #define memptr long | 118 | #define memptr long |
137 | #else | 119 | #else |
@@ -170,7 +152,21 @@ static void scroll(void) | |||
170 | vidmem[i] = ' '; | 152 | vidmem[i] = ' '; |
171 | } | 153 | } |
172 | 154 | ||
173 | static void __putstr(int error, const char *s) | 155 | #define XMTRDY 0x20 |
156 | |||
157 | #define TXR 0 /* Transmit register (WRITE) */ | ||
158 | #define LSR 5 /* Line Status */ | ||
159 | static void serial_putchar(int ch) | ||
160 | { | ||
161 | unsigned timeout = 0xffff; | ||
162 | |||
163 | while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout) | ||
164 | cpu_relax(); | ||
165 | |||
166 | outb(ch, early_serial_base + TXR); | ||
167 | } | ||
168 | |||
169 | void __putstr(int error, const char *s) | ||
174 | { | 170 | { |
175 | int x, y, pos; | 171 | int x, y, pos; |
176 | char c; | 172 | char c; |
@@ -179,6 +175,14 @@ static void __putstr(int error, const char *s) | |||
179 | if (!error) | 175 | if (!error) |
180 | return; | 176 | return; |
181 | #endif | 177 | #endif |
178 | if (early_serial_base) { | ||
179 | const char *str = s; | ||
180 | while (*str) { | ||
181 | if (*str == '\n') | ||
182 | serial_putchar('\r'); | ||
183 | serial_putchar(*str++); | ||
184 | } | ||
185 | } | ||
182 | 186 | ||
183 | if (real_mode->screen_info.orig_video_mode == 0 && | 187 | if (real_mode->screen_info.orig_video_mode == 0 && |
184 | lines == 0 && cols == 0) | 188 | lines == 0 && cols == 0) |
@@ -305,8 +309,10 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap, | |||
305 | { | 309 | { |
306 | real_mode = rmode; | 310 | real_mode = rmode; |
307 | 311 | ||
308 | if (real_mode->hdr.loadflags & QUIET_FLAG) | 312 | if (cmdline_find_option_bool("quiet")) |
309 | quiet = 1; | 313 | quiet = 1; |
314 | if (cmdline_find_option_bool("debug")) | ||
315 | debug = 1; | ||
310 | 316 | ||
311 | if (real_mode->screen_info.orig_video_mode == 7) { | 317 | if (real_mode->screen_info.orig_video_mode == 7) { |
312 | vidmem = (char *) 0xb0000; | 318 | vidmem = (char *) 0xb0000; |
@@ -319,6 +325,10 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap, | |||
319 | lines = real_mode->screen_info.orig_video_lines; | 325 | lines = real_mode->screen_info.orig_video_lines; |
320 | cols = real_mode->screen_info.orig_video_cols; | 326 | cols = real_mode->screen_info.orig_video_cols; |
321 | 327 | ||
328 | console_init(); | ||
329 | if (debug) | ||
330 | putstr("early console in decompress_kernel\n"); | ||
331 | |||
322 | free_mem_ptr = heap; /* Heap */ | 332 | free_mem_ptr = heap; /* Heap */ |
323 | free_mem_end_ptr = heap + BOOT_HEAP_SIZE; | 333 | free_mem_end_ptr = heap + BOOT_HEAP_SIZE; |
324 | 334 | ||
diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h new file mode 100644 index 000000000000..3f19c81a6203 --- /dev/null +++ b/arch/x86/boot/compressed/misc.h | |||
@@ -0,0 +1,39 @@ | |||
1 | #ifndef BOOT_COMPRESSED_MISC_H | ||
2 | #define BOOT_COMPRESSED_MISC_H | ||
3 | |||
4 | /* | ||
5 | * we have to be careful, because no indirections are allowed here, and | ||
6 | * paravirt_ops is a kind of one. As it will only run in baremetal anyway, | ||
7 | * we just keep it from happening | ||
8 | */ | ||
9 | #undef CONFIG_PARAVIRT | ||
10 | #ifdef CONFIG_X86_32 | ||
11 | #define _ASM_X86_DESC_H 1 | ||
12 | #endif | ||
13 | |||
14 | #include <linux/linkage.h> | ||
15 | #include <linux/screen_info.h> | ||
16 | #include <linux/elf.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <asm/page.h> | ||
19 | #include <asm/boot.h> | ||
20 | #include <asm/bootparam.h> | ||
21 | |||
22 | #define BOOT_BOOT_H | ||
23 | #include "../ctype.h" | ||
24 | |||
25 | /* misc.c */ | ||
26 | extern struct boot_params *real_mode; /* Pointer to real-mode data */ | ||
27 | void __putstr(int error, const char *s); | ||
28 | #define putstr(__x) __putstr(0, __x) | ||
29 | #define puts(__x) __putstr(0, __x) | ||
30 | |||
31 | /* cmdline.c */ | ||
32 | int cmdline_find_option(const char *option, char *buffer, int bufsize); | ||
33 | int cmdline_find_option_bool(const char *option); | ||
34 | |||
35 | /* early_serial_console.c */ | ||
36 | extern int early_serial_base; | ||
37 | void console_init(void); | ||
38 | |||
39 | #endif | ||
diff --git a/arch/x86/boot/compressed/string.c b/arch/x86/boot/compressed/string.c new file mode 100644 index 000000000000..19b3e693cd72 --- /dev/null +++ b/arch/x86/boot/compressed/string.c | |||
@@ -0,0 +1,2 @@ | |||
1 | #include "misc.h" | ||
2 | #include "../string.c" | ||
diff --git a/arch/x86/boot/compressed/vmlinux.lds.S b/arch/x86/boot/compressed/vmlinux.lds.S index 5ddabceee124..34d047c98284 100644 --- a/arch/x86/boot/compressed/vmlinux.lds.S +++ b/arch/x86/boot/compressed/vmlinux.lds.S | |||
@@ -41,6 +41,12 @@ SECTIONS | |||
41 | *(.rodata.*) | 41 | *(.rodata.*) |
42 | _erodata = . ; | 42 | _erodata = . ; |
43 | } | 43 | } |
44 | .got : { | ||
45 | _got = .; | ||
46 | KEEP(*(.got.plt)) | ||
47 | KEEP(*(.got)) | ||
48 | _egot = .; | ||
49 | } | ||
44 | .data : { | 50 | .data : { |
45 | _data = . ; | 51 | _data = . ; |
46 | *(.data) | 52 | *(.data) |
diff --git a/arch/x86/boot/ctype.h b/arch/x86/boot/ctype.h new file mode 100644 index 000000000000..25e13403193c --- /dev/null +++ b/arch/x86/boot/ctype.h | |||
@@ -0,0 +1,21 @@ | |||
1 | #ifndef BOOT_ISDIGIT_H | ||
2 | |||
3 | #define BOOT_ISDIGIT_H | ||
4 | |||
5 | static inline int isdigit(int ch) | ||
6 | { | ||
7 | return (ch >= '0') && (ch <= '9'); | ||
8 | } | ||
9 | |||
10 | static inline int isxdigit(int ch) | ||
11 | { | ||
12 | if (isdigit(ch)) | ||
13 | return true; | ||
14 | |||
15 | if ((ch >= 'a') && (ch <= 'f')) | ||
16 | return true; | ||
17 | |||
18 | return (ch >= 'A') && (ch <= 'F'); | ||
19 | } | ||
20 | |||
21 | #endif | ||
diff --git a/arch/x86/boot/early_serial_console.c b/arch/x86/boot/early_serial_console.c new file mode 100644 index 000000000000..030f4b93e255 --- /dev/null +++ b/arch/x86/boot/early_serial_console.c | |||
@@ -0,0 +1,139 @@ | |||
1 | #include "boot.h" | ||
2 | |||
3 | #define DEFAULT_SERIAL_PORT 0x3f8 /* ttyS0 */ | ||
4 | |||
5 | #define XMTRDY 0x20 | ||
6 | |||
7 | #define DLAB 0x80 | ||
8 | |||
9 | #define TXR 0 /* Transmit register (WRITE) */ | ||
10 | #define RXR 0 /* Receive register (READ) */ | ||
11 | #define IER 1 /* Interrupt Enable */ | ||
12 | #define IIR 2 /* Interrupt ID */ | ||
13 | #define FCR 2 /* FIFO control */ | ||
14 | #define LCR 3 /* Line control */ | ||
15 | #define MCR 4 /* Modem control */ | ||
16 | #define LSR 5 /* Line Status */ | ||
17 | #define MSR 6 /* Modem Status */ | ||
18 | #define DLL 0 /* Divisor Latch Low */ | ||
19 | #define DLH 1 /* Divisor latch High */ | ||
20 | |||
21 | #define DEFAULT_BAUD 9600 | ||
22 | |||
23 | static void early_serial_init(int port, int baud) | ||
24 | { | ||
25 | unsigned char c; | ||
26 | unsigned divisor; | ||
27 | |||
28 | outb(0x3, port + LCR); /* 8n1 */ | ||
29 | outb(0, port + IER); /* no interrupt */ | ||
30 | outb(0, port + FCR); /* no fifo */ | ||
31 | outb(0x3, port + MCR); /* DTR + RTS */ | ||
32 | |||
33 | divisor = 115200 / baud; | ||
34 | c = inb(port + LCR); | ||
35 | outb(c | DLAB, port + LCR); | ||
36 | outb(divisor & 0xff, port + DLL); | ||
37 | outb((divisor >> 8) & 0xff, port + DLH); | ||
38 | outb(c & ~DLAB, port + LCR); | ||
39 | |||
40 | early_serial_base = port; | ||
41 | } | ||
42 | |||
43 | static void parse_earlyprintk(void) | ||
44 | { | ||
45 | int baud = DEFAULT_BAUD; | ||
46 | char arg[32]; | ||
47 | int pos = 0; | ||
48 | int port = 0; | ||
49 | |||
50 | if (cmdline_find_option("earlyprintk", arg, sizeof arg) > 0) { | ||
51 | char *e; | ||
52 | |||
53 | if (!strncmp(arg, "serial", 6)) { | ||
54 | port = DEFAULT_SERIAL_PORT; | ||
55 | pos += 6; | ||
56 | } | ||
57 | |||
58 | if (arg[pos] == ',') | ||
59 | pos++; | ||
60 | |||
61 | if (!strncmp(arg, "ttyS", 4)) { | ||
62 | static const int bases[] = { 0x3f8, 0x2f8 }; | ||
63 | int idx = 0; | ||
64 | |||
65 | if (!strncmp(arg + pos, "ttyS", 4)) | ||
66 | pos += 4; | ||
67 | |||
68 | if (arg[pos++] == '1') | ||
69 | idx = 1; | ||
70 | |||
71 | port = bases[idx]; | ||
72 | } | ||
73 | |||
74 | if (arg[pos] == ',') | ||
75 | pos++; | ||
76 | |||
77 | baud = simple_strtoull(arg + pos, &e, 0); | ||
78 | if (baud == 0 || arg + pos == e) | ||
79 | baud = DEFAULT_BAUD; | ||
80 | } | ||
81 | |||
82 | if (port) | ||
83 | early_serial_init(port, baud); | ||
84 | } | ||
85 | |||
86 | #define BASE_BAUD (1843200/16) | ||
87 | static unsigned int probe_baud(int port) | ||
88 | { | ||
89 | unsigned char lcr, dll, dlh; | ||
90 | unsigned int quot; | ||
91 | |||
92 | lcr = inb(port + LCR); | ||
93 | outb(lcr | DLAB, port + LCR); | ||
94 | dll = inb(port + DLL); | ||
95 | dlh = inb(port + DLH); | ||
96 | outb(lcr, port + LCR); | ||
97 | quot = (dlh << 8) | dll; | ||
98 | |||
99 | return BASE_BAUD / quot; | ||
100 | } | ||
101 | |||
102 | static void parse_console_uart8250(void) | ||
103 | { | ||
104 | char optstr[64], *options; | ||
105 | int baud = DEFAULT_BAUD; | ||
106 | int port = 0; | ||
107 | |||
108 | /* | ||
109 | * console=uart8250,io,0x3f8,115200n8 | ||
110 | * need to make sure it is last one console ! | ||
111 | */ | ||
112 | if (cmdline_find_option("console", optstr, sizeof optstr) <= 0) | ||
113 | return; | ||
114 | |||
115 | options = optstr; | ||
116 | |||
117 | if (!strncmp(options, "uart8250,io,", 12)) | ||
118 | port = simple_strtoull(options + 12, &options, 0); | ||
119 | else if (!strncmp(options, "uart,io,", 8)) | ||
120 | port = simple_strtoull(options + 8, &options, 0); | ||
121 | else | ||
122 | return; | ||
123 | |||
124 | if (options && (options[0] == ',')) | ||
125 | baud = simple_strtoull(options + 1, &options, 0); | ||
126 | else | ||
127 | baud = probe_baud(port); | ||
128 | |||
129 | if (port) | ||
130 | early_serial_init(port, baud); | ||
131 | } | ||
132 | |||
133 | void console_init(void) | ||
134 | { | ||
135 | parse_earlyprintk(); | ||
136 | |||
137 | if (!early_serial_base) | ||
138 | parse_console_uart8250(); | ||
139 | } | ||
diff --git a/arch/x86/boot/main.c b/arch/x86/boot/main.c index 140172b895bd..40358c8905be 100644 --- a/arch/x86/boot/main.c +++ b/arch/x86/boot/main.c | |||
@@ -130,6 +130,11 @@ void main(void) | |||
130 | /* First, copy the boot header into the "zeropage" */ | 130 | /* First, copy the boot header into the "zeropage" */ |
131 | copy_boot_params(); | 131 | copy_boot_params(); |
132 | 132 | ||
133 | /* Initialize the early-boot console */ | ||
134 | console_init(); | ||
135 | if (cmdline_find_option_bool("debug")) | ||
136 | puts("early console in setup code\n"); | ||
137 | |||
133 | /* End of heap check */ | 138 | /* End of heap check */ |
134 | init_heap(); | 139 | init_heap(); |
135 | 140 | ||
@@ -168,10 +173,6 @@ void main(void) | |||
168 | /* Set the video mode */ | 173 | /* Set the video mode */ |
169 | set_video(); | 174 | set_video(); |
170 | 175 | ||
171 | /* Parse command line for 'quiet' and pass it to decompressor. */ | ||
172 | if (cmdline_find_option_bool("quiet")) | ||
173 | boot_params.hdr.loadflags |= QUIET_FLAG; | ||
174 | |||
175 | /* Do the last things and invoke protected mode */ | 176 | /* Do the last things and invoke protected mode */ |
176 | go_to_protected_mode(); | 177 | go_to_protected_mode(); |
177 | } | 178 | } |
diff --git a/arch/x86/boot/printf.c b/arch/x86/boot/printf.c index 50e47cdbdddd..cdac91ca55d3 100644 --- a/arch/x86/boot/printf.c +++ b/arch/x86/boot/printf.c | |||
@@ -34,7 +34,7 @@ static int skip_atoi(const char **s) | |||
34 | #define SMALL 32 /* Must be 32 == 0x20 */ | 34 | #define SMALL 32 /* Must be 32 == 0x20 */ |
35 | #define SPECIAL 64 /* 0x */ | 35 | #define SPECIAL 64 /* 0x */ |
36 | 36 | ||
37 | #define do_div(n,base) ({ \ | 37 | #define __do_div(n, base) ({ \ |
38 | int __res; \ | 38 | int __res; \ |
39 | __res = ((unsigned long) n) % (unsigned) base; \ | 39 | __res = ((unsigned long) n) % (unsigned) base; \ |
40 | n = ((unsigned long) n) / (unsigned) base; \ | 40 | n = ((unsigned long) n) / (unsigned) base; \ |
@@ -83,7 +83,7 @@ static char *number(char *str, long num, int base, int size, int precision, | |||
83 | tmp[i++] = '0'; | 83 | tmp[i++] = '0'; |
84 | else | 84 | else |
85 | while (num != 0) | 85 | while (num != 0) |
86 | tmp[i++] = (digits[do_div(num, base)] | locase); | 86 | tmp[i++] = (digits[__do_div(num, base)] | locase); |
87 | if (i > precision) | 87 | if (i > precision) |
88 | precision = i; | 88 | precision = i; |
89 | size -= precision; | 89 | size -= precision; |
diff --git a/arch/x86/boot/string.c b/arch/x86/boot/string.c index f94b7a0c2abf..3cbc4058dd26 100644 --- a/arch/x86/boot/string.c +++ b/arch/x86/boot/string.c | |||
@@ -30,6 +30,22 @@ int strcmp(const char *str1, const char *str2) | |||
30 | return 0; | 30 | return 0; |
31 | } | 31 | } |
32 | 32 | ||
33 | int strncmp(const char *cs, const char *ct, size_t count) | ||
34 | { | ||
35 | unsigned char c1, c2; | ||
36 | |||
37 | while (count) { | ||
38 | c1 = *cs++; | ||
39 | c2 = *ct++; | ||
40 | if (c1 != c2) | ||
41 | return c1 < c2 ? -1 : 1; | ||
42 | if (!c1) | ||
43 | break; | ||
44 | count--; | ||
45 | } | ||
46 | return 0; | ||
47 | } | ||
48 | |||
33 | size_t strnlen(const char *s, size_t maxlen) | 49 | size_t strnlen(const char *s, size_t maxlen) |
34 | { | 50 | { |
35 | const char *es = s; | 51 | const char *es = s; |
@@ -48,3 +64,50 @@ unsigned int atou(const char *s) | |||
48 | i = i * 10 + (*s++ - '0'); | 64 | i = i * 10 + (*s++ - '0'); |
49 | return i; | 65 | return i; |
50 | } | 66 | } |
67 | |||
68 | /* Works only for digits and letters, but small and fast */ | ||
69 | #define TOLOWER(x) ((x) | 0x20) | ||
70 | |||
71 | static unsigned int simple_guess_base(const char *cp) | ||
72 | { | ||
73 | if (cp[0] == '0') { | ||
74 | if (TOLOWER(cp[1]) == 'x' && isxdigit(cp[2])) | ||
75 | return 16; | ||
76 | else | ||
77 | return 8; | ||
78 | } else { | ||
79 | return 10; | ||
80 | } | ||
81 | } | ||
82 | |||
83 | /** | ||
84 | * simple_strtoull - convert a string to an unsigned long long | ||
85 | * @cp: The start of the string | ||
86 | * @endp: A pointer to the end of the parsed string will be placed here | ||
87 | * @base: The number base to use | ||
88 | */ | ||
89 | |||
90 | unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base) | ||
91 | { | ||
92 | unsigned long long result = 0; | ||
93 | |||
94 | if (!base) | ||
95 | base = simple_guess_base(cp); | ||
96 | |||
97 | if (base == 16 && cp[0] == '0' && TOLOWER(cp[1]) == 'x') | ||
98 | cp += 2; | ||
99 | |||
100 | while (isxdigit(*cp)) { | ||
101 | unsigned int value; | ||
102 | |||
103 | value = isdigit(*cp) ? *cp - '0' : TOLOWER(*cp) - 'a' + 10; | ||
104 | if (value >= base) | ||
105 | break; | ||
106 | result = result * base + value; | ||
107 | cp++; | ||
108 | } | ||
109 | if (endp) | ||
110 | *endp = (char *)cp; | ||
111 | |||
112 | return result; | ||
113 | } | ||
diff --git a/arch/x86/boot/tty.c b/arch/x86/boot/tty.c index 01ec69c901c7..def2451f46ae 100644 --- a/arch/x86/boot/tty.c +++ b/arch/x86/boot/tty.c | |||
@@ -10,23 +10,36 @@ | |||
10 | * ----------------------------------------------------------------------- */ | 10 | * ----------------------------------------------------------------------- */ |
11 | 11 | ||
12 | /* | 12 | /* |
13 | * Very simple screen I/O | 13 | * Very simple screen and serial I/O |
14 | * XXX: Probably should add very simple serial I/O? | ||
15 | */ | 14 | */ |
16 | 15 | ||
17 | #include "boot.h" | 16 | #include "boot.h" |
18 | 17 | ||
18 | int early_serial_base; | ||
19 | |||
20 | #define XMTRDY 0x20 | ||
21 | |||
22 | #define TXR 0 /* Transmit register (WRITE) */ | ||
23 | #define LSR 5 /* Line Status */ | ||
24 | |||
19 | /* | 25 | /* |
20 | * These functions are in .inittext so they can be used to signal | 26 | * These functions are in .inittext so they can be used to signal |
21 | * error during initialization. | 27 | * error during initialization. |
22 | */ | 28 | */ |
23 | 29 | ||
24 | void __attribute__((section(".inittext"))) putchar(int ch) | 30 | static void __attribute__((section(".inittext"))) serial_putchar(int ch) |
25 | { | 31 | { |
26 | struct biosregs ireg; | 32 | unsigned timeout = 0xffff; |
27 | 33 | ||
28 | if (ch == '\n') | 34 | while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout) |
29 | putchar('\r'); /* \n -> \r\n */ | 35 | cpu_relax(); |
36 | |||
37 | outb(ch, early_serial_base + TXR); | ||
38 | } | ||
39 | |||
40 | static void __attribute__((section(".inittext"))) bios_putchar(int ch) | ||
41 | { | ||
42 | struct biosregs ireg; | ||
30 | 43 | ||
31 | initregs(&ireg); | 44 | initregs(&ireg); |
32 | ireg.bx = 0x0007; | 45 | ireg.bx = 0x0007; |
@@ -36,6 +49,17 @@ void __attribute__((section(".inittext"))) putchar(int ch) | |||
36 | intcall(0x10, &ireg, NULL); | 49 | intcall(0x10, &ireg, NULL); |
37 | } | 50 | } |
38 | 51 | ||
52 | void __attribute__((section(".inittext"))) putchar(int ch) | ||
53 | { | ||
54 | if (ch == '\n') | ||
55 | putchar('\r'); /* \n -> \r\n */ | ||
56 | |||
57 | bios_putchar(ch); | ||
58 | |||
59 | if (early_serial_base != 0) | ||
60 | serial_putchar(ch); | ||
61 | } | ||
62 | |||
39 | void __attribute__((section(".inittext"))) puts(const char *str) | 63 | void __attribute__((section(".inittext"))) puts(const char *str) |
40 | { | 64 | { |
41 | while (*str) | 65 | while (*str) |
@@ -112,3 +136,4 @@ int getchar_timeout(void) | |||
112 | 136 | ||
113 | return 0; /* Timeout! */ | 137 | return 0; /* Timeout! */ |
114 | } | 138 | } |
139 | |||