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.


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