VirtualBox

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

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

added license

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.3 KB
Line 
1/* $Id: logo.c 9534 2008-06-09 11:37:06Z 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 actual_device = 0;
261 Bit8u first_ctrl_printed = 0;
262 Bit8u second_ctrl_printed = 0;
263 Bit8u device;
264
265 device = read_byte(ebda_seg, &EbdaData->ata.hdidmap[actual_device]);
266
267 while ((actual_device < BX_MAX_ATA_DEVICES) && (device < BX_MAX_ATA_DEVICES))
268 {
269 Bit8u device_position;
270
271 device_position = device;
272
273 if ((device_position < 4) && (first_ctrl_printed == 0))
274 {
275 printf("IDE controller:\n");
276 first_ctrl_printed = 1;
277 }
278 else if ((device_position >= 4) && (second_ctrl_printed == 0))
279 {
280 printf("\n\nAHCI controller:\n");
281 second_ctrl_printed = 1;
282 }
283
284 printf("\n %d) ", actual_device+1);
285
286 /*
287 * If actual_device is bigger than or equal 4
288 * this is the next controller and
289 * the positions start at the beginning.
290 */
291 if (device_position >= 4)
292 device_position -= 4;
293
294 if (device_position / 2)
295 printf("Secondary ");
296 else
297 printf("Primary ");
298
299 if (device_position % 2)
300 printf("Slave");
301 else
302 printf("Master");
303
304 actual_device++;
305 device = read_byte(ebda_seg, &EbdaData->ata.hdidmap[actual_device]);
306 }
307
308 printf("\n");
309}
310
311Bit8u get_boot_drive(scode)
312 Bit8u scode;
313{
314 Bit16u ebda_seg=read_word(0x0040,0x000E);
315 Bit8u actual_device;
316 Bit8u detected_devices = 0;
317
318 for (actual_device = 0; actual_device < BX_MAX_ATA_DEVICES; actual_device++)
319 {
320 Bit8u device = read_byte(ebda_seg, &EbdaData->ata.hdidmap[actual_device]);
321
322 if (device < BX_MAX_ATA_DEVICES)
323 {
324 scode--;
325 if (scode == 0x01)
326 return actual_device;
327 }
328 }
329
330 /* Scancode is higher than number of available devices */
331 return 0x08;
332}
333
334void show_logo()
335{
336 Bit16u ebda_seg = read_word(0x0040,0x000E);
337 Bit8u f12_pressed = 0;
338 Bit8u scode;
339 Bit16u tmp, i;
340
341 LOGOHDR *logo_hdr = 0;
342 Bit8u is_fade_in, is_fade_out, uBootMenu;
343 Bit16u logo_time;
344
345
346 // Set PIT to 1ms ticks
347 wait_init();
348
349
350 // Get main signature
351 tmp = read_logo_word(&logo_hdr->u16Signature);
352 if (tmp != 0x66BB)
353 goto done;
354
355 // Get options
356 is_fade_in = read_logo_byte(&logo_hdr->fu8FadeIn);
357 is_fade_out = read_logo_byte(&logo_hdr->fu8FadeOut);
358 logo_time = read_logo_word(&logo_hdr->u16LogoMillies);
359 uBootMenu = read_logo_byte(&logo_hdr->fu8ShowBootMenu);
360
361 // Is Logo disabled?
362 if (!is_fade_in && !is_fade_out && !logo_time)
363 goto done;
364
365 // Set video mode #0x142 640x480x32bpp
366 vesa_set_mode(0x142);
367
368 if (is_fade_in)
369 {
370 for (i = 0; i <= LOGO_SHOW_STEPS; i++)
371 {
372 outw(LOGO_IO_PORT, LOGO_CMD_SHOW_BMP | i);
373 scode = wait(16 / WAIT_MS, 0);
374 if (scode == F12_SCAN_CODE)
375 {
376 f12_pressed = 1;
377 break;
378 }
379 }
380 }
381 else
382 outw(LOGO_IO_PORT, LOGO_CMD_SHOW_BMP | LOGO_SHOW_STEPS);
383
384 // Wait (interval in milliseconds)
385 if (!f12_pressed)
386 {
387 scode = wait(logo_time / WAIT_MS, 1);
388 if (scode == F12_SCAN_CODE)
389 f12_pressed = 1;
390 }
391
392 // Fade out (only if F12 was not pressed)
393 if (is_fade_out && !f12_pressed)
394 {
395 for (i = LOGO_SHOW_STEPS; i > 0 ; i--)
396 {
397 outw(LOGO_IO_PORT, LOGO_CMD_SHOW_BMP | i);
398 scode = wait(16 / WAIT_MS, 0);
399 if (scode == F12_SCAN_CODE)
400 {
401 f12_pressed = 1;
402 break;
403 }
404 }
405 }
406
407done:
408 // Clear forced boot drive setting.
409 write_byte(ebda_seg, &EbdaData->uForceBootDevice, 0);
410
411 // Don't restore previous video mode
412 // The default text mode should be set up. (defect #1235)
413 set_mode(0x0003);
414
415 // If Setup menu enabled
416 if (uBootMenu)
417 {
418 // If the graphics logo disabled
419 if (!is_fade_in && !is_fade_out && !logo_time)
420 {
421 int i;
422
423 if (uBootMenu == 2)
424 printf("Press F12 to select boot device.\n");
425
426 // if the user has pressed F12 don't wait here
427 if (!f12_pressed)
428 {
429 // Wait for timeout or keystroke
430 scode = wait(F12_WAIT_TIME, 1);
431 if (scode == F12_SCAN_CODE)
432 f12_pressed = 1;
433 }
434 }
435
436 // If F12 pressed, show boot menu
437 if (f12_pressed)
438 {
439 Bit8u boot_device = 0;
440 Bit8u boot_drive = 0;
441
442 clear_screen();
443
444 // Show menu. Note that some versions of bcc freak out if we split these strings.
445 printf("\nVirtualBox temporary boot device selection\n\nDetected Hard disks:\n\n");
446 print_detected_harddisks();
447 printf("\nOther boot devices:\n f) Floppy\n c) CD-ROM\n l) LAN\n\n b) Continue booting\n");
448
449
450
451 // Wait for keystroke
452 for (;;)
453 {
454 do
455 {
456 scode = wait(WAIT_HZ, 1);
457 } while (scode == 0);
458
459 if (scode == 0x30)
460 {
461 // 'b' ... continue
462 break;
463 }
464
465 // Check if hard disk was selected
466 if ((scode >= 0x02) && (scode <= 0x09))
467 {
468 boot_drive = get_boot_drive(scode);
469
470 /*
471 * We support a maximum of 8 boot drives.
472 * If this value is bigger than 7 not all
473 * values are used and the user pressed
474 * and invalid key.
475 * Wait for the next pressed key.
476 */
477 if (boot_drive > 7)
478 continue;
479
480 write_byte(ebda_seg, &EbdaData->uForceBootDrive, boot_drive);
481 boot_device = 0x02;
482 break;
483 }
484
485 switch (scode)
486 {
487 case 0x21:
488 // Floppy
489 boot_device = 0x01;
490 break;
491 case 0x2e:
492 // CD-ROM
493 boot_device = 0x03;
494 break;
495 case 0x26:
496 // LAN
497 boot_device = 0x04;
498 break;
499 }
500
501 if (boot_device != 0)
502 break;
503 }
504
505 write_byte(ebda_seg, &EbdaData->uForceBootDevice, boot_device);
506
507 // Switch to text mode. Clears screen and enables cursor again.
508 set_mode(0x0003);
509 }
510 }
511
512 // Restore PIT ticks
513 wait_uninit();
514
515 return;
516}
517
518
519void delay_boot(secs)
520 Bit16u secs;
521{
522 Bit16u i;
523
524 if (!secs)
525 return;
526
527 // Set PIT to 1ms ticks
528 wait_init();
529
530 printf("Delaying boot for %d seconds:", secs);
531 for (i = secs; i > 0; i--)
532 {
533 printf(" %d", i);
534 wait(WAIT_HZ, 0);
535 }
536 printf("\n");
537 // Restore PIT ticks
538 wait_uninit();
539}
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