VirtualBox

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

Last change on this file since 18324 was 18324, checked in by vboxsync, 16 years ago

BIOS: Make it possible to select SCSI disks on the boot screen

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