ia64/xen-unstable

changeset 16716:e6e165f72e57

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>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Jan 15 14:22:50 2008 +0000 (2008-01-15)
parents b6cc74f275fd
children b64be2bc7a91
files tools/firmware/rombios/rombios.c
line diff
     1.1 --- a/tools/firmware/rombios/rombios.c	Tue Jan 15 14:17:22 2008 +0000
     1.2 +++ b/tools/firmware/rombios/rombios.c	Tue Jan 15 14:22:50 2008 +0000
     1.3 @@ -2031,6 +2031,229 @@ print_cdromboot_failure( code )
     1.4    return;
     1.5  }
     1.6  
     1.7 +#define WAIT_HZ 18
     1.8 +/**
     1.9 + * Check for keystroke.
    1.10 + * @returns    True if keystroke available, False if not.
    1.11 + */
    1.12 +Bit8u check_for_keystroke()
    1.13 +{
    1.14 +ASM_START
    1.15 +    mov  ax, #0x100
    1.16 +    int  #0x16
    1.17 +    jz   no_key
    1.18 +    mov  al, #1
    1.19 +    jmp  done
    1.20 +no_key:
    1.21 +    xor  al, al
    1.22 +done:
    1.23 +ASM_END
    1.24 +}
    1.25 +
    1.26 +/**
    1.27 + * Get keystroke.
    1.28 + * @returns    BIOS scan code.
    1.29 + */
    1.30 +Bit8u get_keystroke()
    1.31 +{
    1.32 +ASM_START
    1.33 +    mov  ax, #0x0
    1.34 +    int  #0x16
    1.35 +    xchg ah, al
    1.36 +ASM_END
    1.37 +}
    1.38 +
    1.39 +/**
    1.40 + * Waits (sleeps) for the given number of ticks.
    1.41 + * Checks for keystroke.
    1.42 + *
    1.43 + * @returns BIOS scan code if available, 0 if not.
    1.44 + * @param   ticks       Number of ticks to sleep.
    1.45 + * @param   stop_on_key Whether to stop immediately upon keypress.
    1.46 + */
    1.47 +Bit8u wait(ticks, stop_on_key)
    1.48 +  Bit16u ticks;
    1.49 +  Bit8u stop_on_key;
    1.50 +{
    1.51 +    long ticks_to_wait, delta;
    1.52 +    Bit32u prev_ticks, t;
    1.53 +    Bit8u scan_code = 0;
    1.54 +
    1.55 +    /*
    1.56 +     * The 0:046c wraps around at 'midnight' according to a 18.2Hz clock.
    1.57 +     * We also have to be careful about interrupt storms.
    1.58 +     */
    1.59 +    ticks_to_wait = ticks;
    1.60 +    prev_ticks = read_dword(0x0, 0x46c);
    1.61 +    do
    1.62 +    {
    1.63 +        t = read_dword(0x0, 0x46c);
    1.64 +        if (t > prev_ticks)
    1.65 +        {
    1.66 +            delta = t - prev_ticks;     /* The temp var is required or bcc screws up. */
    1.67 +            ticks_to_wait -= delta;
    1.68 +        }
    1.69 +        else if (t < prev_ticks)
    1.70 +            ticks_to_wait -= t;         /* wrapped */
    1.71 +        prev_ticks = t;
    1.72 +
    1.73 +        if (check_for_keystroke())
    1.74 +        {
    1.75 +            scan_code = get_keystroke();
    1.76 +            bios_printf(BIOS_PRINTF_DEBUG, "Key pressed: %x\n", scan_code);
    1.77 +            if (stop_on_key)
    1.78 +                return scan_code;
    1.79 +        }
    1.80 +    } while (ticks_to_wait > 0);
    1.81 +    return scan_code;
    1.82 +}
    1.83 +
    1.84 +static void clearscreen() {
    1.85 +    /* Hide cursor, clear screen and move cursor to starting position */
    1.86 +ASM_START
    1.87 +        push bx
    1.88 +        push cx
    1.89 +        push dx
    1.90 +
    1.91 +        mov  ax, #0x100
    1.92 +        mov  cx, #0x1000
    1.93 +        int  #0x10
    1.94 +
    1.95 +        mov  ax, #0x700
    1.96 +        mov  bh, #7
    1.97 +        xor  cx, cx
    1.98 +        mov  dx, #0x184f
    1.99 +        int  #0x10
   1.100 +
   1.101 +        mov  ax, #0x200
   1.102 +        xor  bx, bx
   1.103 +        xor  dx, dx
   1.104 +        int  #0x10
   1.105 +
   1.106 +        pop  dx
   1.107 +        pop  cx
   1.108 +        pop  bx
   1.109 +ASM_END
   1.110 +}
   1.111 +
   1.112 +int bootmenu(selected)
   1.113 +  int selected;
   1.114 +{
   1.115 +    Bit8u scode;
   1.116 +    int max;
   1.117 +
   1.118 +    /* get the number of boot devices */
   1.119 +    max = read_word(IPL_SEG, IPL_COUNT_OFFSET);
   1.120 +
   1.121 +    for(;;) {
   1.122 +        if (selected > max || selected < 1) selected = 1;
   1.123 +        clearscreen();
   1.124 +        bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "\n\n\n\n\n\n\n");
   1.125 +        bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "          Select boot device\n\n");
   1.126 +        bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "            1. Floppy\n");
   1.127 +        bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "            2. Hard drive\n");
   1.128 +        bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "            3. CD-ROM\n");
   1.129 +        if (max == 4)
   1.130 +            bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "            4. Network\n");
   1.131 +        bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "\n\n          Currently selected: %d\n", selected);
   1.132 +
   1.133 +        do {
   1.134 +            scode = wait(WAIT_HZ, 1);
   1.135 +        } while (scode == 0);
   1.136 +        switch(scode) {
   1.137 +        case 0x02:
   1.138 +        case 0x03:
   1.139 +        case 0x04:
   1.140 +            selected = scode - 1;
   1.141 +            break;
   1.142 +        case 0x05:
   1.143 +            if (max == 4)
   1.144 +                selected = scode -1 ;
   1.145 +            else
   1.146 +                scode = 0;
   1.147 +            break;
   1.148 +        case 0x48:
   1.149 +            selected -= 1;
   1.150 +            if (selected < 1)
   1.151 +                selected = 1;
   1.152 +            scode = 0;
   1.153 +            break;
   1.154 +        case 0x50:
   1.155 +            selected += 1;
   1.156 +            if (selected > max)
   1.157 +                selected = max;
   1.158 +            scode = 0;
   1.159 +            break;
   1.160 +        case 0x1c:
   1.161 +            break;
   1.162 +        default:
   1.163 +            scode = 0;
   1.164 +            break;
   1.165 +        }
   1.166 +        if (scode != 0)
   1.167 +            break;
   1.168 +    }
   1.169 +
   1.170 +    switch (selected) {
   1.171 +    case 1:
   1.172 +        return 0x3D;
   1.173 +    case 2:
   1.174 +        return 0x3E;
   1.175 +    case 3:
   1.176 +        return 0x3F;
   1.177 +    case 4:
   1.178 +        return 0x58;
   1.179 +    default:
   1.180 +        return 0;
   1.181 +    }
   1.182 +}
   1.183 +
   1.184 +void interactive_bootkey()
   1.185 +{
   1.186 +    Bit16u i;
   1.187 +    Bit8u scan = 0;
   1.188 +
   1.189 +    bios_printf(BIOS_PRINTF_SCREEN | BIOS_PRINTF_INFO, "\n\nPress F10 to select boot device.\n");
   1.190 +    for (i = 3; i > 0; i--)
   1.191 +    {
   1.192 +        scan = wait(WAIT_HZ, 0);
   1.193 +        switch (scan) {
   1.194 +        case 0x3D:
   1.195 +        case 0x3E:
   1.196 +        case 0x3F:
   1.197 +        case 0x58:
   1.198 +            break;
   1.199 +        case 0x44:
   1.200 +            scan = bootmenu(inb_cmos(0x3d) & 0x0f);
   1.201 +            break;
   1.202 +        default:
   1.203 +            scan = 0;
   1.204 +            break;
   1.205 +        }
   1.206 +        if (scan != 0)
   1.207 +            break;
   1.208 +    }
   1.209 +
   1.210 +    /* set the default based on the keypress or menu */
   1.211 +    switch(scan) {
   1.212 +    case 0x3D:
   1.213 +        outb_cmos(0x3d, 0x01);
   1.214 +        break;
   1.215 +    case 0x3E:
   1.216 +        outb_cmos(0x3d, 0x02);
   1.217 +        break;
   1.218 +    case 0x3F:
   1.219 +        outb_cmos(0x3d, 0x03);
   1.220 +        break;
   1.221 +    case 0x58:
   1.222 +        outb_cmos(0x3d, 0x04);
   1.223 +        break;
   1.224 +    default:
   1.225 +        break;
   1.226 +    }
   1.227 +}
   1.228 +
   1.229 +
   1.230  void
   1.231  nmi_handler_msg()
   1.232  {
   1.233 @@ -9825,7 +10048,9 @@ post_default_ints:
   1.234    call _cdemu_init
   1.235    ;;
   1.236  #endif // BX_ELTORITO_BOOT
   1.237 - 
   1.238 +
   1.239 +  call _interactive_bootkey
   1.240 +
   1.241  #if BX_TCGBIOS
   1.242    call _tcpa_calling_int19h          /* specs: 8.2.3 step 1 */
   1.243    call _tcpa_add_event_separators    /* specs: 8.2.3 step 2 */