debuggers.hg
changeset 16753: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>
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 */