2 * This file is part of the Palacios Virtual Machine Monitor developed
3 * by the V3VEE Project with funding from the United States National
4 * Science Foundation and the Department of Energy.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
10 * Copyright (c) 2013, Oscar Mondragon <omondrag@cs.unm.edu>
11 * Copyright (c) 2013, Patrick G. Bridges <bridges@cs.unm.edu>
12 * Copyright (c) 2013, The V3VEE Project <http://www.v3vee.org>
13 * All rights reserved.
15 * Author: Oscar Mondragon <omondrag@cs.unm.edu>
16 * Patrick G. Bridges <bridges@cs.unm.edu>
18 * This is free software. You are permitted to use,
19 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
22 #include <palacios/vmm.h>
23 #include <palacios/vm_guest.h>
24 #include <palacios/vmm_cpu_mapper.h>
25 #include <palacios/vmm_hashtable.h>
27 #ifndef V3_CONFIG_DEBUG_CPU_MAPPER
29 #define PrintDebug(fmt, args...)
32 static char default_strategy[] = "default";
33 static struct hashtable * master_cpu_mapper_table = NULL;
34 static int create_default_cpu_mapper();
35 static int destroy_default_cpu_mapper();
37 static struct vm_cpu_mapper_impl *cpu_mapper = NULL;
39 static uint_t cpu_mapper_hash_fn(addr_t key) {
40 char * name = (char *)key;
41 return v3_hash_buffer((uint8_t *)name, strlen(name));
44 static int cpu_mapper_eq_fn(addr_t key1, addr_t key2) {
45 char * name1 = (char *)key1;
46 char * name2 = (char *)key2;
48 return (strcmp(name1, name2) == 0);
51 int V3_init_cpu_mapper() {
53 PrintDebug(VM_NONE, VCORE_NONE,"Initializing cpu_mapper");
55 master_cpu_mapper_table = v3_create_htable(0, cpu_mapper_hash_fn, cpu_mapper_eq_fn);
56 return create_default_cpu_mapper();
60 int V3_deinit_cpu_mapper() {
62 destroy_default_cpu_mapper();
63 // we must leave the keys and values unfreed
64 // since we have no idea whether they are heap or otherwise
65 // the user must have done appropriate unregisters before this
66 v3_free_htable(master_cpu_mapper_table, 0, 0);
70 int v3_register_cpu_mapper(struct vm_cpu_mapper_impl *s) {
72 PrintDebug(VM_NONE, VCORE_NONE,"Registering cpu_mapper (%s)\n", s->name);
74 if (v3_htable_search(master_cpu_mapper_table, (addr_t)(s->name))) {
75 PrintError(VM_NONE, VCORE_NONE, "Multiple instances of cpu_mapper (%s)\n", s->name);
79 if (v3_htable_insert(master_cpu_mapper_table,
82 PrintError(VM_NONE, VCORE_NONE, "Could not register cpu_mapper (%s)\n", s->name);
89 struct vm_cpu_mapper_impl *v3_unregister_cpu_mapper(char *name) {
91 PrintDebug(VM_NONE, VCORE_NONE,"Unregistering cpu_mapper (%s)\n",name);
93 struct vm_cpu_mapper_impl *f = (struct vm_cpu_mapper_impl *) v3_htable_remove(master_cpu_mapper_table,(addr_t)(name),0);
96 PrintError(VM_NONE,VCORE_NONE,"Could not find cpu_mapper (%s)\n",name);
104 struct vm_cpu_mapper_impl *v3_cpu_mapper_lookup(char *name)
106 return (struct vm_cpu_mapper_impl *)v3_htable_search(master_cpu_mapper_table, (addr_t)(name));
109 int V3_enable_cpu_mapper() {
113 mapper_name = v3_lookup_option("cpu_mapper");
116 cpu_mapper = v3_cpu_mapper_lookup(mapper_name);
120 cpu_mapper = v3_cpu_mapper_lookup(default_strategy);
124 PrintError(VM_NONE, VCORE_NONE,"Specified Palacios cpu_mapper \"%s\" not found.\n", default_strategy);
128 PrintDebug(VM_NONE, VCORE_NONE,"cpu_mapper %s found",cpu_mapper->name);
130 if (cpu_mapper->init) {
131 return cpu_mapper->init();
137 int V3_disable_cpu_mapper()
139 if (cpu_mapper->deinit) {
140 return cpu_mapper->deinit();
146 int v3_cpu_mapper_register_vm(struct v3_vm_info *vm) {
147 if (cpu_mapper->vm_init) {
148 return cpu_mapper->vm_init(vm);
154 int v3_cpu_mapper_admit_vm(struct v3_vm_info *vm, unsigned int cpu_mask) {
155 if (cpu_mapper->admit) {
156 return cpu_mapper->admit(vm,cpu_mask);
163 int v3_cpu_mapper_admit_core(struct v3_vm_info * vm, int vcore_id, int target_cpu) {
164 if (cpu_mapper->admit_core) {
165 return cpu_mapper->admit_core(vm,vcore_id,target_cpu);
171 int default_mapper_vm_init(struct v3_vm_info *vm){
175 int default_mapper_admit_core(struct v3_vm_info * vm, int vcore_id, int target_cpu){
180 int default_mapper_admit(struct v3_vm_info *vm, unsigned int cpu_mask){
184 uint8_t * core_mask = (uint8_t *)&cpu_mask;
186 for (i = 0, vcore_id = vm->num_cores - 1; vcore_id >= 0; i++) {
190 struct guest_info * core = &(vm->cores[vcore_id]);
191 char * specified_cpu = v3_cfg_val(core->core_cfg_data, "target_cpu");
192 uint32_t core_idx = 0;
194 if (specified_cpu != NULL) {
195 core_idx = atoi(specified_cpu);
198 PrintError(vm, VCORE_NONE, "Target CPU out of bounds (%d) \n", core_idx);
201 i--; // We reset the logical core idx. Not strictly necessary I guess...
206 major = core_idx / 8;
207 minor = core_idx % 8;
209 if ((core_mask[major] & (0x1 << minor)) == 0) {
210 PrintError(vm, VCORE_NONE, "Logical CPU %d not available for virtual core %d; not started\n",
213 if (specified_cpu != NULL) {
214 PrintError(vm, VCORE_NONE, "CPU was specified explicitly (%d). HARD ERROR\n", core_idx);
223 core->pcpu_id = core_idx;
236 static struct vm_cpu_mapper_impl default_mapper_impl = {
240 .vm_init = default_mapper_vm_init,
242 .admit_core = default_mapper_admit_core,
243 .admit = default_mapper_admit
247 static int create_default_cpu_mapper()
249 v3_register_cpu_mapper(&default_mapper_impl);
253 static int destroy_default_cpu_mapper()
255 v3_unregister_cpu_mapper(default_mapper_impl.name);
256 // note - is not deleted since it's a global...