menu "Time Management"
-config VIRTUALIZE_TIME
- bool "Enable Time virtualization"
+config TIME_DILATION
+ bool "Control Guest/Host Time Offseting"
default n
+ depends on EXPERIMENTAL
help
- Enables the timer virtualization extensions
-
+ Controls the relative speeds of the guest and host processor
+ to allow the VM to provide the illusion of the guest seeing time
+ pass at a different rate than the host system does.
+
config TIME_HIDE_VM_COST
bool "Hide VMM Run Cost"
default n
- depends on VIRTUALIZE_TIME
+ depends on EXPERIMENTAL
help
Offset guest time from host time sufficiently to hide the cost of
running in the virtual machine. This can aid the consistency of
config TIME_VIRTUALIZE_TSC
bool "Fully virtualize guest TSC"
default n
- depends on VIRTUALIZE_TIME
+ depends on EXPERIMENTAL
help
Virtualize the processor time stamp counter in the guest,
generally increasing consistency between various time sources
but also potentially making guest time run slower than real time.
-
+
endmenu
return 0;
}
-
static int keyed_stream_ioctl_user(struct inode *inode, struct file *filp, unsigned int ioctl, unsigned long arg)
{
void __user *argp = (void __user *)arg;
}
}
+static long keyed_stream_compat_ioctl_user(struct file * filp, unsigned int ioctl, unsigned long arg)
+{
+ return keyed_stream_ioctl_user(NULL, filp, ioctl, arg);
+}
+
static int keyed_stream_release_user(struct inode *inode, struct file *filp)
{
struct user_keyed_stream *s = filp->private_data;
static struct file_operations user_keyed_stream_fops = {
.poll = keyed_stream_poll_user,
+#ifdef HAVE_COMPAT_IOCTL
+ .compat_ioctl = keyed_stream_compat_ioctl_user,
+#else
.ioctl = keyed_stream_ioctl_user,
+#endif
.release = keyed_stream_release_user,
};
WARN(!pgs, "Could not allocate pages\n");
- printk("%llu pages (order=%d) aquired from alloc_pages\n",
- num_pages, order);
+ /* printk("%llu pages (order=%d) aquired from alloc_pages\n",
+ num_pages, order); */
addr = page_to_pfn(pgs) << PAGE_SHIFT;
} else {
- printk("Allocating %llu pages from bitmap allocator\n", num_pages);
+ //printk("Allocating %llu pages from bitmap allocator\n", num_pages);
//addr = pool.base_addr;
addr = alloc_contig_pgs(num_pages, alignment);
}
- printk("Returning from alloc addr=%p, vaddr=%p\n", (void *)addr, __va(addr));
+ //printk("Returning from alloc addr=%p, vaddr=%p\n", (void *)addr, __va(addr));
return addr;
}
void free_palacios_pgs(uintptr_t pg_addr, int num_pages) {
- printk("Freeing Memory page %p\n", (void *)pg_addr);
+ //printk("Freeing Memory page %p\n", (void *)pg_addr);
if ((pg_addr >= pool.base_addr) &&
(pg_addr < pool.base_addr + (4096 * pool.num_pages))) {
return NULL;
}
- set_cpus_allowed_ptr(thread, cpumask_of(cpu_id));
+ if (set_cpus_allowed_ptr(thread, cpumask_of(cpu_id)) != 0) {
+ kthread_stop(thread);
+ return NULL;
+ }
+
wake_up_process(thread);
return thread;
case V3_VM_LAUNCH: {
printk("palacios: launching vm\n");
- if (v3_start_vm(guest->v3_ctx, 0xfffffffe) < 0) {
+ if (v3_start_vm(guest->v3_ctx, (0x1 << num_online_cpus()) - 1) < 0) {
printk("palacios: launch of vm failed\n");
return -1;
}
#define ETH_ALEN 6
#define MIN_MTU 68
-#define MAX_MTU 65535
+#define MAX_MTU 65536
-#define MAX_PACKET_LEN (MAX_MTU)
+#define MAX_PACKET_LEN (MAX_MTU + ETHERNET_HEADER_LEN)
#ifdef V3_CONFIG_VNET
extern int net_debug;
case XOR_MEM2_8:
case XOR_IMM2_8:
case INC_8:
+ case INT:
case DEC_8:
case NEG_8:
case NOT_8:
return -1;
}
- case INT:
+ //case INT:
case MOV_DR2:
case MOV_2DR:
case MOV_CR2:
#include <palacios/vmm_types.h>
#include <palacios/vmm_list.h>
+#define SYSENTER_CS_MSR 0x00000174
+#define SYSENTER_ESP_MSR 0x00000175
+#define SYSENTER_EIP_MSR 0x00000176
+#define EFER_MSR 0xc0000080
+#define IA32_STAR_MSR 0xc0000081
+#define IA32_LSTAR_MSR 0xc0000082
+#define IA32_CSTAR_MSR 0xc0000083
+#define IA32_FMASK_MSR 0xc0000084
+#define FS_BASE_MSR 0xc0000100
+#define GS_BASE_MSR 0xc0000101
+#define IA32_KERN_GS_BASE_MSR 0xc0000102
+
+
struct guest_info;
struct v3_vm_info;
}
// Returns *monotonic* guest time.
-static inline uint64_t v3_get_guest_time(struct vm_time *t) {
+static inline uint64_t v3_compute_guest_time(struct vm_time *t, uint64_t ht) {
#ifdef V3_CONFIG_TIME_HIDE_VM_COST
V3_ASSERT(t->exit_time);
return t->exit_time + t->guest_host_offset;
#endif
}
+static inline uint64_t v3_get_guest_time(struct vm_time *t) {
+ return v3_compute_guest_time(t, v3_get_host_time(t));
+}
+
// Returns the TSC value seen by the guest
+static inline uint64_t v3_compute_guest_tsc(struct vm_time *t, uint64_t ht) {
+ return v3_compute_guest_time(t, ht) + t->tsc_guest_offset;
+}
+
static inline uint64_t v3_get_guest_tsc(struct vm_time *t) {
- return v3_get_guest_time(t) + t->tsc_guest_offset;
+ return v3_compute_guest_tsc(t, v3_get_host_time(t));
}
// Returns offset of guest TSC from host TSC
help
Includes the Virtual APIC device
+config APIC_ENQUEUE_MISSED_TMR_IRQS
+ bool "Enqueue missed APIC timer interrpts"
+ default n
+ depends on APIC
+ help
+ Make up missed APIC periodic timer interrupts on later
+ exits into the virtual machine
config DEBUG_APIC
bool "APIC Debugging"
help
Enable debugging for the APIC
-
-
config IO_APIC
bool "IOAPIC"
depends on APIC
struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]);
// raise irq
- PrintDebug("apic %u: core %u: Raising APIC Timer interrupt (periodic=%d) (icnt=%d) (div=%d)\n",
+ PrintDebug("apic %u: core %u: Raising APIC Timer interrupt (periodic=%d) (icnt=%d)\n",
apic->lapic_id.val, core->vcpu_id,
- apic->tmr_vec_tbl.tmr_mode, apic->tmr_init_cnt, shift_num);
+ apic->tmr_vec_tbl.tmr_mode, apic->tmr_init_cnt);
if (apic_intr_pending(core, priv_data)) {
PrintDebug("apic %u: core %u: Overriding pending IRQ %d\n",
if (tmr_ticks < apic->tmr_cur_cnt) {
apic->tmr_cur_cnt -= tmr_ticks;
- if (apic->missed_ints) {
+#ifdef V3_CONFIG_APIC_ENQUEUE_MISSED_TMR_IRQS
+ if (apic->missed_ints && !apic_intr_pending(core, priv_data)) {
+ PrintDebug("apic %u: core %u: Injecting queued APIC timer interrupt.\n",
+ apic->lapic_id.val, core->vcpu_id);
apic_inject_timer_intr(core, priv_data);
apic->missed_ints--;
}
+#endif /* CONFIG_APIC_ENQUEUE_MISSED_TMR_IRQS */
} else {
tmr_ticks -= apic->tmr_cur_cnt;
apic->tmr_cur_cnt = 0;
apic_inject_timer_intr(core, priv_data);
if (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_PERIODIC) {
- apic->missed_ints += tmr_ticks / apic->tmr_init_cnt;
+ int queued_ints = tmr_ticks / apic->tmr_init_cnt;
tmr_ticks = tmr_ticks % apic->tmr_init_cnt;
apic->tmr_cur_cnt = apic->tmr_init_cnt - tmr_ticks;
+ apic->missed_ints += queued_ints;
}
}
+
/*
* This file is part of the Palacios Virtual Machine Monitor developed
* by the V3VEE Project with funding from the United States National
uint8_t mergeable_rx_bufs;
struct v3_timer * timer;
- struct vnet_thread * poll_thread;
-
struct nic_statistics stats;
struct v3_dev_net_ops * net_ops;
virtio_state->stats.rx_interrupts ++;
}
- V3_Print("Virtio Intr Line %d\n", virtio_state->pci_dev->config_header.intr_line);
-
if(txed > 0) {
V3_Net_Print(2, "Virtio Handle TX: txed pkts: %d, left %d\n", txed, left);
}
pfn, page_addr);
if(virtio->tx_notify == 0){
disable_cb(&virtio->tx_vq);
- vnet_thread_wakeup(virtio->poll_thread);
}
+ virtio->status = 1;
break;
case 2:
virtio_setup_queue(core, virtio,
static int virtio_poll(int quote, void * data){
struct virtio_net_state * virtio = (struct virtio_net_state *)data;
- return handle_pkt_tx(&(virtio->vm->cores[0]), virtio, quote);
+ if (virtio->status) {
+
+ return handle_pkt_tx(&(virtio->vm->cores[0]), virtio, quote);
+ }
+
+ return 0;
}
static int register_dev(struct virtio_dev_state * virtio,
return 0;
}
-
#define RATE_UPPER_THRESHOLD 10 /* 10000 pkts per second, around 100Mbits */
#define RATE_LOWER_THRESHOLD 1
#define PROFILE_PERIOD 10000 /*us*/
V3_Print("Virtio NIC: Switch TX to VMM driven mode\n");
disable_cb(&(net_state->tx_vq));
net_state->tx_notify = 0;
- vnet_thread_wakeup(net_state->poll_thread);
}
if(tx_rate < RATE_LOWER_THRESHOLD && net_state->tx_notify == 0){
net_state->net_ops = ops;
net_state->backend_data = private_data;
net_state->virtio_dev = virtio;
- net_state->tx_notify = 0;
- net_state->rx_notify = 0;
+
+ net_state->tx_notify = 1;
+ net_state->rx_notify = 1;
net_state->timer = v3_add_timer(&(info->cores[0]),
- &timer_ops,net_state);
+ &timer_ops,net_state);
ops->recv = virtio_rx;
ops->poll = virtio_poll;
ops->config.fnt_mac = V3_Malloc(ETH_ALEN);
memcpy(ops->config.fnt_mac, virtio->mac, ETH_ALEN);
- net_state->status = 1;
-
return 0;
}
memcpy(pkt.header, virtio_pkt->pkt, ETHERNET_HEADER_LEN);
pkt.data = virtio_pkt->pkt;
- v3_vnet_send_pkt(&pkt, NULL, 1);
+ v3_vnet_send_pkt(&pkt, NULL);
q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size];
q->used->ring[q->used->index % q->queue_size].length = pkt_desc->length; // What do we set this to????
&v3_handle_vm_cr_read,
&v3_handle_vm_cr_write,
core);
+
+
+ {
+ v3_hook_msr(core->vm_info, IA32_STAR_MSR, NULL, NULL, NULL);
+ v3_hook_msr(core->vm_info, IA32_LSTAR_MSR, NULL, NULL, NULL);
+ v3_hook_msr(core->vm_info, IA32_FMASK_MSR, NULL, NULL, NULL);
+ v3_hook_msr(core->vm_info, IA32_KERN_GS_BASE_MSR, NULL, NULL, NULL);
+ v3_hook_msr(core->vm_info, IA32_CSTAR_MSR, NULL, NULL, NULL);
+
+ v3_hook_msr(core->vm_info, SYSENTER_CS_MSR, NULL, NULL, NULL);
+ v3_hook_msr(core->vm_info, SYSENTER_ESP_MSR, NULL, NULL, NULL);
+ v3_hook_msr(core->vm_info, SYSENTER_EIP_MSR, NULL, NULL, NULL);
+ }
}
vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
addr_t exit_code = 0, exit_info1 = 0, exit_info2 = 0;
+ sint64_t tsc_offset;
// Conditionally yield the CPU if the timeslice has expired
v3_yield_cond(info);
#endif
v3_time_enter_vm(info);
- // guest_ctrl->TSC_OFFSET = v3_tsc_host_offset(&info->time_state);
+ tsc_offset = v3_tsc_host_offset(&info->time_state);
+ guest_ctrl->TSC_OFFSET = tsc_offset;
//V3_Print("Calling v3_svm_launch\n");
vm->io_map.update_map = update_map;
vm->io_map.arch_data = V3_VAddr(V3_AllocPages(3));
- memset(vm->io_map.arch_data, 0, PAGE_SIZE_4KB * 3);
+ memset(vm->io_map.arch_data, 0xff, PAGE_SIZE_4KB * 3);
v3_refresh_io_map(vm);
struct v3_io_hook * hook = v3_get_io_hook(core->vm_info, io_info->port);
int read_size = 0;
- if (hook == NULL) {
- PrintError("Hook Not present for in on port 0x%x\n", io_info->port);
- // error, we should not have exited on this port
- return -1;
- }
-
-
if (io_info->sz8) {
read_size = 1;
} else if (io_info->sz16) {
PrintDebug("IN of %d bytes on port %d (0x%x)\n", read_size, io_info->port, io_info->port);
- if (hook->read(core, io_info->port, &(core->vm_regs.rax), read_size, hook->priv_data) != read_size) {
- // not sure how we handle errors.....
- PrintError("Read Failure for in on port 0x%x\n", io_info->port);
- return -1;
+ if (hook == NULL) {
+ PrintDebug("IN operation on unhooked IO port 0x%x\n", io_info->port);
+
+ /* What are the HW semantics for an IN on an invalid port?
+ * Do we need to clear the register value or leave it untouched???
+ */
+ } else {
+ if (hook->read(core, io_info->port, &(core->vm_regs.rax), read_size, hook->priv_data) != read_size) {
+ // not sure how we handle errors.....
+ PrintError("Read Failure for in on port 0x%x\n", io_info->port);
+ return -1;
+ }
}
+
return 0;
}
if (flags->df) {
direction = -1;
}
-
-
- if (hook == NULL) {
- PrintError("Hook Not present for ins on port 0x%x\n", io_info->port);
- // error, we should not have exited on this port
- return -1;
- }
-
-
+
if (v3_gva_to_hva(core, get_addr_linear(core, core->rip, &(core->segments.cs)), &inst_ptr) == -1) {
PrintError("Can't access instruction\n");
//rep_num = info->vm_regs.rcx;
}
-
PrintDebug("INS size=%d for %d steps\n", read_size, rep_num);
while (rep_num > 0) {
return -1;
}
- if (hook->read(core, io_info->port, (char *)host_addr, read_size, hook->priv_data) != read_size) {
- // not sure how we handle errors.....
- PrintError("Read Failure for ins on port 0x%x\n", io_info->port);
- return -1;
+ if (hook == NULL) {
+ PrintDebug("INS operation on unhooked IO port 0x%x\n", io_info->port);
+ /* What are the HW semantics for an INS on an invalid port?
+ * Do we need to clear the memory region or leave it untouched???
+ */
+ } else {
+ if (hook->read(core, io_info->port, (char *)host_addr, read_size, hook->priv_data) != read_size) {
+ // not sure how we handle errors.....
+ PrintError("Read Failure for ins on port 0x%x\n", io_info->port);
+ return -1;
+ }
}
-
+
core->vm_regs.rdi += (read_size * direction);
if (io_info->rep) {
struct v3_io_hook * hook = v3_get_io_hook(core->vm_info, io_info->port);
int write_size = 0;
- if (hook == NULL) {
- PrintError("Hook Not present for out on port 0x%x\n", io_info->port);
- // error, we should not have exited on this port
- return -1;
- }
-
-
if (io_info->sz8) {
write_size = 1;
} else if (io_info->sz16) {
PrintDebug("OUT of %d bytes on port %d (0x%x)\n", write_size, io_info->port, io_info->port);
- if (hook->write(core, io_info->port, &(core->vm_regs.rax), write_size, hook->priv_data) != write_size) {
- // not sure how we handle errors.....
- PrintError("Write Failure for out on port 0x%x\n", io_info->port);
- return -1;
+ if (hook == NULL) {
+ PrintDebug("OUT operation on unhooked IO port 0x%x\n", io_info->port);
+ } else {
+ if (hook->write(core, io_info->port, &(core->vm_regs.rax), write_size, hook->priv_data) != write_size) {
+ // not sure how we handle errors.....
+ PrintError("Write Failure for out on port 0x%x\n", io_info->port);
+ return -1;
+ }
}
+
return 0;
}
direction = -1;
}
-
- if (hook == NULL) {
- PrintError("Hook Not present for outs on port 0x%x\n", io_info->port);
- // error, we should not have exited on this port
- return -1;
- }
-
PrintDebug("OUTS on port %d (0x%x)\n", io_info->port, io_info->port);
if (io_info->sz8) {
return -1;
}
- if (hook->write(core, io_info->port, (char*)host_addr, write_size, hook->priv_data) != write_size) {
- // not sure how we handle errors.....
- PrintError("Write Failure for outs on port 0x%x\n", io_info->port);
- return -1;
+ if (hook == NULL) {
+ PrintDebug("OUTS operation on unhooked IO port 0x%x\n", io_info->port);
+ } else {
+ if (hook->write(core, io_info->port, (char*)host_addr, write_size, hook->priv_data) != write_size) {
+ // not sure how we handle errors.....
+ PrintError("Write Failure for outs on port 0x%x\n", io_info->port);
+ return -1;
+ }
}
+
core->vm_regs.rsi += write_size * direction;
msr_map->update_map = update_map;
msr_map->arch_data = V3_VAddr(V3_AllocPages(2));
- memset(msr_map->arch_data, 0, PAGE_SIZE_4KB * 2);
+ memset(msr_map->arch_data, 0xff, PAGE_SIZE_4KB * 2);
v3_refresh_msr_map(vm);
int minor = i % 8;
if (core_mask[major] & (0x1 << minor)) {
- avail_cores++;
+ if (v3_cpu_types[i] == V3_INVALID_CPU) {
+ core_mask[major] &= ~(0x1 << minor);
+ } else {
+ avail_cores++;
+ }
}
}
vcore_id--;
}
+ if (vcore_id >= 0) {
+ PrintError("Error starting VM: Not enough available CPU cores\n");
+ v3_stop_vm(vm);
+ return -1;
+ }
+
return 0;
cur_cycle = v3_get_host_time(&info->time_state);
if (cur_cycle > (info->yield_start_cycle + info->vm_info->yield_cycle_period)) {
-
- /*
- PrintDebug("Conditional Yield (cur_cyle=%p, start_cycle=%p, period=%p)\n",
- (void *)cur_cycle, (void *)info->yield_start_cycle, (void *)info->yield_cycle_period);
- */
+ //PrintDebug("Conditional Yield (cur_cyle=%p, start_cycle=%p, period=%p)\n",
+ // (void *)cur_cycle, (void *)info->yield_start_cycle,
+ // (void *)info->yield_cycle_period);
+
V3_Yield();
info->yield_start_cycle = v3_get_host_time(&info->time_state);
}
uint32_t msr_num = info->vm_regs.rcx;
struct v3_msr msr_val;
struct v3_msr_hook * hook = NULL;
+
+ msr_val.value = 0;
PrintDebug("MSR write for msr 0x%x\n", msr_num);
hook = v3_get_msr_hook(info->vm_info, msr_num);
- if (!hook) {
- PrintError("Hook for MSR write %d not found\n", msr_num);
- return -1;
- }
-
- msr_val.value = 0;
- msr_val.lo = info->vm_regs.rax;
- msr_val.hi = info->vm_regs.rdx;
-
- if (hook->write(info, msr_num, msr_val, hook->priv_data) == -1) {
- PrintError("Error in MSR hook Write\n");
- return -1;
+ if (hook == NULL) {
+ PrintError("Write to unhooked MSR 0x%x\n", msr_num);
+ } else {
+ msr_val.lo = info->vm_regs.rax;
+ msr_val.hi = info->vm_regs.rdx;
+
+ if (hook->write(info, msr_num, msr_val, hook->priv_data) == -1) {
+ PrintError("Error in MSR hook Write\n");
+ return -1;
+ }
}
info->rip += 2;
struct v3_msr msr_val;
struct v3_msr_hook * hook = NULL;
- hook = v3_get_msr_hook(info->vm_info, msr_num);
-
- if (!hook) {
- PrintError("Hook for MSR read 0x%x not found\n", msr_num);
- return -1;
- }
-
msr_val.value = 0;
- if (hook->read(info, msr_num, &msr_val, hook->priv_data) == -1) {
- PrintError("Error in MSR hook Read\n");
- return -1;
+ hook = v3_get_msr_hook(info->vm_info, msr_num);
+
+ if (hook == NULL) {
+ PrintError("Read from unhooked MSR 0x%x\n", msr_num);
+ } else {
+ if (hook->read(info, msr_num, &msr_val, hook->priv_data) == -1) {
+ PrintError("Error in MSR hook Read\n");
+ return -1;
+ }
}
-
+
info->vm_regs.rax = msr_val.lo;
info->vm_regs.rdx = msr_val.hi;
int v3_offset_time( struct guest_info * info, sint64_t offset )
{
struct vm_time * time_state = &(info->time_state);
-// PrintDebug("Adding additional offset of %lld to guest time.\n", offset);
+ PrintDebug("Adding additional offset of %lld to guest time.\n", offset);
time_state->guest_host_offset += offset;
return 0;
}
-static uint64_t compute_target_host_time(struct guest_info * info)
+#ifdef V3_CONFIG_TIME_DILATION
+static uint64_t compute_target_host_time(struct guest_info * info, uint64_t guest_time)
{
struct vm_time * time_state = &(info->time_state);
uint64_t guest_elapsed, desired_elapsed;
- guest_elapsed = (v3_get_guest_time(time_state) - time_state->initial_time);
+ guest_elapsed = (guest_time - time_state->initial_time);
desired_elapsed = (guest_elapsed * time_state->host_cpu_freq) / time_state->guest_cpu_freq;
return time_state->initial_time + desired_elapsed;
}
uint64_t host_time, target_host_time;
uint64_t guest_time, old_guest_time;
- /* Compute the target host time given how much time has *already*
- * passed in the guest */
- target_host_time = compute_target_host_time(info);
-
/* Now, let the host run while the guest is stopped to make the two
* sync up. Note that this doesn't assume that guest time is stopped;
* the offsetting in the next step will change add an offset to guest
* time to account for the time paused even if the geust isn't
* usually paused in the VMM. */
host_time = v3_get_host_time(time_state);
- old_guest_time = v3_get_guest_time(time_state);
+ old_guest_time = v3_compute_guest_time(time_state, host_time);
+ target_host_time = compute_target_host_time(info, old_guest_time);
while (target_host_time > host_time) {
v3_yield(info);
host_time = v3_get_host_time(time_state);
}
- guest_time = v3_get_guest_time(time_state);
+ guest_time = v3_compute_guest_time(time_state, host_time);
/* We do *not* assume the guest timer was paused in the VM. If it was
* this offseting is 0. If it wasn't, we need this. */
- v3_offset_time(info, (sint64_t)old_guest_time - (sint64_t)guest_time);
+ v3_offset_time(info, (sint64_t)(old_guest_time - guest_time));
return 0;
}
if (time_state->enter_time) {
/* Limit forward skew to 10% of the amount the guest has
* run since we last could skew time */
- max_skew = ((sint64_t)guest_time - (sint64_t)time_state->enter_time) / 10;
+ max_skew = (sint64_t)(guest_time - time_state->enter_time) / 10.0;
} else {
max_skew = 0;
}
- desired_skew = (sint64_t)target_guest_time - (sint64_t)guest_time;
+ desired_skew = (sint64_t)(target_guest_time - guest_time);
skew = desired_skew > max_skew ? max_skew : desired_skew;
PrintDebug("Guest %lld cycles behind where it should be.\n",
desired_skew);
return 0;
}
+#endif /* V3_CONFIG_TIME_DILATION */
// Control guest time in relation to host time so that the two stay
// appropriately synchronized to the extent possible.
int v3_adjust_time(struct guest_info * info) {
+#ifdef V3_CONFIG_TIME_DILATION
/* First deal with yielding if we want to slow down the guest */
yield_host_time(info);
* or because the VMM is doing something that takes a long time to emulate)
* allow guest time to jump forward a bit */
skew_guest_time(info);
-
+#endif
return 0;
}
v3_time_enter_vm( struct guest_info * info )
{
struct vm_time * time_state = &(info->time_state);
- uint64_t guest_time, host_time;
+ uint64_t host_time;
host_time = v3_get_host_time(time_state);
- guest_time = v3_get_guest_time(time_state);
time_state->enter_time = host_time;
- time_state->guest_host_offset = (sint64_t)guest_time - (sint64_t)host_time;
+#ifdef V3_CONFIG_TIME_DILATION
+ {
+ uint64_t guest_time;
+ sint64_t offset;
+ guest_time = v3_compute_guest_time(time_state, host_time);
+ // XXX we probably want to use an inline function to do these
+ // time differences to deal with sign and overflow carefully
+ offset = (sint64_t)guest_time - (sint64_t)host_time;
+ PrintDebug("v3_time_enter_vm: guest time offset %lld from host time.\n", offset);
+ time_state->guest_host_offset = offset;
+ }
+#else
+ time_state->guest_host_offset = 0;
+#endif
return 0;
}
void v3_update_timers(struct guest_info * info) {
struct vm_time *time_state = &info->time_state;
struct v3_timer * tmp_timer;
- uint64_t old_time = info->time_state.last_update;
sint64_t cycles;
+ uint64_t old_time = info->time_state.last_update;
time_state->last_update = v3_get_guest_time(time_state);
- cycles = time_state->last_update - old_time;
+ cycles = (sint64_t)(time_state->last_update - old_time);
V3_ASSERT(cycles >= 0);
// V3_Print("Updating timers with %lld elapsed cycles.\n", cycles);
break;
}
+ case INT: {
+ instr->dst_operand.type = IMM_OPERAND;
+ instr->dst_operand.size = operand_width;
+ instr->dst_operand.operand = *(uint8_t *)instr_ptr;
+ instr_ptr += operand_width;
+ instr->num_operands = 1;
+
+ break;
+ }
case INVLPG: {
uint8_t reg_code = 0;
case INVLPG:
return V3_OP_INVLPG;
- case INT:
+ case INT:
return V3_OP_INT;
case MOV_CR2:
// save STAR, LSTAR, FMASK, KERNEL_GS_BASE MSRs in MSR load/store area
{
-#define IA32_STAR 0xc0000081
-#define IA32_LSTAR 0xc0000082
-#define IA32_FMASK 0xc0000084
-#define IA32_KERN_GS_BASE 0xc0000102
-
-#define IA32_CSTAR 0xc0000083 // Compatibility mode STAR (ignored for now... hopefully its not that important...)
-
int msr_ret = 0;
struct vmcs_msr_entry * exit_store_msrs = NULL;
entry_load_msrs = (struct vmcs_msr_entry *)(vmx_state->msr_area + (sizeof(struct vmcs_msr_entry) * 8));
- exit_store_msrs[0].index = IA32_STAR;
- exit_store_msrs[1].index = IA32_LSTAR;
- exit_store_msrs[2].index = IA32_FMASK;
- exit_store_msrs[3].index = IA32_KERN_GS_BASE;
+ exit_store_msrs[0].index = IA32_STAR_MSR;
+ exit_store_msrs[1].index = IA32_LSTAR_MSR;
+ exit_store_msrs[2].index = IA32_FMASK_MSR;
+ exit_store_msrs[3].index = IA32_KERN_GS_BASE_MSR;
memcpy(exit_store_msrs, exit_load_msrs, sizeof(struct vmcs_msr_entry) * 4);
memcpy(exit_store_msrs, entry_load_msrs, sizeof(struct vmcs_msr_entry) * 4);
- v3_get_msr(IA32_STAR, &(exit_load_msrs[0].hi), &(exit_load_msrs[0].lo));
- v3_get_msr(IA32_LSTAR, &(exit_load_msrs[1].hi), &(exit_load_msrs[1].lo));
- v3_get_msr(IA32_FMASK, &(exit_load_msrs[2].hi), &(exit_load_msrs[2].lo));
- v3_get_msr(IA32_KERN_GS_BASE, &(exit_load_msrs[3].hi), &(exit_load_msrs[3].lo));
+ v3_get_msr(IA32_STAR_MSR, &(exit_load_msrs[0].hi), &(exit_load_msrs[0].lo));
+ v3_get_msr(IA32_LSTAR_MSR, &(exit_load_msrs[1].hi), &(exit_load_msrs[1].lo));
+ v3_get_msr(IA32_FMASK_MSR, &(exit_load_msrs[2].hi), &(exit_load_msrs[2].lo));
+ v3_get_msr(IA32_KERN_GS_BASE_MSR, &(exit_load_msrs[3].hi), &(exit_load_msrs[3].lo));
msr_ret |= check_vmcs_write(VMCS_EXIT_MSR_STORE_ADDR, (addr_t)V3_PAddr(exit_store_msrs));
msr_ret |= check_vmcs_write(VMCS_EXIT_MSR_LOAD_ADDR, (addr_t)V3_PAddr(exit_load_msrs));
msr_ret |= check_vmcs_write(VMCS_ENTRY_MSR_LOAD_ADDR, (addr_t)V3_PAddr(entry_load_msrs));
+
+ v3_hook_msr(core->vm_info, IA32_STAR_MSR, NULL, NULL, NULL);
+ v3_hook_msr(core->vm_info, IA32_LSTAR_MSR, NULL, NULL, NULL);
+ v3_hook_msr(core->vm_info, IA32_FMASK_MSR, NULL, NULL, NULL);
+ v3_hook_msr(core->vm_info, IA32_KERN_GS_BASE_MSR, NULL, NULL, NULL);
+
+
+ // IMPORTANT: These SYSCALL MSRs are currently not handled by hardware or cached
+ // We should really emulate these ourselves, or ideally include them in the MSR store area if there is room
+ v3_hook_msr(core->vm_info, IA32_CSTAR_MSR, NULL, NULL, NULL);
+ v3_hook_msr(core->vm_info, SYSENTER_CS_MSR, NULL, NULL, NULL);
+ v3_hook_msr(core->vm_info, SYSENTER_ESP_MSR, NULL, NULL, NULL);
+ v3_hook_msr(core->vm_info, SYSENTER_EIP_MSR, NULL, NULL, NULL);
}
/* Sanity check ctrl/reg fields against hw_defaults */
*/
int v3_vmx_enter(struct guest_info * info) {
int ret = 0;
- //uint32_t tsc_offset_low, tsc_offset_high;
+ uint32_t tsc_offset_low, tsc_offset_high;
struct vmx_exit_info exit_info;
struct vmx_data * vmx_info = (struct vmx_data *)(info->vmm_data);
// Perform last-minute time bookkeeping prior to entering the VM
v3_time_enter_vm(info);
- // tsc_offset_high = (uint32_t)((v3_tsc_host_offset(&info->time_state) >> 32) & 0xffffffff);
- // tsc_offset_low = (uint32_t)(v3_tsc_host_offset(&info->time_state) & 0xffffffff);
- // check_vmcs_write(VMCS_TSC_OFFSET_HIGH, tsc_offset_high);
- // check_vmcs_write(VMCS_TSC_OFFSET, tsc_offset_low);
+ tsc_offset_high = (uint32_t)((v3_tsc_host_offset(&info->time_state) >> 32) & 0xffffffff);
+ tsc_offset_low = (uint32_t)(v3_tsc_host_offset(&info->time_state) & 0xffffffff);
+ check_vmcs_write(VMCS_TSC_OFFSET_HIGH, tsc_offset_high);
+ check_vmcs_write(VMCS_TSC_OFFSET, tsc_offset_low);
if (v3_update_vmcs_host_state(info)) {
v3_enable_ints();
vm->io_map.update_map = update_map;
vm->io_map.arch_data = V3_VAddr(V3_AllocPages(2));
- memset(vm->io_map.arch_data, 0, PAGE_SIZE_4KB * 2);
+ memset(vm->io_map.arch_data, 0xff, PAGE_SIZE_4KB * 2);
v3_refresh_io_map(vm);
struct v3_io_hook * hook = NULL;
int read_size = 0;
-
hook = v3_get_io_hook(core->vm_info, io_qual.port);
- if (hook == NULL) {
- PrintError("Hook not present for IN on port %x\n", io_qual.port);
- return -1;
- }
-
read_size = io_qual.access_size + 1;
PrintDebug("IN of %d bytes on port %d (0x%x)\n", read_size, io_qual.port, io_qual.port);
- if (hook->read(core, io_qual.port, &(core->vm_regs.rax), read_size, hook->priv_data) != read_size) {
- PrintError("Read failure for IN on port %x\n", io_qual.port);
- return -1;
- }
+ if (hook == NULL) {
+ PrintDebug("IN operation on unhooked IO port 0x%x\n", io_qual.port);
+ /* What are the HW semantics for an IN on an invalid port?
+ * Do we need to clear the register value or leave it untouched???
+ */
+ } else {
+ if (hook->read(core, io_qual.port, &(core->vm_regs.rax), read_size, hook->priv_data) != read_size) {
+ PrintError("Read failure for IN on port %x\n", io_qual.port);
+ return -1;
+ }
+ }
+
core->rip += exit_info->instr_len;
hook = v3_get_io_hook(core->vm_info, io_qual.port);
- if (hook == NULL) {
- PrintError("Hook not present for INS on port 0x%x\n", io_qual.port);
- return -1;
- }
PrintDebug("INS on port 0x%x\n", io_qual.port);
}
do {
- if (hook->read(core, io_qual.port, (char *)host_addr, read_size, hook->priv_data) != read_size) {
- PrintError("Read Failure for INS on port 0x%x\n", io_qual.port);
- return -1;
- }
+
+ if (hook == NULL) {
+ PrintDebug("INS operation on unhooked IO port 0x%x\n", io_qual.port);
+
+ /* What are the HW semantics for an INS on an invalid port?
+ * Do we need to clear the memory region or leave it untouched???
+ */
+ } else {
+ if (hook->read(core, io_qual.port, (char *)host_addr, read_size, hook->priv_data) != read_size) {
+ PrintError("Read Failure for INS on port 0x%x\n", io_qual.port);
+ return -1;
+ }
+ }
+
host_addr += rdi_change;
core->vm_regs.rdi += rdi_change;
hook = v3_get_io_hook(core->vm_info, io_qual.port);
- if (hook == NULL) {
- PrintError("Hook not present for out on port %x\n", io_qual.port);
- return -1;
- }
write_size = io_qual.access_size + 1;
PrintDebug("OUT of %d bytes on port %d (0x%x)\n", write_size, io_qual.port, io_qual.port);
- if (hook->write(core, io_qual.port, &(core->vm_regs.rax), write_size, hook->priv_data) != write_size) {
- PrintError("Write failure for out on port %x\n",io_qual.port);
- return -1;
+ if (hook == NULL) {
+ PrintDebug("OUT operation on unhooked IO port 0x%x\n", io_qual.port);
+ } else {
+ if (hook->write(core, io_qual.port, &(core->vm_regs.rax), write_size, hook->priv_data) != write_size) {
+ PrintError("Write failure for out on port %x\n",io_qual.port);
+ return -1;
+ }
}
-
-
core->rip += exit_info->instr_len;
return 0;
hook = v3_get_io_hook(core->vm_info, io_qual.port);
- if (hook == NULL) {
- PrintError("Hook not present for OUTS on port 0x%x\n", io_qual.port);
- return -1;
- }
-
PrintDebug("OUTS on port 0x%x\n", io_qual.port);
write_size = io_qual.access_size + 1;
}
do {
- if (hook->write(core, io_qual.port, (char *)host_addr, write_size, hook->priv_data) != write_size) {
- PrintError("Read failure for INS on port 0x%x\n", io_qual.port);
- return -1;
- }
+
+ if (hook == NULL) {
+ PrintDebug("OUTS operation on unhooked IO port 0x%x\n", io_qual.port);
+ } else {
+ if (hook->write(core, io_qual.port, (char *)host_addr, write_size, hook->priv_data) != write_size) {
+ PrintError("Read failure for INS on port 0x%x\n", io_qual.port);
+ return -1;
+ }
+ }
+
host_addr += rsi_change;
core->vm_regs.rsi += rsi_change;
msr_map->update_map = update_map;
msr_map->arch_data = V3_VAddr(V3_AllocPages(1));
- memset(msr_map->arch_data, 0, PAGE_SIZE_4KB);
+ memset(msr_map->arch_data, 0xff, PAGE_SIZE_4KB);
v3_refresh_msr_map(vm);
void * private_data;
- struct list_head node;\r
+ struct list_head node;
} __attribute__((packed));
flags = vnet_lock_irqsave(vnet_state.lock);
list_for_each_entry(route, &(vnet_state.routes), node) {
- V3_Print("v3_vnet_del_route, route idx: %d\n", route->idx);
+ Vnet_Print(0, "v3_vnet_del_route, route idx: %d\n", route->idx);
if(route->idx == route_idx){
list_del(&(route->node));
Vnet_Free(route);
int v3_vnet_add_dev(struct v3_vm_info * vm, uint8_t * mac,
- struct v3_vnet_dev_ops *ops, int quote, int poll_state,
+ struct v3_vnet_dev_ops * ops, int quote, int poll_state,
void * priv_data){
struct vnet_dev * new_dev = NULL;
unsigned long flags;
memcpy(new_dev->mac_addr, mac, 6);
new_dev->dev_ops.input = ops->input;
+ new_dev->dev_ops.poll = ops->poll;
new_dev->private_data = priv_data;
new_dev->vm = vm;
new_dev->dev_id = 0;
list_add(&(new_dev->node), &(vnet_state.devs));
new_dev->dev_id = ++ vnet_state.dev_idx;
vnet_state.num_devs ++;
+
+ if(new_dev->poll) {
+ v3_enqueue(vnet_state.poll_devs, (addr_t)new_dev);
+ }
+ } else {
+ PrintError("VNET/P: Device with the same MAC is already there\n");
}
vnet_unlock_irqrestore(vnet_state.lock, flags);
* that runs on multiple cores
* or it could be running on a dedicated side core
*/
-static int vnet_tx_flush(void *args){
+static int vnet_tx_flush(void * args){
struct vnet_dev * dev = NULL;
int ret;
Vnet_Print(0, "VNET/P Polling Thread Starting ....\n");
- /* we need thread sleep/wakeup in Palacios */
while(!vnet_thread_should_stop()){
dev = (struct vnet_dev *)v3_dequeue(vnet_state.poll_devs);
if(dev != NULL){
if(dev->poll && dev->dev_ops.poll != NULL){
ret = dev->dev_ops.poll(dev->vm, dev->quote, dev->private_data);
-
+
if (ret < 0){
- PrintDebug("VNET/P: poll from device %p error!\n", dev);
+ Vnet_Print(0, "VNET/P: poll from device %p error!\n", dev);
}
-
- v3_enqueue(vnet_state.poll_devs, (addr_t)dev);
}
+ v3_enqueue(vnet_state.poll_devs, (addr_t)dev);
}else { /* no device needs to be polled */
/* sleep here? */
Vnet_Yield();
return 0;
}
-
int v3_init_vnet() {
memset(&vnet_state, 0, sizeof(vnet_state));
vnet_state.poll_devs = v3_create_queue();
- vnet_state.pkt_flush_thread = vnet_start_thread(vnet_tx_flush, NULL, "vnetd");
+ vnet_state.pkt_flush_thread = vnet_start_thread(vnet_tx_flush, NULL, "vnetd-1");
Vnet_Debug("VNET/P is initiated\n");
<device class="8254_PIT" id="PIT" />
<device class="BOCHS_DEBUG" id="bochs debug"/>
<device class="OS_DEBUG" id="os debug" />
-
-
-<!--
<device class="LAPIC" id="apic"/>
<device class="IOAPIC" id="ioapic">
<apic>apic</apic>
</device>
--->
<!--
<device class="CGA_VIDEO" id="cga" passthrough="enable" />
<device class="TELNET_CONSOLE" id="telnet console">