blob: a06ed4f92e0eeef1551611944700bc700b042b01 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001
2#include <linux/kernel.h>
3#include <linux/fs.h>
4#include <linux/minix_fs.h>
5#include <linux/ext2_fs.h>
6#include <linux/romfs_fs.h>
7#include <linux/cramfs_fs.h>
8#include <linux/initrd.h>
9#include <linux/string.h>
10
11#include "do_mounts.h"
12
Alain Knaff30d65db2009-01-04 22:46:17 +010013#include <linux/decompress/generic.h>
14
Alain Knaff30d65db2009-01-04 22:46:17 +010015
Linus Torvalds1da177e2005-04-16 15:20:36 -070016int __initdata rd_prompt = 1;/* 1 = prompt for RAM disk, 0 = don't prompt */
17
18static int __init prompt_ramdisk(char *str)
19{
20 rd_prompt = simple_strtol(str,NULL,0) & 1;
21 return 1;
22}
23__setup("prompt_ramdisk=", prompt_ramdisk);
24
25int __initdata rd_image_start; /* starting block # of image */
26
27static int __init ramdisk_start_setup(char *str)
28{
29 rd_image_start = simple_strtol(str,NULL,0);
30 return 1;
31}
32__setup("ramdisk_start=", ramdisk_start_setup);
33
Alain Knaff30d65db2009-01-04 22:46:17 +010034static int __init crd_load(int in_fd, int out_fd, decompress_fn deco);
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
36/*
37 * This routine tries to find a RAM disk image to load, and returns the
38 * number of blocks to read for a non-compressed image, 0 if the image
39 * is a compressed image, and -1 if an image with the right magic
40 * numbers could not be found.
41 *
42 * We currently check for the following magic numbers:
H. Peter Anvinb172fd82009-01-04 14:42:52 -080043 * minix
44 * ext2
Linus Torvalds1da177e2005-04-16 15:20:36 -070045 * romfs
46 * cramfs
H. Peter Anvinb172fd82009-01-04 14:42:52 -080047 * gzip
Linus Torvalds1da177e2005-04-16 15:20:36 -070048 */
H. Peter Anvinb172fd82009-01-04 14:42:52 -080049static int __init
Alain Knaff30d65db2009-01-04 22:46:17 +010050identify_ramdisk_image(int fd, int start_block, decompress_fn *decompressor)
Linus Torvalds1da177e2005-04-16 15:20:36 -070051{
52 const int size = 512;
53 struct minix_super_block *minixsb;
54 struct ext2_super_block *ext2sb;
55 struct romfs_super_block *romfsb;
56 struct cramfs_super *cramfsb;
57 int nblocks = -1;
58 unsigned char *buf;
H. Peter Anvin889c92d2009-01-08 15:14:17 -080059 const char *compress_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
61 buf = kmalloc(size, GFP_KERNEL);
Stephen Hemmingerc80544d2007-10-18 03:07:05 -070062 if (!buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 return -1;
64
65 minixsb = (struct minix_super_block *) buf;
66 ext2sb = (struct ext2_super_block *) buf;
67 romfsb = (struct romfs_super_block *) buf;
68 cramfsb = (struct cramfs_super *) buf;
69 memset(buf, 0xe5, size);
70
71 /*
H. Peter Anvinb172fd82009-01-04 14:42:52 -080072 * Read block 0 to test for compressed kernel
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 */
74 sys_lseek(fd, start_block * BLOCK_SIZE, 0);
75 sys_read(fd, buf, size);
76
H. Peter Anvin889c92d2009-01-08 15:14:17 -080077 *decompressor = decompress_method(buf, size, &compress_name);
78 if (*decompressor) {
79 printk(KERN_NOTICE "RAMDISK: %s image found at block %d\n",
80 compress_name, start_block);
81 nblocks = 0;
82 goto done;
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 }
84
85 /* romfs is at block zero too */
86 if (romfsb->word0 == ROMSB_WORD0 &&
87 romfsb->word1 == ROMSB_WORD1) {
88 printk(KERN_NOTICE
89 "RAMDISK: romfs filesystem found at block %d\n",
90 start_block);
91 nblocks = (ntohl(romfsb->size)+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS;
92 goto done;
93 }
94
95 if (cramfsb->magic == CRAMFS_MAGIC) {
96 printk(KERN_NOTICE
97 "RAMDISK: cramfs filesystem found at block %d\n",
98 start_block);
99 nblocks = (cramfsb->size + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS;
100 goto done;
101 }
102
103 /*
104 * Read block 1 to test for minix and ext2 superblock
105 */
106 sys_lseek(fd, (start_block+1) * BLOCK_SIZE, 0);
107 sys_read(fd, buf, size);
108
109 /* Try minix */
110 if (minixsb->s_magic == MINIX_SUPER_MAGIC ||
111 minixsb->s_magic == MINIX_SUPER_MAGIC2) {
112 printk(KERN_NOTICE
113 "RAMDISK: Minix filesystem found at block %d\n",
114 start_block);
115 nblocks = minixsb->s_nzones << minixsb->s_log_zone_size;
116 goto done;
117 }
118
119 /* Try ext2 */
120 if (ext2sb->s_magic == cpu_to_le16(EXT2_SUPER_MAGIC)) {
121 printk(KERN_NOTICE
122 "RAMDISK: ext2 filesystem found at block %d\n",
123 start_block);
124 nblocks = le32_to_cpu(ext2sb->s_blocks_count) <<
125 le32_to_cpu(ext2sb->s_log_block_size);
126 goto done;
127 }
128
129 printk(KERN_NOTICE
130 "RAMDISK: Couldn't find valid RAM disk image starting at %d.\n",
131 start_block);
H. Peter Anvinb172fd82009-01-04 14:42:52 -0800132
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133done:
134 sys_lseek(fd, start_block * BLOCK_SIZE, 0);
135 kfree(buf);
136 return nblocks;
137}
138
139int __init rd_load_image(char *from)
140{
141 int res = 0;
142 int in_fd, out_fd;
143 unsigned long rd_blocks, devblocks;
144 int nblocks, i, disk;
145 char *buf = NULL;
146 unsigned short rotate = 0;
Alain Knaff30d65db2009-01-04 22:46:17 +0100147 decompress_fn decompressor = NULL;
Martin Schwidefsky347a8dc2006-01-06 00:19:28 -0800148#if !defined(CONFIG_S390) && !defined(CONFIG_PPC_ISERIES)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 char rotator[4] = { '|' , '/' , '-' , '\\' };
150#endif
151
152 out_fd = sys_open("/dev/ram", O_RDWR, 0);
153 if (out_fd < 0)
154 goto out;
155
156 in_fd = sys_open(from, O_RDONLY, 0);
157 if (in_fd < 0)
158 goto noclose_input;
159
Alain Knaff30d65db2009-01-04 22:46:17 +0100160 nblocks = identify_ramdisk_image(in_fd, rd_image_start, &decompressor);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 if (nblocks < 0)
162 goto done;
163
164 if (nblocks == 0) {
Alain Knaff30d65db2009-01-04 22:46:17 +0100165 if (crd_load(in_fd, out_fd, decompressor) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 goto successful_load;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 goto done;
168 }
169
170 /*
171 * NOTE NOTE: nblocks is not actually blocks but
172 * the number of kibibytes of data to load into a ramdisk.
173 * So any ramdisk block size that is a multiple of 1KiB should
174 * work when the appropriate ramdisk_blocksize is specified
175 * on the command line.
176 *
177 * The default ramdisk_blocksize is 1KiB and it is generally
178 * silly to use anything else, so make sure to use 1KiB
179 * blocksize while generating ext2fs ramdisk-images.
180 */
181 if (sys_ioctl(out_fd, BLKGETSIZE, (unsigned long)&rd_blocks) < 0)
182 rd_blocks = 0;
183 else
184 rd_blocks >>= 1;
185
186 if (nblocks > rd_blocks) {
187 printk("RAMDISK: image too big! (%dKiB/%ldKiB)\n",
188 nblocks, rd_blocks);
189 goto done;
190 }
H. Peter Anvinb172fd82009-01-04 14:42:52 -0800191
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 /*
193 * OK, time to copy in the data
194 */
195 if (sys_ioctl(in_fd, BLKGETSIZE, (unsigned long)&devblocks) < 0)
196 devblocks = 0;
197 else
198 devblocks >>= 1;
199
200 if (strcmp(from, "/initrd.image") == 0)
201 devblocks = nblocks;
202
203 if (devblocks == 0) {
204 printk(KERN_ERR "RAMDISK: could not determine device size\n");
205 goto done;
206 }
207
208 buf = kmalloc(BLOCK_SIZE, GFP_KERNEL);
Harvey Harrisond613c3e2008-04-28 14:13:14 -0700209 if (!buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 printk(KERN_ERR "RAMDISK: could not allocate buffer\n");
211 goto done;
212 }
213
214 printk(KERN_NOTICE "RAMDISK: Loading %dKiB [%ld disk%s] into ram disk... ",
215 nblocks, ((nblocks-1)/devblocks)+1, nblocks>devblocks ? "s" : "");
216 for (i = 0, disk = 1; i < nblocks; i++) {
217 if (i && (i % devblocks == 0)) {
218 printk("done disk #%d.\n", disk++);
219 rotate = 0;
220 if (sys_close(in_fd)) {
221 printk("Error closing the disk.\n");
222 goto noclose_input;
223 }
224 change_floppy("disk #%d", disk);
225 in_fd = sys_open(from, O_RDONLY, 0);
226 if (in_fd < 0) {
227 printk("Error opening disk.\n");
228 goto noclose_input;
229 }
230 printk("Loading disk #%d... ", disk);
231 }
232 sys_read(in_fd, buf, BLOCK_SIZE);
233 sys_write(out_fd, buf, BLOCK_SIZE);
Martin Schwidefsky347a8dc2006-01-06 00:19:28 -0800234#if !defined(CONFIG_S390) && !defined(CONFIG_PPC_ISERIES)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 if (!(i % 16)) {
236 printk("%c\b", rotator[rotate & 0x3]);
237 rotate++;
238 }
239#endif
240 }
241 printk("done.\n");
242
243successful_load:
244 res = 1;
245done:
246 sys_close(in_fd);
247noclose_input:
248 sys_close(out_fd);
249out:
250 kfree(buf);
251 sys_unlink("/dev/ram");
252 return res;
253}
254
255int __init rd_load_disk(int n)
256{
257 if (rd_prompt)
258 change_floppy("root floppy disk to be loaded into RAM disk");
Greg Kroah-Hartmanbdaf8522005-06-20 21:15:16 -0700259 create_dev("/dev/root", ROOT_DEV);
260 create_dev("/dev/ram", MKDEV(RAMDISK_MAJOR, n));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 return rd_load_image("/dev/root");
262}
263
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264static int exit_code;
Alain Knaff30d65db2009-01-04 22:46:17 +0100265static int decompress_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266static int crd_infd, crd_outfd;
267
Alain Knaff30d65db2009-01-04 22:46:17 +0100268static int __init compr_fill(void *buf, unsigned int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269{
Alain Knaff30d65db2009-01-04 22:46:17 +0100270 int r = sys_read(crd_infd, buf, len);
271 if (r < 0)
272 printk(KERN_ERR "RAMDISK: error while reading compressed data");
273 else if (r == 0)
274 printk(KERN_ERR "RAMDISK: EOF while reading compressed data");
275 return r;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276}
277
Alain Knaff30d65db2009-01-04 22:46:17 +0100278static int __init compr_flush(void *window, unsigned int outcnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279{
Alain Knaff30d65db2009-01-04 22:46:17 +0100280 int written = sys_write(crd_outfd, window, outcnt);
281 if (written != outcnt) {
282 if (decompress_error == 0)
283 printk(KERN_ERR
284 "RAMDISK: incomplete write (%d != %d)\n",
285 written, outcnt);
286 decompress_error = 1;
287 return -1;
288 }
289 return outcnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290}
291
292static void __init error(char *x)
293{
294 printk(KERN_ERR "%s\n", x);
295 exit_code = 1;
Alain Knaff30d65db2009-01-04 22:46:17 +0100296 decompress_error = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297}
298
Alain Knaff30d65db2009-01-04 22:46:17 +0100299static int __init crd_load(int in_fd, int out_fd, decompress_fn deco)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300{
301 int result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 crd_infd = in_fd;
303 crd_outfd = out_fd;
Alain Knaff30d65db2009-01-04 22:46:17 +0100304 result = deco(NULL, 0, compr_fill, compr_flush, NULL, NULL, error);
305 if (decompress_error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 result = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 return result;
308}