/* * Copyright (C) 2018 Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include /* NOTE: * * MISRA C requires that all unsigned constants should have the suffix 'U' * (e.g. 0xffU), but the assembler may not accept such C-style constants. For * example, binutils 2.26 fails to compile assembly in that case. To work this * around, all unsigned constants must be explicitly spells out in assembly * with a comment tracking the original expression from which the magic * number is calculated. As an example: * * /* 0x00000668 = * * (CR4_DE | CR4_PAE | CR4_MCE | CR4_OSFXSR | CR4_OSXMMEXCPT) *\/ * movl $0x00000668, %eax * * Make sure that these numbers are updated accordingly if the definition of * the macros involved are changed. */ /* MULTIBOOT HEADER */ #define MULTIBOOT_HEADER_MAGIC 0x1badb002 #define MULTIBOOT_HEADER_FLAGS 0x00000002 /*flags bit 1 : enable mem_*, mmap_**/ .extern cpu_primary_save32 .extern cpu_primary_save64 .section multiboot_header, "a" .align 4 /* header magic */ .long MULTIBOOT_HEADER_MAGIC /* header flags - flags bit 6 : enable mmap_* */ .long MULTIBOOT_HEADER_FLAGS /* header checksum = -(magic + flags) */ .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) .section entry, "ax" .align 8 .code32 .global cpu_primary_start_32 cpu_primary_start_32: /* save the MULTBOOT magic number & MBI */ movl %eax, (boot_regs) movl %ebx, (boot_regs+4) /* Save boot context from 32bit mode */ call cpu_primary_save_32 /* Disable interrupts */ cli /* Clear direction flag */ cld /* detect whether it is in long mode * * 0xc0000080 = MSR_IA32_EFER */ movl $0xc0000080, %ecx rdmsr /* 0x400 = MSR_IA32_EFER_LMA_BIT */ test $0x400, %eax /* jump to 64bit entry if it is already in long mode */ jne cpu_primary_start_64 /* Disable paging */ mov %cr0, %ebx /* 0x7fffffff = ~CR0_PG */ andl $0x7fffffff, %ebx mov %ebx, %cr0 /* Set DE, PAE, MCE and OS support bits in CR4 * 0x00000668 = * (CR4_DE | CR4_PAE | CR4_MCE | CR4_OSFXSR | CR4_OSXMMEXCPT) */ movl $0x00000668, %eax mov %eax, %cr4 /* Set CR3 to PML4 table address */ movl $cpu_boot32_page_tables_start, %edi mov %edi, %cr3 /* Set LME bit in EFER */ /* 0xc0000080 = MSR_IA32_EFER */ movl $0xc0000080, %ecx rdmsr /* 0x00000100 = MSR_IA32_EFER_LME_BIT */ orl $0x00000100, %eax wrmsr /* Enable paging, protection, numeric error and co-processor monitoring in CR0 to enter long mode */ mov %cr0, %ebx /* 0x80000023 = (CR0_PG | CR0_PE | CR0_MP | CR0_NE) */ orl $0x80000023, %ebx mov %ebx, %cr0 /* Load temportary GDT pointer value */ mov $cpu_primary32_gdt_ptr, %ebx lgdt (%ebx) /* Perform a long jump based to start executing in 64-bit mode */ /* 0x0008 = HOST_GDT_RING0_CODE_SEL */ ljmp $0x0008, $primary_start_long_mode .code64 .org 0x200 .global cpu_primary_start_64 cpu_primary_start_64: /* save the MULTBOOT magic number & MBI */ lea boot_regs(%rip), %rax movl %edi, (%rax) movl %esi, 4(%rax) /* Save boot context from 64bit mode */ call cpu_primary_save_64 primary_start_long_mode: /* Initialize temporary stack pointer */ lea _ld_bss_end(%rip), %rsp /*0x1000 = CPU_PAGE_SIZE*/ add $0x1000,%rsp /* 16 = CPU_STACK_ALIGN */ and $(~(16 - 1)),%rsp /* * Fix up the .rela sections * Notes: this includes the fixup to IDT tables and temporary * page tables */ call _relocate /* Load temportary GDT pointer value */ lea cpu_primary32_gdt_ptr(%rip), %rbx lgdt (%ebx) /* Set the correct long jump address */ lea jmpbuf(%rip), %rax lea after(%rip), %rbx mov %rbx, (%rax) rex.w ljmp *(%rax) .data jmpbuf: .quad 0 /* 0x0008 = HOST_GDT_RING0_CODE_SEL */ .word 0x0008 .text after: // load all selector registers with appropriate values xor %edx, %edx lldt %dx /* 0x10 = HOST_GDT_RING0_DATA_SEL*/ movl $0x10,%eax mov %eax,%ss // Was 32bit POC Stack mov %eax,%ds // Was 32bit POC Data mov %eax,%es // Was 32bit POC Data mov %edx,%fs // Was 32bit POC Data mov %edx,%gs // Was 32bit POC CLS /* * Fix up the IDT desciptors * The relocation delta in IDT tables has been fixed in _relocate() */ leal HOST_IDT(%rip), %edx movl $HOST_IDT_ENTRIES, %ecx .fixup_idt_entries: xorl %eax, %eax xchgl %eax, 12(%edx) /* Set rsvd bits to 0; eax now has high 32 of entry point */ xchgl %eax, 8(%edx) /* Set bits 63..32 of entry point; eax now has low 32 of entry point */ movw %ax, (%edx) /* Set bits 0-15 of procedure entry point */ shr $16, %eax movw %ax, 6(%edx) /* Set bits 16-31 of entry point */ addl $X64_IDT_DESC_SIZE,%edx loop .fixup_idt_entries /* Load IDT */ lea HOST_IDTR(%rip), %rbx lidtq (%rbx) /* continue with chipset level initialization */ call bsp_boot_init loop: jmp loop .align 4 .global boot_regs boot_regs: .long 0x00000000 .long 0x00000000 /* GDT table */ .align 4 cpu_primary32_gdt: .quad 0x0000000000000000 .quad 0x00af9b000000ffff .quad 0x00cf93000000ffff cpu_primary32_gdt_end: /* GDT pointer */ .align 2 cpu_primary32_gdt_ptr: .short (cpu_primary32_gdt_end - cpu_primary32_gdt) - 1 .quad cpu_primary32_gdt /* PML4, PDPT, and PD tables initialized to map first 4 GBytes of memory */ /*0x1000 = CPU_PAGE_SIZE*/ .align 0x1000 .global cpu_boot32_page_tables_start cpu_boot32_page_tables_start: /* 0x3 = (PAGE_PRESENT | PAGE_RW) */ .quad cpu_primary32_pdpt_addr + 0x3 /*0x1000 = CPU_PAGE_SIZE*/ .align 0x1000 cpu_primary32_pdpt_addr: address = 0 .rept 4 /* 0x3 = (PAGE_PRESENT | PAGE_RW) */ .quad cpu_primary32_pdt_addr + address + 0x3 /*0x1000 = CPU_PAGE_SIZE*/ address = address + 0x1000 .endr /*0x1000 = CPU_PAGE_SIZE*/ .align 0x1000 cpu_primary32_pdt_addr: address = 0 .rept 2048 /* 0x83 = (PAGE_PSE | PAGE_PRESENT | PAGE_RW) */ .quad address + 0x83 address = address + 0x200000 .endr