diff --git a/hw/hw.h b/hw/hw.h
index 1e5783d..19ebef2 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -269,4 +269,128 @@ typedef int QEMUBootSetHandler(void *opaque, const char *boot_devices);
 void qemu_register_boot_set(QEMUBootSetHandler *func, void *opaque);
 int qemu_boot_set(const char *boot_devices);

+enum VMStateType {
+    VMSTATE_TYPE_UNSPEC = 0,
+    VMSTATE_TYPE_INT8,
+    VMSTATE_TYPE_INT16,
+    VMSTATE_TYPE_INT32,
+    VMSTATE_TYPE_INT64,
+    VMSTATE_TYPE_UINT8,
+    VMSTATE_TYPE_UINT16,
+    VMSTATE_TYPE_UINT32,
+    VMSTATE_TYPE_UINT64,
+    VMSTATE_TYPE_TIMER,
+};
+
+typedef struct VMStateInfo VMStateInfo;
+
+struct VMStateInfo {
+    const char *name;
+    size_t size;
+    enum VMStateType type;
+    void (*get)(QEMUFile *f, VMStateInfo *info, void *pv);
+    void (*put)(QEMUFile *f, VMStateInfo *info, const void *pv);
+};
+
+typedef struct {
+    const char *name;
+    size_t num;
+    size_t offset;
+    VMStateInfo *info;
+    int version_id;
+} VMStateField;
+
+typedef struct {
+    const char *name;
+    int version_id;
+    int minimum_version_id;
+    VMStateField *fields;
+} VMStateDescription;
+
+extern VMStateInfo vmstate_info_int8;
+extern VMStateInfo vmstate_info_int16;
+extern VMStateInfo vmstate_info_int32;
+extern VMStateInfo vmstate_info_int64;
+
+extern VMStateInfo vmstate_info_uint8;
+extern VMStateInfo vmstate_info_uint16;
+extern VMStateInfo vmstate_info_uint32;
+extern VMStateInfo vmstate_info_uint64;
+
+extern VMStateInfo vmstate_info_timer;
+
+#define typeof_field2(type, field) typeof(((type *)0)->field)
+#define type_check2(t1,t2) ((t1*)0 - (t2*)0)
+#define type_check_array(t1,t2,n) ((t1(*)[n])0 - (t2*)0)
+
+#define VMSTATE_FIELD(_field, _state, _version, _info, _type) {           \
+    .name       = (stringify(_field)),                                     \
+    .num        = 1,                                                       \
+    .version_id = (_version),                                              \
+    .info       = &(_info),                                                \
+    .offset     = offsetof(_state, _field)                                 \
+            + type_check2(_type,typeof_field2(_state, _field))            \
+}
+
+#define VMSTATE_FIELD_A(_field, _state, _version, _num, _info, _type) {   \
+    .name       = (stringify(_field)),                                     \
+    .num        = (_num),                                                  \
+    .version_id = (_version),                                              \
+    .info       = &(_info),                                                \
+    .offset     = offsetof(_state, _field)                                 \
+            + type_check_array(_type,typeof_field2(_state, _field),_num)  \
+}
+
+/* _f : field name
+   _s : struct state name
+   _v : version
+   _n : num of elements
+*/
+
+
+#define VMSTATE_INT8_ARRAY(_f, _s, _v, _n)                            \
+    VMSTATE_FIELD_A(_f, _s, _v, _n, vmstate_info_int8, int8_t)
+#define VMSTATE_INT16_ARRAY(_f, _s, _v, _n)                           \
+    VMSTATE_FIELD_A(_f, _s, _v, _n, vmstate_info_int16, int16_t)
+#define VMSTATE_INT32_ARRAY(_f, _s, _v, _n)                           \
+    VMSTATE_FIELD_A(_f, _s, _v, _n, vmstate_info_int32, int32_t)
+#define VMSTATE_INT64_ARRAY(_f, _s, _v, _n)                           \
+    VMSTATE_FIELD_A(_f, _s, _v, _n, vmstate_info_int64, int64_t)
+
+#define VMSTATE_UINT8_ARRAY(_f, _s, _v, _n)                           \
+    VMSTATE_FIELD_A(_f, _s, _v, _n, vmstate_info_uint8, uint8_t)
+#define VMSTATE_UINT16_ARRAY(_f, _s, _v, _n)                          \
+    VMSTATE_FIELD_A(_f, _s, _v, _n, vmstate_info_uint16, uint16_t)
+#define VMSTATE_UINT32_ARRAY(_f, _s, _v, _n)                          \
+    VMSTATE_FIELD_A(_f, _s, _v, _n, vmstate_info_uint32, uint32_t)
+#define VMSTATE_UINT64_ARRAY(_f, _s, _v, _n)                          \
+    VMSTATE_FIELD_A(_f, _s, _v, _n, vmstate_info_uint64, uint64_t)
+
+#define VMSTATE_INT8(_f, _s, _v)                                      \
+    VMSTATE_FIELD(_f, _s, _v, vmstate_info_int8, int8_t)
+#define VMSTATE_INT16(_f, _s, _v)                                     \
+    VMSTATE_FIELD(_f, _s, _v, vmstate_info_int16, int16_t)
+#define VMSTATE_INT32(_f, _s, _v)                                     \
+    VMSTATE_FIELD(_f, _s, _v, vmstate_info_int32, int32_t)
+#define VMSTATE_INT64(_f, _s, _v)                                     \
+    VMSTATE_FIELD(_f, _s, _v, vmstate_info_int64, int64_t)
+
+#define VMSTATE_UINT8(_f, _s, _v)                                     \
+    VMSTATE_FIELD(_f, _s, _v, vmstate_info_uint8, uint8_t)
+#define VMSTATE_UINT16(_f, _s, _v)                                    \
+    VMSTATE_FIELD(_f, _s, _v, vmstate_info_uint16, uint16_t)
+#define VMSTATE_UINT32(_f, _s, _v)                                    \
+    VMSTATE_FIELD(_f, _s, _v, vmstate_info_uint32, uint32_t)
+#define VMSTATE_UINT64(_f, _s, _v)                                    \
+    VMSTATE_FIELD(_f, _s, _v, vmstate_info_uint64, uint64_t)
+
+#define VMSTATE_TIMER(_f, _s, _v)                                     \
+    VMSTATE_FIELD(_f, _s, _v, vmstate_info_timer, QEMUTimer *)
+
+#define VMSTATE_END_OF_LIST()               \
+    {}
+
+extern int vmstate_register(int instance_id, VMStateDescription *vmsd,
+                            void *base);
+extern void vmstate_unregister(const char *idstr, void *opaque);
 #endif
