]>
Commit | Line | Data |
---|---|---|
b5b31860 PMD |
1 | /* |
2 | * QEMU PC System Firmware (OVMF specific) | |
3 | * | |
4 | * Copyright (c) 2003-2004 Fabrice Bellard | |
5 | * Copyright (c) 2011-2012 Intel Corporation | |
6 | * | |
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
8 | * of this software and associated documentation files (the "Software"), to deal | |
9 | * in the Software without restriction, including without limitation the rights | |
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
11 | * copies of the Software, and to permit persons to whom the Software is | |
12 | * furnished to do so, subject to the following conditions: | |
13 | * | |
14 | * The above copyright notice and this permission notice shall be included in | |
15 | * all copies or substantial portions of the Software. | |
16 | * | |
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
23 | * THE SOFTWARE. | |
24 | */ | |
25 | ||
26 | #include "qemu/osdep.h" | |
64915058 | 27 | #include "qemu/error-report.h" |
b5b31860 PMD |
28 | #include "hw/i386/pc.h" |
29 | #include "cpu.h" | |
30 | ||
31 | #define OVMF_TABLE_FOOTER_GUID "96b582de-1fb2-45f7-baea-a366c55a082d" | |
32 | ||
bfc8c144 DM |
33 | static const int bytes_after_table_footer = 32; |
34 | ||
b5b31860 PMD |
35 | static bool ovmf_flash_parsed; |
36 | static uint8_t *ovmf_table; | |
37 | static int ovmf_table_len; | |
38 | ||
39 | void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size) | |
40 | { | |
41 | uint8_t *ptr; | |
42 | QemuUUID guid; | |
43 | int tot_len; | |
44 | ||
45 | /* should only be called once */ | |
46 | if (ovmf_flash_parsed) { | |
47 | return; | |
48 | } | |
49 | ||
50 | ovmf_flash_parsed = true; | |
51 | ||
52 | if (flash_size < TARGET_PAGE_SIZE) { | |
53 | return; | |
54 | } | |
55 | ||
56 | /* | |
57 | * if this is OVMF there will be a table footer | |
bfc8c144 DM |
58 | * guid 48 bytes before the end of the flash file |
59 | * (= 32 bytes after the table + 16 bytes the GUID itself). | |
60 | * If it's not found, silently abort the flash parsing. | |
b5b31860 PMD |
61 | */ |
62 | qemu_uuid_parse(OVMF_TABLE_FOOTER_GUID, &guid); | |
63 | guid = qemu_uuid_bswap(guid); /* guids are LE */ | |
bfc8c144 | 64 | ptr = flash_ptr + flash_size - (bytes_after_table_footer + sizeof(guid)); |
b5b31860 PMD |
65 | if (!qemu_uuid_is_equal((QemuUUID *)ptr, &guid)) { |
66 | return; | |
67 | } | |
68 | ||
69 | /* if found, just before is two byte table length */ | |
70 | ptr -= sizeof(uint16_t); | |
71 | tot_len = le16_to_cpu(*(uint16_t *)ptr) - sizeof(guid) - sizeof(uint16_t); | |
72 | ||
64915058 DM |
73 | if (tot_len < 0 || tot_len > (ptr - flash_ptr)) { |
74 | error_report("OVMF table has invalid size %d", tot_len); | |
75 | return; | |
76 | } | |
77 | ||
78 | if (tot_len == 0) { | |
79 | /* no entries in the OVMF table */ | |
b5b31860 PMD |
80 | return; |
81 | } | |
82 | ||
83 | ovmf_table = g_malloc(tot_len); | |
84 | ovmf_table_len = tot_len; | |
85 | ||
86 | /* | |
87 | * ptr is the foot of the table, so copy it all to the newly | |
88 | * allocated ovmf_table and then set the ovmf_table pointer | |
89 | * to the table foot | |
90 | */ | |
91 | memcpy(ovmf_table, ptr - tot_len, tot_len); | |
92 | ovmf_table += tot_len; | |
93 | } | |
94 | ||
95 | /** | |
96 | * pc_system_ovmf_table_find - Find the data associated with an entry in OVMF's | |
97 | * reset vector GUIDed table. | |
98 | * | |
99 | * @entry: GUID string of the entry to lookup | |
100 | * @data: Filled with a pointer to the entry's value (if not NULL) | |
101 | * @data_len: Filled with the length of the entry's value (if not NULL). Pass | |
102 | * NULL here if the length of data is known. | |
103 | * | |
104 | * Return: true if the entry was found in the OVMF table; false otherwise. | |
105 | */ | |
106 | bool pc_system_ovmf_table_find(const char *entry, uint8_t **data, | |
107 | int *data_len) | |
108 | { | |
109 | uint8_t *ptr = ovmf_table; | |
110 | int tot_len = ovmf_table_len; | |
111 | QemuUUID entry_guid; | |
112 | ||
113 | assert(ovmf_flash_parsed); | |
114 | ||
115 | if (qemu_uuid_parse(entry, &entry_guid) < 0) { | |
116 | return false; | |
117 | } | |
118 | ||
119 | if (!ptr) { | |
120 | return false; | |
121 | } | |
122 | ||
123 | entry_guid = qemu_uuid_bswap(entry_guid); /* guids are LE */ | |
124 | while (tot_len >= sizeof(QemuUUID) + sizeof(uint16_t)) { | |
125 | int len; | |
126 | QemuUUID *guid; | |
127 | ||
128 | /* | |
129 | * The data structure is | |
130 | * arbitrary length data | |
131 | * 2 byte length of entire entry | |
132 | * 16 byte guid | |
133 | */ | |
134 | guid = (QemuUUID *)(ptr - sizeof(QemuUUID)); | |
135 | len = le16_to_cpu(*(uint16_t *)(ptr - sizeof(QemuUUID) - | |
136 | sizeof(uint16_t))); | |
137 | ||
138 | /* | |
139 | * just in case the table is corrupt, wouldn't want to spin in | |
140 | * the zero case | |
141 | */ | |
142 | if (len < sizeof(QemuUUID) + sizeof(uint16_t)) { | |
143 | return false; | |
144 | } else if (len > tot_len) { | |
145 | return false; | |
146 | } | |
147 | ||
148 | ptr -= len; | |
149 | tot_len -= len; | |
150 | if (qemu_uuid_is_equal(guid, &entry_guid)) { | |
151 | if (data) { | |
152 | *data = ptr; | |
153 | } | |
154 | if (data_len) { | |
155 | *data_len = len - sizeof(QemuUUID) - sizeof(uint16_t); | |
156 | } | |
157 | return true; | |
158 | } | |
159 | } | |
160 | return false; | |
161 | } |