r2052 - in trunk/src/host/qemu-neo1973: . hw

andrew at sita.openmoko.org andrew at sita.openmoko.org
Tue May 22 01:47:19 CEST 2007


Author: andrew
Date: 2007-05-22 01:47:12 +0200 (Tue, 22 May 2007)
New Revision: 2052

Modified:
   trunk/src/host/qemu-neo1973/ecc.h
   trunk/src/host/qemu-neo1973/hw/i2c.c
   trunk/src/host/qemu-neo1973/hw/i2c.h
   trunk/src/host/qemu-neo1973/hw/jbt6k74.c
   trunk/src/host/qemu-neo1973/hw/nand.c
   trunk/src/host/qemu-neo1973/hw/neo1973.c
   trunk/src/host/qemu-neo1973/hw/pcf5060x.c
   trunk/src/host/qemu-neo1973/hw/s3c2410.c
   trunk/src/host/qemu-neo1973/hw/s3c24xx_gpio.c
   trunk/src/host/qemu-neo1973/hw/s3c24xx_lcd.c
   trunk/src/host/qemu-neo1973/hw/s3c24xx_mmci.c
   trunk/src/host/qemu-neo1973/hw/s3c24xx_rtc.c
   trunk/src/host/qemu-neo1973/hw/s3c24xx_udc.c
   trunk/src/host/qemu-neo1973/hw/wm8750.c
   trunk/src/host/qemu-neo1973/hw/wm8753.c
   trunk/src/host/qemu-neo1973/vl.c
Log:
"savevm"/"loadvm" support for ARM cores, the S3C peripherals and random other hardware.
Allow snapshot storing in mtdblock images and rip out some of the hardcoded HDD snapshot checks.


Modified: trunk/src/host/qemu-neo1973/ecc.h
===================================================================
--- trunk/src/host/qemu-neo1973/ecc.h	2007-05-21 23:27:58 UTC (rev 2051)
+++ trunk/src/host/qemu-neo1973/ecc.h	2007-05-21 23:47:12 UTC (rev 2052)
@@ -75,3 +75,20 @@
     s->cp = 0x00;
     s->count = 0;
 }
+
+/* Save/restore */
+static inline void ecc_put(QEMUFile *f, struct ecc_state_s *s)
+{
+    qemu_put_8s(f, &s->cp);
+    qemu_put_be16s(f, &s->lp[0]);
+    qemu_put_be16s(f, &s->lp[1]);
+    qemu_put_be16s(f, &s->count);
+}
+
+static inline void ecc_get(QEMUFile *f, struct ecc_state_s *s)
+{
+    qemu_get_8s(f, &s->cp);
+    qemu_get_be16s(f, &s->lp[0]);
+    qemu_get_be16s(f, &s->lp[1]);
+    qemu_get_be16s(f, &s->count);
+}

Modified: trunk/src/host/qemu-neo1973/hw/i2c.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/i2c.c	2007-05-21 23:27:58 UTC (rev 2051)
+++ trunk/src/host/qemu-neo1973/hw/i2c.c	2007-05-21 23:47:12 UTC (rev 2052)
@@ -115,3 +115,34 @@
     dev->event(dev, I2C_NACK);
 }
 
+void i2c_bus_save(QEMUFile *f, i2c_bus *bus)
+{
+    qemu_put_byte(f, bus->current_dev ? bus->current_dev->address : 0x00);
+}
+
+void i2c_bus_load(QEMUFile *f, i2c_bus *bus)
+{
+    i2c_slave *dev;
+    uint8_t address = qemu_get_byte(f);
+
+    if (address) {
+        for (dev = bus->dev; dev; dev = dev->next)
+            if (dev->address == address) {
+                bus->current_dev = dev;
+                return;
+            }
+
+        fprintf(stderr, "%s: I2C slave with address %02x disappeared\n",
+                __FUNCTION__, address);
+    }
+}
+
+void i2c_slave_save(QEMUFile *f, i2c_slave *dev)
+{
+    qemu_put_byte(f, dev->address);
+}
+
+void i2c_slave_load(QEMUFile *f, i2c_slave *dev)
+{
+    dev->address = qemu_get_byte(f);
+}

Modified: trunk/src/host/qemu-neo1973/hw/i2c.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/i2c.h	2007-05-21 23:27:58 UTC (rev 2051)
+++ trunk/src/host/qemu-neo1973/hw/i2c.h	2007-05-21 23:47:12 UTC (rev 2052)
@@ -45,6 +45,10 @@
 void i2c_nack(i2c_bus *bus);
 int i2c_send(i2c_bus *bus, uint8_t data);
 int i2c_recv(i2c_bus *bus);
+void i2c_bus_save(QEMUFile *f, i2c_bus *bus);
+void i2c_bus_load(QEMUFile *f, i2c_bus *bus);
+void i2c_slave_save(QEMUFile *f, i2c_slave *dev);
+void i2c_slave_load(QEMUFile *f, i2c_slave *dev);
 
 /* max7310.c */
 i2c_slave *max7310_init(i2c_bus *bus);

Modified: trunk/src/host/qemu-neo1973/hw/jbt6k74.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/jbt6k74.c	2007-05-21 23:27:58 UTC (rev 2051)
+++ trunk/src/host/qemu-neo1973/hw/jbt6k74.c	2007-05-21 23:47:12 UTC (rev 2052)
@@ -216,10 +216,48 @@
     return ret;
 }
 
+static void jbt6k74_save(QEMUFile *f, void *opaque)
+{
+    struct jbt6k74_s *s = (struct jbt6k74_s *) opaque;
+    int i;
+
+    qemu_put_8s(f, &s->command);
+    qemu_put_be32s(f, &s->parameter);
+    qemu_put_be32s(f, &s->response);
+    qemu_put_be32(f, s->dc);
+    qemu_put_be32(f, s->bit);
+    qemu_put_be32(f, s->bytes);
+    qemu_put_be32(f, s->respbit);
+    for (i = 0; i < 0x100; i ++)
+        qemu_put_be16s(f, &s->regs[i]);
+}
+
+static int jbt6k74_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct jbt6k74_s *s = (struct jbt6k74_s *) opaque;
+    int i;
+
+    qemu_get_8s(f, &s->command);
+    qemu_get_be32s(f, &s->parameter);
+    qemu_get_be32s(f, &s->response);
+    s->dc = qemu_get_be32(f);
+    s->bit = qemu_get_be32(f);
+    s->bytes = qemu_get_be32(f);
+    s->respbit = qemu_get_be32(f);
+    for (i = 0; i < 0x100; i ++)
+        qemu_get_be16s(f, &s->regs[i]);
+
+    return 0;
+}
+
+static int jbt6k74_iid = 0;
+
 void *jbt6k74_init()
 {
     struct jbt6k74_s *s = qemu_mallocz(sizeof(struct jbt6k74_s));
     jbt6k74_reset(s);
+    register_savevm("jbt6k74", jbt6k74_iid ++, 0,
+                    jbt6k74_save, jbt6k74_load, s);
 
     return s;
 }

Modified: trunk/src/host/qemu-neo1973/hw/nand.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/nand.c	2007-05-21 23:27:58 UTC (rev 2051)
+++ trunk/src/host/qemu-neo1973/hw/nand.c	2007-05-21 23:47:12 UTC (rev 2052)
@@ -273,6 +273,50 @@
     }
 }
 
