]> Git Repo - qemu.git/blob - slirp/src/vmstate.c
hw/pci-host: Use object_initialize_child for correct reference counting
[qemu.git] / slirp / src / vmstate.c
1 /* SPDX-License-Identifier: BSD-3-Clause */
2 /*
3  * VMState interpreter
4  *
5  * Copyright (c) 2009-2018 Red Hat Inc
6  *
7  * Authors:
8  *  Juan Quintela <[email protected]>
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * 1. Redistributions of source code must retain the above
15  * copyright notice, this list of conditions and the following
16  * disclaimer.
17  *
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.
22  *
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.
26  *
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.
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
48 static 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
58 static 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
70 const VMStateInfo slirp_vmstate_info_nullptr = {
71     .name = "uint64",
72     .get  = get_nullptr,
73     .put  = put_nullptr,
74 };
75
76 /* 8 bit unsigned int */
77
78 static 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
85 static 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
92 const VMStateInfo slirp_vmstate_info_uint8 = {
93     .name = "uint8",
94     .get  = get_uint8,
95     .put  = put_uint8,
96 };
97
98 /* 16 bit unsigned int */
99
100 static 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
108 static 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
116 const VMStateInfo slirp_vmstate_info_uint16 = {
117     .name = "uint16",
118     .get  = get_uint16,
119     .put  = put_uint16,
120 };
121
122 /* 32 bit unsigned int */
123
124 static 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
132 static 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
140 const VMStateInfo slirp_vmstate_info_uint32 = {
141     .name = "uint32",
142     .get  = get_uint32,
143     .put  = put_uint32,
144 };
145
146 /* 16 bit int */
147
148 static 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
155 static 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
162 const VMStateInfo slirp_vmstate_info_int16 = {
163     .name = "int16",
164     .get  = get_int16,
165     .put  = put_int16,
166 };
167
168 /* 32 bit int */
169
170 static 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
177 static 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
184 const VMStateInfo slirp_vmstate_info_int32 = {
185     .name = "int32",
186     .get  = get_int32,
187     .put  = put_int32,
188 };
189
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
194  * stream.
195  */
196 static 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     /* Writes the parent field which is at the start of the tmp */
204     *(void **)tmp = pv;
205     ret = slirp_vmstate_load_state(f, vmsd, tmp, version_id);
206     g_free(tmp);
207     return ret;
208 }
209
210 static 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     /* Writes the parent field which is at the start of the tmp */
217     *(void **)tmp = pv;
218     ret = slirp_vmstate_save_state(f, vmsd, tmp);
219     g_free(tmp);
220
221     return ret;
222 }
223
224 const VMStateInfo slirp_vmstate_info_tmp = {
225     .name = "tmp",
226     .get = get_tmp,
227     .put = put_tmp,
228 };
229
230 /* uint8_t buffers */
231
232 static 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
239 static 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
246 const VMStateInfo slirp_vmstate_info_buffer = {
247     .name = "buffer",
248     .get  = get_buffer,
249     .put  = put_buffer,
250 };
251
252 static 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
275 static 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
289 static int
290 vmstate_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                     /* 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);
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
356 int 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
362 static 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
373 int 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                     /* 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);
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 }
This page took 0.044385 seconds and 4 git commands to generate.