All of lore.kernel.org
 help / color / mirror / Atom feed
From: Marcelo Tosatti <mtosatti@redhat.com>
To: Avi Kivity <avi@qumranet.com>, Anthony Liguori <aliguori@us.ibm.com>
Cc: kvm-devel <kvm-devel@lists.sourceforge.net>
Subject: [patch 07/13] QEMU: grab device lock for ioport/iomem processing
Date: Thu, 17 Apr 2008 17:10:28 -0300	[thread overview]
Message-ID: <20080417203026.706258528@localhost.localdomain> (raw)
In-Reply-To: 20080417201021.515148882@localhost.localdomain

[-- Attachment #1: lock-and-unlock --]
[-- Type: text/plain, Size: 14296 bytes --]

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

  parent reply	other threads:[~2008-04-17 20:10 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-04-17 20:10 [patch 00/13] RFC: split the global mutex Marcelo Tosatti
2008-04-17 20:10 ` [patch 01/13] QEMU: get rid of global cpu_single_env Marcelo Tosatti
2008-04-17 20:10 ` [patch 02/13] QEMU: introduce QEMUDevice Marcelo Tosatti
2008-04-17 20:10 ` [patch 03/13] QEMU: make esp.c build conditional to SPARC target Marcelo Tosatti
2008-04-17 20:10 ` [patch 04/13] QEMU: plug QEMUDevice pt1 / ioport awareness Marcelo Tosatti
2008-04-17 20:10 ` [patch 05/13] QEMU: add a mutex to protect IRQ chip data structures Marcelo Tosatti
2008-04-17 20:10 ` [patch 06/13] QEMU: plug QEMUDevice pt2 / iomem awareness Marcelo Tosatti
2008-04-17 20:10 ` Marcelo Tosatti [this message]
2008-04-17 20:10 ` [patch 08/13] QEMU: character device locking Marcelo Tosatti
2008-04-17 20:10 ` [patch 09/13] QEMU: network " Marcelo Tosatti
2008-04-17 20:10 ` [patch 10/13] QEMU: get rid of aiocb cache Marcelo Tosatti
2008-04-17 20:10 ` [patch 11/13] QEMU: block device locking Marcelo Tosatti
2008-04-17 20:10 ` [patch 12/13] QEMU: scsi-disk reentrancy fix Marcelo Tosatti
2008-04-17 20:10 ` [patch 13/13] QEMU/KVM: get rid of global lock Marcelo Tosatti
2008-04-20 11:16 ` [patch 00/13] RFC: split the global mutex Avi Kivity
2008-04-21  0:00   ` Marcelo Tosatti
2008-04-21  6:10     ` Avi Kivity

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080417203026.706258528@localhost.localdomain \
    --to=mtosatti@redhat.com \
    --cc=aliguori@us.ibm.com \
    --cc=avi@qumranet.com \
    --cc=kvm-devel@lists.sourceforge.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.