+static void nand_save(QEMUFile *f, void *opaque)
+{
+    struct nand_flash_s *s = (struct nand_flash_s *) opaque;
+    qemu_put_byte(f, s->cle);
+    qemu_put_byte(f, s->ale);
+    qemu_put_byte(f, s->ce);
+    qemu_put_byte(f, s->wp);
+    qemu_put_byte(f, s->gnd);
+    qemu_put_buffer(f, s->io, sizeof(s->io));
+    qemu_put_be32(f, s->ioaddr - s->io);
+    qemu_put_be32(f, s->iolen);
+
+    qemu_put_be32s(f, &s->cmd);
+    qemu_put_be32s(f, &s->addr);
+    qemu_put_be32(f, s->addrlen);
+    qemu_put_be32(f, s->status);
+    qemu_put_be32(f, s->offset);
+    /* XXX: do we want to save s->storage too? */
+}
+
+static int nand_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct nand_flash_s *s = (struct nand_flash_s *) opaque;
+    s->cle = qemu_get_byte(f);
+    s->ale = qemu_get_byte(f);
+    s->ce = qemu_get_byte(f);
+    s->wp = qemu_get_byte(f);
+    s->gnd = qemu_get_byte(f);
+    qemu_get_buffer(f, s->io, sizeof(s->io));
+    s->ioaddr = s->io + qemu_get_be32(f);
+    s->iolen = qemu_get_be32(f);
+    if (s->ioaddr >= s->io + sizeof(s->io) || s->ioaddr < s->io)
+        return -EINVAL;
+
+    qemu_get_be32s(f, &s->cmd);
+    qemu_get_be32s(f, &s->addr);
+    s->addrlen = qemu_get_be32(f);
+    s->status = qemu_get_be32(f);
+    s->offset = qemu_get_be32(f);
+    return 0;
+}
+
+static int nand_iid = 0;
+
 /*
  * Chip inputs are CLE, ALE, CE, WP, GND and eight I/O pins.  Chip
  * outputs are R/B and eight I/O pins.
@@ -443,6 +487,9 @@
     if (pagesize)
         s->storage = (uint8_t *) memset(qemu_malloc(s->pages * pagesize),
                         0xff, s->pages * pagesize);
+
+    register_savevm("nand", nand_iid ++, 0, nand_save, nand_load, s);
+
     return s;
 }
 

Modified: trunk/src/host/qemu-neo1973/hw/neo1973.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/neo1973.c	2007-05-21 23:27:58 UTC (rev 2051)
+++ trunk/src/host/qemu-neo1973/hw/neo1973.c	2007-05-21 23:47:12 UTC (rev 2052)
@@ -276,6 +276,21 @@
     return 0;
 }
 
+static void lm_save(QEMUFile *f, void *opaque)
+{
+    struct lm4857_s *s = (struct lm4857_s *) opaque;
+    qemu_put_buffer(f, s->regs, sizeof(s->regs));
+    i2c_slave_save(f, &s->i2c);
+}
+
+static int lm_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct lm4857_s *s = (struct lm4857_s *) opaque;
+    qemu_get_buffer(f, s->regs, sizeof(s->regs));
+    i2c_slave_load(f, &s->i2c);
+    return 0;
+}
+
 i2c_slave *lm4857_init(i2c_bus *bus)
 {
     struct lm4857_s *s = (struct lm4857_s *)
@@ -285,6 +300,7 @@
     s->i2c.recv = lm_rx;
 
     lm_reset(&s->i2c);
+    register_savevm("lm4857", 0, 0, lm_save, lm_load, s);
 
     return &s->i2c;
 }

Modified: trunk/src/host/qemu-neo1973/hw/pcf5060x.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pcf5060x.c	2007-05-21 23:27:58 UTC (rev 2051)
+++ trunk/src/host/qemu-neo1973/hw/pcf5060x.c	2007-05-21 23:47:12 UTC (rev 2052)
@@ -785,6 +785,137 @@
     pcf_update(s);
 }
 
+static void pcf_save(QEMUFile *f, void *opaque)
+{
+    struct pcf_s *s = (struct pcf_s *) opaque;
+    qemu_put_be32(f, s->firstbyte);
+    qemu_put_be32(f, s->charging);
+    qemu_put_8s(f, &s->reg);
+    qemu_put_8s(f, &s->oocs);
+    qemu_put_8s(f, &s->oocc[0]);
+    qemu_put_8s(f, &s->oocc[1]);
+    qemu_put_8s(f, &s->intr[0]);
+    qemu_put_8s(f, &s->intr[1]);
+    qemu_put_8s(f, &s->intr[2]);
+    qemu_put_8s(f, &s->intm[0]);
+    qemu_put_8s(f, &s->intm[1]);
+    qemu_put_8s(f, &s->intm[2]);
+    qemu_put_8s(f, &s->pssc);
+    qemu_put_8s(f, &s->pwrokm);
+    qemu_put_8s(f, &s->dcdc[0]);
+    qemu_put_8s(f, &s->dcdc[1]);
+    qemu_put_8s(f, &s->dcdc[2]);
+    qemu_put_8s(f, &s->dcdc[3]);
+    qemu_put_8s(f, &s->dcdec[0]);
+    qemu_put_8s(f, &s->dcdec[1]);
+    qemu_put_8s(f, &s->dcudc[0]);
+    qemu_put_8s(f, &s->dcudc[1]);
+    qemu_put_8s(f, &s->ioregc);
+    qemu_put_8s(f, &s->dregc[0]);
+    qemu_put_8s(f, &s->dregc[1]);
+    qemu_put_8s(f, &s->dregc[2]);
+    qemu_put_8s(f, &s->lpregc[0]);
+    qemu_put_8s(f, &s->lpregc[1]);
+    qemu_put_8s(f, &s->mbcc[0]);
+    qemu_put_8s(f, &s->mbcc[1]);
+    qemu_put_8s(f, &s->mbcc[2]);
+    qemu_put_8s(f, &s->bbcc);
+    qemu_put_8s(f, &s->adcc[0]);
+    qemu_put_8s(f, &s->adcc[1]);
+    qemu_put_8s(f, &s->adcs[0]);
+    qemu_put_8s(f, &s->adcs[1]);
+    qemu_put_8s(f, &s->adcs[2]);
+    qemu_put_8s(f, &s->acdc[0]);
+    qemu_put_8s(f, &s->bvmc);
+    qemu_put_8s(f, &s->pwmc[0]);
+    qemu_put_8s(f, &s->ledc[0]);
+    qemu_put_8s(f, &s->ledc[1]);
+    qemu_put_8s(f, &s->gpoc[0]);
+    qemu_put_8s(f, &s->gpoc[1]);
+    qemu_put_8s(f, &s->gpoc[2]);
+    qemu_put_8s(f, &s->gpoc[3]);
+    qemu_put_8s(f, &s->gpoc[4]);
+    qemu_put_be32(f, s->ts.x);
+    qemu_put_be32(f, s->ts.y);
+    qemu_put_be32s(f, &s->rtc.sec);
+    qemu_put_8s(f, &s->rtc.alm_sec);
+    qemu_put_8s(f, &s->rtc.alm_min);
+    qemu_put_8s(f, &s->rtc.alm_hour);
+    qemu_put_8s(f, &s->rtc.alm_wday);
+    qemu_put_8s(f, &s->rtc.alm_mday);
+    qemu_put_8s(f, &s->rtc.alm_mon);
+    qemu_put_8s(f, &s->rtc.alm_year);
+    qemu_put_8s(f, &s->gpo);
+    i2c_slave_save(f, &s->i2c);
+}
+
+static int pcf_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct pcf_s *s = (struct pcf_s *) opaque;
+    s->firstbyte = qemu_get_be32(f);
+    s->charging = qemu_get_be32(f);
+    qemu_get_8s(f, &s->reg);
+    qemu_get_8s(f, &s->oocs);
+    qemu_get_8s(f, &s->oocc[0]);
+    qemu_get_8s(f, &s->oocc[1]);
+    qemu_get_8s(f, &s->intr[0]);
+    qemu_get_8s(f, &s->intr[1]);
+    qemu_get_8s(f, &s->intr[2]);
+    qemu_get_8s(f, &s->intm[0]);
+    qemu_get_8s(f, &s->intm[1]);
+    qemu_get_8s(f, &s->intm[2]);
+    qemu_get_8s(f, &s->pssc);
+    qemu_get_8s(f, &s->pwrokm);
+    qemu_get_8s(f, &s->dcdc[0]);
+    qemu_get_8s(f, &s->dcdc[1]);
+    qemu_get_8s(f, &s->dcdc[2]);
+    qemu_get_8s(f, &s->dcdc[3]);
+    qemu_get_8s(f, &s->dcdec[0]);
+    qemu_get_8s(f, &s->dcdec[1]);
+    qemu_get_8s(f, &s->dcudc[0]);
+    qemu_get_8s(f, &s->dcudc[1]);
+    qemu_get_8s(f, &s->ioregc);
+    qemu_get_8s(f, &s->dregc[0]);
+    qemu_get_8s(f, &s->dregc[1]);
+    qemu_get_8s(f, &s->dregc[2]);
+    qemu_get_8s(f, &s->lpregc[0]);
+    qemu_get_8s(f, &s->lpregc[1]);
+    qemu_get_8s(f, &s->mbcc[0]);
+    qemu_get_8s(f, &s->mbcc[1]);
+    qemu_get_8s(f, &s->mbcc[2]);
+    qemu_get_8s(f, &s->bbcc);
+    qemu_get_8s(f, &s->adcc[0]);
+    qemu_get_8s(f, &s->adcc[1]);
+    qemu_get_8s(f, &s->adcs[0]);
+    qemu_get_8s(f, &s->adcs[1]);
+    qemu_get_8s(f, &s->adcs[2]);
+    qemu_get_8s(f, &s->acdc[0]);
+    qemu_get_8s(f, &s->bvmc);
+    qemu_get_8s(f, &s->pwmc[0]);
+    qemu_get_8s(f, &s->ledc[0]);
+    qemu_get_8s(f, &s->ledc[1]);
+    qemu_get_8s(f, &s->gpoc[0]);
+    qemu_get_8s(f, &s->gpoc[1]);
+    qemu_get_8s(f, &s->gpoc[2]);
+    qemu_get_8s(f, &s->gpoc[3]);
+    qemu_get_8s(f, &s->gpoc[4]);
+    s->ts.x = qemu_get_be32(f);
+    s->ts.y = qemu_get_be32(f);
+    qemu_get_be32s(f, &s->rtc.sec);
+    qemu_get_8s(f, &s->rtc.alm_sec);
+    qemu_get_8s(f, &s->rtc.alm_min);
+    qemu_get_8s(f, &s->rtc.alm_hour);
+    qemu_get_8s(f, &s->rtc.alm_wday);
+    qemu_get_8s(f, &s->rtc.alm_mday);
+    qemu_get_8s(f, &s->rtc.alm_mon);
+    qemu_get_8s(f, &s->rtc.alm_year);
+    qemu_get_8s(f, &s->gpo);
+    i2c_slave_load(f, &s->i2c);
+    return 0;
+}
+
+static int pcf_iid = 0;
+
 i2c_slave *pcf5060x_init(i2c_bus *bus, qemu_irq irq, int tsc)
 {
     struct pcf_s *s = (struct pcf_s *)
@@ -804,9 +935,11 @@
     if (tsc) {
         /* We want absolute coordinates */
         qemu_add_mouse_event_handler(pcf_adc_event, s, 1,
-                        "QEMU ADS7846-driven Touchscreen");
+                        "QEMU PCF50606-driven Touchscreen");
     }
 
+    register_savevm("pcf5060x", pcf_iid ++, 0, pcf_save, pcf_load, s);
+
     return &s->i2c;
 }
 

Modified: trunk/src/host/qemu-neo1973/hw/s3c2410.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/s3c2410.c	2007-05-21 23:27:58 UTC (rev 2051)
+++ trunk/src/host/qemu-neo1973/hw/s3c2410.c	2007-05-21 23:47:12 UTC (rev 2052)
@@ -287,6 +287,34 @@
     s3c_pic_write,
 };
 
+static void s3c_pic_save(QEMUFile *f, void *opaque)
+{
+    struct s3c_pic_state_s *s = (struct s3c_pic_state_s *) opaque;
+    qemu_put_be32s(f, &s->srcpnd);
+    qemu_put_be32s(f, &s->intpnd);
+    qemu_put_be32s(f, &s->intmsk);
+    qemu_put_be32s(f, &s->intmod);
+    qemu_put_be32s(f, &s->priority);
+    qemu_put_be32s(f, &s->subsrcpnd);
+    qemu_put_be32s(f, &s->intsubmsk);
+    qemu_put_be32(f, s->intoffset);
+}
+
+static int s3c_pic_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct s3c_pic_state_s *s = (struct s3c_pic_state_s *) opaque;
+    qemu_get_be32s(f, &s->srcpnd);
+    qemu_get_be32s(f, &s->intpnd);
+    qemu_get_be32s(f, &s->intmsk);
+    qemu_get_be32s(f, &s->intmod);
+    qemu_get_be32s(f, &s->priority);
+    qemu_get_be32s(f, &s->subsrcpnd);
+    qemu_get_be32s(f, &s->intsubmsk);
+    s->intoffset = qemu_get_be32(f);
+    s3c_pic_update(s);
+    return 0;
+}
+
 struct s3c_pic_state_s *s3c_pic_init(target_phys_addr_t base,
                 qemu_irq *arm_pic)
 {
@@ -304,6 +332,8 @@
                     s3c_pic_writefn, s);
     cpu_register_physical_memory(s->base, 0xffffff, iomemtype);
 
