menu "Supported host OS features"
-config MULTITHREAD_OS
- bool "Host support for multiple threads"
- default y
- help
- Select this if your OS supports multiple threads of execution. This will enable features in Palacios
- to require the creation of additional execution threads.
-
config ALIGNED_PG_ALLOC
bool "Host support for aligned page allocations"
struct v3_guest * guest = kmalloc(sizeof(struct v3_guest), GFP_KERNEL);
if (IS_ERR(guest)) {
- printk("Error allocating Kernel guest_image\n");
+ printk("Palacios: Error allocating Kernel guest_image\n");
return -EFAULT;
}
memset(guest, 0, sizeof(struct v3_guest));
- printk("Starting V3 Guest... (%p)\n", guest);
+ printk("Palacios: Starting V3 Guest...\n");
vm_minor = register_vm(guest);
if (vm_minor == -1) {
- printk("Too many VMs are currently running\n");
+ printk("Palacios Error: Too many VMs are currently running\n");
return -EFAULT;
}
guest->vm_dev = MKDEV(v3_major_num, vm_minor);
if (copy_from_user(&user_image, argp, sizeof(struct v3_guest_img))) {
- printk("copy from user error getting guest image...\n");
+ printk("Palacios Error: copy from user error getting guest image...\n");
return -EFAULT;
}
guest->img_size = user_image.size;
- printk("Allocating kernel memory for guest image (%llu bytes)\n", user_image.size);
+ printk("Palacios: Allocating kernel memory for guest image (%llu bytes)\n", user_image.size);
guest->img = vmalloc(guest->img_size);
if (IS_ERR(guest->img)) {
- printk("Error: Could not allocate space for guest image\n");
+ printk("Palacios Error: Could not allocate space for guest image\n");
return -EFAULT;
}
if (copy_from_user(guest->img, user_image.guest_data, guest->img_size)) {
- printk("Error loading guest data\n");
+ printk("Palacios: Error loading guest data\n");
return -EFAULT;
}
strncpy(guest->name, user_image.name, 127);
- printk("Launching VM\n");
+ printk("Palacios: Launching VM\n");
INIT_LIST_HEAD(&(guest->exts));
- init_completion(&(guest->start_done));
- init_completion(&(guest->thread_done));
-
- {
- struct task_struct * launch_thread = NULL;
- // At some point we're going to want to allow the user to specify a CPU mask
- // But for now, well just launch from the local core, and rely on the global cpu mask
-
- preempt_disable();
- launch_thread = kthread_create(start_palacios_vm, guest, guest->name);
-
- if (IS_ERR(launch_thread)) {
- preempt_enable();
- printk("Palacios error creating launch thread for vm (%s)\n", guest->name);
- return -EFAULT;
- }
-
- kthread_bind(launch_thread, smp_processor_id());
- preempt_enable();
-
- wake_up_process(launch_thread);
+ if (start_palacios_vm(guest) == -1) {
+ printk("Palacios: Error starting guest\n");
+ return -EFAULT;
}
- wait_for_completion(&(guest->start_done));
-
return guest->vm_dev;
break;
}
/**
* Creates a kernel thread.
*/
-static void
+static void *
palacios_start_kernel_thread(
int (*fn) (void * arg),
void * arg,
thread_info->arg = arg;
thread_info->name = thread_name;
- kthread_run( lnx_thread_target, thread_info, thread_name );
- return;
+ return kthread_run( lnx_thread_target, thread_info, thread_name );
}
return NULL;
}
- kthread_bind(thread, cpu_id);
+ set_cpus_allowed_ptr(thread, cpumask_of(cpu_id));
wake_up_process(thread);
return thread;
struct rb_root vm_ctrls;
struct list_head exts;
- struct completion start_done;
- struct completion thread_done;
-
dev_t vm_dev;
struct cdev cdev;
};
extern u32 mallocs;
extern u32 frees;
-int start_palacios_vm(void * arg) {
- struct v3_guest * guest = (struct v3_guest *)arg;
+int start_palacios_vm(struct v3_guest * guest) {
int err;
-
- daemonize(guest->name);
- // allow_signal(SIGKILL);
-
-
init_vm_extensions(guest);
guest->v3_ctx = v3_create_vm(guest->img, (void *)guest, guest->name);
if (guest->v3_ctx == NULL) {
printk("palacios: failed to create vm\n");
- complete(&(guest->start_done));
return -1;
}
if (err) {
printk("Fails to add cdev\n");
v3_free_vm(guest->v3_ctx);
- complete(&(guest->start_done));
return -1;
}
printk("Fails to create device\n");
cdev_del(&(guest->cdev));
v3_free_vm(guest->v3_ctx);
- complete(&(guest->start_done));
return -1;
}
- complete(&(guest->start_done));
-
printk("palacios: launching vm\n");
if (v3_start_vm(guest->v3_ctx, 0xffffffff) < 0) {
return -1;
}
- complete(&(guest->thread_done));
-
printk("palacios: vm completed. returning.\n");
return 0;
v3_stop_vm(guest->v3_ctx);
- wait_for_completion(&(guest->thread_done));
v3_free_vm(guest->v3_ctx);
#include "palacios.h"
-int start_palacios_vm(void * arg);
+int start_palacios_vm(struct v3_guest * guest);
int stop_palacios_vm(struct v3_guest * guest);
})
-#ifdef V3_CONFIG_MULTITHREAD_OS
-#define V3_CREATE_THREAD(fn, arg, name) \
- do { \
- extern struct v3_os_hooks * os_hooks; \
- if ((os_hooks) && (os_hooks)->start_kernel_thread) { \
- (os_hooks)->start_kernel_thread(fn, arg, name); \
- } \
- } while (0)
+
+#define V3_CREATE_THREAD(fn, arg, name) ({ \
+ void * thread = NULL; \
+ extern struct v3_os_hooks * os_hooks; \
+ if ((os_hooks) && (os_hooks)->start_kernel_thread) { \
+ thread = (os_hooks)->start_kernel_thread(fn, arg, name); \
+ } \
+ thread; \
+ })
ret; \
})
-#endif
/* ** */
void v3_yield_cond(struct guest_info * info);
void v3_print_cond(const char * fmt, ...);
-
-#ifdef V3_CONFIG_MULTITHREAD_OS
void v3_interrupt_cpu(struct v3_vm_info * vm, int logical_cpu, int vector);
-#endif
+
v3_cpu_arch_t v3_get_cpu_type(int cpu_id);
- void (*start_kernel_thread)(int (*fn)(void * arg), void * arg, char * thread_name);
+ void * (*start_kernel_thread)(int (*fn)(void * arg), void * arg, char * thread_name);
void (*interrupt_cpu)(struct v3_vm_info * vm, int logical_cpu, int vector);
void (*call_on_cpu)(int logical_cpu, void (*fn)(void * arg), void * arg);
void * (*start_thread_on_cpu)(int cpu_id, int (*fn)(void * arg), void * arg, char * thread_name);
-#ifdef V3_CONFIG_MULTITHREAD_OS
+
if ((hooks) && (hooks->call_on_cpu)) {
for (i = 0; i < num_cpus; i++) {
hooks->call_on_cpu(i, &init_cpu, (void *)(addr_t)i);
}
}
-#else
- init_cpu(0);
-#endif
+
}
#endif
-#ifdef V3_CONFIG_MULTITHREAD_OS
if ((os_hooks) && (os_hooks->call_on_cpu)) {
for (i = 0; i < V3_CONFIG_MAX_CPUS; i++) {
if (v3_cpu_types[i] != V3_INVALID_CPU) {
}
}
}
-#else
- deinit_cpu(0);
-#endif
}
// For the moment very ugly. Eventually we will shift the cpu_mask to an arbitrary sized type...
-#ifdef V3_CONFIG_MULTITHREAD_OS
#define MAX_CORES 32
-#else
-#define MAX_CORES 1
-#endif
int v3_start_vm(struct v3_vm_info * vm, unsigned int cpu_mask) {
return -1;
}
-#ifdef V3_CONFIG_MULTITHREAD_OS
- // spawn off new threads, for other cores
- for (i = 0, vcore_id = 1; (i < MAX_CORES) && (vcore_id < vm->num_cores); i++) {
+ // Spawn off threads for each core.
+ // We work backwards, so that core 0 is always started last.
+ for (i = 0, vcore_id = vm->num_cores - 1; (i < MAX_CORES) && (vcore_id >= 0); i++) {
int major = 0;
int minor = 0;
struct guest_info * core = &(vm->cores[vcore_id]);
i--; // We reset the logical core idx. Not strictly necessary I guess...
} else {
-
- if (i == V3_Get_CPU()) {
- // We skip the local CPU because it is reserved for vcore 0
- continue;
- }
-
core_idx = i;
}
major = core_idx / 8;
minor = core_idx % 8;
-
if ((core_mask[major] & (0x1 << minor)) == 0) {
PrintError("Logical CPU %d not available for virtual core %d; not started\n",
core_idx, vcore_id);
PrintDebug("run: core=%u, func=0x%p, arg=0x%p, name=%s\n",
core_idx, start_core, core, core->exec_name);
- // TODO: actually manage these threads instead of just launching them
core->pcpu_id = core_idx;
core->core_thread = V3_CREATE_THREAD_ON_CPU(core_idx, start_core, core, core->exec_name);
return -1;
}
- vcore_id++;
- }
-#endif
-
- sprintf(vm->cores[0].exec_name, "%s", vm->name);
-
- vm->cores[0].pcpu_id = V3_Get_CPU();
-
- if (start_core(&(vm->cores[0])) != 0) {
- PrintError("Error starting VM core 0\n");
- v3_stop_vm(vm);
- return -1;
+ vcore_id--;
}
}
-#ifdef V3_CONFIG_MULTITHREAD_OS
void v3_interrupt_cpu(struct v3_vm_info * vm, int logical_cpu, int vector) {
extern struct v3_os_hooks * os_hooks;
(os_hooks)->interrupt_cpu(vm, logical_cpu, vector);
}
}
-#endif