xref: /openbmc/qemu/migration/vmstate-types.c (revision 69242e7e)
1576d1abcSJuan Quintela /*
2576d1abcSJuan Quintela  * VMStateInfo's for basic typse
3576d1abcSJuan Quintela  *
4576d1abcSJuan Quintela  * Copyright (c) 2009-2017 Red Hat Inc
5576d1abcSJuan Quintela  *
6576d1abcSJuan Quintela  * Authors:
7576d1abcSJuan Quintela  *  Juan Quintela <quintela@redhat.com>
8576d1abcSJuan Quintela  *
9576d1abcSJuan Quintela  * This work is licensed under the terms of the GNU GPL, version 2 or later.
10576d1abcSJuan Quintela  * See the COPYING file in the top-level directory.
11576d1abcSJuan Quintela  */
12576d1abcSJuan Quintela 
13576d1abcSJuan Quintela #include "qemu/osdep.h"
14*69242e7eSMarc-André Lureau #include "qemu/cpu-float.h"
1508a0aee1SJuan Quintela #include "qemu-file.h"
166666c96aSJuan Quintela #include "migration.h"
17576d1abcSJuan Quintela #include "migration/vmstate.h"
18576d1abcSJuan Quintela #include "qemu/error-report.h"
19576d1abcSJuan Quintela #include "qemu/queue.h"
20576d1abcSJuan Quintela #include "trace.h"
21576d1abcSJuan Quintela 
22576d1abcSJuan Quintela /* bool */
23576d1abcSJuan Quintela 
get_bool(QEMUFile * f,void * pv,size_t size,const VMStateField * field)2403fee66fSMarc-André Lureau static int get_bool(QEMUFile *f, void *pv, size_t size,
2503fee66fSMarc-André Lureau                     const VMStateField *field)
26576d1abcSJuan Quintela {
27576d1abcSJuan Quintela     bool *v = pv;
28576d1abcSJuan Quintela     *v = qemu_get_byte(f);
29576d1abcSJuan Quintela     return 0;
30576d1abcSJuan Quintela }
31576d1abcSJuan Quintela 
put_bool(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)3203fee66fSMarc-André Lureau static int put_bool(QEMUFile *f, void *pv, size_t size,
333ddba9a9SMarkus Armbruster                     const VMStateField *field, JSONWriter *vmdesc)
34576d1abcSJuan Quintela {
35576d1abcSJuan Quintela     bool *v = pv;
36576d1abcSJuan Quintela     qemu_put_byte(f, *v);
37576d1abcSJuan Quintela     return 0;
38576d1abcSJuan Quintela }
39576d1abcSJuan Quintela 
40576d1abcSJuan Quintela const VMStateInfo vmstate_info_bool = {
41576d1abcSJuan Quintela     .name = "bool",
42576d1abcSJuan Quintela     .get  = get_bool,
43576d1abcSJuan Quintela     .put  = put_bool,
44576d1abcSJuan Quintela };
45576d1abcSJuan Quintela 
46576d1abcSJuan Quintela /* 8 bit int */
47576d1abcSJuan Quintela 
get_int8(QEMUFile * f,void * pv,size_t size,const VMStateField * field)4803fee66fSMarc-André Lureau static int get_int8(QEMUFile *f, void *pv, size_t size,
4903fee66fSMarc-André Lureau                     const VMStateField *field)
50576d1abcSJuan Quintela {
51576d1abcSJuan Quintela     int8_t *v = pv;
52576d1abcSJuan Quintela     qemu_get_s8s(f, v);
53576d1abcSJuan Quintela     return 0;
54576d1abcSJuan Quintela }
55576d1abcSJuan Quintela 
put_int8(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)5603fee66fSMarc-André Lureau static int put_int8(QEMUFile *f, void *pv, size_t size,
573ddba9a9SMarkus Armbruster                     const VMStateField *field, JSONWriter *vmdesc)
58576d1abcSJuan Quintela {
59576d1abcSJuan Quintela     int8_t *v = pv;
60576d1abcSJuan Quintela     qemu_put_s8s(f, v);
61576d1abcSJuan Quintela     return 0;
62576d1abcSJuan Quintela }
63576d1abcSJuan Quintela 
64576d1abcSJuan Quintela const VMStateInfo vmstate_info_int8 = {
65576d1abcSJuan Quintela     .name = "int8",
66576d1abcSJuan Quintela     .get  = get_int8,
67576d1abcSJuan Quintela     .put  = put_int8,
68576d1abcSJuan Quintela };
69576d1abcSJuan Quintela 
70576d1abcSJuan Quintela /* 16 bit int */
71576d1abcSJuan Quintela 
get_int16(QEMUFile * f,void * pv,size_t size,const VMStateField * field)7203fee66fSMarc-André Lureau static int get_int16(QEMUFile *f, void *pv, size_t size,
7303fee66fSMarc-André Lureau                      const VMStateField *field)
74576d1abcSJuan Quintela {
75576d1abcSJuan Quintela     int16_t *v = pv;
76576d1abcSJuan Quintela     qemu_get_sbe16s(f, v);
77576d1abcSJuan Quintela     return 0;
78576d1abcSJuan Quintela }
79576d1abcSJuan Quintela 
put_int16(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)8003fee66fSMarc-André Lureau static int put_int16(QEMUFile *f, void *pv, size_t size,
813ddba9a9SMarkus Armbruster                      const VMStateField *field, JSONWriter *vmdesc)
82576d1abcSJuan Quintela {
83576d1abcSJuan Quintela     int16_t *v = pv;
84576d1abcSJuan Quintela     qemu_put_sbe16s(f, v);
85576d1abcSJuan Quintela     return 0;
86576d1abcSJuan Quintela }
87576d1abcSJuan Quintela 
88576d1abcSJuan Quintela const VMStateInfo vmstate_info_int16 = {
89576d1abcSJuan Quintela     .name = "int16",
90576d1abcSJuan Quintela     .get  = get_int16,
91576d1abcSJuan Quintela     .put  = put_int16,
92576d1abcSJuan Quintela };
93576d1abcSJuan Quintela 
94576d1abcSJuan Quintela /* 32 bit int */
95576d1abcSJuan Quintela 
get_int32(QEMUFile * f,void * pv,size_t size,const VMStateField * field)9603fee66fSMarc-André Lureau static int get_int32(QEMUFile *f, void *pv, size_t size,
9703fee66fSMarc-André Lureau                      const VMStateField *field)
98576d1abcSJuan Quintela {
99576d1abcSJuan Quintela     int32_t *v = pv;
100576d1abcSJuan Quintela     qemu_get_sbe32s(f, v);
101576d1abcSJuan Quintela     return 0;
102576d1abcSJuan Quintela }
103576d1abcSJuan Quintela 
put_int32(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)10403fee66fSMarc-André Lureau static int put_int32(QEMUFile *f, void *pv, size_t size,
1053ddba9a9SMarkus Armbruster                      const VMStateField *field, JSONWriter *vmdesc)
106576d1abcSJuan Quintela {
107576d1abcSJuan Quintela     int32_t *v = pv;
108576d1abcSJuan Quintela     qemu_put_sbe32s(f, v);
109576d1abcSJuan Quintela     return 0;
110576d1abcSJuan Quintela }
111576d1abcSJuan Quintela 
112576d1abcSJuan Quintela const VMStateInfo vmstate_info_int32 = {
113576d1abcSJuan Quintela     .name = "int32",
114576d1abcSJuan Quintela     .get  = get_int32,
115576d1abcSJuan Quintela     .put  = put_int32,
116576d1abcSJuan Quintela };
117576d1abcSJuan Quintela 
118576d1abcSJuan Quintela /* 32 bit int. See that the received value is the same than the one
119576d1abcSJuan Quintela    in the field */
120576d1abcSJuan Quintela 
get_int32_equal(QEMUFile * f,void * pv,size_t size,const VMStateField * field)121576d1abcSJuan Quintela static int get_int32_equal(QEMUFile *f, void *pv, size_t size,
12203fee66fSMarc-André Lureau                            const VMStateField *field)
123576d1abcSJuan Quintela {
124576d1abcSJuan Quintela     int32_t *v = pv;
125576d1abcSJuan Quintela     int32_t v2;
126576d1abcSJuan Quintela     qemu_get_sbe32s(f, &v2);
127576d1abcSJuan Quintela 
128576d1abcSJuan Quintela     if (*v == v2) {
129576d1abcSJuan Quintela         return 0;
130576d1abcSJuan Quintela     }
131576d1abcSJuan Quintela     error_report("%" PRIx32 " != %" PRIx32, *v, v2);
132d2164ad3SHalil Pasic     if (field->err_hint) {
133d2164ad3SHalil Pasic         error_printf("%s\n", field->err_hint);
134d2164ad3SHalil Pasic     }
135576d1abcSJuan Quintela     return -EINVAL;
136576d1abcSJuan Quintela }
137576d1abcSJuan Quintela 
138576d1abcSJuan Quintela const VMStateInfo vmstate_info_int32_equal = {
139576d1abcSJuan Quintela     .name = "int32 equal",
140576d1abcSJuan Quintela     .get  = get_int32_equal,
141576d1abcSJuan Quintela     .put  = put_int32,
142576d1abcSJuan Quintela };
143576d1abcSJuan Quintela 
144576d1abcSJuan Quintela /* 32 bit int. Check that the received value is non-negative
145576d1abcSJuan Quintela  * and less than or equal to the one in the field.
146576d1abcSJuan Quintela  */
147576d1abcSJuan Quintela 
get_int32_le(QEMUFile * f,void * pv,size_t size,const VMStateField * field)14803fee66fSMarc-André Lureau static int get_int32_le(QEMUFile *f, void *pv, size_t size,
14903fee66fSMarc-André Lureau                         const VMStateField *field)
150576d1abcSJuan Quintela {
151576d1abcSJuan Quintela     int32_t *cur = pv;
152576d1abcSJuan Quintela     int32_t loaded;
153576d1abcSJuan Quintela     qemu_get_sbe32s(f, &loaded);
154576d1abcSJuan Quintela 
155576d1abcSJuan Quintela     if (loaded >= 0 && loaded <= *cur) {
156576d1abcSJuan Quintela         *cur = loaded;
157576d1abcSJuan Quintela         return 0;
158576d1abcSJuan Quintela     }
159576d1abcSJuan Quintela     error_report("Invalid value %" PRId32
160576d1abcSJuan Quintela                  " expecting positive value <= %" PRId32,
161576d1abcSJuan Quintela                  loaded, *cur);
162576d1abcSJuan Quintela     return -EINVAL;
163576d1abcSJuan Quintela }
164576d1abcSJuan Quintela 
165576d1abcSJuan Quintela const VMStateInfo vmstate_info_int32_le = {
166576d1abcSJuan Quintela     .name = "int32 le",
167576d1abcSJuan Quintela     .get  = get_int32_le,
168576d1abcSJuan Quintela     .put  = put_int32,
169576d1abcSJuan Quintela };
170576d1abcSJuan Quintela 
171576d1abcSJuan Quintela /* 64 bit int */
172576d1abcSJuan Quintela 
get_int64(QEMUFile * f,void * pv,size_t size,const VMStateField * field)17303fee66fSMarc-André Lureau static int get_int64(QEMUFile *f, void *pv, size_t size,
17403fee66fSMarc-André Lureau                      const VMStateField *field)
175576d1abcSJuan Quintela {
176576d1abcSJuan Quintela     int64_t *v = pv;
177576d1abcSJuan Quintela     qemu_get_sbe64s(f, v);
178576d1abcSJuan Quintela     return 0;
179576d1abcSJuan Quintela }
180576d1abcSJuan Quintela 
put_int64(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)18103fee66fSMarc-André Lureau static int put_int64(QEMUFile *f, void *pv, size_t size,
1823ddba9a9SMarkus Armbruster                      const VMStateField *field, JSONWriter *vmdesc)
183576d1abcSJuan Quintela {
184576d1abcSJuan Quintela     int64_t *v = pv;
185576d1abcSJuan Quintela     qemu_put_sbe64s(f, v);
186576d1abcSJuan Quintela     return 0;
187576d1abcSJuan Quintela }
188576d1abcSJuan Quintela 
189576d1abcSJuan Quintela const VMStateInfo vmstate_info_int64 = {
190576d1abcSJuan Quintela     .name = "int64",
191576d1abcSJuan Quintela     .get  = get_int64,
192576d1abcSJuan Quintela     .put  = put_int64,
193576d1abcSJuan Quintela };
194576d1abcSJuan Quintela 
195576d1abcSJuan Quintela /* 8 bit unsigned int */
196576d1abcSJuan Quintela 
get_uint8(QEMUFile * f,void * pv,size_t size,const VMStateField * field)19703fee66fSMarc-André Lureau static int get_uint8(QEMUFile *f, void *pv, size_t size,
19803fee66fSMarc-André Lureau                      const VMStateField *field)
199576d1abcSJuan Quintela {
200576d1abcSJuan Quintela     uint8_t *v = pv;
201576d1abcSJuan Quintela     qemu_get_8s(f, v);
202576d1abcSJuan Quintela     return 0;
203576d1abcSJuan Quintela }
204576d1abcSJuan Quintela 
put_uint8(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)20503fee66fSMarc-André Lureau static int put_uint8(QEMUFile *f, void *pv, size_t size,
2063ddba9a9SMarkus Armbruster                      const VMStateField *field, JSONWriter *vmdesc)
207576d1abcSJuan Quintela {
208576d1abcSJuan Quintela     uint8_t *v = pv;
209576d1abcSJuan Quintela     qemu_put_8s(f, v);
210576d1abcSJuan Quintela     return 0;
211576d1abcSJuan Quintela }
212576d1abcSJuan Quintela 
213576d1abcSJuan Quintela const VMStateInfo vmstate_info_uint8 = {
214576d1abcSJuan Quintela     .name = "uint8",
215576d1abcSJuan Quintela     .get  = get_uint8,
216576d1abcSJuan Quintela     .put  = put_uint8,
217576d1abcSJuan Quintela };
218576d1abcSJuan Quintela 
219576d1abcSJuan Quintela /* 16 bit unsigned int */
220576d1abcSJuan Quintela 
get_uint16(QEMUFile * f,void * pv,size_t size,const VMStateField * field)22103fee66fSMarc-André Lureau static int get_uint16(QEMUFile *f, void *pv, size_t size,
22203fee66fSMarc-André Lureau                       const VMStateField *field)
223576d1abcSJuan Quintela {
224576d1abcSJuan Quintela     uint16_t *v = pv;
225576d1abcSJuan Quintela     qemu_get_be16s(f, v);
226576d1abcSJuan Quintela     return 0;
227576d1abcSJuan Quintela }
228576d1abcSJuan Quintela 
put_uint16(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)22903fee66fSMarc-André Lureau static int put_uint16(QEMUFile *f, void *pv, size_t size,
2303ddba9a9SMarkus Armbruster                       const VMStateField *field, JSONWriter *vmdesc)
231576d1abcSJuan Quintela {
232576d1abcSJuan Quintela     uint16_t *v = pv;
233576d1abcSJuan Quintela     qemu_put_be16s(f, v);
234576d1abcSJuan Quintela     return 0;
235576d1abcSJuan Quintela }
236576d1abcSJuan Quintela 
237576d1abcSJuan Quintela const VMStateInfo vmstate_info_uint16 = {
238576d1abcSJuan Quintela     .name = "uint16",
239576d1abcSJuan Quintela     .get  = get_uint16,
240576d1abcSJuan Quintela     .put  = put_uint16,
241576d1abcSJuan Quintela };
242576d1abcSJuan Quintela 
243576d1abcSJuan Quintela /* 32 bit unsigned int */
244576d1abcSJuan Quintela 
get_uint32(QEMUFile * f,void * pv,size_t size,const VMStateField * field)24503fee66fSMarc-André Lureau static int get_uint32(QEMUFile *f, void *pv, size_t size,
24603fee66fSMarc-André Lureau                       const VMStateField *field)
247576d1abcSJuan Quintela {
248576d1abcSJuan Quintela     uint32_t *v = pv;
249576d1abcSJuan Quintela     qemu_get_be32s(f, v);
250576d1abcSJuan Quintela     return 0;
251576d1abcSJuan Quintela }
252576d1abcSJuan Quintela 
put_uint32(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)25303fee66fSMarc-André Lureau static int put_uint32(QEMUFile *f, void *pv, size_t size,
2543ddba9a9SMarkus Armbruster                       const VMStateField *field, JSONWriter *vmdesc)
255576d1abcSJuan Quintela {
256576d1abcSJuan Quintela     uint32_t *v = pv;
257576d1abcSJuan Quintela     qemu_put_be32s(f, v);
258576d1abcSJuan Quintela     return 0;
259576d1abcSJuan Quintela }
260576d1abcSJuan Quintela 
261576d1abcSJuan Quintela const VMStateInfo vmstate_info_uint32 = {
262576d1abcSJuan Quintela     .name = "uint32",
263576d1abcSJuan Quintela     .get  = get_uint32,
264576d1abcSJuan Quintela     .put  = put_uint32,
265576d1abcSJuan Quintela };
266576d1abcSJuan Quintela 
267576d1abcSJuan Quintela /* 32 bit uint. See that the received value is the same than the one
268576d1abcSJuan Quintela    in the field */
269576d1abcSJuan Quintela 
get_uint32_equal(QEMUFile * f,void * pv,size_t size,const VMStateField * field)270576d1abcSJuan Quintela static int get_uint32_equal(QEMUFile *f, void *pv, size_t size,
27103fee66fSMarc-André Lureau                             const VMStateField *field)
272576d1abcSJuan Quintela {
273576d1abcSJuan Quintela     uint32_t *v = pv;
274576d1abcSJuan Quintela     uint32_t v2;
275576d1abcSJuan Quintela     qemu_get_be32s(f, &v2);
276576d1abcSJuan Quintela 
277576d1abcSJuan Quintela     if (*v == v2) {
278576d1abcSJuan Quintela         return 0;
279576d1abcSJuan Quintela     }
280576d1abcSJuan Quintela     error_report("%" PRIx32 " != %" PRIx32, *v, v2);
281d2164ad3SHalil Pasic     if (field->err_hint) {
282d2164ad3SHalil Pasic         error_printf("%s\n", field->err_hint);
283d2164ad3SHalil Pasic     }
284576d1abcSJuan Quintela     return -EINVAL;
285576d1abcSJuan Quintela }
286576d1abcSJuan Quintela 
287576d1abcSJuan Quintela const VMStateInfo vmstate_info_uint32_equal = {
288576d1abcSJuan Quintela     .name = "uint32 equal",
289576d1abcSJuan Quintela     .get  = get_uint32_equal,
290576d1abcSJuan Quintela     .put  = put_uint32,
291576d1abcSJuan Quintela };
292576d1abcSJuan Quintela 
293576d1abcSJuan Quintela /* 64 bit unsigned int */
294576d1abcSJuan Quintela 
get_uint64(QEMUFile * f,void * pv,size_t size,const VMStateField * field)29503fee66fSMarc-André Lureau static int get_uint64(QEMUFile *f, void *pv, size_t size,
29603fee66fSMarc-André Lureau                       const VMStateField *field)
297576d1abcSJuan Quintela {
298576d1abcSJuan Quintela     uint64_t *v = pv;
299576d1abcSJuan Quintela     qemu_get_be64s(f, v);
300576d1abcSJuan Quintela     return 0;
301576d1abcSJuan Quintela }
302576d1abcSJuan Quintela 
put_uint64(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)30303fee66fSMarc-André Lureau static int put_uint64(QEMUFile *f, void *pv, size_t size,
3043ddba9a9SMarkus Armbruster                       const VMStateField *field, JSONWriter *vmdesc)
305576d1abcSJuan Quintela {
306576d1abcSJuan Quintela     uint64_t *v = pv;
307576d1abcSJuan Quintela     qemu_put_be64s(f, v);
308576d1abcSJuan Quintela     return 0;
309576d1abcSJuan Quintela }
310576d1abcSJuan Quintela 
311576d1abcSJuan Quintela const VMStateInfo vmstate_info_uint64 = {
312576d1abcSJuan Quintela     .name = "uint64",
313576d1abcSJuan Quintela     .get  = get_uint64,
314576d1abcSJuan Quintela     .put  = put_uint64,
315576d1abcSJuan Quintela };
316576d1abcSJuan Quintela 
get_nullptr(QEMUFile * f,void * pv,size_t size,const VMStateField * field)31703fee66fSMarc-André Lureau static int get_nullptr(QEMUFile *f, void *pv, size_t size,
31803fee66fSMarc-André Lureau                        const VMStateField *field)
319576d1abcSJuan Quintela 
320576d1abcSJuan Quintela {
321576d1abcSJuan Quintela     if (qemu_get_byte(f) == VMS_NULLPTR_MARKER) {
322576d1abcSJuan Quintela         return  0;
323576d1abcSJuan Quintela     }
324576d1abcSJuan Quintela     error_report("vmstate: get_nullptr expected VMS_NULLPTR_MARKER");
325576d1abcSJuan Quintela     return -EINVAL;
326576d1abcSJuan Quintela }
327576d1abcSJuan Quintela 
put_nullptr(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)328576d1abcSJuan Quintela static int put_nullptr(QEMUFile *f, void *pv, size_t size,
3293ddba9a9SMarkus Armbruster                         const VMStateField *field, JSONWriter *vmdesc)
330576d1abcSJuan Quintela 
331576d1abcSJuan Quintela {
332576d1abcSJuan Quintela     if (pv == NULL) {
333576d1abcSJuan Quintela         qemu_put_byte(f, VMS_NULLPTR_MARKER);
334576d1abcSJuan Quintela         return 0;
335576d1abcSJuan Quintela     }
336576d1abcSJuan Quintela     error_report("vmstate: put_nullptr must be called with pv == NULL");
337576d1abcSJuan Quintela     return -EINVAL;
338576d1abcSJuan Quintela }
339576d1abcSJuan Quintela 
340576d1abcSJuan Quintela const VMStateInfo vmstate_info_nullptr = {
341576d1abcSJuan Quintela     .name = "uint64",
342576d1abcSJuan Quintela     .get  = get_nullptr,
343576d1abcSJuan Quintela     .put  = put_nullptr,
344576d1abcSJuan Quintela };
345576d1abcSJuan Quintela 
346576d1abcSJuan Quintela /* 64 bit unsigned int. See that the received value is the same than the one
347576d1abcSJuan Quintela    in the field */
348576d1abcSJuan Quintela 
get_uint64_equal(QEMUFile * f,void * pv,size_t size,const VMStateField * field)349576d1abcSJuan Quintela static int get_uint64_equal(QEMUFile *f, void *pv, size_t size,
35003fee66fSMarc-André Lureau                             const VMStateField *field)
351576d1abcSJuan Quintela {
352576d1abcSJuan Quintela     uint64_t *v = pv;
353576d1abcSJuan Quintela     uint64_t v2;
354576d1abcSJuan Quintela     qemu_get_be64s(f, &v2);
355576d1abcSJuan Quintela 
356576d1abcSJuan Quintela     if (*v == v2) {
357576d1abcSJuan Quintela         return 0;
358576d1abcSJuan Quintela     }
359576d1abcSJuan Quintela     error_report("%" PRIx64 " != %" PRIx64, *v, v2);
360d2164ad3SHalil Pasic     if (field->err_hint) {
361d2164ad3SHalil Pasic         error_printf("%s\n", field->err_hint);
362d2164ad3SHalil Pasic     }
363576d1abcSJuan Quintela     return -EINVAL;
364576d1abcSJuan Quintela }
365576d1abcSJuan Quintela 
366576d1abcSJuan Quintela const VMStateInfo vmstate_info_uint64_equal = {
367576d1abcSJuan Quintela     .name = "int64 equal",
368576d1abcSJuan Quintela     .get  = get_uint64_equal,
369576d1abcSJuan Quintela     .put  = put_uint64,
370576d1abcSJuan Quintela };
371576d1abcSJuan Quintela 
372576d1abcSJuan Quintela /* 8 bit int. See that the received value is the same than the one
373576d1abcSJuan Quintela    in the field */
374576d1abcSJuan Quintela 
get_uint8_equal(QEMUFile * f,void * pv,size_t size,const VMStateField * field)375576d1abcSJuan Quintela static int get_uint8_equal(QEMUFile *f, void *pv, size_t size,
37603fee66fSMarc-André Lureau                            const VMStateField *field)
377576d1abcSJuan Quintela {
378576d1abcSJuan Quintela     uint8_t *v = pv;
379576d1abcSJuan Quintela     uint8_t v2;
380576d1abcSJuan Quintela     qemu_get_8s(f, &v2);
381576d1abcSJuan Quintela 
382576d1abcSJuan Quintela     if (*v == v2) {
383576d1abcSJuan Quintela         return 0;
384576d1abcSJuan Quintela     }
385576d1abcSJuan Quintela     error_report("%x != %x", *v, v2);
386d2164ad3SHalil Pasic     if (field->err_hint) {
387d2164ad3SHalil Pasic         error_printf("%s\n", field->err_hint);
388d2164ad3SHalil Pasic     }
389576d1abcSJuan Quintela     return -EINVAL;
390576d1abcSJuan Quintela }
391576d1abcSJuan Quintela 
392576d1abcSJuan Quintela const VMStateInfo vmstate_info_uint8_equal = {
393576d1abcSJuan Quintela     .name = "uint8 equal",
394576d1abcSJuan Quintela     .get  = get_uint8_equal,
395576d1abcSJuan Quintela     .put  = put_uint8,
396576d1abcSJuan Quintela };
397576d1abcSJuan Quintela 
398576d1abcSJuan Quintela /* 16 bit unsigned int int. See that the received value is the same than the one
399576d1abcSJuan Quintela    in the field */
400576d1abcSJuan Quintela 
get_uint16_equal(QEMUFile * f,void * pv,size_t size,const VMStateField * field)401576d1abcSJuan Quintela static int get_uint16_equal(QEMUFile *f, void *pv, size_t size,
40203fee66fSMarc-André Lureau                             const VMStateField *field)
403576d1abcSJuan Quintela {
404576d1abcSJuan Quintela     uint16_t *v = pv;
405576d1abcSJuan Quintela     uint16_t v2;
406576d1abcSJuan Quintela     qemu_get_be16s(f, &v2);
407576d1abcSJuan Quintela 
408576d1abcSJuan Quintela     if (*v == v2) {
409576d1abcSJuan Quintela         return 0;
410576d1abcSJuan Quintela     }
411576d1abcSJuan Quintela     error_report("%x != %x", *v, v2);
412d2164ad3SHalil Pasic     if (field->err_hint) {
413d2164ad3SHalil Pasic         error_printf("%s\n", field->err_hint);
414d2164ad3SHalil Pasic     }
415576d1abcSJuan Quintela     return -EINVAL;
416576d1abcSJuan Quintela }
417576d1abcSJuan Quintela 
418576d1abcSJuan Quintela const VMStateInfo vmstate_info_uint16_equal = {
419576d1abcSJuan Quintela     .name = "uint16 equal",
420576d1abcSJuan Quintela     .get  = get_uint16_equal,
421576d1abcSJuan Quintela     .put  = put_uint16,
422576d1abcSJuan Quintela };
423576d1abcSJuan Quintela 
424576d1abcSJuan Quintela /* CPU_DoubleU type */
425576d1abcSJuan Quintela 
get_cpudouble(QEMUFile * f,void * pv,size_t size,const VMStateField * field)426576d1abcSJuan Quintela static int get_cpudouble(QEMUFile *f, void *pv, size_t size,
42703fee66fSMarc-André Lureau                          const VMStateField *field)
428576d1abcSJuan Quintela {
429576d1abcSJuan Quintela     CPU_DoubleU *v = pv;
430576d1abcSJuan Quintela     qemu_get_be32s(f, &v->l.upper);
431576d1abcSJuan Quintela     qemu_get_be32s(f, &v->l.lower);
432576d1abcSJuan Quintela     return 0;
433576d1abcSJuan Quintela }
434576d1abcSJuan Quintela 
put_cpudouble(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)435576d1abcSJuan Quintela static int put_cpudouble(QEMUFile *f, void *pv, size_t size,
4363ddba9a9SMarkus Armbruster                          const VMStateField *field, JSONWriter *vmdesc)
437576d1abcSJuan Quintela {
438576d1abcSJuan Quintela     CPU_DoubleU *v = pv;
439576d1abcSJuan Quintela     qemu_put_be32s(f, &v->l.upper);
440576d1abcSJuan Quintela     qemu_put_be32s(f, &v->l.lower);
441576d1abcSJuan Quintela     return 0;
442576d1abcSJuan Quintela }
443576d1abcSJuan Quintela 
444576d1abcSJuan Quintela const VMStateInfo vmstate_info_cpudouble = {
445576d1abcSJuan Quintela     .name = "CPU_Double_U",
446576d1abcSJuan Quintela     .get  = get_cpudouble,
447576d1abcSJuan Quintela     .put  = put_cpudouble,
448576d1abcSJuan Quintela };
449576d1abcSJuan Quintela 
450576d1abcSJuan Quintela /* uint8_t buffers */
451576d1abcSJuan Quintela 
get_buffer(QEMUFile * f,void * pv,size_t size,const VMStateField * field)452576d1abcSJuan Quintela static int get_buffer(QEMUFile *f, void *pv, size_t size,
45303fee66fSMarc-André Lureau                       const VMStateField *field)
454576d1abcSJuan Quintela {
455576d1abcSJuan Quintela     uint8_t *v = pv;
456576d1abcSJuan Quintela     qemu_get_buffer(f, v, size);
457576d1abcSJuan Quintela     return 0;
458576d1abcSJuan Quintela }
459576d1abcSJuan Quintela 
put_buffer(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)46003fee66fSMarc-André Lureau static int put_buffer(QEMUFile *f, void *pv, size_t size,
4613ddba9a9SMarkus Armbruster                       const VMStateField *field, JSONWriter *vmdesc)
462576d1abcSJuan Quintela {
463576d1abcSJuan Quintela     uint8_t *v = pv;
464576d1abcSJuan Quintela     qemu_put_buffer(f, v, size);
465576d1abcSJuan Quintela     return 0;
466576d1abcSJuan Quintela }
467576d1abcSJuan Quintela 
468576d1abcSJuan Quintela const VMStateInfo vmstate_info_buffer = {
469576d1abcSJuan Quintela     .name = "buffer",
470576d1abcSJuan Quintela     .get  = get_buffer,
471576d1abcSJuan Quintela     .put  = put_buffer,
472576d1abcSJuan Quintela };
473576d1abcSJuan Quintela 
474576d1abcSJuan Quintela /* unused buffers: space that was used for some fields that are
475576d1abcSJuan Quintela    not useful anymore */
476576d1abcSJuan Quintela 
get_unused_buffer(QEMUFile * f,void * pv,size_t size,const VMStateField * field)477576d1abcSJuan Quintela static int get_unused_buffer(QEMUFile *f, void *pv, size_t size,
47803fee66fSMarc-André Lureau                              const VMStateField *field)
479576d1abcSJuan Quintela {
480576d1abcSJuan Quintela     uint8_t buf[1024];
481576d1abcSJuan Quintela     int block_len;
482576d1abcSJuan Quintela 
483576d1abcSJuan Quintela     while (size > 0) {
484576d1abcSJuan Quintela         block_len = MIN(sizeof(buf), size);
485576d1abcSJuan Quintela         size -= block_len;
486576d1abcSJuan Quintela         qemu_get_buffer(f, buf, block_len);
487576d1abcSJuan Quintela     }
488576d1abcSJuan Quintela    return 0;
489576d1abcSJuan Quintela }
490576d1abcSJuan Quintela 
put_unused_buffer(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)491576d1abcSJuan Quintela static int put_unused_buffer(QEMUFile *f, void *pv, size_t size,
4923ddba9a9SMarkus Armbruster                              const VMStateField *field, JSONWriter *vmdesc)
493576d1abcSJuan Quintela {
494576d1abcSJuan Quintela     static const uint8_t buf[1024];
495576d1abcSJuan Quintela     int block_len;
496576d1abcSJuan Quintela 
497576d1abcSJuan Quintela     while (size > 0) {
498576d1abcSJuan Quintela         block_len = MIN(sizeof(buf), size);
499576d1abcSJuan Quintela         size -= block_len;
500576d1abcSJuan Quintela         qemu_put_buffer(f, buf, block_len);
501576d1abcSJuan Quintela     }
502576d1abcSJuan Quintela 
503576d1abcSJuan Quintela     return 0;
504576d1abcSJuan Quintela }
505576d1abcSJuan Quintela 
506576d1abcSJuan Quintela const VMStateInfo vmstate_info_unused_buffer = {
507576d1abcSJuan Quintela     .name = "unused_buffer",
508576d1abcSJuan Quintela     .get  = get_unused_buffer,
509576d1abcSJuan Quintela     .put  = put_unused_buffer,
510576d1abcSJuan Quintela };
511576d1abcSJuan Quintela 
512576d1abcSJuan Quintela /* vmstate_info_tmp, see VMSTATE_WITH_TMP, the idea is that we allocate
513576d1abcSJuan Quintela  * a temporary buffer and the pre_load/pre_save methods in the child vmsd
514576d1abcSJuan Quintela  * copy stuff from the parent into the child and do calculations to fill
515576d1abcSJuan Quintela  * in fields that don't really exist in the parent but need to be in the
516576d1abcSJuan Quintela  * stream.
517576d1abcSJuan Quintela  */
get_tmp(QEMUFile * f,void * pv,size_t size,const VMStateField * field)51803fee66fSMarc-André Lureau static int get_tmp(QEMUFile *f, void *pv, size_t size,
51903fee66fSMarc-André Lureau                    const VMStateField *field)
520576d1abcSJuan Quintela {
521576d1abcSJuan Quintela     int ret;
522576d1abcSJuan Quintela     const VMStateDescription *vmsd = field->vmsd;
523576d1abcSJuan Quintela     int version_id = field->version_id;
524576d1abcSJuan Quintela     void *tmp = g_malloc(size);
525576d1abcSJuan Quintela 
526576d1abcSJuan Quintela     /* Writes the parent field which is at the start of the tmp */
527576d1abcSJuan Quintela     *(void **)tmp = pv;
528576d1abcSJuan Quintela     ret = vmstate_load_state(f, vmsd, tmp, version_id);
529576d1abcSJuan Quintela     g_free(tmp);
530576d1abcSJuan Quintela     return ret;
531576d1abcSJuan Quintela }
532576d1abcSJuan Quintela 
put_tmp(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)53303fee66fSMarc-André Lureau static int put_tmp(QEMUFile *f, void *pv, size_t size,
5343ddba9a9SMarkus Armbruster                    const VMStateField *field, JSONWriter *vmdesc)
535576d1abcSJuan Quintela {
536576d1abcSJuan Quintela     const VMStateDescription *vmsd = field->vmsd;
537576d1abcSJuan Quintela     void *tmp = g_malloc(size);
5382f168d07SDr. David Alan Gilbert     int ret;
539576d1abcSJuan Quintela 
540576d1abcSJuan Quintela     /* Writes the parent field which is at the start of the tmp */
541576d1abcSJuan Quintela     *(void **)tmp = pv;
5422f168d07SDr. David Alan Gilbert     ret = vmstate_save_state(f, vmsd, tmp, vmdesc);
543576d1abcSJuan Quintela     g_free(tmp);
544576d1abcSJuan Quintela 
5452f168d07SDr. David Alan Gilbert     return ret;
546576d1abcSJuan Quintela }
547576d1abcSJuan Quintela 
548576d1abcSJuan Quintela const VMStateInfo vmstate_info_tmp = {
549576d1abcSJuan Quintela     .name = "tmp",
550576d1abcSJuan Quintela     .get = get_tmp,
551576d1abcSJuan Quintela     .put = put_tmp,
552576d1abcSJuan Quintela };
553576d1abcSJuan Quintela 
554576d1abcSJuan Quintela /* bitmaps (as defined by bitmap.h). Note that size here is the size
555576d1abcSJuan Quintela  * of the bitmap in bits. The on-the-wire format of a bitmap is 64
556576d1abcSJuan Quintela  * bit words with the bits in big endian order. The in-memory format
557576d1abcSJuan Quintela  * is an array of 'unsigned long', which may be either 32 or 64 bits.
558576d1abcSJuan Quintela  */
559576d1abcSJuan Quintela /* This is the number of 64 bit words sent over the wire */
560576d1abcSJuan Quintela #define BITS_TO_U64S(nr) DIV_ROUND_UP(nr, 64)
get_bitmap(QEMUFile * f,void * pv,size_t size,const VMStateField * field)56103fee66fSMarc-André Lureau static int get_bitmap(QEMUFile *f, void *pv, size_t size,
56203fee66fSMarc-André Lureau                       const VMStateField *field)
563576d1abcSJuan Quintela {
564576d1abcSJuan Quintela     unsigned long *bmp = pv;
565576d1abcSJuan Quintela     int i, idx = 0;
566576d1abcSJuan Quintela     for (i = 0; i < BITS_TO_U64S(size); i++) {
567576d1abcSJuan Quintela         uint64_t w = qemu_get_be64(f);
568576d1abcSJuan Quintela         bmp[idx++] = w;
569576d1abcSJuan Quintela         if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
570576d1abcSJuan Quintela             bmp[idx++] = w >> 32;
571576d1abcSJuan Quintela         }
572576d1abcSJuan Quintela     }
573576d1abcSJuan Quintela     return 0;
574576d1abcSJuan Quintela }
575576d1abcSJuan Quintela 
put_bitmap(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)57603fee66fSMarc-André Lureau static int put_bitmap(QEMUFile *f, void *pv, size_t size,
5773ddba9a9SMarkus Armbruster                       const VMStateField *field, JSONWriter *vmdesc)
578576d1abcSJuan Quintela {
579576d1abcSJuan Quintela     unsigned long *bmp = pv;
580576d1abcSJuan Quintela     int i, idx = 0;
581576d1abcSJuan Quintela     for (i = 0; i < BITS_TO_U64S(size); i++) {
582576d1abcSJuan Quintela         uint64_t w = bmp[idx++];
583576d1abcSJuan Quintela         if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
584576d1abcSJuan Quintela             w |= ((uint64_t)bmp[idx++]) << 32;
585576d1abcSJuan Quintela         }
586576d1abcSJuan Quintela         qemu_put_be64(f, w);
587576d1abcSJuan Quintela     }
588576d1abcSJuan Quintela 
589576d1abcSJuan Quintela     return 0;
590576d1abcSJuan Quintela }
591576d1abcSJuan Quintela 
592576d1abcSJuan Quintela const VMStateInfo vmstate_info_bitmap = {
593576d1abcSJuan Quintela     .name = "bitmap",
594576d1abcSJuan Quintela     .get = get_bitmap,
595576d1abcSJuan Quintela     .put = put_bitmap,
596576d1abcSJuan Quintela };
597576d1abcSJuan Quintela 
598576d1abcSJuan Quintela /* get for QTAILQ
599576d1abcSJuan Quintela  * meta data about the QTAILQ is encoded in a VMStateField structure
600576d1abcSJuan Quintela  */
get_qtailq(QEMUFile * f,void * pv,size_t unused_size,const VMStateField * field)601576d1abcSJuan Quintela static int get_qtailq(QEMUFile *f, void *pv, size_t unused_size,
60203fee66fSMarc-André Lureau                       const VMStateField *field)
603576d1abcSJuan Quintela {
604576d1abcSJuan Quintela     int ret = 0;
605576d1abcSJuan Quintela     const VMStateDescription *vmsd = field->vmsd;
606576d1abcSJuan Quintela     /* size of a QTAILQ element */
607576d1abcSJuan Quintela     size_t size = field->size;
608576d1abcSJuan Quintela     /* offset of the QTAILQ entry in a QTAILQ element */
609576d1abcSJuan Quintela     size_t entry_offset = field->start;
610576d1abcSJuan Quintela     int version_id = field->version_id;
611576d1abcSJuan Quintela     void *elm;
612576d1abcSJuan Quintela 
613576d1abcSJuan Quintela     trace_get_qtailq(vmsd->name, version_id);
614576d1abcSJuan Quintela     if (version_id > vmsd->version_id) {
615576d1abcSJuan Quintela         error_report("%s %s",  vmsd->name, "too new");
616576d1abcSJuan Quintela         trace_get_qtailq_end(vmsd->name, "too new", -EINVAL);
617576d1abcSJuan Quintela 
618576d1abcSJuan Quintela         return -EINVAL;
619576d1abcSJuan Quintela     }
620576d1abcSJuan Quintela     if (version_id < vmsd->minimum_version_id) {
621576d1abcSJuan Quintela         error_report("%s %s",  vmsd->name, "too old");
622576d1abcSJuan Quintela         trace_get_qtailq_end(vmsd->name, "too old", -EINVAL);
623576d1abcSJuan Quintela         return -EINVAL;
624576d1abcSJuan Quintela     }
625576d1abcSJuan Quintela 
626576d1abcSJuan Quintela     while (qemu_get_byte(f)) {
627576d1abcSJuan Quintela         elm = g_malloc(size);
628576d1abcSJuan Quintela         ret = vmstate_load_state(f, vmsd, elm, version_id);
629576d1abcSJuan Quintela         if (ret) {
630576d1abcSJuan Quintela             return ret;
631576d1abcSJuan Quintela         }
632576d1abcSJuan Quintela         QTAILQ_RAW_INSERT_TAIL(pv, elm, entry_offset);
633576d1abcSJuan Quintela     }
634576d1abcSJuan Quintela 
635576d1abcSJuan Quintela     trace_get_qtailq_end(vmsd->name, "end", ret);
636576d1abcSJuan Quintela     return ret;
637576d1abcSJuan Quintela }
638576d1abcSJuan Quintela 
639576d1abcSJuan Quintela /* put for QTAILQ */
put_qtailq(QEMUFile * f,void * pv,size_t unused_size,const VMStateField * field,JSONWriter * vmdesc)640576d1abcSJuan Quintela static int put_qtailq(QEMUFile *f, void *pv, size_t unused_size,
6413ddba9a9SMarkus Armbruster                       const VMStateField *field, JSONWriter *vmdesc)
642576d1abcSJuan Quintela {
643576d1abcSJuan Quintela     const VMStateDescription *vmsd = field->vmsd;
644576d1abcSJuan Quintela     /* offset of the QTAILQ entry in a QTAILQ element*/
645576d1abcSJuan Quintela     size_t entry_offset = field->start;
646576d1abcSJuan Quintela     void *elm;
6472f168d07SDr. David Alan Gilbert     int ret;
648576d1abcSJuan Quintela 
649576d1abcSJuan Quintela     trace_put_qtailq(vmsd->name, vmsd->version_id);
650576d1abcSJuan Quintela 
651576d1abcSJuan Quintela     QTAILQ_RAW_FOREACH(elm, pv, entry_offset) {
652576d1abcSJuan Quintela         qemu_put_byte(f, true);
6532f168d07SDr. David Alan Gilbert         ret = vmstate_save_state(f, vmsd, elm, vmdesc);
6542f168d07SDr. David Alan Gilbert         if (ret) {
6552f168d07SDr. David Alan Gilbert             return ret;
6562f168d07SDr. David Alan Gilbert         }
657576d1abcSJuan Quintela     }
658576d1abcSJuan Quintela     qemu_put_byte(f, false);
659576d1abcSJuan Quintela 
660576d1abcSJuan Quintela     trace_put_qtailq_end(vmsd->name, "end");
661576d1abcSJuan Quintela 
662576d1abcSJuan Quintela     return 0;
663576d1abcSJuan Quintela }
664576d1abcSJuan Quintela const VMStateInfo vmstate_info_qtailq = {
665576d1abcSJuan Quintela     .name = "qtailq",
666576d1abcSJuan Quintela     .get  = get_qtailq,
667576d1abcSJuan Quintela     .put  = put_qtailq,
668576d1abcSJuan Quintela };
6699a85e4b8SEric Auger 
6709a85e4b8SEric Auger struct put_gtree_data {
6719a85e4b8SEric Auger     QEMUFile *f;
6729a85e4b8SEric Auger     const VMStateDescription *key_vmsd;
6739a85e4b8SEric Auger     const VMStateDescription *val_vmsd;
6743ddba9a9SMarkus Armbruster     JSONWriter *vmdesc;
6759a85e4b8SEric Auger     int ret;
6769a85e4b8SEric Auger };
6779a85e4b8SEric Auger 
put_gtree_elem(gpointer key,gpointer value,gpointer data)6789a85e4b8SEric Auger static gboolean put_gtree_elem(gpointer key, gpointer value, gpointer data)
6799a85e4b8SEric Auger {
6809a85e4b8SEric Auger     struct put_gtree_data *capsule = (struct put_gtree_data *)data;
6819a85e4b8SEric Auger     QEMUFile *f = capsule->f;
6829a85e4b8SEric Auger     int ret;
6839a85e4b8SEric Auger 
6849a85e4b8SEric Auger     qemu_put_byte(f, true);
6859a85e4b8SEric Auger 
6869a85e4b8SEric Auger     /* put the key */
6879a85e4b8SEric Auger     if (!capsule->key_vmsd) {
6889a85e4b8SEric Auger         qemu_put_be64(f, (uint64_t)(uintptr_t)(key)); /* direct key */
6899a85e4b8SEric Auger     } else {
6909a85e4b8SEric Auger         ret = vmstate_save_state(f, capsule->key_vmsd, key, capsule->vmdesc);
6919a85e4b8SEric Auger         if (ret) {
6929a85e4b8SEric Auger             capsule->ret = ret;
6939a85e4b8SEric Auger             return true;
6949a85e4b8SEric Auger         }
6959a85e4b8SEric Auger     }
6969a85e4b8SEric Auger 
6979a85e4b8SEric Auger     /* put the data */
6989a85e4b8SEric Auger     ret = vmstate_save_state(f, capsule->val_vmsd, value, capsule->vmdesc);
6999a85e4b8SEric Auger     if (ret) {
7009a85e4b8SEric Auger         capsule->ret = ret;
7019a85e4b8SEric Auger         return true;
7029a85e4b8SEric Auger     }
7039a85e4b8SEric Auger     return false;
7049a85e4b8SEric Auger }
7059a85e4b8SEric Auger 
put_gtree(QEMUFile * f,void * pv,size_t unused_size,const VMStateField * field,JSONWriter * vmdesc)7069a85e4b8SEric Auger static int put_gtree(QEMUFile *f, void *pv, size_t unused_size,
7073ddba9a9SMarkus Armbruster                      const VMStateField *field, JSONWriter *vmdesc)
7089a85e4b8SEric Auger {
7099a85e4b8SEric Auger     bool direct_key = (!field->start);
7109a85e4b8SEric Auger     const VMStateDescription *key_vmsd = direct_key ? NULL : &field->vmsd[1];
7119a85e4b8SEric Auger     const VMStateDescription *val_vmsd = &field->vmsd[0];
7129a85e4b8SEric Auger     const char *key_vmsd_name = direct_key ? "direct" : key_vmsd->name;
7139a85e4b8SEric Auger     struct put_gtree_data capsule = {
7149a85e4b8SEric Auger         .f = f,
7159a85e4b8SEric Auger         .key_vmsd = key_vmsd,
7169a85e4b8SEric Auger         .val_vmsd = val_vmsd,
7179a85e4b8SEric Auger         .vmdesc = vmdesc,
7189a85e4b8SEric Auger         .ret = 0};
7199a85e4b8SEric Auger     GTree **pval = pv;
7209a85e4b8SEric Auger     GTree *tree = *pval;
7219a85e4b8SEric Auger     uint32_t nnodes = g_tree_nnodes(tree);
7229a85e4b8SEric Auger     int ret;
7239a85e4b8SEric Auger 
7249a85e4b8SEric Auger     trace_put_gtree(field->name, key_vmsd_name, val_vmsd->name, nnodes);
7259a85e4b8SEric Auger     qemu_put_be32(f, nnodes);
7269a85e4b8SEric Auger     g_tree_foreach(tree, put_gtree_elem, (gpointer)&capsule);
7279a85e4b8SEric Auger     qemu_put_byte(f, false);
7289a85e4b8SEric Auger     ret = capsule.ret;
7299a85e4b8SEric Auger     if (ret) {
7309a85e4b8SEric Auger         error_report("%s : failed to save gtree (%d)", field->name, ret);
7319a85e4b8SEric Auger     }
7329a85e4b8SEric Auger     trace_put_gtree_end(field->name, key_vmsd_name, val_vmsd->name, ret);
7339a85e4b8SEric Auger     return ret;
7349a85e4b8SEric Auger }
7359a85e4b8SEric Auger 
get_gtree(QEMUFile * f,void * pv,size_t unused_size,const VMStateField * field)7369a85e4b8SEric Auger static int get_gtree(QEMUFile *f, void *pv, size_t unused_size,
7379a85e4b8SEric Auger                      const VMStateField *field)
7389a85e4b8SEric Auger {
7399a85e4b8SEric Auger     bool direct_key = (!field->start);
7409a85e4b8SEric Auger     const VMStateDescription *key_vmsd = direct_key ? NULL : &field->vmsd[1];
7419a85e4b8SEric Auger     const VMStateDescription *val_vmsd = &field->vmsd[0];
7429a85e4b8SEric Auger     const char *key_vmsd_name = direct_key ? "direct" : key_vmsd->name;
7439a85e4b8SEric Auger     int version_id = field->version_id;
7449a85e4b8SEric Auger     size_t key_size = field->start;
7459a85e4b8SEric Auger     size_t val_size = field->size;
7469a85e4b8SEric Auger     int nnodes, count = 0;
7479a85e4b8SEric Auger     GTree **pval = pv;
7489a85e4b8SEric Auger     GTree *tree = *pval;
7499a85e4b8SEric Auger     void *key, *val;
7509a85e4b8SEric Auger     int ret = 0;
7519a85e4b8SEric Auger 
7529a85e4b8SEric Auger     /* in case of direct key, the key vmsd can be {}, ie. check fields */
7539a85e4b8SEric Auger     if (!direct_key && version_id > key_vmsd->version_id) {
7549a85e4b8SEric Auger         error_report("%s %s",  key_vmsd->name, "too new");
7559a85e4b8SEric Auger         return -EINVAL;
7569a85e4b8SEric Auger     }
7579a85e4b8SEric Auger     if (!direct_key && version_id < key_vmsd->minimum_version_id) {
7589a85e4b8SEric Auger         error_report("%s %s",  key_vmsd->name, "too old");
7599a85e4b8SEric Auger         return -EINVAL;
7609a85e4b8SEric Auger     }
7619a85e4b8SEric Auger     if (version_id > val_vmsd->version_id) {
7629a85e4b8SEric Auger         error_report("%s %s",  val_vmsd->name, "too new");
7639a85e4b8SEric Auger         return -EINVAL;
7649a85e4b8SEric Auger     }
7659a85e4b8SEric Auger     if (version_id < val_vmsd->minimum_version_id) {
7669a85e4b8SEric Auger         error_report("%s %s",  val_vmsd->name, "too old");
7679a85e4b8SEric Auger         return -EINVAL;
7689a85e4b8SEric Auger     }
7699a85e4b8SEric Auger 
7709a85e4b8SEric Auger     nnodes = qemu_get_be32(f);
7719a85e4b8SEric Auger     trace_get_gtree(field->name, key_vmsd_name, val_vmsd->name, nnodes);
7729a85e4b8SEric Auger 
7739a85e4b8SEric Auger     while (qemu_get_byte(f)) {
7749a85e4b8SEric Auger         if ((++count) > nnodes) {
7759a85e4b8SEric Auger             ret = -EINVAL;
7769a85e4b8SEric Auger             break;
7779a85e4b8SEric Auger         }
7789a85e4b8SEric Auger         if (direct_key) {
7799a85e4b8SEric Auger             key = (void *)(uintptr_t)qemu_get_be64(f);
7809a85e4b8SEric Auger         } else {
7819a85e4b8SEric Auger             key = g_malloc0(key_size);
7829a85e4b8SEric Auger             ret = vmstate_load_state(f, key_vmsd, key, version_id);
7839a85e4b8SEric Auger             if (ret) {
7849a85e4b8SEric Auger                 error_report("%s : failed to load %s (%d)",
7859a85e4b8SEric Auger                              field->name, key_vmsd->name, ret);
7869a85e4b8SEric Auger                 goto key_error;
7879a85e4b8SEric Auger             }
7889a85e4b8SEric Auger         }
7899a85e4b8SEric Auger         val = g_malloc0(val_size);
7909a85e4b8SEric Auger         ret = vmstate_load_state(f, val_vmsd, val, version_id);
7919a85e4b8SEric Auger         if (ret) {
7929a85e4b8SEric Auger             error_report("%s : failed to load %s (%d)",
7939a85e4b8SEric Auger                          field->name, val_vmsd->name, ret);
7949a85e4b8SEric Auger             goto val_error;
7959a85e4b8SEric Auger         }
7969a85e4b8SEric Auger         g_tree_insert(tree, key, val);
7979a85e4b8SEric Auger     }
7989a85e4b8SEric Auger     if (count != nnodes) {
7999a85e4b8SEric Auger         error_report("%s inconsistent stream when loading the gtree",
8009a85e4b8SEric Auger                      field->name);
8019a85e4b8SEric Auger         return -EINVAL;
8029a85e4b8SEric Auger     }
8039a85e4b8SEric Auger     trace_get_gtree_end(field->name, key_vmsd_name, val_vmsd->name, ret);
8049a85e4b8SEric Auger     return ret;
8059a85e4b8SEric Auger val_error:
8069a85e4b8SEric Auger     g_free(val);
8079a85e4b8SEric Auger key_error:
8089a85e4b8SEric Auger     if (!direct_key) {
8099a85e4b8SEric Auger         g_free(key);
8109a85e4b8SEric Auger     }
8119a85e4b8SEric Auger     trace_get_gtree_end(field->name, key_vmsd_name, val_vmsd->name, ret);
8129a85e4b8SEric Auger     return ret;
8139a85e4b8SEric Auger }
8149a85e4b8SEric Auger 
8159a85e4b8SEric Auger 
8169a85e4b8SEric Auger const VMStateInfo vmstate_info_gtree = {
8179a85e4b8SEric Auger     .name = "gtree",
8189a85e4b8SEric Auger     .get  = get_gtree,
8199a85e4b8SEric Auger     .put  = put_gtree,
8209a85e4b8SEric Auger };
8214746dbf8SEric Auger 
put_qlist(QEMUFile * f,void * pv,size_t unused_size,const VMStateField * field,JSONWriter * vmdesc)8224746dbf8SEric Auger static int put_qlist(QEMUFile *f, void *pv, size_t unused_size,
8233ddba9a9SMarkus Armbruster                      const VMStateField *field, JSONWriter *vmdesc)
8244746dbf8SEric Auger {
8254746dbf8SEric Auger     const VMStateDescription *vmsd = field->vmsd;
8264746dbf8SEric Auger     /* offset of the QTAILQ entry in a QTAILQ element*/
8274746dbf8SEric Auger     size_t entry_offset = field->start;
8284746dbf8SEric Auger     void *elm;
8294746dbf8SEric Auger     int ret;
8304746dbf8SEric Auger 
8314746dbf8SEric Auger     trace_put_qlist(field->name, vmsd->name, vmsd->version_id);
8324746dbf8SEric Auger     QLIST_RAW_FOREACH(elm, pv, entry_offset) {
8334746dbf8SEric Auger         qemu_put_byte(f, true);
8344746dbf8SEric Auger         ret = vmstate_save_state(f, vmsd, elm, vmdesc);
8354746dbf8SEric Auger         if (ret) {
8364746dbf8SEric Auger             error_report("%s: failed to save %s (%d)", field->name,
8374746dbf8SEric Auger                          vmsd->name, ret);
8384746dbf8SEric Auger             return ret;
8394746dbf8SEric Auger         }
8404746dbf8SEric Auger     }
8414746dbf8SEric Auger     qemu_put_byte(f, false);
8424746dbf8SEric Auger     trace_put_qlist_end(field->name, vmsd->name);
8434746dbf8SEric Auger 
8444746dbf8SEric Auger     return 0;
8454746dbf8SEric Auger }
8464746dbf8SEric Auger 
get_qlist(QEMUFile * f,void * pv,size_t unused_size,const VMStateField * field)8474746dbf8SEric Auger static int get_qlist(QEMUFile *f, void *pv, size_t unused_size,
8484746dbf8SEric Auger                      const VMStateField *field)
8494746dbf8SEric Auger {
8504746dbf8SEric Auger     int ret = 0;
8514746dbf8SEric Auger     const VMStateDescription *vmsd = field->vmsd;
8524746dbf8SEric Auger     /* size of a QLIST element */
8534746dbf8SEric Auger     size_t size = field->size;
8544746dbf8SEric Auger     /* offset of the QLIST entry in a QLIST element */
8554746dbf8SEric Auger     size_t entry_offset = field->start;
8564746dbf8SEric Auger     int version_id = field->version_id;
857a085664fSEric Auger     void *elm, *prev = NULL;
8584746dbf8SEric Auger 
8594746dbf8SEric Auger     trace_get_qlist(field->name, vmsd->name, vmsd->version_id);
8604746dbf8SEric Auger     if (version_id > vmsd->version_id) {
8614746dbf8SEric Auger         error_report("%s %s",  vmsd->name, "too new");
8624746dbf8SEric Auger         return -EINVAL;
8634746dbf8SEric Auger     }
8644746dbf8SEric Auger     if (version_id < vmsd->minimum_version_id) {
8654746dbf8SEric Auger         error_report("%s %s",  vmsd->name, "too old");
8664746dbf8SEric Auger         return -EINVAL;
8674746dbf8SEric Auger     }
8684746dbf8SEric Auger 
8694746dbf8SEric Auger     while (qemu_get_byte(f)) {
8704746dbf8SEric Auger         elm = g_malloc(size);
8714746dbf8SEric Auger         ret = vmstate_load_state(f, vmsd, elm, version_id);
8724746dbf8SEric Auger         if (ret) {
8734746dbf8SEric Auger             error_report("%s: failed to load %s (%d)", field->name,
8744746dbf8SEric Auger                          vmsd->name, ret);
8754746dbf8SEric Auger             g_free(elm);
8764746dbf8SEric Auger             return ret;
8774746dbf8SEric Auger         }
878a085664fSEric Auger         if (!prev) {
8794746dbf8SEric Auger             QLIST_RAW_INSERT_HEAD(pv, elm, entry_offset);
880a085664fSEric Auger         } else {
881a085664fSEric Auger             QLIST_RAW_INSERT_AFTER(pv, prev, elm, entry_offset);
8824746dbf8SEric Auger         }
883a085664fSEric Auger         prev = elm;
884a085664fSEric Auger     }
8854746dbf8SEric Auger     trace_get_qlist_end(field->name, vmsd->name);
8864746dbf8SEric Auger 
8874746dbf8SEric Auger     return ret;
8884746dbf8SEric Auger }
8894746dbf8SEric Auger 
8904746dbf8SEric Auger const VMStateInfo vmstate_info_qlist = {
8914746dbf8SEric Auger     .name = "qlist",
8924746dbf8SEric Auger     .get  = get_qlist,
8934746dbf8SEric Auger     .put  = put_qlist,
8944746dbf8SEric Auger };
895