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.


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