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.


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