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.


Error checking fixes, minor bug in keyed stream, minor bug in checkpoint
[palacios.git] / linux_module / palacios-stubs.c
1 #include <linux/kernel.h>
2 #include <linux/kthread.h>
3 #include <linux/spinlock.h>
4 #include <linux/gfp.h>
5 #include <linux/interrupt.h>
6 #include <linux/linkage.h>
7 #include <linux/sched.h>
8 #include <linux/uaccess.h>
9 #include <asm/irq_vectors.h>
10 #include <asm/io.h>
11
12 #include <linux/init.h>
13 #include <linux/module.h>
14 #include <linux/kthread.h>
15 #include <asm/uaccess.h>
16 #include <linux/smp.h>
17 #include <linux/vmalloc.h>
18
19 #include <asm/i387.h>
20
21 #include <palacios/vmm.h>
22 #include <palacios/vmm_host_events.h>
23
24 #ifdef V3_CONFIG_HOST_LAZY_FPU_SWITCH
25 #include <interfaces/vmm_lazy_fpu.h>
26 #endif
27
28 #include "palacios.h"
29
30 #include "mm.h"
31
32 #include "memcheck.h"
33 #include "lockcheck.h"
34
35
36
37 // The following can be used to track memory bugs
38 // zero memory after allocation (now applies to valloc and page alloc as well)
39 #define ALLOC_ZERO_MEM 1
40 // pad allocations by this many bytes on both ends of block (heap only)
41 #define ALLOC_PAD      0
42
43
44 u32 pg_allocs = 0;
45 u32 pg_frees = 0;
46 u32 mallocs = 0;
47 u32 frees = 0;
48 u32 vmallocs = 0;
49 u32 vfrees = 0;
50
51 static struct v3_vm_info * irq_to_guest_map[256];
52
53
54 extern unsigned int cpu_khz;
55
56 extern int cpu_list[NR_CPUS];
57 extern int cpu_list_len;
58
59
60 static char *print_buffer[NR_CPUS];
61
62 static void deinit_print_buffers(void)
63 {
64     int i;
65
66     for (i=0;i<NR_CPUS;i++) {
67         if (print_buffer[i]) { 
68             palacios_free(print_buffer[i]);
69             print_buffer[i]=0;
70         }
71     }
72 }
73
74 static int init_print_buffers(void)
75 {
76     int i;
77     
78     memset(print_buffer,0,sizeof(char*)*NR_CPUS);
79
80 #if !V3_PRINTK_OLD_STYLE_OUTPUT
81
82     for (i=0;i<NR_CPUS;i++) { 
83         print_buffer[i] = palacios_alloc(V3_PRINTK_BUF_SIZE);
84         if (!print_buffer[i]) { 
85             ERROR("Cannot allocate print buffer for cpu %d\n",i);
86             deinit_print_buffers();
87             return -1;
88         }
89         memset(print_buffer[i],0,V3_PRINTK_BUF_SIZE);
90     }
91
92 #endif
93     
94     return 0;
95
96 }
97  
98 /**
99  * Prints a message to the console.
100  */
101 void palacios_print_scoped(void * vm, int vcore, const char *fmt, ...) {
102
103 #if V3_PRINTK_OLD_STYLE_OUTPUT
104
105   va_list ap;
106
107   va_start(ap, fmt);
108   vprintk(fmt, ap);
109   va_end(ap);
110
111   return
112
113 #else 
114
115   va_list ap;
116   char *buf;
117   unsigned int cpu = palacios_get_cpu();
118   struct v3_guest *guest = (struct v3_guest *)vm;
119
120   buf = print_buffer[cpu];
121
122   if (!buf) { 
123       printk(KERN_INFO "palacios (pcore %u): output skipped - no allocated buffer\n",cpu);
124       return;
125   } 
126
127   va_start(ap, fmt);
128   vsnprintf(buf,V3_PRINTK_BUF_SIZE, fmt, ap);
129   va_end(ap);
130
131 #if V3_PRINTK_CHECK_7BIT
132   {
133       char c=0;
134       int i;
135       for (i=0;i<strlen(buf);i++) { 
136           if (buf[i] < 0) {
137               c=buf[i];
138               break;
139           }
140       }
141       if (c!=0) { 
142           printk(KERN_INFO "palacios (pcore %u): ALERT ALERT 8 BIT CHAR (c=%d) DETECTED\n", cpu,c);
143       }
144   }
145 #endif
146
147   if (guest) {
148     if (vcore>=0) { 
149       printk(KERN_INFO "palacios (pcore %u vm %s vcore %u): %s",
150              cpu,
151              guest->name,
152              vcore,
153              buf);
154     } else {
155        printk(KERN_INFO "palacios (pcore %u vm %s): %s",
156              cpu,
157              guest->name,
158              buf);
159     }
160   } else {
161     printk(KERN_INFO "palacios (pcore %u): %s",
162            cpu,
163            buf);
164   }
165     
166   return;
167
168 #endif
169
170 }
171
172
173 /*
174  * Allocates a contiguous region of pages of the requested size.
175  * Returns the physical address of the first page in the region.
176  */
177 void *palacios_allocate_pages(int num_pages, unsigned int alignment, int node_id, int constraints) {
178     void * pg_addr = NULL;
179
180     if (num_pages<=0) { 
181         ERROR("ALERT ALERT Attempt to allocate zero or fewer pages (%d pages, alignment %d, node %d, constraints 0x%x)\n",num_pages, alignment, node_id, constraints);
182       return NULL;
183     }
184
185     pg_addr = (void *)alloc_palacios_pgs(num_pages, alignment, node_id, constraints);
186
187     if (!pg_addr) { 
188         ERROR("ALERT ALERT  Page allocation has FAILED Warning (%d pages, alignment %d, node %d, constraints 0x%x)\n",num_pages, alignment, node_id, constraints);
189         return NULL;
190     }
191
192     pg_allocs += num_pages;
193
194 #if ALLOC_ZERO_MEM
195     memset(__va(pg_addr),0,num_pages*4096);
196 #endif
197
198     MEMCHECK_ALLOC_PAGES(pg_addr,num_pages*4096);
199
200     return pg_addr;
201 }
202
203
204 /**
205  * Frees a page previously allocated via palacios_allocate_page().
206  * Note that palacios_allocate_page() can allocate multiple pages with
207  * a single call while palacios_free_page() only frees a single page.
208  */
209
210 void palacios_free_pages(void * page_paddr, int num_pages) {
211     if (!page_paddr) { 
212         ERROR("Ignoring free pages: 0x%p (0x%lx)for %d pages\n", page_paddr, (uintptr_t)page_paddr, num_pages);
213         dump_stack();
214     }
215     pg_frees += num_pages;
216     free_palacios_pgs((uintptr_t)page_paddr, num_pages);
217     MEMCHECK_FREE_PAGES(page_paddr,num_pages*4096);
218
219 }
220
221
222 void *
223 palacios_alloc_extended(unsigned int size, unsigned int flags, int node) {
224     void * addr = NULL;
225
226     if (size==0) { 
227       // note that modern kernels will respond to a zero byte
228       // kmalloc and return the address 0x10...  In Palacios, 
229       // we will simply not allow 0 byte allocs at all, of any kind
230       ERROR("ALERT ALERT attempt to kmalloc zero bytes rejected\n");
231       return NULL;
232     }
233
234     if (node==-1) { 
235         addr = kmalloc(size+2*ALLOC_PAD, flags);
236     } else {
237         addr = kmalloc_node(size+2*ALLOC_PAD, flags, node);
238     }
239
240     if (!addr || IS_ERR(addr)) { 
241        ERROR("ALERT ALERT  kmalloc has FAILED FAILED FAILED\n");
242        return NULL;
243     }   
244
245     mallocs++;
246
247 #if ALLOC_ZERO_MEM
248     memset(addr,0,size+2*ALLOC_PAD);
249 #endif
250
251     MEMCHECK_KMALLOC(addr,size+2*ALLOC_PAD);
252
253     return addr+ALLOC_PAD;
254 }
255
256 void *
257 palacios_valloc(unsigned int size)
258 {
259     void * addr = NULL;
260
261     if (size==0) { 
262       ERROR("ALERT ALERT attempt to vmalloc zero bytes rejected\n");
263       return NULL;
264     }
265
266     addr = vmalloc(size);
267
268     if (!addr || IS_ERR(addr)) { 
269        ERROR("ALERT ALERT  vmalloc has FAILED FAILED FAILED\n");
270        return NULL;
271     }   
272
273     vmallocs++;
274
275 #if ALLOC_ZERO_MEM
276     memset(addr,0,size);
277 #endif
278
279     MEMCHECK_VMALLOC(addr,size);
280
281     return addr;
282 }
283
284 void palacios_vfree(void *p)
285 {
286   vfree(p);
287   vfrees++;
288   MEMCHECK_VFREE(p);
289 }
290
291 /**
292  * Allocates 'size' bytes of kernel memory.
293  * Returns the kernel virtual address of the memory allocated.
294  */
295 void *
296 palacios_alloc(unsigned int size) {
297
298     // It is very important that this test remains since 
299     // this function is used extensively throughout palacios and the linux
300     // module, both in places where interrupts are off and where they are on
301     // a GFP_KERNEL call, when done with interrupts off can lead to DEADLOCK
302     if (irqs_disabled()) {
303         return palacios_alloc_extended(size,GFP_ATOMIC,-1);
304     } else {
305         return palacios_alloc_extended(size,GFP_KERNEL,-1);
306     }
307
308 }
309
310 /**
311  * Frees memory that was previously allocated by palacios_alloc().
312  */
313 void
314 palacios_free(
315         void *                  addr
316 )
317 {
318     if (!addr) {
319         ERROR("Ignoring free : 0x%p\n", addr);
320         dump_stack();
321     }
322     frees++;
323     kfree(addr-ALLOC_PAD);
324     MEMCHECK_KFREE(addr-ALLOC_PAD);
325 }
326
327 /**
328  * Converts a kernel virtual address to the corresponding physical address.
329  */
330 void *
331 palacios_vaddr_to_paddr(
332         void *                  vaddr
333 )
334 {
335     return (void*) __pa(vaddr);
336
337 }
338
339 /**
340  * Converts a physical address to the corresponding kernel virtual address.
341  */
342 void *
343 palacios_paddr_to_vaddr(
344         void *                  paddr
345 )
346 {
347   return __va(paddr);
348 }
349
350 /**
351  * Runs a function on the specified CPU.
352  */
353 static void 
354 palacios_xcall(
355         int                     cpu_id, 
356         void                    (*fn)(void *arg),
357         void *                  arg
358 )
359 {
360
361
362     // We set wait to 1, but I'm not sure this is necessary
363     smp_call_function_single(cpu_id, fn, arg, 1);
364     
365     return;
366 }
367
368
369 #define MAX_THREAD_NAME 32
370
371 struct lnx_thread_arg {
372     int (*fn)(void * arg);
373     void * arg;
374     char name[MAX_THREAD_NAME];
375 };
376
377 static int lnx_thread_target(void * arg) {
378     struct lnx_thread_arg * thread_info = (struct lnx_thread_arg *)arg;
379     int ret = 0;
380     /*
381       INFO("Daemonizing new Palacios thread (name=%s)\n", thread_info->name);
382
383       daemonize(thread_info->name);
384       allow_signal(SIGKILL);
385     */
386
387 #ifdef V3_CONFIG_HOST_LAZY_FPU_SWITCH
388     // We are a kernel thread that needs FPU save/restore state
389     // vcores definitely need this, all the other threads get it too, 
390     // but they just won't use it
391     fpu_alloc(&(current->thread.fpu));
392 #endif
393
394     ret = thread_info->fn(thread_info->arg);
395
396     INFO("Palacios Thread (%s) EXITING\n", thread_info->name);
397
398     palacios_free(thread_info);
399     // handle cleanup 
400
401     // We rely on do_exit to free the fpu data
402     // since we could get switched at any point until the thread is done... 
403
404     do_exit(ret);
405
406     return 0; // should not get here.
407 }
408
409 /**
410  * Creates a kernel thread.
411  */
412 void *
413 palacios_start_kernel_thread(
414         int (*fn)               (void * arg),
415         void *                  arg,
416         char *                  thread_name) {
417
418     struct lnx_thread_arg * thread_info = palacios_alloc(sizeof(struct lnx_thread_arg));
419
420     if (!thread_info) { 
421         ERROR("ALERT ALERT Unable to allocate thread\n");
422         return NULL;
423     }
424
425     thread_info->fn = fn;
426     thread_info->arg = arg;
427     strncpy(thread_info->name,thread_name,MAX_THREAD_NAME);
428     thread_info->name[MAX_THREAD_NAME-1] =0;
429
430     return kthread_run( lnx_thread_target, thread_info, thread_info->name );
431 }
432
433
434 /**
435  * Starts a kernel thread on the specified CPU.
436  */
437 void * 
438 palacios_start_thread_on_cpu(int cpu_id, 
439                              int (*fn)(void * arg), 
440                              void * arg, 
441                              char * thread_name ) {
442     struct task_struct * thread = NULL;
443     struct lnx_thread_arg * thread_info = palacios_alloc(sizeof(struct lnx_thread_arg));
444
445     if (!thread_info) { 
446         ERROR("ALERT ALERT Unable to allocate thread to start on cpu\n");
447         return NULL;
448     }
449
450     thread_info->fn = fn;
451     thread_info->arg = arg;
452     strncpy(thread_info->name,thread_name,MAX_THREAD_NAME);
453     thread_info->name[MAX_THREAD_NAME-1] =0;
454
455     thread = kthread_create( lnx_thread_target, thread_info, thread_info->name );
456
457     if (!thread || IS_ERR(thread)) {
458         WARNING("Palacios error creating thread: %s\n", thread_info->name);
459         palacios_free(thread_info);
460         return NULL;
461     }
462
463     if (set_cpus_allowed_ptr(thread, cpumask_of(cpu_id)) != 0) {
464         WARNING("Attempt to start thread on disallowed CPU\n");
465         kthread_stop(thread);
466         palacios_free(thread_info);
467         return NULL;
468     }
469
470     wake_up_process(thread);
471
472     return thread;
473 }
474
475
476 /**
477  * Rebind a kernel thread to the specified CPU
478  * The thread will be running on target CPU on return
479  * non-zero return means failure
480  */
481 int
482 palacios_move_thread_to_cpu(int new_cpu_id, 
483                             void * thread_ptr) {
484     struct task_struct * thread = (struct task_struct *)thread_ptr;
485
486     INFO("Moving thread (%p) to cpu %d\n", thread, new_cpu_id);
487
488     if (thread == NULL) {
489         thread = current;
490     }
491
492     /*
493      * Bind to the specified CPU.  When this call returns,
494      * the thread should be running on the target CPU.
495      */
496     return set_cpus_allowed_ptr(thread, cpumask_of(new_cpu_id));
497 }
498
499
500 /**
501  * Returns the CPU ID that the caller is running on.
502  */
503 unsigned int 
504 palacios_get_cpu(void) 
505 {
506
507     /* We want to call smp_processor_id()
508      * But this is not safe if kernel preemption is possible 
509      * We need to ensure that the palacios threads are bound to a give cpu
510      */
511
512     unsigned int cpu_id = get_cpu(); 
513     put_cpu();
514     return cpu_id;
515 }
516
517 /**
518  * Interrupts the physical CPU corresponding to the specified logical guest cpu.
519  *
520  * NOTE: 
521  * This is dependent on the implementation of xcall_reschedule().  Currently
522  * xcall_reschedule does not explicitly call schedule() on the destination CPU,
523  * but instead relies on the return to user space to handle it. Because
524  * palacios is a kernel thread schedule will not be called, which is correct.
525  * If it ever changes to induce side effects, we'll need to figure something
526  * else out...
527  */
528
529 #include <asm/apic.h>
530
531 static void
532 palacios_interrupt_cpu(
533         struct v3_vm_info *     vm, 
534         int                     cpu_id, 
535         int                     vector
536 )
537 {
538     if (vector == 0) {
539         smp_send_reschedule(cpu_id);
540     } else {
541         apic->send_IPI_mask(cpumask_of(cpu_id), vector);
542     }
543     return;
544 }
545
546 /**
547  * Dispatches an interrupt to Palacios for handling.
548  */
549 static void
550 palacios_dispatch_interrupt( int vector, void * dev, struct pt_regs * regs ) {
551     struct v3_interrupt intr = {
552         .irq            = vector,
553         .error          = regs->orig_ax,
554         .should_ack     = 1,
555     };
556     
557     if (irq_to_guest_map[vector]) {
558         v3_deliver_irq(irq_to_guest_map[vector], &intr);
559     }
560     
561 }
562
563 /**
564  * Instructs the kernel to forward the specified IRQ to Palacios.
565  */
566 static int
567 palacios_hook_interrupt(struct v3_vm_info *     vm,
568                         unsigned int            vector ) {
569     INFO("hooking vector %d\n", vector);        
570
571     if (irq_to_guest_map[vector]) {
572         WARNING(
573                "%s: Interrupt vector %u is already hooked.\n",
574                __func__, vector);
575         return -1;
576     }
577
578     DEBUG(
579            "%s: Hooking interrupt vector %u to vm %p.\n",
580            __func__, vector, vm);
581
582     irq_to_guest_map[vector] = vm;
583
584     /*
585      * NOTE: Normally PCI devices are supposed to be level sensitive,
586      *       but we need them to be edge sensitive so that they are
587      *       properly latched by Palacios.  Leaving them as level
588      *       sensitive would lead to an interrupt storm.
589      */
590     //ioapic_set_trigger_for_vector(vector, ioapic_edge_sensitive);
591     
592     //set_idtvec_handler(vector, palacios_dispatch_interrupt);
593     if (vector < 32) {
594         ERROR("unexpected vector for hooking\n");
595         return -1;
596     } else {
597         int device_id = 0;              
598         
599         int flag = 0;
600         int error;
601                 
602         DEBUG("hooking vector: %d\n", vector);          
603
604         if (vector == 32) {
605             flag = IRQF_TIMER;
606         } else {
607             flag = IRQF_SHARED;
608         }
609
610         error = request_irq((vector - 32),
611                             (void *)palacios_dispatch_interrupt,
612                             flag,
613                             "interrupt_for_palacios",
614                             &device_id);
615         
616         if (error) {
617             ERROR("error code for request_irq is %d\n", error);
618             ERROR("request vector %d failed", vector);
619             return -1;
620         }
621     }
622         
623     return 0;
624 }
625
626
627
628 /**
629  * Acknowledges an interrupt.
630  */
631 static int
632 palacios_ack_interrupt(
633         int                     vector
634
635 {
636   ack_APIC_irq(); 
637   DEBUG("Pretending to ack interrupt, vector=%d\n", vector);
638   return 0;
639 }
640   
641 /**
642  * Returns the CPU frequency in kilohertz.
643  */
644 unsigned int
645 palacios_get_cpu_khz(void) 
646 {
647     INFO("cpu_khz is %u\n", cpu_khz);
648
649     if (cpu_khz == 0) { 
650         INFO("faking cpu_khz to 1000000\n");
651         return 1000000;
652     } else {
653         return cpu_khz;
654     }
655   //return 1000000;
656 }
657
658 /**
659  * Yield the CPU so other host OS tasks can run.
660  * This will return immediately if there is no other thread that is runnable
661  * And there is no real bound on how long it will yield
662  */
663 void
664 palacios_yield_cpu(void)
665 {
666     schedule();
667     return;
668 }
669
670 /**
671  * Yield the CPU so other host OS tasks can run.
672  * Given now immediately if there is no other thread that is runnable
673  * And there is no real bound on how long it will yield
674  */
675 void palacios_sleep_cpu(unsigned int us)
676 {
677
678     set_current_state(TASK_INTERRUPTIBLE);
679     if (us) {
680         unsigned int uspj = 1000000U/HZ;
681         unsigned int jiffies = us/uspj + ((us%uspj) !=0);  // ceiling 
682         schedule_timeout(jiffies);
683     } else {
684         schedule();
685     }
686     return;
687 }
688
689 void palacios_wakeup_cpu(void *thread)
690 {
691     wake_up_process(thread);
692     return;
693 }
694
695 /**
696  * Allocates a mutex.
697  * Returns NULL on failure.
698  */
699 void *
700 palacios_mutex_alloc(void)
701 {
702     spinlock_t *lock = palacios_alloc(sizeof(spinlock_t));
703
704     if (lock) {
705         spin_lock_init(lock);
706         LOCKCHECK_ALLOC(lock);
707     } else {
708         ERROR("ALERT ALERT Unable to allocate lock\n");
709         return NULL;
710     }
711     
712     return lock;
713 }
714
715 void palacios_mutex_init(void *mutex)
716 {
717   spinlock_t *lock = (spinlock_t*)mutex;
718   
719   if (lock) {
720     spin_lock_init(lock);
721     LOCKCHECK_ALLOC(lock);
722   }
723 }
724
725 void palacios_mutex_deinit(void *mutex)
726 {
727   spinlock_t *lock = (spinlock_t*)mutex;
728   
729   if (lock) {
730     // no actual spin_lock_deinit on linux
731     // our purpose here is to drive the lock checker
732     LOCKCHECK_FREE(lock);
733   }
734 }
735
736
737 /**
738  * Frees a mutex.
739  */
740 void
741 palacios_mutex_free(void * mutex) {
742     palacios_free(mutex);
743     LOCKCHECK_FREE(mutex);
744 }
745
746 /**
747  * Locks a mutex.
748  */
749 void 
750 palacios_mutex_lock(void * mutex, int must_spin) {
751
752     LOCKCHECK_LOCK_PRE(mutex);
753     spin_lock((spinlock_t *)mutex);
754     LOCKCHECK_LOCK_POST(mutex);
755 }
756
757
758 /**
759  * Locks a mutex, disabling interrupts on this core
760  */
761 void *
762 palacios_mutex_lock_irqsave(void * mutex, int must_spin) {
763     
764     unsigned long flags; 
765     
766     LOCKCHECK_LOCK_IRQSAVE_PRE(mutex,flags);
767     spin_lock_irqsave((spinlock_t *)mutex,flags);
768     LOCKCHECK_LOCK_IRQSAVE_POST(mutex,flags);
769
770     return (void *)flags;
771 }
772
773
774 /**
775  * Unlocks a mutex.
776  */
777 void 
778 palacios_mutex_unlock(
779         void *                  mutex
780
781 {
782     LOCKCHECK_UNLOCK_PRE(mutex);
783     spin_unlock((spinlock_t *)mutex);
784     LOCKCHECK_UNLOCK_POST(mutex);
785 }
786
787
788 /**
789  * Unlocks a mutex and restores previous interrupt state on this core
790  */
791 void 
792 palacios_mutex_unlock_irqrestore(void *mutex, void *flags)
793 {
794     LOCKCHECK_UNLOCK_IRQRESTORE_PRE(mutex,(unsigned long)flags);
795     // This is correct, flags is opaque
796     spin_unlock_irqrestore((spinlock_t *)mutex,(unsigned long)flags);
797     LOCKCHECK_UNLOCK_IRQRESTORE_POST(mutex,(unsigned long)flags);
798 }
799
800 void palacios_used_fpu(void)
801 {
802    struct thread_info *cur = current_thread_info();
803
804    // We assume we are not preemptible here...
805    cur->status |= TS_USEDFPU;
806    clts(); 
807    // After this, FP Save should be handled by Linux if it
808    // switches to a different task and that task uses FPU
809 }
810
811 inline int ists(void)
812 {
813    return read_cr0() & X86_CR0_TS;
814
815 }
816 void palacios_need_fpu(void)
817 {
818     // We assume we are not preemptible here... 
819     if (ists()) { 
820       // we have been switched back to from somewhere else...
821       // Do a restore now - this will also do a clts()
822       math_state_restore();
823     }
824 }
825
826
827 /**
828  * Structure used by the Palacios hypervisor to interface with the host kernel.
829  */
830 static struct v3_os_hooks palacios_os_hooks = {
831         .print                  = palacios_print_scoped,
832         .allocate_pages         = palacios_allocate_pages,
833         .free_pages             = palacios_free_pages,
834         .malloc                 = palacios_alloc,
835         .free                   = palacios_free,
836         .vaddr_to_paddr         = palacios_vaddr_to_paddr,
837         .paddr_to_vaddr         = palacios_paddr_to_vaddr,
838         .hook_interrupt         = palacios_hook_interrupt,
839         .ack_irq                = palacios_ack_interrupt,
840         .get_cpu_khz            = palacios_get_cpu_khz,
841         .start_kernel_thread    = palacios_start_kernel_thread,
842         .yield_cpu              = palacios_yield_cpu,
843         .sleep_cpu              = palacios_sleep_cpu,
844         .wakeup_cpu             = palacios_wakeup_cpu,
845         .mutex_alloc            = palacios_mutex_alloc,
846         .mutex_free             = palacios_mutex_free,
847         .mutex_lock             = palacios_mutex_lock, 
848         .mutex_unlock           = palacios_mutex_unlock,
849         .mutex_lock_irqsave     = palacios_mutex_lock_irqsave, 
850         .mutex_unlock_irqrestore= palacios_mutex_unlock_irqrestore,
851         .get_cpu                = palacios_get_cpu,
852         .interrupt_cpu          = palacios_interrupt_cpu,
853         .call_on_cpu            = palacios_xcall,
854         .start_thread_on_cpu    = palacios_start_thread_on_cpu,
855         .move_thread_to_cpu     = palacios_move_thread_to_cpu,
856 };
857
858
859 #ifdef V3_CONFIG_HOST_LAZY_FPU_SWITCH
860 // Note that this host interface is defined here since it's
861 // intertwined with thread creation... 
862 static struct v3_lazy_fpu_iface palacios_fpu_hooks = {
863         .used_fpu               = palacios_used_fpu,
864         .need_fpu               = palacios_need_fpu
865 };
866
867 #endif
868
869
870 int palacios_vmm_init( char *options )
871 {
872     int num_cpus = num_online_cpus();
873     char * cpu_mask = NULL;
874
875     if (cpu_list_len > 0) {
876         int major = 0;
877         int minor = 0;
878         int i = 0;
879
880         cpu_mask = palacios_alloc((num_cpus / 8) + 1);
881
882         if (!cpu_mask) { 
883             ERROR("Cannot allocate cpu mask\n");
884             return -1;
885         }
886
887         memset(cpu_mask, 0, (num_cpus / 8) + 1);
888         
889         for (i = 0; i < cpu_list_len; i++) {
890             if (cpu_list[i] >= num_cpus) {
891                 WARNING("CPU (%d) exceeds number of available CPUs. Ignoring...\n", cpu_list[i]);
892                 continue;
893             }
894
895             major = cpu_list[i] / 8;
896             minor = cpu_list[i] % 8;
897     
898             *(cpu_mask + major) |= (0x1 << minor);
899         }
900     }
901
902     memset(irq_to_guest_map, 0, sizeof(struct v3_vm_info *) * 256);
903
904     if (init_print_buffers()) {
905         ERROR("Cannot initialize print buffers\n");
906         palacios_free(cpu_mask);
907         return -1;
908     }
909
910     INFO("palacios_init starting - calling init_v3\n");
911
912     Init_V3(&palacios_os_hooks, cpu_mask, num_cpus, options);
913
914 #ifdef V3_CONFIG_HOST_LAZY_FPU_SWITCH
915     V3_Init_Lazy_FPU(&palacios_fpu_hooks);
916 #endif
917
918     return 0;
919
920 }
921
922
923 int palacios_vmm_exit( void ) {
924
925     Shutdown_V3();
926
927     INFO("palacios shutdown complete\n");
928
929     deinit_print_buffers();
930
931     return 0;
932 }