2002-07-12 Yoshinori K. Okuji <okuji@enbug.org>

* stage2/boot.c (load_image): Rewrite the Linux booting support
	radically. Now it should work even on a machine having, say,
	only 128KB, theoretically. Of course, GRUB itself doesn't work
	on such a system, though.
	(load_initrd): Initialize LH based on CUR_ADDR, because the
	location becomes dynamic.
	* stage2/shared.h (LINUX_MAX_SETUP_SECTS): Set to 64.
	(LINUX_HEAP_END_OFFSET): Set to (0x9000 - 0x200).
	(LINUX_STAGING_AREA): Removed.
	(LINUX_SETUP): Likewise.
	(LINUX_KERNEL): Likewise.
	(LINUX_KERNEL_MAXLEN): Likewise.
	(LINUX_SETUP_SEG): Likewise.
	(LINUX_INIT_SEG): Likewise.
	(LINUX_SETUP_STACK): Set to 0x9000.
	(LINUX_BZIMAGE_ADDR): New macro.
	(LINUX_ZIMAGE_ADDR): Likewise.
	(LINUX_OLD_REAL_MODE_ADDR): Likewise.
	(CL_MY_LOCATION): Removed.
	(CL_MY_END_ADDR): Likewise.
	(CL_BASE_ADDR): Likewise.
	(CL_MAGIC): Renamed to ...
	(LINUX_CL_MAGIC): ... this.
	(LINUX_CL_OFFSET): New macro.
	(LINUX_CL_END_OFFSET): Likewise.
	(LINUX_SETUP_MOVE_SIZE): Likewise.
	(struct linux_kernel_header): Change the type of the member
	"cmd_line_ptr" to char *.
	(linux_data_tmp_addr): Declared.
	(linux_data_real_addr): Likewise.
	* stage2/asm.S [!STAGE1_5] (linux_data_tmp_addr): New variable.
	[!STAGE1_5] (linux_data_real_addr): Likewise.
	[!STAGE1_5] (big_linux_boot): Copy the real mode part from
	LINUX_DATA_TMP_ADDR to LINUX_DATA_REAL_ADDR.
	* grub/asmstub.c (linux_data_tmp_addr): New variable.
	(linux_data_real_addr): Likewise.
This commit is contained in:
okuji 2002-07-12 09:55:55 +00:00
parent f8b4503f1b
commit 51955d52d8
6 changed files with 158 additions and 88 deletions

View file

@ -1,3 +1,42 @@
2002-07-12 Yoshinori K. Okuji <okuji@enbug.org>
* stage2/boot.c (load_image): Rewrite the Linux booting support
radically. Now it should work even on a machine having, say,
only 128KB, theoretically. Of course, GRUB itself doesn't work
on such a system, though.
(load_initrd): Initialize LH based on CUR_ADDR, because the
location becomes dynamic.
* stage2/shared.h (LINUX_MAX_SETUP_SECTS): Set to 64.
(LINUX_HEAP_END_OFFSET): Set to (0x9000 - 0x200).
(LINUX_STAGING_AREA): Removed.
(LINUX_SETUP): Likewise.
(LINUX_KERNEL): Likewise.
(LINUX_KERNEL_MAXLEN): Likewise.
(LINUX_SETUP_SEG): Likewise.
(LINUX_INIT_SEG): Likewise.
(LINUX_SETUP_STACK): Set to 0x9000.
(LINUX_BZIMAGE_ADDR): New macro.
(LINUX_ZIMAGE_ADDR): Likewise.
(LINUX_OLD_REAL_MODE_ADDR): Likewise.
(CL_MY_LOCATION): Removed.
(CL_MY_END_ADDR): Likewise.
(CL_BASE_ADDR): Likewise.
(CL_MAGIC): Renamed to ...
(LINUX_CL_MAGIC): ... this.
(LINUX_CL_OFFSET): New macro.
(LINUX_CL_END_OFFSET): Likewise.
(LINUX_SETUP_MOVE_SIZE): Likewise.
(struct linux_kernel_header): Change the type of the member
"cmd_line_ptr" to char *.
(linux_data_tmp_addr): Declared.
(linux_data_real_addr): Likewise.
* stage2/asm.S [!STAGE1_5] (linux_data_tmp_addr): New variable.
[!STAGE1_5] (linux_data_real_addr): Likewise.
[!STAGE1_5] (big_linux_boot): Copy the real mode part from
LINUX_DATA_TMP_ADDR to LINUX_DATA_REAL_ADDR.
* grub/asmstub.c (linux_data_tmp_addr): New variable.
(linux_data_real_addr): Likewise.
2002-07-09 Yoshinori K. Okuji <okuji@enbug.org>
From Mark Kettenis <kettenis@chello.nl>:

