1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40#include <assert.h>
41#include <errno.h>
42#include <string.h>
43#include <glib.h>
44
45#include "stream.h"
46#include "vmstate.h"
47
48static int get_nullptr(SlirpIStream *f, void *pv, size_t size,
49 const VMStateField *field)
50{
51 if (slirp_istream_read_u8(f) == VMS_NULLPTR_MARKER) {
52 return 0;
53 }
54 g_warning("vmstate: get_nullptr expected VMS_NULLPTR_MARKER");
55 return -EINVAL;
56}
57
58static int put_nullptr(SlirpOStream *f, void *pv, size_t size,
59 const VMStateField *field)
60
61{
62 if (pv == NULL) {
63 slirp_ostream_write_u8(f, VMS_NULLPTR_MARKER);
64 return 0;
65 }
66 g_warning("vmstate: put_nullptr must be called with pv == NULL");
67 return -EINVAL;
68}
69
70const VMStateInfo slirp_vmstate_info_nullptr = {
71 .name = "uint64",
72 .get = get_nullptr,
73 .put = put_nullptr,
74};
75
76
77
78static int get_uint8(SlirpIStream *f, void *pv, size_t size, const VMStateField *field)
79{
80 uint8_t *v = pv;
81 *v = slirp_istream_read_u8(f);
82 return 0;
83}
84
85static int put_uint8(SlirpOStream *f, void *pv, size_t size, const VMStateField *field)
86{
87 uint8_t *v = pv;
88 slirp_ostream_write_u8(f, *v);
89 return 0;
90}
91
92const VMStateInfo slirp_vmstate_info_uint8 = {
93 .name = "uint8",
94 .get = get_uint8,
95 .put = put_uint8,
96};
97
98
99
100static int get_uint16(SlirpIStream *f, void *pv, size_t size,
101 const VMStateField *field)
102{
103 uint16_t *v = pv;
104 *v = slirp_istream_read_u16(f);
105 return 0;
106}
107
108static int put_uint16(SlirpOStream *f, void *pv, size_t size,
109 const VMStateField *field)
110{
111 uint16_t *v = pv;
112 slirp_ostream_write_u16(f, *v);
113 return 0;
114}
115
116const VMStateInfo slirp_vmstate_info_uint16 = {
117 .name = "uint16",
118 .get = get_uint16,
119 .put = put_uint16,
120};
121
122
123
124static int get_uint32(SlirpIStream *f, void *pv, size_t size,
125 const VMStateField *field)
126{
127 uint32_t *v = pv;
128 *v = slirp_istream_read_u32(f);
129 return 0;
130}
131
132static int put_uint32(SlirpOStream *f, void *pv, size_t size,
133 const VMStateField *field)
134{
135 uint32_t *v = pv;
136 slirp_ostream_write_u32(f, *v);
137 return 0;
138}
139
140const VMStateInfo slirp_vmstate_info_uint32 = {
141 .name = "uint32",
142 .get = get_uint32,
143 .put = put_uint32,
144};
145
146
147
148static int get_int16(SlirpIStream *f, void *pv, size_t size, const VMStateField *field)
149{
150 int16_t *v = pv;
151 *v = slirp_istream_read_i16(f);
152 return 0;
153}
154
155static int put_int16(SlirpOStream *f, void *pv, size_t size, const VMStateField *field)
156{
157 int16_t *v = pv;
158 slirp_ostream_write_i16(f, *v);
159 return 0;
160}
161
162const VMStateInfo slirp_vmstate_info_int16 = {
163 .name = "int16",
164 .get = get_int16,
165 .put = put_int16,
166};
167
168
169
170static int get_int32(SlirpIStream *f, void *pv, size_t size, const VMStateField *field)
171{
172 int32_t *v = pv;
173 *v = slirp_istream_read_i32(f);
174 return 0;
175}
176
177static int put_int32(SlirpOStream *f, void *pv, size_t size, const VMStateField *field)
178{
179 int32_t *v = pv;
180 slirp_ostream_write_i32(f, *v);
181 return 0;
182}
183
184const VMStateInfo slirp_vmstate_info_int32 = {
185 .name = "int32",
186 .get = get_int32,
187 .put = put_int32,
188};
189
190
191
192
193
194
195
196static int get_tmp(SlirpIStream *f, void *pv, size_t size, const VMStateField *field)
197{
198 int ret;
199 const VMStateDescription *vmsd = field->vmsd;
200 int version_id = field->version_id;
201 void *tmp = g_malloc(size);
202
203
204 *(void **)tmp = pv;
205 ret = slirp_vmstate_load_state(f, vmsd, tmp, version_id);
206 g_free(tmp);
207 return ret;
208}
209
210static int put_tmp(SlirpOStream *f, void *pv, size_t size, const VMStateField *field)
211{
212 const VMStateDescription *vmsd = field->vmsd;
213 void *tmp = g_malloc(size);
214 int ret;
215
216
217 *(void **)tmp = pv;
218 ret = slirp_vmstate_save_state(f, vmsd, tmp);
219 g_free(tmp);
220
221 return ret;
222}
223
224const VMStateInfo slirp_vmstate_info_tmp = {
225 .name = "tmp",
226 .get = get_tmp,
227 .put = put_tmp,
228};
229
230
231
232static int get_buffer(SlirpIStream *f, void *pv, size_t size,
233 const VMStateField *field)
234{
235 slirp_istream_read(f, pv, size);
236 return 0;
237}
238
239static int put_buffer(SlirpOStream *f, void *pv, size_t size,
240 const VMStateField *field)
241{
242 slirp_ostream_write(f, pv, size);
243 return 0;
244}
245
246const VMStateInfo slirp_vmstate_info_buffer = {
247 .name = "buffer",
248 .get = get_buffer,
249 .put = put_buffer,
250};
251
252static int vmstate_n_elems(void *opaque, const VMStateField *field)
253{
254 int n_elems = 1;
255
256 if (field->flags & VMS_ARRAY) {
257 n_elems = field->num;
258 } else if (field->flags & VMS_VARRAY_INT32) {
259 n_elems = *(int32_t *)(opaque + field->num_offset);
260 } else if (field->flags & VMS_VARRAY_UINT32) {
261 n_elems = *(uint32_t *)(opaque + field->num_offset);
262 } else if (field->flags & VMS_VARRAY_UINT16) {
263 n_elems = *(uint16_t *)(opaque + field->num_offset);
264 } else if (field->flags & VMS_VARRAY_UINT8) {
265 n_elems = *(uint8_t *)(opaque + field->num_offset);
266 }
267
268 if (field->flags & VMS_MULTIPLY_ELEMENTS) {
269 n_elems *= field->num;
270 }
271
272 return n_elems;
273}
274
275static int vmstate_size(void *opaque, const VMStateField *field)
276{
277 int size = field->size;
278
279 if (field->flags & VMS_VBUFFER) {
280 size = *(int32_t *)(opaque + field->size_offset);
281 if (field->flags & VMS_MULTIPLY) {
282 size *= field->size;
283 }
284 }
285
286 return size;
287}
288
289static int
290vmstate_save_state_v(SlirpOStream *f, const VMStateDescription *vmsd,
291 void *opaque, int version_id)
292{
293 int ret = 0;
294 const VMStateField *field = vmsd->fields;
295
296 if (vmsd->pre_save) {
297 ret = vmsd->pre_save(opaque);
298 if (ret) {
299 g_warning("pre-save failed: %s", vmsd->name);
300 return ret;
301 }
302 }
303
304 while (field->name) {
305 if ((field->field_exists &&
306 field->field_exists(opaque, version_id)) ||
307 (!field->field_exists &&
308 field->version_id <= version_id)) {
309 void *first_elem = opaque + field->offset;
310 int i, n_elems = vmstate_n_elems(opaque, field);
311 int size = vmstate_size(opaque, field);
312
313 if (field->flags & VMS_POINTER) {
314 first_elem = *(void **)first_elem;
315 assert(first_elem || !n_elems || !size);
316 }
317 for (i = 0; i < n_elems; i++) {
318 void *curr_elem = first_elem + size * i;
319 ret = 0;
320
321 if (field->flags & VMS_ARRAY_OF_POINTER) {
322 assert(curr_elem);
323 curr_elem = *(void **)curr_elem;
324 }
325 if (!curr_elem && size) {
326
327 assert(field->flags & VMS_ARRAY_OF_POINTER);
328 ret = slirp_vmstate_info_nullptr.put(f, curr_elem, size, NULL);
329 } else if (field->flags & VMS_STRUCT) {
330 ret = slirp_vmstate_save_state(f, field->vmsd, curr_elem);
331 } else if (field->flags & VMS_VSTRUCT) {
332 ret = vmstate_save_state_v(f, field->vmsd, curr_elem,
333 field->struct_version_id);
334 } else {
335 ret = field->info->put(f, curr_elem, size, field);
336 }
337 if (ret) {
338 g_warning("Save of field %s/%s failed",
339 vmsd->name, field->name);
340 return ret;
341 }
342 }
343 } else {
344 if (field->flags & VMS_MUST_EXIST) {
345 g_warning("Output state validation failed: %s/%s",
346 vmsd->name, field->name);
347 assert(!(field->flags & VMS_MUST_EXIST));
348 }
349 }
350 field++;
351 }
352
353 return 0;
354}
355
356int slirp_vmstate_save_state(SlirpOStream *f, const VMStateDescription *vmsd,
357 void *opaque)
358{
359 return vmstate_save_state_v(f, vmsd, opaque, vmsd->version_id);
360}
361
362static void vmstate_handle_alloc(void *ptr, VMStateField *field, void *opaque)
363{
364 if (field->flags & VMS_POINTER && field->flags & VMS_ALLOC) {
365 size_t size = vmstate_size(opaque, field);
366 size *= vmstate_n_elems(opaque, field);
367 if (size) {
368 *(void **)ptr = g_malloc(size);
369 }
370 }
371}
372
373int slirp_vmstate_load_state(SlirpIStream *f, const VMStateDescription *vmsd,
374 void *opaque, int version_id)
375{
376 VMStateField *field = vmsd->fields;
377 int ret = 0;
378
379 if (version_id > vmsd->version_id) {
380 g_warning("%s: incoming version_id %d is too new "
381 "for local version_id %d",
382 vmsd->name, version_id, vmsd->version_id);
383 return -EINVAL;
384 }
385 if (vmsd->pre_load) {
386 int ret = vmsd->pre_load(opaque);
387 if (ret) {
388 return ret;
389 }
390 }
391 while (field->name) {
392 if ((field->field_exists &&
393 field->field_exists(opaque, version_id)) ||
394 (!field->field_exists &&
395 field->version_id <= version_id)) {
396 void *first_elem = opaque + field->offset;
397 int i, n_elems = vmstate_n_elems(opaque, field);
398 int size = vmstate_size(opaque, field);
399
400 vmstate_handle_alloc(first_elem, field, opaque);
401 if (field->flags & VMS_POINTER) {
402 first_elem = *(void **)first_elem;
403 assert(first_elem || !n_elems || !size);
404 }
405 for (i = 0; i < n_elems; i++) {
406 void *curr_elem = first_elem + size * i;
407
408 if (field->flags & VMS_ARRAY_OF_POINTER) {
409 curr_elem = *(void **)curr_elem;
410 }
411 if (!curr_elem && size) {
412
413 assert(field->flags & VMS_ARRAY_OF_POINTER);
414 ret = slirp_vmstate_info_nullptr.get(f, curr_elem, size, NULL);
415 } else if (field->flags & VMS_STRUCT) {
416 ret = slirp_vmstate_load_state(f, field->vmsd, curr_elem,
417 field->vmsd->version_id);
418 } else if (field->flags & VMS_VSTRUCT) {
419 ret = slirp_vmstate_load_state(f, field->vmsd, curr_elem,
420 field->struct_version_id);
421 } else {
422 ret = field->info->get(f, curr_elem, size, field);
423 }
424 if (ret < 0) {
425 g_warning("Failed to load %s:%s", vmsd->name,
426 field->name);
427 return ret;
428 }
429 }
430 } else if (field->flags & VMS_MUST_EXIST) {
431 g_warning("Input validation failed: %s/%s",
432 vmsd->name, field->name);
433 return -1;
434 }
435 field++;
436 }
437 if (vmsd->post_load) {
438 ret = vmsd->post_load(opaque, version_id);
439 }
440 return ret;
441}
442