xref: /kvmtool/x86/bios.c (revision da4cfc3e540341b84c4bbad705b5a15865bc1f80)
1 #include "kvm/kvm.h"
2 #include "kvm/boot-protocol.h"
3 #include "kvm/e820.h"
4 #include "kvm/interrupt.h"
5 #include "kvm/util.h"
6 
7 #include <string.h>
8 
9 #include "bios/bios-rom.h"
10 
11 struct irq_handler {
12 	unsigned long		address;
13 	unsigned int		irq;
14 	void			*handler;
15 	size_t			size;
16 };
17 
18 #define BIOS_IRQ_PA_ADDR(name)	(MB_BIOS_BEGIN + BIOS_OFFSET__##name)
19 #define BIOS_IRQ_FUNC(name)	((char *)&bios_rom[BIOS_OFFSET__##name])
20 #define BIOS_IRQ_SIZE(name)	(BIOS_ENTRY_SIZE(BIOS_OFFSET__##name))
21 
22 #define DEFINE_BIOS_IRQ_HANDLER(_irq, _handler)			\
23 	{							\
24 		.irq		= _irq,				\
25 		.address	= BIOS_IRQ_PA_ADDR(_handler),	\
26 		.handler	= BIOS_IRQ_FUNC(_handler),	\
27 		.size		= BIOS_IRQ_SIZE(_handler),	\
28 	}
29 
30 static struct irq_handler bios_irq_handlers[] = {
31 	DEFINE_BIOS_IRQ_HANDLER(0x10, bios_int10),
32 	DEFINE_BIOS_IRQ_HANDLER(0x15, bios_int15),
33 };
34 
setup_irq_handler(struct kvm * kvm,struct irq_handler * handler)35 static void setup_irq_handler(struct kvm *kvm, struct irq_handler *handler)
36 {
37 	struct real_intr_desc intr_desc;
38 	void *p;
39 
40 	p = guest_flat_to_host(kvm, handler->address);
41 	memcpy(p, handler->handler, handler->size);
42 
43 	intr_desc = (struct real_intr_desc) {
44 		.segment	= REAL_SEGMENT(MB_BIOS_BEGIN),
45 		.offset		= handler->address - MB_BIOS_BEGIN,
46 	};
47 
48 	DIE_IF((handler->address - MB_BIOS_BEGIN + 1) > MB_BIOS_SIZE);
49 
50 	interrupt_table__set(&kvm->arch.interrupt_table, &intr_desc, handler->irq);
51 }
52 
53 /**
54  * e820_setup - setup some simple E820 memory map
55  * @kvm - guest system descriptor
56  */
e820_setup(struct kvm * kvm)57 static void e820_setup(struct kvm *kvm)
58 {
59 	struct e820map *e820;
60 	struct e820entry *mem_map;
61 	unsigned int i = 0;
62 
63 	e820		= guest_flat_to_host(kvm, E820_MAP_START);
64 	mem_map		= e820->map;
65 
66 	mem_map[i++]	= (struct e820entry) {
67 		.addr		= REAL_MODE_IVT_BEGIN,
68 		.size		= EBDA_START - REAL_MODE_IVT_BEGIN,
69 		.type		= E820_RAM,
70 	};
71 	mem_map[i++]	= (struct e820entry) {
72 		.addr		= EBDA_START,
73 		.size		= VGA_RAM_BEGIN - EBDA_START,
74 		.type		= E820_RESERVED,
75 	};
76 	mem_map[i++]	= (struct e820entry) {
77 		.addr		= MB_BIOS_BEGIN,
78 		.size		= MB_BIOS_SIZE,
79 		.type		= E820_RESERVED,
80 	};
81 	if (kvm->ram_size < KVM_32BIT_GAP_START) {
82 		mem_map[i++]	= (struct e820entry) {
83 			.addr		= BZ_KERNEL_START,
84 			.size		= kvm->ram_size - BZ_KERNEL_START,
85 			.type		= E820_RAM,
86 		};
87 	} else {
88 		mem_map[i++]	= (struct e820entry) {
89 			.addr		= BZ_KERNEL_START,
90 			.size		= KVM_32BIT_GAP_START - BZ_KERNEL_START,
91 			.type		= E820_RAM,
92 		};
93 		mem_map[i++]	= (struct e820entry) {
94 			.addr		= KVM_32BIT_MAX_MEM_SIZE,
95 			.size		= kvm->ram_size - KVM_32BIT_MAX_MEM_SIZE,
96 			.type		= E820_RAM,
97 		};
98 	}
99 
100 	BUG_ON(i > E820_X_MAX);
101 
102 	e820->nr_map = i;
103 }
104 
setup_vga_rom(struct kvm * kvm)105 static void setup_vga_rom(struct kvm *kvm)
106 {
107 	u16 *mode;
108 	void *p;
109 
110 	p = guest_flat_to_host(kvm, VGA_ROM_OEM_STRING);
111 	memset(p, 0, VGA_ROM_OEM_STRING_SIZE);
112 	strncpy(p, "KVM VESA", VGA_ROM_OEM_STRING_SIZE);
113 
114 	mode = guest_flat_to_host(kvm, VGA_ROM_MODES);
115 	mode[0]	= 0x0112;
116 	mode[1] = 0xffff;
117 }
118 
119 /**
120  * setup_bios - inject BIOS into guest memory
121  * @kvm - guest system descriptor
122  */
setup_bios(struct kvm * kvm)123 void setup_bios(struct kvm *kvm)
124 {
125 	unsigned long address = MB_BIOS_BEGIN;
126 	struct real_intr_desc intr_desc;
127 	unsigned int i;
128 	void *p;
129 
130 	/*
131 	 * before anything else -- clean some known areas
132 	 * we definitely don't want any trash here
133 	 */
134 	p = guest_flat_to_host(kvm, BDA_START);
135 	memset(p, 0, BDA_SIZE);
136 
137 	p = guest_flat_to_host(kvm, EBDA_START);
138 	memset(p, 0, EBDA_SIZE);
139 
140 	p = guest_flat_to_host(kvm, MB_BIOS_BEGIN);
141 	memset(p, 0, MB_BIOS_SIZE);
142 
143 	p = guest_flat_to_host(kvm, VGA_ROM_BEGIN);
144 	memset(p, 0, VGA_ROM_SIZE);
145 
146 	/* just copy the bios rom into the place */
147 	p = guest_flat_to_host(kvm, MB_BIOS_BEGIN);
148 	memcpy(p, bios_rom, bios_rom_size);
149 
150 	/* E820 memory map must be present */
151 	e820_setup(kvm);
152 
153 	/* VESA needs own tricks */
154 	setup_vga_rom(kvm);
155 
156 	/*
157 	 * Setup a *fake* real mode vector table, it has only
158 	 * one real handler which does just iret
159 	 */
160 	address = BIOS_IRQ_PA_ADDR(bios_intfake);
161 	intr_desc = (struct real_intr_desc) {
162 		.segment	= REAL_SEGMENT(MB_BIOS_BEGIN),
163 		.offset		= address - MB_BIOS_BEGIN,
164 	};
165 	interrupt_table__setup(&kvm->arch.interrupt_table, &intr_desc);
166 
167 	for (i = 0; i < ARRAY_SIZE(bios_irq_handlers); i++)
168 		setup_irq_handler(kvm, &bios_irq_handlers[i]);
169 
170 	/* we almost done */
171 	p = guest_flat_to_host(kvm, 0);
172 	interrupt_table__copy(&kvm->arch.interrupt_table, p, REAL_INTR_SIZE);
173 }
174