blob: 9637f87dfdfea581bd355b90ceb935c387cc7e30 [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
10#include "config.h"
11#include "ioport.h"
12#include "paravirt.h"
13
14int qemu_cfg_present;
15
16static void
17qemu_cfg_select(u16 f)
18{
19 outw(f, PORT_QEMU_CFG_CTL);
20}
21
22static void
23qemu_cfg_read(u8 *buf, int len)
24{
25 while (len--)
26 *(buf++) = inb(PORT_QEMU_CFG_DATA);
27}
28
29static void
Kevin O'Connor4e4b4102009-10-08 21:21:59 -040030qemu_cfg_skip(int len)
31{
32 while (len--)
33 inb(PORT_QEMU_CFG_DATA);
34}
35
36static void
Kevin O'Connore7cc7642009-10-04 10:05:16 -040037qemu_cfg_read_entry(void *buf, int e, int len)
38{
39 qemu_cfg_select(e);
40 qemu_cfg_read(buf, len);
41}
42
43void qemu_cfg_port_probe(void)
44{
45 char *sig = "QEMU";
46 int i;
47
48 if (CONFIG_COREBOOT)
49 return;
50
51 qemu_cfg_present = 1;
52
53 qemu_cfg_select(QEMU_CFG_SIGNATURE);
54
55 for (i = 0; i < 4; i++)
56 if (inb(PORT_QEMU_CFG_DATA) != sig[i]) {
57 qemu_cfg_present = 0;
58 break;
59 }
60 dprintf(4, "qemu_cfg_present=%d\n", qemu_cfg_present);
61}
62
63void qemu_cfg_get_uuid(u8 *uuid)
64{
65 if (!qemu_cfg_present)
66 return;
67
68 qemu_cfg_read_entry(uuid, QEMU_CFG_UUID, 16);
69}
70
71int qemu_cfg_show_boot_menu(void)
72{
73 u16 v;
74 if (!qemu_cfg_present)
75 return 1;
76
77 qemu_cfg_read_entry(&v, QEMU_CFG_BOOT_MENU, sizeof(v));
78
79 return v;
80}
81
Kevin O'Connorcc6dc462009-10-08 21:18:41 -040082u16 qemu_cfg_acpi_additional_tables(void)
83{
84 u16 cnt;
85
86 if (!qemu_cfg_present)
87 return 0;
88
89 qemu_cfg_read_entry(&cnt, QEMU_CFG_ACPI_TABLES, sizeof(cnt));
90
91 return cnt;
92}
93
94u16 qemu_cfg_next_acpi_table_len(void)
95{
96 u16 len;
97
98 qemu_cfg_read((u8*)&len, sizeof(len));
99
100 return len;
101}
102
103void* qemu_cfg_next_acpi_table_load(void *addr, u16 len)
104{
105 qemu_cfg_read(addr, len);
106 return addr;
107}
108
Kevin O'Connor4e4b4102009-10-08 21:21:59 -0400109u16 qemu_cfg_smbios_entries(void)
110{
111 u16 cnt;
112
113 if (!qemu_cfg_present)
114 return 0;
115
116 qemu_cfg_read_entry(&cnt, QEMU_CFG_SMBIOS_ENTRIES, sizeof(cnt));
117
118 return cnt;
119}
120
121struct smbios_header {
122 u16 length;
123 u8 type;
124} PACKED;
125
126struct smbios_field {
127 struct smbios_header header;
128 u8 type;
129 u16 offset;
130 u8 data[];
131} PACKED;
132
133struct smbios_table {
134 struct smbios_header header;
135 u8 data[];
136} PACKED;
137
138#define SMBIOS_FIELD_ENTRY 0
139#define SMBIOS_TABLE_ENTRY 1
140
141size_t qemu_cfg_smbios_load_field(int type, size_t offset, void *addr)
142{
143 int i;
144
145 for (i = qemu_cfg_smbios_entries(); i > 0; i--) {
146 struct smbios_field field;
147
148 qemu_cfg_read((u8 *)&field, sizeof(struct smbios_header));
149 field.header.length -= sizeof(struct smbios_header);
150
151 if (field.header.type != SMBIOS_FIELD_ENTRY) {
152 qemu_cfg_skip(field.header.length);
153 continue;
154 }
155
156 qemu_cfg_read((u8 *)&field.type,
157 sizeof(field) - sizeof(struct smbios_header));
158 field.header.length -= sizeof(field) - sizeof(struct smbios_header);
159
160 if (field.type != type || field.offset != offset) {
161 qemu_cfg_skip(field.header.length);
162 continue;
163 }
164
165 qemu_cfg_read(addr, field.header.length);
166 return (size_t)field.header.length;
167 }
168 return 0;
169}
170
171/* This goes at the beginning of every SMBIOS structure. */
172struct smbios_structure_header {
173 u8 type;
174 u8 length;
175 u16 handle;
176} PACKED;
177
178int qemu_cfg_smbios_load_external(int type, char **p, unsigned *nr_structs,
179 unsigned *max_struct_size, char *end)
180{
181 static u64 used_bitmap[4] = { 0 };
182 char *start = *p;
183 int i;
184
185 /* Check if we've already reported these tables */
186 if (used_bitmap[(type >> 6) & 0x3] & (1ULL << (type & 0x3f)))
187 return 1;
188
189 /* Don't introduce spurious end markers */
190 if (type == 127)
191 return 0;
192
193 for (i = qemu_cfg_smbios_entries(); i > 0; i--) {
194 struct smbios_table table;
195 struct smbios_structure_header *header = (void *)*p;
196 int string;
197
198 qemu_cfg_read((u8 *)&table, sizeof(struct smbios_header));
199 table.header.length -= sizeof(struct smbios_header);
200
201 if (table.header.type != SMBIOS_TABLE_ENTRY) {
202 qemu_cfg_skip(table.header.length);
203 continue;
204 }
205
206 if (end - *p < sizeof(struct smbios_structure_header)) {
207 dprintf(1, "No more memory for additional smbios tables\n");
208 break;
209 }
210
211 qemu_cfg_read((u8 *)*p, sizeof(struct smbios_structure_header));
212 table.header.length -= sizeof(struct smbios_structure_header);
213
214 if (header->type != type) {
215 qemu_cfg_skip(table.header.length);
216 continue;
217 }
218
219 *p += sizeof(struct smbios_structure_header);
220
221 /* Entries end with a double NULL char, if there's a string at
222 * the end (length is greater than formatted length), the string
223 * terminator provides the first NULL. */
224 string = header->length < table.header.length +
225 sizeof(struct smbios_structure_header);
226
227 /* Read the rest and terminate the entry */
228 if (end - *p < table.header.length) {
229 dprintf(1, "No memory for smbios table %d\n", header->type);
230 *p -= sizeof(struct smbios_structure_header);
231 continue;
232 }
233 qemu_cfg_read((u8 *)*p, table.header.length);
234 *p += table.header.length;
235 *((u8*)*p) = 0;
236 (*p)++;
237 if (!string) {
238 *((u8*)*p) = 0;
239 (*p)++;
240 }
241
242 (*nr_structs)++;
243 if (*p - (char *)header > *max_struct_size)
244 *max_struct_size = *p - (char *)header;
245 }
246
247 if (start != *p) {
248 /* Mark that we've reported on this type */
249 used_bitmap[(type >> 6) & 0x3] |= (1ULL << (type & 0x3f));
250 return 1;
251 }
252
253 return 0;
254}
255