From ea4097134fbd834d2f688363f9a8208bf6a49ecd Mon Sep 17 00:00:00 2001 From: okuji Date: Sun, 31 Jul 2005 16:12:29 +0000 Subject: [PATCH] 2005-07-31 Yoshinori K. Okuji * loader/i386/pc/multiboot.c (grub_multiboot_is_elf32): New function. (grub_multiboot_load_elf32): Likewise. (grub_multiboot_is_elf64): Likewise. (grub_multiboot_load_elf64): Likewise. (grub_multiboot_load_elf): Likewise. (grub_rescue_cmd_multiboot): Call grub_multiboot_load_elf to load an ELF32 or ELF64 file. This is based on a patch from Ruslan Nikolaev . From Serbinenko Vladimir : * kern/disk.c (grub_print_partinfo): Check if FS->LABEL is not NULL before calling FS->LABEL. * fs/fat.c (grub_fat_dir): Initialize DIRNAME to NULL. * commands/ls.c (grub_ls_list_files): Show labels, if possible. (grub_ls_list_disks): Check if FS and FS->LABEL are not NULL before calling FS->LABEL. --- ChangeLog | 20 +++ THANKS | 2 + commands/ls.c | 40 ++++-- fs/fat.c | 2 +- kern/disk.c | 2 +- loader/i386/pc/multiboot.c | 241 ++++++++++++++++++++++++++----------- 6 files changed, 222 insertions(+), 85 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9e89ce3db..cef584158 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +2005-07-31 Yoshinori K. Okuji + + * loader/i386/pc/multiboot.c (grub_multiboot_is_elf32): New + function. + (grub_multiboot_load_elf32): Likewise. + (grub_multiboot_is_elf64): Likewise. + (grub_multiboot_load_elf64): Likewise. + (grub_multiboot_load_elf): Likewise. + (grub_rescue_cmd_multiboot): Call grub_multiboot_load_elf to load + an ELF32 or ELF64 file. + This is based on a patch from Ruslan Nikolaev . + + From Serbinenko Vladimir : + * kern/disk.c (grub_print_partinfo): Check if FS->LABEL is not + NULL before calling FS->LABEL. + * fs/fat.c (grub_fat_dir): Initialize DIRNAME to NULL. + * commands/ls.c (grub_ls_list_files): Show labels, if possible. + (grub_ls_list_disks): Check if FS and FS->LABEL are not NULL + before calling FS->LABEL. + 2005-07-26 Yoshinori K. Okuji * util/i386/pc/grub-install.in (datadir): New variable. diff --git a/THANKS b/THANKS index 4209aa64b..bc49b47f4 100644 --- a/THANKS +++ b/THANKS @@ -13,6 +13,8 @@ Hollis Blanchard Marco Gerards NIIBE Yutaka Robert Bihlmeyer +Ruslan Nikolaev +Serbinenko Vladimir Timothy Baldwin Tomas Ebenlendr Tsuneyoshi Yasuo diff --git a/commands/ls.c b/commands/ls.c index b28ff035a..dc762bc4c 100644 --- a/commands/ls.c +++ b/commands/ls.c @@ -83,17 +83,20 @@ grub_ls_list_disks (int longlist) grub_errno = GRUB_ERR_NONE; grub_printf (", Filesystem type %s", - fs ? fs->name : "Unknown"); - - (fs->label) (dev, &label); - if (grub_errno == GRUB_ERR_NONE) + fs ? fs->name : "unknown"); + + if (fs && fs->label) { - if (label && grub_strlen (label)) - grub_printf (", Label: %s", label); - grub_free (label); + (fs->label) (dev, &label); + if (grub_errno == GRUB_ERR_NONE) + { + if (label && grub_strlen (label)) + grub_printf (", Label: %s", label); + grub_free (label); + } + else + grub_errno = GRUB_ERR_NONE; } - else - grub_errno = GRUB_ERR_NONE; } grub_putchar ('\n'); @@ -221,8 +224,25 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human) if (grub_errno == GRUB_ERR_UNKNOWN_FS) grub_errno = GRUB_ERR_NONE; - grub_printf ("(%s): Filesystem is %s.\n", + grub_printf ("(%s): Filesystem is %s", device_name, fs ? fs->name : "unknown"); + + if (fs && fs->label) + { + char *label; + + (fs->label) (dev, &label); + if (grub_errno == GRUB_ERR_NONE) + { + if (label && grub_strlen (label)) + grub_printf (", Label: %s", label); + grub_free (label); + } + else + grub_errno = GRUB_ERR_NONE; + } + + grub_putchar ('\n'); } else if (fs) { diff --git a/fs/fat.c b/fs/fat.c index 1388ff953..c3d04c30e 100644 --- a/fs/fat.c +++ b/fs/fat.c @@ -629,7 +629,7 @@ grub_fat_dir (grub_device_t device, const char *path, struct grub_fat_data *data = 0; grub_disk_t disk = device->disk; grub_size_t len; - char *dirname; + char *dirname = 0; char *p; #ifndef GRUB_UTIL diff --git a/kern/disk.c b/kern/disk.c index 0def7e03a..c459579cc 100644 --- a/kern/disk.c +++ b/kern/disk.c @@ -535,7 +535,7 @@ grub_print_partinfo (grub_device_t disk, char *partname) grub_printf ("\tPartition num:%s, Filesystem type %s", partname, fs ? fs->name : "Unknown"); - if (fs) + if (fs && fs->label) { (fs->label) (part, &label); if (grub_errno == GRUB_ERR_NONE) diff --git a/loader/i386/pc/multiboot.c b/loader/i386/pc/multiboot.c index 32b9abf91..ebe9aeb43 100644 --- a/loader/i386/pc/multiboot.c +++ b/loader/i386/pc/multiboot.c @@ -81,6 +81,158 @@ grub_multiboot_unload (void) return GRUB_ERR_NONE; } +/* Check if BUFFER contains ELF32. */ +static int +grub_multiboot_is_elf32 (void *buffer) +{ + Elf32_Ehdr *ehdr = (Elf32_Ehdr *) buffer; + + return ehdr->e_ident[EI_CLASS] == ELFCLASS32; +} + +static grub_err_t +grub_multiboot_load_elf32 (grub_file_t file, void *buffer) +{ + Elf32_Ehdr *ehdr = (Elf32_Ehdr *) buffer; + Elf32_Phdr *phdr; + int i; + + if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) + return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF class"); + + if (grub_dl_check_header (ehdr, sizeof(Elf32_Ehdr))) + return grub_error (GRUB_ERR_UNKNOWN_OS, "no valid ELF header found"); + + if (ehdr->e_type != ET_EXEC) + return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF file type"); + + /* FIXME: Should we support program headers at strange locations? */ + if (ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize > GRUB_MB_SEARCH) + return grub_error (GRUB_ERR_BAD_OS, "program header at a too high offset"); + + entry = ehdr->e_entry; + + /* Load every loadable segment in memory. */ + for (i = 0; i < ehdr->e_phnum; i++) + { + phdr = (Elf32_Phdr *) ((char *) buffer + ehdr->e_phoff + + i * ehdr->e_phentsize); + if (phdr->p_type == PT_LOAD) + { + /* The segment should fit in the area reserved for the OS. */ + if ((phdr->p_paddr < grub_os_area_addr) + || (phdr->p_paddr + phdr->p_memsz + > grub_os_area_addr + grub_os_area_size)) + return grub_error (GRUB_ERR_BAD_OS, + "segment doesn't fit in memory reserved for the OS"); + + if (grub_file_seek (file, phdr->p_offset) == -1) + return grub_error (GRUB_ERR_BAD_OS, + "invalid offset in program header"); + + if (grub_file_read (file, (void *) phdr->p_paddr, phdr->p_filesz) + != (grub_ssize_t) phdr->p_filesz) + return grub_error (GRUB_ERR_BAD_OS, + "couldn't read segment from file"); + + if (phdr->p_filesz < phdr->p_memsz) + grub_memset ((char *) phdr->p_paddr + phdr->p_filesz, 0, + phdr->p_memsz - phdr->p_filesz); + } + } + + return grub_errno; +} + +/* Check if BUFFER contains ELF64. */ +static int +grub_multiboot_is_elf64 (void *buffer) +{ + Elf64_Ehdr *ehdr = (Elf64_Ehdr *) buffer; + + return ehdr->e_ident[EI_CLASS] == ELFCLASS64; +} + +static grub_err_t +grub_multiboot_load_elf64 (grub_file_t file, void *buffer) +{ + Elf64_Ehdr *ehdr = (Elf64_Ehdr *) buffer; + Elf64_Phdr *phdr; + int i; + + if (ehdr->e_ident[EI_CLASS] != ELFCLASS64) + return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF class"); + + if (ehdr->e_ident[EI_MAG0] != ELFMAG0 + || ehdr->e_ident[EI_MAG1] != ELFMAG1 + || ehdr->e_ident[EI_MAG2] != ELFMAG2 + || ehdr->e_ident[EI_MAG3] != ELFMAG3 + || ehdr->e_version != EV_CURRENT + || ehdr->e_ident[EI_DATA] != ELFDATA2LSB + || ehdr->e_machine != EM_X86_64) + return grub_error(GRUB_ERR_UNKNOWN_OS, "no valid ELF header found"); + + if (ehdr->e_type != ET_EXEC) + return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF file type"); + + /* FIXME: Should we support program headers at strange locations? */ + if (ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize > GRUB_MB_SEARCH) + return grub_error (GRUB_ERR_BAD_OS, "program header at a too high offset"); + + /* We still in 32-bit mode */ + if (ehdr->e_entry > 0xffffffff) + return grub_error (GRUB_ERR_BAD_OS, "invalid entry point for ELF64"); + + entry = ehdr->e_entry; + + /* Load every loadable segment in memory. */ + for (i = 0; i < ehdr->e_phnum; i++) + { + phdr = (Elf64_Phdr *) ((char *) buffer + ehdr->e_phoff + + i * ehdr->e_phentsize); + if (phdr->p_type == PT_LOAD) + { + /* The segment should fit in the area reserved for the OS. */ + if ((phdr->p_paddr < (grub_uint64_t) grub_os_area_addr) + || (phdr->p_paddr + phdr->p_memsz + > ((grub_uint64_t) grub_os_area_addr + + (grub_uint64_t) grub_os_area_size))) + return grub_error (GRUB_ERR_BAD_OS, + "segment doesn't fit in memory reserved for the OS"); + + if (grub_file_seek (file, phdr->p_offset) == -1) + return grub_error (GRUB_ERR_BAD_OS, + "invalid offset in program header"); + + if (grub_file_read (file, (void *) ((grub_uint32_t) phdr->p_paddr), + phdr->p_filesz) + != (grub_ssize_t) phdr->p_filesz) + return grub_error (GRUB_ERR_BAD_OS, + "couldn't read segment from file"); + + if (phdr->p_filesz < phdr->p_memsz) + grub_memset (((char *) ((grub_uint32_t) phdr->p_paddr) + + phdr->p_filesz), + 0, + phdr->p_memsz - phdr->p_filesz); + } + } + + return grub_errno; +} + +/* Load ELF32 or ELF64. */ +static grub_err_t +grub_multiboot_load_elf (grub_file_t file, void *buffer) +{ + if (grub_multiboot_is_elf32 (buffer)) + return grub_multiboot_load_elf32 (file, buffer); + else if (grub_multiboot_is_elf64 (buffer)) + return grub_multiboot_load_elf64 (file, buffer); + + return grub_error (GRUB_ERR_UNKNOWN_OS, "unknown ELF class"); +} + void grub_rescue_cmd_multiboot (int argc, char *argv[]) { @@ -89,11 +241,10 @@ grub_rescue_cmd_multiboot (int argc, char *argv[]) struct grub_multiboot_header *header; grub_ssize_t len; int i; - Elf32_Ehdr *ehdr; grub_dl_ref (my_mod); - grub_loader_unset(); + grub_loader_unset (); if (argc == 0) { @@ -102,7 +253,7 @@ grub_rescue_cmd_multiboot (int argc, char *argv[]) } file = grub_file_open (argv[0]); - if (!file) + if (! file) { grub_error (GRUB_ERR_BAD_ARGUMENT, "Couldn't open file"); goto fail; @@ -119,11 +270,11 @@ grub_rescue_cmd_multiboot (int argc, char *argv[]) be at least 12 bytes and aligned on a 4-byte boundary. */ for (header = (struct grub_multiboot_header *) buffer; ((char *) header <= buffer + len - 12) || (header = 0); - header = (struct grub_multiboot_header *) ((char *)header + 4)) + header = (struct grub_multiboot_header *) ((char *) header + 4)) { if (header->magic == GRUB_MB_MAGIC && !(header->magic + header->flags + header->checksum)) - break; + break; } if (header == 0) @@ -134,72 +285,16 @@ grub_rescue_cmd_multiboot (int argc, char *argv[]) if (header->flags & GRUB_MB_UNSUPPORTED) { - grub_error (GRUB_ERR_UNKNOWN_OS, "Unsupported flag: 0x%x", header->flags); + grub_error (GRUB_ERR_UNKNOWN_OS, + "Unsupported flag: 0x%x", header->flags); goto fail; } - ehdr = (Elf32_Ehdr *) buffer; - - if (grub_dl_check_header (ehdr, sizeof(*ehdr))) - { - grub_error (GRUB_ERR_UNKNOWN_OS, "No valid ELF header found"); - goto fail; - } - - if (ehdr->e_type != ET_EXEC) - { - grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF file type"); - goto fail; - } - - /* FIXME: Should we support program headers at strange locations? */ - if (ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize > GRUB_MB_SEARCH) - { - grub_error (GRUB_ERR_UNKNOWN_OS, "Program header at a too high offset"); - goto fail; - } - - entry = ehdr->e_entry; - - /* Load every loadable segment in memory. */ - for (i = 0; i < ehdr->e_phnum; i++) - { - Elf32_Phdr *phdr; - phdr = (Elf32_Phdr *) (buffer + ehdr->e_phoff + i * ehdr->e_phentsize); - - if (phdr->p_type == PT_LOAD) - { - /* The segment should fit in the area reserved for the OS. */ - if ((phdr->p_paddr < grub_os_area_addr) - || (phdr->p_paddr + phdr->p_memsz - > grub_os_area_addr + grub_os_area_size)) - { - grub_error (GRUB_ERR_BAD_OS, - "Segment doesn't fit in memory reserved for the OS"); - goto fail; - } - - if (grub_file_seek (file, phdr->p_offset) == -1) - { - grub_error (GRUB_ERR_BAD_OS, "Invalid offset in program header"); - goto fail; - } - - if (grub_file_read (file, (void *) phdr->p_paddr, phdr->p_filesz) - != (grub_ssize_t) phdr->p_filesz) - { - grub_error (GRUB_ERR_BAD_OS, "Couldn't read segment from file"); - goto fail; - } - - if (phdr->p_filesz < phdr->p_memsz) - grub_memset ((char *) phdr->p_paddr + phdr->p_filesz, 0, - phdr->p_memsz - phdr->p_filesz); - } - } - + if (grub_multiboot_load_elf (file, buffer) != GRUB_ERR_NONE) + goto fail; + mbi = grub_malloc (sizeof (struct grub_multiboot_info)); - if (!mbi) + if (! mbi) goto fail; mbi->flags = GRUB_MB_INFO_MEMORY; @@ -212,7 +307,7 @@ grub_rescue_cmd_multiboot (int argc, char *argv[]) len += grub_strlen (argv[i]) + 1; cmdline = p = grub_malloc (len); - if (!cmdline) + if (! cmdline) goto fail; for (i = 0; i < argc; i++) @@ -267,12 +362,12 @@ grub_rescue_cmd_module (int argc, char *argv[]) } file = grub_file_open (argv[0]); - if (!file) + if (! file) goto fail; size = grub_file_size (file); module = grub_memalign (GRUB_MB_MOD_ALIGN, size); - if (!module) + if (! module) goto fail; if (grub_file_read (file, module, size) != size) @@ -285,7 +380,7 @@ grub_rescue_cmd_module (int argc, char *argv[]) len += grub_strlen (argv[i]) + 1; cmdline = p = grub_malloc (len); - if (!cmdline) + if (! cmdline) goto fail; for (i = 0; i < argc; i++) @@ -303,7 +398,7 @@ grub_rescue_cmd_module (int argc, char *argv[]) modlist = grub_realloc (modlist, (mbi->mods_count + 1) * sizeof (struct grub_mod_list)); - if (!modlist) + if (! modlist) goto fail; mbi->mods_addr = (grub_uint32_t) modlist; modlist += mbi->mods_count; @@ -316,7 +411,7 @@ grub_rescue_cmd_module (int argc, char *argv[]) else { struct grub_mod_list *modlist = grub_malloc (sizeof (struct grub_mod_list)); - if (!modlist) + if (! modlist) goto fail; modlist->mod_start = (grub_uint32_t) module; modlist->mod_end = (grub_uint32_t) module + size;