aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2008-01-15 14:22:50 +0000
committerKeir Fraser <keir.fraser@citrix.com>2008-01-15 14:22:50 +0000
commit136beff1783158d3a05f94aef6ccc4339263a2a8 (patch)
tree87b55f04a9e163cc05cbff13c535baf6f8d29dd7
parent6aef553b661b7504ff927ee5e120a69b44ba92aa (diff)
downloadxen-136beff1783158d3a05f94aef6ccc4339263a2a8.tar.gz
xen-136beff1783158d3a05f94aef6ccc4339263a2a8.tar.bz2
xen-136beff1783158d3a05f94aef6ccc4339263a2a8.zip
hvm, x86: Add QEMU BIOS menu for choosing boot device.
The attached patch implements a mini BIOS menu for choosing a non-default boot device. When a guest starts it'll display 'Press F10 to select boot device' And wait 3 seconds, before continuing with the normal boot device. If they press the F10 key, a menu is shown allowing a choice between floppy, harddisk, cdrom and network (PXE). I can't take credit for this originally - Jeremy Katz wrote it for KVM, I merely re-diffed the patch to work against Xen's QEMU/BIOS code tree. It has been tested in Fedora successfully against 3.1.x and 3.2.x Signed-off-by: Daniel P. Berrange <berrange@redhat.com> CC: Jeremy Katz <katzj@redhat.com> If more than one boot device has been selected, the currently selected number displayed in the menu is wrong. Signed-off-by: Stefano Stabellini <stefano.stabellini@citrix.com>
-rw-r--r--tools/firmware/rombios/rombios.c227
1 files changed, 226 insertions, 1 deletions
diff --git a/tools/firmware/rombios/rombios.c b/tools/firmware/rombios/rombios.c
index 287840727d..a37879bd95 100644
--- a/tools/firmware/rombios/rombios.c
+++ b/tools/firmware/rombios/rombios.c
@@ -2031,6 +2031,229 @@ print_cdromboot_failure( code )
return;
}
+#define WAIT_HZ 18
+/**
+ * Check for keystroke.
+ * @returns True if keystroke available, False if not.
+ */
+Bit8u check_for_keystroke()
+{
+ASM_START
+ mov ax, #0x100
+ int #0x16
+ jz no_key
+ mov al, #1
+ jmp done
+no_key:
+ xor al, al
+done:
+ASM_END
+}
+
+/**
+ * Get keystroke.
+ * @returns BIOS scan code.
+ */
+Bit8u get_keystroke()
+{
+ASM_START
+ mov ax, #0x0
+ int #0x16
+ xchg ah, al
+ASM_END
+}
+
+/**
+ * Waits (sleeps) for the given number of ticks.
+ * Checks for keystroke.
+ *
+ * @returns BIOS scan code if available, 0 if not.
+ * @param ticks Number of ticks to sleep.
+ * @param stop_on_key Whether to stop immediately upon keypress.
+ */
+Bit8u wait(ticks, stop_on_key)
+ Bit16u ticks;
+ Bit8u stop_on_key;
+{
+ long ticks_to_wait, delta;
+ Bit32u prev_ticks, t;
+ Bit8u scan_code = 0;
+
+ /*
+ * The 0:046c wraps around at 'midnight' according to a 18.2Hz clock.
+ * We also have to be careful about interrupt storms.
+ */
+ ticks_to_wait = ticks;
+ prev_ticks = read_dword(0x0, 0x46c);
+ do
+ {
+ t = read_dword(0x0, 0x46c);
+ if (t > prev_ticks)
+ {
+ delta = t - prev_ticks; /* The temp var is required or bcc screws up. */
+ ticks_to_wait -= delta;
+ }
+ else if (t < prev_ticks)
+ ticks_to_wait -= t; /* wrapped */
+ prev_ticks = t;
+
+ if (check_for_keystroke())
+ {
+ scan_code = get_keystroke();
+ bios_printf(BIOS_PRINTF_DEBUG, "Key pressed: %x\n", scan_code);
+ if (stop_on_key)
+ return scan_code;
+ }
+ } while (ticks_to_wait > 0);
+ return scan_code;
+}
+
+static void clearscreen() {
+ /* 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
+}
+
+int bootmenu(selected)
+ int selected;
+{
+ Bit8u scode;
+ int max;
+
+ /* get the number of boot devices */
+ max = read_word(IPL_SEG, IPL_COUNT_OFFSET);
+
+ for(;;) {
+ if (selected > max || selected < 1) selected = 1;
+ clearscreen();
+ bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "\n\n\n\n\n\n\n");
+ bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, " Select boot device\n\n");
+ bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, " 1. Floppy\n");
+ bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, " 2. Hard drive\n");
+ bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, " 3. CD-ROM\n");
+ if (max == 4)
+ bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, " 4. Network\n");
+ bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "\n\n Currently selected: %d\n", selected);
+
+ do {
+ scode = wait(WAIT_HZ, 1);
+ } while (scode == 0);
+ switch(scode) {
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ selected = scode - 1;
+ break;
+ case 0x05:
+ if (max == 4)
+ selected = scode -1 ;
+ else
+ scode = 0;
+ break;
+ case 0x48:
+ selected -= 1;
+ if (selected < 1)
+ selected = 1;
+ scode = 0;
+ break;
+ case 0x50:
+ selected += 1;
+ if (selected > max)
+ selected = max;
+ scode = 0;
+ break;
+ case 0x1c:
+ break;
+ default:
+ scode = 0;
+ break;
+ }
+ if (scode != 0)
+ break;
+ }
+
+ switch (selected) {
+ case 1:
+ return 0x3D;
+ case 2:
+ return 0x3E;
+ case 3:
+ return 0x3F;
+ case 4:
+ return 0x58;
+ default:
+ return 0;
+ }
+}
+
+void interactive_bootkey()
+{
+ Bit16u i;
+ Bit8u scan = 0;
+
+ bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "\n\nPress F10 to select boot device.\n");
+ for (i = 3; i > 0; i--)
+ {
+ scan = wait(WAIT_HZ, 0);
+ switch (scan) {
+ case 0x3D:
+ case 0x3E:
+ case 0x3F:
+ case 0x58:
+ break;
+ case 0x44:
+ scan = bootmenu(inb_cmos(0x3d) & 0x0f);
+ break;
+ default:
+ scan = 0;
+ break;
+ }
+ if (scan != 0)
+ break;
+ }
+
+ /* set the default based on the keypress or menu */
+ switch(scan) {
+ case 0x3D:
+ outb_cmos(0x3d, 0x01);
+ break;
+ case 0x3E:
+ outb_cmos(0x3d, 0x02);
+ break;
+ case 0x3F:
+ outb_cmos(0x3d, 0x03);
+ break;
+ case 0x58:
+ outb_cmos(0x3d, 0x04);
+ break;
+ default:
+ break;
+ }
+}
+
+
void
nmi_handler_msg()
{
@@ -9825,7 +10048,9 @@ post_default_ints:
call _cdemu_init
;;
#endif // BX_ELTORITO_BOOT
-
+
+ call _interactive_bootkey
+
#if BX_TCGBIOS
call _tcpa_calling_int19h /* specs: 8.2.3 step 1 */
call _tcpa_add_event_separators /* specs: 8.2.3 step 2 */