VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/BIOS/logo.c@ 7891

Last change on this file since 7891 was 7891, checked in by vboxsync, 17 years ago

immediately abort if F12 was pressed

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.8 KB
Line 
1#define WAIT_HZ 64
2#define WAIT_MS 16
3
4#define F12_SCAN_CODE 0x86
5#define F12_WAIT_TIME (3 * WAIT_HZ) /* 3 seconds. Used only if logo disabled. */
6
7#define uint8_t Bit8u
8#define uint16_t Bit16u
9#define uint32_t Bit32u
10#include <VBox/bioslogo.h>
11
12//static void set_mode(mode);
13//static void vesa_set_mode(mode);
14//static Bit8u wait(ticks, stop_on_key);
15
16/**
17 * Set video mode (VGA).
18 * @params New video mode.
19 */
20void set_mode(mode)
21 Bit8u mode;
22 {
23 ASM_START
24 push bp
25 mov bp, sp
26
27 push ax
28
29 mov ah, #0
30 mov al, 4[bp] ; mode
31 int #0x10
32
33 pop ax
34
35 pop bp
36 ASM_END
37 }
38
39/**
40 * Set VESA video mode.
41 * @params New video mode.
42 */
43Bit16u vesa_set_mode(mode)
44 Bit16u mode;
45 {
46 ASM_START
47 push bp
48 mov bp, sp
49
50 push bx
51
52 mov ax, #0x4f02
53 mov bx, 4[bp] ; mode
54 int #0x10
55
56 pop bx
57
58 pop bp
59 ASM_END
60}
61
62/**
63 * Check for keystroke.
64 * @returns True if keystroke available, False if not.
65 */
66Bit8u check_for_keystroke()
67 {
68 ASM_START
69 mov ax, #0x100
70 int #0x16
71 jz no_key
72 mov al, #1
73 jmp done
74no_key:
75 xor al, al
76done:
77 ASM_END
78}
79
80/**
81 * Get keystroke.
82 * @returns BIOS scan code.
83 */
84Bit8u get_keystroke()
85 {
86 ASM_START
87 mov ax, #0x0
88 int #0x16
89 xchg ah, al
90 ASM_END
91}
92
93void wait_init()
94{
95 // The default is 18.2 ticks per second (~55ms tick interval).
96 // Set the timer to 16ms ticks (64K / (Hz / (PIT_HZ / 64K)) = count).
97 // 0x10000 / (1000 / (1193182 / 0x10000)) = 1193 (0x04a9)
98 // 0x10000 / ( 128 / (1193182 / 0x10000)) = 9321 (0x2469)
99 // 0x10000 / ( 64 / (1193182 / 0x10000)) = 18643 (0x48d3)
100ASM_START
101 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
102 out 0x43, al
103 mov al, #0xd3 ; Low byte - 64Hz
104 out 0x40, al
105 mov al, #0x48 ; High byte - 64Hz
106 out 0x40, al
107ASM_END
108}
109
110void wait_uninit()
111{
112ASM_START
113 pushf
114 cli
115
116 /* Restore the timer to the default 18.2Hz. */
117 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
118 out 0x43, al
119 xor ax, ax ; maximum count of 0000H = 18.2Hz
120 out 0x40, al
121 out 0x40, al
122
123 /*
124 * Reinitialize the tick and rollover counts since we've
125 * screwed them up by running the timer at WAIT_HZ for a while.
126 */
127 pushad
128 push ds
129 mov ds, ax ; already 0
130 call timer_tick_post
131 pop ds
132 popad
133
134 popf
135ASM_END
136}
137
138/**
139 * Waits (sleeps) for the given number of ticks.
140 * Checks for keystroke.
141 *
142 * @returns BIOS scan code if available, 0 if not.
143 * @param ticks Number of ticks to sleep.
144 * @param stop_on_key Whether to stop immediately upon keypress.
145 */
146Bit8u wait(ticks, stop_on_key)
147 Bit16u ticks;
148 Bit8u stop_on_key;
149{
150 long ticks_to_wait, delta;
151 Bit32u prev_ticks, t;
152 Bit8u scan_code = 0;
153
154 /*
155 * The 0:046c wraps around at 'midnight' according to a 18.2Hz clock.
156 * We also have to be careful about interrupt storms.
157 */
158ASM_START
159 pushf
160 sti
161ASM_END
162 ticks_to_wait = ticks;
163 prev_ticks = read_dword(0x0, 0x46c);
164 do
165 {
166ASM_START
167 hlt
168ASM_END
169 t = read_dword(0x0, 0x46c);
170 if (t > prev_ticks)
171 {
172 delta = t - prev_ticks; /* The temp var is required or bcc screws up. */
173 ticks_to_wait -= delta;
174 }
175 else if (t < prev_ticks)
176 ticks_to_wait -= t; /* wrapped */
177 prev_ticks = t;
178
179 if (check_for_keystroke())
180 {
181 scan_code = get_keystroke();
182 bios_printf(BIOS_PRINTF_INFO, "Key pressed: %x\n", scan_code);
183 if (stop_on_key)
184 return scan_code;
185 }
186 } while (ticks_to_wait > 0);
187ASM_START
188 popf
189ASM_END
190 return scan_code;
191}
192
193Bit8u read_logo_byte(offset)
194 Bit8u offset;
195{
196 outw(LOGO_IO_PORT, LOGO_CMD_SET_OFFSET | offset);
197 return inb(LOGO_IO_PORT);
198}
199
200Bit16u read_logo_word(offset)
201 Bit8u offset;
202{
203 outw(LOGO_IO_PORT, LOGO_CMD_SET_OFFSET | offset);
204 return inw(LOGO_IO_PORT);
205}
206
207void clear_screen()
208{
209// Hide cursor, clear screen and move cursor to starting position
210ASM_START
211 push bx
212 push cx
213 push dx
214
215 mov ax, #0x100
216 mov cx, #0x1000
217 int #0x10
218
219 mov ax, #0x700
220 mov bh, #7
221 xor cx, cx
222 mov dx, #0x184f
223 int #0x10
224
225 mov ax, #0x200
226 xor bx, bx
227 xor dx, dx
228 int #0x10
229
230 pop dx
231 pop cx
232 pop bx
233ASM_END
234}
235
236void print_detected_harddisks()
237{
238 Bit16u ebda_seg=read_word(0x0040,0x000E);
239 Bit8u actual_device = 0;
240 Bit8u first_ctrl_printed = 0;
241 Bit8u second_ctrl_printed = 0;
242 Bit8u device;
243
244 device = read_byte(ebda_seg, &EbdaData->ata.hdidmap[actual_device]);
245
246 while ((actual_device < BX_MAX_ATA_DEVICES) && (device < BX_MAX_ATA_DEVICES))
247 {
248 Bit8u device_position;
249
250 device_position = device;
251
252 if ((device_position < 4) && (first_ctrl_printed == 0))
253 {
254 printf("IDE controller:\n");
255 first_ctrl_printed = 1;
256 }
257 else if ((device_position >= 4) && (second_ctrl_printed == 0))
258 {
259 printf("\n\nAHCI controller:\n");
260 second_ctrl_printed = 1;
261 }
262
263 printf("\n %d) ", actual_device+1);
264
265 /*
266 * If actual_device is bigger than or equal 4
267 * this is the next controller and
268 * the positions start at the beginning.
269 */
270 if (device_position >= 4)
271 device_position -= 4;
272
273 if (device_position / 2)
274 printf("Secondary ");
275 else
276 printf("Primary ");
277
278 if (device_position % 2)
279 printf("Slave");
280 else
281 printf("Master");
282
283 actual_device++;
284 device = read_byte(ebda_seg, &EbdaData->ata.hdidmap[actual_device]);
285 }
286
287 printf("\n");
288}
289
290Bit8u get_boot_drive(scode)
291 Bit8u scode;
292{
293 Bit16u ebda_seg=read_word(0x0040,0x000E);
294 Bit8u actual_device;
295 Bit8u detected_devices = 0;
296
297 for (actual_device = 0; actual_device < BX_MAX_ATA_DEVICES; actual_device++)
298 {
299 Bit8u device = read_byte(ebda_seg, &EbdaData->ata.hdidmap[actual_device]);
300
301 if (device < BX_MAX_ATA_DEVICES)
302 {
303 scode--;
304 if (scode == 0x01)
305 return actual_device;
306 }
307 }
308
309 /* Scancode is higher than number of available devices */
310 return 0x08;
311}
312
313void show_logo()
314{
315 Bit16u ebda_seg=read_word(0x0040,0x000E);
316
317 LOGOHDR *logo_hdr;
318 Bit16u logo_hdr_size, tmp, i;
319 Bit32u hdr_size;
320
321 Bit8u is_fade_in, is_fade_out, is_logo_failed, uBootMenu;
322 Bit16u logo_time;
323
324 Bit32u offset;
325
326 Bit8u scode, f12_pressed = 0;
327 Bit8u c;
328
329 // Set PIT to 1ms ticks
330 wait_init();
331
332 is_logo_failed = 0;
333
334 logo_hdr = 0;
335 logo_hdr_size = sizeof(LOGOHDR);
336
337 // Get main signature
338 tmp = read_logo_word(&logo_hdr->u16Signature);
339 if (tmp != 0x66BB)
340 goto done;
341
342 // Get options
343 is_fade_in = read_logo_byte(&logo_hdr->fu8FadeIn);
344 is_fade_out = read_logo_byte(&logo_hdr->fu8FadeOut);
345 logo_time = read_logo_word(&logo_hdr->u16LogoMillies);
346 uBootMenu = read_logo_byte(&logo_hdr->fu8ShowBootMenu);
347
348 // Is Logo disabled?
349 if (!is_fade_in && !is_fade_out && !logo_time)
350 goto done;
351
352 // Set video mode #0x142 640x480x32bpp
353 vesa_set_mode(0x142);
354
355 if (is_fade_in)
356 {
357 for (i = 0; i <= LOGO_SHOW_STEPS; i++)
358 {
359 outw(LOGO_IO_PORT, LOGO_CMD_SHOW_BMP | i);
360 scode = wait(16 / WAIT_MS, 0);
361 if (scode == F12_SCAN_CODE)
362 {
363 f12_pressed = 1;
364 break;
365 }
366 }
367 }
368 else
369 outw(LOGO_IO_PORT, LOGO_CMD_SHOW_BMP | LOGO_SHOW_STEPS);
370
371 // Wait (interval in milliseconds)
372 if (!f12_pressed)
373 {
374 scode = wait(logo_time / WAIT_MS, 0);
375 if (scode == F12_SCAN_CODE)
376 f12_pressed = 1;
377 }
378
379 // Fade out (only if F12 was not pressed)
380 if (is_fade_out && !f12_pressed)
381 {
382 for (i = LOGO_SHOW_STEPS; i > 0 ; i--)
383 {
384 outw(LOGO_IO_PORT, LOGO_CMD_SHOW_BMP | i);
385 scode = wait(16 / WAIT_MS, 0);
386 if (scode == F12_SCAN_CODE)
387 {
388 f12_pressed = 1;
389 break;
390 }
391 }
392 }
393
394done:
395 // Clear forced boot drive setting.
396 write_byte(ebda_seg,&EbdaData->uForceBootDevice, 0);
397
398 // Don't restore previous video mode
399 // The default text mode should be set up. (defect #1235)
400 set_mode(0x0003);
401
402 // If Setup menu enabled
403 if (uBootMenu)
404 {
405 // If the graphics logo disabled
406 if (!is_fade_in && !is_fade_out && !logo_time)
407 {
408 int i;
409
410 if (uBootMenu == 2)
411 printf("Press F12 to select boot device.");
412
413 // if the user has pressed F12 don't wait here
414 if (!f12_pressed)
415 {
416 // Wait for timeout or keystroke
417 scode = wait(F12_WAIT_TIME, 1);
418 if (scode == F12_SCAN_CODE)
419 f12_pressed = 1;
420 }
421 }
422
423 // If F12 pressed, show boot menu
424 if (f12_pressed)
425 {
426 Bit8u boot_device = 0;
427 Bit8u boot_drive = 0;
428
429 clear_screen();
430
431 // Show menu
432 printf("\n"
433 "VirtualBox temporary boot device selection\n"
434 "\n"
435 "Detected Hard disks:\n"
436 "\n");
437 print_detected_harddisks();
438 printf("\n"
439 "Other boot devices:\n"
440 " f) Floppy\n"
441 " c) CD-ROM\n"
442 " l) LAN\n"
443 "\n"
444 " b) Continue booting\n");
445
446
447
448 // Wait for keystroke
449 for (;;)
450 {
451 do
452 {
453 scode = wait(WAIT_HZ, 1);
454 } while (scode == 0);
455
456 if (scode == 0x30)
457 {
458 // 'b' ... continue
459 break;
460 }
461
462 // Check if hard disk was selected
463 if ((scode >= 0x02) && (scode <= 0x09))
464 {
465 boot_drive = get_boot_drive(scode);
466
467 /*
468 * We support a maximum of 8 boot drives.
469 * If this value is bigger than 7 not all
470 * values are used and the user pressed
471 * and invalid key.
472 * Wait for the next pressed key.
473 */
474 if (boot_drive > 7)
475 continue;
476
477 write_byte(ebda_seg, &EbdaData->uForceBootDrive, boot_drive);
478 boot_device = 0x02;
479 break;
480 }
481
482 switch (scode)
483 {
484 case 0x21:
485 // Floppy
486 boot_device = 0x01;
487 break;
488 case 0x2e:
489 // CD-ROM
490 boot_device = 0x03;
491 break;
492 case 0x26:
493 // LAN
494 boot_device = 0x04;
495 break;
496 }
497
498 if (boot_device != 0)
499 break;
500 }
501
502 write_byte(ebda_seg, &EbdaData->uForceBootDevice, boot_device);
503
504 // Switch to text mode. Clears screen and enables cursor again.
505 set_mode(0x0003);
506 }
507 }
508
509 // Restore PIT ticks
510 wait_uninit();
511
512 return;
513}
514
515
516void delay_boot(secs)
517 Bit16u secs;
518{
519 Bit16u i;
520
521 if (!secs)
522 return;
523
524 // Set PIT to 1ms ticks
525 wait_init();
526
527 printf("Delaying boot for %d seconds:", secs);
528 for (i = secs; i > 0; i--)
529 {
530 printf(" %d", i);
531 wait(WAIT_HZ, 0);
532 }
533 printf("\n");
534 // Restore PIT ticks
535 wait_uninit();
536}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette