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.


Compile fix for Nautilus changes
[palacios.git] / nautilus / palacios-stubs.c
1 #include <nautilus/nautilus.h>
2 #include <nautilus/thread.h>
3 #include <nautilus/printk.h>
4 #include <nautilus/cpu.h>
5 #include <nautilus/mm.h>
6 #include <nautilus/vc.h>
7 #include <nautilus/timer.h>
8 #include <dev/apic.h>
9
10 #include <palacios/vmm.h>
11
12 #include "palacios.h"
13 #include "console.h"
14
15
16 /*
17   This is a simple proof-of-concept implementation of the Palacios
18   host interface on top of Nautilus.   It is sufficient to allow
19   us to boot a guest OS running Linux.   A few things to note:
20
21   - Nautilus currently has a grand-unified allocator designed to help
22     support parallel run-time integration.   All of alloc/valloc/page 
23     allocation are built on top of that. 
24   - For page allocation, constraints, NUMA, and filter expressions are
25     ignored.
26   - thread migration is not supported currently
27   - hooking of host interrupts is not supported currently.
28   - Palacios can sleep, yield, wakeup, etc, but be aware
29     that Nautilus threads operate differently than those of
30     a traditional kernel.
31
32   Usage:
33   - Do Nautilus regular startup to bring all cores to idle
34   - From a kernel thread, ideally the init thread on core 0, 
35     do palacios_vmm_init(memory_size_bytes,options)
36   - You can now use the Palacios v3_* functions, which are
37     not wrapped here.
38   - You need to keep the Nautilus VM state in sync with
39     the Palacios VM state.   The protocol for this is:
40         1. before doing a VM creation, call 
41               palacios_inform_new_vm_pre(name)
42            this will also select the new vm for
43            the creation and going forward
44            then, once v3_create is done, call
45               palacios_inform_new_vm_post(name, vm)
46         2. during execution, whenever you want to
47            manage a different VM, call 
48               palacios_inform_select_vm(vm) 
49            or 
50               palacios_inform_select_vm_by_name(name)
51            It is OK to to select repeatedly, etc.
52         3. after doing a VM free, call
53               palacios_inform_free_vm(name)
54            or
55               palacios_inform_free_selected_vm()
56   - After you are done, do a palacios_vmm_deinit();
57
58 */
59
60 // The following can be used to track memory bugs
61 // zero memory after allocation (now applies to valloc and page alloc as well)
62 #define ALLOC_ZERO_MEM 1
63 // pad allocations by this many bytes on both ends of block (heap only)
64 #define ALLOC_PAD       0
65 #define MAX_THREAD_NAME 32
66
67 int run_nk_thread = 0;
68
69 static struct nk_vm_state vms[NR_VMS];
70
71 static struct nk_vm_state *selected_vm;
72
73 static struct v3_vm_info * irq_to_guest_map[256];
74
75 static unsigned int cpu_khz=-1;
76
77 static char *print_buffer[NR_CPUS];
78
79 static void deinit_print_buffers(void)
80 {
81     int i;
82
83     for (i=0;i<NR_CPUS;i++) {
84         if (print_buffer[i]) { 
85             palacios_free(print_buffer[i]);
86             print_buffer[i]=0;
87         }
88     }
89 }
90
91 static int init_print_buffers(void)
92 {
93     int i;
94     
95     memset(print_buffer,0,sizeof(char*)*NR_CPUS);
96
97     for (i=0;i<NR_CPUS;i++) { 
98         print_buffer[i] = palacios_alloc(V3_PRINTK_BUF_SIZE);
99         if (!print_buffer[i]) { 
100             ERROR("Cannot allocate print buffer for cpu %d\n",i);
101             deinit_print_buffers();
102             return -1;
103         }
104         memset(print_buffer[i],0,V3_PRINTK_BUF_SIZE);
105     }
106
107     
108     return 0;
109
110 }
111
112
113  
114 /**
115  * Prints a message to the console.
116  */
117 void palacios_print_scoped(void * vm, int vcore, const char *fmt, ...) 
118 {
119
120   va_list ap;
121   unsigned int cpu = palacios_get_cpu();
122   char *buf = cpu < NR_CPUS ? print_buffer[cpu] : 0;
123
124   if (!buf) { 
125       INFO_PRINT("palacios (pcore %u): output skipped - no allocated buffer\n",cpu);
126       return;
127   } 
128
129
130   va_start(ap, fmt);
131   vsnprintf(buf,V3_PRINTK_BUF_SIZE, fmt, ap);
132   va_end(ap);
133
134   if (vm) {
135     if (vcore>=0) { 
136       INFO_PRINT("palacios (pcore %u vm %s vcore %u): %s",
137                  cpu,
138                  "some_guest",
139                  vcore,
140                  buf);
141     } else {
142       INFO_PRINT(KERN_INFO "palacios (pcore %u vm %s): %s",
143                  cpu,
144                  "some_guest",
145                  buf);
146     }
147   } else {
148     INFO_PRINT(KERN_INFO "palacios (pcore %u): %s",
149                cpu,
150                buf);
151   }
152     
153   return;
154 }
155
156
157
158 /*
159  * Allocates a contiguous region of pages of the requested size.
160  * Returns the physical address of the first page in the region.
161  */
162 void *palacios_allocate_pages(int num_pages, unsigned int alignment, int node_id, int (*filter_func)(void *paddr, void *filter_state), void *filter_state) 
163 {
164     void * pg_addr = NULL;
165
166     if (num_pages<=0) { 
167         ERROR("ALERT ALERT Attempt to allocate zero or fewer pages (%d pages, alignment %d, node %d, filter_func %p, filter_state %p)\n",num_pages, alignment, node_id, filter_func, filter_state);
168         return NULL;
169     }
170
171     // malloc currently guarantees alignment to the size of 
172     // the allocation
173     pg_addr = (void *)malloc(num_pages*4096);
174
175     if (!pg_addr) { 
176         ERROR("ALERT ALERT  Page allocation has FAILED Warning (%d pages, alignment %d, node %d, filter_func %p, filter_state %p)\n",num_pages, alignment, node_id, filter_func, filter_state);
177         return NULL;
178     }
179     
180     if ((uint64_t)pg_addr & 0xfff) { 
181       ERROR("ALERT ALERT Page allocation has surprise offset\n");
182       return NULL;
183     }
184
185 #if ALLOC_ZERO_MEM
186     memset(pg_addr,0,num_pages*4096);
187 #endif
188
189     //INFO("allocpages: %p (%llu pages) alignment=%u\n", pg_addr, num_pages, alignment);
190
191     return pg_addr;
192 }
193
194
195 /**
196  * Frees a page previously allocated via palacios_allocate_page().
197  * Note that palacios_allocate_page() can allocate multiple pages with
198  * a single call while palacios_free_page() only frees a single page.
199  */
200
201 void palacios_free_pages(void * page_paddr, int num_pages) 
202 {
203     //INFO("freepages: %p (%llu pages) alignment=%u\n", page_paddr, num_pages);
204
205     if (!page_paddr) { 
206         ERROR("Ignoring free pages: 0x%p (0x%lx)for %d pages\n", page_paddr, (uintptr_t)page_paddr, num_pages);
207         return;
208     }
209
210     free(page_paddr);
211
212 }
213
214
215 void *
216 palacios_alloc_extended(unsigned int size, unsigned int flags, int node) {
217     void * addr = NULL;
218
219     if (size==0) { 
220       ERROR("ALERT ALERT attempt to kmalloc zero bytes rejected\n");
221       return NULL;
222     }
223
224     if (node==-1) { 
225         addr = malloc(size+2*ALLOC_PAD);
226     } else {
227         // currently no numa-zone specific kmalloc
228         addr = malloc(size+2*ALLOC_PAD);
229     }
230
231     if (!addr) { 
232        ERROR("ALERT ALERT  kmalloc has FAILED FAILED FAILED\n");
233        return NULL;
234     }   
235
236 #if ALLOC_ZERO_MEM
237     memset(addr,0,size+2*ALLOC_PAD);
238 #endif
239
240     //INFO("malloc: 0x%p (%llu bytes)\n",addr+ALLOC_PAD,size);
241
242     return addr+ALLOC_PAD;
243 }
244
245 void *
246 palacios_valloc(unsigned int size)
247 {
248     void * addr = NULL;
249
250
251     if (size==0) { 
252       ERROR("ALERT ALERT attempt to vmalloc zero bytes rejected\n");
253       return NULL;
254     }
255
256     // currently no vmalloc
257     addr = malloc(size);
258
259     if (!addr) {
260        ERROR("ALERT ALERT  vmalloc has FAILED FAILED FAILED\n");
261        return NULL;
262     }   
263
264 #if ALLOC_ZERO_MEM
265     memset(addr,0,size);
266 #endif
267
268     //INFO("valloc: 0x%p (%llu bytes)\n",addr,size);
269
270     return addr;
271 }
272
273 void palacios_vfree(void *p)
274 {
275   //INFO("vfree: 0x%p\n",p);
276
277   if (!p) { 
278       ERROR("Ignoring vfree: 0x%p\n",p);
279       return;
280   }
281
282   free(p);
283
284 }
285
286 /**
287  * Allocates 'size' bytes of kernel memory.
288  * Returns the kernel virtual address of the memory allocated.
289  */
290 void *
291 palacios_alloc(unsigned int size) 
292 {
293     return palacios_alloc_extended(size,0,-1);
294 }
295
296 /**
297  * Frees memory that was previously allocated by palacios_alloc().
298  */
299 void
300 palacios_free(void *addr)
301 {
302     //INFO("free: %p\n",addr-ALLOC_PAD);
303
304     if (!addr) {
305         ERROR("Ignoring free : 0x%p\n", addr);
306         return;
307     }
308
309     free(addr-ALLOC_PAD);
310 }
311
312 /**
313  * Converts a kernel virtual address to the corresponding physical address.
314  */
315 void *
316 palacios_vaddr_to_paddr(
317         void *                  vaddr
318 )
319 {
320   // our memory mapping is identity
321   // this currently does not include Nautilus PA offsetting
322   // as in Multiverse, but we don't envision running a VM
323   // within an HRT either, so we should be fine
324   return vaddr; 
325 }
326
327 /**
328  * Converts a physical address to the corresponding kernel virtual address.
329  */
330 void *
331 palacios_paddr_to_vaddr(
332         void *                  paddr
333 )
334 {
335     return paddr; // our memory mapping is identity, see v->p comment
336 }
337
338 /**
339  * Runs a function on the specified CPU.
340  */
341 void 
342 palacios_xcall(
343         int                     cpu_id, 
344         void                    (*fn)(void *arg),
345         void *                  arg
346 )
347 {
348
349     smp_xcall(cpu_id,fn,arg,1);
350
351     return;
352 }
353
354
355
356 struct nautilus_thread_arg {
357     int (*fn)(void * arg);
358     void *arg; 
359     char name[MAX_THREAD_NAME];
360 };
361
362 static void nautilus_thread_target(void * in, void ** out) 
363 {
364     struct nautilus_thread_arg * thread_info = (struct nautilus_thread_arg *)in;
365     int ret;
366
367     ret = thread_info->fn(thread_info->arg);
368
369     INFO("Palacios Thread (%s) EXITING with return code %d\n", thread_info->name, ret);
370
371     palacios_free(thread_info); 
372 }
373
374 /**
375  * Creates a kernel thread.
376  */
377 void *
378 palacios_create_and_start_kernel_thread(
379         int (*fn)               (void * arg),
380         void *                  arg,
381         char *                  thread_name,
382         v3_resource_control_t   *rctl) 
383 {
384     
385     struct nautilus_thread_arg * thread_info = palacios_alloc(sizeof(struct nautilus_thread_arg));
386     nk_thread_id_t tid = 0;
387     
388     if (!thread_info) { 
389         ERROR("ALERT ALERT Unable to allocate thread\n");
390         return NULL;
391     }
392     
393     thread_info->fn = fn;
394     thread_info->arg = arg;
395     strncpy(thread_info->name,thread_name,MAX_THREAD_NAME);
396     thread_info->name[MAX_THREAD_NAME-1] =0;
397     
398     nk_thread_start(nautilus_thread_target, thread_info, 0, 0, 0, &tid, CPU_ANY);
399
400     return tid;
401 }
402
403
404 /**
405  * Starts a kernel thread on the specified CPU.
406  */
407 void * 
408 palacios_create_thread_on_cpu(int cpu_id,
409                               int (*fn)(void * arg), 
410                               void * arg, 
411                               char * thread_name,
412                               v3_resource_control_t *rctl) 
413 {
414     nk_thread_id_t newtid;
415     nk_thread_t * newthread = NULL;
416     struct nautilus_thread_arg * thread_info = palacios_alloc(sizeof(struct nautilus_thread_arg));
417     
418     thread_info->fn = fn;
419     thread_info->arg = arg;
420     strncpy(thread_info->name, thread_name, MAX_THREAD_NAME);
421     thread_info->name[MAX_THREAD_NAME-1] = 0;
422     
423     //INFO("CREATING A THREAD ON CPU ID: %d\n", cpu_id);
424     
425     if (nk_thread_create(nautilus_thread_target, thread_info, 0, 0, 0, &newtid, cpu_id) < 0) {
426         ERROR("COULD NOT CREATE THREAD\n");
427         return NULL;
428     }
429     //INFO("newtid: %lu\n", newtid);
430     
431     return newtid;
432 }
433
434 void
435 palacios_start_thread(void * th)
436 {
437     nk_thread_run(th);
438 }
439
440 /*
441   Convenience wrapper
442 */
443 void * 
444 palacios_create_and_start_thread_on_cpu(int cpu_id,
445                                         int (*fn)(void * arg), 
446                                         void * arg, 
447                                         char * thread_name,
448                                         v3_resource_control_t *rctl ) 
449 {
450
451     nk_thread_id_t tid;
452
453     struct nautilus_thread_arg * thread_info = palacios_alloc(sizeof(struct nautilus_thread_arg));
454
455     if (!thread_info) { 
456         ERROR("ALERT ALERT Unable to allocate thread to start on cpu\n");
457         return NULL;
458     }
459
460     thread_info->fn = fn;
461     thread_info->arg = arg;
462     strncpy(thread_info->name,thread_name,MAX_THREAD_NAME);
463     thread_info->name[MAX_THREAD_NAME-1] =0;
464
465     nk_thread_start(nautilus_thread_target, thread_info, 0, 0, 0,&tid,cpu_id); //
466
467     return tid;
468 }
469
470
471
472 /**
473  * Rebind a kernel thread to the specified CPU
474  * The thread will be running on target CPU on return
475  * non-zero return means failure
476  */
477 int
478 palacios_move_thread_to_cpu(int new_cpu_id, 
479                             void * thread_ptr) 
480 {
481
482     INFO("Moving thread (%p) to cpu %d\n", thread_ptr, new_cpu_id);
483     ERROR("NOT CURRENTLY SUPPORTED\n");
484     return -1;
485 }
486
487
488 /**
489  * Returns the CPU ID that the caller is running on.
490  */
491 unsigned int 
492 palacios_get_cpu(void) 
493 {
494     return  my_cpu_id(); 
495 }
496
497 static void
498 palacios_interrupt_cpu( struct v3_vm_info *     vm, 
499                         int                     cpu_id, 
500                         int                     vector)
501 {
502   apic_ipi(per_cpu_get(apic),cpu_id,vector); // find out apic_dev * and cpu to apic id mapping 
503 }
504
505 struct pt_regs;
506
507
508 /**
509  * Dispatches an interrupt to Palacios for handling.
510  */
511 static void
512 palacios_dispatch_interrupt( int vector, void * dev, struct pt_regs * regs ) {
513     struct v3_interrupt intr = {
514         .irq            = vector,
515         .error          = 0, //regs->orig_ax, /* TODO fix this */
516         .should_ack     = 1,
517     };
518     
519     if (irq_to_guest_map[vector]) {
520         v3_deliver_irq(irq_to_guest_map[vector], &intr);
521     }
522     
523 }
524
525 /**
526  * Instructs the kernel to forward the specified IRQ to Palacios.
527  */
528 static int
529 palacios_hook_interrupt(struct v3_vm_info *     vm,
530                         unsigned int            vector ) 
531 {
532     ERROR("UNSUPPORTED: PALACIOS_HOOK_INTERRUPT\n");
533     return -1;
534 }
535
536
537 /**
538  * Acknowledges an interrupt.
539  */
540 static int
541 palacios_ack_interrupt(
542         int                     vector
543
544 {
545     ERROR("UNSUPPORTED: PALACIOS_ACK_INTERRUPT\n");
546     return -1;
547 }
548   
549 /**
550  * Returns the CPU frequency in kilohertz.
551  */
552 unsigned int
553 palacios_get_cpu_khz(void) 
554 {
555     if (cpu_khz==-1) { 
556         uint32_t cpu = (uint32_t)my_cpu_id();
557         
558         cpu_khz = nk_detect_cpu_freq(cpu);
559         if (cpu_khz==-1) {
560             INFO("CANNOT GET THE CPU FREQUENCY. FAKING TO 1000000\n");
561             cpu_khz=1000000;
562         }
563     }
564     INFO("Nautilus frequency at %u KHz\n",cpu_khz);
565     return cpu_khz;
566 }
567
568 /**
569  * Yield the CPU so other host OS tasks can run.
570  * This will return immediately if there is no other thread that is runnable
571  * And there is no real bound on how long it will yield
572  */
573 void
574 palacios_yield_cpu(void)
575 {
576     nk_yield();
577     return;
578 }
579
580 /**
581  * Yield the CPU so other host OS tasks can run.
582  * Given now immediately if there is no other thread that is runnable
583  * And there is no real bound on how long it will yield
584  */
585 void palacios_sleep_cpu(unsigned int us)
586 {
587     // sleep not supported on Nautilus
588     // just yield
589     nk_yield();
590     udelay(us);
591 }
592
593 void palacios_wakeup_cpu(void *thread)
594 {
595     // threads never go to sleep, so shouldn't happen
596     ERROR("ERROR ERROR: WAKEUP_CPU CALLED. THREADS ARE NEVER ASLEEP");
597     return;
598 }
599
600 /**
601  * Allocates a mutex.
602  * Returns NULL on failure.
603  */
604 void *
605 palacios_mutex_alloc(void)
606 {
607     spinlock_t *lock = palacios_alloc(sizeof(spinlock_t));
608     
609     if (lock) {
610         spinlock_init(lock);
611     } else {
612         ERROR("ALERT ALERT Unable to allocate lock\n");
613         return NULL;
614     }
615     
616     return lock;
617 }
618
619 void palacios_mutex_init(void *mutex)
620 {
621     spinlock_t *lock = (spinlock_t*)mutex;
622     
623     if (lock) {
624         spinlock_init(lock);
625         LOCKCHECK_ALLOC(lock);
626     }
627     
628 }
629
630 void palacios_mutex_deinit(void *mutex)
631 {
632     spinlock_t *lock = (spinlock_t*)mutex;
633   
634     if (lock) {
635         spinlock_deinit(lock);
636         LOCKCHECK_FREE(lock);
637     }
638 }
639
640
641 /**
642  * Frees a mutex.
643  */
644 void
645 palacios_mutex_free(void * mutex) {
646     palacios_free(mutex);
647     LOCKCHECK_FREE(mutex);
648 }
649
650 /**
651  * Locks a mutex.
652  */
653 void 
654 palacios_mutex_lock(void * mutex, int must_spin) {
655     LOCKCHECK_LOCK_PRE(mutex);
656     spin_lock((spinlock_t *)mutex);
657     LOCKCHECK_LOCK_POST(mutex);
658 }
659
660
661 /**
662  * Locks a mutex, disabling interrupts on this core
663  */
664 void *
665 palacios_mutex_lock_irqsave(void * mutex, int must_spin) {
666     
667     unsigned long flags; 
668     
669     LOCKCHECK_LOCK_IRQSAVE_PRE(mutex,flags);
670     flags = spin_lock_irq_save((spinlock_t *)mutex);
671     LOCKCHECK_LOCK_IRQSAVE_POST(mutex,flags);
672
673     //INFO("lock irqsave flags=%lu\n",flags);
674     return (void *)flags;
675 }
676
677
678 /**
679  * Unlocks a mutex.
680  */
681 void 
682 palacios_mutex_unlock(
683         void *                  mutex
684
685 {
686     LOCKCHECK_UNLOCK_PRE(mutex);
687     spin_unlock((spinlock_t *)mutex);
688     LOCKCHECK_UNLOCK_POST(mutex);
689 }
690
691
692 /**
693  * Unlocks a mutex and restores previous interrupt state on this core
694  */
695 void 
696 palacios_mutex_unlock_irqrestore(void *mutex, void *flags)
697 {
698     //INFO("unlock irqrestore flags=%lu\n",(unsigned long)flags);
699     LOCKCHECK_UNLOCK_IRQRESTORE_PRE(mutex,(unsigned long)flags);
700     // This is correct, flags is opaque
701     spin_unlock_irq_restore((spinlock_t *)mutex,(uint8_t) (unsigned long)flags);
702     LOCKCHECK_UNLOCK_IRQRESTORE_POST(mutex,(unsigned long)flags);
703 }
704
705
706 /**
707  * Structure used by the Palacios hypervisor to interface with the host kernel.
708  */
709 static struct v3_os_hooks palacios_os_hooks = {
710         .print                      = palacios_print_scoped, 
711         .allocate_pages             = palacios_allocate_pages,  
712         .free_pages                 = palacios_free_pages, 
713         .vmalloc                    = palacios_valloc, 
714         .vfree                      = palacios_vfree, 
715         .malloc                     = palacios_alloc, 
716         .free                       = palacios_free, 
717         .vaddr_to_paddr             = palacios_vaddr_to_paddr,  
718         .paddr_to_vaddr             = palacios_paddr_to_vaddr,  
719         .hook_interrupt             = palacios_hook_interrupt,  
720         .ack_irq                    = palacios_ack_interrupt,  
721         .get_cpu_khz                = palacios_get_cpu_khz, 
722         .start_kernel_thread        = palacios_create_and_start_kernel_thread, 
723         .yield_cpu                  = palacios_yield_cpu, 
724         .sleep_cpu                  = palacios_sleep_cpu, 
725         .wakeup_cpu                 = palacios_wakeup_cpu, 
726         .mutex_alloc                = palacios_mutex_alloc, 
727         .mutex_free                 = palacios_mutex_free, 
728         .mutex_lock                 = palacios_mutex_lock, 
729         .mutex_unlock               = palacios_mutex_unlock, 
730         .mutex_lock_irqsave         = palacios_mutex_lock_irqsave,  
731         .mutex_unlock_irqrestore    = palacios_mutex_unlock_irqrestore, 
732         .get_cpu                    = palacios_get_cpu, 
733         .interrupt_cpu              = palacios_interrupt_cpu, 
734         .call_on_cpu                = palacios_xcall, 
735         .create_thread_on_cpu       = palacios_create_thread_on_cpu, 
736         .start_thread               = palacios_start_thread, 
737         .move_thread_to_cpu         = palacios_move_thread_to_cpu, // unsupported
738 };
739
740
741 int palacios_vmm_init(char * options)
742 {
743     int num_cpus = nautilus_info.sys.num_cpus;
744     char * cpu_mask = NULL;
745
746     if (num_cpus > 0) {
747         int major = 0;
748         int minor = 0;
749         int i = 0;
750
751         cpu_mask = palacios_alloc((num_cpus / 8) + 1);
752         
753         if (!cpu_mask) { 
754             ERROR("Cannot allocate cpu mask\n");
755             return -1;
756         }
757
758         memset(cpu_mask, 0, (num_cpus / 8) + 1);
759         
760         for (i = 0; i < num_cpus; i++) {
761
762             major = i / 8;
763             minor = i % 8;
764     
765             *(cpu_mask + major) |= (0x1 << minor);
766         }
767     } else {
768       ERROR("Must initialize at least one CPU\n");
769       return -1;
770     }
771
772
773     memset(irq_to_guest_map, 0, sizeof(struct v3_vm_info *) * 256);
774
775     memset(vms,0,sizeof(vms));
776
777     if (init_print_buffers()) {
778         INFO("Cannot initialize print buffers\n");
779         palacios_free(cpu_mask);
780         return -1;
781     }
782     
783     INFO("printbuffer init done\n");
784
785     INFO("NR_CPU: %d\n", NR_CPUS);
786
787     INFO("palacios_init starting - calling init_v3\n");
788
789     INFO("calling init_v3 = %p\n", Init_V3);
790
791     INFO("num_cpus: %d\ncpu_mask: %x\noptions: %s\n", num_cpus, *cpu_mask, options);
792
793     Init_V3(&palacios_os_hooks, cpu_mask, num_cpus, options);
794
795     INFO("init_v3 done\n");
796
797 #ifdef V3_CONFIG_CONSOLE
798     INFO("Initializing console\n");
799     nautilus_console_init();
800 #endif
801
802     palacios_free(cpu_mask);
803
804
805     return 0;
806
807 }
808
809
810 int palacios_vmm_exit( void ) 
811 {
812
813 #ifdef V3_CONFIG_CONSOLE
814     nautilus_console_deinit();
815 #endif
816
817     Shutdown_V3();
818
819     INFO("palacios shutdown complete\n");
820
821     deinit_print_buffers();
822
823     return 0;
824 }
825
826
827 void palacios_inform_new_vm_pre(char *name)
828 {
829   int i;
830   for (i=0;i<NR_VMS;i++) { 
831     if (!vms[i].name[0]) {
832       strncpy(vms[i].name,name,MAX_VM_NAME);
833       vms[i].name[MAX_VM_NAME-1]=0;
834       selected_vm = &vms[i];
835       return;
836     }
837   }
838 }
839
840 void palacios_inform_new_vm_post(char *name, struct v3_vm_info *vm)
841 {
842   struct nk_vm_state *n = palacios_find_vm_by_name(name);
843
844   if (n) { 
845     n->vm = vm;
846     INFO("Registered VM %p with name %s, node=%p, selected VM=%p\n",
847          vm, n->name, n, selected_vm);
848   } else {
849     ERROR("Cannot find VM with name \"%s\"\n",name);
850   }
851 }
852
853 void palacios_inform_free_vm(char *name) 
854 {
855   struct nk_vm_state *n = palacios_find_vm_by_name(name);
856
857   if (n==selected_vm) { 
858     selected_vm = 0;
859   }
860
861   if (n) { 
862     n->vm = 0;
863     n->vc = 0;
864     n->name[0] = 0;
865   }
866   
867 }
868
869 void palacios_inform_free_selected_vm()
870 {
871   struct nk_vm_state *n = selected_vm;
872
873   selected_vm = 0;
874
875   if (n) { 
876     n->vm = 0;
877     n->vc = 0;
878     n->name[0] = 0;
879   }
880 }
881
882
883 struct nk_vm_state *palacios_find_vm_by_name(char *name)
884 {
885   int i;
886   for (i=0;i<NR_VMS;i++) { 
887     if (!strncmp(vms[i].name,name,MAX_VM_NAME)) {
888       return &vms[i];
889     }
890   }
891   return 0;
892 }
893
894 struct nk_vm_state *palacios_find_vm(struct v3_vm_info *vm)
895 {
896   int i;
897   for (i=0;i<NR_VMS;i++) { 
898     if (vms[i].vm == vm) { 
899       return &vms[i];
900     }
901   }
902   return 0;
903 }
904
905 void palacios_select_vm(struct v3_vm_info *vm)
906 {
907   struct nk_vm_state *n = palacios_find_vm(vm);
908   if (n) {
909     selected_vm = n;
910   }
911 }
912
913 void palacios_select_vm_by_name(char *name)
914 {
915   struct nk_vm_state *n = palacios_find_vm_by_name(name);
916   if (n) {
917     selected_vm = n;
918   }
919 }
920
921 struct nk_vm_state *palacios_get_selected_vm()
922 {
923   return selected_vm;
924 }
925