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