diff --git a/savevm.c b/savevm.c
index 55a1b50..aff4c82 100644
--- a/savevm.c
+++ b/savevm.c
@@ -610,6 +610,204 @@ uint64_t qemu_get_be64(QEMUFile *f)
     return v;
 }

+/* 8 bit int */
+
+static void get_int8(QEMUFile *f, VMStateInfo *info, void *pv)
+{
+    int8_t *v = pv;
+    qemu_get_s8s(f, v);
+}
+
+static void put_int8(QEMUFile *f, VMStateInfo *info, const void *pv)
+{
+    const int8_t *v = pv;
+    qemu_put_s8s(f, v);
+}
+
+VMStateInfo vmstate_info_int8 = {
+    .name  = "int8",
+    .type  = VMSTATE_TYPE_INT8,
+    .size  = sizeof(int8_t),
+    .get = get_int8,
+    .put = put_int8,
+};
+
+/* 16 bit int */
+
+static void get_int16(QEMUFile *f, VMStateInfo *info, void *pv)
+{
+    int16_t *v = pv;
+    qemu_get_sbe16s(f, v);
+}
+
+static void put_int16(QEMUFile *f, VMStateInfo *info, const void *pv)
+{
+    const int16_t *v = pv;
+    qemu_put_sbe16s(f, v);
+}
+
+VMStateInfo vmstate_info_int16 = {
+    .name  = "int16",
+    .type  = VMSTATE_TYPE_INT16,
+    .size  = sizeof(int16_t),
+    .get = get_int16,
+    .put = put_int16,
+};
+
+/* 32 bit int */
+
+static void get_int32(QEMUFile *f, VMStateInfo *info, void *pv)
+{
+    int32_t *v = pv;
+    qemu_get_sbe32s(f, v);
+}
+
+static void put_int32(QEMUFile *f, VMStateInfo *info, const void *pv)
+{
+    const int32_t *v = pv;
+    qemu_put_sbe32s(f, v);
+}
+
+VMStateInfo vmstate_info_int32 = {
+    .name  = "int32",
+    .type  = VMSTATE_TYPE_INT32,
+    .size  = sizeof(int32_t),
+    .get = get_int32,
+    .put = put_int32,
+};
+
+/* 64 bit int */
+
+static void get_int64(QEMUFile *f, VMStateInfo *info, void *pv)
+{
+    int64_t *v = pv;
+    qemu_get_sbe64s(f, v);
+}
+
+static void put_int64(QEMUFile *f, VMStateInfo *info, const void *pv)
+{
+    const int64_t *v = pv;
+    qemu_put_sbe64s(f, v);
+}
+
+VMStateInfo vmstate_info_int64 = {
+    .name  = "int64",
+    .type  = VMSTATE_TYPE_INT64,
+    .size  = sizeof(int64_t),
+    .get = get_int64,
+    .put = put_int64,
+};
+
+/* 8 bit unsigned int */
+
+static void get_uint8(QEMUFile *f, VMStateInfo *info, void *pv)
+{
+    uint8_t *v = pv;
+    qemu_get_8s(f, v);
+}
+
+static void put_uint8(QEMUFile *f, VMStateInfo *info, const void *pv)
+{
+    const uint8_t *v = pv;
+    qemu_put_8s(f, v);
+}
+
+VMStateInfo vmstate_info_uint8 = {
+    .name  = "uint8",
+    .type  = VMSTATE_TYPE_UINT8,
+    .size  = sizeof(uint8_t),
+    .get = get_uint8,
+    .put = put_uint8,
+};
+
+/* 16 bit unsigned int */
+
+static void get_uint16(QEMUFile *f, VMStateInfo *info, void *pv)
+{
+    uint16_t *v = pv;
+    qemu_get_be16s(f, v);
+}
+
+static void put_uint16(QEMUFile *f, VMStateInfo *info, const void *pv)
+{
+    const uint16_t *v = pv;
+    qemu_put_be16s(f, v);
+}
+
+VMStateInfo vmstate_info_uint16 = {
+    .name  = "uint16",
+    .type  = VMSTATE_TYPE_UINT16,
+    .size  = sizeof(uint16_t),
+    .get = get_uint16,
+    .put = put_uint16,
+};
+
+/* 32 bit unsigned int */
+
+static void get_uint32(QEMUFile *f, VMStateInfo *info, void *pv)
+{
+    uint32_t *v = pv;
+    qemu_get_be32s(f, v);
+}
+
+static void put_uint32(QEMUFile *f, VMStateInfo *info, const void *pv)
+{
+    const uint32_t *v = pv;
+    qemu_put_be32s(f, v);
+}
+
+VMStateInfo vmstate_info_uint32 = {
+    .name  = "uint32",
+    .type  = VMSTATE_TYPE_UINT32,
+    .size  = sizeof(uint32_t),
+    .get = get_uint32,
+    .put = put_uint32,
+};
+
+/* 64 bit unsigned int */
+
+static void get_uint64(QEMUFile *f, VMStateInfo *info, void *pv)
+{
+    uint64_t *v = pv;
+    qemu_get_be64s(f, v);
+}
+
+static void put_uint64(QEMUFile *f, VMStateInfo *info, const void *pv)
+{
+    const uint64_t *v = pv;
+    qemu_put_be64s(f, v);
+}
+
+VMStateInfo vmstate_info_uint64 = {
+    .name  = "uint64",
+    .type  = VMSTATE_TYPE_UINT64,
+    .size  = sizeof(uint64_t),
+    .get = get_uint64,
+    .put = put_uint64,
+};
+
+/* timers  */
+
+static void get_timer(QEMUFile *f, VMStateInfo *info, void *pv)
+{
+    QEMUTimer **v = pv;
+    qemu_get_timer(f, *v);
+}
+
+static void put_timer(QEMUFile *f, VMStateInfo *info, const void *pv)
+{
+    QEMUTimer **v = (void *)pv;
+    qemu_put_timer(f, *v);
+}
+
+VMStateInfo vmstate_info_timer = {
+    .name  = "timer",
+    .type  = VMSTATE_TYPE_TIMER,
+    .size  = sizeof(uint64_t),
+    .get = get_timer,
+    .put = put_timer,
+};
+
 typedef struct SaveStateEntry {
     char idstr[256];
     int instance_id;
@@ -618,11 +816,13 @@ typedef struct SaveStateEntry {
     SaveLiveStateHandler *save_live_state;
     SaveStateHandler *save_state;
     LoadStateHandler *load_state;
+    VMStateDescription *vmsd;
     void *opaque;
     struct SaveStateEntry *next;
 } SaveStateEntry;

 static SaveStateEntry *first_se;
+static int global_section_id;

 /* TODO: Individual devices generally have very little idea about the rest
    of the system, so instance_id should be removed/replaced.
@@ -637,7 +837,6 @@ int register_savevm_live(const char *idstr,
                          void *opaque)
 {
     SaveStateEntry *se, **pse;
-    static int global_section_id;

     se = qemu_malloc(sizeof(SaveStateEntry));
     pstrcpy(se->idstr, sizeof(se->idstr), idstr);
@@ -648,6 +847,7 @@ int register_savevm_live(const char *idstr,
     se->save_state = save_state;
     se->load_state = load_state;
     se->opaque = opaque;
+    se->vmsd = NULL;
     se->next = NULL;

     /* add at the end of list */
@@ -690,6 +890,88 @@ void unregister_savevm(const char *idstr, void *opaque)
     }
 }

