Hi, This patch is based on robert's memdisk patch. I also modify lnxboot so that it can load the memdisk using initrd. Changes:
1, copy memdisk to grub_alloc'ed memory in grub_machine_init, so that it won't be corrupted. 2, code cleanup for lnxboot.S, now it doesn't contain code that uses 32-bit address. 3, lnxboot.S will set the memdisk address to the initrd image 4, add option -x for grub-mkimage, it's used to build linux format kernel directly. ./grub-mkimage -x -o grub2.bin modules Now you can load memdisk using initrd: kernel grub2.bin initrd memdisk or embed it in grub2.bin/core.img using -m option ./grub-mkimage -x -o grub2.bin -m memdisk modules If both memdisk is used, external memdisk will take preference. diff --git a/boot/i386/pc/lnxboot.S b/boot/i386/pc/lnxboot.S index f1a4ded..6503e26 100644 --- a/boot/i386/pc/lnxboot.S +++ b/boot/i386/pc/lnxboot.S @@ -36,22 +36,7 @@ .globl start, _start data_start: - pushw %cs - popw %ds - xorl %eax, %eax - xorl %ebx, %ebx - call data_next - -data_next: - popw %bx - movw %cs, %ax - shll $4, %eax - leal 0x200 + data_start - data_next(%ebx,%eax), %eax - movzbl setup_sects - data_next(%bx), %ecx - shll $9, %ecx - addl %ecx, %eax - movl %eax, code32_start - data_next(%bx) - + xorl %ebp, %ebp jmp linux_next . = data_start + 0x1F1 @@ -76,7 +61,7 @@ boot_flag: start: _start: - jmp linux_code + jmp linux_init .ascii "HdrS" // Header signature .word 0x0203 // Header version number @@ -134,9 +119,10 @@ reg_edx: data_leng: .long 0 -linux_code: +linux_init: movw %cs:(reg_edx - start), %dx + movl %cs:(code32_start - start), %ebp linux_next: @@ -164,9 +150,6 @@ real_code: movw %si, %ss movw $(CODE_ADDR), %sp - pushl %esi - pushl %edi - // Move itself to 0:CODE_ADDR cld @@ -183,17 +166,26 @@ real_code: real_code_2: + xchgl %ebp, %esi + orl %esi, %esi + jnz 1f + movw %ds, %si + shll $4, %esi + addl %ebp, %esi +1: + pushw %es popw %ds - movl (ramdisk_image - start), %esi - or %esi, %esi + movl (data_leng - start), %ecx + or %ecx, %ecx jnz 1f - movl (code32_start - start), %esi + movl (ramdisk_image - start), %esi + movl (ramdisk_size - start), %ecx + addl $0x200, %esi + subl $0x200, %ecx 1: - movl $0x200, %ecx - addl %ecx, %esi movl $DATA_ADDR, %edi call move_memory @@ -204,13 +196,17 @@ real_code_2: movsbl (reg_edx + 2 - start), %eax movl %eax, %ss:(DATA_ADDR + GRUB_KERNEL_MACHINE_INSTALL_BSD_PART) - movl %ss:(DATA_ADDR + GRUB_KERNEL_MACHINE_COMPRESSED_SIZE), %ecx - addl $(GRUB_KERNEL_MACHINE_RAW_SIZE - 0x200), %ecx + movl (data_leng - start), %eax + or %eax, %eax + jz 1f + movl (ramdisk_size - start), %eax + or %eax, %eax + jz 1f - call move_memory - - popl %edi - popl %esi + movl %eax, %ss:(DATA_ADDR + GRUB_KERNEL_MACHINE_MEMDISK_IMAGE_SIZE) + movl (ramdisk_image - start), %eax + movl %eax, %ss:(DATA_ADDR + GRUB_KERNEL_MACHINE_MEMDISK_IMAGE_ADDR) +1: ljmp $(DATA_ADDR >> 4), $0 @@ -261,8 +257,8 @@ move_memory: 2: - leal (%esi, %eax), %esi - leal (%edi, %eax), %edi + addl %eax, %esi + addl %eax, %edi subl %eax, %ecx jnz 1b diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index 2638ee5..b5f6a04 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -39,7 +39,7 @@ kernel_img_HEADERS = arg.h boot.h cache.h device.h disk.h dl.h elf.h elfload.h \ env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \ partition.h pc_partition.h rescue.h symbol.h term.h time.h types.h \ machine/biosdisk.h machine/boot.h machine/console.h machine/init.h \ - machine/memory.h machine/loader.h machine/vga.h machine/vbe.h + machine/memory.h machine/loader.h machine/vga.h machine/vbe.h machine/kernel.h kernel_img_CFLAGS = $(COMMON_CFLAGS) kernel_img_ASFLAGS = $(COMMON_ASFLAGS) kernel_img_LDFLAGS = $(COMMON_LDFLAGS) -Wl,-N,-Ttext,8200 $(COMMON_CFLAGS) @@ -136,7 +136,7 @@ pkglib_MODULES = biosdisk.mod _chain.mod _linux.mod linux.mod normal.mod \ _multiboot.mod chain.mod multiboot.mod reboot.mod halt.mod \ vbe.mod vbetest.mod vbeinfo.mod video.mod gfxterm.mod \ videotest.mod play.mod bitmap.mod tga.mod cpuid.mod serial.mod ata.mod \ - vga.mod + vga.mod memdisk.mod # For biosdisk.mod. biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c @@ -263,4 +263,9 @@ vga_mod_SOURCES = term/i386/pc/vga.c vga_mod_CFLAGS = $(COMMON_CFLAGS) vga_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For memdisk.mod. +memdisk_mod_SOURCES = disk/memdisk.c +memdisk_mod_CFLAGS = $(COMMON_CFLAGS) +memdisk_mod_LDFLAGS = $(COMMON_LDFLAGS) + include $(srcdir)/conf/common.mk diff --git a/include/grub/disk.h b/include/grub/disk.h index 4301942..9891a9c 100644 --- a/include/grub/disk.h +++ b/include/grub/disk.h @@ -35,7 +35,8 @@ enum grub_disk_dev_id GRUB_DISK_DEVICE_RAID_ID, GRUB_DISK_DEVICE_LVM_ID, GRUB_DISK_DEVICE_HOST_ID, - GRUB_DISK_DEVICE_ATA_ID + GRUB_DISK_DEVICE_ATA_ID, + GRUB_DISK_DEVICE_MEMDISK_ID, }; struct grub_disk; diff --git a/include/grub/i386/pc/kernel.h b/include/grub/i386/pc/kernel.h index ec207a5..126df2b 100644 --- a/include/grub/i386/pc/kernel.h +++ b/include/grub/i386/pc/kernel.h @@ -34,8 +34,14 @@ /* The offset of GRUB_INSTALL_BSD_PART. */ #define GRUB_KERNEL_MACHINE_INSTALL_BSD_PART 0x18 +/* The offset of GRUB_MEMDISK_IMAGE_ADDR */ +#define GRUB_KERNEL_MACHINE_MEMDISK_IMAGE_ADDR 0x1c + +/* The offset of GRUB_MEMDISK_IMAGE_SIZE. */ +#define GRUB_KERNEL_MACHINE_MEMDISK_IMAGE_SIZE 0x20 + /* The offset of GRUB_PREFIX. */ -#define GRUB_KERNEL_MACHINE_PREFIX 0x1c +#define GRUB_KERNEL_MACHINE_PREFIX 0x24 /* End of the data section. */ #define GRUB_KERNEL_MACHINE_DATA_END 0x50 @@ -47,12 +53,24 @@ #include <grub/types.h> +/* The size of kernel image. */ +extern grub_int32_t grub_kernel_image_size; + +/* The total size of module images following the kernel. */ +extern grub_int32_t grub_total_module_size; + /* The DOS partition number of the installed partition. */ extern grub_int32_t grub_install_dos_part; /* The BSD partition number of the installed partition. */ extern grub_int32_t grub_install_bsd_part; +/* The address of memory disk image, if present. */ +extern grub_int32_t grub_memdisk_image_addr; + +/* The size of memory disk image, if present. */ +extern grub_int32_t grub_memdisk_image_size; + /* The prefix which points to the directory where GRUB modules and its configuration file are located. */ extern char grub_prefix[]; diff --git a/include/grub/kernel.h b/include/grub/kernel.h index 77d209a..7413e19 100644 --- a/include/grub/kernel.h +++ b/include/grub/kernel.h @@ -20,6 +20,7 @@ #define GRUB_KERNEL_HEADER 1 #include <grub/types.h> +#include <grub/symbol.h> /* The module header. */ struct grub_module_header @@ -44,6 +45,8 @@ struct grub_module_info }; extern grub_addr_t grub_arch_modules_addr (void); +extern grub_addr_t EXPORT_FUNC(grub_arch_memdisk_addr) (void); +extern grub_off_t EXPORT_FUNC(grub_arch_memdisk_size) (void); /* The start point of the C code. */ void grub_main (void); diff --git a/kern/i386/pc/init.c b/kern/i386/pc/init.c index 72ff9a2..2bdbc49 100644 --- a/kern/i386/pc/init.c +++ b/kern/i386/pc/init.c @@ -229,9 +229,26 @@ grub_machine_init (void) } else grub_mm_init_region ((void *) mem_regions[i].addr, mem_regions[i].size); - + if (! grub_os_area_addr) grub_fatal ("no upper memory"); + + if (grub_memdisk_image_size) + { + char *p; + + if (! grub_memdisk_image_addr) + grub_memdisk_image_addr = 0x100000 + (grub_kernel_image_size - GRUB_KERNEL_MACHINE_RAW_SIZE) + grub_total_module_size; + + p = grub_malloc (grub_memdisk_image_size); + if (! p) + grub_memdisk_image_size = 0; // Not enough memory, dump the memdisk + else + { + grub_memcpy (p, (char*) grub_memdisk_image_addr, grub_memdisk_image_size); + grub_memdisk_image_addr = (grub_uint32_t) p; + } + } } void @@ -253,3 +270,17 @@ grub_arch_modules_addr (void) { return grub_end_addr; } + +/* Return the start of the memdisk image. */ +grub_addr_t +grub_arch_memdisk_addr (void) +{ + return grub_memdisk_image_addr; +} + +/* Return the size of the memdisk image. */ +grub_off_t +grub_arch_memdisk_size (void) +{ + return grub_memdisk_image_size; +} diff --git a/kern/i386/pc/startup.S b/kern/i386/pc/startup.S index 4267f5b..33b301c 100644 --- a/kern/i386/pc/startup.S +++ b/kern/i386/pc/startup.S @@ -95,6 +95,10 @@ VARIABLE(grub_install_dos_part) .long 0xFFFFFFFF VARIABLE(grub_install_bsd_part) .long 0xFFFFFFFF +VARIABLE(grub_memdisk_image_addr) + .long 0 +VARIABLE(grub_memdisk_image_size) + .long 0 VARIABLE(grub_prefix) /* to be filled by grub-mkimage */ diff --git a/util/i386/pc/grub-mkimage.c b/util/i386/pc/grub-mkimage.c index e19649d..dd48509 100644 --- a/util/i386/pc/grub-mkimage.c +++ b/util/i386/pc/grub-mkimage.c @@ -25,6 +25,7 @@ #include <grub/disk.h> #include <grub/util/misc.h> #include <grub/util/resolve.h> +#include <grub/misc.h> #include <stdio.h> #include <unistd.h> @@ -75,11 +76,11 @@ compress_kernel (char *kernel_img, size_t kernel_size, } static void -generate_image (const char *dir, char *prefix, FILE *out, char *mods[]) +generate_image (const char *dir, char *prefix, FILE *out, char *mods[], char *memdisk_path, int is_linux) { grub_addr_t module_addr = 0; char *kernel_img, *boot_img, *core_img; - size_t kernel_size, boot_size, total_module_size, core_size; + size_t kernel_size, boot_size, total_module_size, core_size, memdisk_size = 0; char *kernel_path, *boot_path; unsigned num; size_t offset; @@ -98,7 +99,13 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[]) grub_util_info ("the total module size is 0x%x", total_module_size); - kernel_img = xmalloc (kernel_size + total_module_size); + if (memdisk_path) + { + memdisk_size = ALIGN_UP(grub_util_get_image_size (memdisk_path), 512); + grub_util_info ("the size of memory disk is 0x%x", memdisk_size); + } + + kernel_img = xmalloc (kernel_size + total_module_size + memdisk_size); grub_util_load_image (kernel_path, kernel_img); if (GRUB_KERNEL_MACHINE_PREFIX + strlen (prefix) + 1 > GRUB_KERNEL_MACHINE_DATA_END) @@ -122,13 +129,19 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[]) header = (struct grub_module_header *) (kernel_img + offset); header->offset = grub_cpu_to_le32 (sizeof (*header)); header->size = grub_cpu_to_le32 (mod_size + sizeof (*header)); - - grub_util_load_image (p->name, kernel_img + offset + sizeof (*header)); + offset += sizeof (*header); + + grub_util_load_image (p->name, kernel_img + offset); + offset += mod_size; + } - offset += sizeof (*header) + mod_size; + if (memdisk_path) + { + grub_util_load_image (memdisk_path, kernel_img + offset); + offset += memdisk_size; } - compress_kernel (kernel_img, kernel_size + total_module_size, + compress_kernel (kernel_img, kernel_size + total_module_size + memdisk_size, &core_img, &core_size); grub_util_info ("the core size is 0x%x", core_size); @@ -137,17 +150,25 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[]) if (num > 0xffff) grub_util_error ("the core image is too big"); - boot_path = grub_util_get_path (dir, "diskboot.img"); + boot_path = grub_util_get_path (dir, (is_linux)? "lnxboot.img":"diskboot.img"); boot_size = grub_util_get_image_size (boot_path); - if (boot_size != GRUB_DISK_SECTOR_SIZE) + if ((! is_linux) && (boot_size != GRUB_DISK_SECTOR_SIZE)) grub_util_error ("diskboot.img is not one sector size"); boot_img = grub_util_read_image (boot_path); - - /* i386 is a little endian architecture. */ - *((grub_uint16_t *) (boot_img + GRUB_DISK_SECTOR_SIZE + + if (is_linux) + { + *((grub_uint32_t *) (boot_img + 0x264)) + = grub_cpu_to_le32 (core_size); + } + else + { + /* i386 is a little endian architecture. */ + *((grub_uint16_t *) (boot_img + GRUB_DISK_SECTOR_SIZE - GRUB_BOOT_MACHINE_LIST_SIZE + 8)) - = grub_cpu_to_le16 (num); + = grub_cpu_to_le16 (num); + } grub_util_write_image (boot_img, boot_size, out); free (boot_img); @@ -163,6 +184,8 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[]) = grub_cpu_to_le32 (total_module_size); *((grub_uint32_t *) (core_img + GRUB_KERNEL_MACHINE_KERNEL_IMAGE_SIZE)) = grub_cpu_to_le32 (kernel_size); + *((grub_uint32_t *) (core_img + GRUB_KERNEL_MACHINE_MEMDISK_IMAGE_SIZE)) + = grub_cpu_to_le32 (memdisk_size); *((grub_uint32_t *) (core_img + GRUB_KERNEL_MACHINE_COMPRESSED_SIZE)) = grub_cpu_to_le32 (core_size - GRUB_KERNEL_MACHINE_RAW_SIZE); @@ -186,7 +209,9 @@ static struct option options[] = { {"directory", required_argument, 0, 'd'}, {"prefix", required_argument, 0, 'p'}, + {"memdisk", required_argument, 0, 'm'}, {"output", required_argument, 0, 'o'}, + {"linux", no_argument, 0, 'x'}, {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, {"verbose", no_argument, 0, 'v'}, @@ -206,7 +231,9 @@ Make a bootable image of GRUB.\n\ \n\ -d, --directory=DIR use images and modules under DIR [default=%s]\n\ -p, --prefix=DIR set grub_prefix directory [default=%s]\n\ + -m, --memdisk=FILE embed FILE as a memdisk image\n\ -o, --output=FILE output a generated image to FILE [default=stdout]\n\ + -x, --linux add linux header\n\ -h, --help display this message and exit\n\ -V, --version print version information and exit\n\ -v, --verbose print verbose messages\n\ @@ -223,13 +250,15 @@ main (int argc, char *argv[]) char *output = NULL; char *dir = NULL; char *prefix = NULL; + char *memdisk = NULL; FILE *fp = stdout; + int is_linux = 0; progname = "grub-mkimage"; while (1) { - int c = getopt_long (argc, argv, "d:p:o:hVv", options, 0); + int c = getopt_long (argc, argv, "d:p:m:o:hVvx", options, 0); if (c == -1) break; @@ -250,6 +279,17 @@ main (int argc, char *argv[]) dir = xstrdup (optarg); break; + case 'm': + if (memdisk) + free (memdisk); + + memdisk = xstrdup (optarg); + break; + + case 'x': + is_linux = 1; + break; + case 'h': usage (0); break; @@ -282,7 +322,7 @@ main (int argc, char *argv[]) grub_util_error ("cannot open %s", output); } - generate_image (dir ? : GRUB_LIBDIR, prefix ? : DEFAULT_DIRECTORY, fp, argv + optind); + generate_image (dir ? : GRUB_LIBDIR, prefix ? : DEFAULT_DIRECTORY, fp, argv + optind, memdisk, is_linux); fclose (fp); diff --git a/disk/memdisk.c b/disk/memdisk.c new file mode 100755 index 0000000..48e0514 --- /dev/null +++ b/disk/memdisk.c @@ -0,0 +1,94 @@ +/* memdisk.c - Access embedded memory disk. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2007 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <grub/disk.h> +#include <grub/dl.h> +#include <grub/kernel.h> +#include <grub/misc.h> +#include <grub/mm.h> +#include <grub/types.h> + +static grub_addr_t memdisk_addr; + +static int +grub_memdisk_iterate (int (*hook) (const char *name)) +{ + return hook ("memdisk"); +} + +static grub_err_t +grub_memdisk_open (const char *name, grub_disk_t disk) +{ + if (grub_strcmp (name, "memdisk")) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a memdisk"); + + disk->total_sectors = grub_arch_memdisk_size () / GRUB_DISK_SECTOR_SIZE; + disk->id = (int) 'mdsk'; + disk->has_partitions = 0; + + return GRUB_ERR_NONE; +} + +static void +grub_memdisk_close (grub_disk_t disk __attribute((unused))) +{ +} + +static grub_err_t +grub_memdisk_read (grub_disk_t disk __attribute((unused)), grub_disk_addr_t sector, + grub_size_t size, char *buf) +{ + grub_memcpy (buf, memdisk_addr + (sector << GRUB_DISK_SECTOR_BITS), size << GRUB_DISK_SECTOR_BITS); + return 0; +} + +static grub_err_t +grub_memdisk_write (grub_disk_t disk __attribute((unused)), grub_disk_addr_t sector, + grub_size_t size, const char *buf) +{ + grub_memcpy (memdisk_addr + (sector << GRUB_DISK_SECTOR_BITS), buf, size << GRUB_DISK_SECTOR_BITS); + return 0; +} + +static struct grub_disk_dev grub_memdisk_dev = + { + .name = "memdisk", + .id = GRUB_DISK_DEVICE_MEMDISK_ID, + .iterate = grub_memdisk_iterate, + .open = grub_memdisk_open, + .close = grub_memdisk_close, + .read = grub_memdisk_read, + .write = grub_memdisk_write, + .next = 0 + }; + +GRUB_MOD_INIT(memdisk) +{ + if (! grub_arch_memdisk_size ()) + return; + memdisk_addr = grub_arch_memdisk_addr (); + grub_disk_dev_register (&grub_memdisk_dev); +} + +GRUB_MOD_FINI(memdisk) +{ + if (! grub_arch_memdisk_size ()) + return; + grub_disk_dev_unregister (&grub_memdisk_dev); +} -- Bean _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org http://lists.gnu.org/mailman/listinfo/grub-devel