diff options
Diffstat (limited to 'arch/x86_64/boot')
-rw-r--r-- | arch/x86_64/boot/compressed/Makefile | 12 | ||||
-rw-r--r-- | arch/x86_64/boot/compressed/head.S | 322 | ||||
-rw-r--r-- | arch/x86_64/boot/compressed/misc.c | 247 | ||||
-rw-r--r-- | arch/x86_64/boot/compressed/vmlinux.lds | 44 | ||||
-rw-r--r-- | arch/x86_64/boot/compressed/vmlinux.scr | 9 |
5 files changed, 418 insertions, 216 deletions
diff --git a/arch/x86_64/boot/compressed/Makefile b/arch/x86_64/boot/compressed/Makefile index e70fa6e1da08..705a3e33d7e1 100644 --- a/arch/x86_64/boot/compressed/Makefile +++ b/arch/x86_64/boot/compressed/Makefile | |||
@@ -8,16 +8,14 @@ | |||
8 | 8 | ||
9 | targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o | 9 | targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o |
10 | EXTRA_AFLAGS := -traditional | 10 | EXTRA_AFLAGS := -traditional |
11 | AFLAGS := $(subst -m64,-m32,$(AFLAGS)) | ||
12 | 11 | ||
13 | # cannot use EXTRA_CFLAGS because base CFLAGS contains -mkernel which conflicts with | 12 | # cannot use EXTRA_CFLAGS because base CFLAGS contains -mkernel which conflicts with |
14 | # -m32 | 13 | # -m32 |
15 | CFLAGS := -m32 -D__KERNEL__ -Iinclude -O2 -fno-strict-aliasing | 14 | CFLAGS := -m64 -D__KERNEL__ -Iinclude -O2 -fno-strict-aliasing -fPIC -mcmodel=small -fno-builtin |
16 | LDFLAGS := -m elf_i386 | 15 | LDFLAGS := -m elf_x86_64 |
17 | 16 | ||
18 | LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup_32 -m elf_i386 | 17 | LDFLAGS_vmlinux := -T |
19 | 18 | $(obj)/vmlinux: $(src)/vmlinux.lds $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE | |
20 | $(obj)/vmlinux: $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE | ||
21 | $(call if_changed,ld) | 19 | $(call if_changed,ld) |
22 | @: | 20 | @: |
23 | 21 | ||
@@ -27,7 +25,7 @@ $(obj)/vmlinux.bin: vmlinux FORCE | |||
27 | $(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE | 25 | $(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE |
28 | $(call if_changed,gzip) | 26 | $(call if_changed,gzip) |
29 | 27 | ||
30 | LDFLAGS_piggy.o := -r --format binary --oformat elf32-i386 -T | 28 | LDFLAGS_piggy.o := -r --format binary --oformat elf64-x86-64 -T |
31 | 29 | ||
32 | $(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE | 30 | $(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE |
33 | $(call if_changed,ld) | 31 | $(call if_changed,ld) |
diff --git a/arch/x86_64/boot/compressed/head.S b/arch/x86_64/boot/compressed/head.S index 6f55565e4d42..c353a9266ea4 100644 --- a/arch/x86_64/boot/compressed/head.S +++ b/arch/x86_64/boot/compressed/head.S | |||
@@ -26,116 +26,262 @@ | |||
26 | 26 | ||
27 | #include <linux/linkage.h> | 27 | #include <linux/linkage.h> |
28 | #include <asm/segment.h> | 28 | #include <asm/segment.h> |
29 | #include <asm/pgtable.h> | ||
29 | #include <asm/page.h> | 30 | #include <asm/page.h> |
31 | #include <asm/msr.h> | ||
30 | 32 | ||
33 | .section ".text.head" | ||
31 | .code32 | 34 | .code32 |
32 | .globl startup_32 | 35 | .globl startup_32 |
33 | 36 | ||
34 | startup_32: | 37 | startup_32: |
35 | cld | 38 | cld |
36 | cli | 39 | cli |
37 | movl $(__KERNEL_DS),%eax | 40 | movl $(__KERNEL_DS), %eax |
38 | movl %eax,%ds | 41 | movl %eax, %ds |
39 | movl %eax,%es | 42 | movl %eax, %es |
40 | movl %eax,%fs | 43 | movl %eax, %ss |
41 | movl %eax,%gs | 44 | |
42 | 45 | /* Calculate the delta between where we were compiled to run | |
43 | lss stack_start,%esp | 46 | * at and where we were actually loaded at. This can only be done |
44 | xorl %eax,%eax | 47 | * with a short local call on x86. Nothing else will tell us what |
45 | 1: incl %eax # check that A20 really IS enabled | 48 | * address we are running at. The reserved chunk of the real-mode |
46 | movl %eax,0x000000 # loop forever if it isn't | 49 | * data at 0x34-0x3f are used as the stack for this calculation. |
47 | cmpl %eax,0x100000 | 50 | * Only 4 bytes are needed. |
48 | je 1b | 51 | */ |
52 | leal 0x40(%esi), %esp | ||
53 | call 1f | ||
54 | 1: popl %ebp | ||
55 | subl $1b, %ebp | ||
56 | |||
57 | /* Compute the delta between where we were compiled to run at | ||
58 | * and where the code will actually run at. | ||
59 | */ | ||
60 | /* %ebp contains the address we are loaded at by the boot loader and %ebx | ||
61 | * contains the address where we should move the kernel image temporarily | ||
62 | * for safe in-place decompression. | ||
63 | */ | ||
64 | |||
65 | #ifdef CONFIG_RELOCATABLE | ||
66 | movl %ebp, %ebx | ||
67 | addl $(LARGE_PAGE_SIZE -1), %ebx | ||
68 | andl $LARGE_PAGE_MASK, %ebx | ||
69 | #else | ||
70 | movl $CONFIG_PHYSICAL_START, %ebx | ||
71 | #endif | ||
72 | |||
73 | /* Replace the compressed data size with the uncompressed size */ | ||
74 | subl input_len(%ebp), %ebx | ||
75 | movl output_len(%ebp), %eax | ||
76 | addl %eax, %ebx | ||
77 | /* Add 8 bytes for every 32K input block */ | ||
78 | shrl $12, %eax | ||
79 | addl %eax, %ebx | ||
80 | /* Add 32K + 18 bytes of extra slack and align on a 4K boundary */ | ||
81 | addl $(32768 + 18 + 4095), %ebx | ||
82 | andl $~4095, %ebx | ||
49 | 83 | ||
50 | /* | 84 | /* |
51 | * Initialize eflags. Some BIOS's leave bits like NT set. This would | 85 | * Prepare for entering 64 bit mode |
52 | * confuse the debugger if this code is traced. | ||
53 | * XXX - best to initialize before switching to protected mode. | ||
54 | */ | 86 | */ |
55 | pushl $0 | 87 | |
56 | popfl | 88 | /* Load new GDT with the 64bit segments using 32bit descriptor */ |
89 | leal gdt(%ebp), %eax | ||
90 | movl %eax, gdt+2(%ebp) | ||
91 | lgdt gdt(%ebp) | ||
92 | |||
93 | /* Enable PAE mode */ | ||
94 | xorl %eax, %eax | ||
95 | orl $(1 << 5), %eax | ||
96 | movl %eax, %cr4 | ||
97 | |||
98 | /* | ||
99 | * Build early 4G boot pagetable | ||
100 | */ | ||
101 | /* Initialize Page tables to 0*/ | ||
102 | leal pgtable(%ebx), %edi | ||
103 | xorl %eax, %eax | ||
104 | movl $((4096*6)/4), %ecx | ||
105 | rep stosl | ||
106 | |||
107 | /* Build Level 4 */ | ||
108 | leal pgtable + 0(%ebx), %edi | ||
109 | leal 0x1007 (%edi), %eax | ||
110 | movl %eax, 0(%edi) | ||
111 | |||
112 | /* Build Level 3 */ | ||
113 | leal pgtable + 0x1000(%ebx), %edi | ||
114 | leal 0x1007(%edi), %eax | ||
115 | movl $4, %ecx | ||
116 | 1: movl %eax, 0x00(%edi) | ||
117 | addl $0x00001000, %eax | ||
118 | addl $8, %edi | ||
119 | decl %ecx | ||
120 | jnz 1b | ||
121 | |||
122 | /* Build Level 2 */ | ||
123 | leal pgtable + 0x2000(%ebx), %edi | ||
124 | movl $0x00000183, %eax | ||
125 | movl $2048, %ecx | ||
126 | 1: movl %eax, 0(%edi) | ||
127 | addl $0x00200000, %eax | ||
128 | addl $8, %edi | ||
129 | decl %ecx | ||
130 | jnz 1b | ||
131 | |||
132 | /* Enable the boot page tables */ | ||
133 | leal pgtable(%ebx), %eax | ||
134 | movl %eax, %cr3 | ||
135 | |||
136 | /* Enable Long mode in EFER (Extended Feature Enable Register) */ | ||
137 | movl $MSR_EFER, %ecx | ||
138 | rdmsr | ||
139 | btsl $_EFER_LME, %eax | ||
140 | wrmsr | ||
141 | |||
142 | /* Setup for the jump to 64bit mode | ||
143 | * | ||
144 | * When the jump is performend we will be in long mode but | ||
145 | * in 32bit compatibility mode with EFER.LME = 1, CS.L = 0, CS.D = 1 | ||
146 | * (and in turn EFER.LMA = 1). To jump into 64bit mode we use | ||
147 | * the new gdt/idt that has __KERNEL_CS with CS.L = 1. | ||
148 | * We place all of the values on our mini stack so lret can | ||
149 | * used to perform that far jump. | ||
150 | */ | ||
151 | pushl $__KERNEL_CS | ||
152 | leal startup_64(%ebp), %eax | ||
153 | pushl %eax | ||
154 | |||
155 | /* Enter paged protected Mode, activating Long Mode */ | ||
156 | movl $0x80000001, %eax /* Enable Paging and Protected mode */ | ||
157 | movl %eax, %cr0 | ||
158 | |||
159 | /* Jump from 32bit compatibility mode into 64bit mode. */ | ||
160 | lret | ||
161 | |||
162 | /* Be careful here startup_64 needs to be at a predictable | ||
163 | * address so I can export it in an ELF header. Bootloaders | ||
164 | * should look at the ELF header to find this address, as | ||
165 | * it may change in the future. | ||
166 | */ | ||
167 | .code64 | ||
168 | .org 0x100 | ||
169 | ENTRY(startup_64) | ||
170 | /* We come here either from startup_32 or directly from a | ||
171 | * 64bit bootloader. If we come here from a bootloader we depend on | ||
172 | * an identity mapped page table being provied that maps our | ||
173 | * entire text+data+bss and hopefully all of memory. | ||
174 | */ | ||
175 | |||
176 | /* Setup data segments. */ | ||
177 | xorl %eax, %eax | ||
178 | movl %eax, %ds | ||
179 | movl %eax, %es | ||
180 | movl %eax, %ss | ||
181 | |||
182 | /* Compute the decompressed kernel start address. It is where | ||
183 | * we were loaded at aligned to a 2M boundary. %rbp contains the | ||
184 | * decompressed kernel start address. | ||
185 | * | ||
186 | * If it is a relocatable kernel then decompress and run the kernel | ||
187 | * from load address aligned to 2MB addr, otherwise decompress and | ||
188 | * run the kernel from CONFIG_PHYSICAL_START | ||
189 | */ | ||
190 | |||
191 | /* Start with the delta to where the kernel will run at. */ | ||
192 | #ifdef CONFIG_RELOCATABLE | ||
193 | leaq startup_32(%rip) /* - $startup_32 */, %rbp | ||
194 | addq $(LARGE_PAGE_SIZE - 1), %rbp | ||
195 | andq $LARGE_PAGE_MASK, %rbp | ||
196 | movq %rbp, %rbx | ||
197 | #else | ||
198 | movq $CONFIG_PHYSICAL_START, %rbp | ||
199 | movq %rbp, %rbx | ||
200 | #endif | ||
201 | |||
202 | /* Replace the compressed data size with the uncompressed size */ | ||
203 | movl input_len(%rip), %eax | ||
204 | subq %rax, %rbx | ||
205 | movl output_len(%rip), %eax | ||
206 | addq %rax, %rbx | ||
207 | /* Add 8 bytes for every 32K input block */ | ||
208 | shrq $12, %rax | ||
209 | addq %rax, %rbx | ||
210 | /* Add 32K + 18 bytes of extra slack and align on a 4K boundary */ | ||
211 | addq $(32768 + 18 + 4095), %rbx | ||
212 | andq $~4095, %rbx | ||
213 | |||
214 | /* Copy the compressed kernel to the end of our buffer | ||
215 | * where decompression in place becomes safe. | ||
216 | */ | ||
217 | leaq _end(%rip), %r8 | ||
218 | leaq _end(%rbx), %r9 | ||
219 | movq $_end /* - $startup_32 */, %rcx | ||
220 | 1: subq $8, %r8 | ||
221 | subq $8, %r9 | ||
222 | movq 0(%r8), %rax | ||
223 | movq %rax, 0(%r9) | ||
224 | subq $8, %rcx | ||
225 | jnz 1b | ||
226 | |||
227 | /* | ||
228 | * Jump to the relocated address. | ||
229 | */ | ||
230 | leaq relocated(%rbx), %rax | ||
231 | jmp *%rax | ||
232 | |||
233 | .section ".text" | ||
234 | relocated: | ||
235 | |||
57 | /* | 236 | /* |
58 | * Clear BSS | 237 | * Clear BSS |
59 | */ | 238 | */ |
60 | xorl %eax,%eax | 239 | xorq %rax, %rax |
61 | movl $_edata,%edi | 240 | leaq _edata(%rbx), %rdi |
62 | movl $_end,%ecx | 241 | leaq _end(%rbx), %rcx |
63 | subl %edi,%ecx | 242 | subq %rdi, %rcx |
64 | cld | 243 | cld |
65 | rep | 244 | rep |
66 | stosb | 245 | stosb |
246 | |||
247 | /* Setup the stack */ | ||
248 | leaq user_stack_end(%rip), %rsp | ||
249 | |||
250 | /* zero EFLAGS after setting rsp */ | ||
251 | pushq $0 | ||
252 | popfq | ||
253 | |||
67 | /* | 254 | /* |
68 | * Do the decompression, and jump to the new kernel.. | 255 | * Do the decompression, and jump to the new kernel.. |
69 | */ | 256 | */ |
70 | subl $16,%esp # place for structure on the stack | 257 | pushq %rsi # Save the real mode argument |
71 | movl %esp,%eax | 258 | movq %rsi, %rdi # real mode address |
72 | pushl %esi # real mode pointer as second arg | 259 | leaq _heap(%rip), %rsi # _heap |
73 | pushl %eax # address of structure as first arg | 260 | leaq input_data(%rip), %rdx # input_data |
74 | call decompress_kernel | 261 | movl input_len(%rip), %eax |
75 | orl %eax,%eax | 262 | movq %rax, %rcx # input_len |
76 | jnz 3f | 263 | movq %rbp, %r8 # output |
77 | addl $8,%esp | 264 | call decompress_kernel |
78 | xorl %ebx,%ebx | 265 | popq %rsi |
79 | ljmp $(__KERNEL_CS), $__PHYSICAL_START | ||
80 | 266 | ||
81 | /* | ||
82 | * We come here, if we were loaded high. | ||
83 | * We need to move the move-in-place routine down to 0x1000 | ||
84 | * and then start it with the buffer addresses in registers, | ||
85 | * which we got from the stack. | ||
86 | */ | ||
87 | 3: | ||
88 | movl %esi,%ebx | ||
89 | movl $move_routine_start,%esi | ||
90 | movl $0x1000,%edi | ||
91 | movl $move_routine_end,%ecx | ||
92 | subl %esi,%ecx | ||
93 | addl $3,%ecx | ||
94 | shrl $2,%ecx | ||
95 | cld | ||
96 | rep | ||
97 | movsl | ||
98 | |||
99 | popl %esi # discard the address | ||
100 | addl $4,%esp # real mode pointer | ||
101 | popl %esi # low_buffer_start | ||
102 | popl %ecx # lcount | ||
103 | popl %edx # high_buffer_start | ||
104 | popl %eax # hcount | ||
105 | movl $__PHYSICAL_START,%edi | ||
106 | cli # make sure we don't get interrupted | ||
107 | ljmp $(__KERNEL_CS), $0x1000 # and jump to the move routine | ||
108 | 267 | ||
109 | /* | 268 | /* |
110 | * Routine (template) for moving the decompressed kernel in place, | 269 | * Jump to the decompressed kernel. |
111 | * if we were high loaded. This _must_ PIC-code ! | ||
112 | */ | 270 | */ |
113 | move_routine_start: | 271 | jmp *%rbp |
114 | movl %ecx,%ebp | ||
115 | shrl $2,%ecx | ||
116 | rep | ||
117 | movsl | ||
118 | movl %ebp,%ecx | ||
119 | andl $3,%ecx | ||
120 | rep | ||
121 | movsb | ||
122 | movl %edx,%esi | ||
123 | movl %eax,%ecx # NOTE: rep movsb won't move if %ecx == 0 | ||
124 | addl $3,%ecx | ||
125 | shrl $2,%ecx | ||
126 | rep | ||
127 | movsl | ||
128 | movl %ebx,%esi # Restore setup pointer | ||
129 | xorl %ebx,%ebx | ||
130 | ljmp $(__KERNEL_CS), $__PHYSICAL_START | ||
131 | move_routine_end: | ||
132 | 272 | ||
133 | 273 | .data | |
134 | /* Stack for uncompression */ | 274 | gdt: |
135 | .align 32 | 275 | .word gdt_end - gdt |
136 | user_stack: | 276 | .long gdt |
277 | .word 0 | ||
278 | .quad 0x0000000000000000 /* NULL descriptor */ | ||
279 | .quad 0x00af9a000000ffff /* __KERNEL_CS */ | ||
280 | .quad 0x00cf92000000ffff /* __KERNEL_DS */ | ||
281 | gdt_end: | ||
282 | .bss | ||
283 | /* Stack for uncompression */ | ||
284 | .balign 4 | ||
285 | user_stack: | ||
137 | .fill 4096,4,0 | 286 | .fill 4096,4,0 |
138 | stack_start: | 287 | user_stack_end: |
139 | .long user_stack+4096 | ||
140 | .word __KERNEL_DS | ||
141 | |||
diff --git a/arch/x86_64/boot/compressed/misc.c b/arch/x86_64/boot/compressed/misc.c index 3755b2e394d0..fee54dbf1749 100644 --- a/arch/x86_64/boot/compressed/misc.c +++ b/arch/x86_64/boot/compressed/misc.c | |||
@@ -9,10 +9,95 @@ | |||
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 | #define _LINUX_STRING_H_ 1 | ||
13 | #define __LINUX_BITMAP_H 1 | ||
14 | |||
15 | #include <linux/linkage.h> | ||
12 | #include <linux/screen_info.h> | 16 | #include <linux/screen_info.h> |
13 | #include <asm/io.h> | 17 | #include <asm/io.h> |
14 | #include <asm/page.h> | 18 | #include <asm/page.h> |
15 | 19 | ||
20 | /* WARNING!! | ||
21 | * This code is compiled with -fPIC and it is relocated dynamically | ||
22 | * at run time, but no relocation processing is performed. | ||
23 | * This means that it is not safe to place pointers in static structures. | ||
24 | */ | ||
25 | |||
26 | /* | ||
27 | * Getting to provable safe in place decompression is hard. | ||
28 | * Worst case behaviours need to be analized. | ||
29 | * Background information: | ||
30 | * | ||
31 | * The file layout is: | ||
32 | * magic[2] | ||
33 | * method[1] | ||
34 | * flags[1] | ||
35 | * timestamp[4] | ||
36 | * extraflags[1] | ||
37 | * os[1] | ||
38 | * compressed data blocks[N] | ||
39 | * crc[4] orig_len[4] | ||
40 | * | ||
41 | * resulting in 18 bytes of non compressed data overhead. | ||
42 | * | ||
43 | * Files divided into blocks | ||
44 | * 1 bit (last block flag) | ||
45 | * 2 bits (block type) | ||
46 | * | ||
47 | * 1 block occurs every 32K -1 bytes or when there 50% compression has been achieved. | ||
48 | * The smallest block type encoding is always used. | ||
49 | * | ||
50 | * stored: | ||
51 | * 32 bits length in bytes. | ||
52 | * | ||
53 | * fixed: | ||
54 | * magic fixed tree. | ||
55 | * symbols. | ||
56 | * | ||
57 | * dynamic: | ||
58 | * dynamic tree encoding. | ||
59 | * symbols. | ||
60 | * | ||
61 | * | ||
62 | * The buffer for decompression in place is the length of the | ||
63 | * uncompressed data, plus a small amount extra to keep the algorithm safe. | ||
64 | * The compressed data is placed at the end of the buffer. The output | ||
65 | * pointer is placed at the start of the buffer and the input pointer | ||
66 | * is placed where the compressed data starts. Problems will occur | ||
67 | * when the output pointer overruns the input pointer. | ||
68 | * | ||
69 | * The output pointer can only overrun the input pointer if the input | ||
70 | * pointer is moving faster than the output pointer. A condition only | ||
71 | * triggered by data whose compressed form is larger than the uncompressed | ||
72 | * form. | ||
73 | * | ||
74 | * The worst case at the block level is a growth of the compressed data | ||
75 | * of 5 bytes per 32767 bytes. | ||
76 | * | ||
77 | * The worst case internal to a compressed block is very hard to figure. | ||
78 | * The worst case can at least be boundined by having one bit that represents | ||
79 | * 32764 bytes and then all of the rest of the bytes representing the very | ||
80 | * very last byte. | ||
81 | * | ||
82 | * All of which is enough to compute an amount of extra data that is required | ||
83 | * to be safe. To avoid problems at the block level allocating 5 extra bytes | ||
84 | * per 32767 bytes of data is sufficient. To avoind problems internal to a block | ||
85 | * adding an extra 32767 bytes (the worst case uncompressed block size) is | ||
86 | * sufficient, to ensure that in the worst case the decompressed data for | ||
87 | * block will stop the byte before the compressed data for a block begins. | ||
88 | * To avoid problems with the compressed data's meta information an extra 18 | ||
89 | * bytes are needed. Leading to the formula: | ||
90 | * | ||
91 | * extra_bytes = (uncompressed_size >> 12) + 32768 + 18 + decompressor_size. | ||
92 | * | ||
93 | * Adding 8 bytes per 32K is a bit excessive but much easier to calculate. | ||
94 | * Adding 32768 instead of 32767 just makes for round numbers. | ||
95 | * Adding the decompressor_size is necessary as it musht live after all | ||
96 | * of the data as well. Last I measured the decompressor is about 14K. | ||
97 | * 10K of actuall data and 4K of bss. | ||
98 | * | ||
99 | */ | ||
100 | |||
16 | /* | 101 | /* |
17 | * gzip declarations | 102 | * gzip declarations |
18 | */ | 103 | */ |
@@ -28,15 +113,20 @@ typedef unsigned char uch; | |||
28 | typedef unsigned short ush; | 113 | typedef unsigned short ush; |
29 | typedef unsigned long ulg; | 114 | typedef unsigned long ulg; |
30 | 115 | ||
31 | #define WSIZE 0x8000 /* Window size must be at least 32k, */ | 116 | #define WSIZE 0x80000000 /* Window size must be at least 32k, |
32 | /* and a power of two */ | 117 | * and a power of two |
118 | * We don't actually have a window just | ||
119 | * a huge output buffer so I report | ||
120 | * a 2G windows size, as that should | ||
121 | * always be larger than our output buffer. | ||
122 | */ | ||
33 | 123 | ||
34 | static uch *inbuf; /* input buffer */ | 124 | static uch *inbuf; /* input buffer */ |
35 | static uch window[WSIZE]; /* Sliding window buffer */ | 125 | static uch *window; /* Sliding window buffer, (and final output buffer) */ |
36 | 126 | ||
37 | static unsigned insize = 0; /* valid bytes in inbuf */ | 127 | static unsigned insize; /* valid bytes in inbuf */ |
38 | static unsigned inptr = 0; /* index of next byte to be processed in inbuf */ | 128 | static unsigned inptr; /* index of next byte to be processed in inbuf */ |
39 | static unsigned outcnt = 0; /* bytes in output buffer */ | 129 | static unsigned outcnt; /* bytes in output buffer */ |
40 | 130 | ||
41 | /* gzip flag byte */ | 131 | /* gzip flag byte */ |
42 | #define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ | 132 | #define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ |
@@ -87,8 +177,6 @@ extern unsigned char input_data[]; | |||
87 | extern int input_len; | 177 | extern int input_len; |
88 | 178 | ||
89 | static long bytes_out = 0; | 179 | static long bytes_out = 0; |
90 | static uch *output_data; | ||
91 | static unsigned long output_ptr = 0; | ||
92 | 180 | ||
93 | static void *malloc(int size); | 181 | static void *malloc(int size); |
94 | static void free(void *where); | 182 | static void free(void *where); |
@@ -98,17 +186,10 @@ static void *memcpy(void *dest, const void *src, unsigned n); | |||
98 | 186 | ||
99 | static void putstr(const char *); | 187 | static void putstr(const char *); |
100 | 188 | ||
101 | extern int end; | 189 | static long free_mem_ptr; |
102 | static long free_mem_ptr = (long)&end; | ||
103 | static long free_mem_end_ptr; | 190 | static long free_mem_end_ptr; |
104 | 191 | ||
105 | #define INPLACE_MOVE_ROUTINE 0x1000 | 192 | #define HEAP_SIZE 0x6000 |
106 | #define LOW_BUFFER_START 0x2000 | ||
107 | #define LOW_BUFFER_MAX 0x90000 | ||
108 | #define HEAP_SIZE 0x3000 | ||
109 | static unsigned int low_buffer_end, low_buffer_size; | ||
110 | static int high_loaded =0; | ||
111 | static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/; | ||
112 | 193 | ||
113 | static char *vidmem = (char *)0xb8000; | 194 | static char *vidmem = (char *)0xb8000; |
114 | static int vidport; | 195 | static int vidport; |
@@ -218,58 +299,31 @@ static void* memcpy(void* dest, const void* src, unsigned n) | |||
218 | */ | 299 | */ |
219 | static int fill_inbuf(void) | 300 | static int fill_inbuf(void) |
220 | { | 301 | { |
221 | if (insize != 0) { | 302 | error("ran out of input data"); |
222 | error("ran out of input data"); | 303 | return 0; |
223 | } | ||
224 | |||
225 | inbuf = input_data; | ||
226 | insize = input_len; | ||
227 | inptr = 1; | ||
228 | return inbuf[0]; | ||
229 | } | 304 | } |
230 | 305 | ||
231 | /* =========================================================================== | 306 | /* =========================================================================== |
232 | * Write the output window window[0..outcnt-1] and update crc and bytes_out. | 307 | * Write the output window window[0..outcnt-1] and update crc and bytes_out. |
233 | * (Used for the decompressed data only.) | 308 | * (Used for the decompressed data only.) |
234 | */ | 309 | */ |
235 | static void flush_window_low(void) | ||
236 | { | ||
237 | ulg c = crc; /* temporary variable */ | ||
238 | unsigned n; | ||
239 | uch *in, *out, ch; | ||
240 | |||
241 | in = window; | ||
242 | out = &output_data[output_ptr]; | ||
243 | for (n = 0; n < outcnt; n++) { | ||
244 | ch = *out++ = *in++; | ||
245 | c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); | ||
246 | } | ||
247 | crc = c; | ||
248 | bytes_out += (ulg)outcnt; | ||
249 | output_ptr += (ulg)outcnt; | ||
250 | outcnt = 0; | ||
251 | } | ||
252 | |||
253 | static void flush_window_high(void) | ||
254 | { | ||
255 | ulg c = crc; /* temporary variable */ | ||
256 | unsigned n; | ||
257 | uch *in, ch; | ||
258 | in = window; | ||
259 | for (n = 0; n < outcnt; n++) { | ||
260 | ch = *output_data++ = *in++; | ||
261 | if ((ulg)output_data == low_buffer_end) output_data=high_buffer_start; | ||
262 | c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); | ||
263 | } | ||
264 | crc = c; | ||
265 | bytes_out += (ulg)outcnt; | ||
266 | outcnt = 0; | ||
267 | } | ||
268 | |||
269 | static void flush_window(void) | 310 | static void flush_window(void) |
270 | { | 311 | { |
271 | if (high_loaded) flush_window_high(); | 312 | /* With my window equal to my output buffer |
272 | else flush_window_low(); | 313 | * I only need to compute the crc here. |
314 | */ | ||
315 | ulg c = crc; /* temporary variable */ | ||
316 | unsigned n; | ||
317 | uch *in, ch; | ||
318 | |||
319 | in = window; | ||
320 | for (n = 0; n < outcnt; n++) { | ||
321 | ch = *in++; | ||
322 | c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); | ||
323 | } | ||
324 | crc = c; | ||
325 | bytes_out += (ulg)outcnt; | ||
326 | outcnt = 0; | ||
273 | } | 327 | } |
274 | 328 | ||
275 | static void error(char *x) | 329 | static void error(char *x) |
@@ -281,57 +335,8 @@ static void error(char *x) | |||
281 | while(1); /* Halt */ | 335 | while(1); /* Halt */ |
282 | } | 336 | } |
283 | 337 | ||
284 | static void setup_normal_output_buffer(void) | 338 | asmlinkage void decompress_kernel(void *rmode, unsigned long heap, |
285 | { | 339 | uch *input_data, unsigned long input_len, uch *output) |
286 | #ifdef STANDARD_MEMORY_BIOS_CALL | ||
287 | if (RM_EXT_MEM_K < 1024) error("Less than 2MB of memory"); | ||
288 | #else | ||
289 | if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) < 1024) error("Less than 2MB of memory"); | ||
290 | #endif | ||
291 | output_data = (unsigned char *)__PHYSICAL_START; /* Normally Points to 1M */ | ||
292 | free_mem_end_ptr = (long)real_mode; | ||
293 | } | ||
294 | |||
295 | struct moveparams { | ||
296 | uch *low_buffer_start; int lcount; | ||
297 | uch *high_buffer_start; int hcount; | ||
298 | }; | ||
299 | |||
300 | static void setup_output_buffer_if_we_run_high(struct moveparams *mv) | ||
301 | { | ||
302 | high_buffer_start = (uch *)(((ulg)&end) + HEAP_SIZE); | ||
303 | #ifdef STANDARD_MEMORY_BIOS_CALL | ||
304 | if (RM_EXT_MEM_K < (3*1024)) error("Less than 4MB of memory"); | ||
305 | #else | ||
306 | if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) < (3*1024)) error("Less than 4MB of memory"); | ||
307 | #endif | ||
308 | mv->low_buffer_start = output_data = (unsigned char *)LOW_BUFFER_START; | ||
309 | low_buffer_end = ((unsigned int)real_mode > LOW_BUFFER_MAX | ||
310 | ? LOW_BUFFER_MAX : (unsigned int)real_mode) & ~0xfff; | ||
311 | low_buffer_size = low_buffer_end - LOW_BUFFER_START; | ||
312 | high_loaded = 1; | ||
313 | free_mem_end_ptr = (long)high_buffer_start; | ||
314 | if ( (__PHYSICAL_START + low_buffer_size) > ((ulg)high_buffer_start)) { | ||
315 | high_buffer_start = (uch *)(__PHYSICAL_START + low_buffer_size); | ||
316 | mv->hcount = 0; /* say: we need not to move high_buffer */ | ||
317 | } | ||
318 | else mv->hcount = -1; | ||
319 | mv->high_buffer_start = high_buffer_start; | ||
320 | } | ||
321 | |||
322 | static void close_output_buffer_if_we_run_high(struct moveparams *mv) | ||
323 | { | ||
324 | if (bytes_out > low_buffer_size) { | ||
325 | mv->lcount = low_buffer_size; | ||
326 | if (mv->hcount) | ||
327 | mv->hcount = bytes_out - low_buffer_size; | ||
328 | } else { | ||
329 | mv->lcount = bytes_out; | ||
330 | mv->hcount = 0; | ||
331 | } | ||
332 | } | ||
333 | |||
334 | int decompress_kernel(struct moveparams *mv, void *rmode) | ||
335 | { | 340 | { |
336 | real_mode = rmode; | 341 | real_mode = rmode; |
337 | 342 | ||
@@ -346,13 +351,21 @@ int decompress_kernel(struct moveparams *mv, void *rmode) | |||
346 | lines = RM_SCREEN_INFO.orig_video_lines; | 351 | lines = RM_SCREEN_INFO.orig_video_lines; |
347 | cols = RM_SCREEN_INFO.orig_video_cols; | 352 | cols = RM_SCREEN_INFO.orig_video_cols; |
348 | 353 | ||
349 | if (free_mem_ptr < 0x100000) setup_normal_output_buffer(); | 354 | window = output; /* Output buffer (Normally at 1M) */ |
350 | else setup_output_buffer_if_we_run_high(mv); | 355 | free_mem_ptr = heap; /* Heap */ |
356 | free_mem_end_ptr = heap + HEAP_SIZE; | ||
357 | inbuf = input_data; /* Input buffer */ | ||
358 | insize = input_len; | ||
359 | inptr = 0; | ||
360 | |||
361 | if ((ulg)output & 0x1fffffUL) | ||
362 | error("Destination address not 2M aligned"); | ||
363 | if ((ulg)output >= 0xffffffffffUL) | ||
364 | error("Destination address too large"); | ||
351 | 365 | ||
352 | makecrc(); | 366 | makecrc(); |
353 | putstr(".\nDecompressing Linux..."); | 367 | putstr(".\nDecompressing Linux..."); |
354 | gunzip(); | 368 | gunzip(); |
355 | putstr("done.\nBooting the kernel.\n"); | 369 | putstr("done.\nBooting the kernel.\n"); |
356 | if (high_loaded) close_output_buffer_if_we_run_high(mv); | 370 | return; |
357 | return high_loaded; | ||
358 | } | 371 | } |
diff --git a/arch/x86_64/boot/compressed/vmlinux.lds b/arch/x86_64/boot/compressed/vmlinux.lds new file mode 100644 index 000000000000..94c13e557fb4 --- /dev/null +++ b/arch/x86_64/boot/compressed/vmlinux.lds | |||
@@ -0,0 +1,44 @@ | |||
1 | OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") | ||
2 | OUTPUT_ARCH(i386:x86-64) | ||
3 | ENTRY(startup_64) | ||
4 | SECTIONS | ||
5 | { | ||
6 | /* Be careful parts of head.S assume startup_32 is at | ||
7 | * address 0. | ||
8 | */ | ||
9 | . = 0; | ||
10 | .text : { | ||
11 | _head = . ; | ||
12 | *(.text.head) | ||
13 | _ehead = . ; | ||
14 | *(.text.compressed) | ||
15 | _text = .; /* Text */ | ||
16 | *(.text) | ||
17 | *(.text.*) | ||
18 | _etext = . ; | ||
19 | } | ||
20 | .rodata : { | ||
21 | _rodata = . ; | ||
22 | *(.rodata) /* read-only data */ | ||
23 | *(.rodata.*) | ||
24 | _erodata = . ; | ||
25 | } | ||
26 | .data : { | ||
27 | _data = . ; | ||
28 | *(.data) | ||
29 | *(.data.*) | ||
30 | _edata = . ; | ||
31 | } | ||
32 | .bss : { | ||
33 | _bss = . ; | ||
34 | *(.bss) | ||
35 | *(.bss.*) | ||
36 | *(COMMON) | ||
37 | . = ALIGN(8); | ||
38 | _end = . ; | ||
39 | . = ALIGN(4096); | ||
40 | pgtable = . ; | ||
41 | . = . + 4096 * 6; | ||
42 | _heap = .; | ||
43 | } | ||
44 | } | ||
diff --git a/arch/x86_64/boot/compressed/vmlinux.scr b/arch/x86_64/boot/compressed/vmlinux.scr index 1ed9d791f863..bd1429ce193e 100644 --- a/arch/x86_64/boot/compressed/vmlinux.scr +++ b/arch/x86_64/boot/compressed/vmlinux.scr | |||
@@ -1,9 +1,10 @@ | |||
1 | SECTIONS | 1 | SECTIONS |
2 | { | 2 | { |
3 | .data : { | 3 | .text.compressed : { |
4 | input_len = .; | 4 | input_len = .; |
5 | LONG(input_data_end - input_data) input_data = .; | 5 | LONG(input_data_end - input_data) input_data = .; |
6 | *(.data) | 6 | *(.data) |
7 | input_data_end = .; | 7 | output_len = . - 4; |
8 | input_data_end = .; | ||
8 | } | 9 | } |
9 | } | 10 | } |