1 /* SPDX-License-Identifier: BSD-3-Clause */
5 * Copyright (c) 2009-2018 Red Hat Inc
8 * Juan Quintela <quintela@redhat.com>
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
18 * 2. Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials provided
21 * with the distribution.
23 * 3. Neither the name of the copyright holder nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
30 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
31 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
32 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
34 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
38 * OF THE POSSIBILITY OF SUCH DAMAGE.
48 static int get_nullptr(SlirpIStream
*f
, void *pv
, size_t size
,
49 const VMStateField
*field
)
51 if (slirp_istream_read_u8(f
) == VMS_NULLPTR_MARKER
) {
54 g_warning("vmstate: get_nullptr expected VMS_NULLPTR_MARKER");
58 static int put_nullptr(SlirpOStream
*f
, void *pv
, size_t size
,
59 const VMStateField
*field
)
63 slirp_ostream_write_u8(f
, VMS_NULLPTR_MARKER
);
66 g_warning("vmstate: put_nullptr must be called with pv == NULL");
70 const VMStateInfo slirp_vmstate_info_nullptr
= {
76 /* 8 bit unsigned int */
78 static int get_uint8(SlirpIStream
*f
, void *pv
, size_t size
, const VMStateField
*field
)
81 *v
= slirp_istream_read_u8(f
);
85 static int put_uint8(SlirpOStream
*f
, void *pv
, size_t size
, const VMStateField
*field
)
88 slirp_ostream_write_u8(f
, *v
);
92 const VMStateInfo slirp_vmstate_info_uint8
= {
98 /* 16 bit unsigned int */
100 static int get_uint16(SlirpIStream
*f
, void *pv
, size_t size
,
101 const VMStateField
*field
)
104 *v
= slirp_istream_read_u16(f
);
108 static int put_uint16(SlirpOStream
*f
, void *pv
, size_t size
,
109 const VMStateField
*field
)
112 slirp_ostream_write_u16(f
, *v
);
116 const VMStateInfo slirp_vmstate_info_uint16
= {
122 /* 32 bit unsigned int */
124 static int get_uint32(SlirpIStream
*f
, void *pv
, size_t size
,
125 const VMStateField
*field
)
128 *v
= slirp_istream_read_u32(f
);
132 static int put_uint32(SlirpOStream
*f
, void *pv
, size_t size
,
133 const VMStateField
*field
)
136 slirp_ostream_write_u32(f
, *v
);
140 const VMStateInfo slirp_vmstate_info_uint32
= {
148 static int get_int16(SlirpIStream
*f
, void *pv
, size_t size
, const VMStateField
*field
)
151 *v
= slirp_istream_read_i16(f
);
155 static int put_int16(SlirpOStream
*f
, void *pv
, size_t size
, const VMStateField
*field
)
158 slirp_ostream_write_i16(f
, *v
);
162 const VMStateInfo slirp_vmstate_info_int16
= {
170 static int get_int32(SlirpIStream
*f
, void *pv
, size_t size
, const VMStateField
*field
)
173 *v
= slirp_istream_read_i32(f
);
177 static int put_int32(SlirpOStream
*f
, void *pv
, size_t size
, const VMStateField
*field
)
180 slirp_ostream_write_i32(f
, *v
);
184 const VMStateInfo slirp_vmstate_info_int32
= {
190 /* vmstate_info_tmp, see VMSTATE_WITH_TMP, the idea is that we allocate
191 * a temporary buffer and the pre_load/pre_save methods in the child vmsd
192 * copy stuff from the parent into the child and do calculations to fill
193 * in fields that don't really exist in the parent but need to be in the
196 static int get_tmp(SlirpIStream
*f
, void *pv
, size_t size
, const VMStateField
*field
)
199 const VMStateDescription
*vmsd
= field
->vmsd
;
200 int version_id
= field
->version_id
;
201 void *tmp
= g_malloc(size
);
203 /* Writes the parent field which is at the start of the tmp */
205 ret
= slirp_vmstate_load_state(f
, vmsd
, tmp
, version_id
);
210 static int put_tmp(SlirpOStream
*f
, void *pv
, size_t size
, const VMStateField
*field
)
212 const VMStateDescription
*vmsd
= field
->vmsd
;
213 void *tmp
= g_malloc(size
);
216 /* Writes the parent field which is at the start of the tmp */
218 ret
= slirp_vmstate_save_state(f
, vmsd
, tmp
);
224 const VMStateInfo slirp_vmstate_info_tmp
= {
230 /* uint8_t buffers */
232 static int get_buffer(SlirpIStream
*f
, void *pv
, size_t size
,
233 const VMStateField
*field
)
235 slirp_istream_read(f
, pv
, size
);
239 static int put_buffer(SlirpOStream
*f
, void *pv
, size_t size
,
240 const VMStateField
*field
)
242 slirp_ostream_write(f
, pv
, size
);
246 const VMStateInfo slirp_vmstate_info_buffer
= {
252 static int vmstate_n_elems(void *opaque
, const VMStateField
*field
)
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
);
268 if (field
->flags
& VMS_MULTIPLY_ELEMENTS
) {
269 n_elems
*= field
->num
;
275 static int vmstate_size(void *opaque
, const VMStateField
*field
)
277 int size
= field
->size
;
279 if (field
->flags
& VMS_VBUFFER
) {
280 size
= *(int32_t *)(opaque
+ field
->size_offset
);
281 if (field
->flags
& VMS_MULTIPLY
) {
290 vmstate_save_state_v(SlirpOStream
*f
, const VMStateDescription
*vmsd
,
291 void *opaque
, int version_id
)
294 const VMStateField
*field
= vmsd
->fields
;
296 if (vmsd
->pre_save
) {
297 ret
= vmsd
->pre_save(opaque
);
299 g_warning("pre-save failed: %s", vmsd
->name
);
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
);
313 if (field
->flags
& VMS_POINTER
) {
314 first_elem
= *(void **)first_elem
;
315 assert(first_elem
|| !n_elems
|| !size
);
317 for (i
= 0; i
< n_elems
; i
++) {
318 void *curr_elem
= first_elem
+ size
* i
;
321 if (field
->flags
& VMS_ARRAY_OF_POINTER
) {
323 curr_elem
= *(void **)curr_elem
;
325 if (!curr_elem
&& size
) {
326 /* if null pointer write placeholder and do not follow */
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
);
335 ret
= field
->info
->put(f
, curr_elem
, size
, field
);
338 g_warning("Save of field %s/%s failed",
339 vmsd
->name
, field
->name
);
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
));
356 int slirp_vmstate_save_state(SlirpOStream
*f
, const VMStateDescription
*vmsd
,
359 return vmstate_save_state_v(f
, vmsd
, opaque
, vmsd
->version_id
);
362 static void vmstate_handle_alloc(void *ptr
, VMStateField
*field
, void *opaque
)
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
);
368 *(void **)ptr
= g_malloc(size
);
373 int slirp_vmstate_load_state(SlirpIStream
*f
, const VMStateDescription
*vmsd
,
374 void *opaque
, int version_id
)
376 VMStateField
*field
= vmsd
->fields
;
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
);
385 if (vmsd
->pre_load
) {
386 int ret
= vmsd
->pre_load(opaque
);
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
);
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
);
405 for (i
= 0; i
< n_elems
; i
++) {
406 void *curr_elem
= first_elem
+ size
* i
;
408 if (field
->flags
& VMS_ARRAY_OF_POINTER
) {
409 curr_elem
= *(void **)curr_elem
;
411 if (!curr_elem
&& size
) {
412 /* if null pointer check placeholder and do not follow */
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
);
422 ret
= field
->info
->get(f
, curr_elem
, size
, field
);
425 g_warning("Failed to load %s:%s", vmsd
->name
,
430 } else if (field
->flags
& VMS_MUST_EXIST
) {
431 g_warning("Input validation failed: %s/%s",
432 vmsd
->name
, field
->name
);
437 if (vmsd
->post_load
) {
438 ret
= vmsd
->post_load(opaque
, version_id
);