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

guest-loader.c (4942B)


      1/*
      2 * Guest Loader
      3 *
      4 * Copyright (C) 2020 Linaro
      5 * Written by Alex Bennée <alex.bennee@linaro.org>
      6 * (based on the generic-loader by Li Guang <lig.fnst@cn.fujitsu.com>)
      7 *
      8 * SPDX-License-Identifier: GPL-2.0-or-later
      9 *
     10 * This work is licensed under the terms of the GNU GPL, version 2 or later.
     11 * See the COPYING file in the top-level directory.
     12 */
     13
     14/*
     15 * Much like the generic-loader this is treated as a special device
     16 * inside QEMU. However unlike the generic-loader this device is used
     17 * to load guest images for hypervisors. As part of that process the
     18 * hypervisor needs to have platform information passed to it by the
     19 * lower levels of the stack (e.g. firmware/bootloader). If you boot
     20 * the hypervisor directly you use the guest-loader to load the Dom0
     21 * or equivalent guest images in the right place in the same way a
     22 * boot loader would.
     23 *
     24 * This is only relevant for full system emulation.
     25 */
     26
     27#include "qemu/osdep.h"
     28#include "hw/core/cpu.h"
     29#include "sysemu/dma.h"
     30#include "hw/loader.h"
     31#include "hw/qdev-properties.h"
     32#include "qapi/error.h"
     33#include "qemu/module.h"
     34#include "guest-loader.h"
     35#include "sysemu/device_tree.h"
     36#include "hw/boards.h"
     37
     38/*
     39 * Insert some FDT nodes for the loaded blob.
     40 */
     41static void loader_insert_platform_data(GuestLoaderState *s, int size,
     42                                        Error **errp)
     43{
     44    MachineState *machine = MACHINE(qdev_get_machine());
     45    void *fdt = machine->fdt;
     46    g_autofree char *node = g_strdup_printf("/chosen/module@0x%08" PRIx64,
     47                                            s->addr);
     48    uint64_t reg_attr[2] = {cpu_to_be64(s->addr), cpu_to_be64(size)};
     49
     50    if (!fdt) {
     51        error_setg(errp, "Cannot modify FDT fields if the machine has none");
     52        return;
     53    }
     54
     55    qemu_fdt_add_subnode(fdt, node);
     56    qemu_fdt_setprop(fdt, node, "reg", &reg_attr, sizeof(reg_attr));
     57
     58    if (s->kernel) {
     59        const char *compat[2] = { "multiboot,module", "multiboot,kernel" };
     60        if (qemu_fdt_setprop_string_array(fdt, node, "compatible",
     61                                          (char **) &compat,
     62                                          ARRAY_SIZE(compat)) < 0) {
     63            error_setg(errp, "couldn't set %s/compatible", node);
     64            return;
     65        }
     66        if (s->args) {
     67            if (qemu_fdt_setprop_string(fdt, node, "bootargs", s->args) < 0) {
     68                error_setg(errp, "couldn't set %s/bootargs", node);
     69            }
     70        }
     71    } else if (s->initrd) {
     72        const char *compat[2] = { "multiboot,module", "multiboot,ramdisk" };
     73        if (qemu_fdt_setprop_string_array(fdt, node, "compatible",
     74                                          (char **) &compat,
     75                                          ARRAY_SIZE(compat)) < 0) {
     76            error_setg(errp, "couldn't set %s/compatible", node);
     77            return;
     78        }
     79    }
     80}
     81
     82static void guest_loader_realize(DeviceState *dev, Error **errp)
     83{
     84    GuestLoaderState *s = GUEST_LOADER(dev);
     85    char *file = s->kernel ? s->kernel : s->initrd;
     86    int size = 0;
     87
     88    /* Perform some error checking on the user's options */
     89    if (s->kernel && s->initrd) {
     90        error_setg(errp, "Cannot specify a kernel and initrd in same stanza");
     91        return;
     92    } else if (!s->kernel && !s->initrd)  {
     93        error_setg(errp, "Need to specify a kernel or initrd image");
     94        return;
     95    } else if (!s->addr) {
     96        error_setg(errp, "Need to specify the address of guest blob");
     97        return;
     98    } else if (s->args && !s->kernel) {
     99        error_setg(errp, "Boot args only relevant to kernel blobs");
    100    }
    101
    102    /* Default to the maximum size being the machine's ram size */
    103    size = load_image_targphys_as(file, s->addr, current_machine->ram_size,
    104                                  NULL);
    105    if (size < 0) {
    106        error_setg(errp, "Cannot load specified image %s", file);
    107        return;
    108    }
    109
    110    /* Now the image is loaded we need to update the platform data */
    111    loader_insert_platform_data(s, size, errp);
    112}
    113
    114static Property guest_loader_props[] = {
    115    DEFINE_PROP_UINT64("addr", GuestLoaderState, addr, 0),
    116    DEFINE_PROP_STRING("kernel", GuestLoaderState, kernel),
    117    DEFINE_PROP_STRING("bootargs", GuestLoaderState, args),
    118    DEFINE_PROP_STRING("initrd", GuestLoaderState, initrd),
    119    DEFINE_PROP_END_OF_LIST(),
    120};
    121
    122static void guest_loader_class_init(ObjectClass *klass, void *data)
    123{
    124    DeviceClass *dc = DEVICE_CLASS(klass);
    125
    126    dc->realize = guest_loader_realize;
    127    device_class_set_props(dc, guest_loader_props);
    128    dc->desc = "Guest Loader";
    129    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
    130}
    131
    132static TypeInfo guest_loader_info = {
    133    .name = TYPE_GUEST_LOADER,
    134    .parent = TYPE_DEVICE,
    135    .instance_size = sizeof(GuestLoaderState),
    136    .class_init = guest_loader_class_init,
    137};
    138
    139static void guest_loader_register_type(void)
    140{
    141    type_register_static(&guest_loader_info);
    142}
    143
    144type_init(guest_loader_register_type)