comply with the linux/i386 boot protocol version 2.02.

This commit is contained in:
okuji 2000-07-23 21:21:37 +00:00
parent a4a19300f1
commit c786d8603e
5 changed files with 166 additions and 54 deletions

View file

@ -1,3 +1,43 @@
2000-07-24 OKUJI Yoshinori <okuji@gnu.org>
Comply with the Linux/i386 boot protocol version 2.02.
* stage2/asm.S [!STAGE1_5] (linux_boot): Set the length of moved
bytes to LINUX_KERNEL_MAXLEN instead of
LINUX_KERNEL_LEN_OFFSET(%eax), since the field is obsolete.
[!STAGE1_5] (big_linux_boot): Don't use SEGMENT or OFFSET.
Instead, embed the segment and the offset in the code itself.
Set %ds, %es, %fs and %gs to %ax (LINUX_INIT_SEG).
* stage2/boot.c (load_image): Rewrite the Linux support code
heavily. Use a structure instead of a batch of macros, to access
a Linux kernel header.
(load_initrd): If MOVETO plus LEN is greater than or equal to
LINUX_INITRD_MAX_ADDRESS, set MOVETO to LINUX_INITRD_MAX_ADDRESS
minus LEN with page aligned.
* stage2/shared.h (LINUX_MAGIC_SIGNATURE): New macro.
(LINUX_DEFAULT_SETUP_SECTS): Likewise.
(LINUX_FLAG_CAN_USE_HEAP): Likewise.
(LINUX_INITRD_MAX_ADDRESS): Likewise.
(LINUX_MAX_SETUP_SECTS): Likewise.
(LINUX_BOOT_LOADER_TYPE): Likewise.
(LINUX_HEAP_END_OFFSET): Likewise.
(LINUX_SETUP_MAXLEN): Removed.
(LINUX_KERNEL_LEN_OFFSET): Likewise.
(LINUX_SETUP_LEN_OFFSET): Likewise.
(LINUX_SETUP_STACK): Set to 0x7F00 instead of 0x3FF4 (why was it
this value?).
(LINUX_SETUP_LOADER): Removed.
(LINUX_SETUP_LOAD_FLAGS): Likewise.
(LINUX_SETUP_CODE_START): Likewise.
(LINUX_SETUP_INITRD): Likewise.
(CL_MY_LOCATION): Set to RAW_ADDR(0x97F00) instead of
RAW_ADDR(0x92000).
(CL_MY_END_ADDR): Set to RAW_addr(0x97FFF) instead of
RAW_ADDR(0x920FF).
(CL_MAGIC_ADDR): Removed.
(CL_OFFSET): Likewise.
[!ASM_FILE] (struct linux_kernel_header): New structure tag.
2000-07-23 OKUJI Yoshinori <okuji@gnu.org>
* docs/tutorial.texi: Fix some syntax errors and ambiguous

1
NEWS
View file

