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"
18879e7f07SLike 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__
find_highmem(void)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 */
setup_tss(u8 * stacktop)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 */
setup_tss(u8 * stacktop)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,
149*2821b32dSSean Christopherson (unsigned long)stacktop - PER_CPU_SIZE, 0xfffff, 0x93, 0xc0);
1507e33895dSPaolo Bonzini
1517e33895dSPaolo Bonzini return TSS_MAIN + id * 8;
1527e33895dSPaolo Bonzini }
15348a0145fSPaolo Bonzini #endif
15448a0145fSPaolo Bonzini
setup_multiboot(struct mbi_bootinfo * bi)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
setup_gdt_tss(void)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
setup_segments64(void)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
setup_memory_allocator(efi_bootinfo_t * efi_bootinfo)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
setup_rsdp(efi_bootinfo_t * efi_bootinfo)245b4e8c300SZixuan Wang static efi_status_t setup_rsdp(efi_bootinfo_t *efi_bootinfo)
2461ae9072eSZixuan Wang {
2471ae9072eSZixuan Wang efi_status_t status;
248169f786fSAlexandru Elisei struct acpi_table_rsdp *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
setup_page_table(void)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
setup_efi(efi_bootinfo_t * efi_bootinfo)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
setup_libcflat(void)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
save_id(void)3850b7501c3SVarad Gautam void save_id(void)
3860b7501c3SVarad Gautam {
3870b7501c3SVarad Gautam set_bit(apic_id(), online_cpus);
3880b7501c3SVarad Gautam }
3890b7501c3SVarad Gautam
ap_start64(void)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
bsp_rest_init(void)401d6d3a3bdSSean Christopherson void bsp_rest_init(void)
402d6d3a3bdSSean Christopherson {
403d6d3a3bdSSean Christopherson bringup_aps();
404d6d3a3bdSSean Christopherson enable_x2apic();
405d6d3a3bdSSean Christopherson smp_init();
406879e7f07SLike Xu pmu_init();
407d6d3a3bdSSean Christopherson }
408