diff -urN qemu.orig/cpu-all.h qemu.callback_mem/cpu-all.h --- qemu.orig/cpu-all.h 2004-05-21 13:59:13.000000000 +0100 +++ qemu.callback_mem/cpu-all.h 2004-06-01 03:11:05.000000000 +0100 @@ -680,10 +680,28 @@ #define IO_MEM_UNASSIGNED (2 << IO_MEM_SHIFT) #define IO_MEM_CODE (3 << IO_MEM_SHIFT) /* used internally, never use directly */ #define IO_MEM_NOTDIRTY (4 << IO_MEM_SHIFT) /* used internally, never use directly */ +#define IO_MEM_CALLBACK (5 << IO_MEM_SHIFT) /* Callback functions */ typedef void CPUWriteMemoryFunc(target_phys_addr_t addr, uint32_t value); typedef uint32_t CPUReadMemoryFunc(target_phys_addr_t addr); +typedef void (*CPUWriteMemoryCallback)(void *opaque, + target_phys_addr_t addr, + int len, + uint32_t val); +typedef uint32_t (*CPUReadMemoryCallback)(void *opaque, + target_phys_addr_t addr, + int len); + +int cpu_register_callback_memory(target_phys_addr_t start_addr, + unsigned long size, + CPUReadMemoryCallback mem_read, + CPUWriteMemoryCallback mem_write, + void *opaque); +int cpu_unregister_callback_memory(target_phys_addr_t start_addr, + unsigned long size); + + void cpu_register_physical_memory(target_phys_addr_t start_addr, unsigned long size, unsigned long phys_offset); diff -urN qemu.orig/exec.c qemu.callback_mem/exec.c --- qemu.orig/exec.c 2004-05-25 23:48:00.000000000 +0100 +++ qemu.callback_mem/exec.c 2004-06-01 03:42:42.000000000 +0100 @@ -731,6 +731,149 @@ } } +#if defined(CONFIG_SOFTMMU) +struct cpu_callback { + struct cpu_callback *prev, *next; + target_phys_addr_t begin, end; + CPUReadMemoryCallback read; + CPUWriteMemoryCallback write; + void *opaque; +}; + +static struct cpu_callback cpu_cbfn = { + .prev = &cpu_cbfn, + .next = &cpu_cbfn, +}; + +static struct cpu_callback *cpu_cbfn_lookup(target_phys_addr_t begin, + target_phys_addr_t end) +{ + struct cpu_callback *c; + + for(c=cpu_cbfn.next; c != &cpu_cbfn; c=c->next) { + if ( (begin < c->end && end > c->end) || + (end > c->begin && begin < c->begin) ) { + fprintf(stderr, "cpu_cbfn_lookup: %x/%u straddles region: " + "%x-%x\n", begin, end-begin, c->begin, c->end); + } + if ( begin >= c->begin && end <= c->end ) + return c; + } + + fprintf(stderr, "cpu_cbfn_lookup: %x/%u not found\n", begin, end-begin); + return NULL; +} + +static void cpu_cbfn_write(target_phys_addr_t addr, int len, uint32_t value) +{ + struct cpu_callback *c; + c = cpu_cbfn_lookup(addr, addr + len); + if ( c == NULL ) + return; + if ( c->write ) + (*c->write)(c->opaque, addr, len, value); +} + +static uint32_t cpu_cbfn_read(target_phys_addr_t addr, int len) +{ + struct cpu_callback *c; + c = cpu_cbfn_lookup(addr, addr + len); + if ( c == NULL ) + return 0xffffffff; + if ( c->read ) + return (*c->read)(c->opaque, addr, len); + return 0; /* NULL read handler means return all zeros */ +} + +static uint32_t cpu_cbfn_readb(target_phys_addr_t addr) +{ + return cpu_cbfn_read(addr, 1); +} +static uint32_t cpu_cbfn_readw(target_phys_addr_t addr) +{ + return cpu_cbfn_read(addr, 2); +} +static uint32_t cpu_cbfn_readl(target_phys_addr_t addr) +{ + return cpu_cbfn_read(addr, 4); +} +static void cpu_cbfn_writeb(target_phys_addr_t addr, uint32_t value) +{ + return cpu_cbfn_write(addr, 1, value); +} +static void cpu_cbfn_writew(target_phys_addr_t addr, uint32_t value) +{ + return cpu_cbfn_write(addr, 2, value); +} +static void cpu_cbfn_writel(target_phys_addr_t addr, uint32_t value) +{ + return cpu_cbfn_write(addr, 4, value); +} + +static CPUReadMemoryFunc *cpu_callback_read[3]={ + cpu_cbfn_readb, + cpu_cbfn_readw, + cpu_cbfn_readl, +}; +static CPUWriteMemoryFunc *cpu_callback_write[3]={ + cpu_cbfn_writeb, + cpu_cbfn_writew, + cpu_cbfn_writel, +}; + +int cpu_register_callback_memory(target_phys_addr_t start_addr, + unsigned long size, + CPUReadMemoryCallback mem_read, + CPUWriteMemoryCallback mem_write, + void *opaque) +{ + struct cpu_callback *c; + target_phys_addr_t end_addr = start_addr + size; + + /* Check for overlaps (not permitted) */ + for(c=cpu_cbfn.next; c != &cpu_cbfn; c=c->next) { + if ( (c->begin >= start_addr && c->begin <= end_addr) || + (start_addr >= c->begin && start_addr <= c->end) ) { + fprintf(stderr, "mem_callback: %x:%x overlaps %x:%x\n", + start_addr, end_addr, c->begin, c->end); + return 1; + } + } + + c = malloc(sizeof(*c)); + if ( c == NULL ) + return 0; + + c->next = cpu_cbfn.next; + c->next->prev = c; + c->prev = &cpu_cbfn; + c->prev->next = c; + c->begin = start_addr; + c->end = end_addr; + c->read = mem_read; + c->write = mem_write; + c->opaque = opaque; + + cpu_register_physical_memory(start_addr, size, IO_MEM_CALLBACK); + + return 1; +} + +int cpu_unregister_callback_memory(target_phys_addr_t start_addr, + unsigned long size) +{ + struct cpu_callback *c; + c = cpu_cbfn_lookup(start_addr, start_addr + size); + if ( c == NULL ) + return 0; + + c->prev->next = c->next; + c->next->prev = c->prev; + free(c); + return 1; +} +#endif + #if !defined(CONFIG_SOFTMMU) static void tb_invalidate_phys_page(target_ulong addr, unsigned long pc, void *puc) @@ -1901,6 +2044,9 @@ cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write); cpu_register_io_memory(IO_MEM_CODE >> IO_MEM_SHIFT, code_mem_read, code_mem_write); cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, code_mem_read, notdirty_mem_write); +#if defined(CONFIG_SOFTMMU) + cpu_register_io_memory(IO_MEM_CALLBACK >> IO_MEM_SHIFT, cpu_callback_read, cpu_callback_write); +#endif io_mem_nb = 5; /* alloc dirty bits array */