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.


integrated new configuration system
[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 #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     v3_lock_t nvram_lock;
107
108     uint_t        us;   //microseconds - for clock update - zeroed every second
109     uint_t        pus;  //microseconds - for periodic interrupt - cleared every period
110 };
111
112
113 struct rtc_stata {
114     uint_t        rate: 4;  // clock rate = 65536Hz / 2 rate (0110=1024 Hz)
115     uint_t        basis: 3; // time base, 010 = 32,768 Hz
116     uint_t        uip: 1;   // 1=update in progress
117 } __attribute__((__packed__)) __attribute__((__aligned__ (1)))  ;
118
119 struct rtc_statb {
120     uint_t        sum: 1;  // 1=summer (daylight savings)
121     uint_t        h24: 1;  // 1=24h clock
122     uint_t        dm: 1;   // 1=date/time is in bcd, 0=binary
123     uint_t        rec: 1;  // 1=rectangular signal
124     uint_t        ui: 1;   // 1=update interrupt
125     uint_t        ai: 1;   // 1=alarm interrupt
126     uint_t        pi: 1;   // 1=periodic interrupt
127     uint_t        set: 1;  // 1=blocked update
128 } __attribute__((__packed__))  __attribute__((__aligned__ (1))) ;
129
130 struct rtc_statc {
131     uint_t        res: 4;   // reserved
132     uint_t        uf: 1;    // 1=source of interrupt is update
133     uint_t        af: 1;    // 1=source of interrupt is alarm interrupt
134     uint_t        pf: 1;    // 1=source of interrupt is periodic interrupt
135     uint_t        irq: 1;   // 1=interrupt requested
136 }  __attribute__((__packed__))  __attribute__((__aligned__ (1))) ;
137
138 struct rtc_statd {
139     uint_t        res: 7;   // reserved
140     uint_t        val: 1;   // 1=cmos ram data is OK
141 }  __attribute__((__packed__))  __attribute__((__aligned__ (1))) ;
142
143
144
145
146 struct bcd_num {
147     uchar_t bot : 4;
148     uchar_t top : 4;
149 };
150
151
152
153 static void set_reg_num(struct nvram_internal * nvram, uint8_t reg_num) {
154     int major = (reg_num / 8);
155     int minor = reg_num % 8;
156
157     nvram->reg_map[major] |= (0x1 << minor);
158 }
159
160 static int is_reg_set(struct nvram_internal * nvram, uint8_t reg_num) {
161     int major = (reg_num / 8);
162     int minor = reg_num % 8;
163     
164     return (nvram->reg_map[major] & (0x1 << minor)) ? 1 : 0;
165 }
166
167
168 static void set_memory(struct nvram_internal * nvram, uint8_t reg, uint8_t val) {
169     set_reg_num(nvram, reg);
170     nvram->mem_state[reg] = val;
171 }
172
173 static int get_memory(struct nvram_internal * nvram, uint8_t reg, uint8_t * val) {
174
175     if (!is_reg_set(nvram, reg)) {
176         *val = 0;
177         return -1;
178     }
179
180     *val = nvram->mem_state[reg];
181     return 0;
182 }
183
184
185 static uchar_t add_to(uchar_t * left, uchar_t * right, uchar_t bcd) {
186     uchar_t temp;
187
188     if (bcd) { 
189         struct bcd_num * bl = (struct bcd_num *)left;
190         struct bcd_num * br = (struct bcd_num *)right;
191         uchar_t carry = 0;
192
193         bl->bot += br->bot;
194         carry = bl->bot / 0xa;
195         bl->bot %= 0xa;
196
197         bl->top += carry + br->top;
198         carry = bl->top / 0xa;
199         bl->top %= 0xa;
200
201         return carry;
202     } else {
203         temp = *left;
204         *left += *right;
205
206         if (*left < temp) { 
207             return 1;
208         } else {
209             return 0;
210         }
211     }
212 }
213
214
215 static uchar_t days_in_month(uchar_t month, uchar_t bcd) {
216     // This completely ignores Julian / Gregorian stuff right now
217
218     if (bcd) { 
219
220         switch (month) 
221             {
222                 case 0x1: //jan
223                 case 0x3: //march
224                 case 0x5: //may
225                 case 0x7: //july
226                 case 0x8: //aug
227                 case 0x10: //oct
228                 case 0x12: //dec
229                     return 0x31;
230                     break;
231                 case 0x4: //april
232                 case 0x6: //june
233                 case 0x9: //sept
234                 case 0x11: //nov
235                     return 0x30;
236                     break;
237                 case 0x2: //feb
238                     return 0x28;
239                     break;
240                 default:
241                     return 0x30;
242             }
243     
244     } else {
245
246         switch (month) 
247             {
248                 case 1: //jan
249                 case 3: //march
250                 case 5: //may
251                 case 7: //july
252                 case 8: //aug
253                 case 10: //oct
254                 case 12: //dec
255                     return 31;
256                     break;
257                 case 4: //april
258                 case 6: //june
259                 case 9: //sept
260                 case 11: //nov
261                     return 30;
262                     break;
263                 case 2: //feb
264                     return 28;
265                     break;
266                 default:
267                     return 30;
268             }
269     }
270 }
271
272
273 static void update_time( struct vm_device * dev, uint_t period_us) {
274     struct nvram_internal * data = (struct nvram_internal *) (dev->private_data);
275     struct rtc_stata * stata = (struct rtc_stata *) &((data->mem_state[NVRAM_REG_STAT_A]));
276     struct rtc_statb * statb = (struct rtc_statb *) &((data->mem_state[NVRAM_REG_STAT_B]));
277     struct rtc_statc * statc = (struct rtc_statc *) &((data->mem_state[NVRAM_REG_STAT_C]));
278     //struct rtc_statd *statd = (struct rtc_statd *) &((data->mem_state[NVRAM_REG_STAT_D]));
279     uchar_t * sec = (uchar_t *) &(data->mem_state[NVRAM_REG_SEC]);
280     uchar_t * min = (uchar_t *) &(data->mem_state[NVRAM_REG_MIN]);
281     uchar_t * hour = (uchar_t *) &(data->mem_state[NVRAM_REG_HOUR]);
282     uchar_t * weekday = (uchar_t *) &(data->mem_state[NVRAM_REG_WEEK_DAY]);
283     uchar_t * monthday = (uchar_t *) &(data->mem_state[NVRAM_REG_MONTH_DAY]);
284     uchar_t * month = (uchar_t *) &(data->mem_state[NVRAM_REG_MONTH]);
285     uchar_t * year = (uchar_t *) &(data->mem_state[NVRAM_REG_YEAR]);
286     uchar_t * cent = (uchar_t *) &(data->mem_state[NVRAM_REG_IBM_CENTURY_BYTE]);
287     uchar_t * seca = (uchar_t *) &(data->mem_state[NVRAM_REG_SEC_ALARM]);
288     uchar_t * mina = (uchar_t *) &(data->mem_state[NVRAM_REG_MIN_ALARM]);
289     uchar_t * houra = (uchar_t *) &(data->mem_state[NVRAM_REG_HOUR_ALARM]);
290     uchar_t hour24;
291
292     uchar_t bcd = (statb->dm == 1);
293     uchar_t carry = 0;
294     uchar_t nextday = 0;
295     uint_t  periodic_period;
296
297     //PrintDebug("nvram: sizeof(struct rtc_stata)=%d\n", sizeof(struct rtc_stata));
298
299
300     //PrintDebug("nvram: update_time\n",statb->pi);
301   
302     // We will set these flags on exit
303     statc->irq = 0;
304     statc->pf = 0;
305     statc->af = 0;
306     statc->uf = 0;
307
308     // We will reset us after one second
309     data->us += period_us;
310     // We will reset pus after one periodic_period
311     data->pus += period_us;
312
313     if (data->us > 1000000) { 
314         carry = 1;
315         carry = add_to(sec, &carry, bcd);
316
317         if (carry) { 
318             PrintDebug("nvram: somehow managed to get a carry in second update\n"); 
319         }
320
321         if ( (bcd && (*sec == 0x60)) || 
322              ((!bcd) && (*sec == 60))) { 
323   
324             *sec = 0;
325
326             carry = 1;
327             carry = add_to(min, &carry, bcd);
328             if (carry) { 
329                 PrintDebug("nvram: somehow managed to get a carry in minute update\n"); 
330             }
331
332             if ( (bcd && (*min == 0x60)) || 
333                  ((!bcd) && (*min == 60))) { 
334
335                 *min = 0;
336                 hour24 = *hour;
337
338                 if (!(statb->h24)) { 
339
340                     if (hour24 & 0x80) { 
341                         hour24 &= 0x8f;
342                         uchar_t temp = ((bcd) ? 0x12 : 12);
343                         add_to(&hour24, &temp, bcd);
344                     }
345                 }
346
347                 carry = 1;
348                 carry = add_to(&hour24, &carry, bcd);
349                 if (carry) { 
350                     PrintDebug("nvram: somehow managed to get a carry in hour update\n"); 
351                 }
352
353                 if ( (bcd && (hour24 == 0x24)) || 
354                      ((!bcd) && (hour24 == 24))) { 
355                     carry = 1;
356                     nextday = 1;
357                     hour24 = 0;
358                 } else {
359                     carry = 0;
360                 }
361
362
363                 if (statb->h24) { 
364                     *hour = hour24;
365                 } else {
366                     if ( (bcd && (hour24 < 0x12)) || 
367                          ((!bcd) && (hour24 < 12))) { 
368                         *hour = hour24;
369
370                     } else {
371
372                         if (!bcd) { 
373                             *hour = (hour24 - 12) | 0x80;
374                         } else {
375                             *hour = hour24;
376                             struct bcd_num * n = (struct bcd_num *)hour;
377
378                             if (n->bot < 0x2) { 
379                                 n->top--;
380                                 n->bot += 0xa;
381                             }
382
383                             n->bot -= 0x2;
384                             n->top -= 0x1;
385                         }
386                     }
387                 }
388
389                 // now see if we need to carry into the days and further
390                 if (nextday) { 
391                     carry = 1;
392                     add_to(weekday, &carry, bcd);
393
394                     *weekday %= 0x7;  // same regardless of bcd
395
396                     if ((*monthday) != days_in_month(*month, bcd)) {
397                         add_to(monthday, &carry, bcd);
398                     } else {
399                         *monthday = 0x1;
400
401                         carry = 1;
402                         add_to(month, &carry, bcd);
403
404                         if ( (bcd && (*month == 0x13)) || 
405                              ((!bcd) && (*month == 13))) { 
406                             *month = 1; // same for both 
407
408                             carry = 1;
409                             carry = add_to(year, &carry, bcd);
410
411                             if ( (bcd && carry) || 
412                                  ((!bcd) && (*year == 100))) { 
413                                 *year = 0;
414                                 carry = 1;
415                                 add_to(cent, &carry, bcd);
416                             }
417                         }
418                     }
419                 }
420             }
421         }
422
423
424         data->us -= 1000000;
425         // OK, now check for the alarm, if it is set to interrupt
426         if (statb->ai) { 
427             if ((*sec == *seca) && (*min == *mina) && (*hour == *houra)) { 
428                 statc->af = 1;
429                 PrintDebug("nvram: interrupt on alarm\n");
430             }
431         }
432     }
433
434     if (statb->pi) { 
435         periodic_period = 1000000 / (65536 / (0x1 << stata->rate));
436         if (data->pus >= periodic_period) { 
437             statc->pf = 1;
438             data->pus -= periodic_period;
439             PrintDebug("nvram: interrupt on periodic\n");
440         }
441     }
442
443     if (statb->ui) { 
444         statc->uf = 1;
445         PrintDebug("nvram: interrupt on update\n");
446     }
447
448     statc->irq = (statc->pf || statc->af || statc->uf);
449   
450     //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);
451   
452     // Interrupt associated VM, if needed
453     if (statc->irq) { 
454         PrintDebug("nvram: injecting interrupt\n");
455         v3_raise_irq(dev->vm, NVRAM_RTC_IRQ);
456     }
457 }
458
459
460 static int handle_timer_event(struct guest_info * info, 
461                               struct v3_timer_event * evt, 
462                               void * priv_data) {
463
464     struct vm_device * dev = (struct vm_device *)priv_data;
465
466     if (dev) {
467         struct nvram_internal * data = (struct nvram_internal *) (dev->private_data);
468         
469         addr_t irq_state = v3_lock_irqsave(data->nvram_lock);
470         update_time(dev, 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 vm_device * dev) {
596     struct guest_info * info = dev->vm;
597     struct nvram_internal * nvram = (struct nvram_internal *)dev->private_data;
598   
599     memset(nvram->mem_state, 0, NVRAM_REG_MAX);
600     memset(nvram->reg_map, 0, NVRAM_REG_MAX / 8);
601
602     v3_lock_init(&(nvram->nvram_lock));
603
604     //
605     // 2 1.44 MB floppy drives
606     //
607 #if 1
608     set_memory(nvram, NVRAM_REG_FLOPPY_TYPE, 0x44);
609 #else
610     set_memory(nvram, NVRAM_REG_FLOPPY_TYPE, 0x00);
611 #endif
612
613     //
614     // For old boot sequence style, do floppy first
615     //
616     set_memory(nvram, NVRAM_REG_BOOTSEQ_OLD, 0x10);
617
618 #if 0
619     // For new boot sequence style, do floppy, cd, then hd
620     set_memory(nvram, NVRAM_REG_BOOTSEQ_NEW_FIRST, 0x31);
621     set_memory(nvram, NVRAM_REG_BOOTSEQ_NEW_SECOND, 0x20);
622 #endif
623
624     // For new boot sequence style, do cd, hd, floppy
625     set_memory(nvram, NVRAM_REG_BOOTSEQ_NEW_FIRST, 0x23);
626     set_memory(nvram, NVRAM_REG_BOOTSEQ_NEW_SECOND, 0x10);
627   
628   
629     // Set equipment byte to note 2 floppies, vga display, keyboard,math,floppy
630     set_memory(nvram, NVRAM_REG_EQUIPMENT_BYTE, 0x4f);
631     // set_memory(nvram, NVRAM_REG_EQUIPMENT_BYTE, 0xf);
632   
633
634     // Set the shutdown status gently
635     // soft reset
636     set_memory(nvram, NVRAM_REG_SHUTDOWN_STATUS, 0x0);
637
638
639     // RTC status A
640     // 00100110 = no update in progress, base=32768 Hz, rate = 1024 Hz
641     set_memory(nvram, NVRAM_REG_STAT_A, 0x26); 
642
643     // RTC status B
644     // 00000100 = not setting, no interrupts, blocked rect signal, bcd mode, 24 hour, normal time
645     set_memory(nvram, NVRAM_REG_STAT_B, 0x06); 
646
647
648     // RTC status C
649     // No IRQ requested, result not do to any source
650     set_memory(nvram, NVRAM_REG_STAT_C, 0x00);
651
652     // RTC status D
653     // Battery is OK
654     set_memory(nvram, NVRAM_REG_STAT_D, 0x80);
655
656
657     // january 1, 2008, 00:00:00
658     set_memory(nvram, NVRAM_REG_SEC, 0x00);
659     set_memory(nvram, NVRAM_REG_SEC_ALARM, 0x00);
660     set_memory(nvram, NVRAM_REG_MIN, 0x00);
661     set_memory(nvram, NVRAM_REG_MIN_ALARM, 0x00);
662     set_memory(nvram, NVRAM_REG_HOUR, 0x00);
663     set_memory(nvram, NVRAM_REG_HOUR_ALARM, 0x00);
664
665     set_memory(nvram, NVRAM_REG_MONTH, 0x01);
666     set_memory(nvram, NVRAM_REG_MONTH_DAY, 0x1);
667     set_memory(nvram, NVRAM_REG_WEEK_DAY, 0x1);
668     set_memory(nvram, NVRAM_REG_YEAR, 0x08);
669
670     set_memory(nvram, NVRAM_REG_DIAGNOSTIC_STATUS, 0x00);
671     
672     nvram->us = 0;
673     nvram->pus = 0;
674
675     set_memory_size(nvram, info->mem_size);
676     init_harddrives(nvram);
677     
678     nvram->dev_state = NVRAM_READY;
679     nvram->thereg = 0;
680
681     return 0;
682 }
683
684
685
686
687 static int nvram_reset_device(struct vm_device * dev) {
688
689     return 0;
690 }
691
692
693
694
695
696 static int nvram_start_device(struct vm_device * dev) {
697     PrintDebug("nvram: start device\n");
698     return 0;
699 }
700
701
702 static int nvram_stop_device(struct vm_device * dev) {
703     PrintDebug("nvram: stop device\n");
704     return 0;
705 }
706
707
708
709
710 static int nvram_write_reg_port(ushort_t port,
711                                 void * src, 
712                                 uint_t length,
713                                 struct vm_device * dev) {
714
715     struct nvram_internal * data = (struct nvram_internal *)dev->private_data;
716     
717     memcpy(&(data->thereg), src, 1);
718     PrintDebug("Writing To NVRAM reg: 0x%x\n", data->thereg);
719
720     return 1;
721 }
722
723 static int nvram_read_data_port(ushort_t port,
724                                 void * dst, 
725                                 uint_t length,
726                                 struct vm_device * dev) {
727
728     struct nvram_internal * data = (struct nvram_internal *)dev->private_data;
729
730     addr_t irq_state = v3_lock_irqsave(data->nvram_lock);
731
732     if (get_memory(data, data->thereg, (uint8_t *)dst) == -1) {
733         PrintError("Register %d (0x%x) Not set\n", data->thereg, data->thereg);
734
735         v3_unlock_irqrestore(data->nvram_lock, irq_state);
736
737         return -1;
738     }
739
740     PrintDebug("nvram_read_data_port(0x%x)  =  0x%x\n", data->thereg, *(uint8_t *)dst);
741
742     // hack
743     if (data->thereg == NVRAM_REG_STAT_A) { 
744         data->mem_state[data->thereg] ^= 0x80;  // toggle Update in progess
745     }
746
747     v3_unlock_irqrestore(data->nvram_lock, irq_state);
748
749     return 1;
750 }
751
752
753 static int nvram_write_data_port(ushort_t port,
754                                  void * src, 
755                                  uint_t length,
756                                  struct vm_device * dev) {
757
758     struct nvram_internal * data = (struct nvram_internal *)dev->private_data;
759
760     addr_t irq_state = v3_lock_irqsave(data->nvram_lock);
761
762     set_memory(data, data->thereg, *(uint8_t *)src);
763
764     v3_unlock_irqrestore(data->nvram_lock, irq_state);
765
766     PrintDebug("nvram_write_data_port(0x%x) = 0x%x\n", 
767                data->thereg, data->mem_state[data->thereg]);
768
769     return 1;
770 }
771
772
773
774
775 static int nvram_free(struct vm_device * dev) {
776     v3_dev_unhook_io(dev, NVRAM_REG_PORT);
777     v3_dev_unhook_io(dev, NVRAM_DATA_PORT);
778
779     return 0;
780 }
781
782
783
784
785
786 static struct v3_device_ops dev_ops = {  
787     .free = nvram_free,
788     .reset = nvram_reset_device,
789     .start = nvram_start_device,
790     .stop = nvram_stop_device,
791 };
792
793
794
795
796
797 static int nvram_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
798     struct nvram_internal * nvram_state = NULL;
799     struct vm_device * ide = v3_find_dev(vm, v3_cfg_val(cfg, "storage"));
800     char * name = v3_cfg_val(cfg, "name");
801
802     if (!ide) {
803         PrintError("Could not find IDE device\n");
804         return -1;
805     }
806
807     PrintDebug("nvram: init_device\n");
808     nvram_state = (struct nvram_internal *)V3_Malloc(sizeof(struct nvram_internal) + 1000);
809
810     PrintDebug("nvram: internal at %p\n", (void *)nvram_state);
811
812     nvram_state->ide = ide;
813
814     struct vm_device * dev = v3_allocate_device(name, &dev_ops, nvram_state);
815
816
817     if (v3_attach_device(vm, dev) == -1) {
818         PrintError("Could not attach device %s\n", name);
819         return -1;
820     }
821
822     init_nvram_state(dev);
823
824     // hook ports
825     v3_dev_hook_io(dev, NVRAM_REG_PORT, NULL, &nvram_write_reg_port);
826     v3_dev_hook_io(dev, NVRAM_DATA_PORT, &nvram_read_data_port, &nvram_write_data_port);
827   
828     v3_hook_host_event(vm, HOST_TIMER_EVT, V3_HOST_EVENT_HANDLER(handle_timer_event), dev);
829
830     return 0;
831 }
832
833 device_register("NVRAM", nvram_init)