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.


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