Ok, seeing a few changes in grub recently, I think I might have
another go at it. The fixes at least made it load config files on my
machine, but stage 1.5 still didn't work....
...
(very, very long pause!)
...
.... so here I am finally with a patch, having taken up most of the
weekend :-(
It turns out that the stage 1.5 stuff was completely broken - it can't
have been working at all for a while. The first instruction jumped to
the wrong place, and it didn't include code to open partitions. So I
fixed that, and fixed install to enable one to set a partition
correctly into stage 1.5, and now... it works!
Anyway during all that I added one useful command, chainconfig= which
lets one do submenus, and jump to a useful config file from a command
line dumped grub. I also added --enable-write support to
/sbin/grub. Very handy!
So here's the patch: (Changelog entries and docs included)
diff -r -u3 --exclude=*.in grub-cvs/ChangeLog grub/ChangeLog
--- grub-cvs/ChangeLog Sat May 8 11:29:44 1999
+++ grub/ChangeLog Sun May 9 18:57:39 1999
@@ -1,3 +1,15 @@
+1999-05-09 Brian Brunswick <[EMAIL PROTECTED]>
+
+ * shared_src/cmdline.c: Add chainconfig; p<dev> option on install.
+
+ * grub/asmstub.c:
+ * grub/main.c: Added support for --enable-write option
+
+ * shared_src/asm.S: Fix startup for stage 1.5
+ * shared_src/cmdline.c: Fix install for stage 1.5
+ * shared_src/disk_io.c:
+ * shared_src/stage1_5.c: Fix partition selection for stage 1.5
+
1999-05-03 Gordon Matzigkeit <[EMAIL PROTECTED]>
From Pavel Roskin:
diff -r -u3 --exclude=*.in grub-cvs/docs/commands.txt grub/docs/commands.txt
--- grub-cvs/docs/commands.txt Sat May 8 11:31:32 1999
+++ grub/docs/commands.txt Sun May 9 18:52:13 1999
@@ -144,7 +144,8 @@
Loads an initial ramdisk for a Linux format boot image and sets
the appropriate parameters in the Linux setup area in memory.
- -- "install= <stage1_file> [d] <dest_dev> <file> <addr> [p] [<config_file>]"
+ -- "install= <stage1_file> [d] <dest_dev> <file> <addr>
+ [p][<dev>] [<config_file>]"
This command is fairly complex, and for detailed examples one
should look at the install documentation. In short, it will
perform a full install presuming the stage1.5 or stage2 (they're
@@ -163,6 +164,7 @@
block of the device <dest_dev>. If the options "p" or <config_file>
are present, then it reads the first block of stage2, modifies it
with the values of the partition <file> was found on (for "p") or
+ the partition specified after the p in the format p<dev> or
places the string <config_file> into the area telling the stage2
where to look for a configuration file at boot time. Finally, it
preserves the DOS BPB (and for hard disks, the partition table) of
@@ -178,6 +180,10 @@
if running the fully interactive command-line (it is implicit at the
end of a config-file entry).
+ -- "chainconfig= <new_config_file>"
+ Loads the <new_config_file> as a new config file and restarts
+ the GRUB Stage 2. This can be used to implement submenus or from
+ the command line to recover easily from a bad or misplaced config.
Commands usable in config files and interactively which are only available
in the debug version of the GRUB Stage 2.
diff -r -u3 --exclude=*.in grub-cvs/docs/install.lst grub/docs/install.lst
--- grub-cvs/docs/install.lst Sun May 9 19:03:19 1999
+++ grub/docs/install.lst Sun May 9 19:04:50 1999
@@ -0,0 +1,37 @@
+title=main menu...
+chainconfig=/boot/grub/menu.lst
+
+# For installing GRUB into the hard disk
+title= Install GRUB into the hard disk
+root= (hd0,0)
+install= /boot/grub/stage1 d (hd0) /boot/grub/stage2 0x8000 p
+
+title=install to /dev/hda2 for stage1_5 on /dev/hda block 1+20
+root=(hd0,1)
+install=/boot/grub/stage1 d (hd0,1) (hd0)1+20 0x2000 p(hd0,1) /boot/grub/stage2
+# Note stage1_5 won't understand partition specs in stage2 file
+# Intended for use after using:
+# dd < e2fs_stage1_5 1<> /dev/hda seek=1 bs=512
+
+title=install to /dev/hda2 for stage2 on /dev/hda2
+root=(hd0,1)
+install=/boot/grub/stage1 d (hd0,1) /boot/grub/stage2 0x8000 p
+(hd0,1)/boot/grub/menu.lst
+# the partition spec in config file means it will be found when booting
+# from a floppy created by :cat /grub/stage1 /grub/stage2 > /dev/fd0
+# using the modified stage2 created by the install line.
+
+title=hda1 active
+root=(hd0,0)
+makeactive
+
+title=hda2 active
+root=(hd0,1)
+makeactive
+
+title=hda3 active
+root=(hd0,2)
+makeactive
+
+title=hda4 active
+root=(hd0,3)
+makeactive
diff -r -u3 --exclude=*.in grub-cvs/docs/menu.lst grub/docs/menu.lst
--- grub-cvs/docs/menu.lst Sat May 8 11:32:07 1999
+++ grub/docs/menu.lst Sun May 9 19:03:37 1999
@@ -43,7 +43,7 @@
makeactive
chainloader= +1
-# For installing GRUB into the hard disk
-title= Install GRUB into the hard disk
-root= (hd0,0)
-install= /boot/grub/stage1 d (hd0) /boot/grub/stage2 0x8000 p
+title=install menu...
+chainconfig=/boot/grub/install.lst
+pause=Press any key to return to menu
+
diff -r -u3 --exclude=*.in grub-cvs/grub/asmstub.c grub/grub/asmstub.c
--- grub-cvs/grub/asmstub.c Sat May 8 11:33:31 1999
+++ grub/grub/asmstub.c Sun May 9 14:08:33 1999
@@ -58,10 +58,14 @@
#define DEFAULT_HD_HEADS 128
#define DEFAULT_HD_SECTORS 63
+extern int enable_write; /* allow writing to the disk */
+
unsigned long install_partition = 0x20000;
unsigned long boot_drive = 0;
char version_string[] = VERSION;
char config_file[128] = "/boot/grub/menu.lst"; /* FIXME: arbitrary */
+/* FIXME - assumption that config_file_end is immediately after config_file */
+char config_file_end[] = "";
/* Emulation requirements. */
char *grub_scratch_mem = 0;
@@ -478,9 +482,9 @@
return -1;
/* Open read/write, or read-only if that failed. */
- disks[drive].flags = open (devname, O_RDWR);
+ disks[drive].flags = open (devname, O_RDWR|O_SYNC);
if (! disks[drive].flags)
- disks[drive].flags = open (devname, O_RDONLY);
+ disks[drive].flags = open (devname, O_RDONLY|O_SYNC);
/* Attempt to read the first sector. */
if (read (disks[drive].flags, buf, 512) != 512)
@@ -570,9 +574,25 @@
buf = (char *) (segment << 4);
/* FIXME: handle EINTR */
- if (read (fd, buf, nsec * SECTOR_SIZE) != nsec * SECTOR_SIZE)
+ switch (subfunc)
+ {
+ case BIOSDISK_READ:
+ if (read (fd, buf, nsec * SECTOR_SIZE) != nsec * SECTOR_SIZE)
+ return -1;
+ return 0;
+ case BIOSDISK_WRITE:
+ if (enable_write)
+ {
+ if (write (fd, buf, nsec * SECTOR_SIZE) != nsec * SECTOR_SIZE)
+ return -1;
+ fsync(fd);
+ }
+ else
+ grub_printf("(use --enable-write to actually write %d+%d)",sector,nsec);
+ return 0;
+ default:
return -1;
- return 0;
+ }
}
diff -r -u3 --exclude=*.in grub-cvs/grub/main.c grub/grub/main.c
--- grub-cvs/grub/main.c Sat May 8 11:33:33 1999
+++ grub/grub/main.c Sun May 9 01:07:49 1999
@@ -37,6 +37,7 @@
static int default_boot_drive;
static int default_install_partition;
static char *default_config_file;
+int enable_write = 0;
#define OPT_HELP -2
#define OPT_VERSION -3
@@ -47,6 +48,7 @@
#define OPT_DISABLE_CONFIG_FILE -8
#define OPT_DISABLE_CURSES -9
#define OPT_BATCH -10
+#define OPT_ENABLE_WRITE -11
#define OPTSTRING ""
static struct option longopts[] =
@@ -60,6 +62,7 @@
{"disable-config-file", no_argument, 0, OPT_DISABLE_CONFIG_FILE},
{"disable-curses", no_argument, 0, OPT_DISABLE_CURSES},
{"batch", no_argument, 0, OPT_BATCH},
+ {"enable-write", no_argument, 0, OPT_ENABLE_WRITE},
{0},
};
@@ -81,6 +84,7 @@
--config-file=FILE specify stage2 config_file [default=%s]\n\
--disable-config-file disable to use the config file\n\
--disable-curses disable to use curses\n\
+ --enable-write enable writing to the disk\n\
--help display this message and exit\n\
--hold wait until a debugger will attach\n\
--install-partition=PAR specify stage2 install_partition [default=0x%x]\n\
@@ -158,6 +162,10 @@
case OPT_DISABLE_CURSES:
use_curses = 0;
+ break;
+
+ case OPT_ENABLE_WRITE:
+ enable_write = 1;
break;
case OPT_BATCH:
diff -r -u3 --exclude=*.in grub-cvs/shared_src/asm.S grub/shared_src/asm.S
--- grub-cvs/shared_src/asm.S Sat May 8 11:33:43 1999
+++ grub/shared_src/asm.S Sun May 9 18:26:23 1999
@@ -37,7 +37,11 @@
/*
* Guarantee that "start" is loaded at 0x0:0x8000.
*/
+#ifndef STAGE1_5
ljmp $0, $(codestart - EXT_C(start) + 0x8000)
+#else
+ ljmp $0, $(codestart - EXT_C(start) + 0x2000)
+#endif
/*
* Compatibility version number
@@ -70,6 +74,7 @@
*/
. = EXT_C(start) + 0x70
+VARIABLE(config_file_end)
/* the real mode code continues... */
codestart:
diff -r -u3 --exclude=*.in grub-cvs/shared_src/cmdline.c grub/shared_src/cmdline.c
--- grub-cvs/shared_src/cmdline.c Sat May 8 11:33:54 1999
+++ grub/shared_src/cmdline.c Sun May 9 14:06:49 1999
@@ -105,13 +105,15 @@
" Possible commands are: \"pause= ...\", \"uppermem= <kbytes>\", \"root= <device>\",
\"rootnoverify= <device>\", \"chainloader= <file>\", \"kernel= <file> ...\",
\"testload= <file>\", \"read= <addr>\", \"displaymem\", \"impsprobe\", \"fstest\",
- \"module= <file> ...\", \"modulenounzip= <file> ...\", \"makeactive\", \"boot\", and
+ \"module= <file> ...\", \"modulenounzip= <file> ...\", \"makeactive\", \"boot\",
+ \"chainconfig= <config_file>\", and
\"install= <stage1_file> [d] <dest_dev> <file> <addr> [p] [<config_file>]\"\n";
#else /* DEBUG */
char commands[] =
" Possible commands are: \"pause= ...\", \"uppermem= <kbytes>\", \"root= <device>\",
\"rootnoverify= <device>\", \"chainloader= <file>\", \"kernel= <file> ...\",
- \"module= <file> ...\", \"modulenounzip= <file> ...\", \"makeactive\", \"boot\", and
+ \"module= <file> ...\", \"modulenounzip= <file> ...\", \"makeactive\", \"boot\",
+ \"chainconfig= <config_file>\", and
\"install= <stage1_file> [d] <dest_dev> <file> <addr> [p] [<config_file>]\"\n";
#endif /* DEBUG */
@@ -271,6 +273,12 @@
type = 0;
}
}
+ else if (substring("chainconfig", cur_heap) < 1)
+ {
+ config_file[0]=0; /* fake strcpy */
+ strncat(config_file,cur_cmdline,config_file_end-config_file);
+ return 2;
+ }
else if (substring("pause", cur_heap) < 1)
{
if (ASCII_CHAR (getkey ()) == 27)
@@ -378,6 +386,7 @@
set_device (dest_dev) && open_partition () &&
devread (0, 0, SECTOR_SIZE, old_sect))
{
+ long stage2start=0x70ea+((unsigned long)installaddr<<8);
int dest_drive = current_drive;
struct geometry dest_geom = buf_geom;
int dest_sector = part_start, i;
@@ -439,7 +448,7 @@
if (!errnum &&
grub_read ((char *) SCRATCHADDR, SECTOR_SIZE) == SECTOR_SIZE)
{
- if (*((long *)SCRATCHADDR) != 0x8070ea
+ if (*((long *)SCRATCHADDR) != stage2start
|| (*((short *)(SCRATCHADDR+STAGE2_VER_MAJ_OFFS))
!= COMPAT_VERSION))
errnum = ERR_BAD_VERSION;
@@ -452,9 +461,19 @@
if (*ptr == 'p')
{
+ long patch_partition = current_partition;
+ if (ptr[1]!=' ')
+ {
+ long save_current_partition = current_partition;
+ long save_current_drive = current_drive;
+ set_device(ptr+1);
+ patch_partition = current_partition;
+ current_partition = save_current_partition;
+ current_drive = save_current_drive;
+ }
write_stage2_sect++;
*((long *)(SCRATCHADDR+STAGE2_INSTALLPART))
- = current_partition;
+ = patch_partition;
ptr = skip_to(0, ptr);
}
if (*ptr)
@@ -467,7 +486,7 @@
while ((*(str++) = *(ptr++)) != 0); /* do copy */
}
- grub_read ((char *) 0x100000, -1);
+ grub_read ((char*)RAW_ADDR(0x100000), -1);
buf_track = -1;
@@ -494,6 +513,7 @@
/* Error running the install script, so drop to command line. */
if (script)
{
+ print_error();
fallback = -1;
return 1;
}
@@ -515,7 +535,7 @@
/* read whole file first */
printf("Whole file: ");
- grub_read ((char *) 0x100000, -1);
+ grub_read ((char *)RAW_ADDR(0x100000), -1);
/* now compare two sections of the file read differently */
diff -r -u3 --exclude=*.in grub-cvs/shared_src/disk_io.c grub/shared_src/disk_io.c
--- grub-cvs/shared_src/disk_io.c Sat May 8 11:34:04 1999
+++ grub/shared_src/disk_io.c Sun May 9 18:33:23 1999
@@ -64,7 +64,11 @@
int bsd_evil_hack;
/* filesystem type */
+#ifndef STAGE1_5
int fsys_type = NUM_FSYS;
+#else
+int fsys_type = 0; /* default to first type (only in stage 1.5) */
+#endif /* def STAGE1_5 */
#ifndef NO_BLOCK_FILES
int block_file = 0;
#endif /* NO_BLOCK_FILES */
@@ -231,7 +235,6 @@
}
-#if !defined(STAGE1_5) || !defined(NO_BLOCK_FILES)
static int
sane_partition (void)
{
@@ -247,10 +250,8 @@
errnum = ERR_DEV_VALUES;
return 0;
}
-#endif /* !defined(STAGE1_5) || !defined(NO_BLOCK_FILES) */
-#ifndef STAGE1_5
static void
attempt_mount (void)
{
@@ -260,7 +261,6 @@
if (fsys_type == NUM_FSYS && errnum == ERR_NONE)
errnum = ERR_FSYS_MOUNT;
}
-#endif /* STAGE1_5 */
#ifndef STAGE1_5
@@ -384,7 +384,6 @@
#endif /* !defined(STAGE1_5) || !defined(NO_BLOCK_FILES) */
-#if !defined(STAGE1_5) || !defined(NO_BLOCK_FILES)
/* This isn't static, because the GRUB utility's char_io.c (memcheck)
needs to know about it as a special case. */
char cur_part_desc[16];
@@ -492,9 +491,11 @@
{
if ((current_partition & 0xFF00) != 0xFF00)
{
+#if !defined(STAGE1_5) || !defined(NO_BLOCK_FILES)
if (current_slice == PC_SLICE_TYPE_BSD)
check_BSD_parts (0);
else
+#endif /* !defined(STAGE1_5) || !defined(NO_BLOCK_FILES) */
errnum = ERR_NO_PART;
}
@@ -525,10 +526,12 @@
* We're looking at a floppy disk
*/
ext = -1;
+#if !defined(STAGE1_5) || !defined(NO_BLOCK_FILES)
if ((flags || (current_partition & 0xFF00) != 0xFF00)
&& check_BSD_parts (flags))
ext = -2;
else
+#endif /* !defined(STAGE1_5) || !defined(NO_BLOCK_FILES) */
{
errnum = 0;
if (!flags)
@@ -566,7 +569,6 @@
{
return real_open_partition (0);
}
-#endif /* !defined(STAGE1_5) || !defined(NO_BLOCK_FILES) */
#ifndef STAGE1_5
@@ -752,7 +754,6 @@
}
#endif /* STAGE1_5 */
-#ifndef STAGE1_5
/*
* This performs a "mount" on the current device, both drive and partition
* number.
@@ -769,7 +770,6 @@
return 1;
}
-#endif /* STAGE1_5 */
#ifndef STAGE1_5
@@ -964,6 +964,9 @@
#ifndef STAGE1_5
if (!(filename = setup_part (filename)))
+ return 0;
+#else
+ if (!open_device())
return 0;
#endif /* STAGE1_5 */
diff -r -u3 --exclude=*.in grub-cvs/shared_src/shared.h grub/shared_src/shared.h
--- grub-cvs/shared_src/shared.h Sat May 8 11:34:26 1999
+++ grub/shared_src/shared.h Sun May 9 14:04:59 1999
@@ -281,6 +281,7 @@
extern unsigned long boot_drive;
extern char version_string[];
extern char config_file[];
+extern char config_file_end[]; /* limit of config_file area */
#ifdef GRUB_UTIL
/* If not using config file, this variable is set to zero,
diff -r -u3 --exclude=*.in grub-cvs/shared_src/stage1_5.c grub/shared_src/stage1_5.c
--- grub-cvs/shared_src/stage1_5.c Sat May 8 11:34:30 1999
+++ grub/shared_src/stage1_5.c Sun May 9 18:31:44 1999
@@ -29,6 +29,8 @@
* Here load the true second-stage boot-loader.
*/
+ current_drive = boot_drive;
+ current_partition = install_partition;
if (grub_open (config_file) && grub_read ((char *) 0x8000, -1))
chain_stage2 (0, 0x8000);
@@ -37,6 +39,5 @@
*/
print_error ();
-
stop ();
}
diff -r -u3 --exclude=*.in grub-cvs/shared_src/stage2.c grub/shared_src/stage2.c
--- grub-cvs/shared_src/stage2.c Sat May 8 11:34:32 1999
+++ grub/shared_src/stage2.c Sun May 9 13:52:11 1999
@@ -415,7 +415,8 @@
}
if (c == 'c')
{
- enter_cmdline (NULL, heap);
+ if (enter_cmdline (NULL, heap)==2)
+ return;
goto restart;
}
}
@@ -439,7 +440,10 @@
if (!cur_entry)
cur_entry = get_entry(config_entries, first_entry+entryno, 1);
- if (!(c = enter_cmdline (cur_entry, heap)))
+ c = enter_cmdline (cur_entry, heap);
+ if (c==2) /* special code means chainconfig was used */
+ return; /* back to outer loop reloads config */
+ if (!c)
{
if (fallback < 0)
break;
@@ -610,14 +614,13 @@
*/
if (!num_entries)
- while (1)
- enter_cmdline (NULL, config_entries);
-
- /*
- * Run menu interface (this shouldn't return!).
- */
-
- run_menu(menu_entries, config_entries, num_entries,
- menu_entries+menu_len, default_entry);
+ while (enter_cmdline (NULL, config_entries)!=2)
+ ; /* 2 means reload new config file */
+ else
+ /*
+ * run menu interface; only returns if new config file
+ */
+ run_menu(menu_entries, config_entries, num_entries,
+ menu_entries+menu_len, default_entry);
}
}
--
[EMAIL PROTECTED]!Shortsig rules!