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
15 .space CONFIG_STACK_SIZE
17 .set _stack_size, _estack - _stack
19 .section ".text._start", "ax", @progbits
33 ljmp $RAM_CODE_SEG, $1f
35 1: movl $RAM_DATA_SEG, %eax
39 xor %eax, %eax /* zero out the gs and fs segment index */
41 movl %eax, %gs /* Will be used for cpu_info */
43 mov $RAM_CODE_SEG64, %ecx
47 post_code(POSTCODE_ENTRY_C_START) /* post 13 */
53 movabs %rax, _cbmem_top_ptr
56 /* The return argument is at 0(%esp), the calling argument at 4(%esp) */
58 movl %eax, _cbmem_top_ptr
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
70 shr $3, %rcx /* it is 64 bit aligned, right? */
71 movq $0xDEADBEEFDEADBEEF, %rax
75 /* Set new stack with enforced alignment. */
77 movq $(0xfffffffffffffff0), %rax
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
87 shrl $2, %ecx /* it is 32 bit aligned, right? */
88 movl $0xDEADBEEF, %eax
92 /* Set new stack with enforced alignment. */
94 andl $(0xfffffff0), %esp
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.
102 post_code(POSTCODE_PRE_HARDWAREMAIN) /* post 6e */
105 movq $0xFFFFFFFFFFFFFFF0, %rax
108 andl $0xFFFFFFF0, %esp
111 #if CONFIG(ASAN_IN_RAMSTAGE)
117 call gdb_stub_breakpoint
122 post_code(POSTCODE_DEAD_CODE) /* post ee */
128 .globl gdb_stub_breakpoint
131 pop %rax /* Return address */
135 push %rax /* Return address */
136 push $0 /* No error code */
137 push $32 /* vector 32 is user defined */
139 popl %eax /* Return address */
142 pushl %eax /* Return address */
143 pushl $0 /* No error code */
144 pushl $32 /* vector 32 is user defined */
150 .global per_cpu_segment_descriptors, per_cpu_segment_selector
153 .word gdt_end - gdt - 1
157 .long gdt /* we know the offset */
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
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.
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.
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 */
185 .byte 0x00, 0x9b, 0xcf, 0x00 /* G=1 and 0x0f, So we get 4Gbytes for
189 /* selgdt 0x18, flat data segment */
192 .byte 0x00, 0x92, 0xcf, 0x00
194 .byte 0x00, 0x93, 0xcf, 0x00
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 */
207 /* selgdt 0x30 16 bit 64k data at 0x00000000 */
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
219 /* selgdt 0x40, flat code segment 16 bit */
221 .byte 0x00, 0x9b, 0x8f, 0x00 /* G=1 and 0x0f, So we get 4Gbytes for
226 /* selgdt 0x48, flat x64 code segment */
228 .byte 0x00, 0x9b, 0xaf, 0x00
230 per_cpu_segment_descriptors:
231 .rept CONFIG_MAX_CPUS
232 /* flat data segment */
235 .byte 0x00, 0x92, 0xcf, 0x00
237 .byte 0x00, 0x93, 0xcf, 0x00
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
249 # save rsp because iret will align it to a 16 byte boundary
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,
259 push %rcx # cx is code segment selector from caller
260 movabs $setCodeSelectorLongJump, %rax
263 # the iret will continue at next instruction, with the new cs value
267 setCodeSelectorLongJump:
268 # restore rsp, it might not have been 16-byte aligned on entry