+    register_savevm("s3c24xx_pic", 0, 0, s3c_pic_save, s3c_pic_load, s);
+
     return s;
 }
 
@@ -386,6 +416,23 @@
     s3c_mc_write,
 };
 
+static void s3c_mc_save(QEMUFile *f, void *opaque)
+{
+    struct s3c_state_s *s = (struct s3c_state_s *) opaque;
+    int i;
+    for (i = 0; i < 13; i ++)
+        qemu_put_be32s(f, &s->mc_regs[i]);
+}
+
+static int s3c_mc_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct s3c_state_s *s = (struct s3c_state_s *) opaque;
+    int i;
+    for (i = 0; i < 13; i ++)
+        qemu_get_be32s(f, &s->mc_regs[i]);
+    return 0;
+}
+
 /* NAND Flash controller */
 #define S3C_NFCONF	0x00	/* NAND Flash Configuration register */
 #define S3C_NFCMD	0x04	/* NAND Flash Command Set register */
@@ -504,6 +551,27 @@
     s3c_nand_write,
 };
 
+static void s3c_nand_save(QEMUFile *f, void *opaque)
+{
+    struct s3c_state_s *s = (struct s3c_state_s *) opaque;
+    qemu_put_be16s(f, &s->nfconf);
+    qemu_put_8s(f, &s->nfcmd);
+    qemu_put_8s(f, &s->nfaddr);
+    qemu_put_be32(f, s->nfwp);
+    ecc_put(f, &s->nfecc);
+}
+
+static int s3c_nand_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct s3c_state_s *s = (struct s3c_state_s *) opaque;
+    qemu_get_be16s(f, &s->nfconf);
+    qemu_get_8s(f, &s->nfcmd);
+    qemu_get_8s(f, &s->nfaddr);
+    s->nfwp = qemu_get_be32(f);
+    ecc_get(f, &s->nfecc);
+    return 0;
+}
+
 /* Clock & power management */
 #define S3C_LOCKTIME	0x00	/* PLL Lock Time Count register */
 #define S3C_MPLLCON	0x04	/* MPLL Configuration register */
@@ -588,6 +656,23 @@
     s3c_clkpwr_write,
 };
 
+static void s3c_clkpwr_save(QEMUFile *f, void *opaque)
+{
+    struct s3c_state_s *s = (struct s3c_state_s *) opaque;
+    int i;
+    for (i = 0; i < 6; i ++)
+        qemu_put_be32s(f, &s->clkpwr_regs[i]);
+}
+
+static int s3c_clkpwr_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct s3c_state_s *s = (struct s3c_state_s *) opaque;
+    int i;
+    for (i = 0; i < 6; i ++)
+        qemu_get_be32s(f, &s->clkpwr_regs[i]);
+    return 0;
+}
+
 /* DMA controller */
 #define S3C_DMA_CH_N	4
 
@@ -792,6 +877,43 @@
     s3c_dma_write,
 };
 
+static void s3c_dma_save(QEMUFile *f, void *opaque)
+{
+    struct s3c_dma_state_s *s = (struct s3c_dma_state_s *) opaque;
+    int i;
+    for (i = 0; i < S3C_DMA_CH_N; i ++) {
+        qemu_put_be32(f, s->ch[i].curr_tc);
+        qemu_put_be32(f, s->ch[i].req);
+        qemu_put_be32s(f, &s->ch[i].con);
+        qemu_put_be32s(f, &s->ch[i].isrc);
+        qemu_put_be32s(f, &s->ch[i].isrcc);
+        qemu_put_be32s(f, &s->ch[i].idst);
+        qemu_put_be32s(f, &s->ch[i].idstc);
+        qemu_put_be32s(f, &s->ch[i].csrc);
+        qemu_put_be32s(f, &s->ch[i].cdst);
+        qemu_put_be32s(f, &s->ch[i].mask);
+    }
+}
+
+static int s3c_dma_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct s3c_dma_state_s *s = (struct s3c_dma_state_s *) opaque;
+    int i;
+    for (i = 0; i < S3C_DMA_CH_N; i ++) {
+        s->ch[i].curr_tc = qemu_get_be32(f);
+        s->ch[i].req = qemu_get_be32(f);
+        qemu_get_be32s(f, &s->ch[i].con);
+        qemu_get_be32s(f, &s->ch[i].isrc);
+        qemu_get_be32s(f, &s->ch[i].isrcc);
+        qemu_get_be32s(f, &s->ch[i].idst);
+        qemu_get_be32s(f, &s->ch[i].idstc);
+        qemu_get_be32s(f, &s->ch[i].csrc);
+        qemu_get_be32s(f, &s->ch[i].cdst);
+        qemu_get_be32s(f, &s->ch[i].mask);
+    }
+    return 0;
+}
+
 struct s3c_dma_state_s *s3c_dma_init(target_phys_addr_t base, qemu_irq *pic)
 {
     int iomemtype;
@@ -811,6 +933,8 @@
                     s3c_dma_writefn, s);
     cpu_register_physical_memory(s->base, 0xffffff, iomemtype);
 
+    register_savevm("s3c24xx_dma", 0, 0, s3c_dma_save, s3c_dma_load, s);
+
     return s;
 }
 
@@ -1047,6 +1171,52 @@
     s3c_timers_write,
 };
 
+static void s3c_timers_save(QEMUFile *f, void *opaque)
+{
+    struct s3c_timers_state_s *s = (struct s3c_timers_state_s *) opaque;
+    int i;
+    for (i = 0; i < 5; i ++) {
+        qemu_put_be32(f, s->timer[i].running);
+        s3c_timers_stop(s, i);
+        qemu_put_be32s(f, &s->timer[i].divider);
+        qemu_put_be16s(f, &s->timer[i].count);
+        qemu_put_be64s(f, &s->timer[i].reload);
+    }
+
+    for (i = 0; i < 4; i ++)
+        qemu_put_be16s(f, &s->compareb[i]);
+    for (i = 0; i < 5; i ++)
+        qemu_put_be16s(f, &s->countb[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_put_be32s(f, &s->config[i]);
+    qemu_put_be32s(f, &s->control);
+}
+
+static int s3c_timers_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct s3c_timers_state_s *s = (struct s3c_timers_state_s *) opaque;
+    int i;
+    for (i = 0; i < 5; i ++) {
+        s->timer[i].running = qemu_get_be32(f);
+        qemu_get_be32s(f, &s->timer[i].divider);
+        qemu_get_be16s(f, &s->timer[i].count);
+        qemu_get_be64s(f, &s->timer[i].reload);
+    }
+
+    for (i = 0; i < 4; i ++)
+        qemu_get_be16s(f, &s->compareb[i]);
+    for (i = 0; i < 5; i ++)
+        qemu_get_be16s(f, &s->countb[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_get_be32s(f, &s->config[i]);
+    qemu_get_be32s(f, &s->control);
+
+    for (i = 0; i < 5; i ++)
+        s3c_timers_start(s, i);
+
+    return 0;
+}
+
 struct s3c_timers_state_s *s3c_timers_init(target_phys_addr_t base,
                 qemu_irq *pic, qemu_irq *dma)
 {
@@ -1072,6 +1242,9 @@
                     s3c_timers_writefn, s);
     cpu_register_physical_memory(s->base, 0xffffff, iomemtype);
 
+    register_savevm("s3c24xx_timers", 0, 0,
+                    s3c_timers_save, s3c_timers_load, s);
+
     return s;
 }
 
@@ -1367,6 +1540,38 @@
     s3c_uart_write,
 };
 
+static void s3c_uart_save(QEMUFile *f, void *opaque)
+{
+    struct s3c_uart_state_s *s = (struct s3c_uart_state_s *) opaque;
+    qemu_put_8s(f, &s->data);
+    qemu_put_buffer(f, s->rxfifo, sizeof(s->rxfifo));
+    qemu_put_be32(f, s->rxstart);
+    qemu_put_be32(f, s->rxlen);
+    qemu_put_8s(f, &s->lcontrol);
+    qemu_put_8s(f, &s->fcontrol);
+    qemu_put_8s(f, &s->mcontrol);
+    qemu_put_be16s(f, &s->control);
+    qemu_put_be16s(f, &s->brdiv);
+    qemu_put_8s(f, &s->errstat);
+}
+
+static int s3c_uart_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct s3c_uart_state_s *s = (struct s3c_uart_state_s *) opaque;
+    qemu_get_8s(f, &s->data);
+    qemu_get_buffer(f, s->rxfifo, sizeof(s->rxfifo));
+    s->rxstart = qemu_get_be32(f);
+    s->rxlen = qemu_get_be32(f);
+    qemu_get_8s(f, &s->lcontrol);
+    qemu_get_8s(f, &s->fcontrol);
+    qemu_get_8s(f, &s->mcontrol);
+    qemu_get_be16s(f, &s->control);
+    qemu_get_be16s(f, &s->brdiv);
+    qemu_get_8s(f, &s->errstat);
+
+    return 0;
+}
+
 struct s3c_uart_state_s *s3c_uart_init(target_phys_addr_t base,
                 qemu_irq *irqs, qemu_irq *dma)
 {
@@ -1384,6 +1589,8 @@
                     s3c_uart_writefn, s);
     cpu_register_physical_memory(s->base, 0xfff, iomemtype);
 
+    register_savevm("s3c24xx_uart", base, 0, s3c_uart_save, s3c_uart_load, s);
+
     return s;
 }
 
@@ -1430,7 +1637,7 @@
 
 static void s3c_adc_start(struct s3c_adc_state_s *s)
 {
-    if (!s->enable && (s->ts & 7) == 0)
+    if (!s->enable || (s->ts & 7) == 0)
         return;
     s->control &= ~(1 << 15);
     s->in_idx = (s->control >> 3) & 7;
@@ -1547,6 +1754,45 @@
     s3c_adc_write,
 };
 
