qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio
at jcs-hda-dma 342 lines 9.4 kB view raw
1/* 2 * QEMU Boot Device Implement 3 * 4 * Copyright (c) 2014 HUAWEI TECHNOLOGIES CO., LTD. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 25#include "qemu/osdep.h" 26#include "qapi/error.h" 27#include "sysemu/sysemu.h" 28#include "qapi/visitor.h" 29#include "qemu/error-report.h" 30#include "sysemu/reset.h" 31#include "hw/qdev-core.h" 32 33typedef struct FWBootEntry FWBootEntry; 34 35struct FWBootEntry { 36 QTAILQ_ENTRY(FWBootEntry) link; 37 int32_t bootindex; 38 DeviceState *dev; 39 char *suffix; 40}; 41 42static QTAILQ_HEAD(, FWBootEntry) fw_boot_order = 43 QTAILQ_HEAD_INITIALIZER(fw_boot_order); 44static QEMUBootSetHandler *boot_set_handler; 45static void *boot_set_opaque; 46 47void qemu_register_boot_set(QEMUBootSetHandler *func, void *opaque) 48{ 49 boot_set_handler = func; 50 boot_set_opaque = opaque; 51} 52 53void qemu_boot_set(const char *boot_order, Error **errp) 54{ 55 Error *local_err = NULL; 56 57 if (!boot_set_handler) { 58 error_setg(errp, "no function defined to set boot device list for" 59 " this architecture"); 60 return; 61 } 62 63 validate_bootdevices(boot_order, &local_err); 64 if (local_err) { 65 error_propagate(errp, local_err); 66 return; 67 } 68 69 boot_set_handler(boot_set_opaque, boot_order, errp); 70} 71 72void validate_bootdevices(const char *devices, Error **errp) 73{ 74 /* We just do some generic consistency checks */ 75 const char *p; 76 int bitmap = 0; 77 78 for (p = devices; *p != '\0'; p++) { 79 /* Allowed boot devices are: 80 * a-b: floppy disk drives 81 * c-f: IDE disk drives 82 * g-m: machine implementation dependent drives 83 * n-p: network devices 84 * It's up to each machine implementation to check if the given boot 85 * devices match the actual hardware implementation and firmware 86 * features. 87 */ 88 if (*p < 'a' || *p > 'p') { 89 error_setg(errp, "Invalid boot device '%c'", *p); 90 return; 91 } 92 if (bitmap & (1 << (*p - 'a'))) { 93 error_setg(errp, "Boot device '%c' was given twice", *p); 94 return; 95 } 96 bitmap |= 1 << (*p - 'a'); 97 } 98} 99 100void restore_boot_order(void *opaque) 101{ 102 char *normal_boot_order = opaque; 103 static int first = 1; 104 105 /* Restore boot order and remove ourselves after the first boot */ 106 if (first) { 107 first = 0; 108 return; 109 } 110 111 if (boot_set_handler) { 112 qemu_boot_set(normal_boot_order, &error_abort); 113 } 114 115 qemu_unregister_reset(restore_boot_order, normal_boot_order); 116 g_free(normal_boot_order); 117} 118 119void check_boot_index(int32_t bootindex, Error **errp) 120{ 121 FWBootEntry *i; 122 123 if (bootindex >= 0) { 124 QTAILQ_FOREACH(i, &fw_boot_order, link) { 125 if (i->bootindex == bootindex) { 126 error_setg(errp, "The bootindex %d has already been used", 127 bootindex); 128 return; 129 } 130 } 131 } 132} 133 134void del_boot_device_path(DeviceState *dev, const char *suffix) 135{ 136 FWBootEntry *i; 137 138 if (dev == NULL) { 139 return; 140 } 141 142 QTAILQ_FOREACH(i, &fw_boot_order, link) { 143 if ((!suffix || !g_strcmp0(i->suffix, suffix)) && 144 i->dev == dev) { 145 QTAILQ_REMOVE(&fw_boot_order, i, link); 146 g_free(i->suffix); 147 g_free(i); 148 149 break; 150 } 151 } 152} 153 154void add_boot_device_path(int32_t bootindex, DeviceState *dev, 155 const char *suffix) 156{ 157 FWBootEntry *node, *i; 158 159 if (bootindex < 0) { 160 del_boot_device_path(dev, suffix); 161 return; 162 } 163 164 assert(dev != NULL || suffix != NULL); 165 166 del_boot_device_path(dev, suffix); 167 168 node = g_malloc0(sizeof(FWBootEntry)); 169 node->bootindex = bootindex; 170 node->suffix = g_strdup(suffix); 171 node->dev = dev; 172 173 QTAILQ_FOREACH(i, &fw_boot_order, link) { 174 if (i->bootindex == bootindex) { 175 error_report("Two devices with same boot index %d", bootindex); 176 exit(1); 177 } else if (i->bootindex < bootindex) { 178 continue; 179 } 180 QTAILQ_INSERT_BEFORE(i, node, link); 181 return; 182 } 183 QTAILQ_INSERT_TAIL(&fw_boot_order, node, link); 184} 185 186DeviceState *get_boot_device(uint32_t position) 187{ 188 uint32_t counter = 0; 189 FWBootEntry *i = NULL; 190 DeviceState *res = NULL; 191 192 if (!QTAILQ_EMPTY(&fw_boot_order)) { 193 QTAILQ_FOREACH(i, &fw_boot_order, link) { 194 if (counter == position) { 195 res = i->dev; 196 break; 197 } 198 counter++; 199 } 200 } 201 return res; 202} 203 204/* 205 * This function returns null terminated string that consist of new line 206 * separated device paths. 207 * 208 * memory pointed by "size" is assigned total length of the array in bytes 209 * 210 */ 211char *get_boot_devices_list(size_t *size, bool ignore_suffixes) 212{ 213 FWBootEntry *i; 214 size_t total = 0; 215 char *list = NULL; 216 217 QTAILQ_FOREACH(i, &fw_boot_order, link) { 218 char *devpath = NULL, *suffix = NULL; 219 char *bootpath; 220 char *d; 221 size_t len; 222 223 if (i->dev) { 224 devpath = qdev_get_fw_dev_path(i->dev); 225 assert(devpath); 226 } 227 228 if (!ignore_suffixes) { 229 if (i->dev) { 230 d = qdev_get_own_fw_dev_path_from_handler(i->dev->parent_bus, 231 i->dev); 232 if (d) { 233 assert(!i->suffix); 234 suffix = d; 235 } else { 236 suffix = g_strdup(i->suffix); 237 } 238 } else { 239 suffix = g_strdup(i->suffix); 240 } 241 } 242 243 bootpath = g_strdup_printf("%s%s", 244 devpath ? devpath : "", 245 suffix ? suffix : ""); 246 g_free(devpath); 247 g_free(suffix); 248 249 if (total) { 250 list[total-1] = '\n'; 251 } 252 len = strlen(bootpath) + 1; 253 list = g_realloc(list, total + len); 254 memcpy(&list[total], bootpath, len); 255 total += len; 256 g_free(bootpath); 257 } 258 259 *size = total; 260 261 if (boot_strict && *size > 0) { 262 list[total-1] = '\n'; 263 list = g_realloc(list, total + 5); 264 memcpy(&list[total], "HALT", 5); 265 *size = total + 5; 266 } 267 return list; 268} 269 270typedef struct { 271 int32_t *bootindex; 272 const char *suffix; 273 DeviceState *dev; 274} BootIndexProperty; 275 276static void device_get_bootindex(Object *obj, Visitor *v, const char *name, 277 void *opaque, Error **errp) 278{ 279 BootIndexProperty *prop = opaque; 280 visit_type_int32(v, name, prop->bootindex, errp); 281} 282 283static void device_set_bootindex(Object *obj, Visitor *v, const char *name, 284 void *opaque, Error **errp) 285{ 286 BootIndexProperty *prop = opaque; 287 int32_t boot_index; 288 Error *local_err = NULL; 289 290 visit_type_int32(v, name, &boot_index, &local_err); 291 if (local_err) { 292 goto out; 293 } 294 /* check whether bootindex is present in fw_boot_order list */ 295 check_boot_index(boot_index, &local_err); 296 if (local_err) { 297 goto out; 298 } 299 /* change bootindex to a new one */ 300 *prop->bootindex = boot_index; 301 302 add_boot_device_path(*prop->bootindex, prop->dev, prop->suffix); 303 304out: 305 error_propagate(errp, local_err); 306} 307 308static void property_release_bootindex(Object *obj, const char *name, 309 void *opaque) 310 311{ 312 BootIndexProperty *prop = opaque; 313 314 del_boot_device_path(prop->dev, prop->suffix); 315 g_free(prop); 316} 317 318void device_add_bootindex_property(Object *obj, int32_t *bootindex, 319 const char *name, const char *suffix, 320 DeviceState *dev, Error **errp) 321{ 322 Error *local_err = NULL; 323 BootIndexProperty *prop = g_malloc0(sizeof(*prop)); 324 325 prop->bootindex = bootindex; 326 prop->suffix = suffix; 327 prop->dev = dev; 328 329 object_property_add(obj, name, "int32", 330 device_get_bootindex, 331 device_set_bootindex, 332 property_release_bootindex, 333 prop, &local_err); 334 335 if (local_err) { 336 error_propagate(errp, local_err); 337 g_free(prop); 338 return; 339 } 340 /* initialize devices' bootindex property to -1 */ 341 object_property_set_int(obj, -1, name, NULL); 342}