showing a splash picture when start
Added options to let qemu transfer two configuration files to bios:
"bootsplash.bmp" and "etc/boot-menu-wait", which could be specified by command
    -boot splash=P,splash-time=T
P is jpg/bmp file name or an absolute path, T have a max value of 0xffff, unit
is ms. With these two options, if user invoke qemu with menu=on option, then
a splash picture would be showed in a given time. For example:
    qemu -boot menu=on,splash=/root/boot.bmp,splash-time=5000
would make boot.bmp shown as a brand with 5 seconds in the booting up process.
This feature need the new seabios's support, which could be got from git.
Signed-off-by: Wayne Xia <xiawenc@linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
			
			
This commit is contained in:
		
							
								
								
									
										140
									
								
								hw/fw_cfg.c
									
									
									
									
									
								
							
							
						
						
									
										140
									
								
								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,143 @@ 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 = -1; | ||||
|     const char *boot_splash_filename = NULL; | ||||
|     char *p; | ||||
|     char *filename; | ||||
|     FILE *fp; | ||||
|     int fop_ret; | ||||
|     int file_size; | ||||
|     int file_type = -1; | ||||
|     const char *temp; | ||||
|  | ||||
|     /* get user configuration */ | ||||
|     QemuOptsList *plist = qemu_find_opts("boot-opts"); | ||||
|     QemuOpts *opts = QTAILQ_FIRST(&plist->head); | ||||
|     if (opts != NULL) { | ||||
|         temp = qemu_opt_get(opts, "splash"); | ||||
|         if (temp != NULL) { | ||||
|             boot_splash_filename = temp; | ||||
|         } | ||||
|         temp = qemu_opt_get(opts, "splash-time"); | ||||
|         if (temp != NULL) { | ||||
|             p = (char *)temp; | ||||
|             boot_splash_time = strtol(p, (char **)&p, 10); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /* insert splash time if user configurated */ | ||||
|     if (boot_splash_time >= 0) { | ||||
|         /* validate the input */ | ||||
|         if (boot_splash_time > 0xffff) { | ||||
|             error_report("splash time is big than 65535, force it to 65535."); | ||||
|             boot_splash_time = 0xffff; | ||||
|         } | ||||
|         /* 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, "etc/boot-menu-wait", qemu_extra_params_fw, 2); | ||||
|     } | ||||
|  | ||||
|     /* insert splash file if user configurated */ | ||||
|     if (boot_splash_filename != NULL) { | ||||
|         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); | ||||
|         } | ||||
|         qemu_free(filename); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void fw_cfg_write(FWCfgState *s, uint8_t value) | ||||
| { | ||||
|     int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL); | ||||
| @@ -352,7 +490,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); | ||||
|   | ||||
| @@ -480,6 +480,32 @@ static QemuOptsList qemu_machine_opts = { | ||||
|     }, | ||||
| }; | ||||
|  | ||||
| QemuOptsList qemu_boot_opts = { | ||||
|     .name = "boot-opts", | ||||
|     .head = QTAILQ_HEAD_INITIALIZER(qemu_boot_opts.head), | ||||
|     .desc = { | ||||
|         /* the three names below are 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", | ||||
|             .type = QEMU_OPT_STRING, | ||||
|         }, { | ||||
|             .name = "splash-time", | ||||
|             .type = QEMU_OPT_STRING, | ||||
|         }, | ||||
|         { /*End of list */ } | ||||
|     }, | ||||
| }; | ||||
|  | ||||
| static QemuOptsList *vm_config_groups[32] = { | ||||
|     &qemu_drive_opts, | ||||
|     &qemu_chardev_opts, | ||||
| @@ -495,6 +521,7 @@ static QemuOptsList *vm_config_groups[32] = { | ||||
| #endif | ||||
|     &qemu_option_rom_opts, | ||||
|     &qemu_machine_opts, | ||||
|     &qemu_boot_opts, | ||||
|     NULL, | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -303,10 +303,13 @@ ETEXI | ||||
|  | ||||
| DEF("boot", HAS_ARG, QEMU_OPTION_boot, | ||||
|     "-boot [order=drives][,once=drives][,menu=on|off]\n" | ||||
|     "                'drives': floppy (a), hard disk (c), CD-ROM (d), network (n)\n", | ||||
|     "      [,splash=sp_name][,splash-time=sp_time]\n" | ||||
|     "                'drives': floppy (a), hard disk (c), CD-ROM (d), network (n)\n" | ||||
|     "                'sp_name': the file's name that would be passed to bios as logo picture, if menu=on\n" | ||||
|     "                'sp_time': the period that splash picture last if menu=on, unit is ms\n", | ||||
|     QEMU_ARCH_ALL) | ||||
| STEXI | ||||
| @item -boot [order=@var{drives}][,once=@var{drives}][,menu=on|off] | ||||
| @item -boot [order=@var{drives}][,once=@var{drives}][,menu=on|off][,splash=@var{sp_name}][,splash-time=@var{sp_time}] | ||||
| @findex -boot | ||||
| Specify boot order @var{drives} as a string of drive letters. Valid | ||||
| drive letters depend on the target achitecture. The x86 PC uses: a, b | ||||
| @@ -318,11 +321,20 @@ particular boot order only on the first startup, specify it via | ||||
| Interactive boot menus/prompts can be enabled via @option{menu=on} as far | ||||
| as firmware/BIOS supports them. The default is non-interactive boot. | ||||
|  | ||||
| A splash picture could be passed to bios, enabling user to show it as logo, | ||||
| when option splash=@var{sp_name} is given and menu=on, If firmware/BIOS | ||||
| supports them. Currently Seabios for X86 system support it. | ||||
| limitation: The splash file could be a jpeg file or a BMP file in 24 BPP | ||||
| format(true color). The resolution should be supported by the SVGA mode, so | ||||
| the recommended is 320x240, 640x480, 800x640. | ||||
|  | ||||
| @example | ||||
| # try to boot from network first, then from hard disk | ||||
| qemu -boot order=nc | ||||
| # boot from CD-ROM first, switch back to default order after reboot | ||||
| qemu -boot once=d | ||||
| # boot with a splash picture for 5 seconds. | ||||
| qemu -boot menu=on,splash=/root/boot.bmp,splash-time=5000 | ||||
| @end example | ||||
|  | ||||
| Note: The legacy format '-boot @var{drives}' is still supported but its | ||||
|   | ||||
							
								
								
									
										3
									
								
								sysemu.h
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								sysemu.h
									
									
									
									
									
								
							| @@ -123,6 +123,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[2]; | ||||
| extern QEMUClock *rtc_clock; | ||||
|  | ||||
| #define MAX_NODES 64 | ||||
|   | ||||
							
								
								
									
										17
									
								
								vl.c
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								vl.c
									
									
									
									
									
								
							| @@ -228,6 +228,9 @@ int ctrl_grab = 0; | ||||
| unsigned int nb_prom_envs = 0; | ||||
| const char *prom_envs[MAX_PROM_ENVS]; | ||||
| int boot_menu; | ||||
| uint8_t *boot_splash_filedata; | ||||
| int boot_splash_filedata_size; | ||||
| uint8_t qemu_extra_params_fw[2]; | ||||
|  | ||||
| typedef struct FWBootEntry FWBootEntry; | ||||
|  | ||||
| @@ -293,6 +296,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"); | ||||
| @@ -2330,7 +2341,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", "splash-time", NULL | ||||
|                     }; | ||||
|                     char buf[sizeof(boot_devices)]; | ||||
|                     char *standard_boot_devices; | ||||
| @@ -2373,6 +2385,8 @@ int main(int argc, char **argv, char **envp) | ||||
|                                 exit(1); | ||||
|                             } | ||||
|                         } | ||||
|                         qemu_opts_parse(qemu_find_opts("boot-opts"), | ||||
|                                         optarg, 0); | ||||
|                     } | ||||
|                 } | ||||
|                 break; | ||||
| @@ -3335,6 +3349,7 @@ int main(int argc, char **argv, char **envp) | ||||
|     main_loop(); | ||||
|     quit_timers(); | ||||
|     net_cleanup(); | ||||
|     res_free(); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user