#define COMPRESS_NONE 0 #define COMPRESS_RLE8 1 #define COMPRESS_RLE4 2 #define BMP_HEADER_OS21 12 #define BMP_HEADER_OS22 64 #define BMP_HEADER_WIN3 40 #define F12_SCAN_CODE 0x86 #define F12_WAIT_TIME 3 * 1000 /* Milliseconds, used only if logo disabled */ typedef struct { Bit8u Blue; Bit8u Green; Bit8u Red; } RGBPAL; /* BMP File Format Bitmap Header. */ typedef struct { Bit16u Type; /* File Type Identifier */ Bit32u FileSize; /* Size of File */ Bit16u Reserved1; /* Reserved (should be 0) */ Bit16u Reserved2; /* Reserved (should be 0) */ Bit32u Offset; /* Offset to bitmap data */ } BMPINFO; /* OS/2 1.x Information Header Format. */ typedef struct { Bit32u Size; /* Size of Remianing Header */ Bit16u Width; /* Width of Bitmap in Pixels */ Bit16u Height; /* Height of Bitmap in Pixels */ Bit16u Planes; /* Number of Planes */ Bit16u BitCount; /* Color Bits Per Pixel */ } OS2HDR; /* OS/2 2.0 Information Header Format. */ typedef struct { Bit32u Size; /* Size of Remianing Header */ Bit32u Width; /* Width of Bitmap in Pixels */ Bit32u Height; /* Height of Bitmap in Pixels */ Bit16u Planes; /* Number of Planes */ Bit16u BitCount; /* Color Bits Per Pixel */ Bit32u Compression; /* Compression Scheme (0=none) */ Bit32u SizeImage; /* Size of bitmap in bytes */ Bit32u XPelsPerMeter; /* Horz. Resolution in Pixels/Meter */ Bit32u YPelsPerMeter; /* Vert. Resolution in Pixels/Meter */ Bit32u ClrUsed; /* Number of Colors in Color Table */ Bit32u ClrImportant; /* Number of Important Colors */ Bit16u Units; /* Resolution Mesaurement Used */ Bit16u Reserved; /* Reserved FIelds (always 0) */ Bit16u Recording; /* Orientation of Bitmap */ Bit16u Rendering; /* Halftone Algorithm Used on Image */ Bit32u Size1; /* Halftone Algorithm Data */ Bit32u Size2; /* Halftone Algorithm Data */ Bit32u ColorEncoding; /* Color Table Format (always 0) */ Bit32u Identifier; /* Misc. Field for Application Use */ } OS22HDR; /* Windows 3.x Information Header Format. */ typedef struct { Bit32u Size; /* Size of Remianing Header */ Bit32u Width; /* Width of Bitmap in Pixels */ Bit32u Height; /* Height of Bitmap in Pixels */ Bit16u Planes; /* Number of Planes */ Bit16u BitCount; /* Bits Per Pixel */ Bit32u Compression; /* Compression Scheme (0=none) */ Bit32u SizeImage; /* Size of bitmap in bytes */ Bit32u XPelsPerMeter; /* Horz. Resolution in Pixels/Meter */ Bit32u YPelsPerMeter; /* Vert. Resolution in Pixels/Meter */ Bit32u ClrUsed; /* Number of Colors in Color Table */ Bit32u ClrImportant; /* Number of Important Colors */ } WINHDR; // Logo settings header typedef struct { Bit16u Signature; Bit8u FadeIn; Bit8u FadeOut; Bit16u LogoTime; Bit8u ShowBootMenu; Bit32u LogoSize; } LOGOHDR; // Width and height of the "Press F12 to select boot device." bitmap. Anything // that exceeds the limit of F12BootText below is filled with background. #define F12BOOTTEXTWIDTH 284 #define F12BOOTTEXTHEIGHT 13 // "Press F12 to select boot device." bitmap. Bit8u F12BootText[] = { 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x0C, 0x3E, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x20, 0x00, 0x70, 0x00, 0x00, 0x00, 0x04, 0x00, 0x70, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0xE1, 0x30, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x60, 0x00, 0x00, 0x06, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x11, 0x0F, 0x60, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x30, 0x00, 0x60, 0x00, 0x00, 0x00, 0x06, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x66, 0x87, 0x0F, 0x1F, 0x3E, 0x00, 0x58, 0xC0, 0x00, 0x03, 0xC0, 0x0F, 0x1F, 0x00, 0x7C, 0xF8, 0xC0, 0xE0, 0xC3, 0xC7, 0x0F, 0x00, 0x1E, 0x7C, 0xF8, 0xF8, 0x01, 0x80, 0x87, 0x8F, 0x61, 0x1C, 0x7C, 0xF8, 0x00, 0x3E, 0xDC, 0x8C, 0x19, 0x33, 0x06, 0x80, 0x07, 0x0C, 0x18, 0x00, 0x30, 0x18, 0x03, 0x60, 0xCC, 0x18, 0x0C, 0x63, 0xC6, 0x30, 0x00, 0x60, 0x63, 0xCC, 0x18, 0x06, 0x00, 0x6C, 0x8C, 0x19, 0x86, 0x61, 0xCC, 0x18, 0x60, 0xC0, 0xCC, 0x1F, 0x03, 0x06, 0x00, 0x58, 0xC0, 0xC0, 0x00, 0x00, 0x83, 0x31, 0x00, 0x0C, 0xFC, 0xC1, 0xF0, 0x67, 0x00, 0x03, 0x00, 0x66, 0xC6, 0x8C, 0x61, 0x00, 0x60, 0xC6, 0x9F, 0x61, 0x18, 0x06, 0xFC, 0x01, 0x06, 0x0C, 0x0C, 0xE0, 0xC0, 0x01, 0x80, 0x01, 0x0C, 0x06, 0x00, 0x30, 0x18, 0x03, 0x80, 0xC3, 0x00, 0x0C, 0x03, 0x06, 0x30, 0x00, 0x60, 0x66, 0xCC, 0x18, 0x06, 0x00, 0x66, 0x0C, 0x18, 0x86, 0x61, 0xC0, 0x00, 0x60, 0xC0, 0xC0, 0x00, 0x18, 0x30, 0x00, 0x18, 0xC0, 0x30, 0x00, 0x00, 0x83, 0x31, 0x00, 0x60, 0x0C, 0xC0, 0x30, 0x60, 0x00, 0x03, 0x00, 0x66, 0xC6, 0x8C, 0x61, 0x00, 0x60, 0xC6, 0x00, 0x33, 0x18, 0x06, 0x0C, 0x00, 0x06, 0x0C, 0x8C, 0x19, 0x33, 0x06, 0x80, 0x01, 0x0C, 0x63, 0x00, 0xB0, 0x19, 0x03, 0x60, 0xCC, 0x18, 0x0C, 0x63, 0xC6, 0xB0, 0x01, 0x60, 0x66, 0xCC, 0x18, 0x36, 0x00, 0x66, 0x8C, 0xE1, 0x81, 0x61, 0xCC, 0x18, 0xFC, 0xE0, 0x81, 0x0F, 0x1F, 0x3E, 0x00, 0x3C, 0xF0, 0xF3, 0x07, 0x00, 0x0E, 0x1F, 0x00, 0x7C, 0xF8, 0xE0, 0xE1, 0xC3, 0x07, 0x0E, 0x00, 0x3E, 0x7C, 0xF8, 0xC0, 0x01, 0xC0, 0x8D, 0x0F, 0x0C, 0x3C, 0x7C, 0xF8, 0xC0 }; static unsigned char get_mode(); static void set_mode(); static Bit8u wait(ms); static void write_pixel(); /** * Get current video mode (VGA). * @returns Video mode. */ unsigned char get_mode() { ASM_START push bp mov bp, sp push bx mov ax, #0x0F00 int #0x10 pop bx pop bp ASM_END } /** * Set video mode (VGA). * @params New video mode. */ void set_mode(mode) Bit8u mode; { ASM_START push bp mov bp, sp push ax mov ah, #0 mov al, 4[bp] ; mode int #0x10 pop ax pop bp ASM_END } /** * Set VESA video mode. * @params New video mode. */ Bit16u vesa_set_mode(mode) Bit16u mode; { ASM_START push bp mov bp, sp push bx mov ax, #0x4f02 mov bx, 4[bp] ; mode int #0x10 pop bx pop bp ASM_END } /** * Check for keystroke. * @returns True if keystroke available, False if not. */ Bit8u check_for_keystroke() { ASM_START mov ax, #0x100 int #0x16 jz no_key mov al, #1 jmp done no_key: xor al, al done: ASM_END } /** * Get keystroke. * @returns BIOS scan code. */ Bit8u get_keystroke() { ASM_START mov ax, #0x0 int #0x16 xchg ah, al ASM_END } void wait_init() { // The default is 18.2 ticks per second (~55ms tick interval). // Set the timer to 1ms ticks (65536 / (Hz / 18.2)). ASM_START mov al, #0x34 ; timer0: binary count, 16bit count, mode 2 out 0x43, al mov al, #0xA9 ; Low byte out 0x40, al mov al, #0x04 ; High byte out 0x40, al ASM_END } void wait_uninit() { ASM_START pushf cli /* Restore the timer to the default 18.2Hz. */ mov al, #0x34 ; timer0: binary count, 16bit count, mode 2 out 0x43, al xor ax, ax ; maximum count of 0000H = 18.2Hz out 0x40, al out 0x40, al /* * Reinitialize the tick and rollover counts since we've * screwed them up by running the timer at 1000HZ for a while. */ pushad push ds mov ds, ax ; already 0 call timer_tick_post pop ds popad popf ASM_END } /** * Waits (sleeps) for the given number of milliseconds. * Checks for keystroke. * * @returns BIOS scan code if available, 0 if not. * @param ms Number of milliseconds to sleep. */ Bit8u wait(ms) Bit16u ms; { long ticks_to_wait, delta; Bit32u prev_ticks, t; Bit8u scan_code = 0; /* * The 0:046c wraps around at 'midnight' according to a 18.2Hz clock. * We also have to be careful about interrupt storms. */ ASM_START pushf sti ASM_END ticks_to_wait = ms; prev_ticks = read_dword(0x0, 0x46c); do { ASM_START hlt ASM_END t = read_dword(0x0, 0x46c); if (t > prev_ticks) { delta = t - prev_ticks; /* The temp var is required or bcc screws up. */ ticks_to_wait -= delta; } else if (t < prev_ticks) ticks_to_wait -= t; /* wrapped */ prev_ticks = t; if (check_for_keystroke()) { scan_code = get_keystroke(); bios_printf(BIOS_PRINTF_INFO, "Key pressed: %x\n", scan_code); } } while (ticks_to_wait > 0); ASM_START popf ASM_END return scan_code; } void write_pixel(x,y,color) unsigned short x; unsigned short y; unsigned char color; { ASM_START push bp mov bp, sp push ax push bx push cx push dx mov ah, #0x0C xor bh, bh mov al, 8[bp] ; color mov cx, 4[bp] ; x mov dx, 6[bp] ; y int #0x10 pop dx pop cx pop bx pop ax pop bp ASM_END } void read_palette(bmp_seg, pal_seg, bmp_off, size, type) Bit16u bmp_seg; Bit16u pal_seg; Bit16u bmp_off; Bit16u size; Bit16u type; { Bit16u i; RGBPAL *palette; palette = 0; for (i = 0; i < size; i++) { Bit8u pal; pal = read_byte(bmp_seg, bmp_off); write_byte(pal_seg, &palette->Blue, pal); bmp_off++; pal = read_byte(bmp_seg, bmp_off); write_byte(pal_seg, &palette->Green, pal); bmp_off++; pal = read_byte(bmp_seg, bmp_off); write_byte(pal_seg, &palette->Red, pal); bmp_off++; if (type != BMP_HEADER_OS21) { // Skip 4th byte bmp_off++; } *palette++; } } void set_dark_palette(palette_size) Bit16u palette_size; { Bit16u i; // Set bitmap palette (dark) outb(0x03c8, palette_size); for (i = 0; i < palette_size; i++) { outb(0x03c8, i); outb(0x03c9, 0); outb(0x03c9, 0); outb(0x03c9, 0); } } void set_bitmap_palette(palette_seg, palette_size) Bit16u palette_seg; Bit16u palette_size; { RGBPAL *palette; Bit16u i; palette = 0; outb(0x03c6, palette_size); for (i = 0; i < palette_size; i++) { Bit8u b; outb(0x03c8, i); b = read_byte(palette_seg, &palette->Red); outb(0x03c9, b >> 2); b = read_byte(palette_seg, &palette->Green); outb(0x03c9, b >> 2); b = read_byte(palette_seg, &palette->Blue); outb(0x03c9, b >> 2); *palette++; } } /** * Fade in and check for keystroke. * @returns BIOS scan code if available, 0 if not. */ Bit8u fade_in(palette_seg, palette_size) Bit16u palette_seg; Bit16u palette_size; { RGBPAL *palette; Bit16u i, j; Bit8u scode, scan_code = 0; // Fade in for (i = 0; i < 0x3F; i++) { outb(0x03c6, palette_size); palette = 0; for (j = 0; j < palette_size; j++) { Bit8u r, g, b; r = read_byte(palette_seg, &palette->Red) >> 2; g = read_byte(palette_seg, &palette->Green) >> 2; b = read_byte(palette_seg, &palette->Blue) >> 2; if (r > 0 && r >= i) r = i; if (g > 0 && g >= i) g = i; if (b > 0 && b >= i) b = i; outb(0x03c8, j); outb(0x03c9, r); outb(0x03c9, g); outb(0x03c9, b); *palette++; } scode = wait(15); if (scode) scan_code = scode; } return scan_code; } /** * Fade out and check for keystroke. * @returns BIOS scan code if available, 0 if not. */ Bit8u fade_out(palette_seg, palette_size) Bit16u palette_seg; Bit16u palette_size; { RGBPAL *palette; Bit16u i, j; Bit8u scode, scan_code = 0; // Fade out for (i = 0x3F; i > 0; i--) { outb(0x03c6, palette_size); palette = 0; for (j = 0; j < palette_size; j++) { Bit8u r, g, b; r = read_byte(palette_seg, &palette->Red) >> 2; g = read_byte(palette_seg, &palette->Green) >> 2; b = read_byte(palette_seg, &palette->Blue) >> 2; if (r > 0 && r >= i) r = i; if (g > 0 && g >= i) g = i; if (b > 0 && b >= i) b = i; outb(0x03c8, j); outb(0x03c9, r); outb(0x03c9, g); outb(0x03c9, b); *palette++; } scode = wait(15); if (scode) scan_code = scode; } return scan_code; } void vesa_set_bank(bank) Bit16u bank; { ASM_START push bp mov bp, sp push bx push dx mov ax, #0x4f05 xor bx, bx mov dx, 4[bp] ; bank int #0x10 pop dx pop bx pop bp ASM_END } #define VID_SEG 0xA000 #define ROM_SEG 0xD000 #define TMP_SEG 0x1000 void show_logo() { Bit16u ebda_seg=read_word(0x0040,0x000E); LOGOHDR *logo_hdr; BMPINFO *bmp_info; OS2HDR *os2_head; OS22HDR *os22_head; WINHDR *win_head; Bit16u rom_seg, bmp_seg, pal_seg, logo_hdr_size, tmp, i; Bit32u hdr_size; Bit8u vid_mode; Bit8u is_fade_in, is_fade_out, is_logo_failed, uBootMenu; Bit16u logo_time; Bit32u offset; Bit16u bank = 0; Bit8u logo_bank = 0; Bit16u address; Bit8u scode, scan_code = 0; Bit8u c; // Set PIT to 1ms ticks wait_init(); is_logo_failed = 0; // Switch to ROM bank 0 write_byte(ROM_SEG, 0, logo_bank); rom_seg = bmp_seg = ROM_SEG; logo_hdr = 0; logo_hdr_size = sizeof(LOGOHDR); // Get main signature tmp = read_word(rom_seg, &logo_hdr->Signature); if (tmp != 0x66BB) goto done; // Get options is_fade_in = read_byte(rom_seg, &logo_hdr->FadeIn); is_fade_out = read_byte(rom_seg, &logo_hdr->FadeOut); logo_time = read_word(rom_seg, &logo_hdr->LogoTime); uBootMenu = read_byte(rom_seg, &logo_hdr->ShowBootMenu); // Is Logo disabled? if (!is_fade_in && !is_fade_out && !logo_time) goto done; show_bmp: // Set offset of bitmap header bmp_info = logo_hdr_size; os2_head = os22_head = win_head = logo_hdr_size + sizeof(BMPINFO); // Check bitmap ID tmp = read_word(rom_seg, &bmp_info->Type); if (tmp != 0x4D42) // 'BM' { goto error; } else { Bit16u scr_width, scr_height, start_x, start_y, bmp_data, j; Bit16u width, height, compr, clr_used; Bit16u pad_bytes, depth, planes, palette_size, palette_data; Bit16u bidx, didx; signed x, y; // Check the size of the information header that indicates // the structure type hdr_size = read_dword(bmp_seg, &win_head->Size); if (hdr_size == BMP_HEADER_OS21) // OS2 1.x header { width = read_word(bmp_seg, &os2_head->Width); height = read_word(bmp_seg, &os2_head->Height); planes = read_word(bmp_seg, &os2_head->Planes); depth = read_word(bmp_seg, &os2_head->BitCount); compr = COMPRESS_NONE; clr_used = 0; } else if (hdr_size == BMP_HEADER_OS22) // OS2 2.0 header { width = read_word(bmp_seg, &os22_head->Width); height = read_word(bmp_seg, &os22_head->Height); planes = read_word(bmp_seg, &os22_head->Planes); depth = read_word(bmp_seg, &os22_head->BitCount); compr = read_word(bmp_seg, &os22_head->Compression); clr_used = read_word(bmp_seg, &os22_head->ClrUsed); } else if (hdr_size == BMP_HEADER_WIN3) // Windows 3.x header { width = read_word(bmp_seg, &win_head->Width); height = read_word(bmp_seg, &win_head->Height); planes = read_word(bmp_seg, &win_head->Planes); depth = read_word(bmp_seg, &win_head->BitCount); compr = read_word(bmp_seg, &win_head->Compression); clr_used = read_word(bmp_seg, &win_head->ClrUsed); } else goto error; // Test some bitmap fields if (width > 640 || height > 480) goto error; if (planes != 1) goto error; if (depth < 4 || depth > 8) goto error; if (clr_used > 256) goto error; // Bitmap processing if (compr != COMPRESS_NONE) goto error; // Screen size scr_width = 640; scr_height = 480; // Center of screen start_x = (scr_width - width) / 2; start_y = (scr_height - height) / 2; // Read palette if (hdr_size == BMP_HEADER_OS21) { palette_size = (Bit16u) (1 << (planes * depth)); } else if (hdr_size == BMP_HEADER_WIN3 || hdr_size == BMP_HEADER_OS22) { if (clr_used) palette_size = clr_used; else palette_size = (Bit16u) (1 << (planes * depth)); } pal_seg = TMP_SEG; palette_data = logo_hdr_size + sizeof(BMPINFO) + hdr_size; read_palette(bmp_seg, pal_seg, palette_data, palette_size, hdr_size); // Get current video mode vid_mode = get_mode(); // Set video mode #0x101 640x480x8bpp vesa_set_mode(0x101); // Set dark/bitmap palette if (is_fade_in) set_dark_palette(palette_size); else set_bitmap_palette(pal_seg, palette_size); // 0 bank vesa_set_bank(0); // Show bitmap tmp = read_word(bmp_seg, &bmp_info->Offset); bmp_data = logo_hdr_size + tmp; switch(depth) { case 4: // Compute padding bytes if (((width % 8) == 0) || ((width % 8) > 6)) pad_bytes = 0; else if ((width % 8) <= 2) pad_bytes = 3; else if ((width % 8) <= 4) pad_bytes = 2; else pad_bytes = 1; // For 4 bits per pixel, each byte is two pixels. // The upper half go to the first pixel, // and the lower half to the second. for (y = height; y > 0; y--) { Bit8u z; for (x = 0; x < width; x += 2) { Bit8u c; c = read_byte(bmp_seg, bmp_data++); if (bmp_data == 0xffff) { bmp_data = 0; write_byte(ROM_SEG, 0, ++logo_bank); } for (z = 0; z < 2; z++) { Bit8u color; Bit16u new_bank; offset = (((Bit32u)start_y + (Bit32u)y) * (Bit32u)scr_width) + ((Bit32u)start_x + (Bit32u)x + (Bit32u)z); new_bank = (offset >> 16); address = (Bit16u)(offset & 0xffffL); if (bank != new_bank) { bank = new_bank; vesa_set_bank(bank); } if (z & 1) color = c & 0xF; else color = (c >> 4) & 0xF; write_byte(VID_SEG, address, color); } } for (z = 0; z < pad_bytes; z++) { if (++bmp_data == 0xffff) { bmp_data = 0; write_byte(ROM_SEG, 0, ++logo_bank); } } } break; case 8: // Compute padding bytes pad_bytes = ((width % 4) == 0) ? 0 : (4 - (width % 4)); // For 8 bits per pixel, each byte is one pixel. for (y = height; y > 0; y--) { Bit8u z; for (x = 0; x < width; x++) { Bit8u c, z; Bit16u new_bank; c = read_byte(bmp_seg, bmp_data++); if (bmp_data == 0xffff) { bmp_data = 0; write_byte(ROM_SEG, 0, ++logo_bank); } offset = (((Bit32u)start_y + (Bit32u)y) * (Bit32u)scr_width) + ((Bit32u)start_x + (Bit32u)x); new_bank = (offset >> 16); address = (Bit16u)(offset & 0xffffL); if (bank != new_bank) { bank = new_bank; vesa_set_bank(bank); } write_byte(VID_SEG, address, c); } for (z = 0; z < pad_bytes; z++) { if (++bmp_data == 0xffff) { bmp_data = 0; write_byte(ROM_SEG, 0, ++logo_bank); } } } break; #if 0 // 24bpp bitmaps are unsupported case 24: // Compute padding bytes pad_bytes = width % 4; // For 24 bits per pixel it's RGB structure. for (y = height; y > 0; y--) { Bit8u z; for (x = 0; x < width; x++) { for (z = 0; z < 3; z++) { Bit8u color; Bit16u new_bank; color = read_byte(bmp_seg, bmp_data++); if (bmp_data == 0xffff) { bmp_data = 0; write_byte(ROM_SEG, 0, ++logo_bank); } offset = (((Bit32u)start_y + (Bit32u)y) * (Bit32u)scr_width*3) + (((Bit32u)start_x + (Bit32u)x) * (Bit32u)3 + z); new_bank = (offset >> 16); address = (Bit16u)(offset & 0xffffL); if (bank != new_bank) { bank = new_bank; vesa_set_bank(bank); } write_byte(VID_SEG, address, color); } } for (z = 0; z < pad_bytes; z++) { if (++bmp_data == 0xffff) { bmp_data = 0; write_byte(ROM_SEG, 0, ++logo_bank); } } } break; #endif } // If Setup menu enabled if (uBootMenu == 2 && (is_fade_in || is_fade_out || logo_time)) { RGBPAL *palette = 0; Bit16u blum, dlum; // Get the brightest and the darkest palette indexes bidx = didx = blum = 0; dlum = 3 * 0xff; for (i = 0; i < palette_size; i++) { Bit8u r, g, b; Bit16u lum; r = read_byte(pal_seg, &palette->Red) >> 2; g = read_byte(pal_seg, &palette->Green) >> 2; b = read_byte(pal_seg, &palette->Blue) >> 2; lum = (Bit16u)r + (Bit16u)g + (Bit16u)b; if (lum > blum) { blum = lum; bidx = i; } if (lum < dlum) { dlum = lum; didx = i; } *palette++; } // 0 bank vesa_set_bank(0); // Top-left corner of screen start_x = 340; start_y = 450; // Image size width = (start_x + F12BOOTTEXTWIDTH <= scr_width) ? F12BOOTTEXTWIDTH : scr_width - start_x; height = (start_y + F12BOOTTEXTHEIGHT <= scr_height) ? F12BOOTTEXTHEIGHT : scr_height - start_y; bmp_data = j = 0; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { Bit16u new_bank; Bit8u pix_idx; if (!j) { if (bmp_data < sizeof(F12BootText)) c = read_byte(0xf000, F12BootText + bmp_data++); else c = 0; } offset = (((Bit32u)start_y + (Bit32u)y) * (Bit32u)scr_width) + ((Bit32u)start_x + (Bit32u)x); new_bank = (offset >> 16); address = (Bit16u)(offset & 0xffffL); if (bank != new_bank) { bank = new_bank; vesa_set_bank(bank); } pix_idx = c & 1; c >>= 1; if (pix_idx) pix_idx = bidx; else pix_idx = didx; write_byte(VID_SEG, address, pix_idx); if (j++ >= 7) j = 0; } } } // Fade in if (is_fade_in) { scode = fade_in(pal_seg, palette_size); if (scode) scan_code = scode; } // Wait (interval in milliseconds) scode = wait(logo_time); if (scode) scan_code = scode; // Fade out if (is_fade_out) { scode = fade_out(pal_seg, palette_size); if (scode) scan_code = scode; } } // Clear video memory #if 0 // Really need to clear VESA memory? for (i = 0; i < 0x9600; i += 2) { write_word(VID_SEG, i, 0); } #endif goto done; error: if (!is_logo_failed) { is_logo_failed = 1; logo_hdr_size = 0; // Switch to ROM bank 255 (default logo) write_byte(ROM_SEG, 0, 255); goto show_bmp; } done: // Clear forced boot drive setting. write_byte(ebda_seg,&EbdaData->uForceBootDrive, 0); // Don't restore previous video mode // The default text mode should be set up. (defect #1235) set_mode(0x0003); // If Setup menu enabled if (uBootMenu) { // If the graphics logo disabled if (!is_fade_in && !is_fade_out && !logo_time) { int i; if (uBootMenu == 2) printf("Press F12 to select boot device."); // Wait for timeout or keystroke for (i = 0; i < F12_WAIT_TIME; i++) { scan_code = wait(1); if (scan_code) break; } } // If F12 pressed, show boot menu if (scan_code == F12_SCAN_CODE) { // Hide cursor, clear screen and move cursor to starting position ASM_START push bx push cx push dx mov ax, #0x100 mov cx, #0x1000 int #0x10 mov ax, #0x700 mov bh, #7 xor cx, cx mov dx, #0x184f int #0x10 mov ax, #0x200 xor bx, bx xor dx, dx int #0x10 pop dx pop cx pop bx ASM_END // Show menu printf("\n"); printf(" 1) Floppy\n"); printf(" 2) Hard Disk\n"); printf(" 3) CD-ROM\n"); printf(" 4) LAN\n\n"); printf(" 0) Continue booting\n"); // Wait for keystroke for (;;) { scan_code = wait(1); if (scan_code) break; } // Change first boot device code to selected one if (scan_code > 0x02 && scan_code <= 0x05) { write_byte(ebda_seg,&EbdaData->uForceBootDrive, scan_code-1); } // Switch to text mode. Clears screen and enables cursor again. set_mode(0x0003); } } // Restore PIT ticks wait_uninit(); return; } void delay_boot(secs) Bit16u secs; { Bit16u i; if (!secs) return; // Set PIT to 1ms ticks wait_init(); printf("Delaying boot for %d seconds:", secs); for (i = secs; i > 0; i--) { printf(" %d", i); wait(1000); } printf("\n"); // Restore PIT ticks wait_uninit(); }