VirtualBox

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

Last change on this file since 8618 was 8618, checked in by vboxsync, 17 years ago

New line after the F12 message.

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