11da177e4SLinus Torvalds 21da177e4SLinus Torvalds #include <linux/kernel.h> 31da177e4SLinus Torvalds #include <linux/fs.h> 41da177e4SLinus Torvalds #include <linux/minix_fs.h> 51da177e4SLinus Torvalds #include <linux/ext2_fs.h> 61da177e4SLinus Torvalds #include <linux/romfs_fs.h> 71da177e4SLinus Torvalds #include <linux/cramfs_fs.h> 81da177e4SLinus Torvalds #include <linux/initrd.h> 91da177e4SLinus Torvalds #include <linux/string.h> 10*5a0e3ad6STejun Heo #include <linux/slab.h> 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds #include "do_mounts.h" 13b8fed87dSPhillip Lougher #include "../fs/squashfs/squashfs_fs.h" 141da177e4SLinus Torvalds 1530d65dbfSAlain Knaff #include <linux/decompress/generic.h> 1630d65dbfSAlain Knaff 1730d65dbfSAlain Knaff 181da177e4SLinus Torvalds int __initdata rd_prompt = 1;/* 1 = prompt for RAM disk, 0 = don't prompt */ 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds static int __init prompt_ramdisk(char *str) 211da177e4SLinus Torvalds { 221da177e4SLinus Torvalds rd_prompt = simple_strtol(str,NULL,0) & 1; 231da177e4SLinus Torvalds return 1; 241da177e4SLinus Torvalds } 251da177e4SLinus Torvalds __setup("prompt_ramdisk=", prompt_ramdisk); 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds int __initdata rd_image_start; /* starting block # of image */ 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds static int __init ramdisk_start_setup(char *str) 301da177e4SLinus Torvalds { 311da177e4SLinus Torvalds rd_image_start = simple_strtol(str,NULL,0); 321da177e4SLinus Torvalds return 1; 331da177e4SLinus Torvalds } 341da177e4SLinus Torvalds __setup("ramdisk_start=", ramdisk_start_setup); 351da177e4SLinus Torvalds 3630d65dbfSAlain Knaff static int __init crd_load(int in_fd, int out_fd, decompress_fn deco); 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds /* 391da177e4SLinus Torvalds * This routine tries to find a RAM disk image to load, and returns the 401da177e4SLinus Torvalds * number of blocks to read for a non-compressed image, 0 if the image 411da177e4SLinus Torvalds * is a compressed image, and -1 if an image with the right magic 421da177e4SLinus Torvalds * numbers could not be found. 431da177e4SLinus Torvalds * 441da177e4SLinus Torvalds * We currently check for the following magic numbers: 451da177e4SLinus Torvalds * minix 461da177e4SLinus Torvalds * ext2 471da177e4SLinus Torvalds * romfs 481da177e4SLinus Torvalds * cramfs 49b8fed87dSPhillip Lougher * squashfs 501da177e4SLinus Torvalds * gzip 511da177e4SLinus Torvalds */ 521da177e4SLinus Torvalds static int __init 5330d65dbfSAlain Knaff identify_ramdisk_image(int fd, int start_block, decompress_fn *decompressor) 541da177e4SLinus Torvalds { 551da177e4SLinus Torvalds const int size = 512; 561da177e4SLinus Torvalds struct minix_super_block *minixsb; 571da177e4SLinus Torvalds struct ext2_super_block *ext2sb; 581da177e4SLinus Torvalds struct romfs_super_block *romfsb; 591da177e4SLinus Torvalds struct cramfs_super *cramfsb; 60b8fed87dSPhillip Lougher struct squashfs_super_block *squashfsb; 611da177e4SLinus Torvalds int nblocks = -1; 621da177e4SLinus Torvalds unsigned char *buf; 63889c92d2SH. Peter Anvin const char *compress_name; 641da177e4SLinus Torvalds 651da177e4SLinus Torvalds buf = kmalloc(size, GFP_KERNEL); 66c80544dcSStephen Hemminger if (!buf) 671da177e4SLinus Torvalds return -1; 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds minixsb = (struct minix_super_block *) buf; 701da177e4SLinus Torvalds ext2sb = (struct ext2_super_block *) buf; 711da177e4SLinus Torvalds romfsb = (struct romfs_super_block *) buf; 721da177e4SLinus Torvalds cramfsb = (struct cramfs_super *) buf; 73b8fed87dSPhillip Lougher squashfsb = (struct squashfs_super_block *) buf; 741da177e4SLinus Torvalds memset(buf, 0xe5, size); 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds /* 77b172fd88SH. Peter Anvin * Read block 0 to test for compressed kernel 781da177e4SLinus Torvalds */ 791da177e4SLinus Torvalds sys_lseek(fd, start_block * BLOCK_SIZE, 0); 801da177e4SLinus Torvalds sys_read(fd, buf, size); 811da177e4SLinus Torvalds 82889c92d2SH. Peter Anvin *decompressor = decompress_method(buf, size, &compress_name); 8323a22d57SH. Peter Anvin if (compress_name) { 84889c92d2SH. Peter Anvin printk(KERN_NOTICE "RAMDISK: %s image found at block %d\n", 85889c92d2SH. Peter Anvin compress_name, start_block); 8623a22d57SH. Peter Anvin if (!*decompressor) 8773310a16SH. Peter Anvin printk(KERN_EMERG 8873310a16SH. Peter Anvin "RAMDISK: %s decompressor not configured!\n", 8923a22d57SH. Peter Anvin compress_name); 901da177e4SLinus Torvalds nblocks = 0; 911da177e4SLinus Torvalds goto done; 921da177e4SLinus Torvalds } 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds /* romfs is at block zero too */ 951da177e4SLinus Torvalds if (romfsb->word0 == ROMSB_WORD0 && 961da177e4SLinus Torvalds romfsb->word1 == ROMSB_WORD1) { 971da177e4SLinus Torvalds printk(KERN_NOTICE 981da177e4SLinus Torvalds "RAMDISK: romfs filesystem found at block %d\n", 991da177e4SLinus Torvalds start_block); 1001da177e4SLinus Torvalds nblocks = (ntohl(romfsb->size)+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS; 1011da177e4SLinus Torvalds goto done; 1021da177e4SLinus Torvalds } 1031da177e4SLinus Torvalds 1041da177e4SLinus Torvalds if (cramfsb->magic == CRAMFS_MAGIC) { 1051da177e4SLinus Torvalds printk(KERN_NOTICE 1061da177e4SLinus Torvalds "RAMDISK: cramfs filesystem found at block %d\n", 1071da177e4SLinus Torvalds start_block); 1081da177e4SLinus Torvalds nblocks = (cramfsb->size + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS; 1091da177e4SLinus Torvalds goto done; 1101da177e4SLinus Torvalds } 1111da177e4SLinus Torvalds 112b8fed87dSPhillip Lougher /* squashfs is at block zero too */ 113b8fed87dSPhillip Lougher if (le32_to_cpu(squashfsb->s_magic) == SQUASHFS_MAGIC) { 114b8fed87dSPhillip Lougher printk(KERN_NOTICE 115b8fed87dSPhillip Lougher "RAMDISK: squashfs filesystem found at block %d\n", 116b8fed87dSPhillip Lougher start_block); 117b8fed87dSPhillip Lougher nblocks = (le64_to_cpu(squashfsb->bytes_used) + BLOCK_SIZE - 1) 118b8fed87dSPhillip Lougher >> BLOCK_SIZE_BITS; 119b8fed87dSPhillip Lougher goto done; 120b8fed87dSPhillip Lougher } 121b8fed87dSPhillip Lougher 1221da177e4SLinus Torvalds /* 1231da177e4SLinus Torvalds * Read block 1 to test for minix and ext2 superblock 1241da177e4SLinus Torvalds */ 1251da177e4SLinus Torvalds sys_lseek(fd, (start_block+1) * BLOCK_SIZE, 0); 1261da177e4SLinus Torvalds sys_read(fd, buf, size); 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds /* Try minix */ 1291da177e4SLinus Torvalds if (minixsb->s_magic == MINIX_SUPER_MAGIC || 1301da177e4SLinus Torvalds minixsb->s_magic == MINIX_SUPER_MAGIC2) { 1311da177e4SLinus Torvalds printk(KERN_NOTICE 1321da177e4SLinus Torvalds "RAMDISK: Minix filesystem found at block %d\n", 1331da177e4SLinus Torvalds start_block); 1341da177e4SLinus Torvalds nblocks = minixsb->s_nzones << minixsb->s_log_zone_size; 1351da177e4SLinus Torvalds goto done; 1361da177e4SLinus Torvalds } 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds /* Try ext2 */ 1391da177e4SLinus Torvalds if (ext2sb->s_magic == cpu_to_le16(EXT2_SUPER_MAGIC)) { 1401da177e4SLinus Torvalds printk(KERN_NOTICE 1411da177e4SLinus Torvalds "RAMDISK: ext2 filesystem found at block %d\n", 1421da177e4SLinus Torvalds start_block); 1431da177e4SLinus Torvalds nblocks = le32_to_cpu(ext2sb->s_blocks_count) << 1441da177e4SLinus Torvalds le32_to_cpu(ext2sb->s_log_block_size); 1451da177e4SLinus Torvalds goto done; 1461da177e4SLinus Torvalds } 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds printk(KERN_NOTICE 1491da177e4SLinus Torvalds "RAMDISK: Couldn't find valid RAM disk image starting at %d.\n", 1501da177e4SLinus Torvalds start_block); 1511da177e4SLinus Torvalds 1521da177e4SLinus Torvalds done: 1531da177e4SLinus Torvalds sys_lseek(fd, start_block * BLOCK_SIZE, 0); 1541da177e4SLinus Torvalds kfree(buf); 1551da177e4SLinus Torvalds return nblocks; 1561da177e4SLinus Torvalds } 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds int __init rd_load_image(char *from) 1591da177e4SLinus Torvalds { 1601da177e4SLinus Torvalds int res = 0; 1611da177e4SLinus Torvalds int in_fd, out_fd; 1621da177e4SLinus Torvalds unsigned long rd_blocks, devblocks; 1631da177e4SLinus Torvalds int nblocks, i, disk; 1641da177e4SLinus Torvalds char *buf = NULL; 1651da177e4SLinus Torvalds unsigned short rotate = 0; 16630d65dbfSAlain Knaff decompress_fn decompressor = NULL; 167347a8dc3SMartin Schwidefsky #if !defined(CONFIG_S390) && !defined(CONFIG_PPC_ISERIES) 1681da177e4SLinus Torvalds char rotator[4] = { '|' , '/' , '-' , '\\' }; 1691da177e4SLinus Torvalds #endif 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds out_fd = sys_open("/dev/ram", O_RDWR, 0); 1721da177e4SLinus Torvalds if (out_fd < 0) 1731da177e4SLinus Torvalds goto out; 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds in_fd = sys_open(from, O_RDONLY, 0); 1761da177e4SLinus Torvalds if (in_fd < 0) 1771da177e4SLinus Torvalds goto noclose_input; 1781da177e4SLinus Torvalds 17930d65dbfSAlain Knaff nblocks = identify_ramdisk_image(in_fd, rd_image_start, &decompressor); 1801da177e4SLinus Torvalds if (nblocks < 0) 1811da177e4SLinus Torvalds goto done; 1821da177e4SLinus Torvalds 1831da177e4SLinus Torvalds if (nblocks == 0) { 18430d65dbfSAlain Knaff if (crd_load(in_fd, out_fd, decompressor) == 0) 1851da177e4SLinus Torvalds goto successful_load; 1861da177e4SLinus Torvalds goto done; 1871da177e4SLinus Torvalds } 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds /* 1901da177e4SLinus Torvalds * NOTE NOTE: nblocks is not actually blocks but 1911da177e4SLinus Torvalds * the number of kibibytes of data to load into a ramdisk. 1921da177e4SLinus Torvalds * So any ramdisk block size that is a multiple of 1KiB should 1931da177e4SLinus Torvalds * work when the appropriate ramdisk_blocksize is specified 1941da177e4SLinus Torvalds * on the command line. 1951da177e4SLinus Torvalds * 1961da177e4SLinus Torvalds * The default ramdisk_blocksize is 1KiB and it is generally 1971da177e4SLinus Torvalds * silly to use anything else, so make sure to use 1KiB 1981da177e4SLinus Torvalds * blocksize while generating ext2fs ramdisk-images. 1991da177e4SLinus Torvalds */ 2001da177e4SLinus Torvalds if (sys_ioctl(out_fd, BLKGETSIZE, (unsigned long)&rd_blocks) < 0) 2011da177e4SLinus Torvalds rd_blocks = 0; 2021da177e4SLinus Torvalds else 2031da177e4SLinus Torvalds rd_blocks >>= 1; 2041da177e4SLinus Torvalds 2051da177e4SLinus Torvalds if (nblocks > rd_blocks) { 2061da177e4SLinus Torvalds printk("RAMDISK: image too big! (%dKiB/%ldKiB)\n", 2071da177e4SLinus Torvalds nblocks, rd_blocks); 2081da177e4SLinus Torvalds goto done; 2091da177e4SLinus Torvalds } 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds /* 2121da177e4SLinus Torvalds * OK, time to copy in the data 2131da177e4SLinus Torvalds */ 2141da177e4SLinus Torvalds if (sys_ioctl(in_fd, BLKGETSIZE, (unsigned long)&devblocks) < 0) 2151da177e4SLinus Torvalds devblocks = 0; 2161da177e4SLinus Torvalds else 2171da177e4SLinus Torvalds devblocks >>= 1; 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds if (strcmp(from, "/initrd.image") == 0) 2201da177e4SLinus Torvalds devblocks = nblocks; 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds if (devblocks == 0) { 2231da177e4SLinus Torvalds printk(KERN_ERR "RAMDISK: could not determine device size\n"); 2241da177e4SLinus Torvalds goto done; 2251da177e4SLinus Torvalds } 2261da177e4SLinus Torvalds 2271da177e4SLinus Torvalds buf = kmalloc(BLOCK_SIZE, GFP_KERNEL); 228d613c3e2SHarvey Harrison if (!buf) { 2291da177e4SLinus Torvalds printk(KERN_ERR "RAMDISK: could not allocate buffer\n"); 2301da177e4SLinus Torvalds goto done; 2311da177e4SLinus Torvalds } 2321da177e4SLinus Torvalds 2331da177e4SLinus Torvalds printk(KERN_NOTICE "RAMDISK: Loading %dKiB [%ld disk%s] into ram disk... ", 2341da177e4SLinus Torvalds nblocks, ((nblocks-1)/devblocks)+1, nblocks>devblocks ? "s" : ""); 2351da177e4SLinus Torvalds for (i = 0, disk = 1; i < nblocks; i++) { 2361da177e4SLinus Torvalds if (i && (i % devblocks == 0)) { 2371da177e4SLinus Torvalds printk("done disk #%d.\n", disk++); 2381da177e4SLinus Torvalds rotate = 0; 2391da177e4SLinus Torvalds if (sys_close(in_fd)) { 2401da177e4SLinus Torvalds printk("Error closing the disk.\n"); 2411da177e4SLinus Torvalds goto noclose_input; 2421da177e4SLinus Torvalds } 2431da177e4SLinus Torvalds change_floppy("disk #%d", disk); 2441da177e4SLinus Torvalds in_fd = sys_open(from, O_RDONLY, 0); 2451da177e4SLinus Torvalds if (in_fd < 0) { 2461da177e4SLinus Torvalds printk("Error opening disk.\n"); 2471da177e4SLinus Torvalds goto noclose_input; 2481da177e4SLinus Torvalds } 2491da177e4SLinus Torvalds printk("Loading disk #%d... ", disk); 2501da177e4SLinus Torvalds } 2511da177e4SLinus Torvalds sys_read(in_fd, buf, BLOCK_SIZE); 2521da177e4SLinus Torvalds sys_write(out_fd, buf, BLOCK_SIZE); 253347a8dc3SMartin Schwidefsky #if !defined(CONFIG_S390) && !defined(CONFIG_PPC_ISERIES) 2541da177e4SLinus Torvalds if (!(i % 16)) { 2551da177e4SLinus Torvalds printk("%c\b", rotator[rotate & 0x3]); 2561da177e4SLinus Torvalds rotate++; 2571da177e4SLinus Torvalds } 2581da177e4SLinus Torvalds #endif 2591da177e4SLinus Torvalds } 2601da177e4SLinus Torvalds printk("done.\n"); 2611da177e4SLinus Torvalds 2621da177e4SLinus Torvalds successful_load: 2631da177e4SLinus Torvalds res = 1; 2641da177e4SLinus Torvalds done: 2651da177e4SLinus Torvalds sys_close(in_fd); 2661da177e4SLinus Torvalds noclose_input: 2671da177e4SLinus Torvalds sys_close(out_fd); 2681da177e4SLinus Torvalds out: 2691da177e4SLinus Torvalds kfree(buf); 2701da177e4SLinus Torvalds sys_unlink("/dev/ram"); 2711da177e4SLinus Torvalds return res; 2721da177e4SLinus Torvalds } 2731da177e4SLinus Torvalds 2741da177e4SLinus Torvalds int __init rd_load_disk(int n) 2751da177e4SLinus Torvalds { 2761da177e4SLinus Torvalds if (rd_prompt) 2771da177e4SLinus Torvalds change_floppy("root floppy disk to be loaded into RAM disk"); 278bdaf8529SGreg Kroah-Hartman create_dev("/dev/root", ROOT_DEV); 279bdaf8529SGreg Kroah-Hartman create_dev("/dev/ram", MKDEV(RAMDISK_MAJOR, n)); 2801da177e4SLinus Torvalds return rd_load_image("/dev/root"); 2811da177e4SLinus Torvalds } 2821da177e4SLinus Torvalds 2831da177e4SLinus Torvalds static int exit_code; 28430d65dbfSAlain Knaff static int decompress_error; 2851da177e4SLinus Torvalds static int crd_infd, crd_outfd; 2861da177e4SLinus Torvalds 28730d65dbfSAlain Knaff static int __init compr_fill(void *buf, unsigned int len) 2881da177e4SLinus Torvalds { 28930d65dbfSAlain Knaff int r = sys_read(crd_infd, buf, len); 29030d65dbfSAlain Knaff if (r < 0) 29130d65dbfSAlain Knaff printk(KERN_ERR "RAMDISK: error while reading compressed data"); 29230d65dbfSAlain Knaff else if (r == 0) 29330d65dbfSAlain Knaff printk(KERN_ERR "RAMDISK: EOF while reading compressed data"); 29430d65dbfSAlain Knaff return r; 29530d65dbfSAlain Knaff } 2961da177e4SLinus Torvalds 29730d65dbfSAlain Knaff static int __init compr_flush(void *window, unsigned int outcnt) 29830d65dbfSAlain Knaff { 29930d65dbfSAlain Knaff int written = sys_write(crd_outfd, window, outcnt); 30030d65dbfSAlain Knaff if (written != outcnt) { 30130d65dbfSAlain Knaff if (decompress_error == 0) 30230d65dbfSAlain Knaff printk(KERN_ERR 30330d65dbfSAlain Knaff "RAMDISK: incomplete write (%d != %d)\n", 30430d65dbfSAlain Knaff written, outcnt); 30530d65dbfSAlain Knaff decompress_error = 1; 3061da177e4SLinus Torvalds return -1; 3071da177e4SLinus Torvalds } 30830d65dbfSAlain Knaff return outcnt; 3091da177e4SLinus Torvalds } 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds static void __init error(char *x) 3121da177e4SLinus Torvalds { 3131da177e4SLinus Torvalds printk(KERN_ERR "%s\n", x); 3141da177e4SLinus Torvalds exit_code = 1; 31530d65dbfSAlain Knaff decompress_error = 1; 3161da177e4SLinus Torvalds } 3171da177e4SLinus Torvalds 31830d65dbfSAlain Knaff static int __init crd_load(int in_fd, int out_fd, decompress_fn deco) 3191da177e4SLinus Torvalds { 3201da177e4SLinus Torvalds int result; 3211da177e4SLinus Torvalds crd_infd = in_fd; 3221da177e4SLinus Torvalds crd_outfd = out_fd; 32330d65dbfSAlain Knaff result = deco(NULL, 0, compr_fill, compr_flush, NULL, NULL, error); 32430d65dbfSAlain Knaff if (decompress_error) 3251da177e4SLinus Torvalds result = 1; 3261da177e4SLinus Torvalds return result; 3271da177e4SLinus Torvalds } 328