Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Resource control extensions to host OS interface
Peter Dinda [Mon, 31 Aug 2015 20:12:45 +0000 (15:12 -0500)]
plus changes internal to Palacios to use them

The basic idea here is that on creating a thread, Palacios
can hand the host a resource control structure for that thread.
For resource allocations (e.g., page allocations) made by
that thread, the host can then use the resource control
structure to decide which resources will be provided.
This makes it possible for code in Palacios to be
resource aware despite separation of concerns.

This is used by cache partitioning to make any subsequent
page allocations by a core thread (e.g., in nested or shadow
page fault handling) to obey the cache placement constraints.

palacios/include/palacios/vm_guest.h
palacios/include/palacios/vmm.h
palacios/include/vnet/vnet_host.h
palacios/src/devices/telnet_cons.c
palacios/src/palacios/vmm.c
palacios/src/palacios/vmm_config.c
palacios/src/palacios/vmm_direct_paging.c
palacios/src/palacios/vmm_mem.c
palacios/src/vnet/vnet_host.c

index 7a78c0a..84468b2 100644 (file)
@@ -78,7 +78,9 @@ struct v3_sym_core_state;
 #include <palacios/vmm_hvm.h>
 #endif
 
-
+#ifdef V3_CONFIG_CACHEPART
+#include <palacios/vmm_cachepart.h>
+#endif
 
 #include <palacios/vmm_config.h>
 
@@ -99,6 +101,9 @@ struct guest_info {
     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;
@@ -202,6 +207,11 @@ struct v3_vm_info {
     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)
@@ -280,6 +290,11 @@ struct v3_vm_info {
     // 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;  
 
 
index f1d2390..108da4a 100644 (file)
@@ -210,11 +210,11 @@ int      v3_get_vcore(struct guest_info *);
 
 
 
-#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;                                                     \
        })
@@ -232,11 +232,11 @@ int      v3_get_vcore(struct guest_info *);
 
 
 
-#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;                                                     \
        })
@@ -248,8 +248,8 @@ int      v3_get_vcore(struct guest_info *);
        }                                                               \
   })
 
-#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);                                \
             }                                                           \
@@ -344,6 +344,16 @@ int v3_reset_vm_core(struct guest_info * core, addr_t rip);
 
 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
@@ -359,14 +369,20 @@ struct v3_os_hooks {
     // 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);
 
@@ -391,10 +407,14 @@ struct v3_os_hooks {
 
     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);
 };
index 548a252..ec6a28c 100644 (file)
@@ -38,7 +38,8 @@ typedef void *vnet_intr_flags_t;
 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);
@@ -61,7 +62,7 @@ struct vnet_host_hooks {
     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);
@@ -92,7 +93,7 @@ extern struct vnet_host_hooks * host_hooks;
 /* 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;
index 5ba8a1b..be40ba4 100644 (file)
@@ -555,7 +555,7 @@ static int cons_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
 
     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;
 }
index eef2d3d..57d567b 100644 (file)
@@ -44,7 +44,6 @@
 #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;
 
@@ -151,6 +150,10 @@ void Init_V3(struct v3_os_hooks * hooks, char * cpu_mask, int num_cpus, char *op
        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);
 
@@ -162,6 +165,7 @@ void Init_V3(struct v3_os_hooks * hooks, char * cpu_mask, int num_cpus, char *op
     v3_init_hvm();
 #endif
 
+
     // Memory manager initialization
     v3_init_mem();
 
@@ -273,6 +277,9 @@ void Shutdown_V3() {
 
     v3_deinit_options();
     
+#ifdef V3_CONFIG_CACHEPART
+    v3_deinit_cachepart();
+#endif
 
 }
 
@@ -364,7 +371,12 @@ struct v3_vm_info * v3_create_vm(void * cfg, void * priv_data, char * name, unsi
         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");
@@ -727,7 +739,8 @@ int v3_move_vm_mem(struct v3_vm_info * vm, void *gpa, int target_cpu) {
     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");
index 7987957..7897f3e 100644 (file)
@@ -293,6 +293,7 @@ static inline uint32_t get_alignment(char * align_str) {
     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 
 
@@ -324,6 +325,11 @@ static int pre_config_vm(struct v3_vm_info * vm, v3_cfg_tree_t * vm_cfg) {
     // 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)) {
@@ -585,6 +591,10 @@ static struct v3_vm_info * allocate_guest(int num_cores) {
     return vm;
 }
 
+/*
+   
+
+*/
 
 
 struct v3_vm_info * v3_config_guest(void * cfg_blob, void * priv_data) {
@@ -596,6 +606,7 @@ 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;
@@ -603,11 +614,13 @@ struct v3_vm_info * v3_config_guest(void * cfg_blob, void * priv_data) {
 
     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) {
@@ -630,6 +643,16 @@ struct v3_vm_info * v3_config_guest(void * cfg_blob, void * priv_data) {
        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;
index 1175b25..7c3e72f 100644 (file)
@@ -161,7 +161,10 @@ static addr_t create_generic_pt_page(struct guest_info *core) {
     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");
index 9cf6ea1..ac91eeb 100644 (file)
@@ -217,11 +217,12 @@ int v3_init_mem_map(struct v3_vm_info * vm) {
 #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");
index 5d0c3bf..c03e0fa 100644 (file)
@@ -32,7 +32,7 @@ struct vnet_thread * vnet_start_thread(int (*func)(void *), void *arg, char * na
            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;