coreboot-kgpe-d16/src/arch/x86/c_start.S

431 lines
8.2 KiB
ArmAsm

/*
* This file is part of the coreboot project.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <cpu/x86/post_code.h>
/* Place the stack in the bss section. It's not necessary to define it in the
* the linker script. */
.section .bss, "aw", @nobits
.global _stack
.global _estack
.align CONFIG_STACK_SIZE
_stack:
.space CONFIG_MAX_CPUS*CONFIG_STACK_SIZE
_estack:
#if CONFIG_COOP_MULTITASKING
.global thread_stacks
thread_stacks:
.space CONFIG_STACK_SIZE*CONFIG_NUM_THREADS
#endif
.section ".text._start", "ax", @progbits
#ifdef __x86_64__
.code64
#else
.code32
#endif
.globl _start
_start:
cli
lgdt %cs:gdtaddr
#ifndef __x86_64__
ljmp $0x10, $1f
#endif
1: movl $0x18, %eax
movl %eax, %ds
movl %eax, %es
movl %eax, %ss
movl %eax, %fs
movl %eax, %gs
#ifdef __x86_64__
mov $0x48, %ecx
call SetCodeSelector
#endif
post_code(POST_ENTRY_C_START) /* post 13 */
cld
/** poison the stack. Code should not count on the
* stack being full of zeros. This stack poisoning
* recently uncovered a bug in the broadcast SIPI
* code.
*/
leal _stack, %edi
movl $_estack, %ecx
subl %edi, %ecx
shrl $2, %ecx /* it is 32 bit aligned, right? */
movl $0xDEADBEEF, %eax
rep
stosl
/* set new stack */
movl $_estack, %esp
#if CONFIG_COOP_MULTITASKING
/* Push the thread pointer. */
push $0
#endif
/* Push the CPU index and struct CPU */
push $0
push $0
/* Initialize the Interrupt Descriptor table */
leal _idt, %edi
leal vec0, %ebx
movl $(0x10 << 16), %eax /* cs selector */
1: movw %bx, %ax
movl %ebx, %edx
movw $0x8E00, %dx /* Interrupt gate - dpl=0, present */
movl %eax, 0(%edi)
movl %edx, 4(%edi)
addl $6, %ebx
addl $8, %edi
cmpl $_idt_end, %edi
jne 1b
/* Load the Interrupt descriptor table */
#ifndef __x86_64__
lidt idtarg
#else
// FIXME port table to x64 - lidt idtarg
#endif
/*
* Now we are finished. Memory is up, data is copied and
* bss is cleared. Now we call the main routine and
* let it do the rest.
*/
post_code(POST_PRE_HARDWAREMAIN) /* post fe */
#if CONFIG_GDB_WAIT
call gdb_hw_init
call gdb_stub_breakpoint
#endif
call main
/* NOTREACHED */
.Lhlt:
post_code(POST_DEAD_CODE) /* post ee */
hlt
jmp .Lhlt
vec0:
push $0 /* error code */
push $0 /* vector */
jmp int_hand
vec1:
push $0 /* error code */
push $1 /* vector */
jmp int_hand
vec2:
push $0 /* error code */
push $2 /* vector */
jmp int_hand
vec3:
push $0 /* error code */
push $3 /* vector */
jmp int_hand
vec4:
push $0 /* error code */
push $4 /* vector */
jmp int_hand
vec5:
push $0 /* error code */
push $5 /* vector */
jmp int_hand
vec6:
push $0 /* error code */
push $6 /* vector */
jmp int_hand
vec7:
push $0 /* error code */
push $7 /* vector */
jmp int_hand
vec8:
/* error code */
push $8 /* vector */
jmp int_hand
.word 0x9090
vec9:
push $0 /* error code */
push $9 /* vector */
jmp int_hand
vec10:
/* error code */
push $10 /* vector */
jmp int_hand
.word 0x9090
vec11:
/* error code */
push $11 /* vector */
jmp int_hand
.word 0x9090
vec12:
/* error code */
push $12 /* vector */
jmp int_hand
.word 0x9090
vec13:
/* error code */
push $13 /* vector */
jmp int_hand
.word 0x9090
vec14:
/* error code */
push $14 /* vector */
jmp int_hand
.word 0x9090
vec15:
push $0 /* error code */
push $15 /* vector */
jmp int_hand
vec16:
push $0 /* error code */
push $16 /* vector */
jmp int_hand
vec17:
/* error code */
push $17 /* vector */
jmp int_hand
.word 0x9090
vec18:
push $0 /* error code */
push $18 /* vector */
jmp int_hand
vec19:
push $0 /* error code */
push $19 /* vector */
jmp int_hand
int_hand:
/* At this point, on x86-32, on the stack there is:
* 0(%esp) vector
* 4(%esp) error code
* 8(%esp) eip
* 12(%esp) cs
* 16(%esp) eflags
*/
#ifdef __x86_64__
push %rdi
push %rsi
push %rbp
/* Original stack pointer */
lea 32(%rsp), %rbp
push %rbp
push %rbx
push %rdx
push %rcx
push %rax
push %rsp /* Pointer to structure on the stack */
call x86_exception
pop %rax /* Drop the pointer */
pop %rax
pop %rcx
pop %rdx
pop %rbx
pop %rbp /* Ignore saved %rsp value */
pop %rbp
pop %rsi
pop %rdi
add $8, %rsp /* pop of the vector and error code */
#else
pushl %edi
pushl %esi
pushl %ebp
/* Original stack pointer */
leal 32(%esp), %ebp
pushl %ebp
pushl %ebx
pushl %edx
pushl %ecx
pushl %eax
pushl %esp /* Pointer to structure on the stack */
call x86_exception
pop %eax /* Drop the pointer */
popl %eax
popl %ecx
popl %edx
popl %ebx
popl %ebp /* Ignore saved %esp value */
popl %ebp
popl %esi
popl %edi
addl $8, %esp /* pop of the vector and error code */
#endif
iret
#if CONFIG_GDB_WAIT
.globl gdb_stub_breakpoint
gdb_stub_breakpoint:
#ifdef __x86_64__
pop %rax /* Return address */
pushfl
push %cs
push %rax /* Return address */
push $0 /* No error code */
push $32 /* vector 32 is user defined */
#else
popl %eax /* Return address */
pushfl
pushl %cs
pushl %eax /* Return address */
pushl $0 /* No error code */
pushl $32 /* vector 32 is user defined */
#endif
jmp int_hand
#endif
.globl gdt, gdt_end, idtarg
gdtaddr:
.word gdt_end - gdt - 1
#ifdef __x86_64__
.quad gdt
#else
.long gdt /* we know the offset */
#endif
.data
/* This is the gdt for GCC part of coreboot.
* It is different from the gdt in ROMCC/ASM part of coreboot
* which is defined in entry32.inc
*
* When the machine is initially started, we use a very simple
* gdt from ROM (that in entry32.inc) which only contains those
* entries we need for protected mode.
*
* When we're executing code from RAM, we want to do more complex
* stuff, like initializing PCI option ROMs in real mode, or doing
* a resume from a suspend to RAM.
*/
gdt:
/* selgdt 0, unused */
.word 0x0000, 0x0000 /* dummy */
.byte 0x00, 0x00, 0x00, 0x00
/* selgdt 8, unused */
.word 0x0000, 0x0000 /* dummy */
.byte 0x00, 0x00, 0x00, 0x00
/* selgdt 0x10, flat code segment */
.word 0xffff, 0x0000
.byte 0x00, 0x9b, 0xcf, 0x00 /* G=1 and 0x0f, So we get 4Gbytes for limit */
/* selgdt 0x18, flat data segment */
.word 0xffff, 0x0000
#ifdef __x86_64__
.byte 0x00, 0x92, 0xcf, 0x00
#else
.byte 0x00, 0x93, 0xcf, 0x00
#endif
/* selgdt 0x20, unused */
.word 0x0000, 0x0000 /* dummy */
.byte 0x00, 0x00, 0x00, 0x00
/* The next two entries are used for executing VGA option ROMs */
/* selgdt 0x28 16 bit 64k code at 0x00000000 */
.word 0xffff, 0x0000
.byte 0, 0x9a, 0, 0
/* selgdt 0x30 16 bit 64k data at 0x00000000 */
.word 0xffff, 0x0000
.byte 0, 0x92, 0, 0
/* The next two entries are used for ACPI S3 RESUME */
/* selgdt 0x38, flat data segment 16 bit */
.word 0x0000, 0x0000 /* dummy */
.byte 0x00, 0x93, 0x8f, 0x00 /* G=1 and 0x0f, So we get 4Gbytes for limit */
/* selgdt 0x40, flat code segment 16 bit */
.word 0xffff, 0x0000
.byte 0x00, 0x9b, 0x8f, 0x00 /* G=1 and 0x0f, So we get 4Gbytes for limit */
#ifdef __x86_64__
/* selgdt 0x48, flat x64 code segment */
.word 0xffff, 0x0000
.byte 0x00, 0x9b, 0xaf, 0x00
#endif
gdt_end:
idtarg:
.word _idt_end - _idt - 1 /* limit */
.long _idt
.word 0
_idt:
.fill 20, 8, 0 # idt is uninitialized
_idt_end:
.section ".text._start", "ax", @progbits
#ifdef __x86_64__
SetCodeSelector:
# save rsp because iret will align it to a 16 byte boundary
mov %rsp, %rdx
# use iret to jump to a 64-bit offset in a new code segment
# iret will pop cs:rip, flags, then ss:rsp
mov %ss, %ax # need to push ss..
push %rax # push ss instuction not valid in x64 mode, so use ax
push %rsp
pushfq
push %rcx # cx is code segment selector from caller
mov $setCodeSelectorLongJump, %rax
push %rax
# the iret will continue at next instruction, with the new cs value loaded
iretq
setCodeSelectorLongJump:
# restore rsp, it might not have been 16-byte aligned on entry
mov %rdx, %rsp
ret
.previous
.code64
#else
.previous
.code32
#endif