mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 11:07:45 +00:00
Kernel: Merge the x86 and x86_64 boot code into a single file
They're mostly the same apart from some x86_64-specific parts.
This commit is contained in:
parent
ce6658acc1
commit
040fe0054b
6 changed files with 414 additions and 600 deletions
|
@ -74,18 +74,19 @@
|
||||||
# define PAGE_SIZE sysconf(_SC_PAGESIZE)
|
# define PAGE_SIZE sysconf(_SC_PAGESIZE)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef _BOOTLOADER
|
||||||
ALWAYS_INLINE int count_trailing_zeroes_32(unsigned int val)
|
ALWAYS_INLINE int count_trailing_zeroes_32(unsigned int val)
|
||||||
{
|
{
|
||||||
#if defined(__GNUC__) || defined(__clang__)
|
# if defined(__GNUC__) || defined(__clang__)
|
||||||
return __builtin_ctz(val);
|
return __builtin_ctz(val);
|
||||||
#else
|
# else
|
||||||
for (u8 i = 0; i < 32; ++i) {
|
for (u8 i = 0; i < 32; ++i) {
|
||||||
if ((val >> i) & 1) {
|
if ((val >> i) & 1) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE int count_trailing_zeroes_32_safe(unsigned int val)
|
ALWAYS_INLINE int count_trailing_zeroes_32_safe(unsigned int val)
|
||||||
|
@ -94,6 +95,7 @@ ALWAYS_INLINE int count_trailing_zeroes_32_safe(unsigned int val)
|
||||||
return 32;
|
return 32;
|
||||||
return count_trailing_zeroes_32(val);
|
return count_trailing_zeroes_32(val);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef AK_OS_BSD_GENERIC
|
#ifdef AK_OS_BSD_GENERIC
|
||||||
# define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC
|
# define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#define _BOOTLOADER
|
||||||
|
#include <AK/Platform.h>
|
||||||
|
|
||||||
.code32
|
.code32
|
||||||
.set KERNEL_VIRTUAL_BASE, 0xc0000000
|
.set KERNEL_VIRTUAL_BASE, 0xc0000000
|
||||||
|
|
||||||
|
@ -12,9 +15,11 @@ kernel_cmdline:
|
||||||
|
|
||||||
.section .page_tables, "aw", @nobits
|
.section .page_tables, "aw", @nobits
|
||||||
.align 4096
|
.align 4096
|
||||||
|
#if ARCH(X86_64)
|
||||||
.global boot_pml4t
|
.global boot_pml4t
|
||||||
boot_pml4t:
|
boot_pml4t:
|
||||||
.skip 4096
|
.skip 4096
|
||||||
|
#endif
|
||||||
.global boot_pdpt
|
.global boot_pdpt
|
||||||
boot_pdpt:
|
boot_pdpt:
|
||||||
.skip 4096
|
.skip 4096
|
||||||
|
@ -47,6 +52,7 @@ boot_pd3_pt1023:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
construct the following (64-bit PML4T) page table layout:
|
construct the following (64-bit PML4T) page table layout:
|
||||||
|
(the PML4T part is not used for 32-bit x86)
|
||||||
|
|
||||||
pml4t:
|
pml4t:
|
||||||
|
|
||||||
|
@ -89,20 +95,25 @@ the 9 page tables each contain 512 pte's that map individual 4KB pages
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#if ARCH(X86_64)
|
||||||
gdt64:
|
gdt64:
|
||||||
.quad 0
|
.quad 0
|
||||||
gdt64code:
|
gdt64code:
|
||||||
.quad (1<<43) | (1<<44) | (1<<47) | (1<<53) /* executable, code segment, present, 64-bit */
|
.quad (1<<43) | (1<<44) | (1<<47) | (1<<53) /* executable, code segment, present, 64-bit */
|
||||||
|
.global gdt64ptr
|
||||||
gdt64ptr:
|
gdt64ptr:
|
||||||
.short . - gdt64 - 1
|
.short . - gdt64 - 1
|
||||||
.quad gdt64
|
.quad gdt64
|
||||||
|
|
||||||
|
.global code64_sel
|
||||||
.set code64_sel, gdt64code - gdt64
|
.set code64_sel, gdt64code - gdt64
|
||||||
|
#endif
|
||||||
|
|
||||||
start:
|
start:
|
||||||
cli
|
cli
|
||||||
cld
|
cld
|
||||||
|
|
||||||
|
#if ARCH(X86_64)
|
||||||
/* test for long mode presence, save the most important registers from corruption */
|
/* test for long mode presence, save the most important registers from corruption */
|
||||||
pushl %eax
|
pushl %eax
|
||||||
pushl %edx
|
pushl %edx
|
||||||
|
@ -119,6 +130,7 @@ continue:
|
||||||
popl %ebx
|
popl %ebx
|
||||||
popl %edx
|
popl %edx
|
||||||
popl %eax
|
popl %eax
|
||||||
|
#endif
|
||||||
|
|
||||||
/* We don't know where the bootloader might have put the command line.
|
/* We don't know where the bootloader might have put the command line.
|
||||||
* It might be at an inconvenient location that we're not about to map,
|
* It might be at an inconvenient location that we're not about to map,
|
||||||
|
@ -133,6 +145,7 @@ continue:
|
||||||
movl $(kernel_cmdline - KERNEL_VIRTUAL_BASE), %edi
|
movl $(kernel_cmdline - KERNEL_VIRTUAL_BASE), %edi
|
||||||
rep movsl
|
rep movsl
|
||||||
|
|
||||||
|
#if ARCH(X86_64)
|
||||||
/* clear pml4t */
|
/* clear pml4t */
|
||||||
movl $(boot_pml4t - KERNEL_VIRTUAL_BASE), %edi
|
movl $(boot_pml4t - KERNEL_VIRTUAL_BASE), %edi
|
||||||
movl $1024, %ecx
|
movl $1024, %ecx
|
||||||
|
@ -144,6 +157,7 @@ continue:
|
||||||
movl $(boot_pdpt - KERNEL_VIRTUAL_BASE), 0(%edi)
|
movl $(boot_pdpt - KERNEL_VIRTUAL_BASE), 0(%edi)
|
||||||
/* R/W + Present */
|
/* R/W + Present */
|
||||||
orl $0x3, 0(%edi)
|
orl $0x3, 0(%edi)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* clear pdpt */
|
/* clear pdpt */
|
||||||
movl $(boot_pdpt - KERNEL_VIRTUAL_BASE), %edi
|
movl $(boot_pdpt - KERNEL_VIRTUAL_BASE), %edi
|
||||||
|
@ -153,8 +167,13 @@ continue:
|
||||||
|
|
||||||
/* set up pdpt[0] and pdpt[3] */
|
/* set up pdpt[0] and pdpt[3] */
|
||||||
movl $(boot_pdpt - KERNEL_VIRTUAL_BASE), %edi
|
movl $(boot_pdpt - KERNEL_VIRTUAL_BASE), %edi
|
||||||
|
#if ARCH(X86_64)
|
||||||
movl $((boot_pd0 - KERNEL_VIRTUAL_BASE) + 3), 0(%edi)
|
movl $((boot_pd0 - KERNEL_VIRTUAL_BASE) + 3), 0(%edi)
|
||||||
movl $((boot_pd3 - KERNEL_VIRTUAL_BASE) + 3), 24(%edi)
|
movl $((boot_pd3 - KERNEL_VIRTUAL_BASE) + 3), 24(%edi)
|
||||||
|
#else
|
||||||
|
movl $((boot_pd0 - KERNEL_VIRTUAL_BASE) + 1), 0(%edi)
|
||||||
|
movl $((boot_pd3 - KERNEL_VIRTUAL_BASE) + 1), 24(%edi)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* clear pd0 */
|
/* clear pd0 */
|
||||||
movl $(boot_pd0 - KERNEL_VIRTUAL_BASE), %edi
|
movl $(boot_pd0 - KERNEL_VIRTUAL_BASE), %edi
|
||||||
|
@ -232,8 +251,14 @@ continue:
|
||||||
orl $0x3, 4088(%edi)
|
orl $0x3, 4088(%edi)
|
||||||
movl $0, 4092(%edi)
|
movl $0, 4092(%edi)
|
||||||
|
|
||||||
|
#if ARCH(X86_64)
|
||||||
/* point CR3 to PML4T */
|
/* point CR3 to PML4T */
|
||||||
movl $(boot_pml4t - KERNEL_VIRTUAL_BASE), %eax
|
movl $(boot_pml4t - KERNEL_VIRTUAL_BASE), %eax
|
||||||
|
#else
|
||||||
|
/* point CR3 to PDPT */
|
||||||
|
movl $(boot_pdpt - KERNEL_VIRTUAL_BASE), %eax
|
||||||
|
#endif
|
||||||
|
|
||||||
movl %eax, %cr3
|
movl %eax, %cr3
|
||||||
|
|
||||||
/* enable PAE + PSE */
|
/* enable PAE + PSE */
|
||||||
|
@ -241,18 +266,19 @@ continue:
|
||||||
orl $0x60, %eax
|
orl $0x60, %eax
|
||||||
movl %eax, %cr4
|
movl %eax, %cr4
|
||||||
|
|
||||||
|
#if ARCH(X86_64)
|
||||||
1:
|
1:
|
||||||
/* Enter Long-mode! ref(https://wiki.osdev.org/Setting_Up_Long_Mode)*/
|
/* Enter Long-mode! ref(https://wiki.osdev.org/Setting_Up_Long_Mode)*/
|
||||||
mov $0xC0000080, %ecx /* Set the C-register to 0xC0000080, which is the EFER MSR.*/
|
mov $0xC0000080, %ecx /* Set the C-register to 0xC0000080, which is the EFER MSR.*/
|
||||||
rdmsr /* Read from the model-specific register.*/
|
rdmsr /* Read from the model-specific register.*/
|
||||||
or $(1 << 8), %eax /* Set the LM-bit which is the 9th bit (bit 8).*/
|
or $(1 << 8), %eax /* Set the LM-bit which is the 9th bit (bit 8).*/
|
||||||
wrmsr /* Write to the model-specific register.*/
|
wrmsr /* Write to the model-specific register.*/
|
||||||
|
#endif
|
||||||
|
|
||||||
/* enable PG */
|
/* enable PG */
|
||||||
movl %cr0, %eax
|
movl %cr0, %eax
|
||||||
orl $0x80000000, %eax
|
orl $0x80000000, %eax
|
||||||
movl %eax, %cr0
|
movl %eax, %cr0
|
||||||
/* Now we are in 32-bit compatibility mode, We still need to load a 64-bit GDT */
|
|
||||||
|
|
||||||
/* set up stack */
|
/* set up stack */
|
||||||
mov $stack_top, %esp
|
mov $stack_top, %esp
|
||||||
|
@ -279,6 +305,8 @@ continue:
|
||||||
addl $KERNEL_VIRTUAL_BASE, %ebx
|
addl $KERNEL_VIRTUAL_BASE, %ebx
|
||||||
movl %ebx, multiboot_info_ptr
|
movl %ebx, multiboot_info_ptr
|
||||||
|
|
||||||
|
#if ARCH(X86_64)
|
||||||
|
/* Now we are in 32-bit compatibility mode, We still need to load a 64-bit GDT */
|
||||||
lgdt gdt64ptr
|
lgdt gdt64ptr
|
||||||
ljmpl $code64_sel, $1f
|
ljmpl $code64_sel, $1f
|
||||||
|
|
||||||
|
@ -290,200 +318,17 @@ continue:
|
||||||
mov %ax, %es
|
mov %ax, %es
|
||||||
mov %ax, %fs
|
mov %ax, %fs
|
||||||
mov %ax, %gs
|
mov %ax, %gs
|
||||||
|
#endif
|
||||||
|
|
||||||
call init
|
call init
|
||||||
|
#if ARCH(X86_64)
|
||||||
add $4, %rsp
|
add $4, %rsp
|
||||||
|
#else
|
||||||
|
add $4, %esp
|
||||||
|
#endif
|
||||||
|
|
||||||
cli
|
cli
|
||||||
loop:
|
loop:
|
||||||
hlt
|
hlt
|
||||||
jmp loop
|
jmp loop
|
||||||
|
|
||||||
.extern init_ap
|
|
||||||
.type init_ap, @function
|
|
||||||
|
|
||||||
/*
|
|
||||||
The apic_ap_start function will be loaded to P0x00008000 where the APIC
|
|
||||||
will boot the AP from in real mode. This code also contains space for
|
|
||||||
special variables that *must* remain here. When initializing the APIC,
|
|
||||||
the code here gets copied to P0x00008000, the variables in here get
|
|
||||||
populated and then the the boot of the APs will be triggered. Having
|
|
||||||
the variables here allows us to access them from real mode. Also, the
|
|
||||||
code here avoids the need for relocation entries.
|
|
||||||
|
|
||||||
Basically, the variables between apic_ap_start and end_apic_ap_start
|
|
||||||
*MUST* remain here and cannot be moved into a .bss or any other location.
|
|
||||||
*/
|
|
||||||
.global apic_ap_start
|
|
||||||
.type apic_ap_start, @function
|
|
||||||
apic_ap_start:
|
|
||||||
.code16
|
|
||||||
cli
|
|
||||||
jmp $0x800, $(1f - apic_ap_start) /* avoid relocation entries */
|
|
||||||
1:
|
|
||||||
mov %cs, %ax
|
|
||||||
mov %ax, %ds
|
|
||||||
|
|
||||||
xor %ax, %ax
|
|
||||||
mov %ax, %sp
|
|
||||||
|
|
||||||
/* load the first temporary gdt */
|
|
||||||
lgdt (ap_cpu_gdtr_initial - apic_ap_start)
|
|
||||||
|
|
||||||
/* enable PM */
|
|
||||||
movl %cr0, %eax
|
|
||||||
orl $1, %eax
|
|
||||||
movl %eax, %cr0
|
|
||||||
|
|
||||||
ljmpl $8, $(apic_ap_start32 - apic_ap_start + 0x8000)
|
|
||||||
apic_ap_start32:
|
|
||||||
.code32
|
|
||||||
mov $0x10, %ax
|
|
||||||
mov %ax, %ss
|
|
||||||
mov %ax, %ds
|
|
||||||
mov %ax, %es
|
|
||||||
mov %ax, %fs
|
|
||||||
mov %ax, %gs
|
|
||||||
|
|
||||||
movl $0x8000, %ebp
|
|
||||||
|
|
||||||
/* generate a unique ap cpu id (0 means 1st ap, not bsp!) */
|
|
||||||
xorl %eax, %eax
|
|
||||||
incl %eax
|
|
||||||
lock; xaddl %eax, (ap_cpu_id - apic_ap_start)(%ebp) /* avoid relocation entries */
|
|
||||||
movl %eax, %esi
|
|
||||||
|
|
||||||
/* find our allocated stack based on the generated id */
|
|
||||||
movl (ap_cpu_init_stacks - apic_ap_start)(%ebp, %eax, 4), %esp
|
|
||||||
|
|
||||||
/* check if we support NX and enable it if we do */
|
|
||||||
movl $0x80000001, %eax
|
|
||||||
cpuid
|
|
||||||
testl $0x100000, %edx
|
|
||||||
// TODO: Uncomment this
|
|
||||||
//je (1f - apic_ap_start + 0x8000)
|
|
||||||
/* turn on IA32_EFER.NXE */
|
|
||||||
movl $0xc0000080, %ecx
|
|
||||||
rdmsr
|
|
||||||
orl $0x800, %eax
|
|
||||||
wrmsr
|
|
||||||
1:
|
|
||||||
|
|
||||||
/* load the bsp's cr3 value */
|
|
||||||
movl (ap_cpu_init_cr3 - apic_ap_start)(%ebp), %eax
|
|
||||||
movl %eax, %cr3
|
|
||||||
|
|
||||||
/* Enter Long-mode! ref(https://wiki.osdev.org/Setting_Up_Long_Mode)*/
|
|
||||||
mov $0xC0000080, %ecx /* Set the C-register to 0xC0000080, which is the EFER MSR.*/
|
|
||||||
rdmsr /* Read from the model-specific register.*/
|
|
||||||
or $(1 << 8), %eax /* Set the LM-bit which is the 9th bit (bit 8).*/
|
|
||||||
wrmsr /* Write to the model-specific register.*/
|
|
||||||
|
|
||||||
/* enable PAE + PSE */
|
|
||||||
movl %cr4, %eax
|
|
||||||
orl $0x60, %eax
|
|
||||||
movl %eax, %cr4
|
|
||||||
|
|
||||||
/* enable PG */
|
|
||||||
movl %cr0, %eax
|
|
||||||
orl $0x80000000, %eax
|
|
||||||
movl %eax, %cr0
|
|
||||||
|
|
||||||
/* load the temporary 64-bit gdt from boot that points above 3GB */
|
|
||||||
lgdt gdt64ptr
|
|
||||||
|
|
||||||
/* jump above 3GB into our identity mapped area now */
|
|
||||||
ljmpl $code64_sel, $(apic_ap_start64 - apic_ap_start + 0xc0008000)
|
|
||||||
.code64
|
|
||||||
apic_ap_start64:
|
|
||||||
mov $0, %ax
|
|
||||||
mov %ax, %ss
|
|
||||||
mov %ax, %ds
|
|
||||||
mov %ax, %es
|
|
||||||
mov %ax, %fs
|
|
||||||
mov %ax, %gs
|
|
||||||
|
|
||||||
/* flush the TLB */
|
|
||||||
movq %cr3, %rax
|
|
||||||
movq %rax, %cr3
|
|
||||||
|
|
||||||
movl $0xc0008000, %ebp
|
|
||||||
|
|
||||||
/* now load the final gdt and idt from the identity mapped area */
|
|
||||||
movq (ap_cpu_gdtr - apic_ap_start)(%rbp), %rax
|
|
||||||
lgdt (%rax)
|
|
||||||
movq (ap_cpu_idtr - apic_ap_start)(%rbp), %rax
|
|
||||||
lidt (%rax)
|
|
||||||
|
|
||||||
/* set same cr0 and cr4 values as the BSP */
|
|
||||||
movq (ap_cpu_init_cr0 - apic_ap_start)(%rbp), %rax
|
|
||||||
movq %rax, %cr0
|
|
||||||
movq (ap_cpu_init_cr4 - apic_ap_start)(%rbp), %rax
|
|
||||||
movq %rax, %cr4
|
|
||||||
|
|
||||||
/* push the Processor pointer this CPU is going to use */
|
|
||||||
movq (ap_cpu_init_processor_info_array - apic_ap_start)(%ebp), %rax
|
|
||||||
movq $KERNEL_VIRTUAL_BASE, %r8
|
|
||||||
addq %r8, %rax
|
|
||||||
movq 0(%rax, %rsi, 4), %rax
|
|
||||||
push %rax
|
|
||||||
|
|
||||||
/* push the cpu id, 0 representing the bsp and call into c++ */
|
|
||||||
incq %rsi
|
|
||||||
push %rsi
|
|
||||||
|
|
||||||
xor %ebp, %ebp
|
|
||||||
cld
|
|
||||||
|
|
||||||
/* We are in identity mapped P0x8000 and the BSP will unload this code
|
|
||||||
once all APs are initialized, so call init_ap but return to our
|
|
||||||
infinite loop */
|
|
||||||
movabs $loop, %rax
|
|
||||||
pushq %rax
|
|
||||||
movabs $init_ap, %rax
|
|
||||||
jmp *(%rax)
|
|
||||||
|
|
||||||
.align 4
|
|
||||||
.global apic_ap_start_size
|
|
||||||
apic_ap_start_size:
|
|
||||||
.2byte end_apic_ap_start - apic_ap_start
|
|
||||||
.align 4
|
|
||||||
ap_cpu_id:
|
|
||||||
.4byte 0x0
|
|
||||||
ap_cpu_gdt:
|
|
||||||
/* null */
|
|
||||||
.8byte 0x0
|
|
||||||
/* code */
|
|
||||||
.4byte 0x0000FFFF
|
|
||||||
.4byte 0x00cf9a00
|
|
||||||
/* data */
|
|
||||||
.4byte 0x0000FFFF
|
|
||||||
.4byte 0x00cf9200
|
|
||||||
ap_cpu_gdt_end:
|
|
||||||
ap_cpu_gdtr_initial:
|
|
||||||
.2byte ap_cpu_gdt_end - ap_cpu_gdt - 1
|
|
||||||
.4byte (ap_cpu_gdt - apic_ap_start) + 0x8000
|
|
||||||
.global ap_cpu_gdtr
|
|
||||||
ap_cpu_gdtr:
|
|
||||||
.8byte 0x0 /* will be set at runtime */
|
|
||||||
.global ap_cpu_idtr
|
|
||||||
ap_cpu_idtr:
|
|
||||||
.8byte 0x0 /* will be set at runtime */
|
|
||||||
.global ap_cpu_init_cr0
|
|
||||||
ap_cpu_init_cr0:
|
|
||||||
.8byte 0x0 /* will be set at runtime */
|
|
||||||
.global ap_cpu_init_cr3
|
|
||||||
ap_cpu_init_cr3:
|
|
||||||
.8byte 0x0 /* will be set at runtime */
|
|
||||||
.global ap_cpu_init_cr4
|
|
||||||
ap_cpu_init_cr4:
|
|
||||||
.8byte 0x0 /* will be set at runtime */
|
|
||||||
.global ap_cpu_init_processor_info_array
|
|
||||||
ap_cpu_init_processor_info_array:
|
|
||||||
.8byte 0x0 /* will be set at runtime */
|
|
||||||
.global ap_cpu_init_stacks
|
|
||||||
ap_cpu_init_stacks:
|
|
||||||
/* array of allocated stack pointers */
|
|
||||||
/* NOTE: ap_cpu_init_stacks must be the last variable before
|
|
||||||
end_apic_ap_start! */
|
|
||||||
.set end_apic_ap_start, .
|
|
179
Kernel/Arch/x86/i386/Boot/ap_setup.S
Normal file
179
Kernel/Arch/x86/i386/Boot/ap_setup.S
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
.set KERNEL_VIRTUAL_BASE, 0xc0000000
|
||||||
|
|
||||||
|
.extern init_ap
|
||||||
|
.type init_ap, @function
|
||||||
|
|
||||||
|
/*
|
||||||
|
The apic_ap_start function will be loaded to P0x00008000 where the APIC
|
||||||
|
will boot the AP from in real mode. This code also contains space for
|
||||||
|
special variables that *must* remain here. When initializing the APIC,
|
||||||
|
the code here gets copied to P0x00008000, the variables in here get
|
||||||
|
populated and then the the boot of the APs will be triggered. Having
|
||||||
|
the variables here allows us to access them from real mode. Also, the
|
||||||
|
code here avoids the need for relocation entries.
|
||||||
|
|
||||||
|
Basically, the variables between apic_ap_start and end_apic_ap_start
|
||||||
|
*MUST* remain here and cannot be moved into a .bss or any other location.
|
||||||
|
*/
|
||||||
|
.global apic_ap_start
|
||||||
|
.type apic_ap_start, @function
|
||||||
|
apic_ap_start:
|
||||||
|
.code16
|
||||||
|
cli
|
||||||
|
jmp $0x800, $(1f - apic_ap_start) /* avoid relocation entries */
|
||||||
|
1:
|
||||||
|
mov %cs, %ax
|
||||||
|
mov %ax, %ds
|
||||||
|
|
||||||
|
xor %ax, %ax
|
||||||
|
mov %ax, %sp
|
||||||
|
|
||||||
|
/* load the first temporary gdt */
|
||||||
|
lgdt (ap_cpu_gdtr_initial - apic_ap_start)
|
||||||
|
|
||||||
|
/* enable PM */
|
||||||
|
movl %cr0, %eax
|
||||||
|
orl $1, %eax
|
||||||
|
movl %eax, %cr0
|
||||||
|
|
||||||
|
ljmpl $8, $(apic_ap_start32 - apic_ap_start + 0x8000)
|
||||||
|
apic_ap_start32:
|
||||||
|
.code32
|
||||||
|
mov $0x10, %ax
|
||||||
|
mov %ax, %ss
|
||||||
|
mov %ax, %ds
|
||||||
|
mov %ax, %es
|
||||||
|
mov %ax, %fs
|
||||||
|
mov %ax, %gs
|
||||||
|
|
||||||
|
movl $0x8000, %ebp
|
||||||
|
|
||||||
|
/* generate a unique ap cpu id (0 means 1st ap, not bsp!) */
|
||||||
|
xorl %eax, %eax
|
||||||
|
incl %eax
|
||||||
|
lock; xaddl %eax, (ap_cpu_id - apic_ap_start)(%ebp) /* avoid relocation entries */
|
||||||
|
movl %eax, %esi
|
||||||
|
|
||||||
|
/* find our allocated stack based on the generated id */
|
||||||
|
movl (ap_cpu_init_stacks - apic_ap_start)(%ebp, %eax, 4), %esp
|
||||||
|
|
||||||
|
/* check if we support NX and enable it if we do */
|
||||||
|
movl $0x80000001, %eax
|
||||||
|
cpuid
|
||||||
|
testl $0x100000, %edx
|
||||||
|
je (1f - apic_ap_start + 0x8000)
|
||||||
|
/* turn on IA32_EFER.NXE */
|
||||||
|
movl $0xc0000080, %ecx
|
||||||
|
rdmsr
|
||||||
|
orl $0x800, %eax
|
||||||
|
wrmsr
|
||||||
|
1:
|
||||||
|
|
||||||
|
/* load the bsp's cr3 value */
|
||||||
|
movl (ap_cpu_init_cr3 - apic_ap_start)(%ebp), %eax
|
||||||
|
movl %eax, %cr3
|
||||||
|
|
||||||
|
/* enable PAE + PSE */
|
||||||
|
movl %cr4, %eax
|
||||||
|
orl $0x60, %eax
|
||||||
|
movl %eax, %cr4
|
||||||
|
|
||||||
|
/* enable PG */
|
||||||
|
movl %cr0, %eax
|
||||||
|
orl $0x80000000, %eax
|
||||||
|
movl %eax, %cr0
|
||||||
|
|
||||||
|
/* load a second temporary gdt that points above 3GB */
|
||||||
|
lgdt (ap_cpu_gdtr_initial2 - apic_ap_start + 0xc0008000)
|
||||||
|
|
||||||
|
/* jump above 3GB into our identity mapped area now */
|
||||||
|
ljmp $8, $(apic_ap_start32_2 - apic_ap_start + 0xc0008000)
|
||||||
|
apic_ap_start32_2:
|
||||||
|
/* flush the TLB */
|
||||||
|
movl %cr3, %eax
|
||||||
|
movl %eax, %cr3
|
||||||
|
|
||||||
|
movl $0xc0008000, %ebp
|
||||||
|
|
||||||
|
/* now load the final gdt and idt from the identity mapped area */
|
||||||
|
movl (ap_cpu_gdtr - apic_ap_start)(%ebp), %eax
|
||||||
|
lgdt (%eax)
|
||||||
|
movl (ap_cpu_idtr - apic_ap_start)(%ebp), %eax
|
||||||
|
lidt (%eax)
|
||||||
|
|
||||||
|
/* set same cr0 and cr4 values as the BSP */
|
||||||
|
movl (ap_cpu_init_cr0 - apic_ap_start)(%ebp), %eax
|
||||||
|
movl %eax, %cr0
|
||||||
|
movl (ap_cpu_init_cr4 - apic_ap_start)(%ebp), %eax
|
||||||
|
movl %eax, %cr4
|
||||||
|
|
||||||
|
/* push the Processor pointer this CPU is going to use */
|
||||||
|
movl (ap_cpu_init_processor_info_array - apic_ap_start)(%ebp), %eax
|
||||||
|
addl $KERNEL_VIRTUAL_BASE, %eax
|
||||||
|
movl 0(%eax, %esi, 4), %eax
|
||||||
|
push %eax
|
||||||
|
|
||||||
|
/* push the cpu id, 0 representing the bsp and call into c++ */
|
||||||
|
incl %esi
|
||||||
|
push %esi
|
||||||
|
|
||||||
|
xor %ebp, %ebp
|
||||||
|
cld
|
||||||
|
|
||||||
|
/* We are in identity mapped P0x8000 and the BSP will unload this code
|
||||||
|
once all APs are initialized, so call init_ap but return to our
|
||||||
|
infinite loop */
|
||||||
|
push $loop
|
||||||
|
ljmp $8, $init_ap
|
||||||
|
|
||||||
|
loop:
|
||||||
|
hlt
|
||||||
|
jmp loop
|
||||||
|
|
||||||
|
.align 4
|
||||||
|
.global apic_ap_start_size
|
||||||
|
apic_ap_start_size:
|
||||||
|
.2byte end_apic_ap_start - apic_ap_start
|
||||||
|
.align 4
|
||||||
|
ap_cpu_id:
|
||||||
|
.4byte 0x0
|
||||||
|
ap_cpu_gdt:
|
||||||
|
/* null */
|
||||||
|
.8byte 0x0
|
||||||
|
/* code */
|
||||||
|
.4byte 0x0000FFFF
|
||||||
|
.4byte 0x00cf9a00
|
||||||
|
/* data */
|
||||||
|
.4byte 0x0000FFFF
|
||||||
|
.4byte 0x00cf9200
|
||||||
|
ap_cpu_gdt_end:
|
||||||
|
ap_cpu_gdtr_initial:
|
||||||
|
.2byte ap_cpu_gdt_end - ap_cpu_gdt - 1
|
||||||
|
.4byte (ap_cpu_gdt - apic_ap_start) + 0x8000
|
||||||
|
ap_cpu_gdtr_initial2:
|
||||||
|
.2byte ap_cpu_gdt_end - ap_cpu_gdt - 1
|
||||||
|
.4byte (ap_cpu_gdt - apic_ap_start) + 0xc0008000
|
||||||
|
.global ap_cpu_gdtr
|
||||||
|
ap_cpu_gdtr:
|
||||||
|
.4byte 0x0 /* will be set at runtime */
|
||||||
|
.global ap_cpu_idtr
|
||||||
|
ap_cpu_idtr:
|
||||||
|
.4byte 0x0 /* will be set at runtime */
|
||||||
|
.global ap_cpu_init_cr0
|
||||||
|
ap_cpu_init_cr0:
|
||||||
|
.4byte 0x0 /* will be set at runtime */
|
||||||
|
.global ap_cpu_init_cr3
|
||||||
|
ap_cpu_init_cr3:
|
||||||
|
.4byte 0x0 /* will be set at runtime */
|
||||||
|
.global ap_cpu_init_cr4
|
||||||
|
ap_cpu_init_cr4:
|
||||||
|
.4byte 0x0 /* will be set at runtime */
|
||||||
|
.global ap_cpu_init_processor_info_array
|
||||||
|
ap_cpu_init_processor_info_array:
|
||||||
|
.4byte 0x0 /* will be set at runtime */
|
||||||
|
.global ap_cpu_init_stacks
|
||||||
|
ap_cpu_init_stacks:
|
||||||
|
/* array of allocated stack pointers */
|
||||||
|
/* NOTE: ap_cpu_init_stacks must be the last variable before
|
||||||
|
end_apic_ap_start! */
|
||||||
|
.set end_apic_ap_start, .
|
|
@ -1,407 +0,0 @@
|
||||||
.set KERNEL_VIRTUAL_BASE, 0xc0000000
|
|
||||||
|
|
||||||
.section .stack, "aw", @nobits
|
|
||||||
stack_bottom:
|
|
||||||
.skip 32768
|
|
||||||
stack_top:
|
|
||||||
|
|
||||||
.global kernel_cmdline
|
|
||||||
kernel_cmdline:
|
|
||||||
.skip 4096
|
|
||||||
|
|
||||||
.section .page_tables, "aw", @nobits
|
|
||||||
.align 4096
|
|
||||||
.global boot_pdpt
|
|
||||||
boot_pdpt:
|
|
||||||
.skip 4096
|
|
||||||
.global boot_pd0
|
|
||||||
boot_pd0:
|
|
||||||
.skip 4096
|
|
||||||
.global boot_pd3
|
|
||||||
boot_pd3:
|
|
||||||
.skip 4096
|
|
||||||
.global boot_pd0_pt0
|
|
||||||
boot_pd0_pt0:
|
|
||||||
.skip 4096 * 4
|
|
||||||
.global boot_pd3_pts
|
|
||||||
boot_pd3_pts:
|
|
||||||
.skip 4096 * 16
|
|
||||||
.global boot_pd3_pt1023
|
|
||||||
boot_pd3_pt1023:
|
|
||||||
.skip 4096
|
|
||||||
|
|
||||||
.section .boot_text, "ax"
|
|
||||||
|
|
||||||
.global start
|
|
||||||
.type start, @function
|
|
||||||
|
|
||||||
.extern init
|
|
||||||
.type init, @function
|
|
||||||
|
|
||||||
.extern multiboot_info_ptr
|
|
||||||
.type multiboot_info_ptr, @object
|
|
||||||
|
|
||||||
/*
|
|
||||||
construct the following (32-bit PAE) page table layout:
|
|
||||||
|
|
||||||
pdpt
|
|
||||||
|
|
||||||
0: boot_pd0 (0-1GB)
|
|
||||||
1: n/a (1-2GB)
|
|
||||||
2: n/a (2-3GB)
|
|
||||||
3: boot_pd3 (3-4GB)
|
|
||||||
|
|
||||||
boot_pd0 : 512 pde's
|
|
||||||
|
|
||||||
0: boot_pd0_pt0 (0-2MB) (id 512 4KB pages)
|
|
||||||
|
|
||||||
boot_pd3 : 512 pde's
|
|
||||||
|
|
||||||
0: boot_pd3_pts[0] (3072-3074MB) (pseudo 512 4KB pages)
|
|
||||||
1: boot_pd3_pts[1] (3074-3076MB) (pseudo 512 4KB pages)
|
|
||||||
2: boot_pd3_pts[2] (3076-3078MB) (pseudo 512 4KB pages)
|
|
||||||
3: boot_pd3_pts[3] (3078-3080MB) (pseudo 512 4KB pages)
|
|
||||||
4: boot_pd3_pts[4] (3080-3082MB) (pseudo 512 4KB pages)
|
|
||||||
5: boot_pd3_pts[5] (3082-3084MB) (pseudo 512 4KB pages)
|
|
||||||
6: boot_pd3_pts[6] (3084-3086MB) (pseudo 512 4KB pages)
|
|
||||||
7: boot_pd3_pts[7] (3086-3088MB) (pseudo 512 4KB pages)
|
|
||||||
|
|
||||||
8: boot_pd3_pts[8] (3088-3090MB) (pseudo 512 4KB pages)
|
|
||||||
9: boot_pd3_pts[9] (3090-3076MB) (pseudo 512 4KB pages)
|
|
||||||
10: boot_pd3_pts[10] (3092-3094MB) (pseudo 512 4KB pages)
|
|
||||||
11: boot_pd3_pts[11] (3094-3096MB) (pseudo 512 4KB pages)
|
|
||||||
12: boot_pd3_pts[12] (3096-3098MB) (pseudo 512 4KB pages)
|
|
||||||
13: boot_pd3_pts[13] (3098-3100MB) (pseudo 512 4KB pages)
|
|
||||||
14: boot_pd3_pts[14] (3100-3102MB) (pseudo 512 4KB pages)
|
|
||||||
15: boot_pd3_pts[15] (3102-3104MB) (pseudo 512 4KB pages)
|
|
||||||
|
|
||||||
16: boot_pd3_pt1023 (4094-4096MB) (for page table mappings)
|
|
||||||
|
|
||||||
the 9 page tables each contain 512 pte's that map individual 4KB pages
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
start:
|
|
||||||
cli
|
|
||||||
cld
|
|
||||||
|
|
||||||
/* We don't know where the bootloader might have put the command line.
|
|
||||||
* It might be at an inconvenient location that we're not about to map,
|
|
||||||
* so let's just copy it to a convenient location while we have the whole
|
|
||||||
* memory space identity-mapped anyway. :^)
|
|
||||||
*/
|
|
||||||
|
|
||||||
movl %ebx, %esi
|
|
||||||
addl $16, %esi
|
|
||||||
movl (%esi), %esi
|
|
||||||
movl $1024, %ecx
|
|
||||||
movl $(kernel_cmdline - KERNEL_VIRTUAL_BASE), %edi
|
|
||||||
rep movsl
|
|
||||||
|
|
||||||
/* clear pdpt */
|
|
||||||
movl $(boot_pdpt - KERNEL_VIRTUAL_BASE), %edi
|
|
||||||
movl $1024, %ecx
|
|
||||||
xorl %eax, %eax
|
|
||||||
rep stosl
|
|
||||||
|
|
||||||
/* set up pdpt[0] and pdpt[3] */
|
|
||||||
movl $(boot_pdpt - KERNEL_VIRTUAL_BASE), %edi
|
|
||||||
movl $((boot_pd0 - KERNEL_VIRTUAL_BASE) + 1), 0(%edi)
|
|
||||||
movl $((boot_pd3 - KERNEL_VIRTUAL_BASE) + 1), 24(%edi)
|
|
||||||
|
|
||||||
/* clear pd0 */
|
|
||||||
movl $(boot_pd0 - KERNEL_VIRTUAL_BASE), %edi
|
|
||||||
movl $1024, %ecx
|
|
||||||
xorl %eax, %eax
|
|
||||||
rep stosl
|
|
||||||
|
|
||||||
/* clear pd3 */
|
|
||||||
movl $(boot_pd3 - KERNEL_VIRTUAL_BASE), %edi
|
|
||||||
movl $1024, %ecx
|
|
||||||
xorl %eax, %eax
|
|
||||||
rep stosl
|
|
||||||
|
|
||||||
/* clear pd0's pt's */
|
|
||||||
movl $(boot_pd0_pt0 - KERNEL_VIRTUAL_BASE), %edi
|
|
||||||
movl $(1024 * 4), %ecx
|
|
||||||
xorl %eax, %eax
|
|
||||||
rep stosl
|
|
||||||
|
|
||||||
/* clear pd3's pt's */
|
|
||||||
movl $(boot_pd3_pts - KERNEL_VIRTUAL_BASE), %edi
|
|
||||||
movl $(1024 * 17), %ecx
|
|
||||||
xorl %eax, %eax
|
|
||||||
rep stosl
|
|
||||||
|
|
||||||
/* add boot_pd0_pt0 to boot_pd0 */
|
|
||||||
movl $(boot_pd0 - KERNEL_VIRTUAL_BASE), %edi
|
|
||||||
movl $(boot_pd0_pt0 - KERNEL_VIRTUAL_BASE), %eax
|
|
||||||
movl %eax, 0(%edi)
|
|
||||||
/* R/W + Present */
|
|
||||||
orl $0x3, 0(%edi)
|
|
||||||
|
|
||||||
/* add boot_pd3_pts to boot_pd3 */
|
|
||||||
movl $16, %ecx
|
|
||||||
movl $(boot_pd3 - KERNEL_VIRTUAL_BASE), %edi
|
|
||||||
movl $(boot_pd3_pts - KERNEL_VIRTUAL_BASE), %eax
|
|
||||||
|
|
||||||
1:
|
|
||||||
movl %eax, 0(%edi)
|
|
||||||
/* R/W + Present */
|
|
||||||
orl $0x3, 0(%edi)
|
|
||||||
addl $8, %edi
|
|
||||||
addl $4096, %eax
|
|
||||||
loop 1b
|
|
||||||
|
|
||||||
/* identity map the 0 to 2MB range */
|
|
||||||
movl $512, %ecx
|
|
||||||
movl $(boot_pd0_pt0 - KERNEL_VIRTUAL_BASE), %edi
|
|
||||||
xorl %eax, %eax
|
|
||||||
|
|
||||||
1:
|
|
||||||
movl %eax, 0(%edi)
|
|
||||||
/* R/W + Present */
|
|
||||||
orl $0x3, 0(%edi)
|
|
||||||
addl $8, %edi
|
|
||||||
addl $4096, %eax
|
|
||||||
loop 1b
|
|
||||||
|
|
||||||
/* pseudo identity map the 3072-3102MB range */
|
|
||||||
movl $(512 * 16), %ecx
|
|
||||||
movl $(boot_pd3_pts - KERNEL_VIRTUAL_BASE), %edi
|
|
||||||
xorl %eax, %eax
|
|
||||||
|
|
||||||
1:
|
|
||||||
movl %eax, 0(%edi)
|
|
||||||
/* R/W + Present */
|
|
||||||
orl $0x3, 0(%edi)
|
|
||||||
addl $8, %edi
|
|
||||||
addl $4096, %eax
|
|
||||||
loop 1b
|
|
||||||
|
|
||||||
/* create an empty page table for the top 2MB at the 4GB mark */
|
|
||||||
movl $(boot_pd3 - KERNEL_VIRTUAL_BASE), %edi
|
|
||||||
movl $(boot_pd3_pt1023 - KERNEL_VIRTUAL_BASE), 4088(%edi)
|
|
||||||
orl $0x3, 4088(%edi)
|
|
||||||
movl $0, 4092(%edi)
|
|
||||||
|
|
||||||
/* point CR3 to PDPT */
|
|
||||||
movl $(boot_pdpt - KERNEL_VIRTUAL_BASE), %eax
|
|
||||||
movl %eax, %cr3
|
|
||||||
|
|
||||||
/* enable PAE + PSE */
|
|
||||||
movl %cr4, %eax
|
|
||||||
orl $0x60, %eax
|
|
||||||
movl %eax, %cr4
|
|
||||||
|
|
||||||
/* enable PG */
|
|
||||||
movl %cr0, %eax
|
|
||||||
orl $0x80000000, %eax
|
|
||||||
movl %eax, %cr0
|
|
||||||
|
|
||||||
/* set up stack */
|
|
||||||
mov $stack_top, %esp
|
|
||||||
and $-16, %esp
|
|
||||||
|
|
||||||
/* jmp to an address above the 3GB mark */
|
|
||||||
movl $1f,%eax
|
|
||||||
jmp *%eax
|
|
||||||
1:
|
|
||||||
movl %cr3, %eax
|
|
||||||
movl %eax, %cr3
|
|
||||||
|
|
||||||
/* unmap the 0-1MB range, which isn't used after jmp-ing up here */
|
|
||||||
movl $256, %ecx
|
|
||||||
movl $(boot_pd0_pt0 - KERNEL_VIRTUAL_BASE), %edi
|
|
||||||
xorl %eax, %eax
|
|
||||||
|
|
||||||
1:
|
|
||||||
movl %eax, 0(%edi)
|
|
||||||
addl $8, %edi
|
|
||||||
loop 1b
|
|
||||||
|
|
||||||
/* jump into C++ land */
|
|
||||||
addl $KERNEL_VIRTUAL_BASE, %ebx
|
|
||||||
movl %ebx, multiboot_info_ptr
|
|
||||||
|
|
||||||
call init
|
|
||||||
add $4, %esp
|
|
||||||
|
|
||||||
cli
|
|
||||||
loop:
|
|
||||||
hlt
|
|
||||||
jmp loop
|
|
||||||
|
|
||||||
.extern init_ap
|
|
||||||
.type init_ap, @function
|
|
||||||
|
|
||||||
/*
|
|
||||||
The apic_ap_start function will be loaded to P0x00008000 where the APIC
|
|
||||||
will boot the AP from in real mode. This code also contains space for
|
|
||||||
special variables that *must* remain here. When initializing the APIC,
|
|
||||||
the code here gets copied to P0x00008000, the variables in here get
|
|
||||||
populated and then the the boot of the APs will be triggered. Having
|
|
||||||
the variables here allows us to access them from real mode. Also, the
|
|
||||||
code here avoids the need for relocation entries.
|
|
||||||
|
|
||||||
Basically, the variables between apic_ap_start and end_apic_ap_start
|
|
||||||
*MUST* remain here and cannot be moved into a .bss or any other location.
|
|
||||||
*/
|
|
||||||
.global apic_ap_start
|
|
||||||
.type apic_ap_start, @function
|
|
||||||
apic_ap_start:
|
|
||||||
.code16
|
|
||||||
cli
|
|
||||||
jmp $0x800, $(1f - apic_ap_start) /* avoid relocation entries */
|
|
||||||
1:
|
|
||||||
mov %cs, %ax
|
|
||||||
mov %ax, %ds
|
|
||||||
|
|
||||||
xor %ax, %ax
|
|
||||||
mov %ax, %sp
|
|
||||||
|
|
||||||
/* load the first temporary gdt */
|
|
||||||
lgdt (ap_cpu_gdtr_initial - apic_ap_start)
|
|
||||||
|
|
||||||
/* enable PM */
|
|
||||||
movl %cr0, %eax
|
|
||||||
orl $1, %eax
|
|
||||||
movl %eax, %cr0
|
|
||||||
|
|
||||||
ljmpl $8, $(apic_ap_start32 - apic_ap_start + 0x8000)
|
|
||||||
apic_ap_start32:
|
|
||||||
.code32
|
|
||||||
mov $0x10, %ax
|
|
||||||
mov %ax, %ss
|
|
||||||
mov %ax, %ds
|
|
||||||
mov %ax, %es
|
|
||||||
mov %ax, %fs
|
|
||||||
mov %ax, %gs
|
|
||||||
|
|
||||||
movl $0x8000, %ebp
|
|
||||||
|
|
||||||
/* generate a unique ap cpu id (0 means 1st ap, not bsp!) */
|
|
||||||
xorl %eax, %eax
|
|
||||||
incl %eax
|
|
||||||
lock; xaddl %eax, (ap_cpu_id - apic_ap_start)(%ebp) /* avoid relocation entries */
|
|
||||||
movl %eax, %esi
|
|
||||||
|
|
||||||
/* find our allocated stack based on the generated id */
|
|
||||||
movl (ap_cpu_init_stacks - apic_ap_start)(%ebp, %eax, 4), %esp
|
|
||||||
|
|
||||||
/* check if we support NX and enable it if we do */
|
|
||||||
movl $0x80000001, %eax
|
|
||||||
cpuid
|
|
||||||
testl $0x100000, %edx
|
|
||||||
je (1f - apic_ap_start + 0x8000)
|
|
||||||
/* turn on IA32_EFER.NXE */
|
|
||||||
movl $0xc0000080, %ecx
|
|
||||||
rdmsr
|
|
||||||
orl $0x800, %eax
|
|
||||||
wrmsr
|
|
||||||
1:
|
|
||||||
|
|
||||||
/* load the bsp's cr3 value */
|
|
||||||
movl (ap_cpu_init_cr3 - apic_ap_start)(%ebp), %eax
|
|
||||||
movl %eax, %cr3
|
|
||||||
|
|
||||||
/* enable PAE + PSE */
|
|
||||||
movl %cr4, %eax
|
|
||||||
orl $0x60, %eax
|
|
||||||
movl %eax, %cr4
|
|
||||||
|
|
||||||
/* enable PG */
|
|
||||||
movl %cr0, %eax
|
|
||||||
orl $0x80000000, %eax
|
|
||||||
movl %eax, %cr0
|
|
||||||
|
|
||||||
/* load a second temporary gdt that points above 3GB */
|
|
||||||
lgdt (ap_cpu_gdtr_initial2 - apic_ap_start + 0xc0008000)
|
|
||||||
|
|
||||||
/* jump above 3GB into our identity mapped area now */
|
|
||||||
ljmp $8, $(apic_ap_start32_2 - apic_ap_start + 0xc0008000)
|
|
||||||
apic_ap_start32_2:
|
|
||||||
/* flush the TLB */
|
|
||||||
movl %cr3, %eax
|
|
||||||
movl %eax, %cr3
|
|
||||||
|
|
||||||
movl $0xc0008000, %ebp
|
|
||||||
|
|
||||||
/* now load the final gdt and idt from the identity mapped area */
|
|
||||||
movl (ap_cpu_gdtr - apic_ap_start)(%ebp), %eax
|
|
||||||
lgdt (%eax)
|
|
||||||
movl (ap_cpu_idtr - apic_ap_start)(%ebp), %eax
|
|
||||||
lidt (%eax)
|
|
||||||
|
|
||||||
/* set same cr0 and cr4 values as the BSP */
|
|
||||||
movl (ap_cpu_init_cr0 - apic_ap_start)(%ebp), %eax
|
|
||||||
movl %eax, %cr0
|
|
||||||
movl (ap_cpu_init_cr4 - apic_ap_start)(%ebp), %eax
|
|
||||||
movl %eax, %cr4
|
|
||||||
|
|
||||||
/* push the Processor pointer this CPU is going to use */
|
|
||||||
movl (ap_cpu_init_processor_info_array - apic_ap_start)(%ebp), %eax
|
|
||||||
addl $KERNEL_VIRTUAL_BASE, %eax
|
|
||||||
movl 0(%eax, %esi, 4), %eax
|
|
||||||
push %eax
|
|
||||||
|
|
||||||
/* push the cpu id, 0 representing the bsp and call into c++ */
|
|
||||||
incl %esi
|
|
||||||
push %esi
|
|
||||||
|
|
||||||
xor %ebp, %ebp
|
|
||||||
cld
|
|
||||||
|
|
||||||
/* We are in identity mapped P0x8000 and the BSP will unload this code
|
|
||||||
once all APs are initialized, so call init_ap but return to our
|
|
||||||
infinite loop */
|
|
||||||
push $loop
|
|
||||||
ljmp $8, $init_ap
|
|
||||||
|
|
||||||
.align 4
|
|
||||||
.global apic_ap_start_size
|
|
||||||
apic_ap_start_size:
|
|
||||||
.2byte end_apic_ap_start - apic_ap_start
|
|
||||||
.align 4
|
|
||||||
ap_cpu_id:
|
|
||||||
.4byte 0x0
|
|
||||||
ap_cpu_gdt:
|
|
||||||
/* null */
|
|
||||||
.8byte 0x0
|
|
||||||
/* code */
|
|
||||||
.4byte 0x0000FFFF
|
|
||||||
.4byte 0x00cf9a00
|
|
||||||
/* data */
|
|
||||||
.4byte 0x0000FFFF
|
|
||||||
.4byte 0x00cf9200
|
|
||||||
ap_cpu_gdt_end:
|
|
||||||
ap_cpu_gdtr_initial:
|
|
||||||
.2byte ap_cpu_gdt_end - ap_cpu_gdt - 1
|
|
||||||
.4byte (ap_cpu_gdt - apic_ap_start) + 0x8000
|
|
||||||
ap_cpu_gdtr_initial2:
|
|
||||||
.2byte ap_cpu_gdt_end - ap_cpu_gdt - 1
|
|
||||||
.4byte (ap_cpu_gdt - apic_ap_start) + 0xc0008000
|
|
||||||
.global ap_cpu_gdtr
|
|
||||||
ap_cpu_gdtr:
|
|
||||||
.4byte 0x0 /* will be set at runtime */
|
|
||||||
.global ap_cpu_idtr
|
|
||||||
ap_cpu_idtr:
|
|
||||||
.4byte 0x0 /* will be set at runtime */
|
|
||||||
.global ap_cpu_init_cr0
|
|
||||||
ap_cpu_init_cr0:
|
|
||||||
.4byte 0x0 /* will be set at runtime */
|
|
||||||
.global ap_cpu_init_cr3
|
|
||||||
ap_cpu_init_cr3:
|
|
||||||
.4byte 0x0 /* will be set at runtime */
|
|
||||||
.global ap_cpu_init_cr4
|
|
||||||
ap_cpu_init_cr4:
|
|
||||||
.4byte 0x0 /* will be set at runtime */
|
|
||||||
.global ap_cpu_init_processor_info_array
|
|
||||||
ap_cpu_init_processor_info_array:
|
|
||||||
.4byte 0x0 /* will be set at runtime */
|
|
||||||
.global ap_cpu_init_stacks
|
|
||||||
ap_cpu_init_stacks:
|
|
||||||
/* array of allocated stack pointers */
|
|
||||||
/* NOTE: ap_cpu_init_stacks must be the last variable before
|
|
||||||
end_apic_ap_start! */
|
|
||||||
.set end_apic_ap_start, .
|
|
194
Kernel/Arch/x86/x86_64/Boot/ap_setup.S
Normal file
194
Kernel/Arch/x86/x86_64/Boot/ap_setup.S
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
.set KERNEL_VIRTUAL_BASE, 0xc0000000
|
||||||
|
|
||||||
|
.extern init_ap
|
||||||
|
.type init_ap, @function
|
||||||
|
|
||||||
|
/*
|
||||||
|
The apic_ap_start function will be loaded to P0x00008000 where the APIC
|
||||||
|
will boot the AP from in real mode. This code also contains space for
|
||||||
|
special variables that *must* remain here. When initializing the APIC,
|
||||||
|
the code here gets copied to P0x00008000, the variables in here get
|
||||||
|
populated and then the the boot of the APs will be triggered. Having
|
||||||
|
the variables here allows us to access them from real mode. Also, the
|
||||||
|
code here avoids the need for relocation entries.
|
||||||
|
|
||||||
|
Basically, the variables between apic_ap_start and end_apic_ap_start
|
||||||
|
*MUST* remain here and cannot be moved into a .bss or any other location.
|
||||||
|
*/
|
||||||
|
.global apic_ap_start
|
||||||
|
.type apic_ap_start, @function
|
||||||
|
apic_ap_start:
|
||||||
|
.code16
|
||||||
|
cli
|
||||||
|
jmp $0x800, $(1f - apic_ap_start) /* avoid relocation entries */
|
||||||
|
1:
|
||||||
|
mov %cs, %ax
|
||||||
|
mov %ax, %ds
|
||||||
|
|
||||||
|
xor %ax, %ax
|
||||||
|
mov %ax, %sp
|
||||||
|
|
||||||
|
/* load the first temporary gdt */
|
||||||
|
lgdt (ap_cpu_gdtr_initial - apic_ap_start)
|
||||||
|
|
||||||
|
/* enable PM */
|
||||||
|
movl %cr0, %eax
|
||||||
|
orl $1, %eax
|
||||||
|
movl %eax, %cr0
|
||||||
|
|
||||||
|
ljmpl $8, $(apic_ap_start32 - apic_ap_start + 0x8000)
|
||||||
|
apic_ap_start32:
|
||||||
|
.code32
|
||||||
|
mov $0x10, %ax
|
||||||
|
mov %ax, %ss
|
||||||
|
mov %ax, %ds
|
||||||
|
mov %ax, %es
|
||||||
|
mov %ax, %fs
|
||||||
|
mov %ax, %gs
|
||||||
|
|
||||||
|
movl $0x8000, %ebp
|
||||||
|
|
||||||
|
/* generate a unique ap cpu id (0 means 1st ap, not bsp!) */
|
||||||
|
xorl %eax, %eax
|
||||||
|
incl %eax
|
||||||
|
lock; xaddl %eax, (ap_cpu_id - apic_ap_start)(%ebp) /* avoid relocation entries */
|
||||||
|
movl %eax, %esi
|
||||||
|
|
||||||
|
/* find our allocated stack based on the generated id */
|
||||||
|
movl (ap_cpu_init_stacks - apic_ap_start)(%ebp, %eax, 4), %esp
|
||||||
|
|
||||||
|
/* check if we support NX and enable it if we do */
|
||||||
|
movl $0x80000001, %eax
|
||||||
|
cpuid
|
||||||
|
testl $0x100000, %edx
|
||||||
|
// TODO: Uncomment this
|
||||||
|
//je (1f - apic_ap_start + 0x8000)
|
||||||
|
/* turn on IA32_EFER.NXE */
|
||||||
|
movl $0xc0000080, %ecx
|
||||||
|
rdmsr
|
||||||
|
orl $0x800, %eax
|
||||||
|
wrmsr
|
||||||
|
1:
|
||||||
|
|
||||||
|
/* load the bsp's cr3 value */
|
||||||
|
movl (ap_cpu_init_cr3 - apic_ap_start)(%ebp), %eax
|
||||||
|
movl %eax, %cr3
|
||||||
|
|
||||||
|
/* Enter Long-mode! ref(https://wiki.osdev.org/Setting_Up_Long_Mode)*/
|
||||||
|
mov $0xC0000080, %ecx /* Set the C-register to 0xC0000080, which is the EFER MSR.*/
|
||||||
|
rdmsr /* Read from the model-specific register.*/
|
||||||
|
or $(1 << 8), %eax /* Set the LM-bit which is the 9th bit (bit 8).*/
|
||||||
|
wrmsr /* Write to the model-specific register.*/
|
||||||
|
|
||||||
|
/* enable PAE + PSE */
|
||||||
|
movl %cr4, %eax
|
||||||
|
orl $0x60, %eax
|
||||||
|
movl %eax, %cr4
|
||||||
|
|
||||||
|
/* enable PG */
|
||||||
|
movl %cr0, %eax
|
||||||
|
orl $0x80000000, %eax
|
||||||
|
movl %eax, %cr0
|
||||||
|
|
||||||
|
/* load the temporary 64-bit gdt from boot that points above 3GB */
|
||||||
|
lgdt gdt64ptr
|
||||||
|
|
||||||
|
/* jump above 3GB into our identity mapped area now */
|
||||||
|
ljmpl $code64_sel, $(apic_ap_start64 - apic_ap_start + 0xc0008000)
|
||||||
|
.code64
|
||||||
|
apic_ap_start64:
|
||||||
|
mov $0, %ax
|
||||||
|
mov %ax, %ss
|
||||||
|
mov %ax, %ds
|
||||||
|
mov %ax, %es
|
||||||
|
mov %ax, %fs
|
||||||
|
mov %ax, %gs
|
||||||
|
|
||||||
|
/* flush the TLB */
|
||||||
|
movq %cr3, %rax
|
||||||
|
movq %rax, %cr3
|
||||||
|
|
||||||
|
movl $0xc0008000, %ebp
|
||||||
|
|
||||||
|
/* now load the final gdt and idt from the identity mapped area */
|
||||||
|
movq (ap_cpu_gdtr - apic_ap_start)(%rbp), %rax
|
||||||
|
lgdt (%rax)
|
||||||
|
movq (ap_cpu_idtr - apic_ap_start)(%rbp), %rax
|
||||||
|
lidt (%rax)
|
||||||
|
|
||||||
|
/* set same cr0 and cr4 values as the BSP */
|
||||||
|
movq (ap_cpu_init_cr0 - apic_ap_start)(%rbp), %rax
|
||||||
|
movq %rax, %cr0
|
||||||
|
movq (ap_cpu_init_cr4 - apic_ap_start)(%rbp), %rax
|
||||||
|
movq %rax, %cr4
|
||||||
|
|
||||||
|
/* push the Processor pointer this CPU is going to use */
|
||||||
|
movq (ap_cpu_init_processor_info_array - apic_ap_start)(%ebp), %rax
|
||||||
|
movq $KERNEL_VIRTUAL_BASE, %r8
|
||||||
|
addq %r8, %rax
|
||||||
|
movq 0(%rax, %rsi, 4), %rax
|
||||||
|
push %rax
|
||||||
|
|
||||||
|
/* push the cpu id, 0 representing the bsp and call into c++ */
|
||||||
|
incq %rsi
|
||||||
|
push %rsi
|
||||||
|
|
||||||
|
xor %ebp, %ebp
|
||||||
|
cld
|
||||||
|
|
||||||
|
/* We are in identity mapped P0x8000 and the BSP will unload this code
|
||||||
|
once all APs are initialized, so call init_ap but return to our
|
||||||
|
infinite loop */
|
||||||
|
movabs $loop, %rax
|
||||||
|
pushq %rax
|
||||||
|
movabs $init_ap, %rax
|
||||||
|
jmp *(%rax)
|
||||||
|
|
||||||
|
loop:
|
||||||
|
hlt
|
||||||
|
jmp loop
|
||||||
|
|
||||||
|
.align 4
|
||||||
|
.global apic_ap_start_size
|
||||||
|
apic_ap_start_size:
|
||||||
|
.2byte end_apic_ap_start - apic_ap_start
|
||||||
|
.align 4
|
||||||
|
ap_cpu_id:
|
||||||
|
.4byte 0x0
|
||||||
|
ap_cpu_gdt:
|
||||||
|
/* null */
|
||||||
|
.8byte 0x0
|
||||||
|
/* code */
|
||||||
|
.4byte 0x0000FFFF
|
||||||
|
.4byte 0x00cf9a00
|
||||||
|
/* data */
|
||||||
|
.4byte 0x0000FFFF
|
||||||
|
.4byte 0x00cf9200
|
||||||
|
ap_cpu_gdt_end:
|
||||||
|
ap_cpu_gdtr_initial:
|
||||||
|
.2byte ap_cpu_gdt_end - ap_cpu_gdt - 1
|
||||||
|
.4byte (ap_cpu_gdt - apic_ap_start) + 0x8000
|
||||||
|
.global ap_cpu_gdtr
|
||||||
|
ap_cpu_gdtr:
|
||||||
|
.8byte 0x0 /* will be set at runtime */
|
||||||
|
.global ap_cpu_idtr
|
||||||
|
ap_cpu_idtr:
|
||||||
|
.8byte 0x0 /* will be set at runtime */
|
||||||
|
.global ap_cpu_init_cr0
|
||||||
|
ap_cpu_init_cr0:
|
||||||
|
.8byte 0x0 /* will be set at runtime */
|
||||||
|
.global ap_cpu_init_cr3
|
||||||
|
ap_cpu_init_cr3:
|
||||||
|
.8byte 0x0 /* will be set at runtime */
|
||||||
|
.global ap_cpu_init_cr4
|
||||||
|
ap_cpu_init_cr4:
|
||||||
|
.8byte 0x0 /* will be set at runtime */
|
||||||
|
.global ap_cpu_init_processor_info_array
|
||||||
|
ap_cpu_init_processor_info_array:
|
||||||
|
.8byte 0x0 /* will be set at runtime */
|
||||||
|
.global ap_cpu_init_stacks
|
||||||
|
ap_cpu_init_stacks:
|
||||||
|
/* array of allocated stack pointers */
|
||||||
|
/* NOTE: ap_cpu_init_stacks must be the last variable before
|
||||||
|
end_apic_ap_start! */
|
||||||
|
.set end_apic_ap_start, .
|
|
@ -281,7 +281,7 @@ set(KERNEL_SOURCES
|
||||||
set(KERNEL_SOURCES
|
set(KERNEL_SOURCES
|
||||||
${KERNEL_SOURCES}
|
${KERNEL_SOURCES}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Arch/x86/${KERNEL_ARCH}/ASM_wrapper.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/Arch/x86/${KERNEL_ARCH}/ASM_wrapper.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Arch/x86/${KERNEL_ARCH}/Boot/boot.S
|
${CMAKE_CURRENT_SOURCE_DIR}/Arch/x86/${KERNEL_ARCH}/Boot/ap_setup.S
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Arch/x86/${KERNEL_ARCH}/InterruptEntry.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/Arch/x86/${KERNEL_ARCH}/InterruptEntry.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Arch/x86/${KERNEL_ARCH}/Processor.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/Arch/x86/${KERNEL_ARCH}/Processor.cpp
|
||||||
)
|
)
|
||||||
|
@ -289,6 +289,7 @@ set(KERNEL_SOURCES
|
||||||
set(KERNEL_SOURCES
|
set(KERNEL_SOURCES
|
||||||
${KERNEL_SOURCES}
|
${KERNEL_SOURCES}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Arch/x86/common/ASM_wrapper.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/Arch/x86/common/ASM_wrapper.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/Arch/x86/common/Boot/boot.S
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Arch/x86/common/Boot/multiboot.S
|
${CMAKE_CURRENT_SOURCE_DIR}/Arch/x86/common/Boot/multiboot.S
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Arch/x86/common/CPU.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/Arch/x86/common/CPU.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Arch/x86/common/Interrupts.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/Arch/x86/common/Interrupts.cpp
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue