[PATCH] i386: Relocatable kernel support
[linux-2.6.22.y-op.git] / arch / i386 / boot / compressed / head.S
blobe4dd7a6b9b0ff8318f47ace4b6f862bc466256ed
1 /*
2  *  linux/boot/head.S
3  *
4  *  Copyright (C) 1991, 1992, 1993  Linus Torvalds
5  */
7 /*
8  *  head.S contains the 32-bit startup code.
9  *
10  * NOTE!!! Startup happens at absolute address 0x00001000, which is also where
11  * the page directory will exist. The startup code will be overwritten by
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]
14  *
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
17  * useful for future device drivers that either access the BIOS via VM86 
18  * mode.
19  */
22  * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
23  */
24 .text
26 #include <linux/linkage.h>
27 #include <asm/segment.h>
28 #include <asm/page.h>
30 .section ".text.head"
31         .globl startup_32
33 startup_32:
34         cld
35         cli
36         movl $(__BOOT_DS),%eax
37         movl %eax,%ds
38         movl %eax,%es
39         movl %eax,%fs
40         movl %eax,%gs
41         movl %eax,%ss
43 /* Calculate the delta between where we were compiled to run
44  * at and where we were actually loaded at.  This can only be done
45  * with a short local call on x86.  Nothing  else will tell us what
46  * address we are running at.  The reserved chunk of the real-mode
47  * data at 0x34-0x3f are used as the stack for this calculation.
48  * Only 4 bytes are needed.
49  */
50         leal 0x40(%esi), %esp
51         call 1f
52 1:      popl %ebp
53         subl $1b, %ebp
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
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
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
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
103  * Jump to the relocated address.
104  */
105         leal relocated(%ebx), %eax
106         jmp *%eax
107 .section ".text"
108 relocated:
111  * Clear BSS
112  */
113         xorl %eax,%eax
114         leal _edata(%ebx),%edi
115         leal _end(%ebx), %ecx
116         subl %edi,%ecx
117         cld
118         rep
119         stosb
122  * Setup the stack for the decompressor
123  */
124         leal stack_end(%ebx), %esp
127  * Do the decompression, and jump to the new kernel..
128  */
129         movl output_len(%ebx), %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
138         pushl %esi      # real mode pointer as second arg
139         call decompress_kernel
140         addl $20, %esp
141         popl %ecx
143 #if CONFIG_RELOCATABLE
144 /* Find the address of the relocations.
145  */
146         movl %ebp, %edi
147         addl %ecx, %edi
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
156  * Process relocations.
157  */
159 1:      subl $4, %edi
160         movl 0(%edi), %ecx
161         testl %ecx, %ecx
162         jz 2f
163         addl %ebx, -__PAGE_OFFSET(%ebx, %ecx)
164         jmp 1b
166 #endif
169  * Jump to the decompressed kernel.
170  */
171         xorl %ebx,%ebx
172         jmp *%ebp
174 .bss
175 .balign 4
176 stack:
177         .fill 4096, 1, 0
178 stack_end: