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.


timer interface updates to allow state cleanup on exit
[palacios.git] / palacios / src / palacios / vmm_dev_mgr.c
1 /* 
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.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20 #include <palacios/vmm_dev_mgr.h>
21 #include <palacios/vm_guest.h>
22 #include <palacios/vmm.h>
23 #include <palacios/vmm_decoder.h>
24
25
26 #ifndef CONFIG_DEBUG_DEV_MGR
27 #undef PrintDebug
28 #define PrintDebug(fmt, args...)
29 #endif
30
31
32 static struct hashtable * master_dev_table = NULL;
33
34 static uint_t dev_hash_fn(addr_t key) {
35     char * name = (char *)key;
36     return v3_hash_buffer((uchar_t *)name, strlen(name));
37 }
38
39 static int dev_eq_fn(addr_t key1, addr_t key2) {
40     char * name1 = (char *)key1;
41     char * name2 = (char *)key2;
42     
43     return (strcmp(name1, name2) == 0);
44 }
45
46
47 int v3_init_devices() {
48     extern struct v3_device_info __start__v3_devices[];
49     extern struct v3_device_info __stop__v3_devices[];
50     struct v3_device_info * tmp_dev =  __start__v3_devices;
51     int i = 0;
52
53 #ifdef CONFIG_DEBUG_DEV_MGR
54     {
55         int num_devices = (__stop__v3_devices - __start__v3_devices) / sizeof(struct v3_device_info);
56         PrintDebug("%d Virtual devices registered with Palacios\n", num_devices);
57     }
58 #endif
59
60     PrintDebug("Start addres=%p, Stop address=%p\n", __start__v3_devices, __stop__v3_devices);
61
62     master_dev_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
63
64
65
66     while (tmp_dev != __stop__v3_devices) {
67         PrintDebug("Device: %s\n", tmp_dev->name);
68
69         if (v3_htable_search(master_dev_table, (addr_t)(tmp_dev->name))) {
70             PrintError("Multiple instance of device (%s)\n", tmp_dev->name);
71             return -1;
72         }
73
74         if (v3_htable_insert(master_dev_table, 
75                              (addr_t)(tmp_dev->name), 
76                              (addr_t)(tmp_dev->init)) == 0) {
77             PrintError("Could not add device %s to master list\n", tmp_dev->name);
78             return -1;
79         }
80
81         tmp_dev = &(__start__v3_devices[++i]);
82     }
83
84
85     return 0;
86 }
87
88
89 int v3_init_dev_mgr(struct v3_vm_info * vm) {
90     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
91
92     INIT_LIST_HEAD(&(mgr->dev_list));
93     mgr->num_devs = 0;
94
95     mgr->dev_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
96
97     INIT_LIST_HEAD(&(mgr->blk_list));
98     INIT_LIST_HEAD(&(mgr->net_list));
99     INIT_LIST_HEAD(&(mgr->char_list));
100     INIT_LIST_HEAD(&(mgr->console_list));
101
102     mgr->blk_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
103     mgr->net_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
104     mgr->char_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
105     mgr->console_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
106     
107     return 0;
108 }
109
110
111 int v3_dev_mgr_deinit(struct v3_vm_info * vm) {
112     struct vm_device * dev;
113     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
114     struct vm_device * tmp;
115
116     list_for_each_entry_safe(dev, tmp, &(mgr->dev_list), dev_link) {
117         v3_detach_device(dev);
118         v3_free_device(dev);
119     }
120
121     v3_free_htable(mgr->blk_table, 0, 0);
122     v3_free_htable(mgr->net_table, 0, 0);
123     v3_free_htable(mgr->char_table, 0, 0);
124     v3_free_htable(mgr->console_table, 0, 0);
125
126     v3_free_htable(mgr->dev_table, 0, 0);
127
128     return 0;
129 }
130
131 /*
132 int v3_init_core_dev_mgr(struct v3_vm_info * vm) {
133     struct v3_core_dev_mgr * mgr = &(vm->core_dev_mgr);
134
135     INIT_LIST_HEAD(&(mgr->dev_list));
136     mgr->dev_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
137
138     return 0;
139 }
140
141 int v3_core_dev_mgr_deinit(struct v3_vm_info * vm) {
142     struct vm_device * dev;
143     struct v3_core_dev_mgr * mgr = &(vm->core_dev_mgr);
144     struct vm_device * tmp;
145
146     list_for_each_entry_safe(dev, tmp, &(mgr->dev_list), dev_link) {
147         v3_detach_device(dev);
148         v3_free_device(dev);
149     }
150
151     // TODO: Clear hash tables 
152
153 }
154 */
155
156
157 int v3_create_device(struct v3_vm_info * vm, const char * dev_name, v3_cfg_tree_t * cfg) {
158     int (*dev_init)(struct v3_vm_info * vm, void * cfg_data);
159
160     dev_init = (void *)v3_htable_search(master_dev_table, (addr_t)dev_name);
161
162     if (dev_init == NULL) {
163         PrintError("Could not find device %s in master device table\n", dev_name);
164         return -1;
165     }
166
167
168     if (dev_init(vm, cfg) == -1) {
169         PrintError("Could not initialize Device %s\n", dev_name);
170         return -1;
171     }
172
173     return 0;
174 }
175
176
177 void v3_free_device(struct vm_device * dev) {
178     V3_Free(dev);
179 }
180
181
182
183 struct vm_device * v3_find_dev(struct v3_vm_info * vm, const char * dev_name) {
184     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
185
186     if (!dev_name) {
187         return NULL;
188     }
189
190     return (struct vm_device *)v3_htable_search(mgr->dev_table, (addr_t)dev_name);
191 }
192
193
194 /****************************************************************/
195 /* The remaining functions are called by the devices themselves */
196 /****************************************************************/
197
198 /* IO HOOKS */
199 int v3_dev_hook_io(struct vm_device * dev, uint16_t port,
200                    int (*read)(struct guest_info * core, uint16_t port, void * dst, uint_t length, struct vm_device * dev),
201                    int (*write)(struct guest_info * core, uint16_t port, void * src, uint_t length, struct vm_device * dev)) {
202     return v3_hook_io_port(dev->vm, port, 
203                            (int (*)(struct guest_info * core, ushort_t, void *, uint_t, void *))read, 
204                            (int (*)(struct guest_info * core, ushort_t, void *, uint_t, void *))write, 
205                            (void *)dev);
206 }
207
208
209 int v3_dev_unhook_io(struct vm_device * dev, uint16_t port) {
210     return v3_unhook_io_port(dev->vm, port);
211 }
212
213
214
215 int v3_detach_device(struct vm_device * dev) {
216     struct vmm_dev_mgr * mgr = &(dev->vm->dev_mgr);
217
218     if (dev->ops->free) {
219         dev->ops->free(dev);
220     } else {
221         PrintError("Error: %s free() not implemented\n",  dev->name);
222     }
223
224     list_del(&(dev->dev_link));
225     mgr->num_devs--;
226
227     dev->vm = NULL;
228
229     return -1;
230 }
231
232
233 struct vm_device * v3_allocate_device(char * name, 
234                                       struct v3_device_ops * ops, 
235                                       void * private_data) {
236     struct vm_device * dev = NULL;
237
238     dev = (struct vm_device*)V3_Malloc(sizeof(struct vm_device));
239
240     strncpy(dev->name, name, 32);
241     dev->ops = ops;
242     dev->private_data = private_data;
243
244     dev->vm = NULL;
245
246     return dev;
247 }
248
249
250 int v3_attach_device(struct v3_vm_info * vm, struct vm_device * dev ) {
251     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
252
253     dev->vm = vm;
254
255     list_add(&(dev->dev_link), &(mgr->dev_list));
256     mgr->num_devs++;
257
258
259     v3_htable_insert(mgr->dev_table, (addr_t)(dev->name), (addr_t)dev);
260
261     return 0;
262 }
263
264
265
266 void v3_print_dev_mgr(struct v3_vm_info * vm) {
267     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
268     struct vm_device * dev;
269
270     V3_Print("%d devices registered with manager\n", mgr->num_devs);
271
272     list_for_each_entry(dev, &(mgr->dev_list), dev_link) {
273         V3_Print("Device: %s\n", dev->name);
274     }
275
276     return;
277 }
278
279
280
281
282 struct blk_frontend {
283     int (*connect)(struct v3_vm_info * vm, 
284                     void * frontend_data, 
285                     struct v3_dev_blk_ops * ops, 
286                     v3_cfg_tree_t * cfg, 
287                     void * priv_data);
288         
289
290     struct list_head blk_node;
291
292     void * priv_data;
293 };
294
295
296
297 int v3_dev_add_blk_frontend(struct v3_vm_info * vm, 
298                             char * name, 
299                             int (*connect)(struct v3_vm_info * vm, 
300                                             void * frontend_data, 
301                                             struct v3_dev_blk_ops * ops, 
302                                             v3_cfg_tree_t * cfg, 
303                                             void * priv_data), 
304                             void * priv_data) {
305
306     struct blk_frontend * frontend = NULL;
307
308     frontend = (struct blk_frontend *)V3_Malloc(sizeof(struct blk_frontend));
309     memset(frontend, 0, sizeof(struct blk_frontend));
310     
311     frontend->connect = connect;
312     frontend->priv_data = priv_data;
313         
314     list_add(&(frontend->blk_node), &(vm->dev_mgr.blk_list));
315     v3_htable_insert(vm->dev_mgr.blk_table, (addr_t)(name), (addr_t)frontend);
316
317     return 0;
318 }
319
320 int v3_dev_connect_blk(struct v3_vm_info * vm, 
321                        char * frontend_name, 
322                        struct v3_dev_blk_ops * ops, 
323                        v3_cfg_tree_t * cfg, 
324                        void * private_data) {
325
326     struct blk_frontend * frontend = NULL;
327
328     frontend = (struct blk_frontend *)v3_htable_search(vm->dev_mgr.blk_table,
329                                                        (addr_t)frontend_name);
330     
331     if (frontend == NULL) {
332         PrintError("Could not find frontend blk device %s\n", frontend_name);
333         return 0;
334     }
335
336     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
337         PrintError("Error connecting to block frontend %s\n", frontend_name);
338         return -1;
339     }
340
341     return 0;
342 }
343
344
345
346 struct net_frontend {
347     int (*connect)(struct v3_vm_info * vm, 
348                     void * frontend_data, 
349                     struct v3_dev_net_ops * ops, 
350                     v3_cfg_tree_t * cfg, 
351                     void * priv_data);
352     
353
354     struct list_head net_node;
355
356     void * priv_data;
357 };
358
359
360 int v3_dev_add_net_frontend(struct v3_vm_info * vm, 
361                             char * name, 
362                             int (*connect)(struct v3_vm_info * vm, 
363                                             void * frontend_data, 
364                                             struct v3_dev_net_ops * ops, 
365                                             v3_cfg_tree_t * cfg, 
366                                             void * private_data), 
367                             void * priv_data)
368 {
369     struct net_frontend * frontend = NULL;
370
371     frontend = (struct net_frontend *)V3_Malloc(sizeof(struct net_frontend));
372     memset(frontend, 0, sizeof(struct net_frontend));
373     
374     frontend->connect = connect;
375     frontend->priv_data = priv_data;
376         
377     list_add(&(frontend->net_node), &(vm->dev_mgr.net_list));
378     v3_htable_insert(vm->dev_mgr.net_table, (addr_t)(name), (addr_t)frontend);
379
380     return 0;
381 }
382
383
384 int v3_dev_connect_net(struct v3_vm_info * vm, 
385                        char * frontend_name, 
386                        struct v3_dev_net_ops * ops, 
387                        v3_cfg_tree_t * cfg, 
388                        void * private_data)
389 {
390     struct net_frontend * frontend = NULL;
391
392     frontend = (struct net_frontend *)v3_htable_search(vm->dev_mgr.net_table,
393                                                        (addr_t)frontend_name);
394     
395     if (frontend == NULL) {
396         PrintError("Could not find frontend net device %s\n", frontend_name);
397         return 0;
398     }
399
400     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
401         PrintError("Error connecting to net frontend %s\n", frontend_name);
402         return -1;
403     }
404
405     return 0;
406 }
407
408
409 struct char_frontend {
410     int (*connect)(struct v3_vm_info * vm, 
411                    void * frontend_data, 
412                    struct v3_dev_char_ops * ops, 
413                    v3_cfg_tree_t * cfg, 
414                    void * priv_data, 
415                    void ** push_fn_arg);
416     
417
418     struct list_head char_node;
419
420     void * priv_data;
421 };
422
423
424
425 int v3_dev_add_char_frontend(struct v3_vm_info * vm, 
426                              char * name, 
427                              int (*connect)(struct v3_vm_info * vm, 
428                                             void * frontend_data, 
429                                             struct v3_dev_char_ops * ops, 
430                                             v3_cfg_tree_t * cfg, 
431                                             void * private_data, 
432                                             void ** push_fn_arg), 
433                              void * priv_data)
434 {
435     struct char_frontend * frontend = NULL;
436
437     frontend = (struct char_frontend *)V3_Malloc(sizeof(struct char_frontend));
438     memset(frontend, 0, sizeof(struct char_frontend));
439     
440     frontend->connect = connect;
441     frontend->priv_data = priv_data;
442         
443     list_add(&(frontend->char_node), &(vm->dev_mgr.char_list));
444     v3_htable_insert(vm->dev_mgr.char_table, (addr_t)(name), (addr_t)frontend);
445
446     return 0;
447 }
448
449
450 int v3_dev_connect_char(struct v3_vm_info * vm, 
451                         char * frontend_name, 
452                         struct v3_dev_char_ops * ops, 
453                         v3_cfg_tree_t * cfg, 
454                         void * private_data, 
455                         void ** push_fn_arg)
456 {
457     struct char_frontend * frontend = NULL;
458
459     frontend = (struct char_frontend *)v3_htable_search(vm->dev_mgr.char_table,
460                                                         (addr_t)frontend_name);
461     
462     if (frontend == NULL) {
463         PrintError("Could not find frontend char device %s\n", frontend_name);
464         return 0;
465     }
466     
467     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data, push_fn_arg) == -1) {
468         PrintError("Error connecting to char frontend %s\n", frontend_name);
469         return -1;
470     }
471
472     return 0;
473 }
474