2005-04-17 02:20:36 +04:00
# include <linux/kernel.h>
# include <linux/fs.h>
# include <linux/minix_fs.h>
# include <linux/ext2_fs.h>
# include <linux/romfs_fs.h>
# include <linux/cramfs_fs.h>
# include <linux/initrd.h>
# include <linux/string.h>
# include "do_mounts.h"
2009-01-05 11:46:28 +03:00
# include "../fs/squashfs/squashfs_fs.h"
2005-04-17 02:20:36 +04:00
2009-01-05 00:46:17 +03:00
# include <linux/decompress/generic.h>
2005-04-17 02:20:36 +04:00
int __initdata rd_prompt = 1 ; /* 1 = prompt for RAM disk, 0 = don't prompt */
static int __init prompt_ramdisk ( char * str )
{
rd_prompt = simple_strtol ( str , NULL , 0 ) & 1 ;
return 1 ;
}
__setup ( " prompt_ramdisk= " , prompt_ramdisk ) ;
int __initdata rd_image_start ; /* starting block # of image */
static int __init ramdisk_start_setup ( char * str )
{
rd_image_start = simple_strtol ( str , NULL , 0 ) ;
return 1 ;
}
__setup ( " ramdisk_start= " , ramdisk_start_setup ) ;
2009-01-05 00:46:17 +03:00
static int __init crd_load ( int in_fd , int out_fd , decompress_fn deco ) ;
2005-04-17 02:20:36 +04:00
/*
* This routine tries to find a RAM disk image to load , and returns the
* number of blocks to read for a non - compressed image , 0 if the image
* is a compressed image , and - 1 if an image with the right magic
* numbers could not be found .
*
* We currently check for the following magic numbers :
2009-01-05 01:42:52 +03:00
* minix
* ext2
2005-04-17 02:20:36 +04:00
* romfs
* cramfs
2009-01-05 11:46:28 +03:00
* squashfs
2009-01-05 01:42:52 +03:00
* gzip
2005-04-17 02:20:36 +04:00
*/
2009-01-05 01:42:52 +03:00
static int __init
2009-01-05 00:46:17 +03:00
identify_ramdisk_image ( int fd , int start_block , decompress_fn * decompressor )
2005-04-17 02:20:36 +04:00
{
const int size = 512 ;
struct minix_super_block * minixsb ;
struct ext2_super_block * ext2sb ;
struct romfs_super_block * romfsb ;
struct cramfs_super * cramfsb ;
2009-01-05 11:46:28 +03:00
struct squashfs_super_block * squashfsb ;
2005-04-17 02:20:36 +04:00
int nblocks = - 1 ;
unsigned char * buf ;
2009-01-09 02:14:17 +03:00
const char * compress_name ;
2005-04-17 02:20:36 +04:00
buf = kmalloc ( size , GFP_KERNEL ) ;
2007-10-18 14:07:05 +04:00
if ( ! buf )
2005-04-17 02:20:36 +04:00
return - 1 ;
minixsb = ( struct minix_super_block * ) buf ;
ext2sb = ( struct ext2_super_block * ) buf ;
romfsb = ( struct romfs_super_block * ) buf ;
cramfsb = ( struct cramfs_super * ) buf ;
2009-01-05 11:46:28 +03:00
squashfsb = ( struct squashfs_super_block * ) buf ;
2005-04-17 02:20:36 +04:00
memset ( buf , 0xe5 , size ) ;
/*
2009-01-05 01:42:52 +03:00
* Read block 0 to test for compressed kernel
2005-04-17 02:20:36 +04:00
*/
sys_lseek ( fd , start_block * BLOCK_SIZE , 0 ) ;
sys_read ( fd , buf , size ) ;
2009-01-09 02:14:17 +03:00
* decompressor = decompress_method ( buf , size , & compress_name ) ;
2009-01-13 01:24:04 +03:00
if ( compress_name ) {
2009-01-09 02:14:17 +03:00
printk ( KERN_NOTICE " RAMDISK: %s image found at block %d \n " ,
compress_name , start_block ) ;
2009-01-13 01:24:04 +03:00
if ( ! * decompressor )
2009-01-14 22:28:35 +03:00
printk ( KERN_EMERG
" RAMDISK: %s decompressor not configured! \n " ,
2009-01-13 01:24:04 +03:00
compress_name ) ;
2009-01-09 02:14:17 +03:00
nblocks = 0 ;
goto done ;
2005-04-17 02:20:36 +04:00
}
/* romfs is at block zero too */
if ( romfsb - > word0 = = ROMSB_WORD0 & &
romfsb - > word1 = = ROMSB_WORD1 ) {
printk ( KERN_NOTICE
" RAMDISK: romfs filesystem found at block %d \n " ,
start_block ) ;
nblocks = ( ntohl ( romfsb - > size ) + BLOCK_SIZE - 1 ) > > BLOCK_SIZE_BITS ;
goto done ;
}
if ( cramfsb - > magic = = CRAMFS_MAGIC ) {
printk ( KERN_NOTICE
" RAMDISK: cramfs filesystem found at block %d \n " ,
start_block ) ;
nblocks = ( cramfsb - > size + BLOCK_SIZE - 1 ) > > BLOCK_SIZE_BITS ;
goto done ;
}
2009-01-05 11:46:28 +03:00
/* squashfs is at block zero too */
if ( le32_to_cpu ( squashfsb - > s_magic ) = = SQUASHFS_MAGIC ) {
printk ( KERN_NOTICE
" RAMDISK: squashfs filesystem found at block %d \n " ,
start_block ) ;
nblocks = ( le64_to_cpu ( squashfsb - > bytes_used ) + BLOCK_SIZE - 1 )
> > BLOCK_SIZE_BITS ;
goto done ;
}
2005-04-17 02:20:36 +04:00
/*
* Read block 1 to test for minix and ext2 superblock
*/
sys_lseek ( fd , ( start_block + 1 ) * BLOCK_SIZE , 0 ) ;
sys_read ( fd , buf , size ) ;
/* Try minix */
if ( minixsb - > s_magic = = MINIX_SUPER_MAGIC | |
minixsb - > s_magic = = MINIX_SUPER_MAGIC2 ) {
printk ( KERN_NOTICE
" RAMDISK: Minix filesystem found at block %d \n " ,
start_block ) ;
nblocks = minixsb - > s_nzones < < minixsb - > s_log_zone_size ;
goto done ;
}
/* Try ext2 */
if ( ext2sb - > s_magic = = cpu_to_le16 ( EXT2_SUPER_MAGIC ) ) {
printk ( KERN_NOTICE
" RAMDISK: ext2 filesystem found at block %d \n " ,
start_block ) ;
nblocks = le32_to_cpu ( ext2sb - > s_blocks_count ) < <
le32_to_cpu ( ext2sb - > s_log_block_size ) ;
goto done ;
}
printk ( KERN_NOTICE
" RAMDISK: Couldn't find valid RAM disk image starting at %d. \n " ,
start_block ) ;
2009-01-05 01:42:52 +03:00
2005-04-17 02:20:36 +04:00
done :
sys_lseek ( fd , start_block * BLOCK_SIZE , 0 ) ;
kfree ( buf ) ;
return nblocks ;
}
int __init rd_load_image ( char * from )
{
int res = 0 ;
int in_fd , out_fd ;
unsigned long rd_blocks , devblocks ;
int nblocks , i , disk ;
char * buf = NULL ;
unsigned short rotate = 0 ;
2009-01-05 00:46:17 +03:00
decompress_fn decompressor = NULL ;
2006-01-06 11:19:28 +03:00
# if !defined(CONFIG_S390) && !defined(CONFIG_PPC_ISERIES)
2005-04-17 02:20:36 +04:00
char rotator [ 4 ] = { ' | ' , ' / ' , ' - ' , ' \\ ' } ;
# endif
out_fd = sys_open ( " /dev/ram " , O_RDWR , 0 ) ;
if ( out_fd < 0 )
goto out ;
in_fd = sys_open ( from , O_RDONLY , 0 ) ;
if ( in_fd < 0 )
goto noclose_input ;
2009-01-05 00:46:17 +03:00
nblocks = identify_ramdisk_image ( in_fd , rd_image_start , & decompressor ) ;
2005-04-17 02:20:36 +04:00
if ( nblocks < 0 )
goto done ;
if ( nblocks = = 0 ) {
2009-01-05 00:46:17 +03:00
if ( crd_load ( in_fd , out_fd , decompressor ) = = 0 )
2005-04-17 02:20:36 +04:00
goto successful_load ;
goto done ;
}
/*
* NOTE NOTE : nblocks is not actually blocks but
* the number of kibibytes of data to load into a ramdisk .
* So any ramdisk block size that is a multiple of 1 KiB should
* work when the appropriate ramdisk_blocksize is specified
* on the command line .
*
* The default ramdisk_blocksize is 1 KiB and it is generally
* silly to use anything else , so make sure to use 1 KiB
* blocksize while generating ext2fs ramdisk - images .
*/
if ( sys_ioctl ( out_fd , BLKGETSIZE , ( unsigned long ) & rd_blocks ) < 0 )
rd_blocks = 0 ;
else
rd_blocks > > = 1 ;
if ( nblocks > rd_blocks ) {
printk ( " RAMDISK: image too big! (%dKiB/%ldKiB) \n " ,
nblocks , rd_blocks ) ;
goto done ;
}
2009-01-05 01:42:52 +03:00
2005-04-17 02:20:36 +04:00
/*
* OK , time to copy in the data
*/
if ( sys_ioctl ( in_fd , BLKGETSIZE , ( unsigned long ) & devblocks ) < 0 )
devblocks = 0 ;
else
devblocks > > = 1 ;
if ( strcmp ( from , " /initrd.image " ) = = 0 )
devblocks = nblocks ;
if ( devblocks = = 0 ) {
printk ( KERN_ERR " RAMDISK: could not determine device size \n " ) ;
goto done ;
}
buf = kmalloc ( BLOCK_SIZE , GFP_KERNEL ) ;
2008-04-29 01:13:14 +04:00
if ( ! buf ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " RAMDISK: could not allocate buffer \n " ) ;
goto done ;
}
printk ( KERN_NOTICE " RAMDISK: Loading %dKiB [%ld disk%s] into ram disk... " ,
nblocks , ( ( nblocks - 1 ) / devblocks ) + 1 , nblocks > devblocks ? " s " : " " ) ;
for ( i = 0 , disk = 1 ; i < nblocks ; i + + ) {
if ( i & & ( i % devblocks = = 0 ) ) {
printk ( " done disk #%d. \n " , disk + + ) ;
rotate = 0 ;
if ( sys_close ( in_fd ) ) {
printk ( " Error closing the disk. \n " ) ;
goto noclose_input ;
}
change_floppy ( " disk #%d " , disk ) ;
in_fd = sys_open ( from , O_RDONLY , 0 ) ;
if ( in_fd < 0 ) {
printk ( " Error opening disk. \n " ) ;
goto noclose_input ;
}
printk ( " Loading disk #%d... " , disk ) ;
}
sys_read ( in_fd , buf , BLOCK_SIZE ) ;
sys_write ( out_fd , buf , BLOCK_SIZE ) ;
2006-01-06 11:19:28 +03:00
# if !defined(CONFIG_S390) && !defined(CONFIG_PPC_ISERIES)
2005-04-17 02:20:36 +04:00
if ( ! ( i % 16 ) ) {
printk ( " %c \b " , rotator [ rotate & 0x3 ] ) ;
rotate + + ;
}
# endif
}
printk ( " done. \n " ) ;
successful_load :
res = 1 ;
done :
sys_close ( in_fd ) ;
noclose_input :
sys_close ( out_fd ) ;
out :
kfree ( buf ) ;
sys_unlink ( " /dev/ram " ) ;
return res ;
}
int __init rd_load_disk ( int n )
{
if ( rd_prompt )
change_floppy ( " root floppy disk to be loaded into RAM disk " ) ;
2005-06-21 08:15:16 +04:00
create_dev ( " /dev/root " , ROOT_DEV ) ;
create_dev ( " /dev/ram " , MKDEV ( RAMDISK_MAJOR , n ) ) ;
2005-04-17 02:20:36 +04:00
return rd_load_image ( " /dev/root " ) ;
}
static int exit_code ;
2009-01-05 00:46:17 +03:00
static int decompress_error ;
2005-04-17 02:20:36 +04:00
static int crd_infd , crd_outfd ;
2009-01-05 00:46:17 +03:00
static int __init compr_fill ( void * buf , unsigned int len )
2005-04-17 02:20:36 +04:00
{
2009-01-05 00:46:17 +03:00
int r = sys_read ( crd_infd , buf , len ) ;
if ( r < 0 )
printk ( KERN_ERR " RAMDISK: error while reading compressed data " ) ;
else if ( r = = 0 )
printk ( KERN_ERR " RAMDISK: EOF while reading compressed data " ) ;
return r ;
2005-04-17 02:20:36 +04:00
}
2009-01-05 00:46:17 +03:00
static int __init compr_flush ( void * window , unsigned int outcnt )
2005-04-17 02:20:36 +04:00
{
2009-01-05 00:46:17 +03:00
int written = sys_write ( crd_outfd , window , outcnt ) ;
if ( written ! = outcnt ) {
if ( decompress_error = = 0 )
printk ( KERN_ERR
" RAMDISK: incomplete write (%d != %d) \n " ,
written , outcnt ) ;
decompress_error = 1 ;
return - 1 ;
}
return outcnt ;
2005-04-17 02:20:36 +04:00
}
static void __init error ( char * x )
{
printk ( KERN_ERR " %s \n " , x ) ;
exit_code = 1 ;
2009-01-05 00:46:17 +03:00
decompress_error = 1 ;
2005-04-17 02:20:36 +04:00
}
2009-01-05 00:46:17 +03:00
static int __init crd_load ( int in_fd , int out_fd , decompress_fn deco )
2005-04-17 02:20:36 +04:00
{
int result ;
crd_infd = in_fd ;
crd_outfd = out_fd ;
2009-01-05 00:46:17 +03:00
result = deco ( NULL , 0 , compr_fill , compr_flush , NULL , NULL , error ) ;
if ( decompress_error )
2005-04-17 02:20:36 +04:00
result = 1 ;
return result ;
}