/sbin/grub works

This commit is contained in:
gord 1999-03-21 23:50:33 +00:00
parent db34e7d7f1
commit 3688d873d4
12 changed files with 302 additions and 122 deletions

View File

@ -1,3 +1,48 @@
1999-03-21 Gordon Matzigkeit <gord@trick.fig.org>
* shared_src/boot.c (load_image): Make sure we use the mapped
address before actually writing data to memaddr.
* shared_src/char_io.c (get_cmdline): Only zero-terminate if there
were leading blanks. This prevents accidental truncation of
commands.
* grub/asmstub.c (get_diskinfo): Cache device geometries as well
as file handles.
Use the Linux HDIO_GETGEO ioctl to make a better guess at hard
disk geometries.
1999-03-16 Gordon Matzigkeit <gord@trick.fig.org>
* shared_src/shared.h (geometry_t): Delete typedef, until we
actually use it.
1999-03-16 OKUJI Yoshinori <okuji@kuicr.kyoto-u.ac.jp>
* shared_src/asm.S (biosdisk): Use a structure for geometry
instead of a integer.
(get_diskinfo): Take a pointer to a geometry structure as the
second argument, and fill a geometry in it. Return 1 if an error
occurs, otherwise return 0.
* shared_src/boot.c (bsd_boot): Compute BIOS geometries for BSD.
* shared_src/cmdline.c (enter_cmdline): Declare dest_geom as
struct geometry.
* shared_src/disk_io.c (buf_geom): Declare as struct geometry.
* shared_src/filesys.h (SECTORS): Deleted.
(HEADS): Likewise.
(CYLINDERS): Likewise.
* shared_src/shared.h (BIOSDISK_FLAG_LBA_EXTENSION): New macro.
(struct geometry): New structure.
(buf_geom): Correct the prototype.
(get_diskinfo): Likewise.
(biosdisk): Likewise.
1999-03-15 Gordon Matzigkeit <gord@trick.fig.org>
* grub/asmstub.c (doit): Nested function to get a clean stack
frame while in grub_stage2.
Use different assembler magic. From OKUJI Yoshinori.
1999-03-14 Gordon Matzigkeit <gord@trick.fig.org>
* shared_src/stage2.c (run_menu): Use A_REVERSE and A_NORMAL

4
NEWS
View File

@ -1,5 +1,9 @@
NEWS - list of user-visible changes between releases of GRUB
New:
* The /sbin/grub stage2 simulator now works for simple cases, and uses
the Linux HDIO_GETGEO ioctl to determine hard disk geometry.
New in 0.5.91 - 1999-03-14, Gordon Matzigkeit:
* LBA and preliminary AWARD BIOS disk extension support.
* Started docs/grub.texi.

2
configure vendored
View File

@ -692,7 +692,7 @@ fi
PACKAGE=grub
VERSION=0.5.91
VERSION=0.5.92
if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then

6
debian/changelog vendored
View File

@ -1,3 +1,9 @@
grub (0.5.92) unstable; urgency=low
*
--
grub (0.5.91) unstable; urgency=low
* Added support for LBA mode and preliminary AWARD/AMI hard disk BIOS

View File

