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 <<<<<<< HEAD:palacios/src/devices/generic.c
107 >>>>>>> ramdisk:palacios/src/devices/generic.c
108 v3_outb(port,((uchar_t*)src)[0]);
111 v3_outw(port,((ushort_t*)src)[0]);
114 v3_outdw(port,((uint_t*)src)[0]);
115 <<<<<<< HEAD:palacios/src/devices/generic.c
118 >>>>>>> ramdisk:palacios/src/devices/generic.c
121 for (i = 0; i < length; i++) {
122 v3_outb(port, ((uchar_t*)src)[i]);
127 PrintDebug(" done\n");
132 int generic_read_port_passthrough(ushort_t port,
135 struct vm_device * dev)
139 PrintDebug("generic: reading 0x%x bytes from port 0x%x ...", length, port);
144 ((uchar_t*)src)[0] = v3_inb(port);
147 ((ushort_t*)src)[0] = v3_inw(port);
150 ((uint_t*)src)[0] = v3_indw(port);
153 for (i = 0; i < length; i++) {
154 ((uchar_t*)src)[i] = v3_inb(port);
158 PrintDebug(" done ... read 0x");
160 for (i = 0; i < length; i++) {
161 PrintDebug("%x", ((uchar_t*)src)[i]);
169 int generic_write_port_ignore(ushort_t port,
172 struct vm_device * dev)
176 PrintDebug("generic: writing 0x");
178 for (i = 0; i < length; i++) {
179 PrintDebug("%x", ((uchar_t*)src)[i]);
182 PrintDebug(" to port 0x%x ... ignored\n", port);
187 int generic_read_port_ignore(ushort_t port,
190 struct vm_device * dev)
193 PrintDebug("generic: reading 0x%x bytes from port 0x%x ...", length, port);
195 memset((char*)src, 0, length);
196 PrintDebug(" ignored (return zeroed buffer)\n");
203 int generic_interrupt(uint_t irq, struct vm_device * dev) {
204 PrintDebug("generic: interrupt 0x%x - injecting into VM\n", irq);
206 dev->vm->vm_ops.raise_irq(dev->vm, irq);
212 int generic_init_device(struct vm_device * dev) {
213 struct generic_internal * state = (struct generic_internal *)(dev->private_data);
215 PrintDebug("generic: init_device\n");
216 generic_reset_device(dev);
219 if (PORT_HOOKS) { // This is a runtime conditional on a #define
220 struct port_range * tmp = NULL;
222 list_for_each_entry(tmp, &(state->port_list), range_link) {
225 PrintDebug("generic: hooking ports 0x%x to 0x%x as %x\n",
226 tmp->start, tmp->end,
227 (tmp->type == GENERIC_PRINT_AND_PASSTHROUGH) ? "print-and-passthrough" : "print-and-ignore");
229 for (i = tmp->start; i <= tmp->end; i++) {
230 if (tmp->type == GENERIC_PRINT_AND_PASSTHROUGH) {
232 if (dev_hook_io(dev, i, &generic_read_port_passthrough, &generic_write_port_passthrough)) {
233 PrintDebug("generic: can't hook port 0x%x (already hooked?)\n", i);
236 } else if (tmp->type == GENERIC_PRINT_AND_IGNORE) {
238 if (dev_hook_io(dev, i, &generic_read_port_ignore, &generic_write_port_ignore)) {
239 PrintDebug("generic: can't hook port 0x%x (already hooked?)\n", i);
246 PrintDebug("generic: hooking ports not supported\n");
251 if (MEM_HOOKS) { // This is a runtime conditional on a #define
252 struct mem_range * tmp;
254 list_for_each_entry(tmp, &(state->mem_list), range_link) {
256 PrintDebug("generic: hooking addresses 0x%x to 0x%x\n",
257 tmp->start, tmp->end);
260 if (dev_hook_mem(dev, tmp->start, tmp->end)) {
261 PrintDebug("generic: Can't hook addresses 0x%x to 0x%x (already hooked?)\n",
262 tmp->start, tmp->end);
266 PrintDebug("generic: hooking addresses not supported\n");
272 if (IRQ_HOOKS) { // This is a runtime conditional on a #define
273 struct irq_range * tmp;
275 list_for_each_entry(tmp, &(state->irq_list), range_link) {
278 PrintDebug("generic: hooking irqs 0x%x to 0x%x\n",
279 tmp->start, tmp->end);
281 for (i = tmp->start; i <= tmp->end; i++) {
282 if (dev_hook_irq(dev, i, &generic_interrupt)) {
283 PrintDebug("generic: can't hook irq 0x%x (already hooked?)\n", i);
289 PrintDebug("generic: hooking irqs not supported\n");
297 int generic_deinit_device(struct vm_device * dev) {
298 struct generic_internal * state = (struct generic_internal *)(dev->private_data);
301 PrintDebug("generic: deinit_device\n");
304 if (IRQ_HOOKS) { // This is a runtime conditional on a #define
305 struct irq_range * tmp;
306 struct irq_range * cur;
308 list_for_each_entry_safe(cur, tmp, &(state->irq_list), range_link) {
311 PrintDebug("generic: unhooking irqs 0x%x to 0x%x\n",
312 cur->start, cur->end);
315 for (i = cur->start; i <= cur->end; i++) {
316 if (dev_unhook_irq(dev, i)) {
317 PrintDebug("generic: can't unhook irq 0x%x (already unhooked?)\n", i);
321 list_del(&(cur->range_link));
322 state->num_irq_ranges--;
326 PrintDebug("generic: unhooking irqs not supported\n");
331 struct mem_range * tmp;
332 struct mem_range * cur;
334 list_for_each_entry_safe(cur, tmp, &(state->mem_list), range_link) {
336 PrintDebug("generic: unhooking addresses 0x%x to 0x%x\n",
337 cur->start, cur->end);
339 if (dev_unhook_mem(dev, cur->start, cur->end)) {
340 PrintDebug("generic: Can't unhook addresses 0x%x to 0x%x (already unhooked?)\n",
341 cur->start, cur->end);
344 list_del(&(cur->range_link));
345 state->num_mem_ranges--;
349 PrintDebug("generic: unhooking addresses not supported\n");
354 struct port_range * tmp;
355 struct port_range * cur;
357 list_for_each_entry_safe(cur, tmp, &(state->port_list), range_link) {
360 PrintDebug("generic: unhooking ports 0x%x to 0x%x\n",
361 cur->start, cur->end);
363 for (i = cur->start; i <= cur->end; i++) {
364 if (dev_unhook_io(dev, i)) {
365 PrintDebug("generic: can't unhook port 0x%x (already unhooked?)\n", i);
369 list_del(&(cur->range_link));
370 state->num_port_ranges--;
374 PrintDebug("generic: unhooking ports not supported\n");
379 generic_reset_device(dev);
387 static struct vm_device_ops dev_ops = {
388 .init = generic_init_device,
389 .deinit = generic_deinit_device,
390 .reset = generic_reset_device,
391 .start = generic_start_device,
392 .stop = generic_stop_device,
398 int v3_generic_add_port_range(struct vm_device * dev, uint_t start, uint_t end, uint_t type) {
401 struct generic_internal * state = (struct generic_internal *)(dev->private_data);
403 struct port_range * range = (struct port_range *)V3_Malloc(sizeof(struct port_range));
404 range->start = start;
409 PrintDebug("generic: Adding Port Range: 0x%x to 0x%x as %x\n",
410 range->start, range->end,
411 (range->type == GENERIC_PRINT_AND_PASSTHROUGH) ? "print-and-passthrough" : "print-and-ignore");
413 list_add(&(range->range_link), &(state->port_list));
414 state->num_port_ranges++;
416 PrintDebug("generic: hooking IO ports not supported\n");
423 int v3_generic_add_mem_range(struct vm_device * dev, void * start, void * end, uint_t type) {
426 struct generic_internal * state = (struct generic_internal *)(dev->private_data);
428 struct mem_range * range = (struct mem_range *)V3_Malloc(sizeof(struct mem_range));
429 range->start = start;
433 list_add(&(range->range_link), &(state->port_list));
434 state->num_mem_ranges++;
436 PrintDebug("generic: hooking memory not supported\n");
444 int v3_generic_add_irq_range(struct vm_device * dev, uint_t start, uint_t end, uint_t type) {
447 struct generic_internal * state = (struct generic_internal *)(dev->private_data);
449 struct irq_range * range = (struct irq_range *)V3_Malloc(sizeof(struct irq_range));
450 range->start = start;
454 list_add(&(range->range_link), &(state->port_list));
455 state->num_irq_ranges++;
457 PrintDebug("generic: hooking IRQs not supported\n");
466 struct vm_device * create_generic() {
467 struct generic_internal * generic_state = (struct generic_internal *)V3_Malloc(sizeof(struct generic_internal));
469 generic_state->num_port_ranges = 0;
470 generic_state->num_mem_ranges = 0;
471 generic_state->num_irq_ranges = 0;
473 INIT_LIST_HEAD(&(generic_state->port_list));
474 INIT_LIST_HEAD(&(generic_state->mem_list));
475 INIT_LIST_HEAD(&(generic_state->irq_list));
477 struct vm_device * device = create_device("GENERIC", &dev_ops, generic_state);