xref: /kvm-unit-tests/lib/x86/setup.c (revision dbd3800490429358367c717669aab76678429ef1)
193dd2aa3SAndrew Jones /*
293dd2aa3SAndrew Jones  * Initialize machine setup information
393dd2aa3SAndrew Jones  *
493dd2aa3SAndrew Jones  * Copyright (C) 2017, Red Hat Inc, Andrew Jones <drjones@redhat.com>
5*dbd38004SZixuan 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"
13*dbd38004SZixuan Wang #include "desc.h"
14*dbd38004SZixuan Wang #include "apic.h"
15*dbd38004SZixuan Wang #include "apic-defs.h"
16*dbd38004SZixuan Wang #include "asm/setup.h"
1793dd2aa3SAndrew Jones 
18716cea8aSPaolo Bonzini extern char edata;
19716cea8aSPaolo Bonzini 
20716cea8aSPaolo Bonzini struct mbi_bootinfo {
21716cea8aSPaolo Bonzini 	u32 flags;
22716cea8aSPaolo Bonzini 	u32 mem_lower;
23716cea8aSPaolo Bonzini 	u32 mem_upper;
24716cea8aSPaolo Bonzini 	u32 boot_device;
25716cea8aSPaolo Bonzini 	u32 cmdline;
26716cea8aSPaolo Bonzini 	u32 mods_count;
27716cea8aSPaolo Bonzini 	u32 mods_addr;
2848a0145fSPaolo Bonzini 	u32 reserved[4];   /* 28-43 */
2948a0145fSPaolo Bonzini 	u32 mmap_length;
30716cea8aSPaolo Bonzini 	u32 mmap_addr;
31716cea8aSPaolo Bonzini 	u32 reserved0[3];  /* 52-63 */
32716cea8aSPaolo Bonzini 	u32 bootloader;
33716cea8aSPaolo Bonzini 	u32 reserved1[5];  /* 68-87 */
34716cea8aSPaolo Bonzini 	u32 size;
35716cea8aSPaolo Bonzini };
36716cea8aSPaolo Bonzini 
37716cea8aSPaolo Bonzini struct mbi_module {
38716cea8aSPaolo Bonzini 	u32 start, end;
39716cea8aSPaolo Bonzini 	u32 cmdline;
40716cea8aSPaolo Bonzini 	u32 unused;
41716cea8aSPaolo Bonzini };
4293dd2aa3SAndrew Jones 
4348a0145fSPaolo Bonzini struct mbi_mem {
4448a0145fSPaolo Bonzini 	u32 size;
4548a0145fSPaolo Bonzini 	u64 base_addr;
4648a0145fSPaolo Bonzini 	u64 length;
4748a0145fSPaolo Bonzini 	u32 type;
4848a0145fSPaolo Bonzini } __attribute__((packed));
4948a0145fSPaolo Bonzini 
503c7d322eSAndrew Jones #define ENV_SIZE 16384
513c7d322eSAndrew Jones 
5206846df5SThomas Huth void setup_env(char *env, int size);
5306846df5SThomas Huth void setup_multiboot(struct mbi_bootinfo *bootinfo);
5406846df5SThomas Huth void setup_libcflat(void);
553c7d322eSAndrew Jones 
5693dd2aa3SAndrew Jones char *initrd;
5793dd2aa3SAndrew Jones u32 initrd_size;
5893dd2aa3SAndrew Jones 
593c7d322eSAndrew Jones static char env[ENV_SIZE];
6048a0145fSPaolo Bonzini static struct mbi_bootinfo *bootinfo;
613c7d322eSAndrew Jones 
6248a0145fSPaolo Bonzini #define HUGEPAGE_SIZE (1 << 21)
6348a0145fSPaolo Bonzini 
6448a0145fSPaolo Bonzini #ifdef __x86_64__
6548a0145fSPaolo Bonzini void find_highmem(void)
6648a0145fSPaolo Bonzini {
6748a0145fSPaolo Bonzini 	/* Memory above 4 GB is only supported on 64-bit systems.  */
6848a0145fSPaolo Bonzini 	if (!(bootinfo->flags & 64))
6948a0145fSPaolo Bonzini 	    	return;
7048a0145fSPaolo Bonzini 
7148a0145fSPaolo Bonzini 	u64 upper_end = bootinfo->mem_upper * 1024ull;
7248a0145fSPaolo Bonzini 	u64 best_start = (uintptr_t) &edata;
7348a0145fSPaolo Bonzini 	u64 best_end = upper_end;
74eb2db85dSNadav Amit 	u64 max_end = fwcfg_get_u64(FW_CFG_MAX_RAM);
75eb2db85dSNadav Amit 	if (max_end == 0)
76eb2db85dSNadav Amit 		max_end = -1ull;
7748a0145fSPaolo Bonzini 	bool found = false;
7848a0145fSPaolo Bonzini 
7948a0145fSPaolo Bonzini 	uintptr_t mmap = bootinfo->mmap_addr;
8048a0145fSPaolo Bonzini 	while (mmap < bootinfo->mmap_addr + bootinfo->mmap_length) {
8148a0145fSPaolo Bonzini 		struct mbi_mem *mem = (void *)mmap;
8248a0145fSPaolo Bonzini 		mmap += mem->size + 4;
8348a0145fSPaolo Bonzini 		if (mem->type != 1)
8448a0145fSPaolo Bonzini 			continue;
8548a0145fSPaolo Bonzini 		if (mem->base_addr <= (uintptr_t) &edata ||
8648a0145fSPaolo Bonzini 		    (mem->base_addr <= upper_end && mem->base_addr + mem->length <= upper_end))
8748a0145fSPaolo Bonzini 			continue;
8848a0145fSPaolo Bonzini 		if (mem->length < best_end - best_start)
8948a0145fSPaolo Bonzini 			continue;
90eb2db85dSNadav Amit 		if (mem->base_addr >= max_end)
91eb2db85dSNadav Amit 			continue;
9248a0145fSPaolo Bonzini 		best_start = mem->base_addr;
9348a0145fSPaolo Bonzini 		best_end = mem->base_addr + mem->length;
94eb2db85dSNadav Amit 		if (best_end > max_end)
95eb2db85dSNadav Amit 			best_end = max_end;
9648a0145fSPaolo Bonzini 		found = true;
9748a0145fSPaolo Bonzini 	}
9848a0145fSPaolo Bonzini 
9948a0145fSPaolo Bonzini 	if (found) {
10048a0145fSPaolo Bonzini 		best_start = (best_start + HUGEPAGE_SIZE - 1) & -HUGEPAGE_SIZE;
10148a0145fSPaolo Bonzini 		best_end = best_end & -HUGEPAGE_SIZE;
10248a0145fSPaolo Bonzini 		phys_alloc_init(best_start, best_end - best_start);
10348a0145fSPaolo Bonzini 	}
10448a0145fSPaolo Bonzini }
105*dbd38004SZixuan Wang 
106*dbd38004SZixuan Wang /* Setup TSS for the current processor, and return TSS offset within GDT */
107*dbd38004SZixuan Wang unsigned long setup_tss(void)
108*dbd38004SZixuan Wang {
109*dbd38004SZixuan Wang 	u32 id;
110*dbd38004SZixuan Wang 	tss64_t *tss_entry;
111*dbd38004SZixuan Wang 
112*dbd38004SZixuan Wang 	id = apic_id();
113*dbd38004SZixuan Wang 
114*dbd38004SZixuan Wang 	/* Runtime address of current TSS */
115*dbd38004SZixuan Wang 	tss_entry = &tss[id];
116*dbd38004SZixuan Wang 
117*dbd38004SZixuan Wang 	/* Update TSS */
118*dbd38004SZixuan Wang 	memset((void *)tss_entry, 0, sizeof(tss64_t));
119*dbd38004SZixuan Wang 
120*dbd38004SZixuan Wang 	/* Update TSS descriptors; each descriptor takes up 2 entries */
121*dbd38004SZixuan Wang 	set_gdt_entry(TSS_MAIN + id * 16, (unsigned long)tss_entry, 0xffff, 0x89, 0);
122*dbd38004SZixuan Wang 
123*dbd38004SZixuan Wang 	return TSS_MAIN + id * 16;
124*dbd38004SZixuan Wang }
12548a0145fSPaolo Bonzini #endif
12648a0145fSPaolo Bonzini 
12748a0145fSPaolo Bonzini void setup_multiboot(struct mbi_bootinfo *bi)
12893dd2aa3SAndrew Jones {
129716cea8aSPaolo Bonzini 	struct mbi_module *mods;
13093dd2aa3SAndrew Jones 
13148a0145fSPaolo Bonzini 	bootinfo = bi;
13248a0145fSPaolo Bonzini 
13348a0145fSPaolo Bonzini 	u64 best_start = (uintptr_t) &edata;
13448a0145fSPaolo Bonzini 	u64 best_end = bootinfo->mem_upper * 1024ull;
13548a0145fSPaolo Bonzini 	phys_alloc_init(best_start, best_end - best_start);
136cb67196aSPaolo Bonzini 
137716cea8aSPaolo Bonzini 	if (bootinfo->mods_count != 1)
13893dd2aa3SAndrew Jones 		return;
13993dd2aa3SAndrew Jones 
140716cea8aSPaolo Bonzini 	mods = (struct mbi_module *)(uintptr_t) bootinfo->mods_addr;
14193dd2aa3SAndrew Jones 
142716cea8aSPaolo Bonzini 	initrd = (char *)(uintptr_t) mods->start;
143716cea8aSPaolo Bonzini 	initrd_size = mods->end - mods->start;
14493dd2aa3SAndrew Jones }
1453c7d322eSAndrew Jones 
146716cea8aSPaolo Bonzini void setup_libcflat(void)
1473c7d322eSAndrew Jones {
1483c7d322eSAndrew Jones 	if (initrd) {
1493c7d322eSAndrew Jones 		/* environ is currently the only file in the initrd */
1503c7d322eSAndrew Jones 		u32 size = MIN(initrd_size, ENV_SIZE);
15103b1e457SNadav Amit 		const char *str;
15203b1e457SNadav Amit 
1533c7d322eSAndrew Jones 		memcpy(env, initrd, size);
1543c7d322eSAndrew Jones 		setup_env(env, size);
15503b1e457SNadav Amit 		if ((str = getenv("BOOTLOADER")) && atol(str) != 0)
15603b1e457SNadav Amit 			add_setup_arg("bootloader");
1573c7d322eSAndrew Jones 	}
1583c7d322eSAndrew Jones }
159