193dd2aa3SAndrew Jones /* 293dd2aa3SAndrew Jones * Initialize machine setup information 393dd2aa3SAndrew Jones * 493dd2aa3SAndrew Jones * Copyright (C) 2017, Red Hat Inc, Andrew Jones <drjones@redhat.com> 5dbd38004SZixuan Wang * Copyright (C) 2021, Google Inc, Zixuan Wang <zixuanwang@google.com> 693dd2aa3SAndrew Jones * 793dd2aa3SAndrew Jones * This work is licensed under the terms of the GNU LGPL, version 2. 893dd2aa3SAndrew Jones */ 993dd2aa3SAndrew Jones #include "libcflat.h" 10716cea8aSPaolo Bonzini #include "fwcfg.h" 11716cea8aSPaolo Bonzini #include "alloc_phys.h" 1203b1e457SNadav Amit #include "argv.h" 13dbd38004SZixuan Wang #include "desc.h" 14dbd38004SZixuan Wang #include "apic.h" 15dbd38004SZixuan Wang #include "apic-defs.h" 16dbd38004SZixuan Wang #include "asm/setup.h" 170b7501c3SVarad Gautam #include "atomic.h" 18*879e7f07SLike Xu #include "pmu.h" 190b7501c3SVarad Gautam #include "processor.h" 200b7501c3SVarad Gautam #include "smp.h" 2193dd2aa3SAndrew Jones 22716cea8aSPaolo Bonzini extern char edata; 23716cea8aSPaolo Bonzini 24716cea8aSPaolo Bonzini struct mbi_bootinfo { 25716cea8aSPaolo Bonzini u32 flags; 26716cea8aSPaolo Bonzini u32 mem_lower; 27716cea8aSPaolo Bonzini u32 mem_upper; 28716cea8aSPaolo Bonzini u32 boot_device; 29716cea8aSPaolo Bonzini u32 cmdline; 30716cea8aSPaolo Bonzini u32 mods_count; 31716cea8aSPaolo Bonzini u32 mods_addr; 3248a0145fSPaolo Bonzini u32 reserved[4]; /* 28-43 */ 3348a0145fSPaolo Bonzini u32 mmap_length; 34716cea8aSPaolo Bonzini u32 mmap_addr; 35716cea8aSPaolo Bonzini u32 reserved0[3]; /* 52-63 */ 36716cea8aSPaolo Bonzini u32 bootloader; 37716cea8aSPaolo Bonzini u32 reserved1[5]; /* 68-87 */ 38716cea8aSPaolo Bonzini u32 size; 39716cea8aSPaolo Bonzini }; 40716cea8aSPaolo Bonzini 41716cea8aSPaolo Bonzini struct mbi_module { 42716cea8aSPaolo Bonzini u32 start, end; 43716cea8aSPaolo Bonzini u32 cmdline; 44716cea8aSPaolo Bonzini u32 unused; 45716cea8aSPaolo Bonzini }; 4693dd2aa3SAndrew Jones 4748a0145fSPaolo Bonzini struct mbi_mem { 4848a0145fSPaolo Bonzini u32 size; 4948a0145fSPaolo Bonzini u64 base_addr; 5048a0145fSPaolo Bonzini u64 length; 5148a0145fSPaolo Bonzini u32 type; 5248a0145fSPaolo Bonzini } __attribute__((packed)); 5348a0145fSPaolo Bonzini 543c7d322eSAndrew Jones #define ENV_SIZE 16384 553c7d322eSAndrew Jones 5606846df5SThomas Huth void setup_env(char *env, int size); 5706846df5SThomas Huth void setup_multiboot(struct mbi_bootinfo *bootinfo); 5806846df5SThomas Huth void setup_libcflat(void); 593c7d322eSAndrew Jones 6093dd2aa3SAndrew Jones char *initrd; 6193dd2aa3SAndrew Jones u32 initrd_size; 6293dd2aa3SAndrew Jones 633c7d322eSAndrew Jones static char env[ENV_SIZE]; 6448a0145fSPaolo Bonzini static struct mbi_bootinfo *bootinfo; 653c7d322eSAndrew Jones 6648a0145fSPaolo Bonzini #define HUGEPAGE_SIZE (1 << 21) 6748a0145fSPaolo Bonzini 6848a0145fSPaolo Bonzini #ifdef __x86_64__ 6948a0145fSPaolo Bonzini void find_highmem(void) 7048a0145fSPaolo Bonzini { 7148a0145fSPaolo Bonzini /* Memory above 4 GB is only supported on 64-bit systems. */ 7248a0145fSPaolo Bonzini if (!(bootinfo->flags & 64)) 7348a0145fSPaolo Bonzini return; 7448a0145fSPaolo Bonzini 7548a0145fSPaolo Bonzini u64 upper_end = bootinfo->mem_upper * 1024ull; 7648a0145fSPaolo Bonzini u64 best_start = (uintptr_t) &edata; 7748a0145fSPaolo Bonzini u64 best_end = upper_end; 78eb2db85dSNadav Amit u64 max_end = fwcfg_get_u64(FW_CFG_MAX_RAM); 79eb2db85dSNadav Amit if (max_end == 0) 80eb2db85dSNadav Amit max_end = -1ull; 8148a0145fSPaolo Bonzini bool found = false; 8248a0145fSPaolo Bonzini 8348a0145fSPaolo Bonzini uintptr_t mmap = bootinfo->mmap_addr; 8448a0145fSPaolo Bonzini while (mmap < bootinfo->mmap_addr + bootinfo->mmap_length) { 8548a0145fSPaolo Bonzini struct mbi_mem *mem = (void *)mmap; 8648a0145fSPaolo Bonzini mmap += mem->size + 4; 8748a0145fSPaolo Bonzini if (mem->type != 1) 8848a0145fSPaolo Bonzini continue; 8948a0145fSPaolo Bonzini if (mem->base_addr <= (uintptr_t) &edata || 9048a0145fSPaolo Bonzini (mem->base_addr <= upper_end && mem->base_addr + mem->length <= upper_end)) 9148a0145fSPaolo Bonzini continue; 9248a0145fSPaolo Bonzini if (mem->length < best_end - best_start) 9348a0145fSPaolo Bonzini continue; 94eb2db85dSNadav Amit if (mem->base_addr >= max_end) 95eb2db85dSNadav Amit continue; 9648a0145fSPaolo Bonzini best_start = mem->base_addr; 9748a0145fSPaolo Bonzini best_end = mem->base_addr + mem->length; 98eb2db85dSNadav Amit if (best_end > max_end) 99eb2db85dSNadav Amit best_end = max_end; 10048a0145fSPaolo Bonzini found = true; 10148a0145fSPaolo Bonzini } 10248a0145fSPaolo Bonzini 10348a0145fSPaolo Bonzini if (found) { 10448a0145fSPaolo Bonzini best_start = (best_start + HUGEPAGE_SIZE - 1) & -HUGEPAGE_SIZE; 10548a0145fSPaolo Bonzini best_end = best_end & -HUGEPAGE_SIZE; 10648a0145fSPaolo Bonzini phys_alloc_init(best_start, best_end - best_start); 10748a0145fSPaolo Bonzini } 10848a0145fSPaolo Bonzini } 109dbd38004SZixuan Wang 110dbd38004SZixuan Wang /* Setup TSS for the current processor, and return TSS offset within GDT */ 1117e33895dSPaolo Bonzini unsigned long setup_tss(u8 *stacktop) 112dbd38004SZixuan Wang { 113dbd38004SZixuan Wang u32 id; 114dbd38004SZixuan Wang tss64_t *tss_entry; 115dbd38004SZixuan Wang 116d8de5a33SSean Christopherson id = pre_boot_apic_id(); 117dbd38004SZixuan Wang 118dbd38004SZixuan Wang /* Runtime address of current TSS */ 119dbd38004SZixuan Wang tss_entry = &tss[id]; 120dbd38004SZixuan Wang 121dbd38004SZixuan Wang /* Update TSS */ 122dbd38004SZixuan Wang memset((void *)tss_entry, 0, sizeof(tss64_t)); 123dbd38004SZixuan Wang 124dbd38004SZixuan Wang /* Update TSS descriptors; each descriptor takes up 2 entries */ 125dbd38004SZixuan Wang set_gdt_entry(TSS_MAIN + id * 16, (unsigned long)tss_entry, 0xffff, 0x89, 0); 126dbd38004SZixuan Wang 127dbd38004SZixuan Wang return TSS_MAIN + id * 16; 128dbd38004SZixuan Wang } 1297e33895dSPaolo Bonzini #else 1307e33895dSPaolo Bonzini /* Setup TSS for the current processor, and return TSS offset within GDT */ 1317e33895dSPaolo Bonzini unsigned long setup_tss(u8 *stacktop) 1327e33895dSPaolo Bonzini { 1337e33895dSPaolo Bonzini u32 id; 1347e33895dSPaolo Bonzini tss32_t *tss_entry; 1357e33895dSPaolo Bonzini 136d8de5a33SSean Christopherson id = pre_boot_apic_id(); 1377e33895dSPaolo Bonzini 1387e33895dSPaolo Bonzini /* Runtime address of current TSS */ 1397e33895dSPaolo Bonzini tss_entry = &tss[id]; 1407e33895dSPaolo Bonzini 1417e33895dSPaolo Bonzini /* Update TSS */ 1427e33895dSPaolo Bonzini memset((void *)tss_entry, 0, sizeof(tss32_t)); 1437e33895dSPaolo Bonzini tss_entry->ss0 = KERNEL_DS; 1447e33895dSPaolo Bonzini 1457e33895dSPaolo Bonzini /* Update descriptors for TSS and percpu data segment. */ 1467e33895dSPaolo Bonzini set_gdt_entry(TSS_MAIN + id * 8, 1477e33895dSPaolo Bonzini (unsigned long)tss_entry, 0xffff, 0x89, 0); 1487e33895dSPaolo Bonzini set_gdt_entry(TSS_MAIN + MAX_TEST_CPUS * 8 + id * 8, 1497e33895dSPaolo Bonzini (unsigned long)stacktop - 4096, 0xfffff, 0x93, 0xc0); 1507e33895dSPaolo Bonzini 1517e33895dSPaolo Bonzini return TSS_MAIN + id * 8; 1527e33895dSPaolo Bonzini } 15348a0145fSPaolo Bonzini #endif 15448a0145fSPaolo Bonzini 15548a0145fSPaolo Bonzini void setup_multiboot(struct mbi_bootinfo *bi) 15693dd2aa3SAndrew Jones { 157716cea8aSPaolo Bonzini struct mbi_module *mods; 15893dd2aa3SAndrew Jones 15948a0145fSPaolo Bonzini bootinfo = bi; 16048a0145fSPaolo Bonzini 16148a0145fSPaolo Bonzini u64 best_start = (uintptr_t) &edata; 16248a0145fSPaolo Bonzini u64 best_end = bootinfo->mem_upper * 1024ull; 16348a0145fSPaolo Bonzini phys_alloc_init(best_start, best_end - best_start); 164cb67196aSPaolo Bonzini 165716cea8aSPaolo Bonzini if (bootinfo->mods_count != 1) 16693dd2aa3SAndrew Jones return; 16793dd2aa3SAndrew Jones 168716cea8aSPaolo Bonzini mods = (struct mbi_module *)(uintptr_t) bootinfo->mods_addr; 16993dd2aa3SAndrew Jones 170716cea8aSPaolo Bonzini initrd = (char *)(uintptr_t) mods->start; 171716cea8aSPaolo Bonzini initrd_size = mods->end - mods->start; 17293dd2aa3SAndrew Jones } 1733c7d322eSAndrew Jones 1740b7501c3SVarad Gautam static void setup_gdt_tss(void) 1750b7501c3SVarad Gautam { 1760b7501c3SVarad Gautam size_t tss_offset; 1770b7501c3SVarad Gautam 1780b7501c3SVarad Gautam /* 64-bit setup_tss does not use the stacktop argument. */ 1790b7501c3SVarad Gautam tss_offset = setup_tss(NULL); 1800b7501c3SVarad Gautam load_gdt_tss(tss_offset); 1810b7501c3SVarad Gautam } 1820b7501c3SVarad Gautam 183c98ce6e0SAlexandru Elisei #ifdef CONFIG_EFI 184ad5fb883SZixuan Wang 1853c50214cSVarad Gautam static struct percpu_data __percpu_data[MAX_TEST_CPUS]; 1863c50214cSVarad Gautam 18777b681d3SVarad Gautam static void setup_segments64(void) 18877b681d3SVarad Gautam { 18977b681d3SVarad Gautam /* Update data segments */ 19077b681d3SVarad Gautam write_ds(KERNEL_DS); 19177b681d3SVarad Gautam write_es(KERNEL_DS); 19277b681d3SVarad Gautam write_fs(KERNEL_DS); 19377b681d3SVarad Gautam write_gs(KERNEL_DS); 19477b681d3SVarad Gautam write_ss(KERNEL_DS); 19577b681d3SVarad Gautam 1963c50214cSVarad Gautam 19777b681d3SVarad Gautam /* 19877b681d3SVarad Gautam * Update the code segment by putting it on the stack before the return 19977b681d3SVarad Gautam * address, then doing a far return: this will use the new code segment 20077b681d3SVarad Gautam * along with the address. 20177b681d3SVarad Gautam */ 20277b681d3SVarad Gautam asm volatile("pushq %1\n\t" 20377b681d3SVarad Gautam "lea 1f(%%rip), %0\n\t" 20477b681d3SVarad Gautam "pushq %0\n\t" 20577b681d3SVarad Gautam "lretq\n\t" 20677b681d3SVarad Gautam "1:" 20777b681d3SVarad Gautam :: "r" ((u64)KERNEL_DS), "i" (KERNEL_CS)); 20877b681d3SVarad Gautam } 2093298643cSZixuan Wang 210b4e8c300SZixuan Wang static efi_status_t setup_memory_allocator(efi_bootinfo_t *efi_bootinfo) 2111ae9072eSZixuan Wang { 2121ae9072eSZixuan Wang int i; 213b4e8c300SZixuan Wang unsigned long free_mem_pages = 0; 214b4e8c300SZixuan Wang unsigned long free_mem_start = 0; 215b4e8c300SZixuan Wang struct efi_boot_memmap *map = &(efi_bootinfo->mem_map); 216b4e8c300SZixuan Wang efi_memory_desc_t *buffer = *map->map; 217b4e8c300SZixuan Wang efi_memory_desc_t *d = NULL; 2181ae9072eSZixuan Wang 2191ae9072eSZixuan Wang /* 2201ae9072eSZixuan Wang * The 'buffer' contains multiple descriptors that describe memory 2211ae9072eSZixuan Wang * regions maintained by UEFI. This code records the largest free 2221ae9072eSZixuan Wang * EFI_CONVENTIONAL_MEMORY region which will be used to set up the 2231ae9072eSZixuan Wang * memory allocator, so that the memory allocator can work in the 2241ae9072eSZixuan Wang * largest free continuous memory region. 2251ae9072eSZixuan Wang */ 226b4e8c300SZixuan Wang for (i = 0; i < *(map->map_size); i += *(map->desc_size)) { 2271ae9072eSZixuan Wang d = (efi_memory_desc_t *)(&((u8 *)buffer)[i]); 2281ae9072eSZixuan Wang if (d->type == EFI_CONVENTIONAL_MEMORY) { 229b4e8c300SZixuan Wang if (free_mem_pages < d->num_pages) { 230b4e8c300SZixuan Wang free_mem_pages = d->num_pages; 231b4e8c300SZixuan Wang free_mem_start = d->phys_addr; 2321ae9072eSZixuan Wang } 2331ae9072eSZixuan Wang } 2341ae9072eSZixuan Wang } 2351ae9072eSZixuan Wang 236b4e8c300SZixuan Wang if (free_mem_pages == 0) { 2371ae9072eSZixuan Wang return EFI_OUT_OF_RESOURCES; 2381ae9072eSZixuan Wang } 2391ae9072eSZixuan Wang 240b4e8c300SZixuan Wang phys_alloc_init(free_mem_start, free_mem_pages << EFI_PAGE_SHIFT); 241b4e8c300SZixuan Wang 2421ae9072eSZixuan Wang return EFI_SUCCESS; 2431ae9072eSZixuan Wang } 2441ae9072eSZixuan Wang 245b4e8c300SZixuan Wang static efi_status_t setup_rsdp(efi_bootinfo_t *efi_bootinfo) 2461ae9072eSZixuan Wang { 2471ae9072eSZixuan Wang efi_status_t status; 248b4e8c300SZixuan Wang struct rsdp_descriptor *rsdp; 2491ae9072eSZixuan Wang 250b4e8c300SZixuan Wang /* 251b4e8c300SZixuan Wang * RSDP resides in an EFI_ACPI_RECLAIM_MEMORY region, which is not used 252b4e8c300SZixuan Wang * by kvm-unit-tests x86's memory allocator. So it is not necessary to 253b4e8c300SZixuan Wang * copy the data structure to another memory region to prevent 254b4e8c300SZixuan Wang * unintentional overwrite. 255b4e8c300SZixuan Wang */ 256b4e8c300SZixuan Wang status = efi_get_system_config_table(ACPI_TABLE_GUID, (void **)&rsdp); 2571ae9072eSZixuan Wang if (status != EFI_SUCCESS) { 2581ae9072eSZixuan Wang return status; 2591ae9072eSZixuan Wang } 2601ae9072eSZixuan Wang 261b4e8c300SZixuan Wang set_efi_rsdp(rsdp); 262706ede18SZixuan Wang 2631ae9072eSZixuan Wang return EFI_SUCCESS; 2641ae9072eSZixuan Wang } 2651ae9072eSZixuan Wang 266e6f65fa4SZixuan Wang /* Defined in cstart64.S or efistart64.S */ 267e6f65fa4SZixuan Wang extern u8 ptl4; 268e6f65fa4SZixuan Wang extern u8 ptl3; 269e6f65fa4SZixuan Wang extern u8 ptl2; 270e6f65fa4SZixuan Wang 271e6f65fa4SZixuan Wang static void setup_page_table(void) 272e6f65fa4SZixuan Wang { 273e6f65fa4SZixuan Wang pgd_t *curr_pt; 274e6f65fa4SZixuan Wang phys_addr_t flags; 275e6f65fa4SZixuan Wang int i; 276e6f65fa4SZixuan Wang 277e6f65fa4SZixuan Wang /* Set default flags */ 278e6f65fa4SZixuan Wang flags = PT_PRESENT_MASK | PT_WRITABLE_MASK | PT_USER_MASK; 279e6f65fa4SZixuan Wang 280350bf64aSZixuan Wang /* Set AMD SEV C-Bit for page table entries */ 281350bf64aSZixuan Wang flags |= get_amd_sev_c_bit_mask(); 282350bf64aSZixuan Wang 283e6f65fa4SZixuan Wang /* Level 4 */ 284e6f65fa4SZixuan Wang curr_pt = (pgd_t *)&ptl4; 285e6f65fa4SZixuan Wang curr_pt[0] = ((phys_addr_t)&ptl3) | flags; 286e6f65fa4SZixuan Wang /* Level 3 */ 287e6f65fa4SZixuan Wang curr_pt = (pgd_t *)&ptl3; 288e6f65fa4SZixuan Wang for (i = 0; i < 4; i++) { 289e6f65fa4SZixuan Wang curr_pt[i] = (((phys_addr_t)&ptl2) + i * PAGE_SIZE) | flags; 290e6f65fa4SZixuan Wang } 291e6f65fa4SZixuan Wang /* Level 2 */ 292e6f65fa4SZixuan Wang curr_pt = (pgd_t *)&ptl2; 293e6f65fa4SZixuan Wang flags |= PT_ACCESSED_MASK | PT_DIRTY_MASK | PT_PAGE_SIZE_MASK | PT_GLOBAL_MASK; 294e6f65fa4SZixuan Wang for (i = 0; i < 4 * 512; i++) { 295832e1c15SVarad Gautam curr_pt[i] = ((phys_addr_t) i << 21) | flags; 296e6f65fa4SZixuan Wang } 297e6f65fa4SZixuan Wang 298b114aa57SZixuan Wang if (amd_sev_es_enabled()) { 299b114aa57SZixuan Wang setup_ghcb_pte((pgd_t *)&ptl4); 300b114aa57SZixuan Wang } 301b114aa57SZixuan Wang 302e6f65fa4SZixuan Wang /* Load 4-level page table */ 303e6f65fa4SZixuan Wang write_cr3((ulong)&ptl4); 304e6f65fa4SZixuan Wang } 305e6f65fa4SZixuan Wang 306b4e8c300SZixuan Wang efi_status_t setup_efi(efi_bootinfo_t *efi_bootinfo) 307ad5fb883SZixuan Wang { 308b4e8c300SZixuan Wang efi_status_t status; 3098238fdcaSPaolo Bonzini const char *phase; 310b4e8c300SZixuan Wang 311b4e8c300SZixuan Wang status = setup_memory_allocator(efi_bootinfo); 312b4e8c300SZixuan Wang if (status != EFI_SUCCESS) { 313b4e8c300SZixuan Wang printf("Failed to set up memory allocator: "); 314b4e8c300SZixuan Wang switch (status) { 315b4e8c300SZixuan Wang case EFI_OUT_OF_RESOURCES: 316b4e8c300SZixuan Wang printf("No free memory region\n"); 317b4e8c300SZixuan Wang break; 318b4e8c300SZixuan Wang default: 319b4e8c300SZixuan Wang printf("Unknown error\n"); 320b4e8c300SZixuan Wang break; 321b4e8c300SZixuan Wang } 322b4e8c300SZixuan Wang return status; 323b4e8c300SZixuan Wang } 324b4e8c300SZixuan Wang 325b4e8c300SZixuan Wang status = setup_rsdp(efi_bootinfo); 326b4e8c300SZixuan Wang if (status != EFI_SUCCESS) { 327b4e8c300SZixuan Wang printf("Cannot find RSDP in EFI system table\n"); 328b4e8c300SZixuan Wang return status; 329b4e8c300SZixuan Wang } 330b4e8c300SZixuan Wang 3318238fdcaSPaolo Bonzini phase = "AMD SEV"; 332b4e8c300SZixuan Wang status = setup_amd_sev(); 3338238fdcaSPaolo Bonzini 3348238fdcaSPaolo Bonzini /* Continue if AMD SEV is not supported, but skip SEV-ES setup */ 3358238fdcaSPaolo Bonzini if (status == EFI_SUCCESS) { 3368238fdcaSPaolo Bonzini phase = "AMD SEV-ES"; 3378238fdcaSPaolo Bonzini status = setup_amd_sev_es(); 338b4e8c300SZixuan Wang } 339b4e8c300SZixuan Wang 3408238fdcaSPaolo Bonzini if (status != EFI_SUCCESS && status != EFI_UNSUPPORTED) { 3418238fdcaSPaolo Bonzini printf("%s setup failed, error = 0x%lx\n", phase, status); 342b4e8c300SZixuan Wang return status; 343b4e8c300SZixuan Wang } 344b4e8c300SZixuan Wang 3453298643cSZixuan Wang setup_gdt_tss(); 34677b681d3SVarad Gautam setup_segments64(); 3474143d8a7SZixuan Wang setup_idt(); 3484143d8a7SZixuan Wang load_idt(); 349350e77c3SVasant Karasulli /* 350350e77c3SVasant Karasulli * Load GS.base with the per-vCPU data. This must be done after 351350e77c3SVasant Karasulli * loading the IDT as reading the APIC ID may #VC when running 352350e77c3SVasant Karasulli * as an SEV-ES guest 353350e77c3SVasant Karasulli */ 354350e77c3SVasant Karasulli wrmsr(MSR_GS_BASE, (u64)&__percpu_data[pre_boot_apic_id()]); 355350e77c3SVasant Karasulli /* 356350e77c3SVasant Karasulli * Resetting the APIC sets the per-vCPU APIC ops and so must be 357350e77c3SVasant Karasulli * done after loading GS.base with the per-vCPU data. 358350e77c3SVasant Karasulli */ 359350e77c3SVasant Karasulli reset_apic(); 360ad5fb883SZixuan Wang mask_pic_interrupts(); 3611542cd7bSVarad Gautam setup_page_table(); 362ad5fb883SZixuan Wang enable_apic(); 3630b7501c3SVarad Gautam save_id(); 364d6d3a3bdSSean Christopherson bsp_rest_init(); 365b4e8c300SZixuan Wang 366b4e8c300SZixuan Wang return EFI_SUCCESS; 367ad5fb883SZixuan Wang } 368ad5fb883SZixuan Wang 369c98ce6e0SAlexandru Elisei #endif /* CONFIG_EFI */ 370ad5fb883SZixuan Wang 371716cea8aSPaolo Bonzini void setup_libcflat(void) 3723c7d322eSAndrew Jones { 3733c7d322eSAndrew Jones if (initrd) { 3743c7d322eSAndrew Jones /* environ is currently the only file in the initrd */ 3753c7d322eSAndrew Jones u32 size = MIN(initrd_size, ENV_SIZE); 37603b1e457SNadav Amit const char *str; 37703b1e457SNadav Amit 3783c7d322eSAndrew Jones memcpy(env, initrd, size); 3793c7d322eSAndrew Jones setup_env(env, size); 38003b1e457SNadav Amit if ((str = getenv("BOOTLOADER")) && atol(str) != 0) 38103b1e457SNadav Amit add_setup_arg("bootloader"); 3823c7d322eSAndrew Jones } 3833c7d322eSAndrew Jones } 3840b7501c3SVarad Gautam 3850b7501c3SVarad Gautam void save_id(void) 3860b7501c3SVarad Gautam { 3870b7501c3SVarad Gautam set_bit(apic_id(), online_cpus); 3880b7501c3SVarad Gautam } 3890b7501c3SVarad Gautam 3900b7501c3SVarad Gautam void ap_start64(void) 3910b7501c3SVarad Gautam { 3920b7501c3SVarad Gautam setup_gdt_tss(); 3930b7501c3SVarad Gautam reset_apic(); 3940b7501c3SVarad Gautam load_idt(); 3950b7501c3SVarad Gautam save_id(); 3960b7501c3SVarad Gautam enable_apic(); 3970b7501c3SVarad Gautam enable_x2apic(); 398cd6bfb1dSSean Christopherson ap_online(); 3990b7501c3SVarad Gautam } 400d6d3a3bdSSean Christopherson 401d6d3a3bdSSean Christopherson void bsp_rest_init(void) 402d6d3a3bdSSean Christopherson { 403d6d3a3bdSSean Christopherson bringup_aps(); 404d6d3a3bdSSean Christopherson enable_x2apic(); 405d6d3a3bdSSean Christopherson smp_init(); 406*879e7f07SLike Xu pmu_init(); 407d6d3a3bdSSean Christopherson } 408