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.


Remove non-multithreaded OS option. Change VM creation to be fully asynchronous....
[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     return kthread_run( lnx_thread_target, thread_info, thread_name );
196 }
197
198
199 /**
200  * Starts a kernel thread on the specified CPU.
201  */
202 static void * 
203 palacios_start_thread_on_cpu(int cpu_id, 
204                              int (*fn)(void * arg), 
205                              void * arg, 
206                              char * thread_name ) {
207     struct task_struct * thread = NULL;
208     struct lnx_thread_arg * thread_info = kmalloc(sizeof(struct lnx_thread_arg), GFP_KERNEL);
209
210     thread_info->fn = fn;
211     thread_info->arg = arg;
212     thread_info->name = thread_name;
213
214
215     thread = kthread_create( lnx_thread_target, thread_info, thread_name );
216
217     if (IS_ERR(thread)) {
218         printk("Palacios error creating thread: %s\n", thread_name);
219         return NULL;
220     }
221
222     set_cpus_allowed_ptr(thread, cpumask_of(cpu_id));
223     wake_up_process(thread);
224
225     return thread;
226 }
227
228
229 /**
230  * Rebind a kernel thread to the specified CPU
231  * The thread will be running on target CPU on return
232  * non-zero return means failure
233  */
234 static int
235 palacios_move_thread_to_cpu(int new_cpu_id, 
236                             void * thread_ptr) {
237     struct task_struct * thread = (struct task_struct *)thread_ptr;
238
239     printk("Moving thread (%p) to cpu %d\n", thread, new_cpu_id);
240
241     if (thread == NULL) {
242         thread = current;
243     }
244
245     /*
246      * Bind to the specified CPU.  When this call returns,
247      * the thread should be running on the target CPU.
248      */
249     return set_cpus_allowed_ptr(thread, cpumask_of(new_cpu_id));
250 }
251
252
253 /**
254  * Returns the CPU ID that the caller is running on.
255  */
256 static unsigned int 
257 palacios_get_cpu(void) 
258 {
259
260     /* We want to call smp_processor_id()
261      * But this is not safe if kernel preemption is possible 
262      * We need to ensure that the palacios threads are bound to a give cpu
263      */
264
265     unsigned int cpu_id = get_cpu(); 
266     put_cpu();
267     return cpu_id;
268 }
269
270 /**
271  * Interrupts the physical CPU corresponding to the specified logical guest cpu.
272  *
273  * NOTE: 
274  * This is dependent on the implementation of xcall_reschedule().  Currently
275  * xcall_reschedule does not explicitly call schedule() on the destination CPU,
276  * but instead relies on the return to user space to handle it. Because
277  * palacios is a kernel thread schedule will not be called, which is correct.
278  * If it ever changes to induce side effects, we'll need to figure something
279  * else out...
280  */
281
282 #include <asm/apic.h>
283
284 static void
285 palacios_interrupt_cpu(
286         struct v3_vm_info *     vm, 
287         int                     cpu_id, 
288         int                     vector
289 )
290 {
291     if (vector == 0) {
292         smp_send_reschedule(cpu_id);
293     } else {
294         apic->send_IPI_mask(cpumask_of(cpu_id), vector);
295     }
296     return;
297 }
298
299 /**
300  * Dispatches an interrupt to Palacios for handling.
301  */
302 static void
303 palacios_dispatch_interrupt( int vector, void * dev, struct pt_regs * regs ) {
304     struct v3_interrupt intr = {
305         .irq            = vector,
306         .error          = regs->orig_ax,
307         .should_ack     = 1,
308     };
309     
310     if (irq_to_guest_map[vector]) {
311         v3_deliver_irq(irq_to_guest_map[vector], &intr);
312     }
313     
314 }
315
316 /**
317  * Instructs the kernel to forward the specified IRQ to Palacios.
318  */
319 static int
320 palacios_hook_interrupt(struct v3_vm_info *     vm,
321                         unsigned int            vector ) {
322     printk("hooking vector %d\n", vector);      
323
324     if (irq_to_guest_map[vector]) {
325         printk(KERN_WARNING
326                "%s: Interrupt vector %u is already hooked.\n",
327                __func__, vector);
328         return -1;
329     }
330
331     printk(KERN_DEBUG
332            "%s: Hooking interrupt vector %u to vm %p.\n",
333            __func__, vector, vm);
334
335     irq_to_guest_map[vector] = vm;
336
337     /*
338      * NOTE: Normally PCI devices are supposed to be level sensitive,
339      *       but we need them to be edge sensitive so that they are
340      *       properly latched by Palacios.  Leaving them as level
341      *       sensitive would lead to an interrupt storm.
342      */
343     //ioapic_set_trigger_for_vector(vector, ioapic_edge_sensitive);
344     
345     //set_idtvec_handler(vector, palacios_dispatch_interrupt);
346     if (vector < 32) {
347         panic("unexpected vector for hooking\n");
348     } else {
349         int device_id = 0;              
350         
351         int flag = 0;
352         int error;
353                 
354         printk("hooking vector: %d\n", vector);         
355
356         if (vector == 32) {
357             flag = IRQF_TIMER;
358         } else {
359             flag = IRQF_SHARED;
360         }
361
362         error = request_irq((vector - 32),
363                             (void *)palacios_dispatch_interrupt,
364                             flag,
365                             "interrupt_for_palacios",
366                             &device_id);
367         
368         if (error) {
369             printk("error code for request_irq is %d\n", error);
370             panic("request vector %d failed",vector);
371         }
372     }
373         
374     return 0;
375 }
376
377
378
379 /**
380  * Acknowledges an interrupt.
381  */
382 static int
383 palacios_ack_interrupt(
384         int                     vector
385
386 {
387   ack_APIC_irq(); 
388   printk("Pretending to ack interrupt, vector=%d\n",vector);
389   return 0;
390 }
391   
392 /**
393  * Returns the CPU frequency in kilohertz.
394  */
395 static unsigned int
396 palacios_get_cpu_khz(void) 
397 {
398     printk("cpu_khz is %u\n",cpu_khz);
399
400     if (cpu_khz == 0) { 
401         printk("faking cpu_khz to 1000000\n");
402         return 1000000;
403     } else {
404         return cpu_khz;
405     }
406   //return 1000000;
407 }
408
409 /**
410  * Yield the CPU so other host OS tasks can run.
411  */
412 static void
413 palacios_yield_cpu(void)
414 {
415     schedule();
416     return;
417 }
418
419
420
421 /**
422  * Allocates a mutex.
423  * Returns NULL on failure.
424  */
425 static void *
426 palacios_mutex_alloc(void)
427 {
428     spinlock_t *lock = kmalloc(sizeof(spinlock_t), GFP_KERNEL);
429
430     if (lock) {
431         spin_lock_init(lock);
432     }
433     
434     return lock;
435 }
436
437 /**
438  * Frees a mutex.
439  */
440 static void
441 palacios_mutex_free(void * mutex) {
442     kfree(mutex);
443 }
444
445 /**
446  * Locks a mutex.
447  */
448 static void 
449 palacios_mutex_lock(void * mutex, int must_spin) {
450     spin_lock((spinlock_t *)mutex);
451 }
452
453 /**
454  * Unlocks a mutex.
455  */
456 static void 
457 palacios_mutex_unlock(
458         void *                  mutex
459
460 {
461     spin_unlock((spinlock_t *)mutex);
462 }
463
464 /**
465  * Structure used by the Palacios hypervisor to interface with the host kernel.
466  */
467 static struct v3_os_hooks palacios_os_hooks = {
468         .print                  = palacios_print,
469         .allocate_pages         = palacios_allocate_pages,
470         .free_pages             = palacios_free_pages,
471         .malloc                 = palacios_alloc,
472         .free                   = palacios_free,
473         .vaddr_to_paddr         = palacios_vaddr_to_paddr,
474         .paddr_to_vaddr         = palacios_paddr_to_vaddr,
475         .hook_interrupt         = palacios_hook_interrupt,
476         .ack_irq                = palacios_ack_interrupt,
477         .get_cpu_khz            = palacios_get_cpu_khz,
478         .start_kernel_thread    = palacios_start_kernel_thread,
479         .yield_cpu              = palacios_yield_cpu,
480         .mutex_alloc            = palacios_mutex_alloc,
481         .mutex_free             = palacios_mutex_free,
482         .mutex_lock             = palacios_mutex_lock, 
483         .mutex_unlock           = palacios_mutex_unlock,
484         .get_cpu                = palacios_get_cpu,
485         .interrupt_cpu          = palacios_interrupt_cpu,
486         .call_on_cpu            = palacios_xcall,
487         .start_thread_on_cpu    = palacios_start_thread_on_cpu,
488         .move_thread_to_cpu = palacios_move_thread_to_cpu,
489 };
490
491
492
493
494 int palacios_vmm_init( void )
495 {
496     
497     memset(irq_to_guest_map, 0, sizeof(struct v3_vm_info *) * 256);
498     
499     printk("palacios_init starting - calling init_v3\n");
500     
501     Init_V3(&palacios_os_hooks, num_online_cpus());
502
503     return 0;
504
505 }
506
507
508 int palacios_vmm_exit( void ) {
509
510     Shutdown_V3();
511
512     return 0;
513 }