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.


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