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.


b7d1a181001368de960bf16ee7e17a680bb2341a
[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 };
41
42
43
44
45 static int generic_write_port_passthrough(struct guest_info * core, uint16_t port, void * src, 
46                                           uint_t length, void * priv_data) {
47     uint_t i;
48
49     switch (length) {
50         case 1:
51             v3_outb(port, ((uint8_t *)src)[0]);
52             break;
53         case 2:
54             v3_outw(port, ((uint16_t *)src)[0]);
55             break;
56         case 4:
57             v3_outdw(port, ((uint32_t *)src)[0]);
58             break;
59         default:
60             for (i = 0; i < length; i++) { 
61                 v3_outb(port, ((uint8_t *)src)[i]);
62             }
63     }
64
65     return length;
66 }
67
68 static int generic_write_port_print_and_passthrough(struct guest_info * core, uint16_t port, void * src, 
69                                                     uint_t length, void * priv_data) {
70     uint_t i;
71     int rc;
72
73     PrintDebug("generic: writing 0x");
74
75     for (i = 0; i < length; i++) { 
76         PrintDebug("%x", ((uint8_t *)src)[i]);
77     }
78   
79     PrintDebug(" to port 0x%x ... ", port);
80
81     rc=generic_write_port_passthrough(core,port,src,length,priv_data);
82
83     PrintDebug(" done\n");
84   
85     return rc;
86 }
87
88 static int generic_read_port_passthrough(struct guest_info * core, uint16_t port, void * src, 
89                                          uint_t length, void * priv_data) {
90     uint_t i;
91
92     switch (length) {
93         case 1:
94             ((uint8_t *)src)[0] = v3_inb(port);
95             break;
96         case 2:
97             ((uint16_t *)src)[0] = v3_inw(port);
98             break;
99         case 4:
100             ((uint32_t *)src)[0] = v3_indw(port);
101             break;
102         default:
103             for (i = 0; i < length; i++) { 
104                 ((uint8_t *)src)[i] = v3_inb(port);
105             }
106     }
107
108     return length;
109 }
110
111 static int generic_read_port_print_and_passthrough(struct guest_info * core, uint16_t port, void * src, 
112                                                    uint_t length, void * priv_data) {
113     uint_t i;
114     int rc;
115     
116     PrintDebug("generic: reading 0x%x bytes from port 0x%x ...", length, port);
117
118
119     rc=generic_read_port_passthrough(core,port,src,length,priv_data);
120
121     PrintDebug(" done ... read 0x");
122
123     for (i = 0; i < rc; i++) { 
124         PrintDebug("%x", ((uint8_t *)src)[i]);
125     }
126
127     PrintDebug("\n");
128
129     return rc;
130 }
131
132
133 static int generic_read_port_ignore(struct guest_info * core, uint16_t port, void * src, 
134                                     uint_t length, void * priv_data) {
135
136     memset((uint8_t *)src, 0, length);
137
138     return length;
139 }
140
141 static int generic_read_port_print_and_ignore(struct guest_info * core, uint16_t port, void * src, 
142                                               uint_t length, void * priv_data) {
143    
144     PrintDebug("generic: reading 0x%x bytes from port 0x%x ...", length, port);
145
146     memset((uint8_t *)src, 0, length);
147     PrintDebug(" ignored (return zeroed buffer)\n");
148
149     return length;
150 }
151
152 static int generic_write_port_ignore(struct guest_info * core, uint16_t port, void * src, 
153                                      uint_t length, void * priv_data) {
154
155     return length;
156 }
157
158 static int generic_write_port_print_and_ignore(struct guest_info * core, uint16_t port, void * src, 
159                                               uint_t length, void * priv_data) {
160     int i;
161
162     PrintDebug("generic: writing 0x%x bytes to port 0x%x ", length, port);
163
164     memset((uint8_t *)src, 0, length);
165     PrintDebug(" ignored - data was: 0x");
166
167     for (i = 0; i < length; i++) { 
168         PrintDebug("%x", ((uint8_t *)src)[i]);
169     }
170     
171     PrintDebug("\n");
172
173     return length;
174 }
175
176
177
178
179 static int generic_free(struct generic_internal * state) {
180     PrintDebug("generic: deinit_device\n");
181
182     V3_Free(state);
183     return 0;
184 }
185
186
187
188
189
190 static struct v3_device_ops dev_ops = { 
191     .free = (int (*)(void *))generic_free, 
192 };
193
194
195
196
197 static int add_port_range(struct vm_device * dev, uint_t start, uint_t end, generic_mode_t mode) {
198     uint_t i = 0;
199
200     PrintDebug("generic: Adding Port Range: 0x%x to 0x%x as %s\n", 
201                start, end, 
202                (mode == GENERIC_PRINT_AND_PASSTHROUGH) ? "print-and-passthrough" : "print-and-ignore");
203     
204     for (i = start; i <= end; i++) { 
205         if (mode == GENERIC_PRINT_AND_PASSTHROUGH) { 
206             if (v3_dev_hook_io(dev, i, 
207                                 &generic_read_port_print_and_passthrough, 
208                                 &generic_write_port_print_and_passthrough) == -1) { 
209                 PrintError("generic: can't hook port 0x%x (already hooked?)\n", i);
210                 return -1;
211             }
212         } else if (mode == GENERIC_PRINT_AND_IGNORE) { 
213             if (v3_dev_hook_io(dev, i, 
214                                 &generic_read_port_print_and_ignore, 
215                                 &generic_write_port_print_and_ignore) == -1) { 
216                 PrintError("generic: can't hook port 0x%x (already hooked?)\n", i);
217                 return -1;
218             }
219         } else if (mode == GENERIC_PASSTHROUGH) { 
220             if (v3_dev_hook_io(dev, i, 
221                                 &generic_read_port_passthrough, 
222                                 &generic_write_port_passthrough) == -1) { 
223                 PrintError("generic: can't hook port 0x%x (already hooked?)\n", i);
224                 return -1;
225             }
226         } else if (mode == GENERIC_IGNORE) { 
227             if (v3_dev_hook_io(dev, i, 
228                                 &generic_read_port_ignore, 
229                                 &generic_write_port_ignore) == -1) { 
230                 PrintError("generic: can't hook port 0x%x (already hooked?)\n", i);
231                 return -1;
232             }
233         } 
234     }
235     
236     return 0;
237 }
238
239
240
241
242
243 static int generic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
244     struct generic_internal * state = NULL;
245     char * dev_id = v3_cfg_val(cfg, "ID");
246     v3_cfg_tree_t * port_cfg = v3_cfg_subtree(cfg, "ports");
247
248
249     state = (struct generic_internal *)V3_Malloc(sizeof(struct generic_internal));
250
251     if (state == NULL) {
252         PrintError("Could not allocate generic state\n");
253         return -1;
254     }
255     
256     memset(state, 0, sizeof(struct generic_internal));
257     
258     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, state);
259
260     if (dev == NULL) {
261         PrintError("Could not attach device %s\n", dev_id);
262         V3_Free(state);
263         return -1;
264     }
265
266     PrintDebug("generic: init_device\n");
267
268     // scan port list....
269     while (port_cfg) {
270         uint16_t start = atox(v3_cfg_val(port_cfg, "start"));
271         uint16_t end = atox(v3_cfg_val(port_cfg, "end"));
272         char * mode_str = v3_cfg_val(port_cfg, "mode");
273         generic_mode_t mode = GENERIC_IGNORE;
274
275         if (strcasecmp(mode_str, "print_and_ignore") == 0) {
276             mode = GENERIC_PRINT_AND_IGNORE;
277         } else if (strcasecmp(mode_str, "print_and_passthrough") == 0) {
278             mode = GENERIC_PRINT_AND_PASSTHROUGH;
279         } else if (strcasecmp(mode_str, "passthrough") == 0) {
280             mode = GENERIC_PASSTHROUGH;
281         } else if (strcasecmp(mode_str, "ignore") == 0) {
282             mode = GENERIC_IGNORE;
283         } else {
284             PrintError("Invalid Mode %s\n", mode_str);
285             v3_remove_device(dev);
286             return -1;
287         }
288         
289         if (add_port_range(dev, start, end, mode) == -1) {
290             PrintError("Could not add port range %d-%d\n", start, end);
291             v3_remove_device(dev);
292             return -1;
293         }
294
295         port_cfg = v3_cfg_next_branch(port_cfg);
296     }
297
298
299     return 0;
300 }
301
302 device_register("GENERIC", generic_init)