drivers/wifi: Remove unnecessary data structure copy
[coreboot2.git] / src / arch / x86 / c_start.S
blob94b9bd9fa50925fd6b02b6970b438ecfb775023e
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <cpu/x86/post_code.h>
4 #include <arch/ram_segs.h>
6 /* Place the stack in the bss section. It's not necessary to define it in
7  * the linker script. */
8         .section .bss, "aw", @nobits
9 .global _stack
10 .global _estack
11 .global _stack_size
13 .align 16
14 _stack:
15 .space CONFIG_STACK_SIZE
16 _estack:
17 .set _stack_size, _estack - _stack
19         .section ".text._start", "ax", @progbits
20 #if ENV_X86_64
21         .code64
22 #else
23         .code32
24 #endif
25         .globl _start
26 _start:
27         cli
28 #if ENV_X86_64
29         movabs  $gdtaddr, %rax
30         lgdt    (%rax)
31 #else
32         lgdt    %cs:gdtaddr
33         ljmp    $RAM_CODE_SEG, $1f
34 #endif
35 1:      movl    $RAM_DATA_SEG, %eax
36         movl    %eax, %ds
37         movl    %eax, %es
38         movl    %eax, %ss
39         xor     %eax, %eax /* zero out the gs and fs segment index */
40         movl    %eax, %fs
41         movl    %eax, %gs /* Will be used for cpu_info */
42 #if ENV_X86_64
43         mov     $RAM_CODE_SEG64, %ecx
44         call    SetCodeSelector
45 #endif
47         post_code(POSTCODE_ENTRY_C_START)               /* post 13 */
49         cld
51 #if ENV_X86_64
52         mov     %rdi, %rax
53         movabs  %rax, _cbmem_top_ptr
54         movabs  $_stack, %rdi
55 #else
56         /* The return argument is at 0(%esp), the calling argument at 4(%esp) */
57         movl    4(%esp), %eax
58         movl    %eax, _cbmem_top_ptr
59         leal    _stack, %edi
60 #endif
62 #if ENV_X86_64
63         /** poison the stack. Code should not count on the
64          * stack being full of zeros. This stack poisoning
65          * recently uncovered a bug in the broadcast SIPI
66          * code.
67          */
68         movabs  $_estack, %rcx
69         sub     %rdi, %rcx
70         shr     $3, %rcx   /* it is 64 bit aligned, right? */
71         movq    $0xDEADBEEFDEADBEEF, %rax
72         rep
73         stosq
75         /* Set new stack with enforced alignment. */
76         movabs  $_estack, %rsp
77         movq    $(0xfffffffffffffff0), %rax
78         and     %rax, %rsp
79 #else
80         /** poison the stack. Code should not count on the
81          * stack being full of zeros. This stack poisoning
82          * recently uncovered a bug in the broadcast SIPI
83          * code.
84          */
85         movl    $_estack, %ecx
86         subl    %edi, %ecx
87         shrl    $2, %ecx   /* it is 32 bit aligned, right? */
88         movl    $0xDEADBEEF, %eax
89         rep
90         stosl
92         /* Set new stack with enforced alignment. */
93         movl    $_estack, %esp
94         andl    $(0xfffffff0), %esp
95 #endif
97         /*
98          *      Now we are finished. Memory is up, data is copied and
99          *      bss is cleared.   Now we call the main routine and
100          *      let it do the rest.
101          */
102         post_code(POSTCODE_PRE_HARDWAREMAIN)    /* post 6e */
104 #if ENV_X86_64
105         movq    $0xFFFFFFFFFFFFFFF0, %rax
106         and     %rax, %rsp
107 #else
108         andl    $0xFFFFFFF0, %esp
109 #endif
111 #if CONFIG(ASAN_IN_RAMSTAGE)
112         call asan_init
113 #endif
115 #if CONFIG(GDB_WAIT)
116         call gdb_hw_init
117         call gdb_stub_breakpoint
118 #endif
119         call    main
120         /* NOTREACHED */
121 .Lhlt:
122         post_code(POSTCODE_DEAD_CODE)   /* post ee */
123         hlt
124         jmp     .Lhlt
126 #if CONFIG(GDB_WAIT)
128         .globl gdb_stub_breakpoint
129 gdb_stub_breakpoint:
130 #if ENV_X86_64
131         pop     %rax    /* Return address */
132         pushfq
133         mov     %cs, %rbx
134         push    %rbx
135         push    %rax    /* Return address */
136         push    $0      /* No error code */
137         push    $32     /* vector 32 is user defined */
138 #else
139         popl    %eax    /* Return address */
140         pushfl
141         pushl   %cs
142         pushl   %eax    /* Return address */
143         pushl   $0      /* No error code */
144         pushl   $32     /* vector 32 is user defined */
145 #endif
146         jmp     int_hand
147 #endif
149         .globl gdt, gdt_end
150         .global per_cpu_segment_descriptors, per_cpu_segment_selector
152 gdtaddr:
153         .word   gdt_end - gdt - 1
154 #if ENV_X86_64
155         .quad   gdt
156 #else
157         .long   gdt             /* we know the offset */
158 #endif
160         .data
162         /* This is the gdt for GCC part of coreboot.
163          * It is different from the gdt in ASM part of coreboot
164          * which is defined in gdt_init.S
165          *
166          * When the machine is initially started, we use a very simple
167          * gdt from ROM (that in gdt_init.S) which only contains those
168          * entries we need for protected mode.
169          *
170          * When we're executing code from RAM, we want to do more complex
171          * stuff, like initializing PCI option ROMs in real mode, or doing
172          * a resume from a suspend to RAM.
173          */
174 gdt:
175         /* selgdt 0, unused */
176         .word   0x0000, 0x0000          /* dummy */
177         .byte   0x00, 0x00, 0x00, 0x00
179         /* selgdt 8, unused */
180         .word   0x0000, 0x0000          /* dummy */
181         .byte   0x00, 0x00, 0x00, 0x00
183         /* selgdt 0x10, flat code segment */
184         .word   0xffff, 0x0000
185         .byte   0x00, 0x9b, 0xcf, 0x00 /* G=1 and 0x0f, So we get 4Gbytes for
186                                         * limit
187                                         */
189         /* selgdt 0x18, flat data segment */
190         .word   0xffff, 0x0000
191 #if ENV_X86_64
192         .byte   0x00, 0x92, 0xcf, 0x00
193 #else
194         .byte   0x00, 0x93, 0xcf, 0x00
195 #endif
197         /* selgdt 0x20, unused */
198         .word   0x0000, 0x0000          /* dummy */
199         .byte   0x00, 0x00, 0x00, 0x00
201         /* The next two entries are used for executing VGA option ROMs */
203         /* selgdt 0x28 16 bit 64k code at 0x00000000 */
204         .word   0xffff, 0x0000
205         .byte   0, 0x9a, 0, 0
207         /* selgdt 0x30 16 bit 64k data at 0x00000000 */
208         .word   0xffff, 0x0000
209         .byte   0, 0x92, 0, 0
211         /* The next two entries are used for ACPI S3 RESUME */
213         /* selgdt 0x38, flat data segment 16 bit */
214         .word   0x0000, 0x0000          /* dummy */
215         .byte   0x00, 0x93, 0x8f, 0x00 /* G=1 and 0x0f, So we get 4Gbytes for
216                                         * limit
217                                         */
219         /* selgdt 0x40, flat code segment 16 bit */
220         .word   0xffff, 0x0000
221         .byte   0x00, 0x9b, 0x8f, 0x00 /* G=1 and 0x0f, So we get 4Gbytes for
222                                         * limit
223                                         */
225 #if ENV_X86_64
226         /* selgdt 0x48, flat x64 code segment */
227         .word   0xffff, 0x0000
228         .byte   0x00, 0x9b, 0xaf, 0x00
229 #endif
230 per_cpu_segment_descriptors:
231         .rept CONFIG_MAX_CPUS
232         /* flat data segment */
233         .word   0xffff, 0x0000
234 #if ENV_X86_64
235         .byte   0x00, 0x92, 0xcf, 0x00
236 #else
237         .byte   0x00, 0x93, 0xcf, 0x00
238 #endif
239         .endr
240 gdt_end:
242 /* Segment selector pointing to the first per_cpu_segment_descriptor. */
243 per_cpu_segment_selector:
244         .long   per_cpu_segment_descriptors - gdt
246         .section ".text._start", "ax", @progbits
247 #if ENV_X86_64
248 SetCodeSelector:
249         # save rsp because iret will align it to a 16 byte boundary
250         mov     %rsp, %rdx
252         # use iret to jump to a 64-bit offset in a new code segment
253         # iret will pop cs:rip, flags, then ss:rsp
254         mov     %ss, %ax        # need to push ss..
255         push    %rax            # push ss instruction not valid in x64 mode,
256                                 # so use ax
257         push    %rsp
258         pushfq
259         push    %rcx            # cx is code segment selector from caller
260         movabs  $setCodeSelectorLongJump, %rax
261         push    %rax
263         # the iret will continue at next instruction, with the new cs value
264         # loaded
265         iretq
267 setCodeSelectorLongJump:
268         # restore rsp, it might not have been 16-byte aligned on entry
269         mov     %rdx, %rsp
270         ret
271 #endif