xref: /kvmtool/x86/bios.c (revision b3594ec7e0dd3d02043f8da034fe31e9591cd658)
19292f776SCyrill Gorcunov #include "kvm/kvm.h"
2*b3594ec7SCyrill Gorcunov #include "kvm/boot-protocol.h"
3*b3594ec7SCyrill Gorcunov #include "kvm/e820.h"
49292f776SCyrill Gorcunov #include "kvm/interrupt.h"
59292f776SCyrill Gorcunov #include "kvm/util.h"
69292f776SCyrill Gorcunov 
79292f776SCyrill Gorcunov #include <string.h>
89292f776SCyrill Gorcunov 
928ce0d66SCyrill Gorcunov #include "bios/bios-rom.h"
1028ce0d66SCyrill Gorcunov 
11ca82361eSPekka Enberg struct irq_handler {
12ca82361eSPekka Enberg 	unsigned long		address;
13ca82361eSPekka Enberg 	unsigned int		irq;
14ca82361eSPekka Enberg 	void			*handler;
15ca82361eSPekka Enberg 	size_t			size;
169292f776SCyrill Gorcunov };
179292f776SCyrill Gorcunov 
1828ce0d66SCyrill Gorcunov #define BIOS_IRQ_ADDR(name) (MB_BIOS_BEGIN + BIOS_OFFSET__##name)
1928ce0d66SCyrill Gorcunov #define BIOS_IRQ_FUNC(name) ((char *)&bios_rom[BIOS_OFFSET__##name])
2028ce0d66SCyrill Gorcunov #define BIOS_IRQ_SIZE(name) (BIOS_ENTRY_SIZE(BIOS_OFFSET__##name))
2128ce0d66SCyrill Gorcunov 
22ca82361eSPekka Enberg #define DEFINE_BIOS_IRQ_HANDLER(_irq, _handler)			\
23ca82361eSPekka Enberg 	{							\
24ca82361eSPekka Enberg 		.irq		= _irq,				\
25ca82361eSPekka Enberg 		.address	= BIOS_IRQ_ADDR(_handler),	\
26ca82361eSPekka Enberg 		.handler	= BIOS_IRQ_FUNC(_handler),	\
27ca82361eSPekka Enberg 		.size		= BIOS_IRQ_SIZE(_handler),	\
28ca82361eSPekka Enberg 	}
29ca82361eSPekka Enberg 
30ca82361eSPekka Enberg static struct irq_handler bios_irq_handlers[] = {
31ca82361eSPekka Enberg 	DEFINE_BIOS_IRQ_HANDLER(0x10, bios_int10),
32ca82361eSPekka Enberg 	DEFINE_BIOS_IRQ_HANDLER(0x15, bios_int15),
33ca82361eSPekka Enberg };
34ca82361eSPekka Enberg 
35ca82361eSPekka Enberg static void setup_irq_handler(struct kvm *kvm, struct irq_handler *handler)
36ca82361eSPekka Enberg {
37ca82361eSPekka Enberg 	struct real_intr_desc intr_desc;
38ca82361eSPekka Enberg 	void *p;
39ca82361eSPekka Enberg 
40ca82361eSPekka Enberg 	p	= guest_flat_to_host(kvm, handler->address);
41ca82361eSPekka Enberg 	memcpy(p, handler->handler, handler->size);
42ca82361eSPekka Enberg 
43ca82361eSPekka Enberg 	intr_desc = (struct real_intr_desc) {
44ca82361eSPekka Enberg 		.segment	= REAL_SEGMENT(handler->address),
45ca82361eSPekka Enberg 		.offset		= REAL_OFFSET(handler->address),
46ca82361eSPekka Enberg 	};
47ca82361eSPekka Enberg 
48ca82361eSPekka Enberg 	interrupt_table__set(&kvm->interrupt_table, &intr_desc, handler->irq);
49ca82361eSPekka Enberg }
50ca82361eSPekka Enberg 
51*b3594ec7SCyrill Gorcunov /**
52*b3594ec7SCyrill Gorcunov  * e820_setup - setup some simple E820 memory map
53*b3594ec7SCyrill Gorcunov  * @kvm - guest system descriptor
54*b3594ec7SCyrill Gorcunov  */
55*b3594ec7SCyrill Gorcunov static void e820_setup(struct kvm *kvm)
56*b3594ec7SCyrill Gorcunov {
57*b3594ec7SCyrill Gorcunov 	struct e820_entry *mem_map;
58*b3594ec7SCyrill Gorcunov 	unsigned char *size;
59*b3594ec7SCyrill Gorcunov 	unsigned int i = 0;
60*b3594ec7SCyrill Gorcunov 
61*b3594ec7SCyrill Gorcunov 	size		= guest_flat_to_host(kvm, E820_MAP_SIZE);
62*b3594ec7SCyrill Gorcunov 	mem_map		= guest_flat_to_host(kvm, E820_MAP_START);
63*b3594ec7SCyrill Gorcunov 
64*b3594ec7SCyrill Gorcunov 	*size		= E820_MEM_AREAS;
65*b3594ec7SCyrill Gorcunov 
66*b3594ec7SCyrill Gorcunov 	mem_map[i++]	= (struct e820_entry) {
67*b3594ec7SCyrill Gorcunov 		.addr		= REAL_MODE_IVT_BEGIN,
68*b3594ec7SCyrill Gorcunov 		.size		= EBDA_START - REAL_MODE_IVT_BEGIN,
69*b3594ec7SCyrill Gorcunov 		.type		= E820_MEM_USABLE,
70*b3594ec7SCyrill Gorcunov 	};
71*b3594ec7SCyrill Gorcunov 	mem_map[i++]	= (struct e820_entry) {
72*b3594ec7SCyrill Gorcunov 		.addr		= EBDA_START,
73*b3594ec7SCyrill Gorcunov 		.size		= VGA_RAM_BEGIN - EBDA_START,
74*b3594ec7SCyrill Gorcunov 		.type		= E820_MEM_RESERVED,
75*b3594ec7SCyrill Gorcunov 	};
76*b3594ec7SCyrill Gorcunov 	mem_map[i++]	= (struct e820_entry) {
77*b3594ec7SCyrill Gorcunov 		.addr		= MB_BIOS_BEGIN,
78*b3594ec7SCyrill Gorcunov 		.size		= MB_BIOS_END - MB_BIOS_BEGIN,
79*b3594ec7SCyrill Gorcunov 		.type		= E820_MEM_RESERVED,
80*b3594ec7SCyrill Gorcunov 	};
81*b3594ec7SCyrill Gorcunov 	mem_map[i++]	= (struct e820_entry) {
82*b3594ec7SCyrill Gorcunov 		.addr		= BZ_KERNEL_START,
83*b3594ec7SCyrill Gorcunov 		.size		= kvm->ram_size - BZ_KERNEL_START,
84*b3594ec7SCyrill Gorcunov 		.type		= E820_MEM_USABLE,
85*b3594ec7SCyrill Gorcunov 	};
86*b3594ec7SCyrill Gorcunov 
87*b3594ec7SCyrill Gorcunov 	BUILD_BUG_ON(i > E820_MEM_AREAS);
88*b3594ec7SCyrill Gorcunov }
89*b3594ec7SCyrill Gorcunov 
90*b3594ec7SCyrill Gorcunov /**
91*b3594ec7SCyrill Gorcunov  * setup_bios - inject BIOS into guest memory
92*b3594ec7SCyrill Gorcunov  * @kvm - guest system descriptor
93*b3594ec7SCyrill Gorcunov  */
949292f776SCyrill Gorcunov void setup_bios(struct kvm *kvm)
959292f776SCyrill Gorcunov {
969292f776SCyrill Gorcunov 	unsigned long address = MB_BIOS_BEGIN;
979292f776SCyrill Gorcunov 	struct real_intr_desc intr_desc;
98ca82361eSPekka Enberg 	unsigned int i;
999292f776SCyrill Gorcunov 	void *p;
1009292f776SCyrill Gorcunov 
10115c2b0a0SCyrill Gorcunov 	/*
10215c2b0a0SCyrill Gorcunov 	 * before anything else -- clean some known areas
10315c2b0a0SCyrill Gorcunov 	 * we definitely don't want any trash here
10415c2b0a0SCyrill Gorcunov 	 */
10515c2b0a0SCyrill Gorcunov 	p = guest_flat_to_host(kvm, BDA_START);
10615c2b0a0SCyrill Gorcunov 	memset(p, 0, BDA_END - BDA_START);
10715c2b0a0SCyrill Gorcunov 
10815c2b0a0SCyrill Gorcunov 	p = guest_flat_to_host(kvm, EBDA_START);
10915c2b0a0SCyrill Gorcunov 	memset(p, 0, EBDA_END - EBDA_START);
11015c2b0a0SCyrill Gorcunov 
11115c2b0a0SCyrill Gorcunov 	p = guest_flat_to_host(kvm, MB_BIOS_BEGIN);
11215c2b0a0SCyrill Gorcunov 	memset(p, 0, MB_BIOS_END - MB_BIOS_BEGIN);
11315c2b0a0SCyrill Gorcunov 
11415c2b0a0SCyrill Gorcunov 	p = guest_flat_to_host(kvm, VGA_ROM_BEGIN);
11515c2b0a0SCyrill Gorcunov 	memset(p, 0, VGA_ROM_END - VGA_ROM_BEGIN);
11615c2b0a0SCyrill Gorcunov 
11728ce0d66SCyrill Gorcunov 	/* just copy the bios rom into the place */
11828ce0d66SCyrill Gorcunov 	p = guest_flat_to_host(kvm, MB_BIOS_BEGIN);
11928ce0d66SCyrill Gorcunov 	memcpy(p, bios_rom, bios_rom_size);
12028ce0d66SCyrill Gorcunov 
121*b3594ec7SCyrill Gorcunov 	/* E820 memory map must be present */
122*b3594ec7SCyrill Gorcunov 	e820_setup(kvm);
123*b3594ec7SCyrill Gorcunov 
1249292f776SCyrill Gorcunov 	/*
1259292f776SCyrill Gorcunov 	 * Setup a *fake* real mode vector table, it has only
1269292f776SCyrill Gorcunov 	 * one real hadler which does just iret
1279292f776SCyrill Gorcunov 	 */
12828ce0d66SCyrill Gorcunov 	address = BIOS_IRQ_ADDR(bios_intfake);
1299292f776SCyrill Gorcunov 	intr_desc = (struct real_intr_desc) {
1309292f776SCyrill Gorcunov 		.segment	= REAL_SEGMENT(address),
1319292f776SCyrill Gorcunov 		.offset		= REAL_OFFSET(address),
1329292f776SCyrill Gorcunov 	};
1339292f776SCyrill Gorcunov 	interrupt_table__setup(&kvm->interrupt_table, &intr_desc);
1349292f776SCyrill Gorcunov 
135ca82361eSPekka Enberg 	for (i = 0; i < ARRAY_SIZE(bios_irq_handlers); i++)
136ca82361eSPekka Enberg 		setup_irq_handler(kvm, &bios_irq_handlers[i]);
1379292f776SCyrill Gorcunov 
13828ce0d66SCyrill Gorcunov 	/* we almost done */
1399292f776SCyrill Gorcunov 	p = guest_flat_to_host(kvm, 0);
1409292f776SCyrill Gorcunov 	interrupt_table__copy(&kvm->interrupt_table, p, REAL_INTR_SIZE);
1419292f776SCyrill Gorcunov }
142