Record which device owns ioports/memports, and use that to grab the appropriate
lock when entering ioport/iomem processing.
Make cpu_physical_memory_rw() unlocked (called from inside device code), and
locking optional from __cpu_physical_memory_rw(), to be called when a vcpu
enters mmio read/write.
The debugging checks should aid finding most problems.
Index: kvm-userspace.io/qemu/exec.c
===================================================================
--- kvm-userspace.io.orig/qemu/exec.c
+++ kvm-userspace.io/qemu/exec.c
@@ -170,6 +170,7 @@ PhysPageDesc **l1_phys_map;
CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
void *io_mem_opaque[IO_MEM_NB_ENTRIES];
+QEMUDevice *io_mem_devices[IO_MEM_NB_ENTRIES];
char io_mem_used[IO_MEM_NB_ENTRIES];
#if defined(CONFIG_SOFTMMU)
static int io_mem_watch;
@@ -2039,6 +2040,11 @@ static inline void tlb_set_dirty(CPUStat
}
#endif /* defined(CONFIG_USER_ONLY) */
+QEMUDevice *qemu_find_device_iomem(int io_index)
+{
+ return io_mem_devices[io_index >> IO_MEM_SHIFT];
+}
+
static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
int memory);
static void *subpage_init (target_phys_addr_t base, uint32_t *phys,
@@ -2502,11 +2508,12 @@ static void *subpage_init (target_phys_a
{
subpage_t *mmio;
int subpage_memory;
+ QEMUDevice *dev = qemu_find_device_iomem(*phys);
mmio = qemu_mallocz(sizeof(subpage_t));
if (mmio != NULL) {
mmio->base = base;
- subpage_memory = cpu_register_io_memory(NULL, 0, subpage_read,
subpage_write, mmio);
+ subpage_memory = cpu_register_io_memory(dev, 0, subpage_read,
subpage_write, mmio);
#if defined(DEBUG_SUBPAGE)
printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
mmio, base, TARGET_PAGE_SIZE, subpage_memory);
@@ -2582,6 +2589,7 @@ int cpu_register_io_memory(QEMUDevice *d
io_mem_write[io_index][i] = mem_write[i];
}
io_mem_opaque[io_index] = opaque;
+ io_mem_devices[io_index] = dev;
return (io_index << IO_MEM_SHIFT) | subwidth;
}
@@ -2651,8 +2659,42 @@ void cpu_physical_memory_rw(target_phys_
}
#else
-void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
- int len, int is_write)
+
+#define WRITE 0x80
+
+void qemu_iomem_dev_lock(int io_index, void *unassigned_io_fn, int iotype,
+ int has_lock)
+{
+ if (!io_mem_devices[io_index]) {
+ void *handler;
+
+ if (iotype & WRITE)
+ handler = io_mem_write[io_index][iotype & ~WRITE];
+ else
+ handler = io_mem_read[io_index][iotype];
+
+ if (handler != unassigned_io_fn)
+ hw_error("iomem %x has no registered QEMUDevice, but has valid "
+ "handling fn\n", io_index);
+ return;
+ }
+ if (has_lock)
+ assert_is_locked(&io_mem_devices[io_index]->lock);
+ else
+ qemu_mutex_lock(&io_mem_devices[io_index]->lock);
+}
+
+void qemu_iomem_dev_unlock(int io_index, int has_lock)
+{
+ if (has_lock)
+ assert_is_locked(&io_mem_devices[io_index]->lock);
+ else if (io_mem_devices[io_index])
+ qemu_mutex_unlock(&io_mem_devices[io_index]->lock);
+}
+
+
+void __cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
+ int len, int is_write, int has_lock)
{
int l, io_index;
uint8_t *ptr;
@@ -2666,6 +2708,7 @@ void cpu_physical_memory_rw(target_phys_
l = (page + TARGET_PAGE_SIZE) - addr;
if (l > len)
l = len;
+ /* FIXME: verify safety of concurrent phys_page_find */
p = phys_page_find(page >> TARGET_PAGE_BITS);
if (!p) {
pd = IO_MEM_UNASSIGNED;
@@ -2681,19 +2724,26 @@ void cpu_physical_memory_rw(target_phys_
if (l >= 4 && ((addr & 3) == 0)) {
/* 32 bit write access */
val = ldl_p(buf);
+ qemu_iomem_dev_lock(io_index, unassigned_mem_writeb,
+ 2|WRITE, has_lock);
io_mem_write[io_index][2](io_mem_opaque[io_index], addr,
val);
l = 4;
} else if (l >= 2 && ((addr & 1) == 0)) {
/* 16 bit write access */
val = lduw_p(buf);
+ qemu_iomem_dev_lock(io_index, unassigned_mem_writeb,
+ 1|WRITE, has_lock);
io_mem_write[io_index][1](io_mem_opaque[io_index], addr,
val);
l = 2;
} else {
/* 8 bit write access */
val = ldub_p(buf);
+ qemu_iomem_dev_lock(io_index, unassigned_mem_writeb,
+ 0|WRITE, has_lock);
io_mem_write[io_index][0](io_mem_opaque[io_index], addr,
val);
l = 1;
}
+ qemu_iomem_dev_unlock(io_index, has_lock);
} else {
unsigned long addr1;
addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
@@ -2719,21 +2769,28 @@ void cpu_physical_memory_rw(target_phys_
/* I/O case */
io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
if (l >= 4 && ((addr & 3) == 0)) {
+ qemu_iomem_dev_lock(io_index, unassigned_mem_readb, 2,
+ has_lock);
/* 32 bit read access */
val = io_mem_read[io_index][2](io_mem_opaque[io_index],
addr);
stl_p(buf, val);
l = 4;
} else if (l >= 2 && ((addr & 1) == 0)) {
/* 16 bit read access */
+ qemu_iomem_dev_lock(io_index, unassigned_mem_readb, 1,
+ has_lock);
val = io_mem_read[io_index][1](io_mem_opaque[io_index],
addr);
stw_p(buf, val);
l = 2;
} else {
/* 8 bit read access */
+ qemu_iomem_dev_lock(io_index, unassigned_mem_readb, 0,
+ has_lock);
val = io_mem_read[io_index][0](io_mem_opaque[io_index],
addr);
stb_p(buf, val);
l = 1;
}
+ qemu_iomem_dev_unlock(io_index, has_lock);
} else {
/* RAM case */
ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
@@ -2747,6 +2804,13 @@ void cpu_physical_memory_rw(target_phys_
}
}
+void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
+ int len, int is_write)
+{
+ __cpu_physical_memory_rw(addr, buf, len, is_write, 1);
+ return;
+}
+
/* used for ROM loading : can write in RAM and ROM */
void cpu_physical_memory_write_rom(target_phys_addr_t addr,
const uint8_t *buf, int len)
Index: kvm-userspace.io/qemu/vl.c
===================================================================
--- kvm-userspace.io.orig/qemu/vl.c
+++ kvm-userspace.io/qemu/vl.c
@@ -170,6 +170,7 @@ int inet_aton(const char *cp, struct in_
const char *bios_dir = CONFIG_QEMU_SHAREDIR;
const char *bios_name = NULL;
void *ioport_opaque[MAX_IOPORTS];
+QEMUDevice *ioport_devices[MAX_IOPORTS];
IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS];
IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
/* Note: drives_table[MAX_DRIVES] is a dummy block driver if none available
@@ -366,6 +367,10 @@ int register_ioport_read(QEMUDevice *dev
if (ioport_opaque[i] != NULL && ioport_opaque[i] != opaque)
hw_error("register_ioport_read: invalid opaque");
ioport_opaque[i] = opaque;
+
+ if (ioport_devices[i] != NULL && ioport_devices[i] != dev)
+ hw_error("register_ioport_read: invalid device");
+ ioport_devices[i] = dev;
}
return 0;
}
@@ -391,6 +396,10 @@ int register_ioport_write(QEMUDevice *de
if (ioport_opaque[i] != NULL && ioport_opaque[i] != opaque)
hw_error("register_ioport_write: invalid opaque");
ioport_opaque[i] = opaque;
+
+ if (ioport_devices[i] != NULL && ioport_devices[i] != dev)
+ hw_error("register_ioport_write: invalid device");
+ ioport_devices[i] = dev;
}
return 0;
}
@@ -409,18 +418,47 @@ void isa_unassign_ioport(int start, int
ioport_write_table[2][i] = default_ioport_writel;
ioport_opaque[i] = NULL;
+ ioport_devices[i] = NULL;
}
}
+#define WRITE 0x80
+
/***********************************************************/
+void qemu_ioport_dev_lock(int addr, void *unassigned_io_fn, int iotype)
+{
+ if (!ioport_devices[addr]) {
+ void *handler;
+
+ if (iotype & WRITE)
+ handler = ioport_write_table[iotype & ~WRITE][addr];
+ else
+ handler = ioport_read_table[iotype][addr];
+
+ if (handler != unassigned_io_fn)
+ hw_error("ioport %x has no registered QEMUDevice, but has valid "
+ "handling fn\n", addr);
+ return;
+ }
+ qemu_mutex_lock(&ioport_devices[addr]->lock);
+}
+
+void qemu_ioport_dev_unlock(int addr)
+{
+ if (ioport_devices[addr])
+ qemu_mutex_unlock(&ioport_devices[addr]->lock);
+}
+
void cpu_outb(CPUState *env, int addr, int val)
{
#ifdef DEBUG_IOPORT
if (loglevel & CPU_LOG_IOPORT)
fprintf(logfile, "outb: %04x %02x\n", addr, val);
#endif
+ qemu_ioport_dev_lock(addr, default_ioport_writeb, 0|WRITE);
ioport_write_table[0][addr](ioport_opaque[addr], addr, val);
+ qemu_ioport_dev_unlock(addr);
#ifdef USE_KQEMU
if (env)
env->last_io_time = cpu_get_time_fast();
@@ -433,7 +471,9 @@ void cpu_outw(CPUState *env, int addr, i
if (loglevel & CPU_LOG_IOPORT)
fprintf(logfile, "outw: %04x %04x\n", addr, val);
#endif
+ qemu_ioport_dev_lock(addr, default_ioport_writew, 1|WRITE);
ioport_write_table[1][addr](ioport_opaque[addr], addr, val);
+ qemu_ioport_dev_unlock(addr);
#ifdef USE_KQEMU
if (env)
env->last_io_time = cpu_get_time_fast();
@@ -446,7 +486,9 @@ void cpu_outl(CPUState *env, int addr, i
if (loglevel & CPU_LOG_IOPORT)
fprintf(logfile, "outl: %04x %08x\n", addr, val);
#endif
+ qemu_ioport_dev_lock(addr, default_ioport_writel, 2|WRITE);
ioport_write_table[2][addr](ioport_opaque[addr], addr, val);
+ qemu_ioport_dev_unlock(addr);
#ifdef USE_KQEMU
if (env)
env->last_io_time = cpu_get_time_fast();
@@ -456,7 +498,9 @@ void cpu_outl(CPUState *env, int addr, i
int cpu_inb(CPUState *env, int addr)
{
int val;
+ qemu_ioport_dev_lock(addr, default_ioport_readb, 0);
val = ioport_read_table[0][addr](ioport_opaque[addr], addr);
+ qemu_ioport_dev_unlock(addr);
#ifdef DEBUG_IOPORT
if (loglevel & CPU_LOG_IOPORT)
fprintf(logfile, "inb : %04x %02x\n", addr, val);
@@ -471,7 +515,9 @@ int cpu_inb(CPUState *env, int addr)
int cpu_inw(CPUState *env, int addr)
{
int val;
+ qemu_ioport_dev_lock(addr, default_ioport_readw, 1);
val = ioport_read_table[1][addr](ioport_opaque[addr], addr);
+ qemu_ioport_dev_unlock(addr);
#ifdef DEBUG_IOPORT
if (loglevel & CPU_LOG_IOPORT)
fprintf(logfile, "inw : %04x %04x\n", addr, val);
@@ -486,7 +532,9 @@ int cpu_inw(CPUState *env, int addr)
int cpu_inl(CPUState *env, int addr)
{
int val;
+ qemu_ioport_dev_lock(addr, default_ioport_readl, 2);
val = ioport_read_table[2][addr](ioport_opaque[addr], addr);
+ qemu_ioport_dev_unlock(addr);
#ifdef DEBUG_IOPORT
if (loglevel & CPU_LOG_IOPORT)
fprintf(logfile, "inl : %04x %08x\n", addr, val);
Index: kvm-userspace.io/qemu/hw/pc.c
===================================================================
--- kvm-userspace.io.orig/qemu/hw/pc.c
+++ kvm-userspace.io/qemu/hw/pc.c
@@ -1046,7 +1046,6 @@ static void pc_init1(ram_addr_t ram_size
}
}
- qemu_system_hot_add_init(cpu_model);
#define USE_HYPERCALL
#ifdef USE_HYPERCALL
pci_hypercall_init(pci_bus);
@@ -1110,6 +1109,8 @@ static void pc_init1(ram_addr_t ram_size
i440fx_init_memory_mappings(i440fx_state);
}
+ qemu_system_hot_add_init(cpu_model);
+
if (pci_enabled) {
int max_bus;
int bus, unit;
Index: kvm-userspace.io/qemu/cpu-all.h
===================================================================
--- kvm-userspace.io.orig/qemu/cpu-all.h
+++ kvm-userspace.io/qemu/cpu-all.h
@@ -850,6 +850,10 @@ CPUReadMemoryFunc **cpu_get_io_memory_re
void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
int len, int is_write);
+/* the same as above, but specify whether device locks are held */
+void __cpu_physical_memory_rw_lock(target_phys_addr_t addr, uint8_t *buf,
+ int len, int is_write, int has_lock);
+
static inline void cpu_physical_memory_read(target_phys_addr_t addr,
uint8_t *buf, int len)
{
Index: kvm-userspace.io/qemu/qemu-kvm.c
===================================================================
--- kvm-userspace.io.orig/qemu/qemu-kvm.c
+++ kvm-userspace.io/qemu/qemu-kvm.c
@@ -555,13 +555,13 @@ static int kvm_outl(void *opaque, uint16
static int kvm_mmio_read(void *opaque, uint64_t addr, uint8_t *data, int len)
{
- cpu_physical_memory_rw(addr, data, len, 0);
+ __cpu_physical_memory_rw(addr, data, len, 0, 0);
return 0;
}
static int kvm_mmio_write(void *opaque, uint64_t addr, uint8_t *data, int len)
{
- cpu_physical_memory_rw(addr, data, len, 1);
+ __cpu_physical_memory_rw(addr, data, len, 1, 0);
return 0;
}
--
-------------------------------------------------------------------------
This SF.net email is sponsored by the 2008 JavaOne(SM) Conference
Don't miss this year's exciting event. There's still time to save $100.
Use priority code J8TL2D2.
http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone
_______________________________________________
kvm-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/kvm-devel