+static void s3c_adc_save(QEMUFile *f, void *opaque)
+{
+    struct s3c_adc_state_s *s = (struct s3c_adc_state_s *) opaque;
+    int i;
+    qemu_put_be32(f, s->enable);
+    for (i = 0; i < 8; i ++)
+        qemu_put_be32(f, s->input[i]);
+    qemu_put_be32(f, s->in_idx);
+    qemu_put_be32(f, s->noise);
+
+    qemu_put_be16s(f, &s->control);
+    qemu_put_be16s(f, &s->ts);
+    qemu_put_be16s(f, &s->delay);
+    qemu_put_be16s(f, &s->xdata);
+    qemu_put_be16s(f, &s->ydata);
+}
+
+static int s3c_adc_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct s3c_adc_state_s *s = (struct s3c_adc_state_s *) opaque;
+    int i;
+    s->enable = qemu_get_be32(f);
+    for (i = 0; i < 8; i ++)
+        s->input[i] = qemu_get_be32(f);
+    s->in_idx = qemu_get_be32(f);
+    s->noise = qemu_get_be32(f);
+
+    qemu_get_be16s(f, &s->control);
+    qemu_get_be16s(f, &s->ts);
+    qemu_get_be16s(f, &s->delay);
+    qemu_get_be16s(f, &s->xdata);
+    qemu_get_be16s(f, &s->ydata);
+
+    if (s->enable && (s->ts & 7) && !(s->control & (1 << 15)))
+        s3c_adc_start(s);
+
+    return 0;
+}
+
 struct s3c_adc_state_s *s3c_adc_init(target_phys_addr_t base, qemu_irq irq,
                 qemu_irq tcirq)
 {
@@ -1570,6 +1816,8 @@
     qemu_add_mouse_event_handler(s3c_adc_event, s, 1,
                     "QEMU S3C2410-driven Touchscreen");
 
+    register_savevm("s3c24xx_adc", 0, 0, s3c_adc_save, s3c_adc_load, s);
+
     return s;
 }
 
@@ -1769,6 +2017,37 @@
     s3c_i2c_write,
 };
 
+static void s3c_i2c_save(QEMUFile *f, void *opaque)
+{
+    struct s3c_i2c_state_s *s = (struct s3c_i2c_state_s *) opaque;
+    qemu_put_8s(f, &s->control);
+    qemu_put_8s(f, &s->status);
+    qemu_put_8s(f, &s->data);
+    qemu_put_8s(f, &s->addy);
+
+    qemu_put_be32(f, s->busy);
+    qemu_put_be32(f, s->newstart);
+
+    i2c_bus_save(f, s->bus);
+    i2c_slave_save(f, &s->slave);
+}
+
+static int s3c_i2c_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct s3c_i2c_state_s *s = (struct s3c_i2c_state_s *) opaque;
+    qemu_get_8s(f, &s->control);
+    qemu_get_8s(f, &s->status);
+    qemu_get_8s(f, &s->data);
+    qemu_get_8s(f, &s->addy);
+
+    s->busy = qemu_get_be32(f);
+    s->newstart = qemu_get_be32(f);
+
+    i2c_bus_load(f, s->bus);
+    i2c_slave_load(f, &s->slave);
+    return 0;
+}
+
 struct s3c_i2c_state_s *s3c_i2c_init(target_phys_addr_t base, qemu_irq irq)
 {
     int iomemtype;
@@ -1788,6 +2067,8 @@
                     s3c_i2c_writefn, s);
     cpu_register_physical_memory(s->base, 0xffffff, iomemtype);
 
+    register_savevm("s3c24xx_i2c", 0, 0, s3c_i2c_save, s3c_i2c_load, s);
+
     return s;
 }
 
@@ -1950,6 +2231,44 @@
     s3c_spi_write,
 };
 
+static void s3c_spi_save(QEMUFile *f, void *opaque)
+{
+    struct s3c_spi_state_s *s = (struct s3c_spi_state_s *) opaque;
+    int i;
+    for (i = 0; i < 2; i ++) {
+        qemu_put_8s(f, &s->chan[i].control);
+        qemu_put_8s(f, &s->chan[i].pin);
+        qemu_put_8s(f, &s->chan[i].pre);
+
+        qemu_put_8s(f, &s->chan[i].txbuf);
+        qemu_put_8s(f, &s->chan[i].rxbuf);
+        qemu_put_be32(f, s->chan[i].cs_pin);
+        qemu_put_be32(f, s->chan[i].clk_pin);
+        qemu_put_be32(f, s->chan[i].mosi_pin);
+        qemu_put_be32(f, s->chan[i].bit);
+    }
+}
+
+static int s3c_spi_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct s3c_spi_state_s *s = (struct s3c_spi_state_s *) opaque;
+    int i;
+    for (i = 0; i < 2; i ++) {
+        qemu_get_8s(f, &s->chan[i].control);
+        qemu_get_8s(f, &s->chan[i].pin);
+        qemu_get_8s(f, &s->chan[i].pre);
+
+        qemu_get_8s(f, &s->chan[i].txbuf);
+        qemu_get_8s(f, &s->chan[i].rxbuf);
+        s->chan[i].cs_pin = qemu_get_be32(f);
+        s->chan[i].clk_pin = qemu_get_be32(f);
+        s->chan[i].mosi_pin = qemu_get_be32(f);
+        s->chan[i].bit = qemu_get_be32(f);
+    }
+
+    return 0;
+}
+
 static void s3c_spi_bitbang_cs(void *opaque, int line, int level)
 {
     struct s3c_spi_state_s *s = (struct s3c_spi_state_s *) opaque;
@@ -2051,6 +2370,8 @@
 
     s3c_spi_bitbang_init(s, gpio);
 
+    register_savevm("s3c24xx_spi", 0, 0, s3c_spi_save, s3c_spi_load, s);
+
     return s;
 }
 
@@ -2192,6 +2513,40 @@
     s3c_i2s_write,
 };
 
+static void s3c_i2s_save(QEMUFile *f, void *opaque)
+{
+    struct s3c_i2s_state_s *s = (struct s3c_i2s_state_s *) opaque;
+    qemu_put_be16s(f, &s->control);
+    qemu_put_be16s(f, &s->mode);
+    qemu_put_be16s(f, &s->prescaler);
+    qemu_put_be16s(f, &s->fcontrol);
+
+    qemu_put_be32(f, s->tx_en);
+    qemu_put_be32(f, s->rx_en);
+    qemu_put_be32(f, s->tx_len);
+    qemu_put_be32(f, s->rx_len);
+    qemu_put_be16(f, s->buffer);
+    qemu_put_be32(f, s->cycle);
+}
+
+static int s3c_i2s_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct s3c_i2s_state_s *s = (struct s3c_i2s_state_s *) opaque;
+    qemu_get_be16s(f, &s->control);
+    qemu_get_be16s(f, &s->mode);
+    qemu_get_be16s(f, &s->prescaler);
+    qemu_get_be16s(f, &s->fcontrol);
+
+    s->tx_en = qemu_get_be32(f);
+    s->rx_en = qemu_get_be32(f);
+    s->tx_len = qemu_get_be32(f);
+    s->rx_len = qemu_get_be32(f);
+    s->buffer = qemu_get_be16(f);
+    s->cycle = qemu_get_be32(f);
+
+    return 0;
+}
+
 static void s3c_i2s_data_req(void *opaque, int tx, int rx)
 {
     struct s3c_i2s_state_s *s = (struct s3c_i2s_state_s *) opaque;
@@ -2216,6 +2571,8 @@
                     s3c_i2s_writefn, s);
     cpu_register_physical_memory(s->base, 0xffffff, iomemtype);
 
+    register_savevm("s3c24xx_iis", 0, 0, s3c_i2s_save, s3c_i2s_load, s);
+
     return s;
 }
 
@@ -2336,6 +2693,30 @@
     s3c_wdt_write,
 };
 
+static void s3c_wdt_save(QEMUFile *f, void *opaque)
+{
+    struct s3c_wdt_state_s *s = (struct s3c_wdt_state_s *) opaque;
+
+    s3c_wdt_stop(s);
+    qemu_put_be16s(f, &s->control);
+    qemu_put_be16s(f, &s->data);
+    qemu_put_be16s(f, &s->count);
+    qemu_put_be64s(f, &s->timestamp);
+}
+
+static int s3c_wdt_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct s3c_wdt_state_s *s = (struct s3c_wdt_state_s *) opaque;
+
+    qemu_get_be16s(f, &s->control);
+    qemu_get_be16s(f, &s->data);
+    qemu_get_be16s(f, &s->count);
+    qemu_get_be64s(f, &s->timestamp);
+    s3c_wdt_start(s);
+
+    return 0;
+}
+
 struct s3c_wdt_state_s *s3c_wdt_init(target_phys_addr_t base, qemu_irq irq)
 {
     int iomemtype;
@@ -2352,6 +2733,8 @@
                     s3c_wdt_writefn, s);
     cpu_register_physical_memory(s->base, 0xffffff, iomemtype);
 
+    register_savevm("s3c24xx_wdt", 0, 0, s3c_wdt_save, s3c_wdt_load, s);
+
     return s;
 }
 
@@ -2414,6 +2797,7 @@
 
     s->env = cpu_init();
     cpu_arm_set_model(s->env, "arm920t");
+    register_savevm("cpu", 0, 0, cpu_save, cpu_load, s->env);
 
     cpu_register_physical_memory(S3C_RAM_BASE, sdram_size,
                     qemu_ram_alloc(sdram_size) | IO_MEM_RAM);
@@ -2426,6 +2810,7 @@
     s3c_mc_reset(s);
     iomemtype = cpu_register_io_memory(0, s3c_mc_readfn, s3c_mc_writefn, s);
     cpu_register_physical_memory(s->mc_base, 0xffffff, iomemtype);
+    register_savevm("s3c24xx_mc", 0, 0, s3c_mc_save, s3c_mc_load, s);
 
     s->pic = s3c_pic_init(0x4a000000, arm_pic_init_cpu(s->env));
     s->irq = s3c_pic_get(s->pic);
