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.


reformatted device source files
[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 * 1024 * 16)) / (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     memset(nvram_state->mem_state, 0, NVRAM_REG_MAX);
478
479     //
480     // 2 1.44 MB floppy drives
481     //
482 #if 1
483     nvram_state->mem_state[NVRAM_REG_FLOPPY_TYPE] = 0x44;
484 #else
485     nvram_state->mem_state[NVRAM_REG_FLOPPY_TYPE] = 0x00;
486 #endif
487
488     //
489     // For old boot sequence style, do floppy first
490     //
491     nvram_state->mem_state[NVRAM_REG_BOOTSEQ_OLD] = 0x10;
492
493 #if 0
494     // For new boot sequence style, do floppy, cd, then hd
495     nvram_state->mem_state[NVRAM_REG_BOOTSEQ_NEW_FIRST] = 0x31;
496     nvram_state->mem_state[NVRAM_REG_BOOTSEQ_NEW_SECOND] = 0x20;
497 #endif
498
499     // For new boot sequence style, do cd, hd, floppy
500     nvram_state->mem_state[NVRAM_REG_BOOTSEQ_NEW_FIRST] = 0x23;
501     nvram_state->mem_state[NVRAM_REG_BOOTSEQ_NEW_SECOND] = 0x10;
502   
503   
504     // Set equipment byte to note 2 floppies, vga display, keyboard,math,floppy
505     nvram_state->mem_state[NVRAM_REG_EQUIPMENT_BYTE] = 0x4f;
506     // nvram_state->mem_state[NVRAM_REG_EQUIPMENT_BYTE] = 0xf;
507   
508
509     // This is the harddisk type.... Set accordingly...
510     nvram_state->mem_state[NVRAM_IBM_HD_DATA] = 0x20;
511
512     // Set the shutdown status gently
513     // soft reset
514     nvram_state->mem_state[NVRAM_REG_SHUTDOWN_STATUS] = 0x0;
515
516
517     // RTC status A
518     // 00100110 = no update in progress, base=32768 Hz, rate = 1024 Hz
519     nvram_state->mem_state[NVRAM_REG_STAT_A] = 0x26; 
520
521     // RTC status B
522     // 00000100 = not setting, no interrupts, blocked rect signal, bcd mode, 24 hour, normal time
523     nvram_state->mem_state[NVRAM_REG_STAT_B] = 0x06; 
524
525
526     // RTC status C
527     // No IRQ requested, result not do to any source
528     nvram_state->mem_state[NVRAM_REG_STAT_C] = 0x00;
529
530     // RTC status D
531     // Battery is OK
532     nvram_state->mem_state[NVRAM_REG_STAT_D] = 0x80;
533
534
535     // january 1, 2008, 00:00:00
536     nvram_state->mem_state[NVRAM_REG_MONTH] = 0x1;
537     nvram_state->mem_state[NVRAM_REG_MONTH_DAY] = 0x1;
538     nvram_state->mem_state[NVRAM_REG_WEEK_DAY] = 0x1;
539     nvram_state->mem_state[NVRAM_REG_YEAR] = 0x08;
540
541     nvram_state->us = 0;
542     nvram_state->pus = 0;
543
544     set_memory_size(nvram_state, info->mem_size);
545
546     nvram_state->dev_state = NVRAM_READY;
547     nvram_state->thereg = 0;
548
549     return 0;
550 }
551
552
553
554
555 static int nvram_reset_device(struct vm_device * dev) {
556
557     return 0;
558 }
559
560
561
562
563
564 static int nvram_start_device(struct vm_device * dev) {
565     PrintDebug("nvram: start device\n");
566     return 0;
567 }
568
569
570 static int nvram_stop_device(struct vm_device * dev) {
571     PrintDebug("nvram: stop device\n");
572     return 0;
573 }
574
575
576
577
578 static int nvram_write_reg_port(ushort_t port,
579                                 void * src, 
580                                 uint_t length,
581                                 struct vm_device * dev) {
582     struct nvram_internal * data = (struct nvram_internal *)dev->private_data;
583
584     memcpy(&(data->thereg), src, 1);
585     PrintDebug("Writing To NVRAM reg: 0x%x\n", data->thereg);
586
587
588     return 1;
589 }
590
591 static int nvram_read_data_port(ushort_t port,
592                                 void * dst, 
593                                 uint_t length,
594                                 struct vm_device * dev) {
595     struct nvram_internal * data = (struct nvram_internal *)dev->private_data;
596
597     memcpy(dst, &(data->mem_state[data->thereg]), 1);
598
599     PrintDebug("nvram_read_data_port(0x%x)=0x%x\n", data->thereg, data->mem_state[data->thereg]);
600
601     // hack
602     if (data->thereg == NVRAM_REG_STAT_A) { 
603         data->mem_state[data->thereg] ^= 0x80;  // toggle Update in progess
604     }
605
606
607     return 1;
608 }
609
610 static int nvram_write_data_port(ushort_t port,
611                                  void * src, 
612                                  uint_t length,
613                                  struct vm_device * dev) {
614     struct nvram_internal * data = (struct nvram_internal *)dev->private_data;
615
616     memcpy(&(data->mem_state[data->thereg]), src, 1);
617
618     PrintDebug("nvram_write_data_port(0x%x)=0x%x\n", data->thereg, data->mem_state[data->thereg]);
619
620     return 1;
621 }
622
623
624
625 static int nvram_init_device(struct vm_device * dev) {
626     PrintDebug("nvram: init_device\n");
627
628     init_nvram_state(dev);
629
630     // hook ports
631     v3_dev_hook_io(dev, NVRAM_REG_PORT, NULL, &nvram_write_reg_port);
632     v3_dev_hook_io(dev, NVRAM_DATA_PORT, &nvram_read_data_port, &nvram_write_data_port);
633   
634     v3_hook_host_event(dev->vm, HOST_TIMER_EVT, V3_HOST_EVENT_HANDLER(handle_timer_event), dev);
635
636     return 0;
637 }
638
639 static int nvram_deinit_device(struct vm_device * dev) {
640     v3_dev_unhook_io(dev, NVRAM_REG_PORT);
641     v3_dev_unhook_io(dev, NVRAM_DATA_PORT);
642
643     nvram_reset_device(dev);
644     return 0;
645 }
646
647
648
649
650
651 static struct vm_device_ops dev_ops = { 
652     .init = nvram_init_device, 
653     .deinit = nvram_deinit_device,
654     .reset = nvram_reset_device,
655     .start = nvram_start_device,
656     .stop = nvram_stop_device,
657 };
658
659
660
661
662 struct vm_device * v3_create_nvram() {
663     struct nvram_internal * nvram_state = NULL;
664
665     nvram_state = (struct nvram_internal *)V3_Malloc(sizeof(struct nvram_internal) + 1000);
666
667     PrintDebug("nvram: internal at %p\n", (void *)nvram_state);
668
669     struct vm_device * device = v3_create_device("NVRAM", &dev_ops, nvram_state);
670
671     return device;
672 }