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);
197 PrintDebug(core->vm_info, core, " done ... read 0x");
199 for (i = 0; i < rc; i++) {
200 PrintDebug(core->vm_info, core, "%x", ((uint8_t *)src)[i]);
203 PrintDebug(core->vm_info, core, "\n");
209 static int generic_read_port_ignore(struct guest_info * core, uint16_t port, void * src,
210 uint_t length, void * priv_data) {
212 memset((uint8_t *)src, 0, length);
217 static int generic_read_port_print_and_ignore(struct guest_info * core, uint16_t port, void * src,
218 uint_t length, void * priv_data) {
220 #ifdef V3_CONFIG_DEBUG_GENERIC
221 struct generic_internal *state = (struct generic_internal *) priv_data;
224 PrintDebug(core->vm_info, core, "generic (%s): reading 0x%x bytes from port 0x%x using %s ...", state->name, length, port,
225 state->forward_type == GENERIC_PHYSICAL ? "physical" :
226 state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
229 memset((uint8_t *)src, 0, length);
230 PrintDebug(core->vm_info, core, " ignored (return zeroed buffer)\n");
235 static int generic_write_port_ignore(struct guest_info * core, uint16_t port, void * src,
236 uint_t length, void * priv_data) {
241 static int generic_write_port_print_and_ignore(struct guest_info * core, uint16_t port, void * src,
242 uint_t length, void * priv_data) {
245 #ifdef V3_CONFIG_DEBUG_GENERIC
246 struct generic_internal *state = (struct generic_internal *) priv_data;
249 PrintDebug(core->vm_info, core, "generic (%s): writing 0x%x bytes to port 0x%x using %s ", state->name, length, port,
250 state->forward_type == GENERIC_PHYSICAL ? "physical" :
251 state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
253 memset((uint8_t *)src, 0, length);
254 PrintDebug(core->vm_info, core, " ignored - data was: 0x");
256 for (i = 0; i < length; i++) {
257 PrintDebug(core->vm_info, core, "%x", ((uint8_t *)src)[i]);
260 PrintDebug(core->vm_info, core, "\n");
267 static int generic_write_mem_passthrough(struct guest_info * core,
273 struct vm_device *dev = (struct vm_device *) priv;
274 struct generic_internal *state = (struct generic_internal *) dev->private_data;
276 switch (state->forward_type) {
277 case GENERIC_PHYSICAL:
278 memcpy(V3_VAddr((void*)gpa),src,len);
281 #ifdef V3_CONFIG_HOST_DEVICE
283 if (state->host_dev) {
284 return v3_host_dev_write_mem(state->host_dev,gpa,src,len);
291 PrintError(core->vm_info, core, "generic (%s): unknown forwarding type\n", state->name);
297 static int generic_write_mem_print_and_passthrough(struct guest_info * core,
303 #ifdef V3_CONFIG_DEBUG_GENERIC
304 struct vm_device *dev = (struct vm_device *) priv;
305 struct generic_internal *state = (struct generic_internal *) dev->private_data;
308 PrintDebug(core->vm_info, core, "generic (%s): writing %u bytes to GPA 0x%p via %s ... ", state->name,
310 state->forward_type == GENERIC_PHYSICAL ? "physical" :
311 state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
313 int rc = generic_write_mem_passthrough(core,gpa,src,len,priv);
315 PrintDebug(core->vm_info, core, "done\n");
320 static int generic_write_mem_ignore(struct guest_info * core,
329 static int generic_write_mem_print_and_ignore(struct guest_info * core,
335 #ifdef V3_CONFIG_DEBUG_GENERIC
336 struct vm_device *dev = (struct vm_device *) priv;
337 struct generic_internal *state = (struct generic_internal *) dev->private_data;
340 PrintDebug(core->vm_info, core, "generic (%s): ignoring write of %u bytes to GPA 0x%p via %s", state->name,
342 state->forward_type == GENERIC_PHYSICAL ? "physical" :
343 state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
348 static int generic_read_mem_passthrough(struct guest_info * core,
354 struct vm_device *dev = (struct vm_device *) priv;
355 struct generic_internal *state = (struct generic_internal *) dev->private_data;
357 switch (state->forward_type) {
358 case GENERIC_PHYSICAL:
359 memcpy(dst,V3_VAddr((void*)gpa),len);
362 #ifdef V3_CONFIG_HOST_DEVICE
364 if (state->host_dev) {
365 return v3_host_dev_read_mem(state->host_dev,gpa,dst,len);
372 PrintError(core->vm_info, core, "generic (%s): unknown forwarding type\n", state->name);
379 static int generic_read_mem_print_and_passthrough(struct guest_info * core,
385 #ifdef V3_CONFIG_DEBUG_GENERIC
386 struct vm_device *dev = (struct vm_device *) priv;
387 struct generic_internal *state = (struct generic_internal *) dev->private_data;
390 PrintDebug(core->vm_info, core, "generic (%s): attempting to read %u bytes from GPA 0x%p via %s ... ", state->name,
392 state->forward_type == GENERIC_PHYSICAL ? "physical" :
393 state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
395 int rc = generic_read_mem_passthrough(core,gpa,dst,len,priv);
397 PrintDebug(core->vm_info, core, "done - read %d bytes\n", rc);
402 static int generic_read_mem_ignore(struct guest_info * core,
408 #ifdef V3_CONFIG_DEBUG_GENERIC
409 struct vm_device *dev = (struct vm_device *) priv;
410 struct generic_internal *state = (struct generic_internal *) dev->private_data;
413 PrintDebug(core->vm_info, core, "generic (%s): ignoring attempt to read %u bytes from GPA 0x%p via %s ... ", state->name,
415 state->forward_type == GENERIC_PHYSICAL ? "physical" :
416 state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
418 memset((uint8_t *)dst, 0, len);
420 PrintDebug(core->vm_info, core, "returning zeros\n");
426 static int generic_read_mem_print_and_ignore(struct guest_info * core,
432 memset((uint8_t *)dst, 0, len);
437 static int generic_free(struct generic_internal * state) {
440 PrintDebug(VM_NONE,VCORE_NONE, "generic (%s): deinit_device\n", state->name);
442 #ifdef V3_CONFIG_HOST_DEVICE
443 if (state->host_dev) {
444 v3_host_dev_close(state->host_dev);
449 // Note that the device manager handles unhooking the I/O ports
450 // We need to handle unhooking memory regions
451 for (i=0;i<state->num_mem_hooks;i++) {
452 if (v3_unhook_mem(state->dev->vm,V3_MEM_CORE_ANY,state->mem_hook[i])<0) {
453 PrintError(VM_NONE,VCORE_NONE , "generic (%s): unable to unhook memory starting at 0x%p\n", state->name,(void*)(state->mem_hook[i]));
466 static struct v3_device_ops dev_ops = {
467 .free = (int (*)(void *))generic_free,
473 static int add_port_range(struct vm_device * dev, uint_t start, uint_t end, generic_mode_t mode) {
476 struct generic_internal *state = (struct generic_internal *) dev->private_data;
478 PrintDebug(VM_NONE, VCORE_NONE, "generic (%s): adding port range 0x%x to 0x%x as %s\n", state->name,
480 (mode == GENERIC_PRINT_AND_PASSTHROUGH) ? "print-and-passthrough" :
481 (mode == GENERIC_PRINT_AND_IGNORE) ? "print-and-ignore" :
482 (mode == GENERIC_PASSTHROUGH) ? "passthrough" :
483 (mode == GENERIC_IGNORE) ? "ignore" : "UNKNOWN");
485 for (i = start; i <= end; i++) {
487 case GENERIC_PRINT_AND_PASSTHROUGH:
488 if (v3_dev_hook_io(dev, i,
489 &generic_read_port_print_and_passthrough,
490 &generic_write_port_print_and_passthrough) == -1) {
491 PrintError(VM_NONE, VCORE_NONE, "generic (%s): can't hook port 0x%x (already hooked?)\n", state->name, i);
496 case GENERIC_PRINT_AND_IGNORE:
497 if (v3_dev_hook_io(dev, i,
498 &generic_read_port_print_and_ignore,
499 &generic_write_port_print_and_ignore) == -1) {
500 PrintError(VM_NONE, VCORE_NONE, "generic (%s): can't hook port 0x%x (already hooked?)\n", state->name, i);
504 case GENERIC_PASSTHROUGH:
505 if (v3_dev_hook_io(dev, i,
506 &generic_read_port_passthrough,
507 &generic_write_port_passthrough) == -1) {
508 PrintError(VM_NONE, VCORE_NONE, "generic (%s): can't hook port 0x%x (already hooked?)\n", state->name, i);
513 if (v3_dev_hook_io(dev, i,
514 &generic_read_port_ignore,
515 &generic_write_port_ignore) == -1) {
516 PrintError(VM_NONE, VCORE_NONE, "generic (%s): can't hook port 0x%x (already hooked?)\n", state->name, i);
521 PrintError(VM_NONE, VCORE_NONE, "generic (%s): huh?\n", state->name);
530 static int add_mem_range(struct vm_device * dev, addr_t start, addr_t end, generic_mode_t mode) {
532 struct generic_internal *state = (struct generic_internal *) dev->private_data;
534 PrintDebug(VM_NONE, VCORE_NONE, "generic (%s): adding memory range 0x%p to 0x%p as %s\n", state->name,
535 (void*)start, (void*)end,
536 (mode == GENERIC_PRINT_AND_PASSTHROUGH) ? "print-and-passthrough" :
537 (mode == GENERIC_PRINT_AND_IGNORE) ? "print-and-ignore" :
538 (mode == GENERIC_PASSTHROUGH) ? "passthrough" :
539 (mode == GENERIC_IGNORE) ? "ignore" : "UNKNOWN");
542 case GENERIC_PRINT_AND_PASSTHROUGH:
543 if (v3_hook_full_mem(dev->vm, V3_MEM_CORE_ANY, start, end+1,
544 &generic_read_mem_print_and_passthrough,
545 &generic_write_mem_print_and_passthrough, dev) == -1) {
546 PrintError(VM_NONE, VCORE_NONE, "generic (%s): can't hook memory region 0x%p to 0x%p\n", state->name,(void*)start,(void*)end);
551 case GENERIC_PRINT_AND_IGNORE:
552 if (v3_hook_full_mem(dev->vm, V3_MEM_CORE_ANY, start, end+1,
553 &generic_read_mem_print_and_ignore,
554 &generic_write_mem_print_and_ignore, dev) == -1) {
555 PrintError(VM_NONE, VCORE_NONE, "generic (%s): can't hook memory region 0x%p to 0x%p\n", state->name,(void*)start,(void*)end);
560 case GENERIC_PASSTHROUGH:
561 if (v3_hook_full_mem(dev->vm, V3_MEM_CORE_ANY, start, end+1,
562 &generic_read_mem_passthrough,
563 &generic_write_mem_passthrough, dev) == -1) {
564 PrintError(VM_NONE, VCORE_NONE, "generic (%s): can't hook memory region 0x%p to 0x%p\n", state->name,(void*)start,(void*)end);
570 if (v3_hook_full_mem(dev->vm, V3_MEM_CORE_ANY, start, end+1,
571 &generic_read_mem_ignore,
572 &generic_write_mem_ignore, dev) == -1) {
573 PrintError(VM_NONE, VCORE_NONE, "generic (%s): can't hook memory region 0x%p to 0x%p\n", state->name,(void*)start,(void*)end);
578 PrintError(VM_NONE, VCORE_NONE, "generic (%s): huh?\n",state->name);
588 //This is a hack for host device testing and will be removed
590 static int osdebug_hcall(struct guest_info *core, uint_t hcall_id, void * priv_data)
592 struct generic_internal * state = (struct generic_internal *)priv_data;
594 int msg_len = core->vm_regs.rcx;
595 addr_t msg_gpa = core->vm_regs.rbx;
596 int buf_is_va = core->vm_regs.rdx;
599 PrintDebug(core->vm_info, core, "generic (%s): handling hypercall (len=%d) as sequence of port writes\n",
600 state->name, msg_len);
603 for (i=0;i<msg_len;i++) {
604 if (buf_is_va == 1) {
605 if (v3_read_gva_memory(core, msg_gpa+i, 1, &c) != 1) {
606 PrintError(core->vm_info, core, "generic (%s): could not read debug message\n",state->name);
610 if (v3_read_gpa_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 (generic_write_port_print_and_passthrough(core,0xc0c0,&c,1,priv_data)!=1) {
616 PrintError(core->vm_info, core, "generic (%s): write port passthrough failed\n",state->name);
626 #ifdef V3_CONFIG_HOST_DEVICE
627 static void generic_intr_update_callback(v3_host_dev_t hdev, v3_guest_dev_t gdev, uint8_t irq, int raise)
630 struct vm_device *dev = (struct vm_device *) gdev;
632 v3_raise_irq(dev->vm,irq);
634 v3_lower_irq(dev->vm,irq);
641 The device can be used to forward to the underlying physical device
642 or to a host device that has a given url. Both memory and ports can be forwarded as
644 GENERIC_PASSTHROUGH => send writes and reads to physical device or host
645 GENERIC_PRINT_AND_PASSTHROUGH => also print what it's doing
647 GENERIC_IGNORE => ignore writes and reads
648 GENERIC_PRINT_AND_PASSTHROUGH => also print what it's doing
651 The purpose of the "PRINT" variants is to make it easy to spy on
652 device interactions (although you will not see DMA or interrupts)
655 <device class="generic" id="my_id"
656 empty | forward="physical_device" or forward="host_device" hostdev="url">
658 (empty implies physical_dev)
661 <start>portno1</start>
662 <end>portno2</end> => portno1 through portno2 (inclusive)
663 <mode>PRINT_AND_PASSTHROUGH</mode> (as above)
668 <end>gpa2</end> => memory addreses gpa1 through gpa2 (inclusive); page granularity
669 <mode> ... as above </mode>
674 static int generic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
675 struct generic_internal * state = NULL;
676 char * dev_id = v3_cfg_val(cfg, "ID");
677 char * forward = v3_cfg_val(cfg, "forward");
678 #ifdef V3_CONFIG_HOST_DEVICE
679 char * host_dev = v3_cfg_val(cfg, "hostdev");
681 v3_cfg_tree_t * port_cfg = v3_cfg_subtree(cfg, "ports");
682 v3_cfg_tree_t * mem_cfg = v3_cfg_subtree(cfg, "memory");
685 state = (struct generic_internal *)V3_Malloc(sizeof(struct generic_internal));
688 PrintError(vm, VCORE_NONE, "generic (%s): could not allocate generic state\n",dev_id);
692 memset(state, 0, sizeof(struct generic_internal));
693 strncpy(state->name,dev_id,MAX_NAME);
694 state->name[MAX_NAME-1] = 0;
697 state->forward_type=GENERIC_PHYSICAL;
699 if (!strcasecmp(forward,"physical_device")) {
700 state->forward_type=GENERIC_PHYSICAL;
701 } else if (!strcasecmp(forward,"host_device")) {
702 #ifdef V3_CONFIG_HOST_DEVICE
703 state->forward_type=GENERIC_HOST;
705 PrintError(vm, VCORE_NONE, "generic (%s): cannot configure host device since host device support is not built in\n", state->name);
710 PrintError(vm, VCORE_NONE, "generic (%s): unknown forwarding type \"%s\"\n", state->name, forward);
716 struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, state);
719 PrintError(vm, VCORE_NONE, "generic: could not attach device %s\n", state->name);
727 #ifdef V3_CONFIG_HOST_DEVICE
728 if (state->forward_type==GENERIC_HOST) {
730 PrintError(vm, VCORE_NONE, "generic (%s): host forwarding requested, but no host device given\n", state->name);
731 v3_remove_device(dev);
734 state->host_dev = v3_host_dev_open(host_dev,V3_BUS_CLASS_DIRECT,dev,generic_intr_update_callback,vm);
735 if (!(state->host_dev)) {
736 PrintError(vm, VCORE_NONE, "generic (%s): unable to open host device \"%s\"\n", state->name,host_dev);
737 v3_remove_device(dev);
740 PrintDebug(vm, VCORE_NONE, "generic (%s): successfully attached host device \"%s\"\n", state->name,host_dev);
746 PrintDebug(vm, VCORE_NONE, "generic (%s): init_device\n", state->name);
748 // scan port list....
750 uint16_t start = atox(v3_cfg_val(port_cfg, "start"));
751 uint16_t end = atox(v3_cfg_val(port_cfg, "end"));
752 char * mode_str = v3_cfg_val(port_cfg, "mode");
754 PrintError(vm, VCORE_NONE, "generic (%s): error getting port mode\n", state->name);
757 generic_mode_t mode = GENERIC_IGNORE;
758 if (strcasecmp(mode_str, "print_and_ignore") == 0) {
759 mode = GENERIC_PRINT_AND_IGNORE;
760 } else if (strcasecmp(mode_str, "print_and_passthrough") == 0) {
761 mode = GENERIC_PRINT_AND_PASSTHROUGH;
762 } else if (strcasecmp(mode_str, "passthrough") == 0) {
763 mode = GENERIC_PASSTHROUGH;
764 } else if (strcasecmp(mode_str, "ignore") == 0) {
765 mode = GENERIC_IGNORE;
767 PrintError(vm, VCORE_NONE, "generic (%s): invalid mode %s in adding ports\n", state->name, mode_str);
768 v3_remove_device(dev);
773 if (add_port_range(dev, start, end, mode) == -1) {
774 PrintError(vm, VCORE_NONE, "generic (%s): could not add port range 0x%x to 0x%x\n", state->name, start, end);
775 v3_remove_device(dev);
779 port_cfg = v3_cfg_next_branch(port_cfg);
782 // scan memory list....
784 addr_t start = atox(v3_cfg_val(mem_cfg, "start"));
785 addr_t end = atox(v3_cfg_val(mem_cfg, "end"));
786 char * mode_str = v3_cfg_val(mem_cfg, "mode");
787 generic_mode_t mode = GENERIC_IGNORE;
789 if (strcasecmp(mode_str, "print_and_ignore") == 0) {
790 mode = GENERIC_PRINT_AND_IGNORE;
791 } else if (strcasecmp(mode_str, "print_and_passthrough") == 0) {
792 mode = GENERIC_PRINT_AND_PASSTHROUGH;
793 } else if (strcasecmp(mode_str, "passthrough") == 0) {
794 mode = GENERIC_PASSTHROUGH;
795 } else if (strcasecmp(mode_str, "ignore") == 0) {
796 mode = GENERIC_IGNORE;
798 PrintError(vm, VCORE_NONE, "generic (%s): invalid mode %s for adding memory\n", state->name, mode_str);
799 v3_remove_device(dev);
803 if (state->num_mem_hooks>=MAX_MEM_HOOKS) {
804 PrintError(vm, VCORE_NONE, "generic (%s): cannot add another memory hook (increase MAX_MEM_HOOKS)\n", state->name);
805 v3_remove_device(dev);
809 if (add_mem_range(dev, start, end, mode) == -1) {
810 PrintError(vm, VCORE_NONE, "generic (%s): could not add memory range 0x%p to 0x%p\n", state->name, (void*)start, (void*)end);
811 v3_remove_device(dev);
815 state->mem_hook[state->num_mem_hooks] = start;
816 state->num_mem_hooks++;
818 mem_cfg = v3_cfg_next_branch(port_cfg);
822 // hack for os debug testing
823 if (strcasecmp(state->name,"os debug")==0) {
824 PrintDebug(vm, VCORE_NONE, "generic (%s): adding hypercall for os debug device\n", state->name);
825 v3_register_hypercall(vm,0xc0c0,osdebug_hcall,state);
829 PrintDebug(vm, VCORE_NONE, "generic (%s): initialization complete\n", state->name);
834 device_register("GENERIC", generic_init)