+int vmstate_register(int instance_id, VMStateDescription *vmsd,
+                     void *opaque)
+{
+    SaveStateEntry *se, **pse;
+
+    se = qemu_malloc(sizeof(SaveStateEntry));
+    pstrcpy(se->idstr, sizeof(se->idstr), vmsd->name);
+    se->instance_id = (instance_id == -1) ? 0 : instance_id;
+    se->version_id = vmsd->version_id;
+    se->section_id = global_section_id++;
+    se->save_live_state = NULL;
+    se->save_state = NULL;
+    se->load_state = NULL;
+    se->opaque = opaque;
+    se->vmsd = vmsd;
+    se->next = NULL;
+
+    /* add at the end of list */
+    pse = &first_se;
+    while (*pse != NULL) {
+        if (instance_id == -1
+                && strcmp(se->idstr, (*pse)->idstr) == 0
+                && se->instance_id <= (*pse)->instance_id)
+            se->instance_id = (*pse)->instance_id + 1;
+        pse = &(*pse)->next;
+    }
+    *pse = se;
+    return 0;
+}
+
+void vmstate_unregister(const char *idstr,  void *opaque)
+{
+    SaveStateEntry **pse;
+
+    pse = &first_se;
+    while (*pse != NULL) {
+        if (strcmp((*pse)->idstr, idstr) == 0 && (*pse)->opaque == opaque) {
+            SaveStateEntry *next = (*pse)->next;
+            qemu_free(*pse);
+            *pse = next;
+            continue;
+        }
+        pse = &(*pse)->next;
+    }
+}
+
+static void vmstate_save(QEMUFile *f, VMStateDescription *vmsd, void *base)
+{
+    VMStateField *field = vmsd->fields;
+    int i;
+
+    while(field->name) {
+        for (i = 0; i < field->num; i++) {
+            field->info->put(f, field->info, base + field->offset +
+                             field->info->size * i);
+        }
+        field++;
+    }
+}
+
+static int vmstate_load(QEMUFile *f, VMStateDescription *vmsd, void *base,
+                        int version_id)
+{
+    VMStateField *field = vmsd->fields;
+    int i;
+
+    if (version_id > vmsd->version_id ||
+        version_id < vmsd->minimum_version_id)
+        return -EINVAL;
+
+    while(field->name) {
+        for (i = 0; i < field->num; i++) {
+            if (field->version_id <= version_id) {
+                field->info->get(f, field->info, base + field->offset +
+                                 field->info->size * i);
+            }
+        }
+        field++;
+    }
+    return 0;
+}
+
 #define QEMU_VM_FILE_MAGIC           0x5145564d
 #define QEMU_VM_FILE_VERSION_COMPAT  0x00000002
 #define QEMU_VM_FILE_VERSION         0x00000003
