1 /* 2 * QEMU NVRAM emulation for DS1225Y chip 3 * 4 * Copyright (c) 2007-2008 Hervé Poussineau 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 "hw/qdev-properties.h" 27 #include "hw/sysbus.h" 28 #include "migration/vmstate.h" 29 #include "trace.h" 30 #include "qemu/error-report.h" 31 #include "qemu/module.h" 32 33 typedef struct { 34 MemoryRegion iomem; 35 uint32_t chip_size; 36 char *filename; 37 FILE *file; 38 uint8_t *contents; 39 } NvRamState; 40 41 static uint64_t nvram_read(void *opaque, hwaddr addr, unsigned size) 42 { 43 NvRamState *s = opaque; 44 uint32_t val; 45 46 val = s->contents[addr]; 47 trace_nvram_read(addr, val); 48 return val; 49 } 50 51 static void nvram_write(void *opaque, hwaddr addr, uint64_t val, 52 unsigned size) 53 { 54 NvRamState *s = opaque; 55 56 val &= 0xff; 57 trace_nvram_write(addr, s->contents[addr], val); 58 59 s->contents[addr] = val; 60 if (s->file) { 61 fseek(s->file, addr, SEEK_SET); 62 fputc(val, s->file); 63 fflush(s->file); 64 } 65 } 66 67 static const MemoryRegionOps nvram_ops = { 68 .read = nvram_read, 69 .write = nvram_write, 70 .impl = { 71 .min_access_size = 1, 72 .max_access_size = 1, 73 }, 74 .endianness = DEVICE_LITTLE_ENDIAN, 75 }; 76 77 static int nvram_post_load(void *opaque, int version_id) 78 { 79 NvRamState *s = opaque; 80 81 /* Close file, as filename may has changed in load/store process */ 82 if (s->file) { 83 fclose(s->file); 84 } 85 86 /* Write back nvram contents */ 87 s->file = s->filename ? fopen(s->filename, "wb") : NULL; 88 if (s->file) { 89 /* Write back contents, as 'wb' mode cleaned the file */ 90 if (fwrite(s->contents, s->chip_size, 1, s->file) != 1) { 91 printf("nvram_post_load: short write\n"); 92 } 93 fflush(s->file); 94 } 95 96 return 0; 97 } 98 99 static const VMStateDescription vmstate_nvram = { 100 .name = "nvram", 101 .version_id = 0, 102 .minimum_version_id = 0, 103 .post_load = nvram_post_load, 104 .fields = (VMStateField[]) { 105 VMSTATE_VARRAY_UINT32(contents, NvRamState, chip_size, 0, 106 vmstate_info_uint8, uint8_t), 107 VMSTATE_END_OF_LIST() 108 } 109 }; 110 111 #define TYPE_DS1225Y "ds1225y" 112 #define DS1225Y(obj) OBJECT_CHECK(SysBusNvRamState, (obj), TYPE_DS1225Y) 113 114 typedef struct { 115 SysBusDevice parent_obj; 116 117 NvRamState nvram; 118 } SysBusNvRamState; 119 120 static void nvram_sysbus_realize(DeviceState *dev, Error **errp) 121 { 122 SysBusNvRamState *sys = DS1225Y(dev); 123 NvRamState *s = &sys->nvram; 124 FILE *file; 125 126 s->contents = g_malloc0(s->chip_size); 127 128 memory_region_init_io(&s->iomem, OBJECT(s), &nvram_ops, s, 129 "nvram", s->chip_size); 130 sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); 131 132 /* Read current file */ 133 file = s->filename ? fopen(s->filename, "rb") : NULL; 134 if (file) { 135 /* Read nvram contents */ 136 if (fread(s->contents, s->chip_size, 1, file) != 1) { 137 error_report("nvram_sysbus_realize: short read"); 138 } 139 fclose(file); 140 } 141 nvram_post_load(s, 0); 142 } 143 144 static Property nvram_sysbus_properties[] = { 145 DEFINE_PROP_UINT32("size", SysBusNvRamState, nvram.chip_size, 0x2000), 146 DEFINE_PROP_STRING("filename", SysBusNvRamState, nvram.filename), 147 DEFINE_PROP_END_OF_LIST(), 148 }; 149 150 static void nvram_sysbus_class_init(ObjectClass *klass, void *data) 151 { 152 DeviceClass *dc = DEVICE_CLASS(klass); 153 154 dc->realize = nvram_sysbus_realize; 155 dc->vmsd = &vmstate_nvram; 156 device_class_set_props(dc, nvram_sysbus_properties); 157 } 158 159 static const TypeInfo nvram_sysbus_info = { 160 .name = TYPE_DS1225Y, 161 .parent = TYPE_SYS_BUS_DEVICE, 162 .instance_size = sizeof(SysBusNvRamState), 163 .class_init = nvram_sysbus_class_init, 164 }; 165 166 static void nvram_register_types(void) 167 { 168 type_register_static(&nvram_sysbus_info); 169 } 170 171 type_init(nvram_register_types) 172