2006-01-07 Roland McGrath <roland@redhat.com>
[glibc-ports.git] / sysdeps / standalone / i386 / start.S
blobb3fd315e5a89916a4d00d8fb02ef4c150d4eb20a
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.
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.
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.)
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.
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.
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.  */
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  */
47         .data
48         .global  _Do_Load_IDT
49         .global  _Do_Load_GDT
51         .text
52               .global  start                  # GNU default entry point
53         .global  _establish_stack
55         .global   _bsp_start
56         .global   _load_segments
57         .global   __exit
59 start:
60         nop
61         cli                             # DISABLE INTERRUPTS!!!
63 #  Load the segment registers
65 #  NOTE: Upon return, gs will contain the segment descriptor for
66 #        a segment which maps directly to all of physical memory.
68         jmp     _load_segments          # load board dependent segments
71 #  Set up the stack
74 _establish_stack:
76         movl    $stack_end,%esp         # set stack pointer
77         movl    $stack_end,%ebp         # set base pointer
80 #  Zero out the BSS segment
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
93 #  Set the C heap information for malloc
95         movl    $heap_size,___C_heap_size    # set ___C_heap_size
96         movl    $heap_memory,___C_heap_start # set ___C_heap_start
99 #  Copy the Global Descriptor Table to our space
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
106         # make ds:esi point to the original GDT
108         movl    _Original_GDTR_base,%esi
109         push    %ds                     # save ds
110         movw    %gs,%ax
111         movw    %ax,%ds
113         # make es:edi point to the new (our copy) GDT
114         movl    $_Global_descriptor_table,%edi
116         rep
117         movsb                            # copy the GDT (ds:esi -> es:edi)
119         pop     %ds                      # restore ds
121         # Build and load new contents of GDTR
122         movw    _Original_GDTR_limit,%ecx # set new limit
123         movw    %cx,_New_GDTR_limit
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
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:
137 #  Copy the Interrupt Descriptor Table to our space
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
145         # make ds:esi point to the original IDT
146         movl    _Original_IDTR_base,%esi
148         push    %ds                     # save ds
149         movw    %gs,%ax
150         movw    %ax,%ds
152         # make es:edi point to the new (our copy) IDT
153         movl    $_Interrupt_descriptor_table,%edi
155         rep
156         movsb                            # copy the IDT (ds:esi -> es:edi)
157         pop     %ds                      # restore ds
159         # Build and load new contents of IDTR
160         movw    _Original_IDTR_limit,%ecx # set new limit
161         movw    %cx,_New_IDTR_limit
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
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:
175 #  Initialize the i387.
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.
182         fninit                           # MUST USE NO-WAIT FORM
184         call    __Board_Initialize       # initialize the board
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
193         pushl   $0                       # argc = NULL
194         call    __exit                   # call the Board specific exit
195         addl     $4,%esp
198 #  Clean up
202         .global  _Bsp_cleanup
204         .global   _return_to_monitor
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:
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
219 #  void *Logical_to_physical(
220 #     rtems_unsigned16  segment,
221 #     void             *address
222 #  );
224 #  Returns thirty-two bit physical address for segment:address.
227         .global  _Logical_to_physical
229 .set SEGMENT_ARG, 4
230 .set ADDRESS_ARG, 8
232 _Logical_to_physical:
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
248 #  void *Physical_to_logical(
249 #     rtems_unsigned16  segment,
250 #     void             *address
251 #  );
253 #  Returns thirty-two bit physical address for segment:address.
256         .global  _Physical_to_logical
258 #.set SEGMENT_ARG, 4
259 #.set ADDRESS_ARG, 8   -- use sets from above
261 _Physical_to_logical:
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
278  *  Data Declarations.  Start with a macro which helps declare space.
279  */
281         .bss
283 #define DECLARE_SPACE(_name,_space,_align) \
284           .globl   _name ; \
285           .align   _align ; \
286 _name##:  .space _space
288 #define DECLARE_LABEL(_name) \
289           .globl   _name ; \
290 _name##:
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)
297  *  Require environment stuff
298  */
300 DECLARE_LABEL(_environ)
301 DECLARE_PTR(environ)
303 DECLARE_LABEL(_errno)
304 DECLARE_U32(errno)
307  *  Miscellaneous Variables used to restore the CPU state.
309  *  Start with a macro to declare the space for the contents of
310  *  a Descriptor Table register.
311  */
313 #define DECLARE_DTR_SPACE(_name) \
314           .global   _name ; \
315           .align    4 ; \
316 _name##:  ; \
317 _name##_limit:  .space 2  ; \
318 _name##_base:   .space 4
320 DECLARE_SPACE(_Interrupt_descriptor_table,256*8,4)
321 DECLARE_SPACE(_Global_descriptor_table,8192*8,4)
323 DECLARE_DTR_SPACE(_Original_IDTR)
324 DECLARE_DTR_SPACE(_New_IDTR)
325 DECLARE_DTR_SPACE(_Original_GDTR)
326 DECLARE_DTR_SPACE(_New_GDTR)
328 DECLARE_SPACE(_Physical_base_of_ds,4,4)
329 DECLARE_SPACE(_Physical_base_of_cs,4,4)
332  *  Stack Size and Space
333  */
335         .set stack_size, 0x20000
337 DECLARE_SPACE(stack_memory,stack_size,4)
338 DECLARE_LABEL(stack_end)