#include <palacios/vmm_types.h>
#include <palacios/vmm_mem.h>
+#include <palacios/vmm_mem_hook.h>
#include <palacios/vmm_io.h>
#include <palacios/vmm_shadow_paging.h>
#include <palacios/vmm_intr.h>
addr_t mem_size; // In bytes for now
struct v3_mem_map mem_map;
+ struct v3_mem_hooks mem_hooks;
struct v3_shdw_impl_state shdw_impl;
uint8_t read : 1;
uint8_t write : 1;
uint8_t exec : 1;
- uint8_t hook : 1;
uint8_t base : 1;
uint8_t alloced : 1;
} __attribute__((packed));
addr_t host_addr; // This either points to a host address mapping
- // Called when data is read from a memory page
- int (*read_hook)(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data);
- // Called when data is written to a memory page
- int (*write_hook)(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data);
+ int (*unhandled)(struct guest_info * info, addr_t guest_va, addr_t guest_pa,
+ struct v3_shadow_region * reg, pf_error_t access_info);
void * priv_data;
struct v3_shadow_region base_region;
struct rb_root shdw_regions;
-
- void * hook_hvas; // this is an array of pages, equal to the number of cores
};
-int v3_add_shadow_mem(struct v3_vm_info * vm, uint16_t core_id,
- addr_t guest_addr_start, addr_t guest_addr_end, addr_t host_addr);
-
-int v3_hook_full_mem(struct v3_vm_info * vm, uint16_t core_id,
- addr_t guest_addr_start, addr_t guest_addr_end,
- int (*read)(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data),
- int (*write)(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data),
- void * priv_data);
-
-int v3_hook_write_mem(struct v3_vm_info * vm, uint16_t core_id,
- addr_t guest_addr_start, addr_t guest_addr_end, addr_t host_addr,
- int (*write)(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data),
- void * priv_data);
-
-
-int v3_unhook_mem(struct v3_vm_info * vm, uint16_t core_id, addr_t guest_addr_start);
-
-
+struct v3_shadow_region * v3_create_mem_region(struct v3_vm_info * vm, uint16_t core_id,
+ addr_t guest_addr_start, addr_t guest_addr_end);
+int v3_insert_shadow_region(struct v3_vm_info * vm, struct v3_shadow_region * reg);
void v3_delete_shadow_region(struct v3_vm_info * vm, struct v3_shadow_region * reg);
+/* This is a shortcut function for creating + inserting a memory region which redirects to host memory */
+int v3_add_shadow_mem(struct v3_vm_info * vm, uint16_t core_id,
+ addr_t guest_addr_start, addr_t guest_addr_end, addr_t host_addr);
+
struct v3_shadow_region * v3_get_shadow_region(struct v3_vm_info * vm, uint16_t core_id, addr_t guest_addr);
-int v3_handle_mem_hook(struct guest_info * info, addr_t guest_va, addr_t guest_pa,
- struct v3_shadow_region * reg, pf_error_t access_info);
#endif // ! __V3VEE__
--- /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) 2008, Jack Lange <jarusl@cs.northwestern.edu>
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+
+#ifndef __VMM_MEM_HOOK_H
+#define __VMM_MEM_HOOK_H
+
+
+#ifdef __V3VEE__
+
+
+struct v3_mem_hooks {
+
+ void * hook_hvas; // this is an array of pages, equal to the number of cores
+
+ struct list_head hook_list;
+
+};
+
+
+int v3_init_mem_hooks(struct v3_vm_info * vm);
+
+
+int v3_hook_full_mem(struct v3_vm_info * vm, uint16_t core_id,
+ addr_t guest_addr_start, addr_t guest_addr_end,
+ int (*read)(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data),
+ int (*write)(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data),
+ void * priv_data);
+
+int v3_hook_write_mem(struct v3_vm_info * vm, uint16_t core_id,
+ addr_t guest_addr_start, addr_t guest_addr_end, addr_t host_addr,
+ int (*write)(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data),
+ void * priv_data);
+
+
+int v3_unhook_mem(struct v3_vm_info * vm, uint16_t core_id, addr_t guest_addr_start);
+
+
+
+
+#endif /* ! __V3VEE__ */
+
+
+#endif
vmm_binaries.o \
vmm_cpuid.o \
vmm_xml.o \
- vmm_muxer.o
+ vmm_muxer.o \
+ vmm_mem_hook.o \
obj-$(CONFIG_SVM) += svm.o \
svm_io.o \
}
-
- // Write hooks trump all, and are set Read Only
if (shdw_reg->flags.write == 0) {
shadow_pte->writable = 0;
}
- } else if (shdw_reg->flags.hook == 1) {
+ } else {
// Page fault handled by hook functions
- if (v3_handle_mem_hook(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
+ if (shdw_reg->unhandled(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
PrintError("Special Page fault handler returned error for address: %p\n", (void *)fault_addr);
return -1;
}
} else if (shadow_pte_access == PT_ACCESS_WRITE_ERROR) {
guest_pte->dirty = 1;
- if (shdw_reg->flags.hook == 1) {
- if (v3_handle_mem_hook(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
+
+ if (shdw_reg->flags.write == 1) {
+ PrintDebug("Shadow PTE Write Error\n");
+ shadow_pte->writable = guest_pte->writable;
+ } else {
+ if (shdw_reg->unhandled(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
PrintError("Special Page fault handler returned error for address: %p\n", (void *)fault_addr);
return -1;
}
- } else if (shdw_reg->flags.write == 1) {
- PrintDebug("Shadow PTE Write Error\n");
- shadow_pte->writable = guest_pte->writable;
- }
+ }
return 0;
shadow_pte->global_page = large_guest_pde->global_page;
//
- } else if (shdw_reg->flags.hook == 1) {
- if (v3_handle_mem_hook(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
+ } else {
+ if (shdw_reg->unhandled(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
return -1;
}
}
} else if (shadow_pte_access == PT_ACCESS_WRITE_ERROR) {
-
- if (shdw_reg->flags.hook == 1) {
- if (v3_handle_mem_hook(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
- PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
- return -1;
- }
- }
-
+ if (shdw_reg->unhandled(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
+ PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
+ return -1;
+ }
} else {
PrintError("Error in large page fault handler...\n");
PrintError("This case should have been handled at the top level handler\n");
// Page Table Entry Not Present
PrintDebug("guest_pa =%p\n", (void *)guest_pa);
- if ((shdw_reg->flags.hook == 1) ||
+ if ((shdw_reg->flags.alloced == 1) ||
(shdw_reg->flags.read == 1)) {
addr_t shadow_pa = v3_get_shadow_addr(shdw_reg, info->cpu_id, guest_pa);
shadow_pte->writable = 0;
}
- } else if (shdw_reg->flags.hook == 1) {
+ } else {
// Page fault handled by hook functions
- if (v3_handle_mem_hook(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
+ if (shdw_reg->unhandled(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
PrintError("Special Page fault handler returned error for address: %p\n", (void *)fault_addr);
return -1;
}
} else if (shadow_pte_access == PT_ACCESS_WRITE_ERROR) {
guest_pte->dirty = 1;
- if (shdw_reg->flags.hook == 1) {
- if (v3_handle_mem_hook(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
+
+
+ if (shdw_reg->flags.write == 1) {
+ PrintDebug("Shadow PTE Write Error\n");
+ shadow_pte->writable = guest_pte->writable;
+ } else {
+ if (shdw_reg->unhandled(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
PrintError("Special Page fault handler returned error for address: %p\n", (void *)fault_addr);
return -1;
}
- } else if (shdw_reg->flags.write == 1) {
- PrintDebug("Shadow PTE Write Error\n");
- shadow_pte->writable = guest_pte->writable;
}
shadow_pte->global_page = large_guest_pde->global_page;
//
- } else if (shdw_reg->flags.hook == 1) {
- if (v3_handle_mem_hook(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
+ } else {
+ if (shdw_reg->unhandled(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
return -1;
}
}
} else if (shadow_pte_access == PT_ACCESS_WRITE_ERROR) {
- if (shdw_reg->flags.hook == 1) {
-
- if (v3_handle_mem_hook(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
- PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
- return -1;
- }
+ if (shdw_reg->unhandled(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
+ PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
+ return -1;
}
} else {
shadow_pte->writable = 0;
}
- } else if (shdw_reg->flags.hook == 1) {
- // Page fault handled by hook functions
-
- if (v3_handle_mem_hook(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
+ } else {
+ // Page fault on unhandled memory region
+
+ if (shdw_reg->unhandled(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
PrintError("Special Page fault handler returned error for address: %p\n", (void *)fault_addr);
return -1;
}
} else if (shadow_pte_access == PT_ACCESS_WRITE_ERROR) {
guest_pte->dirty = 1;
- if (shdw_reg->flags.hook == 1) {
- if (v3_handle_mem_hook(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
+ if (shdw_reg->flags.write == 1) {
+ PrintDebug("Shadow PTE Write Error\n");
+ shadow_pte->writable = guest_pte->writable;
+ } else {
+ if (shdw_reg->unhandled(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
PrintError("Special Page fault handler returned error for address: %p\n", (void *)fault_addr);
return -1;
}
- } else if (shdw_reg->flags.write == 1) {
- PrintDebug("Shadow PTE Write Error\n");
- shadow_pte->writable = guest_pte->writable;
}
shadow_pte->writable = 1;
}
- } else if (shdw_reg->flags.hook == 1) {
- if (v3_handle_mem_hook(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
+ } else {
+ if (shdw_reg->unhandled(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
return -1;
}
}
} else if (shadow_pte_access == PT_ACCESS_WRITE_ERROR) {
- if (shdw_reg->flags.hook == 1) {
- if (v3_handle_mem_hook(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
+ if (shdw_reg->flags.write == 0) {
+ if (shdw_reg->unhandled(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
return -1;
}
shadow_pte->writable = 0;
}
- } else if (shdw_reg->flags.hook == 1) {
- // Page fault handled by hook functions
+ } else {
+ // Pass to unhandled call back
- if (v3_handle_mem_hook(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
+ if (shdw_reg->unhandled(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
PrintError("Special Page fault handler returned error for address: %p\n", (void *)fault_addr);
return -1;
}
} else if (shadow_pte_access == PT_ACCESS_WRITE_ERROR) {
guest_pte->dirty = 1;
- if (shdw_reg->flags.hook == 1) {
- if (v3_handle_mem_hook(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
+
+ if (shdw_reg->flags.write == 1) {
+ PrintDebug("Shadow PTE Write Error\n");
+ shadow_pte->writable = guest_pte->writable;
+ } else {
+ if (shdw_reg->unhandled(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
PrintError("Special Page fault handler returned error for address: %p\n", (void *)fault_addr);
return -1;
}
- } else if (shdw_reg->flags.write == 1) {
- PrintDebug("Shadow PTE Write Error\n");
- shadow_pte->writable = guest_pte->writable;
}
+
return 0;
} else {
shadow_pte->global_page = large_guest_pde->global_page;
//
- } else if (shdw_reg->flags.hook == 1) {
- if (v3_handle_mem_hook(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
+ } else {
+ if (shdw_reg->unhandled(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
return -1;
}
}
} else if (shadow_pte_access == PT_ACCESS_WRITE_ERROR) {
-
- if (shdw_reg->flags.hook == 1) {
- if (v3_handle_mem_hook(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
- PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
- return -1;
- }
+ if (shdw_reg->unhandled(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
+ PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
+ return -1;
}
-
} else {
PrintError("Error in large page fault handler...\n");
PrintError("This case should have been handled at the top level handler\n");
return -1;
}
+ v3_init_mem_hooks(vm);
if (v3_init_shdw_impl(vm) == -1) {
PrintError("VM initialization error in shadow implementaion\n");
// Fix up the PTE entry
if (pte[pte_index].present == 0) {
- pte[pte_index].user_page = 1;
if ((region->flags.alloced == 1) &&
(region->flags.read == 1)) {
+ pte[pte_index].user_page = 1;
+
pte[pte_index].present = 1;
if (region->flags.write == 1) {
}
pte[pte_index].page_base_addr = PAGE_BASE_ADDR(host_addr);
+ } else {
+ return region->unhandled(info, fault_addr, fault_addr, region, error_code);
}
+ } else {
+ // We fix all permissions on the first pass,
+ // so we only get here if its an unhandled exception
+ return region->unhandled(info, fault_addr, fault_addr, region, error_code);
}
- if (region->flags.hook == 1) {
- if ((error_code.write == 1) || (region->flags.read == 0)) {
- return v3_handle_mem_hook(info, fault_addr, fault_addr, region, error_code);
- }
- }
-
return 0;
}
}
pte[pte_index].page_base_addr = PAGE_BASE_ADDR(host_addr);
+ } else {
+ return region->unhandled(info, fault_addr, fault_addr, region, error_code);
}
- }
-
- if (region->flags.hook == 1) {
- if ((error_code.write == 1) || (region->flags.read == 0)) {
- return v3_handle_mem_hook(info, fault_addr, fault_addr, region, error_code);
- }
+ } else {
+ return region->unhandled(info, fault_addr, fault_addr, region, error_code);
}
return 0;
}
pte[pte_index].page_base_addr = PAGE_BASE_ADDR(host_addr);
+ } else {
+ return region->unhandled(info, fault_addr, fault_addr, region, error_code);
}
- }
-
- if (region->flags.hook == 1) {
- if ((error_code.write == 1) || (region->flags.read == 0)) {
- return v3_handle_mem_hook(info, fault_addr, fault_addr, region, error_code);
- }
+ } else {
+ // We fix all permissions on the first pass,
+ // so we only get here if its an unhandled exception
+
+ return region->unhandled(info, fault_addr, fault_addr, region, error_code);
}
return 0;
#include <palacios/vmm_direct_paging.h>
-static inline
-struct v3_shadow_region * insert_shadow_region(struct v3_vm_info * vm,
- struct v3_shadow_region * region);
static int mem_offset_hypercall(struct guest_info * info, uint_t hcall_id, void * private_data) {
return 0;
}
+static int unhandled_err(struct guest_info * core, addr_t guest_va, addr_t guest_pa,
+ struct v3_shadow_region * reg, pf_error_t access_info) {
+
+ PrintError("Unhandled memory access error\n");
+
+ v3_print_mem_map(core->vm_info);
+
+ v3_print_guest_state(core);
+
+ return -1;
+}
+
+
int v3_init_mem_map(struct v3_vm_info * vm) {
struct v3_mem_map * map = &(vm->mem_map);
map->shdw_regions.rb_node = NULL;
- map->hook_hvas = V3_VAddr(V3_AllocPages(vm->num_cores));
-
-
// There is an underlying region that contains all of the guest memory
// PrintDebug("Mapping %d pages of memory (%u bytes)\n", (int)mem_pages, (uint_t)info->mem_size);
map->base_region.flags.exec = 1;
map->base_region.flags.base = 1;
map->base_region.flags.alloced = 1;
+
+ map->base_region.unhandled = unhandled_err;
if ((void *)map->base_region.host_addr == NULL) {
PrintError("Could not allocate Guest memory\n");
}
-static inline addr_t get_hook_hva(struct guest_info * info) {
- return (addr_t)(info->vm_info->mem_map.hook_hvas + (PAGE_SIZE_4KB * info->cpu_id));
-}
-
-void v3_delete_shadow_map(struct v3_vm_info * vm) {
+void v3_delete_mem_map(struct v3_vm_info * vm) {
struct rb_node * node = v3_rb_first(&(vm->mem_map.shdw_regions));
struct v3_shadow_region * reg;
struct rb_node * tmp_node = NULL;
}
V3_FreePage((void *)(vm->mem_map.base_region.host_addr));
- V3_FreePage(V3_PAddr((void *)(vm->mem_map.hook_hvas)));
}
-
-
-int v3_add_shadow_mem( struct v3_vm_info * vm, uint16_t core_id,
- addr_t guest_addr_start,
- addr_t guest_addr_end,
- addr_t host_addr)
-{
+struct v3_shadow_region * v3_create_mem_region(struct v3_vm_info * vm, uint16_t core_id,
+ addr_t guest_addr_start, addr_t guest_addr_end) {
+
struct v3_shadow_region * entry = (struct v3_shadow_region *)V3_Malloc(sizeof(struct v3_shadow_region));
memset(entry, 0, sizeof(struct v3_shadow_region));
entry->guest_start = guest_addr_start;
entry->guest_end = guest_addr_end;
- entry->host_addr = host_addr;
- entry->write_hook = NULL;
- entry->read_hook = NULL;
- entry->priv_data = NULL;
entry->core_id = core_id;
+ entry->unhandled = unhandled_err;
- entry->flags.read = 1;
- entry->flags.write = 1;
- entry->flags.exec = 1;
- entry->flags.alloced = 1;
-
- if (insert_shadow_region(vm, entry)) {
- V3_Free(entry);
- return -1;
- }
-
- return 0;
+ return entry;
}
-int v3_hook_write_mem(struct v3_vm_info * vm, uint16_t core_id,
- addr_t guest_addr_start, addr_t guest_addr_end, addr_t host_addr,
- int (*write)(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data),
- void * priv_data) {
- struct v3_shadow_region * entry = (struct v3_shadow_region *)V3_Malloc(sizeof(struct v3_shadow_region));
- memset(entry, 0, sizeof(struct v3_shadow_region));
+int v3_add_shadow_mem( struct v3_vm_info * vm, uint16_t core_id,
+ addr_t guest_addr_start,
+ addr_t guest_addr_end,
+ addr_t host_addr)
+{
+ struct v3_shadow_region * entry = NULL;
+
+ entry = v3_create_mem_region(vm, core_id,
+ guest_addr_start,
+ guest_addr_end);
- entry->guest_start = guest_addr_start;
- entry->guest_end = guest_addr_end;
entry->host_addr = host_addr;
- entry->write_hook = write;
- entry->read_hook = NULL;
- entry->priv_data = priv_data;
- entry->core_id = core_id;
- entry->flags.hook = 1;
+
entry->flags.read = 1;
+ entry->flags.write = 1;
entry->flags.exec = 1;
entry->flags.alloced = 1;
-
- if (insert_shadow_region(vm, entry)) {
- V3_Free(entry);
- return -1;
- }
-
- return 0;
-}
-
-int v3_hook_full_mem(struct v3_vm_info * vm, uint16_t core_id,
- addr_t guest_addr_start, addr_t guest_addr_end,
- int (*read)(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data),
- int (*write)(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data),
- void * priv_data) {
-
- struct v3_shadow_region * entry = (struct v3_shadow_region *)V3_Malloc(sizeof(struct v3_shadow_region));
- memset(entry, 0, sizeof(struct v3_shadow_region));
-
- entry->guest_start = guest_addr_start;
- entry->guest_end = guest_addr_end;
- entry->host_addr = (addr_t)NULL;
- entry->write_hook = write;
- entry->read_hook = read;
- entry->priv_data = priv_data;
- entry->core_id = core_id;
-
- entry->flags.hook = 1;
-
- if (insert_shadow_region(vm, entry)) {
+ if (v3_insert_shadow_region(vm, entry) == -1) {
V3_Free(entry);
return -1;
}
}
-// This will unhook the memory hook registered at start address
-// We do not support unhooking subregions
-int v3_unhook_mem(struct v3_vm_info * vm, uint16_t core_id, addr_t guest_addr_start) {
- struct v3_shadow_region * reg = v3_get_shadow_region(vm, core_id, guest_addr_start);
-
- if (!reg->flags.hook) {
- PrintError("Trying to unhook a non hooked memory region (addr=%p)\n", (void *)guest_addr_start);
- return -1;
- }
-
- v3_delete_shadow_region(vm, reg);
-
- return 0;
-}
-
-
static inline
struct v3_shadow_region * __insert_shadow_region(struct v3_vm_info * vm,
}
-static inline
-struct v3_shadow_region * insert_shadow_region(struct v3_vm_info * vm,
- struct v3_shadow_region * region) {
+
+int v3_insert_shadow_region(struct v3_vm_info * vm,
+ struct v3_shadow_region * region) {
struct v3_shadow_region * ret;
int i = 0;
if ((ret = __insert_shadow_region(vm, region))) {
- return ret;
+ return -1;
}
v3_rb_insert_color(&(region->tree_node), &(vm->mem_map.shdw_regions));
}
}
- return NULL;
-}
-
-
-
-
-
-
-int v3_handle_mem_hook(struct guest_info * info, addr_t guest_va, addr_t guest_pa,
- struct v3_shadow_region * reg, pf_error_t access_info) {
-
- addr_t op_addr = 0;
-
- if (reg->flags.alloced == 0) {
- op_addr = get_hook_hva(info);
- } else {
- op_addr = (addr_t)V3_VAddr((void *)v3_get_shadow_addr(reg, info->cpu_id, guest_pa));
- }
-
-
- if (access_info.write == 1) {
- // Write Operation
-
- if (v3_emulate_write_op(info, guest_va, guest_pa, op_addr,
- reg->write_hook, reg->priv_data) == -1) {
- PrintError("Write Full Hook emulation failed\n");
- return -1;
- }
- } else {
- // Read Operation
-
- if (reg->flags.read == 1) {
- PrintError("Tried to emulate read for a guest Readable page\n");
- return -1;
- }
-
- if (v3_emulate_read_op(info, guest_va, guest_pa, op_addr,
- reg->read_hook, reg->write_hook,
- reg->priv_data) == -1) {
- PrintError("Read Full Hook emulation failed\n");
- return -1;
- }
-
- }
-
-
return 0;
}
-
+
(void *)(reg->guest_end - 1),
(void *)(reg->host_addr));
- V3_Print("\t(flags=%x) (WriteHook = 0x%p) (ReadHook = 0x%p)\n",
+ V3_Print("\t(flags=%x) (unhandled = 0x%p)\n",
reg->flags.value,
- (void *)(reg->write_hook),
- (void *)(reg->read_hook));
+ reg->unhandled);
i++;
} while ((node = v3_rb_next(node)));
--- /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) 2008, Jack Lange <jarusl@cs.northwestern.edu>
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#include <palacios/vmm.h>
+#include <palacios/vm_guest.h>
+#include <palacios/vmm_mem_hook.h>
+#include <palacios/vmm_emulator.h>
+
+struct mem_hook {
+
+ // Called when data is read from a memory page
+ int (*read)(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data);
+ // Called when data is written to a memory page
+ int (*write)(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data);
+
+ void * priv_data;
+ addr_t hook_hva;
+
+
+};
+
+
+
+int v3_init_mem_hooks(struct v3_vm_info * vm) {
+ struct v3_mem_hooks * hooks = &(vm->mem_hooks);
+
+ hooks->hook_hvas = V3_VAddr(V3_AllocPages(vm->num_cores));
+
+ INIT_LIST_HEAD(&(hooks->hook_list));
+
+ return 0;
+}
+
+
+
+
+static int handle_mem_hook(struct guest_info * info, addr_t guest_va, addr_t guest_pa,
+ struct v3_shadow_region * reg, pf_error_t access_info) {
+ struct mem_hook * hook = reg->priv_data;
+ addr_t op_addr = 0;
+
+ if (reg->flags.alloced == 0) {
+ op_addr = hook->hook_hva;
+ } else {
+ op_addr = (addr_t)V3_VAddr((void *)v3_get_shadow_addr(reg, info->cpu_id, guest_pa));
+ }
+
+
+ if (access_info.write == 1) {
+ // Write Operation
+
+ if (v3_emulate_write_op(info, guest_va, guest_pa, op_addr,
+ hook->write, hook->priv_data) == -1) {
+ PrintError("Write Full Hook emulation failed\n");
+ return -1;
+ }
+ } else {
+ // Read Operation
+
+ if (reg->flags.read == 1) {
+ PrintError("Tried to emulate read for a guest Readable page\n");
+ return -1;
+ }
+
+ if (v3_emulate_read_op(info, guest_va, guest_pa, op_addr,
+ hook->read, hook->write,
+ hook->priv_data) == -1) {
+ PrintError("Read Full Hook emulation failed\n");
+ return -1;
+ }
+
+ }
+
+
+ return 0;
+}
+
+
+
+
+int v3_hook_write_mem(struct v3_vm_info * vm, uint16_t core_id,
+ addr_t guest_addr_start, addr_t guest_addr_end, addr_t host_addr,
+ int (*write)(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data),
+ void * priv_data) {
+ struct v3_shadow_region * entry = NULL;
+ struct mem_hook * hook = V3_Malloc(sizeof(struct mem_hook));
+ // struct v3_mem_hooks * hooks = &(vm->mem_hooks);
+
+ memset(hook, 0, sizeof(struct mem_hook));
+
+ hook->write = write;
+ hook->read = NULL;
+ hook->priv_data = priv_data;
+ hook->hook_hva = (addr_t)V3_VAddr((void *)host_addr);
+
+ entry = v3_create_mem_region(vm, core_id, guest_addr_start, guest_addr_end);
+
+ entry->host_addr = host_addr;
+ entry->unhandled = handle_mem_hook;
+ entry->priv_data = hook;
+
+ entry->flags.read = 1;
+ entry->flags.exec = 1;
+ entry->flags.alloced = 1;
+
+ if (v3_insert_shadow_region(vm, entry) == -1) {
+ V3_Free(entry);
+ V3_Free(hook);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+int v3_hook_full_mem(struct v3_vm_info * vm, uint16_t core_id,
+ addr_t guest_addr_start, addr_t guest_addr_end,
+ int (*read)(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data),
+ int (*write)(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data),
+ void * priv_data) {
+
+ struct v3_shadow_region * entry = NULL;
+ struct mem_hook * hook = V3_Malloc(sizeof(struct mem_hook));
+ struct v3_mem_hooks * hooks = &(vm->mem_hooks);
+
+ memset(hook, 0, sizeof(struct mem_hook));
+
+ hook->write = write;
+ hook->read = read;
+ hook->priv_data = priv_data;
+ hook->hook_hva = (addr_t)hooks->hook_hvas + (PAGE_SIZE_4KB * core_id);
+
+ entry = v3_create_mem_region(vm, core_id, guest_addr_start, guest_addr_end);
+
+ entry->unhandled = handle_mem_hook;
+ entry->priv_data = hook;
+
+ if (v3_insert_shadow_region(vm, entry)) {
+ V3_Free(entry);
+ V3_Free(hook);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+// This will unhook the memory hook registered at start address
+// We do not support unhooking subregions
+int v3_unhook_mem(struct v3_vm_info * vm, uint16_t core_id, addr_t guest_addr_start) {
+ struct v3_shadow_region * reg = v3_get_shadow_region(vm, core_id, guest_addr_start);
+ struct mem_hook * hook = reg->priv_data;
+
+ V3_Free(hook);
+
+ v3_delete_shadow_region(vm, reg);
+
+ return 0;
+}
+
+