1 /* (c) 2008, Peter Dinda <pdinda@northwestern.edu> */
2 /* (c) 2008, The V3VEE Project <http://www.v3vee.org> */
5 #include <devices/generic.h>
6 #include <palacios/vmm.h>
7 #include <palacios/vmm_types.h>
14 #define PrintDebug(fmt, args...)
19 #define MEM_HOOKS 0 // not yet implmented in device model
20 #define IRQ_HOOKS 0 // not yet implemented in device model
22 struct generic_internal {
23 generic_port_range_type * port_ranges;
24 uint_t num_port_ranges;
25 generic_address_range_type * address_ranges;
26 uint_t num_address_ranges;
27 generic_irq_range_type * irq_ranges;
28 uint_t num_irq_ranges;
33 int generic_reset_device(struct vm_device * dev)
35 PrintDebug("generic: reset device\n");
45 int generic_start_device(struct vm_device * dev)
47 PrintDebug("generic: start device\n");
52 int generic_stop_device(struct vm_device * dev)
54 PrintDebug("generic: stop device\n");
61 int generic_write_port_passthrough(ushort_t port,
64 struct vm_device * dev)
68 PrintDebug("generic: writing 0x");
70 for (i = 0; i < length; i++) {
71 PrintDebug("%x", ((uchar_t*)src)[i]);
74 PrintDebug(" to port 0x%x ... ", port);
80 v3_outb(port,((uchar_t*)src)[0]);
83 v3_outw(port,((ushort_t*)src)[0]);
86 v3_outdw(port,((uint_t*)src)[0]);
90 for (i = 0; i < length; i++) {
91 v3_outb(port, ((uchar_t*)src)[i]);
96 PrintDebug(" done\n");
101 int generic_read_port_passthrough(ushort_t port,
104 struct vm_device * dev)
108 PrintDebug("generic: reading 0x%x bytes from port 0x%x ...", length, port);
113 ((uchar_t*)src)[0] = v3_inb(port);
116 ((ushort_t*)src)[0] = v3_inw(port);
119 ((uint_t*)src)[0] = v3_indw(port);
122 for (i = 0; i < length; i++) {
123 ((uchar_t*)src)[i] = v3_inb(port);
127 PrintDebug(" done ... read 0x");
129 for (i = 0; i < length; i++) {
130 PrintDebug("%x", ((uchar_t*)src)[i]);
138 int generic_write_port_ignore(ushort_t port,
141 struct vm_device * dev)
145 PrintDebug("generic: writing 0x");
147 for (i = 0; i < length; i++) {
148 PrintDebug("%x", ((uchar_t*)src)[i]);
151 PrintDebug(" to port 0x%x ... ", port);
153 PrintDebug(" ignored\n");
158 int generic_read_port_ignore(ushort_t port,
161 struct vm_device * dev)
164 PrintDebug("generic: reading 0x%x bytes from port 0x%x ...", length, port);
166 memset((char*)src, 0, length);
167 PrintDebug(" ignored (return zeroed buffer)\n");
174 int generic_interrupt(uint_t irq, struct vm_device * dev) {
175 PrintDebug("generic: interrupt 0x%x - injecting into VM\n", irq);
177 dev->vm->vm_ops.raise_irq(dev->vm, irq);
183 int generic_init_device(struct vm_device * dev) {
184 struct generic_internal * state = (struct generic_internal *)(dev->private_data);
187 PrintDebug("generic: init_device\n");
189 // Would read state here
191 generic_reset_device(dev);
193 for (i = 0; i < state->num_port_ranges; i++) {
195 PrintDebug("generic: hooking ports 0x%x to 0x%x as %x\n",
196 state->port_ranges[i][0], state->port_ranges[i][1],
197 (state->port_ranges[i][2] == GENERIC_PRINT_AND_PASSTHROUGH) ? "print-and-passthrough" : "print-and-ignore");
199 if (PORT_HOOKS) { // This is a runtime conditional on a #define
200 for (j = state->port_ranges[i][0]; j <= state->port_ranges[i][1]; j++) {
201 if (state->port_ranges[i][2] == GENERIC_PRINT_AND_PASSTHROUGH) {
203 if (dev_hook_io(dev, j, &generic_read_port_passthrough, &generic_write_port_passthrough)) {
204 PrintDebug("generic: can't hook port 0x%x (already hooked?)\n", j);
207 } else if (state->port_ranges[i][2] == GENERIC_PRINT_AND_IGNORE) {
209 if (dev_hook_io(dev, j, &generic_read_port_ignore, &generic_write_port_ignore)) {
210 PrintDebug("generic: can't hook port 0x%x (already hooked?)\n", j);
216 PrintDebug("generic: hooking ports not supported\n");
221 for (i = 0; i < state->num_address_ranges; i++) {
223 PrintDebug("generic: hooking addresses 0x%x to 0x%x\n",
224 state->address_ranges[i][0], state->address_ranges[i][1]);
226 if (MEM_HOOKS) { // This is a runtime conditional on a #define
227 if (dev_hook_mem(dev, state->address_ranges[i][0], state->address_ranges[i][1])) {
228 PrintDebug("generic: Can't hook addresses 0x%x to 0x%x (already hooked?)\n",
229 state->address_ranges[i][0], state->address_ranges[i][1]);
232 PrintDebug("generic: hooking addresses not supported\n");
236 for (i = 0; i < state->num_irq_ranges; i++) {
238 PrintDebug("generic: hooking irqs 0x%x to 0x%x\n",
239 state->irq_ranges[i][0], state->irq_ranges[i][1]);
241 if (IRQ_HOOKS) { // This is a runtime conditional on a #define
242 for (j = state->irq_ranges[i][0]; j <= state->irq_ranges[i][1]; j++) {
243 if (dev_hook_irq(dev, j, &generic_interrupt)) {
244 PrintDebug("generic: can't hook irq 0x%x (already hooked?)\n", j);
248 PrintDebug("generic: hooking irqs not supported\n");
256 int generic_deinit_device(struct vm_device * dev) {
257 struct generic_internal *state = (struct generic_internal *)(dev->private_data);
260 PrintDebug("generic: deinit_device\n");
263 for (i = 0; i < state->num_irq_ranges; i++) {
265 PrintDebug("generic: unhooking irqs 0x%x to 0x%x\n",
266 state->irq_ranges[i][0], state->irq_ranges[i][1]);
268 if (IRQ_HOOKS) { // This is a runtime conditional on a #define
269 for (j = state->irq_ranges[i][0]; j <= state->irq_ranges[i][1]; j++) {
271 if (dev_unhook_irq(dev, j)) {
272 PrintDebug("generic: can't unhook irq 0x%x (already unhooked?)\n",j);
277 PrintDebug("generic: unhooking irqs not supported\n");
281 for (i = 0; i < state->num_address_ranges; i++) {
283 PrintDebug("generic: unhooking addresses 0x%x to 0x%x\n",
284 state->address_ranges[i][0], state->address_ranges[i][1]);
287 if (dev_unhook_mem(dev, state->address_ranges[i][0], state->address_ranges[i][1])) {
289 PrintDebug("generic: Can't unhook addresses 0x%x to 0x%x (already unhooked?)\n",
290 state->address_ranges[i][0], state->address_ranges[i][1]);
294 PrintDebug("generic: unhooking addresses not supported\n");
298 for (i = 0; i < state->num_port_ranges; i++) {
299 PrintDebug("generic: unhooking ports 0x%x to 0x%x\n",
300 state->port_ranges[i][0], state->port_ranges[i][1]);
303 for (j = state->port_ranges[i][0]; j <= state->port_ranges[i][1]; j++) {
304 if (dev_unhook_io(dev, j)) {
305 PrintDebug("generic: can't unhook port 0x%x (already unhooked?)\n", j);
309 PrintDebug("generic: unhooking ports not supported\n");
314 generic_reset_device(dev);
322 static struct vm_device_ops dev_ops = {
323 .init = generic_init_device,
324 .deinit = generic_deinit_device,
325 .reset = generic_reset_device,
326 .start = generic_start_device,
327 .stop = generic_stop_device,
333 struct vm_device *create_generic(generic_port_range_type port_ranges[],
334 generic_address_range_type address_ranges[],
335 generic_irq_range_type irq_ranges[])
337 struct generic_internal * generic_state = (struct generic_internal *)V3_Malloc(sizeof(struct generic_internal));
339 uint_t num_port_ranges;
340 uint_t num_address_ranges;
341 uint_t num_irq_ranges;
346 if (port_ranges != NULL) {
349 while ((port_ranges[i] != NULL) &&
350 ( !( (port_ranges[i][0] == 0) &&
351 (port_ranges[i][1] == 0) &&
352 (port_ranges[i][2] == 0)) ) )
360 num_address_ranges = 0;
362 if (address_ranges != NULL) {
365 while ((address_ranges[i] != NULL) &&
366 ( !( (address_ranges[i][0] == 0) &&
367 (address_ranges[i][1] == 0) &&
368 (address_ranges[i][2] == 0)) ) )
370 num_address_ranges++;
377 if (irq_ranges != NULL) {
380 while ((irq_ranges[i] != NULL) &&
381 ( !( (irq_ranges[i][0] == 0) &&
382 (irq_ranges[i][1] == 0) &&
383 (irq_ranges[i][2] == 0)) ) )
391 generic_state->num_port_ranges = num_port_ranges;
393 if (num_port_ranges > 0) {
395 generic_state->port_ranges = V3_Malloc(sizeof(generic_address_range_type) * num_port_ranges);
396 memcpy(generic_state->port_ranges, port_ranges,
397 (sizeof(generic_port_range_type) * num_port_ranges));
400 generic_state->port_ranges = NULL;
404 generic_state->num_address_ranges = num_address_ranges;
406 if (num_address_ranges > 0) {
408 generic_state->address_ranges = V3_Malloc(sizeof(generic_address_range_type) * num_address_ranges);
409 memcpy(generic_state->address_ranges, address_ranges,
410 (sizeof(generic_address_range_type) * num_address_ranges));
413 generic_state->address_ranges = NULL;
417 generic_state->num_irq_ranges = num_irq_ranges;
419 if (num_irq_ranges > 0) {
421 generic_state->irq_ranges = V3_Malloc(sizeof(generic_address_range_type) * num_irq_ranges);
422 memcpy(generic_state->irq_ranges, irq_ranges,
423 (sizeof(generic_irq_range_type) * num_port_ranges));
426 generic_state->irq_ranges = NULL;
429 struct vm_device *device = create_device("GENERIC", &dev_ops, generic_state);