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.


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