[PATCH 2/3] [BIOS] Add splash image support

Laurent Vivier
2008-12-16T15:20:30Z

This patch adds Qemu firmware configuration device interface to display
a splash image at BIOS startup.

Idea and some parts of code are stollen from VirtualBox.

Signed-off-by: Laurent Vivier <Laurent.Vivier@bull.net>
---
bios/Makefile | 4 +-
bios/logo.c | 206 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
bios/logo.h | 56 +++++++++++++++
bios/rombios.c | 125 +++++++++++++++++++++-------------
4 files changed, 340 insertions(+), 51 deletions(-)
create mode 100644 bios/logo.c
create mode 100644 bios/logo.h

diff --git a/bios/Makefile b/bios/Makefile
index a2759a9..d30be7d 100644
--- a/bios/Makefile
+++ b/bios/Makefile
@@ -79,7 +79,7 @@ dist-clean: clean
bios-clean:
rm -f BIOS-bochs-*

-BIOS-bochs-legacy: rombios.c apmbios.S biossums rombios.h
+BIOS-bochs-legacy: rombios.c apmbios.S biossums rombios.h logo.c logo.h
$(GCC) $(BIOS_BUILD_DATE) -DLEGACY -E -P $< > _rombiosl_.c
$(BCC) -o rombiosl.s -C-c -D__i86__ -0 -S _rombiosl_.c
sed -e 's/^\.text//' -e 's/^\.data//' rombiosl.s > _rombiosl_.s
@@ -90,7 +90,7 @@ BIOS-bochs-legacy: rombios.c apmbios.S biossums rombios.h
rm -f _rombiosl_.s

