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> 105a0e3ad6STejun 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) 67ea611b26SDavidlohr Bueso return -ENOMEM; 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 /* 123*f919b923SNeil Armstrong * Read 512 bytes further to check if cramfs is padded 124*f919b923SNeil Armstrong */ 125*f919b923SNeil Armstrong sys_lseek(fd, start_block * BLOCK_SIZE + 0x200, 0); 126*f919b923SNeil Armstrong sys_read(fd, buf, size); 127*f919b923SNeil Armstrong 128*f919b923SNeil Armstrong if (cramfsb->magic == CRAMFS_MAGIC) { 129*f919b923SNeil Armstrong printk(KERN_NOTICE 130*f919b923SNeil Armstrong "RAMDISK: cramfs filesystem found at block %d\n", 131*f919b923SNeil Armstrong start_block); 132*f919b923SNeil Armstrong nblocks = (cramfsb->size + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS; 133*f919b923SNeil Armstrong goto done; 134*f919b923SNeil Armstrong } 135*f919b923SNeil Armstrong 136*f919b923SNeil Armstrong /* 1371da177e4SLinus Torvalds * Read block 1 to test for minix and ext2 superblock 1381da177e4SLinus Torvalds */ 1391da177e4SLinus Torvalds sys_lseek(fd, (start_block+1) * BLOCK_SIZE, 0); 1401da177e4SLinus Torvalds sys_read(fd, buf, size); 1411da177e4SLinus Torvalds 1421da177e4SLinus Torvalds /* Try minix */ 1431da177e4SLinus Torvalds if (minixsb->s_magic == MINIX_SUPER_MAGIC || 1441da177e4SLinus Torvalds minixsb->s_magic == MINIX_SUPER_MAGIC2) { 1451da177e4SLinus Torvalds printk(KERN_NOTICE 1461da177e4SLinus Torvalds "RAMDISK: Minix filesystem found at block %d\n", 1471da177e4SLinus Torvalds start_block); 1481da177e4SLinus Torvalds nblocks = minixsb->s_nzones << minixsb->s_log_zone_size; 1491da177e4SLinus Torvalds goto done; 1501da177e4SLinus Torvalds } 1511da177e4SLinus Torvalds 1521da177e4SLinus Torvalds /* Try ext2 */ 1531da177e4SLinus Torvalds if (ext2sb->s_magic == cpu_to_le16(EXT2_SUPER_MAGIC)) { 1541da177e4SLinus Torvalds printk(KERN_NOTICE 1551da177e4SLinus Torvalds "RAMDISK: ext2 filesystem found at block %d\n", 1561da177e4SLinus Torvalds start_block); 1571da177e4SLinus Torvalds nblocks = le32_to_cpu(ext2sb->s_blocks_count) << 1581da177e4SLinus Torvalds le32_to_cpu(ext2sb->s_log_block_size); 1591da177e4SLinus Torvalds goto done; 1601da177e4SLinus Torvalds } 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds printk(KERN_NOTICE 1631da177e4SLinus Torvalds "RAMDISK: Couldn't find valid RAM disk image starting at %d.\n", 1641da177e4SLinus Torvalds start_block); 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds done: 1671da177e4SLinus Torvalds sys_lseek(fd, start_block * BLOCK_SIZE, 0); 1681da177e4SLinus Torvalds kfree(buf); 1691da177e4SLinus Torvalds return nblocks; 1701da177e4SLinus Torvalds } 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds int __init rd_load_image(char *from) 1731da177e4SLinus Torvalds { 1741da177e4SLinus Torvalds int res = 0; 1751da177e4SLinus Torvalds int in_fd, out_fd; 1761da177e4SLinus Torvalds unsigned long rd_blocks, devblocks; 1771da177e4SLinus Torvalds int nblocks, i, disk; 1781da177e4SLinus Torvalds char *buf = NULL; 1791da177e4SLinus Torvalds unsigned short rotate = 0; 18030d65dbfSAlain Knaff decompress_fn decompressor = NULL; 181347a8dc3SMartin Schwidefsky #if !defined(CONFIG_S390) && !defined(CONFIG_PPC_ISERIES) 1821da177e4SLinus Torvalds char rotator[4] = { '|' , '/' , '-' , '\\' }; 1831da177e4SLinus Torvalds #endif 1841da177e4SLinus Torvalds 185562f5e63SNamhyung Kim out_fd = sys_open((const char __user __force *) "/dev/ram", O_RDWR, 0); 1861da177e4SLinus Torvalds if (out_fd < 0) 1871da177e4SLinus Torvalds goto out; 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds in_fd = sys_open(from, O_RDONLY, 0); 1901da177e4SLinus Torvalds if (in_fd < 0) 1911da177e4SLinus Torvalds goto noclose_input; 1921da177e4SLinus Torvalds 19330d65dbfSAlain Knaff nblocks = identify_ramdisk_image(in_fd, rd_image_start, &decompressor); 1941da177e4SLinus Torvalds if (nblocks < 0) 1951da177e4SLinus Torvalds goto done; 1961da177e4SLinus Torvalds 1971da177e4SLinus Torvalds if (nblocks == 0) { 19830d65dbfSAlain Knaff if (crd_load(in_fd, out_fd, decompressor) == 0) 1991da177e4SLinus Torvalds goto successful_load; 2001da177e4SLinus Torvalds goto done; 2011da177e4SLinus Torvalds } 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds /* 2041da177e4SLinus Torvalds * NOTE NOTE: nblocks is not actually blocks but 2051da177e4SLinus Torvalds * the number of kibibytes of data to load into a ramdisk. 2061da177e4SLinus Torvalds * So any ramdisk block size that is a multiple of 1KiB should 2071da177e4SLinus Torvalds * work when the appropriate ramdisk_blocksize is specified 2081da177e4SLinus Torvalds * on the command line. 2091da177e4SLinus Torvalds * 2101da177e4SLinus Torvalds * The default ramdisk_blocksize is 1KiB and it is generally 2111da177e4SLinus Torvalds * silly to use anything else, so make sure to use 1KiB 2121da177e4SLinus Torvalds * blocksize while generating ext2fs ramdisk-images. 2131da177e4SLinus Torvalds */ 2141da177e4SLinus Torvalds if (sys_ioctl(out_fd, BLKGETSIZE, (unsigned long)&rd_blocks) < 0) 2151da177e4SLinus Torvalds rd_blocks = 0; 2161da177e4SLinus Torvalds else 2171da177e4SLinus Torvalds rd_blocks >>= 1; 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds if (nblocks > rd_blocks) { 2201da177e4SLinus Torvalds printk("RAMDISK: image too big! (%dKiB/%ldKiB)\n", 2211da177e4SLinus Torvalds nblocks, rd_blocks); 2221da177e4SLinus Torvalds goto done; 2231da177e4SLinus Torvalds } 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds /* 2261da177e4SLinus Torvalds * OK, time to copy in the data 2271da177e4SLinus Torvalds */ 2281da177e4SLinus Torvalds if (sys_ioctl(in_fd, BLKGETSIZE, (unsigned long)&devblocks) < 0) 2291da177e4SLinus Torvalds devblocks = 0; 2301da177e4SLinus Torvalds else 2311da177e4SLinus Torvalds devblocks >>= 1; 2321da177e4SLinus Torvalds 2331da177e4SLinus Torvalds if (strcmp(from, "/initrd.image") == 0) 2341da177e4SLinus Torvalds devblocks = nblocks; 2351da177e4SLinus Torvalds 2361da177e4SLinus Torvalds if (devblocks == 0) { 2371da177e4SLinus Torvalds printk(KERN_ERR "RAMDISK: could not determine device size\n"); 2381da177e4SLinus Torvalds goto done; 2391da177e4SLinus Torvalds } 2401da177e4SLinus Torvalds 2411da177e4SLinus Torvalds buf = kmalloc(BLOCK_SIZE, GFP_KERNEL); 242d613c3e2SHarvey Harrison if (!buf) { 2431da177e4SLinus Torvalds printk(KERN_ERR "RAMDISK: could not allocate buffer\n"); 2441da177e4SLinus Torvalds goto done; 2451da177e4SLinus Torvalds } 2461da177e4SLinus Torvalds 2471da177e4SLinus Torvalds printk(KERN_NOTICE "RAMDISK: Loading %dKiB [%ld disk%s] into ram disk... ", 2481da177e4SLinus Torvalds nblocks, ((nblocks-1)/devblocks)+1, nblocks>devblocks ? "s" : ""); 2491da177e4SLinus Torvalds for (i = 0, disk = 1; i < nblocks; i++) { 2501da177e4SLinus Torvalds if (i && (i % devblocks == 0)) { 2511da177e4SLinus Torvalds printk("done disk #%d.\n", disk++); 2521da177e4SLinus Torvalds rotate = 0; 2531da177e4SLinus Torvalds if (sys_close(in_fd)) { 2541da177e4SLinus Torvalds printk("Error closing the disk.\n"); 2551da177e4SLinus Torvalds goto noclose_input; 2561da177e4SLinus Torvalds } 2571da177e4SLinus Torvalds change_floppy("disk #%d", disk); 2581da177e4SLinus Torvalds in_fd = sys_open(from, O_RDONLY, 0); 2591da177e4SLinus Torvalds if (in_fd < 0) { 2601da177e4SLinus Torvalds printk("Error opening disk.\n"); 2611da177e4SLinus Torvalds goto noclose_input; 2621da177e4SLinus Torvalds } 2631da177e4SLinus Torvalds printk("Loading disk #%d... ", disk); 2641da177e4SLinus Torvalds } 2651da177e4SLinus Torvalds sys_read(in_fd, buf, BLOCK_SIZE); 2661da177e4SLinus Torvalds sys_write(out_fd, buf, BLOCK_SIZE); 267347a8dc3SMartin Schwidefsky #if !defined(CONFIG_S390) && !defined(CONFIG_PPC_ISERIES) 2681da177e4SLinus Torvalds if (!(i % 16)) { 2691da177e4SLinus Torvalds printk("%c\b", rotator[rotate & 0x3]); 2701da177e4SLinus Torvalds rotate++; 2711da177e4SLinus Torvalds } 2721da177e4SLinus Torvalds #endif 2731da177e4SLinus Torvalds } 2741da177e4SLinus Torvalds printk("done.\n"); 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds successful_load: 2771da177e4SLinus Torvalds res = 1; 2781da177e4SLinus Torvalds done: 2791da177e4SLinus Torvalds sys_close(in_fd); 2801da177e4SLinus Torvalds noclose_input: 2811da177e4SLinus Torvalds sys_close(out_fd); 2821da177e4SLinus Torvalds out: 2831da177e4SLinus Torvalds kfree(buf); 284562f5e63SNamhyung Kim sys_unlink((const char __user __force *) "/dev/ram"); 2851da177e4SLinus Torvalds return res; 2861da177e4SLinus Torvalds } 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds int __init rd_load_disk(int n) 2891da177e4SLinus Torvalds { 2901da177e4SLinus Torvalds if (rd_prompt) 2911da177e4SLinus Torvalds change_floppy("root floppy disk to be loaded into RAM disk"); 292bdaf8529SGreg Kroah-Hartman create_dev("/dev/root", ROOT_DEV); 293bdaf8529SGreg Kroah-Hartman create_dev("/dev/ram", MKDEV(RAMDISK_MAJOR, n)); 2941da177e4SLinus Torvalds return rd_load_image("/dev/root"); 2951da177e4SLinus Torvalds } 2961da177e4SLinus Torvalds 2971da177e4SLinus Torvalds static int exit_code; 29830d65dbfSAlain Knaff static int decompress_error; 2991da177e4SLinus Torvalds static int crd_infd, crd_outfd; 3001da177e4SLinus Torvalds 30130d65dbfSAlain Knaff static int __init compr_fill(void *buf, unsigned int len) 3021da177e4SLinus Torvalds { 30330d65dbfSAlain Knaff int r = sys_read(crd_infd, buf, len); 30430d65dbfSAlain Knaff if (r < 0) 30530d65dbfSAlain Knaff printk(KERN_ERR "RAMDISK: error while reading compressed data"); 30630d65dbfSAlain Knaff else if (r == 0) 30730d65dbfSAlain Knaff printk(KERN_ERR "RAMDISK: EOF while reading compressed data"); 30830d65dbfSAlain Knaff return r; 30930d65dbfSAlain Knaff } 3101da177e4SLinus Torvalds 31130d65dbfSAlain Knaff static int __init compr_flush(void *window, unsigned int outcnt) 31230d65dbfSAlain Knaff { 31330d65dbfSAlain Knaff int written = sys_write(crd_outfd, window, outcnt); 31430d65dbfSAlain Knaff if (written != outcnt) { 31530d65dbfSAlain Knaff if (decompress_error == 0) 31630d65dbfSAlain Knaff printk(KERN_ERR 31730d65dbfSAlain Knaff "RAMDISK: incomplete write (%d != %d)\n", 31830d65dbfSAlain Knaff written, outcnt); 31930d65dbfSAlain Knaff decompress_error = 1; 3201da177e4SLinus Torvalds return -1; 3211da177e4SLinus Torvalds } 32230d65dbfSAlain Knaff return outcnt; 3231da177e4SLinus Torvalds } 3241da177e4SLinus Torvalds 3251da177e4SLinus Torvalds static void __init error(char *x) 3261da177e4SLinus Torvalds { 3271da177e4SLinus Torvalds printk(KERN_ERR "%s\n", x); 3281da177e4SLinus Torvalds exit_code = 1; 32930d65dbfSAlain Knaff decompress_error = 1; 3301da177e4SLinus Torvalds } 3311da177e4SLinus Torvalds 33230d65dbfSAlain Knaff static int __init crd_load(int in_fd, int out_fd, decompress_fn deco) 3331da177e4SLinus Torvalds { 3341da177e4SLinus Torvalds int result; 3351da177e4SLinus Torvalds crd_infd = in_fd; 3361da177e4SLinus Torvalds crd_outfd = out_fd; 33730d65dbfSAlain Knaff result = deco(NULL, 0, compr_fill, compr_flush, NULL, NULL, error); 33830d65dbfSAlain Knaff if (decompress_error) 3391da177e4SLinus Torvalds result = 1; 3401da177e4SLinus Torvalds return result; 3411da177e4SLinus Torvalds } 342