-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathinitrd.txt
More file actions
261 lines (179 loc) · 9.4 KB
/
initrd.txt
File metadata and controls
261 lines (179 loc) · 9.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
Booting with initrd
~~~~~~~~~~~~~~~~~~~
Initrd (initramfs) is a small filesystem image that gets loaded alongside the
kernel (or as a part of the kernel) into the RAM by the bootloader. Since it
is already in RAM by the time the kernel starts, the code needed to mount it
is very simple, unconditional and device-independent.
With initrd, the task of locating and mounting the real root filesystem gets
moved to the userspace, resulting in less awful kernel space code and much
more flexibility in implementing device-locating logic.
Indications for using initrd:
* modular kernel, with modules either for the device containing
the real root, or the filesystem used there
* device containing the real root is identified by something other
than a fixed major:minor pair
* something needs to be done prior to mounting the real root
(fsck, encryption, device mapper setup etc)
Realistically, with current Linux, only some SoC-based systems can safely get
away without initrd. For anything else, in particular anything PC-like, initrd
is pretty much unavoidable.
This project provides several tools designed specifically for use in initrd.
# Technical note: modern Linux systems use initramfs, with initrd proper
# considered outdated, and this project only really supports initramfs.
# However, the distinction is not really important outside of the kernel,
# so in this file, "initrd" is used to refer to either.
Startup script
~~~~~~~~~~~~~~
# NOTE: somewhat outdated after devinit changes, to be re-written.
The kernel "mounts" initrd as filesystem root and spawns a single process,
execing /linuxrc as pid 1. Typical contents:
#!/bin/msh
# mount required virtual filesystems
run /bin/mount -vc /dev /sys /proc
# wait for devices, see below
run /bin/devinit -i # creates /dev/mapper/root
# mount the real root filesystem
run /bin/kmount /root /dev/mapper/root
# transition to the real root
exec /bin/switchroot /root /etc/boot/start
The overall goal of this script is simply to get the real root mounted
somewhere, and then call switchroot to that directory.
Locating the root device
~~~~~~~~~~~~~~~~~~~~~~~~
There are essentially three problems to solve at this stage:
* load driver modules for the storage device and the bus it's on;
* wait for the device to be initialized;
* figure out which /dev node corresponds to the right device.
The tools that address them are `devinit` and `findblk`. The role of devinit
is to handle kernel-initiated module loading requests, which is normally done
by udev service (`udevmod` here). Unlike the service, `devinit` does not need
to run indefinitely. Instead, it spawns a script, /etc/devinit, and does its
thing only until the script exits.
The script runs with udev events being handled in the background. Its role is
to wait until the right device appears in /dev.
Typical contents of /etc/devinit:
#!/bin/msh
run /bin/findblk mbr:00112233 1:boot 2:root
See man pages for `devinit` and `findblk` for detailed description.
To work properly, `devinit` needs one more script, /etc/modpipe:
#!/bin/msh
exec /bin/modprobe -ip
See modprobe man page on what it does.
Statically-located root devices
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In case the kernel is modular but the list of modules to load is known ahead
of time, `devinit` should be skipped, and both `modprobe` and `findblk` should
be called directly from /init:
#!/bin/msh
run /bin/kmount -vc /dev /sys /proc
run /bin/modprobe -i some-mmc-controller
run /bin/findblk name:mmcblk0 p1:root
run /bin/kmount /root /dev/mapper/root
exec /bin/switchroot /root /etc/boot/start
The reason to use `findblk` in the example above is to pause the script
until /dev/mmcblk0 appears, since modprobe does not wait for the module
to initialize. In simpler cases, it can be replaced with `waitfor` msh
built-in.
If the name of the device node is static, and it does not require waiting,
`findblk` stage can be skipped as well:
#!/bin/msh
run /bin/kmount -vc /dev /sys /proc
run /bin/kmount /root /dev/mmcblk0p1
exec /bin/switchroot /root /etc/boot/start
At this point, the need to use initrd in the first place should be questioned.
Encrypted rootfs
~~~~~~~~~~~~~~~~
Encryption layer must be setup up before mounting the file system.
Sample /etc/devinit using `passblk`:
#!/bin/msh
run /bin/findblk mbr:00112233 1:root
run /bin/passblk /etc/keyfile root
See `passblk` man page for a detailed description. The end result, again, will
be a mountable partition pointed to by /dev/mapper/root.
Running `passblk` from devinit given the kernel a chance to request encryption
support modules if those aren't loaded. Alternatively, the module can be loaded
statically in /init, and `findblk` can be called there as well:
#!/bin/msh
run /bin/kmount -vc /dev /sys /proc
run /bin/modprobe -i crypto_engine
run /bin/modprobe -i crypto_user
run /bin/modprobe -i cryptd
run /bin/modprobe -i cbc
run /bin/modprobe -i ecb
run /bin/modprobe -i xts
run /bin/modprobe -i dm-crypt
run /bin/devinit -i
run /bin/passblk /etc/keyfile root
run /bin/kmount /root /dev/mapper/root
exec /bin/switchroot /root /etc/boot/start
Depending on configuration, some modules may need to be loaded statically even
if `passblk` gets called from /etc/devinit.
Entering to the real root
~~~~~~~~~~~~~~~~~~~~~~~~~
Once the root partition is mounted, /init should exec into `switchroot`,
which will subsequently exec into the next stage, which in the examples above
is `/etc/boot/start`. Not much else to discuss here, check the man page for
`switchroot` for a detailed description of what exactly it does.
This is the one of the few points outside of the kernel where the distinction
between initrd proper and initramfs matters. `switchroot` only works with
initramfs. Switching from initrd proper requires a different tool that would
perform a different syscall sequence. There is no such tool in this project
at this moment. Initrd proper (as in, initial ramdisk) is generally considered
deprecated in favor of initramfs.
Virtual and non-root filesystems
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
It is up to the system builder to decide whether to mount particular virtual
filesystems in initrd, or delay it to the real root startup script. There are
several that need to be mounted early: /dev, /sys and possibly /proc. This
depends solely on the tools used in initrd. For instance, `findblk` needs both
/dev and /sys to work.
In case separate partitions are used for /var or some other directories,
those probably should be located and possibly mounted from initrd as well.
This mostly depends on the convenience of running devinit (and/or findblk)
from the real root.
`switchroot` will attempt to preserve any mount points when switching from
the virtual initramfs root to the real filesystem. Check the man page on how
it does so.
Which modules to put into initrd
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Ideally, only modules needed to mount the rootfs should be put into initrd.
Anything that could remain in the real rootfs, should remain there.
In particular, avoid DRM modules unless absolutely necessary (i.e. graphical
passphrase prompt or something like that), those tend to be quite large.
Use `depmod` to re-build dependency index and verify that no dependencies
are missing. Avoid using the full index from the real rootfs; it will work,
but will take more time than necessary to parse.
Modules and compression
~~~~~~~~~~~~~~~~~~~~~~~
There are essentially two ways of compressing initrd:
* compress the whole image
* compress individual modules
Compressing the whole image results in the best ratio, but forces complete
decompression early during kernel startup. Compressing modules individually
and leaving the image uncompressed results in subpar compression ratios, but
allows only the modules in actual use to be decompressed.
Whole-image compression should therefore be preferred for cases where most of
the initrd contents will be used, whereas individually compressed modules are
better when initrd has to carry lots of modules but only few are expected to
get loaded. The latter is often the case for generic PC distributions.
Avoid dual compression (compressed image with individually compressed modules),
it serves no purpose and slows down module loading. If the whole image gets
compressed, leave everything inside uncompressed.
Initrd filesystem layout
~~~~~~~~~~~~~~~~~~~~~~~~
This projects supports two distinct layouts for initrd: full and simplified.
The full layout means initrd paths as the same as they would be on the real
rootfs. In particular, as far as this project is concerned,
* config files are in /base/etc, and
* kernel modules are in /lib/modules/$REVISION
This kind of layout allows using abritrary tools from rootfs, unchanged, in
initrd context. However, in many cases that's not important, and the extra
directories serve no purpose in the restricted initrd environment.
Simplified layout is meant to addrees this concern:
* all config files are in /etc
* kernel modules are in /lib/modules (no $REVISION!)
A couple of tools from this project, modprobe and devinit, that would otherwise
try to access /base/etc, accept command line option -i to use the simplified
layout. Check respective manual pages for exact paths. Several other tools,
like msh and findblk, do not use /base paths, or do not use abosolute paths
at all, and can be used in initrd environment at is.