qemu/hw/nvram/spapr_nvram.c
<<
>>
Prefs
   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 <libfdt.h>
  26
  27#include "sysemu/device_tree.h"
  28#include "hw/sysbus.h"
  29#include "hw/ppc/spapr.h"
  30#include "hw/ppc/spapr_vio.h"
  31
  32typedef struct sPAPRNVRAM {
  33    VIOsPAPRDevice sdev;
  34    uint32_t size;
  35    uint8_t *buf;
  36    BlockDriverState *drive;
  37} sPAPRNVRAM;
  38
  39#define TYPE_VIO_SPAPR_NVRAM "spapr-nvram"
  40#define VIO_SPAPR_NVRAM(obj) \
  41     OBJECT_CHECK(sPAPRNVRAM, (obj), TYPE_VIO_SPAPR_NVRAM)
  42
  43#define MIN_NVRAM_SIZE 8192
  44#define DEFAULT_NVRAM_SIZE 65536
  45#define MAX_NVRAM_SIZE (UINT16_MAX * 16)
  46
  47static void rtas_nvram_fetch(PowerPCCPU *cpu, sPAPREnvironment *spapr,
  48                             uint32_t token, uint32_t nargs,
  49                             target_ulong args,
  50                             uint32_t nret, target_ulong rets)
  51{
  52    sPAPRNVRAM *nvram = spapr->nvram;
  53    hwaddr offset, buffer, len;
  54    int alen;
  55    void *membuf;
  56
  57    if ((nargs != 3) || (nret != 2)) {
  58        rtas_st(rets, 0, -3);
  59        return;
  60    }
  61
  62    if (!nvram) {
  63        rtas_st(rets, 0, -1);
  64        rtas_st(rets, 1, 0);
  65        return;
  66    }
  67
  68    offset = rtas_ld(args, 0);
  69    buffer = rtas_ld(args, 1);
  70    len = rtas_ld(args, 2);
  71
  72    if (((offset + len) < offset)
  73        || ((offset + len) > nvram->size)) {
  74        rtas_st(rets, 0, -3);
  75        rtas_st(rets, 1, 0);
  76        return;
  77    }
  78
  79    membuf = cpu_physical_memory_map(buffer, &len, 1);
  80    if (nvram->drive) {
  81        alen = bdrv_pread(nvram->drive, offset, membuf, len);
  82    } else {
  83        assert(nvram->buf);
  84
  85        memcpy(membuf, nvram->buf + offset, len);
  86        alen = len;
  87    }
  88    cpu_physical_memory_unmap(membuf, len, 1, len);
  89
  90    rtas_st(rets, 0, (alen < len) ? -1 : 0);
  91    rtas_st(rets, 1, (alen < 0) ? 0 : alen);
  92}
  93
  94static void rtas_nvram_store(PowerPCCPU *cpu, sPAPREnvironment *spapr,
  95                             uint32_t token, uint32_t nargs,
  96                             target_ulong args,
  97                             uint32_t nret, target_ulong rets)
  98{
  99    sPAPRNVRAM *nvram = spapr->nvram;
 100    hwaddr offset, buffer, len;
 101    int alen;
 102    void *membuf;
 103
 104    if ((nargs != 3) || (nret != 2)) {
 105        rtas_st(rets, 0, -3);
 106        return;
 107    }
 108
 109    if (!nvram) {
 110        rtas_st(rets, 0, -1);
 111        return;
 112    }
 113
 114    offset = rtas_ld(args, 0);
 115    buffer = rtas_ld(args, 1);
 116    len = rtas_ld(args, 2);
 117
 118    if (((offset + len) < offset)
 119        || ((offset + len) > nvram->size)) {
 120        rtas_st(rets, 0, -3);
 121        return;
 122    }
 123
 124    membuf = cpu_physical_memory_map(buffer, &len, 0);
 125    if (nvram->drive) {
 126        alen = bdrv_pwrite(nvram->drive, offset, membuf, len);
 127    } else {
 128        assert(nvram->buf);
 129
 130        memcpy(nvram->buf + offset, membuf, len);
 131        alen = len;
 132    }
 133    cpu_physical_memory_unmap(membuf, len, 0, len);
 134
 135    rtas_st(rets, 0, (alen < len) ? -1 : 0);
 136    rtas_st(rets, 1, (alen < 0) ? 0 : alen);
 137}
 138
 139static int spapr_nvram_init(VIOsPAPRDevice *dev)
 140{
 141    sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(dev);
 142
 143    if (nvram->drive) {
 144        nvram->size = bdrv_getlength(nvram->drive);
 145    } else {
 146        nvram->size = DEFAULT_NVRAM_SIZE;
 147        nvram->buf = g_malloc0(nvram->size);
 148    }
 149
 150    if ((nvram->size < MIN_NVRAM_SIZE) || (nvram->size > MAX_NVRAM_SIZE)) {
 151        fprintf(stderr, "spapr-nvram must be between %d and %d bytes in size\n",
 152                MIN_NVRAM_SIZE, MAX_NVRAM_SIZE);
 153        return -1;
 154    }
 155
 156    spapr_rtas_register("nvram-fetch", rtas_nvram_fetch);
 157    spapr_rtas_register("nvram-store", rtas_nvram_store);
 158
 159    return 0;
 160}
 161
 162static int spapr_nvram_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
 163{
 164    sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(dev);
 165
 166    return fdt_setprop_cell(fdt, node_off, "#bytes", nvram->size);
 167}
 168
 169static Property spapr_nvram_properties[] = {
 170    DEFINE_SPAPR_PROPERTIES(sPAPRNVRAM, sdev),
 171    DEFINE_PROP_DRIVE("drive", sPAPRNVRAM, drive),
 172    DEFINE_PROP_END_OF_LIST(),
 173};
 174
 175static void spapr_nvram_class_init(ObjectClass *klass, void *data)
 176{
 177    DeviceClass *dc = DEVICE_CLASS(klass);
 178    VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
 179
 180    k->init = spapr_nvram_init;
 181    k->devnode = spapr_nvram_devnode;
 182    k->dt_name = "nvram";
 183    k->dt_type = "nvram";
 184    k->dt_compatible = "qemu,spapr-nvram";
 185    dc->props = spapr_nvram_properties;
 186}
 187
 188static const TypeInfo spapr_nvram_type_info = {
 189    .name          = TYPE_VIO_SPAPR_NVRAM,
 190    .parent        = TYPE_VIO_SPAPR_DEVICE,
 191    .instance_size = sizeof(sPAPRNVRAM),
 192    .class_init    = spapr_nvram_class_init,
 193};
 194
 195static void spapr_nvram_register_types(void)
 196{
 197    type_register_static(&spapr_nvram_type_info);
 198}
 199
 200type_init(spapr_nvram_register_types)
 201