Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


deallocation of devices
[palacios.releases.git] / palacios / src / devices / nvram.c
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Peter Dinda <pdinda@northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Peter Dinda <pdinda@northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20
21 #include <palacios/vmm_dev_mgr.h>
22 #include <palacios/vmm.h>
23 #include <palacios/vmm_types.h>
24
25 #include <palacios/vmm_lock.h>
26
27 #include <devices/ide.h>
28 #include <palacios/vmm_intr.h>
29 #include <palacios/vmm_host_events.h>
30 #include <palacios/vm_guest.h>
31
32 #ifndef CONFIG_DEBUG_NVRAM
33 #undef PrintDebug
34 #define PrintDebug(fmt, args...)
35 #endif
36
37
38 #define NVRAM_REG_PORT  0x70
39 #define NVRAM_DATA_PORT 0x71
40
41 #define NVRAM_RTC_IRQ   0x8
42
43
44 typedef enum {NVRAM_READY, NVRAM_REG_POSTED} nvram_state_t;
45
46
47 #define NVRAM_REG_MAX   256
48
49
50 // These are borrowed from Bochs, which borrowed from
51 // Ralf Brown's interupt list, and extended
52 #define NVRAM_REG_SEC                     0x00
53 #define NVRAM_REG_SEC_ALARM               0x01
54 #define NVRAM_REG_MIN                     0x02
55 #define NVRAM_REG_MIN_ALARM               0x03
56 #define NVRAM_REG_HOUR                    0x04
57 #define NVRAM_REG_HOUR_ALARM              0x05
58 #define NVRAM_REG_WEEK_DAY                0x06
59 #define NVRAM_REG_MONTH_DAY               0x07
60 #define NVRAM_REG_MONTH                   0x08
61 #define NVRAM_REG_YEAR                    0x09
62 #define NVRAM_REG_STAT_A                  0x0a
63 #define NVRAM_REG_STAT_B                  0x0b
64 #define NVRAM_REG_STAT_C                  0x0c
65 #define NVRAM_REG_STAT_D                  0x0d
66 #define NVRAM_REG_DIAGNOSTIC_STATUS       0x0e  
67 #define NVRAM_REG_SHUTDOWN_STATUS         0x0f
68
69 #define NVRAM_IBM_HD_DATA                 0x12
70 #define NVRAM_IDE_TRANSLATION             0x39
71
72 #define NVRAM_REG_FLOPPY_TYPE             0x10
73 #define NVRAM_REG_EQUIPMENT_BYTE          0x14
74
75 #define NVRAM_REG_BASE_MEMORY_HIGH        0x16
76 #define NVRAM_REG_BASE_MEMORY_LOW         0x15
77
78 #define NVRAM_REG_EXT_MEMORY_HIGH         0x18
79 #define NVRAM_REG_EXT_MEMORY_LOW          0x17
80
81 #define NVRAM_REG_EXT_MEMORY_2ND_HIGH     0x31
82 #define NVRAM_REG_EXT_MEMORY_2ND_LOW      0x30
83
84 #define NVRAM_REG_BOOTSEQ_OLD             0x2d
85
86 #define NVRAM_REG_AMI_BIG_MEMORY_HIGH     0x35
87 #define NVRAM_REG_AMI_BIG_MEMORY_LOW      0x34
88
89 #define NVRAM_REG_CSUM_HIGH               0x2e
90 #define NVRAM_REG_CSUM_LOW                0x2f
91 #define NVRAM_REG_IBM_CENTURY_BYTE        0x32  
92 #define NVRAM_REG_IBM_PS2_CENTURY_BYTE    0x37  
93
94 #define NVRAM_REG_BOOTSEQ_NEW_FIRST       0x3D
95 #define NVRAM_REG_BOOTSEQ_NEW_SECOND      0x38
96
97
98 struct nvram_internal {
99     nvram_state_t dev_state;
100     uchar_t       thereg;
101     uchar_t       mem_state[NVRAM_REG_MAX];
102     uchar_t       reg_map[NVRAM_REG_MAX / 8];
103
104     struct vm_device * ide;
105
106     struct v3_vm_info * vm;
107
108     v3_lock_t nvram_lock;
109
110     uint_t        us;   //microseconds - for clock update - zeroed every second
111     uint_t        pus;  //microseconds - for periodic interrupt - cleared every period
112 };
113
114
115 struct rtc_stata {
116     uint_t        rate: 4;  // clock rate = 65536Hz / 2 rate (0110=1024 Hz)
117     uint_t        basis: 3; // time base, 010 = 32,768 Hz
118     uint_t        uip: 1;   // 1=update in progress
119 } __attribute__((__packed__)) __attribute__((__aligned__ (1)))  ;
120
121 struct rtc_statb {
122     uint_t        sum: 1;  // 1=summer (daylight savings)
123     uint_t        h24: 1;  // 1=24h clock
124     uint_t        dm: 1;   // 1=date/time is in bcd, 0=binary
125     uint_t        rec: 1;  // 1=rectangular signal
126     uint_t        ui: 1;   // 1=update interrupt
127     uint_t        ai: 1;   // 1=alarm interrupt
128     uint_t        pi: 1;   // 1=periodic interrupt
129     uint_t        set: 1;  // 1=blocked update
130 } __attribute__((__packed__))  __attribute__((__aligned__ (1))) ;
131
132 struct rtc_statc {
133     uint_t        res: 4;   // reserved
134     uint_t        uf: 1;    // 1=source of interrupt is update
135     uint_t        af: 1;    // 1=source of interrupt is alarm interrupt
136     uint_t        pf: 1;    // 1=source of interrupt is periodic interrupt
137     uint_t        irq: 1;   // 1=interrupt requested
138 }  __attribute__((__packed__))  __attribute__((__aligned__ (1))) ;
139
140 struct rtc_statd {
141     uint_t        res: 7;   // reserved
142     uint_t        val: 1;   // 1=cmos ram data is OK
143 }  __attribute__((__packed__))  __attribute__((__aligned__ (1))) ;
144
145
146
147
148 struct bcd_num {
149     uchar_t bot : 4;
150     uchar_t top : 4;
151 };
152
153
154
155 static void set_reg_num(struct nvram_internal * nvram, uint8_t reg_num) {
156     int major = (reg_num / 8);
157     int minor = reg_num % 8;
158
159     nvram->reg_map[major] |= (0x1 << minor);
160 }
161
162 static int is_reg_set(struct nvram_internal * nvram, uint8_t reg_num) {
163     int major = (reg_num / 8);
164     int minor = reg_num % 8;
165     
166     return (nvram->reg_map[major] & (0x1 << minor)) ? 1 : 0;
167 }
168
169
170 static void set_memory(struct nvram_internal * nvram, uint8_t reg, uint8_t val) {
171     set_reg_num(nvram, reg);
172     nvram->mem_state[reg] = val;
173 }
174
175 static int get_memory(struct nvram_internal * nvram, uint8_t reg, uint8_t * val) {
176
177     if (!is_reg_set(nvram, reg)) {
178         *val = 0;
179         return -1;
180     }
181
182     *val = nvram->mem_state[reg];
183     return 0;
184 }
185
186
187 static uchar_t add_to(uchar_t * left, uchar_t * right, uchar_t bcd) {
188     uchar_t temp;
189
190     if (bcd) { 
191         struct bcd_num * bl = (struct bcd_num *)left;
192         struct bcd_num * br = (struct bcd_num *)right;
193         uchar_t carry = 0;
194
195         bl->bot += br->bot;
196         carry = bl->bot / 0xa;
197         bl->bot %= 0xa;
198
199         bl->top += carry + br->top;
200         carry = bl->top / 0xa;
201         bl->top %= 0xa;
202
203         return carry;
204     } else {
205         temp = *left;
206         *left += *right;
207
208         if (*left < temp) { 
209             return 1;
210         } else {
211             return 0;
212         }
213     }
214 }
215
216
217 static uchar_t days_in_month(uchar_t month, uchar_t bcd) {
218     // This completely ignores Julian / Gregorian stuff right now
219
220     if (bcd) { 
221
222         switch (month) 
223             {
224                 case 0x1: //jan
225                 case 0x3: //march
226                 case 0x5: //may
227                 case 0x7: //july
228                 case 0x8: //aug
229                 case 0x10: //oct
230                 case 0x12: //dec
231                     return 0x31;
232                     break;
233                 case 0x4: //april
234                 case 0x6: //june
235                 case 0x9: //sept
236                 case 0x11: //nov
237                     return 0x30;
238                     break;
239                 case 0x2: //feb
240                     return 0x28;
241                     break;
242                 default:
243                     return 0x30;
244             }
245     
246     } else {
247
248         switch (month) 
249             {
250                 case 1: //jan
251                 case 3: //march
252                 case 5: //may
253                 case 7: //july
254                 case 8: //aug
255                 case 10: //oct
256                 case 12: //dec
257                     return 31;
258                     break;
259                 case 4: //april
260                 case 6: //june
261                 case 9: //sept
262                 case 11: //nov
263                     return 30;
264                     break;
265                 case 2: //feb
266                     return 28;
267                     break;
268                 default:
269                     return 30;
270             }
271     }
272 }
273
274
275 static void update_time(struct nvram_internal * data, uint_t period_us) {
276     struct rtc_stata * stata = (struct rtc_stata *) &((data->mem_state[NVRAM_REG_STAT_A]));
277     struct rtc_statb * statb = (struct rtc_statb *) &((data->mem_state[NVRAM_REG_STAT_B]));
278     struct rtc_statc * statc = (struct rtc_statc *) &((data->mem_state[NVRAM_REG_STAT_C]));
279     //struct rtc_statd *statd = (struct rtc_statd *) &((data->mem_state[NVRAM_REG_STAT_D]));
280     uchar_t * sec = (uchar_t *) &(data->mem_state[NVRAM_REG_SEC]);
281     uchar_t * min = (uchar_t *) &(data->mem_state[NVRAM_REG_MIN]);
282     uchar_t * hour = (uchar_t *) &(data->mem_state[NVRAM_REG_HOUR]);
283     uchar_t * weekday = (uchar_t *) &(data->mem_state[NVRAM_REG_WEEK_DAY]);
284     uchar_t * monthday = (uchar_t *) &(data->mem_state[NVRAM_REG_MONTH_DAY]);
285     uchar_t * month = (uchar_t *) &(data->mem_state[NVRAM_REG_MONTH]);
286     uchar_t * year = (uchar_t *) &(data->mem_state[NVRAM_REG_YEAR]);
287     uchar_t * cent = (uchar_t *) &(data->mem_state[NVRAM_REG_IBM_CENTURY_BYTE]);
288     uchar_t * seca = (uchar_t *) &(data->mem_state[NVRAM_REG_SEC_ALARM]);
289     uchar_t * mina = (uchar_t *) &(data->mem_state[NVRAM_REG_MIN_ALARM]);
290     uchar_t * houra = (uchar_t *) &(data->mem_state[NVRAM_REG_HOUR_ALARM]);
291     uchar_t hour24;
292
293     uchar_t bcd = (statb->dm == 1);
294     uchar_t carry = 0;
295     uchar_t nextday = 0;
296     uint_t  periodic_period;
297
298     //PrintDebug("nvram: sizeof(struct rtc_stata)=%d\n", sizeof(struct rtc_stata));
299
300
301     //PrintDebug("nvram: update_time\n",statb->pi);
302   
303     // We will set these flags on exit
304     statc->irq = 0;
305     statc->pf = 0;
306     statc->af = 0;
307     statc->uf = 0;
308
309     // We will reset us after one second
310     data->us += period_us;
311     // We will reset pus after one periodic_period
312     data->pus += period_us;
313
314     if (data->us > 1000000) { 
315         carry = 1;
316         carry = add_to(sec, &carry, bcd);
317
318         if (carry) { 
319             PrintDebug("nvram: somehow managed to get a carry in second update\n"); 
320         }
321
322         if ( (bcd && (*sec == 0x60)) || 
323              ((!bcd) && (*sec == 60))) { 
324   
325             *sec = 0;
326
327             carry = 1;
328             carry = add_to(min, &carry, bcd);
329             if (carry) { 
330                 PrintDebug("nvram: somehow managed to get a carry in minute update\n"); 
331             }
332
333             if ( (bcd && (*min == 0x60)) || 
334                  ((!bcd) && (*min == 60))) { 
335
336                 *min = 0;
337                 hour24 = *hour;
338
339                 if (!(statb->h24)) { 
340
341                     if (hour24 & 0x80) { 
342                         hour24 &= 0x8f;
343                         uchar_t temp = ((bcd) ? 0x12 : 12);
344                         add_to(&hour24, &temp, bcd);
345                     }
346                 }
347
348                 carry = 1;
349                 carry = add_to(&hour24, &carry, bcd);
350                 if (carry) { 
351                     PrintDebug("nvram: somehow managed to get a carry in hour update\n"); 
352                 }
353
354                 if ( (bcd && (hour24 == 0x24)) || 
355                      ((!bcd) && (hour24 == 24))) { 
356                     carry = 1;
357                     nextday = 1;
358                     hour24 = 0;
359                 } else {
360                     carry = 0;
361                 }
362
363
364                 if (statb->h24) { 
365                     *hour = hour24;
366                 } else {
367                     if ( (bcd && (hour24 < 0x12)) || 
368                          ((!bcd) && (hour24 < 12))) { 
369                         *hour = hour24;
370
371                     } else {
372
373                         if (!bcd) { 
374                             *hour = (hour24 - 12) | 0x80;
375                         } else {
376                             *hour = hour24;
377                             struct bcd_num * n = (struct bcd_num *)hour;
378
379                             if (n->bot < 0x2) { 
380                                 n->top--;
381                                 n->bot += 0xa;
382                             }
383
384                             n->bot -= 0x2;
385                             n->top -= 0x1;
386                         }
387                     }
388                 }
389
390                 // now see if we need to carry into the days and further
391                 if (nextday) { 
392                     carry = 1;
393                     add_to(weekday, &carry, bcd);
394
395                     *weekday %= 0x7;  // same regardless of bcd
396
397                     if ((*monthday) != days_in_month(*month, bcd)) {
398                         add_to(monthday, &carry, bcd);
399                     } else {
400                         *monthday = 0x1;
401
402                         carry = 1;
403                         add_to(month, &carry, bcd);
404
405                         if ( (bcd && (*month == 0x13)) || 
406                              ((!bcd) && (*month == 13))) { 
407                             *month = 1; // same for both 
408
409                             carry = 1;
410                             carry = add_to(year, &carry, bcd);
411
412                             if ( (bcd && carry) || 
413                                  ((!bcd) && (*year == 100))) { 
414                                 *year = 0;
415                                 carry = 1;
416                                 add_to(cent, &carry, bcd);
417                             }
418                         }
419                     }
420                 }
421             }
422         }
423
424
425         data->us -= 1000000;
426         // OK, now check for the alarm, if it is set to interrupt
427         if (statb->ai) { 
428             if ((*sec == *seca) && (*min == *mina) && (*hour == *houra)) { 
429                 statc->af = 1;
430                 PrintDebug("nvram: interrupt on alarm\n");
431             }
432         }
433     }
434
435     if (statb->pi) { 
436         periodic_period = 1000000 / (65536 / (0x1 << stata->rate));
437         if (data->pus >= periodic_period) { 
438             statc->pf = 1;
439             data->pus -= periodic_period;
440             PrintDebug("nvram: interrupt on periodic\n");
441         }
442     }
443
444     if (statb->ui) { 
445         statc->uf = 1;
446         PrintDebug("nvram: interrupt on update\n");
447     }
448
449     statc->irq = (statc->pf || statc->af || statc->uf);
450   
451     //PrintDebug("nvram: time is now: YMDHMS: 0x%x:0x%x:0x%x:0x%x:0x%x,0x%x bcd=%d\n", *year, *month, *monthday, *hour, *min, *sec,bcd);
452   
453     // Interrupt associated VM, if needed
454     if (statc->irq) { 
455         PrintDebug("nvram: injecting interrupt\n");
456         v3_raise_irq(data->vm, NVRAM_RTC_IRQ);
457     }
458 }
459
460
461 static int handle_timer_event(struct v3_vm_info * vm, 
462                               struct v3_timer_event * evt, 
463                               void * priv_data) {
464
465
466     struct nvram_internal * data = priv_data;
467
468     if (data) {
469         addr_t irq_state = v3_lock_irqsave(data->nvram_lock);
470         update_time(data, evt->period_us);
471         v3_unlock_irqrestore(data->nvram_lock, irq_state);
472     }
473   
474     return 0;
475 }
476
477
478
479 static void set_memory_size(struct nvram_internal * nvram, addr_t bytes) {
480     // 1. Conventional Mem: 0-640k in K
481     // 2. Extended Mem: 0-16MB in K
482     // 3. Big Mem: 0-4G in 64K
483
484     if (bytes > 640 * 1024) {
485         set_memory(nvram, NVRAM_REG_BASE_MEMORY_HIGH, 0x02);
486         set_memory(nvram, NVRAM_REG_BASE_MEMORY_LOW, 0x80);
487
488         //      nvram->mem_state[NVRAM_REG_BASE_MEMORY_HIGH] = 0x02;
489         //      nvram->mem_state[NVRAM_REG_BASE_MEMORY_LOW] = 0x80;
490     } else {
491         uint16_t memk = bytes * 1024;
492         set_memory(nvram, NVRAM_REG_BASE_MEMORY_HIGH, (memk >> 8) & 0x00ff);
493         set_memory(nvram, NVRAM_REG_BASE_MEMORY_LOW, memk & 0x00ff);
494
495         return;
496     }
497
498     if (bytes > (16 * 1024 * 1024)) {
499         // Set extended memory to 15 MB
500         set_memory(nvram, NVRAM_REG_EXT_MEMORY_HIGH, 0x3C);
501         set_memory(nvram, NVRAM_REG_EXT_MEMORY_LOW, 0x00);
502         set_memory(nvram, NVRAM_REG_EXT_MEMORY_2ND_HIGH, 0x3C);
503         set_memory(nvram, NVRAM_REG_EXT_MEMORY_2ND_LOW, 0x00);
504     } else {
505         uint16_t memk = bytes * 1024;
506
507         set_memory(nvram, NVRAM_REG_EXT_MEMORY_HIGH, (memk >> 8) & 0x00ff);
508         set_memory(nvram, NVRAM_REG_EXT_MEMORY_LOW, memk & 0x00ff);
509         set_memory(nvram, NVRAM_REG_EXT_MEMORY_2ND_HIGH, (memk >> 8) & 0x00ff);
510         set_memory(nvram, NVRAM_REG_EXT_MEMORY_2ND_LOW, memk & 0x00ff);
511
512         return;
513     }
514
515     {
516         // Set the extended memory beyond 16 MB in 64k chunks
517         uint16_t mem_chunks = (bytes - (1024 * 1024 * 16)) / (1024 * 64);
518
519         set_memory(nvram, NVRAM_REG_AMI_BIG_MEMORY_HIGH, (mem_chunks >> 8) & 0x00ff);
520         set_memory(nvram, NVRAM_REG_AMI_BIG_MEMORY_LOW, mem_chunks & 0x00ff);
521     }
522
523     return;
524 }
525
526
527
528 static void init_harddrives(struct nvram_internal * nvram) {
529     uint8_t hd_data = 0;
530     uint32_t cyls;
531     uint32_t sects;
532     uint32_t heads;
533     int i = 0;
534     int info_base_reg = 0x1b;
535     int type_reg = 0x19;
536
537     // 0x19 == first drive type
538     // 0x1a == second drive type
539
540     // 0x1b == first drive geometry base
541     // 0x24 == second drive geometry base
542
543     // It looks like the BIOS only tracks the disks on the first channel at 0x12?
544     for (i = 0; i < 2; i++) {
545         if (v3_ide_get_geometry(nvram->ide, 0, i, &cyls, &heads, &sects) == 0) {
546
547             int info_reg = info_base_reg + (i * 9);
548
549             set_memory(nvram, type_reg + i, 0x2f);
550
551             set_memory(nvram, info_reg, cyls & 0xff);
552             set_memory(nvram, info_reg + 1, (cyls >> 8) & 0xff);
553             set_memory(nvram, info_reg + 2, heads & 0xff);
554
555             // Write precomp cylinder (1 and 2)
556             set_memory(nvram, info_reg + 3, 0xff);
557             set_memory(nvram, info_reg + 4, 0xff);
558
559             // harddrive control byte 
560             set_memory(nvram, info_reg + 5, 0xc0 | ((heads > 8) << 3));
561
562             set_memory(nvram, info_reg + 6, cyls & 0xff);
563             set_memory(nvram, info_reg + 7, (cyls >> 8) & 0xff);
564
565             set_memory(nvram, info_reg + 8, sects & 0xff);
566             
567             hd_data |= (0xf0 >> (i * 4));
568         }
569     }
570
571     set_memory(nvram, NVRAM_IBM_HD_DATA, hd_data);
572     
573     {
574 #define TRANSLATE_NONE  0x0
575 #define TRANSLATE_LBA   0x1
576 #define TRANSLATE_LARGE 0x2
577 #define TRANSLATE_RECHS 0x3
578         // We're going to do LBA translation for everything...
579         uint8_t trans = 0;
580
581         for (i = 0; i < 4; i++) {
582             int chan_num = i / 2;
583             int drive_num = i % 2;
584             uint32_t tmp[3];
585
586             if (v3_ide_get_geometry(nvram->ide, chan_num, drive_num, &tmp[0], &tmp[1], &tmp[2]) == 0) {
587                 trans |= TRANSLATE_LBA << (i * 2);
588             }
589         }
590
591         set_memory(nvram, NVRAM_IDE_TRANSLATION, trans);
592     }
593 }
594
595 static int init_nvram_state(struct v3_vm_info * vm, struct nvram_internal * nvram) {
596
597     memset(nvram->mem_state, 0, NVRAM_REG_MAX);
598     memset(nvram->reg_map, 0, NVRAM_REG_MAX / 8);
599
600     v3_lock_init(&(nvram->nvram_lock));
601
602     //
603     // 2 1.44 MB floppy drives
604     //
605 #if 1
606     set_memory(nvram, NVRAM_REG_FLOPPY_TYPE, 0x44);
607 #else
608     set_memory(nvram, NVRAM_REG_FLOPPY_TYPE, 0x00);
609 #endif
610
611     //
612     // For old boot sequence style, do floppy first
613     //
614     set_memory(nvram, NVRAM_REG_BOOTSEQ_OLD, 0x10);
615
616 #if 0
617     // For new boot sequence style, do floppy, cd, then hd
618     set_memory(nvram, NVRAM_REG_BOOTSEQ_NEW_FIRST, 0x31);
619     set_memory(nvram, NVRAM_REG_BOOTSEQ_NEW_SECOND, 0x20);
620 #endif
621
622     // For new boot sequence style, do cd, hd, floppy
623     set_memory(nvram, NVRAM_REG_BOOTSEQ_NEW_FIRST, 0x23);
624     set_memory(nvram, NVRAM_REG_BOOTSEQ_NEW_SECOND, 0x10);
625   
626   
627     // Set equipment byte to note 2 floppies, vga display, keyboard,math,floppy
628     set_memory(nvram, NVRAM_REG_EQUIPMENT_BYTE, 0x4f);
629     // set_memory(nvram, NVRAM_REG_EQUIPMENT_BYTE, 0xf);
630   
631
632     // Set the shutdown status gently
633     // soft reset
634     set_memory(nvram, NVRAM_REG_SHUTDOWN_STATUS, 0x0);
635
636
637     // RTC status A
638     // 00100110 = no update in progress, base=32768 Hz, rate = 1024 Hz
639     set_memory(nvram, NVRAM_REG_STAT_A, 0x26); 
640
641     // RTC status B
642     // 00000100 = not setting, no interrupts, blocked rect signal, bcd mode, 24 hour, normal time
643     set_memory(nvram, NVRAM_REG_STAT_B, 0x06); 
644
645
646     // RTC status C
647     // No IRQ requested, result not do to any source
648     set_memory(nvram, NVRAM_REG_STAT_C, 0x00);
649
650     // RTC status D
651     // Battery is OK
652     set_memory(nvram, NVRAM_REG_STAT_D, 0x80);
653
654
655     // january 1, 2008, 00:00:00
656     set_memory(nvram, NVRAM_REG_SEC, 0x00);
657     set_memory(nvram, NVRAM_REG_SEC_ALARM, 0x00);
658     set_memory(nvram, NVRAM_REG_MIN, 0x00);
659     set_memory(nvram, NVRAM_REG_MIN_ALARM, 0x00);
660     set_memory(nvram, NVRAM_REG_HOUR, 0x00);
661     set_memory(nvram, NVRAM_REG_HOUR_ALARM, 0x00);
662
663     set_memory(nvram, NVRAM_REG_MONTH, 0x01);
664     set_memory(nvram, NVRAM_REG_MONTH_DAY, 0x1);
665     set_memory(nvram, NVRAM_REG_WEEK_DAY, 0x1);
666     set_memory(nvram, NVRAM_REG_YEAR, 0x08);
667
668     set_memory(nvram, NVRAM_REG_DIAGNOSTIC_STATUS, 0x00);
669     
670     nvram->us = 0;
671     nvram->pus = 0;
672
673     set_memory_size(nvram, vm->mem_size);
674     init_harddrives(nvram);
675     
676     nvram->dev_state = NVRAM_READY;
677     nvram->thereg = 0;
678
679     return 0;
680 }
681
682
683
684
685
686
687 static int nvram_write_reg_port(struct guest_info * core, ushort_t port,
688                                 void * src, uint_t length, void * priv_data) {
689
690     struct nvram_internal * data = priv_data;
691     
692     memcpy(&(data->thereg), src, 1);
693     PrintDebug("Writing To NVRAM reg: 0x%x\n", data->thereg);
694
695     return 1;
696 }
697
698 static int nvram_read_data_port(struct guest_info * core, ushort_t port,
699                                 void * dst, uint_t length, void * priv_data) {
700
701     struct nvram_internal * data = priv_data;
702
703     addr_t irq_state = v3_lock_irqsave(data->nvram_lock);
704
705     if (get_memory(data, data->thereg, (uint8_t *)dst) == -1) {
706         PrintError("Register %d (0x%x) Not set\n", data->thereg, data->thereg);
707
708         v3_unlock_irqrestore(data->nvram_lock, irq_state);
709
710         return -1;
711     }
712
713     PrintDebug("nvram_read_data_port(0x%x)  =  0x%x\n", data->thereg, *(uint8_t *)dst);
714
715     // hack
716     if (data->thereg == NVRAM_REG_STAT_A) { 
717         data->mem_state[data->thereg] ^= 0x80;  // toggle Update in progess
718     }
719
720     v3_unlock_irqrestore(data->nvram_lock, irq_state);
721
722     return 1;
723 }
724
725
726 static int nvram_write_data_port(struct guest_info * core, ushort_t port,
727                                  void * src, uint_t length, void * priv_data) {
728
729     struct nvram_internal * data = priv_data;
730
731     addr_t irq_state = v3_lock_irqsave(data->nvram_lock);
732
733     set_memory(data, data->thereg, *(uint8_t *)src);
734
735     v3_unlock_irqrestore(data->nvram_lock, irq_state);
736
737     PrintDebug("nvram_write_data_port(0x%x) = 0x%x\n", 
738                data->thereg, data->mem_state[data->thereg]);
739
740     return 1;
741 }
742
743
744
745
746 static int nvram_free(struct nvram_internal * nvram_state) {
747
748     // unregister host events
749
750     V3_Free(nvram_state);
751     return 0;
752 }
753
754
755
756
757
758 static struct v3_device_ops dev_ops = {  
759     .free = (int (*)(void *))nvram_free,
760 };
761
762
763
764
765
766 static int nvram_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
767     struct nvram_internal * nvram_state = NULL;
768     struct vm_device * ide = v3_find_dev(vm, v3_cfg_val(cfg, "storage"));
769     char * dev_id = v3_cfg_val(cfg, "ID");
770     int ret = 0;
771
772     if (!ide) {
773         PrintError("Could not find IDE device\n");
774         return -1;
775     }
776
777     PrintDebug("nvram: init_device\n");
778     nvram_state = (struct nvram_internal *)V3_Malloc(sizeof(struct nvram_internal) + 1000);
779
780     PrintDebug("nvram: internal at %p\n", (void *)nvram_state);
781
782     nvram_state->ide = ide;
783     nvram_state->vm = vm;
784
785     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, nvram_state);
786
787     if (dev == NULL) {
788         PrintError("Could not attach device %s\n", dev_id);
789         V3_Free(nvram_state);
790         return -1;
791     }
792
793     init_nvram_state(vm, nvram_state);
794
795     // hook ports
796     ret |= v3_dev_hook_io(dev, NVRAM_REG_PORT, NULL, &nvram_write_reg_port);
797     ret |= v3_dev_hook_io(dev, NVRAM_DATA_PORT, &nvram_read_data_port, &nvram_write_data_port);
798   
799     if (ret != 0) {
800         PrintError("Error hooking NVRAM IO ports\n");
801         v3_remove_device(dev);
802         return -1;
803     }
804
805     v3_hook_host_event(vm, HOST_TIMER_EVT, V3_HOST_EVENT_HANDLER(handle_timer_event), nvram_state);
806
807     return 0;
808 }
809
810 device_register("NVRAM", nvram_init)