diff -Nru grub-0.95/configure.ac grub-0.95-new/configure.ac --- grub-0.95/configure.ac 2004-06-13 19:38:17.000000000 +0200 +++ grub-0.95-new/configure.ac 2004-08-20 22:51:11.051556727 +0200 @@ -207,9 +207,9 @@ # Unless the user specify --without-curses, check for curses. if test "x$with_curses" != "xno"; then - AC_CHECK_LIB(ncurses, wgetch, [GRUB_LIBS="$GRUB_LIBS -lncurses" + AC_CHECK_LIB(ncurses, wgetch, [GRUB_LIBS="$GRUB_LIBS -Wl,-Bstatic -lncurses -Wl,-Bdynamic" AC_DEFINE(HAVE_LIBCURSES, 1, [Define if you have a curses library])], - [AC_CHECK_LIB(curses, wgetch, [GRUB_LIBS="$GRUB_LIBS -lcurses" + [AC_CHECK_LIB(curses, wgetch, [GRUB_LIBS="$GRUB_LIBS -Wl,-Bstatic -lcurses -Wl,-Bdynamic" AC_DEFINE(HAVE_LIBCURSES, 1, [Define if you have a curses library])])]) fi @@ -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 -Nru grub-0.95/docs/grub.texi grub-0.95-new/docs/grub.texi --- grub-0.95/docs/grub.texi 2004-05-11 14:11:17.000000000 +0200 +++ grub-0.95-new/docs/grub.texi 2004-08-20 22:51:25.822051247 +0200 @@ -2010,6 +2010,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 @@ -2389,6 +2390,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 diff -Nru grub-0.95/lib/device.c grub-0.95-new/lib/device.c --- grub-0.95/lib/device.c 2004-05-23 18:34:29.000000000 +0200 +++ grub-0.95-new/lib/device.c 2004-08-20 22:53:24.497068834 +0200 @@ -131,6 +131,122 @@ #include #include +#if defined(__linux__) +/* The 2.6 kernel has removed all of the geometry handling for IDE drives + * that did fixups for LBA, etc. This means that the geometry we get + * with the ioctl has a good chance of being wrong. So, we get to + * also know about partition tables and try to read what the geometry + * is there. *grumble* Very closely based on code from cfdisk + */ +static void get_kernel_geometry(int fd, int *cyl, int *heads, int *sectors) { + struct hd_geometry hdg; + + if (ioctl (fd, HDIO_GETGEO, &hdg)) + return; + + *cyl = hdg.cylinders; + *heads = hdg.heads; + *sectors = hdg.sectors; +} + +struct partition { + unsigned char boot_ind; /* 0x80 - active */ + unsigned char head; /* starting head */ + unsigned char sector; /* starting sector */ + unsigned char cyl; /* starting cylinder */ + unsigned char sys_ind; /* What partition type */ + unsigned char end_head; /* end head */ + unsigned char end_sector; /* end sector */ + unsigned char end_cyl; /* end cylinder */ + unsigned char start4[4]; /* starting sector counting from 0 */ + unsigned char size4[4]; /* nr of sectors in partition */ +}; + +#define ALIGNMENT 2 +typedef union { + struct { + unsigned char align[ALIGNMENT]; + unsigned char b[SECTOR_SIZE]; + } c; + struct { + unsigned char align[ALIGNMENT]; + unsigned char buffer[0x1BE]; + struct partition part[4]; + unsigned char magicflag[2]; + } p; +} partition_table; + +#define PART_TABLE_FLAG0 0x55 +#define PART_TABLE_FLAG1 0xAA + +static void +get_partition_table_geometry(partition_table *bufp, int *cyl, int *heads, + int *sectors) { + struct partition *p; + int i,h,s,hh,ss; + int first = 1; + int bad = 0; + + if (bufp->p.magicflag[0] != PART_TABLE_FLAG0 || + bufp->p.magicflag[1] != PART_TABLE_FLAG1) { + /* Matthew Wilcox: slightly friendlier version of + fatal(_("Bad signature on partition table"), 3); + */ + fprintf(stderr, "Unknown partition table signature\n"); + return; + } + + hh = ss = 0; + for (i=0; i<4; i++) { + p = &(bufp->p.part[i]); + if (p->sys_ind != 0) { + h = p->end_head + 1; + s = (p->end_sector & 077); + if (first) { + hh = h; + ss = s; + first = 0; + } else if (hh != h || ss != s) + bad = 1; + } + } + + if (!first && !bad) { + *heads = hh; + *sectors = ss; + } +} + +static void get_linux_geometry (int fd, struct geometry *geom) { + int kern_cyl = 0, kern_head = 0, kern_sectors = 0; + int pt_cyl = 0, pt_head = 0, pt_sectors = 0; + partition_table bufp; + + get_kernel_geometry(fd, &kern_cyl, &kern_head, &kern_sectors); + + if (read(fd, bufp.c.b, SECTOR_SIZE) == SECTOR_SIZE) { + get_partition_table_geometry(&bufp, &pt_cyl, &pt_head, &pt_sectors); + } else { + fprintf(stderr, "Unable to read partition table: %s\n", strerror(errno)); + } + + if (pt_head && pt_sectors) { + int cyl_size; + + geom->heads = pt_head; + geom->sectors = pt_sectors; + cyl_size = pt_head * pt_sectors; + geom->cylinders = geom->total_sectors/cyl_size; + } else { + geom->heads = kern_head; + geom->sectors = kern_sectors; + geom->cylinders = kern_cyl; + } + + return; +} +#endif + /* Get the geometry of a drive DRIVE. */ void get_drive_geometry (struct geometry *geom, char **map, int drive) @@ -151,20 +267,16 @@ #if defined(__linux__) /* Linux */ { - struct hd_geometry hdg; unsigned long nr; - if (ioctl (fd, HDIO_GETGEO, &hdg)) - goto fail; - if (ioctl (fd, BLKGETSIZE, &nr)) goto fail; - - /* Got the geometry, so save it. */ - geom->cylinders = hdg.cylinders; - geom->heads = hdg.heads; - geom->sectors = hdg.sectors; + geom->total_sectors = nr; + get_linux_geometry(fd, geom); + + if (!geom->heads && !geom->cylinders && !geom->sectors) + goto fail; goto success; } @@ -858,7 +970,14 @@ 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) ? "p" : "", + ((partition >> 16) & 0xFF) + 1); /* Open the partition. */ fd = open (dev, O_RDWR); diff -Nru grub-0.95/stage2/Makefile.am grub-0.95-new/stage2/Makefile.am --- grub-0.95/stage2/Makefile.am 2004-06-13 19:57:27.000000000 +0200 +++ grub-0.95-new/stage2/Makefile.am 2004-08-20 22:51:11.043558627 +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 -Nru grub-0.95/stage2/asm.S grub-0.95-new/stage2/asm.S --- grub-0.95/stage2/asm.S 2004-05-23 18:22:23.000000000 +0200 +++ grub-0.95-new/stage2/asm.S 2004-08-20 22:51:11.033561001 +0200 @@ -2215,6 +2215,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 -Nru grub-0.95/stage2/boot.c grub-0.95-new/stage2/boot.c --- grub-0.95/stage2/boot.c 2004-03-30 13:44:08.000000000 +0200 +++ grub-0.95-new/stage2/boot.c 2004-08-20 22:53:06.009407458 +0200 @@ -824,8 +824,12 @@ moveto = (mbi.mem_upper + 0x400) << 10; moveto = (moveto - len) & 0xfffff000; +#if 0 max_addr = (lh->header == LINUX_MAGIC_SIGNATURE && lh->version >= 0x0203 ? lh->initrd_addr_max : LINUX_INITRD_MAX_ADDRESS); +#else + max_addr = LINUX_INITRD_MAX_ADDRESS; +#endif if (moveto + len >= max_addr) moveto = (max_addr - len) & 0xfffff000; diff -Nru grub-0.95/stage2/builtins.c grub-0.95-new/stage2/builtins.c --- grub-0.95/stage2/builtins.c 2004-05-14 21:30:52.000000000 +0200 +++ grub-0.95-new/stage2/builtins.c 2004-08-20 22:51:44.019739537 +0200 @@ -233,12 +233,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 (); @@ -302,6 +312,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; } @@ -760,6 +777,18 @@ default_func (char *arg, int flags) { #ifndef SUPPORT_DISKLESS +#ifndef GRUB_UTIL + /* Has a forced once-only default been specified? */ + static int savedefault_helper(int); + if ((saved_entryno & STAGE2_ONCEONLY_ENTRY) != 0) + { + int old_defaults=saved_entryno & ~STAGE2_ONCEONLY_ENTRY; + grub_timeout = 0; + default_entry = old_defaults >> 8; + savedefault_helper(old_defaults & 0xff); + return 0; + } +#endif if (grub_strcmp (arg, "saved") == 0) { default_entry = saved_entryno; @@ -846,6 +875,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 @@ -3180,22 +3341,15 @@ }; -/* savedefault */ + +#if !defined(SUPPORT_DISKLESS) && !defined(GRUB_UTIL) +/* Write specified default entry number into stage2 file. */ static int -savedefault_func (char *arg, int flags) +savedefault_helper(int new_default) { -#if !defined(SUPPORT_DISKLESS) && !defined(GRUB_UTIL) char buffer[512]; int *entryno_ptr; - - /* This command is only useful when you boot an entry from the menu - interface. */ - if (! (flags & BUILTIN_SCRIPT)) - { - errnum = ERR_UNRECOGNIZED; - return 1; - } - + /* Get the geometry of the boot drive (i.e. the disk which contains this stage2). */ if (get_diskinfo (boot_drive, &buf_geom)) @@ -3221,10 +3375,10 @@ entryno_ptr = (int *) (buffer + STAGE2_SAVED_ENTRYNO); /* Check if the saved entry number differs from current entry number. */ - if (*entryno_ptr != current_entryno) + if (*entryno_ptr != new_default) { /* Overwrite the saved entry number. */ - *entryno_ptr = current_entryno; + *entryno_ptr = new_default; /* Save the image in the disk. */ if (! rawwrite (boot_drive, install_second_sector, buffer)) @@ -3235,6 +3389,127 @@ } return 0; +} +#endif + +#if !defined(SUPPORT_DISKLESS) && defined(GRUB_UTIL) +/* + * Full implementation of new `savedefault' for GRUB shell. + * XXX This needs fixing for stage2 files which aren't accessible + * through a mounted filesystem. + */ +static int +savedefault_shell(char *arg, int flags) +{ + char *stage2_os_file = "/boot/grub/stage2"; /* Default filename */ + FILE *fp; + char buffer[512]; + int *entryno_ptr; + int new_default = 0; + int old_default = 0; + + while (1) + { + if (grub_memcmp ("--stage2=", arg, sizeof ("--stage2=") - 1) == 0) + { + stage2_os_file = arg + sizeof ("--stage2=") - 1; + arg = skip_to (0, arg); + nul_terminate (stage2_os_file); + } + else if (grub_memcmp ("--default=", arg, sizeof ("--default=") - 1) == 0) + { + char *p = arg + sizeof ("--default=") - 1; + if (! safe_parse_maxint (&p, &new_default)) + return 1; + arg = skip_to (0, arg); + } + else if (grub_memcmp ("--once", arg, sizeof ("--once") - 1) == 0) + { + new_default <<= 8; + new_default |= STAGE2_ONCEONLY_ENTRY; + arg = skip_to (0, arg); + } + else + break; + } + + if (! (fp = fopen(stage2_os_file, "r+"))) + { + errnum = ERR_FILE_NOT_FOUND; + return 1; + } + + if (fseek (fp, SECTOR_SIZE, SEEK_SET) != 0) + { + fclose (fp); + errnum = ERR_BAD_VERSION; + return 1; + } + + if (fread (buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE) + { + fclose (fp); + errnum = ERR_READ; + return 1; + } + + /* Sanity check. */ + if (buffer[STAGE2_STAGE2_ID] != STAGE2_ID_STAGE2 + || *((short *) (buffer + STAGE2_VER_MAJ_OFFS)) != COMPAT_VERSION) + { + errnum = ERR_BAD_VERSION; + return 1; + } + + entryno_ptr = (int *) (buffer + STAGE2_SAVED_ENTRYNO); + if (new_default & STAGE2_ONCEONLY_ENTRY) + { + old_default=*entryno_ptr; + *entryno_ptr = new_default + (old_default & 0xFF); + } + else + { + *entryno_ptr = new_default; + } + + if (fseek (fp, SECTOR_SIZE, SEEK_SET) != 0) + { + fclose (fp); + errnum = ERR_BAD_VERSION; + return 1; + } + + if (fwrite (buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE) + { + fclose (fp); + errnum = ERR_WRITE; + return 1; + } + + (void)fflush (fp); + fclose (fp); + return 0; +} +#endif + +/* savedefault */ +static int +savedefault_func (char *arg, int flags) +{ +#if !defined(SUPPORT_DISKLESS) +#if !defined(GRUB_UTIL) + /* This command is only useful when you boot an entry from the menu + interface. */ + if (! (flags & BUILTIN_SCRIPT)) + { + errnum = ERR_UNRECOGNIZED; + return 1; + } + + return savedefault_helper(current_entryno); +#else /* defined(GRUB_UTIL) */ + return savedefault_shell(arg, flags); +#endif #else /* ! SUPPORT_DISKLESS && ! GRUB_UTIL */ errnum = ERR_UNRECOGNIZED; return 1; @@ -3246,8 +3521,14 @@ "savedefault", savedefault_func, BUILTIN_CMDLINE, +#ifdef GRUB_UTIL + "savedefault [--stage2=STAGE2_FILE] [--default=DEFAULT] [--once]", + "Save DEFAULT as the default boot entry in STAGE2_FILE. If '--once'" + " is specified, the default is reset after the next reboot." +#else "savedefault", "Save the current entry as the default boot entry." +#endif }; @@ -3958,7 +4239,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) @@ -4117,17 +4398,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; } @@ -4137,7 +4422,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" @@ -4149,7 +4434,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 @@ -4471,6 +4756,15 @@ static int timeout_func (char *arg, int flags) { + /* One-shot default shenanigans -- don't piss around with the menu! */ + if (grub_timeout != -1) + return 0; + if ((saved_entryno & STAGE2_ONCEONLY_ENTRY) != 0) + { + grub_timeout = 0; + return 0; + } + if (! safe_parse_maxint (&arg, &grub_timeout)) return 1; @@ -4668,6 +4962,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 @@ -4675,6 +4972,7 @@ #endif /* SUPPORT_NETBOOT */ &builtin_cat, &builtin_chainloader, + &builtin_clear, &builtin_cmp, &builtin_color, &builtin_configfile, @@ -4694,6 +4992,9 @@ &builtin_embed, &builtin_fallback, &builtin_find, +#ifdef SUPPORT_GRAPHICS + &builtin_foreground, +#endif &builtin_fstest, &builtin_geometry, &builtin_halt, @@ -4737,9 +5038,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 -Nru grub-0.95/stage2/char_io.c grub-0.95-new/stage2/char_io.c --- grub-0.95/stage2/char_io.c 2004-05-23 18:45:43.000000000 +0200 +++ grub-0.95-new/stage2/char_io.c 2004-08-20 22:51:11.050556964 +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 -Nru grub-0.95/stage2/cmdline.c grub-0.95-new/stage2/cmdline.c --- grub-0.95/stage2/cmdline.c 2004-03-18 00:08:48.000000000 +0100 +++ grub-0.95-new/stage2/cmdline.c 2004-08-20 22:50:12.302552672 +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 -Nru grub-0.95/stage2/graphics.c grub-0.95-new/stage2/graphics.c --- grub-0.95/stage2/graphics.c 1970-01-01 01:00:00.000000000 +0100 +++ grub-0.95-new/stage2/graphics.c 2004-08-20 22:51:11.042558864 +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 -Nru grub-0.95/stage2/graphics.h grub-0.95-new/stage2/graphics.h --- grub-0.95/stage2/graphics.h 1970-01-01 01:00:00.000000000 +0100 +++ grub-0.95-new/stage2/graphics.h 2004-08-20 22:51:11.045558152 +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 -Nru grub-0.95/stage2/shared.h grub-0.95-new/stage2/shared.h --- grub-0.95/stage2/shared.h 2004-05-14 21:38:37.000000000 +0200 +++ grub-0.95-new/stage2/shared.h 2004-08-20 22:51:11.047557677 +0200 @@ -196,6 +196,8 @@ #define STAGE2_FORCE_LBA 0x11 #define STAGE2_VER_STR_OFFS 0x12 +#define STAGE2_ONCEONLY_ENTRY 0x10000 + /* Stage 2 identifiers */ #define STAGE2_ID_STAGE2 0 #define STAGE2_ID_FFS_STAGE1_5 1 @@ -854,9 +856,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. */ @@ -865,6 +873,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 -Nru grub-0.95/stage2/stage2.c grub-0.95-new/stage2/stage2.c --- grub-0.95/stage2/stage2.c 2004-03-27 17:09:41.000000000 +0100 +++ grub-0.95-new/stage2/stage2.c 2004-08-20 22:51:56.637754429 +0200 @@ -233,6 +233,9 @@ { int c, time1, time2 = -1, first_entry = 0; char *cur_entry = 0; + struct term_entry *prev_term = NULL; + + cls(); /* * Main loop for menu UI. @@ -261,11 +264,12 @@ /* Get current time. */ while ((time1 = getrtsecs ()) == 0xFF) ; + grub_printf("\rPress any key to enter the menu\n\n\n"); while (1) { /* Check if ESC is pressed. */ - if (checkkey () != -1 && ASCII_CHAR (getkey ()) == '\e') + if (checkkey () != -1) { grub_timeout = -1; show_menu = 1; @@ -287,7 +291,8 @@ grub_timeout--; /* Print a message. */ - grub_printf ("\rPress `ESC' to enter the menu... %d ", + grub_printf ("\rBooting %s in %d seconds...", + get_entry(menu_entries, first_entry + entryno, 0), grub_timeout); } } @@ -319,7 +324,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 +661,7 @@ else { cls (); - print_cmdline_message (0); + print_cmdline_message (CMDLINE_EDIT_MODE); new_heap = heap + NEW_HEAPSIZE + 1; @@ -697,6 +703,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 +812,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 +852,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 +1103,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 -Nru grub-0.95/stage2/term.h grub-0.95-new/stage2/term.h --- grub-0.95/stage2/term.h 2003-07-09 13:45:53.000000000 +0200 +++ grub-0.95-new/stage2/term.h 2004-08-20 22:51:11.044558389 +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 -Nru grub-0.95/util/grub-install.in grub-0.95-new/util/grub-install.in --- grub-0.95/util/grub-install.in 2004-03-12 19:07:57.000000000 +0100 +++ grub-0.95-new/util/grub-install.in 2004-08-20 22:49:24.970892766 +0200 @@ -40,6 +40,7 @@ force_lba= recheck=no debug=no +justcopy=no # look for secure tempfile creation wrappers on this platform if test -x /bin/tempfile; then @@ -223,6 +224,17 @@ echo "$tmp_fname" } +copy_images() { + # Copy the GRUB images to the GRUB directory. + for file in ${grubdir}/stage1 ${grubdir}/stage2 ${grubdir}/*stage1_5; do + rm -f $file || exit 1 + done + for file in \ + ${pkgdatadir}/stage1 ${pkgdatadir}/stage2 ${pkgdatadir}/*stage1_5; do + cp -f $file ${grubdir} || exit 1 + done +} + # Check the arguments. for option in "$@"; do case "$option" in @@ -242,6 +254,8 @@ force_lba="--force-lba" ;; --recheck) recheck=yes ;; + --just-copy) + justcopy=yes ;; # This is an undocumented feature... --debug) debug=yes ;; @@ -260,12 +274,6 @@ esac done -if test "x$install_device" = x; then - echo "install_device not specified." 1>&2 - usage - exit 1 -fi - # If the debugging feature is enabled, print commands. if test $debug = yes; then set -x @@ -288,6 +296,18 @@ grubdir=${bootdir}/grub device_map=${grubdir}/device.map +# if they just want the images copied, copy the images and then exit +if test $justcopy = yes; then + copy_images + exit 0 +fi + +if test "x$install_device" = x; then + echo "install_device not specified." 1>&2 + usage + exit 1 +fi + # Check if GRUB is installed. # This is necessary, because the user can specify "grub --read-only". set $grub_shell dummy @@ -319,6 +339,8 @@ test -d "$bootdir" || mkdir "$bootdir" || exit 1 test -d "$grubdir" || mkdir "$grubdir" || exit 1 +copy_images + # If --recheck is specified, remove the device map, if present. if test $recheck = yes; then rm -f $device_map @@ -331,6 +353,10 @@ # Create a safe temporary file. test -n "$mklog" && log_file=`$mklog` + # Before all invocations of the grub shell, call sync to make sure + # the raw device is in sync with any bufferring in filesystems. + sync + $grub_shell --batch $no_floppy --device-map=$device_map <$log_file quit EOF @@ -401,15 +427,6 @@ exit 1 fi -# Copy the GRUB images to the GRUB directory. -for file in ${grubdir}/stage1 ${grubdir}/stage2 ${grubdir}/*stage1_5; do - rm -f $file || exit 1 -done -for file in \ - ${pkgdatadir}/stage1 ${pkgdatadir}/stage2 ${pkgdatadir}/*stage1_5; do - cp -f $file ${grubdir} || exit 1 -done - # Make sure that GRUB reads the same images as the host OS. test -n "$mkimg" && img_file=`$mkimg` test -n "$mklog" && log_file=`$mklog` @@ -442,6 +459,10 @@ # Create a safe temporary file. test -n "$mklog" && log_file=`$mklog` +# Before all invocations of the grub shell, call sync to make sure +# the raw device is in sync with any bufferring in filesystems. +sync + # Now perform the installation. $grub_shell --batch $no_floppy --device-map=$device_map <$log_file root $root_drive