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> 2002-07-09 Yoshinori K. Okuji <okuji@enbug.org>
From Mark Kettenis <kettenis@chello.nl>: 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). intelligent terminal (such as the comint mode in GNU Emacs).
* The utility ``grub-md5-crypt'' prompts to retype a password and checks * The utility ``grub-md5-crypt'' prompts to retype a password and checks
if the passwords match. if the passwords match.
* Support for booting Linux is rewritten, so GRUB now supports
large-EBDA systems.
New in 0.92 - 2002-04-30: New in 0.92 - 2002-04-30:
* The command "displaymem" uses only hex digits for consistency. * The command "displaymem" uses only hex digits for consistency.

View file

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

View file

@ -1728,6 +1728,12 @@ ENTRY(patch_code_end)
VARIABLE(linux_text_len) VARIABLE(linux_text_len)
.long 0 .long 0
VARIABLE(linux_data_tmp_addr)
.long 0
VARIABLE(linux_data_real_addr)
.long 0
ENTRY(linux_boot) ENTRY(linux_boot)
/* don't worry about saving anything, we're committed at this point */ /* don't worry about saving anything, we're committed at this point */
cld /* forward copying */ cld /* forward copying */
@ -1736,13 +1742,29 @@ ENTRY(linux_boot)
movl EXT_C(linux_text_len), %ecx movl EXT_C(linux_text_len), %ecx
addl $3, %ecx addl $3, %ecx
shrl $2, %ecx shrl $2, %ecx
movl $LINUX_STAGING_AREA, %esi movl $LINUX_BZIMAGE_ADDR, %esi
movl $LINUX_KERNEL, %edi movl $LINUX_ZIMAGE_ADDR, %edi
rep rep
movsl movsl
ENTRY(big_linux_boot) 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 */ /* XXX new stack pointer in safe area for calling functions */
movl $0x4000, %esp movl $0x4000, %esp
call EXT_C(stop_floppy) call EXT_C(stop_floppy)
@ -1754,20 +1776,20 @@ ENTRY(big_linux_boot)
/* final setup for linux boot */ /* final setup for linux boot */
cli cli
movw $LINUX_INIT_SEG, %ax movw %bx, %ss
movw %ax, %ss
movw $LINUX_SETUP_STACK, %sp movw $LINUX_SETUP_STACK, %sp
movw %ax, %ds movw %bx, %ds
movw %ax, %es movw %bx, %es
movw %ax, %fs movw %bx, %fs
movw %ax, %gs movw %bx, %gs
/* jump to start */ /* jump to start */
/* ljmp */ /* ljmp */
.byte 0xea .byte 0xea
.word 0 .word 0
.word LINUX_SETUP_SEG linux_setup_seg:
.word 0
.code32 .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); big_linux = (lh->loadflags & LINUX_FLAG_BIG_KERNEL);
lh->type_of_loader = LINUX_BOOT_LOADER_TYPE; 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) if (lh->version >= 0x0201)
{ {
lh->heap_end_ptr = LINUX_HEAP_END_OFFSET; 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) if (lh->version >= 0x0202)
lh->cmd_line_ptr = CL_MY_LOCATION; lh->cmd_line_ptr = linux_data_real_addr + LINUX_CL_OFFSET;
else else
{ {
lh->cl_magic = CL_MAGIC; lh->cl_magic = LINUX_CL_MAGIC;
lh->cl_offset = CL_MY_LOCATION - CL_BASE_ADDR; lh->cl_offset = LINUX_CL_OFFSET;
lh->setup_move_size lh->setup_move_size = LINUX_SETUP_MOVE_SIZE;
= (unsigned short) (CL_MY_END_ADDR - CL_BASE_ADDR + 1);
} }
} }
else else
{ {
/* Your kernel is quite old... */ /* Your kernel is quite old... */
lh->cl_magic = CL_MAGIC; lh->cl_magic = LINUX_CL_MAGIC;
lh->cl_offset = CL_MY_LOCATION - CL_BASE_ADDR; lh->cl_offset = LINUX_CL_OFFSET;
setup_sects = LINUX_DEFAULT_SETUP_SECTS; 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). */ /* 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; data_len = setup_sects << 9;
text_len = filemax - data_len - SECTOR_SIZE; 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_printf (" linux 'zImage' kernel too big, try 'make bzImage'\n");
grub_close ();
errnum = ERR_WONT_FIT; errnum = ERR_WONT_FIT;
return KERNEL_TYPE_NONE;
} }
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", grub_printf (" [Linux-%s, setup=0x%x, size=0x%x]\n",
(big_linux ? "bzImage" : "zImage"), data_len, text_len); (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)
{
/* Video mode selection support. What a mess! */ /* Video mode selection support. What a mess! */
/* NOTE: Even the word "mess" is not still enough to /* NOTE: Even the word "mess" is not still enough to
represent how wrong and bad the Linux video support is, 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, /* It is possible that DATA_LEN is greater than MULTIBOOT_SEARCH,
so the data may have been read partially. */ so the data may have been read partially. */
if (data_len <= MULTIBOOT_SEARCH) if (data_len <= MULTIBOOT_SEARCH)
grub_memmove ((char *) LINUX_SETUP, buffer, grub_memmove (linux_data_tmp_addr, buffer,
data_len + SECTOR_SIZE); data_len + SECTOR_SIZE);
else else
{ {
grub_memmove ((char *) LINUX_SETUP, buffer, MULTIBOOT_SEARCH); grub_memmove (linux_data_tmp_addr, buffer, MULTIBOOT_SEARCH);
grub_read ((char *) LINUX_SETUP + MULTIBOOT_SEARCH, grub_read (linux_data_tmp_addr + MULTIBOOT_SEARCH,
data_len + SECTOR_SIZE - MULTIBOOT_SEARCH); data_len + SECTOR_SIZE - MULTIBOOT_SEARCH);
} }
if (lh->header != LINUX_MAGIC_SIGNATURE || if (lh->header != LINUX_MAGIC_SIGNATURE ||
lh->version < 0x0200) lh->version < 0x0200)
/* Clear the heap space. */ /* Clear the heap space. */
grub_memset ((char *) LINUX_SETUP + ((setup_sects - 1) << 9), grub_memset (linux_data_tmp_addr + ((setup_sects + 1) << 9),
0, 0,
(64 - setup_sects - 1) << 9); (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. */ avoid to copy spaces unnecessarily. Hell. */
{ {
char *src = skip_to (0, arg); 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++); *(dest++) = *(src++);
/* Add a mem option automatically only if the user doesn't /* Add a mem option automatically only if the user doesn't
specify it explicitly. */ specify it explicitly. */
if (! grub_strstr (arg, "mem=") 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++ = ' ';
*(dest++) = ' '; *dest++ = 'm';
*dest++ = 'e';
grub_memmove (dest, "mem=", 4); *dest++ = 'm';
dest += 4; *dest++ = '=';
dest = convert_to_ascii (dest, 'u', (extended_memory + 0x400)); dest = convert_to_ascii (dest, 'u', (extended_memory + 0x400));
*(dest++) = 'K'; *dest++ = 'K';
} }
*dest = 0; *dest = 0;
@ -419,8 +429,8 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
/* offset into file */ /* offset into file */
grub_seek (data_len + SECTOR_SIZE); grub_seek (data_len + SECTOR_SIZE);
cur_addr = LINUX_STAGING_AREA + text_len; cur_addr = (int) linux_data_tmp_addr + LINUX_SETUP_MOVE_SIZE;
grub_read ((char *) LINUX_STAGING_AREA, text_len); grub_read ((char *) LINUX_BZIMAGE_ADDR, text_len);
if (errnum == ERR_NONE) 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; return big_linux ? KERNEL_TYPE_BIG_LINUX : KERNEL_TYPE_LINUX;
} }
grub_close ();
} }
else
errnum = ERR_WONT_FIT;
} }
else /* no recognizable format */ else /* no recognizable format */
errnum = ERR_EXEC_FORMAT; errnum = ERR_EXEC_FORMAT;
@ -780,7 +786,8 @@ load_initrd (char *initrd)
{ {
int len; int len;
unsigned long moveto; 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 #ifndef NO_DECOMPRESSION
no_decompression = 1; no_decompression = 1;
@ -815,7 +822,6 @@ load_initrd (char *initrd)
printf (" [Linux-initrd @ 0x%x, 0x%x bytes]\n", moveto, len); printf (" [Linux-initrd @ 0x%x, 0x%x bytes]\n", moveto, len);
/* FIXME: Should check if the kernel supports INITRD. */ /* FIXME: Should check if the kernel supports INITRD. */
lh = (struct linux_kernel_header *) LINUX_SETUP;
lh->ramdisk_image = RAW_ADDR (moveto); lh->ramdisk_image = RAW_ADDR (moveto);
lh->ramdisk_size = len; lh->ramdisk_size = len;

View file

@ -138,17 +138,14 @@ extern char *grub_scratch_mem;
#define LINUX_DEFAULT_SETUP_SECTS 4 #define LINUX_DEFAULT_SETUP_SECTS 4
#define LINUX_FLAG_CAN_USE_HEAP 0x80 #define LINUX_FLAG_CAN_USE_HEAP 0x80
#define LINUX_INITRD_MAX_ADDRESS 0x38000000 #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_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_BZIMAGE_ADDR RAW_ADDR (0x100000)
#define LINUX_SETUP RAW_ADDR (0x90000) #define LINUX_ZIMAGE_ADDR RAW_ADDR (0x10000)
#define LINUX_KERNEL RAW_ADDR (0x10000) #define LINUX_OLD_REAL_MODE_ADDR RAW_ADDR (0x90000)
#define LINUX_KERNEL_MAXLEN 0x7F000 #define LINUX_SETUP_STACK 0x9000
#define LINUX_SETUP_SEG 0x9020
#define LINUX_INIT_SEG 0x9000
#define LINUX_SETUP_STACK 0x7F00
#define LINUX_FLAG_BIG_KERNEL 0x1 #define LINUX_FLAG_BIG_KERNEL 0x1
@ -157,10 +154,10 @@ extern char *grub_scratch_mem;
#define LINUX_VID_MODE_EXTENDED 0xFFFE #define LINUX_VID_MODE_EXTENDED 0xFFFE
#define LINUX_VID_MODE_ASK 0xFFFD #define LINUX_VID_MODE_ASK 0xFFFD
#define CL_MY_LOCATION RAW_ADDR (0x97F00) #define LINUX_CL_OFFSET 0x9000
#define CL_MY_END_ADDR RAW_ADDR (0x97FFF) #define LINUX_CL_END_OFFSET 0x90FF
#define CL_MAGIC 0xA33F #define LINUX_SETUP_MOVE_SIZE 0x9100
#define CL_BASE_ADDR RAW_ADDR (0x90000) #define LINUX_CL_MAGIC 0xA33F
/* /*
* General disk stuff * General disk stuff
@ -376,7 +373,7 @@ extern char *grub_scratch_mem;
#include "mb_header.h" #include "mb_header.h"
#include "mb_info.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 struct linux_kernel_header
{ {
char code1[0x0020]; char code1[0x0020];
@ -405,7 +402,7 @@ struct linux_kernel_header
unsigned long bootsect_kludge; /* obsolete */ unsigned long bootsect_kludge; /* obsolete */
unsigned short heap_end_ptr; /* Free memory after setup end */ unsigned short heap_end_ptr; /* Free memory after setup end */
unsigned short pad1; /* Unused */ 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)); } __attribute__ ((packed));
/* Memory map address range descriptor used by GET_MMAP_ENTRY. */ /* 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 version_string[];
extern char config_file[]; extern char config_file[];
extern unsigned long linux_text_len; extern unsigned long linux_text_len;
extern char *linux_data_tmp_addr;
extern char *linux_data_real_addr;
#ifdef GRUB_UTIL #ifdef GRUB_UTIL
/* If not using config file, this variable is set to zero, /* If not using config file, this variable is set to zero,