VirtualBox

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

Last change on this file since 21205 was 18391, checked in by vboxsync, 15 years ago

OSE fix

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

© 2023 Oracle
ContactPrivacy policyTerms of Use