blob: 3660a47c51ca6cb177d9e9293beb431bdd53c0e9 [file] [log] [blame]
aurel3230aa5c02008-03-13 01:19:15 +00001/*
2 * QEMU NVRAM emulation for DS1225Y chip
aurel3202cb1582008-03-13 19:23:00 +00003 *
Stefan Weilbcc4e412011-12-02 10:30:41 +01004 * Copyright (c) 2007-2008 Hervé Poussineau
aurel3202cb1582008-03-13 19:23:00 +00005 *
aurel3230aa5c02008-03-13 01:19:15 +00006 * 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
Peter Maydell04308912016-01-26 18:17:30 +000025#include "qemu/osdep.h"
Markus Armbrustera27bd6c2019-08-12 07:23:51 +020026#include "hw/qdev-properties.h"
Paolo Bonzini83c9f4c2013-02-04 15:40:22 +010027#include "hw/sysbus.h"
Markus Armbrusterd6454272019-08-12 07:23:45 +020028#include "migration/vmstate.h"
Hervé Poussineaud43ed9e2011-07-18 23:34:21 +020029#include "trace.h"
Mao Zhongyi296097f2018-12-13 13:48:00 +000030#include "qemu/error-report.h"
Markus Armbruster0b8fa322019-05-23 16:35:07 +020031#include "qemu/module.h"
Eduardo Habkostdb1015e2020-09-03 16:43:22 -040032#include "qom/object.h"
aurel3230aa5c02008-03-13 01:19:15 +000033
Hervé Poussineaucd3e2402011-07-18 23:34:22 +020034typedef struct {
Avi Kivity871321a2011-11-10 11:24:24 +020035 MemoryRegion iomem;
aurel3202cb1582008-03-13 19:23:00 +000036 uint32_t chip_size;
Hervé Poussineaucd3e2402011-07-18 23:34:22 +020037 char *filename;
Juan Quintela3a230252011-09-13 14:41:18 +020038 FILE *file;
aurel3202cb1582008-03-13 19:23:00 +000039 uint8_t *contents;
Hervé Poussineaucd3e2402011-07-18 23:34:22 +020040} NvRamState;
aurel3230aa5c02008-03-13 01:19:15 +000041
Avi Kivitya8170e52012-10-23 12:30:10 +020042static uint64_t nvram_read(void *opaque, hwaddr addr, unsigned size)
aurel3230aa5c02008-03-13 01:19:15 +000043{
Hervé Poussineaucd3e2402011-07-18 23:34:22 +020044 NvRamState *s = opaque;
aurel3202cb1582008-03-13 19:23:00 +000045 uint32_t val;
aurel3230aa5c02008-03-13 01:19:15 +000046
pbrook8da3ff12008-12-01 18:59:50 +000047 val = s->contents[addr];
Hervé Poussineaud43ed9e2011-07-18 23:34:21 +020048 trace_nvram_read(addr, val);
aurel3202cb1582008-03-13 19:23:00 +000049 return val;
aurel3230aa5c02008-03-13 01:19:15 +000050}
51
Avi Kivitya8170e52012-10-23 12:30:10 +020052static void nvram_write(void *opaque, hwaddr addr, uint64_t val,
Avi Kivity871321a2011-11-10 11:24:24 +020053 unsigned size)
aurel3202cb1582008-03-13 19:23:00 +000054{
Hervé Poussineaucd3e2402011-07-18 23:34:22 +020055 NvRamState *s = opaque;
aurel3230aa5c02008-03-13 01:19:15 +000056
Hervé Poussineaud43ed9e2011-07-18 23:34:21 +020057 val &= 0xff;
58 trace_nvram_write(addr, s->contents[addr], val);
aurel3202cb1582008-03-13 19:23:00 +000059
Hervé Poussineaud43ed9e2011-07-18 23:34:21 +020060 s->contents[addr] = val;
aurel3202cb1582008-03-13 19:23:00 +000061 if (s->file) {
Juan Quintela3a230252011-09-13 14:41:18 +020062 fseek(s->file, addr, SEEK_SET);
63 fputc(val, s->file);
64 fflush(s->file);
aurel3230aa5c02008-03-13 01:19:15 +000065 }
66}
67
Avi Kivity871321a2011-11-10 11:24:24 +020068static const MemoryRegionOps nvram_ops = {
69 .read = nvram_read,
70 .write = nvram_write,
71 .impl = {
72 .min_access_size = 1,
73 .max_access_size = 1,
74 },
75 .endianness = DEVICE_LITTLE_ENDIAN,
aurel3230aa5c02008-03-13 01:19:15 +000076};
77
Hervé Poussineaucd3e2402011-07-18 23:34:22 +020078static int nvram_post_load(void *opaque, int version_id)
aurel3230aa5c02008-03-13 01:19:15 +000079{
Hervé Poussineaucd3e2402011-07-18 23:34:22 +020080 NvRamState *s = opaque;
aurel3230aa5c02008-03-13 01:19:15 +000081
Hervé Poussineaucd3e2402011-07-18 23:34:22 +020082 /* Close file, as filename may has changed in load/store process */
83 if (s->file) {
Juan Quintela3a230252011-09-13 14:41:18 +020084 fclose(s->file);
aurel3202cb1582008-03-13 19:23:00 +000085 }
Hervé Poussineaucd3e2402011-07-18 23:34:22 +020086
87 /* Write back nvram contents */
Marc-André Lureaub7438452018-01-04 17:05:22 +010088 s->file = s->filename ? fopen(s->filename, "wb") : NULL;
aurel3202cb1582008-03-13 19:23:00 +000089 if (s->file) {
90 /* Write back contents, as 'wb' mode cleaned the file */
Juan Quintela3a230252011-09-13 14:41:18 +020091 if (fwrite(s->contents, s->chip_size, 1, s->file) != 1) {
92 printf("nvram_post_load: short write\n");
93 }
94 fflush(s->file);
aurel3202cb1582008-03-13 19:23:00 +000095 }
aurel3230aa5c02008-03-13 01:19:15 +000096
Hervé Poussineaucd3e2402011-07-18 23:34:22 +020097 return 0;
aurel3230aa5c02008-03-13 01:19:15 +000098}
Hervé Poussineaucd3e2402011-07-18 23:34:22 +020099
100static const VMStateDescription vmstate_nvram = {
101 .name = "nvram",
102 .version_id = 0,
103 .minimum_version_id = 0,
Hervé Poussineaucd3e2402011-07-18 23:34:22 +0200104 .post_load = nvram_post_load,
105 .fields = (VMStateField[]) {
106 VMSTATE_VARRAY_UINT32(contents, NvRamState, chip_size, 0,
107 vmstate_info_uint8, uint8_t),
108 VMSTATE_END_OF_LIST()
109 }
110};
111
Andreas Färber8c1892c2013-07-27 12:50:29 +0200112#define TYPE_DS1225Y "ds1225y"
Eduardo Habkost80633962020-09-16 14:25:19 -0400113OBJECT_DECLARE_SIMPLE_TYPE(SysBusNvRamState, DS1225Y)
Andreas Färber8c1892c2013-07-27 12:50:29 +0200114
Eduardo Habkostdb1015e2020-09-03 16:43:22 -0400115struct SysBusNvRamState {
Andreas Färber8c1892c2013-07-27 12:50:29 +0200116 SysBusDevice parent_obj;
117
Hervé Poussineaucd3e2402011-07-18 23:34:22 +0200118 NvRamState nvram;
Eduardo Habkostdb1015e2020-09-03 16:43:22 -0400119};
Hervé Poussineaucd3e2402011-07-18 23:34:22 +0200120
Mao Zhongyi296097f2018-12-13 13:48:00 +0000121static void nvram_sysbus_realize(DeviceState *dev, Error **errp)
Hervé Poussineaucd3e2402011-07-18 23:34:22 +0200122{
Andreas Färber8c1892c2013-07-27 12:50:29 +0200123 SysBusNvRamState *sys = DS1225Y(dev);
124 NvRamState *s = &sys->nvram;
Juan Quintela3a230252011-09-13 14:41:18 +0200125 FILE *file;
Hervé Poussineaucd3e2402011-07-18 23:34:22 +0200126
Anthony Liguori7267c092011-08-20 22:09:37 -0500127 s->contents = g_malloc0(s->chip_size);
Hervé Poussineaucd3e2402011-07-18 23:34:22 +0200128
Paolo Bonzinieedfac62013-06-06 21:25:08 -0400129 memory_region_init_io(&s->iomem, OBJECT(s), &nvram_ops, s,
130 "nvram", s->chip_size);
Mao Zhongyi296097f2018-12-13 13:48:00 +0000131 sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
Hervé Poussineaucd3e2402011-07-18 23:34:22 +0200132
133 /* Read current file */
Marc-André Lureaub7438452018-01-04 17:05:22 +0100134 file = s->filename ? fopen(s->filename, "rb") : NULL;
Hervé Poussineaucd3e2402011-07-18 23:34:22 +0200135 if (file) {
136 /* Read nvram contents */
Juan Quintela3a230252011-09-13 14:41:18 +0200137 if (fread(s->contents, s->chip_size, 1, file) != 1) {
Mao Zhongyi296097f2018-12-13 13:48:00 +0000138 error_report("nvram_sysbus_realize: short read");
Juan Quintela3a230252011-09-13 14:41:18 +0200139 }
140 fclose(file);
Hervé Poussineaucd3e2402011-07-18 23:34:22 +0200141 }
142 nvram_post_load(s, 0);
Hervé Poussineaucd3e2402011-07-18 23:34:22 +0200143}
144
Anthony Liguori999e12b2012-01-24 13:12:29 -0600145static Property nvram_sysbus_properties[] = {
146 DEFINE_PROP_UINT32("size", SysBusNvRamState, nvram.chip_size, 0x2000),
147 DEFINE_PROP_STRING("filename", SysBusNvRamState, nvram.filename),
148 DEFINE_PROP_END_OF_LIST(),
149};
150
151static void nvram_sysbus_class_init(ObjectClass *klass, void *data)
152{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600153 DeviceClass *dc = DEVICE_CLASS(klass);
Anthony Liguori999e12b2012-01-24 13:12:29 -0600154
Mao Zhongyi296097f2018-12-13 13:48:00 +0000155 dc->realize = nvram_sysbus_realize;
Anthony Liguori39bffca2011-12-07 21:34:16 -0600156 dc->vmsd = &vmstate_nvram;
Marc-André Lureau4f67d302020-01-10 19:30:32 +0400157 device_class_set_props(dc, nvram_sysbus_properties);
Anthony Liguori999e12b2012-01-24 13:12:29 -0600158}
159
Andreas Färber8c43a6f2013-01-10 16:19:07 +0100160static const TypeInfo nvram_sysbus_info = {
Andreas Färber8c1892c2013-07-27 12:50:29 +0200161 .name = TYPE_DS1225Y,
Anthony Liguori39bffca2011-12-07 21:34:16 -0600162 .parent = TYPE_SYS_BUS_DEVICE,
163 .instance_size = sizeof(SysBusNvRamState),
164 .class_init = nvram_sysbus_class_init,
Hervé Poussineaucd3e2402011-07-18 23:34:22 +0200165};
166
Andreas Färber83f7d432012-02-09 15:20:55 +0100167static void nvram_register_types(void)
Hervé Poussineaucd3e2402011-07-18 23:34:22 +0200168{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600169 type_register_static(&nvram_sysbus_info);
Hervé Poussineaucd3e2402011-07-18 23:34:22 +0200170}
171
Andreas Färber83f7d432012-02-09 15:20:55 +0100172type_init(nvram_register_types)