@ -6,6 +6,7 @@ New in 0.5.96 - XXXX-XX-XX:
with this command.
* You can specify `--no-mem-option' to the command "kernel", if you want
GRUB not to pass a Linux's mem option automatically.
* Now GRUB is compliant with the Linux/i386 boot protocol version 2.02.
New in 0.5.95 - 2000-06-27:
* NetBSD ELF kernel support is added. You have to specify the new option

View file

@ -1695,7 +1695,8 @@ ENTRY(linux_boot)
/* copy kernel */
movl $LINUX_SETUP, %eax
movl LINUX_KERNEL_LEN_OFFSET(%eax), %ecx
/* XXX: Too many bytes, but there is no bad effect */
movl $LINUX_KERNEL_MAXLEN, %ecx
shll $2, %ecx
movl $LINUX_STAGING_AREA, %esi
movl $LINUX_KERNEL, %edi
@ -1710,12 +1711,6 @@ ENTRY(big_linux_boot)
/* final setup for linux boot */
movw $LINUX_SETUP_SEG, %ax
movw %ax, segment
xorl %eax, %eax
movl %eax, offset
call EXT_C(prot_to_real)
.code16
@ -1724,13 +1719,16 @@ ENTRY(big_linux_boot)
movw $LINUX_INIT_SEG, %ax
movw %ax, %ss
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
/* jump to start */
#ifdef ABSOLUTE_WITHOUT_ASTERISK
DATA32 ADDR32 ljmp (offset)
#else
DATA32 ADDR32 ljmp *(offset)
#endif
/* ljmp */
.byte 0xea
.word LINUX_SETUP_SEG
.word 0
.code32

View file

@ -45,6 +45,7 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
kernel_t type = KERNEL_TYPE_NONE;
unsigned long flags = 0, text_len = 0, data_len = 0, bss_len = 0;
char *str = 0, *str2 = 0;
struct linux_kernel_header *lh;
union
{
struct multiboot_header *mb;
@ -90,6 +91,10 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
}
}
/* Use BUFFER as a linux kernel header, if the image is Linux zImage
or bzImage. */
lh = (struct linux_kernel_header *) buffer;
/* ELF loading supported if multiboot, FreeBSD and NetBSD. */
if ((type == KERNEL_TYPE_MULTIBOOT
|| grub_strcmp (pu.elf->e_ident + EI_BRAND, "FreeBSD") == 0
@ -200,31 +205,63 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
exec_type = 1;
str = "a.out";
}
else if ((*((unsigned short *) (buffer + BOOTSEC_SIG_OFFSET))
== BOOTSEC_SIGNATURE)
&& ((data_len
= (((long) *((unsigned char *)
(buffer + LINUX_SETUP_LEN_OFFSET))) << 9))
<= LINUX_SETUP_MAXLEN)
&& ((text_len
= (((long) *((unsigned long *)
(buffer + LINUX_KERNEL_LEN_OFFSET))) << 4)),
(data_len + text_len + SECTOR_SIZE) <= ((filemax + 15) & 0xFFFFFFF0)))
else if (lh->boot_flag == BOOTSEC_SIGNATURE
&& lh->setup_sects <= LINUX_MAX_SETUP_SECTS)
{
int big_linux = buffer[LINUX_SETUP_LOAD_FLAGS] & LINUX_FLAG_BIG_KERNEL;
buffer[LINUX_SETUP_LOADER] = 0x70;
int big_linux = 0;
int setup_sects = lh->setup_sects;
if (lh->header == LINUX_MAGIC_SIGNATURE && lh->version >= 0x0200)
{
big_linux = (lh->loadflags & LINUX_FLAG_BIG_KERNEL);
lh->type_of_loader = LINUX_BOOT_LOADER_TYPE;
if (lh->version >= 0x0201)
{
lh->heap_end_ptr = LINUX_HEAP_END_OFFSET;
lh->loadflags |= LINUX_FLAG_CAN_USE_HEAP;
}
if (lh->version >= 0x0202)
lh->cmd_line_ptr = CL_MY_LOCATION;
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);
}
}
else
{
/* Your kernel is quite old... */
lh->cl_magic = CL_MAGIC;
lh->cl_offset = CL_MY_LOCATION - CL_BASE_ADDR;
setup_sects = LINUX_DEFAULT_SETUP_SECTS;
}
/* If SETUP_SECTS is not set, set it to the default (4). */
if (! setup_sects)
setup_sects = LINUX_DEFAULT_SETUP_SECTS;
data_len = setup_sects << 9;
text_len = filemax - data_len - SECTOR_SIZE;
if (! big_linux && text_len > LINUX_KERNEL_MAXLEN)
{
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;
return KERNEL_TYPE_NONE;
}
printf (" [Linux-%s, setup=0x%x, size=0x%x]\n",
(big_linux ? "bzImage" : "zImage"), data_len, text_len);
grub_printf (" [Linux-%s, setup=0x%x, size=0x%x]\n",
(big_linux ? "bzImage" : "zImage"), data_len, text_len);
if (mbi.mem_lower >= 608)
/* 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 shit! */
{
@ -254,24 +291,24 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
return KERNEL_TYPE_NONE;
}
/* 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));
lh->vid_mode = vid_mode;
}
}
memmove ((char *) LINUX_SETUP, buffer, data_len + SECTOR_SIZE);
if (lh->header != LINUX_MAGIC_SIGNATURE ||
lh->version < 0x0200)
/* Clear the heap space. */
grub_memset ((char *) LINUX_SETUP + ((setup_sects - 1) << 9),
0,
(64 - setup_sects - 1) << 9);
/* copy command-line plus memory hack to staging area */
{
char *src = arg;
char *dest = (char *) CL_MY_LOCATION;
*((unsigned short *) CL_OFFSET) = CL_MY_LOCATION - CL_BASE_ADDR;
*((unsigned short *) CL_MAGIC_ADDR) = CL_MAGIC;
/* Add a mem option automatically only if the user doesn't
specify it explicitly. */
if (! grub_strstr (src, "mem=")
@ -563,8 +600,9 @@ int
load_initrd (char *initrd)
{
int len;
unsigned long *ramdisk, moveto;
unsigned long moveto;
struct linux_kernel_header *lh;
if (! grub_open (initrd))
return 0;
@ -575,7 +613,10 @@ load_initrd (char *initrd)
return 0;
}
moveto = ((mbi.mem_upper + 0x400) * 0x400 - len) & 0x3ffff000;
moveto = ((mbi.mem_upper + 0x400) * 0x400 - len) & 0xfffff000;
if (moveto + len >= LINUX_INITRD_MAX_ADDRESS)
moveto = (LINUX_INITRD_MAX_ADDRESS - len) & 0xfffff000;
/* XXX: Linux 2.3.xx has a bug in the memory range check, so avoid
the last page. */
moveto -= 0x1000;
@ -583,9 +624,10 @@ load_initrd (char *initrd)
printf (" [Linux-initrd @ 0x%x, 0x%x bytes]\n", moveto, len);
ramdisk = (unsigned long *) (LINUX_SETUP + LINUX_SETUP_INITRD);
ramdisk[0] = RAW_ADDR (moveto);
ramdisk[1] = 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;
grub_close ();
return 1;

View file

@ -135,22 +135,23 @@ extern char *grub_scratch_mem;
* Linux setup parameters
*/
#define LINUX_MAGIC_SIGNATURE 0x53726448 /* "HdrS" */
#define LINUX_DEFAULT_SETUP_SECTS 4
#define LINUX_FLAG_CAN_USE_HEAP 0x80
#define LINUX_INITRD_MAX_ADDRESS 0x3C000000
#define LINUX_MAX_SETUP_SECTS 63
#define LINUX_BOOT_LOADER_TYPE 0x71
#define LINUX_HEAP_END_OFFSET (0x7F00 - 0x200)
#define LINUX_STAGING_AREA RAW_ADDR (0x100000)
#define LINUX_SETUP RAW_ADDR (0x90000)
#define LINUX_SETUP_MAXLEN 0x1E00
#define LINUX_KERNEL RAW_ADDR (0x10000)
#define LINUX_KERNEL_MAXLEN 0x7F000
#define LINUX_SETUP_SEG 0x9020
#define LINUX_INIT_SEG 0x9000
#define LINUX_KERNEL_LEN_OFFSET 0x1F4
#define LINUX_SETUP_LEN_OFFSET 0x1F1
#define LINUX_SETUP_STACK 0x3FF4
#define LINUX_SETUP_STACK 0x7F00
#define LINUX_SETUP_LOADER 0x210
#define LINUX_SETUP_LOAD_FLAGS 0x211
#define LINUX_FLAG_BIG_KERNEL 0x1
#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
@ -158,12 +159,10 @@ extern char *grub_scratch_mem;
#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)
#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 CL_OFFSET RAW_ADDR (0x90022)
/*
* General disk stuff
@ -370,6 +369,38 @@ extern char *grub_scratch_mem;
#include "mb_header.h"
#include "mb_info.h"
/* For the Linux/i386 boot protocol version 2.02. */
struct linux_kernel_header
{
char code1[0x0020];
unsigned short cl_magic; /* Magic number 0xA33F */
unsigned short cl_offset; /* The offset of command line */
char code2[0x01F1 - 0x0020 - 2 - 2];
unsigned char setup_sects; /* The size of the setup in sectors */
unsigned short root_flags; /* If the root is mounted readonly */
unsigned short syssize; /* obsolete */
unsigned short swap_dev; /* obsolete */
unsigned short ram_size; /* obsolete */
unsigned short vid_mode; /* Video mode control */
unsigned short root_dev; /* Default root device number */
unsigned short boot_flag; /* 0xAA55 magic number */
unsigned short jump; /* Jump instruction */
unsigned long header; /* Magic signature "HdrS" */
unsigned short version; /* Boot protocol version supported */
unsigned long realmode_swtch; /* Boot loader hook */
unsigned long start_sys; /* Points to kernel version string */
unsigned char type_of_loader; /* Boot loader identifier */
unsigned char loadflags; /* Boot protocol option flags */
unsigned short setup_move_size; /* Move to high memory size */
unsigned long code32_start; /* Boot loader hook */
unsigned long ramdisk_image; /* initrd load address */
unsigned long ramdisk_size; /* initrd size */
unsigned long bootsect_kludge; /* obsolete */
unsigned long heap_end_ptr; /* Free memory after setup end */
unsigned short pad1; /* Unused */
unsigned long cmd_line_ptr; /* Points to the kernel command line */
} __attribute__ ((packed));
/* Memory map address range descriptor used by GET_MMAP_ENTRY. */
struct mmar_desc
{