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.


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