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.


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