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>
8 #include <palacios/vmm_list.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
23 struct generic_internal {
24 struct list_head port_range;
25 uint_t num_port_ranges;
26 struct list_head mem_range;
27 uint_t num_mem_ranges;
28 struct list_head irq_range;
29 uint_t num_irq_ranges;
37 struct list_head range_list;
44 struct list_head range_list;
51 struct list_head range_list;
56 int generic_reset_device(struct vm_device * dev)
58 PrintDebug("generic: reset device\n");
68 int generic_start_device(struct vm_device * dev)
70 PrintDebug("generic: start device\n");
75 int generic_stop_device(struct vm_device * dev)
77 PrintDebug("generic: stop device\n");
84 int generic_write_port_passthrough(ushort_t port,
87 struct vm_device * dev)
91 PrintDebug("generic: writing 0x");
93 for (i = 0; i < length; i++) {
94 PrintDebug("%x", ((uchar_t*)src)[i]);
97 PrintDebug(" to port 0x%x ... ", port);
103 v3_outb(port,((uchar_t*)src)[0]);
106 v3_outw(port,((ushort_t*)src)[0]);
109 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;
214 list_for_each_entry(tmp, &(state->port_range), range_list) {
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_range), range_list) {
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_range), range_list) {
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_range), range_list) {
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);
316 PrintDebug("generic: unhooking irqs not supported\n");
321 struct mem_range * tmp;
322 struct mem_range * cur;
324 list_for_each_entry_safe(cur, tmp, &(state->mem_range), range_list) {
326 PrintDebug("generic: unhooking addresses 0x%x to 0x%x\n",
327 cur->start, cur->end);
329 if (dev_unhook_mem(dev, cur->start, cur->end)) {
330 PrintDebug("generic: Can't unhook addresses 0x%x to 0x%x (already unhooked?)\n",
331 cur->start, cur->end);
337 PrintDebug("generic: unhooking addresses not supported\n");
342 struct port_range * tmp;
343 struct port_range * cur;
345 list_for_each_entry_safe(cur, tmp, &(state->mem_range), range_list) {
348 PrintDebug("generic: unhooking ports 0x%x to 0x%x\n",
349 cur->start, cur->end);
351 for (i = cur->start; i <= cur->end; i++) {
352 if (dev_unhook_io(dev, i)) {
353 PrintDebug("generic: can't unhook port 0x%x (already unhooked?)\n", i);
360 PrintDebug("generic: unhooking ports not supported\n");
365 generic_reset_device(dev);
373 static struct vm_device_ops dev_ops = {
374 .init = generic_init_device,
375 .deinit = generic_deinit_device,
376 .reset = generic_reset_device,
377 .start = generic_start_device,
378 .stop = generic_stop_device,
384 int v3_generic_add_port_range(struct vm_device * dev, uint_t start, uint_t end, uint_t type) {
387 struct generic_internal * state = (struct generic_internal *)(dev->private_data);
389 struct port_range * range = (struct port_range *)V3_Malloc(sizeof(struct port_range));
390 range->start = start;
394 list_add(&(state->port_range), &(range->range_list));
395 state->num_port_ranges++;
397 PrintDebug("generic: hooking IO ports not supported\n");
404 int v3_generic_add_mem_range(struct vm_device * dev, void * start, void * end, uint_t type) {
407 struct generic_internal * state = (struct generic_internal *)(dev->private_data);
409 struct mem_range * range = (struct mem_range *)V3_Malloc(sizeof(struct mem_range));
410 range->start = start;
414 list_add(&(state->port_range), &(range->range_list));
415 state->num_mem_ranges++;
417 PrintDebug("generic: hooking memory not supported\n");
425 int v3_generic_add_irq_range(struct vm_device * dev, uint_t start, uint_t end, uint_t type) {
428 struct generic_internal * state = (struct generic_internal *)(dev->private_data);
430 struct irq_range * range = (struct irq_range *)V3_Malloc(sizeof(struct irq_range));
431 range->start = start;
435 list_add(&(state->port_range), &(range->range_list));
436 state->num_irq_ranges++;
438 PrintDebug("generic: hooking IRQs not supported\n");
447 struct vm_device *create_generic() {
448 struct generic_internal * generic_state = (struct generic_internal *)V3_Malloc(sizeof(struct generic_internal));
450 generic_state->num_port_ranges = 0;
451 generic_state->num_mem_ranges = 0;
452 generic_state->num_irq_ranges = 0;
454 INIT_LIST_HEAD(&(generic_state->port_range));
455 INIT_LIST_HEAD(&(generic_state->mem_range));
456 INIT_LIST_HEAD(&(generic_state->irq_range));
458 struct vm_device * device = create_device("GENERIC", &dev_ops, generic_state);