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.


reworked device IO hook framework
[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     }
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->console_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 char_frontend {
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 * priv_data, 
432                    void ** push_fn_arg);
433     
434
435     struct list_head char_node;
436
437     void * priv_data;
438 };
439
440
441
442 int v3_dev_add_char_frontend(struct v3_vm_info * vm, 
443                              char * name, 
444                              int (*connect)(struct v3_vm_info * vm, 
445                                             void * frontend_data, 
446                                             struct v3_dev_char_ops * ops, 
447                                             v3_cfg_tree_t * cfg, 
448                                             void * private_data, 
449                                             void ** push_fn_arg), 
450                              void * priv_data)
451 {
452     struct char_frontend * frontend = NULL;
453
454     frontend = (struct char_frontend *)V3_Malloc(sizeof(struct char_frontend));
455     memset(frontend, 0, sizeof(struct char_frontend));
456     
457     frontend->connect = connect;
458     frontend->priv_data = priv_data;
459         
460     list_add(&(frontend->char_node), &(vm->dev_mgr.char_list));
461     v3_htable_insert(vm->dev_mgr.char_table, (addr_t)(name), (addr_t)frontend);
462
463     return 0;
464 }
465
466
467 int v3_dev_connect_char(struct v3_vm_info * vm, 
468                         char * frontend_name, 
469                         struct v3_dev_char_ops * ops, 
470                         v3_cfg_tree_t * cfg, 
471                         void * private_data, 
472                         void ** push_fn_arg)
473 {
474     struct char_frontend * frontend = NULL;
475
476     frontend = (struct char_frontend *)v3_htable_search(vm->dev_mgr.char_table,
477                                                         (addr_t)frontend_name);
478     
479     if (frontend == NULL) {
480         PrintError("Could not find frontend char device %s\n", frontend_name);
481         return 0;
482     }
483     
484     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data, push_fn_arg) == -1) {
485         PrintError("Error connecting to char frontend %s\n", frontend_name);
486         return -1;
487     }
488
489     return 0;
490 }
491