#include <palacios/vmm_hvm.h>
#endif
-
+#ifdef V3_CONFIG_CACHEPART
+#include <palacios/vmm_cachepart.h>
+#endif
#include <palacios/vmm_config.h>
struct v3_core_timeouts timeouts;
void * sched_priv_data;
+ // Resource constraints/etc for the thread running this core
+ v3_resource_control_t resource_control;
+
v3_paging_mode_t shdw_pg_mode;
// arch-independent state of shadow pager
struct v3_shdw_pg_state shdw_pg_state;
char name[128];
v3_vm_class_t vm_class;
+
+ // Resource control for whole VM - determined early and used
+ // when building the VM, then cloned to each core
+ v3_resource_control_t resource_control;
+
struct v3_fw_cfg_state fw_cfg_state;
// This is always the total RAM (addresses 0...mem_size)
// used to implement reset of regular VM and ROS
v3_counting_barrier_t reset_barrier;
+#ifdef V3_CONFIG_CACHEPART
+ v3_cachepart_t cachepart_state;
+#endif
+
+
uint64_t yield_cycle_period;
-#define V3_CREATE_AND_START_THREAD(fn, arg, name) ({ \
+#define V3_CREATE_AND_START_THREAD(fn, arg, name, rctl) ({ \
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 = (os_hooks)->start_kernel_thread(fn, arg, name,rctl); \
} \
thread; \
})
-#define V3_CREATE_THREAD_ON_CPU(cpu, fn, arg, name) ({ \
+#define V3_CREATE_THREAD_ON_CPU(cpu, fn, arg, name, rctl) ({ \
void * thread = NULL; \
extern struct v3_os_hooks * os_hooks; \
if ((os_hooks) && (os_hooks)->create_thread_on_cpu) { \
- thread = (os_hooks)->create_thread_on_cpu(cpu, fn, arg, name); \
+ thread = (os_hooks)->create_thread_on_cpu(cpu, fn, arg, name, rctl); \
} \
thread; \
})
} \
})
-#define V3_CREATE_AND_START_THREAD_ON_CPU(cpu, fn, arg, name) ({ \
- void *thread = V3_CREATE_THREAD_ON_CPU(cpu,fn,arg,name); \
+#define V3_CREATE_AND_START_THREAD_ON_CPU(cpu, fn, arg, name, rctl) ({ \
+ void *thread = V3_CREATE_THREAD_ON_CPU(cpu,fn,arg,name,rctl); \
if (thread) { \
V3_START_THREAD(thread); \
} \
struct v3_vm_info;
+// Resource management constraints placed
+// on a thread
+typedef struct v3_resource_control {
+ // Page allocations, including for the thread stack
+ unsigned int pg_alignment; // alignment e.g., large pages
+ int pg_node_id; // numa node
+ int (*pg_filter_func)(void *paddr, void *filter_state);
+ void *pg_filter_state;
+} v3_resource_control_t;
+
/* This will contain function pointers that provide OS services */
struct v3_os_hooks {
// the vm pointer is the host os's "priv_data" from v3_create_vm
// Allocates physically contiguous pages
// - with desired alignment
// - that the filter_func returns nonzero on (if filter_func is given)
+ // For any constraint that is not given, if a resource control struture
+ // exists for the thread, its fields are used. This allows Palacios
+ // to manage resources using its internal knowledge of what the
+ // purpose of thread is
void *(*allocate_pages)(int num_pages, unsigned int alignment, int node_id, int (*filter_func)(void *paddr, void *filter_state), void *filter_state);
void (*free_pages)(void * page, int num_pages);
// Allocates virtually contiguous memory
+ // the resource control structure for the thread is used, if it exists
void *(*vmalloc)(unsigned int size);
void (*vfree)(void * addr);
// Allocates virtually and physically contiguous memory
+ // the resource control structure for the thread is used, if it exists
void *(*malloc)(unsigned int size);
void (*free)(void * addr);
unsigned int (*get_cpu)(void);
- void * (*start_kernel_thread)(int (*fn)(void * arg), void * arg, char * thread_name);
+ // Resource allocations to instantiate a thread obey the resource
+ // control structure, if it exists, and if it is possible.
+ // The structure is then bound to the thread and used for subsequent
+ // allocations, etc.
+ void * (*start_kernel_thread)(int (*fn)(void * arg), void * arg, char * thread_name, v3_resource_control_t *rctl);
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 * (*create_thread_on_cpu)(int cpu_id, int (*fn)(void * arg), void * arg, char * thread_name);
+ void * (*create_thread_on_cpu)(int cpu_id, int (*fn)(void * arg), void * arg, char * thread_name, v3_resource_control_t *rctl);
void (*start_thread)(void * core_thread);
int (*move_thread_to_cpu)(int cpu_id, void * thread);
};
struct vnet_host_hooks {
void *(*thread_start)(int (*fn)(void * arg),
void * arg,
- char * thread_name);
+ char * thread_name,
+ v3_resource_control_t *resource_control);
void (*thread_sleep)(long timeout);
void (*thread_wakeup)(void * thread);
void (*print)(void *vm , int core, const char * format, ...)
__attribute__ ((format (printf, 3, 4)));
- void *(*allocate_pages)(int num_pages, unsigned int alignment, int node_id, int constraints);
+ void *(*allocate_pages)(int num_pages, unsigned int alignment, int node_id);
void (*free_pages)(void * page, int num_pages);
void *(*malloc)(unsigned int size);
/* 4KB-aligned */
static inline void * Vnet_AllocPages(int num_pages){
if ((host_hooks) && host_hooks->allocate_pages) {
- return host_hooks->allocate_pages(num_pages, PAGE_SIZE_4KB,-1,0); // any zone, no constraints
+ return host_hooks->allocate_pages(num_pages, PAGE_SIZE_4KB,-1);
}
return NULL;
v3_console_register_cga(frontend, &cons_ops, state);
- V3_CREATE_AND_START_THREAD(cons_server, state, "Telnet Console Network Server");
+ V3_CREATE_AND_START_THREAD(cons_server, state, "Telnet Console Network Server", 0);
return 0;
}
#include <palacios/vmm_checkpoint.h>
#endif
-
v3_cpu_arch_t v3_cpu_types[V3_CONFIG_MAX_CPUS];
v3_cpu_arch_t v3_mach_type = V3_INVALID_CPU;
v3_cpu_types[i] = V3_INVALID_CPU;
}
+#ifdef V3_CONFIG_CACHEPART
+ v3_init_cachepart();
+#endif
+
// Parse host-os defined options into an easily-accessed format.
v3_parse_options(options);
v3_init_hvm();
#endif
+
// Memory manager initialization
v3_init_mem();
v3_deinit_options();
+#ifdef V3_CONFIG_CACHEPART
+ v3_deinit_cachepart();
+#endif
}
PrintDebug(vm, VCORE_NONE, "run: core=%u, func=0x%p, arg=0x%p, name=%s\n",
core->pcpu_id, start_core, core, core->exec_name);
- core->core_thread = V3_CREATE_THREAD_ON_CPU(core->pcpu_id, start_core, core, core->exec_name);
+
+ // Resource controls for cores can be independent, but
+ // currently are not, hence this copy.
+ core->resource_control = vm->resource_control;
+
+ core->core_thread = V3_CREATE_THREAD_ON_CPU(core->pcpu_id, start_core, core, core->exec_name, &core->resource_control);
if (core->core_thread == NULL) {
PrintError(vm, VCORE_NONE, "Thread creation failed\n");
new_hpa = V3_AllocPagesExtended(num_pages,
PAGE_SIZE_4KB,
new_node,
- 0, 0); // no constraints given new shadow pager impl
+ vm->resource_control.pg_filter_func,
+ vm->resource_control.pg_filter_state);
if (!new_hpa) {
PrintError(vm, VCORE_NONE, "Cannot allocate memory for new base region...\n");
if (alignment != PAGE_SIZE_4KB) {
PrintError(VM_NONE, VCORE_NONE, "Aligned page allocations are not supported in this host (requested alignment=%d)\n", alignment);
PrintError(VM_NONE, VCORE_NONE, "Ignoring alignment request\n");
+ alignment = PAGE_SIZE_4KB;
}
#endif
// Amount of ram the Guest will have, always in MB
vm->mem_size = (addr_t)atoi(memory_str) * 1024 * 1024;
vm->mem_align = get_alignment(align_str);
+
+ // set up defaults for memory management for threads associated
+ // with this VM
+ vm->resource_control.pg_alignment=vm->mem_align;
+ vm->resource_control.pg_node_id=-1;
#ifdef V3_CONFIG_SWAPPING
if (v3_init_swapping_vm(vm,vm_cfg)) {
return vm;
}
+/*
+
+
+*/
struct v3_vm_info * v3_config_guest(void * cfg_blob, void * priv_data) {
v3_cfg_tree_t * cores_cfg = NULL;
v3_cfg_tree_t * per_core_cfg = NULL;
+
if (v3_mach_type == V3_INVALID_CPU) {
PrintError(VM_NONE, VCORE_NONE, "Configuring guest on invalid CPU\n");
return NULL;
cfg_data = parse_config(cfg_blob);
+
if (!cfg_data) {
PrintError(VM_NONE, VCORE_NONE, "Could not parse configuration\n");
return NULL;
}
+
cores_cfg = v3_cfg_subtree(cfg_data->cfg, "cores");
if (!cores_cfg) {
return NULL;
}
+#ifdef V3_CONFIG_CACHEPART
+ // Need to initialize cache management and resource control
+ // as early as possible so that allocations are done accordingly
+ if (v3_init_cachepart_vm(vm,cfg_data->cfg)) {
+ PrintError(VM_NONE, VCORE_NONE, "Could not initialize cache partioning\n");
+ V3_Free(vm);
+ return NULL;
+ }
+#endif
+
vm->host_priv_data = priv_data;
vm->cfg_data = cfg_data;
void * page = 0;
void *temp;
- temp = V3_AllocPagesExtended(1, PAGE_SIZE_4KB, -1, 0, 0); // no constraints
+ temp = V3_AllocPagesExtended(1, PAGE_SIZE_4KB,
+ core->resource_control.pg_node_id,
+ core->resource_control.pg_filter_func,
+ core->resource_control.pg_filter_state);
if (!temp) {
PrintError(VM_NONE, VCORE_NONE,"Cannot allocate page\n");
#ifdef V3_CONFIG_SWAPPING
// nothing to do - memset will have done it.
#endif
-
+
region->host_addr = (addr_t)V3_AllocPagesExtended(block_pages,
PAGE_SIZE_4KB,
node_id,
- 0, 0); // no constraints
+ vm->resource_control.pg_filter_func,
+ vm->resource_control.pg_filter_state);
if ((void *)region->host_addr == NULL) {
PrintError(vm, VCORE_NONE, "Could not allocate guest memory\n");
return NULL;
}
- thread->host_thread = host_hooks->thread_start(func, arg, name);
+ thread->host_thread = host_hooks->thread_start(func, arg, name, 0);
if(thread->host_thread){
return thread;