diff --git a/ChangeLog_GRUB4DOS.txt b/ChangeLog_GRUB4DOS.txt index 5612e590..2332326c 100644 --- a/ChangeLog_GRUB4DOS.txt +++ b/ChangeLog_GRUB4DOS.txt @@ -1,5 +1,5 @@ -2014-11-03 (tinybit) mask off non-booting floppy drives in order to gain more -stability. +2014-11-10 supported initrdfs. +2014-11-03 (tinybit) mask off non-booting floppy drives in order to gain more stability. 2014-11-02 (tinybit) fix offset nestification problem for virtual drives built on another in-situ virtual drive. 2014-10-25 disabled warning and errinfo message redirect. 2014-10-17 PXE Boot supported proxyDHCP and gateway. diff --git a/configure b/configure index 400ed807..14fe14ed 100755 --- a/configure +++ b/configure @@ -764,6 +764,7 @@ enable_jfs enable_xfs enable_iso9660 enable_pxe +enable_initrdfs enable_fb enable_gunzip enable_md5_password @@ -6476,6 +6477,16 @@ if test x"$enable_pxe" != xno; then FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_PXE=1" fi +# Check whether --enable-initrdfs was given. +if test "${enable_initrdfs+set}" = set; then : + enableval=$enable_initrdfs; +fi + + +if test x"$enable_initrdfs" != xno; then + FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_INITRD=1" +fi + # Check whether --enable-fb was given. if test "${enable_fb+set}" = set; then : enableval=$enable_fb; diff --git a/configure.ac b/configure.ac index 53154eac..56b95880 100644 --- a/configure.ac +++ b/configure.ac @@ -343,6 +343,13 @@ if test x"$enable_pxe" != xno; then FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_PXE=1" fi +AC_ARG_ENABLE(initrdfs, + [ --disable-initrdfs disable initrdfs support in Stage 2]) + +if test x"$enable_initrdfs" != xno; then + FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_INITRD=1" +fi + AC_ARG_ENABLE(fb, [ --disable-fb disable FB support in Stage 2]) diff --git a/stage2/Makefile.am b/stage2/Makefile.am index 8a1a88be..3de61fc4 100644 --- a/stage2/Makefile.am +++ b/stage2/Makefile.am @@ -7,7 +7,7 @@ noinst_SCRIPTS = $(TESTS) noinst_HEADERS = fat.h filesys.h freebsd.h hercules.h \ iso9660.h jfs.h mb_header.h mb_info.h md5.h \ pc_slice.h serial.h shared.h term.h \ - terminfo.h tparm.h ufs2.h vstafs.h xfs.h pxe.h graphics.h + terminfo.h tparm.h ufs2.h vstafs.h xfs.h pxe.h graphics.h fsys_initrd.h cpio.h EXTRA_DIST = $(noinst_SCRIPTS) # Stage 2 and Stage 1.5's. @@ -57,7 +57,7 @@ STAGE2_COMPILE = $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ pre_stage2_exec_SOURCES = asm.S bios.c boot.c builtins.c char_io.c \ cmdline.c common.c console.c dec_lzma.c disk_io.c fsys_ext2fs.c \ fsys_fat.c fsys_ntfs.c fsys_ffs.c fsys_iso9660.c fsys_jfs.c fsys_minix.c \ - fsys_reiserfs.c fsys_ufs2.c fsys_vstafs.c fsys_xfs.c fsys_pxe.c fsys_fb.c gunzip.c \ + fsys_reiserfs.c fsys_ufs2.c fsys_vstafs.c fsys_xfs.c fsys_pxe.c fsys_initrd.c fsys_fb.c gunzip.c \ hercules.c md5.c serial.c stage2.c terminfo.c tparm.c graphics.c pre_stage2_exec_CFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS) pre_stage2_exec_CCASFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS) diff --git a/stage2/Makefile.in b/stage2/Makefile.in index 156666df..341cdb6c 100644 --- a/stage2/Makefile.in +++ b/stage2/Makefile.in @@ -132,6 +132,7 @@ am_pre_stage2_exec_OBJECTS = pre_stage2_exec-asm.$(OBJEXT) \ pre_stage2_exec-fsys_vstafs.$(OBJEXT) \ pre_stage2_exec-fsys_xfs.$(OBJEXT) \ pre_stage2_exec-fsys_pxe.$(OBJEXT) \ + pre_stage2_exec-fsys_initrd.$(OBJEXT) \ pre_stage2_exec-fsys_fb.$(OBJEXT) \ pre_stage2_exec-gunzip.$(OBJEXT) \ pre_stage2_exec-hercules.$(OBJEXT) \ @@ -326,7 +327,7 @@ noinst_SCRIPTS = $(TESTS) noinst_HEADERS = fat.h filesys.h freebsd.h hercules.h \ iso9660.h jfs.h mb_header.h mb_info.h md5.h \ pc_slice.h serial.h shared.h term.h \ - terminfo.h tparm.h ufs2.h vstafs.h xfs.h pxe.h graphics.h + terminfo.h tparm.h ufs2.h vstafs.h xfs.h pxe.h fsys_initrd.h graphics.h EXTRA_DIST = $(noinst_SCRIPTS) @@ -354,7 +355,7 @@ STAGE2_COMPILE = $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ pre_stage2_exec_SOURCES = asm.S bios.c boot.c builtins.c char_io.c \ cmdline.c common.c console.c dec_lzma.c disk_io.c fsys_ext2fs.c \ fsys_fat.c fsys_ntfs.c fsys_ffs.c fsys_iso9660.c fsys_jfs.c fsys_minix.c \ - fsys_reiserfs.c fsys_ufs2.c fsys_vstafs.c fsys_xfs.c fsys_pxe.c fsys_fb.c gunzip.c \ + fsys_reiserfs.c fsys_ufs2.c fsys_vstafs.c fsys_xfs.c fsys_pxe.c fsys_initrd.c fsys_fb.c gunzip.c \ hercules.c md5.c serial.c stage2.c terminfo.c tparm.c graphics.c pre_stage2_exec_CFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS) @@ -483,6 +484,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pre_stage2_exec-fsys_minix.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pre_stage2_exec-fsys_ntfs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pre_stage2_exec-fsys_pxe.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pre_stage2_exec-fsys_initrd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pre_stage2_exec-fsys_reiserfs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pre_stage2_exec-fsys_ufs2.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pre_stage2_exec-fsys_vstafs.Po@am__quote@ @@ -917,6 +919,21 @@ pre_stage2_exec-fsys_pxe.obj: fsys_pxe.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pre_stage2_exec_CFLAGS) $(CFLAGS) -c -o pre_stage2_exec-fsys_pxe.obj `if test -f 'fsys_pxe.c'; then $(CYGPATH_W) 'fsys_pxe.c'; else $(CYGPATH_W) '$(srcdir)/fsys_pxe.c'; fi` +pre_stage2_exec-fsys_initrd.o: fsys_initrd.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pre_stage2_exec_CFLAGS) $(CFLAGS) -MT pre_stage2_exec-fsys_initrd.o -MD -MP -MF $(DEPDIR)/pre_stage2_exec-fsys_initrd.Tpo -c -o pre_stage2_exec-fsys_initrd.o `test -f 'fsys_initrd.c' || echo '$(srcdir)/'`fsys_initrd.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pre_stage2_exec-fsys_initrd.Tpo $(DEPDIR)/pre_stage2_exec-fsys_initrd.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fsys_initrd.c' object='pre_stage2_exec-fsys_initrd.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pre_stage2_exec_CFLAGS) $(CFLAGS) -c -o pre_stage2_exec-fsys_initrd.o `test -f 'fsys_initrd.c' || echo '$(srcdir)/'`fsys_initrd.c + +pre_stage2_exec-fsys_initrd.obj: fsys_initrd.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pre_stage2_exec_CFLAGS) $(CFLAGS) -MT pre_stage2_exec-fsys_initrd.obj -MD -MP -MF $(DEPDIR)/pre_stage2_exec-fsys_initrd.Tpo -c -o pre_stage2_exec-fsys_initrd.obj `if test -f 'fsys_initrd.c'; then $(CYGPATH_W) 'fsys_initrd.c'; else $(CYGPATH_W) '$(srcdir)/fsys_initrd.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pre_stage2_exec-fsys_initrd.Tpo $(DEPDIR)/pre_stage2_exec-fsys_initrd.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fsys_initrd.c' object='pre_stage2_exec-fsys_initrd.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pre_stage2_exec_CFLAGS) $(CFLAGS) -c -o pre_stage2_exec-fsys_initrd.obj `if test -f 'fsys_initrd.c'; then $(CYGPATH_W) 'fsys_initrd.c'; else $(CYGPATH_W) '$(srcdir)/fsys_initrd.c'; fi` + + pre_stage2_exec-fsys_fb.o: fsys_fb.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pre_stage2_exec_CFLAGS) $(CFLAGS) -MT pre_stage2_exec-fsys_fb.o -MD -MP -MF $(DEPDIR)/pre_stage2_exec-fsys_fb.Tpo -c -o pre_stage2_exec-fsys_fb.o `test -f 'fsys_fb.c' || echo '$(srcdir)/'`fsys_fb.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pre_stage2_exec-fsys_fb.Tpo $(DEPDIR)/pre_stage2_exec-fsys_fb.Po diff --git a/stage2/boot.c b/stage2/boot.c index c3676fa5..1a14d794 100644 --- a/stage2/boot.c +++ b/stage2/boot.c @@ -21,7 +21,7 @@ #include "shared.h" #include - +#include "cpio.h" #include "freebsd.h" struct exec @@ -952,6 +952,14 @@ load_module (char *module, char *arg) } struct linux_kernel_header *linux_header; +void cpio_set_field(char *field,unsigned long value); + +void cpio_set_field(char *field,unsigned long value) +{ + char buf[9]; + sprintf(buf,"%08x",value); + memcpy(field,buf,8); +} int load_initrd (char *initrd) @@ -961,12 +969,8 @@ load_initrd (char *initrd) unsigned long long tmp; unsigned long long top_addr; char *arg = initrd; -#ifndef NO_DECOMPRESSION - int no_decompression_bak = no_decompression; -#endif linux_header = (struct linux_kernel_header *) (cur_addr - LINUX_SETUP_MOVE_SIZE); - tmp = ((linux_header->header == LINUX_MAGIC_SIGNATURE && linux_header->version >= 0x0203) ? linux_header->initrd_addr_max : LINUX_INITRD_MAX_ADDRESS); @@ -990,14 +994,14 @@ load_initrd (char *initrd) moveto &= 0xfffff000; - len = 0; - next_file: -#ifndef NO_DECOMPRESSION - no_decompression = 1; -#endif - + if (*initrd == '@') + { + moveto -= 0x200; + initrd = skip_to (1, initrd); + } + if (! grub_open (initrd)) goto fail; @@ -1020,18 +1024,15 @@ load_initrd (char *initrd) tmp = filemax; grub_close (); - initrd = skip_to (0, initrd); if (*initrd) - { - len += ((tmp + 0xFFF) & 0xfffff000); goto next_file; - } - len += tmp; { char map_tmp[64]; + grub_u32_t cpio_hdr_sz; + grub_u32_t cpio_img_sz; tmp = top_addr - moveto; tmp += 0x1FF; tmp >>= 9; /* sectors needed */ @@ -1062,15 +1063,38 @@ load_initrd (char *initrd) top_addr = moveto = initrd_start_sector << 9; memset ((char *)(unsigned long)top_addr, 0, tmp << 9); initrd = arg; + len = 0; next_file1: -#ifndef NO_DECOMPRESSION - no_decompression = 1; -#endif - grub_open (initrd); - tmp = grub_read (RAW_ADDR (moveto), -1ULL, 0xedde0d90); + if (*initrd == '@') + { + char *name = initrd + 1; + initrd = skip_to (SKIP_WITH_TERMINATE |1, initrd); + struct cpio_header *cpio = (struct cpio_header *)(grub_u32_t)moveto; + grub_u32_t name_len = grub_strlen(name); + grub_open (initrd); + memset(cpio,'0',sizeof(struct cpio_header)); + memcpy(cpio->c_magic,CPIO_MAGIC,sizeof(cpio->c_magic)); + cpio_set_field (cpio->c_mode, 0100644 ); + cpio_set_field (cpio->c_nlink,1); + cpio_set_field (cpio->c_filesize, filemax); + cpio_set_field (cpio->c_namesize, name_len); + memcpy((void*)(cpio+1),name,name_len); + cpio_hdr_sz = (sizeof(struct cpio_header) + 3 + name_len) & ~3; + } + else + { + cpio_hdr_sz = 0; + grub_open (initrd); + } + + arg = skip_to (0, initrd); + if (debug) printf("Loading:%.*s\n",arg-initrd,initrd); + + tmp = grub_read (RAW_ADDR (moveto + cpio_hdr_sz), -1ULL, GRUB_READ); grub_close (); + if (tmp != filemax) { //sprintf (map_tmp, "(0x22) (0x22)"); // INITRD_DRIVE @@ -1080,11 +1104,18 @@ load_initrd (char *initrd) errnum = ERR_READ; goto fail; } - moveto += ((tmp + 0xFFF) & 0xfffff000); - initrd = skip_to (0, initrd); + + cpio_img_sz = (tmp + cpio_hdr_sz + 0xFFF) & ~0xFFF; + moveto += cpio_img_sz; + initrd = arg; if (*initrd) + { + len += cpio_img_sz; goto next_file1; + } + + len += tmp + cpio_hdr_sz; unset_int13_handler (0); /* unhook it */ set_int13_handler (bios_drive_map); /* hook it */ @@ -1100,10 +1131,6 @@ load_initrd (char *initrd) fail: -#ifndef NO_DECOMPRESSION - no_decompression = no_decompression_bak; -#endif - return ! errnum; } diff --git a/stage2/builtins.c b/stage2/builtins.c index c10dc555..899734da 100644 --- a/stage2/builtins.c +++ b/stage2/builtins.c @@ -7292,8 +7292,8 @@ static struct builtin builtin_initrd = { "initrd", initrd_func, - BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_SCRIPT | BUILTIN_HELP_LIST, - "initrd FILE [FILE ...]", + BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_SCRIPT | BUILTIN_HELP_LIST | BUILTIN_NO_DECOMPRESSION, + "initrd [@name=]FILE [@name=][FILE ...]", "Load an initial ramdisk FILE for a Linux format boot image and set the" " appropriate parameters in the Linux setup area in memory. For Linux" " 2.6+ kernels, multiple cpio files can be loaded." @@ -10771,29 +10771,14 @@ static struct builtin builtin_module = static int modulenounzip_func (char *arg, int flags) { - int ret; -#ifndef NO_DECOMPRESSION - int no_decompression_bak = no_decompression; -#endif - -#ifndef NO_DECOMPRESSION - no_decompression = 1; -#endif - - ret = module_func (arg, flags); - -#ifndef NO_DECOMPRESSION - no_decompression = no_decompression_bak; -#endif - - return ret; + return module_func (arg, flags); } static struct builtin builtin_modulenounzip = { "modulenounzip", modulenounzip_func, - BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_SCRIPT | BUILTIN_HELP_LIST, + BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_SCRIPT | BUILTIN_HELP_LIST | BUILTIN_NO_DECOMPRESSION, "modulenounzip FILE [ARG ...]", "The same as `module', except that automatic decompression is" " disabled." diff --git a/stage2/char_io.c b/stage2/char_io.c index 8b68c4e5..2a792d94 100644 --- a/stage2/char_io.c +++ b/stage2/char_io.c @@ -252,7 +252,6 @@ grub_putstr (const char *str) //} #endif -unsigned char *putchar_hook_back; int grub_sprintf (char *buffer, const char *format, ...) { @@ -272,6 +271,7 @@ grub_sprintf (char *buffer, const char *format, ...) unsigned int length; int align; unsigned int accuracy; + unsigned char *putchar_hook_back=NULL; int stdout = 1; if (buffer == (char*)1 || buffer == (char*)2) { @@ -279,9 +279,8 @@ grub_sprintf (char *buffer, const char *format, ...) return 1; stdout = 0; - putchar_hook_back = set_putchar_hook(NULL); - bp=NULL;//reset buffer and bp to NULL - buffer=NULL; + putchar_hook_back = set_putchar_hook((grub_u8_t*)0); + bp=buffer=NULL;//reset buffer and bp to NULL } //dataptr++; //dataptr++; diff --git a/stage2/cpio.h b/stage2/cpio.h new file mode 100644 index 00000000..0a550976 --- /dev/null +++ b/stage2/cpio.h @@ -0,0 +1,35 @@ +#ifndef _CPIO_H +#define _CPIO_H + +/** A CPIO archive header + * + * All field are hexadecimal ASCII numbers padded with '0' on the + * left to the full width of the field. + */ +struct cpio_header { + char c_magic[6]; /** The string "070701" or "070702" */ + char c_ino[8]; /** File inode number */ + char c_mode[8]; /** File mode and permissions */ + char c_uid[8]; /** File uid */ + char c_gid[8]; /** File gid */ + char c_nlink[8]; /** Number of links */ + char c_mtime[8]; /** Modification time */ + char c_filesize[8]; /** Size of data field */ + char c_maj[8]; /** Major part of file device number */ + char c_min[8]; /** Minor part of file device number */ + char c_rmaj[8]; /** Major part of device node reference */ + char c_rmin[8]; /** Minor part of device node reference */ + char c_namesize[8]; /** Length of filename, including final NUL */ + char c_chksum[8]; /** Checksum of data field if c_magic is 070702, othersize zero */ +} __attribute__ (( packed )); + +/** CPIO magic */ +#define CPIO_MAGIC "070701" +#define CPIO_MODE_DIR 0040000 +#define CPIO_ALIGN 4 +static inline grub_u32_t cpio_image_align( grub_u32_t len ) +{ + return (len + (CPIO_ALIGN - 1)) & ~(CPIO_ALIGN - 1); +} + +#endif /* _CPIO_H */ diff --git a/stage2/disk_io.c b/stage2/disk_io.c index 8e35a87f..429bdcf0 100644 --- a/stage2/disk_io.c +++ b/stage2/disk_io.c @@ -168,6 +168,9 @@ struct fsys_entry fsys_table[NUM_FSYS + 1] = on floppies from track 1 to 2, while others only use 1. */ # ifdef FSYS_FFS {"ffs", ffs_mount, ffs_read, ffs_dir, 0, ffs_embed}, +# endif +# ifdef FSYS_INITRD + {"initrdfs", initrdfs_mount, initrdfs_read, initrdfs_dir, 0, 0}, # endif {0, 0, 0, 0, 0, 0} }; diff --git a/stage2/filesys.h b/stage2/filesys.h index 5cc47ddb..c80f91a9 100644 --- a/stage2/filesys.h +++ b/stage2/filesys.h @@ -172,6 +172,17 @@ void pxe_close (void); #define FSYS_PXE_NUM 0 #endif +#ifdef FSYS_INITRD +#define FSYS_INITRD_NUM 1 +#ifndef ASM_FILE +int initrdfs_mount (void); +unsigned long long initrdfs_read (unsigned long long buf, unsigned long long len, unsigned long write); +int initrdfs_dir (char *dirname); +#endif +#else +#define FSYS_INITRD_NUM 0 +#endif + #ifdef FSYS_FB #define FSYS_FB_NUM 1 #ifndef ASM_FILE @@ -187,7 +198,7 @@ int fb_dir (char *dirname); #define NUM_FSYS \ (FSYS_FFS_NUM + FSYS_FAT_NUM + FSYS_NTFS_NUM + FSYS_EXT2FS_NUM + FSYS_MINIX_NUM \ + FSYS_REISERFS_NUM + FSYS_VSTAFS_NUM + FSYS_JFS_NUM + FSYS_XFS_NUM \ - + FSYS_TFTP_NUM + FSYS_ISO9660_NUM + FSYS_UFS2_NUM + FSYS_PXE_NUM + FSYS_FB_NUM) + + FSYS_TFTP_NUM + FSYS_ISO9660_NUM + FSYS_UFS2_NUM + FSYS_PXE_NUM + FSYS_FB_NUM + FSYS_INITRD_NUM) #endif #ifndef ASM_FILE diff --git a/stage2/fsys_initrd.c b/stage2/fsys_initrd.c new file mode 100644 index 00000000..f5d2d083 --- /dev/null +++ b/stage2/fsys_initrd.c @@ -0,0 +1,224 @@ +/* + * initrd file system for grub4dos + * + * Copyright (C) 2014 chenall (chenall.cn@gmail.com) + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef FSYS_INITRD + +#include "shared.h" +#include "filesys.h" +#include "fsys_initrd.h" + +#define FILE_INFO + +static grub_u64_t initrdfs_base; +static grub_u64_t initrdfs_size; + +struct initrdfs_file *p_fnode = (struct initrdfs_file*)FSYS_BUF; +struct initrdfs_file *cur_file = (struct initrdfs_file*)FSYS_BUF; + +grub_u64_t char2u64(char *node) +{ + char buf[11]="0x"; + grub_u64_t tmp; + memcpy(&buf[2],node,8); + char *p=buf; + if (!safe_parse_maxint(&p,&tmp)) + return 0; + return tmp; +} + +grub_u32_t raw_file(grub_u64_t base,struct initrdfs_file *p_fn,grub_u32_t max_size) +{ + grub_u32_t size = 0; + p_fn->isdir = 0; + p_fn->base = base; + p_fn->name = -1LL; + + while(size < max_size) + { + size += 4096;//4KB align + char *p = (grub_u32_t)(base + size); + if (*(grub_u32_t*)p == 0x54414221UL)//!BAT + break; + if (*(grub_u16_t*)p == 0x8B1F)//GZIP + break; + if (*(p-1) == '\0') + { + grub_u32_t *t = (grub_u32_t*)p; + while(*t == 0) + { + if ((grub_u32_t)(++t) - (grub_u32_t)p >= 4096) + break; + } + if (*t) break; + } + } + p_fn->size = size; + return size; +} + +grub_u32_t cpio_file(grub_u64_t base,struct initrdfs_file *p_fn) +{ + grub_u64_t namesize; + grub_u16_t hdr_sz; + struct cpio_header *p_cpio; + p_cpio =(struct cpio_header *)(grub_u32_t)base; + p_fn->isdir = char2u64(p_cpio->c_mode); + namesize = char2u64(p_cpio->c_namesize); + p_fn->size = char2u64(p_cpio->c_filesize); + if (errnum || p_fn->isdir == 0) + { + errnum = 0; + return 0; + } + p_fn->name=base + sizeof(struct cpio_header); + hdr_sz = cpio_image_align(sizeof(struct cpio_header) + namesize); + p_fn->isdir &= CPIO_MODE_DIR; + p_fn->base = base + hdr_sz; + return cpio_image_align(hdr_sz + p_fn->size); +} + +int cpio_dir(void) +{ + struct initrdfs_file *p_fn = p_fnode; + grub_u64_t cpio_base = initrdfs_base; + grub_u64_t cpio_end = cpio_base + initrdfs_size; + grub_u32_t node_size = 0; + p_fnode->base = 0ll; + + while(cpio_base < cpio_end) + { + grub_u16_t c_flag = *(grub_u16_t*)(grub_u32_t)(cpio_base+4); + if (*(grub_u32_t*)(grub_u32_t)cpio_base == 0x37303730 && (c_flag == 0x3130 || c_flag == 0x3230)) + node_size = cpio_file(cpio_base,p_fn); + else + node_size = raw_file(cpio_base,p_fn,cpio_end - cpio_base); + + if (node_size == 0 || node_size == -1) + break; + cpio_base += node_size; + if (*(grub_u32_t*)(grub_u32_t)cpio_base != 0x37303730) + { + cpio_base += (node_size + 0xFFF) & ~0xFFF; + cpio_base -= node_size; + } + ++p_fn; + } + p_fn->base=0; + return p_fnode->base; +} + +int initrdfs_mount (void) +{ + int i; + + initrdfs_base = 0; + initrdfs_size = 0; + if (current_drive == ram_drive) + { + initrdfs_base = rd_base; + initrdfs_size = rd_size; + } + else + { + if (unset_int13_handler (1)) + return 0; + for (i = 0; i < DRIVE_MAP_SIZE && !drive_map_slot_empty (hooked_drive_map[i]); i++) + { + if (hooked_drive_map[i].from_drive == (unsigned char)current_drive) + { + if (hooked_drive_map[i].to_drive == 0xFF) + { + initrdfs_base = (grub_u64_t)hooked_drive_map[i].start_sector << 9; + initrdfs_size = (grub_u64_t)hooked_drive_map[i].sector_count << 9; + } + break; + } + } + } + + if (initrdfs_base == 0) return 0; + + return cpio_dir(); +} + +int initrdfs_dir (char *dirname) +{ + grub_u32_t found = 0; + char raw_name[9]; + char *dirpath = dirname + grub_strlen(dirname); + grub_u32_t path_len; + cur_file = p_fnode; + + while (*dirname == '/') + dirname++; + + while(dirpath != dirname && *dirpath !='/') + --dirpath; + + path_len = dirpath - dirname; + if (*dirpath == '/') ++path_len; + + while(cur_file->base) + { + char *filename; + if (cur_file->name != -1) + filename = (char*)(grub_u32_t)cur_file->name; + else + { + sprintf(raw_name,"%08X",(grub_u32_t)cur_file->base); + filename = raw_name; + } + + if (print_possibilities) + { + if (substring (dirname,filename, 1) <= 0/* && grub_strstr(filename + path_len,"/") == 0*/) + { + found = 1; + print_a_completion (filename + path_len, 1); + } + } + else if (substring (dirname, filename, 1) == 0) + { + found = 1; + filemax = cur_file->size; + break; + } + ++cur_file; + } + + if (!found) errnum = ERR_FILE_NOT_FOUND; + + return found; +} + +unsigned long long initrdfs_read (unsigned long long buf, unsigned long long len, unsigned long write) +{ + if (disk_read_hook && debug > 1) + printf("\n",cur_file->base,cur_file->size,filepos); + if (filepos > cur_file->size) return 0; + if (len > cur_file->size - filepos) len = cur_file->size - filepos; + if (write == GRUB_WRITE) grub_memmove64(cur_file->base + filepos,buf,len); + if (write == GRUB_READ && buf) grub_memmove64(buf,cur_file->base + filepos,len); + + filepos += len; + return len; +} + +#endif /* FSYS_INITRD */ \ No newline at end of file diff --git a/stage2/fsys_initrd.h b/stage2/fsys_initrd.h new file mode 100644 index 00000000..a9d2ec01 --- /dev/null +++ b/stage2/fsys_initrd.h @@ -0,0 +1,19 @@ +#ifndef _INITRDFS_H_ +#define _INITRDFS_H_ + +#include "cpio.h" + +struct initrdfs_file +{ + grub_u64_t base; + grub_u64_t name; + grub_u32_t size; + grub_u32_t isdir; +}; + +grub_u64_t char2u64(char *node); +int cpio_dir(void); +grub_u32_t cpio_file(grub_u64_t base,struct initrdfs_file *p_fn); +grub_u32_t raw_file(grub_u64_t base,struct initrdfs_file *p_fn,grub_u32_t max_size); + +#endif /* _INITRDFS_H_ */