ia64/xen-unstable

view tools/ioemu/hw/m48t08.c @ 6946:e703abaf6e3d

Add behaviour to the remove methods to remove the transaction's path itself. This allows us to write Remove(path) to remove the specified path rather than having to slice the path ourselves.
author emellor@ewan
date Sun Sep 18 14:42:13 2005 +0100 (2005-09-18)
parents 8e5fc5fe636c
children
line source
1 /*
2 * QEMU M48T08 NVRAM emulation for Sparc platform
3 *
4 * Copyright (c) 2003-2004 Jocelyn Mayer
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 #include "vl.h"
25 #include "m48t08.h"
27 //#define DEBUG_NVRAM
29 #if defined(DEBUG_NVRAM)
30 #define NVRAM_PRINTF(fmt, args...) do { printf(fmt , ##args); } while (0)
31 #else
32 #define NVRAM_PRINTF(fmt, args...) do { } while (0)
33 #endif
35 #define NVRAM_MAX_MEM 0xfff0
37 struct m48t08_t {
38 /* Hardware parameters */
39 int mem_index;
40 uint32_t mem_base;
41 uint16_t size;
42 /* RTC management */
43 time_t time_offset;
44 time_t stop_time;
45 /* NVRAM storage */
46 uint8_t lock;
47 uint16_t addr;
48 uint8_t *buffer;
49 };
51 /* Fake timer functions */
52 /* Generic helpers for BCD */
53 static inline uint8_t toBCD (uint8_t value)
54 {
55 return (((value / 10) % 10) << 4) | (value % 10);
56 }
58 static inline uint8_t fromBCD (uint8_t BCD)
59 {
60 return ((BCD >> 4) * 10) + (BCD & 0x0F);
61 }
63 /* RTC management helpers */
64 static void get_time (m48t08_t *NVRAM, struct tm *tm)
65 {
66 time_t t;
68 t = time(NULL) + NVRAM->time_offset;
69 #ifdef _WIN32
70 memcpy(tm,localtime(&t),sizeof(*tm));
71 #else
72 localtime_r (&t, tm) ;
73 #endif
74 }
76 static void set_time (m48t08_t *NVRAM, struct tm *tm)
77 {
78 time_t now, new_time;
80 new_time = mktime(tm);
81 now = time(NULL);
82 NVRAM->time_offset = new_time - now;
83 }
85 /* Direct access to NVRAM */
86 void m48t08_write (m48t08_t *NVRAM, uint32_t val)
87 {
88 struct tm tm;
89 int tmp;
91 if (NVRAM->addr > NVRAM_MAX_MEM && NVRAM->addr < 0x2000)
92 NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, NVRAM->addr, val);
93 switch (NVRAM->addr) {
94 case 0x1FF8:
95 /* control */
96 NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90;
97 break;
98 case 0x1FF9:
99 /* seconds (BCD) */
100 tmp = fromBCD(val & 0x7F);
101 if (tmp >= 0 && tmp <= 59) {
102 get_time(NVRAM, &tm);
103 tm.tm_sec = tmp;
104 set_time(NVRAM, &tm);
105 }
106 if ((val & 0x80) ^ (NVRAM->buffer[0x1FF9] & 0x80)) {
107 if (val & 0x80) {
108 NVRAM->stop_time = time(NULL);
109 } else {
110 NVRAM->time_offset += NVRAM->stop_time - time(NULL);
111 NVRAM->stop_time = 0;
112 }
113 }
114 NVRAM->buffer[0x1FF9] = val & 0x80;
115 break;
116 case 0x1FFA:
117 /* minutes (BCD) */
118 tmp = fromBCD(val & 0x7F);
119 if (tmp >= 0 && tmp <= 59) {
120 get_time(NVRAM, &tm);
121 tm.tm_min = tmp;
122 set_time(NVRAM, &tm);
123 }
124 break;
125 case 0x1FFB:
126 /* hours (BCD) */
127 tmp = fromBCD(val & 0x3F);
128 if (tmp >= 0 && tmp <= 23) {
129 get_time(NVRAM, &tm);
130 tm.tm_hour = tmp;
131 set_time(NVRAM, &tm);
132 }
133 break;
134 case 0x1FFC:
135 /* day of the week / century */
136 tmp = fromBCD(val & 0x07);
137 get_time(NVRAM, &tm);
138 tm.tm_wday = tmp;
139 set_time(NVRAM, &tm);
140 NVRAM->buffer[0x1FFC] = val & 0x40;
141 break;
142 case 0x1FFD:
143 /* date */
144 tmp = fromBCD(val & 0x1F);
145 if (tmp != 0) {
146 get_time(NVRAM, &tm);
147 tm.tm_mday = tmp;
148 set_time(NVRAM, &tm);
149 }
150 break;
151 case 0x1FFE:
152 /* month */
153 tmp = fromBCD(val & 0x1F);
154 if (tmp >= 1 && tmp <= 12) {
155 get_time(NVRAM, &tm);
156 tm.tm_mon = tmp - 1;
157 set_time(NVRAM, &tm);
158 }
159 break;
160 case 0x1FFF:
161 /* year */
162 tmp = fromBCD(val);
163 if (tmp >= 0 && tmp <= 99) {
164 get_time(NVRAM, &tm);
165 tm.tm_year = fromBCD(val);
166 set_time(NVRAM, &tm);
167 }
168 break;
169 default:
170 /* Check lock registers state */
171 if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1))
172 break;
173 if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2))
174 break;
175 if (NVRAM->addr < NVRAM_MAX_MEM ||
176 (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) {
177 NVRAM->buffer[NVRAM->addr] = val & 0xFF;
178 }
179 break;
180 }
181 }
183 uint32_t m48t08_read (m48t08_t *NVRAM)
184 {
185 struct tm tm;
186 uint32_t retval = 0xFF;
188 switch (NVRAM->addr) {
189 case 0x1FF8:
190 /* control */
191 goto do_read;
192 case 0x1FF9:
193 /* seconds (BCD) */
194 get_time(NVRAM, &tm);
195 retval = (NVRAM->buffer[0x1FF9] & 0x80) | toBCD(tm.tm_sec);
196 break;
197 case 0x1FFA:
198 /* minutes (BCD) */
199 get_time(NVRAM, &tm);
200 retval = toBCD(tm.tm_min);
201 break;
202 case 0x1FFB:
203 /* hours (BCD) */
204 get_time(NVRAM, &tm);
205 retval = toBCD(tm.tm_hour);
206 break;
207 case 0x1FFC:
208 /* day of the week / century */
209 get_time(NVRAM, &tm);
210 retval = NVRAM->buffer[0x1FFC] | tm.tm_wday;
211 break;
212 case 0x1FFD:
213 /* date */
214 get_time(NVRAM, &tm);
215 retval = toBCD(tm.tm_mday);
216 break;
217 case 0x1FFE:
218 /* month */
219 get_time(NVRAM, &tm);
220 retval = toBCD(tm.tm_mon + 1);
221 break;
222 case 0x1FFF:
223 /* year */
224 get_time(NVRAM, &tm);
225 retval = toBCD(tm.tm_year);
226 break;
227 default:
228 /* Check lock registers state */
229 if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1))
230 break;
231 if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2))
232 break;
233 if (NVRAM->addr < NVRAM_MAX_MEM ||
234 (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) {
235 do_read:
236 retval = NVRAM->buffer[NVRAM->addr];
237 }
238 break;
239 }
240 if (NVRAM->addr > NVRAM_MAX_MEM + 1 && NVRAM->addr < 0x2000)
241 NVRAM_PRINTF("0x%08x <= 0x%08x\n", NVRAM->addr, retval);
243 return retval;
244 }
246 void m48t08_set_addr (m48t08_t *NVRAM, uint32_t addr)
247 {
248 NVRAM->addr = addr;
249 }
251 void m48t08_toggle_lock (m48t08_t *NVRAM, int lock)
252 {
253 NVRAM->lock ^= 1 << lock;
254 }
256 static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
257 {
258 m48t08_t *NVRAM = opaque;
260 addr -= NVRAM->mem_base;
261 if (addr < NVRAM_MAX_MEM)
262 NVRAM->buffer[addr] = value;
263 }
265 static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
266 {
267 m48t08_t *NVRAM = opaque;
269 addr -= NVRAM->mem_base;
270 if (addr < NVRAM_MAX_MEM) {
271 NVRAM->buffer[addr] = value >> 8;
272 NVRAM->buffer[addr + 1] = value;
273 }
274 }
276 static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
277 {
278 m48t08_t *NVRAM = opaque;
280 addr -= NVRAM->mem_base;
281 if (addr < NVRAM_MAX_MEM) {
282 NVRAM->buffer[addr] = value >> 24;
283 NVRAM->buffer[addr + 1] = value >> 16;
284 NVRAM->buffer[addr + 2] = value >> 8;
285 NVRAM->buffer[addr + 3] = value;
286 }
287 }
289 static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
290 {
291 m48t08_t *NVRAM = opaque;
292 uint32_t retval = 0;
294 addr -= NVRAM->mem_base;
295 if (addr < NVRAM_MAX_MEM)
296 retval = NVRAM->buffer[addr];
298 return retval;
299 }
301 static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr)
302 {
303 m48t08_t *NVRAM = opaque;
304 uint32_t retval = 0;
306 addr -= NVRAM->mem_base;
307 if (addr < NVRAM_MAX_MEM) {
308 retval = NVRAM->buffer[addr] << 8;
309 retval |= NVRAM->buffer[addr + 1];
310 }
312 return retval;
313 }
315 static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr)
316 {
317 m48t08_t *NVRAM = opaque;
318 uint32_t retval = 0;
320 addr -= NVRAM->mem_base;
321 if (addr < NVRAM_MAX_MEM) {
322 retval = NVRAM->buffer[addr] << 24;
323 retval |= NVRAM->buffer[addr + 1] << 16;
324 retval |= NVRAM->buffer[addr + 2] << 8;
325 retval |= NVRAM->buffer[addr + 3];
326 }
328 return retval;
329 }
331 static CPUWriteMemoryFunc *nvram_write[] = {
332 &nvram_writeb,
333 &nvram_writew,
334 &nvram_writel,
335 };
337 static CPUReadMemoryFunc *nvram_read[] = {
338 &nvram_readb,
339 &nvram_readw,
340 &nvram_readl,
341 };
343 /* Initialisation routine */
344 m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size, uint8_t *macaddr)
345 {
346 m48t08_t *s;
347 int i;
348 unsigned char tmp = 0;
350 s = qemu_mallocz(sizeof(m48t08_t));
351 if (!s)
352 return NULL;
353 s->buffer = qemu_mallocz(size);
354 if (!s->buffer) {
355 qemu_free(s);
356 return NULL;
357 }
358 s->size = size;
359 s->mem_base = mem_base;
360 s->addr = 0;
361 if (mem_base != 0) {
362 s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s);
363 cpu_register_physical_memory(mem_base, 0x4000, s->mem_index);
364 }
365 s->lock = 0;
367 i = 0x1fd8;
368 s->buffer[i++] = 0x01;
369 s->buffer[i++] = 0x80; /* Sun4m OBP */
370 memcpy(&s->buffer[i], macaddr, 6);
372 /* Calculate checksum */
373 for (i = 0x1fd8; i < 0x1fe7; i++) {
374 tmp ^= s->buffer[i];
375 }
376 s->buffer[0x1fe7] = tmp;
377 return s;
378 }
380 #if 0
381 struct idprom
382 {
383 unsigned char id_format; /* Format identifier (always 0x01) */
384 unsigned char id_machtype; /* Machine type */
385 unsigned char id_ethaddr[6]; /* Hardware ethernet address */
386 long id_date; /* Date of manufacture */
387 unsigned int id_sernum:24; /* Unique serial number */
388 unsigned char id_cksum; /* Checksum - xor of the data bytes */
389 unsigned char reserved[16];
390 };
391 #endif