Load SMBIOS entries and files from qemu
[seabios.git] / 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"
11 #include "ioport.h"
12 #include "paravirt.h"
13
14 int qemu_cfg_present;
15
16 static void
17 qemu_cfg_select(u16 f)
18 {
19     outw(f, PORT_QEMU_CFG_CTL);
20 }
21
22 static void
23 qemu_cfg_read(u8 *buf, int len)
24 {
25     while (len--)
26         *(buf++) = inb(PORT_QEMU_CFG_DATA);
27 }
28
29 static void
30 qemu_cfg_skip(int len)
31 {
32     while (len--)
33         inb(PORT_QEMU_CFG_DATA);
34 }
35
36 static void
37 qemu_cfg_read_entry(void *buf, int e, int len)
38 {
39     qemu_cfg_select(e);
40     qemu_cfg_read(buf, len);
41 }
42
43 void 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
63 void 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
71 int 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
82 u16 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
94 u16 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
103 void* qemu_cfg_next_acpi_table_load(void *addr, u16 len)
104 {
105     qemu_cfg_read(addr, len);
106     return addr;
107 }
108
109 u16 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
121 struct smbios_header {
122     u16 length;
123     u8 type;
124 } PACKED;
125
126 struct smbios_field {
127     struct smbios_header header;
128     u8 type;
129     u16 offset;
130     u8 data[];
131 } PACKED;
132
133 struct 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
141 size_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. */
172 struct smbios_structure_header {
173         u8 type;
174         u8 length;
175         u16 handle;
176 } PACKED;
177
178 int 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