Submitted By: Alexander E. Patrakov Date: 2003-11-16 Initial Package Version: 0.93 Origin: Jeremy Utley, Debian Source Archive (http.us.debian.org/debian/pool/main/g/grub/grub_0.93+cvs20031021-2.diff.gz) Description: This patch implements support for XPM Pixmaps on the grub boot screen. Pixmaps must be in XPM format, 640x480 resolution, utilizing no more than 14 colors. After this patch has been applied, it is REQUIRED to run the following: aclocal autoheader autoconf automake Note that this patch doesn't include documentation. diff -urN grub-0.93/configure.in grub-0.93+graphics/configure.in --- grub-0.93/configure.in 2002-11-30 01:12:08.000000000 +0500 +++ grub-0.93+graphics/configure.in 2003-11-16 15:50:26.000000000 +0500 @@ -54,8 +54,8 @@ _AM_DEPENDENCIES(CC) dnl Because recent automake complains about AS, set it here. -AS="$CC" -AC_SUBST(AS) +CCAS="$CC" +AC_SUBST(CCAS) AC_ARG_WITH(binutils, [ --with-binutils=DIR search the directory DIR to find binutils]) @@ -72,7 +72,8 @@ # optimization flags if test "x$ac_cv_prog_gcc" = xyes; then if test "x$default_CFLAGS" = xyes; then - CFLAGS="-g" + # Autoconf may set CFLAGS to -O2 and/or -g. So eliminate them. + CFLAGS="`echo $CFLAGS | sed -e 's/-g//g' -e 's/-O[[0-9]]//g'` -g" # If the user specify the directory for binutils, add the option `-B'. if test "x$with_binutils" != x; then CFLAGS="-B$with_binutils/ $CFLAGS" @@ -559,6 +560,11 @@ [ --enable-diskless enable diskless support]) AM_CONDITIONAL(DISKLESS_SUPPORT, test "x$enable_diskless" = xyes) +dnl Graphical splashscreen support +AC_ARG_ENABLE(graphics, + [ --disable-graphics disable graphics terminal support]) +AM_CONDITIONAL(GRAPHICS_SUPPORT, test "x$enable_graphics" != xno) + dnl Hercules terminal AC_ARG_ENABLE(hercules, [ --disable-hercules disable hercules terminal support]) @@ -619,9 +625,9 @@ AC_SUBST(NET_EXTRAFLAGS) AC_SUBST(NETBOOT_DRIVERS) -dnl Because recent automake complains about ASFLAGS, set it here. -ASFLAGS='$(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)' -AC_SUBST(ASFLAGS) +dnl Because recent automake complains about CCASFLAGS, set it here. +CCASFLAGS='$(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)' +AC_SUBST(CCASFLAGS) dnl Output. diff -urN grub-0.93/stage1/Makefile.am grub-0.93+graphics/stage1/Makefile.am --- grub-0.93/stage1/Makefile.am 2002-09-08 07:58:08.000000000 +0600 +++ grub-0.93+graphics/stage1/Makefile.am 2003-11-16 15:49:58.000000000 +0500 @@ -4,7 +4,7 @@ CLEANFILES = $(nodist_pkgdata_DATA) # We can't use builtins or standard includes. -AM_ASFLAGS = $(STAGE1_CFLAGS) -fno-builtin -nostdinc +AM_CCASFLAGS = $(STAGE1_CFLAGS) -fno-builtin -nostdinc LDFLAGS = -nostdlib -Wl,-N,-Ttext,7C00 noinst_PROGRAMS = stage1.exec diff -urN grub-0.93/stage2/asm.S grub-0.93+graphics/stage2/asm.S --- grub-0.93/stage2/asm.S 2002-12-03 04:18:56.000000000 +0500 +++ grub-0.93+graphics/stage2/asm.S 2003-11-16 15:50:26.000000000 +0500 @@ -2224,6 +2224,156 @@ pop %ebx pop %ebp ret + +/* graphics mode functions */ +#ifdef SUPPORT_GRAPHICS +VARIABLE(cursorX) +.word 0 +VARIABLE(cursorY) +.word 0 +VARIABLE(cursorCount) +.word 0 +VARIABLE(cursorBuf) +.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + + +/* + * int set_videomode(mode) + * BIOS call "INT 10H Function 0h" to set video mode + * Call with %ah = 0x0 + * %al = video mode + * Returns old videomode. + */ +ENTRY(set_videomode) + push %ebp + push %ebx + push %ecx + + movb 0x10(%esp), %cl + + call EXT_C(prot_to_real) + .code16 + + xorw %bx, %bx + movb $0xf, %ah + int $0x10 /* Get Current Video mode */ + movb %al, %ch + xorb %ah, %ah + movb %cl, %al + int $0x10 /* Set Video mode */ + + DATA32 call EXT_C(real_to_prot) + .code32 + + xorb %ah, %ah + movb %ch, %al + + pop %ecx + pop %ebx + pop %ebp + ret + + +/* + * unsigned char * graphics_get_font() + * BIOS call "INT 10H Function 11h" to set font + * Call with %ah = 0x11 + */ +ENTRY(graphics_get_font) + push %ebp + push %ebx + push %ecx + push %edx + + call EXT_C(prot_to_real) + .code16 + + movw $0x1130, %ax + movb $6, %bh /* font 8x16 */ + int $0x10 + movw %bp, %dx + movw %es, %cx + + DATA32 call EXT_C(real_to_prot) + .code32 + + xorl %eax, %eax + movw %cx, %ax + shll $4, %eax + movw %dx, %ax + + pop %edx + pop %ecx + pop %ebx + pop %ebp + ret + + + +/* + * graphics_set_palette(index, red, green, blue) + * BIOS call "INT 10H Function 10h" to set individual dac register + * Call with %ah = 0x10 + * %bx = register number + * %ch = new value for green (0-63) + * %cl = new value for blue (0-63) + * %dh = new value for red (0-63) + */ + +ENTRY(graphics_set_palette) + push %ebp + push %eax + push %ebx + push %ecx + push %edx + + movw $0x3c8, %bx /* address write mode register */ + + /* wait vertical retrace */ + + movw $0x3da, %dx +l1b: inb %dx, %al /* wait vertical active display */ + test $8, %al + jnz l1b + +l2b: inb %dx, %al /* wait vertical retrace */ + test $8, %al + jnz l2b + + mov %bx, %dx + movb 0x18(%esp), %al /* index */ + outb %al, %dx + inc %dx + + movb 0x1c(%esp), %al /* red */ + outb %al, %dx + + movb 0x20(%esp), %al /* green */ + outb %al, %dx + + movb 0x24(%esp), %al /* blue */ + outb %al, %dx + + movw 0x18(%esp), %bx + + call EXT_C(prot_to_real) + .code16 + + movb %bl, %bh + movw $0x1000, %ax + int $0x10 + + DATA32 call EXT_C(real_to_prot) + .code32 + + pop %edx + pop %ecx + pop %ebx + pop %eax + pop %ebp + ret + +#endif /* SUPPORT_GRAPHICS */ /* * getrtsecs() diff -urN grub-0.93/stage2/builtins.c grub-0.93+graphics/stage2/builtins.c --- grub-0.93/stage2/builtins.c 2002-12-04 09:41:57.000000000 +0500 +++ grub-0.93+graphics/stage2/builtins.c 2003-11-16 15:50:26.000000000 +0500 @@ -846,6 +846,138 @@ }; #endif /* SUPPORT_NETBOOT */ +static int terminal_func (char *arg, int flags); + +#ifdef SUPPORT_GRAPHICS + +static int splashimage_func(char *arg, int flags) { + char splashimage[64]; + int i; + + /* filename can only be 64 characters due to our buffer size */ + if (strlen(arg) > 63) + return 1; + if (flags == BUILTIN_CMDLINE) { + if (!grub_open(arg)) + return 1; + grub_close(); + } + + strcpy(splashimage, arg); + + /* get rid of TERM_NEED_INIT from the graphics terminal. */ + for (i = 0; term_table[i].name; i++) { + if (grub_strcmp (term_table[i].name, "graphics") == 0) { + term_table[i].flags &= ~TERM_NEED_INIT; + break; + } + } + + graphics_set_splash(splashimage); + + if (flags == BUILTIN_CMDLINE && graphics_inited) { + graphics_end(); + graphics_init(); + graphics_cls(); + } + + /* FIXME: should we be explicitly switching the terminal as a + * side effect here? */ + terminal_func("graphics", flags); + + return 0; +} + +static struct builtin builtin_splashimage = +{ + "splashimage", + splashimage_func, + BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, + "splashimage FILE", + "Load FILE as the background image when in graphics mode." +}; + + +/* foreground */ +static int +foreground_func(char *arg, int flags) +{ + if (grub_strlen(arg) == 6) { + int r = ((hex(arg[0]) << 4) | hex(arg[1])) >> 2; + int g = ((hex(arg[2]) << 4) | hex(arg[3])) >> 2; + int b = ((hex(arg[4]) << 4) | hex(arg[5])) >> 2; + + foreground = (r << 16) | (g << 8) | b; + if (graphics_inited) + graphics_set_palette(15, r, g, b); + + return (0); + } + + return (1); +} + +static struct builtin builtin_foreground = +{ + "foreground", + foreground_func, + BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, + "foreground RRGGBB", + "Sets the foreground color when in graphics mode." + "RR is red, GG is green, and BB blue. Numbers must be in hexadecimal." +}; + + +/* background */ +static int +background_func(char *arg, int flags) +{ + if (grub_strlen(arg) == 6) { + int r = ((hex(arg[0]) << 4) | hex(arg[1])) >> 2; + int g = ((hex(arg[2]) << 4) | hex(arg[3])) >> 2; + int b = ((hex(arg[4]) << 4) | hex(arg[5])) >> 2; + + background = (r << 16) | (g << 8) | b; + if (graphics_inited) + graphics_set_palette(0, r, g, b); + return (0); + } + + return (1); +} + +static struct builtin builtin_background = +{ + "background", + background_func, + BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, + "background RRGGBB", + "Sets the background color when in graphics mode." + "RR is red, GG is green, and BB blue. Numbers must be in hexadecimal." +}; + +#endif /* SUPPORT_GRAPHICS */ + + +/* clear */ +static int +clear_func() +{ + if (current_term->cls) + current_term->cls(); + + return 0; +} + +static struct builtin builtin_clear = +{ + "clear", + clear_func, + BUILTIN_CMDLINE | BUILTIN_HELP_LIST, + "clear", + "Clear the screen" +}; + /* displayapm */ static int @@ -3950,7 +4082,7 @@ }; -#if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES) +#if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES) || defined(SUPPORT_GRAPHICS) /* terminal */ static int terminal_func (char *arg, int flags) @@ -4109,17 +4241,21 @@ end: current_term = term_table + default_term; current_term->flags = term_flags; - + if (lines) max_lines = lines; else - /* 24 would be a good default value. */ - max_lines = 24; - + max_lines = current_term->max_lines; + /* If the interface is currently the command-line, restart it to repaint the screen. */ - if (current_term != prev_term && (flags & BUILTIN_CMDLINE)) + if ((current_term != prev_term) && (flags & BUILTIN_CMDLINE)){ + if (prev_term->shutdown) + prev_term->shutdown(); + if (current_term->startup) + current_term->startup(); grub_longjmp (restart_cmdline_env, 0); + } return 0; } @@ -4129,7 +4265,7 @@ "terminal", terminal_func, BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST, - "terminal [--dumb] [--no-echo] [--no-edit] [--timeout=SECS] [--lines=LINES] [--silent] [console] [serial] [hercules]", + "terminal [--dumb] [--no-echo] [--no-edit] [--timeout=SECS] [--lines=LINES] [--silent] [console] [serial] [hercules] [graphics]", "Select a terminal. When multiple terminals are specified, wait until" " you push any key to continue. If both console and serial are specified," " the terminal to which you input a key first will be selected. If no" @@ -4141,7 +4277,7 @@ " seconds. The option --lines specifies the maximum number of lines." " The option --silent is used to suppress messages." }; -#endif /* SUPPORT_SERIAL || SUPPORT_HERCULES */ +#endif /* SUPPORT_SERIAL || SUPPORT_HERCULES || SUPPORT_GRAPHICS */ #ifdef SUPPORT_SERIAL @@ -4655,6 +4791,9 @@ /* The table of builtin commands. Sorted in dictionary order. */ struct builtin *builtin_table[] = { +#ifdef SUPPORT_GRAPHICS + &builtin_background, +#endif &builtin_blocklist, &builtin_boot, #ifdef SUPPORT_NETBOOT @@ -4662,6 +4801,7 @@ #endif /* SUPPORT_NETBOOT */ &builtin_cat, &builtin_chainloader, + &builtin_clear, &builtin_cmp, &builtin_color, &builtin_configfile, @@ -4681,6 +4821,9 @@ &builtin_embed, &builtin_fallback, &builtin_find, +#ifdef SUPPORT_GRAPHICS + &builtin_foreground, +#endif &builtin_fstest, &builtin_geometry, &builtin_halt, @@ -4724,9 +4867,12 @@ #endif /* SUPPORT_SERIAL */ &builtin_setkey, &builtin_setup, -#if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES) +#ifdef SUPPORT_GRAPHICS + &builtin_splashimage, +#endif /* SUPPORT_GRAPHICS */ +#if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES) || defined(SUPPORT_GRAPHICS) &builtin_terminal, -#endif /* SUPPORT_SERIAL || SUPPORT_HERCULES */ +#endif /* SUPPORT_SERIAL || SUPPORT_HERCULES || SUPPORT_GRAPHICS */ #ifdef SUPPORT_SERIAL &builtin_terminfo, #endif /* SUPPORT_SERIAL */ diff -urN grub-0.93/stage2/char_io.c grub-0.93+graphics/stage2/char_io.c --- grub-0.93/stage2/char_io.c 2002-12-03 04:49:07.000000000 +0500 +++ grub-0.93+graphics/stage2/char_io.c 2003-11-16 15:50:26.000000000 +0500 @@ -35,6 +35,7 @@ { "console", 0, + 24, console_putchar, console_checkkey, console_getkey, @@ -43,13 +44,16 @@ console_cls, console_setcolorstate, console_setcolor, - console_setcursor + console_setcursor, + 0, + 0 }, #ifdef SUPPORT_SERIAL { "serial", /* A serial device must be initialized. */ TERM_NEED_INIT, + 24, serial_putchar, serial_checkkey, serial_getkey, @@ -58,6 +62,8 @@ serial_cls, serial_setcolorstate, 0, + 0, + 0, 0 }, #endif /* SUPPORT_SERIAL */ @@ -65,6 +71,7 @@ { "hercules", 0, + 24, hercules_putchar, console_checkkey, console_getkey, @@ -73,9 +80,28 @@ hercules_cls, hercules_setcolorstate, hercules_setcolor, - hercules_setcursor + hercules_setcursor, + 0, + 0 }, #endif /* SUPPORT_HERCULES */ +#ifdef SUPPORT_GRAPHICS + { "graphics", + TERM_NEED_INIT, /* flags */ + 30, /* number of lines */ + graphics_putchar, /* putchar */ + console_checkkey, /* checkkey */ + console_getkey, /* getkey */ + graphics_getxy, /* getxy */ + graphics_gotoxy, /* gotoxy */ + graphics_cls, /* cls */ + graphics_setcolorstate, /* setcolorstate */ + graphics_setcolor, /* setcolor */ + graphics_setcursor, /* nocursor */ + graphics_init, /* initialize */ + graphics_end /* shutdown */ + }, +#endif /* SUPPORT_GRAPHICS */ /* This must be the last entry. */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; @@ -1039,13 +1065,15 @@ the following grub_printf call will print newlines. */ count_lines = -1; + grub_printf("\n"); if (current_term->setcolorstate) current_term->setcolorstate (COLOR_STATE_HIGHLIGHT); - grub_printf ("\n[Hit return to continue]"); + grub_printf ("[Hit return to continue]"); if (current_term->setcolorstate) current_term->setcolorstate (COLOR_STATE_NORMAL); + do { @@ -1083,7 +1111,7 @@ cls (void) { /* If the terminal is dumb, there is no way to clean the terminal. */ - if (current_term->flags & TERM_DUMB) + if (current_term->flags & TERM_DUMB) grub_putchar ('\n'); else current_term->cls (); @@ -1207,6 +1235,16 @@ return ! errnum; } +void +grub_memcpy(void *dest, const void *src, int len) +{ + int i; + register char *d = (char*)dest, *s = (char*)src; + + for (i = 0; i < len; i++) + d[i] = s[i]; +} + void * grub_memmove (void *to, const void *from, int len) { diff -urN grub-0.93/stage2/graphics.c grub-0.93+graphics/stage2/graphics.c --- grub-0.93/stage2/graphics.c 1970-01-01 05:00:00.000000000 +0500 +++ grub-0.93+graphics/stage2/graphics.c 2003-11-16 15:50:26.000000000 +0500 @@ -0,0 +1,552 @@ +/* graphics.c - graphics mode support for GRUB */ +/* Implemented as a terminal type by Jeremy Katz based + * on a patch by Paulo César Pereira de Andrade + */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2001,2002 Red Hat, Inc. + * Portions copyright (C) 2000 Conectiva, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + + +#ifdef SUPPORT_GRAPHICS + +#include +#include +#include + +int saved_videomode; +unsigned char *font8x16; + +int graphics_inited = 0; +static char splashimage[64]; + +#define VSHADOW VSHADOW1 +unsigned char VSHADOW1[38400]; +unsigned char VSHADOW2[38400]; +unsigned char VSHADOW4[38400]; +unsigned char VSHADOW8[38400]; + +/* constants to define the viewable area */ +const int x0 = 0; +const int x1 = 80; +const int y0 = 0; +const int y1 = 30; + +/* text buffer has to be kept around so that we can write things as we + * scroll and the like */ +unsigned short text[80 * 30]; + +/* why do these have to be kept here? */ +int foreground = (63 << 16) | (63 << 8) | (63), background = 0, border = 0; + +/* current position */ +static int fontx = 0; +static int fonty = 0; + +/* global state so that we don't try to recursively scroll or cursor */ +static int no_scroll = 0; + +/* color state */ +static int graphics_standard_color = A_NORMAL; +static int graphics_normal_color = A_NORMAL; +static int graphics_highlight_color = A_REVERSE; +static int graphics_current_color = A_NORMAL; +static color_state graphics_color_state = COLOR_STATE_STANDARD; + + +/* graphics local functions */ +static void graphics_setxy(int col, int row); +static void graphics_scroll(); + +/* FIXME: where do these really belong? */ +static inline void outb(unsigned short port, unsigned char val) +{ + __asm __volatile ("outb %0,%1"::"a" (val), "d" (port)); +} + +static void MapMask(int value) { + outb(0x3c4, 2); + outb(0x3c5, value); +} + +/* bit mask register */ +static void BitMask(int value) { + outb(0x3ce, 8); + outb(0x3cf, value); +} + + + +/* Set the splash image */ +void graphics_set_splash(char *splashfile) { + grub_strcpy(splashimage, splashfile); +} + +/* Get the current splash image */ +char *graphics_get_splash(void) { + return splashimage; +} + +/* Initialize a vga16 graphics display with the palette based off of + * the image in splashimage. If the image doesn't exist, leave graphics + * mode. */ +int graphics_init() +{ + if (!graphics_inited) { + saved_videomode = set_videomode(0x12); + } + + if (!read_image(splashimage)) { + set_videomode(saved_videomode); + grub_printf("failed to read image\n"); + return 0; + } + + font8x16 = (unsigned char*)graphics_get_font(); + + graphics_inited = 1; + + /* make sure that the highlight color is set correctly */ + graphics_highlight_color = ((graphics_normal_color >> 4) | + ((graphics_normal_color & 0xf) << 4)); + + return 1; +} + +/* Leave graphics mode */ +void graphics_end(void) +{ + if (graphics_inited) { + set_videomode(saved_videomode); + graphics_inited = 0; + } +} + +/* Print ch on the screen. Handle any needed scrolling or the like */ +void graphics_putchar(int ch) { + ch &= 0xff; + + graphics_cursor(0); + + if (ch == '\n') { + if (fonty + 1 < y1) + graphics_setxy(fontx, fonty + 1); + else + graphics_scroll(); + graphics_cursor(1); + return; + } else if (ch == '\r') { + graphics_setxy(x0, fonty); + graphics_cursor(1); + return; + } + + graphics_cursor(0); + + text[fonty * 80 + fontx] = ch; + text[fonty * 80 + fontx] &= 0x00ff; + if (graphics_current_color & 0xf0) + text[fonty * 80 + fontx] |= 0x100; + + graphics_cursor(0); + + if ((fontx + 1) >= x1) { + graphics_setxy(x0, fonty); + if (fonty + 1 < y1) + graphics_setxy(x0, fonty + 1); + else + graphics_scroll(); + } else { + graphics_setxy(fontx + 1, fonty); + } + + graphics_cursor(1); +} + +/* get the current location of the cursor */ +int graphics_getxy(void) { + return (fontx << 8) | fonty; +} + +void graphics_gotoxy(int x, int y) { + graphics_cursor(0); + + graphics_setxy(x, y); + + graphics_cursor(1); +} + +void graphics_cls(void) { + int i; + unsigned char *mem, *s1, *s2, *s4, *s8; + + graphics_cursor(0); + graphics_gotoxy(x0, y0); + + mem = (unsigned char*)VIDEOMEM; + s1 = (unsigned char*)VSHADOW1; + s2 = (unsigned char*)VSHADOW2; + s4 = (unsigned char*)VSHADOW4; + s8 = (unsigned char*)VSHADOW8; + + for (i = 0; i < 80 * 30; i++) + text[i] = ' '; + graphics_cursor(1); + + BitMask(0xff); + + /* plano 1 */ + MapMask(1); + grub_memcpy(mem, s1, 38400); + + /* plano 2 */ + MapMask(2); + grub_memcpy(mem, s2, 38400); + + /* plano 3 */ + MapMask(4); + grub_memcpy(mem, s4, 38400); + + /* plano 4 */ + MapMask(8); + grub_memcpy(mem, s8, 38400); + + MapMask(15); + +} + +void graphics_setcolorstate (color_state state) { + switch (state) { + case COLOR_STATE_STANDARD: + graphics_current_color = graphics_standard_color; + break; + case COLOR_STATE_NORMAL: + graphics_current_color = graphics_normal_color; + break; + case COLOR_STATE_HIGHLIGHT: + graphics_current_color = graphics_highlight_color; + break; + default: + graphics_current_color = graphics_standard_color; + break; + } + + graphics_color_state = state; +} + +void graphics_setcolor (int normal_color, int highlight_color) { + graphics_normal_color = normal_color; + graphics_highlight_color = highlight_color; + + graphics_setcolorstate (graphics_color_state); +} + +void graphics_setcursor (int on) { + /* FIXME: we don't have a cursor in graphics */ + return; +} + +/* Read in the splashscreen image and set the palette up appropriately. + * Format of splashscreen is an xpm (can be gzipped) with 16 colors and + * 640x480. */ +int read_image(char *s) +{ + char buf[32], pal[16]; + unsigned char c, base, mask, *s1, *s2, *s4, *s8; + unsigned i, len, idx, colors, x, y, width, height; + + if (!grub_open(s)) + return 0; + + /* read header */ + if (!grub_read((char*)&buf, 10) || grub_memcmp(buf, "/* XPM */\n", 10)) { + grub_close(); + return 0; + } + + /* parse info */ + while (grub_read(&c, 1)) { + if (c == '"') + break; + } + + while (grub_read(&c, 1) && (c == ' ' || c == '\t')) + ; + + i = 0; + width = c - '0'; + while (grub_read(&c, 1)) { + if (c >= '0' && c <= '9') + width = width * 10 + c - '0'; + else + break; + } + while (grub_read(&c, 1) && (c == ' ' || c == '\t')) + ; + + height = c - '0'; + while (grub_read(&c, 1)) { + if (c >= '0' && c <= '9') + height = height * 10 + c - '0'; + else + break; + } + while (grub_read(&c, 1) && (c == ' ' || c == '\t')) + ; + + colors = c - '0'; + while (grub_read(&c, 1)) { + if (c >= '0' && c <= '9') + colors = colors * 10 + c - '0'; + else + break; + } + + base = 0; + while (grub_read(&c, 1) && c != '"') + ; + + /* palette */ + for (i = 0, idx = 1; i < colors; i++) { + len = 0; + + while (grub_read(&c, 1) && c != '"') + ; + grub_read(&c, 1); /* char */ + base = c; + grub_read(buf, 4); /* \t c # */ + + while (grub_read(&c, 1) && c != '"') { + if (len < sizeof(buf)) + buf[len++] = c; + } + + if (len == 6 && idx < 15) { + int r = ((hex(buf[0]) << 4) | hex(buf[1])) >> 2; + int g = ((hex(buf[2]) << 4) | hex(buf[3])) >> 2; + int b = ((hex(buf[4]) << 4) | hex(buf[5])) >> 2; + + pal[idx] = base; + graphics_set_palette(idx, r, g, b); + ++idx; + } + } + + x = y = len = 0; + + s1 = (unsigned char*)VSHADOW1; + s2 = (unsigned char*)VSHADOW2; + s4 = (unsigned char*)VSHADOW4; + s8 = (unsigned char*)VSHADOW8; + + for (i = 0; i < 38400; i++) + s1[i] = s2[i] = s4[i] = s8[i] = 0; + + /* parse xpm data */ + while (y < height) { + while (1) { + if (!grub_read(&c, 1)) { + grub_close(); + return 0; + } + if (c == '"') + break; + } + + while (grub_read(&c, 1) && c != '"') { + for (i = 1; i < 15; i++) + if (pal[i] == c) { + c = i; + break; + } + + mask = 0x80 >> (x & 7); + if (c & 1) + s1[len + (x >> 3)] |= mask; + if (c & 2) + s2[len + (x >> 3)] |= mask; + if (c & 4) + s4[len + (x >> 3)] |= mask; + if (c & 8) + s8[len + (x >> 3)] |= mask; + + if (++x >= 640) { + x = 0; + + if (y < 480) + len += 80; + ++y; + } + } + } + + grub_close(); + + graphics_set_palette(0, (background >> 16), (background >> 8) & 63, + background & 63); + graphics_set_palette(15, (foreground >> 16), (foreground >> 8) & 63, + foreground & 63); + graphics_set_palette(0x11, (border >> 16), (border >> 8) & 63, + border & 63); + + return 1; +} + + +/* Convert a character which is a hex digit to the appropriate integer */ +int hex(int v) +{ + if (v >= 'A' && v <= 'F') + return (v - 'A' + 10); + if (v >= 'a' && v <= 'f') + return (v - 'a' + 10); + return (v - '0'); +} + + +/* move the graphics cursor location to col, row */ +static void graphics_setxy(int col, int row) { + if (col >= x0 && col < x1) { + fontx = col; + cursorX = col << 3; + } + if (row >= y0 && row < y1) { + fonty = row; + cursorY = row << 4; + } +} + +/* scroll the screen */ +static void graphics_scroll() { + int i, j; + + /* we don't want to scroll recursively... that would be bad */ + if (no_scroll) + return; + no_scroll = 1; + + /* move everything up a line */ + for (j = y0 + 1; j < y1; j++) { + graphics_gotoxy(x0, j - 1); + for (i = x0; i < x1; i++) { + graphics_putchar(text[j * 80 + i]); + } + } + + /* last line should be blank */ + graphics_gotoxy(x0, y1 - 1); + for (i = x0; i < x1; i++) + graphics_putchar(' '); + graphics_setxy(x0, y1 - 1); + + no_scroll = 0; +} + + +void graphics_cursor(int set) { + unsigned char *pat, *mem, *ptr, chr[16 << 2]; + int i, ch, invert, offset; + + if (set && no_scroll) + return; + + offset = cursorY * 80 + fontx; + ch = text[fonty * 80 + fontx] & 0xff; + invert = (text[fonty * 80 + fontx] & 0xff00) != 0; + pat = font8x16 + (ch << 4); + + mem = (unsigned char*)VIDEOMEM + offset; + + if (!set) { + for (i = 0; i < 16; i++) { + unsigned char mask = pat[i]; + + if (!invert) { + chr[i ] = ((unsigned char*)VSHADOW1)[offset]; + chr[16 + i] = ((unsigned char*)VSHADOW2)[offset]; + chr[32 + i] = ((unsigned char*)VSHADOW4)[offset]; + chr[48 + i] = ((unsigned char*)VSHADOW8)[offset]; + + /* FIXME: if (shade) */ + if (1) { + if (ch == DISP_VERT || ch == DISP_LL || + ch == DISP_UR || ch == DISP_LR) { + unsigned char pmask = ~(pat[i] >> 1); + + chr[i ] &= pmask; + chr[16 + i] &= pmask; + chr[32 + i] &= pmask; + chr[48 + i] &= pmask; + } + if (i > 0 && ch != DISP_VERT) { + unsigned char pmask = ~(pat[i - 1] >> 1); + + chr[i ] &= pmask; + chr[16 + i] &= pmask; + chr[32 + i] &= pmask; + chr[48 + i] &= pmask; + if (ch == DISP_HORIZ || ch == DISP_UR || ch == DISP_LR) { + pmask = ~pat[i - 1]; + + chr[i ] &= pmask; + chr[16 + i] &= pmask; + chr[32 + i] &= pmask; + chr[48 + i] &= pmask; + } + } + } + chr[i ] |= mask; + chr[16 + i] |= mask; + chr[32 + i] |= mask; + chr[48 + i] |= mask; + + offset += 80; + } + else { + chr[i ] = mask; + chr[16 + i] = mask; + chr[32 + i] = mask; + chr[48 + i] = mask; + } + } + } + else { + MapMask(15); + ptr = mem; + for (i = 0; i < 16; i++, ptr += 80) { + cursorBuf[i] = pat[i]; + *ptr = ~pat[i]; + } + return; + } + + offset = 0; + for (i = 1; i < 16; i <<= 1, offset += 16) { + int j; + + MapMask(i); + ptr = mem; + for (j = 0; j < 16; j++, ptr += 80) + *ptr = chr[j + offset]; + } + + MapMask(15); +} + +#endif /* SUPPORT_GRAPHICS */ diff -urN grub-0.93/stage2/graphics.h grub-0.93+graphics/stage2/graphics.h --- grub-0.93/stage2/graphics.h 1970-01-01 05:00:00.000000000 +0500 +++ grub-0.93+graphics/stage2/graphics.h 2003-11-16 15:50:26.000000000 +0500 @@ -0,0 +1,42 @@ +/* graphics.h - graphics console interface */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef GRAPHICS_H +#define GRAPHICS_H + +/* magic constant */ +#define VIDEOMEM 0xA0000 + +/* function prototypes */ +char *graphics_get_splash(void); + +int read_image(char *s); +void graphics_cursor(int set); + +/* function prototypes for asm functions */ +void * graphics_get_font(); +void graphics_set_palette(int idx, int red, int green, int blue); +void set_int1c_handler(); +void unset_int1c_handler(); + +extern short cursorX, cursorY; +extern char cursorBuf[16]; + +#endif /* GRAPHICS_H */ diff -urN grub-0.93/stage2/Makefile.am grub-0.93+graphics/stage2/Makefile.am --- grub-0.93/stage2/Makefile.am 2002-11-29 23:00:53.000000000 +0500 +++ grub-0.93+graphics/stage2/Makefile.am 2003-11-16 15:50:26.000000000 +0500 @@ -7,7 +7,7 @@ fat.h filesys.h freebsd.h fs.h hercules.h i386-elf.h \ imgact_aout.h jfs.h mb_header.h mb_info.h md5.h nbi.h \ pc_slice.h serial.h shared.h smp-imps.h term.h terminfo.h \ - tparm.h nbi.h vstafs.h xfs.h + tparm.h nbi.h vstafs.h xfs.h graphics.h EXTRA_DIST = setjmp.S apm.S $(noinst_SCRIPTS) # For . @@ -18,7 +18,7 @@ libgrub_a_SOURCES = boot.c builtins.c char_io.c cmdline.c common.c \ disk_io.c fsys_ext2fs.c fsys_fat.c fsys_ffs.c fsys_jfs.c \ fsys_minix.c fsys_reiserfs.c fsys_vstafs.c fsys_xfs.c gunzip.c \ - md5.c serial.c stage2.c terminfo.c tparm.c + md5.c serial.c stage2.c terminfo.c tparm.c graphics.c libgrub_a_CFLAGS = $(GRUB_CFLAGS) -I$(top_srcdir)/lib \ -DGRUB_UTIL=1 -DFSYS_EXT2FS=1 -DFSYS_FAT=1 -DFSYS_FFS=1 \ -DFSYS_JFS=1 -DFSYS_MINIX=1 -DFSYS_REISERFS=1 -DFSYS_VSTAFS=1 \ @@ -75,8 +75,14 @@ HERCULES_FLAGS = endif +if GRAPHICS_SUPPORT +GRAPHICS_FLAGS = -DSUPPORT_GRAPHICS=1 +else +GRAPHICS_FLAGS = +endif + STAGE2_COMPILE = $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ - $(NETBOOT_FLAGS) $(SERIAL_FLAGS) $(HERCULES_FLAGS) + $(NETBOOT_FLAGS) $(SERIAL_FLAGS) $(HERCULES_FLAGS) $(GRAPHICS_FLAGS) STAGE1_5_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,2000 STAGE1_5_COMPILE = $(STAGE2_COMPILE) -DNO_DECOMPRESSION=1 -DSTAGE1_5=1 @@ -86,9 +92,9 @@ cmdline.c common.c console.c disk_io.c fsys_ext2fs.c \ fsys_fat.c fsys_ffs.c fsys_jfs.c fsys_minix.c fsys_reiserfs.c \ fsys_vstafs.c fsys_xfs.c gunzip.c hercules.c md5.c serial.c \ - smp-imps.c stage2.c terminfo.c tparm.c + smp-imps.c stage2.c terminfo.c tparm.c graphics.c pre_stage2_exec_CFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS) -pre_stage2_exec_ASFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS) +pre_stage2_exec_CCASFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS) pre_stage2_exec_LDFLAGS = $(PRE_STAGE2_LINK) if NETBOOT_SUPPORT @@ -109,7 +115,7 @@ echo "#define STAGE2_SIZE $$6" > stage2_size.h start_exec_SOURCES = start.S -start_exec_ASFLAGS = $(STAGE2_COMPILE) +start_exec_CCASFLAGS = $(STAGE2_COMPILE) start_exec_LDFLAGS = $(START_LINK) # XXX: automake doesn't provide a way to specify dependencies for object @@ -127,7 +133,7 @@ stage1_5.c fsys_ext2fs.c bios.c e2fs_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_EXT2FS=1 \ -DNO_BLOCK_FILES=1 -e2fs_stage1_5_exec_ASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_EXT2FS=1 \ +e2fs_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_EXT2FS=1 \ -DNO_BLOCK_FILES=1 e2fs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK) @@ -136,7 +142,7 @@ stage1_5.c fsys_fat.c bios.c fat_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_FAT=1 \ -DNO_BLOCK_FILES=1 -fat_stage1_5_exec_ASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_FAT=1 \ +fat_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_FAT=1 \ -DNO_BLOCK_FILES=1 fat_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK) @@ -145,7 +151,7 @@ stage1_5.c fsys_ffs.c bios.c ffs_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_FFS=1 \ -DNO_BLOCK_FILES=1 -ffs_stage1_5_exec_ASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_FFS=1 \ +ffs_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_FFS=1 \ -DNO_BLOCK_FILES=1 ffs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK) @@ -154,7 +160,7 @@ stage1_5.c fsys_minix.c bios.c minix_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_MINIX=1 \ -DNO_BLOCK_FILES=1 -minix_stage1_5_exec_ASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_MINIX=1 \ +minix_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_MINIX=1 \ -DNO_BLOCK_FILES=1 minix_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK) @@ -163,7 +169,7 @@ disk_io.c stage1_5.c fsys_reiserfs.c bios.c reiserfs_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_REISERFS=1 \ -DNO_BLOCK_FILES=1 -reiserfs_stage1_5_exec_ASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_REISERFS=1 \ +reiserfs_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_REISERFS=1 \ -DNO_BLOCK_FILES=1 reiserfs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK) @@ -172,7 +178,7 @@ disk_io.c stage1_5.c fsys_vstafs.c bios.c vstafs_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_VSTAFS=1 \ -DNO_BLOCK_FILES=1 -vstafs_stage1_5_exec_ASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_VSTAFS=1 \ +vstafs_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_VSTAFS=1 \ -DNO_BLOCK_FILES=1 vstafs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK) @@ -181,7 +187,7 @@ disk_io.c stage1_5.c fsys_jfs.c bios.c jfs_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_JFS=1 \ -DNO_BLOCK_FILES=1 -jfs_stage1_5_exec_ASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_JFS=1 \ +jfs_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_JFS=1 \ -DNO_BLOCK_FILES=1 jfs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK) @@ -190,7 +196,7 @@ disk_io.c stage1_5.c fsys_xfs.c bios.c xfs_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_XFS=1 \ -DNO_BLOCK_FILES=1 -xfs_stage1_5_exec_ASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_XFS=1 \ +xfs_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_XFS=1 \ -DNO_BLOCK_FILES=1 xfs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK) @@ -198,7 +204,7 @@ diskless_exec_SOURCES = $(pre_stage2_exec_SOURCES) diskless_exec_CFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS) \ -DSUPPORT_DISKLESS=1 -diskless_exec_ASFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS) \ +diskless_exec_CCASFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS) \ -DSUPPORT_DISKLESS=1 diskless_exec_LDFLAGS = $(PRE_STAGE2_LINK) diskless_exec_LDADD = ../netboot/libdrivers.a @@ -210,7 +216,7 @@ # For nbloader target. nbloader_exec_SOURCES = nbloader.S -nbloader_exec_ASFLAGS = $(STAGE2_COMPILE) +nbloader_exec_CCASFLAGS = $(STAGE2_COMPILE) nbloader_exec_LDFLAGS = $(NBLOADER_LINK) # XXX: See the comment for start_exec-start.o. @@ -223,7 +229,7 @@ # For pxeloader target. pxeloader_exec_SOURCES = pxeloader.S -pxeloader_exec_ASFLAGS = $(STAGE2_COMPILE) +pxeloader_exec_CCASFLAGS = $(STAGE2_COMPILE) pxeloader_exec_LDFLAGS = $(PXELOADER_LINK) # XXX: See the comment for start_exec-start.o. diff -urN grub-0.93/stage2/shared.h grub-0.93+graphics/stage2/shared.h --- grub-0.93/stage2/shared.h 2002-12-03 04:15:12.000000000 +0500 +++ grub-0.93+graphics/stage2/shared.h 2003-11-16 15:50:26.000000000 +0500 @@ -854,6 +854,7 @@ int grub_tolower (int c); int grub_isspace (int c); int grub_strncat (char *s1, const char *s2, int n); +void grub_memcpy(void *dest, const void *src, int len); void *grub_memmove (void *to, const void *from, int len); void *grub_memset (void *start, int c, int len); int grub_strncat (char *s1, const char *s2, int n); diff -urN grub-0.93/stage2/stage2.c grub-0.93+graphics/stage2/stage2.c --- grub-0.93/stage2/stage2.c 2002-12-04 05:54:23.000000000 +0500 +++ grub-0.93+graphics/stage2/stage2.c 2003-11-16 15:50:26.000000000 +0500 @@ -233,6 +233,7 @@ { int c, time1, time2 = -1, first_entry = 0; char *cur_entry = 0; + struct term_entry *prev_term = NULL; /* * Main loop for menu UI. @@ -714,6 +715,15 @@ cls (); setcursor (1); + /* if our terminal needed initialization, we should shut it down + * before booting the kernel, but we want to save what it was so + * we can come back if needed */ + prev_term = current_term; + if (current_term->shutdown) + { + (*current_term->shutdown)(); + current_term = term_table; /* assumption: console is first */ + } while (1) { @@ -745,6 +755,13 @@ break; } + /* if we get back here, we should go back to what our term was before */ + current_term = prev_term; + if (current_term->startup) + /* if our terminal fails to initialize, fall back to console since + * it should always work */ + if ((*current_term->startup)() == 0) + current_term = term_table; /* we know that console is first */ show_menu = 1; goto restart; } @@ -989,6 +1006,10 @@ while (is_preset); } + /* go ahead and make sure the terminal is setup */ + if (current_term->startup) + (*current_term->startup)(); + if (! num_entries) { /* If no acceptable config file, goto command-line, starting diff -urN grub-0.93/stage2/term.h grub-0.93+graphics/stage2/term.h --- grub-0.93/stage2/term.h 2002-12-03 03:55:13.000000000 +0500 +++ grub-0.93+graphics/stage2/term.h 2003-11-16 15:50:26.000000000 +0500 @@ -60,6 +60,8 @@ const char *name; /* The feature flags defined above. */ unsigned long flags; + /* Default for maximum number of lines if not specified */ + unsigned short max_lines; /* Put a character. */ void (*putchar) (int c); /* Check if any input character is available. */ @@ -79,6 +81,11 @@ void (*setcolor) (int normal_color, int highlight_color); /* Turn on/off the cursor. */ int (*setcursor) (int on); + + /* function to start a terminal */ + int (*startup) (void); + /* function to use to shutdown a terminal */ + void (*shutdown) (void); }; /* This lists up available terminals. */ @@ -124,4 +131,23 @@ int hercules_setcursor (int on); #endif +#ifdef SUPPORT_GRAPHICS +extern int foreground, background, border, graphics_inited; + +void graphics_set_splash(char *splashfile); +int set_videomode (int mode); +void graphics_putchar (int c); +int graphics_getxy(void); +void graphics_gotoxy(int x, int y); +void graphics_cls(void); +void graphics_setcolorstate (color_state state); +void graphics_setcolor (int normal_color, int highlight_color); +void graphics_setcursor (int on); +int graphics_init(void); +void graphics_end(void); + +int hex(int v); +void graphics_set_palette(int idx, int red, int green, int blue); +#endif /* SUPPORT_GRAPHICS */ + #endif /* ! GRUB_TERM_HEADER */