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.


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