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.


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