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.


7a70e5d81c13bf960fdf5afab029231722b0e17b
[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 <devices/generic.h>
23 #include <palacios/vmm.h>
24 #include <palacios/vmm_types.h>
25 #include <palacios/vmm_list.h>
26
27
28
29 #ifndef DEBUG_GENERIC
30 #undef PrintDebug
31 #define PrintDebug(fmt, args...)
32 #endif
33
34
35 struct generic_internal {
36     struct list_head port_list;
37     uint_t num_port_ranges;
38
39 };
40
41
42 struct port_range {
43     uint_t start;
44     uint_t end;
45     uint_t type;
46     struct list_head range_link;
47 };
48
49
50
51
52 static int generic_reset_device(struct vm_device * dev) {
53     PrintDebug("generic: reset device\n");
54     return 0;
55 }
56
57
58
59
60
61 static int generic_start_device(struct vm_device * dev) {
62     PrintDebug("generic: start device\n");
63     return 0;
64 }
65
66
67 static int generic_stop_device(struct vm_device * dev) {
68     PrintDebug("generic: stop device\n");
69     return 0;
70 }
71
72
73
74
75 static int generic_write_port_passthrough(uint16_t port, void * src, 
76                                           uint_t length, struct vm_device * dev) {
77     uint_t i;
78
79     PrintDebug("generic: writing 0x");
80
81     for (i = 0; i < length; i++) { 
82         PrintDebug("%x", ((uchar_t*)src)[i]);
83     }
84   
85     PrintDebug(" to port 0x%x ... ", port);
86
87     switch (length) {
88         case 1:
89             v3_outb(port,((uchar_t*)src)[0]);
90             break;
91         case 2:
92             v3_outw(port,((uint16_t*)src)[0]);
93             break;
94         case 4:
95             v3_outdw(port,((uint_t*)src)[0]);
96             break;
97         default:
98             for (i = 0; i < length; i++) { 
99                 v3_outb(port, ((uchar_t*)src)[i]);
100             }
101     }
102
103     PrintDebug(" done\n");
104   
105     return length;
106 }
107
108 static int generic_read_port_passthrough(uint16_t port, void * src, 
109                                          uint_t length, struct vm_device * dev) {
110     uint_t i;
111
112     PrintDebug("generic: reading 0x%x bytes from port 0x%x ...", length, port);
113
114
115     switch (length) {
116         case 1:
117             ((uchar_t*)src)[0] = v3_inb(port);
118             break;
119         case 2:
120             ((uint16_t*)src)[0] = v3_inw(port);
121             break;
122         case 4:
123             ((uint_t*)src)[0] = v3_indw(port);
124             break;
125         default:
126             for (i = 0; i < length; i++) { 
127                 ((uchar_t*)src)[i] = v3_inb(port);
128             }
129     }
130
131     PrintDebug(" done ... read 0x");
132
133     for (i = 0; i < length; i++) { 
134         PrintDebug("%x", ((uchar_t*)src)[i]);
135     }
136
137     PrintDebug("\n");
138
139     return length;
140 }
141
142 static int generic_write_port_ignore(uint16_t port, void * src, 
143                                      uint_t length, struct vm_device * dev) {
144     uint_t i;
145
146     PrintDebug("generic: writing 0x");
147
148     for (i = 0; i < length; i++) { 
149         PrintDebug("%x", ((uchar_t*)src)[i]);
150     }
151   
152     PrintDebug(" to port 0x%x ... ignored\n", port);
153  
154     return length;
155 }
156
157 static int generic_read_port_ignore(uint16_t port, void * src, 
158                                     uint_t length, struct vm_device * dev) {
159
160     PrintDebug("generic: reading 0x%x bytes from port 0x%x ...", length, port);
161
162     memset((char*)src, 0, length);
163     PrintDebug(" ignored (return zeroed buffer)\n");
164
165     return length;
166 }
167
168
169
170
171
172 static int generic_free(struct vm_device * dev) {
173     struct generic_internal * state = (struct generic_internal *)(dev->private_data);
174     struct port_range * tmp;
175     struct port_range * cur;
176
177     PrintDebug("generic: deinit_device\n");
178
179     list_for_each_entry_safe(cur, tmp, &(state->port_list), range_link) {
180         uint_t i;
181
182         PrintDebug("generic: unhooking ports 0x%x to 0x%x\n",
183                    cur->start, cur->end);
184         
185         for (i = cur->start; i <= cur->end; i++) {
186             if (v3_dev_unhook_io(dev, i)) {
187                 PrintDebug("generic: can't unhook port 0x%x (already unhooked?)\n", i);
188             }
189         }
190
191         list_del(&(cur->range_link));
192         state->num_port_ranges--;
193         V3_Free(cur);
194     }
195
196     generic_reset_device(dev);
197     return 0;
198 }
199
200
201
202
203
204 static struct v3_device_ops dev_ops = { 
205     .free = generic_free, 
206     .reset = generic_reset_device,
207     .start = generic_start_device,
208     .stop = generic_stop_device,
209 };
210
211
212
213
214 int v3_generic_add_port_range(struct vm_device * dev, uint_t start, uint_t end, uint_t type) {
215     struct generic_internal * state = (struct generic_internal *)(dev->private_data);
216     struct port_range * range = (struct port_range *)V3_Malloc(sizeof(struct port_range));
217     uint_t i = 0;
218
219     range->start = start;
220     range->end = end;
221     range->type = type;
222       
223     PrintDebug("generic: Adding Port Range: 0x%x to 0x%x as %s\n", 
224                range->start, range->end, 
225                (range->type == GENERIC_PRINT_AND_PASSTHROUGH) ? "print-and-passthrough" : "print-and-ignore");
226     
227     for (i = start; i <= end; i++) { 
228         if (type == GENERIC_PRINT_AND_PASSTHROUGH) { 
229             if (v3_dev_hook_io(dev, i, &generic_read_port_passthrough, &generic_write_port_passthrough) == -1) { 
230                 PrintError("generic: can't hook port 0x%x (already hooked?)\n", i);
231                 return -1;
232             }
233         } else if (type == GENERIC_PRINT_AND_IGNORE) { 
234             if (v3_dev_hook_io(dev, i, &generic_read_port_ignore, &generic_write_port_ignore) == -1) { 
235                 PrintError("generic: can't hook port 0x%x (already hooked?)\n", i);
236                 return -1;
237             }
238         } 
239     }
240
241     list_add(&(range->range_link), &(state->port_list));
242     state->num_port_ranges++;
243     
244     return 0;
245 }
246
247
248
249
250
251 static int generic_init(struct guest_info * vm, void * cfg_data) {
252     struct generic_internal * state = (struct generic_internal *)V3_Malloc(sizeof(struct generic_internal));
253   
254     INIT_LIST_HEAD(&(state->port_list));
255     state->num_port_ranges = 0;
256     
257     struct vm_device * dev = v3_allocate_device("GENERIC", &dev_ops, state);
258
259     if (v3_attach_device(vm, dev) == -1) {
260         PrintError("Could not attach device %s\n", "GENERIC");
261         return -1;
262     }
263
264     PrintDebug("generic: init_device\n");
265     generic_reset_device(dev);
266
267     return 0;
268 }
269
270 device_register("GENERIC", generic_init)