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.


OpenBSD reads the century byte, which wasn't being initialized.
[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     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     set_memory(nvram, NVRAM_REG_IBM_CENTURY_BYTE, 0x20);
668
669     set_memory(nvram, NVRAM_REG_DIAGNOSTIC_STATUS, 0x00);
670     
671     nvram->us = 0;
672     nvram->pus = 0;
673
674     set_memory_size(nvram, vm->mem_size);
675     init_harddrives(nvram);
676     
677     nvram->dev_state = NVRAM_READY;
678     nvram->thereg = 0;
679
680     return 0;
681 }
682
683
684
685
686
687
688 static int nvram_write_reg_port(struct guest_info * core, ushort_t port,
689                                 void * src, uint_t length, void * priv_data) {
690
691     struct nvram_internal * data = priv_data;
692     
693     memcpy(&(data->thereg), src, 1);
694     PrintDebug("Writing To NVRAM reg: 0x%x\n", data->thereg);
695
696     return 1;
697 }
698
699 static int nvram_read_data_port(struct guest_info * core, ushort_t port,
700                                 void * dst, uint_t length, void * priv_data) {
701
702     struct nvram_internal * data = priv_data;
703
704     addr_t irq_state = v3_lock_irqsave(data->nvram_lock);
705
706     if (get_memory(data, data->thereg, (uint8_t *)dst) == -1) {
707         PrintError("Register %d (0x%x) Not set\n", data->thereg, data->thereg);
708
709         v3_unlock_irqrestore(data->nvram_lock, irq_state);
710
711         return -1;
712     }
713
714     PrintDebug("nvram_read_data_port(0x%x)  =  0x%x\n", data->thereg, *(uint8_t *)dst);
715
716     // hack
717     if (data->thereg == NVRAM_REG_STAT_A) { 
718         data->mem_state[data->thereg] ^= 0x80;  // toggle Update in progess
719     }
720
721     v3_unlock_irqrestore(data->nvram_lock, irq_state);
722
723     return 1;
724 }
725
726
727 static int nvram_write_data_port(struct guest_info * core, ushort_t port,
728                                  void * src, uint_t length, void * priv_data) {
729
730     struct nvram_internal * data = priv_data;
731
732     addr_t irq_state = v3_lock_irqsave(data->nvram_lock);
733
734     set_memory(data, data->thereg, *(uint8_t *)src);
735
736     v3_unlock_irqrestore(data->nvram_lock, irq_state);
737
738     PrintDebug("nvram_write_data_port(0x%x) = 0x%x\n", 
739                data->thereg, data->mem_state[data->thereg]);
740
741     return 1;
742 }
743
744
745
746
747 static int nvram_free(struct nvram_internal * nvram_state) {
748
749     // unregister host events
750
751     V3_Free(nvram_state);
752     return 0;
753 }
754
755
756
757
758
759 static struct v3_device_ops dev_ops = {  
760     .free = (int (*)(void *))nvram_free,
761 };
762
763
764
765
766
767 static int nvram_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
768     struct nvram_internal * nvram_state = NULL;
769     struct vm_device * ide = v3_find_dev(vm, v3_cfg_val(cfg, "storage"));
770     char * dev_id = v3_cfg_val(cfg, "ID");
771     int ret = 0;
772
773     if (!ide) {
774         PrintError("Could not find IDE device\n");
775         return -1;
776     }
777
778     PrintDebug("nvram: init_device\n");
779     nvram_state = (struct nvram_internal *)V3_Malloc(sizeof(struct nvram_internal) + 1000);
780
781     PrintDebug("nvram: internal at %p\n", (void *)nvram_state);
782
783     nvram_state->ide = ide;
784     nvram_state->vm = vm;
785
786     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, nvram_state);
787
788     if (dev == NULL) {
789         PrintError("Could not attach device %s\n", dev_id);
790         V3_Free(nvram_state);
791         return -1;
792     }
793
794     init_nvram_state(vm, nvram_state);
795
796     // hook ports
797     ret |= v3_dev_hook_io(dev, NVRAM_REG_PORT, NULL, &nvram_write_reg_port);
798     ret |= v3_dev_hook_io(dev, NVRAM_DATA_PORT, &nvram_read_data_port, &nvram_write_data_port);
799   
800     if (ret != 0) {
801         PrintError("Error hooking NVRAM IO ports\n");
802         v3_remove_device(dev);
803         return -1;
804     }
805
806     v3_hook_host_event(vm, HOST_TIMER_EVT, V3_HOST_EVENT_HANDLER(handle_timer_event), nvram_state);
807
808     return 0;
809 }
810
811 device_register("NVRAM", nvram_init)