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.


inspector updates
[palacios.git] / linux_module / palacios.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_lock.h>
17
18 #include <palacios/vmm.h>
19 #include <palacios/vmm_host_events.h>
20 #include "palacios.h"
21
22
23
24
25 #include "palacios-mm.h"
26
27
28 u32 pg_allocs = 0;
29 u32 pg_frees = 0;
30 u32 mallocs = 0;
31 u32 frees = 0;
32
33
34 static struct v3_vm_info * irq_to_guest_map[256];
35
36
37 extern unsigned int cpu_khz;
38
39
40 /**
41  * Prints a message to the console.
42  */
43 static void palacios_print(const char * fmt, ...) {
44   va_list ap;
45   va_start(ap, fmt);
46   vprintk(fmt, ap);
47   va_end(ap);
48   
49   return;
50 }
51
52
53
54 /*
55  * Allocates a contiguous region of pages of the requested size.
56  * Returns the physical address of the first page in the region.
57  */
58 static void * palacios_allocate_pages(int num_pages, unsigned int alignment) {
59     void * pg_addr = NULL;
60
61     pg_addr = (void *)alloc_palacios_pgs(num_pages, alignment);
62     pg_allocs += num_pages;
63
64     return pg_addr;
65 }
66
67
68 /**
69  * Frees a page previously allocated via palacios_allocate_page().
70  * Note that palacios_allocate_page() can allocate multiple pages with
71  * a single call while palacios_free_page() only frees a single page.
72  */
73
74 static void palacios_free_pages(void * page_paddr, int num_pages) {
75     pg_frees += num_pages;
76     free_palacios_pgs((uintptr_t)page_paddr, num_pages);
77 }
78
79
80 /**
81  * Allocates 'size' bytes of kernel memory.
82  * Returns the kernel virtual address of the memory allocated.
83  */
84 static void *
85 palacios_alloc(unsigned int size) {
86     void * addr = NULL;
87
88     addr = kmalloc(size, GFP_KERNEL);
89     mallocs++;
90  
91     return addr;
92 }
93
94 /**
95  * Frees memory that was previously allocated by palacios_alloc().
96  */
97 static void
98 palacios_free(
99         void *                  addr
100 )
101 {
102     frees++;
103     kfree(addr);
104     return;
105 }
106
107 /**
108  * Converts a kernel virtual address to the corresponding physical address.
109  */
110 static void *
111 palacios_vaddr_to_paddr(
112         void *                  vaddr
113 )
114 {
115     return (void*) __pa(vaddr);
116
117 }
118
119 /**
120  * Converts a physical address to the corresponding kernel virtual address.
121  */
122 static void *
123 palacios_paddr_to_vaddr(
124         void *                  paddr
125 )
126 {
127   return __va(paddr);
128 }
129
130 /**
131  * Runs a function on the specified CPU.
132  */
133
134 // For now, do call only on local CPU 
135 static void 
136 palacios_xcall(
137         int                     cpu_id, 
138         void                    (*fn)(void *arg),
139         void *                  arg
140 )
141 {
142   printk("palacios_xcall: Doing 'xcall' to local cpu\n");
143   fn(arg);
144   return;
145 }
146
147 struct lnx_thread_arg {
148     int (*fn)(void * arg);
149     void * arg;
150     char * name;
151 };
152
153 static int lnx_thread_target(void * arg) {
154     struct lnx_thread_arg * thread_info = (struct lnx_thread_arg *)arg;
155
156     /*
157       lock_kernel();
158       printk("Daemonizing new Palacios thread (name=%s)\n", thread_info->name);
159
160       daemonize(thread_info->name);
161       unlock_kernel();
162       allow_signal(SIGKILL);
163     */
164
165
166     thread_info->fn(thread_info->arg);
167
168     kfree(thread_info);
169     // handle cleanup 
170     
171     return 0;
172 }
173
174 /**
175  * Creates a kernel thread.
176  */
177 static void 
178 palacios_start_kernel_thread(
179         int (*fn)               (void * arg),
180         void *                  arg,
181         char *                  thread_name) {
182
183     struct lnx_thread_arg * thread_info = kmalloc(sizeof(struct lnx_thread_arg), GFP_KERNEL);
184
185     thread_info->fn = fn;
186     thread_info->arg = arg;
187     thread_info->name = thread_name;
188
189     kthread_run( lnx_thread_target, thread_info, thread_name );
190     return;
191 }
192
193
194 /**
195  * Starts a kernel thread on the specified CPU.
196  */
197 static void * 
198 palacios_start_thread_on_cpu(int cpu_id, 
199                              int (*fn)(void * arg), 
200                              void * arg, 
201                              char * thread_name ) {
202     struct task_struct * thread = NULL;
203     struct lnx_thread_arg * thread_info = kmalloc(sizeof(struct lnx_thread_arg), GFP_KERNEL);
204
205     thread_info->fn = fn;
206     thread_info->arg = arg;
207     thread_info->name = thread_name;
208
209     thread = kthread_run( lnx_thread_target, thread_info, thread_name );
210
211     if (IS_ERR(thread)) {
212         printk("Palacios error creating thread: %s\n", thread_name);
213         return NULL;
214     }
215
216     return thread;
217 }
218
219 /**
220  * Returns the CPU ID that the caller is running on.
221  */
222 static unsigned int 
223 palacios_get_cpu(void) 
224 {
225 #if 1
226     return 0;
227     // return smp_processor_id();
228     // id = get_cpu(); put_cpu(id);
229     // return this_cpu;
230 #else
231                 struct cpumask mask;    
232                 unsigned int set;
233
234                 if(sched_getaffinity(0,&mask)<0){
235                         panic("sched_getaffinity failed");
236                         return -1;
237                 }
238                 set = cpumask_first(&mask);
239                 printk("***mask.bits: %d",set);
240                 return set;
241 #endif
242 }
243
244 /**
245  * Interrupts the physical CPU corresponding to the specified logical guest cpu.
246  *
247  * NOTE: 
248  * This is dependent on the implementation of xcall_reschedule().  Currently
249  * xcall_reschedule does not explicitly call schedule() on the destination CPU,
250  * but instead relies on the return to user space to handle it. Because
251  * palacios is a kernel thread schedule will not be called, which is correct.
252  * If it ever changes to induce side effects, we'll need to figure something
253  * else out...
254  */
255 static void
256 palacios_interrupt_cpu(
257         struct v3_vm_info *     vm, 
258         int                     cpu_id, 
259         int                     vector
260 )
261 {
262     // panic("palacios_interrupt_cpu");
263         //  printk("Faking interruption of target CPU by not doing anything since there is only one CPU\n");
264   return;
265 }
266
267 /**
268  * Dispatches an interrupt to Palacios for handling.
269  */
270 static void
271 palacios_dispatch_interrupt( int vector, void * dev, struct pt_regs * regs ) {
272     struct v3_interrupt intr = {
273         .irq            = vector,
274         .error          = regs->orig_ax,
275         .should_ack     = 1,
276     };
277     
278     if (irq_to_guest_map[vector]) {
279         v3_deliver_irq(irq_to_guest_map[vector], &intr);
280     }
281     
282 }
283
284 /**
285  * Instructs the kernel to forward the specified IRQ to Palacios.
286  */
287 static int
288 palacios_hook_interrupt(struct v3_vm_info *     vm,
289                         unsigned int            vector ) {
290     printk("hooking vector %d\n", vector);      
291
292     if (irq_to_guest_map[vector]) {
293         printk(KERN_WARNING
294                "%s: Interrupt vector %u is already hooked.\n",
295                __func__, vector);
296         return -1;
297     }
298
299     printk(KERN_DEBUG
300            "%s: Hooking interrupt vector %u to vm %p.\n",
301            __func__, vector, vm);
302
303     irq_to_guest_map[vector] = vm;
304
305     /*
306      * NOTE: Normally PCI devices are supposed to be level sensitive,
307      *       but we need them to be edge sensitive so that they are
308      *       properly latched by Palacios.  Leaving them as level
309      *       sensitive would lead to an interrupt storm.
310      */
311     //ioapic_set_trigger_for_vector(vector, ioapic_edge_sensitive);
312     
313     //set_idtvec_handler(vector, palacios_dispatch_interrupt);
314     if (vector < 32) {
315         panic("unexpected vector for hooking\n");
316     } else {
317         int device_id = 0;              
318         
319         int flag = 0;
320         int error;
321                 
322         printk("hooking vector: %d\n", vector);         
323
324         if (vector == 32) {
325             flag = IRQF_TIMER;
326         } else {
327             flag = IRQF_SHARED;
328         }
329
330         error = request_irq((vector - 32),
331                             (void *)palacios_dispatch_interrupt,
332                             flag,
333                             "interrupt_for_palacios",
334                             &device_id);
335         
336         if (error) {
337             printk("error code for request_irq is %d\n", error);
338             panic("request vector %d failed",vector);
339         }
340     }
341         
342     return 0;
343 }
344
345 /**
346  * Acknowledges an interrupt.
347  */
348 static int
349 palacios_ack_interrupt(
350         int                     vector
351
352 {
353   ack_APIC_irq(); 
354   printk("Pretending to ack interrupt, vector=%d\n",vector);
355   return 0;
356 }
357   
358 /**
359  * Returns the CPU frequency in kilohertz.
360  */
361 static unsigned int
362 palacios_get_cpu_khz(void) 
363 {
364     printk("cpu_khz is %u\n",cpu_khz);
365     if (cpu_khz==0) { 
366         printk("faking cpu_khz to 1000000\n");
367         return 1000000;
368     } else {
369         return cpu_khz;
370     }
371   //return 1000000;
372 }
373
374 /**
375  * Yield the CPU so other host OS tasks can run.
376  */
377 static void
378 palacios_yield_cpu(void)
379 {
380     schedule();
381     return;
382 }
383
384
385
386 /**
387  * Allocates a mutex.
388  * Returns NULL on failure.
389  */
390 static void *
391 palacios_mutex_alloc(void)
392 {
393   spinlock_t *lock = kmalloc(sizeof(spinlock_t), GFP_KERNEL);
394   if (lock)
395        spin_lock_init(lock);
396   return lock;
397 }
398
399 /**
400  * Frees a mutex.
401  */
402 static void
403 palacios_mutex_free(
404         void *                  mutex
405
406 {
407   kfree(mutex);
408 }
409
410 /**
411  * Locks a mutex.
412  */
413 static void 
414 palacios_mutex_lock(
415         void *                  mutex, 
416         int                     must_spin
417 )
418 {
419   spin_lock((spinlock_t*)mutex);
420 }
421
422 /**
423  * Unlocks a mutex.
424  */
425 static void 
426 palacios_mutex_unlock(
427         void *                  mutex
428
429 {
430   spin_unlock((spinlock_t*)mutex);
431 }
432
433 /**
434  * Structure used by the Palacios hypervisor to interface with the host kernel.
435  */
436 static struct v3_os_hooks palacios_os_hooks = {
437         .print                  = palacios_print,
438         .allocate_pages         = palacios_allocate_pages,
439         .free_pages             = palacios_free_pages,
440         .malloc                 = palacios_alloc,
441         .free                   = palacios_free,
442         .vaddr_to_paddr         = palacios_vaddr_to_paddr,
443         .paddr_to_vaddr         = palacios_paddr_to_vaddr,
444         .hook_interrupt         = palacios_hook_interrupt,
445         .ack_irq                = palacios_ack_interrupt,
446         .get_cpu_khz            = palacios_get_cpu_khz,
447         .start_kernel_thread    = palacios_start_kernel_thread,
448         .yield_cpu              = palacios_yield_cpu,
449         .mutex_alloc            = palacios_mutex_alloc,
450         .mutex_free             = palacios_mutex_free,
451         .mutex_lock             = palacios_mutex_lock, 
452         .mutex_unlock           = palacios_mutex_unlock,
453         .get_cpu                = palacios_get_cpu,
454         .interrupt_cpu          = palacios_interrupt_cpu,
455         .call_on_cpu            = palacios_xcall,
456         .start_thread_on_cpu    = palacios_start_thread_on_cpu,
457 };
458
459
460
461
462 int palacios_vmm_init( void )
463 {
464     
465     memset(irq_to_guest_map, 0, sizeof(struct v3_vm_info *) * 256);
466     
467     printk("palacios_init starting - calling init_v3\n");
468     
469     Init_V3(&palacios_os_hooks, 1);
470         
471
472     return 0;
473
474 }
475
476
477 int palacios_vmm_exit( void ) {
478
479     Shutdown_V3();
480
481     return 0;
482 }