<ugly hack warning>
6. (RFC/FYI) In our tree we have a hack that allows us
to append the cramfs image to the kernel image and use it to boot from.
We support both booting from flash where the kernel image is compressed
and the cramfs image is in flash and booting directly from RAM using
the image downloaded through the network interface - in that case the
kernel is not compressed and the cramfs image is in RAM after the kernel.
A "romfs_in_flash" variable is used to determine which mode is
used and if we're booting from RAM, the cramfs is not read through a
real device.
Here is the diff for your amusement and I welcome any feedback
slightly more constructive then "Don't do that!" ;-)
An alternative approach could be to use a mtd-ram device but I don't
know how yet.
Any chance at all of anything like this getting into the official kernel?
(after putting it within a CONFIG_CRAMFS_AS_IMAGE or similar)
(don't bash me to hard please :-)
Any hints of other approaches?
/Johan
Index: linux/fs/cramfs/inode.c
===================================================================
RCS file: /n/cvsroot/os/linux/fs/cramfs/inode.c,v
retrieving revision 1.1.1.10
retrieving revision 1.19
diff -u -p -r1.1.1.10 -r1.19
--- linux/fs/cramfs/inode.c 23 Apr 2002 13:18:36 -0000 1.1.1.10
+++ linux/fs/cramfs/inode.c 29 Apr 2002 12:37:59 -0000 1.19
@@ -28,6 +28,9 @@
#define CRAMFS_SB_BLOCKS u.cramfs_sb.blocks
#define CRAMFS_SB_FILES u.cramfs_sb.files
#define CRAMFS_SB_FLAGS u.cramfs_sb.flags
+#define CRAMFS_SB_FSTIME u.cramfs_sb.fstime
+
+#define CRAMFS_AS_IMAGE
static struct super_operations cramfs_ops;
static struct inode_operations cramfs_dir_inode_operations;
@@ -54,6 +57,8 @@ static struct inode *get_cramfs_inode(st
inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_gid = cramfs_inode->gid;
inode->i_ino = CRAMINO(cramfs_inode);
+ inode->i_mtime = sb->CRAMFS_SB_FSTIME;
+ inode->i_ctime = sb->CRAMFS_SB_FSTIME;
/* inode->i_nlink is left 1 - arguably wrong for directories,
but it's the best we can do without reading the directory
contents. 1 yields the right result in GNU find, even
@@ -109,7 +114,32 @@ static int next_buffer;
* Returns a pointer to a buffer containing at least LEN bytes of
* filesystem starting at byte offset OFFSET into the filesystem.
*/
+
+#ifdef CRAMFS_AS_IMAGE
+
+/* Normally, cramfs_read reads from offset and len bytes on a block device.
+ * But if we have an attached image piggybacked on the end of the kernel
+ * (a la krom/romfs) we can use this trivial routine.
+ */
+
+extern unsigned char *romfs_start; /* set in head.S during boot */
+extern unsigned int romfs_length; /* dito */
+void *(*cramfs_read)(struct super_block *, unsigned int, unsigned int);
+
+/*
+ * Returns a pointer to a buffer containing at least LEN bytes of
+ * filesystem starting at byte offset OFFSET into the filesystem.
+ */
+inline void *mem_cramfs_read(struct super_block *sb, unsigned int offset, unsigned int len)
+{
+ //printk("cramfs_read start 0x%x, offset %d, len %d\n", romfs_start, offset, len);
+ return romfs_start + offset;
+}
+
+void *blk_cramfs_read(struct super_block *sb, unsigned int offset, unsigned int len)
+#else /* CRAMFS_AS_IMAGE */
static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned int len)
+#endif
{
struct buffer_head * bh_array[BLKS_PER_BUF];
struct buffer_head * read_array[BLKS_PER_BUF];
@@ -144,7 +174,7 @@ static void *cramfs_read(struct super_bl
minor = MINOR(sb->s_dev);
if (blk_size[major])
- devsize = blk_size[major][minor] >> 2;
+ devsize = blk_size[major][minor] / (PAGE_CACHE_SIZE / 1024);
/* Ok, read in BLKS_PER_BUF pages completely first. */
unread = 0;
@@ -187,7 +217,6 @@ static void *cramfs_read(struct super_bl
return read_buffers[buffer] + offset;
}
-
static struct super_block * cramfs_read_super(struct super_block *sb, void *data, int silent)
{
int i;
@@ -230,10 +259,13 @@ static struct super_block * cramfs_read_
goto out;
}
root_offset = super.root.offset << 2;
+ sb->CRAMFS_SB_FSTIME = 0;
if (super.flags & CRAMFS_FLAG_FSID_VERSION_2) {
sb->CRAMFS_SB_SIZE=super.size;
sb->CRAMFS_SB_BLOCKS=super.fsid.blocks;
sb->CRAMFS_SB_FILES=super.fsid.files;
+ if (super.flags & CRAMFS_FLAG_EDITION_TIMESTAMP)
+ sb->CRAMFS_SB_FSTIME=super.fsid.edition;
} else {
sb->CRAMFS_SB_SIZE=1<<28;
sb->CRAMFS_SB_BLOCKS=0;
@@ -444,7 +476,10 @@ static struct super_operations cramfs_op
statfs: cramfs_statfs,
};
-static DECLARE_FSTYPE_DEV(cramfs_fs_type, "cramfs", cramfs_read_super);
+/* Don't have this static, init/do_mounts.c removes FS_REQUIRES_DEV if we are
+ * booting from memory with a cramfs image appended to the kernel image /johana
+ */
+DECLARE_FSTYPE_DEV(cramfs_fs_type, "cramfs", cramfs_read_super);
static int __init init_cramfs_fs(void)
{
Index: linux/init/do_mounts.c
===================================================================
RCS file: /n/cvsroot/os/linux/init/do_mounts.c,v
retrieving revision 1.1.1.1
retrieving revision 1.3
diff -u -p -r1.1.1.1 -r1.3
--- linux/init/do_mounts.c 23 Apr 2002 13:18:37 -0000 1.1.1.1
+++ linux/init/do_mounts.c 24 Apr 2002 15:20:01 -0000 1.3
@@ -709,6 +709,38 @@ static void __init devfs_make_root(char
static void __init mount_root(void)
{
+#if defined(CONFIG_CRAMFS)
+ {
+ extern void *(*cramfs_read)(struct super_block *, unsigned int,
+ unsigned int);
+ extern void *mem_cramfs_read(struct super_block *sb,
+ unsigned int offset, unsigned int len);
+ extern void *blk_cramfs_read(struct super_block *sb,
+ unsigned int offset, unsigned int len);
+ extern unsigned long romfs_in_flash; /* From head.S */
+ extern struct file_system_type cramfs_fs_type; /* fs/cramfs/inode.c */
+
+ if (!romfs_in_flash) {
+ cramfs_read = mem_cramfs_read;
+ /* When booting from memory we don't require a device
+ * and can't have the FS_REQUIRES_DEV flag set:
+ */
+ cramfs_fs_type.fs_flags &= ~FS_REQUIRES_DEV;
+
+ if(sys_mount("/dev/root", "/root", "cramfs", root_mountflags, 0)) {
+ printk(KERN_ERR "VFS: Unable to mount cramfs filesystem.\n");
+ /* Panic here ? */
+ }
+ sys_chdir("/root");
+ ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev;
+ printk("VFS: Mounted root (cramfs filesystem).\n");
+ return;
+ } else {
+ cramfs_read = blk_cramfs_read;
+ }
+ }
+#endif
+
#ifdef CONFIG_ROOT_NFS
if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) {
if (mount_nfs_root()) {
Johan Adolfsson <[email protected]> writes:
> <ugly hack warning>
> 6. (RFC/FYI) In our tree we have a hack that allows us
> to append the cramfs image to the kernel image and use it to boot from.
> [...]
> Any hints of other approaches?
It seems much cleaner to use the padding option to put some boot code
in the first 512 bytes of the cramfs image which you can use to jump
to anywhere in the image.
What we did for x86 was to put boot code in the first 512 bytes (the
"-p" option to mkcramfs), then jump to 512 bytes after the superblock
start (offset 1024) which was where we put the kernel (put there via the
"-i" option to mkcramfs, just a normal kernel image padded at the
beginning by 436 bytes so it would start at offset 1024).
We could have just jumped to offset 588 instead of 1024 and not padded
the kernel, but we used even numbers for some (aesthetic?) reason that I
can't recall.
Dan
"Daniel Quinlan" <[email protected]> wrote in message
news:[email protected]...
> Johan Adolfsson <[email protected]> writes:
>
> > <ugly hack warning>
> > 6. (RFC/FYI) In our tree we have a hack that allows us
> > to append the cramfs image to the kernel image and use it to boot
from.
> > [...]
> > Any hints of other approaches?
>
> It seems much cleaner to use the padding option to put some boot code
> in the first 512 bytes of the cramfs image which you can use to jump
> to anywhere in the image.
>
> What we did for x86 was to put boot code in the first 512 bytes (the
> "-p" option to mkcramfs), then jump to 512 bytes after the superblock
> start (offset 1024) which was where we put the kernel (put there via the
> "-i" option to mkcramfs, just a normal kernel image padded at the
> beginning by 436 bytes so it would start at offset 1024).
>
> We could have just jumped to offset 588 instead of 1024 and not padded
> the kernel, but we used even numbers for some (aesthetic?) reason that I
> can't recall.
>
> Dan
That wouldn't work that well for us, I think, or at least we
probably couldn't use the same cramfs image for development
(network boot) as for flash boot.
Our normal flash image looks something like this:
64k bootblock
partition table (with code that jumps over it)
decompressor
compressed kernel
cramfs image
padding
JFFS partition
the compressed kernel is decompressed to RAM and started.
I agree that having the compressed kernel as part of the
cramfs image would be nice, but is the image exposed in the
filesystem as well?
It doesn't look like it when I look at the code.
That could be a nice feature as well.
During development, we download an image to RAM directly without
flashing it which takes two seconds or so instead of waiting for the
flash chips to be erased. That image contains the kernel (not compressed)
with an appended cramfs image.
I don't think we can waste that additional amount of RAM by having
the kernel both uncompressed and then compressed in the cramfs image,
at least not for hardware with only 8MB RAM.
I did some fiddling with the MTD RAM yesterday and think I got it
to work after some editing, patches will be submitted to the mtd list.
/Johan