1 | /* |
---|
2 | * hvm/save.c: Save and restore HVM guest's emulated hardware state. |
---|
3 | * |
---|
4 | * Copyright (c) 2004, Intel Corporation. |
---|
5 | * Copyright (c) 2007, XenSource Inc. |
---|
6 | * |
---|
7 | * This program is free software; you can redistribute it and/or modify it |
---|
8 | * under the terms and conditions of the GNU General Public License, |
---|
9 | * version 2, as published by the Free Software Foundation. |
---|
10 | * |
---|
11 | * This program is distributed in the hope it will be useful, but WITHOUT |
---|
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
---|
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
---|
14 | * more details. |
---|
15 | * |
---|
16 | * You should have received a copy of the GNU General Public License along with |
---|
17 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple |
---|
18 | * Place - Suite 330, Boston, MA 02111-1307 USA. |
---|
19 | */ |
---|
20 | |
---|
21 | #include <xen/config.h> |
---|
22 | #include <xen/compile.h> |
---|
23 | #include <xen/lib.h> |
---|
24 | #include <public/version.h> |
---|
25 | #include <xen/sched.h> |
---|
26 | |
---|
27 | #include <asm/hvm/hvm.h> |
---|
28 | #include <asm/hvm/support.h> |
---|
29 | #include <asm/hvm/domain.h> |
---|
30 | #include <asm/current.h> |
---|
31 | |
---|
32 | |
---|
33 | /* List of handlers for various HVM save and restore types */ |
---|
34 | static struct { |
---|
35 | hvm_save_handler save; |
---|
36 | hvm_load_handler load; |
---|
37 | const char *name; |
---|
38 | size_t size; |
---|
39 | int kind; |
---|
40 | } hvm_sr_handlers [HVM_SAVE_CODE_MAX + 1] = {{NULL, NULL, "<?>"},}; |
---|
41 | |
---|
42 | /* Init-time function to add entries to that list */ |
---|
43 | void hvm_register_savevm(uint16_t typecode, |
---|
44 | const char *name, |
---|
45 | hvm_save_handler save_state, |
---|
46 | hvm_load_handler load_state, |
---|
47 | size_t size, int kind) |
---|
48 | { |
---|
49 | ASSERT(typecode <= HVM_SAVE_CODE_MAX); |
---|
50 | ASSERT(hvm_sr_handlers[typecode].save == NULL); |
---|
51 | ASSERT(hvm_sr_handlers[typecode].load == NULL); |
---|
52 | hvm_sr_handlers[typecode].save = save_state; |
---|
53 | hvm_sr_handlers[typecode].load = load_state; |
---|
54 | hvm_sr_handlers[typecode].name = name; |
---|
55 | hvm_sr_handlers[typecode].size = size; |
---|
56 | hvm_sr_handlers[typecode].kind = kind; |
---|
57 | } |
---|
58 | |
---|
59 | size_t hvm_save_size(struct domain *d) |
---|
60 | { |
---|
61 | struct vcpu *v; |
---|
62 | size_t sz; |
---|
63 | int i; |
---|
64 | |
---|
65 | /* Basic overhead for header and footer */ |
---|
66 | sz = (2 * sizeof (struct hvm_save_descriptor)) + HVM_SAVE_LENGTH(HEADER); |
---|
67 | |
---|
68 | /* Plus space for each thing we will be saving */ |
---|
69 | for ( i = 0; i <= HVM_SAVE_CODE_MAX; i++ ) |
---|
70 | if ( hvm_sr_handlers[i].kind == HVMSR_PER_VCPU ) |
---|
71 | for_each_vcpu(d, v) |
---|
72 | sz += hvm_sr_handlers[i].size; |
---|
73 | else |
---|
74 | sz += hvm_sr_handlers[i].size; |
---|
75 | |
---|
76 | return sz; |
---|
77 | } |
---|
78 | |
---|
79 | |
---|
80 | int hvm_save(struct domain *d, hvm_domain_context_t *h) |
---|
81 | { |
---|
82 | uint32_t eax, ebx, ecx, edx; |
---|
83 | char *c; |
---|
84 | struct hvm_save_header hdr; |
---|
85 | struct hvm_save_end end; |
---|
86 | hvm_save_handler handler; |
---|
87 | uint16_t i; |
---|
88 | |
---|
89 | hdr.magic = HVM_FILE_MAGIC; |
---|
90 | hdr.version = HVM_FILE_VERSION; |
---|
91 | |
---|
92 | /* Save some CPUID bits */ |
---|
93 | cpuid(1, &eax, &ebx, &ecx, &edx); |
---|
94 | hdr.cpuid = eax; |
---|
95 | |
---|
96 | /* Save xen changeset */ |
---|
97 | c = strrchr(XEN_CHANGESET, ':'); |
---|
98 | if ( c ) |
---|
99 | hdr.changeset = simple_strtoll(c, NULL, 16); |
---|
100 | else |
---|
101 | hdr.changeset = -1ULL; /* Unknown */ |
---|
102 | |
---|
103 | hdr.pad0 = 0; |
---|
104 | |
---|
105 | if ( hvm_save_entry(HEADER, 0, h, &hdr) != 0 ) |
---|
106 | { |
---|
107 | gdprintk(XENLOG_ERR, "HVM save: failed to write header\n"); |
---|
108 | return -EFAULT; |
---|
109 | } |
---|
110 | |
---|
111 | /* Save all available kinds of state */ |
---|
112 | for ( i = 0; i <= HVM_SAVE_CODE_MAX; i++ ) |
---|
113 | { |
---|
114 | handler = hvm_sr_handlers[i].save; |
---|
115 | if ( handler != NULL ) |
---|
116 | { |
---|
117 | gdprintk(XENLOG_INFO, "HVM save: %s\n", hvm_sr_handlers[i].name); |
---|
118 | if ( handler(d, h) != 0 ) |
---|
119 | { |
---|
120 | gdprintk(XENLOG_ERR, |
---|
121 | "HVM save: failed to save type %"PRIu16"\n", i); |
---|
122 | return -EFAULT; |
---|
123 | } |
---|
124 | } |
---|
125 | } |
---|
126 | |
---|
127 | /* Save an end-of-file marker */ |
---|
128 | if ( hvm_save_entry(END, 0, h, &end) != 0 ) |
---|
129 | { |
---|
130 | /* Run out of data */ |
---|
131 | gdprintk(XENLOG_ERR, "HVM save: no room for end marker.\n"); |
---|
132 | return -EFAULT; |
---|
133 | } |
---|
134 | |
---|
135 | /* Save macros should not have let us overrun */ |
---|
136 | ASSERT(h->cur <= h->size); |
---|
137 | return 0; |
---|
138 | } |
---|
139 | |
---|
140 | int hvm_load(struct domain *d, hvm_domain_context_t *h) |
---|
141 | { |
---|
142 | uint32_t eax, ebx, ecx, edx; |
---|
143 | char *c; |
---|
144 | uint64_t cset; |
---|
145 | struct hvm_save_header hdr; |
---|
146 | struct hvm_save_descriptor *desc; |
---|
147 | hvm_load_handler handler; |
---|
148 | struct vcpu *v; |
---|
149 | |
---|
150 | /* Read the save header, which must be first */ |
---|
151 | if ( hvm_load_entry(HEADER, h, &hdr) != 0 ) |
---|
152 | return -1; |
---|
153 | |
---|
154 | if (hdr.magic != HVM_FILE_MAGIC) { |
---|
155 | gdprintk(XENLOG_ERR, |
---|
156 | "HVM restore: bad magic number %#"PRIx32"\n", hdr.magic); |
---|
157 | return -1; |
---|
158 | } |
---|
159 | |
---|
160 | if (hdr.version != HVM_FILE_VERSION) { |
---|
161 | gdprintk(XENLOG_ERR, |
---|
162 | "HVM restore: unsupported version %u\n", hdr.version); |
---|
163 | return -1; |
---|
164 | } |
---|
165 | |
---|
166 | cpuid(1, &eax, &ebx, &ecx, &edx); |
---|
167 | /*TODO: need to define how big a difference is acceptable */ |
---|
168 | if (hdr.cpuid != eax) |
---|
169 | gdprintk(XENLOG_WARNING, "HVM restore: saved CPUID (%#"PRIx32") " |
---|
170 | "does not match host (%#"PRIx32").\n", hdr.cpuid, eax); |
---|
171 | |
---|
172 | |
---|
173 | c = strrchr(XEN_CHANGESET, ':'); |
---|
174 | if ( hdr.changeset == -1ULL ) |
---|
175 | gdprintk(XENLOG_WARNING, |
---|
176 | "HVM restore: Xen changeset was not saved.\n"); |
---|
177 | else if ( c == NULL ) |
---|
178 | gdprintk(XENLOG_WARNING, |
---|
179 | "HVM restore: Xen changeset is not available.\n"); |
---|
180 | else |
---|
181 | { |
---|
182 | cset = simple_strtoll(c, NULL, 16); |
---|
183 | if ( hdr.changeset != cset ) |
---|
184 | gdprintk(XENLOG_WARNING, "HVM restore: saved Xen changeset (%#"PRIx64 |
---|
185 | ") does not match host (%#"PRIx64").\n", hdr.changeset, cset); |
---|
186 | } |
---|
187 | |
---|
188 | /* Down all the vcpus: we only re-enable the ones that had state saved. */ |
---|
189 | for_each_vcpu(d, v) |
---|
190 | if ( test_and_set_bit(_VPF_down, &v->pause_flags) ) |
---|
191 | vcpu_sleep_nosync(v); |
---|
192 | |
---|
193 | while(1) { |
---|
194 | |
---|
195 | if ( h->size - h->cur < sizeof(struct hvm_save_descriptor) ) |
---|
196 | { |
---|
197 | /* Run out of data */ |
---|
198 | gdprintk(XENLOG_ERR, |
---|
199 | "HVM restore: save did not end with a null entry\n"); |
---|
200 | return -1; |
---|
201 | } |
---|
202 | |
---|
203 | /* Read the typecode of the next entry and check for the end-marker */ |
---|
204 | desc = (struct hvm_save_descriptor *)(&h->data[h->cur]); |
---|
205 | if ( desc->typecode == 0 ) |
---|
206 | return 0; |
---|
207 | |
---|
208 | /* Find the handler for this entry */ |
---|
209 | if ( desc->typecode > HVM_SAVE_CODE_MAX |
---|
210 | || (handler = hvm_sr_handlers[desc->typecode].load) == NULL ) |
---|
211 | { |
---|
212 | gdprintk(XENLOG_ERR, |
---|
213 | "HVM restore: unknown entry typecode %u\n", |
---|
214 | desc->typecode); |
---|
215 | return -1; |
---|
216 | } |
---|
217 | |
---|
218 | /* Load the entry */ |
---|
219 | gdprintk(XENLOG_INFO, "HVM restore: %s %"PRIu16"\n", |
---|
220 | hvm_sr_handlers[desc->typecode].name, desc->instance); |
---|
221 | if ( handler(d, h) != 0 ) |
---|
222 | { |
---|
223 | gdprintk(XENLOG_ERR, |
---|
224 | "HVM restore: failed to load entry %u/%u\n", |
---|
225 | desc->typecode, desc->instance); |
---|
226 | return -1; |
---|
227 | } |
---|
228 | } |
---|
229 | |
---|
230 | /* Not reached */ |
---|
231 | } |
---|