Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


imported SEABIOS source tree
[palacios.git] / bios / seabios / src / paravirt.c
1 // 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" // CONFIG_COREBOOT
11 #include "util.h" // ntoh[ls]
12 #include "ioport.h" // outw
13 #include "paravirt.h" // qemu_cfg_port_probe
14 #include "smbios.h" // struct smbios_structure_header
15
16 int qemu_cfg_present;
17
18 static void
19 qemu_cfg_select(u16 f)
20 {
21     outw(f, PORT_QEMU_CFG_CTL);
22 }
23
24 static void
25 qemu_cfg_read(u8 *buf, int len)
26 {
27     insb(PORT_QEMU_CFG_DATA, buf, len);
28 }
29
30 static void
31 qemu_cfg_skip(int len)
32 {
33     while (len--)
34         inb(PORT_QEMU_CFG_DATA);
35 }
36
37 static void
38 qemu_cfg_read_entry(void *buf, int e, int len)
39 {
40     qemu_cfg_select(e);
41     qemu_cfg_read(buf, len);
42 }
43
44 void qemu_cfg_port_probe(void)
45 {
46     char *sig = "QEMU";
47     int i;
48
49     if (CONFIG_COREBOOT)
50         return;
51
52     qemu_cfg_present = 1;
53
54     qemu_cfg_select(QEMU_CFG_SIGNATURE);
55
56     for (i = 0; i < 4; i++)
57         if (inb(PORT_QEMU_CFG_DATA) != sig[i]) {
58             qemu_cfg_present = 0;
59             break;
60         }
61     dprintf(4, "qemu_cfg_present=%d\n", qemu_cfg_present);
62 }
63
64 void qemu_cfg_get_uuid(u8 *uuid)
65 {
66     if (!qemu_cfg_present)
67         return;
68
69     qemu_cfg_read_entry(uuid, QEMU_CFG_UUID, 16);
70 }
71
72 int qemu_cfg_show_boot_menu(void)
73 {
74     u16 v;
75     if (!qemu_cfg_present)
76         return 1;
77
78     qemu_cfg_read_entry(&v, QEMU_CFG_BOOT_MENU, sizeof(v));
79
80     return v;
81 }
82
83 int qemu_cfg_irq0_override(void)
84 {
85     u8 v;
86
87     if (!qemu_cfg_present)
88         return 0;
89
90     qemu_cfg_read_entry(&v, QEMU_CFG_IRQ0_OVERRIDE, sizeof(v));
91
92     return v;
93 }
94
95 u16 qemu_cfg_acpi_additional_tables(void)
96 {
97     u16 cnt;
98
99     if (!qemu_cfg_present)
100         return 0;
101
102     qemu_cfg_read_entry(&cnt, QEMU_CFG_ACPI_TABLES, sizeof(cnt));
103
104     return cnt;
105 }
106
107 u16 qemu_cfg_next_acpi_table_len(void)
108 {
109     u16 len;
110
111     qemu_cfg_read((u8*)&len, sizeof(len));
112
113     return len;
114 }
115
116 void* qemu_cfg_next_acpi_table_load(void *addr, u16 len)
117 {
118     qemu_cfg_read(addr, len);
119     return addr;
120 }
121
122 u16 qemu_cfg_smbios_entries(void)
123 {
124     u16 cnt;
125
126     if (!qemu_cfg_present)
127         return 0;
128
129     qemu_cfg_read_entry(&cnt, QEMU_CFG_SMBIOS_ENTRIES, sizeof(cnt));
130
131     return cnt;
132 }
133
134 u32 qemu_cfg_e820_entries(void)
135 {
136     u32 cnt;
137
138     if (!qemu_cfg_present)
139         return 0;
140
141     qemu_cfg_read_entry(&cnt, QEMU_CFG_E820_TABLE, sizeof(cnt));
142     return cnt;
143 }
144
145 void* qemu_cfg_e820_load_next(void *addr)
146 {
147     qemu_cfg_read(addr, sizeof(struct e820_reservation));
148     return addr;
149 }
150
151 struct smbios_header {
152     u16 length;
153     u8 type;
154 } PACKED;
155
156 struct smbios_field {
157     struct smbios_header header;
158     u8 type;
159     u16 offset;
160     u8 data[];
161 } PACKED;
162
163 struct smbios_table {
164     struct smbios_header header;
165     u8 data[];
166 } PACKED;
167
168 #define SMBIOS_FIELD_ENTRY 0
169 #define SMBIOS_TABLE_ENTRY 1
170
171 size_t qemu_cfg_smbios_load_field(int type, size_t offset, void *addr)
172 {
173     int i;
174
175     for (i = qemu_cfg_smbios_entries(); i > 0; i--) {
176         struct smbios_field field;
177
178         qemu_cfg_read((u8 *)&field, sizeof(struct smbios_header));
179         field.header.length -= sizeof(struct smbios_header);
180
181         if (field.header.type != SMBIOS_FIELD_ENTRY) {
182             qemu_cfg_skip(field.header.length);
183             continue;
184         }
185
186         qemu_cfg_read((u8 *)&field.type,
187                       sizeof(field) - sizeof(struct smbios_header));
188         field.header.length -= sizeof(field) - sizeof(struct smbios_header);
189
190         if (field.type != type || field.offset != offset) {
191             qemu_cfg_skip(field.header.length);
192             continue;
193         }
194
195         qemu_cfg_read(addr, field.header.length);
196         return (size_t)field.header.length;
197     }
198     return 0;
199 }
200
201 int qemu_cfg_smbios_load_external(int type, char **p, unsigned *nr_structs,
202                                   unsigned *max_struct_size, char *end)
203 {
204     static u64 used_bitmap[4] = { 0 };
205     char *start = *p;
206     int i;
207
208     /* Check if we've already reported these tables */
209     if (used_bitmap[(type >> 6) & 0x3] & (1ULL << (type & 0x3f)))
210         return 1;
211
212     /* Don't introduce spurious end markers */
213     if (type == 127)
214         return 0;
215
216     for (i = qemu_cfg_smbios_entries(); i > 0; i--) {
217         struct smbios_table table;
218         struct smbios_structure_header *header = (void *)*p;
219         int string;
220
221         qemu_cfg_read((u8 *)&table, sizeof(struct smbios_header));
222         table.header.length -= sizeof(struct smbios_header);
223
224         if (table.header.type != SMBIOS_TABLE_ENTRY) {
225             qemu_cfg_skip(table.header.length);
226             continue;
227         }
228
229         if (end - *p < sizeof(struct smbios_structure_header)) {
230             warn_noalloc();
231             break;
232         }
233
234         qemu_cfg_read((u8 *)*p, sizeof(struct smbios_structure_header));
235         table.header.length -= sizeof(struct smbios_structure_header);
236
237         if (header->type != type) {
238             qemu_cfg_skip(table.header.length);
239             continue;
240         }
241
242         *p += sizeof(struct smbios_structure_header);
243
244         /* Entries end with a double NULL char, if there's a string at
245          * the end (length is greater than formatted length), the string
246          * terminator provides the first NULL. */
247         string = header->length < table.header.length +
248                  sizeof(struct smbios_structure_header);
249
250         /* Read the rest and terminate the entry */
251         if (end - *p < table.header.length) {
252             warn_noalloc();
253             *p -= sizeof(struct smbios_structure_header);
254             continue;
255         }
256         qemu_cfg_read((u8 *)*p, table.header.length);
257         *p += table.header.length;
258         *((u8*)*p) = 0;
259         (*p)++;
260         if (!string) {
261             *((u8*)*p) = 0;
262             (*p)++;
263         }
264
265         (*nr_structs)++;
266         if (*p - (char *)header > *max_struct_size)
267             *max_struct_size = *p - (char *)header;
268     }
269
270     if (start != *p) {
271         /* Mark that we've reported on this type */
272         used_bitmap[(type >> 6) & 0x3] |= (1ULL << (type & 0x3f));
273         return 1;
274     }
275
276     return 0;
277 }
278
279 int qemu_cfg_get_numa_nodes(void)
280 {
281     u64 cnt;
282
283     qemu_cfg_read_entry(&cnt, QEMU_CFG_NUMA, sizeof(cnt));
284
285     return (int)cnt;
286 }
287
288 void qemu_cfg_get_numa_data(u64 *data, int n)
289 {
290     int i;
291
292     for (i = 0; i < n; i++)
293         qemu_cfg_read((u8*)(data + i), sizeof(u64));
294 }
295
296 u16 qemu_cfg_get_max_cpus(void)
297 {
298     u16 cnt;
299
300     if (!qemu_cfg_present)
301         return 0;
302
303     qemu_cfg_read_entry(&cnt, QEMU_CFG_MAX_CPUS, sizeof(cnt));
304
305     return cnt;
306 }
307
308 static QemuCfgFile LastFile;
309
310 static u32
311 __cfg_next_prefix_file(const char *prefix, int prefixlen, u32 prevselect)
312 {
313     if (!qemu_cfg_present)
314         return 0;
315
316     u32 count;
317     qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count));
318     count = ntohl(count);
319     u32 e;
320     for (e = 0; e < count; e++) {
321         qemu_cfg_read((void*)&LastFile, sizeof(LastFile));
322         u32 select = ntohs(LastFile.select);
323         if (select <= prevselect)
324             continue;
325         if (memcmp(prefix, LastFile.name, prefixlen) == 0)
326             return select;
327     }
328     return 0;
329 }
330
331 u32 qemu_cfg_next_prefix_file(const char *prefix, u32 prevselect)
332 {
333     return __cfg_next_prefix_file(prefix, strlen(prefix), prevselect);
334 }
335
336 u32 qemu_cfg_find_file(const char *name)
337 {
338     return __cfg_next_prefix_file(name, strlen(name) + 1, 0);
339 }
340
341 static int
342 __qemu_cfg_set_file(u32 select)
343 {
344     if (!qemu_cfg_present || !select)
345         return -1;
346     if (select == ntohs(LastFile.select))
347         return 0;
348
349     u32 count;
350     qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count));
351     count = ntohl(count);
352     u32 e;
353     for (e = 0; e < count; e++) {
354         qemu_cfg_read((void*)&LastFile, sizeof(LastFile));
355         if (select == ntohs(LastFile.select))
356             return 0;
357     }
358     return -1;
359 }
360
361 int qemu_cfg_size_file(u32 select)
362 {
363     if (__qemu_cfg_set_file(select))
364         return -1;
365     return ntohl(LastFile.size);
366 }
367
368 const char* qemu_cfg_name_file(u32 select)
369 {
370     if (__qemu_cfg_set_file(select))
371         return NULL;
372     return LastFile.name;
373 }
374
375 int qemu_cfg_read_file(u32 select, void *dst, u32 maxlen)
376 {
377     if (__qemu_cfg_set_file(select))
378         return -1;
379     int len = qemu_cfg_size_file(select);
380     if (len < 0 || len > maxlen)
381         return -1;
382     qemu_cfg_read_entry(dst, select, len);
383     return len;
384 }
385
386 // Helper function to find, malloc_tmphigh, and copy a romfile.  This
387 // function adds a trailing zero to the malloc'd copy.
388 void *
389 romfile_loadfile(const char *name, int *psize)
390 {
391     u32 file = romfile_find(name);
392     if (!file)
393         return NULL;
394
395     int filesize = romfile_size(file);
396     if (!filesize)
397         return NULL;
398
399     char *data = malloc_tmphigh(filesize+1);
400     if (!data) {
401         warn_noalloc();
402         return NULL;
403     }
404
405     dprintf(5, "Copying romfile '%s' (len %d)\n", name, filesize);
406     romfile_copy(file, data, filesize);
407     if (psize)
408         *psize = filesize;
409     data[filesize] = '\0';
410     return data;
411 }
412
413 // Attempt to load an integer from the given file - return 'defval'
414 // if unsuccesful.
415 u64
416 romfile_loadint(const char *name, u64 defval)
417 {
418     u32 file = romfile_find(name);
419     if (!file)
420         return defval;
421
422     int filesize = romfile_size(file);
423     if (!filesize || filesize > sizeof(u64) || (filesize & (filesize-1)))
424         // Doesn't look like a valid integer.
425         return defval;
426
427     u64 val = 0;
428     romfile_copy(file, &val, sizeof(val));
429     return val;
430 }