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