1/* Modified by Broadcom Corp. Portions Copyright (c) Broadcom Corp, 2012. */ 2#include <linux/module.h> 3#include <linux/sched.h> 4#include <linux/ctype.h> 5#include <linux/fd.h> 6#include <linux/tty.h> 7#include <linux/suspend.h> 8#include <linux/root_dev.h> 9#include <linux/security.h> 10#include <linux/delay.h> 11#include <linux/genhd.h> 12#include <linux/mount.h> 13#include <linux/device.h> 14#include <linux/init.h> 15#include <linux/fs.h> 16#include <linux/initrd.h> 17#include <linux/async.h> 18#include <linux/fs_struct.h> 19#include <linux/slab.h> 20 21#include <linux/nfs_fs.h> 22#include <linux/nfs_fs_sb.h> 23#include <linux/nfs_mount.h> 24 25#include "do_mounts.h" 26 27int __initdata rd_doload; /* 1 = load RAM disk, 0 = don't load */ 28 29int root_mountflags = MS_RDONLY | MS_SILENT; 30static char * __initdata root_device_name; 31#ifdef CONFIG_BCM47XX 32char __initdata saved_root_name[64]; 33#else 34static char __initdata saved_root_name[64]; 35#endif 36static int __initdata root_wait; 37 38dev_t ROOT_DEV; 39 40static int __init load_ramdisk(char *str) 41{ 42 rd_doload = simple_strtol(str,NULL,0) & 3; 43 return 1; 44} 45__setup("load_ramdisk=", load_ramdisk); 46 47static int __init readonly(char *str) 48{ 49 if (*str) 50 return 0; 51 root_mountflags |= MS_RDONLY; 52 return 1; 53} 54 55static int __init readwrite(char *str) 56{ 57 if (*str) 58 return 0; 59 root_mountflags &= ~MS_RDONLY; 60 return 1; 61} 62 63__setup("ro", readonly); 64__setup("rw", readwrite); 65 66/* 67 * Convert a name into device number. We accept the following variants: 68 * 69 * 1) device number in hexadecimal represents itself 70 * 2) /dev/nfs represents Root_NFS (0xff) 71 * 3) /dev/<disk_name> represents the device number of disk 72 * 4) /dev/<disk_name><decimal> represents the device number 73 * of partition - device number of disk plus the partition number 74 * 5) /dev/<disk_name>p<decimal> - same as the above, that form is 75 * used when disk name of partitioned disk ends on a digit. 76 * 77 * If name doesn't have fall into the categories above, we return (0,0). 78 * block_class is used to check if something is a disk name. If the disk 79 * name contains slashes, the device name has them replaced with 80 * bangs. 81 */ 82 83dev_t name_to_dev_t(char *name) 84{ 85 char s[32]; 86 char *p; 87 dev_t res = 0; 88 int part; 89 90 if (strncmp(name, "/dev/", 5) != 0) { 91 unsigned maj, min; 92 93 if (sscanf(name, "%u:%u", &maj, &min) == 2) { 94 res = MKDEV(maj, min); 95 if (maj != MAJOR(res) || min != MINOR(res)) 96 goto fail; 97 } else { 98 res = new_decode_dev(simple_strtoul(name, &p, 16)); 99 if (*p) 100 goto fail; 101 } 102 goto done; 103 } 104 105 name += 5; 106 res = Root_NFS; 107 if (strcmp(name, "nfs") == 0) 108 goto done; 109 res = Root_RAM0; 110 if (strcmp(name, "ram") == 0) 111 goto done; 112 113 if (strlen(name) > 31) 114 goto fail; 115 strcpy(s, name); 116 for (p = s; *p; p++) 117 if (*p == '/') 118 *p = '!'; 119 res = blk_lookup_devt(s, 0); 120 if (res) 121 goto done; 122 123 /* 124 * try non-existant, but valid partition, which may only exist 125 * after revalidating the disk, like partitioned md devices 126 */ 127 while (p > s && isdigit(p[-1])) 128 p--; 129 if (p == s || !*p || *p == '0') 130 goto fail; 131 132 /* try disk name without <part number> */ 133 part = simple_strtoul(p, NULL, 10); 134 *p = '\0'; 135 res = blk_lookup_devt(s, part); 136 if (res) 137 goto done; 138 139 /* try disk name without p<part number> */ 140 if (p < s + 2 || !isdigit(p[-2]) || p[-1] != 'p') 141 goto fail; 142 p[-1] = '\0'; 143 res = blk_lookup_devt(s, part); 144 if (res) 145 goto done; 146 147fail: 148 return 0; 149done: 150 return res; 151} 152 153static int __init root_dev_setup(char *line) 154{ 155 strlcpy(saved_root_name, line, sizeof(saved_root_name)); 156 return 1; 157} 158 159__setup("root=", root_dev_setup); 160 161static int __init rootwait_setup(char *str) 162{ 163 if (*str) 164 return 0; 165 root_wait = 1; 166 return 1; 167} 168 169__setup("rootwait", rootwait_setup); 170 171static char * __initdata root_mount_data; 172static int __init root_data_setup(char *str) 173{ 174 root_mount_data = str; 175 return 1; 176} 177 178static char * __initdata root_fs_names; 179static int __init fs_names_setup(char *str) 180{ 181 root_fs_names = str; 182 return 1; 183} 184 185static unsigned int __initdata root_delay; 186static int __init root_delay_setup(char *str) 187{ 188 root_delay = simple_strtoul(str, NULL, 0); 189 return 1; 190} 191 192__setup("rootflags=", root_data_setup); 193__setup("rootfstype=", fs_names_setup); 194__setup("rootdelay=", root_delay_setup); 195 196static void __init get_fs_names(char *page) 197{ 198 char *s = page; 199 200 if (root_fs_names) { 201 strcpy(page, root_fs_names); 202 while (*s++) { 203 if (s[-1] == ',') 204 s[-1] = '\0'; 205 } 206 } else { 207 int len = get_filesystem_list(page); 208 char *p, *next; 209 210 page[len] = '\0'; 211 for (p = page-1; p; p = next) { 212 next = strchr(++p, '\n'); 213 if (*p++ != '\t') 214 continue; 215 while ((*s++ = *p++) != '\n') 216 ; 217 s[-1] = '\0'; 218 } 219 } 220 *s = '\0'; 221} 222 223static int __init do_mount_root(char *name, char *fs, int flags, void *data) 224{ 225 int err = sys_mount(name, "/root", fs, flags, data); 226 if (err) 227 return err; 228 229 sys_chdir("/root"); 230 ROOT_DEV = current->fs->pwd.mnt->mnt_sb->s_dev; 231 printk("VFS: Mounted root (%s filesystem)%s on device %u:%u.\n", 232 current->fs->pwd.mnt->mnt_sb->s_type->name, 233 current->fs->pwd.mnt->mnt_sb->s_flags & MS_RDONLY ? 234 " readonly" : "", MAJOR(ROOT_DEV), MINOR(ROOT_DEV)); 235 return 0; 236} 237 238void __init mount_block_root(char *name, int flags) 239{ 240 char *fs_names = __getname_gfp(GFP_KERNEL 241 | __GFP_NOTRACK_FALSE_POSITIVE); 242 char *p; 243#ifdef CONFIG_BLOCK 244 char b[BDEVNAME_SIZE]; 245#else 246 const char *b = name; 247#endif 248 249 get_fs_names(fs_names); 250retry: 251 for (p = fs_names; *p; p += strlen(p)+1) { 252 int err = do_mount_root(name, p, flags, root_mount_data); 253 switch (err) { 254 case 0: 255 goto out; 256 case -EACCES: 257 flags |= MS_RDONLY; 258 goto retry; 259 case -EINVAL: 260 continue; 261 } 262 /* 263 * Allow the user to distinguish between failed sys_open 264 * and bad superblock on root device. 265 * and give them a list of the available devices 266 */ 267#ifdef CONFIG_BLOCK 268 __bdevname(ROOT_DEV, b); 269#endif 270 printk("VFS: Cannot open root device \"%s\" or %s\n", 271 root_device_name, b); 272 printk("Please append a correct \"root=\" boot option; here are the available partitions:\n"); 273 274 printk_all_partitions(); 275#ifdef CONFIG_DEBUG_BLOCK_EXT_DEVT 276 printk("DEBUG_BLOCK_EXT_DEVT is enabled, you need to specify " 277 "explicit textual name for \"root=\" boot option.\n"); 278#endif 279 panic("VFS: Unable to mount root fs on %s", b); 280 } 281 282 printk("List of all partitions:\n"); 283 printk_all_partitions(); 284 printk("No filesystem could mount root, tried: "); 285 for (p = fs_names; *p; p += strlen(p)+1) 286 printk(" %s", p); 287 printk("\n"); 288#ifdef CONFIG_BLOCK 289 __bdevname(ROOT_DEV, b); 290#endif 291 panic("VFS: Unable to mount root fs on %s", b); 292out: 293 putname(fs_names); 294} 295 296#ifdef CONFIG_ROOT_NFS 297static int __init mount_nfs_root(void) 298{ 299 void *data = nfs_root_data(); 300 301 create_dev("/dev/root", ROOT_DEV); 302 if (data && 303 do_mount_root("/dev/root", "nfs", root_mountflags, data) == 0) 304 return 1; 305 return 0; 306} 307#endif 308 309#if defined(CONFIG_BLK_DEV_RAM) || defined(CONFIG_BLK_DEV_FD) 310void __init change_floppy(char *fmt, ...) 311{ 312 struct termios termios; 313 char buf[80]; 314 char c; 315 int fd; 316 va_list args; 317 va_start(args, fmt); 318 vsprintf(buf, fmt, args); 319 va_end(args); 320 fd = sys_open("/dev/root", O_RDWR | O_NDELAY, 0); 321 if (fd >= 0) { 322 sys_ioctl(fd, FDEJECT, 0); 323 sys_close(fd); 324 } 325 printk(KERN_NOTICE "VFS: Insert %s and press ENTER\n", buf); 326 fd = sys_open("/dev/console", O_RDWR, 0); 327 if (fd >= 0) { 328 sys_ioctl(fd, TCGETS, (long)&termios); 329 termios.c_lflag &= ~ICANON; 330 sys_ioctl(fd, TCSETSF, (long)&termios); 331 sys_read(fd, &c, 1); 332 termios.c_lflag |= ICANON; 333 sys_ioctl(fd, TCSETSF, (long)&termios); 334 sys_close(fd); 335 } 336} 337#endif 338 339void __init mount_root(void) 340{ 341#ifdef CONFIG_ROOT_NFS 342 if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) { 343 if (mount_nfs_root()) 344 return; 345 346 printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n"); 347 ROOT_DEV = Root_FD0; 348 } 349#endif 350#ifdef CONFIG_BLK_DEV_FD 351 if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) { 352 /* rd_doload is 2 for a dual initrd/ramload setup */ 353 if (rd_doload==2) { 354 if (rd_load_disk(1)) { 355 ROOT_DEV = Root_RAM1; 356 root_device_name = NULL; 357 } 358 } else 359 change_floppy("root floppy"); 360 } 361#endif 362#ifdef CONFIG_BLOCK 363 create_dev("/dev/root", ROOT_DEV); 364 mount_block_root("/dev/root", root_mountflags); 365#endif 366} 367 368/* 369 * Prepare the namespace - decide what/where to mount, load ramdisks, etc. 370 */ 371void __init prepare_namespace(void) 372{ 373 int is_floppy; 374 375 if (root_delay) { 376 printk(KERN_INFO "Waiting %dsec before mounting root device...\n", 377 root_delay); 378 ssleep(root_delay); 379 } 380 381 /* 382 * wait for the known devices to complete their probing 383 * 384 * Note: this is a potential source of long boot delays. 385 * For example, it is not atypical to wait 5 seconds here 386 * for the touchpad of a laptop to initialize. 387 */ 388 wait_for_device_probe(); 389 390 md_run_setup(); 391 392 if (saved_root_name[0]) { 393 root_device_name = saved_root_name; 394 if (!strncmp(root_device_name, "mtd", 3) || 395 !strncmp(root_device_name, "ubi", 3)) { 396 mount_block_root(root_device_name, root_mountflags); 397 goto out; 398 } 399 ROOT_DEV = name_to_dev_t(root_device_name); 400 if (strncmp(root_device_name, "/dev/", 5) == 0) 401 root_device_name += 5; 402 } 403 404 if (initrd_load()) 405 goto out; 406 407 /* wait for any asynchronous scanning to complete */ 408 if ((ROOT_DEV == 0) && root_wait) { 409 printk(KERN_INFO "Waiting for root device %s...\n", 410 saved_root_name); 411 while (driver_probe_done() != 0 || 412 (ROOT_DEV = name_to_dev_t(saved_root_name)) == 0) 413 msleep(100); 414 async_synchronize_full(); 415 } 416 417 is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR; 418 419 if (is_floppy && rd_doload && rd_load_disk(0)) 420 ROOT_DEV = Root_RAM0; 421 422 mount_root(); 423out: 424 devtmpfs_mount("dev"); 425 sys_mount(".", "/", NULL, MS_MOVE, NULL); 426 sys_chroot("."); 427} 428