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.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
10 * Copyright (c) 2008, Peter Dinda <pdinda@northwestern.edu>
11 * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
12 * All rights reserved.
14 * Author: Peter Dinda <pdinda@northwestern.edu>
15 * Contributor: 2008, Jack Lange <jarusl@cs.northwestern.edu>
18 * This is free software. You are permitted to use,
19 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
22 #include <palacios/vmm.h>
23 #include <palacios/vmm_types.h>
24 #include <palacios/vmm_list.h>
25 #include <palacios/vmm_io.h>
26 #include <palacios/vmm_dev_mgr.h>
27 #include <palacios/vm_guest_mem.h>
29 #ifdef V3_CONFIG_HOST_DEVICE
30 #include <interfaces/vmm_host_dev.h>
33 #ifndef V3_CONFIG_DEBUG_GENERIC
35 #define PrintDebug(fmt, args...)
39 #define MAX_MEM_HOOKS 16
41 typedef enum {GENERIC_IGNORE,
43 GENERIC_PRINT_AND_PASSTHROUGH,
44 GENERIC_PRINT_AND_IGNORE} generic_mode_t;
46 struct generic_internal {
47 enum {GENERIC_PHYSICAL, GENERIC_HOST} forward_type;
48 #ifdef V3_CONFIG_HOST_DEVICE
49 v3_host_dev_t host_dev;
51 struct vm_device *dev; // me
55 uint32_t num_mem_hooks;
56 addr_t mem_hook[MAX_MEM_HOOKS];
62 static int generic_write_port_passthrough(struct guest_info * core,
68 struct generic_internal *state = (struct generic_internal *) priv_data;
71 switch (state->forward_type) {
72 case GENERIC_PHYSICAL:
75 v3_outb(port, ((uint8_t *)src)[0]);
78 v3_outw(port, ((uint16_t *)src)[0]);
81 v3_outdw(port, ((uint32_t *)src)[0]);
84 for (i = 0; i < length; i++) {
85 v3_outb(port, ((uint8_t *)src)[i]);
91 #ifdef V3_CONFIG_HOST_DEVICE
93 if (state->host_dev) {
94 return v3_host_dev_write_io(state->host_dev,port,src,length);
101 PrintError(core->vm_info, core, "generic (%s): unknown forwarding type\n", state->name);
107 static int generic_write_port_print_and_passthrough(struct guest_info * core, uint16_t port, void * src,
108 uint_t length, void * priv_data) {
112 #ifdef V3_CONFIG_DEBUG_GENERIC
113 struct generic_internal *state = (struct generic_internal *) priv_data;
116 PrintDebug(core->vm_info, core, "generic (%s): writing 0x%x bytes to port 0x%x using %s ...", state->name,
118 state->forward_type == GENERIC_PHYSICAL ? "physical" :
119 state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
121 PrintDebug(core->vm_info, core, "generic (%s): writing 0x", state->name);
123 for (i = 0; i < length; i++) {
124 PrintDebug(core->vm_info, core, "%x", ((uint8_t *)src)[i]);
127 PrintDebug(core->vm_info, core, " to port 0x%x ... ", port);
129 rc=generic_write_port_passthrough(core,port,src,length,priv_data);
131 PrintDebug(core->vm_info, core, " done\n");
136 static int generic_read_port_passthrough(struct guest_info * core,
142 struct generic_internal *state = (struct generic_internal *) priv_data;
146 switch (state->forward_type) {
147 case GENERIC_PHYSICAL:
150 ((uint8_t *)dst)[0] = v3_inb(port);
153 ((uint16_t *)dst)[0] = v3_inw(port);
156 ((uint32_t *)dst)[0] = v3_indw(port);
159 for (i = 0; i < length; i++) {
160 ((uint8_t *)dst)[i] = v3_inb(port);
165 #ifdef V3_CONFIG_HOST_DEVICE
167 if (state->host_dev) {
168 return v3_host_dev_read_io(state->host_dev,port,dst,length);
173 PrintError(core->vm_info, core, "generic (%s): unknown forwarding type\n", state->name);
181 static int generic_read_port_print_and_passthrough(struct guest_info * core, uint16_t port, void * src,
182 uint_t length, void * priv_data) {
186 #ifdef V3_CONFIG_DEBUG_GENERIC
187 struct generic_internal *state = (struct generic_internal *) priv_data;
190 PrintDebug(core->vm_info, core, "generic (%s): reading 0x%x bytes from port 0x%x using %s ...", state->name, length, port,
191 state->forward_type == GENERIC_PHYSICAL ? "physical" :
192 state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
195 rc=generic_read_port_passthrough(core,port,src,length,priv_data);
198 PrintError(core->vm_info, core, "FAILED\n");
201 PrintDebug(core->vm_info, core, " done ... read 0x");
203 for (i = 0; i < rc; i++) {
204 PrintDebug(core->vm_info, core, "%x", ((uint8_t *)src)[i]);
207 PrintDebug(core->vm_info, core, "\n");
214 static int generic_read_port_ignore(struct guest_info * core, uint16_t port, void * src,
215 uint_t length, void * priv_data) {
217 memset((uint8_t *)src, 0, length);
222 static int generic_read_port_print_and_ignore(struct guest_info * core, uint16_t port, void * src,
223 uint_t length, void * priv_data) {
225 #ifdef V3_CONFIG_DEBUG_GENERIC
226 struct generic_internal *state = (struct generic_internal *) priv_data;
229 PrintDebug(core->vm_info, core, "generic (%s): reading 0x%x bytes from port 0x%x using %s ...", state->name, length, port,
230 state->forward_type == GENERIC_PHYSICAL ? "physical" :
231 state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
234 memset((uint8_t *)src, 0, length);
235 PrintDebug(core->vm_info, core, " ignored (return zeroed buffer)\n");
240 static int generic_write_port_ignore(struct guest_info * core, uint16_t port, void * src,
241 uint_t length, void * priv_data) {
246 static int generic_write_port_print_and_ignore(struct guest_info * core, uint16_t port, void * src,
247 uint_t length, void * priv_data) {
250 #ifdef V3_CONFIG_DEBUG_GENERIC
251 struct generic_internal *state = (struct generic_internal *) priv_data;
254 PrintDebug(core->vm_info, core, "generic (%s): writing 0x%x bytes to port 0x%x using %s ", state->name, length, port,
255 state->forward_type == GENERIC_PHYSICAL ? "physical" :
256 state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
258 memset((uint8_t *)src, 0, length);
259 PrintDebug(core->vm_info, core, " ignored - data was: 0x");
261 for (i = 0; i < length; i++) {
262 PrintDebug(core->vm_info, core, "%x", ((uint8_t *)src)[i]);
265 PrintDebug(core->vm_info, core, "\n");
272 static int generic_write_mem_passthrough(struct guest_info * core,
278 struct vm_device *dev = (struct vm_device *) priv;
279 struct generic_internal *state = (struct generic_internal *) dev->private_data;
281 switch (state->forward_type) {
282 case GENERIC_PHYSICAL:
283 memcpy(V3_VAddr((void*)gpa),src,len);
286 #ifdef V3_CONFIG_HOST_DEVICE
288 if (state->host_dev) {
289 return v3_host_dev_write_mem(state->host_dev,gpa,src,len);
296 PrintError(core->vm_info, core, "generic (%s): unknown forwarding type\n", state->name);
302 static int generic_write_mem_print_and_passthrough(struct guest_info * core,
308 #ifdef V3_CONFIG_DEBUG_GENERIC
309 struct vm_device *dev = (struct vm_device *) priv;
310 struct generic_internal *state = (struct generic_internal *) dev->private_data;
313 PrintDebug(core->vm_info, core, "generic (%s): writing %u bytes to GPA 0x%p via %s ... ", state->name,
315 state->forward_type == GENERIC_PHYSICAL ? "physical" :
316 state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
318 int rc = generic_write_mem_passthrough(core,gpa,src,len,priv);
320 PrintDebug(core->vm_info, core, "done\n");
325 static int generic_write_mem_ignore(struct guest_info * core,
334 static int generic_write_mem_print_and_ignore(struct guest_info * core,
340 #ifdef V3_CONFIG_DEBUG_GENERIC
341 struct vm_device *dev = (struct vm_device *) priv;
342 struct generic_internal *state = (struct generic_internal *) dev->private_data;
345 PrintDebug(core->vm_info, core, "generic (%s): ignoring write of %u bytes to GPA 0x%p via %s", state->name,
347 state->forward_type == GENERIC_PHYSICAL ? "physical" :
348 state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
353 static int generic_read_mem_passthrough(struct guest_info * core,
359 struct vm_device *dev = (struct vm_device *) priv;
360 struct generic_internal *state = (struct generic_internal *) dev->private_data;
362 switch (state->forward_type) {
363 case GENERIC_PHYSICAL:
364 memcpy(dst,V3_VAddr((void*)gpa),len);
367 #ifdef V3_CONFIG_HOST_DEVICE
369 if (state->host_dev) {
370 return v3_host_dev_read_mem(state->host_dev,gpa,dst,len);
377 PrintError(core->vm_info, core, "generic (%s): unknown forwarding type\n", state->name);
384 static int generic_read_mem_print_and_passthrough(struct guest_info * core,
390 #ifdef V3_CONFIG_DEBUG_GENERIC
391 struct vm_device *dev = (struct vm_device *) priv;
392 struct generic_internal *state = (struct generic_internal *) dev->private_data;
395 PrintDebug(core->vm_info, core, "generic (%s): attempting to read %u bytes from GPA 0x%p via %s ... ", state->name,
397 state->forward_type == GENERIC_PHYSICAL ? "physical" :
398 state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
400 int rc = generic_read_mem_passthrough(core,gpa,dst,len,priv);
402 PrintDebug(core->vm_info, core, "done - read %d bytes\n", rc);
407 static int generic_read_mem_ignore(struct guest_info * core,
413 #ifdef V3_CONFIG_DEBUG_GENERIC
414 struct vm_device *dev = (struct vm_device *) priv;
415 struct generic_internal *state = (struct generic_internal *) dev->private_data;
418 PrintDebug(core->vm_info, core, "generic (%s): ignoring attempt to read %u bytes from GPA 0x%p via %s ... ", state->name,
420 state->forward_type == GENERIC_PHYSICAL ? "physical" :
421 state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
423 memset((uint8_t *)dst, 0, len);
425 PrintDebug(core->vm_info, core, "returning zeros\n");
431 static int generic_read_mem_print_and_ignore(struct guest_info * core,
437 memset((uint8_t *)dst, 0, len);
442 static int generic_free(struct generic_internal * state) {
445 PrintDebug(VM_NONE,VCORE_NONE, "generic (%s): deinit_device\n", state->name);
447 #ifdef V3_CONFIG_HOST_DEVICE
448 if (state->host_dev) {
449 v3_host_dev_close(state->host_dev);
454 // Note that the device manager handles unhooking the I/O ports
455 // We need to handle unhooking memory regions
456 for (i=0;i<state->num_mem_hooks;i++) {
457 if (v3_unhook_mem(state->dev->vm,V3_MEM_CORE_ANY,state->mem_hook[i])<0) {
458 PrintError(VM_NONE,VCORE_NONE , "generic (%s): unable to unhook memory starting at 0x%p\n", state->name,(void*)(state->mem_hook[i]));
471 static struct v3_device_ops dev_ops = {
472 .free = (int (*)(void *))generic_free,
478 static int add_port_range(struct vm_device * dev, uint_t start, uint_t end, generic_mode_t mode) {
481 struct generic_internal *state = (struct generic_internal *) dev->private_data;
483 PrintDebug(VM_NONE, VCORE_NONE, "generic (%s): adding port range 0x%x to 0x%x as %s\n", state->name,
485 (mode == GENERIC_PRINT_AND_PASSTHROUGH) ? "print-and-passthrough" :
486 (mode == GENERIC_PRINT_AND_IGNORE) ? "print-and-ignore" :
487 (mode == GENERIC_PASSTHROUGH) ? "passthrough" :
488 (mode == GENERIC_IGNORE) ? "ignore" : "UNKNOWN");
490 for (i = start; i <= end; i++) {
492 case GENERIC_PRINT_AND_PASSTHROUGH:
493 if (v3_dev_hook_io(dev, i,
494 &generic_read_port_print_and_passthrough,
495 &generic_write_port_print_and_passthrough) == -1) {
496 PrintError(VM_NONE, VCORE_NONE, "generic (%s): can't hook port 0x%x (already hooked?)\n", state->name, i);
501 case GENERIC_PRINT_AND_IGNORE:
502 if (v3_dev_hook_io(dev, i,
503 &generic_read_port_print_and_ignore,
504 &generic_write_port_print_and_ignore) == -1) {
505 PrintError(VM_NONE, VCORE_NONE, "generic (%s): can't hook port 0x%x (already hooked?)\n", state->name, i);
509 case GENERIC_PASSTHROUGH:
510 if (v3_dev_hook_io(dev, i,
511 &generic_read_port_passthrough,
512 &generic_write_port_passthrough) == -1) {
513 PrintError(VM_NONE, VCORE_NONE, "generic (%s): can't hook port 0x%x (already hooked?)\n", state->name, i);
518 if (v3_dev_hook_io(dev, i,
519 &generic_read_port_ignore,
520 &generic_write_port_ignore) == -1) {
521 PrintError(VM_NONE, VCORE_NONE, "generic (%s): can't hook port 0x%x (already hooked?)\n", state->name, i);
526 PrintError(VM_NONE, VCORE_NONE, "generic (%s): huh?\n", state->name);
535 static int add_mem_range(struct vm_device * dev, addr_t start, addr_t end, generic_mode_t mode) {
537 struct generic_internal *state = (struct generic_internal *) dev->private_data;
539 PrintDebug(VM_NONE, VCORE_NONE, "generic (%s): adding memory range 0x%p to 0x%p as %s\n", state->name,
540 (void*)start, (void*)end,
541 (mode == GENERIC_PRINT_AND_PASSTHROUGH) ? "print-and-passthrough" :
542 (mode == GENERIC_PRINT_AND_IGNORE) ? "print-and-ignore" :
543 (mode == GENERIC_PASSTHROUGH) ? "passthrough" :
544 (mode == GENERIC_IGNORE) ? "ignore" : "UNKNOWN");
547 case GENERIC_PRINT_AND_PASSTHROUGH:
548 if (v3_hook_full_mem(dev->vm, V3_MEM_CORE_ANY, start, end+1,
549 &generic_read_mem_print_and_passthrough,
550 &generic_write_mem_print_and_passthrough, dev) == -1) {
551 PrintError(VM_NONE, VCORE_NONE, "generic (%s): can't hook memory region 0x%p to 0x%p\n", state->name,(void*)start,(void*)end);
556 case GENERIC_PRINT_AND_IGNORE:
557 if (v3_hook_full_mem(dev->vm, V3_MEM_CORE_ANY, start, end+1,
558 &generic_read_mem_print_and_ignore,
559 &generic_write_mem_print_and_ignore, dev) == -1) {
560 PrintError(VM_NONE, VCORE_NONE, "generic (%s): can't hook memory region 0x%p to 0x%p\n", state->name,(void*)start,(void*)end);
565 case GENERIC_PASSTHROUGH:
566 if (v3_hook_full_mem(dev->vm, V3_MEM_CORE_ANY, start, end+1,
567 &generic_read_mem_passthrough,
568 &generic_write_mem_passthrough, dev) == -1) {
569 PrintError(VM_NONE, VCORE_NONE, "generic (%s): can't hook memory region 0x%p to 0x%p\n", state->name,(void*)start,(void*)end);
575 if (v3_hook_full_mem(dev->vm, V3_MEM_CORE_ANY, start, end+1,
576 &generic_read_mem_ignore,
577 &generic_write_mem_ignore, dev) == -1) {
578 PrintError(VM_NONE, VCORE_NONE, "generic (%s): can't hook memory region 0x%p to 0x%p\n", state->name,(void*)start,(void*)end);
583 PrintError(VM_NONE, VCORE_NONE, "generic (%s): huh?\n",state->name);
593 //This is a hack for host device testing and will be removed
595 static int osdebug_hcall(struct guest_info *core, uint_t hcall_id, void * priv_data)
597 struct generic_internal * state = (struct generic_internal *)priv_data;
599 int msg_len = core->vm_regs.rcx;
600 addr_t msg_gpa = core->vm_regs.rbx;
601 int buf_is_va = core->vm_regs.rdx;
604 PrintDebug(core->vm_info, core, "generic (%s): handling hypercall (len=%d) as sequence of port writes\n",
605 state->name, msg_len);
608 for (i=0;i<msg_len;i++) {
609 if (buf_is_va == 1) {
610 if (v3_read_gva_memory(core, msg_gpa+i, 1, &c) != 1) {
611 PrintError(core->vm_info, core, "generic (%s): could not read debug message\n",state->name);
615 if (v3_read_gpa_memory(core, msg_gpa+i, 1, &c) != 1) {
616 PrintError(core->vm_info, core, "generic (%s): Could not read debug message\n",state->name);
620 if (generic_write_port_print_and_passthrough(core,0xc0c0,&c,1,priv_data)!=1) {
621 PrintError(core->vm_info, core, "generic (%s): write port passthrough failed\n",state->name);
631 #ifdef V3_CONFIG_HOST_DEVICE
632 static void generic_intr_update_callback(v3_host_dev_t hdev, v3_guest_dev_t gdev, uint8_t irq, int raise)
635 struct vm_device *dev = (struct vm_device *) gdev;
637 v3_raise_irq(dev->vm,irq);
639 v3_lower_irq(dev->vm,irq);
646 The device can be used to forward to the underlying physical device
647 or to a host device that has a given url. Both memory and ports can be forwarded as
649 GENERIC_PASSTHROUGH => send writes and reads to physical device or host
650 GENERIC_PRINT_AND_PASSTHROUGH => also print what it's doing
652 GENERIC_IGNORE => ignore writes and reads
653 GENERIC_PRINT_AND_PASSTHROUGH => also print what it's doing
656 The purpose of the "PRINT" variants is to make it easy to spy on
657 device interactions (although you will not see DMA or interrupts)
660 <device class="generic" id="my_id"
661 empty | forward="physical_device" or forward="host_device" hostdev="url">
663 (empty implies physical_dev)
666 <start>portno1</start>
667 <end>portno2</end> => portno1 through portno2 (inclusive)
668 <mode>PRINT_AND_PASSTHROUGH</mode> (as above)
673 <end>gpa2</end> => memory addreses gpa1 through gpa2 (inclusive); page granularity
674 <mode> ... as above </mode>
679 static int generic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
680 struct generic_internal * state = NULL;
681 char * dev_id = v3_cfg_val(cfg, "ID");
682 char * forward = v3_cfg_val(cfg, "forward");
683 #ifdef V3_CONFIG_HOST_DEVICE
684 char * host_dev = v3_cfg_val(cfg, "hostdev");
686 v3_cfg_tree_t * port_cfg = v3_cfg_subtree(cfg, "ports");
687 v3_cfg_tree_t * mem_cfg = v3_cfg_subtree(cfg, "memory");
690 state = (struct generic_internal *)V3_Malloc(sizeof(struct generic_internal));
693 PrintError(vm, VCORE_NONE, "generic (%s): could not allocate generic state\n",dev_id);
697 memset(state, 0, sizeof(struct generic_internal));
698 strncpy(state->name,dev_id,MAX_NAME);
699 state->name[MAX_NAME-1] = 0;
702 state->forward_type=GENERIC_PHYSICAL;
704 if (!strcasecmp(forward,"physical_device")) {
705 state->forward_type=GENERIC_PHYSICAL;
706 } else if (!strcasecmp(forward,"host_device")) {
707 #ifdef V3_CONFIG_HOST_DEVICE
708 state->forward_type=GENERIC_HOST;
710 PrintError(vm, VCORE_NONE, "generic (%s): cannot configure host device since host device support is not built in\n", state->name);
715 PrintError(vm, VCORE_NONE, "generic (%s): unknown forwarding type \"%s\"\n", state->name, forward);
721 struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, state);
724 PrintError(vm, VCORE_NONE, "generic: could not attach device %s\n", state->name);
732 #ifdef V3_CONFIG_HOST_DEVICE
733 if (state->forward_type==GENERIC_HOST) {
735 PrintError(vm, VCORE_NONE, "generic (%s): host forwarding requested, but no host device given\n", state->name);
736 v3_remove_device(dev);
739 state->host_dev = v3_host_dev_open(host_dev,V3_BUS_CLASS_DIRECT,dev,generic_intr_update_callback,vm);
740 if (!(state->host_dev)) {
741 PrintError(vm, VCORE_NONE, "generic (%s): unable to open host device \"%s\"\n", state->name,host_dev);
742 v3_remove_device(dev);
745 PrintDebug(vm, VCORE_NONE, "generic (%s): successfully attached host device \"%s\"\n", state->name,host_dev);
751 PrintDebug(vm, VCORE_NONE, "generic (%s): init_device\n", state->name);
753 // scan port list....
755 uint16_t start = atox(v3_cfg_val(port_cfg, "start"));
756 uint16_t end = atox(v3_cfg_val(port_cfg, "end"));
757 char * mode_str = v3_cfg_val(port_cfg, "mode");
759 PrintError(vm, VCORE_NONE, "generic (%s): error getting port mode\n", state->name);
762 generic_mode_t mode = GENERIC_IGNORE;
763 if (strcasecmp(mode_str, "print_and_ignore") == 0) {
764 mode = GENERIC_PRINT_AND_IGNORE;
765 } else if (strcasecmp(mode_str, "print_and_passthrough") == 0) {
766 mode = GENERIC_PRINT_AND_PASSTHROUGH;
767 } else if (strcasecmp(mode_str, "passthrough") == 0) {
768 mode = GENERIC_PASSTHROUGH;
769 } else if (strcasecmp(mode_str, "ignore") == 0) {
770 mode = GENERIC_IGNORE;
772 PrintError(vm, VCORE_NONE, "generic (%s): invalid mode %s in adding ports\n", state->name, mode_str);
773 v3_remove_device(dev);
778 if (add_port_range(dev, start, end, mode) == -1) {
779 PrintError(vm, VCORE_NONE, "generic (%s): could not add port range 0x%x to 0x%x\n", state->name, start, end);
780 v3_remove_device(dev);
784 port_cfg = v3_cfg_next_branch(port_cfg);
787 // scan memory list....
789 addr_t start = atox(v3_cfg_val(mem_cfg, "start"));
790 addr_t end = atox(v3_cfg_val(mem_cfg, "end"));
791 char * mode_str = v3_cfg_val(mem_cfg, "mode");
792 generic_mode_t mode = GENERIC_IGNORE;
794 if (strcasecmp(mode_str, "print_and_ignore") == 0) {
795 mode = GENERIC_PRINT_AND_IGNORE;
796 } else if (strcasecmp(mode_str, "print_and_passthrough") == 0) {
797 mode = GENERIC_PRINT_AND_PASSTHROUGH;
798 } else if (strcasecmp(mode_str, "passthrough") == 0) {
799 mode = GENERIC_PASSTHROUGH;
800 } else if (strcasecmp(mode_str, "ignore") == 0) {
801 mode = GENERIC_IGNORE;
803 PrintError(vm, VCORE_NONE, "generic (%s): invalid mode %s for adding memory\n", state->name, mode_str);
804 v3_remove_device(dev);
808 if (state->num_mem_hooks>=MAX_MEM_HOOKS) {
809 PrintError(vm, VCORE_NONE, "generic (%s): cannot add another memory hook (increase MAX_MEM_HOOKS)\n", state->name);
810 v3_remove_device(dev);
814 if (add_mem_range(dev, start, end, mode) == -1) {
815 PrintError(vm, VCORE_NONE, "generic (%s): could not add memory range 0x%p to 0x%p\n", state->name, (void*)start, (void*)end);
816 v3_remove_device(dev);
820 state->mem_hook[state->num_mem_hooks] = start;
821 state->num_mem_hooks++;
823 mem_cfg = v3_cfg_next_branch(port_cfg);
827 // hack for os debug testing
828 if (strcasecmp(state->name,"os debug")==0) {
829 PrintDebug(vm, VCORE_NONE, "generic (%s): adding hypercall for os debug device\n", state->name);
830 v3_register_hypercall(vm,0xc0c0,osdebug_hcall,state);
834 PrintDebug(vm, VCORE_NONE, "generic (%s): initialization complete\n", state->name);
839 device_register("GENERIC", generic_init)