@ -39,10 +39,22 @@ int grub_stage2 (void);
#include <assert.h>
#include <stdio.h>
#ifdef __linux__
# include <sys/ioctl.h> /* ioctl */
# include <linux/hdreg.h> /* HDIO_GETGEO */
#endif /* __linux__ */
/* Simulated memory sizes. */
#define EXTENDED_MEMSIZE (4 * 1024 * 1024) /* 4MB */
#define CONVENTIONAL_MEMSIZE (640) /* 640kB */
/* Simulated disk sizes. */
#define DEFAULT_FD_CYLINDERS 80
#define DEFAULT_FD_HEADS 2
#define DEFAULT_FD_SECTORS 18
#define DEFAULT_HD_CYLINDERS 620
#define DEFAULT_HD_HEADS 128
#define DEFAULT_HD_SECTORS 63
unsigned long install_partition = 0x20000;
unsigned long boot_drive = 0;
@ -53,7 +65,7 @@ char config_file[] = "/boot/grub/menu.lst";
char *grub_scratch_mem = 0;
#define NUM_DISKS 256
static FILE **disks = 0;
static struct geometry *disks = 0;
/* The main entry point into this mess. */
int
@ -65,6 +77,31 @@ grub_stage2 (void)
int i;
char *scratch, *simstack;
/* We need a nested function so that we get a clean stack frame,
regardless of how the code is optimized. */
static volatile void doit ()
{
/* Make sure our stack lives in the simulated memory area. */
asm volatile ("movl %%esp, %0\n\tmovl %1, %%esp\n"
: "&=r" (realstack) : "r" (simstack));
/* FIXME: Do a setjmp here for the stop command. */
if (1)
{
/* Actually enter the generic stage2 code. */
status = 0;
init_bios_info ();
}
else
{
/* Somebody aborted. */
status = 1;
}
/* Replace our stack before we use any local variables. */
asm volatile ("movl %0, %%esp\n" : : "r" (realstack));
}
assert (grub_scratch_mem == 0);
scratch = malloc (0x100000 + EXTENDED_MEMSIZE + 15);
assert (scratch);
@ -93,32 +130,9 @@ grub_stage2 (void)
keypad (stdscr, TRUE);
#endif
/* Make sure our stack lives in the simulated memory area. */
simstack = (char *) RAW_ADDR (PROTSTACKINIT);
#ifdef SIMULATE_STACK
__asm __volatile ("movl %%esp, %0;" : "=d" (realstack));
__asm __volatile ("movl %0, %%esp" :: "d" (simstack));
#endif
{
/* FIXME: Do a setjmp here for the stop command. */
if (1)
{
/* Actually enter the generic stage2 code. */
status = 0;
init_bios_info ();
}
else
{
/* Somebody aborted. */
status = 1;
}
}
#ifdef SIMULATE_STACK
/* Replace our stack before we use any local variables. */
__asm __volatile ("movl %0, %%esp" :: "d" (realstack));
#endif
/* Set our stack, and go for it. */
simstack = (char *) PROTSTACKINIT;
doit ();
#ifdef HAVE_LIBCURSES
endwin ();
@ -126,8 +140,8 @@ grub_stage2 (void)
/* Close off the file pointers we used. */
for (i = 0; i < NUM_DISKS; i ++)
if (disks[i])
fclose (disks[i]);
if (disks[i].flags)
fclose ((FILE *) disks[i].flags);
/* Release memory. */
free (disks);
@ -352,47 +366,107 @@ set_attrib (int attr)
/* Low-level disk I/O. Our stubbed version just returns a file
descriptor, not the actual geometry. */
int
get_diskinfo (int drive)
get_diskinfo (int drive, struct geometry *geometry)
{
/* The unpartitioned device name: /dev/XdX */
char devname[9];
/* FIXME: this function is truly horrid. We try opening the device,
then severely abuse the GEOMETRY->flags field to pass a file
pointer to biosdisk. Thank God nobody's looking at this comment,
or my reputation would be ruined. --Gord */
/* See if we have a cached device. */
if (disks[drive])
return (int) disks[drive];
if (! disks[drive].flags)
{
/* The unpartitioned device name: /dev/XdX */
char devname[9];
/* Try opening the drive device. */
strcpy (devname, "/dev/");
if (drive & 0x80)
devname[5] = 'h';
else
devname[5] = 'f';
devname[6] = 'd';
/* Try opening the drive device. */
strcpy (devname, "/dev/");
/* Check to make sure we don't exceed /dev/hdz. */
devname[7] = (drive & 0x7f) + 'a';
if (devname[7] > 'z')
return 0;
devname[8] = '\0';
#ifdef __linux__
/* Linux uses /dev/hda, and /dev/sda, but /dev/fd0. Go figure. */
if (drive & 0x80)
{
/* Check to make sure we don't exceed /dev/hdz. */
devname[5] = 'h';
devname[7] = 'a' + (drive & 0x7f);
if (devname[7] > 'z')
return -1;
}
else
{
devname[5] = 'f';
devname[7] = '0' + drive;
if (devname[7] > '9')
return -1;
}
#else /* ! __linux__ */
if (drive & 0x80)
devname[5] = 'h';
/* Open read/write, or read-only if that failed. */
disks[drive] = fopen (devname, "r+");
if (! disks[drive])
disks[drive] = fopen (devname, "r");
devname[7] = '0' + drive;
if (devname[7] > '9')
return -1;
#endif /* __linux__ */
return (int) disks[drive];
devname[6] = 'd';
devname[8] = '\0';
/* Open read/write, or read-only if that failed. */
disks[drive].flags = (int) fopen (devname, "r+");
if (! disks[drive].flags)
disks[drive].flags = (int) fopen (devname, "r");
if (disks[drive].flags)
{
#ifdef __linux__
struct hd_geometry hdg;
if (! ioctl (fileno ((FILE *) disks[drive].flags),
HDIO_GETGEO, &hdg))
{
/* Got the geometry, so save it. */
disks[drive].cylinders = hdg.cylinders;
disks[drive].heads = hdg.heads;
disks[drive].sectors = hdg.sectors;
}
else
/* FIXME: should have some other alternatives before using
arbitrary defaults. */
#endif
/* Set some arbitrary defaults. */
if (drive & 0x80)
{
/* Hard drive. */
disks[drive].cylinders = DEFAULT_HD_CYLINDERS;
disks[drive].heads = DEFAULT_HD_HEADS;
disks[drive].sectors = DEFAULT_HD_SECTORS;
}
else
{
/* Floppy. */
disks[drive].cylinders = DEFAULT_FD_CYLINDERS;
disks[drive].heads = DEFAULT_FD_HEADS;
disks[drive].sectors = DEFAULT_FD_SECTORS;
}
}
}
if (! disks[drive].flags)
return -1;
*geometry = disks[drive];
return 0;
}
int
biosdisk (int subfunc, int drive, int geometry,
biosdisk (int subfunc, int drive, struct geometry *geometry,
int sector, int nsec, int segment)
{
char *buf;
FILE *fp;
/* Get the file pointer from the geometry, and make sure it matches. */
fp = (FILE *) geometry;
if (! fp || fp != disks[drive])
fp = (FILE *) geometry->flags;
if (! fp || fp != (FILE *) disks[drive].flags)
return BIOSDISK_ERROR_GEOMETRY;
/* Seek to the specified location. */

View File

@ -352,10 +352,12 @@ ENTRY(biosdisk)
push %ecx
push %edx
push %esi
push %edi
/* Check whether we have LBA. */
movb 0x13(%ebp), %al
andb $0x10, %al
movl 0x10(%ebp), %eax
andb 0xc(%eax), %eax
andl $BIOSDISK_FLAG_LBA_EXTENSION, %eax
jz disk_compute_args /* nope. */
/* set up disk address packet for extended calls (LBA mode) */
@ -416,39 +418,37 @@ ENTRY(biosdisk)
/* either failed, or a floppy, so try standard BIOS calls */
disk_compute_args:
/*
* GEOMETRY is a longword representing the BIOS geometry:
* 4 bit BIOS extension (0 = none, 1 = LBA)
* 12 bit cylinder (bytes 2 & 3)
* 8 bit head (byte 1)
* 8 bit sector (byte 0)
* GEOMETRY is a structure representing the BIOS geometry:
* 32 bit flags (bytes 12-15)
* 32 bit cylinders (bytes 8-11)
* 32 bit heads (bytes 4-7)
* 32 bit sectors (bytes 0-3)
*/
/* set up original sector number */
xorl %edx, %edx
movl 0x14(%ebp), %eax
/* get the pointer to GEOMETRY */
movl 0x10(%ebp), %edi
/* get sector offset, place in %ecx */
xorl %ebx, %ebx
movb 0x10(%ebp), %bl
movl 0x8(%edi), %ebx
divl %ebx
movl %edx, %ecx
/* get track offset (head number) in %edx,
and cylinder offset in %eax */
xorl %edx, %edx
xorl %ebx, %ebx
movb 0x11(%ebp), %bl
inc %ebx
movl 0x4(%edi), %ebx
divl %ebx
/* check cylinder offset, is there a geometry problem here? */
movl 0x10(%ebp), %ebx
shrl $16, %ebx
andb $0xf, %bh /* mask out bios extension code */
movl (%edi), %ebx
cmpl %ebx, %eax
/* if not, go on to standard read function */
jle disk_use_standard_bios
jl disk_use_standard_bios
movl $BIOSDISK_ERROR_GEOMETRY, %eax
jmp disk_exit_32
@ -538,6 +538,7 @@ disk_exit_16:
movb %bl, %al /* return value in %eax */
disk_exit_32:
pop %edi
pop %esi
pop %edx
pop %ecx
@ -549,8 +550,9 @@ disk_exit_32:
/*
*
* get_diskinfo(drive): return a word that represents the
* max number of sectors and heads and cylinders for this drive
* get_diskinfo(drive, geometry): return a structure that represents the
* max number of sectors and heads and cylinders for DRIVE in GEOMETRY.
* If an error occures, return non-zero, otherwise return zero.
*
*/
@ -633,11 +635,12 @@ hard_drive:
jz 1f /* LBA not supported */
/* Wahoo! Got LBA! */
movb $0x1, %bh
movl $BIOSDISK_FLAG_LBA_EXTENSION, %edi
/* FIXME: Should use INT 13 AH=42h */
data32
jmp 2f
1: xorb %bh, %bh /* Too bad, no LBA */
1: xorl %edi, %edi /* Too bad, no LBA */
2: movb $0x8, %ah /* ask for disk info */
int $0x13
@ -649,33 +652,36 @@ hard_drive:
probe_success:
/*
* form a dword representing all this gunk:
* 4 bit BIOS extension (0 = none, 1 = LBA)
* 12 bit cylinder
* 8 bit head
* 8 bit sector
* Store the information for CHS and BIOS extension to registers:
* 32 bit BIOS extension -> edi
* 32 bit cylinder -> ebx
* 32 bit head -> ecx
* 32 bit sector -> edx
*/
movb %bh, %ah /* restore BIOS extensions bits */
#ifdef AWARD_INT13_EXTENSIONS
movb %dh, %al /* bits 10,11 of cylinder count */
andb $0xc0, %al
#endif
shlw $2, %ax /* << 2 */
#endif
movb %cl, %al /* bits 8,9 of cylinder count */
andb $0xc0, %al
shlw $2, %ax /* << 2 */
movb %ch, %al /* Lower 8 bits */
movswl %ax, %ebx /* max cylinder */
incl %ebx /* number of cylinders */
shll $16, %eax /* << 16 */
#ifdef AWARD_INT13_EXTENSIONS
andb $0x3f, %dh /* mask off cylinder gunk */
#endif
movb %dh, %ah /* max head */
movb %dh, %al /* max head */
andb $0x3f, %cl /* mask off cylinder gunk */
movb %cl, %al /* max sector (and # sectors) */
movsbl %cl, %edx /* max sector (and # sectors) */
movsbl %al, %ecx
incl %ecx /* number of heads */
movl %eax, %ebx /* save return value */
data32
jmp got_drive
@ -684,18 +690,37 @@ probe_failed:
* Urk. Call failed. It is not supported for floppies by old
* BIOSes, but it should work for all hard drives!!
*
* Return a 0 here... presume there is no drive present. ????
* Return a 1 here... presume there is no drive present. ????
*/
movl $0, %ebx /* not present value */
data32
call EXT_C(real_to_prot)
.code32
movl $1, %eax
popl %esi
popl %edi
popl %edx
popl %ecx
popl %ebx
popl %ebp
ret
.code16
got_drive:
data32
call EXT_C(real_to_prot) /* back to protected mode */
.code32
/* set up return in correct register */
movl %ebx, %eax
/* set up return structure */
movl 0x0c(%ebp), %eax
movl %ebx, (%eax)
movl %ecx, 0x04(%eax)
movl %edx, 0x08(%eax)
movl %edi, 0x0c(%eax)
xorl %eax, %eax
popl %esi
popl %edi

View File

@ -381,6 +381,7 @@ load_image (void)
loaded++;
/* load the segment */
memaddr = RAW_ADDR (memaddr);
if (memcheck (memaddr, memsiz)
&& grub_read ((char *) memaddr, filesiz) == filesiz)
{
@ -532,7 +533,18 @@ bsd_boot (int type, int bootdev)
bi.bi_n_bios_used = 0; /* this field is apparently unused */
for (i = 0; i < N_BIOS_GEOM; i++)
bi.bi_bios_geom[i] = get_diskinfo (i + 0x80);
{
struct geometry geom;
/* XXX Should check the return value. */
get_diskinfo (i + 0x80, &geom);
/* FIXME: If HEADS or SECTORS is greater than 255, then this will
break the geometry information. That is a drawback of BSD
but not of GRUB. */
bi.bi_bios_geom[i] = (((geom.cylinders - 1) << 16)
+ (((geom.heads - 1) & 0xff) << 8)
+ (geom.sectors & 0xff));
}
bi.bi_size = sizeof (struct bootinfo);
bi.bi_memsizes_valid = 1;

View File

@ -398,9 +398,10 @@ get_cmdline (char *prompt, char *commands, char *cmdline, int maxlen)
lpos++;
}
while (cmdline[lpos]);
}
cmdline[c] = 0;
/* Zero-terminate the string. */
cmdline[c] = 0;
}
return 0;
}
@ -562,13 +563,16 @@ strstr (char *s1, char *s2)
int
memcheck (int start, int len)
{
/* FIXME: fails when used with addresses on our stack. */
/* FIXME: Don't bother checking memory for now, since our globals
are out of range. */
#ifndef GRUB_UTIL
if ((start < RAW_ADDR (0x1000)) ||
(start < RAW_ADDR (0x100000) &&
RAW_ADDR (mbi.mem_lower * 1024) < (start + len)) ||
(start >= RAW_ADDR (0x100000) &&
RAW_ADDR (mbi.mem_upper * 1024) < ((start - 0x100000) + len)))
errnum = ERR_WONT_FIT;
#endif /* GRUB_UTIL */
return (!errnum);
}

