chiark / gitweb /
eglibc (2.11.3-4+deb6u3) squeeze-lts; urgency=medium
[eglibc.git] / ports / sysdeps / standalone / i386 / start.S
1 /* Copyright (C) 1994, 1997 Free Software Foundation, Inc.
2    Contributed by Joel Sherrill (jsherril@redstone-emh2.army.mil),
3      On-Line Applications Research Corporation.
4    This file is part of the GNU C Library.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    In addition to the permissions in the GNU Lesser General Public
12    License, the Free Software Foundation gives you unlimited
13    permission to link the compiled version of this file with other
14    programs, and to distribute those programs without any restriction
15    coming from the use of this file. (The GNU Lesser General Public
16    License restrictions do apply in other respects; for example, they
17    cover modification of the file, and distribution when not linked
18    into another program.)
19
20    Note that people who make modified versions of this file are not
21    obligated to grant this special exception for their modified
22    versions; it is their choice whether to do so. The GNU Lesser
23    General Public License gives permission to release a modified
24    version without this exception; this exception also makes it
25    possible to release a modified version which carries forward this
26    exception.
27
28    The GNU C Library is distributed in the hope that it will be useful,
29    but WITHOUT ANY WARRANTY; without even the implied warranty of
30    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
31    Lesser General Public License for more details.
32
33    You should have received a copy of the GNU Lesser General Public
34    License along with the GNU C Library; if not, write to the Free
35    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
36    02111-1307 USA.  */
37
38 /*  entry.s
39  *
40  *  This file contains the entry point for the application.
41  *  The name of this entry point is compiler dependent.
42  *  It jumps to the BSP which is responsible for performing
43  *  all initialization.
44  *
45  */
46
47         .data
48         .global  _Do_Load_IDT
49         .global  _Do_Load_GDT
50
51         .text
52               .global  start                  # GNU default entry point
53         .global  _establish_stack
54
55         .global   _bsp_start
56         .global   _load_segments
57         .global   __exit
58
59 start:
60         nop
61         cli                             # DISABLE INTERRUPTS!!!
62 #
63 #  Load the segment registers
64 #
65 #  NOTE: Upon return, gs will contain the segment descriptor for
66 #        a segment which maps directly to all of physical memory.
67 #
68         jmp     _load_segments          # load board dependent segments
69
70 #
71 #  Set up the stack
72 #
73
74 _establish_stack:
75
76         movl    $stack_end,%esp         # set stack pointer
77         movl    $stack_end,%ebp         # set base pointer
78
79 #
80 #  Zero out the BSS segment
81 #
82 zero_bss:
83         cld                             # make direction flag count up
84         movl    $_end,%ecx              # find end of .bss
85         movl    $_bss_start,%edi        # edi = beginning of .bss
86         subl    %edi,%ecx               # ecx = size of .bss in bytes
87         shrl    $2,%ecx                 # size of .bss in longs
88         xorl    %eax,%eax               # value to clear out memory
89         repne                           # while ecx != 0
90         stosl                           #   clear a long in the bss
91
92 #
93 #  Set the C heap information for malloc
94 #
95         movl    $heap_size,___C_heap_size    # set ___C_heap_size
96         movl    $heap_memory,___C_heap_start # set ___C_heap_start
97
98 #
99 #  Copy the Global Descriptor Table to our space
100 #
101
102         sgdt    _Original_GDTR          # save original GDT
103         movzwl  _Original_GDTR_limit,%ecx # size of GDT in bytes; limit
104                                           #   is 8192 entries * 8 bytes per
105
106         # make ds:esi point to the original GDT
107
108         movl    _Original_GDTR_base,%esi
109         push    %ds                     # save ds
110         movw    %gs,%ax
111         movw    %ax,%ds
112
113         # make es:edi point to the new (our copy) GDT
114         movl    $_Global_descriptor_table,%edi
115
116         rep
117         movsb                            # copy the GDT (ds:esi -> es:edi)
118
119         pop     %ds                      # restore ds
120
121         # Build and load new contents of GDTR
122         movw    _Original_GDTR_limit,%ecx # set new limit
123         movw    %cx,_New_GDTR_limit
124
125         push    $_Global_descriptor_table
126         push    %es
127         call    _Logical_to_physical
128         addl    $6,%esp
129         movl    %eax,_New_GDTR_base      # set new base
130
131         cmpb    $0,_Do_Load_GDT          # Should the new GDT be loaded?
132         je      no_gdt_load              # NO, then branch
133         lgdt    _New_GDTR                # load the new GDT
134 no_gdt_load:
135
136 #
137 #  Copy the Interrupt Descriptor Table to our space
138 #
139
140         sidt    _Original_IDTR          # save original IDT
141         movzwl  _Original_IDTR_limit,%ecx # size of IDT in bytes; limit
142                                           #   is 256 entries * 8 bytes per
143
144
145         # make ds:esi point to the original IDT
146         movl    _Original_IDTR_base,%esi
147
148         push    %ds                     # save ds
149         movw    %gs,%ax
150         movw    %ax,%ds
151
152         # make es:edi point to the new (our copy) IDT
153         movl    $_Interrupt_descriptor_table,%edi
154
155         rep
156         movsb                            # copy the IDT (ds:esi -> es:edi)
157         pop     %ds                      # restore ds
158
159         # Build and load new contents of IDTR
160         movw    _Original_IDTR_limit,%ecx # set new limit
161         movw    %cx,_New_IDTR_limit
162
163         push    $_Interrupt_descriptor_table
164         push    %es
165         call    _Logical_to_physical
166         addl    $6,%esp
167         movl    %eax,_New_IDTR_base      # set new base
168
169         cmpb    $0,_Do_Load_IDT          # Should the new IDT be loaded?
170         je      no_idt_load              # NO, then branch
171         lidt    _New_IDTR                # load the new IDT
172 no_idt_load:
173
174 #
175 #  Initialize the i387.
176 #
177 #  Using the NO WAIT form of the instruction insures that if
178 #  it is not present the board will not lock up or get an
179 #  exception.
180 #
181
182         fninit                           # MUST USE NO-WAIT FORM
183
184         call    __Board_Initialize       # initialize the board
185
186         pushl   $0                       # envp = NULL
187         pushl   $0                       # argv = NULL
188         pushl   $0                       # argc = NULL
189         call    ___libc_init             # initialize the library and
190                                          #   call main
191         addl    $12,%esp
192
193         pushl   $0                       # argc = NULL
194         call    __exit                   # call the Board specific exit
195         addl     $4,%esp
196
197 #
198 #  Clean up
199 #
200
201
202         .global  _Bsp_cleanup
203
204         .global   _return_to_monitor
205
206 _Bsp_cleanup:
207         cmpb    $0,_Do_Load_IDT          # Was the new IDT loaded?
208         je      no_idt_restore           # NO, then branch
209         lidt    _Original_IDTR           # restore the new IDT
210 no_idt_restore:
211
212         cmpb    $0,_Do_Load_GDT          # Was the new GDT loaded?
213         je      no_gdt_restore           # NO, then branch
214         lgdt    _Original_GDTR           # restore the new GDT
215 no_gdt_restore:
216         jmp     _return_to_monitor
217
218 #
219 #  void *Logical_to_physical(
220 #     rtems_unsigned16  segment,
221 #     void             *address
222 #  );
223 #
224 #  Returns thirty-two bit physical address for segment:address.
225 #
226
227         .global  _Logical_to_physical
228
229 .set SEGMENT_ARG, 4
230 .set ADDRESS_ARG, 8
231
232 _Logical_to_physical:
233
234         xorl    %eax,%eax                # clear eax
235         movzwl  SEGMENT_ARG(%esp),%ecx   # ecx = segment value
236         movl    $_Global_descriptor_table,%edx # edx = address of our GDT
237         addl    %ecx,%edx                # edx = address of desired entry
238         movb    7(%edx),%ah              # ah = base 31:24
239         movb    4(%edx),%al              # al = base 23:16
240         shll    $16,%eax                 # move ax into correct bits
241         movw    2(%edx),%ax              # ax = base 0:15
242         movl    ADDRESS_ARG(%esp),%ecx   # ecx = address to convert
243         addl    %eax,%ecx                # ecx = physical address equivalent
244         movl    %ecx,%eax                # eax = ecx
245         ret
246
247 #
248 #  void *Physical_to_logical(
249 #     rtems_unsigned16  segment,
250 #     void             *address
251 #  );
252 #
253 #  Returns thirty-two bit physical address for segment:address.
254 #
255
256         .global  _Physical_to_logical
257
258 #.set SEGMENT_ARG, 4
259 #.set ADDRESS_ARG, 8   -- use sets from above
260
261 _Physical_to_logical:
262
263         xorl    %eax,%eax                # clear eax
264         movzwl  SEGMENT_ARG(%esp),%ecx   # ecx = segment value
265         movl    $_Global_descriptor_table,%edx # edx = address of our GDT
266         addl    %ecx,%edx                # edx = address of desired entry
267         movb    7(%edx),%ah              # ah = base 31:24
268         movb    4(%edx),%al              # al = base 23:16
269         shll    $16,%eax                 # move ax into correct bits
270         movw    2(%edx),%ax              # ax = base 0:15
271         movl    ADDRESS_ARG(%esp),%ecx   # ecx = address to convert
272         subl    %eax,%ecx                # ecx = logical address equivalent
273         movl    %ecx,%eax                # eax = ecx
274         ret
275
276
277 /*
278  *  Data Declarations.  Start with a macro which helps declare space.
279  */
280
281         .bss
282
283 #define DECLARE_SPACE(_name,_space,_align) \
284           .globl   _name ; \
285           .align   _align ; \
286 _name##:  .space _space
287
288 #define DECLARE_LABEL(_name) \
289           .globl   _name ; \
290 _name##:
291
292 #define DECLARE_PTR(_name) DECLARE_SPACE(_name,4,2)
293 #define DECLARE_U32(_name) DECLARE_SPACE(_name,4,2)
294 #define DECLARE_U16(_name) DECLARE_SPACE(_name,2,1)
295
296 /*
297  *  Require environment stuff
298  */
299
300 DECLARE_LABEL(_environ)
301 DECLARE_PTR(environ)
302
303 DECLARE_LABEL(_errno)
304 DECLARE_U32(errno)
305
306 /*
307  *  Miscellaneous Variables used to restore the CPU state.
308  *
309  *  Start with a macro to declare the space for the contents of
310  *  a Descriptor Table register.
311  */
312
313 #define DECLARE_DTR_SPACE(_name) \
314           .global   _name ; \
315           .align    4 ; \
316 _name##:  ; \
317 _name##_limit:  .space 2  ; \
318 _name##_base:   .space 4
319
320 DECLARE_SPACE(_Interrupt_descriptor_table,256*8,4)
321 DECLARE_SPACE(_Global_descriptor_table,8192*8,4)
322
323 DECLARE_DTR_SPACE(_Original_IDTR)
324 DECLARE_DTR_SPACE(_New_IDTR)
325 DECLARE_DTR_SPACE(_Original_GDTR)
326 DECLARE_DTR_SPACE(_New_GDTR)
327
328 DECLARE_SPACE(_Physical_base_of_ds,4,4)
329 DECLARE_SPACE(_Physical_base_of_cs,4,4)
330
331 /*
332  *  Stack Size and Space
333  */
334
335         .set stack_size, 0x20000
336
337 DECLARE_SPACE(stack_memory,stack_size,4)
338 DECLARE_LABEL(stack_end)