1 /* SPDX-License-Identifier: BSD-3-Clause */
5 * Copyright (c) 2009-2018 Red Hat Inc
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);