diff -Naur grub-0.96/configure.ac grub-0.96-r2/configure.ac --- grub-0.96/configure.ac 2005-01-30 02:02:32.000000000 +0100 +++ grub-0.96-r2/configure.ac 2006-07-25 09:33:45.000000000 +0200 @@ -595,6 +595,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]) diff -Naur grub-0.96/docs/grub.8 grub-0.96-r2/docs/grub.8 --- grub-0.96/docs/grub.8 2005-01-30 02:08:38.000000000 +0100 +++ grub-0.96-r2/docs/grub.8 2006-07-25 09:32:39.000000000 +0200 @@ -15,7 +15,7 @@ specify stage2 boot_drive [default=0x0] .TP \fB\-\-config\-file\fR=\fIFILE\fR -specify stage2 config_file [default=/boot/grub/menu.lst] +specify stage2 config_file [default=/boot/grub/grub.conf] .TP \fB\-\-device\-map\fR=\fIFILE\fR use the device map file FILE diff -Naur grub-0.96/docs/grub.texi grub-0.96-r2/docs/grub.texi --- grub-0.96/docs/grub.texi 2004-09-20 23:47:38.000000000 +0200 +++ grub-0.96-r2/docs/grub.texi 2006-07-25 09:34:04.000000000 +0200 @@ -1265,7 +1265,7 @@ keys) that will do everything to boot an OS. To enable the menu, you need a configuration file, -@file{menu.lst} under the boot directory. We'll analyze an example +@file{grub.conf} under the boot directory. We'll analyze an example file. The file first contains some general settings, the menu interface @@ -1882,8 +1882,8 @@ An absolute file name resembles a Unix absolute file name, using @samp{/} for the directory separator (not @samp{\} as in DOS). One -example is @samp{(hd0,0)/boot/grub/menu.lst}. This means the file -@file{/boot/grub/menu.lst} in the first partition of the first hard +example is @samp{(hd0,0)/boot/grub/grub.conf}. This means the file +@file{/boot/grub/grub.conf} in the first partition of the first hard disk. If you omit the device name in an absolute file name, GRUB uses GRUB's @dfn{root device} implicitly. So if you set the root device to, say, @samp{(hd1,0)} by the command @command{root} (@pxref{root}), then @@ -2199,6 +2199,7 @@ * rarp:: Initialize a network device via RARP * serial:: Set up a serial device * setkey:: Configure the key map +* splashimage:: Use a splash image * terminal:: Choose a terminal * terminfo:: Define escape sequences for a terminal * tftpserver:: Specify a TFTP server @@ -2578,6 +2579,16 @@ @end deffn +@node splashimage +@subsection splashimage + +@deffn Command splashimage file +Select an image to use as the background image. This should be +specified using normal GRUB device naming syntax. The format of the +file is a gzipped xpm which is 640x480 with a 14 color palette. +@end deffn + + @node terminal @subsection terminal @@ -3542,7 +3553,7 @@ @item --config-file=@var{file} Read the configuration file @var{file} instead of -@file{/boot/grub/menu.lst}. The format is the same as the normal GRUB +@file{/boot/grub/grub.conf}. The format is the same as the normal GRUB syntax. See @ref{Filesystem}, for more information. @item --boot-drive=@var{drive} diff -Naur grub-0.96/grub/asmstub.c grub-0.96-r2/grub/asmstub.c --- grub-0.96/grub/asmstub.c 2004-03-12 18:01:49.000000000 +0100 +++ grub-0.96-r2/grub/asmstub.c 2006-07-25 09:32:39.000000000 +0200 @@ -71,7 +71,7 @@ unsigned long boot_drive = 0; int saved_entryno = 0; char version_string[] = VERSION; -char config_file[128] = "/boot/grub/menu.lst"; /* FIXME: arbitrary */ +char config_file[128] = "/boot/grub/grub.conf"; /* FIXME: arbitrary */ unsigned long linux_text_len = 0; char *linux_data_tmp_addr = 0; char *linux_data_real_addr = 0; diff -Naur grub-0.96/lib/device.c grub-0.96-r2/lib/device.c --- grub-0.96/lib/device.c 2004-05-23 18:34:29.000000000 +0200 +++ grub-0.96-r2/lib/device.c 2006-07-25 09:34:42.000000000 +0200 @@ -407,6 +407,12 @@ { sprintf (name, "/dev/ataraid/d%c", unit + '0'); } + +static void +get_i2o_disk_name (char *name, int unit) +{ + sprintf (name, "/dev/i2o/hd%c", unit + 'a'); +} #endif /* Check if DEVICE can be read. If an error occurs, return zero, @@ -798,6 +804,26 @@ } } } + + /* I2O disks. */ + for (i = 0; i < 8; i++) + { + char name[16]; + + get_i2o_disk_name (name, i); + if (check_device (name)) + { + (*map)[num_hd + 0x80] = strdup (name); + assert ((*map)[num_hd + 0x80]); + + /* If the device map file is opened, write the map. */ + if (fp) + fprintf (fp, "(hd%d)\t%s\n", num_hd, name); + + num_hd++; + } + } + #endif /* __linux__ */ /* OK, close the device map file if opened. */ @@ -858,7 +884,15 @@ if (strcmp (dev + strlen(dev) - 5, "/disc") == 0) strcpy (dev + strlen(dev) - 5, "/part"); } - sprintf (dev + strlen(dev), "%d", ((partition >> 16) & 0xFF) + 1); + + sprintf (dev + strlen(dev), "%s%d", + /* Compaq smart and others */ + (strncmp(dev, "/dev/ida/", 9) == 0 || + strncmp(dev, "/dev/ataraid/", 13) == 0 || + strncmp(dev, "/dev/cciss/", 11) == 0 || + strncmp(dev, "/dev/rd/", 8) == 0 || + strncmp(dev, "/dev/i2o/", 9) == 0) ? "p" : "", + ((partition >> 16) & 0xFF) + 1); /* Open the partition. */ fd = open (dev, O_RDWR); diff -Naur grub-0.96/netboot/rtl8139.c grub-0.96-r2/netboot/rtl8139.c --- grub-0.96/netboot/rtl8139.c 2003-07-09 13:45:38.000000000 +0200 +++ grub-0.96-r2/netboot/rtl8139.c 2006-07-25 09:35:12.000000000 +0200 @@ -161,19 +161,11 @@ /* The RTL8139 can only transmit from a contiguous, aligned memory block. */ static unsigned char tx_buffer[TX_BUF_SIZE] __attribute__((aligned(4))); -/* I know that this is a MEGA HACK, but the tagged boot image specification - * states that we can do whatever we want below 0x10000 - so we do! */ -/* But we still give the user the choice of using an internal buffer - just in case - Ken */ -#ifdef USE_LOWMEM_BUFFER -#define rx_ring ((unsigned char *)(0x10000 - (RX_BUF_LEN + 16))) -#else static unsigned char rx_ring[RX_BUF_LEN+16] __attribute__((aligned(4))); -#endif struct nic *rtl8139_probe(struct nic *nic, unsigned short *probeaddrs, struct pci_device *pci); -static int read_eeprom(int location); +static int read_eeprom(int location, int addr_len); static void rtl_reset(struct nic *nic); static void rtl_transmit(struct nic *nic, const char *destaddr, unsigned int type, unsigned int len, const char *data); @@ -186,6 +178,8 @@ { int i; int speed10, fullduplex; + int addr_len; + unsigned short *ap = (unsigned short*)nic->node_addr; /* There are enough "RTL8139" strings on the console already, so * be brief and concentrate on the interesting pieces of info... */ @@ -199,15 +193,9 @@ /* Bring the chip out of low-power mode. */ outb(0x00, ioaddr + Config1); - if (read_eeprom(0) != 0xffff) { - unsigned short *ap = (unsigned short*)nic->node_addr; - for (i = 0; i < 3; i++) - *ap++ = read_eeprom(i + 7); - } else { - unsigned char *ap = (unsigned char*)nic->node_addr; - for (i = 0; i < ETH_ALEN; i++) - *ap++ = inb(ioaddr + MAC0 + i); - } + addr_len = read_eeprom(0,8) == 0x8129 ? 8 : 6; + for (i = 0; i < 3; i++) + *ap++ = read_eeprom(i + 7,addr_len); speed10 = inb(ioaddr + MediaStatus) & MSRSpeed10; fullduplex = inw(ioaddr + MII_BMCR) & BMCRDuplex; @@ -217,6 +205,10 @@ rtl_reset(nic); + if (inb(ioaddr + MediaStatus) & MSRLinkFail) { + printf("Cable not connected or other link failure\n"); + return(0); + } nic->reset = rtl_reset; nic->poll = rtl_poll; nic->transmit = rtl_transmit; @@ -244,22 +236,23 @@ #define eeprom_delay() inl(ee_addr) /* The EEPROM commands include the alway-set leading bit. */ -#define EE_WRITE_CMD (5 << 6) -#define EE_READ_CMD (6 << 6) -#define EE_ERASE_CMD (7 << 6) +#define EE_WRITE_CMD (5) +#define EE_READ_CMD (6) +#define EE_ERASE_CMD (7) -static int read_eeprom(int location) +static int read_eeprom(int location, int addr_len) { int i; unsigned int retval = 0; long ee_addr = ioaddr + Cfg9346; - int read_cmd = location | EE_READ_CMD; + int read_cmd = location | (EE_READ_CMD << addr_len); outb(EE_ENB & ~EE_CS, ee_addr); outb(EE_ENB, ee_addr); + eeprom_delay(); /* Shift the read command bits out. */ - for (i = 10; i >= 0; i--) { + for (i = 4 + addr_len; i >= 0; i--) { int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; outb(EE_ENB | dataval, ee_addr); eeprom_delay(); @@ -279,9 +272,28 @@ /* Terminate the EEPROM access. */ outb(~EE_CS, ee_addr); + eeprom_delay(); return retval; } +static const unsigned int rtl8139_rx_config = + (RX_BUF_LEN_IDX << 11) | + (RX_FIFO_THRESH << 13) | + (RX_DMA_BURST << 8); + +static void set_rx_mode(struct nic *nic) { + unsigned int mc_filter[2]; + int rx_mode; + /* !IFF_PROMISC */ + rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; + mc_filter[1] = mc_filter[0] = 0xffffffff; + + outl(rtl8139_rx_config | rx_mode, ioaddr + RxConfig); + + outl(mc_filter[0], ioaddr + MAR0 + 0); + outl(mc_filter[1], ioaddr + MAR0 + 4); +} + static void rtl_reset(struct nic* nic) { int i; @@ -318,15 +330,22 @@ #endif outl((unsigned long)rx_ring, ioaddr + RxBuf); - /* Start the chip's Tx and Rx process. */ - outl(0, ioaddr + RxMissed); - /* set_rx_mode */ - outb(AcceptBroadcast|AcceptMyPhys, ioaddr + RxConfig); + + /* If we add multicast support, the MAR0 register would have to be * initialized to 0xffffffffffffffff (two 32 bit accesses). Etherboot * only needs broadcast (for ARP/RARP/BOOTP/DHCP) and unicast. */ + outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); + + outl(rtl8139_rx_config, ioaddr + RxConfig); + + /* Start the chip's Tx and Rx process. */ + outl(0, ioaddr + RxMissed); + /* set_rx_mode */ + set_rx_mode(nic); + /* Disable all known interrupts by setting the interrupt mask. */ outw(0, ioaddr + IntrMask); } @@ -337,10 +356,11 @@ unsigned int status, to, nstype; unsigned long txstatus; + /* nstype assignment moved up here to avoid gcc 3.0.3 compiler bug */ + nstype = htons(type); memcpy(tx_buffer, destaddr, ETH_ALEN); memcpy(tx_buffer + ETH_ALEN, nic->node_addr, ETH_ALEN); - nstype = htons(type); - memcpy(tx_buffer + 2 * ETH_ALEN, (char*)&nstype, 2); + memcpy(tx_buffer + 2 * ETH_ALEN, &nstype, 2); memcpy(tx_buffer + ETH_HLEN, data, len); len += ETH_HLEN; @@ -448,6 +468,8 @@ static void rtl_disable(struct nic *nic) { + rtl_reset(nic); + /* reset the chip */ outb(CmdReset, ioaddr + ChipCmd); diff -Naur grub-0.96/stage2/asm.S grub-0.96-r2/stage2/asm.S --- grub-0.96/stage2/asm.S 2004-06-19 18:55:22.000000000 +0200 +++ grub-0.96-r2/stage2/asm.S 2006-07-25 09:33:45.000000000 +0200 @@ -98,7 +98,7 @@ .string VERSION VARIABLE(config_file) #ifndef STAGE1_5 - .string "/boot/grub/menu.lst" + .string "/boot/grub/grub.conf" #else /* STAGE1_5 */ .long 0xffffffff .string "/boot/grub/stage2" @@ -2216,6 +2216,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 -Naur grub-0.96/stage2/builtins.c grub-0.96-r2/stage2/builtins.c --- grub-0.96/stage2/builtins.c 2004-06-20 15:33:04.000000000 +0200 +++ grub-0.96-r2/stage2/builtins.c 2006-07-25 09:34:17.000000000 +0200 @@ -235,12 +235,22 @@ static int boot_func (char *arg, int flags) { + struct term_entry *prev_term = current_term; /* Clear the int15 handler if we can boot the kernel successfully. This assumes that the boot code never fails only if KERNEL_TYPE is not KERNEL_TYPE_NONE. Is this assumption is bad? */ if (kernel_type != KERNEL_TYPE_NONE) unset_int15_handler (); + /* 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 */ + if (current_term->shutdown) + { + (*current_term->shutdown)(); + current_term = term_table; /* assumption: console is first */ + } + #ifdef SUPPORT_NETBOOT /* Shut down the networking. */ cleanup_net (); @@ -304,6 +314,13 @@ return 1; } + /* 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 */ return 0; } @@ -848,6 +865,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 @@ -3961,7 +4110,7 @@ /* The prefix was determined. */ grub_sprintf (stage2, "%s%s", prefix, "/stage2"); - grub_sprintf (config_filename, "%s%s", prefix, "/menu.lst"); + grub_sprintf (config_filename, "%s%s", prefix, "/grub.conf"); *real_config_filename = 0; /* Check if stage2 exists. */ @@ -4073,7 +4222,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) @@ -4232,17 +4381,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; } @@ -4252,7 +4405,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" @@ -4264,7 +4417,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 @@ -4783,6 +4936,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 @@ -4790,6 +4946,7 @@ #endif /* SUPPORT_NETBOOT */ &builtin_cat, &builtin_chainloader, + &builtin_clear, &builtin_cmp, &builtin_color, &builtin_configfile, @@ -4809,6 +4966,9 @@ &builtin_embed, &builtin_fallback, &builtin_find, +#ifdef SUPPORT_GRAPHICS + &builtin_foreground, +#endif &builtin_fstest, &builtin_geometry, &builtin_halt, @@ -4852,9 +5012,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 -Naur grub-0.96/stage2/char_io.c grub-0.96-r2/stage2/char_io.c --- grub-0.96/stage2/char_io.c 2004-05-23 18:45:43.000000000 +0200 +++ grub-0.96-r2/stage2/char_io.c 2006-07-25 09:33:45.000000000 +0200 @@ -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 } }; @@ -1046,13 +1072,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 { @@ -1090,7 +1118,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 (); @@ -1214,6 +1242,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 -Naur grub-0.96/stage2/cmdline.c grub-0.96-r2/stage2/cmdline.c --- grub-0.96/stage2/cmdline.c 2004-08-17 01:23:01.000000000 +0200 +++ grub-0.96-r2/stage2/cmdline.c 2006-07-25 09:33:22.000000000 +0200 @@ -48,12 +48,17 @@ /* Print a helpful message for the command-line interface. */ void -print_cmdline_message (int forever) +print_cmdline_message (int type) { printf (" [ Minimal BASH-like line editing is supported. For the first word, TAB\n" " lists possible command completions. Anywhere else TAB lists the possible\n" - " completions of a device/filename.%s ]\n", - (forever ? "" : " ESC at any time exits.")); + " completions of a device/filename."); + if (type == CMDLINE_NORMAL_MODE) + printf(" ESC at any time exits."); + if (type == CMDLINE_EDIT_MODE) + printf(" ESC at any time cancels. ENTER \n" + " at any time accepts your changes."); + printf("]\n"); } /* Find the builtin whose command name is COMMAND and return the @@ -128,7 +133,7 @@ print_network_configuration (); grub_putchar ('\n'); #endif - print_cmdline_message (forever); + print_cmdline_message (forever ? CMDLINE_FOREVER_MODE : CMDLINE_NORMAL_MODE); while (1) { diff -Naur grub-0.96/stage2/graphics.c grub-0.96-r2/stage2/graphics.c --- grub-0.96/stage2/graphics.c 1970-01-01 01:00:00.000000000 +0100 +++ grub-0.96-r2/stage2/graphics.c 2006-07-25 09:33:45.000000000 +0200 @@ -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 -Naur grub-0.96/stage2/graphics.h grub-0.96-r2/stage2/graphics.h --- grub-0.96/stage2/graphics.h 1970-01-01 01:00:00.000000000 +0100 +++ grub-0.96-r2/stage2/graphics.h 2006-07-25 09:33:45.000000000 +0200 @@ -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 -Naur grub-0.96/stage2/Makefile.am grub-0.96-r2/stage2/Makefile.am --- grub-0.96/stage2/Makefile.am 2004-07-16 13:44:56.000000000 +0200 +++ grub-0.96-r2/stage2/Makefile.am 2006-07-25 09:33:45.000000000 +0200 @@ -7,7 +7,7 @@ fat.h filesys.h freebsd.h fs.h hercules.h i386-elf.h \ imgact_aout.h iso9660.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 ufs2.h vstafs.h xfs.h + terminfo.h tparm.h nbi.h ufs2.h vstafs.h xfs.h graphics.h EXTRA_DIST = setjmp.S apm.S $(noinst_SCRIPTS) # For . @@ -19,7 +19,7 @@ disk_io.c fsys_ext2fs.c fsys_fat.c fsys_ffs.c fsys_iso9660.c \ fsys_jfs.c fsys_minix.c fsys_reiserfs.c fsys_ufs2.c \ fsys_vstafs.c fsys_xfs.c gunzip.c md5.c serial.c stage2.c \ - terminfo.c tparm.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_ISO9660=1 -DFSYS_JFS=1 -DFSYS_MINIX=1 -DFSYS_REISERFS=1 \ @@ -80,8 +80,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 @@ -91,7 +97,8 @@ cmdline.c common.c console.c disk_io.c fsys_ext2fs.c \ fsys_fat.c fsys_ffs.c fsys_iso9660.c fsys_jfs.c fsys_minix.c \ fsys_reiserfs.c fsys_ufs2.c fsys_vstafs.c fsys_xfs.c gunzip.c \ - hercules.c md5.c serial.c smp-imps.c stage2.c terminfo.c tparm.c + hercules.c md5.c serial.c smp-imps.c stage2.c terminfo.c tparm.c \ + graphics.c pre_stage2_exec_CFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS) pre_stage2_exec_CCASFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS) pre_stage2_exec_LDFLAGS = $(PRE_STAGE2_LINK) diff -Naur grub-0.96/stage2/shared.h grub-0.96-r2/stage2/shared.h --- grub-0.96/stage2/shared.h 2004-06-19 18:40:09.000000000 +0200 +++ grub-0.96-r2/stage2/shared.h 2006-07-25 09:33:45.000000000 +0200 @@ -860,9 +860,15 @@ void init_config (void); char *skip_to (int after_equal, char *cmdline); struct builtin *find_command (char *command); -void print_cmdline_message (int forever); void enter_cmdline (char *heap, int forever); int run_script (char *script, char *heap); + +/* the flags for the cmdline message */ +#define CMDLINE_FOREVER_MODE 0x0 +#define CMDLINE_NORMAL_MODE 0x1 +#define CMDLINE_EDIT_MODE 0x2 + +void print_cmdline_message (int type); #endif /* C library replacement functions with identical semantics. */ @@ -871,6 +877,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 -Naur grub-0.96/stage2/stage2.c grub-0.96-r2/stage2/stage2.c --- grub-0.96/stage2/stage2.c 2004-07-24 20:53:47.000000000 +0200 +++ grub-0.96-r2/stage2/stage2.c 2006-07-25 09:33:45.000000000 +0200 @@ -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. @@ -319,7 +320,8 @@ if (config_entries) printf ("\ Press enter to boot the selected OS, \'e\' to edit the\n\ - commands before booting, or \'c\' for a command-line."); + commands before booting, \'a\' to modify the kernel arguments\n\ + before booting, or \'c\' for a command-line."); else printf ("\ Press \'b\' to boot, \'e\' to edit the selected command in the\n\ @@ -655,7 +657,7 @@ else { cls (); - print_cmdline_message (0); + print_cmdline_message (CMDLINE_EDIT_MODE); new_heap = heap + NEW_HEAPSIZE + 1; @@ -697,6 +699,98 @@ enter_cmdline (heap, 0); goto restart; } + if (config_entries && c == 'a') + { + int new_num_entries = 0, i = 0, j; + int needs_padding, amount; + char *new_heap; + char * entries; + char * entry_copy; + char * append_line; + char * start; + + entry_copy = new_heap = heap; + cur_entry = get_entry (config_entries, first_entry + entryno, + 1); + + do + { + while ((*(new_heap++) = cur_entry[i++]) != 0); + new_num_entries++; + } + while (config_entries && cur_entry[i]); + + /* this only needs to be done if config_entries is non-NULL, + but it doesn't hurt to do it always */ + *(new_heap++) = 0; + + new_heap = heap + NEW_HEAPSIZE + 1; + + entries = entry_copy; + while (*entries) + { + if ((strstr(entries, "kernel") == entries) && + isspace(entries[6])) + break; + + while (*entries) entries++; + entries++; + } + + if (!*entries) + goto restart; + + start = entries + 6; + + /* skip the white space */ + while (*start && isspace(*start)) start++; + /* skip the kernel name */ + while (*start && !isspace(*start)) start++; + + /* skip the white space */ + needs_padding = (!*start || !isspace(*start)); + while (*start && isspace(*start)) start++; + + append_line = new_heap; + grub_strcpy(append_line, start); + + cls(); + print_cmdline_message (CMDLINE_EDIT_MODE); + + if (get_cmdline(PACKAGE " append> ", + append_line, NEW_HEAPSIZE + 1, + 0, 1)) + goto restart; + + /* have new args; append_line points to the + new args and start points to the old + args */ + + i = grub_strlen(start); + j = grub_strlen(append_line); + + if (i > (j + needs_padding)) + amount = i; + else + amount = j + needs_padding; + + /* align rest of commands properly */ + memmove (start + j + needs_padding, start + i, + ((int) append_line) - ((int) start) - (amount)); + + if (needs_padding) + *start = ' '; + + /* copy command to correct area */ + memmove (start + needs_padding, append_line, j); + + /* set up this entry to boot */ + config_entries = NULL; + cur_entry = entry_copy; + heap = new_heap; + + break; + } #ifdef GRUB_UTIL if (c == 'q') { @@ -714,6 +808,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) { @@ -748,6 +851,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; } @@ -1049,6 +1159,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 -Naur grub-0.96/stage2/term.h grub-0.96-r2/stage2/term.h --- grub-0.96/stage2/term.h 2003-07-09 13:45:53.000000000 +0200 +++ grub-0.96-r2/stage2/term.h 2006-07-25 09:33:45.000000000 +0200 @@ -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 */ diff -Naur grub-0.96/util/grub-install.in grub-0.96-r2/util/grub-install.in --- grub-0.96/util/grub-install.in 2004-07-24 20:57:31.000000000 +0200 +++ grub-0.96-r2/util/grub-install.in 2006-07-25 09:32:54.000000000 +0200 @@ -447,6 +447,10 @@ rm -f $img_file rm -f $log_file +if ! test -e ${grubdir}/grub.conf ; then + test -e ${grubdir}/menu.lst && ln -s ./menu.lst ${grubdir}/grub.conf +fi + # Create a safe temporary file. test -n "$mklog" && log_file=`$mklog`