@@ -2438,6 +2823,8 @@
     iomemtype = cpu_register_io_memory(0, s3c_clkpwr_readfn,
                     s3c_clkpwr_writefn, s);
     cpu_register_physical_memory(s->clkpwr_base, 0xffffff, iomemtype);
+    register_savevm("s3c24xx_clkpwr", 0, 0,
+                    s3c_clkpwr_save, s3c_clkpwr_load, s);
 
     s->lcd = s3c_lcd_init(0x4d000000, ds, s->irq[S3C_PIC_LCD]);
 
@@ -2446,6 +2833,7 @@
     iomemtype = cpu_register_io_memory(0, s3c_nand_readfn,
                     s3c_nand_writefn, s);
     cpu_register_physical_memory(s->nand_base, 0xffffff, iomemtype);
+    register_savevm("s3c24xx_nand", 0, 0, s3c_nand_save, s3c_nand_load, s);
 
     for (i = 0; s3c2410_uart[i].base; i ++) {
         s->uart[i] = s3c_uart_init(s3c2410_uart[i].base,

Modified: trunk/src/host/qemu-neo1973/hw/s3c24xx_gpio.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/s3c24xx_gpio.c	2007-05-21 23:27:58 UTC (rev 2051)
+++ trunk/src/host/qemu-neo1973/hw/s3c24xx_gpio.c	2007-05-21 23:47:12 UTC (rev 2052)
@@ -313,6 +313,58 @@
     s3c_gpio_write,
 };
 
+static void s3c_gpio_save(QEMUFile *f, void *opaque)
+{
+    struct s3c_gpio_state_s *s = (struct s3c_gpio_state_s *) opaque;
+    int i;
+    for (i = 0; i < S3C_IO_BANKS; i ++) {
+        qemu_put_be32s(f, &s->bank[i].con);
+        qemu_put_be32s(f, &s->bank[i].dat);
+        qemu_put_be32s(f, &s->bank[i].up);
+        qemu_put_be32s(f, &s->bank[i].mask);
+    }
+
+    qemu_put_be32s(f, &s->inform[0]);
+    qemu_put_be32s(f, &s->inform[1]);
+    qemu_put_be32s(f, &s->pwrstat);
+    qemu_put_be32s(f, &s->misccr);
+    qemu_put_be32s(f, &s->dclkcon);
+    qemu_put_be32s(f, &s->extint[0]);
+    qemu_put_be32s(f, &s->extint[1]);
+    qemu_put_be32s(f, &s->extint[2]);
+    qemu_put_be32s(f, &s->eintflt[0]);
+    qemu_put_be32s(f, &s->eintflt[1]);
+    qemu_put_be32s(f, &s->eintmask);
+    qemu_put_be32s(f, &s->eintpend);
+}
+
+static int s3c_gpio_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct s3c_gpio_state_s *s = (struct s3c_gpio_state_s *) opaque;
+    int i;
+    for (i = 0; i < S3C_IO_BANKS; i ++) {
+        qemu_get_be32s(f, &s->bank[i].con);
+        qemu_get_be32s(f, &s->bank[i].dat);
+        qemu_get_be32s(f, &s->bank[i].up);
+        qemu_get_be32s(f, &s->bank[i].mask);
+    }
+
+    qemu_get_be32s(f, &s->inform[0]);
+    qemu_get_be32s(f, &s->inform[1]);
+    qemu_get_be32s(f, &s->pwrstat);
+    qemu_get_be32s(f, &s->misccr);
+    qemu_get_be32s(f, &s->dclkcon);
+    qemu_get_be32s(f, &s->extint[0]);
+    qemu_get_be32s(f, &s->extint[1]);
+    qemu_get_be32s(f, &s->extint[2]);
+    qemu_get_be32s(f, &s->eintflt[0]);
+    qemu_get_be32s(f, &s->eintflt[1]);
+    qemu_get_be32s(f, &s->eintmask);
+    qemu_get_be32s(f, &s->eintpend);
+
+    return 0;
+}
+
 struct s3c_gpio_state_s *s3c_gpio_init(target_phys_addr_t base, qemu_irq *pic)
 {
     int iomemtype;
@@ -338,5 +390,7 @@
                     s3c_gpio_writefn, s);
     cpu_register_physical_memory(s->base, 0xffffff, iomemtype);
 
+    register_savevm("s3c24xx_io", 0, 0, s3c_gpio_save, s3c_gpio_load, s);
+
     return s;
 }

Modified: trunk/src/host/qemu-neo1973/hw/s3c24xx_lcd.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/s3c24xx_lcd.c	2007-05-21 23:27:58 UTC (rev 2051)
+++ trunk/src/host/qemu-neo1973/hw/s3c24xx_lcd.c	2007-05-21 23:47:12 UTC (rev 2052)
@@ -471,6 +471,61 @@
 #define BITS 32
 #include "s3c24xx_template.h"
 
+static void s3c_lcd_save(QEMUFile *f, void *opaque)
+{
+    struct s3c_lcd_state_s *s = (struct s3c_lcd_state_s *) opaque;
+    int i;
+    for (i = 0; i < 5; i ++)
+        qemu_put_be32s(f, &s->con[i]);
+    for (i = 0; i < 3; i ++)
+        qemu_put_be32s(f, &s->saddr[i]);
+    qemu_put_be32s(f, &s->r);
+    qemu_put_be32s(f, &s->g);
+    qemu_put_be16s(f, &s->b);
+    qemu_put_be32s(f, &s->dithmode);
+    qemu_put_be32s(f, &s->tpal);
+    qemu_put_8s(f, &s->intpnd);
+    qemu_put_8s(f, &s->srcpnd);
+    qemu_put_8s(f, &s->intmsk);
+    qemu_put_8s(f, &s->lpcsel);
+    for (i = 0; i < 0x100; i ++)
+        qemu_put_be16s(f, &s->raw_pal[i]);
+}
+
+static int s3c_lcd_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct s3c_lcd_state_s *s = (struct s3c_lcd_state_s *) opaque;
+    int i;
+    for (i = 0; i < 5; i ++)
+        qemu_get_be32s(f, &s->con[i]);
+    for (i = 0; i < 3; i ++)
+        qemu_get_be32s(f, &s->saddr[i]);
+    qemu_get_be32s(f, &s->r);
+    qemu_get_be32s(f, &s->g);
+    qemu_get_be16s(f, &s->b);
+    qemu_get_be32s(f, &s->dithmode);
+    qemu_get_be32s(f, &s->tpal);
+    qemu_get_8s(f, &s->intpnd);
+    qemu_get_8s(f, &s->srcpnd);
+    qemu_get_8s(f, &s->intmsk);
+    qemu_get_8s(f, &s->lpcsel);
+
+    s->invalidate = 1;
+    s->invalidatep = 1;
+    s->width = -1;
+    s->height = -1;
+    s->bpp = (s->con[0] >> 1) & 0xf;
+    s->enable = s->con[0] & 1;
+    s->msb = (s->con[4] >> 12) & 1;
+    s->frm565 = (s->con[4] >> 11) & 1;
+    s->fb = phys_ram_base + (((s->saddr[0] << 1) & 0x7ffffffe) - S3C_RAM_BASE);
+
+    for (i = 0; i < 0x100; i ++)
+        qemu_get_be16s(f, &s->raw_pal[i]);
+
+    return 0;
+}
+
 struct s3c_lcd_state_s *s3c_lcd_init(target_phys_addr_t base, DisplayState *ds,
                 qemu_irq irq)
 {
@@ -491,6 +546,8 @@
                     s3c_lcd_writefn, s);
     cpu_register_physical_memory(s->base, 0xffffff, iomemtype);
 
+    register_savevm("s3c24xx_lcd", 0, 0, s3c_lcd_save, s3c_lcd_load, s);
+
     switch (s->ds->depth) {
     case 0:
         s->dest_width = 0;

Modified: trunk/src/host/qemu-neo1973/hw/s3c24xx_mmci.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/s3c24xx_mmci.c	2007-05-21 23:27:58 UTC (rev 2051)
+++ trunk/src/host/qemu-neo1973/hw/s3c24xx_mmci.c	2007-05-21 23:47:12 UTC (rev 2052)
@@ -355,6 +355,62 @@
     s3c_mmci_write,
 };
 
+static void s3c_mmci_save(QEMUFile *f, void *opaque)
+{
+    struct s3c_mmci_state_s *s = (struct s3c_mmci_state_s *) opaque;
+    qemu_put_be32(f, s->blklen);
+    qemu_put_be32(f, s->blknum);
+    qemu_put_be32(f, s->blklen_cnt);
+    qemu_put_be32(f, s->blknum_cnt);
+    qemu_put_buffer(f, s->fifo, sizeof(s->fifo));
+    qemu_put_be32(f, s->fifolen);
+    qemu_put_be32(f, s->fifostart);
+    qemu_put_be32(f, s->data);
+
+    qemu_put_be32s(f, &s->control);
+    qemu_put_be32s(f, &s->arg);
+    qemu_put_be32s(f, &s->ccontrol);
+    qemu_put_be32s(f, &s->cstatus);
+    qemu_put_be32s(f, &s->dcontrol);
+    qemu_put_be32s(f, &s->dstatus);
+    qemu_put_be32s(f, &s->resp[0]);
+    qemu_put_be32s(f, &s->resp[1]);
+    qemu_put_be32s(f, &s->resp[2]);
+    qemu_put_be32s(f, &s->resp[3]);
+    qemu_put_be16s(f, &s->dtimer);
+    qemu_put_be32s(f, &s->mask);
+    qemu_put_8s(f, &s->prescaler);
+}
+
+static int s3c_mmci_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct s3c_mmci_state_s *s = (struct s3c_mmci_state_s *) opaque;
+    s->blklen = qemu_get_be32(f);
+    s->blknum = qemu_get_be32(f);
+    s->blklen_cnt = qemu_get_be32(f);
+    s->blknum_cnt = qemu_get_be32(f);
+    qemu_get_buffer(f, s->fifo, sizeof(s->fifo));
+    s->fifolen = qemu_get_be32(f);
+    s->fifostart = qemu_get_be32(f);
+    s->data = qemu_get_be32(f);
+
+    qemu_get_be32s(f, &s->control);
+    qemu_get_be32s(f, &s->arg);
+    qemu_get_be32s(f, &s->ccontrol);
+    qemu_get_be32s(f, &s->cstatus);
+    qemu_get_be32s(f, &s->dcontrol);
+    qemu_get_be32s(f, &s->dstatus);
+    qemu_get_be32s(f, &s->resp[0]);
+    qemu_get_be32s(f, &s->resp[1]);
+    qemu_get_be32s(f, &s->resp[2]);
+    qemu_get_be32s(f, &s->resp[3]);
+    qemu_get_be16s(f, &s->dtimer);
+    qemu_get_be32s(f, &s->mask);
+    qemu_get_8s(f, &s->prescaler);
+
+    return 0;
+}
+
 struct s3c_mmci_state_s *s3c_mmci_init(target_phys_addr_t base,
                 qemu_irq irq, qemu_irq *dma)
 {
@@ -372,6 +428,8 @@
                     s3c_mmci_writefn, s);
     cpu_register_physical_memory(s->base, 0xffffff, iomemtype);
 
