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.


ec78bb9517e0ed6998f57c460cb0e209f052372f
[palacios.git] / palacios / src / devices / generic.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, Peter Dinda <pdinda@northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Peter Dinda <pdinda@northwestern.edu>
15  * Contributor: 2008, Jack Lange <jarusl@cs.northwestern.edu>
16  *        
17  *
18  * This is free software.  You are permitted to use,
19  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
20  */
21
22 #include <palacios/vmm.h>
23 #include <palacios/vmm_types.h>
24 #include <palacios/vmm_list.h>
25 #include <palacios/vmm_io.h>
26 #include <palacios/vmm_dev_mgr.h>
27
28 #ifndef CONFIG_DEBUG_GENERIC
29 #undef PrintDebug
30 #define PrintDebug(fmt, args...)
31 #endif
32
33
34 typedef enum {GENERIC_IGNORE, 
35               GENERIC_PASSTHROUGH, 
36               GENERIC_PRINT_AND_PASSTHROUGH, 
37               GENERIC_PRINT_AND_IGNORE} generic_mode_t;
38
39 struct generic_internal {
40     struct list_head port_list;
41     uint_t num_port_ranges;
42
43 };
44
45
46 struct port_range {
47     uint_t start;
48     uint_t end;
49     generic_mode_t mode;
50     struct list_head range_link;
51 };
52
53
54
55
56
57 static int generic_write_port_passthrough(struct guest_info * core, uint16_t port, void * src, 
58                                           uint_t length, void * priv_data) {
59     uint_t i;
60
61     PrintDebug("generic: writing 0x");
62
63     for (i = 0; i < length; i++) { 
64         PrintDebug("%x", ((uint8_t *)src)[i]);
65     }
66   
67     PrintDebug(" to port 0x%x ... ", port);
68
69     switch (length) {
70         case 1:
71             v3_outb(port, ((uint8_t *)src)[0]);
72             break;
73         case 2:
74             v3_outw(port, ((uint16_t *)src)[0]);
75             break;
76         case 4:
77             v3_outdw(port, ((uint32_t *)src)[0]);
78             break;
79         default:
80             for (i = 0; i < length; i++) { 
81                 v3_outb(port, ((uint8_t *)src)[i]);
82             }
83     }
84
85     PrintDebug(" done\n");
86   
87     return length;
88 }
89
90 static int generic_read_port_passthrough(struct guest_info * core, uint16_t port, void * src, 
91                                          uint_t length, void * priv_data) {
92     uint_t i;
93
94     PrintDebug("generic: reading 0x%x bytes from port 0x%x ...", length, port);
95
96
97     switch (length) {
98         case 1:
99             ((uint8_t *)src)[0] = v3_inb(port);
100             break;
101         case 2:
102             ((uint16_t *)src)[0] = v3_inw(port);
103             break;
104         case 4:
105             ((uint32_t *)src)[0] = v3_indw(port);
106             break;
107         default:
108             for (i = 0; i < length; i++) { 
109                 ((uint8_t *)src)[i] = v3_inb(port);
110             }
111     }
112
113     PrintDebug(" done ... read 0x");
114
115     for (i = 0; i < length; i++) { 
116         PrintDebug("%x", ((uint8_t *)src)[i]);
117     }
118
119     PrintDebug("\n");
120
121     return length;
122 }
123
124 static int generic_write_port_ignore(struct guest_info * core, uint16_t port, void * src, 
125                                      uint_t length, void * priv_data) {
126     int i;
127
128     PrintDebug("generic: writing 0x");
129
130     for (i = 0; i < length; i++) { 
131         PrintDebug("%x", ((uint8_t *)src)[i]);
132     }
133   
134     PrintDebug(" to port 0x%x ... ignored\n", port);
135  
136     return length;
137 }
138
139 static int generic_read_port_ignore(struct guest_info * core, uint16_t port, void * src, 
140                                     uint_t length, void * priv_data) {
141
142     PrintDebug("generic: reading 0x%x bytes from port 0x%x ...", length, port);
143
144     memset((uint8_t *)src, 0, length);
145     PrintDebug(" ignored (return zeroed buffer)\n");
146
147     return length;
148 }
149
150
151
152
153
154 static int generic_free(struct vm_device * dev) {
155     struct generic_internal * state = (struct generic_internal *)(dev->private_data);
156     struct port_range * tmp;
157     struct port_range * cur;
158
159     PrintDebug("generic: deinit_device\n");
160
161     list_for_each_entry_safe(cur, tmp, &(state->port_list), range_link) {
162         uint_t i;
163
164         PrintDebug("generic: unhooking ports 0x%x to 0x%x\n",
165                    cur->start, cur->end);
166         
167         for (i = cur->start; i <= cur->end; i++) {
168             if (v3_unhook_io_port(dev->vm, i)) {
169                 PrintDebug("generic: can't unhook port 0x%x (already unhooked?)\n", i);
170             }
171         }
172
173         list_del(&(cur->range_link));
174         state->num_port_ranges--;
175         V3_Free(cur);
176     }
177
178     V3_Free(state);
179     return 0;
180 }
181
182
183
184
185
186 static struct v3_device_ops dev_ops = { 
187     .free = generic_free, 
188 };
189
190
191
192
193 static int add_port_range(struct vm_device * dev, uint_t start, uint_t end, generic_mode_t mode) {
194     struct generic_internal * state = (struct generic_internal *)(dev->private_data);
195     struct port_range * range = (struct port_range *)V3_Malloc(sizeof(struct port_range));
196     uint_t i = 0;
197
198     range->start = start;
199     range->end = end;
200     range->mode = mode;
201       
202     PrintDebug("generic: Adding Port Range: 0x%x to 0x%x as %s\n", 
203                start, end, 
204                (mode == GENERIC_PRINT_AND_PASSTHROUGH) ? "print-and-passthrough" : "print-and-ignore");
205     
206     for (i = start; i <= end; i++) { 
207         if (mode == GENERIC_PRINT_AND_PASSTHROUGH) { 
208             if (v3_hook_io_port(dev->vm, i, 
209                                 &generic_read_port_passthrough, 
210                                 &generic_write_port_passthrough, dev) == -1) { 
211                 PrintError("generic: can't hook port 0x%x (already hooked?)\n", i);
212                 return -1;
213             }
214         } else if (mode == GENERIC_PRINT_AND_IGNORE) { 
215             if (v3_hook_io_port(dev->vm, i, 
216                                 &generic_read_port_ignore, 
217                                 &generic_write_port_ignore, dev) == -1) { 
218                 PrintError("generic: can't hook port 0x%x (already hooked?)\n", i);
219                 return -1;
220             }
221         } 
222     }
223
224     list_add(&(range->range_link), &(state->port_list));
225     state->num_port_ranges++;
226     
227     return 0;
228 }
229
230
231
232
233
234 static int generic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
235     struct generic_internal * state = NULL;
236     char * dev_id = v3_cfg_val(cfg, "ID");
237     v3_cfg_tree_t * port_cfg = v3_cfg_subtree(cfg, "ports");
238
239
240     state = (struct generic_internal *)V3_Malloc(sizeof(struct generic_internal));
241
242     if (state == NULL) {
243         PrintError("Could not allocate generic state\n");
244         return -1;
245     }
246     
247     memset(state, 0, sizeof(struct generic_internal));
248
249     INIT_LIST_HEAD(&(state->port_list));
250     state->num_port_ranges = 0;
251     
252     struct vm_device * dev = v3_allocate_device(dev_id, &dev_ops, state);
253
254     if (v3_attach_device(vm, dev) == -1) {
255         PrintError("Could not attach device %s\n", dev_id);
256         V3_Free(state);
257         return -1;
258     }
259
260     PrintDebug("generic: init_device\n");
261
262     // scan port list....
263     while (port_cfg) {
264         uint16_t start = atox(v3_cfg_val(port_cfg, "start"));
265         uint16_t end = atox(v3_cfg_val(port_cfg, "end"));
266         char * mode_str = v3_cfg_val(port_cfg, "mode");
267         generic_mode_t mode = GENERIC_IGNORE;
268
269         if (strcasecmp(mode_str, "print_and_ignore") == 0) {
270             mode = GENERIC_PRINT_AND_IGNORE;
271         } else if (strcasecmp(mode_str, "print_and_passthrough") == 0) {
272             mode = GENERIC_PRINT_AND_PASSTHROUGH;
273         } else {
274             PrintError("Invalid Mode %s\n", mode_str);
275             v3_detach_device(dev);
276             return -1;
277         }
278         
279         if (add_port_range(dev, start, end, mode) == -1) {
280             PrintError("Could not add port range %d-%d\n", start, end);
281             v3_detach_device(dev);
282             return -1;
283         }
284
285         port_cfg = v3_cfg_next_branch(port_cfg);
286     }
287
288
289     return 0;
290 }
291
292 device_register("GENERIC", generic_init)