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.


Merge branch 'devel' of palacios@newskysaw.cs.northwestern.edu:/home/palacios/palacio...
[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
18 #include <palacios/vmm.h>
19 #include <palacios/vmm_host_events.h>
20 #include "palacios.h"
21
22
23
24
25 #include "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     if (irqs_disabled()) {
89         addr = kmalloc(size, GFP_ATOMIC);
90     } else {
91         addr = kmalloc(size, GFP_KERNEL);
92     }
93     mallocs++;
94
95  
96     return addr;
97 }
98
99 /**
100  * Frees memory that was previously allocated by palacios_alloc().
101  */
102 static void
103 palacios_free(
104         void *                  addr
105 )
106 {
107     frees++;
108     kfree(addr);
109     return;
110 }
111
112 /**
113  * Converts a kernel virtual address to the corresponding physical address.
114  */
115 static void *
116 palacios_vaddr_to_paddr(
117         void *                  vaddr
118 )
119 {
120     return (void*) __pa(vaddr);
121
122 }
123
124 /**
125  * Converts a physical address to the corresponding kernel virtual address.
126  */
127 static void *
128 palacios_paddr_to_vaddr(
129         void *                  paddr
130 )
131 {
132   return __va(paddr);
133 }
134
135 /**
136  * Runs a function on the specified CPU.
137  */
138
139 // For now, do call only on local CPU 
140 static void 
141 palacios_xcall(
142         int                     cpu_id, 
143         void                    (*fn)(void *arg),
144         void *                  arg
145 )
146 {
147
148
149     // We set wait to 1, but I'm not sure this is necessary
150     smp_call_function_single(cpu_id, fn, arg, 1);
151     
152     return;
153 }
154
155 struct lnx_thread_arg {
156     int (*fn)(void * arg);
157     void * arg;
158     char * name;
159 };
160
161 static int lnx_thread_target(void * arg) {
162     struct lnx_thread_arg * thread_info = (struct lnx_thread_arg *)arg;
163
164     /*
165       printk("Daemonizing new Palacios thread (name=%s)\n", thread_info->name);
166
167       daemonize(thread_info->name);
168       allow_signal(SIGKILL);
169     */
170
171
172     thread_info->fn(thread_info->arg);
173
174     kfree(thread_info);
175     // handle cleanup 
176     
177     return 0;
178 }
179
180 /**
181  * Creates a kernel thread.
182  */
183 static void 
184 palacios_start_kernel_thread(
185         int (*fn)               (void * arg),
186         void *                  arg,
187         char *                  thread_name) {
188
189     struct lnx_thread_arg * thread_info = kmalloc(sizeof(struct lnx_thread_arg), GFP_KERNEL);
190
191     thread_info->fn = fn;
192     thread_info->arg = arg;
193     thread_info->name = thread_name;
194
195     kthread_run( lnx_thread_target, thread_info, thread_name );
196     return;
197 }
198
199
200 /**
201  * Starts a kernel thread on the specified CPU.
202  */
203 static void * 
204 palacios_start_thread_on_cpu(int cpu_id, 
205                              int (*fn)(void * arg), 
206                              void * arg, 
207                              char * thread_name ) {
208     struct task_struct * thread = NULL;
209     struct lnx_thread_arg * thread_info = kmalloc(sizeof(struct lnx_thread_arg), GFP_KERNEL);
210
211     thread_info->fn = fn;
212     thread_info->arg = arg;
213     thread_info->name = thread_name;
214
215
216     thread = kthread_create( lnx_thread_target, thread_info, thread_name );
217
218     if (IS_ERR(thread)) {
219         printk("Palacios error creating thread: %s\n", thread_name);
220         return NULL;
221     }
222
223     kthread_bind(thread, cpu_id);
224     wake_up_process(thread);
225
226     return thread;
227 }
228
229
230 /**
231  * Rebind a kernel thread to the specified CPU
232  * The thread will be running on target CPU on return
233  * non-zero return means failure
234  */
235 static int
236 palacios_move_thread_to_cpu(int new_cpu_id, 
237                              void * thread_ptr) {
238     struct task_struct * thread = (struct task_struct *)thread_ptr;
239
240     if(thread == NULL){
241         thread = current;
242     }
243
244     /*
245      * Bind to the specified CPU.  When this call returns,
246      * the thread should be running on the target CPU.
247      */
248     return set_cpus_allowed(thread, cpumask_of_cpu(new_cpu_id));
249 }
250
251
252 /**
253  * Returns the CPU ID that the caller is running on.
254  */
255 static unsigned int 
256 palacios_get_cpu(void) 
257 {
258
259     /* We want to call smp_processor_id()
260      * But this is not safe if kernel preemption is possible 
261      * We need to ensure that the palacios threads are bound to a give cpu
262      */
263
264     unsigned int cpu_id = get_cpu(); 
265     put_cpu();
266     return cpu_id;
267 }
268
269 /**
270  * Interrupts the physical CPU corresponding to the specified logical guest cpu.
271  *
272  * NOTE: 
273  * This is dependent on the implementation of xcall_reschedule().  Currently
274  * xcall_reschedule does not explicitly call schedule() on the destination CPU,
275  * but instead relies on the return to user space to handle it. Because
276  * palacios is a kernel thread schedule will not be called, which is correct.
277  * If it ever changes to induce side effects, we'll need to figure something
278  * else out...
279  */
280
281 #include <asm/apic.h>
282
283 static void
284 palacios_interrupt_cpu(
285         struct v3_vm_info *     vm, 
286         int                     cpu_id, 
287         int                     vector
288 )
289 {
290     if (vector == 0) {
291         smp_send_reschedule(cpu_id);
292     } else {
293         apic->send_IPI_mask(cpumask_of(cpu_id), vector);
294     }
295     return;
296 }
297
298 /**
299  * Dispatches an interrupt to Palacios for handling.
300  */
301 static void
302 palacios_dispatch_interrupt( int vector, void * dev, struct pt_regs * regs ) {
303     struct v3_interrupt intr = {
304         .irq            = vector,
305         .error          = regs->orig_ax,
306         .should_ack     = 1,
307     };
308     
309     if (irq_to_guest_map[vector]) {
310         v3_deliver_irq(irq_to_guest_map[vector], &intr);
311     }
312     
313 }
314
315 /**
316  * Instructs the kernel to forward the specified IRQ to Palacios.
317  */
318 static int
319 palacios_hook_interrupt(struct v3_vm_info *     vm,
320                         unsigned int            vector ) {
321     printk("hooking vector %d\n", vector);      
322
323     if (irq_to_guest_map[vector]) {
324         printk(KERN_WARNING
325                "%s: Interrupt vector %u is already hooked.\n",
326                __func__, vector);
327         return -1;
328     }
329
330     printk(KERN_DEBUG
331            "%s: Hooking interrupt vector %u to vm %p.\n",
332            __func__, vector, vm);
333
334     irq_to_guest_map[vector] = vm;
335
336     /*
337      * NOTE: Normally PCI devices are supposed to be level sensitive,
338      *       but we need them to be edge sensitive so that they are
339      *       properly latched by Palacios.  Leaving them as level
340      *       sensitive would lead to an interrupt storm.
341      */
342     //ioapic_set_trigger_for_vector(vector, ioapic_edge_sensitive);
343     
344     //set_idtvec_handler(vector, palacios_dispatch_interrupt);
345     if (vector < 32) {
346         panic("unexpected vector for hooking\n");
347     } else {
348         int device_id = 0;              
349         
350         int flag = 0;
351         int error;
352                 
353         printk("hooking vector: %d\n", vector);         
354
355         if (vector == 32) {
356             flag = IRQF_TIMER;
357         } else {
358             flag = IRQF_SHARED;
359         }
360
361         error = request_irq((vector - 32),
362                             (void *)palacios_dispatch_interrupt,
363                             flag,
364                             "interrupt_for_palacios",
365                             &device_id);
366         
367         if (error) {
368             printk("error code for request_irq is %d\n", error);
369             panic("request vector %d failed",vector);
370         }
371     }
372         
373     return 0;
374 }
375
376
377
378 /**
379  * Acknowledges an interrupt.
380  */
381 static int
382 palacios_ack_interrupt(
383         int                     vector
384
385 {
386   ack_APIC_irq(); 
387   printk("Pretending to ack interrupt, vector=%d\n",vector);
388   return 0;
389 }
390   
391 /**
392  * Returns the CPU frequency in kilohertz.
393  */
394 static unsigned int
395 palacios_get_cpu_khz(void) 
396 {
397     printk("cpu_khz is %u\n",cpu_khz);
398
399     if (cpu_khz == 0) { 
400         printk("faking cpu_khz to 1000000\n");
401         return 1000000;
402     } else {
403         return cpu_khz;
404     }
405   //return 1000000;
406 }
407
408 /**
409  * Yield the CPU so other host OS tasks can run.
410  */
411 static void
412 palacios_yield_cpu(void)
413 {
414     schedule();
415     return;
416 }
417
418
419
420 /**
421  * Allocates a mutex.
422  * Returns NULL on failure.
423  */
424 static void *
425 palacios_mutex_alloc(void)
426 {
427     spinlock_t *lock = kmalloc(sizeof(spinlock_t), GFP_KERNEL);
428
429     if (lock) {
430         spin_lock_init(lock);
431     }
432     
433     return lock;
434 }
435
436 /**
437  * Frees a mutex.
438  */
439 static void
440 palacios_mutex_free(void * mutex) {
441     kfree(mutex);
442 }
443
444 /**
445  * Locks a mutex.
446  */
447 static void 
448 palacios_mutex_lock(void * mutex, int must_spin) {
449     spin_lock((spinlock_t *)mutex);
450 }
451
452 /**
453  * Unlocks a mutex.
454  */
455 static void 
456 palacios_mutex_unlock(
457         void *                  mutex
458
459 {
460     spin_unlock((spinlock_t *)mutex);
461 }
462
463 /**
464  * Structure used by the Palacios hypervisor to interface with the host kernel.
465  */
466 static struct v3_os_hooks palacios_os_hooks = {
467         .print                  = palacios_print,
468         .allocate_pages         = palacios_allocate_pages,
469         .free_pages             = palacios_free_pages,
470         .malloc                 = palacios_alloc,
471         .free                   = palacios_free,
472         .vaddr_to_paddr         = palacios_vaddr_to_paddr,
473         .paddr_to_vaddr         = palacios_paddr_to_vaddr,
474         .hook_interrupt         = palacios_hook_interrupt,
475         .ack_irq                = palacios_ack_interrupt,
476         .get_cpu_khz            = palacios_get_cpu_khz,
477         .start_kernel_thread    = palacios_start_kernel_thread,
478         .yield_cpu              = palacios_yield_cpu,
479         .mutex_alloc            = palacios_mutex_alloc,
480         .mutex_free             = palacios_mutex_free,
481         .mutex_lock             = palacios_mutex_lock, 
482         .mutex_unlock           = palacios_mutex_unlock,
483         .get_cpu                = palacios_get_cpu,
484         .interrupt_cpu          = palacios_interrupt_cpu,
485         .call_on_cpu            = palacios_xcall,
486         .start_thread_on_cpu    = palacios_start_thread_on_cpu,
487         .move_thread_to_cpu = palacios_move_thread_to_cpu,
488 };
489
490
491
492
493 int palacios_vmm_init( void )
494 {
495     
496     memset(irq_to_guest_map, 0, sizeof(struct v3_vm_info *) * 256);
497     
498     printk("palacios_init starting - calling init_v3\n");
499     
500     Init_V3(&palacios_os_hooks, num_online_cpus());
501
502     return 0;
503
504 }
505
506
507 int palacios_vmm_exit( void ) {
508
509     Shutdown_V3();
510
511     return 0;
512 }