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 32 typedef 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 47 static void rtas_nvram_fetch(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 94 static void rtas_nvram_store(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 139 static 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 162 static 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 169 static 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 175 static 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 188 static 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 195 static void spapr_nvram_register_types(void) 196 { 197 type_register_static(&spapr_nvram_type_info); 198 } 199 200 type_init(spapr_nvram_register_types) 201