summaryrefslogtreecommitdiff
path: root/Kernel/Arch/x86/x86_64/Boot
diff options
context:
space:
mode:
authorHendiadyoin1 <leon2002.la@gmail.com>2021-06-21 17:34:09 +0200
committerAndreas Kling <kling@serenityos.org>2021-06-24 00:38:23 +0200
commit7ca3d413f7ec0e0ef83b20c2473d73c747a9b330 (patch)
tree776412b2cbee270195aa515f71ac42da1b2090d8 /Kernel/Arch/x86/x86_64/Boot
parent37253ebcae6a9e172903ea1b9fae19c42055a53b (diff)
downloadserenity-7ca3d413f7ec0e0ef83b20c2473d73c747a9b330.zip
Kernel: Pull apart CPU.h
This does not add any functional changes
Diffstat (limited to 'Kernel/Arch/x86/x86_64/Boot')
-rw-r--r--Kernel/Arch/x86/x86_64/Boot/boot.S431
1 files changed, 431 insertions, 0 deletions
diff --git a/Kernel/Arch/x86/x86_64/Boot/boot.S b/Kernel/Arch/x86/x86_64/Boot/boot.S
new file mode 100644
index 0000000000..8e1d9d27ba
--- /dev/null
+++ b/Kernel/Arch/x86/x86_64/Boot/boot.S
@@ -0,0 +1,431 @@
+.code32
+.set MULTIBOOT_MAGIC, 0x1badb002
+.set MULTIBOOT_PAGE_ALIGN, 0x1
+.set MULTIBOOT_MEMORY_INFO, 0x2
+.set MULTIBOOT_VIDEO_MODE, 0x4
+.set multiboot_flags, MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | MULTIBOOT_VIDEO_MODE
+.set multiboot_checksum, -(MULTIBOOT_MAGIC + multiboot_flags)
+
+.section .multiboot
+.align 4
+
+.long MULTIBOOT_MAGIC
+.long multiboot_flags
+.long multiboot_checksum
+
+
+/* for MULTIBOOT_MEMORY_INFO */
+.long 0x00000000 /* header_addr */
+.long 0x00000000 /* load_addr */
+.long 0x00000000 /* load_end_addr */
+.long 0x00000000 /* bss_end_addr */
+.long 0x00000000 /* entry_addr */
+
+/* for MULTIBOOT_VIDEO_MODE */
+.long 0x00000000 /* mode_type */
+.long 1280 /* width */
+.long 1024 /* height */
+.long 32 /* depth */
+
+.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 * 8
+.global boot_pd3_pt1023
+boot_pd3_pt1023:
+.skip 4096
+
+.section .text
+
+.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_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 - 0xc0000000), %edi
+ rep movsl
+
+ /* clear pdpt */
+ movl $(boot_pdpt - 0xc0000000), %edi
+ movl $1024, %ecx
+ xorl %eax, %eax
+ rep stosl
+
+ /* set up pdpt[0] and pdpt[3] */
+ movl $(boot_pdpt - 0xc0000000), %edi
+ movl $((boot_pd0 - 0xc0000000) + 1), 0(%edi)
+ movl $((boot_pd3 - 0xc0000000) + 1), 24(%edi)
+
+ /* clear pd0 */
+ movl $(boot_pd0 - 0xc0000000), %edi
+ movl $1024, %ecx
+ xorl %eax, %eax
+ rep stosl
+
+ /* clear pd3 */
+ movl $(boot_pd3 - 0xc0000000), %edi
+ movl $1024, %ecx
+ xorl %eax, %eax
+ rep stosl
+
+ /* clear pd0's pt's */
+ movl $(boot_pd0_pt0 - 0xc0000000), %edi
+ movl $(1024 * 4), %ecx
+ xorl %eax, %eax
+ rep stosl
+
+ /* clear pd3's pt's */
+ movl $(boot_pd3_pts - 0xc0000000), %edi
+ movl $(1024 * 9), %ecx
+ xorl %eax, %eax
+ rep stosl
+
+ /* add boot_pd0_pt0 to boot_pd0 */
+ movl $(boot_pd0 - 0xc0000000), %edi
+ movl $(boot_pd0_pt0 - 0xc0000000), %eax
+ movl %eax, 0(%edi)
+ /* R/W + Present */
+ orl $0x3, 0(%edi)
+
+ /* add boot_pd3_pts to boot_pd3 */
+ movl $8, %ecx
+ movl $(boot_pd3 - 0xc0000000), %edi
+ movl $(boot_pd3_pts - 0xc0000000), %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 - 0xc0000000), %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-3090MB range */
+ movl $(512 * 8), %ecx
+ movl $(boot_pd3_pts - 0xc0000000), %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 - 0xc0000000), %edi
+ movl $(boot_pd3_pt1023 - 0xc0000000), 4088(%edi)
+ orl $0x3, 4088(%edi)
+ movl $0, 4092(%edi)
+
+ /* point CR3 to PDPT */
+ movl $(boot_pdpt - 0xc0000000), %eax
+ movl %eax, %cr3
+
+ /* enable PAE + PSE */
+ movl %cr4, %eax
+ orl $0x60, %eax
+ movl %eax, %cr4
+
+1:
+ /* 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 PG */
+ movl %cr0, %eax
+ orl $0x80000000, %eax
+ movl %eax, %cr0
+ /* Now we are in 32-bit compatibility mode, We still need to load a 64-bit GDT */
+
+ /* 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 - 0xc0000000), %edi
+ xorl %eax, %eax
+1:
+ movl %eax, 0(%edi)
+ addl $8, %edi
+ loop 1b
+
+ /* jump into C++ land */
+ addl $0xc0000000, %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 $0xc0000000, %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, .