diff --git a/Makefile b/Makefile
index 65edcf4..8cdd687 100644
--- a/Makefile
+++ b/Makefile
@@ -188,7 +188,8 @@ bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
 mpc8544ds.dtb \
 multiboot.bin linuxboot.bin \
 s390-zipl.rom \
-spapr-rtas.bin slof.bin
+spapr-rtas.bin slof.bin \
+bootsplash.bmp
 BLOBS += extboot.bin
 BLOBS += vapic.bin
 else
diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c
index 85c8c3c..a1188e5 100644
--- a/hw/fw_cfg.c
+++ b/hw/fw_cfg.c
@@ -26,6 +26,7 @@
 #include "isa.h"
 #include "fw_cfg.h"
 #include "sysbus.h"
+#include "qemu-error.h"
 
 /* debug firmware config */
 //#define DEBUG_FW_CFG
@@ -56,6 +57,134 @@ struct FWCfgState {
     Notifier machine_ready;
 };
 
+#define JPG_FILE 0
+#define BMP_FILE 1
+
+static FILE *probe_splashfile(char *filename, int *file_sizep, int *file_typep)
+{
+    FILE *fp = NULL;
+    int fop_ret;
+    int file_size;
+    int file_type = -1;
+    unsigned char buf[2] = {0, 0};
+    unsigned int filehead_value = 0;
+    int bmp_bpp;
+
+    fp = fopen(filename, "rb");
+    if (fp == NULL) {
+        error_report("failed to open file '%s'.", filename);
+        return fp;
+    }
+    /* check file size */
+    fseek(fp, 0L, SEEK_END);
+    file_size = ftell(fp);
+    if (file_size < 2) {
+        error_report("file size is less than 2 bytes '%s'.", filename);
+        fclose(fp);
+        fp = NULL;
+        return fp;
+    }
+    /* check magic ID */
+    fseek(fp, 0L, SEEK_SET);
+    fop_ret = fread(buf, 1, 2, fp);
+    filehead_value = (buf[0] + (buf[1] << 8)) & 0xffff;
+    if (filehead_value == 0xd8ff) {
+        file_type = JPG_FILE;
+    } else {
+        if (filehead_value == 0x4d42) {
+            file_type = BMP_FILE;
+        }
+    }
+    if (file_type < 0) {
+        error_report("'%s' not jpg/bmp file,head:0x%x.",
+                         filename, filehead_value);
+        fclose(fp);
+        fp = NULL;
+        return fp;
+    }
+    /* check BMP bpp */
+    if (file_type == BMP_FILE) {
+        fseek(fp, 28, SEEK_SET);
+        fop_ret = fread(buf, 1, 2, fp);
+        bmp_bpp = (buf[0] + (buf[1] << 8)) & 0xffff;
+        if (bmp_bpp != 24) {
+            error_report("only 24bpp bmp file is supported.");
+            fclose(fp);
+            fp = NULL;
+            return fp;
+        }
+    }
+    /* return values */
+    *file_sizep = file_size;
+    *file_typep = file_type;
+    return fp;
+}
+
+static void fw_cfg_bootsplash(FWCfgState *s)
+{
+    int boot_splash_time = 5000;
+    const char *boot_splash_filename = "bootsplash.bmp";
+    char *p;
+    char *filename;
+    FILE *fp;
+    int fop_ret;
+    int file_size;
+    int file_type = -1;
+
+    /* get user configuration */
+    QemuOptsList *plist = qemu_find_opts("bootsplash");
+    const char *temp = qemu_opt_get(QTAILQ_FIRST(&plist->head), "splash_time");
+    if (temp != NULL) {
+        p = (char *)temp;
+        boot_splash_time = strtol(p, (char **)&p, 10);
+    }
+    if (boot_splash_time <= 0) {
+        error_report("splash time is minor than 0, abort insert data.");
+        return;
+    }
+    if (boot_splash_time > 0xffff) {
+        error_report("splash time is big than 65535, force it to 65535.");
+        boot_splash_time = 65535;
+    }
+    temp = qemu_opt_get(QTAILQ_FIRST(&plist->head), "splash_filename");
+    if (temp != NULL) {
+        boot_splash_filename = temp;
+    }
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, boot_splash_filename);
+    if (filename == NULL) {
+        error_report("failed to find file '%s'.", boot_splash_filename);
+        return;
+    }
+    /* probing the file */
+    fp = probe_splashfile(filename, &file_size, &file_type);
+    if (fp == NULL) {
+        qemu_free(filename);
+        return;
+    }
+    /* loading file data */
+    if (boot_splash_filedata != NULL) {
+        qemu_free(boot_splash_filedata);
+    }
+    boot_splash_filedata = qemu_malloc(file_size);
+    boot_splash_filedata_size = file_size;
+    fseek(fp, 0L, SEEK_SET);
+    fop_ret = fread(boot_splash_filedata, 1, file_size, fp);
+    fclose(fp);
+    /* insert data */
+    if (file_type == JPG_FILE) {
+        fw_cfg_add_file(s, "bootsplash.jpg",
+                boot_splash_filedata, boot_splash_filedata_size);
+    } else {
+        fw_cfg_add_file(s, "bootsplash.bmp",
+                boot_splash_filedata, boot_splash_filedata_size);
+    }
+    /* use little endian format */
+    qemu_extra_params_fw[0] = (uint8_t)(boot_splash_time & 0xff);
+    qemu_extra_params_fw[1] = (uint8_t)((boot_splash_time >> 8) & 0xff);
+    fw_cfg_add_file(s, "qemu_extra_params_fw.cfg", qemu_extra_params_fw, 4);
+    qemu_free(filename);
+}
+
 static void fw_cfg_write(FWCfgState *s, uint8_t value)
 {
     int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
@@ -352,7 +481,7 @@ FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
     fw_cfg_add_i16(s, FW_CFG_NB_CPUS, (uint16_t)smp_cpus);
     fw_cfg_add_i16(s, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
     fw_cfg_add_i16(s, FW_CFG_BOOT_MENU, (uint16_t)boot_menu);
-
+    fw_cfg_bootsplash(s);
 
     s->machine_ready.notify = fw_cfg_machine_ready;
     qemu_add_machine_init_done_notifier(&s->machine_ready);
diff --git a/qemu-config.c b/qemu-config.c
index efa892c..09eb7d0 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -473,6 +473,32 @@ static QemuOptsList qemu_machine_opts = {
     },
 };
 
+QemuOptsList qemu_bootsplash_opts = {
+    .name = "bootsplash",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_bootsplash_opts.head),
+    .desc = {
+        /* the three names below is not used now */
+        {
+            .name = "order",
+            .type = QEMU_OPT_STRING,
+        }, {
+            .name = "once",
+            .type = QEMU_OPT_STRING,
+        }, {
+            .name = "menu",
+            .type = QEMU_OPT_STRING,
+        /* following are really used */
+        }, {
+            .name = "splash_time",
+            .type = QEMU_OPT_STRING,
+        }, {
+            .name = "splash_filename",
+            .type = QEMU_OPT_STRING,
+        },
+        { /*End of list */ }
+    },
+};
+
 static QemuOptsList *vm_config_groups[32] = {
     &qemu_drive_opts,
     &qemu_chardev_opts,
@@ -488,6 +514,7 @@ static QemuOptsList *vm_config_groups[32] = {
 #endif
     &qemu_option_rom_opts,
     &qemu_machine_opts,
+    &qemu_bootsplash_opts,
     NULL,
 };
 
diff --git a/sysemu.h b/sysemu.h
index a42d83f..2943a52 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -119,6 +119,9 @@ extern int no_shutdown;
 extern int semihosting_enabled;
 extern int old_param;
 extern int boot_menu;
+extern uint8_t *boot_splash_filedata;
+extern int boot_splash_filedata_size;
+extern uint8_t qemu_extra_params_fw[4];
 extern QEMUClock *rtc_clock;
 extern long hpagesize;
 
diff --git a/vl.c b/vl.c
index c84f17b..9e610b1 100644
--- a/vl.c
+++ b/vl.c
@@ -231,6 +231,9 @@ unsigned int nb_prom_envs = 0;
 const char *prom_envs[MAX_PROM_ENVS];
 const char *nvram = NULL;
 int boot_menu;
+uint8_t *boot_splash_filedata;
+int boot_splash_filedata_size;
+uint8_t qemu_extra_params_fw[4];
 
 typedef struct FWBootEntry FWBootEntry;
 
@@ -296,6 +299,14 @@ static struct {
     { .driver = "qxl-vga",              .flag = &default_vga       },
 };
 
+static void res_free(void)
+{
+    if (boot_splash_filedata != NULL) {
+        qemu_free(boot_splash_filedata);
+        boot_splash_filedata = NULL;
+    }
+}
+
 static int default_driver_check(QemuOpts *opts, void *opaque)
 {
     const char *driver = qemu_opt_get(opts, "driver");
@@ -2309,7 +2320,8 @@ int main(int argc, char **argv, char **envp)
             case QEMU_OPTION_boot:
                 {
                     static const char * const params[] = {
-                        "order", "once", "menu", NULL
+                        "order", "once", "menu",
+                        "splash_time", "splash_filename", NULL
                     };
                     char buf[sizeof(boot_devices)];
                     char *standard_boot_devices;
@@ -2352,6 +2364,8 @@ int main(int argc, char **argv, char **envp)
                                 exit(1);
                             }
                         }
+                        qemu_opts_parse(qemu_find_opts("bootsplash"),
+                                        optarg, 0);
                     }
                 }
                 break;
@@ -3333,6 +3347,7 @@ int main(int argc, char **argv, char **envp)
     main_loop();
     quit_timers();
     net_cleanup();
+    res_free();
 
     return 0;
 }
