ia64/xen-unstable

view tools/ioemu/hw/m48t59.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 f7b43e5c42b9
line source
1 /*
2 * QEMU M48T59 NVRAM emulation for PPC PREP 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 "m48t59.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 struct m48t59_t {
36 /* Hardware parameters */
37 int IRQ;
38 int mem_index;
39 uint32_t mem_base;
40 uint32_t io_base;
41 uint16_t size;
42 /* RTC management */
43 time_t time_offset;
44 time_t stop_time;
45 /* Alarm & watchdog */
46 time_t alarm;
47 struct QEMUTimer *alrm_timer;
48 struct QEMUTimer *wd_timer;
49 /* NVRAM storage */
50 uint8_t lock;
51 uint16_t addr;
52 uint8_t *buffer;
53 };
55 /* Fake timer functions */
56 /* Generic helpers for BCD */
57 static inline uint8_t toBCD (uint8_t value)
58 {
59 return (((value / 10) % 10) << 4) | (value % 10);
60 }
62 static inline uint8_t fromBCD (uint8_t BCD)
63 {
64 return ((BCD >> 4) * 10) + (BCD & 0x0F);
65 }
67 /* RTC management helpers */
68 static void get_time (m48t59_t *NVRAM, struct tm *tm)
69 {
70 time_t t;
72 t = time(NULL) + NVRAM->time_offset;
73 #ifdef _WIN32
74 memcpy(tm,localtime(&t),sizeof(*tm));
75 #else
76 localtime_r (&t, tm) ;
77 #endif
78 }
80 static void set_time (m48t59_t *NVRAM, struct tm *tm)
81 {
82 time_t now, new_time;
84 new_time = mktime(tm);
85 now = time(NULL);
86 NVRAM->time_offset = new_time - now;
87 }
89 /* Alarm management */
90 static void alarm_cb (void *opaque)
91 {
92 struct tm tm, tm_now;
93 uint64_t next_time;
94 m48t59_t *NVRAM = opaque;
96 pic_set_irq(NVRAM->IRQ, 1);
97 if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 &&
98 (NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
99 (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
100 (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
101 /* Repeat once a month */
102 get_time(NVRAM, &tm_now);
103 memcpy(&tm, &tm_now, sizeof(struct tm));
104 tm.tm_mon++;
105 if (tm.tm_mon == 13) {
106 tm.tm_mon = 1;
107 tm.tm_year++;
108 }
109 next_time = mktime(&tm);
110 } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
111 (NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
112 (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
113 (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
114 /* Repeat once a day */
115 next_time = 24 * 60 * 60 + mktime(&tm_now);
116 } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
117 (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
118 (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
119 (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
120 /* Repeat once an hour */
121 next_time = 60 * 60 + mktime(&tm_now);
122 } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
123 (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
124 (NVRAM->buffer[0x1FF3] & 0x80) != 0 &&
125 (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
126 /* Repeat once a minute */
127 next_time = 60 + mktime(&tm_now);
128 } else {
129 /* Repeat once a second */
130 next_time = 1 + mktime(&tm_now);
131 }
132 qemu_mod_timer(NVRAM->alrm_timer, next_time * 1000);
133 pic_set_irq(NVRAM->IRQ, 0);
134 }
137 static void get_alarm (m48t59_t *NVRAM, struct tm *tm)
138 {
139 #ifdef _WIN32
140 memcpy(tm,localtime(&NVRAM->alarm),sizeof(*tm));
141 #else
142 localtime_r (&NVRAM->alarm, tm);
143 #endif
144 }
146 static void set_alarm (m48t59_t *NVRAM, struct tm *tm)
147 {
148 NVRAM->alarm = mktime(tm);
149 if (NVRAM->alrm_timer != NULL) {
150 qemu_del_timer(NVRAM->alrm_timer);
151 NVRAM->alrm_timer = NULL;
152 }
153 if (NVRAM->alarm - time(NULL) > 0)
154 qemu_mod_timer(NVRAM->alrm_timer, NVRAM->alarm * 1000);
155 }
157 /* Watchdog management */
158 static void watchdog_cb (void *opaque)
159 {
160 m48t59_t *NVRAM = opaque;
162 NVRAM->buffer[0x1FF0] |= 0x80;
163 if (NVRAM->buffer[0x1FF7] & 0x80) {
164 NVRAM->buffer[0x1FF7] = 0x00;
165 NVRAM->buffer[0x1FFC] &= ~0x40;
166 /* May it be a hw CPU Reset instead ? */
167 qemu_system_reset_request();
168 } else {
169 pic_set_irq(NVRAM->IRQ, 1);
170 pic_set_irq(NVRAM->IRQ, 0);
171 }
172 }
174 static void set_up_watchdog (m48t59_t *NVRAM, uint8_t value)
175 {
176 uint64_t interval; /* in 1/16 seconds */
178 if (NVRAM->wd_timer != NULL) {
179 qemu_del_timer(NVRAM->wd_timer);
180 NVRAM->wd_timer = NULL;
181 }
182 NVRAM->buffer[0x1FF0] &= ~0x80;
183 if (value != 0) {
184 interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F);
185 qemu_mod_timer(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) +
186 ((interval * 1000) >> 4));
187 }
188 }
190 /* Direct access to NVRAM */
191 void m48t59_write (m48t59_t *NVRAM, uint32_t val)
192 {
193 struct tm tm;
194 int tmp;
196 if (NVRAM->addr > 0x1FF8 && NVRAM->addr < 0x2000)
197 NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, NVRAM->addr, val);
198 switch (NVRAM->addr) {
199 case 0x1FF0:
200 /* flags register : read-only */
201 break;
202 case 0x1FF1:
203 /* unused */
204 break;
205 case 0x1FF2:
206 /* alarm seconds */
207 tmp = fromBCD(val & 0x7F);
208 if (tmp >= 0 && tmp <= 59) {
209 get_alarm(NVRAM, &tm);
210 tm.tm_sec = tmp;
211 NVRAM->buffer[0x1FF2] = val;
212 set_alarm(NVRAM, &tm);
213 }
214 break;
215 case 0x1FF3:
216 /* alarm minutes */
217 tmp = fromBCD(val & 0x7F);
218 if (tmp >= 0 && tmp <= 59) {
219 get_alarm(NVRAM, &tm);
220 tm.tm_min = tmp;
221 NVRAM->buffer[0x1FF3] = val;
222 set_alarm(NVRAM, &tm);
223 }
224 break;
225 case 0x1FF4:
226 /* alarm hours */
227 tmp = fromBCD(val & 0x3F);
228 if (tmp >= 0 && tmp <= 23) {
229 get_alarm(NVRAM, &tm);
230 tm.tm_hour = tmp;
231 NVRAM->buffer[0x1FF4] = val;
232 set_alarm(NVRAM, &tm);
233 }
234 break;
235 case 0x1FF5:
236 /* alarm date */
237 tmp = fromBCD(val & 0x1F);
238 if (tmp != 0) {
239 get_alarm(NVRAM, &tm);
240 tm.tm_mday = tmp;
241 NVRAM->buffer[0x1FF5] = val;
242 set_alarm(NVRAM, &tm);
243 }
244 break;
245 case 0x1FF6:
246 /* interrupts */
247 NVRAM->buffer[0x1FF6] = val;
248 break;
249 case 0x1FF7:
250 /* watchdog */
251 NVRAM->buffer[0x1FF7] = val;
252 set_up_watchdog(NVRAM, val);
253 break;
254 case 0x1FF8:
255 /* control */
256 NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90;
257 break;
258 case 0x1FF9:
259 /* seconds (BCD) */
260 tmp = fromBCD(val & 0x7F);
261 if (tmp >= 0 && tmp <= 59) {
262 get_time(NVRAM, &tm);
263 tm.tm_sec = tmp;
264 set_time(NVRAM, &tm);
265 }
266 if ((val & 0x80) ^ (NVRAM->buffer[0x1FF9] & 0x80)) {
267 if (val & 0x80) {
268 NVRAM->stop_time = time(NULL);
269 } else {
270 NVRAM->time_offset += NVRAM->stop_time - time(NULL);
271 NVRAM->stop_time = 0;
272 }
273 }
274 NVRAM->buffer[0x1FF9] = val & 0x80;
275 break;
276 case 0x1FFA:
277 /* minutes (BCD) */
278 tmp = fromBCD(val & 0x7F);
279 if (tmp >= 0 && tmp <= 59) {
280 get_time(NVRAM, &tm);
281 tm.tm_min = tmp;
282 set_time(NVRAM, &tm);
283 }
284 break;
285 case 0x1FFB:
286 /* hours (BCD) */
287 tmp = fromBCD(val & 0x3F);
288 if (tmp >= 0 && tmp <= 23) {
289 get_time(NVRAM, &tm);
290 tm.tm_hour = tmp;
291 set_time(NVRAM, &tm);
292 }
293 break;
294 case 0x1FFC:
295 /* day of the week / century */
296 tmp = fromBCD(val & 0x07);
297 get_time(NVRAM, &tm);
298 tm.tm_wday = tmp;
299 set_time(NVRAM, &tm);
300 NVRAM->buffer[0x1FFC] = val & 0x40;
301 break;
302 case 0x1FFD:
303 /* date */
304 tmp = fromBCD(val & 0x1F);
305 if (tmp != 0) {
306 get_time(NVRAM, &tm);
307 tm.tm_mday = tmp;
308 set_time(NVRAM, &tm);
309 }
310 break;
311 case 0x1FFE:
312 /* month */
313 tmp = fromBCD(val & 0x1F);
314 if (tmp >= 1 && tmp <= 12) {
315 get_time(NVRAM, &tm);
316 tm.tm_mon = tmp - 1;
317 set_time(NVRAM, &tm);
318 }
319 break;
320 case 0x1FFF:
321 /* year */
322 tmp = fromBCD(val);
323 if (tmp >= 0 && tmp <= 99) {
324 get_time(NVRAM, &tm);
325 tm.tm_year = fromBCD(val);
326 set_time(NVRAM, &tm);
327 }
328 break;
329 default:
330 /* Check lock registers state */
331 if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1))
332 break;
333 if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2))
334 break;
335 if (NVRAM->addr < 0x1FF0 ||
336 (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) {
337 NVRAM->buffer[NVRAM->addr] = val & 0xFF;
338 }
339 break;
340 }
341 }
343 uint32_t m48t59_read (m48t59_t *NVRAM)
344 {
345 struct tm tm;
346 uint32_t retval = 0xFF;
348 switch (NVRAM->addr) {
349 case 0x1FF0:
350 /* flags register */
351 goto do_read;
352 case 0x1FF1:
353 /* unused */
354 retval = 0;
355 break;
356 case 0x1FF2:
357 /* alarm seconds */
358 goto do_read;
359 case 0x1FF3:
360 /* alarm minutes */
361 goto do_read;
362 case 0x1FF4:
363 /* alarm hours */
364 goto do_read;
365 case 0x1FF5:
366 /* alarm date */
367 goto do_read;
368 case 0x1FF6:
369 /* interrupts */
370 goto do_read;
371 case 0x1FF7:
372 /* A read resets the watchdog */
373 set_up_watchdog(NVRAM, NVRAM->buffer[0x1FF7]);
374 goto do_read;
375 case 0x1FF8:
376 /* control */
377 goto do_read;
378 case 0x1FF9:
379 /* seconds (BCD) */
380 get_time(NVRAM, &tm);
381 retval = (NVRAM->buffer[0x1FF9] & 0x80) | toBCD(tm.tm_sec);
382 break;
383 case 0x1FFA:
384 /* minutes (BCD) */
385 get_time(NVRAM, &tm);
386 retval = toBCD(tm.tm_min);
387 break;
388 case 0x1FFB:
389 /* hours (BCD) */
390 get_time(NVRAM, &tm);
391 retval = toBCD(tm.tm_hour);
392 break;
393 case 0x1FFC:
394 /* day of the week / century */
395 get_time(NVRAM, &tm);
396 retval = NVRAM->buffer[0x1FFC] | tm.tm_wday;
397 break;
398 case 0x1FFD:
399 /* date */
400 get_time(NVRAM, &tm);
401 retval = toBCD(tm.tm_mday);
402 break;
403 case 0x1FFE:
404 /* month */
405 get_time(NVRAM, &tm);
406 retval = toBCD(tm.tm_mon + 1);
407 break;
408 case 0x1FFF:
409 /* year */
410 get_time(NVRAM, &tm);
411 retval = toBCD(tm.tm_year);
412 break;
413 default:
414 /* Check lock registers state */
415 if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1))
416 break;
417 if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2))
418 break;
419 if (NVRAM->addr < 0x1FF0 ||
420 (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) {
421 do_read:
422 retval = NVRAM->buffer[NVRAM->addr];
423 }
424 break;
425 }
426 if (NVRAM->addr > 0x1FF9 && NVRAM->addr < 0x2000)
427 NVRAM_PRINTF("0x%08x <= 0x%08x\n", NVRAM->addr, retval);
429 return retval;
430 }
432 void m48t59_set_addr (m48t59_t *NVRAM, uint32_t addr)
433 {
434 NVRAM->addr = addr;
435 }
437 void m48t59_toggle_lock (m48t59_t *NVRAM, int lock)
438 {
439 NVRAM->lock ^= 1 << lock;
440 }
442 /* IO access to NVRAM */
443 static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val)
444 {
445 m48t59_t *NVRAM = opaque;
447 addr -= NVRAM->io_base;
448 NVRAM_PRINTF("0x%08x => 0x%08x\n", addr, val);
449 switch (addr) {
450 case 0:
451 NVRAM->addr &= ~0x00FF;
452 NVRAM->addr |= val;
453 break;
454 case 1:
455 NVRAM->addr &= ~0xFF00;
456 NVRAM->addr |= val << 8;
457 break;
458 case 3:
459 m48t59_write(NVRAM, val);
460 NVRAM->addr = 0x0000;
461 break;
462 default:
463 break;
464 }
465 }
467 static uint32_t NVRAM_readb (void *opaque, uint32_t addr)
468 {
469 m48t59_t *NVRAM = opaque;
470 uint32_t retval;
472 addr -= NVRAM->io_base;
473 switch (addr) {
474 case 3:
475 retval = m48t59_read(NVRAM);
476 break;
477 default:
478 retval = -1;
479 break;
480 }
481 NVRAM_PRINTF("0x%08x <= 0x%08x\n", addr, retval);
483 return retval;
484 }
486 static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
487 {
488 m48t59_t *NVRAM = opaque;
490 addr -= NVRAM->mem_base;
491 if (addr < 0x1FF0)
492 NVRAM->buffer[addr] = value;
493 }
495 static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
496 {
497 m48t59_t *NVRAM = opaque;
499 addr -= NVRAM->mem_base;
500 if (addr < 0x1FF0) {
501 NVRAM->buffer[addr] = value >> 8;
502 NVRAM->buffer[addr + 1] = value;
503 }
504 }
506 static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
507 {
508 m48t59_t *NVRAM = opaque;
510 addr -= NVRAM->mem_base;
511 if (addr < 0x1FF0) {
512 NVRAM->buffer[addr] = value >> 24;
513 NVRAM->buffer[addr + 1] = value >> 16;
514 NVRAM->buffer[addr + 2] = value >> 8;
515 NVRAM->buffer[addr + 3] = value;
516 }
517 }
519 static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
520 {
521 m48t59_t *NVRAM = opaque;
522 uint32_t retval = 0;
524 addr -= NVRAM->mem_base;
525 if (addr < 0x1FF0)
526 retval = NVRAM->buffer[addr];
528 return retval;
529 }
531 static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr)
532 {
533 m48t59_t *NVRAM = opaque;
534 uint32_t retval = 0;
536 addr -= NVRAM->mem_base;
537 if (addr < 0x1FF0) {
538 retval = NVRAM->buffer[addr] << 8;
539 retval |= NVRAM->buffer[addr + 1];
540 }
542 return retval;
543 }
545 static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr)
546 {
547 m48t59_t *NVRAM = opaque;
548 uint32_t retval = 0;
550 addr -= NVRAM->mem_base;
551 if (addr < 0x1FF0) {
552 retval = NVRAM->buffer[addr] << 24;
553 retval |= NVRAM->buffer[addr + 1] << 16;
554 retval |= NVRAM->buffer[addr + 2] << 8;
555 retval |= NVRAM->buffer[addr + 3];
556 }
558 return retval;
559 }
561 static CPUWriteMemoryFunc *nvram_write[] = {
562 &nvram_writeb,
563 &nvram_writew,
564 &nvram_writel,
565 };
567 static CPUReadMemoryFunc *nvram_read[] = {
568 &nvram_readb,
569 &nvram_readw,
570 &nvram_readl,
571 };
572 /* Initialisation routine */
573 m48t59_t *m48t59_init (int IRQ, uint32_t mem_base,
574 uint32_t io_base, uint16_t size)
575 {
576 m48t59_t *s;
578 s = qemu_mallocz(sizeof(m48t59_t));
579 if (!s)
580 return NULL;
581 s->buffer = qemu_mallocz(size);
582 if (!s->buffer) {
583 qemu_free(s);
584 return NULL;
585 }
586 s->IRQ = IRQ;
587 s->size = size;
588 s->mem_base = mem_base;
589 s->io_base = io_base;
590 s->addr = 0;
591 register_ioport_read(io_base, 0x04, 1, NVRAM_readb, s);
592 register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s);
593 if (mem_base != 0) {
594 s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s);
595 cpu_register_physical_memory(mem_base, 0x4000, s->mem_index);
596 }
597 s->alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, s);
598 s->wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, s);
599 s->lock = 0;
601 return s;
602 }