/* * linux/kernel/blk_drv/ramdisk.c * * Written by Theodore Ts'o, 12/2/91 * * Modifications by Fred N. van Kempen to allow for bootable root * disks (which are used in LINUX/Pro). Also some cleanups. 03/03/93 */ #include #include #include #include #include #include #include #include #include #define MAJOR_NR MEM_MAJOR #include "blk.h" #define RAMDISK_MINOR 1 extern void wait_for_keypress(void); char *rd_start; int rd_length = 0; static int rd_blocksizes[2] = {0, 0}; static void do_rd_request(void) { int len; char *addr; repeat: INIT_REQUEST; addr = rd_start + (CURRENT->sector << 9); len = CURRENT->current_nr_sectors << 9; if ((MINOR(CURRENT->dev) != RAMDISK_MINOR) || (addr+len > rd_start+rd_length)) { end_request(0); goto repeat; } if (CURRENT-> cmd == WRITE) { (void ) memcpy(addr, CURRENT->buffer, len); } else if (CURRENT->cmd == READ) { (void) memcpy(CURRENT->buffer, addr, len); } else panic("RAMDISK: unknown RAM disk command !\n"); end_request(1); goto repeat; } static struct file_operations rd_fops = { NULL, /* lseek - default */ block_read, /* read - general block-dev read */ block_write, /* write - general block-dev write */ NULL, /* readdir - bad */ NULL, /* select */ NULL, /* ioctl */ NULL, /* mmap */ NULL, /* no special open code */ NULL, /* no special release code */ block_fsync /* fsync */ }; /* * Returns amount of memory which needs to be reserved. */ long rd_init(long mem_start, int length) { int i; char *cp; if (register_blkdev(MEM_MAJOR,"rd",&rd_fops)) { printk("RAMDISK: Unable to get major %d.\n", MEM_MAJOR); return 0; } blk_dev[MEM_MAJOR].request_fn = DEVICE_REQUEST; rd_start = (char *) mem_start; rd_length = length; cp = rd_start; for (i=0; i < length; i++) *cp++ = '\0'; for(i=0;i<2;i++) rd_blocksizes[i] = 1024; blksize_size[MAJOR_NR] = rd_blocksizes; return(length); } static void do_load(void) { struct buffer_head *bh; struct super_block { union { char minix [sizeof (struct minix_super_block)]; char ext2 [sizeof (struct ext2_super_block)]; } record; } sb; struct minix_super_block *minixsb = (struct minix_super_block *)&sb; struct ext2_super_block *ext2sb = (struct ext2_super_block *)&sb; int block, tries; int i = 1; int nblocks; char *cp; /* * Check for a super block on the diskette. * The old-style boot/root diskettes had their RAM image * starting at block 512 of the boot diskette. LINUX/Pro * uses the entire diskette as a file system, so in that * case, we have to look at block 0. Be intelligent about * this, and check both... - FvK */ for (tries = 0; tries < 1000; tries += 512) { block = tries; bh = breada(ROOT_DEV,block+1,BLOCK_SIZE, 0, PAGE_SIZE); if (!bh) { printk("RAMDISK: I/O error while looking for super block!\n"); return; } /* This is silly- why do we require it to be a MINIX FS? */ *((struct super_block *) &sb) = *((struct super_block *) bh->b_data); brelse(bh); /* Try Minix */ nblocks = -1; if (minixsb->s_magic == MINIX_SUPER_MAGIC || minixsb->s_magic == MINIX_SUPER_MAGIC2) { printk("RAMDISK: Minix filesystem found at block %d\n", block); nblocks = minixsb->s_nzones << minixsb->s_log_zone_size; } /* Try ext2 */ if (nblocks == -1 && (ext2sb->s_magic == EXT2_PRE_02B_MAGIC || ext2sb->s_magic == EXT2_SUPER_MAGIC)) { printk("RAMDISK: Ext2 filesystem found at block %d\n", block); nblocks = ext2sb->s_blocks_count; } if (nblocks == -1) { printk("RAMDISK: trying old-style RAM image.\n"); continue; } if (nblocks > (rd_length >> BLOCK_SIZE_BITS)) { printk("RAMDISK: image too big! (%d/%d blocks)\n", nblocks, rd_length >> BLOCK_SIZE_BITS); return; } printk("RAMDISK: Loading %d blocks into RAM disk", nblocks); /* We found an image file system. Load it into core! */ cp = rd_start; while (nblocks) { if (nblocks > 2) bh = breada(ROOT_DEV, block, BLOCK_SIZE, 0, PAGE_SIZE); else bh = bread(ROOT_DEV, block, BLOCK_SIZE); if (!bh) { printk("RAMDISK: I/O error on block %d, aborting!\n", block); return; } (void) memcpy(cp, bh->b_data, BLOCK_SIZE); brelse(bh); if (!(nblocks-- & 15)) printk("."); cp += BLOCK_SIZE; block++; i++; } printk("\ndone\n"); /* We loaded the file system image. Prepare for mounting it. */ ROOT_DEV = ((MEM_MAJOR << 8) | RAMDISK_MINOR); return; } } /* * If the root device is the RAM disk, try to load it. * In order to do this, the root device is originally set to the * floppy, and we later change it to be RAM disk. */ void rd_load(void) { struct inode inode; struct file filp; /* If no RAM disk specified, give up early. */ if (!rd_length) return; printk("RAMDISK: %d bytes, starting at 0x%p\n", rd_length, rd_start); /* If we are doing a diskette boot, we might have to pre-load it. */ if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR) return; /* for Slackware install disks */ printk(KERN_NOTICE "VFS: Insert ramdisk floppy and press ENTER\n"); wait_for_keypress(); memset(&filp, 0, sizeof(filp)); memset(&inode, 0, sizeof(inode)); inode.i_rdev = ROOT_DEV; filp.f_mode = 1; /* read only */ filp.f_inode = &inode; if(blkdev_open(&inode, &filp) == 0 ){ do_load(); if(filp.f_op && filp.f_op->release) filp.f_op->release(&inode,&filp); } }