[34] | 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 | } |
---|