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> 2000-07-23 OKUJI Yoshinori <okuji@gnu.org>
* docs/tutorial.texi: Fix some syntax errors and ambiguous * 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. with this command.
* You can specify `--no-mem-option' to the command "kernel", if you want * You can specify `--no-mem-option' to the command "kernel", if you want
GRUB not to pass a Linux's mem option automatically. 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: New in 0.5.95 - 2000-06-27:
* NetBSD ELF kernel support is added. You have to specify the new option * NetBSD ELF kernel support is added. You have to specify the new option

View file

@ -1695,7 +1695,8 @@ ENTRY(linux_boot)
/* copy kernel */ /* copy kernel */
movl $LINUX_SETUP, %eax 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 shll $2, %ecx
movl $LINUX_STAGING_AREA, %esi movl $LINUX_STAGING_AREA, %esi
movl $LINUX_KERNEL, %edi movl $LINUX_KERNEL, %edi
@ -1710,12 +1711,6 @@ ENTRY(big_linux_boot)
/* final setup for 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) call EXT_C(prot_to_real)
.code16 .code16
@ -1724,13 +1719,16 @@ ENTRY(big_linux_boot)
movw $LINUX_INIT_SEG, %ax movw $LINUX_INIT_SEG, %ax
movw %ax, %ss movw %ax, %ss
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
/* jump to start */ /* jump to start */
#ifdef ABSOLUTE_WITHOUT_ASTERISK /* ljmp */
DATA32 ADDR32 ljmp (offset) .byte 0xea
#else .word LINUX_SETUP_SEG
DATA32 ADDR32 ljmp *(offset) .word 0
#endif
.code32 .code32

View file

@ -45,6 +45,7 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
kernel_t type = KERNEL_TYPE_NONE; kernel_t type = KERNEL_TYPE_NONE;
unsigned long flags = 0, text_len = 0, data_len = 0, bss_len = 0; unsigned long flags = 0, text_len = 0, data_len = 0, bss_len = 0;
char *str = 0, *str2 = 0; char *str = 0, *str2 = 0;
struct linux_kernel_header *lh;
union union
{ {
struct multiboot_header *mb; 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. */ /* ELF loading supported if multiboot, FreeBSD and NetBSD. */
if ((type == KERNEL_TYPE_MULTIBOOT if ((type == KERNEL_TYPE_MULTIBOOT
|| grub_strcmp (pu.elf->e_ident + EI_BRAND, "FreeBSD") == 0 || 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; exec_type = 1;
str = "a.out"; str = "a.out";
} }
else if ((*((unsigned short *) (buffer + BOOTSEC_SIG_OFFSET)) else if (lh->boot_flag == BOOTSEC_SIGNATURE
== BOOTSEC_SIGNATURE) && lh->setup_sects <= LINUX_MAX_SETUP_SECTS)
&& ((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)))
{ {
int big_linux = buffer[LINUX_SETUP_LOAD_FLAGS] & LINUX_FLAG_BIG_KERNEL; int big_linux = 0;
buffer[LINUX_SETUP_LOADER] = 0x70; 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) 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 (); grub_close ();
errnum = ERR_WONT_FIT; errnum = ERR_WONT_FIT;
return KERNEL_TYPE_NONE; return KERNEL_TYPE_NONE;
} }
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);
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! */ /* 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; return KERNEL_TYPE_NONE;
} }
/* Set the vid mode to VID_MODE. Note that this can work lh->vid_mode = vid_mode;
because i386 architecture is little-endian. */
grub_memmove (buffer + LINUX_VID_MODE_OFFSET,
(char *) &vid_mode,
sizeof (unsigned short));
} }
} }
memmove ((char *) LINUX_SETUP, buffer, data_len + SECTOR_SIZE); 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 */ /* copy command-line plus memory hack to staging area */
{ {
char *src = arg; char *src = arg;
char *dest = (char *) CL_MY_LOCATION; 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 /* Add a mem option automatically only if the user doesn't
specify it explicitly. */ specify it explicitly. */
if (! grub_strstr (src, "mem=") if (! grub_strstr (src, "mem=")
@ -563,8 +600,9 @@ int
load_initrd (char *initrd) load_initrd (char *initrd)
{ {
int len; int len;
unsigned long *ramdisk, moveto; unsigned long moveto;
struct linux_kernel_header *lh;
if (! grub_open (initrd)) if (! grub_open (initrd))
return 0; return 0;
@ -575,7 +613,10 @@ load_initrd (char *initrd)
return 0; 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 /* XXX: Linux 2.3.xx has a bug in the memory range check, so avoid
the last page. */ the last page. */
moveto -= 0x1000; moveto -= 0x1000;
@ -583,9 +624,10 @@ 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);
ramdisk = (unsigned long *) (LINUX_SETUP + LINUX_SETUP_INITRD); /* FIXME: Should check if the kernel supports INITRD. */
ramdisk[0] = RAW_ADDR (moveto); lh = (struct linux_kernel_header *) LINUX_SETUP;
ramdisk[1] = len; lh->ramdisk_image = RAW_ADDR (moveto);
lh->ramdisk_size = len;
grub_close (); grub_close ();
return 1; return 1;

View file

@ -135,22 +135,23 @@ extern char *grub_scratch_mem;
* Linux setup parameters * 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_STAGING_AREA RAW_ADDR (0x100000)
#define LINUX_SETUP RAW_ADDR (0x90000) #define LINUX_SETUP RAW_ADDR (0x90000)
#define LINUX_SETUP_MAXLEN 0x1E00
#define LINUX_KERNEL RAW_ADDR (0x10000) #define LINUX_KERNEL RAW_ADDR (0x10000)
#define LINUX_KERNEL_MAXLEN 0x7F000 #define LINUX_KERNEL_MAXLEN 0x7F000
#define LINUX_SETUP_SEG 0x9020 #define LINUX_SETUP_SEG 0x9020
#define LINUX_INIT_SEG 0x9000 #define LINUX_INIT_SEG 0x9000
#define LINUX_KERNEL_LEN_OFFSET 0x1F4 #define LINUX_SETUP_STACK 0x7F00
#define LINUX_SETUP_LEN_OFFSET 0x1F1
#define LINUX_SETUP_STACK 0x3FF4
#define LINUX_SETUP_LOADER 0x210
#define LINUX_SETUP_LOAD_FLAGS 0x211
#define LINUX_FLAG_BIG_KERNEL 0x1 #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! */ /* Linux's video mode selection support. Actually I hate it! */
#define LINUX_VID_MODE_OFFSET 0x1FA #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_EXTENDED 0xFFFE
#define LINUX_VID_MODE_ASK 0xFFFD #define LINUX_VID_MODE_ASK 0xFFFD
#define CL_MY_LOCATION RAW_ADDR (0x92000) #define CL_MY_LOCATION RAW_ADDR (0x97F00)
#define CL_MY_END_ADDR RAW_ADDR (0x920FF) #define CL_MY_END_ADDR RAW_ADDR (0x97FFF)
#define CL_MAGIC_ADDR RAW_ADDR (0x90020)
#define CL_MAGIC 0xA33F #define CL_MAGIC 0xA33F
#define CL_BASE_ADDR RAW_ADDR (0x90000) #define CL_BASE_ADDR RAW_ADDR (0x90000)
#define CL_OFFSET RAW_ADDR (0x90022)
/* /*
* General disk stuff * General disk stuff
@ -370,6 +369,38 @@ 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. */
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. */ /* Memory map address range descriptor used by GET_MMAP_ENTRY. */
struct mmar_desc struct mmar_desc
{ {