1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #include <linux/unistd.h>
3*4882a593Smuzhiyun #include <linux/kernel.h>
4*4882a593Smuzhiyun #include <linux/fs.h>
5*4882a593Smuzhiyun #include <linux/minix_fs.h>
6*4882a593Smuzhiyun #include <linux/romfs_fs.h>
7*4882a593Smuzhiyun #include <linux/initrd.h>
8*4882a593Smuzhiyun #include <linux/sched.h>
9*4882a593Smuzhiyun #include <linux/freezer.h>
10*4882a593Smuzhiyun #include <linux/kmod.h>
11*4882a593Smuzhiyun #include <uapi/linux/mount.h>
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include "do_mounts.h"
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun unsigned long initrd_start, initrd_end;
16*4882a593Smuzhiyun int initrd_below_start_ok;
17*4882a593Smuzhiyun unsigned int real_root_dev; /* do_proc_dointvec cannot handle kdev_t */
18*4882a593Smuzhiyun static int __initdata mount_initrd = 1;
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun phys_addr_t phys_initrd_start __initdata;
21*4882a593Smuzhiyun unsigned long phys_initrd_size __initdata;
22*4882a593Smuzhiyun
no_initrd(char * str)23*4882a593Smuzhiyun static int __init no_initrd(char *str)
24*4882a593Smuzhiyun {
25*4882a593Smuzhiyun mount_initrd = 0;
26*4882a593Smuzhiyun return 1;
27*4882a593Smuzhiyun }
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun __setup("noinitrd", no_initrd);
30*4882a593Smuzhiyun
early_initrdmem(char * p)31*4882a593Smuzhiyun static int __init early_initrdmem(char *p)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun phys_addr_t start;
34*4882a593Smuzhiyun unsigned long size;
35*4882a593Smuzhiyun char *endp;
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun start = memparse(p, &endp);
38*4882a593Smuzhiyun if (*endp == ',') {
39*4882a593Smuzhiyun size = memparse(endp + 1, NULL);
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun phys_initrd_start = start;
42*4882a593Smuzhiyun phys_initrd_size = size;
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun return 0;
45*4882a593Smuzhiyun }
46*4882a593Smuzhiyun early_param("initrdmem", early_initrdmem);
47*4882a593Smuzhiyun
early_initrd(char * p)48*4882a593Smuzhiyun static int __init early_initrd(char *p)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun return early_initrdmem(p);
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun early_param("initrd", early_initrd);
53*4882a593Smuzhiyun
init_linuxrc(struct subprocess_info * info,struct cred * new)54*4882a593Smuzhiyun static int __init init_linuxrc(struct subprocess_info *info, struct cred *new)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun ksys_unshare(CLONE_FS | CLONE_FILES);
57*4882a593Smuzhiyun console_on_rootfs();
58*4882a593Smuzhiyun /* move initrd over / and chdir/chroot in initrd root */
59*4882a593Smuzhiyun init_chdir("/root");
60*4882a593Smuzhiyun init_mount(".", "/", NULL, MS_MOVE, NULL);
61*4882a593Smuzhiyun init_chroot(".");
62*4882a593Smuzhiyun ksys_setsid();
63*4882a593Smuzhiyun return 0;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun
handle_initrd(void)66*4882a593Smuzhiyun static void __init handle_initrd(void)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun struct subprocess_info *info;
69*4882a593Smuzhiyun static char *argv[] = { "linuxrc", NULL, };
70*4882a593Smuzhiyun extern char *envp_init[];
71*4882a593Smuzhiyun int error;
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun pr_warn("using deprecated initrd support, will be removed in 2021.\n");
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun real_root_dev = new_encode_dev(ROOT_DEV);
76*4882a593Smuzhiyun create_dev("/dev/root.old", Root_RAM0);
77*4882a593Smuzhiyun /* mount initrd on rootfs' /root */
78*4882a593Smuzhiyun mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY);
79*4882a593Smuzhiyun init_mkdir("/old", 0700);
80*4882a593Smuzhiyun init_chdir("/old");
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun /*
83*4882a593Smuzhiyun * In case that a resume from disk is carried out by linuxrc or one of
84*4882a593Smuzhiyun * its children, we need to tell the freezer not to wait for us.
85*4882a593Smuzhiyun */
86*4882a593Smuzhiyun current->flags |= PF_FREEZER_SKIP;
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun info = call_usermodehelper_setup("/linuxrc", argv, envp_init,
89*4882a593Smuzhiyun GFP_KERNEL, init_linuxrc, NULL, NULL);
90*4882a593Smuzhiyun if (!info)
91*4882a593Smuzhiyun return;
92*4882a593Smuzhiyun call_usermodehelper_exec(info, UMH_WAIT_PROC);
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun current->flags &= ~PF_FREEZER_SKIP;
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun /* move initrd to rootfs' /old */
97*4882a593Smuzhiyun init_mount("..", ".", NULL, MS_MOVE, NULL);
98*4882a593Smuzhiyun /* switch root and cwd back to / of rootfs */
99*4882a593Smuzhiyun init_chroot("..");
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun if (new_decode_dev(real_root_dev) == Root_RAM0) {
102*4882a593Smuzhiyun init_chdir("/old");
103*4882a593Smuzhiyun return;
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun init_chdir("/");
107*4882a593Smuzhiyun ROOT_DEV = new_decode_dev(real_root_dev);
108*4882a593Smuzhiyun mount_root();
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun printk(KERN_NOTICE "Trying to move old root to /initrd ... ");
111*4882a593Smuzhiyun error = init_mount("/old", "/root/initrd", NULL, MS_MOVE, NULL);
112*4882a593Smuzhiyun if (!error)
113*4882a593Smuzhiyun printk("okay\n");
114*4882a593Smuzhiyun else {
115*4882a593Smuzhiyun if (error == -ENOENT)
116*4882a593Smuzhiyun printk("/initrd does not exist. Ignored.\n");
117*4882a593Smuzhiyun else
118*4882a593Smuzhiyun printk("failed\n");
119*4882a593Smuzhiyun printk(KERN_NOTICE "Unmounting old root\n");
120*4882a593Smuzhiyun init_umount("/old", MNT_DETACH);
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun
initrd_load(void)124*4882a593Smuzhiyun bool __init initrd_load(void)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun if (mount_initrd) {
127*4882a593Smuzhiyun create_dev("/dev/ram", Root_RAM0);
128*4882a593Smuzhiyun /*
129*4882a593Smuzhiyun * Load the initrd data into /dev/ram0. Execute it as initrd
130*4882a593Smuzhiyun * unless /dev/ram0 is supposed to be our actual root device,
131*4882a593Smuzhiyun * in that case the ram disk is just set up here, and gets
132*4882a593Smuzhiyun * mounted in the normal path.
133*4882a593Smuzhiyun */
134*4882a593Smuzhiyun if (rd_load_image("/initrd.image") && ROOT_DEV != Root_RAM0) {
135*4882a593Smuzhiyun init_unlink("/initrd.image");
136*4882a593Smuzhiyun handle_initrd();
137*4882a593Smuzhiyun return true;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun init_unlink("/initrd.image");
141*4882a593Smuzhiyun return false;
142*4882a593Smuzhiyun }
143