2
NEWS
View file

@ -20,6 +20,8 @@ New in 0.93:
intelligent terminal (such as the comint mode in GNU Emacs).
* The utility ``grub-md5-crypt'' prompts to retype a password and checks
if the passwords match.
* Support for booting Linux is rewritten, so GRUB now supports
large-EBDA systems.
New in 0.92 - 2002-04-30:
* The command "displaymem" uses only hex digits for consistency.

View file

@ -73,6 +73,8 @@ int saved_entryno = 0;
char version_string[] = VERSION;
char config_file[128] = "/boot/grub/menu.lst"; /* FIXME: arbitrary */
unsigned long linux_text_len = 0;
char *linux_data_tmp_addr = 0;
char *linux_data_real_addr = 0;
unsigned short io_map[IO_MAP_SIZE];
struct apm_info apm_bios_info;

View file

@ -1728,6 +1728,12 @@ ENTRY(patch_code_end)
VARIABLE(linux_text_len)
.long 0
VARIABLE(linux_data_tmp_addr)
.long 0
VARIABLE(linux_data_real_addr)
.long 0
ENTRY(linux_boot)
/* don't worry about saving anything, we're committed at this point */
cld /* forward copying */
@ -1736,13 +1742,29 @@ ENTRY(linux_boot)
movl EXT_C(linux_text_len), %ecx
addl $3, %ecx
shrl $2, %ecx
movl $LINUX_STAGING_AREA, %esi
movl $LINUX_KERNEL, %edi
movl $LINUX_BZIMAGE_ADDR, %esi
movl $LINUX_ZIMAGE_ADDR, %edi
rep
movsl
ENTRY(big_linux_boot)
movl EXT_C(linux_data_real_addr), %ebx
/* copy the real mode part */
movl EXT_C(linux_data_tmp_addr), %esi
movl %ebx, %edi
movl $LINUX_SETUP_MOVE_SIZE, %ecx
cld
rep
movsb
/* change %ebx to the segment address */
shrl $4, %ebx
movl %ebx, %eax
addl $0x20, %eax
movl %eax, linux_setup_seg
/* XXX new stack pointer in safe area for calling functions */
movl $0x4000, %esp
call EXT_C(stop_floppy)
@ -1754,20 +1776,20 @@ ENTRY(big_linux_boot)
/* final setup for linux boot */
cli
movw $LINUX_INIT_SEG, %ax
movw %ax, %ss
movw %bx, %ss
movw $LINUX_SETUP_STACK, %sp
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw %bx, %ds
movw %bx, %es
movw %bx, %fs
movw %bx, %gs
/* jump to start */
/* ljmp */
.byte 0xea
.word 0
.word LINUX_SETUP_SEG
linux_setup_seg:
.word 0
.code32

View file

