Updated hint
[linux_from_scratch_hints.git] / initramfs.txt
bloba873f20211cb7bddab643b3509a1049becb66834
1 AUTHOR:   Bryan Kadzban <bryan_at_kadzban.is-a-geek.net)
3 DATE:     2005-11-25
5 LICENSE:  Creative Commons Attribution-ShareAlike License, version 2.5
6           (http://creativecommons.org/licenses/by-sa/2.5/)
8 SYNOPSIS: Build a very basic initramfs that creates, then mounts, then
9           runs /sbin/init on, the real root FS device.
11 DESCRIPTION:
13 This hint will guide you through the process used to build an initramfs.
14 The resulting initramfs will be fairly simple, only able to create the
15 device node for the root FS, figure out its filesystem (within limits),
16 mount it, then boot to it.
18 ATTACHMENTS:
20 http://www.linuxfromscratch.org/hints/downloads/attachments/initramfs/initramfs-scripts.tar.gz
22 PREREQUISITES:
24 An LFS system, using kernel 2.6 (preferably the latest stable version) and
25 any version of lfs-bootscripts whose mountkernfs script can handle /proc
26 being mounted when it runs.  (If your mountkernfs script runs "mountpoint
27 /proc", then it's probably OK.)
29 Also make sure you read Appendix B (possible gotchas)!  You may have to
30 modify the /init script on your own.
32 HINT:
34 =============================
35 Contents:
36 =============================
38 1-8.  Initramfs build instructions
40 Appendices:
42 A.    Possible enhancements
43 B.    Possible gotchas
45 =============================
46 Initramfs build instructions
47 =============================
50 1.  Install LFS, by the book all the way through.  Make sure you have a
51 working kernel configuration (i.e., make sure you can boot to it), so that
52 if the initramfs fails, you'll still have a fallback.
55 2.  Export some variables to be used later (you may change the first path
56 at will):
58 export INITRAMFS=~/initramfs
59 export SCRIPTS=$INITRAMFS/scripts
61 If you ever exit the shell that you're using to do these instructions, you
62 MUST reset these variables before resuming the instructions.
64 Now create the directories required (there's no need to make $SCRIPTS,
65 because the initramfs-scripts tarball will create it):
67 mkdir -p $INITRAMFS
70 3.  Download klibc from http://www.kernel.org/pub/linux/libs/klibc/, and
71 extract it into $INITRAMFS.  (The latest version at the time of this
72 writing is v1.1.1.)  Then:
74 cd $INITRAMFS/klibc-1.1.1
75 ln -s /usr/src/linux-2.6.14 linux
76 # (substitute the correct path to your LFS kernel's source tree)
77 make SUBDIRS=utils
79 This will build several tools in $INITRAMFS/klibc-1.1.1/utils/static/,
80 which will be used by the /init script below to mount filesystems, find
81 the filesystem type of the root FS, and nuke-initramfs-then-run-the-
82 final-init.  (The last task is carried out by one utility, run-init.)
84 These tools can be run on any kernel whose version is greater than or
85 equal to the version of the kernel that you build them against.  (In this
86 example, they may not work under kernels earlier than 2.6.14, since the
87 symlink pointed at 2.6.14 when they were built.  Later kernels will
88 include backward-compatibility code to keep them working, but earlier
89 kernels will not necessarily be forward-compatible.)
92 4.  Extract the initramfs-scripts.tar.gz tarball from inside the $INITRAMFS
93 directory.  This will create the scripts (NOTE: not initramfs-scripts!)
94 subdirectory, and extract this hint's init and initramfs-list files into
95 it.
97 We must modify the initramfs-list, so that it has the correct directories
98 in it.  The kernel's build process (which interprets this file) does not
99 substitute shell variables, so we must do this manually:
101 sed -e "s@\$SCRIPTS@$SCRIPTS@g" -e "s@\$INITRAMFS@$INITRAMFS@g" \
102     <$SCRIPTS/initramfs-list-with-vars >$SCRIPTS/initramfs-list
104 This will replace all occurrences of $SCRIPTS and $INITRAMFS in the file
105 with the current values of the corresponding shell variables.  Make SURE
106 you don't miss the backslash escape character before the first $ in each
107 sed script!
110 If you feel the need to modify the init script, you should know a few
111 things about it.  First, it gets run under bash, so you can use *almost*
112 any construct that bash provides.  Second, we will not be copying glibc's
113 NSS libraries, so anything that requires NSS will fail.  (Name lookups
114 are one thing that require NSS; this is why not everything bash is capable
115 of will work.  For instance, the fake /dev/tcp/www.kernel.org/80 "file"
116 that bash provides won't actually work, because bash can't look up
117 www.kernel.org.)  Third, the last line of the script must *exec* run-init.
118 You can't just run run-init without the exec statement, because if you do,
119 your final system's /sbin/init won't work properly.  (/sbin/init from the
120 sysvinit package needs to have PID 1, otherwise it acts like /sbin/telinit,
121 and tries to signal PID 1 to change runlevels.  This obviously won't work
122 unless PID 1 is also /sbin/init.  If you don't exec the run-init utility,
123 it won't have PID 1, so when it exec's /sbin/init, it won't work right.)
125 Other than that, this script can do anything you want.  For this hint, it
126 just does what I consider the bare minimum (create the root block device,
127 mount it, then change over to it and run the final system's /sbin/init).
130 If you need to modify the initramfs-list file, the syntax should be fairly
131 obvious.  But run "usr/gen_init_cpio --help" from the base of your kernel
132 tree to see the full syntax.  Note that if you create any other directories
133 to put files into, you have to list the directory before you list the
134 file(s) that go into it.
137 This will create about a 1-2 megabyte initramfs; this is definitely small
138 enough to fit in even the most RAM-strapped machine's memory at startup.
139 And it deletes everything from the initramfs just before running the final
140 system's /sbin/init, so it won't take any more memory while your system
141 is running, either.
144 5.  Change the kernel's version string, so you won't overwrite your old
145 kernel's modules (if you configured a modular kernel).  The easiest way
146 to do this is to edit the kernel's top-level Makefile, and change the
147 EXTRAVERSION variable at the top.  Adding "-initramfs" to the end would
148 be sufficient, but you can make any change you wish.
151 6.  Build and install the "new" kernel version.  Make sure you set
152 CONFIG_INITRAMFS_SOURCE (in menuconfig, it's under "General setup") to
153 $SCRIPTS/initramfs-list during the kernel configuration.  (You will need
154 to manually expand the $SCRIPTS variable -- the kernel will not do it for
155 you.)  DO NOT move the initramfs-list file without updating the kernel
156 configuration, and DO NOT move any files referred to by the initramfs-list
157 file without updating it!  Files referred to by initramfs-list can be
158 upgraded at will (and the next time initramfs-list is touched, the kernel
159 will rebuild the whole initramfs, including the new versions), but not
160 moved.
162 The kernel's build process will inspect the file that INITRAMFS_SOURCE
163 points to, and build an initramfs using the files, directories, and
164 devices described in the file.  (You could also use a directory, and the
165 build will create an initramfs from all the files in that directory.
166 But I think using a file is simpler, and as above, just touching that
167 file and rebuilding the kernel is enough to get upgrades to take effect.
168 Also, I'm not sure whether using a directory requires the "cpio" tool to
169 be installed; this method definitely does not.)
172 7.  Create a grub menu.lst entry for your initramfs kernel.  *DO NOT*
173 overwrite a kernel you already have installed, just in case the initramfs
174 doesn't work -- then you'll have a backup way to get a usable system, and
175 you will be able to fix the initramfs from there.  It's probably a good
176 idea to always keep a kernel around that's not based on an initramfs, just
177 in case.
179 You don't have to pass any special parameters to the kernel to tell it to
180 use the initramfs you just built (this is different from an initrd) -- the
181 kernel will extract the initramfs image automatically, then check whether
182 there's an /init file.  If so, it will try to run it; if not, it will boot
183 like normal.  (This also means there's no way to disable the initramfs.)
186 8.  Boot to the new kernel.  If you see the LFS bootscripts running, then
187 the initramfs worked.  If you get an error before the bootscripts start,
188 then you will have to investigate what's wrong in the initramfs -- probably
189 the easiest way is to change the init script and add a "/bin/bash" line
190 just before the point where the error happens.  (Some echos won't hurt,
191 either.)  Then, you can look around the environment a bit.  But note: you
192 don't have very many commands.  Just the shell builtins ("echo *" makes a
193 halfway-decent replacement for ls, although it doesn't have an "ls -l"
194 mode), cat, mount, mknod, and fstype.
196 =============================
197 Appendices:
198 =============================
200 A.  Possible enhancements:
202 This initramfs structure can do just about anything.  Here are the first
203 few things that I can think of that might be useful:
205   (1) LVM, etc. for a root FS -- anything that requires special setup.
206       (In fact, I got the basis for this /init script from an LVM howto.)
208   (2) A "make allmodules" kernel -- an initramfs, like an initrd, gives
209       you the ability to build *everything* as a module, including the
210       driver for your root filesystem, the driver for your root disk, etc.
212   (3) A LiveCD -- when making a LiveCD, you don't know which device file
213       will be holding the LiveCD image.  So you have to run a script that
214       checks all possible devices to see whether each is actually holding
215       the LiveCD.   The current LiveCD hints use an initrd for this script,
216       but it would not be difficult to adapt them to an initramfs.
218   (4) Others -- anything that requires code to run before the kernel init=
219       or root= arguments are interpreted is a prime candidate for an initrd
220       or initramfs.
223 B.  Possible gotchas:
225   (1) The /init script creates the correct root device based on the "root="
226       argument given to the kernel.  But it can only handle IDE disks, and
227       then only /dev/hda through /dev/hdd.  Anything not meeting these
228       criteria will give an error when /init gets run.  It is certainly
229       possible to modify /init to handle more devices, and I would suggest
230       you do so if you use a SCSI hard drive or a secondary IDE card.
232   (2) The "fstype" program can only handle certain filesystem types.  If
233       the filesystem on your root device is not among the supported list,
234       fstype will output "unknown", and you will get an error from /init.
235       You can test before you create the initramfs, if you have permission
236       to read your raw root device, by running:
238       $INITRAMFS/klibc-1.1.1/utils/static/fstype </dev/hdXY
240       (where hdXY is your root FS device).  klibc must be built first, of
241       course.  If you get output like this:
243       FSTYPE=ext3
244       FSSIZE=whatever
246       then fstype is able to recognize your root filesystem type.  But if
247       you get this output:
249       FSTYPE=unknown
250       FSSIZE=0
252       then fstype will not work for you.  The solution would be to either
253       try a newer version of fstype, or enhance it yourself to recognize
254       your filesystem, or forget about it altogether and just hard-code
255       your root FS type into /init.  (There are some comments in the script
256       showing where to do that if you need to.  It's near the:
258       mount -t $FSTYPE $root /new-root
260       command.)
263 ACKNOWLEDGEMENTS:
265 Benjamin Smee (strerror_at_disciplina.net): Writing the LVM-DMcrypt-HOWTO,
266   which this hint's /init script is based on
268 CHANGELOG:
270 2005-11-25:  Initial release