-rombios16.bin: rombios.c apmbios.S biossums rombios.h
+rombios16.bin: rombios.c apmbios.S biossums rombios.h logo.c logo.h
$(GCC) $(BIOS_BUILD_DATE) -E -P $< > _rombios_.c
$(BCC) -o rombios.s -C-c -D__i86__ -0 -S _rombios_.c
sed -e 's/^\.text//' -e 's/^\.data//' rombios.s > _rombios_.s
diff --git a/bios/logo.c b/bios/logo.c
new file mode 100644
index 0000000..d41eb10
--- /dev/null
+++ b/bios/logo.c
@@ -0,0 +1,206 @@
+/**
+ * Stuff for drawing the BIOS logo.
+ */
+
+/*
+ * Copyright (C) 2004-2008 Sun Microsystems, Inc.
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ *
+ * QEMU/KVM port by Laurent Vivier <Laurent.Vivier@bull.net>
+ *
+ */
+
+#include "logo.h"
+
+#define BIOS_CFG_IOPORT 0x510
+#define BIOS_CFG_SIGNATURE 0x0000
+#define BIOS_CFG_SPLASH 0x4007
+
+#define WAIT_MS 16
+
+/**
+ * Set video mode (VGA).
+ * @params New video mode.
+ */
+void set_mode(mode)
+ Bit8u mode;
+ {
+ ASM_START
+ push bp
+ mov bp, sp
+
+ push ax
+
+ mov ah, #0
+ mov al, 4[bp] ; mode
+ int #0x10
+
+ pop ax
+
+ pop bp
+ ASM_END
+ }
+
+Bit8u read_logo_byte(offset)
+ Bit8u offset;
+{
+ outw(BIOS_CFG_IOPORT, BIOS_CFG_SPLASH);
+ outb(BIOS_CFG_IOPORT + 1, LOGO_CMD_SET_OFFSET);
+ outb(BIOS_CFG_IOPORT + 1, offset);
+ return inb(BIOS_CFG_IOPORT + 1);
+}
+
+Bit16u read_logo_word(offset)
+ Bit8u offset;
+{
+ Bit16u word;
+ outw(BIOS_CFG_IOPORT, BIOS_CFG_SPLASH);
+ outb(BIOS_CFG_IOPORT + 1, LOGO_CMD_SET_OFFSET);
+ outb(BIOS_CFG_IOPORT + 1, offset);
+ word = inb(BIOS_CFG_IOPORT + 1);
+ word = (inb(BIOS_CFG_IOPORT + 1) << 8) | word;
+ return word;
+}
+
+void clear_screen()
+{
+// Hide cursor, clear screen and move cursor to starting position
+ASM_START
+ push bx
+ push cx
+ push dx
+
+ mov ax, #0x100
+ mov cx, #0x1000
+ int #0x10
+
+ mov ax, #0x700
+ mov bh, #7
+ xor cx, cx
+ mov dx, #0x184f
+ int #0x10
+
+ mov ax, #0x200
+ xor bx, bx
+ xor dx, dx
+ int #0x10
+
+ pop dx
+ pop cx
+ pop bx
+ASM_END
+}
+
+Bit8u
+logo_enabled()
+{
+ LOGOHDR *logo_hdr = 0;
+ Bit8u is_fade_in, is_fade_out, uBootMenu;
+ Bit16u logo_time;
+
+ /* check QEMU signature */
+
+ outw(BIOS_CFG_IOPORT, BIOS_CFG_SIGNATURE);
+ if (inb(BIOS_CFG_IOPORT + 1) != 'Q')
+ return 0;
+ if (inb(BIOS_CFG_IOPORT + 1) != 'E')
+ return 0;
+ if (inb(BIOS_CFG_IOPORT + 1) != 'M')
+ return 0;
+ if (inb(BIOS_CFG_IOPORT + 1) != 'U')
+ return 0;
+
+ /* check splash signature */
+
+ if (read_logo_word(&logo_hdr->u16Signature) != LOGO_HDR_MAGIC)
+ return 0;
+
+ /* Get options */
+
+ is_fade_in = read_logo_byte(&logo_hdr->fu8FadeIn);
+ is_fade_out = read_logo_byte(&logo_hdr->fu8FadeOut);
+ logo_time = read_logo_word(&logo_hdr->u16LogoMillies);
+
+ return (is_fade_in || is_fade_out || logo_time);
+}
+
+void logo_show()
+{
+ LOGOHDR *logo_hdr = 0;
+ Bit8u is_fade_in;
+ Bit16u i;
+
+ set_mode(0x12); /* 640x480 */
+
+ is_fade_in = read_logo_byte(&logo_hdr->fu8FadeIn);
+
+ outw(BIOS_CFG_IOPORT, BIOS_CFG_SPLASH);
+ if (is_fade_in)
+ {
+ for (i = 0; i < LOGO_SHOW_STEPS; i++)
+ {
+ if (i != 0) { /* 0 means "unload image from memory" */
+ outb(BIOS_CFG_IOPORT + 1, LOGO_CMD_SHOW_BMP);
+ outb(BIOS_CFG_IOPORT + 1, i);
+ }
+ delay_ticks_and_check_for_keystroke(16 / WAIT_MS, 1);
+ if (check_for_keystroke())
+ break;
+ }
+ }
+ outb(BIOS_CFG_IOPORT + 1, LOGO_CMD_SHOW_BMP);
+ outb(BIOS_CFG_IOPORT + 1, LOGO_SHOW_STEPS);
+
+ return;
+}
+
+void logo_hide()
+{
+ LOGOHDR *logo_hdr = 0;
+ Bit8u is_fade_out;
+ Bit16u i;
+
+ if (check_for_keystroke())
+ goto hide;
+
+ is_fade_out = read_logo_byte(&logo_hdr->fu8FadeOut);
+
+ outw(BIOS_CFG_IOPORT, BIOS_CFG_SPLASH);
+ if (is_fade_out)
+ {
+ for (i = LOGO_SHOW_STEPS; i > 0 ; i--)
+ {
+ outb(BIOS_CFG_IOPORT + 1, LOGO_CMD_SHOW_BMP);
+ outb(BIOS_CFG_IOPORT + 1, i);
+ delay_ticks_and_check_for_keystroke(16 / WAIT_MS, 1);
+ if (check_for_keystroke())
+ break;
+ }
+ }
+hide:
+ outb(BIOS_CFG_IOPORT + 1, LOGO_CMD_SHOW_BMP);
+ outb(BIOS_CFG_IOPORT + 1, 0);
+ set_mode(0x03);
+ clear_screen();
+
+ return;
+}
+
+Bit8u
+logo_display_boot_list()
+{
+ LOGOHDR *logo_hdr = 0;
+
+ return read_logo_byte(&logo_hdr->fu8ShowBootMenu);
+}
diff --git a/bios/logo.h b/bios/logo.h
new file mode 100644
index 0000000..d7a7b80
--- /dev/null
+++ b/bios/logo.h
@@ -0,0 +1,56 @@
+/**
+ * BiosLogo - The Private BIOS Logo Interface.
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ *
+ * QEMU/KVM port by Laurent Vivier <Laurent.Vivier@bull.net>
+ *
+ */
+
+#define LOGO_SHOW_STEPS 16
+
+#define LOGO_CMD_NOP 0
+#define LOGO_CMD_SET_OFFSET 0x01
+#define LOGO_CMD_SHOW_BMP 0x02
+
+typedef struct LOGOHDR
+{
+ /** Signature (LOGO_HDR_MAGIC/0x66BB). */
+ Bit16u u16Signature;
+ /** Logo time (msec). */
+ Bit16u u16LogoMillies;
+ /** Fade in - boolean. */
+ Bit8u fu8FadeIn;
+ /** Fade out - boolean. */
+ Bit8u fu8FadeOut;
+ /** Show setup - boolean. */
+ Bit8u fu8ShowBootMenu;
+ /** Reserved / padding. */
+ Bit8u u8Reserved;
+ /** Logo file size. */
+ Bit32u cbLogo;
+} LOGOHDR;
+#define LOGO_HDR_MAGIC 0x66BB
diff --git a/bios/rombios.c b/bios/rombios.c
index 9a1cdd6..52a1391 100644
--- a/bios/rombios.c
+++ b/bios/rombios.c
@@ -1917,6 +1917,10 @@ shutdown_status_panic(status)
BX_PANIC("Unimplemented shutdown status: %02x\n",(Bit8u)status);
}

