Skip to content

Commit addff51

Browse files
zbalatonnpiggin
authored andcommitted
ppc/amigaone: Implement NVRAM emulation
The board has a battery backed NVRAM where U-Boot environment is stored which is also accessed by AmigaOS and e.g. C:NVGetVar command crashes without it having at least a valid checksum. [npiggin: 32-bit compile fix] Signed-off-by: BALATON Zoltan <[email protected]> Reviewed-by: Nicholas Piggin <[email protected]> Message-ID: <7e4c0107ef6bdc2b20fb1e780a188275c7dc1e49.1740673173.git.balaton@eik.bme.hu> Signed-off-by: Nicholas Piggin <[email protected]>
1 parent 222d37d commit addff51

File tree

1 file changed

+110
-3
lines changed

1 file changed

+110
-3
lines changed

hw/ppc/amigaone.c

Lines changed: 110 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,13 @@
2121
#include "hw/ide/pci.h"
2222
#include "hw/i2c/smbus_eeprom.h"
2323
#include "hw/ppc/ppc.h"
24+
#include "system/block-backend.h"
2425
#include "system/qtest.h"
2526
#include "system/reset.h"
2627
#include "kvm_ppc.h"
2728

29+
#include <zlib.h> /* for crc32 */
30+
2831
#define BUS_FREQ_HZ 100000000
2932

3033
/*
@@ -46,6 +49,100 @@ static const char dummy_fw[] = {
4649
0x4e, 0x80, 0x00, 0x20, /* blr */
4750
};
4851

52+
#define NVRAM_ADDR 0xfd0e0000
53+
#define NVRAM_SIZE (4 * KiB)
54+
55+
#define TYPE_A1_NVRAM "a1-nvram"
56+
OBJECT_DECLARE_SIMPLE_TYPE(A1NVRAMState, A1_NVRAM)
57+
58+
struct A1NVRAMState {
59+
SysBusDevice parent_obj;
60+
61+
MemoryRegion mr;
62+
BlockBackend *blk;
63+
};
64+
65+
static uint64_t nvram_read(void *opaque, hwaddr addr, unsigned int size)
66+
{
67+
/* read callback not used because of romd mode */
68+
g_assert_not_reached();
69+
}
70+
71+
static void nvram_write(void *opaque, hwaddr addr, uint64_t val,
72+
unsigned int size)
73+
{
74+
A1NVRAMState *s = opaque;
75+
uint8_t *p = memory_region_get_ram_ptr(&s->mr);
76+
77+
p[addr] = val;
78+
if (s->blk) {
79+
blk_pwrite(s->blk, addr, 1, &val, 0);
80+
}
81+
}
82+
83+
static const MemoryRegionOps nvram_ops = {
84+
.read = nvram_read,
85+
.write = nvram_write,
86+
.endianness = DEVICE_BIG_ENDIAN,
87+
.impl = {
88+
.min_access_size = 1,
89+
.max_access_size = 1,
90+
},
91+
};
92+
93+
static void nvram_realize(DeviceState *dev, Error **errp)
94+
{
95+
A1NVRAMState *s = A1_NVRAM(dev);
96+
void *p;
97+
uint32_t *c;
98+
99+
memory_region_init_rom_device(&s->mr, NULL, &nvram_ops, s, "nvram",
100+
NVRAM_SIZE, &error_fatal);
101+
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr);
102+
c = p = memory_region_get_ram_ptr(&s->mr);
103+
if (s->blk) {
104+
if (blk_getlength(s->blk) != NVRAM_SIZE) {
105+
error_setg(errp, "NVRAM backing file size must be %" PRId64 "bytes",
106+
NVRAM_SIZE);
107+
return;
108+
}
109+
blk_set_perm(s->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
110+
BLK_PERM_ALL, &error_fatal);
111+
if (blk_pread(s->blk, 0, NVRAM_SIZE, p, 0) < 0) {
112+
error_setg(errp, "Cannot read NVRAM contents from backing file");
113+
return;
114+
}
115+
}
116+
if (*c == 0) {
117+
*c = cpu_to_be32(crc32(0, p + 4, NVRAM_SIZE - 4));
118+
if (s->blk) {
119+
blk_pwrite(s->blk, 0, 4, p, 0);
120+
}
121+
}
122+
}
123+
124+
static const Property nvram_properties[] = {
125+
DEFINE_PROP_DRIVE("drive", A1NVRAMState, blk),
126+
};
127+
128+
static void nvram_class_init(ObjectClass *oc, void *data)
129+
{
130+
DeviceClass *dc = DEVICE_CLASS(oc);
131+
132+
dc->realize = nvram_realize;
133+
device_class_set_props(dc, nvram_properties);
134+
}
135+
136+
static const TypeInfo nvram_types[] = {
137+
{
138+
.name = TYPE_A1_NVRAM,
139+
.parent = TYPE_SYS_BUS_DEVICE,
140+
.instance_size = sizeof(A1NVRAMState),
141+
.class_init = nvram_class_init,
142+
},
143+
};
144+
DEFINE_TYPES(nvram_types)
145+
49146
static void amigaone_cpu_reset(void *opaque)
50147
{
51148
PowerPCCPU *cpu = opaque;
@@ -72,7 +169,7 @@ static void amigaone_init(MachineState *machine)
72169
DeviceState *dev;
73170
I2CBus *i2c_bus;
74171
uint8_t *spd_data;
75-
int i;
172+
DriveInfo *di;
76173

77174
/* init CPU */
78175
cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
@@ -97,6 +194,16 @@ static void amigaone_init(MachineState *machine)
97194
memory_region_add_subregion(get_system_memory(), 0x40000000, mr);
98195
}
99196

197+
/* nvram */
198+
dev = qdev_new(TYPE_A1_NVRAM);
199+
di = drive_get(IF_MTD, 0, 0);
200+
if (di) {
201+
qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(di));
202+
}
203+
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
204+
memory_region_add_subregion(get_system_memory(), NVRAM_ADDR,
205+
sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0));
206+
100207
/* allocate and load firmware */
101208
rom = g_new(MemoryRegion, 1);
102209
memory_region_init_rom(rom, NULL, "rom", PROM_SIZE, &error_fatal);
@@ -136,7 +243,7 @@ static void amigaone_init(MachineState *machine)
136243
pci_mem = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
137244
mr = g_new(MemoryRegion, 1);
138245
memory_region_init_alias(mr, OBJECT(dev), "pci-mem-low", pci_mem,
139-
0, 0x1000000);
246+
0, 0xe0000);
140247
memory_region_add_subregion(get_system_memory(), 0xfd000000, mr);
141248
mr = g_new(MemoryRegion, 1);
142249
memory_region_init_alias(mr, OBJECT(dev), "pci-mem-high", pci_mem,
@@ -153,7 +260,7 @@ static void amigaone_init(MachineState *machine)
153260
qdev_connect_gpio_out_named(DEVICE(via), "intr", 0,
154261
qdev_get_gpio_in(DEVICE(cpu),
155262
PPC6xx_INPUT_INT));
156-
for (i = 0; i < PCI_NUM_PINS; i++) {
263+
for (int i = 0; i < PCI_NUM_PINS; i++) {
157264
qdev_connect_gpio_out(dev, i, qdev_get_gpio_in_named(DEVICE(via),
158265
"pirq", i));
159266
}

0 commit comments

Comments
 (0)