Skip to content

Commit 90ca4e0

Browse files
committed
hw/uefi: add var-service-core.c
This is the core code for guest <-> host communication. This accepts request messages from the guest, dispatches them to the service called, and sends back the response message. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Message-ID: <20250225163031.1409078-11-kraxel@redhat.com>
1 parent 034cb96 commit 90ca4e0

File tree

1 file changed

+321
-0
lines changed

1 file changed

+321
-0
lines changed

hw/uefi/var-service-core.c

Lines changed: 321 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,321 @@
1+
/*
2+
* SPDX-License-Identifier: GPL-2.0-or-later
3+
*
4+
* uefi vars device
5+
*/
6+
#include "qemu/osdep.h"
7+
#include "qemu/crc32c.h"
8+
#include "system/dma.h"
9+
#include "migration/vmstate.h"
10+
11+
#include "hw/uefi/var-service.h"
12+
#include "hw/uefi/var-service-api.h"
13+
#include "hw/uefi/var-service-edk2.h"
14+
15+
#include "trace/trace-hw_uefi.h"
16+
17+
static int uefi_vars_pre_load(void *opaque)
18+
{
19+
uefi_vars_state *uv = opaque;
20+
21+
uefi_vars_clear_all(uv);
22+
uefi_vars_policies_clear(uv);
23+
g_free(uv->buffer);
24+
return 0;
25+
}
26+
27+
static int uefi_vars_post_load(void *opaque, int version_id)
28+
{
29+
uefi_vars_state *uv = opaque;
30+
31+
uefi_vars_update_storage(uv);
32+
uv->buffer = g_malloc(uv->buf_size);
33+
return 0;
34+
}
35+
36+
const VMStateDescription vmstate_uefi_vars = {
37+
.name = "uefi-vars",
38+
.pre_load = uefi_vars_pre_load,
39+
.post_load = uefi_vars_post_load,
40+
.fields = (VMStateField[]) {
41+
VMSTATE_UINT16(sts, uefi_vars_state),
42+
VMSTATE_UINT32(buf_size, uefi_vars_state),
43+
VMSTATE_UINT32(buf_addr_lo, uefi_vars_state),
44+
VMSTATE_UINT32(buf_addr_hi, uefi_vars_state),
45+
VMSTATE_UINT32(pio_xfer_offset, uefi_vars_state),
46+
VMSTATE_VBUFFER_ALLOC_UINT32(pio_xfer_buffer, uefi_vars_state,
47+
0, NULL, buf_size),
48+
VMSTATE_BOOL(end_of_dxe, uefi_vars_state),
49+
VMSTATE_BOOL(ready_to_boot, uefi_vars_state),
50+
VMSTATE_BOOL(exit_boot_service, uefi_vars_state),
51+
VMSTATE_BOOL(policy_locked, uefi_vars_state),
52+
VMSTATE_UINT64(used_storage, uefi_vars_state),
53+
VMSTATE_QTAILQ_V(variables, uefi_vars_state, 0,
54+
vmstate_uefi_variable, uefi_variable, next),
55+
VMSTATE_QTAILQ_V(var_policies, uefi_vars_state, 0,
56+
vmstate_uefi_var_policy, uefi_var_policy, next),
57+
VMSTATE_END_OF_LIST()
58+
},
59+
};
60+
61+
static uint32_t uefi_vars_cmd_mm(uefi_vars_state *uv, bool dma_mode)
62+
{
63+
hwaddr dma;
64+
mm_header *mhdr;
65+
uint64_t size;
66+
uint32_t retval;
67+
68+
dma = uv->buf_addr_lo | ((hwaddr)uv->buf_addr_hi << 32);
69+
mhdr = (mm_header *) uv->buffer;
70+
71+
if (!uv->buffer || uv->buf_size < sizeof(*mhdr)) {
72+
return UEFI_VARS_STS_ERR_BAD_BUFFER_SIZE;
73+
}
74+
75+
/* read header */
76+
if (dma_mode) {
77+
dma_memory_read(&address_space_memory, dma,
78+
uv->buffer, sizeof(*mhdr),
79+
MEMTXATTRS_UNSPECIFIED);
80+
} else {
81+
memcpy(uv->buffer, uv->pio_xfer_buffer, sizeof(*mhdr));
82+
}
83+
84+
if (uadd64_overflow(sizeof(*mhdr), mhdr->length, &size)) {
85+
return UEFI_VARS_STS_ERR_BAD_BUFFER_SIZE;
86+
}
87+
if (uv->buf_size < size) {
88+
return UEFI_VARS_STS_ERR_BAD_BUFFER_SIZE;
89+
}
90+
91+
/* read buffer (excl header) */
92+
if (dma_mode) {
93+
dma_memory_read(&address_space_memory, dma + sizeof(*mhdr),
94+
uv->buffer + sizeof(*mhdr), mhdr->length,
95+
MEMTXATTRS_UNSPECIFIED);
96+
} else {
97+
memcpy(uv->buffer + sizeof(*mhdr),
98+
uv->pio_xfer_buffer + sizeof(*mhdr),
99+
mhdr->length);
100+
}
101+
memset(uv->buffer + size, 0, uv->buf_size - size);
102+
103+
/* dispatch */
104+
if (qemu_uuid_is_equal(&mhdr->guid, &EfiSmmVariableProtocolGuid)) {
105+
retval = uefi_vars_mm_vars_proto(uv);
106+
107+
} else if (qemu_uuid_is_equal(&mhdr->guid, &VarCheckPolicyLibMmiHandlerGuid)) {
108+
retval = uefi_vars_mm_check_policy_proto(uv);
109+
110+
} else if (qemu_uuid_is_equal(&mhdr->guid, &EfiEndOfDxeEventGroupGuid)) {
111+
trace_uefi_event("end-of-dxe");
112+
uv->end_of_dxe = true;
113+
retval = UEFI_VARS_STS_SUCCESS;
114+
115+
} else if (qemu_uuid_is_equal(&mhdr->guid, &EfiEventReadyToBootGuid)) {
116+
trace_uefi_event("ready-to-boot");
117+
uv->ready_to_boot = true;
118+
retval = UEFI_VARS_STS_SUCCESS;
119+
120+
} else if (qemu_uuid_is_equal(&mhdr->guid, &EfiEventExitBootServicesGuid)) {
121+
trace_uefi_event("exit-boot-service");
122+
uv->exit_boot_service = true;
123+
retval = UEFI_VARS_STS_SUCCESS;
124+
125+
} else {
126+
retval = UEFI_VARS_STS_ERR_NOT_SUPPORTED;
127+
}
128+
129+
/* write buffer */
130+
if (dma_mode) {
131+
dma_memory_write(&address_space_memory, dma,
132+
uv->buffer, sizeof(*mhdr) + mhdr->length,
133+
MEMTXATTRS_UNSPECIFIED);
134+
} else {
135+
memcpy(uv->pio_xfer_buffer + sizeof(*mhdr),
136+
uv->buffer + sizeof(*mhdr),
137+
sizeof(*mhdr) + mhdr->length);
138+
}
139+
140+
return retval;
141+
}
142+
143+
static void uefi_vars_soft_reset(uefi_vars_state *uv)
144+
{
145+
g_free(uv->buffer);
146+
uv->buffer = NULL;
147+
uv->buf_size = 0;
148+
uv->buf_addr_lo = 0;
149+
uv->buf_addr_hi = 0;
150+
}
151+
152+
void uefi_vars_hard_reset(uefi_vars_state *uv)
153+
{
154+
trace_uefi_hard_reset();
155+
uefi_vars_soft_reset(uv);
156+
157+
uv->end_of_dxe = false;
158+
uv->ready_to_boot = false;
159+
uv->exit_boot_service = false;
160+
uv->policy_locked = false;
161+
162+
uefi_vars_clear_volatile(uv);
163+
uefi_vars_policies_clear(uv);
164+
uefi_vars_auth_init(uv);
165+
}
166+
167+
static uint32_t uefi_vars_cmd(uefi_vars_state *uv, uint32_t cmd)
168+
{
169+
switch (cmd) {
170+
case UEFI_VARS_CMD_RESET:
171+
uefi_vars_soft_reset(uv);
172+
return UEFI_VARS_STS_SUCCESS;
173+
case UEFI_VARS_CMD_DMA_MM:
174+
return uefi_vars_cmd_mm(uv, true);
175+
case UEFI_VARS_CMD_PIO_MM:
176+
return uefi_vars_cmd_mm(uv, false);
177+
case UEFI_VARS_CMD_PIO_ZERO_OFFSET:
178+
uv->pio_xfer_offset = 0;
179+
return UEFI_VARS_STS_SUCCESS;
180+
default:
181+
return UEFI_VARS_STS_ERR_NOT_SUPPORTED;
182+
}
183+
}
184+
185+
static uint64_t uefi_vars_read(void *opaque, hwaddr addr, unsigned size)
186+
{
187+
uefi_vars_state *uv = opaque;
188+
uint64_t retval = -1;
189+
void *xfer_ptr;
190+
191+
trace_uefi_reg_read(addr, size);
192+
193+
switch (addr) {
194+
case UEFI_VARS_REG_MAGIC:
195+
retval = UEFI_VARS_MAGIC_VALUE;
196+
break;
197+
case UEFI_VARS_REG_CMD_STS:
198+
retval = uv->sts;
199+
break;
200+
case UEFI_VARS_REG_BUFFER_SIZE:
201+
retval = uv->buf_size;
202+
break;
203+
case UEFI_VARS_REG_DMA_BUFFER_ADDR_LO:
204+
retval = uv->buf_addr_lo;
205+
break;
206+
case UEFI_VARS_REG_DMA_BUFFER_ADDR_HI:
207+
retval = uv->buf_addr_hi;
208+
break;
209+
case UEFI_VARS_REG_PIO_BUFFER_TRANSFER:
210+
if (uv->pio_xfer_offset + size > uv->buf_size) {
211+
retval = 0;
212+
break;
213+
}
214+
xfer_ptr = uv->pio_xfer_buffer + uv->pio_xfer_offset;
215+
switch (size) {
216+
case 1:
217+
retval = *(uint8_t *)xfer_ptr;
218+
break;
219+
case 2:
220+
retval = *(uint16_t *)xfer_ptr;
221+
break;
222+
case 4:
223+
retval = *(uint32_t *)xfer_ptr;
224+
break;
225+
case 8:
226+
retval = *(uint64_t *)xfer_ptr;
227+
break;
228+
}
229+
uv->pio_xfer_offset += size;
230+
break;
231+
case UEFI_VARS_REG_PIO_BUFFER_CRC32C:
232+
retval = crc32c(0xffffffff, uv->pio_xfer_buffer, uv->pio_xfer_offset);
233+
break;
234+
case UEFI_VARS_REG_FLAGS:
235+
retval = 0;
236+
if (uv->use_pio) {
237+
retval |= UEFI_VARS_FLAG_USE_PIO;
238+
}
239+
}
240+
return retval;
241+
}
242+
243+
static void uefi_vars_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
244+
{
245+
uefi_vars_state *uv = opaque;
246+
void *xfer_ptr;
247+
248+
trace_uefi_reg_write(addr, val, size);
249+
250+
switch (addr) {
251+
case UEFI_VARS_REG_CMD_STS:
252+
uv->sts = uefi_vars_cmd(uv, val);
253+
break;
254+
case UEFI_VARS_REG_BUFFER_SIZE:
255+
if (val > MAX_BUFFER_SIZE) {
256+
val = MAX_BUFFER_SIZE;
257+
}
258+
uv->buf_size = val;
259+
g_free(uv->buffer);
260+
g_free(uv->pio_xfer_buffer);
261+
uv->buffer = g_malloc(uv->buf_size);
262+
uv->pio_xfer_buffer = g_malloc(uv->buf_size);
263+
break;
264+
case UEFI_VARS_REG_DMA_BUFFER_ADDR_LO:
265+
uv->buf_addr_lo = val;
266+
break;
267+
case UEFI_VARS_REG_DMA_BUFFER_ADDR_HI:
268+
uv->buf_addr_hi = val;
269+
break;
270+
case UEFI_VARS_REG_PIO_BUFFER_TRANSFER:
271+
if (uv->pio_xfer_offset + size > uv->buf_size) {
272+
break;
273+
}
274+
xfer_ptr = uv->pio_xfer_buffer + uv->pio_xfer_offset;
275+
switch (size) {
276+
case 1:
277+
*(uint8_t *)xfer_ptr = val;
278+
break;
279+
case 2:
280+
*(uint16_t *)xfer_ptr = val;
281+
break;
282+
case 4:
283+
*(uint32_t *)xfer_ptr = val;
284+
break;
285+
case 8:
286+
*(uint64_t *)xfer_ptr = val;
287+
break;
288+
}
289+
uv->pio_xfer_offset += size;
290+
break;
291+
case UEFI_VARS_REG_PIO_BUFFER_CRC32C:
292+
case UEFI_VARS_REG_FLAGS:
293+
default:
294+
break;
295+
}
296+
}
297+
298+
static const MemoryRegionOps uefi_vars_ops = {
299+
.read = uefi_vars_read,
300+
.write = uefi_vars_write,
301+
.endianness = DEVICE_LITTLE_ENDIAN,
302+
.impl = {
303+
.min_access_size = 2,
304+
.max_access_size = 4,
305+
},
306+
};
307+
308+
void uefi_vars_init(Object *obj, uefi_vars_state *uv)
309+
{
310+
QTAILQ_INIT(&uv->variables);
311+
QTAILQ_INIT(&uv->var_policies);
312+
uv->jsonfd = -1;
313+
memory_region_init_io(&uv->mr, obj, &uefi_vars_ops, uv,
314+
"uefi-vars", UEFI_VARS_REGS_SIZE);
315+
}
316+
317+
void uefi_vars_realize(uefi_vars_state *uv, Error **errp)
318+
{
319+
uefi_vars_json_init(uv, errp);
320+
uefi_vars_json_load(uv, errp);
321+
}

0 commit comments

Comments
 (0)