diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index f3c9f93..5d79695 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -262,16 +262,20 @@ void mips_jazz_init (ram_addr_t ram_size,
     /* Serial ports */
     if (serial_hds[0]) {
 #ifdef TARGET_WORDS_BIGENDIAN
-        serial_mm_init(0x80006000, 0, rc4030[8], 8000000/16, serial_hds[0], 1, 1);
+        serial_mm_init(0x80006000, get_system_memory(), 0, rc4030[8],
+                       8000000/16, serial_hds[0], 1, 1);
 #else
-        serial_mm_init(0x80006000, 0, rc4030[8], 8000000/16, serial_hds[0], 1, 0);
+        serial_mm_init(0x80006000, get_system_memory(), 0, rc4030[8],
+                       8000000/16, serial_hds[0], 1, 0);
 #endif
     }
     if (serial_hds[1]) {
 #ifdef TARGET_WORDS_BIGENDIAN
-        serial_mm_init(0x80007000, 0, rc4030[9], 8000000/16, serial_hds[1], 1, 1);
+        serial_mm_init(0x80007000, get_system_memory(), 0, rc4030[9],
+                       8000000/16, serial_hds[1], 1, 1);
 #else
-        serial_mm_init(0x80007000, 0, rc4030[9], 8000000/16, serial_hds[1], 1, 0);
+        serial_mm_init(0x80007000, get_system_memory(), 0, rc4030[9],
+                       8000000/16, serial_hds[1], 1, 0);
 #endif
     }
 
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 86a8ba0..ddd28d3 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -46,6 +46,7 @@
 #include "elf.h"
 #include "mc146818rtc.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 //#define DEBUG_BOARD_INIT
 
@@ -446,9 +447,11 @@ static MaltaFPGAState *malta_fpga_init(target_phys_addr_t base, qemu_irq uart_ir
     s->display = qemu_chr_new("fpga", "vc:320x200", malta_fpga_led_init);
 
 #ifdef TARGET_WORDS_BIGENDIAN
-    s->uart = serial_mm_init(base + 0x900, 3, uart_irq, 230400, uart_chr, 1, 1);
+    s->uart = serial_mm_init(base + 0x900, get_system_memory(), 3, uart_irq,
+                             230400, uart_chr, 1, 1);
 #else
-    s->uart = serial_mm_init(base + 0x900, 3, uart_irq, 230400, uart_chr, 1, 0);
+    s->uart = serial_mm_init(base + 0x900, get_system_memory(), 3, uart_irq,
+                             230400, uart_chr, 1, 0);
 #endif
 
     malta_fpga_reset(s);
diff --git a/hw/musicpal.c b/hw/musicpal.c
index 63dd391..8a3fc2f 100644
--- a/hw/musicpal.c
+++ b/hw/musicpal.c
@@ -19,6 +19,7 @@
 #include "console.h"
 #include "i2c.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 #define MP_MISC_BASE            0x80002000
 #define MP_MISC_SIZE            0x00001000
@@ -1532,20 +1533,20 @@ static void musicpal_init(ram_addr_t ram_size,
 
     if (serial_hds[0]) {
 #ifdef TARGET_WORDS_BIGENDIAN
-        serial_mm_init(MP_UART1_BASE, 2, pic[MP_UART1_IRQ], 1825000,
-                       serial_hds[0], 1, 1);
+        serial_mm_init(MP_UART1_BASE, get_system_memory(), 2,
+                       pic[MP_UART1_IRQ], 1825000, serial_hds[0], 1, 1);
 #else
-        serial_mm_init(MP_UART1_BASE, 2, pic[MP_UART1_IRQ], 1825000,
-                       serial_hds[0], 1, 0);
+        serial_mm_init(MP_UART1_BASE, get_system_memory(), 2,
+                       pic[MP_UART1_IRQ], 1825000, serial_hds[0], 1, 0);
 #endif
     }
     if (serial_hds[1]) {
 #ifdef TARGET_WORDS_BIGENDIAN
-        serial_mm_init(MP_UART2_BASE, 2, pic[MP_UART2_IRQ], 1825000,
-                       serial_hds[1], 1, 1);
+        serial_mm_init(MP_UART2_BASE, get_system_memory(), 2,
+                       pic[MP_UART2_IRQ], 1825000, serial_hds[1], 1, 1);
 #else
-        serial_mm_init(MP_UART2_BASE, 2, pic[MP_UART2_IRQ], 1825000,
-                       serial_hds[1], 1, 0);
+        serial_mm_init(MP_UART2_BASE, get_system_memory(), 2,
+                       pic[MP_UART2_IRQ], 1825000, serial_hds[1], 1, 0);
 #endif
     }
 
diff --git a/hw/omap_uart.c b/hw/omap_uart.c
index 191a0c2..f8ca12f 100644
--- a/hw/omap_uart.c
+++ b/hw/omap_uart.c
@@ -22,6 +22,7 @@
 #include "omap.h"
 /* We use pc-style serial ports.  */
 #include "pc.h"
+#include "exec-memory.h"
 
 /* UARTs */
 struct omap_uart_s {
@@ -61,11 +62,13 @@ struct omap_uart_s *omap_uart_init(target_phys_addr_t base,
     s->fclk = fclk;
     s->irq = irq;
 #ifdef TARGET_WORDS_BIGENDIAN
-    s->serial = serial_mm_init(base, 2, irq, omap_clk_getrate(fclk)/16,
+    s->serial = serial_mm_init(base, get_system_memory(), 2, irq,
+                               omap_clk_getrate(fclk)/16,
                                chr ?: qemu_chr_new(label, "null", NULL), 1,
                                1);
 #else
-    s->serial = serial_mm_init(base, 2, irq, omap_clk_getrate(fclk)/16,
+    s->serial = serial_mm_init(base, get_system_memory(), 2, irq,
+                               omap_clk_getrate(fclk)/16,
                                chr ?: qemu_chr_new(label, "null", NULL), 1,
                                0);
 #endif
@@ -183,12 +186,12 @@ void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr)
 {
     /* TODO: Should reuse or destroy current s->serial */
 #ifdef TARGET_WORDS_BIGENDIAN
-    s->serial = serial_mm_init(s->base, 2, s->irq,
+    s->serial = serial_mm_init(s->base, get_system_memory(), 2, s->irq,
                                omap_clk_getrate(s->fclk) / 16,
                                chr ?: qemu_chr_new("null", "null", NULL), 1,
                                1);
 #else
-    s->serial = serial_mm_init(s->base, 2, s->irq,
+    s->serial = serial_mm_init(s->base, get_system_memory(), 2, s->irq,
                                omap_clk_getrate(s->fclk) / 16,
                                chr ?: qemu_chr_new("null", "null", NULL), 1,
                                0);
diff --git a/hw/pc.h b/hw/pc.h
index dae736e..3cbe945 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -15,10 +15,11 @@
 
 SerialState *serial_init(int base, qemu_irq irq, int baudbase,
                          CharDriverState *chr);
-SerialState *serial_mm_init (target_phys_addr_t base, int it_shift,
-                             qemu_irq irq, int baudbase,
-                             CharDriverState *chr, int ioregister,
-                             int be);
+
+SerialState *serial_mm_init(target_phys_addr_t base, MemoryRegion *mr,
+                            int it_shift, qemu_irq irq, int baudbase,
+                            CharDriverState *chr, int ioregister, int be);
+
 static inline bool serial_isa_init(int index, CharDriverState *chr)
 {
     ISADevice *dev;
diff --git a/hw/petalogix_ml605_mmu.c b/hw/petalogix_ml605_mmu.c
index e3ca310..a5c2405 100644
--- a/hw/petalogix_ml605_mmu.c
+++ b/hw/petalogix_ml605_mmu.c
@@ -38,6 +38,7 @@
 #include "elf.h"
 #include "blockdev.h"
 #include "pc.h"
+#include "exec-memory.h"
 
 #include "microblaze_pic_cpu.h"
 #include "xilinx_axidma.h"
@@ -185,8 +186,8 @@ petalogix_ml605_init(ram_addr_t ram_size,
         irq[i] = qdev_get_gpio_in(dev, i);
     }
 
-    serial_mm_init(UART16550_BASEADDR + 0x1000, 2, irq[5], 115200,
-                   serial_hds[0], 1, 0);
+    serial_mm_init(UART16550_BASEADDR + 0x1000, get_system_memory(), 2, irq[5],
+                   115200, serial_hds[0], 1, 0);
 
     /* 2 timers at irq 2 @ 100 Mhz.  */
     xilinx_timer_create(TIMER_BASEADDR, irq[2], 2, 100 * 1000000);
diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c
index 9d5d2af..7ba34bf 100644
--- a/hw/ppc405_uc.c
+++ b/hw/ppc405_uc.c
@@ -2149,11 +2149,11 @@ CPUState *ppc405cr_init (MemoryRegion ram_memories[4],
     ppc405_dma_init(env, dma_irqs);
     /* Serial ports */
     if (serial_hds[0] != NULL) {
-        serial_mm_init(0xef600300, 0, pic[0], PPC_SERIAL_MM_BAUDBASE,
+        serial_mm_init(0xef600300, get_system_memory(), 0, pic[0], PPC_SERIAL_MM_BAUDBASE,
                        serial_hds[0], 1, 1);
     }
     if (serial_hds[1] != NULL) {
-        serial_mm_init(0xef600400, 0, pic[1], PPC_SERIAL_MM_BAUDBASE,
+        serial_mm_init(0xef600400, get_system_memory(), 0, pic[1], PPC_SERIAL_MM_BAUDBASE,
                        serial_hds[1], 1, 1);
     }
     /* IIC controller */
@@ -2504,11 +2504,11 @@ CPUState *ppc405ep_init (MemoryRegion ram_memories[2],
     ppc405_gpio_init(0xef600700);
     /* Serial ports */
     if (serial_hds[0] != NULL) {
-        serial_mm_init(0xef600300, 0, pic[0], PPC_SERIAL_MM_BAUDBASE,
+        serial_mm_init(0xef600300, get_system_memory(), 0, pic[0], PPC_SERIAL_MM_BAUDBASE,
                        serial_hds[0], 1, 1);
     }
     if (serial_hds[1] != NULL) {
-        serial_mm_init(0xef600400, 0, pic[1], PPC_SERIAL_MM_BAUDBASE,
+        serial_mm_init(0xef600400, get_system_memory(), 0, pic[1], PPC_SERIAL_MM_BAUDBASE,
                        serial_hds[1], 1, 1);
     }
     /* OCM */
diff --git a/hw/ppc440.c b/hw/ppc440.c
index 5885ff0..5cbd4b8 100644
--- a/hw/ppc440.c
+++ b/hw/ppc440.c
@@ -20,6 +20,7 @@
 #include "ppc405.h"
 #include "sysemu.h"
 #include "kvm.h"
+#include "exec-memory.h"
 
 #define PPC440EP_PCI_CONFIG     0xeec00000
 #define PPC440EP_PCI_INTACK     0xeed00000
@@ -92,11 +93,11 @@ CPUState *ppc440ep_init(ram_addr_t *ram_size, PCIBus **pcip,
     isa_mmio_init(PPC440EP_PCI_IO, PPC440EP_PCI_IOLEN);
 
     if (serial_hds[0] != NULL) {
-        serial_mm_init(0xef600300, 0, pic[0], PPC_SERIAL_MM_BAUDBASE,
+        serial_mm_init(0xef600300, get_system_memory(), 0, pic[0], PPC_SERIAL_MM_BAUDBASE,
                        serial_hds[0], 1, 1);
     }
     if (serial_hds[1] != NULL) {
-        serial_mm_init(0xef600400, 0, pic[1], PPC_SERIAL_MM_BAUDBASE,
+        serial_mm_init(0xef600400, get_system_memory(), 0, pic[1], PPC_SERIAL_MM_BAUDBASE,
                        serial_hds[1], 1, 1);
     }
 
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 1274a3e..620ad65 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -32,6 +32,7 @@
 #include "loader.h"
 #include "elf.h"
 #include "sysbus.h"
+#include "exec-memory.h"
 
 #define BINARY_DEVICE_TREE_FILE    "mpc8544ds.dtb"
 #define UIMAGE_LOAD_BASE           0
@@ -274,13 +275,13 @@ static void mpc8544ds_init(ram_addr_t ram_size,
 
     /* Serial */
     if (serial_hds[0]) {
-        serial_mm_init(MPC8544_SERIAL0_REGS_BASE,
+        serial_mm_init(MPC8544_SERIAL0_REGS_BASE, get_system_memory(),
                        0, mpic[12+26], 399193,
                        serial_hds[0], 1, 1);
     }
 
     if (serial_hds[1]) {
-        serial_mm_init(MPC8544_SERIAL1_REGS_BASE,
+        serial_mm_init(MPC8544_SERIAL1_REGS_BASE, get_system_memory(),
                        0, mpic[12+26], 399193,
                        serial_hds[0], 1, 1);
     }
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index 2aa8760..2bacf1c 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -15,6 +15,7 @@
 #include "ssi.h"
 #include "qemu-char.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 static struct {
     target_phys_addr_t io_base;
@@ -2116,11 +2117,11 @@ PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision)
     for (i = 0; pxa270_serial[i].io_base; i ++)
         if (serial_hds[i])
 #ifdef TARGET_WORDS_BIGENDIAN
-            serial_mm_init(pxa270_serial[i].io_base, 2,
+            serial_mm_init(pxa270_serial[i].io_base, get_system_memory(), 2,
                             qdev_get_gpio_in(s->pic, pxa270_serial[i].irqn),
                             14857000 / 16, serial_hds[i], 1, 1);
 #else
-            serial_mm_init(pxa270_serial[i].io_base, 2,
+            serial_mm_init(pxa270_serial[i].io_base, get_system_memory(), 2,
                             qdev_get_gpio_in(s->pic, pxa270_serial[i].irqn),
                             14857000 / 16, serial_hds[i], 1, 0);
 #endif
@@ -2251,11 +2252,11 @@ PXA2xxState *pxa255_init(unsigned int sdram_size)
     for (i = 0; pxa255_serial[i].io_base; i ++)
         if (serial_hds[i]) {
 #ifdef TARGET_WORDS_BIGENDIAN
-            serial_mm_init(pxa255_serial[i].io_base, 2,
+            serial_mm_init(pxa255_serial[i].io_base, get_system_memory(), 2,
                             qdev_get_gpio_in(s->pic, pxa255_serial[i].irqn),
                             14745600 / 16, serial_hds[i], 1, 1);
 #else
-            serial_mm_init(pxa255_serial[i].io_base, 2,
+            serial_mm_init(pxa255_serial[i].io_base, get_system_memory(), 2,
                             qdev_get_gpio_in(s->pic, pxa255_serial[i].irqn),
                             14745600 / 16, serial_hds[i], 1, 0);
 #endif
diff --git a/hw/serial.c b/hw/serial.c
index ed7fd0a..fcbb6df 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -153,6 +153,8 @@ struct SerialState {
     int poll_msl;
 
     struct QEMUTimer *modem_status_poll;
+
+    MemoryRegion  mem;
 };
 
 typedef struct ISASerialState {
@@ -899,37 +901,89 @@ static void serial_mm_writel_le(void *opaque, target_phys_addr_t addr,
     serial_ioport_write(s, addr >> s->it_shift, value);
 }
 
-static CPUReadMemoryFunc * const serial_mm_read_be[] = {
-    &serial_mm_readb,
-    &serial_mm_readw_be,
-    &serial_mm_readl_be,
-};
+static void serial_le_write(void *opaque, target_phys_addr_t addr,
+                            uint64_t value, unsigned size)
+{
+    switch(size) {
+    case 1:
+        return serial_mm_writeb(opaque, addr, value);
+        break;
+    case 2:
+        return serial_mm_writew_le(opaque, addr, value);
+        break;
+    case 4:
+        return serial_mm_writel_le(opaque, addr, value);
+        break;
+    }
+}
 
-static CPUWriteMemoryFunc * const serial_mm_write_be[] = {
-    &serial_mm_writeb,
-    &serial_mm_writew_be,
-    &serial_mm_writel_be,
-};
+static uint64_t serial_le_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
+{
+    switch(size) {
+    case 1:
+        return serial_mm_readb(opaque, addr);
+        break;
+    case 2:
+        return serial_mm_readw_le(opaque, addr);
+        break;
+    case 4:
+        return serial_mm_readl_le(opaque, addr);
+        break;
+    }
+    return 0;
+}
 
-static CPUReadMemoryFunc * const serial_mm_read_le[] = {
-    &serial_mm_readb,
-    &serial_mm_readw_le,
-    &serial_mm_readl_le,
+static const MemoryRegionOps serial_le_ops = {
+    .read = serial_le_read,
+    .write = serial_le_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUWriteMemoryFunc * const serial_mm_write_le[] = {
-    &serial_mm_writeb,
-    &serial_mm_writew_le,
-    &serial_mm_writel_le,
+static void serial_be_write(void *opaque, target_phys_addr_t addr,
+                            uint64_t value, unsigned size)
+{
+    switch(size) {
+    case 1:
+        return serial_mm_writeb(opaque, addr, value);
+        break;
+    case 2:
+        return serial_mm_writew_be(opaque, addr, value);
+        break;
+    case 4:
+        return serial_mm_writel_be(opaque, addr, value);
+        break;
+    }
+}
+
+static uint64_t serial_be_read(void *opaque, target_phys_addr_t addr,
+                               unsigned size)
+{
+    switch(size) {
+    case 1:
+        return serial_mm_readb(opaque, addr);
+        break;
+    case 2:
+        return serial_mm_readw_be(opaque, addr);
+        break;
+    case 4:
+        return serial_mm_readl_be(opaque, addr);
+        break;
+    }
+    return 0;
+}
+
+static const MemoryRegionOps serial_be_ops = {
+    .read = serial_be_read,
+    .write = serial_be_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-SerialState *serial_mm_init (target_phys_addr_t base, int it_shift,
-                             qemu_irq irq, int baudbase,
-                             CharDriverState *chr, int ioregister,
-                             int be)
+SerialState *serial_mm_init(target_phys_addr_t base, MemoryRegion *mr,
+                            int it_shift, qemu_irq irq, int baudbase,
+                            CharDriverState *chr, int ioregister, int be)
 {
     SerialState *s;
-    int s_io_memory;
 
     s = g_malloc0(sizeof(SerialState));
 
@@ -943,16 +997,16 @@ SerialState *serial_mm_init (target_phys_addr_t base, int it_shift,
 
     if (ioregister) {
         if (be) {
-            s_io_memory = cpu_register_io_memory(serial_mm_read_be,
-                                                 serial_mm_write_be, s,
-                                                 DEVICE_NATIVE_ENDIAN);
+            memory_region_init_io(&s->mem, &serial_be_ops, s, "serial",
+                                  8 << it_shift);
         } else {
-            s_io_memory = cpu_register_io_memory(serial_mm_read_le,
-                                                 serial_mm_write_le, s,
-                                                 DEVICE_NATIVE_ENDIAN);
+            memory_region_init_io(&s->mem, &serial_le_ops, s, "serial",
+                                  8 << it_shift);
         }
-        cpu_register_physical_memory(base, 8 << it_shift, s_io_memory);
+
+        memory_region_add_subregion(mr, base, &s->mem);
     }
+
     serial_update_msl(s);
     return s;
 }
diff --git a/hw/sm501.c b/hw/sm501.c
index 1ed0a7e..fecb253 100644
--- a/hw/sm501.c
+++ b/hw/sm501.c
@@ -30,6 +30,7 @@
 #include "sysbus.h"
 #include "qdev-addr.h"
 #include "range.h"
+#include "exec-memory.h"
 
 /*
  * Status: 2010/05/07
@@ -1441,11 +1442,13 @@ void sm501_init(uint32_t base, uint32_t local_mem_bytes, qemu_irq irq,
     /* bridge to serial emulation module */
     if (chr) {
 #ifdef TARGET_WORDS_BIGENDIAN
-        serial_mm_init(base + MMIO_BASE_OFFSET + SM501_UART0, 2,
+        serial_mm_init(base + MMIO_BASE_OFFSET + SM501_UART0,
+                       get_system_memory(), 2,
                        NULL, /* TODO : chain irq to IRL */
                        115200, chr, 1, 1);
 #else
-        serial_mm_init(base + MMIO_BASE_OFFSET + SM501_UART0, 2,
+        serial_mm_init(base + MMIO_BASE_OFFSET + SM501_UART0,
+                       get_system_memory(), 2,
                        NULL, /* TODO : chain irq to IRL */
                        115200, chr, 1, 0);
 #endif
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 32e6ab9..a882d2e 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -38,6 +38,7 @@
 #include "loader.h"
 #include "elf.h"
 #include "blockdev.h"
+#include "exec-memory.h"
 
 //#define DEBUG_IRQ
 //#define DEBUG_EBUS
@@ -771,8 +772,8 @@ static void sun4uv_init(ram_addr_t RAM_size,
 
     i = 0;
     if (hwdef->console_serial_base) {
-        serial_mm_init(hwdef->console_serial_base, 0, NULL, 115200,
-                       serial_hds[i], 1, 1);
+        serial_mm_init(hwdef->console_serial_base, get_system_memory(), 0,
+                       NULL, 115200, serial_hds[i], 1, 1);
         i++;
     }
     for(; i < MAX_SERIAL_PORTS; i++) {
diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c
index 333050c..26c90c6 100644
--- a/hw/virtex_ml507.c
+++ b/hw/virtex_ml507.c
@@ -34,6 +34,7 @@
 #include "loader.h"
 #include "elf.h"
 #include "qemu-log.h"
+#include "exec-memory.h"
 
 #include "ppc.h"
 #include "ppc4xx.h"
@@ -228,7 +229,8 @@ static void virtex_init(ram_addr_t ram_size,
         irq[i] = qdev_get_gpio_in(dev, i);
     }
 
-    serial_mm_init(0x83e01003ULL, 2, irq[9], 115200, serial_hds[0], 1, 0);
+    serial_mm_init(0x83e01003ULL, get_system_memory(), 2, irq[9],
+                   115200, serial_hds[0], 1, 0);
 
     /* 2 timers at irq 2 @ 62 Mhz.  */
     xilinx_timer_create(0x83c00000, irq[3], 2, 62 * 1000000);
