Initial commit: functional for newer bzImage kernels
[wraplinux.git] / reloc / reloc_init.S
1 /* ----------------------------------------------------------------------- *
2  *   
3  *   Copyright 2008 H. Peter Anvin - All Rights Reserved
4  *
5  *   Permission is hereby granted, free of charge, to any person
6  *   obtaining a copy of this software and associated documentation
7  *   files (the "Software"), to deal in the Software without
8  *   restriction, including without limitation the rights to use,
9  *   copy, modify, merge, publish, distribute, sublicense, and/or
10  *   sell copies of the Software, and to permit persons to whom
11  *   the Software is furnished to do so, subject to the following
12  *   conditions:
13  *   
14  *   The above copyright notice and this permission notice shall
15  *   be included in all copies or substantial portions of the Software.
16  *   
17  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19  *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21  *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22  *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24  *   OTHER DEALINGS IN THE SOFTWARE.
25  *
26  * ----------------------------------------------------------------------- */
27
28 /*
29  * Relocation stub start.  This needs to be position-independent code.
30  */
31
32 CS32    = 0x10
33 DS32    = 0x18
34 CS16    = 0x20
35 DS16    = 0x28
36         
37                 /* We will be entered in flat 32-bit protected mode... */
38                 .section ".start","ax",@progbits
39                 .globl  _start
40                 .code32
41 _start:
42                 popl    %edx            /* return address */
43                 pushl   %cs
44                 pushl   %edx
45                 pushfl
46                 pushl   %ds
47                 pushl   %es
48                 pushl   %fs
49                 pushl   %gs
50                 cli
51                 cld
52         
53                 calll   1f
54 1:              popl    %ebx            /* Figure out where we are */
55                 subl    $1b, %ebx       /* %ebx -> offset */
56
57                 movl    %esp, orig_esp(%ebx)
58                 movw    %ss, orig_ss(%ebx)
59
60                 sgdtl   orig_gdt(%ebx)  /* Save current GDT */
61                 sidtl   orig_idt(%ebx)  /* Save current IDT */
62
63                 addl    %ebx, my_gdt+2(%ebx)
64                 lidtl   rm_idt(%ebx)
65                 lgdtl   my_gdt(%ebx)
66
67                 /* Reinitialize segments */
68                 movw    $DS32,%dx
69                 movw    %dx,%ss
70                 leal    stack_end(%ebx),%esp
71                 movw    %dx,%ds
72                 movw    %dx,%es
73                 movw    %dx,%fs
74                 movw    %dx,%gs
75         
76                 leal    2f(%ebx),%edx
77                 pushl   $CS32
78                 pushl   %edx
79                 lretl
80 2:
81                 /* Adjust the real-mode segment bases */
82                 addl    %ebx,my_gdt+CS16+2(%ebx)
83                 addl    %ebx,my_gdt+DS16+2(%ebx)
84                 addl    %ebx,intcall_rm_ret_jmp+2(%ebx)
85
86                 /* Zero the .bss - stack must be empty here! */
87                 leal    __bss_start(%ebx), %edi
88                 leal    _end(%ebx), %ecx
89                 subl    %edi, %ecx
90                 shrl    $2, %ecx
91                 xorl    %eax, %eax
92                 rep; stosl
93
94                 calll   main
95
96                 /* If main() returns, try to return to the original
97                    protected-mode environment.  %eax is live here
98                    and contains the exit code. */
99
100                 .globl  _exit
101 _exit:  
102                 lidtl   orig_idt(%ebx)
103                 lgdtl   orig_gdt(%ebx)
104                 lssl    orig_esp(%ebx),%esp
105                 popl    %gs
106                 popl    %fs
107                 popl    %es
108                 popl    %ds
109                 popfl
110                 lretl
111
112                 /* Call a real-mode interrupt from 32-bit protected mode
113                  *
114                  * %eax -> interrupt number,
115                  * %edx -> input register image,
116                  * %ecx -> output register image
117                  *
118                  */
119                 .text
120                 .globl  intcall
121 intcall:        pushl   %ebx
122                 pushl   %esi
123                 pushl   %edi
124                 pushl   %ebp
125                 pushl   %ecx
126
127                 calll   1f
128 1:              popl    %ebx
129                 subl    $1b,%ebx
130
131                 movl    %edx,%esi
132                 leal    rm_stack_end-(44+12)(%ebx),%edi
133                 movl    $11,%ecx
134                 rep; movsl
135
136                 movl    (,%eax,4),%eax  /* cs:ip */
137                 stosl
138                 movw    $intcall_rm_return,(%edi)
139                 movl    %ebx,%eax
140                 shrl    $4,%eax         /* real mode segment */
141                 movw    %ax,2(%edi)
142                 movw    $2,4(%edi)      /* iret return flags */
143
144                 pushl   %ebx
145                 leal    intcall_pm_return(%ebx),%ecx
146                 movl    %esp,pm_stack(%ebx)
147
148                 movw    $DS16,%dx
149                 ljmpw   $CS16, $intcall_rm
150
151                 .section ".text16","ax",@progbits
152                 .code16
153 intcall_rm:
154                 movw    %dx,%ss
155                 movl    $rm_stack_end-(44+12),%esp
156                 movw    %dx,%ds
157                 movw    %dx,%es
158                 movw    %dx,%fs
159                 movw    %dx,%gs
160
161                 pushw   %ax             /* Real mode segment */
162                 pushw   $1f
163         
164                 movl    %cr0,%edx
165                 andb    $~1,%dl
166                 movl    %edx,%cr0
167                 lretw
168 1:
169                 movw    %ax,%ss
170                 popw    %gs
171                 popw    %fs
172                 popw    %es
173                 popw    %ds
174                 popal
175                 popfl
176                 lretw
177
178 intcall_rm_return:
179                 movw    $rm_stack_end,%sp
180                 pushfl
181                 pushal
182                 pushw   %ds
183                 pushw   %es
184                 pushw   %fs
185                 pushw   %gs
186                 cli
187                 cld
188                 movw    $DS32,%dx
189                 movl    %cs:pm_stack,%esp
190                 movl    %cr0,%eax
191                 orb     $1,%al
192                 movl    %eax,%cr0
193 intcall_rm_ret_jmp:
194                 .byte   0x66, 0xea      /* ljmpl */
195                 .long   intcall_pm_return
196                 .short  CS32
197
198                 .text
199                 .code32
200 intcall_pm_return:
201                 movw    %dx,%ss
202                 movw    %dx,%ds
203                 movw    %dx,%es
204                 movw    %dx,%fs
205                 movw    %dx,%gs
206         
207                 popl    %ebx
208                 popl    %edi
209                 andl    %edi,%edi
210                 jz      1f
211                 leal    rm_stack_end-44(%ebx),%esi
212                 movl    $11,%ecx
213                 rep; movsl
214 1:
215                 popl    %ebp
216                 popl    %edi
217                 popl    %esi
218                 popl    %ebx
219                 retl
220
221 /*
222  * Code to invoke the Linux kernel
223  *
224  * %eax: setup segment address
225  * %edx: kernel initial (e)sp
226  */
227                 .globl  jump_to_kernel
228 jump_to_kernel:
229                 calll   1f
230 1:              popl    %ebx
231                 subl    $1b,%ebx
232                 movw    $DS16, %si
233                 movw    %si,%ss
234                 movl    $rm_stack_end, %esp
235                 movw    %si,%ds
236                 movw    %si,%es
237                 movw    %si,%fs
238                 movw    %si,%gs
239                 shrl    $4,%ebx         /* %bx <- our real mode segment */
240                 ljmpw   $CS16, $jump_to_kernel_rm
241
242                 .section ".text16","ax",@progbits
243                 .code16
244 jump_to_kernel_rm:
245                 pushw   %bx
246                 pushw   $1f
247                 movl    %cr0,%ecx
248                 andb    $~1,%cl
249                 movl    %ecx,%cr0
250                 lretw
251 1:
252                 movw    %ax,%ss
253                 movl    %edx,%esp
254                 movw    %ax,%ds
255                 movw    %ax,%es
256                 movw    %ax,%fs
257                 movw    %ax,%gs
258                 addw    $0x20,%ax
259                 pushw   %ax
260                 pushw   $0
261                 lretw
262         
263
264                 .section ".rodata","a",@progbits
265                 .code32
266                 .balign 4
267 rm_idt:         .short  256*4-1
268                 .long   0
269                 .short  0
270         
271                 .section ".data","aw",@progbits
272                 /* Not really initialized, but can't be in .bss */
273 orig_esp:       .long   0
274 orig_ss:        .short  0       /* Must follow orig_esp */
275 orig_gdt:       .short  0, 0, 0
276 orig_idt:       .short  0, 0, 0
277
278                 .balign 16
279 my_gdt:         .short  my_gdt_end-my_gdt-1
280                 .long   my_gdt
281                 .short  0
282         /* Unused */
283                 .long   0, 0
284         
285         /* CS32 */
286                 .long   0x0000ffff
287                 .long   0x00cf9b00
288         /* DS32 */
289                 .long   0x0000ffff
290                 .long   0x00cf9300
291         /* CS16 */
292                 .long   0x0000ffff
293                 .long   0x00009b00
294         /* DS16 */
295                 .long   0x0000ffff
296                 .long   0x00009300
297 my_gdt_end:
298         
299                 .section ".bss","aw",@nobits
300                 .balign 4
301 pm_stack:       .space 4
302 kernel_entry:   .space 4
303 rm_stack:       .space  1024
304 rm_stack_end:
305 stack:          .space  1024
306 stack_end: