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