VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/BIOS-new/logo.c@ 38699

Last change on this file since 38699 was 38699, checked in by vboxsync, 13 years ago

Converted system BIOS to Watcom C.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.1 KB
Line 
1/* $Id: logo.c 38699 2011-09-09 09:02:23Z vboxsync $ */
2/** @file
3 * Stuff for drawing the BIOS logo.
4 */
5
6/*
7 * Copyright (C) 2004-2011 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#include <stdint.h>
19#include "biosint.h"
20#include "inlines.h"
21#include "ebda.h"
22
23#define WAIT_HZ 64
24#define WAIT_MS 16
25
26#define F12_SCAN_CODE 0x86
27#define F12_WAIT_TIME (3 * WAIT_HZ) /* 3 seconds. Used only if logo disabled. */
28
29#include <VBox/bioslogo.h>
30
31/**
32 * Set video mode (VGA).
33 * @params New video mode.
34 */
35void set_mode(uint8_t mode);
36#pragma aux set_mode = \
37 "mov ah, 0" \
38 "int 10h" \
39 parm [al] modify [ax] nomemory;
40
41
42/**
43 * Set VESA video mode.
44 * @params New video mode.
45 */
46uint16_t vesa_set_mode(uint16_t mode);
47#pragma aux vesa_set_mode = \
48 "mov ax, 4F02h" \
49 "int 10h" \
50 parm [bx] modify [ax] nomemory;
51
52
53/**
54 * Check for keystroke.
55 * @returns True if keystroke available, False if not.
56 */
57//@todo: INT 16h should already be returning the right value in al; could also use setz
58uint8_t check_for_keystroke(void);
59#pragma aux check_for_keystroke = \
60 "mov ax, 100h" \
61 "int 16h" \
62 "jz no_key" \
63 "mov al, 1" \
64 "jmp done" \
65 "no_key:" \
66 "xor al, al" \
67 "done:" \
68 modify [ax] nomemory;
69
70
71/**
72 * Get keystroke.
73 * @returns BIOS scan code.
74 */
75uint8_t get_keystroke(void);
76#pragma aux get_keystroke = \
77 "xor ax, ax" \
78 "int 16h" \
79 "xchg ah, al" \
80 modify [ax] nomemory;
81
82
83//@todo: This whole business with reprogramming the PIT is rather suspect.
84// The BIOS already has waiting facilities in INT 15h (fn 83h, 86h) which
85// should be utilized instead.
86
87// Set the timer to 16ms ticks (64K / (Hz / (PIT_HZ / 64K)) = count).
88void wait_init(void);
89#pragma aux wait_init = \
90 "mov al, 34h" \
91 "out 43h, al" \
92 "mov al, 0D3h" \
93 "out 40h, al" \
94 "mov al, 048h" \
95 "out 40h, al" \
96 modify [ax] nomemory;
97
98//@todo: using this private interface is not great
99extern void rtc_post(void);
100#pragma aux rtc_post "*";
101
102/* Restore the timer to the default 18.2Hz. Reinitialize the tick
103 * and rollover counts since we've screwed them up by running the
104 * timer at WAIT_HZ for a while.
105 */
106void wait_uninit(void);
107#pragma aux wait_uninit = \
108 ".386" \
109 "mov al, 34h" \
110 "out 43h, al" \
111 "xor ax, ax" \
112 "out 40h, al" \
113 "out 40h, al" \
114 "pushad" \
115 "push ds" \
116 "mov ds, ax" \
117 "call rtc_post" \
118 "pop ds" \
119 "popad" \
120 modify [ax] nomemory;
121
122
123/**
124 * Waits (sleeps) for the given number of ticks.
125 * Checks for keystroke.
126 *
127 * @returns BIOS scan code if available, 0 if not.
128 * @param ticks Number of ticks to sleep.
129 * @param stop_on_key Whether to stop immediately upon keypress.
130 */
131uint8_t wait(uint16_t ticks, uint8_t stop_on_key)
132{
133 long ticks_to_wait, delta;
134 uint16_t old_flags;
135 uint32_t prev_ticks, t;
136 uint8_t scan_code = 0;
137
138 /*
139 * We may or may not be called with interrupts disabled. For the duration
140 * of this function, interrupts must be enabled.
141 */
142 old_flags = int_query();
143 int_enable();
144
145 /*
146 * The 0:046c wraps around at 'midnight' according to a 18.2Hz clock.
147 * We also have to be careful about interrupt storms.
148 */
149 ticks_to_wait = ticks;
150 prev_ticks = read_dword(0x0, 0x46c);
151 do
152 {
153 halt();
154 t = read_dword(0x0, 0x46c);
155 if (t > prev_ticks)
156 {
157 delta = t - prev_ticks; /* The temp var is required or bcc screws up. */
158 ticks_to_wait -= delta;
159 }
160 else if (t < prev_ticks)
161 ticks_to_wait -= t; /* wrapped */
162 prev_ticks = t;
163
164 if (check_for_keystroke())
165 {
166 scan_code = get_keystroke();
167 bios_printf(BIOS_PRINTF_INFO, "Key pressed: %x\n", scan_code);
168 if (stop_on_key)
169 return scan_code;
170 }
171 } while (ticks_to_wait > 0);
172 int_restore(old_flags);
173 return scan_code;
174}
175
176uint8_t read_logo_byte(uint8_t offset)
177{
178 outw(LOGO_IO_PORT, LOGO_CMD_SET_OFFSET | offset);
179 return inb(LOGO_IO_PORT);
180}
181
182uint16_t read_logo_word(uint8_t offset)
183{
184 outw(LOGO_IO_PORT, LOGO_CMD_SET_OFFSET | offset);
185 return inw(LOGO_IO_PORT);
186}
187
188// Hide cursor, clear screen and move cursor to starting position
189void clear_screen(void);
190#pragma aux clear_screen = \
191 "mov ax, 100h" \
192 "mov cx, 1000h" \
193 "int 10h" \
194 "mov ax, 700h" \
195 "mov bh, 7" \
196 "xor cx, cx" \
197 "mov dx, 184Fh" \
198 "int 10h" \
199 "mov ax, 200h" \
200 "xor bx, bx" \
201 "xor dx, dx" \
202 "int 10h" \
203 modify [ax bx cx dx] nomemory;
204
205void print_detected_harddisks(void)
206{
207 uint16_t ebda_seg=read_word(0x0040,0x000E);
208 uint8_t hd_count;
209 uint8_t hd_curr = 0;
210 uint8_t ide_ctrl_printed = 0;
211 uint8_t sata_ctrl_printed = 0;
212 uint8_t scsi_ctrl_printed = 0;
213 uint8_t device;
214
215 hd_count = read_byte(ebda_seg, (uint16_t)&EbdaData->ata.hdcount);
216
217 for (hd_curr = 0; hd_curr < hd_count; hd_curr++)
218 {
219 device = read_byte(ebda_seg, (uint16_t)&EbdaData->ata.hdidmap[hd_curr]);
220
221#ifdef VBOX_WITH_SCSI
222 if (!VBOX_IS_SCSI_DEVICE(device))
223#endif
224 {
225
226 if ((device < 4) && (ide_ctrl_printed == 0))
227 {
228 printf("IDE controller:\n");
229 ide_ctrl_printed = 1;
230 }
231 else if ((device >= 4) && (sata_ctrl_printed == 0))
232 {
233 printf("\n\nAHCI controller:\n");
234 sata_ctrl_printed = 1;
235 }
236
237 printf("\n %d) ", hd_curr+1);
238
239 /*
240 * If actual_device is bigger than or equal 4
241 * this is the next controller and
242 * the positions start at the beginning.
243 */
244 if (device >= 4)
245 device -= 4;
246
247 if (device / 2)
248 printf("Secondary ");
249 else
250 printf("Primary ");
251
252 if (device % 2)
253 printf("Slave");
254 else
255 printf("Master");
256 }
257#ifdef VBOX_WITH_SCSI
258 else
259 {
260 if (scsi_ctrl_printed == 0)
261 {
262 printf("\n\nSCSI controller:\n");
263 scsi_ctrl_printed = 1;
264 }
265
266 printf("\n %d) Hard disk", hd_curr+1);
267
268 }
269#endif
270 }
271
272 if ( (ide_ctrl_printed == 0)
273 && (sata_ctrl_printed == 0)
274 && (scsi_ctrl_printed == 0))
275 printf("No hard disks found");
276
277 printf("\n");
278}
279
280uint8_t get_boot_drive(uint8_t scode)
281{
282 uint16_t ebda_seg=read_word(0x0040,0x000E);
283
284 /* Check that the scan code is in the range of detected hard disks. */
285 uint8_t hd_count = read_byte(ebda_seg, (uint16_t)&EbdaData->ata.hdcount);
286
287 /* The key '1' has scancode 0x02 which represents the first disk */
288 scode -= 2;
289
290 if (scode < hd_count)
291 return scode;
292
293 /* Scancode is higher than number of available devices */
294 return 0xff;
295}
296
297void show_logo(void)
298{
299 uint16_t ebda_seg = read_word(0x0040,0x000E);
300 uint8_t f12_pressed = 0;
301 uint8_t scode;
302 uint16_t tmp, i;
303
304 LOGOHDR *logo_hdr = 0;
305 uint8_t is_fade_in, is_fade_out, uBootMenu;
306 uint16_t logo_time;
307
308
309 // Set PIT to 1ms ticks
310 wait_init();
311
312
313 // Get main signature
314 tmp = read_logo_word((uint8_t)&logo_hdr->u16Signature);
315 if (tmp != 0x66BB)
316 goto done;
317
318 // Get options
319 is_fade_in = read_logo_byte((uint8_t)&logo_hdr->fu8FadeIn);
320 is_fade_out = read_logo_byte((uint8_t)&logo_hdr->fu8FadeOut);
321 logo_time = read_logo_word((uint8_t)&logo_hdr->u16LogoMillies);
322 uBootMenu = read_logo_byte((uint8_t)&logo_hdr->fu8ShowBootMenu);
323
324 // Is Logo disabled?
325 if (!is_fade_in && !is_fade_out && !logo_time)
326 goto done;
327
328 // Set video mode #0x142 640x480x32bpp
329 vesa_set_mode(0x142);
330
331 if (is_fade_in)
332 {
333 for (i = 0; i <= LOGO_SHOW_STEPS; i++)
334 {
335 outw(LOGO_IO_PORT, LOGO_CMD_SHOW_BMP | i);
336 scode = wait(16 / WAIT_MS, 0);
337 if (scode == F12_SCAN_CODE)
338 {
339 f12_pressed = 1;
340 break;
341 }
342 }
343 }
344 else
345 outw(LOGO_IO_PORT, LOGO_CMD_SHOW_BMP | LOGO_SHOW_STEPS);
346
347 // Wait (interval in milliseconds)
348 if (!f12_pressed)
349 {
350 scode = wait(logo_time / WAIT_MS, 1);
351 if (scode == F12_SCAN_CODE)
352 f12_pressed = 1;
353 }
354
355 // Fade out (only if F12 was not pressed)
356 if (is_fade_out && !f12_pressed)
357 {
358 for (i = LOGO_SHOW_STEPS; i > 0 ; i--)
359 {
360 outw(LOGO_IO_PORT, LOGO_CMD_SHOW_BMP | i);
361 scode = wait(16 / WAIT_MS, 0);
362 if (scode == F12_SCAN_CODE)
363 {
364 f12_pressed = 1;
365 break;
366 }
367 }
368 }
369
370done:
371 // Clear forced boot drive setting.
372 write_byte(ebda_seg, (uint16_t)&EbdaData->uForceBootDevice, 0);
373
374 // Don't restore previous video mode
375 // The default text mode should be set up. (defect #1235)
376 set_mode(0x0003);
377
378 // If Setup menu enabled
379 if (uBootMenu)
380 {
381 // If the graphics logo disabled
382 if (!is_fade_in && !is_fade_out && !logo_time)
383 {
384 if (uBootMenu == 2)
385 printf("Press F12 to select boot device.\n");
386
387 // if the user has pressed F12 don't wait here
388 if (!f12_pressed)
389 {
390 // Wait for timeout or keystroke
391 scode = wait(F12_WAIT_TIME, 1);
392 if (scode == F12_SCAN_CODE)
393 f12_pressed = 1;
394 }
395 }
396
397 // If F12 pressed, show boot menu
398 if (f12_pressed)
399 {
400 uint8_t boot_device = 0;
401 uint8_t boot_drive = 0;
402
403 clear_screen();
404
405 // Show menu. Note that some versions of bcc freak out if we split these strings.
406 printf("\nVirtualBox temporary boot device selection\n\nDetected Hard disks:\n\n");
407 print_detected_harddisks();
408 printf("\nOther boot devices:\n f) Floppy\n c) CD-ROM\n l) LAN\n\n b) Continue booting\n");
409
410
411
412 // Wait for keystroke
413 for (;;)
414 {
415 do
416 {
417 scode = wait(WAIT_HZ, 1);
418 } while (scode == 0);
419
420 if (scode == 0x30)
421 {
422 // 'b' ... continue
423 break;
424 }
425
426 // Check if hard disk was selected
427 if ((scode >= 0x02) && (scode <= 0x09))
428 {
429 boot_drive = get_boot_drive(scode);
430
431 /*
432 * 0xff indicates that there is no mapping
433 * from the scan code to a hard drive.
434 * Wait for next keystroke.
435 */
436 if (boot_drive == 0xff)
437 continue;
438
439 write_byte(ebda_seg, (uint16_t)&EbdaData->uForceBootDrive, boot_drive);
440 boot_device = 0x02;
441 break;
442 }
443
444 switch (scode)
445 {
446 case 0x21:
447 // Floppy
448 boot_device = 0x01;
449 break;
450 case 0x2e:
451 // CD-ROM
452 boot_device = 0x03;
453 break;
454 case 0x26:
455 // LAN
456 boot_device = 0x04;
457 break;
458 }
459
460 if (boot_device != 0)
461 break;
462 }
463
464 write_byte(ebda_seg, (uint16_t)&EbdaData->uForceBootDevice, boot_device);
465
466 // Switch to text mode. Clears screen and enables cursor again.
467 set_mode(0x0003);
468 }
469 }
470
471 // Restore PIT ticks
472 wait_uninit();
473
474 return;
475}
476
477
478void delay_boot(uint16_t secs)
479{
480 uint16_t i;
481
482 if (!secs)
483 return;
484
485 // Set PIT to 1ms ticks
486 wait_init();
487
488 printf("Delaying boot for %d seconds:", secs);
489 for (i = secs; i > 0; i--)
490 {
491 printf(" %d", i);
492 wait(WAIT_HZ, 0);
493 }
494 printf("\n");
495 // Restore PIT ticks
496 wait_uninit();
497}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use