+    register_savevm("s3c24xx_mmci", 0, 0, s3c_mmci_save, s3c_mmci_load, s);
+
     /* Instantiate the actual storage */
     s->card = sd_init(sd_bdrv);
 

Modified: trunk/src/host/qemu-neo1973/hw/s3c24xx_rtc.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/s3c24xx_rtc.c	2007-05-21 23:27:58 UTC (rev 2051)
+++ trunk/src/host/qemu-neo1973/hw/s3c24xx_rtc.c	2007-05-21 23:47:12 UTC (rev 2052)
@@ -268,6 +268,46 @@
     s3c_rtc_write,
 };
 
+static void s3c_rtc_save(QEMUFile *f, void *opaque)
+{
+    struct s3c_rtc_state_s *s = (struct s3c_rtc_state_s *) opaque;
+    qemu_put_be64s(f, &s->next);
+    qemu_put_8s(f, &s->control);
+    qemu_put_8s(f, &s->tick);
+    qemu_put_8s(f, &s->alarm);
+    qemu_put_8s(f, &s->almsec);
+    qemu_put_8s(f, &s->almmin);
+    qemu_put_8s(f, &s->almday);
+    qemu_put_8s(f, &s->almhour);
+    qemu_put_8s(f, &s->almmon);
+    qemu_put_8s(f, &s->almyear);
+    qemu_put_8s(f, &s->reset);
+    qemu_put_be32s(f, &s->sec);
+}
+
+static int s3c_rtc_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct s3c_rtc_state_s *s = (struct s3c_rtc_state_s *) opaque;
+    qemu_get_be64s(f, &s->next);
+    qemu_get_8s(f, &s->control);
+    qemu_get_8s(f, &s->tick);
+    qemu_get_8s(f, &s->alarm);
+    qemu_get_8s(f, &s->almsec);
+    qemu_get_8s(f, &s->almmin);
+    qemu_get_8s(f, &s->almday);
+    qemu_get_8s(f, &s->almhour);
+    qemu_get_8s(f, &s->almmon);
+    qemu_get_8s(f, &s->almyear);
+    qemu_get_8s(f, &s->reset);
+    qemu_get_be32s(f, &s->sec);
+
+    s->enable = (s->control == 0x1);
+    if (s->tick & (1 << 7))
+        s3c_rtc_tick_mod(s);
+
+    return 0;
+}
+
 struct s3c_rtc_state_s *s3c_rtc_init(target_phys_addr_t base, qemu_irq irq)
 {
     int iomemtype;
@@ -287,5 +327,7 @@
                     s3c_rtc_writefn, s);
     cpu_register_physical_memory(s->base, 0xffffff, iomemtype);
 
+    register_savevm("s3c24xx_rtc", 0, 0, s3c_rtc_save, s3c_rtc_load, s);
+
     return s;
 }

Modified: trunk/src/host/qemu-neo1973/hw/s3c24xx_udc.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/s3c24xx_udc.c	2007-05-21 23:27:58 UTC (rev 2051)
+++ trunk/src/host/qemu-neo1973/hw/s3c24xx_udc.c	2007-05-21 23:47:12 UTC (rev 2052)
@@ -523,6 +523,67 @@
     s3c_udc_write,
 };
 
+static void s3c_udc_save(QEMUFile *f, void *opaque)
+{
+    struct s3c_udc_state_s *s = (struct s3c_udc_state_s *) opaque;
+    int i;
+    qemu_put_8s(f, &s->ep0.csr);
+    qemu_put_8s(f, &s->ep0.maxpacket);
+
+    for (i = 0; i < S3C_EPS - 1; i ++) {
+        qemu_put_8s(f, &s->ep1[i].in_csr[0]);
+        qemu_put_8s(f, &s->ep1[i].in_csr[1]);
+        qemu_put_8s(f, &s->ep1[i].out_csr[0]);
+        qemu_put_8s(f, &s->ep1[i].out_csr[1]);
+        qemu_put_8s(f, &s->ep1[i].maxpacket);
+        qemu_put_8s(f, &s->ep1[i].control);
+        qemu_put_8s(f, &s->ep1[i].unit_cnt);
+        qemu_put_8s(f, &s->ep1[i].fifo_cnt);
+        qemu_put_be32s(f, &s->ep1[i].dma_size);
+    }
+
+    qemu_put_8s(f, &s->index);
+    qemu_put_8s(f, &s->power);
+    qemu_put_8s(f, &s->ep_intr);
+    qemu_put_8s(f, &s->ep_mask);
+    qemu_put_8s(f, &s->usb_intr);
+    qemu_put_8s(f, &s->usb_mask);
+    qemu_put_be16s(f, &s->frame);
+    qemu_put_8s(f, &s->address);
+}
+
+static int s3c_udc_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct s3c_udc_state_s *s = (struct s3c_udc_state_s *) opaque;
+    int i;
+    /* TODO: Make it look more like a disconnect */
+    qemu_put_8s(f, &s->ep0.csr);
+    qemu_put_8s(f, &s->ep0.maxpacket);
+
+    for (i = 0; i < S3C_EPS - 1; i ++) {
+        qemu_put_8s(f, &s->ep1[i].in_csr[0]);
+        qemu_put_8s(f, &s->ep1[i].in_csr[1]);
+        qemu_put_8s(f, &s->ep1[i].out_csr[0]);
+        qemu_put_8s(f, &s->ep1[i].out_csr[1]);
+        qemu_put_8s(f, &s->ep1[i].maxpacket);
+        qemu_put_8s(f, &s->ep1[i].control);
+        qemu_put_8s(f, &s->ep1[i].unit_cnt);
+        qemu_put_8s(f, &s->ep1[i].fifo_cnt);
+        qemu_put_be32s(f, &s->ep1[i].dma_size);
+    }
+
+    qemu_put_8s(f, &s->index);
+    qemu_put_8s(f, &s->power);
+    qemu_put_8s(f, &s->ep_intr);
+    qemu_put_8s(f, &s->ep_mask);
+    qemu_put_8s(f, &s->usb_intr);
+    qemu_put_8s(f, &s->usb_mask);
+    qemu_put_be16s(f, &s->frame);
+    qemu_put_8s(f, &s->address);
+
+    return 0;
+}
+
 static int s3c_udc_handle_packet(USBDevice *dev, USBPacket *p)
 {
     struct s3c_udc_state_s *s = (struct s3c_udc_state_s *) dev->opaque;
@@ -690,6 +751,8 @@
                     s3c_udc_writefn, s);
     cpu_register_physical_memory(s->base, 0xffffff, iomemtype);
 
+    register_savevm("s3c24xx_udc", 0, 0, s3c_udc_save, s3c_udc_load, s);
+
     qemu_register_usb_gadget(&s->dev);
 
     return s;

Modified: trunk/src/host/qemu-neo1973/hw/wm8750.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/wm8750.c	2007-05-21 23:27:58 UTC (rev 2051)
+++ trunk/src/host/qemu-neo1973/hw/wm8750.c	2007-05-21 23:47:12 UTC (rev 2052)
@@ -491,6 +491,93 @@
     return 0x00;
 }
 
