blob: 0c91c8d95cc8796b4e850cffc158afe9d351ca1b [file] [log] [blame]
Kevin O'Connore7cc7642009-10-04 10:05:16 -04001// Paravirtualization support.
2//
3// Copyright (C) 2009 Red Hat Inc.
4//
5// Authors:
6// Gleb Natapov <gnatapov@redhat.com>
7//
8// This file may be distributed under the terms of the GNU LGPLv3 license.
9
Kevin O'Connor897fb112013-02-07 23:32:48 -050010#include "config.h" // CONFIG_QEMU
Kevin O'Connorb3064592012-08-14 21:20:10 -040011#include "util.h" // dprintf
12#include "byteorder.h" // be32_to_cpu
Kevin O'Connor01a85202009-10-18 09:49:59 -040013#include "ioport.h" // outw
Kevin O'Connord83c87b2013-01-21 01:14:12 -050014#include "paravirt.h" // qemu_cfg_preinit
Kevin O'Connorde9e7052013-02-09 19:09:20 -050015#include "smbios.h" // smbios_setup
Kevin O'Connor8ed2e532013-01-21 02:32:48 -050016#include "memmap.h" // add_e820
17#include "cmos.h" // CMOS_*
18#include "acpi.h" // acpi_setup
19#include "mptable.h" // mptable_setup
20#include "pci.h" // create_pirtable
Kevin O'Connore7cc7642009-10-04 10:05:16 -040021
Kevin O'Connor4edda082013-02-09 13:21:08 -050022struct e820_reservation {
23 u64 address;
24 u64 length;
25 u32 type;
26};
Kevin O'Connore7cc7642009-10-04 10:05:16 -040027
Kevin O'Connor7b5bc502013-02-09 13:07:23 -050028/* This CPUID returns the signature 'KVMKVMKVM' in ebx, ecx, and edx. It
29 * should be used to determine that a VM is running under KVM.
30 */
31#define KVM_CPUID_SIGNATURE 0x40000000
32
33static void kvm_preinit(void)
34{
35 if (!CONFIG_QEMU)
36 return;
37 unsigned int eax, ebx, ecx, edx;
38 char signature[13];
39
40 cpuid(KVM_CPUID_SIGNATURE, &eax, &ebx, &ecx, &edx);
41 memcpy(signature + 0, &ebx, 4);
42 memcpy(signature + 4, &ecx, 4);
43 memcpy(signature + 8, &edx, 4);
44 signature[12] = 0;
45
46 if (strcmp(signature, "KVMKVMKVM") == 0) {
47 dprintf(1, "Running on KVM\n");
48 PlatformRunningOn |= PF_KVM;
49 }
50}
51
Kevin O'Connor8ed2e532013-01-21 02:32:48 -050052void
53qemu_ramsize_preinit(void)
54{
Kevin O'Connor02313b22013-02-07 22:42:25 -050055 if (!CONFIG_QEMU)
56 return;
57
58 PlatformRunningOn = PF_QEMU;
Kevin O'Connor7b5bc502013-02-09 13:07:23 -050059 kvm_preinit();
Kevin O'Connor02313b22013-02-07 22:42:25 -050060
Kevin O'Connor8ed2e532013-01-21 02:32:48 -050061 // On emulators, get memory size from nvram.
62 u32 rs = ((inb_cmos(CMOS_MEM_EXTMEM2_LOW) << 16)
63 | (inb_cmos(CMOS_MEM_EXTMEM2_HIGH) << 24));
64 if (rs)
65 rs += 16 * 1024 * 1024;
66 else
67 rs = (((inb_cmos(CMOS_MEM_EXTMEM_LOW) << 10)
68 | (inb_cmos(CMOS_MEM_EXTMEM_HIGH) << 18))
69 + 1 * 1024 * 1024);
70 RamSize = rs;
71 add_e820(0, rs, E820_RAM);
72
73 // Check for memory over 4Gig
74 u64 high = ((inb_cmos(CMOS_MEM_HIGHMEM_LOW) << 16)
75 | ((u32)inb_cmos(CMOS_MEM_HIGHMEM_MID) << 24)
76 | ((u64)inb_cmos(CMOS_MEM_HIGHMEM_HIGH) << 32));
77 RamSizeOver4G = high;
78 add_e820(0x100000000ull, high, E820_RAM);
79
80 /* reserve 256KB BIOS area at the end of 4 GB */
81 add_e820(0xfffc0000, 256*1024, E820_RESERVED);
82
83 u32 count = qemu_cfg_e820_entries();
84 if (count) {
85 struct e820_reservation entry;
86 int i;
87
88 for (i = 0; i < count; i++) {
89 qemu_cfg_e820_load_next(&entry);
90 add_e820(entry.address, entry.length, entry.type);
91 }
Kevin O'Connor7b5bc502013-02-09 13:07:23 -050092 } else if (runningOnKVM()) {
Kevin O'Connor8ed2e532013-01-21 02:32:48 -050093 // Backwards compatibility - provide hard coded range.
94 // 4 pages before the bios, 3 pages for vmx tss pages, the
95 // other page for EPT real mode pagetable
96 add_e820(0xfffbc000, 4*4096, E820_RESERVED);
97 }
98}
99
100void
101qemu_biostable_setup(void)
102{
103 pirtable_setup();
104 mptable_setup();
105 smbios_setup();
106 acpi_setup();
107}
108
Kevin O'Connor4edda082013-02-09 13:21:08 -0500109
110/****************************************************************
111 * QEMU firmware config (fw_cfg) interface
112 ****************************************************************/
113
114int qemu_cfg_present;
115
116#define QEMU_CFG_SIGNATURE 0x00
117#define QEMU_CFG_ID 0x01
118#define QEMU_CFG_UUID 0x02
119#define QEMU_CFG_NUMA 0x0d
120#define QEMU_CFG_BOOT_MENU 0x0e
121#define QEMU_CFG_MAX_CPUS 0x0f
122#define QEMU_CFG_FILE_DIR 0x19
123#define QEMU_CFG_ARCH_LOCAL 0x8000
124#define QEMU_CFG_ACPI_TABLES (QEMU_CFG_ARCH_LOCAL + 0)
125#define QEMU_CFG_SMBIOS_ENTRIES (QEMU_CFG_ARCH_LOCAL + 1)
126#define QEMU_CFG_IRQ0_OVERRIDE (QEMU_CFG_ARCH_LOCAL + 2)
127#define QEMU_CFG_E820_TABLE (QEMU_CFG_ARCH_LOCAL + 3)
128
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400129static void
130qemu_cfg_select(u16 f)
131{
132 outw(f, PORT_QEMU_CFG_CTL);
133}
134
135static void
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500136qemu_cfg_read(void *buf, int len)
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400137{
Kevin O'Connor6039fc52010-08-25 21:43:19 -0400138 insb(PORT_QEMU_CFG_DATA, buf, len);
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400139}
140
141static void
Kevin O'Connor4e4b4102009-10-08 21:21:59 -0400142qemu_cfg_skip(int len)
143{
144 while (len--)
145 inb(PORT_QEMU_CFG_DATA);
146}
147
148static void
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400149qemu_cfg_read_entry(void *buf, int e, int len)
150{
151 qemu_cfg_select(e);
152 qemu_cfg_read(buf, len);
153}
154
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500155void qemu_cfg_preinit(void)
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400156{
157 char *sig = "QEMU";
158 int i;
159
Kevin O'Connor897fb112013-02-07 23:32:48 -0500160 if (!CONFIG_QEMU)
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400161 return;
162
163 qemu_cfg_present = 1;
164
165 qemu_cfg_select(QEMU_CFG_SIGNATURE);
166
167 for (i = 0; i < 4; i++)
168 if (inb(PORT_QEMU_CFG_DATA) != sig[i]) {
169 qemu_cfg_present = 0;
170 break;
171 }
172 dprintf(4, "qemu_cfg_present=%d\n", qemu_cfg_present);
173}
174
Jes Sorensen0360e8e2010-02-16 09:46:08 +0100175u32 qemu_cfg_e820_entries(void)
176{
177 u32 cnt;
178
179 if (!qemu_cfg_present)
180 return 0;
181
182 qemu_cfg_read_entry(&cnt, QEMU_CFG_E820_TABLE, sizeof(cnt));
183 return cnt;
184}
185
186void* qemu_cfg_e820_load_next(void *addr)
187{
188 qemu_cfg_read(addr, sizeof(struct e820_reservation));
189 return addr;
190}
191
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500192static int
193qemu_cfg_read_file(struct romfile_s *file, void *dst, u32 maxlen)
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100194{
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400195 if (file->size > maxlen)
196 return -1;
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500197 qemu_cfg_select(file->id);
198 qemu_cfg_skip(file->rawsize);
199 qemu_cfg_read(dst, file->size);
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400200 return file->size;
201}
202
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500203static void
204qemu_romfile_add(char *name, int select, int skip, int size)
205{
206 struct romfile_s *file = malloc_tmp(sizeof(*file));
207 if (!file) {
208 warn_noalloc();
209 return;
210 }
211 memset(file, 0, sizeof(*file));
212 strtcpy(file->name, name, sizeof(file->name));
213 file->id = select;
214 file->rawsize = skip; // Use rawsize to indicate skip length.
215 file->size = size;
216 file->copy = qemu_cfg_read_file;
217 romfile_add(file);
218}
219
Kevin O'Connorde9e7052013-02-09 19:09:20 -0500220#define SMBIOS_FIELD_ENTRY 0
221#define SMBIOS_TABLE_ENTRY 1
222
223struct qemu_smbios_header {
224 u16 length;
225 u8 headertype;
226 u8 tabletype;
227 u16 fieldoffset;
228} PACKED;
229
Kevin O'Connor188d9942013-02-09 15:24:08 -0500230// Populate romfile entries for legacy fw_cfg ports (that predate the
231// "file" interface).
232static void
233qemu_cfg_legacy(void)
234{
Kevin O'Connor56c50892013-02-09 19:25:51 -0500235 // Misc config items.
236 qemu_romfile_add("etc/show-boot-menu", QEMU_CFG_BOOT_MENU, 0, 2);
237 qemu_romfile_add("etc/irq0-override", QEMU_CFG_IRQ0_OVERRIDE, 0, 1);
238 qemu_romfile_add("etc/max-cpus", QEMU_CFG_MAX_CPUS, 0, 2);
239
Kevin O'Connorf9e4e372013-02-09 19:45:45 -0500240 // NUMA data
241 u64 numacount;
242 qemu_cfg_read_entry(&numacount, QEMU_CFG_NUMA, sizeof(numacount));
243 numacount += romfile_loadint("etc/max-cpus", 0);
244 qemu_romfile_add("etc/numa-nodes", QEMU_CFG_NUMA, sizeof(numacount)
245 , numacount*sizeof(u64));
246
Kevin O'Connor188d9942013-02-09 15:24:08 -0500247 // ACPI tables
248 char name[128];
249 u16 cnt;
250 qemu_cfg_read_entry(&cnt, QEMU_CFG_ACPI_TABLES, sizeof(cnt));
251 int i, offset = sizeof(cnt);
252 for (i = 0; i < cnt; i++) {
253 u16 len;
254 qemu_cfg_read(&len, sizeof(len));
255 offset += sizeof(len);
256 snprintf(name, sizeof(name), "acpi/table%d", i);
257 qemu_romfile_add(name, QEMU_CFG_ACPI_TABLES, offset, len);
258 qemu_cfg_skip(len);
259 offset += len;
260 }
Kevin O'Connorde9e7052013-02-09 19:09:20 -0500261
262 // SMBIOS info
263 qemu_cfg_read_entry(&cnt, QEMU_CFG_SMBIOS_ENTRIES, sizeof(cnt));
264 offset = sizeof(cnt);
265 for (i = 0; i < cnt; i++) {
266 struct qemu_smbios_header header;
267 qemu_cfg_read(&header, sizeof(header));
268 if (header.headertype == SMBIOS_FIELD_ENTRY) {
269 snprintf(name, sizeof(name), "smbios/field%d-%d"
270 , header.tabletype, header.fieldoffset);
271 qemu_romfile_add(name, QEMU_CFG_SMBIOS_ENTRIES
272 , offset + sizeof(header)
273 , header.length - sizeof(header));
274 } else {
275 snprintf(name, sizeof(name), "smbios/table%d-%d"
276 , header.tabletype, i);
277 qemu_romfile_add(name, QEMU_CFG_SMBIOS_ENTRIES
278 , offset + 3, header.length - 3);
279 }
280 qemu_cfg_skip(header.length - sizeof(header));
281 offset += header.length;
282 }
Kevin O'Connor188d9942013-02-09 15:24:08 -0500283}
284
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400285struct QemuCfgFile {
286 u32 size; /* file size */
287 u16 select; /* write this to 0x510 to read it */
288 u16 reserved;
289 char name[56];
290};
291
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500292void qemu_romfile_init(void)
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400293{
Kevin O'Connor897fb112013-02-07 23:32:48 -0500294 if (!CONFIG_QEMU || !qemu_cfg_present)
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400295 return;
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100296
Kevin O'Connor188d9942013-02-09 15:24:08 -0500297 // Populate romfiles for legacy fw_cfg entries
298 qemu_cfg_legacy();
299
300 // Load files found in the fw_cfg file directory
Kevin O'Connore2304262010-06-13 16:05:17 -0400301 u32 count;
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100302 qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count));
Kevin O'Connorb3064592012-08-14 21:20:10 -0400303 count = be32_to_cpu(count);
Kevin O'Connore2304262010-06-13 16:05:17 -0400304 u32 e;
305 for (e = 0; e < count; e++) {
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400306 struct QemuCfgFile qfile;
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500307 qemu_cfg_read(&qfile, sizeof(qfile));
308 qemu_romfile_add(qfile.name, be16_to_cpu(qfile.select)
309 , 0, be32_to_cpu(qfile.size));
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100310 }
Kevin O'Connor8b565782011-07-05 20:32:44 -0400311}