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

spapr_nvram.c (8574B)


      1/*
      2 * QEMU sPAPR NVRAM emulation
      3 *
      4 * Copyright (C) 2012 David Gibson, IBM Corporation.
      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 "qemu/module.h"
     27#include "qemu/units.h"
     28#include "qapi/error.h"
     29#include <libfdt.h>
     30
     31#include "sysemu/block-backend.h"
     32#include "sysemu/device_tree.h"
     33#include "sysemu/sysemu.h"
     34#include "sysemu/runstate.h"
     35#include "migration/vmstate.h"
     36#include "hw/nvram/chrp_nvram.h"
     37#include "hw/ppc/spapr.h"
     38#include "hw/ppc/spapr_vio.h"
     39#include "hw/qdev-properties.h"
     40#include "hw/qdev-properties-system.h"
     41#include "qom/object.h"
     42
     43struct SpaprNvram {
     44    SpaprVioDevice sdev;
     45    uint32_t size;
     46    uint8_t *buf;
     47    BlockBackend *blk;
     48    VMChangeStateEntry *vmstate;
     49};
     50
     51#define TYPE_VIO_SPAPR_NVRAM "spapr-nvram"
     52OBJECT_DECLARE_SIMPLE_TYPE(SpaprNvram, VIO_SPAPR_NVRAM)
     53
     54#define MIN_NVRAM_SIZE      (8 * KiB)
     55#define DEFAULT_NVRAM_SIZE  (64 * KiB)
     56#define MAX_NVRAM_SIZE      (1 * MiB)
     57
     58static void rtas_nvram_fetch(PowerPCCPU *cpu, SpaprMachineState *spapr,
     59                             uint32_t token, uint32_t nargs,
     60                             target_ulong args,
     61                             uint32_t nret, target_ulong rets)
     62{
     63    SpaprNvram *nvram = spapr->nvram;
     64    hwaddr offset, buffer, len;
     65    void *membuf;
     66
     67    if ((nargs != 3) || (nret != 2)) {
     68        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
     69        return;
     70    }
     71
     72    if (!nvram) {
     73        rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
     74        rtas_st(rets, 1, 0);
     75        return;
     76    }
     77
     78    offset = rtas_ld(args, 0);
     79    buffer = rtas_ld(args, 1);
     80    len = rtas_ld(args, 2);
     81
     82    if (((offset + len) < offset)
     83        || ((offset + len) > nvram->size)) {
     84        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
     85        rtas_st(rets, 1, 0);
     86        return;
     87    }
     88
     89    assert(nvram->buf);
     90
     91    membuf = cpu_physical_memory_map(buffer, &len, true);
     92    memcpy(membuf, nvram->buf + offset, len);
     93    cpu_physical_memory_unmap(membuf, len, 1, len);
     94
     95    rtas_st(rets, 0, RTAS_OUT_SUCCESS);
     96    rtas_st(rets, 1, len);
     97}
     98
     99static void rtas_nvram_store(PowerPCCPU *cpu, SpaprMachineState *spapr,
    100                             uint32_t token, uint32_t nargs,
    101                             target_ulong args,
    102                             uint32_t nret, target_ulong rets)
    103{
    104    SpaprNvram *nvram = spapr->nvram;
    105    hwaddr offset, buffer, len;
    106    int alen;
    107    void *membuf;
    108
    109    if ((nargs != 3) || (nret != 2)) {
    110        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
    111        return;
    112    }
    113
    114    if (!nvram) {
    115        rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
    116        return;
    117    }
    118
    119    offset = rtas_ld(args, 0);
    120    buffer = rtas_ld(args, 1);
    121    len = rtas_ld(args, 2);
    122
    123    if (((offset + len) < offset)
    124        || ((offset + len) > nvram->size)) {
    125        rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
    126        return;
    127    }
    128
    129    membuf = cpu_physical_memory_map(buffer, &len, false);
    130
    131    alen = len;
    132    if (nvram->blk) {
    133        alen = blk_pwrite(nvram->blk, offset, membuf, len, 0);
    134    }
    135
    136    assert(nvram->buf);
    137    memcpy(nvram->buf + offset, membuf, len);
    138
    139    cpu_physical_memory_unmap(membuf, len, 0, len);
    140
    141    rtas_st(rets, 0, (alen < len) ? RTAS_OUT_HW_ERROR : RTAS_OUT_SUCCESS);
    142    rtas_st(rets, 1, (alen < 0) ? 0 : alen);
    143}
    144
    145static void spapr_nvram_realize(SpaprVioDevice *dev, Error **errp)
    146{
    147    SpaprNvram *nvram = VIO_SPAPR_NVRAM(dev);
    148    int ret;
    149
    150    if (nvram->blk) {
    151        int64_t len = blk_getlength(nvram->blk);
    152
    153        if (len < 0) {
    154            error_setg_errno(errp, -len,
    155                             "could not get length of backing image");
    156            return;
    157        }
    158
    159        nvram->size = len;
    160
    161        ret = blk_set_perm(nvram->blk,
    162                           BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
    163                           BLK_PERM_ALL, errp);
    164        if (ret < 0) {
    165            return;
    166        }
    167    } else {
    168        nvram->size = DEFAULT_NVRAM_SIZE;
    169    }
    170
    171    nvram->buf = g_malloc0(nvram->size);
    172
    173    if ((nvram->size < MIN_NVRAM_SIZE) || (nvram->size > MAX_NVRAM_SIZE)) {
    174        error_setg(errp,
    175                   "spapr-nvram must be between %" PRId64
    176                   " and %" PRId64 " bytes in size",
    177                   MIN_NVRAM_SIZE, MAX_NVRAM_SIZE);
    178        return;
    179    }
    180
    181    if (nvram->blk) {
    182        int alen = blk_pread(nvram->blk, 0, nvram->buf, nvram->size);
    183
    184        if (alen != nvram->size) {
    185            error_setg(errp, "can't read spapr-nvram contents");
    186            return;
    187        }
    188    } else if (nb_prom_envs > 0) {
    189        /* Create a system partition to pass the -prom-env variables */
    190        chrp_nvram_create_system_partition(nvram->buf, MIN_NVRAM_SIZE / 4,
    191                                           nvram->size);
    192        chrp_nvram_create_free_partition(&nvram->buf[MIN_NVRAM_SIZE / 4],
    193                                         nvram->size - MIN_NVRAM_SIZE / 4);
    194    }
    195
    196    spapr_rtas_register(RTAS_NVRAM_FETCH, "nvram-fetch", rtas_nvram_fetch);
    197    spapr_rtas_register(RTAS_NVRAM_STORE, "nvram-store", rtas_nvram_store);
    198}
    199
    200static int spapr_nvram_devnode(SpaprVioDevice *dev, void *fdt, int node_off)
    201{
    202    SpaprNvram *nvram = VIO_SPAPR_NVRAM(dev);
    203
    204    return fdt_setprop_cell(fdt, node_off, "#bytes", nvram->size);
    205}
    206
    207static int spapr_nvram_pre_load(void *opaque)
    208{
    209    SpaprNvram *nvram = VIO_SPAPR_NVRAM(opaque);
    210
    211    g_free(nvram->buf);
    212    nvram->buf = NULL;
    213    nvram->size = 0;
    214
    215    return 0;
    216}
    217
    218static void postload_update_cb(void *opaque, bool running, RunState state)
    219{
    220    SpaprNvram *nvram = opaque;
    221
    222    /* This is called after bdrv_invalidate_cache_all.  */
    223
    224    qemu_del_vm_change_state_handler(nvram->vmstate);
    225    nvram->vmstate = NULL;
    226
    227    blk_pwrite(nvram->blk, 0, nvram->buf, nvram->size, 0);
    228}
    229
    230static int spapr_nvram_post_load(void *opaque, int version_id)
    231{
    232    SpaprNvram *nvram = VIO_SPAPR_NVRAM(opaque);
    233
    234    if (nvram->blk) {
    235        nvram->vmstate = qemu_add_vm_change_state_handler(postload_update_cb,
    236                                                          nvram);
    237    }
    238
    239    return 0;
    240}
    241
    242static const VMStateDescription vmstate_spapr_nvram = {
    243    .name = "spapr_nvram",
    244    .version_id = 1,
    245    .minimum_version_id = 1,
    246    .pre_load = spapr_nvram_pre_load,
    247    .post_load = spapr_nvram_post_load,
    248    .fields = (VMStateField[]) {
    249        VMSTATE_UINT32(size, SpaprNvram),
    250        VMSTATE_VBUFFER_ALLOC_UINT32(buf, SpaprNvram, 1, NULL, size),
    251        VMSTATE_END_OF_LIST()
    252    },
    253};
    254
    255static Property spapr_nvram_properties[] = {
    256    DEFINE_SPAPR_PROPERTIES(SpaprNvram, sdev),
    257    DEFINE_PROP_DRIVE("drive", SpaprNvram, blk),
    258    DEFINE_PROP_END_OF_LIST(),
    259};
    260
    261static void spapr_nvram_class_init(ObjectClass *klass, void *data)
    262{
    263    DeviceClass *dc = DEVICE_CLASS(klass);
    264    SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
    265
    266    k->realize = spapr_nvram_realize;
    267    k->devnode = spapr_nvram_devnode;
    268    k->dt_name = "nvram";
    269    k->dt_type = "nvram";
    270    k->dt_compatible = "qemu,spapr-nvram";
    271    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
    272    device_class_set_props(dc, spapr_nvram_properties);
    273    dc->vmsd = &vmstate_spapr_nvram;
    274    /* Reason: Internal device only, uses spapr_rtas_register() in realize() */
    275    dc->user_creatable = false;
    276}
    277
    278static const TypeInfo spapr_nvram_type_info = {
    279    .name          = TYPE_VIO_SPAPR_NVRAM,
    280    .parent        = TYPE_VIO_SPAPR_DEVICE,
    281    .instance_size = sizeof(SpaprNvram),
    282    .class_init    = spapr_nvram_class_init,
    283};
    284
    285static void spapr_nvram_register_types(void)
    286{
    287    type_register_static(&spapr_nvram_type_info);
    288}
    289
    290type_init(spapr_nvram_register_types)