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.


added initial global shutdown functionality
[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_deinit_devices() {    
90     v3_free_htable(master_dev_table, 0, 0);
91     return 0;
92 }
93
94
95 int v3_init_dev_mgr(struct v3_vm_info * vm) {
96     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
97
98     INIT_LIST_HEAD(&(mgr->dev_list));
99     mgr->num_devs = 0;
100
101     mgr->dev_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
102
103     INIT_LIST_HEAD(&(mgr->blk_list));
104     INIT_LIST_HEAD(&(mgr->net_list));
105     INIT_LIST_HEAD(&(mgr->char_list));
106     INIT_LIST_HEAD(&(mgr->cons_list));
107
108     mgr->blk_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
109     mgr->net_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
110     mgr->char_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
111     mgr->cons_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
112     
113     return 0;
114 }
115
116
117 int v3_free_vm_devices(struct v3_vm_info * vm) {
118     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
119     struct vm_device * dev;
120     struct vm_device * tmp;
121
122     list_for_each_entry_safe(dev, tmp, &(mgr->dev_list), dev_link) {
123         v3_remove_device(dev);
124     }
125
126     return 0;
127 }
128
129 static int free_frontends(struct v3_vm_info * vm, struct vmm_dev_mgr * mgr);
130
131 int v3_deinit_dev_mgr(struct v3_vm_info * vm) {
132     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
133     
134     // clear frontend lists
135
136     free_frontends(vm, mgr);
137
138
139
140     v3_free_htable(mgr->dev_table, 0, 0);
141
142     return 0;
143 }
144
145
146
147 int v3_create_device(struct v3_vm_info * vm, const char * dev_name, v3_cfg_tree_t * cfg) {
148     int (*dev_init)(struct v3_vm_info * vm, void * cfg_data);
149
150     dev_init = (void *)v3_htable_search(master_dev_table, (addr_t)dev_name);
151
152     if (dev_init == NULL) {
153         PrintError("Could not find device %s in master device table\n", dev_name);
154         return -1;
155     }
156
157
158     if (dev_init(vm, cfg) == -1) {
159         PrintError("Could not initialize Device %s\n", dev_name);
160         return -1;
161     }
162
163     return 0;
164 }
165
166
167
168
169 struct vm_device * v3_find_dev(struct v3_vm_info * vm, const char * dev_name) {
170     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
171
172     if (!dev_name) {
173         return NULL;
174     }
175
176     return (struct vm_device *)v3_htable_search(mgr->dev_table, (addr_t)dev_name);
177 }
178
179
180 /****************************************************************/
181 /* The remaining functions are called by the devices themselves */
182 /****************************************************************/
183
184 struct dev_io_hook {
185     uint16_t port;
186
187     struct list_head node;
188
189 };
190
191 /* IO HOOKS */
192 int v3_dev_hook_io(struct vm_device * dev, uint16_t port,
193                    int (*read)(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * priv_data),
194                    int (*write)(struct guest_info * core, uint16_t port, void * src, uint_t length, void * priv_data)) {
195     struct dev_io_hook * io_hook = NULL;
196     int ret = 0;
197     
198    ret = v3_hook_io_port(dev->vm, port, 
199                          (int (*)(struct guest_info * core, ushort_t, void *, uint_t, void *))read, 
200                          (int (*)(struct guest_info * core, ushort_t, void *, uint_t, void *))write, 
201                          (void *)dev->private_data);
202
203    if (ret == -1) {
204        return -1;
205    }
206
207    io_hook = V3_Malloc(sizeof(struct dev_io_hook));
208
209    if (io_hook == NULL) {
210        PrintError("Could not allocate io hook dev state\n");
211        return -1;
212    }
213
214    io_hook->port = port;
215    list_add(&(io_hook->node), &(dev->io_hooks));
216
217    return 0;
218 }
219
220
221 int v3_dev_unhook_io(struct vm_device * dev, uint16_t port) {
222     struct dev_io_hook * io_hook = NULL;
223     struct dev_io_hook * tmp;
224
225     list_for_each_entry_safe(io_hook, tmp, &(dev->io_hooks), node) {
226         if (io_hook->port == port) {
227
228             list_del(&(io_hook->node));
229             V3_Free(io_hook);
230             
231             return v3_unhook_io_port(dev->vm, port);        
232         }
233     }
234
235     return -1;
236 }
237
238
239
240 int v3_remove_device(struct vm_device * dev) {
241     struct vmm_dev_mgr * mgr = &(dev->vm->dev_mgr);
242     struct dev_io_hook * io_hook = NULL;
243     struct dev_io_hook * tmp;
244
245     list_for_each_entry_safe(io_hook, tmp, &(dev->io_hooks), node) {
246         v3_unhook_io_port(dev->vm, io_hook->port);          
247         list_del(&(io_hook->node));
248         V3_Free(io_hook);    
249     }
250
251     if (dev->ops->free) {
252         dev->ops->free(dev->private_data);
253     } else {
254         PrintError("Error: %s free() not implemented\n",  dev->name);
255     }
256
257     list_del(&(dev->dev_link));
258     mgr->num_devs--;
259
260     dev->vm = NULL;
261
262     V3_Free(dev);
263     return -1;
264 }
265
266
267 struct vm_device * v3_add_device(struct v3_vm_info * vm,
268                                  char * name, 
269                                  struct v3_device_ops * ops, 
270                                  void * private_data) {
271     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
272     struct vm_device * dev = NULL;
273
274     dev = (struct vm_device *)V3_Malloc(sizeof(struct vm_device));
275
276     if (dev == NULL) {
277         return NULL;
278     }
279
280     INIT_LIST_HEAD(&(dev->io_hooks));
281
282     strncpy(dev->name, name, 32);
283     dev->ops = ops;
284     dev->private_data = private_data;
285
286     dev->vm = vm;
287
288     list_add(&(dev->dev_link), &(mgr->dev_list));
289     mgr->num_devs++;
290
291     v3_htable_insert(mgr->dev_table, (addr_t)(dev->name), (addr_t)dev);
292
293     return dev;
294 }
295
296
297 void v3_print_dev_mgr(struct v3_vm_info * vm) {
298     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
299     struct vm_device * dev;
300
301     V3_Print("%d devices registered with manager\n", mgr->num_devs);
302
303     list_for_each_entry(dev, &(mgr->dev_list), dev_link) {
304         V3_Print("Device: %s\n", dev->name);
305     }
306
307     return;
308 }
309
310
311
312
313 struct blk_frontend {
314     int (*connect)(struct v3_vm_info * vm, 
315                     void * frontend_data, 
316                     struct v3_dev_blk_ops * ops, 
317                     v3_cfg_tree_t * cfg, 
318                     void * priv_data);
319         
320
321     struct list_head blk_node;
322
323     void * priv_data;
324 };
325
326
327
328 int v3_dev_add_blk_frontend(struct v3_vm_info * vm, 
329                             char * name, 
330                             int (*connect)(struct v3_vm_info * vm, 
331                                             void * frontend_data, 
332                                             struct v3_dev_blk_ops * ops, 
333                                             v3_cfg_tree_t * cfg, 
334                                             void * priv_data), 
335                             void * priv_data) {
336
337     struct blk_frontend * frontend = NULL;
338
339     frontend = (struct blk_frontend *)V3_Malloc(sizeof(struct blk_frontend));
340     memset(frontend, 0, sizeof(struct blk_frontend));
341     
342     frontend->connect = connect;
343     frontend->priv_data = priv_data;
344         
345     list_add(&(frontend->blk_node), &(vm->dev_mgr.blk_list));
346     v3_htable_insert(vm->dev_mgr.blk_table, (addr_t)(name), (addr_t)frontend);
347
348     return 0;
349 }
350
351 int v3_dev_connect_blk(struct v3_vm_info * vm, 
352                        char * frontend_name, 
353                        struct v3_dev_blk_ops * ops, 
354                        v3_cfg_tree_t * cfg, 
355                        void * private_data) {
356
357     struct blk_frontend * frontend = NULL;
358
359     frontend = (struct blk_frontend *)v3_htable_search(vm->dev_mgr.blk_table,
360                                                        (addr_t)frontend_name);
361     
362     if (frontend == NULL) {
363         PrintError("Could not find frontend blk device %s\n", frontend_name);
364         return 0;
365     }
366
367     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
368         PrintError("Error connecting to block frontend %s\n", frontend_name);
369         return -1;
370     }
371
372     return 0;
373 }
374
375
376
377 struct net_frontend {
378     int (*connect)(struct v3_vm_info * vm, 
379                     void * frontend_data, 
380                     struct v3_dev_net_ops * ops, 
381                     v3_cfg_tree_t * cfg, 
382                     void * priv_data);
383     
384
385     struct list_head net_node;
386
387     void * priv_data;
388 };
389
390
391 int v3_dev_add_net_frontend(struct v3_vm_info * vm, 
392                             char * name, 
393                             int (*connect)(struct v3_vm_info * vm, 
394                                             void * frontend_data, 
395                                             struct v3_dev_net_ops * ops, 
396                                             v3_cfg_tree_t * cfg, 
397                                             void * private_data), 
398                             void * priv_data)
399 {
400     struct net_frontend * frontend = NULL;
401
402     frontend = (struct net_frontend *)V3_Malloc(sizeof(struct net_frontend));
403     memset(frontend, 0, sizeof(struct net_frontend));
404     
405     frontend->connect = connect;
406     frontend->priv_data = priv_data;
407         
408     list_add(&(frontend->net_node), &(vm->dev_mgr.net_list));
409     v3_htable_insert(vm->dev_mgr.net_table, (addr_t)(name), (addr_t)frontend);
410
411     return 0;
412 }
413
414
415 int v3_dev_connect_net(struct v3_vm_info * vm, 
416                        char * frontend_name, 
417                        struct v3_dev_net_ops * ops, 
418                        v3_cfg_tree_t * cfg, 
419                        void * private_data)
420 {
421     struct net_frontend * frontend = NULL;
422
423     frontend = (struct net_frontend *)v3_htable_search(vm->dev_mgr.net_table,
424                                                        (addr_t)frontend_name);
425     
426     if (frontend == NULL) {
427         PrintError("Could not find frontend net device %s\n", frontend_name);
428         return 0;
429     }
430
431     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
432         PrintError("Error connecting to net frontend %s\n", frontend_name);
433         return -1;
434     }
435
436     return 0;
437 }
438
439
440 struct cons_frontend {
441     int (*connect)(struct v3_vm_info * vm, 
442                    void * frontend_data, 
443                    struct v3_dev_console_ops * ops, 
444                    v3_cfg_tree_t * cfg, 
445                    void * priv_data);
446     
447
448     struct list_head cons_node;
449
450     void * priv_data;
451 };
452
453 int v3_dev_add_console_frontend(struct v3_vm_info * vm, 
454                                 char * name, 
455                                 int (*connect)(struct v3_vm_info * vm, 
456                                                void * frontend_data, 
457                                                struct v3_dev_console_ops * ops, 
458                                                v3_cfg_tree_t * cfg, 
459                                                void * private_data), 
460                                 void * priv_data)
461 {
462     struct cons_frontend * frontend = NULL;
463
464     frontend = (struct cons_frontend *)V3_Malloc(sizeof(struct cons_frontend));
465     memset(frontend, 0, sizeof(struct cons_frontend));
466     
467     frontend->connect = connect;
468     frontend->priv_data = priv_data;
469         
470     list_add(&(frontend->cons_node), &(vm->dev_mgr.cons_list));
471     v3_htable_insert(vm->dev_mgr.cons_table, (addr_t)(name), (addr_t)frontend);
472
473     return 0;
474 }
475
476
477 int v3_dev_connect_console(struct v3_vm_info * vm, 
478                            char * frontend_name, 
479                            struct v3_dev_console_ops * ops, 
480                            v3_cfg_tree_t * cfg, 
481                            void * private_data)
482 {
483     struct cons_frontend * frontend = NULL;
484
485     frontend = (struct cons_frontend *)v3_htable_search(vm->dev_mgr.cons_table,
486                                                         (addr_t)frontend_name);
487     
488     if (frontend == NULL) {
489         PrintError("Could not find frontend console device %s\n", frontend_name);
490         return 0;
491     }
492     
493     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
494         PrintError("Error connecting to console frontend %s\n", frontend_name);
495         return -1;
496     }
497
498     return 0;
499 }
500
501 struct char_frontend {
502     int (*connect)(struct v3_vm_info * vm, 
503                    void * frontend_data, 
504                    struct v3_dev_char_ops * ops, 
505                    v3_cfg_tree_t * cfg, 
506                    void * priv_data, 
507                    void ** push_fn_arg);
508     
509
510     struct list_head char_node;
511
512     void * priv_data;
513 };
514
515 int v3_dev_add_char_frontend(struct v3_vm_info * vm, 
516                              char * name, 
517                              int (*connect)(struct v3_vm_info * vm, 
518                                             void * frontend_data, 
519                                             struct v3_dev_char_ops * ops, 
520                                             v3_cfg_tree_t * cfg, 
521                                             void * private_data, 
522                                             void ** push_fn_arg), 
523                              void * priv_data)
524 {
525     struct char_frontend * frontend = NULL;
526
527     frontend = (struct char_frontend *)V3_Malloc(sizeof(struct char_frontend));
528     memset(frontend, 0, sizeof(struct char_frontend));
529     
530     frontend->connect = connect;
531     frontend->priv_data = priv_data;
532         
533     list_add(&(frontend->char_node), &(vm->dev_mgr.char_list));
534     v3_htable_insert(vm->dev_mgr.char_table, (addr_t)(name), (addr_t)frontend);
535
536     return 0;
537 }
538
539
540 int v3_dev_connect_char(struct v3_vm_info * vm, 
541                         char * frontend_name, 
542                         struct v3_dev_char_ops * ops, 
543                         v3_cfg_tree_t * cfg, 
544                         void * private_data, 
545                         void ** push_fn_arg)
546 {
547     struct char_frontend * frontend = NULL;
548
549     frontend = (struct char_frontend *)v3_htable_search(vm->dev_mgr.char_table,
550                                                         (addr_t)frontend_name);
551     
552     if (frontend == NULL) {
553         PrintError("Could not find frontend char device %s\n", frontend_name);
554         return 0;
555     }
556     
557     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data, push_fn_arg) == -1) {
558         PrintError("Error connecting to char frontend %s\n", frontend_name);
559         return -1;
560     }
561
562     return 0;
563 }
564
565
566
567 static int free_frontends(struct v3_vm_info * vm, struct vmm_dev_mgr * mgr) {
568     struct char_frontend * chr = NULL;
569     struct char_frontend * tmp_chr = NULL;
570     struct cons_frontend * cons = NULL;
571     struct cons_frontend * tmp_cons = NULL;
572     struct net_frontend * net = NULL;
573     struct net_frontend * tmp_net = NULL;
574     struct blk_frontend * blk = NULL;
575     struct blk_frontend * tmp_blk = NULL;
576
577
578
579     list_for_each_entry_safe(chr, tmp_chr, &(mgr->char_list), char_node) {
580         list_del(&(chr->char_node));
581         V3_Free(chr);
582     }
583
584     list_for_each_entry_safe(cons, tmp_cons, &(mgr->cons_list), cons_node) {
585         list_del(&(cons->cons_node));
586         V3_Free(cons);
587     }
588
589     list_for_each_entry_safe(net, tmp_net, &(mgr->net_list), net_node) {
590         list_del(&(net->net_node));
591         V3_Free(net);
592     }
593
594     list_for_each_entry_safe(blk, tmp_blk, &(mgr->blk_list), blk_node) {
595         list_del(&(blk->blk_node));
596         V3_Free(blk);
597     }
598
599     v3_free_htable(mgr->blk_table, 0, 0);
600     v3_free_htable(mgr->net_table, 0, 0);
601     v3_free_htable(mgr->char_table, 0, 0);
602     v3_free_htable(mgr->cons_table, 0, 0);
603
604
605     return 0;
606 }