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 char device operations to device manager
[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
122     /* TODO: Clear hash tables */
123
124     return 0;
125 }
126
127 /*
128 int v3_init_core_dev_mgr(struct v3_vm_info * vm) {
129     struct v3_core_dev_mgr * mgr = &(vm->core_dev_mgr);
130
131     INIT_LIST_HEAD(&(mgr->dev_list));
132     mgr->dev_table = v3_create_htable(0, dev_hash_fn, dev_eq_fn);
133
134     return 0;
135 }
136
137 int v3_core_dev_mgr_deinit(struct v3_vm_info * vm) {
138     struct vm_device * dev;
139     struct v3_core_dev_mgr * mgr = &(vm->core_dev_mgr);
140     struct vm_device * tmp;
141
142     list_for_each_entry_safe(dev, tmp, &(mgr->dev_list), dev_link) {
143         v3_detach_device(dev);
144         v3_free_device(dev);
145     }
146
147     // TODO: Clear hash tables 
148
149 }
150 */
151
152
153 int v3_create_device(struct v3_vm_info * vm, const char * dev_name, v3_cfg_tree_t * cfg) {
154     int (*dev_init)(struct v3_vm_info * vm, void * cfg_data);
155
156     dev_init = (void *)v3_htable_search(master_dev_table, (addr_t)dev_name);
157
158     if (dev_init == NULL) {
159         PrintError("Could not find device %s in master device table\n", dev_name);
160         return -1;
161     }
162
163
164     if (dev_init(vm, cfg) == -1) {
165         PrintError("Could not initialize Device %s\n", dev_name);
166         return -1;
167     }
168
169     return 0;
170 }
171
172
173 void v3_free_device(struct vm_device * dev) {
174     V3_Free(dev);
175 }
176
177
178
179 struct vm_device * v3_find_dev(struct v3_vm_info * vm, const char * dev_name) {
180     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
181
182     if (!dev_name) {
183         return NULL;
184     }
185
186     return (struct vm_device *)v3_htable_search(mgr->dev_table, (addr_t)dev_name);
187 }
188
189
190 /****************************************************************/
191 /* The remaining functions are called by the devices themselves */
192 /****************************************************************/
193
194 /* IO HOOKS */
195 int v3_dev_hook_io(struct vm_device * dev, uint16_t port,
196                    int (*read)(struct guest_info * core, uint16_t port, void * dst, uint_t length, struct vm_device * dev),
197                    int (*write)(struct guest_info * core, uint16_t port, void * src, uint_t length, struct vm_device * dev)) {
198     return 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);
202 }
203
204
205 int v3_dev_unhook_io(struct vm_device * dev, uint16_t port) {
206     return v3_unhook_io_port(dev->vm, port);
207 }
208
209
210
211 int v3_detach_device(struct vm_device * dev) {
212     struct vmm_dev_mgr * mgr = &(dev->vm->dev_mgr);
213
214     dev->ops->free(dev);
215
216     list_del(&(dev->dev_link));
217     mgr->num_devs--;
218
219     dev->vm = NULL;
220
221     return -1;
222 }
223
224
225 struct vm_device * v3_allocate_device(char * name, 
226                                       struct v3_device_ops * ops, 
227                                       void * private_data) {
228     struct vm_device * dev = NULL;
229
230     dev = (struct vm_device*)V3_Malloc(sizeof(struct vm_device));
231
232     strncpy(dev->name, name, 32);
233     dev->ops = ops;
234     dev->private_data = private_data;
235
236     dev->vm = NULL;
237
238     return dev;
239 }
240
241
242 int v3_attach_device(struct v3_vm_info * vm, struct vm_device * dev ) {
243     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
244
245     dev->vm = vm;
246
247     list_add(&(dev->dev_link), &(mgr->dev_list));
248     mgr->num_devs++;
249
250
251     v3_htable_insert(mgr->dev_table, (addr_t)(dev->name), (addr_t)dev);
252
253     return 0;
254 }
255
256
257
258 void v3_print_dev_mgr(struct v3_vm_info * vm) {
259     struct vmm_dev_mgr * mgr = &(vm->dev_mgr);
260     struct vm_device * dev;
261
262     V3_Print("%d devices registered with manager\n", mgr->num_devs);
263
264     list_for_each_entry(dev, &(mgr->dev_list), dev_link) {
265         V3_Print("Device: %s\n", dev->name);
266     }
267
268     return;
269 }
270
271
272
273
274 struct blk_frontend {
275     int (*connect)(struct v3_vm_info * vm, 
276                     void * frontend_data, 
277                     struct v3_dev_blk_ops * ops, 
278                     v3_cfg_tree_t * cfg, 
279                     void * priv_data);
280         
281
282     struct list_head blk_node;
283
284     void * priv_data;
285 };
286
287
288
289 int v3_dev_add_blk_frontend(struct v3_vm_info * vm, 
290                             char * name, 
291                             int (*connect)(struct v3_vm_info * vm, 
292                                             void * frontend_data, 
293                                             struct v3_dev_blk_ops * ops, 
294                                             v3_cfg_tree_t * cfg, 
295                                             void * priv_data), 
296                             void * priv_data) {
297
298     struct blk_frontend * frontend = NULL;
299
300     frontend = (struct blk_frontend *)V3_Malloc(sizeof(struct blk_frontend));
301     memset(frontend, 0, sizeof(struct blk_frontend));
302     
303     frontend->connect = connect;
304     frontend->priv_data = priv_data;
305         
306     list_add(&(frontend->blk_node), &(vm->dev_mgr.blk_list));
307     v3_htable_insert(vm->dev_mgr.blk_table, (addr_t)(name), (addr_t)frontend);
308
309     return 0;
310 }
311
312 int v3_dev_connect_blk(struct v3_vm_info * vm, 
313                        char * frontend_name, 
314                        struct v3_dev_blk_ops * ops, 
315                        v3_cfg_tree_t * cfg, 
316                        void * private_data) {
317
318     struct blk_frontend * frontend = NULL;
319
320     frontend = (struct blk_frontend *)v3_htable_search(vm->dev_mgr.blk_table,
321                                                        (addr_t)frontend_name);
322     
323     if (frontend == NULL) {
324         PrintError("Could not find frontend blk device %s\n", frontend_name);
325         return 0;
326     }
327
328     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
329         PrintError("Error connecting to block frontend %s\n", frontend_name);
330         return -1;
331     }
332
333     return 0;
334 }
335
336
337
338 struct net_frontend {
339     int (*connect)(struct v3_vm_info * vm, 
340                     void * frontend_data, 
341                     struct v3_dev_net_ops * ops, 
342                     v3_cfg_tree_t * cfg, 
343                     void * priv_data);
344     
345
346     struct list_head net_node;
347
348     void * priv_data;
349 };
350
351
352 int v3_dev_add_net_frontend(struct v3_vm_info * vm, 
353                             char * name, 
354                             int (*connect)(struct v3_vm_info * vm, 
355                                             void * frontend_data, 
356                                             struct v3_dev_net_ops * ops, 
357                                             v3_cfg_tree_t * cfg, 
358                                             void * private_data), 
359                             void * priv_data)
360 {
361     struct net_frontend * frontend = NULL;
362
363     frontend = (struct net_frontend *)V3_Malloc(sizeof(struct net_frontend));
364     memset(frontend, 0, sizeof(struct net_frontend));
365     
366     frontend->connect = connect;
367     frontend->priv_data = priv_data;
368         
369     list_add(&(frontend->net_node), &(vm->dev_mgr.net_list));
370     v3_htable_insert(vm->dev_mgr.net_table, (addr_t)(name), (addr_t)frontend);
371
372     return 0;
373 }
374
375
376 int v3_dev_connect_net(struct v3_vm_info * vm, 
377                        char * frontend_name, 
378                        struct v3_dev_net_ops * ops, 
379                        v3_cfg_tree_t * cfg, 
380                        void * private_data)
381 {
382     struct net_frontend * frontend = NULL;
383
384     frontend = (struct net_frontend *)v3_htable_search(vm->dev_mgr.net_table,
385                                                        (addr_t)frontend_name);
386     
387     if (frontend == NULL) {
388         PrintError("Could not find frontend net device %s\n", frontend_name);
389         return 0;
390     }
391
392     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data) == -1) {
393         PrintError("Error connecting to net frontend %s\n", frontend_name);
394         return -1;
395     }
396
397     return 0;
398 }
399
400
401 struct char_frontend {
402     int (*connect)(struct v3_vm_info * vm, 
403                    void * frontend_data, 
404                    struct v3_dev_char_ops * ops, 
405                    v3_cfg_tree_t * cfg, 
406                    void * priv_data, 
407                    void ** push_fn_arg);
408     
409
410     struct list_head char_node;
411
412     void * priv_data;
413 };
414
415
416
417 int v3_dev_add_char_frontend(struct v3_vm_info * vm, 
418                              char * name, 
419                              int (*connect)(struct v3_vm_info * vm, 
420                                             void * frontend_data, 
421                                             struct v3_dev_char_ops * ops, 
422                                             v3_cfg_tree_t * cfg, 
423                                             void * private_data, 
424                                             void ** push_fn_arg), 
425                              void * priv_data)
426 {
427     struct char_frontend * frontend = NULL;
428
429     frontend = (struct char_frontend *)V3_Malloc(sizeof(struct char_frontend));
430     memset(frontend, 0, sizeof(struct char_frontend));
431     
432     frontend->connect = connect;
433     frontend->priv_data = priv_data;
434         
435     list_add(&(frontend->char_node), &(vm->dev_mgr.char_list));
436     v3_htable_insert(vm->dev_mgr.char_table, (addr_t)(name), (addr_t)frontend);
437
438     return 0;
439 }
440
441
442 int v3_dev_connect_char(struct v3_vm_info * vm, 
443                         char * frontend_name, 
444                         struct v3_dev_char_ops * ops, 
445                         v3_cfg_tree_t * cfg, 
446                         void * private_data, 
447                         void ** push_fn_arg)
448 {
449     struct char_frontend * frontend = NULL;
450
451     frontend = (struct char_frontend *)v3_htable_search(vm->dev_mgr.char_table,
452                                                         (addr_t)frontend_name);
453     
454     if (frontend == NULL) {
455         PrintError("Could not find frontend char device %s\n", frontend_name);
456         return 0;
457     }
458     
459     if (frontend->connect(vm, frontend->priv_data, ops, cfg, private_data, push_fn_arg) == -1) {
460         PrintError("Error connecting to char frontend %s\n", frontend_name);
461         return -1;
462     }
463
464     return 0;
465 }
466