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

generic-loader.c (7153B)


      1/*
      2 * Generic Loader
      3 *
      4 * Copyright (C) 2014 Li Guang
      5 * Copyright (C) 2016 Xilinx Inc.
      6 * Written by Li Guang <lig.fnst@cn.fujitsu.com>
      7 *
      8 * This program is free software; you can redistribute it and/or modify it
      9 * under the terms of the GNU General Public License as published by the
     10 * Free Software Foundation; either version 2 of the License, or
     11 * (at your option) any later version.
     12 *
     13 * This program is distributed in the hope that it will be useful, but WITHOUT
     14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
     16 * for more details.
     17 *
     18 */
     19
     20/*
     21 * Internally inside QEMU this is a device. It is a strange device that
     22 * provides no hardware interface but allows QEMU to monkey patch memory
     23 * specified when it is created. To be able to do this it has a reset
     24 * callback that does the memory operations.
     25
     26 * This device allows the user to monkey patch memory. To be able to do
     27 * this it needs a backend to manage the datas, the same as other
     28 * memory-related devices. In this case as the backend is so trivial we
     29 * have merged it with the frontend instead of creating and maintaining a
     30 * separate backend.
     31 */
     32
     33#include "qemu/osdep.h"
     34#include "hw/core/cpu.h"
     35#include "sysemu/dma.h"
     36#include "sysemu/reset.h"
     37#include "hw/boards.h"
     38#include "hw/loader.h"
     39#include "hw/qdev-properties.h"
     40#include "qapi/error.h"
     41#include "qemu/module.h"
     42#include "hw/core/generic-loader.h"
     43
     44#define CPU_NONE 0xFFFFFFFF
     45
     46static void generic_loader_reset(void *opaque)
     47{
     48    GenericLoaderState *s = GENERIC_LOADER(opaque);
     49
     50    if (s->set_pc) {
     51        CPUClass *cc = CPU_GET_CLASS(s->cpu);
     52        cpu_reset(s->cpu);
     53        if (cc) {
     54            cc->set_pc(s->cpu, s->addr);
     55        }
     56    }
     57
     58    if (s->data_len) {
     59        assert(s->data_len < sizeof(s->data));
     60        dma_memory_write(s->cpu->as, s->addr, &s->data, s->data_len);
     61    }
     62}
     63
     64static void generic_loader_realize(DeviceState *dev, Error **errp)
     65{
     66    GenericLoaderState *s = GENERIC_LOADER(dev);
     67    hwaddr entry;
     68    int big_endian;
     69    int size = 0;
     70
     71    s->set_pc = false;
     72
     73    /* Perform some error checking on the user's options */
     74    if (s->data || s->data_len  || s->data_be) {
     75        /* User is loading memory values */
     76        if (s->file) {
     77            error_setg(errp, "Specifying a file is not supported when loading "
     78                       "memory values");
     79            return;
     80        } else if (s->force_raw) {
     81            error_setg(errp, "Specifying force-raw is not supported when "
     82                       "loading memory values");
     83            return;
     84        } else if (!s->data_len) {
     85            /* We can't check for !data here as a value of 0 is still valid. */
     86            error_setg(errp, "Both data and data-len must be specified");
     87            return;
     88        } else if (s->data_len > 8) {
     89            error_setg(errp, "data-len cannot be greater then 8 bytes");
     90            return;
     91        }
     92    } else if (s->file || s->force_raw)  {
     93        /* User is loading an image */
     94        if (s->data || s->data_len || s->data_be) {
     95            error_setg(errp, "data can not be specified when loading an "
     96                       "image");
     97            return;
     98        }
     99        /* The user specified a file, only set the PC if they also specified
    100         * a CPU to use.
    101         */
    102        if (s->cpu_num != CPU_NONE) {
    103            s->set_pc = true;
    104        }
    105    } else if (s->addr) {
    106        /* User is setting the PC */
    107        if (s->data || s->data_len || s->data_be) {
    108            error_setg(errp, "data can not be specified when setting a "
    109                       "program counter");
    110            return;
    111        } else if (s->cpu_num == CPU_NONE) {
    112            error_setg(errp, "cpu_num must be specified when setting a "
    113                       "program counter");
    114            return;
    115        }
    116        s->set_pc = true;
    117    } else {
    118        /* Did the user specify anything? */
    119        error_setg(errp, "please include valid arguments");
    120        return;
    121    }
    122
    123    qemu_register_reset(generic_loader_reset, dev);
    124
    125    if (s->cpu_num != CPU_NONE) {
    126        s->cpu = qemu_get_cpu(s->cpu_num);
    127        if (!s->cpu) {
    128            error_setg(errp, "Specified boot CPU#%d is nonexistent",
    129                       s->cpu_num);
    130            return;
    131        }
    132    } else {
    133        s->cpu = first_cpu;
    134    }
    135
    136    big_endian = target_words_bigendian();
    137
    138    if (s->file) {
    139        AddressSpace *as = s->cpu ? s->cpu->as :  NULL;
    140
    141        if (!s->force_raw) {
    142            size = load_elf_as(s->file, NULL, NULL, NULL, &entry, NULL, NULL,
    143                               NULL, big_endian, 0, 0, 0, as);
    144
    145            if (size < 0) {
    146                size = load_uimage_as(s->file, &entry, NULL, NULL, NULL, NULL,
    147                                      as);
    148            }
    149
    150            if (size < 0) {
    151                size = load_targphys_hex_as(s->file, &entry, as);
    152            }
    153        }
    154
    155        if (size < 0 || s->force_raw) {
    156            /* Default to the maximum size being the machine's ram size */
    157            size = load_image_targphys_as(s->file, s->addr, current_machine->ram_size, as);
    158        } else {
    159            s->addr = entry;
    160        }
    161
    162        if (size < 0) {
    163            error_setg(errp, "Cannot load specified image %s", s->file);
    164            return;
    165        }
    166    }
    167
    168    /* Convert the data endiannes */
    169    if (s->data_be) {
    170        s->data = cpu_to_be64(s->data);
    171    } else {
    172        s->data = cpu_to_le64(s->data);
    173    }
    174}
    175
    176static void generic_loader_unrealize(DeviceState *dev)
    177{
    178    qemu_unregister_reset(generic_loader_reset, dev);
    179}
    180
    181static Property generic_loader_props[] = {
    182    DEFINE_PROP_UINT64("addr", GenericLoaderState, addr, 0),
    183    DEFINE_PROP_UINT64("data", GenericLoaderState, data, 0),
    184    DEFINE_PROP_UINT8("data-len", GenericLoaderState, data_len, 0),
    185    DEFINE_PROP_BOOL("data-be", GenericLoaderState, data_be, false),
    186    DEFINE_PROP_UINT32("cpu-num", GenericLoaderState, cpu_num, CPU_NONE),
    187    DEFINE_PROP_BOOL("force-raw", GenericLoaderState, force_raw, false),
    188    DEFINE_PROP_STRING("file", GenericLoaderState, file),
    189    DEFINE_PROP_END_OF_LIST(),
    190};
    191
    192static void generic_loader_class_init(ObjectClass *klass, void *data)
    193{
    194    DeviceClass *dc = DEVICE_CLASS(klass);
    195
    196    /* The reset function is not registered here and is instead registered in
    197     * the realize function to allow this device to be added via the device_add
    198     * command in the QEMU monitor.
    199     * TODO: Improve the device_add functionality to allow resets to be
    200     * connected
    201     */
    202    dc->realize = generic_loader_realize;
    203    dc->unrealize = generic_loader_unrealize;
    204    device_class_set_props(dc, generic_loader_props);
    205    dc->desc = "Generic Loader";
    206    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
    207}
    208
    209static TypeInfo generic_loader_info = {
    210    .name = TYPE_GENERIC_LOADER,
    211    .parent = TYPE_DEVICE,
    212    .instance_size = sizeof(GenericLoaderState),
    213    .class_init = generic_loader_class_init,
    214};
    215
    216static void generic_loader_register_type(void)
    217{
    218    type_register_static(&generic_loader_info);
    219}
    220
    221type_init(generic_loader_register_type)