+static void wm8750_save(QEMUFile *f, void *opaque)
+{
+    struct wm8750_s *s = (struct wm8750_s *) opaque;
+    int i;
+    qemu_put_8s(f, &s->i2c_data[0]);
+    qemu_put_8s(f, &s->i2c_data[1]);
+    qemu_put_be32(f, s->i2c_len);
+    qemu_put_be32(f, s->enable);
+    qemu_put_be32(f, s->idx_in);
+    qemu_put_be32(f, s->req_in);
+    qemu_put_be32(f, s->idx_out);
+    qemu_put_be32(f, s->req_out);
+
+    for (i = 0; i < 7; i ++)
+        qemu_put_8s(f, &s->outvol[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_put_8s(f, &s->outmute[i]);
+    for (i = 0; i < 4; i ++)
+        qemu_put_8s(f, &s->invol[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_put_8s(f, &s->inmute[i]);
+
+    for (i = 0; i < 2; i ++)
+        qemu_put_8s(f, &s->diff[i]);
+    qemu_put_8s(f, &s->pol);
+    qemu_put_8s(f, &s->ds);
+    for (i = 0; i < 2; i ++)
+        qemu_put_8s(f, &s->monomix[i]);
+    qemu_put_8s(f, &s->alc);
+    qemu_put_8s(f, &s->mute);
+    for (i = 0; i < 4; i ++)
+        qemu_put_8s(f, &s->path[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_put_8s(f, &s->mpath[i]);
+    qemu_put_8s(f, &s->format);
+    qemu_put_8s(f, &s->power);
+    qemu_put_be32s(f, &s->inmask);
+    qemu_put_be32s(f, &s->outmask);
+    qemu_put_byte(f, (s->rate - wm_rate_table) / sizeof(*s->rate));
+    i2c_slave_save(f, &s->i2c);
+}
+
+static int wm8750_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct wm8750_s *s = (struct wm8750_s *) opaque;
+    int i;
+    qemu_get_8s(f, &s->i2c_data[0]);
+    qemu_get_8s(f, &s->i2c_data[1]);
+    s->i2c_len = qemu_get_be32(f);
+    s->enable = qemu_get_be32(f);
+    s->idx_in = qemu_get_be32(f);
+    s->req_in = qemu_get_be32(f);
+    s->idx_out = qemu_get_be32(f);
+    s->req_out = qemu_get_be32(f);
+
+    for (i = 0; i < 7; i ++)
+        qemu_get_8s(f, &s->outvol[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_get_8s(f, &s->outmute[i]);
+    for (i = 0; i < 4; i ++)
+        qemu_get_8s(f, &s->invol[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_get_8s(f, &s->inmute[i]);
+
+    for (i = 0; i < 2; i ++)
+        qemu_get_8s(f, &s->diff[i]);
+    qemu_get_8s(f, &s->pol);
+    qemu_get_8s(f, &s->ds);
+    for (i = 0; i < 2; i ++)
+        qemu_get_8s(f, &s->monomix[i]);
+    qemu_get_8s(f, &s->alc);
+    qemu_get_8s(f, &s->mute);
+    for (i = 0; i < 4; i ++)
+        qemu_get_8s(f, &s->path[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_get_8s(f, &s->mpath[i]);
+    qemu_get_8s(f, &s->format);
+    qemu_get_8s(f, &s->power);
+    qemu_get_be32s(f, &s->inmask);
+    qemu_get_be32s(f, &s->outmask);
+    s->rate = &wm_rate_table[(uint8_t) qemu_get_byte(f) & 0x1f];
+    i2c_slave_load(f, &s->i2c);
+    return 0;
+}
+
+static int wm8750_iid = 0;
+
 i2c_slave *wm8750_init(i2c_bus *bus, AudioState *audio)
 {
     struct wm8750_s *s = (struct wm8750_s *)
@@ -501,6 +588,9 @@
 
     AUD_register_card(audio, CODEC, &s->card);
     wm8750_reset(&s->i2c);
+
+    register_savevm(CODEC, wm8750_iid ++, 0, wm8750_save, wm8750_load, s);
+
     return &s->i2c;
 }
 

Modified: trunk/src/host/qemu-neo1973/hw/wm8753.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/wm8753.c	2007-05-21 23:27:58 UTC (rev 2051)
+++ trunk/src/host/qemu-neo1973/hw/wm8753.c	2007-05-21 23:47:12 UTC (rev 2052)
@@ -715,6 +715,115 @@
     wm8753_int_update(s);
 }
 
+static void wm8753_save(QEMUFile *f, void *opaque)
+{
+    struct wm8753_s *s = (struct wm8753_s *) opaque;
+    int i;
+    qemu_put_8s(f, &s->i2c_data[0]);
+    qemu_put_8s(f, &s->i2c_data[1]);
+    qemu_put_be32(f, s->i2c_len);
+    qemu_put_be32(f, s->enable);
+    qemu_put_be32(f, s->idx_in);
+    qemu_put_be32(f, s->req_in);
+    qemu_put_be32(f, s->idx_out);
+    qemu_put_be32(f, s->req_out);
+
+    for (i = 0; i < 7; i ++)
+        qemu_put_8s(f, &s->outvol[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_put_8s(f, &s->outmute[i]);
+    for (i = 0; i < 4; i ++)
+        qemu_put_8s(f, &s->invol[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_put_8s(f, &s->inmute[i]);
+    qemu_put_8s(f, &s->adcin);
+    for (i = 0; i < 2; i ++)
+        qemu_put_8s(f, &s->inctl[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_put_8s(f, &s->recmix[i]);
+    qemu_put_8s(f, &s->adc);
+    qemu_put_8s(f, &s->intpol);
+    qemu_put_8s(f, &s->intmask);
+    qemu_put_8s(f, &s->intlevel);
+    qemu_put_8s(f, &s->inten);
+    qemu_put_8s(f, &s->intinput);
+    qemu_put_8s(f, &s->inthigh);
+    qemu_put_8s(f, &s->intintr);
+    qemu_put_8s(f, &s->intprev);
+    for (i = 0; i < 8; i ++)
+        qemu_put_byte(f, s->line[i].type);
+    qemu_put_8s(f, &s->response);
+    qemu_put_be32s(f, &s->inmask);
+    qemu_put_be32s(f, &s->outmask);
+    qemu_put_byte(f, (s->rate - wm_rate_table) / sizeof(*s->rate));
+    for (i = 0; i < 4; i ++)
+        qemu_put_8s(f, &s->path[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_put_8s(f, &s->mpath[i]);
+    qemu_put_8s(f, &s->format);
+    qemu_put_8s(f, &s->alc);
+    qemu_put_8s(f, &s->mute);
+    for (i = 0; i < 4; i ++)
+        qemu_put_be16s(f, &s->power[i]);
+    i2c_slave_save(f, &s->i2c);
+}
+
+static int wm8753_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct wm8753_s *s = (struct wm8753_s *) opaque;
+    int i;
+    qemu_get_8s(f, &s->i2c_data[0]);
+    qemu_get_8s(f, &s->i2c_data[1]);
+    s->i2c_len = qemu_get_be32(f);
+    s->enable = qemu_get_be32(f);
+    s->idx_in = qemu_get_be32(f);
+    s->req_in = qemu_get_be32(f);
+    s->idx_out = qemu_get_be32(f);
+    s->req_out = qemu_get_be32(f);
+
+    for (i = 0; i < 7; i ++)
+        qemu_get_8s(f, &s->outvol[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_get_8s(f, &s->outmute[i]);
+    for (i = 0; i < 4; i ++)
+        qemu_get_8s(f, &s->invol[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_get_8s(f, &s->inmute[i]);
+    qemu_get_8s(f, &s->adcin);
+    for (i = 0; i < 2; i ++)
+        qemu_get_8s(f, &s->inctl[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_get_8s(f, &s->recmix[i]);
+    qemu_get_8s(f, &s->adc);
+    qemu_get_8s(f, &s->intpol);
+    qemu_get_8s(f, &s->intmask);
+    qemu_get_8s(f, &s->intlevel);
+    qemu_get_8s(f, &s->inten);
+    qemu_get_8s(f, &s->intinput);
+    qemu_get_8s(f, &s->inthigh);
+    qemu_get_8s(f, &s->intintr);
+    qemu_get_8s(f, &s->intprev);
+    for (i = 0; i < 8; i ++)
+        s->line[i].type = qemu_get_byte(f);
+    qemu_get_8s(f, &s->response);
+    qemu_get_be32s(f, &s->inmask);
+    qemu_get_be32s(f, &s->outmask);
+    s->rate = &wm_rate_table[(uint8_t) qemu_get_byte(f) & 0x1f];
+    for (i = 0; i < 4; i ++)
+        qemu_get_8s(f, &s->path[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_get_8s(f, &s->mpath[i]);
+    qemu_get_8s(f, &s->format);
+    qemu_get_8s(f, &s->alc);
+    qemu_get_8s(f, &s->mute);
+    for (i = 0; i < 4; i ++)
+        qemu_get_be16s(f, &s->power[i]);
+    i2c_slave_load(f, &s->i2c);
+    return 0;
+}
+
+static int wm8753_iid = 0;
+
 i2c_slave *wm8753_init(i2c_bus *bus, AudioState *audio)
 {
     struct wm8753_s *s = (struct wm8753_s *)
@@ -726,6 +835,9 @@
 
     AUD_register_card(audio, CODEC, &s->card);
     wm8753_reset(&s->i2c);
+
+    register_savevm(CODEC, wm8753_iid ++, 0, wm8753_save, wm8753_load, s);
+
     return &s->i2c;
 }
 

Modified: trunk/src/host/qemu-neo1973/vl.c
===================================================================
--- trunk/src/host/qemu-neo1973/vl.c	2007-05-21 23:27:58 UTC (rev 2051)
+++ trunk/src/host/qemu-neo1973/vl.c	2007-05-21 23:47:12 UTC (rev 2052)
@@ -1361,6 +1361,8 @@
                 for (i = 0; i < MAX_DISKS; i++) {
                     if (bs_table[i])
                         bdrv_commit(bs_table[i]);
+                    if (mtd_bdrv)
+                        bdrv_commit(mtd_bdrv);
                 }
             }
             break;
@@ -5283,6 +5285,9 @@
         if (bdrv_can_snapshot(bs))
             goto ok;
     }
+    bs = mtd_bdrv;
+    if (bdrv_can_snapshot(bs))
+        goto ok;
     return NULL;
  ok:
     bs_snapshots = bs;
@@ -5313,9 +5318,9 @@
 
 void do_savevm(const char *name)
 {
-    BlockDriverState *bs, *bs1;
+    BlockDriverState *bs;
     QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1;
-    int must_delete, ret, i;
+    int must_delete, ret;
     BlockDriverInfo bdi1, *bdi = &bdi1;
     QEMUFile *f;
     int saved_vm_running;
@@ -5387,22 +5392,19 @@
     
     /* create the snapshots */
 
-    for(i = 0; i < MAX_DISKS; i++) {
-        bs1 = bs_table[i];
-        if (bdrv_has_snapshot(bs1)) {
-            if (must_delete) {
-                ret = bdrv_snapshot_delete(bs1, old_sn->id_str);
-                if (ret < 0) {
-                    term_printf("Error while deleting snapshot on '%s'\n",
-                                bdrv_get_device_name(bs1));
-                }
-            }
-            ret = bdrv_snapshot_create(bs1, sn);
+    if (bdrv_has_snapshot(bs)) {
+        if (must_delete) {
+            ret = bdrv_snapshot_delete(bs, old_sn->id_str);
             if (ret < 0) {
-                term_printf("Error while creating snapshot on '%s'\n",
-                            bdrv_get_device_name(bs1));
+                term_printf("Error while deleting snapshot on '%s'\n",
+                            bdrv_get_device_name(bs));
             }
         }
+        ret = bdrv_snapshot_create(bs, sn);
+        if (ret < 0) {
+            term_printf("Error while creating snapshot on '%s'\n",
+                        bdrv_get_device_name(bs));
+        }
     }
 
  the_end:
@@ -5412,10 +5414,10 @@
 
 void do_loadvm(const char *name)
 {
-    BlockDriverState *bs, *bs1;
+    BlockDriverState *bs;
     BlockDriverInfo bdi1, *bdi = &bdi1;
     QEMUFile *f;
-    int i, ret;
+    int ret;
     int saved_vm_running;
 
     bs = get_bs_snapshots();
@@ -5430,31 +5432,25 @@
     saved_vm_running = vm_running;
     vm_stop(0);
 
-    for(i = 0; i <= MAX_DISKS; i++) {
-        bs1 = bs_table[i];
-        if (bdrv_has_snapshot(bs1)) {
-            ret = bdrv_snapshot_goto(bs1, name);
-            if (ret < 0) {
-                if (bs != bs1)
-                    term_printf("Warning: ");
-                switch(ret) {
-                case -ENOTSUP:
-                    term_printf("Snapshots not supported on device '%s'\n",
-                                bdrv_get_device_name(bs1));
-                    break;
-                case -ENOENT:
-                    term_printf("Could not find snapshot '%s' on device '%s'\n",
-                                name, bdrv_get_device_name(bs1));
-                    break;
-                default:
-                    term_printf("Error %d while activating snapshot on '%s'\n",
-                                ret, bdrv_get_device_name(bs1));
-                    break;
-                }
-                /* fatal on snapshot block device */
-                if (bs == bs1)
-                    goto the_end;
+    if (bdrv_has_snapshot(bs)) {
+        ret = bdrv_snapshot_goto(bs, name);
+        if (ret < 0) {
+            switch(ret) {
+            case -ENOTSUP:
+                term_printf("Snapshots not supported on device '%s'\n",
+                            bdrv_get_device_name(bs));
+                break;
+            case -ENOENT:
+                term_printf("Could not find snapshot '%s' on device '%s'\n",
+                            name, bdrv_get_device_name(bs));
+                break;
+            default:
+                term_printf("Error %d while activating snapshot on '%s'\n",
+                            ret, bdrv_get_device_name(bs));
+                break;
             }
+            /* fatal on snapshot block device */
+            goto the_end;
         }
     }
 
@@ -5482,34 +5478,31 @@
 
 void do_delvm(const char *name)
 {
-    BlockDriverState *bs, *bs1;
-    int i, ret;
+    BlockDriverState *bs;
+    int ret;
 
     bs = get_bs_snapshots();
     if (!bs) {
         term_printf("No block device supports snapshots\n");
         return;
     }
-    
-    for(i = 0; i <= MAX_DISKS; i++) {
-        bs1 = bs_table[i];
-        if (bdrv_has_snapshot(bs1)) {
-            ret = bdrv_snapshot_delete(bs1, name);
-            if (ret < 0) {
-                if (ret == -ENOTSUP)
-                    term_printf("Snapshots not supported on device '%s'\n",
-                                bdrv_get_device_name(bs1));
-                else
-                    term_printf("Error %d while deleting snapshot on '%s'\n",
-                                ret, bdrv_get_device_name(bs1));
-            }
+  
+    if (bdrv_has_snapshot(bs)) {
+        ret = bdrv_snapshot_delete(bs, name);
+        if (ret < 0) {
+            if (ret == -ENOTSUP)
+                term_printf("Snapshots not supported on device '%s'\n",
+                            bdrv_get_device_name(bs));
+            else
+                term_printf("Error %d while deleting snapshot on '%s'\n",
+                            ret, bdrv_get_device_name(bs));
         }
     }
 }
 
 void do_info_snapshots(void)
 {
-    BlockDriverState *bs, *bs1;
+    BlockDriverState *bs;
     QEMUSnapshotInfo *sn_tab, *sn;
     int nb_sns, i;
     char buf[256];
@@ -5520,13 +5513,8 @@
         return;
     }
     term_printf("Snapshot devices:");
-    for(i = 0; i <= MAX_DISKS; i++) {
-        bs1 = bs_table[i];
-        if (bdrv_has_snapshot(bs1)) {
-            if (bs == bs1)
-                term_printf(" %s", bdrv_get_device_name(bs1));
-        }
-    }
+    if (bdrv_has_snapshot(bs))
+        term_printf(" %s", bdrv_get_device_name(bs));
     term_printf("\n");
 
     nb_sns = bdrv_snapshot_list(bs, &sn_tab);
@@ -5899,13 +5887,144 @@
 
 #elif defined(TARGET_ARM)
 
-/* ??? Need to implement these.  */
 void cpu_save(QEMUFile *f, void *opaque)
 {
+    int i;
+    CPUARMState *env = (CPUARMState *)opaque;
+
+    for (i = 0; i < 16; i++) {
+        qemu_put_be32(f, env->regs[i]);
+    }
+    qemu_put_be32(f, cpsr_read(env));
+    qemu_put_be32(f, env->spsr);
+    for (i = 0; i < 6; i++) {
+        qemu_put_be32(f, env->banked_spsr[i]);
+        qemu_put_be32(f, env->banked_r13[i]);
+        qemu_put_be32(f, env->banked_r14[i]);
+    }
+    for (i = 0; i < 5; i++) {
+        qemu_put_be32(f, env->usr_regs[i]);
+        qemu_put_be32(f, env->fiq_regs[i]);
+    }
+    qemu_put_be32(f, env->cp15.c0_cpuid);
+    qemu_put_be32(f, env->cp15.c0_cachetype);
+    qemu_put_be32(f, env->cp15.c1_sys);
+    qemu_put_be32(f, env->cp15.c1_coproc);
+    qemu_put_be32(f, env->cp15.c2_base);
+    qemu_put_be32(f, env->cp15.c2_data);
+    qemu_put_be32(f, env->cp15.c2_insn);
+    qemu_put_be32(f, env->cp15.c3);
+    qemu_put_be32(f, env->cp15.c5_insn);
+    qemu_put_be32(f, env->cp15.c5_data);
+    for (i = 0; i < 8; i++) {
+        qemu_put_be32(f, env->cp15.c6_region[i]);
+    }
+    qemu_put_be32(f, env->cp15.c6_insn);
+    qemu_put_be32(f, env->cp15.c6_data);
+    qemu_put_be32(f, env->cp15.c9_insn);
+    qemu_put_be32(f, env->cp15.c9_data);
+    qemu_put_be32(f, env->cp15.c13_fcse);
+    qemu_put_be32(f, env->cp15.c13_context);
+    qemu_put_be32(f, env->cp15.c15_cpar);
+
+    qemu_put_be32(f, env->features);
+
+    if (arm_feature(env, ARM_FEATURE_VFP)) {
+        for (i = 0;  i < 16; i++) {
+            CPU_DoubleU u;
+            u.d = env->vfp.regs[i];
+            qemu_put_be32(f, u.l.upper);
+            qemu_put_be32(f, u.l.lower);
+        }
+        for (i = 0; i < 16; i++) {
+            qemu_put_be32(f, env->vfp.xregs[i]);
+        }
+
+        /* TODO: Should use proper FPSCR access functions.  */
+        qemu_put_be32(f, env->vfp.vec_len);
+        qemu_put_be32(f, env->vfp.vec_stride);
+    }
+
+    if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
+        for (i = 0; i < 16; i++) {
+            qemu_put_be64(f, env->iwmmxt.regs[i]);
+        }
+        for (i = 0; i < 16; i++) {
+            qemu_put_be32(f, env->iwmmxt.cregs[i]);
+        }
+    }
 }
 
 int cpu_load(QEMUFile *f, void *opaque, int version_id)
 {
+    CPUARMState *env = (CPUARMState *)opaque;
+    int i;
+
+    if (version_id != 0)
+        return -EINVAL;
+
+    for (i = 0; i < 16; i++) {
+        env->regs[i] = qemu_get_be32(f);
+    }
+    cpsr_write(env, qemu_get_be32(f), 0xffffffff);
+    env->spsr = qemu_get_be32(f);
+    for (i = 0; i < 6; i++) {
+        env->banked_spsr[i] = qemu_get_be32(f);
+        env->banked_r13[i] = qemu_get_be32(f);
+        env->banked_r14[i] = qemu_get_be32(f);
+    }
+    for (i = 0; i < 5; i++) {
+        env->usr_regs[i] = qemu_get_be32(f);
+        env->fiq_regs[i] = qemu_get_be32(f);
+    }
+    env->cp15.c0_cpuid = qemu_get_be32(f);
+    env->cp15.c0_cachetype = qemu_get_be32(f);
+    env->cp15.c1_sys = qemu_get_be32(f);
+    env->cp15.c1_coproc = qemu_get_be32(f);
+    env->cp15.c2_base = qemu_get_be32(f);
+    env->cp15.c2_data = qemu_get_be32(f);
+    env->cp15.c2_insn = qemu_get_be32(f);
+    env->cp15.c3 = qemu_get_be32(f);
+    env->cp15.c5_insn = qemu_get_be32(f);
+    env->cp15.c5_data = qemu_get_be32(f);
+    for (i = 0; i < 8; i++) {
+        env->cp15.c6_region[i] = qemu_get_be32(f);
+    }
+    env->cp15.c6_insn = qemu_get_be32(f);
+    env->cp15.c6_data = qemu_get_be32(f);
+    env->cp15.c9_insn = qemu_get_be32(f);
+    env->cp15.c9_data = qemu_get_be32(f);
+    env->cp15.c13_fcse = qemu_get_be32(f);
+    env->cp15.c13_context = qemu_get_be32(f);
+    env->cp15.c15_cpar = qemu_get_be32(f);
+
+    env->features = qemu_get_be32(f);
+
+    if (arm_feature(env, ARM_FEATURE_VFP)) {
+        for (i = 0;  i < 16; i++) {
+            CPU_DoubleU u;
+            u.l.upper = qemu_get_be32(f);
+            u.l.lower = qemu_get_be32(f);
+            env->vfp.regs[i] = u.d;
+        }
+        for (i = 0; i < 16; i++) {
+            env->vfp.xregs[i] = qemu_get_be32(f);
+        }
+
+        /* TODO: Should use proper FPSCR access functions.  */
+        env->vfp.vec_len = qemu_get_be32(f);
+        env->vfp.vec_stride = qemu_get_be32(f);
+    }
+
+    if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
+        for (i = 0; i < 16; i++) {
+            env->iwmmxt.regs[i] = qemu_get_be64(f);
+        }
+        for (i = 0; i < 16; i++) {
+            env->iwmmxt.cregs[i] = qemu_get_be32(f);
+        }
+    }
+
     return 0;
 }
 





More information about the commitlog mailing list