+#ifdef BX_QEMU
+#include "logo.c"
+#endif
+
//--------------------------------------------------------------------------
// print_bios_banner
// displays a the bios version
@@ -1924,6 +1928,10 @@ shutdown_status_panic(status)
void
print_bios_banner()
{
+#ifdef BX_QEMU
+ if (logo_enabled())
+ return;
+#endif
printf(BX_APPNAME" BIOS - build: %s\n%s\nOptions: ",
BIOS_BUILD_DATE, bios_cvs_version_string);
printf(
@@ -2021,65 +2029,78 @@ interactive_bootkey()
Bit16u ss = get_SS();
Bit16u valid_choice = 0;

+#ifdef BX_QEMU
+ if (logo_enabled()) {
+ LOGOHDR *logo_hdr = 0;
+ Bit16u logo_time;
+
+ logo_show();
+ logo_time = read_logo_word(&logo_hdr->u16LogoMillies);
+ if (!check_for_keystroke())
+ delay_ticks_and_check_for_keystroke(WAIT_MS, logo_time / 1000);
+ logo_hide();
+ if (!logo_display_boot_list())
+ return;
+ } else
+#endif // BX_QEMU
+ {
+ while (check_for_keystroke())
+ get_keystroke();
+ printf("Press F12 for boot menu.\n\n");
+ delay_ticks_and_check_for_keystroke(11, 5); /* ~3 seconds */
+ }
+ if (!check_for_keystroke())
+ return;
+ scan_code = get_keystroke();
+ if (scan_code != 0x58) /* F12 */
+ return;
+
while (check_for_keystroke())
get_keystroke();

- printf("Press F12 for boot menu.\n\n");
+ printf("Select boot device:\n\n");

- delay_ticks_and_check_for_keystroke(11, 5); /* ~3 seconds */
- if (check_for_keystroke())
+ count = read_word(IPL_SEG, IPL_COUNT_OFFSET);
+ for (i = 0; i < count; i++)
{
- scan_code = get_keystroke();
- if (scan_code == 0x58) /* F12 */
+ memcpyb(ss, &e, IPL_SEG, IPL_TABLE_OFFSET + i * sizeof (e), sizeof (e));
+ printf("%d. ", i+1);
+ switch(e.type)
{
- while (check_for_keystroke())
- get_keystroke();
-
- printf("Select boot device:\n\n");
-
- count = read_word(IPL_SEG, IPL_COUNT_OFFSET);
- for (i = 0; i < count; i++)
- {
- memcpyb(ss, &e, IPL_SEG, IPL_TABLE_OFFSET + i * sizeof (e), sizeof (e));
- printf("%d. ", i+1);
- switch(e.type)
+ case IPL_TYPE_FLOPPY:
+ case IPL_TYPE_HARDDISK:
+ case IPL_TYPE_CDROM:
+ printf("%s\n", drivetypes[e.type]);
+ break;
+ case IPL_TYPE_BEV:
+ printf("%s", drivetypes[4]);
+ if (e.description != 0)
{
- case IPL_TYPE_FLOPPY:
- case IPL_TYPE_HARDDISK:
- case IPL_TYPE_CDROM:
- printf("%s\n", drivetypes[e.type]);
- break;
- case IPL_TYPE_BEV:
- printf("%s", drivetypes[4]);
- if (e.description != 0)
- {
- memcpyb(ss, &description, (Bit16u)(e.description >> 16), (Bit16u)(e.description & 0xffff), 32);
- description[32] = 0;
- printf(" [%S]", ss, description);
- }
- printf("\n");
- break;
- }
- }
+ memcpyb(ss, &description, (Bit16u)(e.description >> 16), (Bit16u)(e.description & 0xffff), 32);
+ description[32] = 0;
+ printf(" [%S]", ss, description);
+ }
+ printf("\n");
+ break;
+ }
+ }

- count++;
- while (!valid_choice) {
- scan_code = get_keystroke();
- if (scan_code == 0x01 || scan_code == 0x58) /* ESC or F12 */
- {
- valid_choice = 1;
- }
- else if (scan_code <= count)
- {
- valid_choice = 1;
- scan_code -= 1;
- /* Set user selected device */
- write_word(IPL_SEG, IPL_BOOTFIRST_OFFSET, scan_code);
- }
- }
- printf("\n");
+ count++;
+ while (!valid_choice) {
+ scan_code = get_keystroke();
+ if (scan_code == 0x01 || scan_code == 0x58) /* ESC or F12 */
+ {
+ valid_choice = 1;
+ }
+ else if (scan_code <= count)
+ {
+ valid_choice = 1;
+ scan_code -= 1;
+ /* Set user selected device */
+ write_word(IPL_SEG, IPL_BOOTFIRST_OFFSET, scan_code);
}
}
+ printf("\n");
}
#endif // BX_ELTORITO_BOOT

@@ -2706,6 +2727,9 @@ void ata_detect( )
break;
}

+#ifdef BX_QEMU
+ if (!logo_enabled()) {
+#endif
switch (type) {
case ATA_TYPE_ATA:
printf("ata%d %s: ",channel,slave?" slave":"master");
@@ -2727,6 +2751,9 @@ void ata_detect( )
printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
break;
}
+#ifdef BX_QEMU
+ }
+#endif
}
}

--
1.5.6.5