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.


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