1/* 2 * Copyright (C) 2018-2022 Intel Corporation. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7/* NOTE: 8 * 9 * MISRA C requires that all unsigned constants should have the suffix 'U' 10 * (e.g. 0xffU), but the assembler may not accept such C-style constants. For 11 * example, binutils 2.26 fails to compile assembly in that case. To work this 12 * around, all unsigned constants must be explicitly spells out in assembly 13 * with a comment tracking the original expression from which the magic 14 * number is calculated. As an example: 15 * 16 * /* 0x00000668 = 17 * * (CR4_DE | CR4_PAE | CR4_MCE | CR4_OSFXSR | CR4_OSXMMEXCPT) *\/ 18 * movl $0x00000668, %eax 19 * 20 * Make sure that these numbers are updated accordingly if the definition of 21 * the macros involved are changed. 22 */ 23 24#include <config.h> 25#include <multiboot_std.h> 26 27/* MULTIBOOT HEADER */ 28#define MULTIBOOT_HEADER_FLAGS MULTIBOOT_HEADER_NEED_MEMINFO 29 30 .extern cpu_primary_save32 31 .extern cpu_primary_save64 32 .section multiboot_header, "a" 33 34 .align 4 35 36 /* header magic */ 37 .long MULTIBOOT_HEADER_MAGIC 38 /* header flags - flags bit 6 : enable mmap_* */ 39 .long MULTIBOOT_HEADER_FLAGS 40 /* header checksum = -(magic + flags) */ 41 .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) 42 43#ifdef CONFIG_MULTIBOOT2 44 .align MULTIBOOT2_HEADER_ALIGN 45mb2_header_start: 46 /* Magic number indicating a Multiboot2 header. */ 47 .long MULTIBOOT2_HEADER_MAGIC 48 /* Architecture: i386. */ 49 .long MULTIBOOT2_ARCHITECTURE_I386 50 /* Multiboot2 header length. */ 51 .long mb2_header_end - mb2_header_start 52 /* Multiboot2 header checksum. */ 53 .long -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT2_ARCHITECTURE_I386 + (mb2_header_end - mb2_header_start)) 54 55 /* please be aware that each tag should be 8 bytes aligned */ 56 .align MULTIBOOT2_TAG_ALIGN 57 /* 58 * Request infomation from boot loader, which is supposed to provide th relevant information 59 * specified in the following tags to the image through the MBI if it is available 60 */ 61info_req_tag_start: 62 .short MULTIBOOT2_HEADER_TAG_INFORMATION_REQUEST 63 .short 0 64 .long info_req_tag_end - info_req_tag_start 65 .long MULTIBOOT2_TAG_TYPE_MMAP /* memory map */ 66 .long MULTIBOOT2_TAG_TYPE_MODULE /* boot modules infomation */ 67 .long MULTIBOOT2_TAG_TYPE_ACPI_NEW /* a copy of RSDP as defined per ACPI 2.0 or later specification */ 68 .long MULTIBOOT2_TAG_TYPE_EFI64 /* EFI system table, to be passed to guest Linux */ 69 .long MULTIBOOT2_TAG_TYPE_EFI_MMAP /* EFI memory map, to be passed to guest Linux */ 70info_req_tag_end: 71 72#ifdef CONFIG_RELOC 73 .align MULTIBOOT2_TAG_ALIGN 74address_tag_start: 75 .short MULTIBOOT2_HEADER_TAG_ADDRESS 76 .short 0 77 .long address_tag_end - address_tag_start 78 .long mb2_header_start /* address corresponding to the beginning of the Multiboot2 header */ 79 .long ld_ram_start /* load_addr: load from the binary's beginning */ 80 /* 81 * load_end_addr: this includes .bss so that boot loader could reserve the 82 * memory that .bss occupies to avoid placing boot modules or other data in that area. 83 * 84 * However, the boot loader is supposed not to actually load the .bss section because 85 * it's beyond the scope of acrn.bin 86 */ 87 .long ld_ram_end 88 .long 0 /* bss_end_addr, don't ask boot loader to clear .bss */ 89address_tag_end: 90 91 .align MULTIBOOT2_TAG_ALIGN 92entry_address_tag_start: 93 .short MULTIBOOT2_HEADER_TAG_ENTRY_ADDRESS 94 .short 0 95 .long entry_address_tag_end - entry_address_tag_start 96 .long cpu_primary_start_32 /* The address to which the boot loader should jump to start hypervisor */ 97entry_address_tag_end: 98 99 .align MULTIBOOT2_TAG_ALIGN 100relocatable_tag_start: 101 .short MULTIBOOT2_HEADER_TAG_RELOCATABLE 102 .short 0 103 .long relocatable_tag_end - relocatable_tag_start 104 .long CONFIG_HV_RAM_START /* min_addr */ 105 .long 0x80000000 /* max_addr */ 106 .long 0x200000 /* image alignment */ 107 .long 1 /* preference: lowest possible address */ 108relocatable_tag_end: 109#endif /* CONFIG_RELOC */ 110 111 .align MULTIBOOT2_TAG_ALIGN 112 .short MULTIBOOT2_HEADER_TAG_END 113 .short 0 114 .long 8 115mb2_header_end: 116#endif /* CONFIG_MULTIBOOT2 */ 117 118 /* 119 * The page tables are aligned to 4KB, which implicitly aligns this section at 120 * 4KB boundary. Put an extra .align here to explicitly state that regardless 121 * the actual length of the multiboot header section, this section will be linked 122 * at offset 0x1000 to the beginning of the target executable. 123 */ 124 .align 0x1000 125 .section entry, "ax" 126 .align 8 127 .code32 128 129 .global cpu_primary_start_32 130cpu_primary_start_32: 131 132 /* 133 * Calculate the relocation delta between where we were compiled to run 134 * at and where we were actually loaded at. 135 */ 136 call 0f 1370: pop %esi 138 sub $0b, %esi 139 140 /* save the MULTBOOT magic number & MBI */ 141 movl %eax, boot_regs(%esi) 142 movl %ebx, (boot_regs+4)(%esi) 143 144 /* Disable interrupts */ 145 cli 146 147 /* Clear direction flag */ 148 cld 149 150 /* detect whether it is in long mode 151 * 152 * 0xc0000080 = MSR_IA32_EFER 153 */ 154 movl $0xc0000080, %ecx 155 rdmsr 156 /* 0x400 = MSR_IA32_EFER_LMA_BIT */ 157 test $0x400, %eax 158 159 /* jump to 64bit entry if it is already in long mode */ 160 jne primary_start_long_mode 161 162 /* Disable paging */ 163 mov %cr0, %ebx 164 /* 0x7fffffff = ~CR0_PG */ 165 andl $0x7fffffff, %ebx 166 mov %ebx, %cr0 167 168 /* Set DE, PAE, MCE and OS support bits in CR4 169 * 0x00000668 = 170 * (CR4_DE | CR4_PAE | CR4_MCE | CR4_OSFXSR | CR4_OSXMMEXCPT) */ 171 movl $0x00000668, %eax 172 mov %eax, %cr4 173 174 /* fixup page table pointers with relocation delta */ 175 addl %esi, cpu_primary32_pdpt_addr(%esi) 176 addl %esi, (cpu_primary32_pdpt_addr+8)(%esi) 177 addl %esi, (cpu_primary32_pdpt_addr+16)(%esi) 178 addl %esi, (cpu_primary32_pdpt_addr+24)(%esi) 179 180 /* Set CR3 to PML4 table address */ 181 movl $cpu_boot32_page_tables_start, %edi 182 addl %esi, %edi 183 addl %esi, (%edi) 184 mov %edi, %cr3 185 186 /* Set LME bit in EFER */ 187 188 /* 0xc0000080 = MSR_IA32_EFER */ 189 movl $0xc0000080, %ecx 190 rdmsr 191 /* 0x00000100 = MSR_IA32_EFER_LME_BIT */ 192 orl $0x00000100, %eax 193 wrmsr 194 195 /* Enable paging, protection, numeric error and co-processor 196 monitoring in CR0 to enter long mode */ 197 mov %cr0, %ebx 198 /* 0x80000023 = (CR0_PG | CR0_PE | CR0_MP | CR0_NE) */ 199 orl $0x80000023, %ebx 200 mov %ebx, %cr0 201 202 /* Load temportary GDT pointer value */ 203 mov $cpu_primary32_gdt_ptr, %ebx 204 addl %esi, %ebx 205 addl %esi, 2(%ebx) 206 lgdt (%ebx) 207 208 /* Perform a long jump based to start executing in 64-bit mode */ 209 movl $jmpbuf_32, %eax 210 addl %esi, %eax 211 addl %esi, (%eax) 212 ljmp *(%eax) 213 214jmpbuf_32: 215 .long primary_start_long_mode 216 /* 0x0008 = HOST_GDT_RING0_CODE_SEL */ 217 .word 0x0008 218 219.code64 220primary_start_long_mode: 221 222 /* Initialize temporary stack pointer, size = 0x1000 */ 223 lea stack_for_boot(%rip), %rsp 224 /* 16 = CPU_STACK_ALIGN */ 225 and $(~(16 - 1)),%rsp 226 227 /* 228 * Fix up the .rela sections 229 * Notes: this includes the fixup to IDT tables and temporary 230 * page tables 231 */ 232 call relocate 233 234 call 0f 2350: pop %rsi 236 sub $0b, %rsi /* relocation delta */ 237 238 /* Load temportary GDT pointer value */ 239 lea cpu_primary64_gdt_ptr(%rip), %rbx 240 addq %rsi, 2(%rbx) 241 lgdt (%ebx) 242 243 /* Set the correct long jump address */ 244 lea jmpbuf_64(%rip), %rax 245 lea after(%rip), %rbx 246 mov %rbx, (%rax) 247 rex.w ljmp *(%rax) 248jmpbuf_64: .quad 0 249 /* 0x0008 = HOST_GDT_RING0_CODE_SEL */ 250 .word 0x0008 251 252after: 253 /* 0x10 = HOST_GDT_RING0_DATA_SEL*/ 254 movl $0x10,%eax 255 mov %eax,%ss // Was 32bit POC Stack 256 mov %eax,%ds // Was 32bit POC Data 257 mov %eax,%es // Was 32bit POC Data 258 mov %eax,%fs // Was 32bit POC Data 259 mov %eax,%gs // Was 32bit POC CLS 260 261 /* continue with chipset level initialization */ 262 call init_primary_pcpu 263 264loop: 265 jmp loop 266 267 .align 4 268 .global boot_regs 269boot_regs: 270 .long 0x00000000 271 .long 0x00000000 272 273 /* GDT table */ 274 .align 4 275cpu_primary32_gdt: 276 .quad 0x0000000000000000 277 .quad 0x00af9b000000ffff 278 .quad 0x00cf93000000ffff 279cpu_primary32_gdt_end: 280 281/* GDT pointer */ 282 .align 2 283cpu_primary32_gdt_ptr: 284 .short (cpu_primary32_gdt_end - cpu_primary32_gdt) - 1 285 .quad cpu_primary32_gdt 286 287cpu_primary64_gdt_ptr: 288 .short (cpu_primary32_gdt_end - cpu_primary32_gdt) - 1 289 .quad cpu_primary32_gdt 290 291/* PML4, PDPT, and PD tables initialized to map first 4 GBytes of memory */ 292 /*0x1000 = PAGE_SIZE*/ 293 .align 0x1000 294 .global cpu_boot32_page_tables_start 295cpu_boot32_page_tables_start: 296 /* 0x3 = (PAGE_PRESENT | PAGE_RW) */ 297 .quad cpu_primary32_pdpt_addr + 0x3 298 /*0x1000 = PAGE_SIZE*/ 299 .align 0x1000 300cpu_primary32_pdpt_addr: 301 address = 0 302 .rept 4 303 /* 0x3 = (PAGE_PRESENT | PAGE_RW) */ 304 .quad cpu_primary32_pdt_addr + address + 0x3 305 /*0x1000 = PAGE_SIZE*/ 306 address = address + 0x1000 307 .endr 308 /*0x1000 = PAGE_SIZE*/ 309 .align 0x1000 310cpu_primary32_pdt_addr: 311 address = 0 312 .rept 2048 313 /* 0x83 = (PAGE_PSE | PAGE_PRESENT | PAGE_RW) */ 314 .quad address + 0x83 315 address = address + 0x200000 316 .endr 317