xref: /kvm-unit-tests/lib/x86/setup.c (revision 0afd4dd0d59f8ed6d3d92387daf410ac8290efe6)
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"
180b7501c3SVarad Gautam #include "processor.h"
190b7501c3SVarad Gautam #include "smp.h"
2093dd2aa3SAndrew Jones 
21716cea8aSPaolo Bonzini extern char edata;
22716cea8aSPaolo Bonzini 
23716cea8aSPaolo Bonzini struct mbi_bootinfo {
24716cea8aSPaolo Bonzini 	u32 flags;
25716cea8aSPaolo Bonzini 	u32 mem_lower;
26716cea8aSPaolo Bonzini 	u32 mem_upper;
27716cea8aSPaolo Bonzini 	u32 boot_device;
28716cea8aSPaolo Bonzini 	u32 cmdline;
29716cea8aSPaolo Bonzini 	u32 mods_count;
30716cea8aSPaolo Bonzini 	u32 mods_addr;
3148a0145fSPaolo Bonzini 	u32 reserved[4];   /* 28-43 */
3248a0145fSPaolo Bonzini 	u32 mmap_length;
33716cea8aSPaolo Bonzini 	u32 mmap_addr;
34716cea8aSPaolo Bonzini 	u32 reserved0[3];  /* 52-63 */
35716cea8aSPaolo Bonzini 	u32 bootloader;
36716cea8aSPaolo Bonzini 	u32 reserved1[5];  /* 68-87 */
37716cea8aSPaolo Bonzini 	u32 size;
38716cea8aSPaolo Bonzini };
39716cea8aSPaolo Bonzini 
40716cea8aSPaolo Bonzini struct mbi_module {
41716cea8aSPaolo Bonzini 	u32 start, end;
42716cea8aSPaolo Bonzini 	u32 cmdline;
43716cea8aSPaolo Bonzini 	u32 unused;
44716cea8aSPaolo Bonzini };
4593dd2aa3SAndrew Jones 
4648a0145fSPaolo Bonzini struct mbi_mem {
4748a0145fSPaolo Bonzini 	u32 size;
4848a0145fSPaolo Bonzini 	u64 base_addr;
4948a0145fSPaolo Bonzini 	u64 length;
5048a0145fSPaolo Bonzini 	u32 type;
5148a0145fSPaolo Bonzini } __attribute__((packed));
5248a0145fSPaolo Bonzini 
533c7d322eSAndrew Jones #define ENV_SIZE 16384
543c7d322eSAndrew Jones 
5506846df5SThomas Huth void setup_env(char *env, int size);
5606846df5SThomas Huth void setup_multiboot(struct mbi_bootinfo *bootinfo);
5706846df5SThomas Huth void setup_libcflat(void);
583c7d322eSAndrew Jones 
5993dd2aa3SAndrew Jones char *initrd;
6093dd2aa3SAndrew Jones u32 initrd_size;
6193dd2aa3SAndrew Jones 
623c7d322eSAndrew Jones static char env[ENV_SIZE];
6348a0145fSPaolo Bonzini static struct mbi_bootinfo *bootinfo;
643c7d322eSAndrew Jones 
6548a0145fSPaolo Bonzini #define HUGEPAGE_SIZE (1 << 21)
6648a0145fSPaolo Bonzini 
6748a0145fSPaolo Bonzini #ifdef __x86_64__
6848a0145fSPaolo Bonzini void find_highmem(void)
6948a0145fSPaolo Bonzini {
7048a0145fSPaolo Bonzini 	/* Memory above 4 GB is only supported on 64-bit systems.  */
7148a0145fSPaolo Bonzini 	if (!(bootinfo->flags & 64))
7248a0145fSPaolo Bonzini 	    	return;
7348a0145fSPaolo Bonzini 
7448a0145fSPaolo Bonzini 	u64 upper_end = bootinfo->mem_upper * 1024ull;
7548a0145fSPaolo Bonzini 	u64 best_start = (uintptr_t) &edata;
7648a0145fSPaolo Bonzini 	u64 best_end = upper_end;
77eb2db85dSNadav Amit 	u64 max_end = fwcfg_get_u64(FW_CFG_MAX_RAM);
78eb2db85dSNadav Amit 	if (max_end == 0)
79eb2db85dSNadav Amit 		max_end = -1ull;
8048a0145fSPaolo Bonzini 	bool found = false;
8148a0145fSPaolo Bonzini 
8248a0145fSPaolo Bonzini 	uintptr_t mmap = bootinfo->mmap_addr;
8348a0145fSPaolo Bonzini 	while (mmap < bootinfo->mmap_addr + bootinfo->mmap_length) {
8448a0145fSPaolo Bonzini 		struct mbi_mem *mem = (void *)mmap;
8548a0145fSPaolo Bonzini 		mmap += mem->size + 4;
8648a0145fSPaolo Bonzini 		if (mem->type != 1)
8748a0145fSPaolo Bonzini 			continue;
8848a0145fSPaolo Bonzini 		if (mem->base_addr <= (uintptr_t) &edata ||
8948a0145fSPaolo Bonzini 		    (mem->base_addr <= upper_end && mem->base_addr + mem->length <= upper_end))
9048a0145fSPaolo Bonzini 			continue;
9148a0145fSPaolo Bonzini 		if (mem->length < best_end - best_start)
9248a0145fSPaolo Bonzini 			continue;
93eb2db85dSNadav Amit 		if (mem->base_addr >= max_end)
94eb2db85dSNadav Amit 			continue;
9548a0145fSPaolo Bonzini 		best_start = mem->base_addr;
9648a0145fSPaolo Bonzini 		best_end = mem->base_addr + mem->length;
97eb2db85dSNadav Amit 		if (best_end > max_end)
98eb2db85dSNadav Amit 			best_end = max_end;
9948a0145fSPaolo Bonzini 		found = true;
10048a0145fSPaolo Bonzini 	}
10148a0145fSPaolo Bonzini 
10248a0145fSPaolo Bonzini 	if (found) {
10348a0145fSPaolo Bonzini 		best_start = (best_start + HUGEPAGE_SIZE - 1) & -HUGEPAGE_SIZE;
10448a0145fSPaolo Bonzini 		best_end = best_end & -HUGEPAGE_SIZE;
10548a0145fSPaolo Bonzini 		phys_alloc_init(best_start, best_end - best_start);
10648a0145fSPaolo Bonzini 	}
10748a0145fSPaolo Bonzini }
108dbd38004SZixuan Wang 
109dbd38004SZixuan Wang /* Setup TSS for the current processor, and return TSS offset within GDT */
1107e33895dSPaolo Bonzini unsigned long setup_tss(u8 *stacktop)
111dbd38004SZixuan Wang {
112dbd38004SZixuan Wang 	u32 id;
113dbd38004SZixuan Wang 	tss64_t *tss_entry;
114dbd38004SZixuan Wang 
115d8de5a33SSean Christopherson 	id = pre_boot_apic_id();
116dbd38004SZixuan Wang 
117dbd38004SZixuan Wang 	/* Runtime address of current TSS */
118dbd38004SZixuan Wang 	tss_entry = &tss[id];
119dbd38004SZixuan Wang 
120dbd38004SZixuan Wang 	/* Update TSS */
121dbd38004SZixuan Wang 	memset((void *)tss_entry, 0, sizeof(tss64_t));
122dbd38004SZixuan Wang 
123dbd38004SZixuan Wang 	/* Update TSS descriptors; each descriptor takes up 2 entries */
124dbd38004SZixuan Wang 	set_gdt_entry(TSS_MAIN + id * 16, (unsigned long)tss_entry, 0xffff, 0x89, 0);
125dbd38004SZixuan Wang 
126dbd38004SZixuan Wang 	return TSS_MAIN + id * 16;
127dbd38004SZixuan Wang }
1287e33895dSPaolo Bonzini #else
1297e33895dSPaolo Bonzini /* Setup TSS for the current processor, and return TSS offset within GDT */
1307e33895dSPaolo Bonzini unsigned long setup_tss(u8 *stacktop)
1317e33895dSPaolo Bonzini {
1327e33895dSPaolo Bonzini 	u32 id;
1337e33895dSPaolo Bonzini 	tss32_t *tss_entry;
1347e33895dSPaolo Bonzini 
135d8de5a33SSean Christopherson 	id = pre_boot_apic_id();
1367e33895dSPaolo Bonzini 
1377e33895dSPaolo Bonzini 	/* Runtime address of current TSS */
1387e33895dSPaolo Bonzini 	tss_entry = &tss[id];
1397e33895dSPaolo Bonzini 
1407e33895dSPaolo Bonzini 	/* Update TSS */
1417e33895dSPaolo Bonzini 	memset((void *)tss_entry, 0, sizeof(tss32_t));
1427e33895dSPaolo Bonzini 	tss_entry->ss0 = KERNEL_DS;
1437e33895dSPaolo Bonzini 
1447e33895dSPaolo Bonzini 	/* Update descriptors for TSS and percpu data segment.  */
1457e33895dSPaolo Bonzini 	set_gdt_entry(TSS_MAIN + id * 8,
1467e33895dSPaolo Bonzini 		      (unsigned long)tss_entry, 0xffff, 0x89, 0);
1477e33895dSPaolo Bonzini 	set_gdt_entry(TSS_MAIN + MAX_TEST_CPUS * 8 + id * 8,
1487e33895dSPaolo Bonzini 		      (unsigned long)stacktop - 4096, 0xfffff, 0x93, 0xc0);
1497e33895dSPaolo Bonzini 
1507e33895dSPaolo Bonzini 	return TSS_MAIN + id * 8;
1517e33895dSPaolo Bonzini }
15248a0145fSPaolo Bonzini #endif
15348a0145fSPaolo Bonzini 
15448a0145fSPaolo Bonzini void setup_multiboot(struct mbi_bootinfo *bi)
15593dd2aa3SAndrew Jones {
156716cea8aSPaolo Bonzini 	struct mbi_module *mods;
15793dd2aa3SAndrew Jones 
15848a0145fSPaolo Bonzini 	bootinfo = bi;
15948a0145fSPaolo Bonzini 
16048a0145fSPaolo Bonzini 	u64 best_start = (uintptr_t) &edata;
16148a0145fSPaolo Bonzini 	u64 best_end = bootinfo->mem_upper * 1024ull;
16248a0145fSPaolo Bonzini 	phys_alloc_init(best_start, best_end - best_start);
163cb67196aSPaolo Bonzini 
164716cea8aSPaolo Bonzini 	if (bootinfo->mods_count != 1)
16593dd2aa3SAndrew Jones 		return;
16693dd2aa3SAndrew Jones 
167716cea8aSPaolo Bonzini 	mods = (struct mbi_module *)(uintptr_t) bootinfo->mods_addr;
16893dd2aa3SAndrew Jones 
169716cea8aSPaolo Bonzini 	initrd = (char *)(uintptr_t) mods->start;
170716cea8aSPaolo Bonzini 	initrd_size = mods->end - mods->start;
17193dd2aa3SAndrew Jones }
1723c7d322eSAndrew Jones 
1730b7501c3SVarad Gautam static void setup_gdt_tss(void)
1740b7501c3SVarad Gautam {
1750b7501c3SVarad Gautam 	size_t tss_offset;
1760b7501c3SVarad Gautam 
1770b7501c3SVarad Gautam 	/* 64-bit setup_tss does not use the stacktop argument.  */
1780b7501c3SVarad Gautam 	tss_offset = setup_tss(NULL);
1790b7501c3SVarad Gautam 	load_gdt_tss(tss_offset);
1800b7501c3SVarad Gautam }
1810b7501c3SVarad Gautam 
182c98ce6e0SAlexandru Elisei #ifdef CONFIG_EFI
183ad5fb883SZixuan Wang 
1843c50214cSVarad Gautam static struct percpu_data __percpu_data[MAX_TEST_CPUS];
1853c50214cSVarad Gautam 
18677b681d3SVarad Gautam static void setup_segments64(void)
18777b681d3SVarad Gautam {
18877b681d3SVarad Gautam 	/* Update data segments */
18977b681d3SVarad Gautam 	write_ds(KERNEL_DS);
19077b681d3SVarad Gautam 	write_es(KERNEL_DS);
19177b681d3SVarad Gautam 	write_fs(KERNEL_DS);
19277b681d3SVarad Gautam 	write_gs(KERNEL_DS);
19377b681d3SVarad Gautam 	write_ss(KERNEL_DS);
19477b681d3SVarad Gautam 
1953c50214cSVarad Gautam 	/* Setup percpu base */
1963c50214cSVarad Gautam 	wrmsr(MSR_GS_BASE, (u64)&__percpu_data[pre_boot_apic_id()]);
1973c50214cSVarad Gautam 
19877b681d3SVarad Gautam 	/*
19977b681d3SVarad Gautam 	 * Update the code segment by putting it on the stack before the return
20077b681d3SVarad Gautam 	 * address, then doing a far return: this will use the new code segment
20177b681d3SVarad Gautam 	 * along with the address.
20277b681d3SVarad Gautam 	 */
20377b681d3SVarad Gautam 	asm volatile("pushq %1\n\t"
20477b681d3SVarad Gautam 		     "lea 1f(%%rip), %0\n\t"
20577b681d3SVarad Gautam 		     "pushq %0\n\t"
20677b681d3SVarad Gautam 		     "lretq\n\t"
20777b681d3SVarad Gautam 		     "1:"
20877b681d3SVarad Gautam 		     :: "r" ((u64)KERNEL_DS), "i" (KERNEL_CS));
20977b681d3SVarad Gautam }
2103298643cSZixuan Wang 
211b4e8c300SZixuan Wang static efi_status_t setup_memory_allocator(efi_bootinfo_t *efi_bootinfo)
2121ae9072eSZixuan Wang {
2131ae9072eSZixuan Wang 	int i;
214b4e8c300SZixuan Wang 	unsigned long free_mem_pages = 0;
215b4e8c300SZixuan Wang 	unsigned long free_mem_start = 0;
216b4e8c300SZixuan Wang 	struct efi_boot_memmap *map = &(efi_bootinfo->mem_map);
217b4e8c300SZixuan Wang 	efi_memory_desc_t *buffer = *map->map;
218b4e8c300SZixuan Wang 	efi_memory_desc_t *d = NULL;
2191ae9072eSZixuan Wang 
2201ae9072eSZixuan Wang 	/*
2211ae9072eSZixuan Wang 	 * The 'buffer' contains multiple descriptors that describe memory
2221ae9072eSZixuan Wang 	 * regions maintained by UEFI. This code records the largest free
2231ae9072eSZixuan Wang 	 * EFI_CONVENTIONAL_MEMORY region which will be used to set up the
2241ae9072eSZixuan Wang 	 * memory allocator, so that the memory allocator can work in the
2251ae9072eSZixuan Wang 	 * largest free continuous memory region.
2261ae9072eSZixuan Wang 	 */
227b4e8c300SZixuan Wang 	for (i = 0; i < *(map->map_size); i += *(map->desc_size)) {
2281ae9072eSZixuan Wang 		d = (efi_memory_desc_t *)(&((u8 *)buffer)[i]);
2291ae9072eSZixuan Wang 		if (d->type == EFI_CONVENTIONAL_MEMORY) {
230b4e8c300SZixuan Wang 			if (free_mem_pages < d->num_pages) {
231b4e8c300SZixuan Wang 				free_mem_pages = d->num_pages;
232b4e8c300SZixuan Wang 				free_mem_start = d->phys_addr;
2331ae9072eSZixuan Wang 			}
2341ae9072eSZixuan Wang 		}
2351ae9072eSZixuan Wang 	}
2361ae9072eSZixuan Wang 
237b4e8c300SZixuan Wang 	if (free_mem_pages == 0) {
2381ae9072eSZixuan Wang 		return EFI_OUT_OF_RESOURCES;
2391ae9072eSZixuan Wang 	}
2401ae9072eSZixuan Wang 
241b4e8c300SZixuan Wang 	phys_alloc_init(free_mem_start, free_mem_pages << EFI_PAGE_SHIFT);
242b4e8c300SZixuan Wang 
2431ae9072eSZixuan Wang 	return EFI_SUCCESS;
2441ae9072eSZixuan Wang }
2451ae9072eSZixuan Wang 
246b4e8c300SZixuan Wang static efi_status_t setup_rsdp(efi_bootinfo_t *efi_bootinfo)
2471ae9072eSZixuan Wang {
2481ae9072eSZixuan Wang 	efi_status_t status;
249b4e8c300SZixuan Wang 	struct rsdp_descriptor *rsdp;
2501ae9072eSZixuan Wang 
251b4e8c300SZixuan Wang 	/*
252b4e8c300SZixuan Wang 	 * RSDP resides in an EFI_ACPI_RECLAIM_MEMORY region, which is not used
253b4e8c300SZixuan Wang 	 * by kvm-unit-tests x86's memory allocator. So it is not necessary to
254b4e8c300SZixuan Wang 	 * copy the data structure to another memory region to prevent
255b4e8c300SZixuan Wang 	 * unintentional overwrite.
256b4e8c300SZixuan Wang 	 */
257b4e8c300SZixuan Wang 	status = efi_get_system_config_table(ACPI_TABLE_GUID, (void **)&rsdp);
2581ae9072eSZixuan Wang 	if (status != EFI_SUCCESS) {
2591ae9072eSZixuan Wang 		return status;
2601ae9072eSZixuan Wang 	}
2611ae9072eSZixuan Wang 
262b4e8c300SZixuan Wang 	set_efi_rsdp(rsdp);
263706ede18SZixuan Wang 
2641ae9072eSZixuan Wang 	return EFI_SUCCESS;
2651ae9072eSZixuan Wang }
2661ae9072eSZixuan Wang 
267e6f65fa4SZixuan Wang /* Defined in cstart64.S or efistart64.S */
268e6f65fa4SZixuan Wang extern u8 ptl4;
269e6f65fa4SZixuan Wang extern u8 ptl3;
270e6f65fa4SZixuan Wang extern u8 ptl2;
271e6f65fa4SZixuan Wang 
272e6f65fa4SZixuan Wang static void setup_page_table(void)
273e6f65fa4SZixuan Wang {
274e6f65fa4SZixuan Wang 	pgd_t *curr_pt;
275e6f65fa4SZixuan Wang 	phys_addr_t flags;
276e6f65fa4SZixuan Wang 	int i;
277e6f65fa4SZixuan Wang 
278e6f65fa4SZixuan Wang 	/* Set default flags */
279e6f65fa4SZixuan Wang 	flags = PT_PRESENT_MASK | PT_WRITABLE_MASK | PT_USER_MASK;
280e6f65fa4SZixuan Wang 
281350bf64aSZixuan Wang 	/* Set AMD SEV C-Bit for page table entries */
282350bf64aSZixuan Wang 	flags |= get_amd_sev_c_bit_mask();
283350bf64aSZixuan Wang 
284e6f65fa4SZixuan Wang 	/* Level 4 */
285e6f65fa4SZixuan Wang 	curr_pt = (pgd_t *)&ptl4;
286e6f65fa4SZixuan Wang 	curr_pt[0] = ((phys_addr_t)&ptl3) | flags;
287e6f65fa4SZixuan Wang 	/* Level 3 */
288e6f65fa4SZixuan Wang 	curr_pt = (pgd_t *)&ptl3;
289e6f65fa4SZixuan Wang 	for (i = 0; i < 4; i++) {
290e6f65fa4SZixuan Wang 		curr_pt[i] = (((phys_addr_t)&ptl2) + i * PAGE_SIZE) | flags;
291e6f65fa4SZixuan Wang 	}
292e6f65fa4SZixuan Wang 	/* Level 2 */
293e6f65fa4SZixuan Wang 	curr_pt = (pgd_t *)&ptl2;
294e6f65fa4SZixuan Wang 	flags |= PT_ACCESSED_MASK | PT_DIRTY_MASK | PT_PAGE_SIZE_MASK | PT_GLOBAL_MASK;
295e6f65fa4SZixuan Wang 	for (i = 0; i < 4 * 512; i++)	{
296832e1c15SVarad Gautam 		curr_pt[i] = ((phys_addr_t) i << 21) | flags;
297e6f65fa4SZixuan Wang 	}
298e6f65fa4SZixuan Wang 
299b114aa57SZixuan Wang 	if (amd_sev_es_enabled()) {
300b114aa57SZixuan Wang 		setup_ghcb_pte((pgd_t *)&ptl4);
301b114aa57SZixuan Wang 	}
302b114aa57SZixuan Wang 
303e6f65fa4SZixuan Wang 	/* Load 4-level page table */
304e6f65fa4SZixuan Wang 	write_cr3((ulong)&ptl4);
305e6f65fa4SZixuan Wang }
306e6f65fa4SZixuan Wang 
307b4e8c300SZixuan Wang efi_status_t setup_efi(efi_bootinfo_t *efi_bootinfo)
308ad5fb883SZixuan Wang {
309b4e8c300SZixuan Wang 	efi_status_t status;
3108238fdcaSPaolo Bonzini 	const char *phase;
311b4e8c300SZixuan Wang 
312b4e8c300SZixuan Wang 	status = setup_memory_allocator(efi_bootinfo);
313b4e8c300SZixuan Wang 	if (status != EFI_SUCCESS) {
314b4e8c300SZixuan Wang 		printf("Failed to set up memory allocator: ");
315b4e8c300SZixuan Wang 		switch (status) {
316b4e8c300SZixuan Wang 		case EFI_OUT_OF_RESOURCES:
317b4e8c300SZixuan Wang 			printf("No free memory region\n");
318b4e8c300SZixuan Wang 			break;
319b4e8c300SZixuan Wang 		default:
320b4e8c300SZixuan Wang 			printf("Unknown error\n");
321b4e8c300SZixuan Wang 			break;
322b4e8c300SZixuan Wang 		}
323b4e8c300SZixuan Wang 		return status;
324b4e8c300SZixuan Wang 	}
325b4e8c300SZixuan Wang 
326b4e8c300SZixuan Wang 	status = setup_rsdp(efi_bootinfo);
327b4e8c300SZixuan Wang 	if (status != EFI_SUCCESS) {
328b4e8c300SZixuan Wang 		printf("Cannot find RSDP in EFI system table\n");
329b4e8c300SZixuan Wang 		return status;
330b4e8c300SZixuan Wang 	}
331b4e8c300SZixuan Wang 
3328238fdcaSPaolo Bonzini 	phase = "AMD SEV";
333b4e8c300SZixuan Wang 	status = setup_amd_sev();
3348238fdcaSPaolo Bonzini 
3358238fdcaSPaolo Bonzini 	/* Continue if AMD SEV is not supported, but skip SEV-ES setup */
3368238fdcaSPaolo Bonzini 	if (status == EFI_SUCCESS) {
3378238fdcaSPaolo Bonzini 		phase = "AMD SEV-ES";
3388238fdcaSPaolo Bonzini 		status = setup_amd_sev_es();
339b4e8c300SZixuan Wang 	}
340b4e8c300SZixuan Wang 
3418238fdcaSPaolo Bonzini 	if (status != EFI_SUCCESS && status != EFI_UNSUPPORTED) {
3428238fdcaSPaolo Bonzini 		printf("%s setup failed, error = 0x%lx\n", phase, status);
343b4e8c300SZixuan Wang 		return status;
344b4e8c300SZixuan Wang 	}
345b4e8c300SZixuan Wang 
3463298643cSZixuan Wang 	setup_gdt_tss();
3473c50214cSVarad Gautam 	/*
3483c50214cSVarad Gautam 	 * GS.base, which points at the per-vCPU data, must be configured prior
3493c50214cSVarad Gautam 	 * to resetting the APIC, which sets the per-vCPU APIC ops.
3503c50214cSVarad Gautam 	 */
35177b681d3SVarad Gautam 	setup_segments64();
3523c50214cSVarad Gautam 	reset_apic();
3534143d8a7SZixuan Wang 	setup_idt();
3544143d8a7SZixuan Wang 	load_idt();
355ad5fb883SZixuan Wang 	mask_pic_interrupts();
3561542cd7bSVarad Gautam 	setup_page_table();
357ad5fb883SZixuan Wang 	enable_apic();
3580b7501c3SVarad Gautam 	save_id();
359*0afd4dd0SSean Christopherson 	bringup_aps();
360ad5fb883SZixuan Wang 	enable_x2apic();
361ad5fb883SZixuan Wang 	smp_init();
362b4e8c300SZixuan Wang 
363b4e8c300SZixuan Wang 	return EFI_SUCCESS;
364ad5fb883SZixuan Wang }
365ad5fb883SZixuan Wang 
366c98ce6e0SAlexandru Elisei #endif /* CONFIG_EFI */
367ad5fb883SZixuan Wang 
368716cea8aSPaolo Bonzini void setup_libcflat(void)
3693c7d322eSAndrew Jones {
3703c7d322eSAndrew Jones 	if (initrd) {
3713c7d322eSAndrew Jones 		/* environ is currently the only file in the initrd */
3723c7d322eSAndrew Jones 		u32 size = MIN(initrd_size, ENV_SIZE);
37303b1e457SNadav Amit 		const char *str;
37403b1e457SNadav Amit 
3753c7d322eSAndrew Jones 		memcpy(env, initrd, size);
3763c7d322eSAndrew Jones 		setup_env(env, size);
37703b1e457SNadav Amit 		if ((str = getenv("BOOTLOADER")) && atol(str) != 0)
37803b1e457SNadav Amit 			add_setup_arg("bootloader");
3793c7d322eSAndrew Jones 	}
3803c7d322eSAndrew Jones }
3810b7501c3SVarad Gautam 
3820b7501c3SVarad Gautam void save_id(void)
3830b7501c3SVarad Gautam {
3840b7501c3SVarad Gautam 	set_bit(apic_id(), online_cpus);
3850b7501c3SVarad Gautam }
3860b7501c3SVarad Gautam 
3870b7501c3SVarad Gautam void ap_start64(void)
3880b7501c3SVarad Gautam {
3890b7501c3SVarad Gautam 	setup_gdt_tss();
3900b7501c3SVarad Gautam 	reset_apic();
3910b7501c3SVarad Gautam 	load_idt();
3920b7501c3SVarad Gautam 	save_id();
3930b7501c3SVarad Gautam 	enable_apic();
3940b7501c3SVarad Gautam 	enable_x2apic();
3950b7501c3SVarad Gautam 	sti();
3960b7501c3SVarad Gautam 	asm volatile ("nop");
3970b7501c3SVarad Gautam 	printf("setup: AP %d online\n", apic_id());
3980b7501c3SVarad Gautam 	atomic_inc(&cpu_online_count);
3990b7501c3SVarad Gautam 
4000b7501c3SVarad Gautam 	/* Only the BSP runs the test's main(), APs are given work via IPIs. */
4010b7501c3SVarad Gautam 	for (;;)
4020b7501c3SVarad Gautam 		asm volatile("hlt");
4030b7501c3SVarad Gautam }
404