@ -227,6 +227,13 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
big_linux = (lh->loadflags & LINUX_FLAG_BIG_KERNEL);
lh->type_of_loader = LINUX_BOOT_LOADER_TYPE;
/* Put the real mode part at as a high location as possible. */
linux_data_real_addr
= (char *) ((mbi.mem_lower << 10) - LINUX_SETUP_MOVE_SIZE);
/* But it must not exceed the traditional area. */
if (linux_data_real_addr > (char *) LINUX_OLD_REAL_MODE_ADDR)
linux_data_real_addr = (char *) LINUX_OLD_REAL_MODE_ADDR;
if (lh->version >= 0x0201)
{
lh->heap_end_ptr = LINUX_HEAP_END_OFFSET;
@ -234,22 +241,23 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
}
if (lh->version >= 0x0202)
lh->cmd_line_ptr = CL_MY_LOCATION;
lh->cmd_line_ptr = linux_data_real_addr + LINUX_CL_OFFSET;
else
{
lh->cl_magic = CL_MAGIC;
lh->cl_offset = CL_MY_LOCATION - CL_BASE_ADDR;
lh->setup_move_size
= (unsigned short) (CL_MY_END_ADDR - CL_BASE_ADDR + 1);
lh->cl_magic = LINUX_CL_MAGIC;
lh->cl_offset = LINUX_CL_OFFSET;
lh->setup_move_size = LINUX_SETUP_MOVE_SIZE;
}
}
else
{
/* Your kernel is quite old... */
lh->cl_magic = CL_MAGIC;
lh->cl_offset = CL_MY_LOCATION - CL_BASE_ADDR;
lh->cl_magic = LINUX_CL_MAGIC;
lh->cl_offset = LINUX_CL_OFFSET;
setup_sects = LINUX_DEFAULT_SETUP_SECTS;
linux_data_real_addr = (char *) LINUX_OLD_REAL_MODE_ADDR;
}
/* If SETUP_SECTS is not set, set it to the default (4). */
@ -259,21 +267,22 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
data_len = setup_sects << 9;
text_len = filemax - data_len - SECTOR_SIZE;
if (! big_linux && text_len > LINUX_KERNEL_MAXLEN)
linux_data_tmp_addr = (char *) LINUX_BZIMAGE_ADDR + text_len;
if (! big_linux
&& text_len > linux_data_real_addr - (char *) LINUX_ZIMAGE_ADDR)
{
grub_printf (" linux 'zImage' kernel too big, try 'make bzImage'\n");
grub_close ();
errnum = ERR_WONT_FIT;
return KERNEL_TYPE_NONE;
}
grub_printf (" [Linux-%s, setup=0x%x, size=0x%x]\n",
(big_linux ? "bzImage" : "zImage"), data_len, text_len);
/* FIXME: SETUP_SECTS should be supported up to 63.
But do you know there are >640KB conventional memory machines? */
if (mbi.mem_lower >= 608 && setup_sects < 60)
else if (linux_data_real_addr + LINUX_SETUP_MOVE_SIZE
> RAW_ADDR ((char *) (mbi.mem_lower << 10)))
errnum = ERR_WONT_FIT;
else
{
grub_printf (" [Linux-%s, setup=0x%x, size=0x%x]\n",
(big_linux ? "bzImage" : "zImage"), data_len, text_len);
/* Video mode selection support. What a mess! */
/* NOTE: Even the word "mess" is not still enough to
represent how wrong and bad the Linux video support is,
@ -367,19 +376,19 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
/* It is possible that DATA_LEN is greater than MULTIBOOT_SEARCH,
so the data may have been read partially. */
if (data_len <= MULTIBOOT_SEARCH)
grub_memmove ((char *) LINUX_SETUP, buffer,
grub_memmove (linux_data_tmp_addr, buffer,
data_len + SECTOR_SIZE);
else
{
grub_memmove ((char *) LINUX_SETUP, buffer, MULTIBOOT_SEARCH);
grub_read ((char *) LINUX_SETUP + MULTIBOOT_SEARCH,
grub_memmove (linux_data_tmp_addr, buffer, MULTIBOOT_SEARCH);
grub_read (linux_data_tmp_addr + MULTIBOOT_SEARCH,
data_len + SECTOR_SIZE - MULTIBOOT_SEARCH);
}
if (lh->header != LINUX_MAGIC_SIGNATURE ||
lh->version < 0x0200)
/* Clear the heap space. */
grub_memset ((char *) LINUX_SETUP + ((setup_sects - 1) << 9),
grub_memset (linux_data_tmp_addr + ((setup_sects + 1) << 9),
0,
(64 - setup_sects - 1) << 9);
@ -393,24 +402,25 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
avoid to copy spaces unnecessarily. Hell. */
{
char *src = skip_to (0, arg);
char *dest = (char *) CL_MY_LOCATION;
char *dest = linux_data_tmp_addr + LINUX_CL_OFFSET;
while (((int) dest) < CL_MY_END_ADDR && *src)
while (dest < linux_data_tmp_addr + LINUX_CL_END_OFFSET && *src)
*(dest++) = *(src++);
/* Add a mem option automatically only if the user doesn't
specify it explicitly. */
if (! grub_strstr (arg, "mem=")
&& ! (load_flags & KERNEL_LOAD_NO_MEM_OPTION))
&& ! (load_flags & KERNEL_LOAD_NO_MEM_OPTION)
&& dest + 15 < linux_data_tmp_addr + LINUX_CL_END_OFFSET)
{
if (dest != (char *) CL_MY_LOCATION)
*(dest++) = ' ';
grub_memmove (dest, "mem=", 4);
dest += 4;
*dest++ = ' ';
*dest++ = 'm';
*dest++ = 'e';
*dest++ = 'm';
*dest++ = '=';
dest = convert_to_ascii (dest, 'u', (extended_memory + 0x400));
*(dest++) = 'K';
*dest++ = 'K';
}
*dest = 0;
@ -419,8 +429,8 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
/* offset into file */
grub_seek (data_len + SECTOR_SIZE);
cur_addr = LINUX_STAGING_AREA + text_len;
grub_read ((char *) LINUX_STAGING_AREA, text_len);
cur_addr = (int) linux_data_tmp_addr + LINUX_SETUP_MOVE_SIZE;
grub_read ((char *) LINUX_BZIMAGE_ADDR, text_len);
if (errnum == ERR_NONE)
{
@ -440,11 +450,7 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
return big_linux ? KERNEL_TYPE_BIG_LINUX : KERNEL_TYPE_LINUX;
}
grub_close ();
}
else
errnum = ERR_WONT_FIT;
}
else /* no recognizable format */
errnum = ERR_EXEC_FORMAT;
@ -780,7 +786,8 @@ load_initrd (char *initrd)
{
int len;
unsigned long moveto;
struct linux_kernel_header *lh;
struct linux_kernel_header *lh
= (struct linux_kernel_header *) (cur_addr - LINUX_SETUP_MOVE_SIZE);
#ifndef NO_DECOMPRESSION
no_decompression = 1;
@ -815,7 +822,6 @@ load_initrd (char *initrd)
printf (" [Linux-initrd @ 0x%x, 0x%x bytes]\n", moveto, len);
/* FIXME: Should check if the kernel supports INITRD. */
lh = (struct linux_kernel_header *) LINUX_SETUP;
lh->ramdisk_image = RAW_ADDR (moveto);
lh->ramdisk_size = len;

View file

@ -138,29 +138,26 @@ extern char *grub_scratch_mem;
#define LINUX_DEFAULT_SETUP_SECTS 4
#define LINUX_FLAG_CAN_USE_HEAP 0x80
#define LINUX_INITRD_MAX_ADDRESS 0x38000000
#define LINUX_MAX_SETUP_SECTS 63
#define LINUX_MAX_SETUP_SECTS 64
#define LINUX_BOOT_LOADER_TYPE 0x71
#define LINUX_HEAP_END_OFFSET (0x7F00 - 0x200)
#define LINUX_HEAP_END_OFFSET (0x9000 - 0x200)
#define LINUX_STAGING_AREA RAW_ADDR (0x100000)
#define LINUX_SETUP RAW_ADDR (0x90000)
#define LINUX_KERNEL RAW_ADDR (0x10000)
#define LINUX_KERNEL_MAXLEN 0x7F000
#define LINUX_SETUP_SEG 0x9020
#define LINUX_INIT_SEG 0x9000
#define LINUX_SETUP_STACK 0x7F00
#define LINUX_BZIMAGE_ADDR RAW_ADDR (0x100000)
#define LINUX_ZIMAGE_ADDR RAW_ADDR (0x10000)
#define LINUX_OLD_REAL_MODE_ADDR RAW_ADDR (0x90000)
#define LINUX_SETUP_STACK 0x9000
#define LINUX_FLAG_BIG_KERNEL 0x1
#define LINUX_FLAG_BIG_KERNEL 0x1
/* Linux's video mode selection support. Actually I hate it! */
#define LINUX_VID_MODE_NORMAL 0xFFFF
#define LINUX_VID_MODE_EXTENDED 0xFFFE
#define LINUX_VID_MODE_ASK 0xFFFD
#define LINUX_VID_MODE_NORMAL 0xFFFF
#define LINUX_VID_MODE_EXTENDED 0xFFFE
#define LINUX_VID_MODE_ASK 0xFFFD
#define CL_MY_LOCATION RAW_ADDR (0x97F00)
#define CL_MY_END_ADDR RAW_ADDR (0x97FFF)
#define CL_MAGIC 0xA33F
#define CL_BASE_ADDR RAW_ADDR (0x90000)
#define LINUX_CL_OFFSET 0x9000
#define LINUX_CL_END_OFFSET 0x90FF
#define LINUX_SETUP_MOVE_SIZE 0x9100
#define LINUX_CL_MAGIC 0xA33F
/*
* General disk stuff
@ -376,7 +373,7 @@ extern char *grub_scratch_mem;
#include "mb_header.h"
#include "mb_info.h"
/* For the Linux/i386 boot protocol version 2.02. */
/* For the Linux/i386 boot protocol version 2.03. */
struct linux_kernel_header
{
char code1[0x0020];
@ -405,7 +402,7 @@ struct linux_kernel_header
unsigned long bootsect_kludge; /* obsolete */
unsigned short heap_end_ptr; /* Free memory after setup end */
unsigned short pad1; /* Unused */
unsigned long cmd_line_ptr; /* Points to the kernel command line */
char *cmd_line_ptr; /* Points to the kernel command line */
} __attribute__ ((packed));
/* Memory map address range descriptor used by GET_MMAP_ENTRY. */
@ -550,6 +547,8 @@ extern unsigned char force_lba;
extern char version_string[];
extern char config_file[];
extern unsigned long linux_text_len;
extern char *linux_data_tmp_addr;
extern char *linux_data_real_addr;
#ifdef GRUB_UTIL
/* If not using config file, this variable is set to zero,