#define V3_VM_CONSOLE_CONNECT 20
#define V3_VM_STOP 22
+#define V3_VM_PAUSE 23
+#define V3_VM_CONTINUE 24
+
#define V3_VM_INSPECT 30
switch (ioctl) {
case V3_VM_STOP: {
- printk("Stopping VM\n");
+ printk("Stopping VM (%s)\n", guest->name);
stop_palacios_vm(guest);
break;
}
+ case V3_VM_PAUSE: {
+ printk("Pausing VM (%s)\n", guest->name);
+ v3_pause_vm(guest->v3_ctx);
+ break;
+ }
+ case V3_VM_CONTINUE: {
+ printk("Continuing VM (%s)\n", guest->name);
+ v3_continue_vm(guest->v3_ctx);
+ break;
+ }
default: {
struct vm_ctrl * ctrl = get_ctrl(guest, ioctl);
v3_monitor : v3_cons.c v3_ctrl.h
gcc -static v3_monitor.c -o v3_monitor
-v3_net : v3_net.c v3_ctrl.h
- gcc -static v3_net.c -o v3_net
-
v3_user_host_dev_example: v3_user_host_dev_example.c v3_user_host_dev.h v3_user_host_dev.c
gcc -static -I../linux_module v3_user_host_dev_example.c v3_user_host_dev.c -o v3_user_host_dev_example
clean:
- rm -f v3_ctrl v3_cons v3_mem v3_monitor v3_serial v3_net v3_user_host_dev_example v3_os_debug v3_user_keyed_stream_example v3_user_keyed_stream_file
+ rm -f v3_ctrl v3_cons v3_mem v3_monitor v3_serial v3_user_host_dev_example v3_os_debug v3_user_keyed_stream_example v3_user_keyed_stream_file
+++ /dev/null
-/*
- * V3 Control utility for Palacios network services
- * (c) Lei Xia, 2010
- */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <string.h>
-
-#include "v3_ctrl.h"
-
-struct v3_network {
- unsigned char socket;
- unsigned char packet;
- unsigned char vnet;
-};
-
-int main(int argc, char* argv[]) {
- int v3_fd = 0;
- struct v3_network net;
- int i;
-
- if (argc <= 1) {
- printf("Usage: ./v3_mem [socket] [packet] [vnet]\n");
- return -1;
- }
-
- for (i = 1; i < argc; i++){
- if(!strcasecmp (argv[i], "packet")){
- net.packet = 1;
- }else if(!strcasecmp (argv[i], "socket")){
- net.socket = 1;
- }else if(!strcasecmp (argv[i], "vnet")){
- net.vnet = 1;
- }else {
- printf("unknown v3 network service: %s, ignored\n", argv[i]);
- }
- }
-
- printf("Network service: socket: %d, packet: %d, vnet: %d\n", net.socket, net.packet, net.vnet);
-
- v3_fd = open(v3_dev, O_RDONLY);
-
- if (v3_fd == -1) {
- printf("Error opening V3Vee control device\n");
- return -1;
- }
-
- ioctl(v3_fd, V3_START_NETWORK, &net);
-
-
- /* Close the file descriptor. */
- close(v3_fd);
-
-
- return 0;
-}
-
#include <palacios/vmm_cpuid.h>
#include <palacios/vmm_regs.h>
#include <palacios/vmm_extensions.h>
-
+#include <palacios/vmm_barrier.h>
#ifdef V3_CONFIG_TELEMETRY
v3_vm_operating_mode_t run_state;
-
+ struct v3_barrier barrier;
struct v3_extensions extensions;
struct v3_vm_info * v3_create_vm(void * cfg, void * priv_data, char * name);
int v3_start_vm(struct v3_vm_info * vm, unsigned int cpu_mask);
int v3_stop_vm(struct v3_vm_info * vm);
+int v3_pause_vm(struct v3_vm_info * vm);
+int v3_continue_vm(struct v3_vm_info * vm);
+
+
int v3_free_vm(struct v3_vm_info * vm);
int v3_deliver_irq(struct v3_vm_info * vm, struct v3_interrupt * intr);
#ifdef __V3VEE__
+#include <palacios/vmm_lock.h>
+#include <palacios/vmm_bitmap.h>
+
-#include <util/vmm_lock.h>
struct v3_barrier {
- uint64_t cpus;
int active; // If 1, barrier is active, everyone must wait
// If 0, barrier is clear, can proceed
+ struct v3_bitmap cpu_map;
+
v3_lock_t lock;
};
+struct v3_vm_info;
+struct guest_info;
+
+int v3_init_barrier(struct v3_vm_info * vm_info);
+int v3_deinit_barrier(struct v3_vm_info * vm_info);
-int v3_init_barrier(struct v3_barrier * barrier);
+int v3_raise_barrier(struct v3_vm_info * vm_info, struct guest_info * local_core);
+int v3_lower_barrier(struct v3_vm_info * vm_info);
-int v3_activate_barrier(struct guest_info * core);
-int v3_check_barrier(struct guest_info * core);
+int v3_wait_at_barrier(struct guest_info * core);
#endif
--- /dev/null
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National
+ * Science Foundation and the Department of Energy.
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico. You can find out more at
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2011, Jack Lange <jacklange@cs.pitt.edu>
+ * Copyright (c) 2011, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jacklange@cs.pitt.edu>
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+
+
+#ifndef __VMM_BITMAP_H__
+#define __VMM_BITMAP_H__
+
+#ifdef __V3VEE__
+#include <palacios/vmm_types.h>
+
+
+
+struct v3_bitmap {
+ int num_bits; // number of valid bit positions in the bitmap
+ uint8_t * bits; // actual bitmap. Dynamically allocated... ugly
+};
+
+
+int v3_bitmap_init(struct v3_bitmap * bitmap, int num_bits);
+void v3_bitmap_deinit(struct v3_bitmap * bitmap);
+int v3_bitmap_reset(struct v3_bitmap * bitmap);
+
+int v3_bitmap_set(struct v3_bitmap * bitmap, int index);
+int v3_bitmap_clear(struct v3_bitmap * bitmap, int index);
+int v3_bitmap_check(struct v3_bitmap * bitmap, int index);
+
+
+
+#endif
+
+#endif
vmm_extensions.o \
vmm_mtrr.o \
vmm_multitree.o \
-
+ vmm_bitmap.o \
+ vmm_barrier.o \
#include <palacios/svm_msr.h>
#include <palacios/vmm_rbtree.h>
+#include <palacios/vmm_barrier.h>
+
#include <palacios/vmm_direct_paging.h>
break;
}
+ v3_wait_at_barrier(info);
+
if (info->vm_info->run_state == VM_STOPPED) {
info->core_run_state = CORE_STOPPED;
#include <palacios/vmm_sprintf.h>
#include <palacios/vmm_xed.h>
#include <palacios/vmm_direct_paging.h>
-
+#include <palacios/vmm_barrier.h>
v3_cpu_mode_t v3_get_vm_cpu_mode(struct guest_info * info) {
v3_init_intr_routers(vm);
v3_init_ext_manager(vm);
+ v3_init_barrier(vm);
+
// Initialize the memory map
if (v3_init_mem_map(vm) == -1) {
PrintError("Could not initialize shadow map\n");
v3_deinit_intr_routers(vm);
v3_deinit_host_events(vm);
+ v3_deinit_barrier(vm);
+
v3_deinit_cpuid_map(vm);
v3_deinit_msr_map(vm);
v3_deinit_io_map(vm);
}
+int v3_pause_vm(struct v3_vm_info * vm) {
+
+ if (vm->run_state != VM_RUNNING) {
+ PrintError("Tried to pause a VM that was not running\n");
+ return -1;
+ }
+
+ while (v3_raise_barrier(vm, NULL) == -1);
+
+ return 0;
+}
+
+
+int v3_continue_vm(struct v3_vm_info * vm) {
+
+ if (vm->run_state != VM_RUNNING) {
+ PrintError("Tried to continue a VM that was not already running\n");
+ return -1;
+ }
+
+ v3_lower_barrier(vm);
+
+ return 0;
+}
+
+
int v3_free_vm(struct v3_vm_info * vm) {
int i = 0;
// deinitialize guest (free memory, etc...)
*/
-#include <util/vmm_barrier.h>
+#include <palacios/vmm_barrier.h>
+#include <palacios/vmm.h>
+#include <palacios/vm_guest.h>
+int v3_init_barrier(struct v3_vm_info * vm_info) {
+ struct v3_barrier * barrier = &(vm_info->barrier);
-
-int v3_init_barrier(struct v3_barrier * barrier) {
memset(barrier, 0, sizeof(struct v3_barrier));
+ v3_bitmap_init(&(barrier->cpu_map), vm_info->num_cores);
v3_lock_init(&(barrier->lock));
return 0;
}
+int v3_deinit_barrier(struct v3_vm_info * vm_info) {
+ struct v3_barrier * barrier = &(vm_info->barrier);
+
+ v3_bitmap_deinit(&(barrier->cpu_map));
+ v3_lock_deinit(&(barrier->lock));
+
+ return 0;
+}
+
+
+/* Barrier synchronization primitive
+ * -- This call will block until all the guest cores are waiting at a common synchronization point
+ * in a yield loop. The core will block at the sync point until the barrier is lowered.
+ *
+ * ARGUMENTS:
+ * vm_info -- The VM for which the barrier is being activated
+ * local_core -- The core whose thread this function is being called from, or NULL
+ * if the calling thread is not associated with a VM's core context
+ */
-int v3_activate_barrier(struct guest_info * core, struct v3_barrier * barrier) {
+int v3_raise_barrier(struct v3_vm_info * vm_info, struct guest_info * local_core) {
+ struct v3_barrier * barrier = &(vm_info->barrier);
addr_t flag;
int acquired = 0;
-
+ int all_blocked = 0;
+
+ int local_vcpu = -1;
+ int i = 0;
+
+
+
flag = v3_lock_irqsave(barrier->lock);
if (barrier->active == 0) {
v3_unlock_irqrestore(barrier->lock, flag);
if (acquired == 0) {
+ /* If we are in a core context and the barrier has already been acquired
+ we'll be safe and let the other barrier proceed. We will still report an error
+ though to allow possible cleanups to occur at the call site.
+ */
+ if (local_core != NULL) {
+ v3_wait_at_barrier(local_core);
+ }
+
return -1;
}
+ // If we are raising the barrier from a core context
+ // we have to mark ourselves blocked first to avoid deadlock
+ if (local_core != NULL) {
+ local_vcpu = local_core->vcpu_id;
+ v3_bitmap_set(&(barrier->cpu_map), local_vcpu);
+ }
+
- // wait for barrier catch
+ // send out interrupts to force exits on all cores
+ for (i = 0; i < vm_info->num_cores; i++) {
+ if (vm_info->cores[i].vcpu_id != local_vcpu) {
+ v3_interrupt_cpu(vm_info, vm_info->cores[i].pcpu_id, 0);
+ }
+ }
+
+ // wait for barrier catch on all cores
+ while (all_blocked == 0) {
+ all_blocked = 1;
+
+ for (i = 0; i < vm_info->num_cores; i++) {
+ if (v3_bitmap_check(&(barrier->cpu_map), i) == 0) {
+ // There is still a core that is not waiting at the barrier
+ all_blocked = 0;
+ }
+ }
+
+ if (all_blocked == 1) {
+ break;
+ }
+
+ v3_yield(local_core);
+ }
return 0;
+/* Lowers a barrier that has already been raised
+ * guest cores will automatically resume execution
+ * once this has been called
+ *
+ * TODO: Need someway to check that the barrier is active
+ */
+
+int v3_lower_barrier(struct v3_vm_info * vm_info) {
+ struct v3_barrier * barrier = &(vm_info->barrier);
+
+ // Clear the active flag, so cores won't wait
+ barrier->active = 0;
-int v3_deactivate_barrier(struct v3_barrier * barrier) {
+ // Clear all the cpu flags, so cores will proceed
+ v3_bitmap_reset(&(barrier->cpu_map));
+ return 0;
}
-int v3_check_barrier(struct guest_info * core, struct v3_barrier * barrier) {
+/*
+ * Syncronization point for guest cores
+ * -- called as part of the main VMM event loop for each core
+ * -- if a barrier has been activated then the core will signal
+ * it has reached the barrier and sit in a yield loop until the
+ * barrier has been lowered
+ */
+int v3_wait_at_barrier(struct guest_info * core) {
+ struct v3_barrier * barrier = &(core->vm_info->barrier);
- if (barrier->activated == 0) {
+ if (barrier->active == 0) {
return 0;
}
+
+ /* Barrier has been activated.
+ * Wait here until it's lowered
+ */
+
- // set cpu bit
+ // set cpu bit in barrier bitmap
+ v3_bitmap_set(&(barrier->cpu_map), core->vcpu_id);
// wait for cpu bit to clear
+ while (v3_bitmap_check(&(barrier->cpu_map), core->vcpu_id) == 1) {
+ v3_yield(core);
+ }
+ return 0;
}
--- /dev/null
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National
+ * Science Foundation and the Department of Energy.
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico. You can find out more at
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2011, Jack Lange <jacklange@cs.pitt.edu>
+ * Copyright (c) 2011, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jacklange@cs.pitt.edu>
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#include <palacios/vmm_bitmap.h>
+#include <palacios/vmm.h>
+
+
+int v3_bitmap_init(struct v3_bitmap * bitmap, int num_bits) {
+ int num_bytes = (num_bits / 8) + ((num_bits % 8) > 0);
+
+ bitmap->num_bits = num_bits;
+ bitmap->bits = V3_Malloc(num_bytes);
+
+ if (bitmap->bits == NULL) {
+ PrintError("Could not allocate bitmap of %d bits\n", num_bits);
+ return -1;
+ }
+
+ memset(bitmap->bits, 0, num_bytes);
+
+ return 0;
+}
+
+
+void v3_bitmap_deinit(struct v3_bitmap * bitmap) {
+ V3_Free(bitmap->bits);
+}
+
+
+int v3_bitmap_reset(struct v3_bitmap * bitmap) {
+ int num_bytes = (bitmap->num_bits / 8) + ((bitmap->num_bits % 8) > 0);
+
+ memset(bitmap->bits, 0, num_bytes);
+
+ return 0;
+}
+
+int v3_bitmap_set(struct v3_bitmap * bitmap, int index) {
+ int major = index / 8;
+ int minor = index % 8;
+ int old_val = 0;
+
+ if (index > (bitmap->num_bits - 1)) {
+ PrintError("Index out of bitmap range: (pos = %d) (num_bits = %d)\n",
+ index, bitmap->num_bits);
+ return -1;
+ }
+
+ old_val = (bitmap->bits[major] & (0x1 << minor));
+ bitmap->bits[major] |= (0x1 << minor);
+
+ return old_val;
+}
+
+
+int v3_bitmap_clear(struct v3_bitmap * bitmap, int index) {
+ int major = index / 8;
+ int minor = index % 8;
+ int old_val = 0;
+
+ if (index > (bitmap->num_bits - 1)) {
+ PrintError("Index out of bitmap range: (pos = %d) (num_bits = %d)\n",
+ index, bitmap->num_bits);
+ return -1;
+ }
+
+ old_val = (bitmap->bits[major] & (0x1 << minor));
+ bitmap->bits[major] &= ~(0x1 << minor);
+
+ return old_val;
+}
+
+int v3_bitmap_check(struct v3_bitmap * bitmap, int index) {
+ int major = index / 8;
+ int minor = index % 8;
+
+ if (index > (bitmap->num_bits - 1)) {
+ PrintError("Index out of bitmap range: (pos = %d) (num_bits = %d)\n",
+ index, bitmap->num_bits);
+ return -1;
+ }
+
+ return (bitmap->bits[major] & (0x1 << minor));
+}
+