Bug fixes in the geometry detection. Linux video mode selection support. New Stage 1 stage1_lba is added. Stage 1.5 becomes much smaller.

This commit is contained in:
okuji 1999-07-12 00:47:11 +00:00
parent d66583f802
commit cb7e6d5e4e
11 changed files with 655 additions and 139 deletions

3
BUGS
View file

@ -29,7 +29,4 @@ Known problems/bugs:
- Hitting Ctrl-Alt-Delete when in GRUB locks some machines. Use Reset
for now. (This apparently hasn't been observed for a while)
- Stage 1 cannot read data from any >4128705 block. Ask okuji for more
information.
- Stage 1.5 does not work in some environments. Why?

View file

@ -1,3 +1,75 @@
1999-07-12 OKUJI Yoshinori <okuji@kuicr.kyoto-u.ac.jp>
* stage2/bios.c (get_diskinfo): In LBA mode, compute
TOTAL_SECTORS from DRP instead of GEOMETRY.
Clear GEOMETRY->FLAGS first.
* stage2/boot.c (load_image): Fix inverted lines.
1999-07-12 OKUJI Yoshinori <okuji@kuicr.kyoto-u.ac.jp>
Support Linux video mode selection.
* stage2/shared.h (LINUX_VID_MODE_OFFSET): New macro.
(LINUX_VID_MODE_NORMAL): Likewise.
(LINUX_VID_MODE_EXTENDED): Likewise.
(LINUX_VID_MODE_ASK): Likewise.
[!WITHOUT_LIBC_STUBS] (strlen): Likewise.
(grub_strlen): Declared.
* stage2/boot.c (load_image): Added Linux video mode selection.
* stage2/char_io.c [!STAGE1_5] (grub_strlen): New function.
1999-07-12 OKUJI Yoshinori <okuji@kuicr.kyoto-u.ac.jp>
* stage2/char_io.c (print_error): Print ERRNUM in the format of
%u instead of %d.
(convert_to_ascii) [STAGE1_5]: Eliminate the `x' and `d'
handling code.
(grub_printf): Declare FORMAT as `const char *'.
(grub_printf) [STAGE1_5]: Eliminate the `x' and `d' handling
code.
(get_based_digit): Removed.
(safe_parse_maxint): Remove unnecessary `register' prefixes,
because GCC does better optimization.
Declare DIGIT as `unsigned int' and calculate the value by more
compact instructions.
[!STAGE1_5] (grub_strncat): Declare S2 as `const char *'.
[!STAGE1_5] (grub_strcmp): Declare S1 and S2 as `const char *'.
[!STAGE1_5] (grub_strstr): Likewise.
(grub_memmove): Declare FROM as `const char *'.
The copy code is replaced with inline assembly code stolen from
Linux-2.2.2.
* stage2/shared.h (grub_printf) : Corrected.
(grub_strncat): Likewise.
(grub_memmove): Likewise.
(grub_strstr): Likewise.
(grub_strcmp): Likewise.
1999-07-11 OKUJI Yoshinori <okuji@kuicr.kyoto-u.ac.jp>
* stage1/stage1.S (sectors): Change the size to long.
(heads): Likewise.
(sector_start): New variable.
(head_start): Likewise.
(cylinder_start): Likewise.
(final_init): Set %si to SECTORS first, and use %si for memory
references.
Zero %eax so that the high 16 bits are always zero.
Set %di to FIRSTLIST - LISTSIZ instead of FIRSTLIST.
(bootloop): Omit the complex CHS recomputation, and always
compute them from LBA address instead.
Call 32bits div instructions instead of 16bits div instructions.
Update the position where to load data from at the end of this
loop, instead of the beginning.
* stage1/stage1_lba.S: New file.
* stage1/Makefile.am (nodist_pkgdata_DATA): Added stage1_lba.
(LDFLAGS): New variable.
(noinst_PROGRAMS): Added stage1_lba.exec.
(stage1_lba_exec_SOURCES): New variable.
(%: %.exec): New rule.
1999-06-28 OKUJI Yoshinori <okuji@kuicr.kyoto-u.ac.jp>
* grub/main.c (main): The third argument for strtoul is changed

2
NEWS
View file

@ -14,6 +14,8 @@ New:
* New command "quit".
* The man page for /sbin/grub.
* All documents become Texinfo.
* Linux video mode selection is supported.
* The new Stage 1 `stage1_lba' supports LBA addressing mode.
New in 0.5.91 - 1999-03-14, Gordon Matzigkeit:
* LBA and preliminary AWARD BIOS disk extension support.

View file

@ -1,15 +1,14 @@
pkgdatadir = $(datadir)/$(PACKAGE)/$(host_cpu)-$(host_vendor)
nodist_pkgdata_DATA = stage1
nodist_pkgdata_DATA = stage1 stage1_lba
CLEANFILES = $(pkgdata_DATA)
# We can't use builtins or standard includes.
AM_CFLAGS = @STAGE1_CFLAGS@ -fno-builtin -nostdinc
LDFLAGS = -nostdlib -Wl,-N -Wl,-Ttext -Wl,7C00
noinst_PROGRAMS = stage1.exec
noinst_PROGRAMS = stage1.exec stage1_lba.exec
stage1_exec_SOURCES = stage1.S
stage1_lba_exec_SOURCES = stage1_lba.S
stage1.exec: stage1.o
$(LD) -N -Ttext 7C00 -o $@ $<
stage1: stage1.exec
%: %.exec
$(OBJCOPY) -O binary $< $@

View file

@ -76,14 +76,16 @@ install_sh = @install_sh@
pkgdatadir = $(datadir)/$(PACKAGE)/$(host_cpu)-$(host_vendor)
nodist_pkgdata_DATA = stage1
nodist_pkgdata_DATA = stage1 stage1_lba
CLEANFILES = $(pkgdata_DATA)
# We can't use builtins or standard includes.
AM_CFLAGS = @STAGE1_CFLAGS@ -fno-builtin -nostdinc
LDFLAGS = -nostdlib -Wl,-N -Wl,-Ttext -Wl,7C00
noinst_PROGRAMS = stage1.exec
noinst_PROGRAMS = stage1.exec stage1_lba.exec
stage1_exec_SOURCES = stage1.S
stage1_lba_exec_SOURCES = stage1_lba.S
subdir = stage1
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_CLEAN_FILES =
@ -92,18 +94,22 @@ PROGRAMS = $(noinst_PROGRAMS)
DEFS = @DEFS@ -I. -I$(srcdir)
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
am_stage1_exec_OBJECTS = stage1.o
stage1_exec_OBJECTS = $(am_stage1_exec_OBJECTS)
stage1_exec_LDADD = $(LDADD)
stage1_exec_DEPENDENCIES =
stage1_exec_LDFLAGS =
am_stage1_lba_exec_OBJECTS = stage1_lba.o
stage1_lba_exec_OBJECTS = $(am_stage1_lba_exec_OBJECTS)
stage1_lba_exec_LDADD = $(LDADD)
stage1_lba_exec_DEPENDENCIES =
stage1_lba_exec_LDFLAGS =
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CFLAGS = @CFLAGS@
CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
DIST_SOURCES = $(stage1_exec_SOURCES)
DIST_SOURCES = $(stage1_exec_SOURCES) $(stage1_lba_exec_SOURCES)
DATA = $(nodist_pkgdata_DATA)
DIST_COMMON = Makefile.am Makefile.in
@ -112,9 +118,9 @@ DIST_COMMON = Makefile.am Makefile.in
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
GZIP_ENV = --best
DEP_FILES = .deps/stage1.P
SOURCES = $(stage1_exec_SOURCES)
OBJECTS = $(am_stage1_exec_OBJECTS)
DEP_FILES = .deps/stage1.P .deps/stage1_lba.P
SOURCES = $(stage1_exec_SOURCES) $(stage1_lba_exec_SOURCES)
OBJECTS = $(am_stage1_exec_OBJECTS) $(am_stage1_lba_exec_OBJECTS)
all: all-redirect
.SUFFIXES:
@ -145,6 +151,14 @@ distclean-compile:
-rm -f *.tab.c
maintainer-clean-compile:
stage1.exec: $(stage1_exec_OBJECTS) $(stage1_exec_DEPENDENCIES)
@rm -f stage1.exec
$(LINK) $(stage1_exec_LDFLAGS) $(stage1_exec_OBJECTS) $(stage1_exec_LDADD) $(LIBS)
stage1_lba.exec: $(stage1_lba_exec_OBJECTS) $(stage1_lba_exec_DEPENDENCIES)
@rm -f stage1_lba.exec
$(LINK) $(stage1_lba_exec_LDFLAGS) $(stage1_lba_exec_OBJECTS) $(stage1_lba_exec_LDADD) $(LIBS)
.S.o:
$(COMPILE) -c $<
@ -305,10 +319,7 @@ installdirs mostlyclean-generic distclean-generic clean-generic \
maintainer-clean-generic clean mostlyclean distclean maintainer-clean
stage1.exec: stage1.o
$(LD) -N -Ttext 7C00 -o $@ $<
stage1: stage1.exec
%: %.exec
$(OBJCOPY) -O binary $< $@
# Tell versions [3.59,3.63) of GNU make to not export all variables.

View file

@ -1,6 +1,7 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1996 Erich Boleyn <erich@uruk.org>
* Copyright (C) 1999 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
@ -73,11 +74,17 @@
/* scratch space */
sectors:
.word 0
.long 0
heads:
.word 0
.long 0
cylinders:
.word 0
sector_start:
.byte 0
head_start:
.byte 0
cylinder_start:
.word 0
/* more space... */
. = _start + BPBEND
@ -130,11 +137,14 @@ after_BPB:
jmp hd_probe_error
final_init:
/* set %si to sectors */
movw $ABS(sectors), %si
/* save number of heads */
xorb %ah, %ah
xorl %eax, %eax
movb %dh, %al
incw %ax
movw %ax, heads
movl %eax, 4(%si)
xorw %dx, %dx
movb %cl, %dl
@ -144,64 +154,59 @@ final_init:
/* save number of cylinders */
incw %ax
movw %ax, cylinders
movw %ax, 8(%si)
xorw %ax, %ax
movb %dl, %al
shrb $2, %al
/* save number of sectors */
movw $ABS(sectors), %si
movw %ax, (%si)
movl %eax, (%si)
/* this sets up for the first run through "bootloop" */
movw $ABS(firstlist), %di
movw $ABS(firstlist - LISTSIZ), %di
/* this is the loop for reading the secondary boot-loader in */
bootloop:
/* update position to load from */
subw $LISTSIZ, %di
/* check the number of sectors to read */
cmpw $0, 4(%di)
/* if zero, go to the start function */
je bootit
setup_sectors:
/* load logical sector start (bottom half) */
movw (%di), %ax
movl (%di), %eax
/* load logical sector start (top half) */
movw 2(%di), %dx
/* zero %edx */
xorl %edx, %edx
/* divide by number of sectors */
divw (%si)
divl (%si)
/* save sector start */
movb %dl, (%di)
movb %dl, 10(%si)
xorw %dx, %dx /* zero %dx */
divw 2(%si) /* divide by number of heads */
xorl %edx, %edx /* zero %edx */
divl 4(%si) /* divide by number of heads */
/* save head start */
movb %dl, 1(%di)
movb %dl, 11(%si)
/* save cylinder start */
movw %ax, 2(%di)
movw %ax, 12(%si)
/* do we need too many cylinders? */
cmpw 4(%si), %ax
cmpw 8(%si), %ax
jge geometry_error
setup_sectors:
/* determine the maximum sector length of this read */
movw (%si), %ax /* get number of sectors per track/head */
/* subtract sector start */
subb (%di), %al
subb 10(%si), %al
/* how many do we really want to read? */
cmpw %ax, 4(%di) /* compare against total number of sectors */
@ -217,27 +222,30 @@ more_sectors:
/* subtract from total */
subw %ax, 4(%di)
/* add into logical sector start */
addl %eax, (%di)
/*
* This is the loop for taking care of BIOS geometry translation (ugh!)
*/
/* get high bits of cylinder */
movb 3(%di), %dl
movb 13(%si), %dl
shlb $6, %dl /* shift left by 6 bits */
movb (%di), %cl /* get sector */
movb 10(%si), %cl /* get sector */
incb %cl /* normalize sector (sectors go
from 1-N, not 0-(N-1) ) */
orb %dl, %cl /* composite together */
movb 2(%di), %ch /* sector+hcyl in cl, cylinder in ch */
movb 12(%si), %ch /* sector+hcyl in cl, cylinder in ch */
/* restore %dx */
popw %dx
pushw %dx
/* head number */
movb 1(%di), %dh
movb 11(%si), %dh
pushw %ax /* save %ax from destruction! */
@ -304,34 +312,13 @@ more_sectors:
/* check if finished with this dataset */
cmpw $0, 4(%di)
je bootloop
jne setup_sectors
/* find out the next BIOS set to load in */
movb $0, (%di) /* set the sector start */
xorb %ah, %ah /* zero %ah */
movb 1(%di), %al /* load head number into %al */
incw %ax /* increment current head number */
cmpw 2(%si), %ax /* compare to total number of heads */
jne update_heads
movw 2(%di), %ax /* load cylinder number into %ax */
incw %ax /* increment current cylinder number */
cmpw 4(%si), %ax /* compare to total number of cylinders */
je geometry_error /* display error and die if greater */
movw %ax, 2(%di) /* store new cylinder number */
movb $0, %al /* for storing new head number */
update_heads:
movb %al, 1(%di) /* store new head number */
/* jump to "setup_sectors" to determine length of the new read */
jmp setup_sectors
/* update position to load from */
subw $LISTSIZ, %di
/* jump to bootloop */
jmp bootloop
/* END OF MAIN LOOP */

394
stage1/stage1_lba.S Normal file
View file

@ -0,0 +1,394 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1996 Erich Boleyn <erich@uruk.org>
* Copyright (C) 1999 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.
*/
/*
* defines for the code go here
*/
#define SIGNATURE 0xaa55
#define BPBEND 0x3e
#define PARTSTART 0x1be /* starting address of partition table */
#define PARTEND 0x1fe /* ending addres of the partition table */
#define MINPARAMSIZ 13 /* size of extra data parameters */
#define LISTSIZ 8 /* size of sector list */
#define REALSTACK 0x2000 /* stack for this code and BIOS calls */
#define BUFFERSEG 0x7000 /* segment address of disk buffer, the
disk buffer MUST be 32K long and cannot
straddle a 64K boundary */
/* Absolute addresses
This makes the assembler generate the address without support
from the linker. (ELF can't relocate 16-bit addresses!) */
#define ABS(x) (x-_start+0x7c00)
/* Print message string */
#define MSG(x) movw $x, %si; call message
.file "stage1_lba.S"
.text
/* Tell GAS to generate 16-bit instructions so that this code works
in real mode. */
.code16
.globl _start; _start:
/*
* _start is loaded at 0x7c00 and is jumped to with CS:IP 0:0x7c00
*/
/*
* Beginning of the sector is compatible with the FAT/HPFS BIOS
* parameter block.
*/
jmp after_BPB
nop /* do I care about this ??? */
/*
* This space is for the BIOS parameter block!!!! Don't change
* the first jump, nor start the code anywhere but right after
* this area.
*/
. = _start + 4
/* scratch space */
drive_parameter:
disk_address_packet:
/* Actually, must set these values at the runtime. */
.byte 0x10
.byte 0
.word 0
.long 0
.quad 0
/* more space... */
. = _start + BPBEND
/*
* End of BIOS parameter block.
*/
after_BPB:
/* general setup */
cli /* we're not safe here! */
/* set up %ds and %ss as offset from 0 */
xorw %ax, %ax
movw %ax, %ds
movw %ax, %ss
/* set up the REAL stack */
movw $REALSTACK, %sp
sti /* we're safe again */
/*
* Check if we have a forced disk reference here
*/
movb firstlist, %al
cmpb $0xff, %al
je 1f
movb %al, %dl
1:
/* save drive reference first thing! */
pushw %dx
/* check if LBA is supported */
movb $0x41, %ah
movw $0x55aa, %bx
int $0x13
jc lba_probe_error
cmpw $0xaa55, %bx
jne lba_probe_error
/* get the geometry (limited to 2TB!) */
movb $0x48, %ah
movw $ABS(drive_parameter), %si
movw $0x1a, (%si)
int $0x13
jc lba_probe_error
/* save the total number of sectors */
movl 0x10(%si), %ecx
/* this sets up for the first run through "bootloop" */
movw $ABS(firstlist - LISTSIZ), %di
/* this is the loop for reading the secondary boot-loader in */
bootloop:
/* check the number of sectors to read */
cmpw $0, 4(%di)
/* if zero, go to the start function */
je bootit
setup_sectors:
/* load logical sector start */
movl (%di), %ebx
/* check for the geometry */
cmpl %ecx, %ebx
jge geometry_error
/* the maximum is limited to 0x7f because of Phoenix EDD */
xorl %eax, %eax
movb $0x7f, %al
/* how many do we really want to read? */
cmpw %ax, 4(%di) /* compare against total number of sectors */
/* which is greater? */
jg more_sectors
/* if less than, set to total */
movw 4(%di), %ax
more_sectors:
/* subtract from total */
subw %ax, 4(%di)
/* add into logical sector start */
addl %eax, (%di)
/* set up disk address packet */
/* the size and the reserved byte */
movw $0x0010, (%si)
/* the number of sectors */
movw %ax, 2(%si)
/* the absolute address (low 32 bits) */
movl %ebx, 8(%si)
/* the segment of buffer address */
movw 6(%di), %bx
movw %bx, 6(%si)
pushw %ax /* save %ax from destruction! */
/* zero %eax */
xorl %eax, %eax
/* the offset of buffer address */
movw %ax, 4(%si)
/* the absolute address (high 32 bits) */
movl %eax, 12(%si)
/*
* BIOS call "INT 0x13 Function 0x42" to read sectors from disk into memory
* Call with %ah = 0x42
* %dl = drive number
* %ds:%si = segment:offset of disk address packet
* Return:
* %al = 0x0 on success; err code on failure
*/
movb $0x42, %ah
int $0x13
jc read_error
/* save source segment */
movw %es, %bx
/* load addresses for copy from disk buffer to destination */
movw 6(%di), %es /* load destination segment */
/* restore %ax */
popw %ax
/* determine the next possible destination address (presuming
512 byte sectors!) */
shlw $5, %ax /* shift %ax five bits to the left */
addw %ax, 6(%di) /* add the corrected value to the destination
address for next time */
/* save addressing regs */
pushw %ds
pushw %si
pushw %di
pushw %cx
/* get the copy length */
shlw $4, %ax
movw %ax, %cx
xorw %di, %di /* zero offset of destination addresses */
xorw %si, %si /* zero offset of source addresses */
movw %bx, %ds /* restore the source segment */
cld /* sets the copy direction to forward */
/* perform copy */
rep /* sets a repeat */
movsb /* this runs the actual copy */
/* restore addressing regs */
popw %cx
popw %di
popw %si
popw %ds
/* check if finished with this dataset */
cmpw $0, 4(%di)
jne setup_sectors
/* update position to load from */
subw $LISTSIZ, %di
/* jump to bootloop */
jmp bootloop
/* END OF MAIN LOOP */
/*
* BIOS Geometry translation error (past the end of the disk geometry!).
*/
geometry_error:
MSG(geometry_error_string)
jmp general_error
/*
* Disk probe failure.
*/
lba_probe_error:
MSG(lba_probe_error_string)
jmp general_error
/*
* Read error on the disk.
*/
read_error:
MSG(read_error_string)
general_error:
MSG(general_error_string)
/* go here when you need to stop the machine hard after an error condition */
stop: jmp stop
geometry_error_string: .string "Geom"
lba_probe_error_string: .string "LBA"
read_error_string: .string "Read"
general_error_string: .string " Error"
/*
* message: write the string pointed to by %si
*
* WARNING: trashes %si, %ax, and %bx
*/
/*
* Use BIOS "int 10H Function 0Eh" to write character in teletype mode
* %ah = 0xe %al = character
* %bh = page %bl = foreground color (graphics modes)
*/
1:
movw $0x0001, %bx
movb $0xe, %ah
int $0x10 /* display a byte */
incw %si
message:
movb (%si), %al
cmpb $0, %al
jne 1b /* if not end of string, jmp to display */
ret
lastlist:
/*
* This area is an empty space between the main body of code below which
* grows up (fixed after compilation, but between releases it may change
* in size easily), and the lists of sectors to read, which grows down
* from a fixed top location.
*/
/*
* This data area is for keeping general parameters.
*/
. = _start + PARTSTART - MINPARAMSIZ - LISTSIZ
/* this next data area before the partition area is specifically
sized, you should update "MINPARAMSIZ" to reflect any additions
or deletions to this area */
.word 0
.word 0
/* fill the first data listing with the default */
#ifdef FFS_STAGE1_5
.long 2 /* this is the sector start parameter, in logical
sectors from the start of the disk, sector 0 */
.word 14 /* this is the number of sectors to read */
.word 0x0200 /* this is the segment of the starting address
to load the data into */
#else
.long 1 /* this is the sector start parameter, in logical
sectors from the start of the disk, sector 0 */
.word 90 /* this is the number of sectors to read */
.word 0x0800 /* this is the segment of the starting address
to load the data into */
#endif
firstlist: /* this label has to be after the list data!!! */
.byte 0xff /* the disk to load stage2 from */
/* 0xff means use the boot drive */
/*
* Jump here when all data loading is done. This
* goes to the second stage bootloader.
*/
bootit:
popw %dx /* this makes sure %dl is our "boot" drive */
ljmp $0, $0x8000 /* FIXME: make 0x2000 for stage1_5 */
/*
* This is the compatibility version number.
* See ../stage2/shared.h for COMPAT_VERSION_* definitions used
* in stage2 and stage1_5 modules.
*
* DO NOT MOVE THIS!!!
*/
.byte 2, 1
/*
* This is where an MBR would go if on a hard disk. The code
* here isn't even referenced unless we're on a floppy. Kinda
* sneaky, huh?
*/
. = _start + PARTSTART
/* This space cannot be used by any bootloader, uggh... */
. = _start + PARTEND
/* the last 2 bytes in the sector 0 contain the signature */
.word SIGNATURE

View file

@ -118,6 +118,9 @@ int
get_diskinfo (int drive, struct geometry *geometry)
{
int err;
/* Clear the flags. */
geometry->flags = 0;
if (drive & 0x80)
{
@ -159,11 +162,7 @@ get_diskinfo (int drive, struct geometry *geometry)
/* Check if CHS information is valid. */
if (drp.flags & 0x02)
{
total_sectors = (geometry->cylinders
* geometry->heads
* geometry->sectors);
}
total_sectors = drp.cylinders * drp.heads * drp.sectors;
}
}

View file

@ -198,6 +198,44 @@ load_image (void)
if (mbi.mem_lower >= 608)
{
/* Video mode selection support. What a shit! */
{
char *vga;
/* Find the substring "vga=". */
vga = grub_strstr (cur_cmdline, "vga=");
if (vga)
{
char *value = vga + 4;
char *vga_end;
int vid_mode;
/* Handle special strings. */
if (substring ("normal", value) < 1)
vid_mode = LINUX_VID_MODE_NORMAL;
else if (substring ("ext", value) < 1)
vid_mode = LINUX_VID_MODE_EXTENDED;
else if (substring ("ask", value) < 1)
vid_mode = LINUX_VID_MODE_ASK;
else if (safe_parse_maxint (&value, &vid_mode))
;
else
/* ERRNUM is already set inside the function
safe_parse_maxint. */
return 0;
/* Set the vid mode to VID_MODE. Note that this can work
because i386 architecture is little-endian. */
grub_memmove (buffer + LINUX_VID_MODE_OFFSET,
(char *) &vid_mode,
sizeof (unsigned short));
/* Remove the "vga=...". */
vga_end = skip_to (0, vga);
grub_memmove (vga, vga_end, grub_strlen (vga_end));
}
}
memmove ((char *) LINUX_SETUP, buffer, data_len + SECTOR_SIZE);
/* copy command-line plus memory hack to staging area */

View file

@ -31,7 +31,7 @@ print_error (void)
/* printf("\7\n %s\n", err_list[errnum]); */
printf ("\n %s\n", err_list[errnum]);
#else /* STAGE1_5 */
printf ("Error: %d\n", errnum);
printf ("Error: %u\n", errnum);
#endif /* STAGE1_5 */
errnum = ERR_NONE;
@ -44,6 +44,7 @@ convert_to_ascii (char *buf, int c,...)
unsigned long num = *((&c) + 1), mult = 10;
char *ptr = buf;
#ifndef STAGE1_5
if (c == 'x')
mult = 16;
@ -53,6 +54,7 @@ convert_to_ascii (char *buf, int c,...)
*(ptr++) = '-';
buf++;
}
#endif
do
{
@ -80,7 +82,7 @@ convert_to_ascii (char *buf, int c,...)
void
grub_printf (char *format,...)
grub_printf (const char *format,...)
{
int *dataptr = (int *) &format;
char c, *ptr, str[16];
@ -94,9 +96,11 @@ grub_printf (char *format,...)
else
switch (c = *(format++))
{
#ifndef STAGE1_5
case 'd':
case 'u':
case 'x':
#endif
case 'u':
*convert_to_ascii (str, c, *((unsigned long *) dataptr++)) = 0;
ptr = str;
@ -422,39 +426,11 @@ get_cmdline (char *prompt, char *commands, char *cmdline, int maxlen,
#endif /* STAGE1_5 */
int
get_based_digit (int c, int base)
{
int digit = -1;
/* make sure letter in the the range we can check! */
c = tolower (c);
/*
* Is it in the range between zero and nine?
*/
if (base > 0 && c >= '0' && c <= '9' && c < (base + '0'))
{
digit = c - '0';
}
/*
* Is it in the range used by a letter?
*/
if (base > 10 && c >= 'a' && c <= 'z' && c < ((base - 10) + 'a'))
{
digit = c - 'a' + 10;
}
return digit;
}
int
safe_parse_maxint (char **str_ptr, int *myint_ptr)
{
register char *ptr = *str_ptr;
register int myint = 0, digit;
char *ptr = *str_ptr;
int myint = 0;
int mult = 10, found = 0;
/*
@ -466,8 +442,22 @@ safe_parse_maxint (char **str_ptr, int *myint_ptr)
mult = 16;
}
while ((digit = get_based_digit (*ptr, mult)) != -1)
while (1)
{
/* A bit tricky. This below makes use of the equivalence:
(A >= B && A <= C) <=> ((A - B) <= (C - B))
when C > B and A is unsigned. */
unsigned int digit;
digit = tolower (*ptr) - '0';
if (digit > 9)
{
digit -= 'a' - '0';
if (mult == 10 || digit > 5)
break;
digit += 10;
}
found = 1;
if (myint > ((MAXINT - digit) / mult))
{
@ -513,7 +503,7 @@ grub_isspace (int c)
#ifndef STAGE1_5
int
grub_strncat (char *s1, char *s2, int n)
grub_strncat (char *s1, const char *s2, int n)
{
int i = -1;
@ -533,7 +523,7 @@ grub_strncat (char *s1, char *s2, int n)
int
grub_strcmp (char *s1, char *s2)
grub_strcmp (const char *s1, const char *s2)
{
while (*s1 || *s2)
{
@ -571,9 +561,9 @@ substring (char *s1, char *s2)
#ifndef STAGE1_5
char *
grub_strstr (char *s1, char *s2)
grub_strstr (const char *s1, const char *s2)
{
char *ptr, *tmp;
const char *ptr, *tmp;
while (*s1)
{
@ -583,11 +573,22 @@ grub_strstr (char *s1, char *s2)
while (*s1 && *s1++ == *tmp++);
if (tmp > s2 && !*(tmp - 1))
return ptr;
return (char *) ptr;
}
return 0;
}
int
grub_strlen (const char *str)
{
int len = 0;
while (*str++)
len++;
return len;
}
#endif /* ! STAGE1_5 */
@ -616,31 +617,39 @@ memcheck (int start, int len)
char *
grub_memmove (char *to, char *from, int len)
grub_memmove (char *to, const char *from, int len)
{
char *ret = to;
if (memcheck ((int) to, len))
{
if ((to >= from + len) || (to <= from))
/* This assembly code is stolen from
linux-2.2.2/include/asm-i386/string.h. This is not very fast
but compact. */
int d0, d1, d2;
if (to < from)
{
while (len >= sizeof (unsigned long))
{
len -= sizeof (unsigned long);
*(((unsigned long *) to)++) = *(((unsigned long *) from)++);
}
while (len-- > 0)
*(to++) = *(from++);
asm volatile ("cld\n\t"
"rep\n\t"
"movsb"
: "=&c" (d0), "=&S" (d1), "=&D" (d2)
: "0" (len),"1" (from),"2" (to)
: "memory");
}
else
{
/* We have a region that overlaps, but would be overwritten
if we copied it forward. */
while (len-- > 0)
to[len] = from[len];
asm volatile ("std\n\t"
"rep\n\t"
"movsb\n\t"
"cld"
: "=&c" (d0), "=&S" (d1), "=&D" (d2)
: "0" (len),
"1" (len - 1 + from),
"2" (len - 1 + to)
: "memory");
}
}
return errnum ? NULL : ret;
return errnum ? NULL : to;
}

View file

@ -89,6 +89,12 @@ extern char *grub_scratch_mem;
#define LINUX_SETUP_CODE_START 0x214
#define LINUX_SETUP_INITRD 0x218
/* Linux's video mode selection support. Actually I hate it! */
#define LINUX_VID_MODE_OFFSET 0x1FA
#define LINUX_VID_MODE_NORMAL 0xFFFF
#define LINUX_VID_MODE_EXTENDED 0xFFFE
#define LINUX_VID_MODE_ASK 0xFFFD
#define CL_MY_LOCATION RAW_ADDR (0x92000)
#define CL_MY_END_ADDR RAW_ADDR (0x920FF)
#define CL_MAGIC_ADDR RAW_ADDR (0x90020)
@ -235,6 +241,7 @@ extern char *grub_scratch_mem;
#define strstr grub_strstr
#define strcmp grub_strcmp
#define tolower grub_tolower
#define strlen grub_strlen
#endif /* WITHOUT_LIBC_STUBS */
@ -503,14 +510,15 @@ cmdline_t enter_cmdline (char *script, char *heap);
#endif
/* C library replacement functions with identical semantics. */
void grub_printf (char *format,...);
void grub_printf (const char *format,...);
int grub_tolower (int c);
int grub_isspace (int c);
int grub_strncat (char *s1, char *s2, int n);
char *grub_memmove (char *to, char *from, int len);
int grub_strncat (char *s1, const char *s2, int n);
char *grub_memmove (char *to, const char *from, int len);
void *grub_memset (void *start, int c, int len);
char *grub_strstr (char *s1, char *s2);
int grub_strcmp (char *s1, char *s2);
char *grub_strstr (const char *s1, const char *s2);
int grub_strcmp (const char *s1, const char *s2);
int grub_strlen (const char *str);
/* misc */
void init_page (void);