View File

@ -372,7 +372,8 @@ returnit:
set_device (dest_dev) && open_partition () &&
devread (0, 0, SECTOR_SIZE, old_sect))
{
int dest_drive = current_drive, dest_geom = buf_geom;
int dest_drive = current_drive;
struct geometry dest_geom = buf_geom;
int dest_sector = part_start, i;
#ifndef NO_DECOMPRESSION
@ -466,11 +467,11 @@ returnit:
if (!errnum
&& (biosdisk(BIOSDISK_WRITE,
dest_drive, dest_geom,
dest_drive, &dest_geom,
dest_sector, 1, (BOOTSEC_LOCATION>>4))
|| (write_stage2_sect
&& biosdisk(BIOSDISK_WRITE,
current_drive, buf_geom,
current_drive, &buf_geom,
stage2_sect, 1, SCRATCHSEG))))
errnum = ERR_WRITE;
}

View File

@ -78,7 +78,7 @@ int current_slice;
/* disk buffer parameters */
int buf_drive = -1;
int buf_track;
int buf_geom;
struct geometry buf_geom;
/* filesystem common variables */
int filepos;
@ -103,26 +103,24 @@ rawread (int drive, int sector, int byte_offset, int byte_len, char *buf)
*/
if (buf_drive != drive)
{
buf_geom = get_diskinfo (drive);
if (get_diskinfo (drive, &buf_geom))
{
errnum = ERR_NO_DISK;
return 0;
}
buf_drive = drive;
buf_track = -1;
}
if (buf_geom == 0)
{
errnum = ERR_NO_DISK;
return 0;
}
/* Get first sector of track */
soff = sector % SECTORS (buf_geom);
soff = sector % buf_geom.sectors;
track = sector - soff;
num_sect = SECTORS (buf_geom) - soff;
num_sect = buf_geom.sectors - soff;
bufaddr = BUFFERADDR + (soff * SECTOR_SIZE) + byte_offset;
if (track != buf_track)
{
int bios_err, read_start = track, read_len = SECTORS (buf_geom);
int bios_err, read_start = track, read_len = buf_geom.sectors;
/*
* If there's more than one read in this entire loop, then
@ -136,7 +134,7 @@ rawread (int drive, int sector, int byte_offset, int byte_len, char *buf)
bufaddr = BUFFERADDR + byte_offset;
}
bios_err = biosdisk (BIOSDISK_READ, drive, buf_geom,
bios_err = biosdisk (BIOSDISK_READ, drive, &buf_geom,
read_start, read_len, BUFFERSEG);
if (bios_err)
{
@ -151,7 +149,7 @@ rawread (int drive, int sector, int byte_offset, int byte_len, char *buf)
* required sector(s) rather than failing completely.
*/
if (slen > num_sect
|| biosdisk (BIOSDISK_READ, drive, buf_geom,
|| biosdisk (BIOSDISK_READ, drive, &buf_geom,
sector, slen, BUFFERSEG))
errnum = ERR_READ;
@ -293,7 +291,7 @@ make_saved_active (void)
buf_track = -1;
if (biosdisk (BIOSDISK_WRITE, saved_drive, buf_geom,
if (biosdisk (BIOSDISK_WRITE, saved_drive, &buf_geom,
0, 1, SCRATCHSEG))
{
errnum = ERR_WRITE;
@ -406,7 +404,7 @@ real_open_partition (int flags)
bsd_evil_hack = 0;
current_slice = 0;
part_start = 0;
part_length = SECTORS (buf_geom) * HEADS (buf_geom) * CYLINDERS (buf_geom);
part_length = buf_geom.sectors * buf_geom.heads * buf_geom.cylinders;
if (current_drive & 0x80)
{
@ -900,6 +898,7 @@ print_completions (char *filename)
{
/* disk completions */
int disk_no, i, j;
struct geometry geom;
printf (" Possible disks are: ");
@ -908,8 +907,8 @@ print_completions (char *filename)
for (j = 0; j < 8; j++)
{
disk_no = (i * 0x80) + j;
if ((disk_choice || disk_no == current_drive)
&& get_diskinfo (disk_no))
if ((disk_choice || disk_no == current_drive) &&
! get_diskinfo (disk_no, &geom))
printf (" %cd%d", (i ? 'h' : 'f'), j);
}
}

View File

@ -21,10 +21,6 @@
#include "pc_slice.h"
#define SECTORS(geom) ( (geom) & 0xFF )
#define HEADS(geom) ( ( ( (geom) >> 8 ) & 0xFF ) + 1 )
#define CYLINDERS(geom) ( ( ( (geom) >> 16 ) & 0x3FF ) + 1 )
/*
* Default to all functioning filesystems enabled
*/

View File

@ -58,6 +58,7 @@ extern char *grub_scratch_mem;
#define BIOSDISK_READ 0x0
#define BIOSDISK_WRITE 0x1
#define BIOSDISK_ERROR_GEOMETRY 0x100
#define BIOSDISK_FLAG_LBA_EXTENSION 0x1
/*
* This is the filesystem (not raw device) buffer.
@ -304,6 +305,19 @@ extern int fsys_type;
extern int block_file;
#endif /* NO_BLOCK_FILES */
/* The information for a disk geometry */
struct geometry
{
/* The number of cylinders */
unsigned long cylinders;
/* The number of heads */
unsigned long heads;
/* The number of sectors */
unsigned long sectors;
/* Flags */
unsigned long flags;
};
extern long part_start;
extern long part_length;
@ -311,7 +325,7 @@ extern int current_slice;
extern int buf_drive;
extern int buf_track;
extern int buf_geom;
extern struct geometry buf_geom;
/* these are the current file position and maximum file position */
extern int filepos;
@ -418,8 +432,8 @@ int checkkey (void);
void set_attrib (int attr);
/* Low-level disk I/O */
int get_diskinfo (int drive);
int biosdisk (int read, int drive, int geometry,
int get_diskinfo (int drive, struct geometry *geometry);
int biosdisk (int read, int drive, struct geometry *geometry,
int sector, int nsec, int segment);
void stop_floppy (void);
@ -494,6 +508,6 @@ int load_image (void);
int load_module (void);
int load_initrd (void);
void init_bios_info (void) __attribute__ ((noreturn));
void init_bios_info (void);
#endif /* ASM_FILE */