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.


Revised Nautilus Aerokernel Host Functionality
[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 <dev/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     if (!page_paddr) { 
203         ERROR("Ignoring free pages: 0x%p (0x%lx)for %d pages\n", page_paddr, (uintptr_t)page_paddr, num_pages);
204         return;
205     }
206     free(page_paddr);
207
208     INFO("freepages: %p (%llu pages) alignment=%u\n", page_paddr, num_pages);
209 }
210
211
212 void *
213 palacios_alloc_extended(unsigned int size, unsigned int flags, int node) {
214     void * addr = NULL;
215
216     if (size==0) { 
217       ERROR("ALERT ALERT attempt to kmalloc zero bytes rejected\n");
218       return NULL;
219     }
220
221     if (node==-1) { 
222         addr = malloc(size+2*ALLOC_PAD);
223     } else {
224         // currently no numa-zone specific kmalloc
225         addr = malloc(size+2*ALLOC_PAD);
226     }
227
228     if (!addr) { 
229        ERROR("ALERT ALERT  kmalloc has FAILED FAILED FAILED\n");
230        return NULL;
231     }   
232
233 #if ALLOC_ZERO_MEM
234     memset(addr,0,size+2*ALLOC_PAD);
235 #endif
236
237     //INFO("malloc: 0x%p (%llu bytes)\n",addr+ALLOC_PAD,size);
238
239     return addr+ALLOC_PAD;
240 }
241
242 void *
243 palacios_valloc(unsigned int size)
244 {
245     void * addr = NULL;
246
247     if (size==0) { 
248       ERROR("ALERT ALERT attempt to vmalloc zero bytes rejected\n");
249       return NULL;
250     }
251
252     // currently no vmalloc
253     addr = malloc(size);
254
255     if (!addr) {
256        ERROR("ALERT ALERT  vmalloc has FAILED FAILED FAILED\n");
257        return NULL;
258     }   
259
260 #if ALLOC_ZERO_MEM
261     memset(addr,0,size);
262 #endif
263
264     //INFO("valloc: 0x%p (%llu bytes)\n",addr,size);
265
266     return addr;
267 }
268
269 void palacios_vfree(void *p)
270 {
271   if (!p) { 
272       ERROR("Ignoring vfree: 0x%p\n",p);
273       return;
274   }
275   // no vfree currently
276   free(p);
277
278   //INFO("vfree: 0x%p\n",p);
279 }
280
281 /**
282  * Allocates 'size' bytes of kernel memory.
283  * Returns the kernel virtual address of the memory allocated.
284  */
285 void *
286 palacios_alloc(unsigned int size) 
287 {
288     return palacios_alloc_extended(size,0,-1);
289 }
290
291 /**
292  * Frees memory that was previously allocated by palacios_alloc().
293  */
294 void
295 palacios_free(void *addr)
296 {
297     return;
298     if (!addr) {
299         ERROR("Ignoring free : 0x%p\n", addr);
300         return;
301     }
302     // no kfree
303     free(addr-ALLOC_PAD);
304     //INFO("free: %p\n",addr-ALLOC_PAD);
305 }
306
307 /**
308  * Converts a kernel virtual address to the corresponding physical address.
309  */
310 void *
311 palacios_vaddr_to_paddr(
312         void *                  vaddr
313 )
314 {
315     return vaddr; // our memory mapping is identity
316
317 }
318
319 /**
320  * Converts a physical address to the corresponding kernel virtual address.
321  */
322 void *
323 palacios_paddr_to_vaddr(
324         void *                  paddr
325 )
326 {
327     return paddr; // our memory mapping is identity
328 }
329
330 /**
331  * Runs a function on the specified CPU.
332  */
333 void 
334 palacios_xcall(
335         int                     cpu_id, 
336         void                    (*fn)(void *arg),
337         void *                  arg
338 )
339 {
340
341     smp_xcall(cpu_id,fn,arg,1);
342
343     return;
344 }
345
346
347
348 struct nautilus_thread_arg {
349     int (*fn)(void * arg);
350     void *arg; 
351     char name[MAX_THREAD_NAME];
352 };
353
354 static void nautilus_thread_target(void * in, void ** out) 
355 {
356     struct nautilus_thread_arg * thread_info = (struct nautilus_thread_arg *)in;
357     int ret;
358
359     ret = thread_info->fn(thread_info->arg);
360
361     INFO("Palacios Thread (%s) EXITING with return code %d\n", thread_info->name, ret);
362
363     palacios_free(thread_info); 
364 }
365
366 /**
367  * Creates a kernel thread.
368  */
369 void *
370 palacios_create_and_start_kernel_thread(
371         int (*fn)               (void * arg),
372         void *                  arg,
373         char *                  thread_name,
374         v3_resource_control_t   *rctl) 
375 {
376     
377     struct nautilus_thread_arg * thread_info = palacios_alloc(sizeof(struct nautilus_thread_arg));
378     nk_thread_id_t tid = 0;
379     
380     if (!thread_info) { 
381         ERROR("ALERT ALERT Unable to allocate thread\n");
382         return NULL;
383     }
384     
385     thread_info->fn = fn;
386     thread_info->arg = arg;
387     strncpy(thread_info->name,thread_name,MAX_THREAD_NAME);
388     thread_info->name[MAX_THREAD_NAME-1] =0;
389     
390     nk_thread_start(nautilus_thread_target, thread_info, 0, 0, 0, &tid, CPU_ANY);
391
392     return tid;
393 }
394
395
396 /**
397  * Starts a kernel thread on the specified CPU.
398  */
399 void * 
400 palacios_create_thread_on_cpu(int cpu_id,
401                               int (*fn)(void * arg), 
402                               void * arg, 
403                               char * thread_name,
404                               v3_resource_control_t *rctl) 
405 {
406     nk_thread_id_t newtid;
407     nk_thread_t * newthread = NULL;
408     struct nautilus_thread_arg * thread_info = palacios_alloc(sizeof(struct nautilus_thread_arg));
409     
410     thread_info->fn = fn;
411     thread_info->arg = arg;
412     strncpy(thread_info->name, thread_name, MAX_THREAD_NAME);
413     thread_info->name[MAX_THREAD_NAME-1] = 0;
414     
415     //INFO("CREATING A THREAD ON CPU ID: %d\n", cpu_id);
416     
417     if (nk_thread_create(nautilus_thread_target, thread_info, 0, 0, 0, &newtid, cpu_id) < 0) {
418         ERROR("COULD NOT CREATE THREAD\n");
419         return NULL;
420     }
421     //INFO("newtid: %lu\n", newtid);
422     
423     return newtid;
424 }
425
426 void
427 palacios_start_thread(void * th)
428 {
429     nk_thread_run(th);
430 }
431
432 /*
433   Convenience wrapper
434 */
435 void * 
436 palacios_create_and_start_thread_on_cpu(int cpu_id,
437                                         int (*fn)(void * arg), 
438                                         void * arg, 
439                                         char * thread_name,
440                                         v3_resource_control_t *rctl ) 
441 {
442
443     nk_thread_id_t tid;
444
445     struct nautilus_thread_arg * thread_info = palacios_alloc(sizeof(struct nautilus_thread_arg));
446
447     if (!thread_info) { 
448         ERROR("ALERT ALERT Unable to allocate thread to start on cpu\n");
449         return NULL;
450     }
451
452     thread_info->fn = fn;
453     thread_info->arg = arg;
454     strncpy(thread_info->name,thread_name,MAX_THREAD_NAME);
455     thread_info->name[MAX_THREAD_NAME-1] =0;
456
457     nk_thread_start(nautilus_thread_target, thread_info, 0, 0, 0,&tid,cpu_id); //
458
459     return tid;
460 }
461
462
463
464 /**
465  * Rebind a kernel thread to the specified CPU
466  * The thread will be running on target CPU on return
467  * non-zero return means failure
468  */
469 int
470 palacios_move_thread_to_cpu(int new_cpu_id, 
471                             void * thread_ptr) 
472 {
473
474     INFO("Moving thread (%p) to cpu %d\n", thread_ptr, new_cpu_id);
475     ERROR("NOT CURRENTLY SUPPORTED\n");
476     return -1;
477 }
478
479
480 /**
481  * Returns the CPU ID that the caller is running on.
482  */
483 unsigned int 
484 palacios_get_cpu(void) 
485 {
486     return  my_cpu_id(); 
487 }
488
489 static void
490 palacios_interrupt_cpu( struct v3_vm_info *     vm, 
491                         int                     cpu_id, 
492                         int                     vector)
493 {
494   apic_ipi(per_cpu_get(apic),cpu_id,vector); // find out apic_dev * and cpu to apic id mapping 
495 }
496
497 struct pt_regs;
498
499
500 /**
501  * Dispatches an interrupt to Palacios for handling.
502  */
503 static void
504 palacios_dispatch_interrupt( int vector, void * dev, struct pt_regs * regs ) {
505     struct v3_interrupt intr = {
506         .irq            = vector,
507         .error          = 0, //regs->orig_ax, /* TODO fix this */
508         .should_ack     = 1,
509     };
510     
511     if (irq_to_guest_map[vector]) {
512         v3_deliver_irq(irq_to_guest_map[vector], &intr);
513     }
514     
515 }
516
517 /**
518  * Instructs the kernel to forward the specified IRQ to Palacios.
519  */
520 static int
521 palacios_hook_interrupt(struct v3_vm_info *     vm,
522                         unsigned int            vector ) 
523 {
524     ERROR("UNSUPPORTED: PALACIOS_HOOK_INTERRUPT\n");
525     return -1;
526 }
527
528
529 /**
530  * Acknowledges an interrupt.
531  */
532 static int
533 palacios_ack_interrupt(
534         int                     vector
535
536 {
537     ERROR("UNSUPPORTED: PALACIOS_ACK_INTERRUPT\n");
538     return -1;
539 }
540   
541 /**
542  * Returns the CPU frequency in kilohertz.
543  */
544 unsigned int
545 palacios_get_cpu_khz(void) 
546 {
547     if (cpu_khz==-1) { 
548         uint32_t cpu = (uint32_t)my_cpu_id();
549         
550         cpu_khz = nk_detect_cpu_freq(cpu);
551         if (cpu_khz==-1) {
552             INFO("CANNOT GET THE CPU FREQUENCY. FAKING TO 1000000\n");
553             cpu_khz=1000000;
554         }
555     }
556     INFO("Nautilus frequency at %u KHz\n",cpu_khz);
557     return cpu_khz;
558 }
559
560 /**
561  * Yield the CPU so other host OS tasks can run.
562  * This will return immediately if there is no other thread that is runnable
563  * And there is no real bound on how long it will yield
564  */
565 void
566 palacios_yield_cpu(void)
567 {
568     nk_yield();
569     return;
570 }
571
572 /**
573  * Yield the CPU so other host OS tasks can run.
574  * Given now immediately if there is no other thread that is runnable
575  * And there is no real bound on how long it will yield
576  */
577 void palacios_sleep_cpu(unsigned int us)
578 {
579     // sleep not supported on Nautilus
580     // just yield
581     nk_yield();
582     udelay(us);
583 }
584
585 void palacios_wakeup_cpu(void *thread)
586 {
587     // threads never go to sleep, so shouldn't happen
588     ERROR("ERROR ERROR: WAKEUP_CPU CALLED. THREADS ARE NEVER ASLEEP");
589     return;
590 }
591
592 /**
593  * Allocates a mutex.
594  * Returns NULL on failure.
595  */
596 void *
597 palacios_mutex_alloc(void)
598 {
599     spinlock_t *lock = palacios_alloc(sizeof(spinlock_t));
600     
601     if (lock) {
602         spinlock_init(lock);
603     } else {
604         ERROR("ALERT ALERT Unable to allocate lock\n");
605         return NULL;
606     }
607     
608     return lock;
609 }
610
611 void palacios_mutex_init(void *mutex)
612 {
613     spinlock_t *lock = (spinlock_t*)mutex;
614     
615     if (lock) {
616         spinlock_init(lock);
617         LOCKCHECK_ALLOC(lock);
618     }
619     
620 }
621
622 void palacios_mutex_deinit(void *mutex)
623 {
624     spinlock_t *lock = (spinlock_t*)mutex;
625   
626     if (lock) {
627         spinlock_deinit(lock);
628         LOCKCHECK_FREE(lock);
629     }
630 }
631
632
633 /**
634  * Frees a mutex.
635  */
636 void
637 palacios_mutex_free(void * mutex) {
638     palacios_free(mutex);
639     LOCKCHECK_FREE(mutex);
640 }
641
642 /**
643  * Locks a mutex.
644  */
645 void 
646 palacios_mutex_lock(void * mutex, int must_spin) {
647     LOCKCHECK_LOCK_PRE(mutex);
648     spin_lock((spinlock_t *)mutex);
649     LOCKCHECK_LOCK_POST(mutex);
650 }
651
652
653 /**
654  * Locks a mutex, disabling interrupts on this core
655  */
656 void *
657 palacios_mutex_lock_irqsave(void * mutex, int must_spin) {
658     
659     unsigned long flags; 
660     
661     LOCKCHECK_LOCK_IRQSAVE_PRE(mutex,flags);
662     flags = spin_lock_irq_save((spinlock_t *)mutex);
663     LOCKCHECK_LOCK_IRQSAVE_POST(mutex,flags);
664
665     //INFO("lock irqsave flags=%lu\n",flags);
666     return (void *)flags;
667 }
668
669
670 /**
671  * Unlocks a mutex.
672  */
673 void 
674 palacios_mutex_unlock(
675         void *                  mutex
676
677 {
678     LOCKCHECK_UNLOCK_PRE(mutex);
679     spin_unlock((spinlock_t *)mutex);
680     LOCKCHECK_UNLOCK_POST(mutex);
681 }
682
683
684 /**
685  * Unlocks a mutex and restores previous interrupt state on this core
686  */
687 void 
688 palacios_mutex_unlock_irqrestore(void *mutex, void *flags)
689 {
690     //INFO("unlock irqrestore flags=%lu\n",(unsigned long)flags);
691     LOCKCHECK_UNLOCK_IRQRESTORE_PRE(mutex,(unsigned long)flags);
692     // This is correct, flags is opaque
693     spin_unlock_irq_restore((spinlock_t *)mutex,(uint8_t) (unsigned long)flags);
694     LOCKCHECK_UNLOCK_IRQRESTORE_POST(mutex,(unsigned long)flags);
695 }
696
697
698 /**
699  * Structure used by the Palacios hypervisor to interface with the host kernel.
700  */
701 static struct v3_os_hooks palacios_os_hooks = {
702         .print                      = palacios_print_scoped, 
703         .allocate_pages             = palacios_allocate_pages,  
704         .free_pages                 = palacios_free_pages, 
705         .vmalloc                    = palacios_valloc, 
706         .vfree                      = palacios_vfree, 
707         .malloc                     = palacios_alloc, 
708         .free                       = palacios_free, 
709         .vaddr_to_paddr             = palacios_vaddr_to_paddr,  
710         .paddr_to_vaddr             = palacios_paddr_to_vaddr,  
711         .hook_interrupt             = palacios_hook_interrupt,  
712         .ack_irq                    = palacios_ack_interrupt,  
713         .get_cpu_khz                = palacios_get_cpu_khz, 
714         .start_kernel_thread        = palacios_create_and_start_kernel_thread, 
715         .yield_cpu                  = palacios_yield_cpu, 
716         .sleep_cpu                  = palacios_sleep_cpu, 
717         .wakeup_cpu                 = palacios_wakeup_cpu, 
718         .mutex_alloc                = palacios_mutex_alloc, 
719         .mutex_free                 = palacios_mutex_free, 
720         .mutex_lock                 = palacios_mutex_lock, 
721         .mutex_unlock               = palacios_mutex_unlock, 
722         .mutex_lock_irqsave         = palacios_mutex_lock_irqsave,  
723         .mutex_unlock_irqrestore    = palacios_mutex_unlock_irqrestore, 
724         .get_cpu                    = palacios_get_cpu, 
725         .interrupt_cpu              = palacios_interrupt_cpu, 
726         .call_on_cpu                = palacios_xcall, 
727         .create_thread_on_cpu       = palacios_create_thread_on_cpu, 
728         .start_thread               = palacios_start_thread, 
729         .move_thread_to_cpu         = palacios_move_thread_to_cpu, // unsupported
730 };
731
732
733 int palacios_vmm_init(char * options)
734 {
735     int num_cpus = nautilus_info.sys.num_cpus;
736     char * cpu_mask = NULL;
737
738     if (num_cpus > 0) {
739         int major = 0;
740         int minor = 0;
741         int i = 0;
742
743         cpu_mask = palacios_alloc((num_cpus / 8) + 1);
744         
745         if (!cpu_mask) { 
746             ERROR("Cannot allocate cpu mask\n");
747             return -1;
748         }
749
750         memset(cpu_mask, 0, (num_cpus / 8) + 1);
751         
752         for (i = 0; i < num_cpus; i++) {
753
754             major = i / 8;
755             minor = i % 8;
756     
757             *(cpu_mask + major) |= (0x1 << minor);
758         }
759     }
760
761
762     memset(irq_to_guest_map, 0, sizeof(struct v3_vm_info *) * 256);
763
764     memset(vms,0,sizeof(vms));
765
766     if (init_print_buffers()) {
767         INFO("Cannot initialize print buffers\n");
768         palacios_free(cpu_mask);
769         return -1;
770     }
771     
772     INFO("printbuffer init done\n");
773
774     INFO("NR_CPU: %d\n", NR_CPUS);
775
776     INFO("palacios_init starting - calling init_v3\n");
777
778     INFO("calling init_v3 = %p\n", Init_V3);
779
780     INFO("num_cpus: %d\ncpu_mask: %x\noptions: %s\n", num_cpus, *cpu_mask, options);
781
782     Init_V3(&palacios_os_hooks, cpu_mask, num_cpus, options);
783
784     INFO("init_v3 done\n");
785
786 #ifdef V3_CONFIG_CONSOLE
787     INFO("Initializing console\n");
788     nautilus_console_init();
789 #endif
790
791
792     return 0;
793
794 }
795
796
797 int palacios_vmm_exit( void ) 
798 {
799
800 #ifdef V3_CONFIG_CONSOLE
801     nautilus_console_deinit();
802 #endif
803
804     Shutdown_V3();
805
806     INFO("palacios shutdown complete\n");
807
808     deinit_print_buffers();
809
810     return 0;
811 }
812
813
814 void palacios_inform_new_vm_pre(char *name)
815 {
816   int i;
817   for (i=0;i<NR_VMS;i++) { 
818     if (!vms[i].name[0]) {
819       strncpy(vms[i].name,name,MAX_VM_NAME);
820       selected_vm = &vms[i];
821       return;
822     }
823   }
824 }
825
826 void palacios_inform_new_vm_post(char *name, struct v3_vm_info *vm)
827 {
828   struct nk_vm_state *n = palacios_find_vm_by_name(name);
829
830   if (n) { 
831     n->vm = vm;
832     INFO("Registered VM %p with name %s, node=%p, selected VM=%p\n",
833          vm, n->name, n, selected_vm);
834   } else {
835     ERROR("Cannot find VM with name \"%s\"\n",name);
836   }
837 }
838
839 void palacios_inform_free_vm(char *name) 
840 {
841   struct nk_vm_state *n = palacios_find_vm_by_name(name);
842
843   if (n==selected_vm) { 
844     selected_vm = 0;
845   }
846
847   if (n) { 
848     n->vm = 0;
849     n->vc = 0;
850     n->name[0] = 0;
851   }
852   
853 }
854
855 void palacios_inform_free_selected_vm()
856 {
857   struct nk_vm_state *n = selected_vm;
858
859   selected_vm = 0;
860
861   if (n) { 
862     n->vm = 0;
863     n->vc = 0;
864     n->name[0] = 0;
865   }
866 }
867
868
869 struct nk_vm_state *palacios_find_vm_by_name(char *name)
870 {
871   int i;
872   for (i=0;i<NR_VMS;i++) { 
873     if (!strncmp(vms[i].name,name,MAX_VM_NAME)) {
874       return &vms[i];
875     }
876   }
877   return 0;
878 }
879
880 struct nk_vm_state *palacios_find_vm(struct v3_vm_info *vm)
881 {
882   int i;
883   for (i=0;i<NR_VMS;i++) { 
884     if (vms[i].vm == vm) { 
885       return &vms[i];
886     }
887   }
888   return 0;
889 }
890
891 void palacios_select_vm(struct v3_vm_info *vm)
892 {
893   struct nk_vm_state *n = palacios_find_vm(vm);
894   if (n) {
895     selected_vm = n;
896   }
897 }
898
899 void palacios_select_vm_by_name(char *name)
900 {
901   struct nk_vm_state *n = palacios_find_vm_by_name(name);
902   if (n) {
903     selected_vm = n;
904   }
905 }
906
907 struct nk_vm_state *palacios_get_selected_vm()
908 {
909   return selected_vm;
910 }
911