/* * QEMU Boot Device Implement * * Copyright (c) 2014 HUAWEI TECHNOLOGIES CO.,LTD. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "sysemu/sysemu.h" typedef struct FWBootEntry FWBootEntry; struct FWBootEntry { QTAILQ_ENTRY(FWBootEntry) link; int32_t bootindex; DeviceState *dev; char *suffix; }; static QTAILQ_HEAD(, FWBootEntry) fw_boot_order = QTAILQ_HEAD_INITIALIZER(fw_boot_order); void add_boot_device_path(int32_t bootindex, DeviceState *dev, const char *suffix) { FWBootEntry *node, *i; if (bootindex < 0) { return; } assert(dev != NULL || suffix != NULL); node = g_malloc0(sizeof(FWBootEntry)); node->bootindex = bootindex; node->suffix = g_strdup(suffix); node->dev = dev; QTAILQ_FOREACH(i, &fw_boot_order, link) { if (i->bootindex == bootindex) { fprintf(stderr, "Two devices with same boot index %d\n", bootindex); exit(1); } else if (i->bootindex < bootindex) { continue; } QTAILQ_INSERT_BEFORE(i, node, link); return; } QTAILQ_INSERT_TAIL(&fw_boot_order, node, link); } DeviceState *get_boot_device(uint32_t position) { uint32_t counter = 0; FWBootEntry *i = NULL; DeviceState *res = NULL; if (!QTAILQ_EMPTY(&fw_boot_order)) { QTAILQ_FOREACH(i, &fw_boot_order, link) { if (counter == position) { res = i->dev; break; } counter++; } } return res; } /* * This function returns null terminated string that consist of new line * separated device paths. * * memory pointed by "size" is assigned total length of the array in bytes * */ char *get_boot_devices_list(size_t *size, bool ignore_suffixes) { FWBootEntry *i; size_t total = 0; char *list = NULL; QTAILQ_FOREACH(i, &fw_boot_order, link) { char *devpath = NULL, *bootpath; size_t len; if (i->dev) { devpath = qdev_get_fw_dev_path(i->dev); assert(devpath); } if (i->suffix && !ignore_suffixes && devpath) { size_t bootpathlen = strlen(devpath) + strlen(i->suffix) + 1; bootpath = g_malloc(bootpathlen); snprintf(bootpath, bootpathlen, "%s%s", devpath, i->suffix); g_free(devpath); } else if (devpath) { bootpath = devpath; } else if (!ignore_suffixes) { assert(i->suffix); bootpath = g_strdup(i->suffix); } else { bootpath = g_strdup(""); } if (total) { list[total-1] = '\n'; } len = strlen(bootpath) + 1; list = g_realloc(list, total + len); memcpy(&list[total], bootpath, len); total += len; g_free(bootpath); } *size = total; if (boot_strict && *size > 0) { list[total-1] = '\n'; list = g_realloc(list, total + 5); memcpy(&list[total], "HALT", 5); *size = total + 5; } return list; }