1 /* (c) 2008, Peter Dinda <pdinda@northwestern.edu> */
2 /* (c) 2008, The V3VEE Project <http://www.v3vee.org> */
7 #include <devices/generic.h>
8 #include <palacios/vmm.h>
9 #include <palacios/vmm_types.h>
10 #include <palacios/vmm_list.h>
16 #define PrintDebug(fmt, args...)
21 #define MEM_HOOKS 0 // not yet implmented in device model
22 #define IRQ_HOOKS 0 // not yet implemented in device model
25 struct generic_internal {
26 struct list_head port_list;
27 uint_t num_port_ranges;
28 struct list_head mem_list;
29 uint_t num_mem_ranges;
30 struct list_head irq_list;
31 uint_t num_irq_ranges;
39 struct list_head range_link;
46 struct list_head range_link;
53 struct list_head range_link;
58 int generic_reset_device(struct vm_device * dev)
60 PrintDebug("generic: reset device\n");
70 int generic_start_device(struct vm_device * dev)
72 PrintDebug("generic: start device\n");
77 int generic_stop_device(struct vm_device * dev)
79 PrintDebug("generic: stop device\n");
86 int generic_write_port_passthrough(ushort_t port,
89 struct vm_device * dev)
93 PrintDebug("generic: writing 0x");
95 for (i = 0; i < length; i++) {
96 PrintDebug("%x", ((uchar_t*)src)[i]);
99 PrintDebug(" to port 0x%x ... ", port);
104 v3_outb(port,((uchar_t*)src)[0]);
107 v3_outw(port,((ushort_t*)src)[0]);
110 v3_outdw(port,((uint_t*)src)[0]);
113 for (i = 0; i < length; i++) {
114 v3_outb(port, ((uchar_t*)src)[i]);
119 PrintDebug(" done\n");
124 int generic_read_port_passthrough(ushort_t port,
127 struct vm_device * dev)
131 PrintDebug("generic: reading 0x%x bytes from port 0x%x ...", length, port);
136 ((uchar_t*)src)[0] = v3_inb(port);
139 ((ushort_t*)src)[0] = v3_inw(port);
142 ((uint_t*)src)[0] = v3_indw(port);
145 for (i = 0; i < length; i++) {
146 ((uchar_t*)src)[i] = v3_inb(port);
150 PrintDebug(" done ... read 0x");
152 for (i = 0; i < length; i++) {
153 PrintDebug("%x", ((uchar_t*)src)[i]);
161 int generic_write_port_ignore(ushort_t port,
164 struct vm_device * dev)
168 PrintDebug("generic: writing 0x");
170 for (i = 0; i < length; i++) {
171 PrintDebug("%x", ((uchar_t*)src)[i]);
174 PrintDebug(" to port 0x%x ... ignored\n", port);
179 int generic_read_port_ignore(ushort_t port,
182 struct vm_device * dev)
185 PrintDebug("generic: reading 0x%x bytes from port 0x%x ...", length, port);
187 memset((char*)src, 0, length);
188 PrintDebug(" ignored (return zeroed buffer)\n");
195 int generic_interrupt(uint_t irq, struct vm_device * dev) {
196 PrintDebug("generic: interrupt 0x%x - injecting into VM\n", irq);
198 dev->vm->vm_ops.raise_irq(dev->vm, irq);
204 int generic_init_device(struct vm_device * dev) {
205 struct generic_internal * state = (struct generic_internal *)(dev->private_data);
207 PrintDebug("generic: init_device\n");
208 generic_reset_device(dev);
211 if (PORT_HOOKS) { // This is a runtime conditional on a #define
212 struct port_range * tmp = NULL;
214 list_for_each_entry(tmp, &(state->port_list), range_link) {
217 PrintDebug("generic: hooking ports 0x%x to 0x%x as %x\n",
218 tmp->start, tmp->end,
219 (tmp->type == GENERIC_PRINT_AND_PASSTHROUGH) ? "print-and-passthrough" : "print-and-ignore");
221 for (i = tmp->start; i <= tmp->end; i++) {
222 if (tmp->type == GENERIC_PRINT_AND_PASSTHROUGH) {
224 if (dev_hook_io(dev, i, &generic_read_port_passthrough, &generic_write_port_passthrough)) {
225 PrintDebug("generic: can't hook port 0x%x (already hooked?)\n", i);
228 } else if (tmp->type == GENERIC_PRINT_AND_IGNORE) {
230 if (dev_hook_io(dev, i, &generic_read_port_ignore, &generic_write_port_ignore)) {
231 PrintDebug("generic: can't hook port 0x%x (already hooked?)\n", i);
238 PrintDebug("generic: hooking ports not supported\n");
243 if (MEM_HOOKS) { // This is a runtime conditional on a #define
244 struct mem_range * tmp;
246 list_for_each_entry(tmp, &(state->mem_list), range_link) {
248 PrintDebug("generic: hooking addresses 0x%x to 0x%x\n",
249 tmp->start, tmp->end);
252 if (dev_hook_mem(dev, tmp->start, tmp->end)) {
253 PrintDebug("generic: Can't hook addresses 0x%x to 0x%x (already hooked?)\n",
254 tmp->start, tmp->end);
258 PrintDebug("generic: hooking addresses not supported\n");
264 if (IRQ_HOOKS) { // This is a runtime conditional on a #define
265 struct irq_range * tmp;
267 list_for_each_entry(tmp, &(state->irq_list), range_link) {
270 PrintDebug("generic: hooking irqs 0x%x to 0x%x\n",
271 tmp->start, tmp->end);
273 for (i = tmp->start; i <= tmp->end; i++) {
274 if (dev_hook_irq(dev, i, &generic_interrupt)) {
275 PrintDebug("generic: can't hook irq 0x%x (already hooked?)\n", i);
281 PrintDebug("generic: hooking irqs not supported\n");
289 int generic_deinit_device(struct vm_device * dev) {
290 struct generic_internal * state = (struct generic_internal *)(dev->private_data);
293 PrintDebug("generic: deinit_device\n");
296 if (IRQ_HOOKS) { // This is a runtime conditional on a #define
297 struct irq_range * tmp;
298 struct irq_range * cur;
300 list_for_each_entry_safe(cur, tmp, &(state->irq_list), range_link) {
303 PrintDebug("generic: unhooking irqs 0x%x to 0x%x\n",
304 cur->start, cur->end);
307 for (i = cur->start; i <= cur->end; i++) {
308 if (dev_unhook_irq(dev, i)) {
309 PrintDebug("generic: can't unhook irq 0x%x (already unhooked?)\n", i);
313 list_del(&(cur->range_link));
314 state->num_irq_ranges--;
318 PrintDebug("generic: unhooking irqs not supported\n");
323 struct mem_range * tmp;
324 struct mem_range * cur;
326 list_for_each_entry_safe(cur, tmp, &(state->mem_list), range_link) {
328 PrintDebug("generic: unhooking addresses 0x%x to 0x%x\n",
329 cur->start, cur->end);
331 if (dev_unhook_mem(dev, cur->start, cur->end)) {
332 PrintDebug("generic: Can't unhook addresses 0x%x to 0x%x (already unhooked?)\n",
333 cur->start, cur->end);
336 list_del(&(cur->range_link));
337 state->num_mem_ranges--;
341 PrintDebug("generic: unhooking addresses not supported\n");
346 struct port_range * tmp;
347 struct port_range * cur;
349 list_for_each_entry_safe(cur, tmp, &(state->port_list), range_link) {
352 PrintDebug("generic: unhooking ports 0x%x to 0x%x\n",
353 cur->start, cur->end);
355 for (i = cur->start; i <= cur->end; i++) {
356 if (dev_unhook_io(dev, i)) {
357 PrintDebug("generic: can't unhook port 0x%x (already unhooked?)\n", i);
361 list_del(&(cur->range_link));
362 state->num_port_ranges--;
366 PrintDebug("generic: unhooking ports not supported\n");
371 generic_reset_device(dev);
379 static struct vm_device_ops dev_ops = {
380 .init = generic_init_device,
381 .deinit = generic_deinit_device,
382 .reset = generic_reset_device,
383 .start = generic_start_device,
384 .stop = generic_stop_device,
390 int v3_generic_add_port_range(struct vm_device * dev, uint_t start, uint_t end, uint_t type) {
393 struct generic_internal * state = (struct generic_internal *)(dev->private_data);
395 struct port_range * range = (struct port_range *)V3_Malloc(sizeof(struct port_range));
396 range->start = start;
401 PrintDebug("generic: Adding Port Range: 0x%x to 0x%x as %x\n",
402 range->start, range->end,
403 (range->type == GENERIC_PRINT_AND_PASSTHROUGH) ? "print-and-passthrough" : "print-and-ignore");
405 list_add(&(range->range_link), &(state->port_list));
406 state->num_port_ranges++;
408 PrintDebug("generic: hooking IO ports not supported\n");
415 int v3_generic_add_mem_range(struct vm_device * dev, void * start, void * end, uint_t type) {
418 struct generic_internal * state = (struct generic_internal *)(dev->private_data);
420 struct mem_range * range = (struct mem_range *)V3_Malloc(sizeof(struct mem_range));
421 range->start = start;
425 list_add(&(range->range_link), &(state->port_list));
426 state->num_mem_ranges++;
428 PrintDebug("generic: hooking memory not supported\n");
436 int v3_generic_add_irq_range(struct vm_device * dev, uint_t start, uint_t end, uint_t type) {
439 struct generic_internal * state = (struct generic_internal *)(dev->private_data);
441 struct irq_range * range = (struct irq_range *)V3_Malloc(sizeof(struct irq_range));
442 range->start = start;
446 list_add(&(range->range_link), &(state->port_list));
447 state->num_irq_ranges++;
449 PrintDebug("generic: hooking IRQs not supported\n");
458 struct vm_device * create_generic() {
459 struct generic_internal * generic_state = (struct generic_internal *)V3_Malloc(sizeof(struct generic_internal));
461 generic_state->num_port_ranges = 0;
462 generic_state->num_mem_ranges = 0;
463 generic_state->num_irq_ranges = 0;
465 INIT_LIST_HEAD(&(generic_state->port_list));
466 INIT_LIST_HEAD(&(generic_state->mem_list));
467 INIT_LIST_HEAD(&(generic_state->irq_list));
469 struct vm_device * device = create_device("GENERIC", &dev_ops, generic_state);