4 * Copyright (c) 2009-2018 Red Hat Inc
7 * Juan Quintela <quintela@redhat.com>
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
20 static int get_nullptr(SlirpIStream
*f
, void *pv
, size_t size
,
21 const VMStateField
*field
)
23 if (slirp_istream_read_u8(f
) == VMS_NULLPTR_MARKER
) {
26 g_warning("vmstate: get_nullptr expected VMS_NULLPTR_MARKER");
30 static int put_nullptr(SlirpOStream
*f
, void *pv
, size_t size
,
31 const VMStateField
*field
)
35 slirp_ostream_write_u8(f
, VMS_NULLPTR_MARKER
);
38 g_warning("vmstate: put_nullptr must be called with pv == NULL");
42 const VMStateInfo slirp_vmstate_info_nullptr
= {
48 /* 8 bit unsigned int */
50 static int get_uint8(SlirpIStream
*f
, void *pv
, size_t size
, const VMStateField
*field
)
53 *v
= slirp_istream_read_u8(f
);
57 static int put_uint8(SlirpOStream
*f
, void *pv
, size_t size
, const VMStateField
*field
)
60 slirp_ostream_write_u8(f
, *v
);
64 const VMStateInfo slirp_vmstate_info_uint8
= {
70 /* 16 bit unsigned int */
72 static int get_uint16(SlirpIStream
*f
, void *pv
, size_t size
,
73 const VMStateField
*field
)
76 *v
= slirp_istream_read_u16(f
);
80 static int put_uint16(SlirpOStream
*f
, void *pv
, size_t size
,
81 const VMStateField
*field
)
84 slirp_ostream_write_u16(f
, *v
);
88 const VMStateInfo slirp_vmstate_info_uint16
= {
94 /* 32 bit unsigned int */
96 static int get_uint32(SlirpIStream
*f
, void *pv
, size_t size
,
97 const VMStateField
*field
)
100 *v
= slirp_istream_read_u32(f
);
104 static int put_uint32(SlirpOStream
*f
, void *pv
, size_t size
,
105 const VMStateField
*field
)
108 slirp_ostream_write_u32(f
, *v
);
112 const VMStateInfo slirp_vmstate_info_uint32
= {
120 static int get_int16(SlirpIStream
*f
, void *pv
, size_t size
, const VMStateField
*field
)
123 *v
= slirp_istream_read_i16(f
);
127 static int put_int16(SlirpOStream
*f
, void *pv
, size_t size
, const VMStateField
*field
)
130 slirp_ostream_write_i16(f
, *v
);
134 const VMStateInfo slirp_vmstate_info_int16
= {
142 static int get_int32(SlirpIStream
*f
, void *pv
, size_t size
, const VMStateField
*field
)
145 *v
= slirp_istream_read_i32(f
);
149 static int put_int32(SlirpOStream
*f
, void *pv
, size_t size
, const VMStateField
*field
)
152 slirp_ostream_write_i32(f
, *v
);
156 const VMStateInfo slirp_vmstate_info_int32
= {
162 /* vmstate_info_tmp, see VMSTATE_WITH_TMP, the idea is that we allocate
163 * a temporary buffer and the pre_load/pre_save methods in the child vmsd
164 * copy stuff from the parent into the child and do calculations to fill
165 * in fields that don't really exist in the parent but need to be in the
168 static int get_tmp(SlirpIStream
*f
, void *pv
, size_t size
, const VMStateField
*field
)
171 const VMStateDescription
*vmsd
= field
->vmsd
;
172 int version_id
= field
->version_id
;
173 void *tmp
= g_malloc(size
);
175 /* Writes the parent field which is at the start of the tmp */
177 ret
= slirp_vmstate_load_state(f
, vmsd
, tmp
, version_id
);
182 static int put_tmp(SlirpOStream
*f
, void *pv
, size_t size
, const VMStateField
*field
)
184 const VMStateDescription
*vmsd
= field
->vmsd
;
185 void *tmp
= g_malloc(size
);
188 /* Writes the parent field which is at the start of the tmp */
190 ret
= slirp_vmstate_save_state(f
, vmsd
, tmp
);
196 const VMStateInfo slirp_vmstate_info_tmp
= {
202 /* uint8_t buffers */
204 static int get_buffer(SlirpIStream
*f
, void *pv
, size_t size
,
205 const VMStateField
*field
)
207 slirp_istream_read(f
, pv
, size
);
211 static int put_buffer(SlirpOStream
*f
, void *pv
, size_t size
,
212 const VMStateField
*field
)
214 slirp_ostream_write(f
, pv
, size
);
218 const VMStateInfo slirp_vmstate_info_buffer
= {
224 static int vmstate_n_elems(void *opaque
, const VMStateField
*field
)
228 if (field
->flags
& VMS_ARRAY
) {
229 n_elems
= field
->num
;
230 } else if (field
->flags
& VMS_VARRAY_INT32
) {
231 n_elems
= *(int32_t *)(opaque
+ field
->num_offset
);
232 } else if (field
->flags
& VMS_VARRAY_UINT32
) {
233 n_elems
= *(uint32_t *)(opaque
+ field
->num_offset
);
234 } else if (field
->flags
& VMS_VARRAY_UINT16
) {
235 n_elems
= *(uint16_t *)(opaque
+ field
->num_offset
);
236 } else if (field
->flags
& VMS_VARRAY_UINT8
) {
237 n_elems
= *(uint8_t *)(opaque
+ field
->num_offset
);
240 if (field
->flags
& VMS_MULTIPLY_ELEMENTS
) {
241 n_elems
*= field
->num
;
247 static int vmstate_size(void *opaque
, const VMStateField
*field
)
249 int size
= field
->size
;
251 if (field
->flags
& VMS_VBUFFER
) {
252 size
= *(int32_t *)(opaque
+ field
->size_offset
);
253 if (field
->flags
& VMS_MULTIPLY
) {
262 vmstate_save_state_v(SlirpOStream
*f
, const VMStateDescription
*vmsd
,
263 void *opaque
, int version_id
)
266 const VMStateField
*field
= vmsd
->fields
;
268 if (vmsd
->pre_save
) {
269 ret
= vmsd
->pre_save(opaque
);
271 g_warning("pre-save failed: %s", vmsd
->name
);
276 while (field
->name
) {
277 if ((field
->field_exists
&&
278 field
->field_exists(opaque
, version_id
)) ||
279 (!field
->field_exists
&&
280 field
->version_id
<= version_id
)) {
281 void *first_elem
= opaque
+ field
->offset
;
282 int i
, n_elems
= vmstate_n_elems(opaque
, field
);
283 int size
= vmstate_size(opaque
, field
);
285 if (field
->flags
& VMS_POINTER
) {
286 first_elem
= *(void **)first_elem
;
287 assert(first_elem
|| !n_elems
|| !size
);
289 for (i
= 0; i
< n_elems
; i
++) {
290 void *curr_elem
= first_elem
+ size
* i
;
293 if (field
->flags
& VMS_ARRAY_OF_POINTER
) {
295 curr_elem
= *(void **)curr_elem
;
297 if (!curr_elem
&& size
) {
298 /* if null pointer write placeholder and do not follow */
299 assert(field
->flags
& VMS_ARRAY_OF_POINTER
);
300 ret
= slirp_vmstate_info_nullptr
.put(f
, curr_elem
, size
, NULL
);
301 } else if (field
->flags
& VMS_STRUCT
) {
302 ret
= slirp_vmstate_save_state(f
, field
->vmsd
, curr_elem
);
303 } else if (field
->flags
& VMS_VSTRUCT
) {
304 ret
= vmstate_save_state_v(f
, field
->vmsd
, curr_elem
,
305 field
->struct_version_id
);
307 ret
= field
->info
->put(f
, curr_elem
, size
, field
);
310 g_warning("Save of field %s/%s failed",
311 vmsd
->name
, field
->name
);
316 if (field
->flags
& VMS_MUST_EXIST
) {
317 g_warning("Output state validation failed: %s/%s",
318 vmsd
->name
, field
->name
);
319 assert(!(field
->flags
& VMS_MUST_EXIST
));
328 int slirp_vmstate_save_state(SlirpOStream
*f
, const VMStateDescription
*vmsd
,
331 return vmstate_save_state_v(f
, vmsd
, opaque
, vmsd
->version_id
);
334 static void vmstate_handle_alloc(void *ptr
, VMStateField
*field
, void *opaque
)
336 if (field
->flags
& VMS_POINTER
&& field
->flags
& VMS_ALLOC
) {
337 size_t size
= vmstate_size(opaque
, field
);
338 size
*= vmstate_n_elems(opaque
, field
);
340 *(void **)ptr
= g_malloc(size
);
345 int slirp_vmstate_load_state(SlirpIStream
*f
, const VMStateDescription
*vmsd
,
346 void *opaque
, int version_id
)
348 VMStateField
*field
= vmsd
->fields
;
351 if (version_id
> vmsd
->version_id
) {
352 g_warning("%s: incoming version_id %d is too new "
353 "for local version_id %d",
354 vmsd
->name
, version_id
, vmsd
->version_id
);
357 if (vmsd
->pre_load
) {
358 int ret
= vmsd
->pre_load(opaque
);
363 while (field
->name
) {
364 if ((field
->field_exists
&&
365 field
->field_exists(opaque
, version_id
)) ||
366 (!field
->field_exists
&&
367 field
->version_id
<= version_id
)) {
368 void *first_elem
= opaque
+ field
->offset
;
369 int i
, n_elems
= vmstate_n_elems(opaque
, field
);
370 int size
= vmstate_size(opaque
, field
);
372 vmstate_handle_alloc(first_elem
, field
, opaque
);
373 if (field
->flags
& VMS_POINTER
) {
374 first_elem
= *(void **)first_elem
;
375 assert(first_elem
|| !n_elems
|| !size
);
377 for (i
= 0; i
< n_elems
; i
++) {
378 void *curr_elem
= first_elem
+ size
* i
;
380 if (field
->flags
& VMS_ARRAY_OF_POINTER
) {
381 curr_elem
= *(void **)curr_elem
;
383 if (!curr_elem
&& size
) {
384 /* if null pointer check placeholder and do not follow */
385 assert(field
->flags
& VMS_ARRAY_OF_POINTER
);
386 ret
= slirp_vmstate_info_nullptr
.get(f
, curr_elem
, size
, NULL
);
387 } else if (field
->flags
& VMS_STRUCT
) {
388 ret
= slirp_vmstate_load_state(f
, field
->vmsd
, curr_elem
,
389 field
->vmsd
->version_id
);
390 } else if (field
->flags
& VMS_VSTRUCT
) {
391 ret
= slirp_vmstate_load_state(f
, field
->vmsd
, curr_elem
,
392 field
->struct_version_id
);
394 ret
= field
->info
->get(f
, curr_elem
, size
, field
);
397 g_warning("Failed to load %s:%s", vmsd
->name
,
402 } else if (field
->flags
& VMS_MUST_EXIST
) {
403 g_warning("Input validation failed: %s/%s",
404 vmsd
->name
, field
->name
);
409 if (vmsd
->post_load
) {
410 ret
= vmsd
->post_load(opaque
, version_id
);