From e6eced71501f15275f2bc67b0826727ee6d60850 Mon Sep 17 00:00:00 2001 From: jeroen Date: Sun, 15 Feb 2004 10:09:11 +0000 Subject: [PATCH] 2004-02-15 Jeroen Dekkers * fs/ext2.c (pupa_ext2_read_file): Correct the value of BLOCKEND when it is EXT2_BLOCK_SIZE (data). New argument READ_HOOK, all callers changed. Set DATA->DISK->READ_HOOK to READ_HOOK before reading and reset it after reading. (pupa_ext2_close): Return PUPA_ERR_NONE. * include/pupa/i386/pc/linux.h (PUPA_LINUX_INITRD_MAX_ADDRESS): Correct value. (struct linux_kernel_header): Add kernel_version and initrd_addr_max. * loader/i386/pc/linux.c (pupa_rescue_cmd_linux): Check whether pupa_file_read succeeds. (pupa_rescue_cmd_initrd): Implement. --- ChangeLog | 16 +++++++ fs/ext2.c | 33 ++++++++----- include/grub/i386/pc/linux.h | 8 ++-- loader/i386/pc/linux.c | 93 +++++++++++++++++++++++++++++++++--- 4 files changed, 130 insertions(+), 20 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8a0c70d5c..e42b879fe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2004-02-15 Jeroen Dekkers + + * fs/ext2.c (pupa_ext2_read_file): Correct the value of BLOCKEND + when it is EXT2_BLOCK_SIZE (data). New argument READ_HOOK, all + callers changed. Set DATA->DISK->READ_HOOK to READ_HOOK before + reading and reset it after reading. + (pupa_ext2_close): Return PUPA_ERR_NONE. + + * include/pupa/i386/pc/linux.h (PUPA_LINUX_INITRD_MAX_ADDRESS): + Correct value. + (struct linux_kernel_header): Add kernel_version and + initrd_addr_max. + * loader/i386/pc/linux.c (pupa_rescue_cmd_linux): Check whether + pupa_file_read succeeds. + (pupa_rescue_cmd_initrd): Implement. + 2003-12-03 Marco Gerards * fs/ext2.c (pupa_ext2_label): New function. diff --git a/fs/ext2.c b/fs/ext2.c index 9f1cca24f..62e46ef3d 100644 --- a/fs/ext2.c +++ b/fs/ext2.c @@ -1,6 +1,7 @@ /* ext2.c - Second Extended filesystem */ /* * PUPA -- Preliminary Universal Programming Architecture for GRUB + * Copyright (C) 2004 Free Software Foundation, Inc. * Copyright (C) 2003 Marco Gerards . * * This program is free software; you can redistribute it and/or modify @@ -235,8 +236,10 @@ pupa_ext2_get_file_block (struct pupa_ext2_data *data, /* Read LEN bytes from the file described by DATA starting with byte POS. Return the amount of read bytes in READ. */ static pupa_ssize_t -pupa_ext2_read_file (struct pupa_ext2_data *data, int pos, - unsigned int len, char *buf) +pupa_ext2_read_file (struct pupa_ext2_data *data, + void (*read_hook) (unsigned long sector, + unsigned offset, unsigned length), + int pos, unsigned int len, char *buf) { int i; int blockcnt; @@ -264,7 +267,13 @@ pupa_ext2_read_file (struct pupa_ext2_data *data, int pos, /* Last block. */ if (i == blockcnt - 1) - blockend = (len + pos) % EXT2_BLOCK_SIZE (data); + { + blockend = (len + pos) % EXT2_BLOCK_SIZE (data); + + /* The last portion is exactly EXT2_BLOCK_SIZE (data). */ + if (!blockend) + blockend = EXT2_BLOCK_SIZE (data); + } /* First block. */ if (i == pos / EXT2_BLOCK_SIZE (data)) @@ -277,8 +286,10 @@ pupa_ext2_read_file (struct pupa_ext2_data *data, int pos, is zero filled instead. */ if (blknr) { + data->disk->read_hook = read_hook; pupa_disk_read (data->disk, blknr, skipfirst, - blockend, buf); + blockend, buf); + data->disk->read_hook = 0; if (pupa_errno) return -1; } @@ -418,7 +429,7 @@ pupa_ext2_find_file (struct pupa_ext2_data *data, const char *path, int *ino) struct ext2_dirent dirent; /* Read the directory entry. */ - pupa_ext2_read_file (data, fpos, sizeof (struct ext2_dirent), + pupa_ext2_read_file (data, 0, fpos, sizeof (struct ext2_dirent), (char *) &dirent); if (pupa_errno) goto fail; @@ -428,7 +439,7 @@ pupa_ext2_find_file (struct pupa_ext2_data *data, const char *path, int *ino) char filename[dirent.namelen + 1]; /* Read the filename part of this directory entry. */ - pupa_ext2_read_file (data, fpos + pupa_ext2_read_file (data, 0, fpos + sizeof (struct ext2_dirent), dirent.namelen, filename); if (pupa_errno) @@ -468,7 +479,7 @@ pupa_ext2_find_file (struct pupa_ext2_data *data, const char *path, int *ino) pupa_le_to_cpu32 (inode->size)); else { - pupa_ext2_read_file (data, 0, + pupa_ext2_read_file (data, 0, 0, pupa_le_to_cpu32 (inode->size), symlink); if (pupa_errno) @@ -604,7 +615,7 @@ pupa_ext2_close (pupa_file_t file) pupa_dl_unref (my_mod); #endif - return pupa_errno; + return PUPA_ERR_NONE; } /* Read LEN bytes data from FILE into BUF. */ @@ -614,7 +625,7 @@ pupa_ext2_read (pupa_file_t file, char *buf, pupa_ssize_t len) struct pupa_ext2_data *data = (struct pupa_ext2_data *) file->data; - return pupa_ext2_read_file (data, file->offset, len, buf); + return pupa_ext2_read_file (data, file->read_hook, file->offset, len, buf); } @@ -654,7 +665,7 @@ pupa_ext2_dir (pupa_device_t device, const char *path, { struct ext2_dirent dirent; - pupa_ext2_read_file (data, fpos, sizeof (struct ext2_dirent), + pupa_ext2_read_file (data, 0, fpos, sizeof (struct ext2_dirent), (char *) &dirent); if (pupa_errno) goto fail; @@ -663,7 +674,7 @@ pupa_ext2_dir (pupa_device_t device, const char *path, { char filename[dirent.namelen + 1]; - pupa_ext2_read_file (data, fpos + sizeof (struct ext2_dirent), + pupa_ext2_read_file (data, 0, fpos + sizeof (struct ext2_dirent), dirent.namelen, filename); if (pupa_errno) goto fail; diff --git a/include/grub/i386/pc/linux.h b/include/grub/i386/pc/linux.h index 942b09df5..3914e0084 100644 --- a/include/grub/i386/pc/linux.h +++ b/include/grub/i386/pc/linux.h @@ -1,6 +1,6 @@ /* * PUPA -- Preliminary Universal Programming Architecture for GRUB - * Copyright (C) 1999,2000,2001,2002 Free Software Foundation, Inc. + * Copyright (C) 1999,2000,2001,2002,2004 Free Software Foundation, Inc. * Copyright (C) 2003 Yoshinori K. Okuji * * This program is free software; you can redistribute it and/or modify @@ -24,7 +24,7 @@ #define PUPA_LINUX_MAGIC_SIGNATURE 0x53726448 /* "HdrS" */ #define PUPA_LINUX_DEFAULT_SETUP_SECTS 4 #define PUPA_LINUX_FLAG_CAN_USE_HEAP 0x80 -#define PUPA_LINUX_INITRD_MAX_ADDRESS 0x38000000 +#define PUPA_LINUX_INITRD_MAX_ADDRESS 0x37FFFFFF #define PUPA_LINUX_MAX_SETUP_SECTS 64 #define PUPA_LINUX_BOOT_LOADER_TYPE 0x72 #define PUPA_LINUX_HEAP_END_OFFSET (0x9000 - 0x200) @@ -67,7 +67,8 @@ struct linux_kernel_header pupa_uint32_t header; /* Magic signature "HdrS" */ pupa_uint16_t version; /* Boot protocol version supported */ pupa_uint32_t realmode_swtch; /* Boot loader hook */ - pupa_uint32_t start_sys; /* Points to kernel version string */ + pupa_uint16_t start_sys; /* The load-low segment (obsolete) */ + pupa_uint16_t kernel_version; /* Points to kernel version string */ pupa_uint8_t type_of_loader; /* Boot loader identifier */ pupa_uint8_t loadflags; /* Boot protocol option flags */ pupa_uint16_t setup_move_size; /* Move to high memory size */ @@ -78,6 +79,7 @@ struct linux_kernel_header pupa_uint16_t heap_end_ptr; /* Free memory after setup end */ pupa_uint16_t pad1; /* Unused */ char *cmd_line_ptr; /* Points to the kernel command line */ + pupa_uint32_t initrd_addr_max; /* Highest address for initrd */ } __attribute__ ((packed)); #endif /* ! ASM_FILE */ diff --git a/loader/i386/pc/linux.c b/loader/i386/pc/linux.c index b8fb77334..6cd022723 100644 --- a/loader/i386/pc/linux.c +++ b/loader/i386/pc/linux.c @@ -1,7 +1,7 @@ /* linux.c - boot Linux zImage or bzImage */ /* * PUPA -- Preliminary Universal Programming Architecture for GRUB - * Copyright (C) 1999,2000,2001,2002 Free Software Foundation, Inc. + * Copyright (C) 1999,2000,2001,2002,2004 Free Software Foundation, Inc. * Copyright (C) 2003 Yoshinori K. Okuji * * This program is free software; you can redistribute it and/or modify @@ -66,6 +66,7 @@ pupa_rescue_cmd_linux (int argc, char *argv[]) struct linux_kernel_header lh; pupa_uint8_t setup_sects; pupa_size_t real_size, prot_size; + pupa_ssize_t len; int i; char *dest; @@ -233,8 +234,13 @@ pupa_rescue_cmd_linux (int argc, char *argv[]) /* Put the real mode code at the temporary address. */ pupa_memmove (pupa_linux_tmp_addr, &lh, sizeof (lh)); - pupa_file_read (file, pupa_linux_tmp_addr + sizeof (lh), - real_size + PUPA_DISK_SECTOR_SIZE - sizeof (lh)); + + len = real_size + PUPA_DISK_SECTOR_SIZE - sizeof (lh); + if (pupa_file_read (file, pupa_linux_tmp_addr + sizeof (lh), len) != len) + { + pupa_error (PUPA_ERR_FILE_READ_ERROR, "Couldn't read file"); + goto fail; + } if (lh.header != pupa_cpu_to_le32 (PUPA_LINUX_MAGIC_SIGNATURE) || pupa_le_to_cpu16 (lh.version) < 0x0200) @@ -261,8 +267,10 @@ pupa_rescue_cmd_linux (int argc, char *argv[]) *dest = '\0'; - pupa_file_read (file, (char *) PUPA_LINUX_BZIMAGE_ADDR, prot_size); - + len = prot_size; + if (pupa_file_read (file, (char *) PUPA_LINUX_BZIMAGE_ADDR, len) != len) + pupa_error (PUPA_ERR_FILE_READ_ERROR, "Couldn't read file"); + if (pupa_errno == PUPA_ERR_NONE) { pupa_linux_prot_size = prot_size; @@ -285,9 +293,82 @@ pupa_rescue_cmd_linux (int argc, char *argv[]) void pupa_rescue_cmd_initrd (int argc, char *argv[]) { - pupa_error (PUPA_ERR_NOT_IMPLEMENTED_YET, "not implemented yet"); + pupa_file_t file = 0; + pupa_ssize_t size; + pupa_addr_t addr_max, addr_min, addr; + struct linux_kernel_header *lh; + + if (argc == 0) + { + pupa_error (PUPA_ERR_BAD_ARGUMENT, "No module specified"); + goto fail; + } + + if (!loaded) + { + pupa_error (PUPA_ERR_BAD_ARGUMENT, "You need to load the kernel first."); + goto fail; + } + + lh = (struct linux_kernel_header *) pupa_linux_tmp_addr; + + if (!(lh->header == pupa_cpu_to_le32 (PUPA_LINUX_MAGIC_SIGNATURE) + && pupa_le_to_cpu16 (lh->version) >= 0x0200)) + { + pupa_error (PUPA_ERR_BAD_OS, "The kernel is too old for initrd."); + goto fail; + } + + /* Get the highest address available for the initrd. */ + if (pupa_le_to_cpu16 (lh->version) >= 0x0203) + addr_max = pupa_cpu_to_le32 (lh->initrd_addr_max); + else + addr_max = PUPA_LINUX_INITRD_MAX_ADDRESS; + + if (!linux_mem_size && linux_mem_size < addr_max) + addr_max = linux_mem_size; + + /* Linux 2.3.xx has a bug in the memory range check, so avoid + the last page. + Linux 2.2.xx has a bug in the memory range check, which is + worse than that of Linux 2.3.xx, so avoid the last 64kb. */ + addr_max -= 0x10000; + + if (addr_max > pupa_os_area_addr + pupa_os_area_size) + addr_max = pupa_os_area_addr + pupa_os_area_size; + + addr_min = (pupa_addr_t) pupa_linux_tmp_addr + PUPA_LINUX_CL_END_OFFSET; + + file = pupa_file_open (argv[0]); + if (!file) + goto fail; + + size = pupa_file_size (file); + + /* Put the initrd as high as possible, 4Ki aligned. */ + addr = (addr_max - size) & ~0xFFF; + + if (addr < addr_min) + { + pupa_error (PUPA_ERR_OUT_OF_RANGE, "The initrd is too big"); + goto fail; + } + + if (pupa_file_read (file, (void *)addr, size) != size) + { + pupa_error (PUPA_ERR_FILE_READ_ERROR, "Couldn't read file"); + goto fail; + } + + lh->ramdisk_image = addr; + lh->ramdisk_size = size; + + fail: + if (file) + pupa_file_close (file); } + PUPA_MOD_INIT { pupa_rescue_register_command ("linux",