cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

bootdevice.c (11346B)


      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#include "hw/boards.h"
     33
     34typedef struct FWBootEntry FWBootEntry;
     35
     36struct FWBootEntry {
     37    QTAILQ_ENTRY(FWBootEntry) link;
     38    int32_t bootindex;
     39    DeviceState *dev;
     40    char *suffix;
     41};
     42
     43static QTAILQ_HEAD(, FWBootEntry) fw_boot_order =
     44    QTAILQ_HEAD_INITIALIZER(fw_boot_order);
     45static QEMUBootSetHandler *boot_set_handler;
     46static void *boot_set_opaque;
     47
     48void qemu_register_boot_set(QEMUBootSetHandler *func, void *opaque)
     49{
     50    boot_set_handler = func;
     51    boot_set_opaque = opaque;
     52}
     53
     54void qemu_boot_set(const char *boot_order, Error **errp)
     55{
     56    Error *local_err = NULL;
     57
     58    if (!boot_set_handler) {
     59        error_setg(errp, "no function defined to set boot device list for"
     60                         " this architecture");
     61        return;
     62    }
     63
     64    validate_bootdevices(boot_order, &local_err);
     65    if (local_err) {
     66        error_propagate(errp, local_err);
     67        return;
     68    }
     69
     70    boot_set_handler(boot_set_opaque, boot_order, errp);
     71}
     72
     73void validate_bootdevices(const char *devices, Error **errp)
     74{
     75    /* We just do some generic consistency checks */
     76    const char *p;
     77    int bitmap = 0;
     78
     79    for (p = devices; *p != '\0'; p++) {
     80        /* Allowed boot devices are:
     81         * a-b: floppy disk drives
     82         * c-f: IDE disk drives
     83         * g-m: machine implementation dependent drives
     84         * n-p: network devices
     85         * It's up to each machine implementation to check if the given boot
     86         * devices match the actual hardware implementation and firmware
     87         * features.
     88         */
     89        if (*p < 'a' || *p > 'p') {
     90            error_setg(errp, "Invalid boot device '%c'", *p);
     91            return;
     92        }
     93        if (bitmap & (1 << (*p - 'a'))) {
     94            error_setg(errp, "Boot device '%c' was given twice", *p);
     95            return;
     96        }
     97        bitmap |= 1 << (*p - 'a');
     98    }
     99}
    100
    101void restore_boot_order(void *opaque)
    102{
    103    char *normal_boot_order = opaque;
    104    static int first = 1;
    105
    106    /* Restore boot order and remove ourselves after the first boot */
    107    if (first) {
    108        first = 0;
    109        return;
    110    }
    111
    112    if (boot_set_handler) {
    113        qemu_boot_set(normal_boot_order, &error_abort);
    114    }
    115
    116    qemu_unregister_reset(restore_boot_order, normal_boot_order);
    117    g_free(normal_boot_order);
    118}
    119
    120void check_boot_index(int32_t bootindex, Error **errp)
    121{
    122    FWBootEntry *i;
    123
    124    if (bootindex >= 0) {
    125        QTAILQ_FOREACH(i, &fw_boot_order, link) {
    126            if (i->bootindex == bootindex) {
    127                error_setg(errp, "The bootindex %d has already been used",
    128                           bootindex);
    129                return;
    130            }
    131        }
    132    }
    133}
    134
    135void del_boot_device_path(DeviceState *dev, const char *suffix)
    136{
    137    FWBootEntry *i;
    138
    139    if (dev == NULL) {
    140        return;
    141    }
    142
    143    QTAILQ_FOREACH(i, &fw_boot_order, link) {
    144        if ((!suffix || !g_strcmp0(i->suffix, suffix)) &&
    145             i->dev == dev) {
    146            QTAILQ_REMOVE(&fw_boot_order, i, link);
    147            g_free(i->suffix);
    148            g_free(i);
    149
    150            break;
    151        }
    152    }
    153}
    154
    155void add_boot_device_path(int32_t bootindex, DeviceState *dev,
    156                          const char *suffix)
    157{
    158    FWBootEntry *node, *i;
    159
    160    if (bootindex < 0) {
    161        del_boot_device_path(dev, suffix);
    162        return;
    163    }
    164
    165    assert(dev != NULL || suffix != NULL);
    166
    167    del_boot_device_path(dev, suffix);
    168
    169    node = g_malloc0(sizeof(FWBootEntry));
    170    node->bootindex = bootindex;
    171    node->suffix = g_strdup(suffix);
    172    node->dev = dev;
    173
    174    QTAILQ_FOREACH(i, &fw_boot_order, link) {
    175        if (i->bootindex == bootindex) {
    176            error_report("Two devices with same boot index %d", bootindex);
    177            exit(1);
    178        } else if (i->bootindex < bootindex) {
    179            continue;
    180        }
    181        QTAILQ_INSERT_BEFORE(i, node, link);
    182        return;
    183    }
    184    QTAILQ_INSERT_TAIL(&fw_boot_order, node, link);
    185}
    186
    187DeviceState *get_boot_device(uint32_t position)
    188{
    189    uint32_t counter = 0;
    190    FWBootEntry *i = NULL;
    191    DeviceState *res = NULL;
    192
    193    if (!QTAILQ_EMPTY(&fw_boot_order)) {
    194        QTAILQ_FOREACH(i, &fw_boot_order, link) {
    195            if (counter == position) {
    196                res = i->dev;
    197                break;
    198            }
    199            counter++;
    200        }
    201    }
    202    return res;
    203}
    204
    205static char *get_boot_device_path(DeviceState *dev, bool ignore_suffixes,
    206                                  const char *suffix)
    207{
    208    char *devpath = NULL, *s = NULL, *d, *bootpath;
    209
    210    if (dev) {
    211        devpath = qdev_get_fw_dev_path(dev);
    212        assert(devpath);
    213    }
    214
    215    if (!ignore_suffixes) {
    216        if (dev) {
    217            d = qdev_get_own_fw_dev_path_from_handler(dev->parent_bus, dev);
    218            if (d) {
    219                assert(!suffix);
    220                s = d;
    221            } else {
    222                s = g_strdup(suffix);
    223            }
    224        } else {
    225            s = g_strdup(suffix);
    226        }
    227    }
    228
    229    bootpath = g_strdup_printf("%s%s",
    230                               devpath ? devpath : "",
    231                               s ? s : "");
    232    g_free(devpath);
    233    g_free(s);
    234
    235    return bootpath;
    236}
    237
    238/*
    239 * This function returns null terminated string that consist of new line
    240 * separated device paths.
    241 *
    242 * memory pointed by "size" is assigned total length of the array in bytes
    243 *
    244 */
    245char *get_boot_devices_list(size_t *size)
    246{
    247    FWBootEntry *i;
    248    size_t total = 0;
    249    char *list = NULL;
    250    MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
    251    bool ignore_suffixes = mc->ignore_boot_device_suffixes;
    252
    253    QTAILQ_FOREACH(i, &fw_boot_order, link) {
    254        char *bootpath;
    255        size_t len;
    256
    257        bootpath = get_boot_device_path(i->dev, ignore_suffixes, i->suffix);
    258
    259        if (total) {
    260            list[total-1] = '\n';
    261        }
    262        len = strlen(bootpath) + 1;
    263        list = g_realloc(list, total + len);
    264        memcpy(&list[total], bootpath, len);
    265        total += len;
    266        g_free(bootpath);
    267    }
    268
    269    *size = total;
    270
    271    if (boot_strict && *size > 0) {
    272        list[total-1] = '\n';
    273        list = g_realloc(list, total + 5);
    274        memcpy(&list[total], "HALT", 5);
    275        *size = total + 5;
    276    }
    277    return list;
    278}
    279
    280typedef struct {
    281    int32_t *bootindex;
    282    const char *suffix;
    283    DeviceState *dev;
    284} BootIndexProperty;
    285
    286static void device_get_bootindex(Object *obj, Visitor *v, const char *name,
    287                                 void *opaque, Error **errp)
    288{
    289    BootIndexProperty *prop = opaque;
    290    visit_type_int32(v, name, prop->bootindex, errp);
    291}
    292
    293static void device_set_bootindex(Object *obj, Visitor *v, const char *name,
    294                                 void *opaque, Error **errp)
    295{
    296    BootIndexProperty *prop = opaque;
    297    int32_t boot_index;
    298    Error *local_err = NULL;
    299
    300    if (!visit_type_int32(v, name, &boot_index, errp)) {
    301        return;
    302    }
    303    /* check whether bootindex is present in fw_boot_order list  */
    304    check_boot_index(boot_index, &local_err);
    305    if (local_err) {
    306        error_propagate(errp, local_err);
    307        return;
    308    }
    309    /* change bootindex to a new one */
    310    *prop->bootindex = boot_index;
    311
    312    add_boot_device_path(*prop->bootindex, prop->dev, prop->suffix);
    313}
    314
    315static void property_release_bootindex(Object *obj, const char *name,
    316                                       void *opaque)
    317
    318{
    319    BootIndexProperty *prop = opaque;
    320
    321    del_boot_device_path(prop->dev, prop->suffix);
    322    g_free(prop);
    323}
    324
    325void device_add_bootindex_property(Object *obj, int32_t *bootindex,
    326                                   const char *name, const char *suffix,
    327                                   DeviceState *dev)
    328{
    329    BootIndexProperty *prop = g_malloc0(sizeof(*prop));
    330
    331    prop->bootindex = bootindex;
    332    prop->suffix = suffix;
    333    prop->dev = dev;
    334
    335    object_property_add(obj, name, "int32",
    336                        device_get_bootindex,
    337                        device_set_bootindex,
    338                        property_release_bootindex,
    339                        prop);
    340
    341    /* initialize devices' bootindex property to -1 */
    342    object_property_set_int(obj, name, -1, NULL);
    343}
    344
    345typedef struct FWLCHSEntry FWLCHSEntry;
    346
    347struct FWLCHSEntry {
    348    QTAILQ_ENTRY(FWLCHSEntry) link;
    349    DeviceState *dev;
    350    char *suffix;
    351    uint32_t lcyls;
    352    uint32_t lheads;
    353    uint32_t lsecs;
    354};
    355
    356static QTAILQ_HEAD(, FWLCHSEntry) fw_lchs =
    357    QTAILQ_HEAD_INITIALIZER(fw_lchs);
    358
    359void add_boot_device_lchs(DeviceState *dev, const char *suffix,
    360                          uint32_t lcyls, uint32_t lheads, uint32_t lsecs)
    361{
    362    FWLCHSEntry *node;
    363
    364    if (!lcyls && !lheads && !lsecs) {
    365        return;
    366    }
    367
    368    assert(dev != NULL || suffix != NULL);
    369
    370    node = g_malloc0(sizeof(FWLCHSEntry));
    371    node->suffix = g_strdup(suffix);
    372    node->dev = dev;
    373    node->lcyls = lcyls;
    374    node->lheads = lheads;
    375    node->lsecs = lsecs;
    376
    377    QTAILQ_INSERT_TAIL(&fw_lchs, node, link);
    378}
    379
    380void del_boot_device_lchs(DeviceState *dev, const char *suffix)
    381{
    382    FWLCHSEntry *i;
    383
    384    if (dev == NULL) {
    385        return;
    386    }
    387
    388    QTAILQ_FOREACH(i, &fw_lchs, link) {
    389        if ((!suffix || !g_strcmp0(i->suffix, suffix)) &&
    390             i->dev == dev) {
    391            QTAILQ_REMOVE(&fw_lchs, i, link);
    392            g_free(i->suffix);
    393            g_free(i);
    394
    395            break;
    396        }
    397    }
    398}
    399
    400char *get_boot_devices_lchs_list(size_t *size)
    401{
    402    FWLCHSEntry *i;
    403    size_t total = 0;
    404    char *list = NULL;
    405
    406    QTAILQ_FOREACH(i, &fw_lchs, link) {
    407        char *bootpath;
    408        char *chs_string;
    409        size_t len;
    410
    411        bootpath = get_boot_device_path(i->dev, false, i->suffix);
    412        chs_string = g_strdup_printf("%s %" PRIu32 " %" PRIu32 " %" PRIu32,
    413                                     bootpath, i->lcyls, i->lheads, i->lsecs);
    414
    415        if (total) {
    416            list[total - 1] = '\n';
    417        }
    418        len = strlen(chs_string) + 1;
    419        list = g_realloc(list, total + len);
    420        memcpy(&list[total], chs_string, len);
    421        total += len;
    422        g_free(chs_string);
    423        g_free(bootpath);
    424    }
    425
    426    *size = total;
    427
    428    return list;
    429}