VirtualBox

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

Last change on this file since 40754 was 28800, checked in by vboxsync, 14 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.4 KB
Line 
1/* $Id: logo.c 28800 2010-04-27 08:22:32Z vboxsync $ */
2/** @file
3 * Stuff for drawing the BIOS logo.
4 */
5
6/*
7 * Copyright (C) 2004-2008 Oracle Corporation
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
18#define WAIT_HZ 64
19#define WAIT_MS 16
20
21#define F12_SCAN_CODE 0x86
22#define F12_WAIT_TIME (3 * WAIT_HZ) /* 3 seconds. Used only if logo disabled. */
23
24#define uint8_t Bit8u
25#define uint16_t Bit16u
26#define uint32_t Bit32u
27#include <VBox/bioslogo.h>
28
29//static void set_mode(mode);
30//static void vesa_set_mode(mode);
31//static Bit8u wait(ticks, stop_on_key);
32
33/**
34 * Set video mode (VGA).
35 * @params New video mode.
36 */
37void set_mode(mode)
38 Bit8u mode;
39 {
40 ASM_START
41 push bp
42 mov bp, sp
43
44 push ax
45
46 mov ah, #0
47 mov al, 4[bp] ; mode
48 int #0x10
49
50 pop ax
51
52 pop bp
53 ASM_END
54 }
55
56/**
57 * Set VESA video mode.
58 * @params New video mode.
59 */
60Bit16u vesa_set_mode(mode)
61 Bit16u mode;
62 {
63 ASM_START
64 push bp
65 mov bp, sp
66
67 push bx
68
69 mov ax, #0x4f02
70 mov bx, 4[bp] ; mode
71 int #0x10
72
73 pop bx
74
75 pop bp
76 ASM_END
77}
78
79/**
80 * Check for keystroke.
81 * @returns True if keystroke available, False if not.
82 */
83Bit8u check_for_keystroke()
84 {
85 ASM_START
86 mov ax, #0x100
87 int #0x16
88 jz no_key
89 mov al, #1
90 jmp done
91no_key:
92 xor al, al
93done:
94 ASM_END
95}
96
97/**
98 * Get keystroke.
99 * @returns BIOS scan code.
100 */
101Bit8u get_keystroke()
102 {
103 ASM_START
104 mov ax, #0x0
105 int #0x16
106 xchg ah, al
107 ASM_END
108}
109
110void wait_init()
111{
112 // The default is 18.2 ticks per second (~55ms tick interval).
113 // Set the timer to 16ms ticks (64K / (Hz / (PIT_HZ / 64K)) = count).
114 // 0x10000 / (1000 / (1193182 / 0x10000)) = 1193 (0x04a9)
115 // 0x10000 / ( 128 / (1193182 / 0x10000)) = 9321 (0x2469)
116 // 0x10000 / ( 64 / (1193182 / 0x10000)) = 18643 (0x48d3)
117ASM_START
118 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
119 out 0x43, al
120 mov al, #0xd3 ; Low byte - 64Hz
121 out 0x40, al
122 mov al, #0x48 ; High byte - 64Hz
123 out 0x40, al
124ASM_END
125}
126
127void wait_uninit()
128{
129ASM_START
130 pushf
131 cli
132
133 /* Restore the timer to the default 18.2Hz. */
134 mov al, #0x34 ; timer0: binary count, 16bit count, mode 2
135 out 0x43, al
136 xor ax, ax ; maximum count of 0000H = 18.2Hz
137 out 0x40, al
138 out 0x40, al
139
140 /*
141 * Reinitialize the tick and rollover counts since we've
142 * screwed them up by running the timer at WAIT_HZ for a while.
143 */
144 pushad
145 push ds
146 mov ds, ax ; already 0
147 call timer_tick_post
148 pop ds
149 popad
150
151 popf
152ASM_END
153}
154
155/**
156 * Waits (sleeps) for the given number of ticks.
157 * Checks for keystroke.
158 *
159 * @returns BIOS scan code if available, 0 if not.
160 * @param ticks Number of ticks to sleep.
161 * @param stop_on_key Whether to stop immediately upon keypress.
162 */
163Bit8u wait(ticks, stop_on_key)
164 Bit16u ticks;
165 Bit8u stop_on_key;
166{
167 long ticks_to_wait, delta;
168 Bit32u prev_ticks, t;
169 Bit8u scan_code = 0;
170
171 /*
172 * The 0:046c wraps around at 'midnight' according to a 18.2Hz clock.
173 * We also have to be careful about interrupt storms.
174 */
175ASM_START
176 pushf
177 sti
178ASM_END
179 ticks_to_wait = ticks;
180 prev_ticks = read_dword(0x0, 0x46c);
181 do
182 {
183ASM_START
184 hlt
185ASM_END
186 t = read_dword(0x0, 0x46c);
187 if (t > prev_ticks)
188 {
189 delta = t - prev_ticks; /* The temp var is required or bcc screws up. */
190 ticks_to_wait -= delta;
191 }
192 else if (t < prev_ticks)
193 ticks_to_wait -= t; /* wrapped */
194 prev_ticks = t;
195
196 if (check_for_keystroke())
197 {
198 scan_code = get_keystroke();
199 bios_printf(BIOS_PRINTF_INFO, "Key pressed: %x\n", scan_code);
200 if (stop_on_key)
201 return scan_code;
202 }
203 } while (ticks_to_wait > 0);
204ASM_START
205 popf
206ASM_END
207 return scan_code;
208}
209
210Bit8u read_logo_byte(offset)
211 Bit8u offset;
212{
213 outw(LOGO_IO_PORT, LOGO_CMD_SET_OFFSET | offset);
214 return inb(LOGO_IO_PORT);
215}
216
217Bit16u read_logo_word(offset)
218 Bit8u offset;
219{
220 outw(LOGO_IO_PORT, LOGO_CMD_SET_OFFSET | offset);
221 return inw(LOGO_IO_PORT);
222}
223
224void clear_screen()
225{
226// Hide cursor, clear screen and move cursor to starting position
227ASM_START
228 push bx
229 push cx
230 push dx
231
232 mov ax, #0x100
233 mov cx, #0x1000
234 int #0x10
235
236 mov ax, #0x700
237 mov bh, #7
238 xor cx, cx
239 mov dx, #0x184f
240 int #0x10
241
242 mov ax, #0x200
243 xor bx, bx
244 xor dx, dx
245 int #0x10
246
247 pop dx
248 pop cx
249 pop bx
250ASM_END
251}
252
253void print_detected_harddisks()
254{
255 Bit16u ebda_seg=read_word(0x0040,0x000E);
256 Bit8u hd_count;
257 Bit8u hd_curr = 0;
258 Bit8u ide_ctrl_printed = 0;
259 Bit8u sata_ctrl_printed = 0;
260 Bit8u scsi_ctrl_printed = 0;
261 Bit8u device;
262
263 hd_count = read_byte(ebda_seg, &EbdaData->ata.hdcount);
264
265 for (hd_curr = 0; hd_curr < hd_count; hd_curr++)
266 {
267 device = read_byte(ebda_seg, &EbdaData->ata.hdidmap[hd_curr]);
268
269#ifdef VBOX_WITH_SCSI
270 if (!VBOX_IS_SCSI_DEVICE(device))
271#endif
272 {
273
274 if ((device < 4) && (ide_ctrl_printed == 0))
275 {
276 printf("IDE controller:\n");
277 ide_ctrl_printed = 1;
278 }
279 else if ((device >= 4) && (sata_ctrl_printed == 0))
280 {
281 printf("\n\nAHCI controller:\n");
282 sata_ctrl_printed = 1;
283 }
284
285 printf("\n %d) ", hd_curr+1);
286
287 /*
288 * If actual_device is bigger than or equal 4
289 * this is the next controller and
290 * the positions start at the beginning.
291 */
292 if (device >= 4)
293 device -= 4;
294
295 if (device / 2)
296 printf("Secondary ");
297 else
298 printf("Primary ");
299
300 if (device % 2)
301 printf("Slave");
302 else
303 printf("Master");
304 }
305#ifdef VBOX_WITH_SCSI
306 else
307 {
308 if (scsi_ctrl_printed == 0)
309 {
310 printf("\n\nSCSI controller:\n");
311 scsi_ctrl_printed = 1;
312 }
313
314 printf("\n %d) Hard disk", hd_curr+1);
315
316 }
317#endif
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.

© 2023 Oracle
ContactPrivacy policyTerms of Use