ds1225y nvram: Fix some bugs
[qemu] / hw / ds1225y.c
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 "hw.h"
26 #include "mips.h"
27 #include "nvram.h"
28
29 //#define DEBUG_NVRAM
30
31 typedef struct ds1225y_t
32 {
33     target_phys_addr_t mem_base;
34     uint32_t chip_size;
35     QEMUFile *file;
36     uint8_t *contents;
37     uint8_t protection;
38 } ds1225y_t;
39
40
41 static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
42 {
43     ds1225y_t *s = opaque;
44     int64_t pos;
45     uint32_t val;
46
47     pos = addr - s->mem_base;
48     if (pos >= s->chip_size)
49         pos -= s->chip_size;
50
51     val = s->contents[pos];
52
53 #ifdef DEBUG_NVRAM
54     printf("nvram: read 0x%x at " TARGET_FMT_lx "\n", val, addr);
55 #endif
56     return val;
57 }
58
59 static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr)
60 {
61     uint32_t v;
62     v = nvram_readb(opaque, addr);
63     v |= nvram_readb(opaque, addr + 1) << 8;
64     return v;
65 }
66
67 static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr)
68 {
69     uint32_t v;
70     v = nvram_readb(opaque, addr);
71     v |= nvram_readb(opaque, addr + 1) << 8;
72     v |= nvram_readb(opaque, addr + 2) << 16;
73     v |= nvram_readb(opaque, addr + 3) << 24;
74     return v;
75 }
76
77 static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t val)
78 {
79     ds1225y_t *s = opaque;
80     int64_t pos;
81
82 #ifdef DEBUG_NVRAM
83     printf("nvram: write 0x%x at " TARGET_FMT_lx "\n", val, addr);
84 #endif
85
86     pos = addr - s->mem_base;
87     s->contents[pos] = val & 0xff;
88     if (s->file) {
89         qemu_fseek(s->file, pos, SEEK_SET);
90         qemu_put_byte(s->file, (int)val);
91         qemu_fflush(s->file);
92     }
93 }
94
95 static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t val)
96 {
97     nvram_writeb(opaque, addr, val & 0xff);
98     nvram_writeb(opaque, addr + 1, (val >> 8) & 0xff);
99 }
100
101 static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t val)
102 {
103     nvram_writeb(opaque, addr, val & 0xff);
104     nvram_writeb(opaque, addr + 1, (val >> 8) & 0xff);
105     nvram_writeb(opaque, addr + 2, (val >> 16) & 0xff);
106     nvram_writeb(opaque, addr + 3, (val >> 24) & 0xff);
107 }
108
109 static void nvram_writeb_protected (void *opaque, target_phys_addr_t addr, uint32_t val)
110 {
111     ds1225y_t *s = opaque;
112
113     if (s->protection != 7) {
114 #ifdef DEBUG_NVRAM
115     printf("nvram: prevent write of 0x%x at " TARGET_FMT_lx "\n", val, addr);
116 #endif
117         return;
118     }
119
120     nvram_writeb(opaque, addr - s->chip_size, val);
121 }
122
123 static void nvram_writew_protected (void *opaque, target_phys_addr_t addr, uint32_t val)
124 {
125     nvram_writeb_protected(opaque, addr, val & 0xff);
126     nvram_writeb_protected(opaque, addr + 1, (val >> 8) & 0xff);
127 }
128
129 static void nvram_writel_protected (void *opaque, target_phys_addr_t addr, uint32_t val)
130 {
131     nvram_writeb_protected(opaque, addr, val & 0xff);
132     nvram_writeb_protected(opaque, addr + 1, (val >> 8) & 0xff);
133     nvram_writeb_protected(opaque, addr + 2, (val >> 16) & 0xff);
134     nvram_writeb_protected(opaque, addr + 3, (val >> 24) & 0xff);
135 }
136
137 static CPUReadMemoryFunc *nvram_read[] = {
138     &nvram_readb,
139     &nvram_readw,
140     &nvram_readl,
141 };
142
143 static CPUWriteMemoryFunc *nvram_write[] = {
144     &nvram_writeb,
145     &nvram_writew,
146     &nvram_writel,
147 };
148
149 static CPUWriteMemoryFunc *nvram_write_protected[] = {
150     &nvram_writeb_protected,
151     &nvram_writew_protected,
152     &nvram_writel_protected,
153 };
154
155 /* Initialisation routine */
156 void *ds1225y_init(target_phys_addr_t mem_base, const char *filename)
157 {
158     ds1225y_t *s;
159     int mem_indexRW, mem_indexRP;
160     QEMUFile *file;
161
162     s = qemu_mallocz(sizeof(ds1225y_t));
163     if (!s)
164         return NULL;
165     s->chip_size = 0x2000; /* Fixed for ds1225y chip: 8 KiB */
166     s->contents = qemu_mallocz(s->chip_size);
167     if (!s->contents) {
168         return NULL;
169     }
170     s->mem_base = mem_base;
171     s->protection = 7;
172
173     /* Read current file */
174     file = qemu_fopen(filename, "rb");
175     if (file) {
176         /* Read nvram contents */
177         qemu_get_buffer(file, s->contents, s->chip_size);
178         qemu_fclose(file);
179     }
180     s->file = qemu_fopen(filename, "wb");
181     if (s->file) {
182         /* Write back contents, as 'wb' mode cleaned the file */
183         qemu_put_buffer(s->file, s->contents, s->chip_size);
184         qemu_fflush(s->file);
185     }
186
187     /* Read/write memory */
188     mem_indexRW = cpu_register_io_memory(0, nvram_read, nvram_write, s);
189     cpu_register_physical_memory(mem_base, s->chip_size, mem_indexRW);
190     /* Read/write protected memory */
191     mem_indexRP = cpu_register_io_memory(0, nvram_read, nvram_write_protected, s);
192     cpu_register_physical_memory(mem_base + s->chip_size, s->chip_size, mem_indexRP);
193     return s;
194 }