Path: blob/a-new-beginning/SharedDependencies/Sources/libslirp/vmstate.c
2 views
/* SPDX-License-Identifier: BSD-3-Clause */1/*2* VMState interpreter3*4* Copyright (c) 2009-2018 Red Hat Inc5*6* Authors:7* Juan Quintela <[email protected]>8*9* Redistribution and use in source and binary forms, with or without10* modification, are permitted provided that the following conditions11* are met:12*13* 1. Redistributions of source code must retain the above14* copyright notice, this list of conditions and the following15* disclaimer.16*17* 2. Redistributions in binary form must reproduce the above18* copyright notice, this list of conditions and the following19* disclaimer in the documentation and/or other materials provided20* with the distribution.21*22* 3. Neither the name of the copyright holder nor the names of its23* contributors may be used to endorse or promote products derived24* from this software without specific prior written permission.25*26* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS27* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT28* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS29* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE30* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,31* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES32* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR33* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)34* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,35* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)36* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED37* OF THE POSSIBILITY OF SUCH DAMAGE.38*/39#include <assert.h>40#include <errno.h>41#include <string.h>42#include <glib.h>4344#include "stream.h"45#include "vmstate.h"4647static int get_nullptr(SlirpIStream *f, void *pv, size_t size,48const VMStateField *field)49{50if (slirp_istream_read_u8(f) == VMS_NULLPTR_MARKER) {51return 0;52}53g_warning("vmstate: get_nullptr expected VMS_NULLPTR_MARKER");54return -EINVAL;55}5657static int put_nullptr(SlirpOStream *f, void *pv, size_t size,58const VMStateField *field)5960{61if (pv == NULL) {62slirp_ostream_write_u8(f, VMS_NULLPTR_MARKER);63return 0;64}65g_warning("vmstate: put_nullptr must be called with pv == NULL");66return -EINVAL;67}6869const VMStateInfo slirp_vmstate_info_nullptr = {70.name = "uint64",71.get = get_nullptr,72.put = put_nullptr,73};7475/* 8 bit unsigned int */7677static int get_uint8(SlirpIStream *f, void *pv, size_t size,78const VMStateField *field)79{80uint8_t *v = pv;81*v = slirp_istream_read_u8(f);82return 0;83}8485static int put_uint8(SlirpOStream *f, void *pv, size_t size,86const VMStateField *field)87{88uint8_t *v = pv;89slirp_ostream_write_u8(f, *v);90return 0;91}9293const VMStateInfo slirp_vmstate_info_uint8 = {94.name = "uint8",95.get = get_uint8,96.put = put_uint8,97};9899/* 16 bit unsigned int */100101static int get_uint16(SlirpIStream *f, void *pv, size_t size,102const VMStateField *field)103{104uint16_t *v = pv;105*v = slirp_istream_read_u16(f);106return 0;107}108109static int put_uint16(SlirpOStream *f, void *pv, size_t size,110const VMStateField *field)111{112uint16_t *v = pv;113slirp_ostream_write_u16(f, *v);114return 0;115}116117const VMStateInfo slirp_vmstate_info_uint16 = {118.name = "uint16",119.get = get_uint16,120.put = put_uint16,121};122123/* 32 bit unsigned int */124125static int get_uint32(SlirpIStream *f, void *pv, size_t size,126const VMStateField *field)127{128uint32_t *v = pv;129*v = slirp_istream_read_u32(f);130return 0;131}132133static int put_uint32(SlirpOStream *f, void *pv, size_t size,134const VMStateField *field)135{136uint32_t *v = pv;137slirp_ostream_write_u32(f, *v);138return 0;139}140141const VMStateInfo slirp_vmstate_info_uint32 = {142.name = "uint32",143.get = get_uint32,144.put = put_uint32,145};146147/* 16 bit int */148149static int get_int16(SlirpIStream *f, void *pv, size_t size,150const VMStateField *field)151{152int16_t *v = pv;153*v = slirp_istream_read_i16(f);154return 0;155}156157static int put_int16(SlirpOStream *f, void *pv, size_t size,158const VMStateField *field)159{160int16_t *v = pv;161slirp_ostream_write_i16(f, *v);162return 0;163}164165const VMStateInfo slirp_vmstate_info_int16 = {166.name = "int16",167.get = get_int16,168.put = put_int16,169};170171/* 32 bit int */172173static int get_int32(SlirpIStream *f, void *pv, size_t size,174const VMStateField *field)175{176int32_t *v = pv;177*v = slirp_istream_read_i32(f);178return 0;179}180181static int put_int32(SlirpOStream *f, void *pv, size_t size,182const VMStateField *field)183{184int32_t *v = pv;185slirp_ostream_write_i32(f, *v);186return 0;187}188189const VMStateInfo slirp_vmstate_info_int32 = {190.name = "int32",191.get = get_int32,192.put = put_int32,193};194195/* vmstate_info_tmp, see VMSTATE_WITH_TMP, the idea is that we allocate196* a temporary buffer and the pre_load/pre_save methods in the child vmsd197* copy stuff from the parent into the child and do calculations to fill198* in fields that don't really exist in the parent but need to be in the199* stream.200*/201static int get_tmp(SlirpIStream *f, void *pv, size_t size,202const VMStateField *field)203{204int ret;205const VMStateDescription *vmsd = field->vmsd;206int version_id = field->version_id;207void *tmp = g_malloc(size);208209/* Writes the parent field which is at the start of the tmp */210*(void **)tmp = pv;211ret = slirp_vmstate_load_state(f, vmsd, tmp, version_id);212g_free(tmp);213return ret;214}215216static int put_tmp(SlirpOStream *f, void *pv, size_t size,217const VMStateField *field)218{219const VMStateDescription *vmsd = field->vmsd;220void *tmp = g_malloc(size);221int ret;222223/* Writes the parent field which is at the start of the tmp */224*(void **)tmp = pv;225ret = slirp_vmstate_save_state(f, vmsd, tmp);226g_free(tmp);227228return ret;229}230231const VMStateInfo slirp_vmstate_info_tmp = {232.name = "tmp",233.get = get_tmp,234.put = put_tmp,235};236237/* uint8_t buffers */238239static int get_buffer(SlirpIStream *f, void *pv, size_t size,240const VMStateField *field)241{242slirp_istream_read(f, pv, size);243return 0;244}245246static int put_buffer(SlirpOStream *f, void *pv, size_t size,247const VMStateField *field)248{249slirp_ostream_write(f, pv, size);250return 0;251}252253const VMStateInfo slirp_vmstate_info_buffer = {254.name = "buffer",255.get = get_buffer,256.put = put_buffer,257};258259static int vmstate_n_elems(char *opaque, const VMStateField *field)260{261int n_elems = 1;262263if (field->flags & VMS_ARRAY) {264n_elems = field->num;265} else if (field->flags & VMS_VARRAY_INT32) {266n_elems = *(int32_t *)(opaque + field->num_offset);267} else if (field->flags & VMS_VARRAY_UINT32) {268n_elems = *(uint32_t *)(opaque + field->num_offset);269} else if (field->flags & VMS_VARRAY_UINT16) {270n_elems = *(uint16_t *)(opaque + field->num_offset);271} else if (field->flags & VMS_VARRAY_UINT8) {272n_elems = *(uint8_t *)(opaque + field->num_offset);273}274275if (field->flags & VMS_MULTIPLY_ELEMENTS) {276n_elems *= field->num;277}278279return n_elems;280}281282static int vmstate_size(char *opaque, const VMStateField *field)283{284int size = field->size;285286if (field->flags & VMS_VBUFFER) {287size = *(int32_t *)(opaque + field->size_offset);288if (field->flags & VMS_MULTIPLY) {289size *= field->size;290}291}292293return size;294}295296static int vmstate_save_state_v(SlirpOStream *f, const VMStateDescription *vmsd,297char *opaque, int version_id)298{299int ret = 0;300const VMStateField *field = vmsd->fields;301302if (vmsd->pre_save) {303ret = vmsd->pre_save(opaque);304if (ret) {305g_warning("pre-save failed: %s", vmsd->name);306return ret;307}308}309310while (field->name) {311if ((field->field_exists && field->field_exists(opaque, version_id)) ||312(!field->field_exists && field->version_id <= version_id)) {313char *first_elem = opaque + field->offset;314int i, n_elems = vmstate_n_elems(opaque, field);315int size = vmstate_size(opaque, field);316317if (field->flags & VMS_POINTER) {318first_elem = *(void **)first_elem;319assert(first_elem || !n_elems || !size);320}321for (i = 0; i < n_elems; i++) {322void *curr_elem = first_elem + size * i;323324if (field->flags & VMS_ARRAY_OF_POINTER) {325assert(curr_elem);326curr_elem = *(void **)curr_elem;327}328if (!curr_elem && size) {329/* if null pointer write placeholder and do not follow */330assert(field->flags & VMS_ARRAY_OF_POINTER);331ret = slirp_vmstate_info_nullptr.put(f, curr_elem, size,332NULL);333} else if (field->flags & VMS_STRUCT) {334ret = slirp_vmstate_save_state(f, field->vmsd, curr_elem);335} else if (field->flags & VMS_VSTRUCT) {336ret = vmstate_save_state_v(f, field->vmsd, curr_elem,337field->struct_version_id);338} else {339ret = field->info->put(f, curr_elem, size, field);340}341if (ret) {342g_warning("Save of field %s/%s failed", vmsd->name,343field->name);344return ret;345}346}347} else {348if (field->flags & VMS_MUST_EXIST) {349g_warning("Output state validation failed: %s/%s", vmsd->name,350field->name);351assert(!(field->flags & VMS_MUST_EXIST));352}353}354field++;355}356357return 0;358}359360int slirp_vmstate_save_state(SlirpOStream *f, const VMStateDescription *vmsd,361void *opaque)362{363return vmstate_save_state_v(f, vmsd, opaque, vmsd->version_id);364}365366static void vmstate_handle_alloc(void *ptr, VMStateField *field, void *opaque)367{368if (field->flags & VMS_POINTER && field->flags & VMS_ALLOC) {369size_t size = vmstate_size(opaque, field);370size *= vmstate_n_elems(opaque, field);371if (size) {372*(void **)ptr = g_malloc(size);373}374}375}376377int slirp_vmstate_load_state(SlirpIStream *f, const VMStateDescription *vmsd,378void *opaque_, int version_id)379{380VMStateField *field = vmsd->fields;381int ret = 0;382char *opaque = opaque_;383384if (version_id > vmsd->version_id) {385g_warning("%s: incoming version_id %d is too new "386"for local version_id %d",387vmsd->name, version_id, vmsd->version_id);388return -EINVAL;389}390if (vmsd->pre_load) {391int ret = vmsd->pre_load(opaque);392if (ret) {393return ret;394}395}396while (field->name) {397if ((field->field_exists && field->field_exists(opaque, version_id)) ||398(!field->field_exists && field->version_id <= version_id)) {399char *first_elem = opaque + field->offset;400int i, n_elems = vmstate_n_elems(opaque, field);401int size = vmstate_size(opaque, field);402403vmstate_handle_alloc(first_elem, field, opaque);404if (field->flags & VMS_POINTER) {405first_elem = *(void **)first_elem;406assert(first_elem || !n_elems || !size);407}408for (i = 0; i < n_elems; i++) {409void *curr_elem = first_elem + size * i;410411if (field->flags & VMS_ARRAY_OF_POINTER) {412curr_elem = *(void **)curr_elem;413}414if (!curr_elem && size) {415/* if null pointer check placeholder and do not follow */416assert(field->flags & VMS_ARRAY_OF_POINTER);417ret = slirp_vmstate_info_nullptr.get(f, curr_elem, size,418NULL);419} else if (field->flags & VMS_STRUCT) {420ret = slirp_vmstate_load_state(f, field->vmsd, curr_elem,421field->vmsd->version_id);422} else if (field->flags & VMS_VSTRUCT) {423ret = slirp_vmstate_load_state(f, field->vmsd, curr_elem,424field->struct_version_id);425} else {426ret = field->info->get(f, curr_elem, size, field);427}428if (ret < 0) {429g_warning("Failed to load %s:%s", vmsd->name, field->name);430return ret;431}432}433} else if (field->flags & VMS_MUST_EXIST) {434g_warning("Input validation failed: %s/%s", vmsd->name,435field->name);436return -1;437}438field++;439}440if (vmsd->post_load) {441ret = vmsd->post_load(opaque, version_id);442}443return ret;444}445446447