diff --git a/dump.c b/dump.c
index 75ef032..c04e2ae 100644
--- a/dump.c
+++ b/dump.c
@@ -67,6 +67,36 @@ static void dump_error(DumpState *s, const char *reason)
     dump_cleanup(s);
 }
 
+/*
+ * write 'size' of 'c' to dump file
+ */
+static int fill_space(size_t size, int c, void *opaque)
+{
+    DumpState *s = opaque;
+    char tmpbuf[TMP_BUF_SIZE];
+    size_t fill_size;
+    size_t written_size;
+
+    memset(&tmpbuf, c, TMP_BUF_SIZE);
+
+    while (size) {
+        if (size > TMP_BUF_SIZE) {
+            fill_size = TMP_BUF_SIZE;
+        } else {
+            fill_size = size;
+        }
+
+        size -= fill_size;
+
+        written_size = qemu_write_full(s->fd, tmpbuf, fill_size);
+        if (written_size != fill_size) {
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
 static int fd_write_vmcore(void *buf, size_t size, void *opaque)
 {
     DumpState *s = opaque;
@@ -672,6 +702,235 @@ static ram_addr_t get_start_block(DumpState *s)
     return -1;
 }
 
+static int write_dump_header(DumpState *s)
+{
+    int ret;
+    void *dh;
+    void *kh;
+
+    /* write common header */
+    dh = s->dh;
+
+    if (s->dump_info.d_machine == EM_386) {
+        ret = fd_write_vmcore(dh, sizeof(struct disk_dump_header32), s);
+        if (ret < 0) {
+            dump_error(s, "dump: failed to write disk dump header.\n");
+            return -1;
+        }
+    } else {
+        ret = fd_write_vmcore(dh, sizeof(struct disk_dump_header64), s);
+        if (ret < 0) {
+            dump_error(s, "dump: failed to write disk dump header.\n");
+            return -1;
+        }
+    }
+
+    /* fill gap between command header and sub header */
+    ret = fill_space(s->offset_sub_header, 0, s);
+    if (ret < 0) {
+        dump_error(s, "dump: failed to fill the space between header and\
+                    sub header.\n");
+        return -1;
+    }
+
+    /* write sub header */
+    kh = s->kh;
+
+    if (s->dump_info.d_machine == EM_386) {
+        ret = fd_write_vmcore(kh, sizeof(struct kdump_sub_header32), s);
+        if (ret < 0) {
+            dump_error(s, "dump: failed to write kdump sub header.\n");
+            return -1;
+        }
+    } else {
+        ret = fd_write_vmcore(kh, sizeof(struct kdump_sub_header64), s);
+        if (ret < 0) {
+            dump_error(s, "dump: failed to write kdump sub header.\n");
+            return -1;
+        }
+    }
+
+    /* write note */
+    if (s->dump_info.d_class == ELFCLASS64) {
+        if (write_elf64_notes(s) < 0) {
+            return -1;
+        }
+    } else {
+        if (write_elf32_notes(s) < 0) {
+            return -1;
+        }
+   }
+
+    return 0;
+}
+
+static int write_dump_bitmap(DumpState *s)
+{
+    struct cache_data bm;
+    long buf_size;
+    int ret;
+    int no_bitmap;
+
+    /* fill gap between header and dump_bitmap */
+    ret = fill_space(s->offset_dump_bitmap, 0, s);
+    if (ret < 0) {
+        dump_error(s, "dump: failed to fill the space between header and\
+                    dump_bitmap.\n");
+        goto out;
+    }
+
+    bm.buf = g_malloc0(TMP_BUF_SIZE);
+
+    /* write dump_bitmap1 */
+    bm.fd = s->dump_bitmap1->fd;
+    no_bitmap = 1;
+
+again:
+    buf_size = s->len_dump_bitmap / 2;
+    bm.offset = 0;
+
+    while (buf_size > 0) {
+        if (buf_size >= TMP_BUF_SIZE) {
+            bm.cache_size = TMP_BUF_SIZE;
+        } else {
+            bm.cache_size = buf_size;
+        }
+
+        ret = read_cache(&bm);
+        if (ret < 0) {
+            goto out;
+        }
+
+        ret = fd_write_vmcore(bm.buf, bm.cache_size, s);
+        if (ret < 0) {
+            goto out;
+        }
+
+        buf_size -= bm.cache_size;
+    }
+
+    /* switch to dump_bitmap2 */
+    if (no_bitmap == 1) {
+        no_bitmap = 2;
+        bm.fd = s->dump_bitmap2->fd;
+        goto again;
+    }
+
+    return 0;
+
+out:
+    if (bm.buf) {
+        g_free(bm.buf);
+    }
+
+    return -1;
+}
+
+static int write_dump_pages(DumpState *s)
+{
+    struct cache_data page;
+    unsigned long long total_size;
+    int is_page_desc;
+    int ret;
+
+    page.buf = g_malloc0(TMP_BUF_SIZE);
+
+    /* write page_desc */
+    is_page_desc = 1;
+    total_size = s->page_desc_size;
+    page.fd = s->page_desc->fd;
+    page.offset = s->page_desc->offset;
+
+again:
+    while (total_size > 0) {
+        if (total_size > TMP_BUF_SIZE) {
+            page.cache_size = TMP_BUF_SIZE;
+        } else {
+            page.cache_size = total_size;
+        }
+
+        ret = read_cache(&page);
+        if (ret < 0) {
+            goto out;
+        }
+
+        ret = fd_write_vmcore(page.buf, page.cache_size, s);
+        if (ret < 0) {
+            goto out;
+        }
+
+        total_size -= page.cache_size;
+    }
+
+    /* switch to page_data */
+    if (is_page_desc) {
+        is_page_desc = 0;
+        total_size = s->page_data_size;
+        page.fd = s->page_data->fd;
+        page.offset = s->page_data->offset;
+        goto again;
+    }
+
+    return 0;
+
+out:
+    if (page.buf) {
+        g_free(page.buf);
+    }
+
+    return -1;
+}
+
+static int create_kdump_vmcore(DumpState *s)
+{
+    int ret;
+
+    /*
+     * the kdump-compressed format is:
+     *                                               File offset
+     *  +------------------------------------------+ 0x0
+     *  |    main header (struct disk_dump_header) |
+     *  |------------------------------------------+ block 1
+     *  |    sub header (struct kdump_sub_header)  |
+     *  |------------------------------------------+ block 2
+     *  |            1st-dump_bitmap               |
+     *  |------------------------------------------+ block 2 + X blocks
+     *  |            2nd-dump_bitmap               | (aligned by block)
+     *  |------------------------------------------+ block 2 + 2 * X blocks
+     *  |  page desc for pfn 0 (struct page_desc)  | (aligned by block)
+     *  |  page desc for pfn 1 (struct page_desc)  |
+     *  |                    :                     |
+     *  |  page desc for pfn Z (struct page_desc)  |
+     *  |------------------------------------------| (not aligned by block)
+     *  |         page data (pfn 0)                |
+     *  |         page data (pfn 1)                |
+     *  |                        :                 |
+     *  |         page data (pfn Z)                |
+     *  +------------------------------------------+ offset_eraseinfo
+     *  |                    :                     |
+     *  +------------------------------------------+
+     */
+
+    ret = write_dump_header(s);
+    if (ret < 0) {
+        return -1;
+    }
+
+    ret = write_dump_bitmap(s);
+    if (ret < 0) {
+        return -1;
+    }
+
+    ret = write_dump_pages(s);
+    if (ret < 0) {
+        return -1;
+    }
+
+    dump_completed(s);
+
+    return 0;
+}
+
 static int create_header32(DumpState *s)
 {
     struct  disk_dump_header32 *dh;
diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h
index 7cb74d6..000455f 100644
--- a/include/sysemu/dump.h
+++ b/include/sysemu/dump.h
@@ -48,6 +48,7 @@
 #define DISKDUMP_HEADER_BLOCKS      (1)
 #define PHYS_BASE                   (0)
 #define DUMP_LEVEL                  (1)
+#define TMP_BUF_SIZE                (1024)
 #define ARCH_PFN_OFFSET             (0)
 #define FILENAME_BITMAP1            "kdump_bitmap1_XXXXXX"
 #define FILENAME_BITMAP2            "kdump_bitmap2_XXXXXX"