@@ -777,7 +1059,7 @@ int qemu_savevm_state_complete(QEMUFile *f)
     for(se = first_se; se != NULL; se = se->next) {
         int len;

-	if (se->save_state == NULL)
+	if (se->save_state == NULL && se->vmsd == NULL)
 	    continue;

         /* Section type */
@@ -792,7 +1074,10 @@ int qemu_savevm_state_complete(QEMUFile *f)
         qemu_put_be32(f, se->instance_id);
         qemu_put_be32(f, se->version_id);

-        se->save_state(f, se->opaque);
+        if (se->vmsd != NULL)
+            vmstate_save(f, se->vmsd, se->opaque);
+        else
+            se->save_state(f, se->opaque);
     }

     qemu_put_byte(f, QEMU_VM_EOF);
@@ -878,7 +1163,11 @@ static int qemu_loadvm_state_v2(QEMUFile *f)
             fprintf(stderr, "qemu: warning: instance 0x%x of device '%s' not present in current VM\n",
                     instance_id, idstr);
         } else {
-            ret = se->load_state(f, se->opaque, version_id);
+            if (se->vmsd) {
+                ret = vmstate_load(f, se->vmsd, se->opaque, version_id);
+            } else {
+                ret = se->load_state(f, se->opaque, version_id);
+            }
             if (ret < 0) {
                 fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n",
                         instance_id, idstr);
@@ -955,7 +1244,11 @@ int qemu_loadvm_state(QEMUFile *f)
             le->next = first_le;
             first_le = le;

-            ret = le->se->load_state(f, le->se->opaque, le->version_id);
+            if (le->se->vmsd) {
+                ret = vmstate_load(f, le->se->vmsd, le->se->opaque, le->version_id);
+            } else {
+                ret = le->se->load_state(f, le->se->opaque, le->version_id);
+            }
             if (ret < 0) {
                 fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n",
                         instance_id, idstr);
@@ -974,7 +1267,11 @@ int qemu_loadvm_state(QEMUFile *f)
                 goto out;
             }

-            ret = le->se->load_state(f, le->se->opaque, le->version_id);
+            if (le->se->vmsd) {
+                ret = vmstate_load(f, le->se->vmsd, le->se->opaque, le->version_id);
+            } else {
+                ret = le->se->load_state(f, le->se->opaque, le->version_id);
+            }
             if (ret != 0) {
                 fprintf(stderr, "qemu: warning: error while loading state section '%d'\n",
                         section_id);
