diff options
Diffstat (limited to 'arch/i386/boot/compressed/head.S')
-rw-r--r-- | arch/i386/boot/compressed/head.S | 185 |
1 files changed, 118 insertions, 67 deletions
diff --git a/arch/i386/boot/compressed/head.S b/arch/i386/boot/compressed/head.S index b5893e4ecd37..f395a4bb38bb 100644 --- a/arch/i386/boot/compressed/head.S +++ b/arch/i386/boot/compressed/head.S | |||
@@ -26,9 +26,11 @@ | |||
26 | #include <linux/linkage.h> | 26 | #include <linux/linkage.h> |
27 | #include <asm/segment.h> | 27 | #include <asm/segment.h> |
28 | #include <asm/page.h> | 28 | #include <asm/page.h> |
29 | #include <asm/boot.h> | ||
29 | 30 | ||
31 | .section ".text.head" | ||
30 | .globl startup_32 | 32 | .globl startup_32 |
31 | 33 | ||
32 | startup_32: | 34 | startup_32: |
33 | cld | 35 | cld |
34 | cli | 36 | cli |
@@ -37,93 +39,142 @@ startup_32: | |||
37 | movl %eax,%es | 39 | movl %eax,%es |
38 | movl %eax,%fs | 40 | movl %eax,%fs |
39 | movl %eax,%gs | 41 | movl %eax,%gs |
42 | movl %eax,%ss | ||
40 | 43 | ||
41 | lss stack_start,%esp | 44 | /* Calculate the delta between where we were compiled to run |
42 | xorl %eax,%eax | 45 | * at and where we were actually loaded at. This can only be done |
43 | 1: incl %eax # check that A20 really IS enabled | 46 | * with a short local call on x86. Nothing else will tell us what |
44 | movl %eax,0x000000 # loop forever if it isn't | 47 | * address we are running at. The reserved chunk of the real-mode |
45 | cmpl %eax,0x100000 | 48 | * data at 0x34-0x3f are used as the stack for this calculation. |
46 | je 1b | 49 | * Only 4 bytes are needed. |
50 | */ | ||
51 | leal 0x40(%esi), %esp | ||
52 | call 1f | ||
53 | 1: popl %ebp | ||
54 | subl $1b, %ebp | ||
55 | |||
56 | /* %ebp contains the address we are loaded at by the boot loader and %ebx | ||
57 | * contains the address where we should move the kernel image temporarily | ||
58 | * for safe in-place decompression. | ||
59 | */ | ||
60 | |||
61 | #ifdef CONFIG_RELOCATABLE | ||
62 | movl %ebp, %ebx | ||
63 | addl $(CONFIG_PHYSICAL_ALIGN - 1), %ebx | ||
64 | andl $(~(CONFIG_PHYSICAL_ALIGN - 1)), %ebx | ||
65 | #else | ||
66 | movl $LOAD_PHYSICAL_ADDR, %ebx | ||
67 | #endif | ||
68 | |||
69 | /* Replace the compressed data size with the uncompressed size */ | ||
70 | subl input_len(%ebp), %ebx | ||
71 | movl output_len(%ebp), %eax | ||
72 | addl %eax, %ebx | ||
73 | /* Add 8 bytes for every 32K input block */ | ||
74 | shrl $12, %eax | ||
75 | addl %eax, %ebx | ||
76 | /* Add 32K + 18 bytes of extra slack */ | ||
77 | addl $(32768 + 18), %ebx | ||
78 | /* Align on a 4K boundary */ | ||
79 | addl $4095, %ebx | ||
80 | andl $~4095, %ebx | ||
81 | |||
82 | /* Copy the compressed kernel to the end of our buffer | ||
83 | * where decompression in place becomes safe. | ||
84 | */ | ||
85 | pushl %esi | ||
86 | leal _end(%ebp), %esi | ||
87 | leal _end(%ebx), %edi | ||
88 | movl $(_end - startup_32), %ecx | ||
89 | std | ||
90 | rep | ||
91 | movsb | ||
92 | cld | ||
93 | popl %esi | ||
94 | |||
95 | /* Compute the kernel start address. | ||
96 | */ | ||
97 | #ifdef CONFIG_RELOCATABLE | ||
98 | addl $(CONFIG_PHYSICAL_ALIGN - 1), %ebp | ||
99 | andl $(~(CONFIG_PHYSICAL_ALIGN - 1)), %ebp | ||
100 | #else | ||
101 | movl $LOAD_PHYSICAL_ADDR, %ebp | ||
102 | #endif | ||
47 | 103 | ||
48 | /* | 104 | /* |
49 | * Initialize eflags. Some BIOS's leave bits like NT set. This would | 105 | * Jump to the relocated address. |
50 | * confuse the debugger if this code is traced. | ||
51 | * XXX - best to initialize before switching to protected mode. | ||
52 | */ | 106 | */ |
53 | pushl $0 | 107 | leal relocated(%ebx), %eax |
54 | popfl | 108 | jmp *%eax |
109 | .section ".text" | ||
110 | relocated: | ||
111 | |||
55 | /* | 112 | /* |
56 | * Clear BSS | 113 | * Clear BSS |
57 | */ | 114 | */ |
58 | xorl %eax,%eax | 115 | xorl %eax,%eax |
59 | movl $_edata,%edi | 116 | leal _edata(%ebx),%edi |
60 | movl $_end,%ecx | 117 | leal _end(%ebx), %ecx |
61 | subl %edi,%ecx | 118 | subl %edi,%ecx |
62 | cld | 119 | cld |
63 | rep | 120 | rep |
64 | stosb | 121 | stosb |
122 | |||
123 | /* | ||
124 | * Setup the stack for the decompressor | ||
125 | */ | ||
126 | leal stack_end(%ebx), %esp | ||
127 | |||
65 | /* | 128 | /* |
66 | * Do the decompression, and jump to the new kernel.. | 129 | * Do the decompression, and jump to the new kernel.. |
67 | */ | 130 | */ |
68 | subl $16,%esp # place for structure on the stack | 131 | movl output_len(%ebx), %eax |
69 | movl %esp,%eax | 132 | pushl %eax |
133 | pushl %ebp # output address | ||
134 | movl input_len(%ebx), %eax | ||
135 | pushl %eax # input_len | ||
136 | leal input_data(%ebx), %eax | ||
137 | pushl %eax # input_data | ||
138 | leal _end(%ebx), %eax | ||
139 | pushl %eax # end of the image as third argument | ||
70 | pushl %esi # real mode pointer as second arg | 140 | pushl %esi # real mode pointer as second arg |
71 | pushl %eax # address of structure as first arg | ||
72 | call decompress_kernel | 141 | call decompress_kernel |
73 | orl %eax,%eax | 142 | addl $20, %esp |
74 | jnz 3f | 143 | popl %ecx |
75 | popl %esi # discard address | ||
76 | popl %esi # real mode pointer | ||
77 | xorl %ebx,%ebx | ||
78 | ljmp $(__BOOT_CS), $__PHYSICAL_START | ||
79 | 144 | ||
145 | #if CONFIG_RELOCATABLE | ||
146 | /* Find the address of the relocations. | ||
147 | */ | ||
148 | movl %ebp, %edi | ||
149 | addl %ecx, %edi | ||
150 | |||
151 | /* Calculate the delta between where vmlinux was compiled to run | ||
152 | * and where it was actually loaded. | ||
153 | */ | ||
154 | movl %ebp, %ebx | ||
155 | subl $LOAD_PHYSICAL_ADDR, %ebx | ||
156 | jz 2f /* Nothing to be done if loaded at compiled addr. */ | ||
80 | /* | 157 | /* |
81 | * We come here, if we were loaded high. | 158 | * Process relocations. |
82 | * We need to move the move-in-place routine down to 0x1000 | ||
83 | * and then start it with the buffer addresses in registers, | ||
84 | * which we got from the stack. | ||
85 | */ | 159 | */ |
86 | 3: | 160 | |
87 | movl $move_routine_start,%esi | 161 | 1: subl $4, %edi |
88 | movl $0x1000,%edi | 162 | movl 0(%edi), %ecx |
89 | movl $move_routine_end,%ecx | 163 | testl %ecx, %ecx |
90 | subl %esi,%ecx | 164 | jz 2f |
91 | addl $3,%ecx | 165 | addl %ebx, -__PAGE_OFFSET(%ebx, %ecx) |
92 | shrl $2,%ecx | 166 | jmp 1b |
93 | cld | 167 | 2: |
94 | rep | 168 | #endif |
95 | movsl | ||
96 | |||
97 | popl %esi # discard the address | ||
98 | popl %ebx # real mode pointer | ||
99 | popl %esi # low_buffer_start | ||
100 | popl %ecx # lcount | ||
101 | popl %edx # high_buffer_start | ||
102 | popl %eax # hcount | ||
103 | movl $__PHYSICAL_START,%edi | ||
104 | cli # make sure we don't get interrupted | ||
105 | ljmp $(__BOOT_CS), $0x1000 # and jump to the move routine | ||
106 | 169 | ||
107 | /* | 170 | /* |
108 | * Routine (template) for moving the decompressed kernel in place, | 171 | * Jump to the decompressed kernel. |
109 | * if we were high loaded. This _must_ PIC-code ! | ||
110 | */ | 172 | */ |
111 | move_routine_start: | ||
112 | movl %ecx,%ebp | ||
113 | shrl $2,%ecx | ||
114 | rep | ||
115 | movsl | ||
116 | movl %ebp,%ecx | ||
117 | andl $3,%ecx | ||
118 | rep | ||
119 | movsb | ||
120 | movl %edx,%esi | ||
121 | movl %eax,%ecx # NOTE: rep movsb won't move if %ecx == 0 | ||
122 | addl $3,%ecx | ||
123 | shrl $2,%ecx | ||
124 | rep | ||
125 | movsl | ||
126 | movl %ebx,%esi # Restore setup pointer | ||
127 | xorl %ebx,%ebx | 173 | xorl %ebx,%ebx |
128 | ljmp $(__BOOT_CS), $__PHYSICAL_START | 174 | jmp *%ebp |
129 | move_routine_end: | 175 | |
176 | .bss | ||
177 | .balign 4 | ||
178 | stack: | ||
179 | .fill 4096, 1, 0 | ||
180 | stack_end: | ||