aboutsummaryrefslogtreecommitdiffstats
path: root/hw
diff options
context:
space:
mode:
authorOt ten Thije <ottenthije@google.com>2010-09-08 12:38:43 +0100
committerOt ten Thije <ottenthije@google.com>2010-09-08 14:13:05 +0100
commit043b3936ee28f325bbc10e19f84e481d3eb3e183 (patch)
tree5d1bd5c3db42db5263bcb226f1bbd3e279789e02 /hw
parente92bc56ef89ab8b51c4c89d4d9779b64e9491b9b (diff)
downloadexternal_qemu-043b3936ee28f325bbc10e19f84e481d3eb3e183.zip
external_qemu-043b3936ee28f325bbc10e19f84e481d3eb3e183.tar.gz
external_qemu-043b3936ee28f325bbc10e19f84e481d3eb3e183.tar.bz2
Add basic suspend/resume support for networking.
This patch saves the current state of the SMSC 91C111 ethernet emulation. The restore function will restore all buffers, thus preventing segfaults when guest code tries to access data that was there when state was saved. However, no effort is made to re-establish connections. This is probably impossible anyway, since we have no way to generically make the remote end pick up where we left when state was suspended. From the perspective of the guest, resuming is therefore equivalent to a temporary network failure, in which all open connections are lost. After the restore is complete, new connections can be made as though nothing happened. Change-Id: Ibbbabc685ef296e675d4018996f703e07d9aad6a
Diffstat (limited to 'hw')
-rw-r--r--hw/smc91c111.c83
1 files changed, 81 insertions, 2 deletions
diff --git a/hw/smc91c111.c b/hw/smc91c111.c
index cf8d864..1eaba74 100644
--- a/hw/smc91c111.c
+++ b/hw/smc91c111.c
@@ -10,11 +10,13 @@
#include "sysbus.h"
#include "net.h"
#include "devices.h"
+#include "hw/hw.h"
/* For crc32 */
#include <zlib.h>
/* Number of 2k memory pages available. */
#define NUM_PACKETS 4
+#define BUFFER_PER_PACKET 2048
typedef struct {
SysBusDevice busdev;
@@ -39,13 +41,88 @@ typedef struct {
int tx_fifo_done_len;
int tx_fifo_done[NUM_PACKETS];
/* Packet buffer memory. */
- uint8_t data[NUM_PACKETS][2048];
+ uint8_t data[NUM_PACKETS][BUFFER_PER_PACKET];
uint8_t int_level;
uint8_t int_mask;
uint8_t macaddr[6];
int mmio_index;
} smc91c111_state;
+#define SMC91C111_SAVE_VERSION 1
+
+static void smc91c111_save(QEMUFile *f, void *opaque)
+{
+ smc91c111_state *s = opaque;
+
+ /* busdev, vc, macaddr and mmio_index are linked to the host state and
+ * initialized when the emulator starts (in smc91c111_init1 below).
+ * Saving/restoring those values is therefore useless and may even be
+ * harmful, so they are omitted.
+ */
+ qemu_put_be16(f, s->tcr);
+ qemu_put_be16(f, s->rcr);
+ qemu_put_be16(f, s->cr);
+ qemu_put_be16(f, s->ctr);
+ qemu_put_be16(f, s->gpr);
+ qemu_put_be16(f, s->ptr);
+ qemu_put_be16(f, s->ercv);
+
+ qemu_put_be32(f, s->bank);
+ qemu_put_be32(f, s->packet_num);
+
+ qemu_put_be32(f, s->tx_alloc);
+ qemu_put_be32(f, s->allocated);
+ qemu_put_be32(f, s->tx_fifo_len);
+ qemu_put_buffer(f, (uint8_t*) s->tx_fifo, sizeof(s->tx_fifo));
+ qemu_put_be32(f, s->rx_fifo_len);
+ qemu_put_buffer(f, (uint8_t*) s->rx_fifo, sizeof(s->rx_fifo));
+ qemu_put_be32(f, s->tx_fifo_done_len);
+ qemu_put_buffer(f, (uint8_t*) s->tx_fifo_done, sizeof(s->tx_fifo_done));
+
+ /* Packet buffer memory. */
+ qemu_put_buffer(f, (uint8_t*) s->data, sizeof(s->data));
+ qemu_put_byte(f, s->int_level);
+ qemu_put_byte(f, s->int_mask);
+
+ /* macaddr, mmio_index omitted intentionally */
+}
+
+static int smc91c111_load(QEMUFile *f, void *opaque, int version_id)
+{
+ smc91c111_state *s = opaque;
+
+ if (version_id != SMC91C111_SAVE_VERSION) {
+ return -1;
+ }
+
+ s->tcr = qemu_get_be16(f);
+ s->rcr = qemu_get_be16(f);
+ s->cr = qemu_get_be16(f);
+ s->ctr = qemu_get_be16(f);
+ s->gpr = qemu_get_be16(f);
+ s->ptr = qemu_get_be16(f);
+ s->ercv = qemu_get_be16(f);
+
+ s->bank = qemu_get_be32(f);
+ s->packet_num = qemu_get_be32(f);
+
+ s->tx_alloc = qemu_get_be32(f);
+ s->allocated = qemu_get_be32(f);
+ s->tx_fifo_len = qemu_get_be32(f);
+ qemu_get_buffer(f, (uint8_t*) s->tx_fifo, sizeof(s->tx_fifo));
+ s->rx_fifo_len = qemu_get_be32(f);
+ qemu_get_buffer(f, (uint8_t*) s->rx_fifo, sizeof(s->rx_fifo));
+ s->tx_fifo_done_len = qemu_get_be32(f);
+ qemu_get_buffer(f, (uint8_t*) s->tx_fifo_done, sizeof(s->tx_fifo_done));
+
+ /* Packet buffer memory. */
+ qemu_get_buffer(f, (uint8_t*) s->data, sizeof(s->data));
+ s->int_level = qemu_get_byte(f);
+ s->int_mask = qemu_get_byte(f);
+
+ return 0;
+}
+
#define RCR_SOFT_RST 0x8000
#define RCR_STRIP_CRC 0x0200
#define RCR_RXEN 0x0100
@@ -716,7 +793,9 @@ static void smc91c111_init1(SysBusDevice *dev)
smc91c111_can_receive, smc91c111_receive, NULL,
smc91c111_cleanup, s);
qemu_format_nic_info_str(s->vc, s->macaddr);
- /* ??? Save/restore. */
+
+ register_savevm( "smc91c111", 0, SMC91C111_SAVE_VERSION,
+ smc91c111_save, smc91c111_load, s);
}
static void smc91c111_register_devices(void)