diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /init |
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'init')
-rw-r--r-- | init/Kconfig | 463 | ||||
-rw-r--r-- | init/Makefile | 28 | ||||
-rw-r--r-- | init/calibrate.c | 79 | ||||
-rw-r--r-- | init/do_mounts.c | 430 | ||||
-rw-r--r-- | init/do_mounts.h | 92 | ||||
-rw-r--r-- | init/do_mounts_devfs.c | 137 | ||||
-rw-r--r-- | init/do_mounts_initrd.c | 121 | ||||
-rw-r--r-- | init/do_mounts_md.c | 290 | ||||
-rw-r--r-- | init/do_mounts_rd.c | 429 | ||||
-rw-r--r-- | init/initramfs.c | 500 | ||||
-rw-r--r-- | init/main.c | 713 | ||||
-rw-r--r-- | init/version.c | 33 |
12 files changed, 3315 insertions, 0 deletions
diff --git a/init/Kconfig b/init/Kconfig new file mode 100644 index 00000000000..abe2682a6ca --- /dev/null +++ b/init/Kconfig | |||
@@ -0,0 +1,463 @@ | |||
1 | menu "Code maturity level options" | ||
2 | |||
3 | config EXPERIMENTAL | ||
4 | bool "Prompt for development and/or incomplete code/drivers" | ||
5 | ---help--- | ||
6 | Some of the various things that Linux supports (such as network | ||
7 | drivers, file systems, network protocols, etc.) can be in a state | ||
8 | of development where the functionality, stability, or the level of | ||
9 | testing is not yet high enough for general use. This is usually | ||
10 | known as the "alpha-test" phase among developers. If a feature is | ||
11 | currently in alpha-test, then the developers usually discourage | ||
12 | uninformed widespread use of this feature by the general public to | ||
13 | avoid "Why doesn't this work?" type mail messages. However, active | ||
14 | testing and use of these systems is welcomed. Just be aware that it | ||
15 | may not meet the normal level of reliability or it may fail to work | ||
16 | in some special cases. Detailed bug reports from people familiar | ||
17 | with the kernel internals are usually welcomed by the developers | ||
18 | (before submitting bug reports, please read the documents | ||
19 | <file:README>, <file:MAINTAINERS>, <file:REPORTING-BUGS>, | ||
20 | <file:Documentation/BUG-HUNTING>, and | ||
21 | <file:Documentation/oops-tracing.txt> in the kernel source). | ||
22 | |||
23 | This option will also make obsoleted drivers available. These are | ||
24 | drivers that have been replaced by something else, and/or are | ||
25 | scheduled to be removed in a future kernel release. | ||
26 | |||
27 | Unless you intend to help test and develop a feature or driver that | ||
28 | falls into this category, or you have a situation that requires | ||
29 | using these features, you should probably say N here, which will | ||
30 | cause the configurator to present you with fewer choices. If | ||
31 | you say Y here, you will be offered the choice of using features or | ||
32 | drivers that are currently considered to be in the alpha-test phase. | ||
33 | |||
34 | config CLEAN_COMPILE | ||
35 | bool "Select only drivers expected to compile cleanly" if EXPERIMENTAL | ||
36 | default y | ||
37 | help | ||
38 | Select this option if you don't even want to see the option | ||
39 | to configure known-broken drivers. | ||
40 | |||
41 | If unsure, say Y | ||
42 | |||
43 | config BROKEN | ||
44 | bool | ||
45 | depends on !CLEAN_COMPILE | ||
46 | default y | ||
47 | |||
48 | config BROKEN_ON_SMP | ||
49 | bool | ||
50 | depends on BROKEN || !SMP | ||
51 | default y | ||
52 | |||
53 | config LOCK_KERNEL | ||
54 | bool | ||
55 | depends on SMP || PREEMPT | ||
56 | default y | ||
57 | |||
58 | config INIT_ENV_ARG_LIMIT | ||
59 | int | ||
60 | default 32 if !USERMODE | ||
61 | default 128 if USERMODE | ||
62 | help | ||
63 | This is the value of the two limits on the number of argument and of | ||
64 | env.var passed to init from the kernel command line. | ||
65 | |||
66 | endmenu | ||
67 | |||
68 | menu "General setup" | ||
69 | |||
70 | config LOCALVERSION | ||
71 | string "Local version - append to kernel release" | ||
72 | help | ||
73 | Append an extra string to the end of your kernel version. | ||
74 | This will show up when you type uname, for example. | ||
75 | The string you set here will be appended after the contents of | ||
76 | any files with a filename matching localversion* in your | ||
77 | object and source tree, in that order. Your total string can | ||
78 | be a maximum of 64 characters. | ||
79 | |||
80 | config SWAP | ||
81 | bool "Support for paging of anonymous memory (swap)" | ||
82 | depends on MMU | ||
83 | default y | ||
84 | help | ||
85 | This option allows you to choose whether you want to have support | ||
86 | for socalled swap devices or swap files in your kernel that are | ||
87 | used to provide more virtual memory than the actual RAM present | ||
88 | in your computer. If unsure say Y. | ||
89 | |||
90 | config SYSVIPC | ||
91 | bool "System V IPC" | ||
92 | depends on MMU | ||
93 | ---help--- | ||
94 | Inter Process Communication is a suite of library functions and | ||
95 | system calls which let processes (running programs) synchronize and | ||
96 | exchange information. It is generally considered to be a good thing, | ||
97 | and some programs won't run unless you say Y here. In particular, if | ||
98 | you want to run the DOS emulator dosemu under Linux (read the | ||
99 | DOSEMU-HOWTO, available from <http://www.tldp.org/docs.html#howto>), | ||
100 | you'll need to say Y here. | ||
101 | |||
102 | You can find documentation about IPC with "info ipc" and also in | ||
103 | section 6.4 of the Linux Programmer's Guide, available from | ||
104 | <http://www.tldp.org/guides.html>. | ||
105 | |||
106 | config POSIX_MQUEUE | ||
107 | bool "POSIX Message Queues" | ||
108 | depends on NET && EXPERIMENTAL | ||
109 | ---help--- | ||
110 | POSIX variant of message queues is a part of IPC. In POSIX message | ||
111 | queues every message has a priority which decides about succession | ||
112 | of receiving it by a process. If you want to compile and run | ||
113 | programs written e.g. for Solaris with use of its POSIX message | ||
114 | queues (functions mq_*) say Y here. To use this feature you will | ||
115 | also need mqueue library, available from | ||
116 | <http://www.mat.uni.torun.pl/~wrona/posix_ipc/> | ||
117 | |||
118 | POSIX message queues are visible as a filesystem called 'mqueue' | ||
119 | and can be mounted somewhere if you want to do filesystem | ||
120 | operations on message queues. | ||
121 | |||
122 | If unsure, say Y. | ||
123 | |||
124 | config BSD_PROCESS_ACCT | ||
125 | bool "BSD Process Accounting" | ||
126 | help | ||
127 | If you say Y here, a user level program will be able to instruct the | ||
128 | kernel (via a special system call) to write process accounting | ||
129 | information to a file: whenever a process exits, information about | ||
130 | that process will be appended to the file by the kernel. The | ||
131 | information includes things such as creation time, owning user, | ||
132 | command name, memory usage, controlling terminal etc. (the complete | ||
133 | list is in the struct acct in <file:include/linux/acct.h>). It is | ||
134 | up to the user level program to do useful things with this | ||
135 | information. This is generally a good idea, so say Y. | ||
136 | |||
137 | config BSD_PROCESS_ACCT_V3 | ||
138 | bool "BSD Process Accounting version 3 file format" | ||
139 | depends on BSD_PROCESS_ACCT | ||
140 | default n | ||
141 | help | ||
142 | If you say Y here, the process accounting information is written | ||
143 | in a new file format that also logs the process IDs of each | ||
144 | process and it's parent. Note that this file format is incompatible | ||
145 | with previous v0/v1/v2 file formats, so you will need updated tools | ||
146 | for processing it. A preliminary version of these tools is available | ||
147 | at <http://www.physik3.uni-rostock.de/tim/kernel/utils/acct/>. | ||
148 | |||
149 | config SYSCTL | ||
150 | bool "Sysctl support" | ||
151 | ---help--- | ||
152 | The sysctl interface provides a means of dynamically changing | ||
153 | certain kernel parameters and variables on the fly without requiring | ||
154 | a recompile of the kernel or reboot of the system. The primary | ||
155 | interface consists of a system call, but if you say Y to "/proc | ||
156 | file system support", a tree of modifiable sysctl entries will be | ||
157 | generated beneath the /proc/sys directory. They are explained in the | ||
158 | files in <file:Documentation/sysctl/>. Note that enabling this | ||
159 | option will enlarge the kernel by at least 8 KB. | ||
160 | |||
161 | As it is generally a good thing, you should say Y here unless | ||
162 | building a kernel for install/rescue disks or your system is very | ||
163 | limited in memory. | ||
164 | |||
165 | config AUDIT | ||
166 | bool "Auditing support" | ||
167 | default y if SECURITY_SELINUX | ||
168 | help | ||
169 | Enable auditing infrastructure that can be used with another | ||
170 | kernel subsystem, such as SELinux (which requires this for | ||
171 | logging of avc messages output). Does not do system-call | ||
172 | auditing without CONFIG_AUDITSYSCALL. | ||
173 | |||
174 | config AUDITSYSCALL | ||
175 | bool "Enable system-call auditing support" | ||
176 | depends on AUDIT && (X86 || PPC64 || ARCH_S390 || IA64) | ||
177 | default y if SECURITY_SELINUX | ||
178 | help | ||
179 | Enable low-overhead system-call auditing infrastructure that | ||
180 | can be used independently or with another kernel subsystem, | ||
181 | such as SELinux. | ||
182 | |||
183 | config HOTPLUG | ||
184 | bool "Support for hot-pluggable devices" if !ARCH_S390 | ||
185 | default ARCH_S390 | ||
186 | help | ||
187 | This option is provided for the case where no in-kernel-tree | ||
188 | modules require HOTPLUG functionality, but a module built | ||
189 | outside the kernel tree does. Such modules require Y here. | ||
190 | |||
191 | config KOBJECT_UEVENT | ||
192 | bool "Kernel Userspace Events" | ||
193 | depends on NET | ||
194 | default y | ||
195 | help | ||
196 | This option enables the kernel userspace event layer, which is a | ||
197 | simple mechanism for kernel-to-user communication over a netlink | ||
198 | socket. | ||
199 | The goal of the kernel userspace events layer is to provide a simple | ||
200 | and efficient events system, that notifies userspace about kobject | ||
201 | state changes. This will enable applications to just listen for | ||
202 | events instead of polling system devices and files. | ||
203 | Hotplug events (kobject addition and removal) are also available on | ||
204 | the netlink socket in addition to the execution of /sbin/hotplug if | ||
205 | CONFIG_HOTPLUG is enabled. | ||
206 | |||
207 | Say Y, unless you are building a system requiring minimal memory | ||
208 | consumption. | ||
209 | |||
210 | config IKCONFIG | ||
211 | bool "Kernel .config support" | ||
212 | ---help--- | ||
213 | This option enables the complete Linux kernel ".config" file | ||
214 | contents to be saved in the kernel. It provides documentation | ||
215 | of which kernel options are used in a running kernel or in an | ||
216 | on-disk kernel. This information can be extracted from the kernel | ||
217 | image file with the script scripts/extract-ikconfig and used as | ||
218 | input to rebuild the current kernel or to build another kernel. | ||
219 | It can also be extracted from a running kernel by reading | ||
220 | /proc/config.gz if enabled (below). | ||
221 | |||
222 | config IKCONFIG_PROC | ||
223 | bool "Enable access to .config through /proc/config.gz" | ||
224 | depends on IKCONFIG && PROC_FS | ||
225 | ---help--- | ||
226 | This option enables access to the kernel configuration file | ||
227 | through /proc/config.gz. | ||
228 | |||
229 | config CPUSETS | ||
230 | bool "Cpuset support" | ||
231 | depends on SMP | ||
232 | help | ||
233 | This options will let you create and manage CPUSET's which | ||
234 | allow dynamically partitioning a system into sets of CPUs and | ||
235 | Memory Nodes and assigning tasks to run only within those sets. | ||
236 | This is primarily useful on large SMP or NUMA systems. | ||
237 | |||
238 | Say N if unsure. | ||
239 | |||
240 | menuconfig EMBEDDED | ||
241 | bool "Configure standard kernel features (for small systems)" | ||
242 | help | ||
243 | This option allows certain base kernel options and settings | ||
244 | to be disabled or tweaked. This is for specialized | ||
245 | environments which can tolerate a "non-standard" kernel. | ||
246 | Only use this if you really know what you are doing. | ||
247 | |||
248 | config KALLSYMS | ||
249 | bool "Load all symbols for debugging/kksymoops" if EMBEDDED | ||
250 | default y | ||
251 | help | ||
252 | Say Y here to let the kernel print out symbolic crash information and | ||
253 | symbolic stack backtraces. This increases the size of the kernel | ||
254 | somewhat, as all symbols have to be loaded into the kernel image. | ||
255 | |||
256 | config KALLSYMS_ALL | ||
257 | bool "Include all symbols in kallsyms" | ||
258 | depends on DEBUG_KERNEL && KALLSYMS | ||
259 | help | ||
260 | Normally kallsyms only contains the symbols of functions, for nicer | ||
261 | OOPS messages. Some debuggers can use kallsyms for other | ||
262 | symbols too: say Y here to include all symbols, and you | ||
263 | don't care about adding 300k to the size of your kernel. | ||
264 | |||
265 | Say N. | ||
266 | |||
267 | config KALLSYMS_EXTRA_PASS | ||
268 | bool "Do an extra kallsyms pass" | ||
269 | depends on KALLSYMS | ||
270 | help | ||
271 | If kallsyms is not working correctly, the build will fail with | ||
272 | inconsistent kallsyms data. If that occurs, log a bug report and | ||
273 | turn on KALLSYMS_EXTRA_PASS which should result in a stable build. | ||
274 | Always say N here unless you find a bug in kallsyms, which must be | ||
275 | reported. KALLSYMS_EXTRA_PASS is only a temporary workaround while | ||
276 | you wait for kallsyms to be fixed. | ||
277 | |||
278 | config BASE_FULL | ||
279 | default y | ||
280 | bool "Enable full-sized data structures for core" if EMBEDDED | ||
281 | help | ||
282 | Disabling this option reduces the size of miscellaneous core | ||
283 | kernel data structures. This saves memory on small machines, | ||
284 | but may reduce performance. | ||
285 | |||
286 | config FUTEX | ||
287 | bool "Enable futex support" if EMBEDDED | ||
288 | default y | ||
289 | help | ||
290 | Disabling this option will cause the kernel to be built without | ||
291 | support for "fast userspace mutexes". The resulting kernel may not | ||
292 | run glibc-based applications correctly. | ||
293 | |||
294 | config EPOLL | ||
295 | bool "Enable eventpoll support" if EMBEDDED | ||
296 | default y | ||
297 | help | ||
298 | Disabling this option will cause the kernel to be built without | ||
299 | support for epoll family of system calls. | ||
300 | |||
301 | config CC_OPTIMIZE_FOR_SIZE | ||
302 | bool "Optimize for size" if EMBEDDED | ||
303 | default y if ARM || H8300 | ||
304 | help | ||
305 | Enabling this option will pass "-Os" instead of "-O2" to gcc | ||
306 | resulting in a smaller kernel. | ||
307 | |||
308 | WARNING: some versions of gcc may generate incorrect code with this | ||
309 | option. If problems are observed, a gcc upgrade may be needed. | ||
310 | |||
311 | If unsure, say N. | ||
312 | |||
313 | config SHMEM | ||
314 | bool "Use full shmem filesystem" if EMBEDDED | ||
315 | default y | ||
316 | depends on MMU | ||
317 | help | ||
318 | The shmem is an internal filesystem used to manage shared memory. | ||
319 | It is backed by swap and manages resource limits. It is also exported | ||
320 | to userspace as tmpfs if TMPFS is enabled. Disabling this | ||
321 | option replaces shmem and tmpfs with the much simpler ramfs code, | ||
322 | which may be appropriate on small systems without swap. | ||
323 | |||
324 | config CC_ALIGN_FUNCTIONS | ||
325 | int "Function alignment" if EMBEDDED | ||
326 | default 0 | ||
327 | help | ||
328 | Align the start of functions to the next power-of-two greater than n, | ||
329 | skipping up to n bytes. For instance, 32 aligns functions | ||
330 | to the next 32-byte boundary, but 24 would align to the next | ||
331 | 32-byte boundary only if this can be done by skipping 23 bytes or less. | ||
332 | Zero means use compiler's default. | ||
333 | |||
334 | config CC_ALIGN_LABELS | ||
335 | int "Label alignment" if EMBEDDED | ||
336 | default 0 | ||
337 | help | ||
338 | Align all branch targets to a power-of-two boundary, skipping | ||
339 | up to n bytes like ALIGN_FUNCTIONS. This option can easily | ||
340 | make code slower, because it must insert dummy operations for | ||
341 | when the branch target is reached in the usual flow of the code. | ||
342 | Zero means use compiler's default. | ||
343 | |||
344 | config CC_ALIGN_LOOPS | ||
345 | int "Loop alignment" if EMBEDDED | ||
346 | default 0 | ||
347 | help | ||
348 | Align loops to a power-of-two boundary, skipping up to n bytes. | ||
349 | Zero means use compiler's default. | ||
350 | |||
351 | config CC_ALIGN_JUMPS | ||
352 | int "Jump alignment" if EMBEDDED | ||
353 | default 0 | ||
354 | help | ||
355 | Align branch targets to a power-of-two boundary, for branch | ||
356 | targets where the targets can only be reached by jumping, | ||
357 | skipping up to n bytes like ALIGN_FUNCTIONS. In this case, | ||
358 | no dummy operations need be executed. | ||
359 | Zero means use compiler's default. | ||
360 | |||
361 | endmenu # General setup | ||
362 | |||
363 | config TINY_SHMEM | ||
364 | default !SHMEM | ||
365 | bool | ||
366 | |||
367 | config BASE_SMALL | ||
368 | int | ||
369 | default 0 if BASE_FULL | ||
370 | default 1 if !BASE_FULL | ||
371 | |||
372 | menu "Loadable module support" | ||
373 | |||
374 | config MODULES | ||
375 | bool "Enable loadable module support" | ||
376 | help | ||
377 | Kernel modules are small pieces of compiled code which can | ||
378 | be inserted in the running kernel, rather than being | ||
379 | permanently built into the kernel. You use the "modprobe" | ||
380 | tool to add (and sometimes remove) them. If you say Y here, | ||
381 | many parts of the kernel can be built as modules (by | ||
382 | answering M instead of Y where indicated): this is most | ||
383 | useful for infrequently used options which are not required | ||
384 | for booting. For more information, see the man pages for | ||
385 | modprobe, lsmod, modinfo, insmod and rmmod. | ||
386 | |||
387 | If you say Y here, you will need to run "make | ||
388 | modules_install" to put the modules under /lib/modules/ | ||
389 | where modprobe can find them (you may need to be root to do | ||
390 | this). | ||
391 | |||
392 | If unsure, say Y. | ||
393 | |||
394 | config MODULE_UNLOAD | ||
395 | bool "Module unloading" | ||
396 | depends on MODULES | ||
397 | help | ||
398 | Without this option you will not be able to unload any | ||
399 | modules (note that some modules may not be unloadable | ||
400 | anyway), which makes your kernel slightly smaller and | ||
401 | simpler. If unsure, say Y. | ||
402 | |||
403 | config MODULE_FORCE_UNLOAD | ||
404 | bool "Forced module unloading" | ||
405 | depends on MODULE_UNLOAD && EXPERIMENTAL | ||
406 | help | ||
407 | This option allows you to force a module to unload, even if the | ||
408 | kernel believes it is unsafe: the kernel will remove the module | ||
409 | without waiting for anyone to stop using it (using the -f option to | ||
410 | rmmod). This is mainly for kernel developers and desperate users. | ||
411 | If unsure, say N. | ||
412 | |||
413 | config OBSOLETE_MODPARM | ||
414 | bool | ||
415 | default y | ||
416 | depends on MODULES | ||
417 | help | ||
418 | You need this option to use module parameters on modules which | ||
419 | have not been converted to the new module parameter system yet. | ||
420 | If unsure, say Y. | ||
421 | |||
422 | config MODVERSIONS | ||
423 | bool "Module versioning support (EXPERIMENTAL)" | ||
424 | depends on MODULES && EXPERIMENTAL && !UML | ||
425 | help | ||
426 | Usually, you have to use modules compiled with your kernel. | ||
427 | Saying Y here makes it sometimes possible to use modules | ||
428 | compiled for different kernels, by adding enough information | ||
429 | to the modules to (hopefully) spot any changes which would | ||
430 | make them incompatible with the kernel you are running. If | ||
431 | unsure, say N. | ||
432 | |||
433 | config MODULE_SRCVERSION_ALL | ||
434 | bool "Source checksum for all modules" | ||
435 | depends on MODULES | ||
436 | help | ||
437 | Modules which contain a MODULE_VERSION get an extra "srcversion" | ||
438 | field inserted into their modinfo section, which contains a | ||
439 | sum of the source files which made it. This helps maintainers | ||
440 | see exactly which source was used to build a module (since | ||
441 | others sometimes change the module source without updating | ||
442 | the version). With this option, such a "srcversion" field | ||
443 | will be created for all modules. If unsure, say N. | ||
444 | |||
445 | config KMOD | ||
446 | bool "Automatic kernel module loading" | ||
447 | depends on MODULES | ||
448 | help | ||
449 | Normally when you have selected some parts of the kernel to | ||
450 | be created as kernel modules, you must load them (using the | ||
451 | "modprobe" command) before you can use them. If you say Y | ||
452 | here, some parts of the kernel will be able to load modules | ||
453 | automatically: when a part of the kernel needs a module, it | ||
454 | runs modprobe with the appropriate arguments, thereby | ||
455 | loading the module if it is available. If unsure, say Y. | ||
456 | |||
457 | config STOP_MACHINE | ||
458 | bool | ||
459 | default y | ||
460 | depends on (SMP && MODULE_UNLOAD) || HOTPLUG_CPU | ||
461 | help | ||
462 | Need stop_machine() primitive. | ||
463 | endmenu | ||
diff --git a/init/Makefile b/init/Makefile new file mode 100644 index 00000000000..93a53fbdbe7 --- /dev/null +++ b/init/Makefile | |||
@@ -0,0 +1,28 @@ | |||
1 | # | ||
2 | # Makefile for the linux kernel. | ||
3 | # | ||
4 | |||
5 | obj-y := main.o version.o mounts.o initramfs.o | ||
6 | obj-$(CONFIG_GENERIC_CALIBRATE_DELAY) += calibrate.o | ||
7 | |||
8 | mounts-y := do_mounts.o | ||
9 | mounts-$(CONFIG_DEVFS_FS) += do_mounts_devfs.o | ||
10 | mounts-$(CONFIG_BLK_DEV_RAM) += do_mounts_rd.o | ||
11 | mounts-$(CONFIG_BLK_DEV_INITRD) += do_mounts_initrd.o | ||
12 | mounts-$(CONFIG_BLK_DEV_MD) += do_mounts_md.o | ||
13 | |||
14 | # files to be removed upon make clean | ||
15 | clean-files := ../include/linux/compile.h | ||
16 | |||
17 | # dependencies on generated files need to be listed explicitly | ||
18 | |||
19 | $(obj)/version.o: include/linux/compile.h | ||
20 | |||
21 | # compile.h changes depending on hostname, generation number, etc, | ||
22 | # so we regenerate it always. | ||
23 | # mkcompile_h will make sure to only update the | ||
24 | # actual file if its content has changed. | ||
25 | |||
26 | include/linux/compile.h: FORCE | ||
27 | @echo ' CHK $@' | ||
28 | @$(CONFIG_SHELL) $(srctree)/scripts/mkcompile_h $@ "$(UTS_MACHINE)" "$(CONFIG_SMP)" "$(CC) $(CFLAGS)" | ||
diff --git a/init/calibrate.c b/init/calibrate.c new file mode 100644 index 00000000000..c698e04a3db --- /dev/null +++ b/init/calibrate.c | |||
@@ -0,0 +1,79 @@ | |||
1 | /* calibrate.c: default delay calibration | ||
2 | * | ||
3 | * Excised from init/main.c | ||
4 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | #include <linux/sched.h> | ||
8 | #include <linux/delay.h> | ||
9 | #include <linux/init.h> | ||
10 | |||
11 | static unsigned long preset_lpj; | ||
12 | static int __init lpj_setup(char *str) | ||
13 | { | ||
14 | preset_lpj = simple_strtoul(str,NULL,0); | ||
15 | return 1; | ||
16 | } | ||
17 | |||
18 | __setup("lpj=", lpj_setup); | ||
19 | |||
20 | /* | ||
21 | * This is the number of bits of precision for the loops_per_jiffy. Each | ||
22 | * bit takes on average 1.5/HZ seconds. This (like the original) is a little | ||
23 | * better than 1% | ||
24 | */ | ||
25 | #define LPS_PREC 8 | ||
26 | |||
27 | void __devinit calibrate_delay(void) | ||
28 | { | ||
29 | unsigned long ticks, loopbit; | ||
30 | int lps_precision = LPS_PREC; | ||
31 | |||
32 | if (preset_lpj) { | ||
33 | loops_per_jiffy = preset_lpj; | ||
34 | printk("Calibrating delay loop (skipped)... " | ||
35 | "%lu.%02lu BogoMIPS preset\n", | ||
36 | loops_per_jiffy/(500000/HZ), | ||
37 | (loops_per_jiffy/(5000/HZ)) % 100); | ||
38 | } else { | ||
39 | loops_per_jiffy = (1<<12); | ||
40 | |||
41 | printk(KERN_DEBUG "Calibrating delay loop... "); | ||
42 | while ((loops_per_jiffy <<= 1) != 0) { | ||
43 | /* wait for "start of" clock tick */ | ||
44 | ticks = jiffies; | ||
45 | while (ticks == jiffies) | ||
46 | /* nothing */; | ||
47 | /* Go .. */ | ||
48 | ticks = jiffies; | ||
49 | __delay(loops_per_jiffy); | ||
50 | ticks = jiffies - ticks; | ||
51 | if (ticks) | ||
52 | break; | ||
53 | } | ||
54 | |||
55 | /* | ||
56 | * Do a binary approximation to get loops_per_jiffy set to | ||
57 | * equal one clock (up to lps_precision bits) | ||
58 | */ | ||
59 | loops_per_jiffy >>= 1; | ||
60 | loopbit = loops_per_jiffy; | ||
61 | while (lps_precision-- && (loopbit >>= 1)) { | ||
62 | loops_per_jiffy |= loopbit; | ||
63 | ticks = jiffies; | ||
64 | while (ticks == jiffies) | ||
65 | /* nothing */; | ||
66 | ticks = jiffies; | ||
67 | __delay(loops_per_jiffy); | ||
68 | if (jiffies != ticks) /* longer than 1 tick */ | ||
69 | loops_per_jiffy &= ~loopbit; | ||
70 | } | ||
71 | |||
72 | /* Round the value and print it */ | ||
73 | printk("%lu.%02lu BogoMIPS (lpj=%lu)\n", | ||
74 | loops_per_jiffy/(500000/HZ), | ||
75 | (loops_per_jiffy/(5000/HZ)) % 100, | ||
76 | loops_per_jiffy); | ||
77 | } | ||
78 | |||
79 | } | ||
diff --git a/init/do_mounts.c b/init/do_mounts.c new file mode 100644 index 00000000000..b7570c074d0 --- /dev/null +++ b/init/do_mounts.c | |||
@@ -0,0 +1,430 @@ | |||
1 | #include <linux/module.h> | ||
2 | #include <linux/sched.h> | ||
3 | #include <linux/ctype.h> | ||
4 | #include <linux/fd.h> | ||
5 | #include <linux/tty.h> | ||
6 | #include <linux/suspend.h> | ||
7 | #include <linux/root_dev.h> | ||
8 | #include <linux/security.h> | ||
9 | #include <linux/delay.h> | ||
10 | |||
11 | #include <linux/nfs_fs.h> | ||
12 | #include <linux/nfs_fs_sb.h> | ||
13 | #include <linux/nfs_mount.h> | ||
14 | |||
15 | #include "do_mounts.h" | ||
16 | |||
17 | extern int get_filesystem_list(char * buf); | ||
18 | |||
19 | int __initdata rd_doload; /* 1 = load RAM disk, 0 = don't load */ | ||
20 | |||
21 | int root_mountflags = MS_RDONLY | MS_VERBOSE; | ||
22 | char * __initdata root_device_name; | ||
23 | static char __initdata saved_root_name[64]; | ||
24 | |||
25 | /* this is initialized in init/main.c */ | ||
26 | dev_t ROOT_DEV; | ||
27 | |||
28 | EXPORT_SYMBOL(ROOT_DEV); | ||
29 | |||
30 | static int __init load_ramdisk(char *str) | ||
31 | { | ||
32 | rd_doload = simple_strtol(str,NULL,0) & 3; | ||
33 | return 1; | ||
34 | } | ||
35 | __setup("load_ramdisk=", load_ramdisk); | ||
36 | |||
37 | static int __init readonly(char *str) | ||
38 | { | ||
39 | if (*str) | ||
40 | return 0; | ||
41 | root_mountflags |= MS_RDONLY; | ||
42 | return 1; | ||
43 | } | ||
44 | |||
45 | static int __init readwrite(char *str) | ||
46 | { | ||
47 | if (*str) | ||
48 | return 0; | ||
49 | root_mountflags &= ~MS_RDONLY; | ||
50 | return 1; | ||
51 | } | ||
52 | |||
53 | __setup("ro", readonly); | ||
54 | __setup("rw", readwrite); | ||
55 | |||
56 | static dev_t try_name(char *name, int part) | ||
57 | { | ||
58 | char path[64]; | ||
59 | char buf[32]; | ||
60 | int range; | ||
61 | dev_t res; | ||
62 | char *s; | ||
63 | int len; | ||
64 | int fd; | ||
65 | unsigned int maj, min; | ||
66 | |||
67 | /* read device number from .../dev */ | ||
68 | |||
69 | sprintf(path, "/sys/block/%s/dev", name); | ||
70 | fd = sys_open(path, 0, 0); | ||
71 | if (fd < 0) | ||
72 | goto fail; | ||
73 | len = sys_read(fd, buf, 32); | ||
74 | sys_close(fd); | ||
75 | if (len <= 0 || len == 32 || buf[len - 1] != '\n') | ||
76 | goto fail; | ||
77 | buf[len - 1] = '\0'; | ||
78 | if (sscanf(buf, "%u:%u", &maj, &min) == 2) { | ||
79 | /* | ||
80 | * Try the %u:%u format -- see print_dev_t() | ||
81 | */ | ||
82 | res = MKDEV(maj, min); | ||
83 | if (maj != MAJOR(res) || min != MINOR(res)) | ||
84 | goto fail; | ||
85 | } else { | ||
86 | /* | ||
87 | * Nope. Try old-style "0321" | ||
88 | */ | ||
89 | res = new_decode_dev(simple_strtoul(buf, &s, 16)); | ||
90 | if (*s) | ||
91 | goto fail; | ||
92 | } | ||
93 | |||
94 | /* if it's there and we are not looking for a partition - that's it */ | ||
95 | if (!part) | ||
96 | return res; | ||
97 | |||
98 | /* otherwise read range from .../range */ | ||
99 | sprintf(path, "/sys/block/%s/range", name); | ||
100 | fd = sys_open(path, 0, 0); | ||
101 | if (fd < 0) | ||
102 | goto fail; | ||
103 | len = sys_read(fd, buf, 32); | ||
104 | sys_close(fd); | ||
105 | if (len <= 0 || len == 32 || buf[len - 1] != '\n') | ||
106 | goto fail; | ||
107 | buf[len - 1] = '\0'; | ||
108 | range = simple_strtoul(buf, &s, 10); | ||
109 | if (*s) | ||
110 | goto fail; | ||
111 | |||
112 | /* if partition is within range - we got it */ | ||
113 | if (part < range) | ||
114 | return res + part; | ||
115 | fail: | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | /* | ||
120 | * Convert a name into device number. We accept the following variants: | ||
121 | * | ||
122 | * 1) device number in hexadecimal represents itself | ||
123 | * 2) /dev/nfs represents Root_NFS (0xff) | ||
124 | * 3) /dev/<disk_name> represents the device number of disk | ||
125 | * 4) /dev/<disk_name><decimal> represents the device number | ||
126 | * of partition - device number of disk plus the partition number | ||
127 | * 5) /dev/<disk_name>p<decimal> - same as the above, that form is | ||
128 | * used when disk name of partitioned disk ends on a digit. | ||
129 | * | ||
130 | * If name doesn't have fall into the categories above, we return 0. | ||
131 | * Driverfs is used to check if something is a disk name - it has | ||
132 | * all known disks under bus/block/devices. If the disk name | ||
133 | * contains slashes, name of driverfs node has them replaced with | ||
134 | * bangs. try_name() does the actual checks, assuming that driverfs | ||
135 | * is mounted on rootfs /sys. | ||
136 | */ | ||
137 | |||
138 | dev_t name_to_dev_t(char *name) | ||
139 | { | ||
140 | char s[32]; | ||
141 | char *p; | ||
142 | dev_t res = 0; | ||
143 | int part; | ||
144 | |||
145 | #ifdef CONFIG_SYSFS | ||
146 | int mkdir_err = sys_mkdir("/sys", 0700); | ||
147 | if (sys_mount("sysfs", "/sys", "sysfs", 0, NULL) < 0) | ||
148 | goto out; | ||
149 | #endif | ||
150 | |||
151 | if (strncmp(name, "/dev/", 5) != 0) { | ||
152 | unsigned maj, min; | ||
153 | |||
154 | if (sscanf(name, "%u:%u", &maj, &min) == 2) { | ||
155 | res = MKDEV(maj, min); | ||
156 | if (maj != MAJOR(res) || min != MINOR(res)) | ||
157 | goto fail; | ||
158 | } else { | ||
159 | res = new_decode_dev(simple_strtoul(name, &p, 16)); | ||
160 | if (*p) | ||
161 | goto fail; | ||
162 | } | ||
163 | goto done; | ||
164 | } | ||
165 | name += 5; | ||
166 | res = Root_NFS; | ||
167 | if (strcmp(name, "nfs") == 0) | ||
168 | goto done; | ||
169 | res = Root_RAM0; | ||
170 | if (strcmp(name, "ram") == 0) | ||
171 | goto done; | ||
172 | |||
173 | if (strlen(name) > 31) | ||
174 | goto fail; | ||
175 | strcpy(s, name); | ||
176 | for (p = s; *p; p++) | ||
177 | if (*p == '/') | ||
178 | *p = '!'; | ||
179 | res = try_name(s, 0); | ||
180 | if (res) | ||
181 | goto done; | ||
182 | |||
183 | while (p > s && isdigit(p[-1])) | ||
184 | p--; | ||
185 | if (p == s || !*p || *p == '0') | ||
186 | goto fail; | ||
187 | part = simple_strtoul(p, NULL, 10); | ||
188 | *p = '\0'; | ||
189 | res = try_name(s, part); | ||
190 | if (res) | ||
191 | goto done; | ||
192 | |||
193 | if (p < s + 2 || !isdigit(p[-2]) || p[-1] != 'p') | ||
194 | goto fail; | ||
195 | p[-1] = '\0'; | ||
196 | res = try_name(s, part); | ||
197 | done: | ||
198 | #ifdef CONFIG_SYSFS | ||
199 | sys_umount("/sys", 0); | ||
200 | out: | ||
201 | if (!mkdir_err) | ||
202 | sys_rmdir("/sys"); | ||
203 | #endif | ||
204 | return res; | ||
205 | fail: | ||
206 | res = 0; | ||
207 | goto done; | ||
208 | } | ||
209 | |||
210 | static int __init root_dev_setup(char *line) | ||
211 | { | ||
212 | strlcpy(saved_root_name, line, sizeof(saved_root_name)); | ||
213 | return 1; | ||
214 | } | ||
215 | |||
216 | __setup("root=", root_dev_setup); | ||
217 | |||
218 | static char * __initdata root_mount_data; | ||
219 | static int __init root_data_setup(char *str) | ||
220 | { | ||
221 | root_mount_data = str; | ||
222 | return 1; | ||
223 | } | ||
224 | |||
225 | static char * __initdata root_fs_names; | ||
226 | static int __init fs_names_setup(char *str) | ||
227 | { | ||
228 | root_fs_names = str; | ||
229 | return 1; | ||
230 | } | ||
231 | |||
232 | static unsigned int __initdata root_delay; | ||
233 | static int __init root_delay_setup(char *str) | ||
234 | { | ||
235 | root_delay = simple_strtoul(str, NULL, 0); | ||
236 | return 1; | ||
237 | } | ||
238 | |||
239 | __setup("rootflags=", root_data_setup); | ||
240 | __setup("rootfstype=", fs_names_setup); | ||
241 | __setup("rootdelay=", root_delay_setup); | ||
242 | |||
243 | static void __init get_fs_names(char *page) | ||
244 | { | ||
245 | char *s = page; | ||
246 | |||
247 | if (root_fs_names) { | ||
248 | strcpy(page, root_fs_names); | ||
249 | while (*s++) { | ||
250 | if (s[-1] == ',') | ||
251 | s[-1] = '\0'; | ||
252 | } | ||
253 | } else { | ||
254 | int len = get_filesystem_list(page); | ||
255 | char *p, *next; | ||
256 | |||
257 | page[len] = '\0'; | ||
258 | for (p = page-1; p; p = next) { | ||
259 | next = strchr(++p, '\n'); | ||
260 | if (*p++ != '\t') | ||
261 | continue; | ||
262 | while ((*s++ = *p++) != '\n') | ||
263 | ; | ||
264 | s[-1] = '\0'; | ||
265 | } | ||
266 | } | ||
267 | *s = '\0'; | ||
268 | } | ||
269 | |||
270 | static int __init do_mount_root(char *name, char *fs, int flags, void *data) | ||
271 | { | ||
272 | int err = sys_mount(name, "/root", fs, flags, data); | ||
273 | if (err) | ||
274 | return err; | ||
275 | |||
276 | sys_chdir("/root"); | ||
277 | ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev; | ||
278 | printk("VFS: Mounted root (%s filesystem)%s.\n", | ||
279 | current->fs->pwdmnt->mnt_sb->s_type->name, | ||
280 | current->fs->pwdmnt->mnt_sb->s_flags & MS_RDONLY ? | ||
281 | " readonly" : ""); | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | void __init mount_block_root(char *name, int flags) | ||
286 | { | ||
287 | char *fs_names = __getname(); | ||
288 | char *p; | ||
289 | char b[BDEVNAME_SIZE]; | ||
290 | |||
291 | get_fs_names(fs_names); | ||
292 | retry: | ||
293 | for (p = fs_names; *p; p += strlen(p)+1) { | ||
294 | int err = do_mount_root(name, p, flags, root_mount_data); | ||
295 | switch (err) { | ||
296 | case 0: | ||
297 | goto out; | ||
298 | case -EACCES: | ||
299 | flags |= MS_RDONLY; | ||
300 | goto retry; | ||
301 | case -EINVAL: | ||
302 | continue; | ||
303 | } | ||
304 | /* | ||
305 | * Allow the user to distinguish between failed sys_open | ||
306 | * and bad superblock on root device. | ||
307 | */ | ||
308 | __bdevname(ROOT_DEV, b); | ||
309 | printk("VFS: Cannot open root device \"%s\" or %s\n", | ||
310 | root_device_name, b); | ||
311 | printk("Please append a correct \"root=\" boot option\n"); | ||
312 | |||
313 | panic("VFS: Unable to mount root fs on %s", b); | ||
314 | } | ||
315 | panic("VFS: Unable to mount root fs on %s", __bdevname(ROOT_DEV, b)); | ||
316 | out: | ||
317 | putname(fs_names); | ||
318 | } | ||
319 | |||
320 | #ifdef CONFIG_ROOT_NFS | ||
321 | static int __init mount_nfs_root(void) | ||
322 | { | ||
323 | void *data = nfs_root_data(); | ||
324 | |||
325 | create_dev("/dev/root", ROOT_DEV, NULL); | ||
326 | if (data && | ||
327 | do_mount_root("/dev/root", "nfs", root_mountflags, data) == 0) | ||
328 | return 1; | ||
329 | return 0; | ||
330 | } | ||
331 | #endif | ||
332 | |||
333 | #if defined(CONFIG_BLK_DEV_RAM) || defined(CONFIG_BLK_DEV_FD) | ||
334 | void __init change_floppy(char *fmt, ...) | ||
335 | { | ||
336 | struct termios termios; | ||
337 | char buf[80]; | ||
338 | char c; | ||
339 | int fd; | ||
340 | va_list args; | ||
341 | va_start(args, fmt); | ||
342 | vsprintf(buf, fmt, args); | ||
343 | va_end(args); | ||
344 | fd = sys_open("/dev/root", O_RDWR | O_NDELAY, 0); | ||
345 | if (fd >= 0) { | ||
346 | sys_ioctl(fd, FDEJECT, 0); | ||
347 | sys_close(fd); | ||
348 | } | ||
349 | printk(KERN_NOTICE "VFS: Insert %s and press ENTER\n", buf); | ||
350 | fd = sys_open("/dev/console", O_RDWR, 0); | ||
351 | if (fd >= 0) { | ||
352 | sys_ioctl(fd, TCGETS, (long)&termios); | ||
353 | termios.c_lflag &= ~ICANON; | ||
354 | sys_ioctl(fd, TCSETSF, (long)&termios); | ||
355 | sys_read(fd, &c, 1); | ||
356 | termios.c_lflag |= ICANON; | ||
357 | sys_ioctl(fd, TCSETSF, (long)&termios); | ||
358 | sys_close(fd); | ||
359 | } | ||
360 | } | ||
361 | #endif | ||
362 | |||
363 | void __init mount_root(void) | ||
364 | { | ||
365 | #ifdef CONFIG_ROOT_NFS | ||
366 | if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) { | ||
367 | if (mount_nfs_root()) | ||
368 | return; | ||
369 | |||
370 | printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n"); | ||
371 | ROOT_DEV = Root_FD0; | ||
372 | } | ||
373 | #endif | ||
374 | #ifdef CONFIG_BLK_DEV_FD | ||
375 | if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) { | ||
376 | /* rd_doload is 2 for a dual initrd/ramload setup */ | ||
377 | if (rd_doload==2) { | ||
378 | if (rd_load_disk(1)) { | ||
379 | ROOT_DEV = Root_RAM1; | ||
380 | root_device_name = NULL; | ||
381 | } | ||
382 | } else | ||
383 | change_floppy("root floppy"); | ||
384 | } | ||
385 | #endif | ||
386 | create_dev("/dev/root", ROOT_DEV, root_device_name); | ||
387 | mount_block_root("/dev/root", root_mountflags); | ||
388 | } | ||
389 | |||
390 | /* | ||
391 | * Prepare the namespace - decide what/where to mount, load ramdisks, etc. | ||
392 | */ | ||
393 | void __init prepare_namespace(void) | ||
394 | { | ||
395 | int is_floppy; | ||
396 | |||
397 | mount_devfs(); | ||
398 | |||
399 | if (root_delay) { | ||
400 | printk(KERN_INFO "Waiting %dsec before mounting root device...\n", | ||
401 | root_delay); | ||
402 | ssleep(root_delay); | ||
403 | } | ||
404 | |||
405 | md_run_setup(); | ||
406 | |||
407 | if (saved_root_name[0]) { | ||
408 | root_device_name = saved_root_name; | ||
409 | ROOT_DEV = name_to_dev_t(root_device_name); | ||
410 | if (strncmp(root_device_name, "/dev/", 5) == 0) | ||
411 | root_device_name += 5; | ||
412 | } | ||
413 | |||
414 | is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR; | ||
415 | |||
416 | if (initrd_load()) | ||
417 | goto out; | ||
418 | |||
419 | if (is_floppy && rd_doload && rd_load_disk(0)) | ||
420 | ROOT_DEV = Root_RAM0; | ||
421 | |||
422 | mount_root(); | ||
423 | out: | ||
424 | umount_devfs("/dev"); | ||
425 | sys_mount(".", "/", NULL, MS_MOVE, NULL); | ||
426 | sys_chroot("."); | ||
427 | security_sb_post_mountroot(); | ||
428 | mount_devfs_fs (); | ||
429 | } | ||
430 | |||
diff --git a/init/do_mounts.h b/init/do_mounts.h new file mode 100644 index 00000000000..de92bee4f35 --- /dev/null +++ b/init/do_mounts.h | |||
@@ -0,0 +1,92 @@ | |||
1 | #include <linux/config.h> | ||
2 | #include <linux/kernel.h> | ||
3 | #include <linux/devfs_fs_kernel.h> | ||
4 | #include <linux/init.h> | ||
5 | #include <linux/syscalls.h> | ||
6 | #include <linux/unistd.h> | ||
7 | #include <linux/slab.h> | ||
8 | #include <linux/mount.h> | ||
9 | #include <linux/major.h> | ||
10 | #include <linux/root_dev.h> | ||
11 | |||
12 | dev_t name_to_dev_t(char *name); | ||
13 | void change_floppy(char *fmt, ...); | ||
14 | void mount_block_root(char *name, int flags); | ||
15 | void mount_root(void); | ||
16 | extern int root_mountflags; | ||
17 | extern char *root_device_name; | ||
18 | |||
19 | #ifdef CONFIG_DEVFS_FS | ||
20 | |||
21 | void mount_devfs(void); | ||
22 | void umount_devfs(char *path); | ||
23 | int create_dev(char *name, dev_t dev, char *devfs_name); | ||
24 | |||
25 | #else | ||
26 | |||
27 | static inline void mount_devfs(void) {} | ||
28 | static inline void umount_devfs(const char *path) {} | ||
29 | |||
30 | static inline int create_dev(char *name, dev_t dev, char *devfs_name) | ||
31 | { | ||
32 | sys_unlink(name); | ||
33 | return sys_mknod(name, S_IFBLK|0600, new_encode_dev(dev)); | ||
34 | } | ||
35 | |||
36 | #endif | ||
37 | |||
38 | #if BITS_PER_LONG == 32 | ||
39 | static inline u32 bstat(char *name) | ||
40 | { | ||
41 | struct stat64 stat; | ||
42 | if (sys_stat64(name, &stat) != 0) | ||
43 | return 0; | ||
44 | if (!S_ISBLK(stat.st_mode)) | ||
45 | return 0; | ||
46 | if (stat.st_rdev != (u32)stat.st_rdev) | ||
47 | return 0; | ||
48 | return stat.st_rdev; | ||
49 | } | ||
50 | #else | ||
51 | static inline u32 bstat(char *name) | ||
52 | { | ||
53 | struct stat stat; | ||
54 | if (sys_newstat(name, &stat) != 0) | ||
55 | return 0; | ||
56 | if (!S_ISBLK(stat.st_mode)) | ||
57 | return 0; | ||
58 | return stat.st_rdev; | ||
59 | } | ||
60 | #endif | ||
61 | |||
62 | #ifdef CONFIG_BLK_DEV_RAM | ||
63 | |||
64 | int __init rd_load_disk(int n); | ||
65 | int __init rd_load_image(char *from); | ||
66 | |||
67 | #else | ||
68 | |||
69 | static inline int rd_load_disk(int n) { return 0; } | ||
70 | static inline int rd_load_image(char *from) { return 0; } | ||
71 | |||
72 | #endif | ||
73 | |||
74 | #ifdef CONFIG_BLK_DEV_INITRD | ||
75 | |||
76 | int __init initrd_load(void); | ||
77 | |||
78 | #else | ||
79 | |||
80 | static inline int initrd_load(void) { return 0; } | ||
81 | |||
82 | #endif | ||
83 | |||
84 | #ifdef CONFIG_BLK_DEV_MD | ||
85 | |||
86 | void md_run_setup(void); | ||
87 | |||
88 | #else | ||
89 | |||
90 | static inline void md_run_setup(void) {} | ||
91 | |||
92 | #endif | ||
diff --git a/init/do_mounts_devfs.c b/init/do_mounts_devfs.c new file mode 100644 index 00000000000..cc526474690 --- /dev/null +++ b/init/do_mounts_devfs.c | |||
@@ -0,0 +1,137 @@ | |||
1 | |||
2 | #include <linux/kernel.h> | ||
3 | #include <linux/dirent.h> | ||
4 | #include <linux/string.h> | ||
5 | |||
6 | #include "do_mounts.h" | ||
7 | |||
8 | void __init mount_devfs(void) | ||
9 | { | ||
10 | sys_mount("devfs", "/dev", "devfs", 0, NULL); | ||
11 | } | ||
12 | |||
13 | void __init umount_devfs(char *path) | ||
14 | { | ||
15 | sys_umount(path, 0); | ||
16 | } | ||
17 | |||
18 | /* | ||
19 | * If the dir will fit in *buf, return its length. If it won't fit, return | ||
20 | * zero. Return -ve on error. | ||
21 | */ | ||
22 | static int __init do_read_dir(int fd, void *buf, int len) | ||
23 | { | ||
24 | long bytes, n; | ||
25 | char *p = buf; | ||
26 | sys_lseek(fd, 0, 0); | ||
27 | |||
28 | for (bytes = 0; bytes < len; bytes += n) { | ||
29 | n = sys_getdents64(fd, (struct linux_dirent64 *)(p + bytes), | ||
30 | len - bytes); | ||
31 | if (n < 0) | ||
32 | return n; | ||
33 | if (n == 0) | ||
34 | return bytes; | ||
35 | } | ||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | /* | ||
40 | * Try to read all of a directory. Returns the contents at *p, which | ||
41 | * is kmalloced memory. Returns the number of bytes read at *len. Returns | ||
42 | * NULL on error. | ||
43 | */ | ||
44 | static void * __init read_dir(char *path, int *len) | ||
45 | { | ||
46 | int size; | ||
47 | int fd = sys_open(path, 0, 0); | ||
48 | |||
49 | *len = 0; | ||
50 | if (fd < 0) | ||
51 | return NULL; | ||
52 | |||
53 | for (size = 1 << 9; size <= (PAGE_SIZE << MAX_ORDER); size <<= 1) { | ||
54 | void *p = kmalloc(size, GFP_KERNEL); | ||
55 | int n; | ||
56 | if (!p) | ||
57 | break; | ||
58 | n = do_read_dir(fd, p, size); | ||
59 | if (n > 0) { | ||
60 | sys_close(fd); | ||
61 | *len = n; | ||
62 | return p; | ||
63 | } | ||
64 | kfree(p); | ||
65 | if (n == -EINVAL) | ||
66 | continue; /* Try a larger buffer */ | ||
67 | if (n < 0) | ||
68 | break; | ||
69 | } | ||
70 | sys_close(fd); | ||
71 | return NULL; | ||
72 | } | ||
73 | |||
74 | /* | ||
75 | * recursively scan <path>, looking for a device node of type <dev> | ||
76 | */ | ||
77 | static int __init find_in_devfs(char *path, unsigned dev) | ||
78 | { | ||
79 | char *end = path + strlen(path); | ||
80 | int rest = path + 64 - end; | ||
81 | int size; | ||
82 | char *p = read_dir(path, &size); | ||
83 | char *s; | ||
84 | |||
85 | if (!p) | ||
86 | return -1; | ||
87 | for (s = p; s < p + size; s += ((struct linux_dirent64 *)s)->d_reclen) { | ||
88 | struct linux_dirent64 *d = (struct linux_dirent64 *)s; | ||
89 | if (strlen(d->d_name) + 2 > rest) | ||
90 | continue; | ||
91 | switch (d->d_type) { | ||
92 | case DT_BLK: | ||
93 | sprintf(end, "/%s", d->d_name); | ||
94 | if (bstat(path) != dev) | ||
95 | break; | ||
96 | kfree(p); | ||
97 | return 0; | ||
98 | case DT_DIR: | ||
99 | if (strcmp(d->d_name, ".") == 0) | ||
100 | break; | ||
101 | if (strcmp(d->d_name, "..") == 0) | ||
102 | break; | ||
103 | sprintf(end, "/%s", d->d_name); | ||
104 | if (find_in_devfs(path, dev) < 0) | ||
105 | break; | ||
106 | kfree(p); | ||
107 | return 0; | ||
108 | } | ||
109 | } | ||
110 | kfree(p); | ||
111 | return -1; | ||
112 | } | ||
113 | |||
114 | /* | ||
115 | * create a device node called <name> which points to | ||
116 | * <devfs_name> if possible, otherwise find a device node | ||
117 | * which matches <dev> and make <name> a symlink pointing to it. | ||
118 | */ | ||
119 | int __init create_dev(char *name, dev_t dev, char *devfs_name) | ||
120 | { | ||
121 | char path[64]; | ||
122 | |||
123 | sys_unlink(name); | ||
124 | if (devfs_name && devfs_name[0]) { | ||
125 | if (strncmp(devfs_name, "/dev/", 5) == 0) | ||
126 | devfs_name += 5; | ||
127 | sprintf(path, "/dev/%s", devfs_name); | ||
128 | if (sys_access(path, 0) == 0) | ||
129 | return sys_symlink(devfs_name, name); | ||
130 | } | ||
131 | if (!dev) | ||
132 | return -1; | ||
133 | strcpy(path, "/dev"); | ||
134 | if (find_in_devfs(path, new_encode_dev(dev)) < 0) | ||
135 | return -1; | ||
136 | return sys_symlink(path + 5, name); | ||
137 | } | ||
diff --git a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c new file mode 100644 index 00000000000..07e7d31f2d0 --- /dev/null +++ b/init/do_mounts_initrd.c | |||
@@ -0,0 +1,121 @@ | |||
1 | #define __KERNEL_SYSCALLS__ | ||
2 | #include <linux/unistd.h> | ||
3 | #include <linux/kernel.h> | ||
4 | #include <linux/fs.h> | ||
5 | #include <linux/minix_fs.h> | ||
6 | #include <linux/ext2_fs.h> | ||
7 | #include <linux/romfs_fs.h> | ||
8 | #include <linux/initrd.h> | ||
9 | #include <linux/sched.h> | ||
10 | |||
11 | #include "do_mounts.h" | ||
12 | |||
13 | unsigned long initrd_start, initrd_end; | ||
14 | int initrd_below_start_ok; | ||
15 | unsigned int real_root_dev; /* do_proc_dointvec cannot handle kdev_t */ | ||
16 | static int __initdata old_fd, root_fd; | ||
17 | static int __initdata mount_initrd = 1; | ||
18 | |||
19 | static int __init no_initrd(char *str) | ||
20 | { | ||
21 | mount_initrd = 0; | ||
22 | return 1; | ||
23 | } | ||
24 | |||
25 | __setup("noinitrd", no_initrd); | ||
26 | |||
27 | static int __init do_linuxrc(void * shell) | ||
28 | { | ||
29 | static char *argv[] = { "linuxrc", NULL, }; | ||
30 | extern char * envp_init[]; | ||
31 | |||
32 | sys_close(old_fd);sys_close(root_fd); | ||
33 | sys_close(0);sys_close(1);sys_close(2); | ||
34 | sys_setsid(); | ||
35 | (void) sys_open("/dev/console",O_RDWR,0); | ||
36 | (void) sys_dup(0); | ||
37 | (void) sys_dup(0); | ||
38 | return execve(shell, argv, envp_init); | ||
39 | } | ||
40 | |||
41 | static void __init handle_initrd(void) | ||
42 | { | ||
43 | int error; | ||
44 | int i, pid; | ||
45 | |||
46 | real_root_dev = new_encode_dev(ROOT_DEV); | ||
47 | create_dev("/dev/root.old", Root_RAM0, NULL); | ||
48 | /* mount initrd on rootfs' /root */ | ||
49 | mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY); | ||
50 | sys_mkdir("/old", 0700); | ||
51 | root_fd = sys_open("/", 0, 0); | ||
52 | old_fd = sys_open("/old", 0, 0); | ||
53 | /* move initrd over / and chdir/chroot in initrd root */ | ||
54 | sys_chdir("/root"); | ||
55 | sys_mount(".", "/", NULL, MS_MOVE, NULL); | ||
56 | sys_chroot("."); | ||
57 | mount_devfs_fs (); | ||
58 | |||
59 | pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); | ||
60 | if (pid > 0) { | ||
61 | while (pid != sys_wait4(-1, &i, 0, NULL)) | ||
62 | yield(); | ||
63 | } | ||
64 | |||
65 | /* move initrd to rootfs' /old */ | ||
66 | sys_fchdir(old_fd); | ||
67 | sys_mount("/", ".", NULL, MS_MOVE, NULL); | ||
68 | /* switch root and cwd back to / of rootfs */ | ||
69 | sys_fchdir(root_fd); | ||
70 | sys_chroot("."); | ||
71 | sys_close(old_fd); | ||
72 | sys_close(root_fd); | ||
73 | umount_devfs("/old/dev"); | ||
74 | |||
75 | if (new_decode_dev(real_root_dev) == Root_RAM0) { | ||
76 | sys_chdir("/old"); | ||
77 | return; | ||
78 | } | ||
79 | |||
80 | ROOT_DEV = new_decode_dev(real_root_dev); | ||
81 | mount_root(); | ||
82 | |||
83 | printk(KERN_NOTICE "Trying to move old root to /initrd ... "); | ||
84 | error = sys_mount("/old", "/root/initrd", NULL, MS_MOVE, NULL); | ||
85 | if (!error) | ||
86 | printk("okay\n"); | ||
87 | else { | ||
88 | int fd = sys_open("/dev/root.old", O_RDWR, 0); | ||
89 | printk("failed\n"); | ||
90 | printk(KERN_NOTICE "Unmounting old root\n"); | ||
91 | sys_umount("/old", MNT_DETACH); | ||
92 | printk(KERN_NOTICE "Trying to free ramdisk memory ... "); | ||
93 | if (fd < 0) { | ||
94 | error = fd; | ||
95 | } else { | ||
96 | error = sys_ioctl(fd, BLKFLSBUF, 0); | ||
97 | sys_close(fd); | ||
98 | } | ||
99 | printk(!error ? "okay\n" : "failed\n"); | ||
100 | } | ||
101 | } | ||
102 | |||
103 | int __init initrd_load(void) | ||
104 | { | ||
105 | if (mount_initrd) { | ||
106 | create_dev("/dev/ram", Root_RAM0, NULL); | ||
107 | /* | ||
108 | * Load the initrd data into /dev/ram0. Execute it as initrd | ||
109 | * unless /dev/ram0 is supposed to be our actual root device, | ||
110 | * in that case the ram disk is just set up here, and gets | ||
111 | * mounted in the normal path. | ||
112 | */ | ||
113 | if (rd_load_image("/initrd.image") && ROOT_DEV != Root_RAM0) { | ||
114 | sys_unlink("/initrd.image"); | ||
115 | handle_initrd(); | ||
116 | return 1; | ||
117 | } | ||
118 | } | ||
119 | sys_unlink("/initrd.image"); | ||
120 | return 0; | ||
121 | } | ||
diff --git a/init/do_mounts_md.c b/init/do_mounts_md.c new file mode 100644 index 00000000000..3fbc3555ce9 --- /dev/null +++ b/init/do_mounts_md.c | |||
@@ -0,0 +1,290 @@ | |||
1 | |||
2 | #include <linux/raid/md.h> | ||
3 | |||
4 | #include "do_mounts.h" | ||
5 | |||
6 | /* | ||
7 | * When md (and any require personalities) are compiled into the kernel | ||
8 | * (not a module), arrays can be assembles are boot time using with AUTODETECT | ||
9 | * where specially marked partitions are registered with md_autodetect_dev(), | ||
10 | * and with MD_BOOT where devices to be collected are given on the boot line | ||
11 | * with md=..... | ||
12 | * The code for that is here. | ||
13 | */ | ||
14 | |||
15 | static int __initdata raid_noautodetect, raid_autopart; | ||
16 | |||
17 | static struct { | ||
18 | int minor; | ||
19 | int partitioned; | ||
20 | int pers; | ||
21 | int chunk; | ||
22 | char *device_names; | ||
23 | } md_setup_args[MAX_MD_DEVS] __initdata; | ||
24 | |||
25 | static int md_setup_ents __initdata; | ||
26 | |||
27 | extern int mdp_major; | ||
28 | /* | ||
29 | * Parse the command-line parameters given our kernel, but do not | ||
30 | * actually try to invoke the MD device now; that is handled by | ||
31 | * md_setup_drive after the low-level disk drivers have initialised. | ||
32 | * | ||
33 | * 27/11/1999: Fixed to work correctly with the 2.3 kernel (which | ||
34 | * assigns the task of parsing integer arguments to the | ||
35 | * invoked program now). Added ability to initialise all | ||
36 | * the MD devices (by specifying multiple "md=" lines) | ||
37 | * instead of just one. -- KTK | ||
38 | * 18May2000: Added support for persistent-superblock arrays: | ||
39 | * md=n,0,factor,fault,device-list uses RAID0 for device n | ||
40 | * md=n,-1,factor,fault,device-list uses LINEAR for device n | ||
41 | * md=n,device-list reads a RAID superblock from the devices | ||
42 | * elements in device-list are read by name_to_kdev_t so can be | ||
43 | * a hex number or something like /dev/hda1 /dev/sdb | ||
44 | * 2001-06-03: Dave Cinege <dcinege@psychosis.com> | ||
45 | * Shifted name_to_kdev_t() and related operations to md_set_drive() | ||
46 | * for later execution. Rewrote section to make devfs compatible. | ||
47 | */ | ||
48 | static int __init md_setup(char *str) | ||
49 | { | ||
50 | int minor, level, factor, fault, pers, partitioned = 0; | ||
51 | char *pername = ""; | ||
52 | char *str1; | ||
53 | int ent; | ||
54 | |||
55 | if (*str == 'd') { | ||
56 | partitioned = 1; | ||
57 | str++; | ||
58 | } | ||
59 | if (get_option(&str, &minor) != 2) { /* MD Number */ | ||
60 | printk(KERN_WARNING "md: Too few arguments supplied to md=.\n"); | ||
61 | return 0; | ||
62 | } | ||
63 | str1 = str; | ||
64 | if (minor >= MAX_MD_DEVS) { | ||
65 | printk(KERN_WARNING "md: md=%d, Minor device number too high.\n", minor); | ||
66 | return 0; | ||
67 | } | ||
68 | for (ent=0 ; ent< md_setup_ents ; ent++) | ||
69 | if (md_setup_args[ent].minor == minor && | ||
70 | md_setup_args[ent].partitioned == partitioned) { | ||
71 | printk(KERN_WARNING "md: md=%s%d, Specified more than once. " | ||
72 | "Replacing previous definition.\n", partitioned?"d":"", minor); | ||
73 | break; | ||
74 | } | ||
75 | if (ent >= MAX_MD_DEVS) { | ||
76 | printk(KERN_WARNING "md: md=%s%d - too many md initialisations\n", partitioned?"d":"", minor); | ||
77 | return 0; | ||
78 | } | ||
79 | if (ent >= md_setup_ents) | ||
80 | md_setup_ents++; | ||
81 | switch (get_option(&str, &level)) { /* RAID Personality */ | ||
82 | case 2: /* could be 0 or -1.. */ | ||
83 | if (level == 0 || level == LEVEL_LINEAR) { | ||
84 | if (get_option(&str, &factor) != 2 || /* Chunk Size */ | ||
85 | get_option(&str, &fault) != 2) { | ||
86 | printk(KERN_WARNING "md: Too few arguments supplied to md=.\n"); | ||
87 | return 0; | ||
88 | } | ||
89 | md_setup_args[ent].pers = level; | ||
90 | md_setup_args[ent].chunk = 1 << (factor+12); | ||
91 | if (level == LEVEL_LINEAR) { | ||
92 | pers = LINEAR; | ||
93 | pername = "linear"; | ||
94 | } else { | ||
95 | pers = RAID0; | ||
96 | pername = "raid0"; | ||
97 | } | ||
98 | md_setup_args[ent].pers = pers; | ||
99 | break; | ||
100 | } | ||
101 | /* FALL THROUGH */ | ||
102 | case 1: /* the first device is numeric */ | ||
103 | str = str1; | ||
104 | /* FALL THROUGH */ | ||
105 | case 0: | ||
106 | md_setup_args[ent].pers = 0; | ||
107 | pername="super-block"; | ||
108 | } | ||
109 | |||
110 | printk(KERN_INFO "md: Will configure md%d (%s) from %s, below.\n", | ||
111 | minor, pername, str); | ||
112 | md_setup_args[ent].device_names = str; | ||
113 | md_setup_args[ent].partitioned = partitioned; | ||
114 | md_setup_args[ent].minor = minor; | ||
115 | |||
116 | return 1; | ||
117 | } | ||
118 | |||
119 | #define MdpMinorShift 6 | ||
120 | |||
121 | static void __init md_setup_drive(void) | ||
122 | { | ||
123 | int minor, i, ent, partitioned; | ||
124 | dev_t dev; | ||
125 | dev_t devices[MD_SB_DISKS+1]; | ||
126 | |||
127 | for (ent = 0; ent < md_setup_ents ; ent++) { | ||
128 | int fd; | ||
129 | int err = 0; | ||
130 | char *devname; | ||
131 | mdu_disk_info_t dinfo; | ||
132 | char name[16], devfs_name[16]; | ||
133 | |||
134 | minor = md_setup_args[ent].minor; | ||
135 | partitioned = md_setup_args[ent].partitioned; | ||
136 | devname = md_setup_args[ent].device_names; | ||
137 | |||
138 | sprintf(name, "/dev/md%s%d", partitioned?"_d":"", minor); | ||
139 | sprintf(devfs_name, "/dev/md/%s%d", partitioned?"d":"", minor); | ||
140 | if (partitioned) | ||
141 | dev = MKDEV(mdp_major, minor << MdpMinorShift); | ||
142 | else | ||
143 | dev = MKDEV(MD_MAJOR, minor); | ||
144 | create_dev(name, dev, devfs_name); | ||
145 | for (i = 0; i < MD_SB_DISKS && devname != 0; i++) { | ||
146 | char *p; | ||
147 | char comp_name[64]; | ||
148 | u32 rdev; | ||
149 | |||
150 | p = strchr(devname, ','); | ||
151 | if (p) | ||
152 | *p++ = 0; | ||
153 | |||
154 | dev = name_to_dev_t(devname); | ||
155 | if (strncmp(devname, "/dev/", 5) == 0) | ||
156 | devname += 5; | ||
157 | snprintf(comp_name, 63, "/dev/%s", devname); | ||
158 | rdev = bstat(comp_name); | ||
159 | if (rdev) | ||
160 | dev = new_decode_dev(rdev); | ||
161 | if (!dev) { | ||
162 | printk(KERN_WARNING "md: Unknown device name: %s\n", devname); | ||
163 | break; | ||
164 | } | ||
165 | |||
166 | devices[i] = dev; | ||
167 | |||
168 | devname = p; | ||
169 | } | ||
170 | devices[i] = 0; | ||
171 | |||
172 | if (!i) | ||
173 | continue; | ||
174 | |||
175 | printk(KERN_INFO "md: Loading md%s%d: %s\n", | ||
176 | partitioned ? "_d" : "", minor, | ||
177 | md_setup_args[ent].device_names); | ||
178 | |||
179 | fd = sys_open(name, 0, 0); | ||
180 | if (fd < 0) { | ||
181 | printk(KERN_ERR "md: open failed - cannot start " | ||
182 | "array %s\n", name); | ||
183 | continue; | ||
184 | } | ||
185 | if (sys_ioctl(fd, SET_ARRAY_INFO, 0) == -EBUSY) { | ||
186 | printk(KERN_WARNING | ||
187 | "md: Ignoring md=%d, already autodetected. (Use raid=noautodetect)\n", | ||
188 | minor); | ||
189 | sys_close(fd); | ||
190 | continue; | ||
191 | } | ||
192 | |||
193 | if (md_setup_args[ent].pers) { | ||
194 | /* non-persistent */ | ||
195 | mdu_array_info_t ainfo; | ||
196 | ainfo.level = pers_to_level(md_setup_args[ent].pers); | ||
197 | ainfo.size = 0; | ||
198 | ainfo.nr_disks =0; | ||
199 | ainfo.raid_disks =0; | ||
200 | while (devices[ainfo.raid_disks]) | ||
201 | ainfo.raid_disks++; | ||
202 | ainfo.md_minor =minor; | ||
203 | ainfo.not_persistent = 1; | ||
204 | |||
205 | ainfo.state = (1 << MD_SB_CLEAN); | ||
206 | ainfo.layout = 0; | ||
207 | ainfo.chunk_size = md_setup_args[ent].chunk; | ||
208 | err = sys_ioctl(fd, SET_ARRAY_INFO, (long)&ainfo); | ||
209 | for (i = 0; !err && i <= MD_SB_DISKS; i++) { | ||
210 | dev = devices[i]; | ||
211 | if (!dev) | ||
212 | break; | ||
213 | dinfo.number = i; | ||
214 | dinfo.raid_disk = i; | ||
215 | dinfo.state = (1<<MD_DISK_ACTIVE)|(1<<MD_DISK_SYNC); | ||
216 | dinfo.major = MAJOR(dev); | ||
217 | dinfo.minor = MINOR(dev); | ||
218 | err = sys_ioctl(fd, ADD_NEW_DISK, (long)&dinfo); | ||
219 | } | ||
220 | } else { | ||
221 | /* persistent */ | ||
222 | for (i = 0; i <= MD_SB_DISKS; i++) { | ||
223 | dev = devices[i]; | ||
224 | if (!dev) | ||
225 | break; | ||
226 | dinfo.major = MAJOR(dev); | ||
227 | dinfo.minor = MINOR(dev); | ||
228 | sys_ioctl(fd, ADD_NEW_DISK, (long)&dinfo); | ||
229 | } | ||
230 | } | ||
231 | if (!err) | ||
232 | err = sys_ioctl(fd, RUN_ARRAY, 0); | ||
233 | if (err) | ||
234 | printk(KERN_WARNING "md: starting md%d failed\n", minor); | ||
235 | else { | ||
236 | /* reread the partition table. | ||
237 | * I (neilb) and not sure why this is needed, but I cannot | ||
238 | * boot a kernel with devfs compiled in from partitioned md | ||
239 | * array without it | ||
240 | */ | ||
241 | sys_close(fd); | ||
242 | fd = sys_open(name, 0, 0); | ||
243 | sys_ioctl(fd, BLKRRPART, 0); | ||
244 | } | ||
245 | sys_close(fd); | ||
246 | } | ||
247 | } | ||
248 | |||
249 | static int __init raid_setup(char *str) | ||
250 | { | ||
251 | int len, pos; | ||
252 | |||
253 | len = strlen(str) + 1; | ||
254 | pos = 0; | ||
255 | |||
256 | while (pos < len) { | ||
257 | char *comma = strchr(str+pos, ','); | ||
258 | int wlen; | ||
259 | if (comma) | ||
260 | wlen = (comma-str)-pos; | ||
261 | else wlen = (len-1)-pos; | ||
262 | |||
263 | if (!strncmp(str, "noautodetect", wlen)) | ||
264 | raid_noautodetect = 1; | ||
265 | if (strncmp(str, "partitionable", wlen)==0) | ||
266 | raid_autopart = 1; | ||
267 | if (strncmp(str, "part", wlen)==0) | ||
268 | raid_autopart = 1; | ||
269 | pos += wlen+1; | ||
270 | } | ||
271 | return 1; | ||
272 | } | ||
273 | |||
274 | __setup("raid=", raid_setup); | ||
275 | __setup("md=", md_setup); | ||
276 | |||
277 | void __init md_run_setup(void) | ||
278 | { | ||
279 | create_dev("/dev/md0", MKDEV(MD_MAJOR, 0), "md/0"); | ||
280 | if (raid_noautodetect) | ||
281 | printk(KERN_INFO "md: Skipping autodetection of RAID arrays. (raid=noautodetect)\n"); | ||
282 | else { | ||
283 | int fd = sys_open("/dev/md0", 0, 0); | ||
284 | if (fd >= 0) { | ||
285 | sys_ioctl(fd, RAID_AUTORUN, raid_autopart); | ||
286 | sys_close(fd); | ||
287 | } | ||
288 | } | ||
289 | md_setup_drive(); | ||
290 | } | ||
diff --git a/init/do_mounts_rd.c b/init/do_mounts_rd.c new file mode 100644 index 00000000000..c10b08a8098 --- /dev/null +++ b/init/do_mounts_rd.c | |||
@@ -0,0 +1,429 @@ | |||
1 | |||
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 | |||
13 | #define BUILD_CRAMDISK | ||
14 | |||
15 | int __initdata rd_prompt = 1;/* 1 = prompt for RAM disk, 0 = don't prompt */ | ||
16 | |||
17 | static int __init prompt_ramdisk(char *str) | ||
18 | { | ||
19 | rd_prompt = simple_strtol(str,NULL,0) & 1; | ||
20 | return 1; | ||
21 | } | ||
22 | __setup("prompt_ramdisk=", prompt_ramdisk); | ||
23 | |||
24 | int __initdata rd_image_start; /* starting block # of image */ | ||
25 | |||
26 | static int __init ramdisk_start_setup(char *str) | ||
27 | { | ||
28 | rd_image_start = simple_strtol(str,NULL,0); | ||
29 | return 1; | ||
30 | } | ||
31 | __setup("ramdisk_start=", ramdisk_start_setup); | ||
32 | |||
33 | static int __init crd_load(int in_fd, int out_fd); | ||
34 | |||
35 | /* | ||
36 | * This routine tries to find a RAM disk image to load, and returns the | ||
37 | * number of blocks to read for a non-compressed image, 0 if the image | ||
38 | * is a compressed image, and -1 if an image with the right magic | ||
39 | * numbers could not be found. | ||
40 | * | ||
41 | * We currently check for the following magic numbers: | ||
42 | * minix | ||
43 | * ext2 | ||
44 | * romfs | ||
45 | * cramfs | ||
46 | * gzip | ||
47 | */ | ||
48 | static int __init | ||
49 | identify_ramdisk_image(int fd, int start_block) | ||
50 | { | ||
51 | const int size = 512; | ||
52 | struct minix_super_block *minixsb; | ||
53 | struct ext2_super_block *ext2sb; | ||
54 | struct romfs_super_block *romfsb; | ||
55 | struct cramfs_super *cramfsb; | ||
56 | int nblocks = -1; | ||
57 | unsigned char *buf; | ||
58 | |||
59 | buf = kmalloc(size, GFP_KERNEL); | ||
60 | if (buf == 0) | ||
61 | return -1; | ||
62 | |||
63 | minixsb = (struct minix_super_block *) buf; | ||
64 | ext2sb = (struct ext2_super_block *) buf; | ||
65 | romfsb = (struct romfs_super_block *) buf; | ||
66 | cramfsb = (struct cramfs_super *) buf; | ||
67 | memset(buf, 0xe5, size); | ||
68 | |||
69 | /* | ||
70 | * Read block 0 to test for gzipped kernel | ||
71 | */ | ||
72 | sys_lseek(fd, start_block * BLOCK_SIZE, 0); | ||
73 | sys_read(fd, buf, size); | ||
74 | |||
75 | /* | ||
76 | * If it matches the gzip magic numbers, return -1 | ||
77 | */ | ||
78 | if (buf[0] == 037 && ((buf[1] == 0213) || (buf[1] == 0236))) { | ||
79 | printk(KERN_NOTICE | ||
80 | "RAMDISK: Compressed image found at block %d\n", | ||
81 | start_block); | ||
82 | nblocks = 0; | ||
83 | goto done; | ||
84 | } | ||
85 | |||
86 | /* romfs is at block zero too */ | ||
87 | if (romfsb->word0 == ROMSB_WORD0 && | ||
88 | romfsb->word1 == ROMSB_WORD1) { | ||
89 | printk(KERN_NOTICE | ||
90 | "RAMDISK: romfs filesystem found at block %d\n", | ||
91 | start_block); | ||
92 | nblocks = (ntohl(romfsb->size)+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS; | ||
93 | goto done; | ||
94 | } | ||
95 | |||
96 | if (cramfsb->magic == CRAMFS_MAGIC) { | ||
97 | printk(KERN_NOTICE | ||
98 | "RAMDISK: cramfs filesystem found at block %d\n", | ||
99 | start_block); | ||
100 | nblocks = (cramfsb->size + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS; | ||
101 | goto done; | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * Read block 1 to test for minix and ext2 superblock | ||
106 | */ | ||
107 | sys_lseek(fd, (start_block+1) * BLOCK_SIZE, 0); | ||
108 | sys_read(fd, buf, size); | ||
109 | |||
110 | /* Try minix */ | ||
111 | if (minixsb->s_magic == MINIX_SUPER_MAGIC || | ||
112 | minixsb->s_magic == MINIX_SUPER_MAGIC2) { | ||
113 | printk(KERN_NOTICE | ||
114 | "RAMDISK: Minix filesystem found at block %d\n", | ||
115 | start_block); | ||
116 | nblocks = minixsb->s_nzones << minixsb->s_log_zone_size; | ||
117 | goto done; | ||
118 | } | ||
119 | |||
120 | /* Try ext2 */ | ||
121 | if (ext2sb->s_magic == cpu_to_le16(EXT2_SUPER_MAGIC)) { | ||
122 | printk(KERN_NOTICE | ||
123 | "RAMDISK: ext2 filesystem found at block %d\n", | ||
124 | start_block); | ||
125 | nblocks = le32_to_cpu(ext2sb->s_blocks_count) << | ||
126 | le32_to_cpu(ext2sb->s_log_block_size); | ||
127 | goto done; | ||
128 | } | ||
129 | |||
130 | printk(KERN_NOTICE | ||
131 | "RAMDISK: Couldn't find valid RAM disk image starting at %d.\n", | ||
132 | start_block); | ||
133 | |||
134 | done: | ||
135 | sys_lseek(fd, start_block * BLOCK_SIZE, 0); | ||
136 | kfree(buf); | ||
137 | return nblocks; | ||
138 | } | ||
139 | |||
140 | int __init rd_load_image(char *from) | ||
141 | { | ||
142 | int res = 0; | ||
143 | int in_fd, out_fd; | ||
144 | unsigned long rd_blocks, devblocks; | ||
145 | int nblocks, i, disk; | ||
146 | char *buf = NULL; | ||
147 | unsigned short rotate = 0; | ||
148 | #if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_PPC_ISERIES) | ||
149 | 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 | |||
160 | nblocks = identify_ramdisk_image(in_fd, rd_image_start); | ||
161 | if (nblocks < 0) | ||
162 | goto done; | ||
163 | |||
164 | if (nblocks == 0) { | ||
165 | #ifdef BUILD_CRAMDISK | ||
166 | if (crd_load(in_fd, out_fd) == 0) | ||
167 | goto successful_load; | ||
168 | #else | ||
169 | printk(KERN_NOTICE | ||
170 | "RAMDISK: Kernel does not support compressed " | ||
171 | "RAM disk images\n"); | ||
172 | #endif | ||
173 | goto done; | ||
174 | } | ||
175 | |||
176 | /* | ||
177 | * NOTE NOTE: nblocks is not actually blocks but | ||
178 | * the number of kibibytes of data to load into a ramdisk. | ||
179 | * So any ramdisk block size that is a multiple of 1KiB should | ||
180 | * work when the appropriate ramdisk_blocksize is specified | ||
181 | * on the command line. | ||
182 | * | ||
183 | * The default ramdisk_blocksize is 1KiB and it is generally | ||
184 | * silly to use anything else, so make sure to use 1KiB | ||
185 | * blocksize while generating ext2fs ramdisk-images. | ||
186 | */ | ||
187 | if (sys_ioctl(out_fd, BLKGETSIZE, (unsigned long)&rd_blocks) < 0) | ||
188 | rd_blocks = 0; | ||
189 | else | ||
190 | rd_blocks >>= 1; | ||
191 | |||
192 | if (nblocks > rd_blocks) { | ||
193 | printk("RAMDISK: image too big! (%dKiB/%ldKiB)\n", | ||
194 | nblocks, rd_blocks); | ||
195 | goto done; | ||
196 | } | ||
197 | |||
198 | /* | ||
199 | * OK, time to copy in the data | ||
200 | */ | ||
201 | if (sys_ioctl(in_fd, BLKGETSIZE, (unsigned long)&devblocks) < 0) | ||
202 | devblocks = 0; | ||
203 | else | ||
204 | devblocks >>= 1; | ||
205 | |||
206 | if (strcmp(from, "/initrd.image") == 0) | ||
207 | devblocks = nblocks; | ||
208 | |||
209 | if (devblocks == 0) { | ||
210 | printk(KERN_ERR "RAMDISK: could not determine device size\n"); | ||
211 | goto done; | ||
212 | } | ||
213 | |||
214 | buf = kmalloc(BLOCK_SIZE, GFP_KERNEL); | ||
215 | if (buf == 0) { | ||
216 | printk(KERN_ERR "RAMDISK: could not allocate buffer\n"); | ||
217 | goto done; | ||
218 | } | ||
219 | |||
220 | printk(KERN_NOTICE "RAMDISK: Loading %dKiB [%ld disk%s] into ram disk... ", | ||
221 | nblocks, ((nblocks-1)/devblocks)+1, nblocks>devblocks ? "s" : ""); | ||
222 | for (i = 0, disk = 1; i < nblocks; i++) { | ||
223 | if (i && (i % devblocks == 0)) { | ||
224 | printk("done disk #%d.\n", disk++); | ||
225 | rotate = 0; | ||
226 | if (sys_close(in_fd)) { | ||
227 | printk("Error closing the disk.\n"); | ||
228 | goto noclose_input; | ||
229 | } | ||
230 | change_floppy("disk #%d", disk); | ||
231 | in_fd = sys_open(from, O_RDONLY, 0); | ||
232 | if (in_fd < 0) { | ||
233 | printk("Error opening disk.\n"); | ||
234 | goto noclose_input; | ||
235 | } | ||
236 | printk("Loading disk #%d... ", disk); | ||
237 | } | ||
238 | sys_read(in_fd, buf, BLOCK_SIZE); | ||
239 | sys_write(out_fd, buf, BLOCK_SIZE); | ||
240 | #if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_PPC_ISERIES) | ||
241 | if (!(i % 16)) { | ||
242 | printk("%c\b", rotator[rotate & 0x3]); | ||
243 | rotate++; | ||
244 | } | ||
245 | #endif | ||
246 | } | ||
247 | printk("done.\n"); | ||
248 | |||
249 | successful_load: | ||
250 | res = 1; | ||
251 | done: | ||
252 | sys_close(in_fd); | ||
253 | noclose_input: | ||
254 | sys_close(out_fd); | ||
255 | out: | ||
256 | kfree(buf); | ||
257 | sys_unlink("/dev/ram"); | ||
258 | return res; | ||
259 | } | ||
260 | |||
261 | int __init rd_load_disk(int n) | ||
262 | { | ||
263 | if (rd_prompt) | ||
264 | change_floppy("root floppy disk to be loaded into RAM disk"); | ||
265 | create_dev("/dev/root", ROOT_DEV, root_device_name); | ||
266 | create_dev("/dev/ram", MKDEV(RAMDISK_MAJOR, n), NULL); | ||
267 | return rd_load_image("/dev/root"); | ||
268 | } | ||
269 | |||
270 | #ifdef BUILD_CRAMDISK | ||
271 | |||
272 | /* | ||
273 | * gzip declarations | ||
274 | */ | ||
275 | |||
276 | #define OF(args) args | ||
277 | |||
278 | #ifndef memzero | ||
279 | #define memzero(s, n) memset ((s), 0, (n)) | ||
280 | #endif | ||
281 | |||
282 | typedef unsigned char uch; | ||
283 | typedef unsigned short ush; | ||
284 | typedef unsigned long ulg; | ||
285 | |||
286 | #define INBUFSIZ 4096 | ||
287 | #define WSIZE 0x8000 /* window size--must be a power of two, and */ | ||
288 | /* at least 32K for zip's deflate method */ | ||
289 | |||
290 | static uch *inbuf; | ||
291 | static uch *window; | ||
292 | |||
293 | static unsigned insize; /* valid bytes in inbuf */ | ||
294 | static unsigned inptr; /* index of next byte to be processed in inbuf */ | ||
295 | static unsigned outcnt; /* bytes in output buffer */ | ||
296 | static int exit_code; | ||
297 | static int unzip_error; | ||
298 | static long bytes_out; | ||
299 | static int crd_infd, crd_outfd; | ||
300 | |||
301 | #define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) | ||
302 | |||
303 | /* Diagnostic functions (stubbed out) */ | ||
304 | #define Assert(cond,msg) | ||
305 | #define Trace(x) | ||
306 | #define Tracev(x) | ||
307 | #define Tracevv(x) | ||
308 | #define Tracec(c,x) | ||
309 | #define Tracecv(c,x) | ||
310 | |||
311 | #define STATIC static | ||
312 | #define INIT __init | ||
313 | |||
314 | static int __init fill_inbuf(void); | ||
315 | static void __init flush_window(void); | ||
316 | static void __init *malloc(size_t size); | ||
317 | static void __init free(void *where); | ||
318 | static void __init error(char *m); | ||
319 | static void __init gzip_mark(void **); | ||
320 | static void __init gzip_release(void **); | ||
321 | |||
322 | #include "../lib/inflate.c" | ||
323 | |||
324 | static void __init *malloc(size_t size) | ||
325 | { | ||
326 | return kmalloc(size, GFP_KERNEL); | ||
327 | } | ||
328 | |||
329 | static void __init free(void *where) | ||
330 | { | ||
331 | kfree(where); | ||
332 | } | ||
333 | |||
334 | static void __init gzip_mark(void **ptr) | ||
335 | { | ||
336 | } | ||
337 | |||
338 | static void __init gzip_release(void **ptr) | ||
339 | { | ||
340 | } | ||
341 | |||
342 | |||
343 | /* =========================================================================== | ||
344 | * Fill the input buffer. This is called only when the buffer is empty | ||
345 | * and at least one byte is really needed. | ||
346 | * Returning -1 does not guarantee that gunzip() will ever return. | ||
347 | */ | ||
348 | static int __init fill_inbuf(void) | ||
349 | { | ||
350 | if (exit_code) return -1; | ||
351 | |||
352 | insize = sys_read(crd_infd, inbuf, INBUFSIZ); | ||
353 | if (insize == 0) { | ||
354 | error("RAMDISK: ran out of compressed data"); | ||
355 | return -1; | ||
356 | } | ||
357 | |||
358 | inptr = 1; | ||
359 | |||
360 | return inbuf[0]; | ||
361 | } | ||
362 | |||
363 | /* =========================================================================== | ||
364 | * Write the output window window[0..outcnt-1] and update crc and bytes_out. | ||
365 | * (Used for the decompressed data only.) | ||
366 | */ | ||
367 | static void __init flush_window(void) | ||
368 | { | ||
369 | ulg c = crc; /* temporary variable */ | ||
370 | unsigned n, written; | ||
371 | uch *in, ch; | ||
372 | |||
373 | written = sys_write(crd_outfd, window, outcnt); | ||
374 | if (written != outcnt && unzip_error == 0) { | ||
375 | printk(KERN_ERR "RAMDISK: incomplete write (%d != %d) %ld\n", | ||
376 | written, outcnt, bytes_out); | ||
377 | unzip_error = 1; | ||
378 | } | ||
379 | in = window; | ||
380 | for (n = 0; n < outcnt; n++) { | ||
381 | ch = *in++; | ||
382 | c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); | ||
383 | } | ||
384 | crc = c; | ||
385 | bytes_out += (ulg)outcnt; | ||
386 | outcnt = 0; | ||
387 | } | ||
388 | |||
389 | static void __init error(char *x) | ||
390 | { | ||
391 | printk(KERN_ERR "%s\n", x); | ||
392 | exit_code = 1; | ||
393 | unzip_error = 1; | ||
394 | } | ||
395 | |||
396 | static int __init crd_load(int in_fd, int out_fd) | ||
397 | { | ||
398 | int result; | ||
399 | |||
400 | insize = 0; /* valid bytes in inbuf */ | ||
401 | inptr = 0; /* index of next byte to be processed in inbuf */ | ||
402 | outcnt = 0; /* bytes in output buffer */ | ||
403 | exit_code = 0; | ||
404 | bytes_out = 0; | ||
405 | crc = (ulg)0xffffffffL; /* shift register contents */ | ||
406 | |||
407 | crd_infd = in_fd; | ||
408 | crd_outfd = out_fd; | ||
409 | inbuf = kmalloc(INBUFSIZ, GFP_KERNEL); | ||
410 | if (inbuf == 0) { | ||
411 | printk(KERN_ERR "RAMDISK: Couldn't allocate gzip buffer\n"); | ||
412 | return -1; | ||
413 | } | ||
414 | window = kmalloc(WSIZE, GFP_KERNEL); | ||
415 | if (window == 0) { | ||
416 | printk(KERN_ERR "RAMDISK: Couldn't allocate gzip window\n"); | ||
417 | kfree(inbuf); | ||
418 | return -1; | ||
419 | } | ||
420 | makecrc(); | ||
421 | result = gunzip(); | ||
422 | if (unzip_error) | ||
423 | result = 1; | ||
424 | kfree(inbuf); | ||
425 | kfree(window); | ||
426 | return result; | ||
427 | } | ||
428 | |||
429 | #endif /* BUILD_CRAMDISK */ | ||
diff --git a/init/initramfs.c b/init/initramfs.c new file mode 100644 index 00000000000..02c5ce64990 --- /dev/null +++ b/init/initramfs.c | |||
@@ -0,0 +1,500 @@ | |||
1 | #include <linux/init.h> | ||
2 | #include <linux/fs.h> | ||
3 | #include <linux/slab.h> | ||
4 | #include <linux/types.h> | ||
5 | #include <linux/fcntl.h> | ||
6 | #include <linux/delay.h> | ||
7 | #include <linux/string.h> | ||
8 | #include <linux/syscalls.h> | ||
9 | |||
10 | static __initdata char *message; | ||
11 | static void __init error(char *x) | ||
12 | { | ||
13 | if (!message) | ||
14 | message = x; | ||
15 | } | ||
16 | |||
17 | static void __init *malloc(size_t size) | ||
18 | { | ||
19 | return kmalloc(size, GFP_KERNEL); | ||
20 | } | ||
21 | |||
22 | static void __init free(void *where) | ||
23 | { | ||
24 | kfree(where); | ||
25 | } | ||
26 | |||
27 | /* link hash */ | ||
28 | |||
29 | static __initdata struct hash { | ||
30 | int ino, minor, major; | ||
31 | struct hash *next; | ||
32 | char *name; | ||
33 | } *head[32]; | ||
34 | |||
35 | static inline int hash(int major, int minor, int ino) | ||
36 | { | ||
37 | unsigned long tmp = ino + minor + (major << 3); | ||
38 | tmp += tmp >> 5; | ||
39 | return tmp & 31; | ||
40 | } | ||
41 | |||
42 | static char __init *find_link(int major, int minor, int ino, char *name) | ||
43 | { | ||
44 | struct hash **p, *q; | ||
45 | for (p = head + hash(major, minor, ino); *p; p = &(*p)->next) { | ||
46 | if ((*p)->ino != ino) | ||
47 | continue; | ||
48 | if ((*p)->minor != minor) | ||
49 | continue; | ||
50 | if ((*p)->major != major) | ||
51 | continue; | ||
52 | return (*p)->name; | ||
53 | } | ||
54 | q = (struct hash *)malloc(sizeof(struct hash)); | ||
55 | if (!q) | ||
56 | panic("can't allocate link hash entry"); | ||
57 | q->ino = ino; | ||
58 | q->minor = minor; | ||
59 | q->major = major; | ||
60 | q->name = name; | ||
61 | q->next = NULL; | ||
62 | *p = q; | ||
63 | return NULL; | ||
64 | } | ||
65 | |||
66 | static void __init free_hash(void) | ||
67 | { | ||
68 | struct hash **p, *q; | ||
69 | for (p = head; p < head + 32; p++) { | ||
70 | while (*p) { | ||
71 | q = *p; | ||
72 | *p = q->next; | ||
73 | free(q); | ||
74 | } | ||
75 | } | ||
76 | } | ||
77 | |||
78 | /* cpio header parsing */ | ||
79 | |||
80 | static __initdata unsigned long ino, major, minor, nlink; | ||
81 | static __initdata mode_t mode; | ||
82 | static __initdata unsigned long body_len, name_len; | ||
83 | static __initdata uid_t uid; | ||
84 | static __initdata gid_t gid; | ||
85 | static __initdata unsigned rdev; | ||
86 | |||
87 | static void __init parse_header(char *s) | ||
88 | { | ||
89 | unsigned long parsed[12]; | ||
90 | char buf[9]; | ||
91 | int i; | ||
92 | |||
93 | buf[8] = '\0'; | ||
94 | for (i = 0, s += 6; i < 12; i++, s += 8) { | ||
95 | memcpy(buf, s, 8); | ||
96 | parsed[i] = simple_strtoul(buf, NULL, 16); | ||
97 | } | ||
98 | ino = parsed[0]; | ||
99 | mode = parsed[1]; | ||
100 | uid = parsed[2]; | ||
101 | gid = parsed[3]; | ||
102 | nlink = parsed[4]; | ||
103 | body_len = parsed[6]; | ||
104 | major = parsed[7]; | ||
105 | minor = parsed[8]; | ||
106 | rdev = new_encode_dev(MKDEV(parsed[9], parsed[10])); | ||
107 | name_len = parsed[11]; | ||
108 | } | ||
109 | |||
110 | /* FSM */ | ||
111 | |||
112 | static __initdata enum state { | ||
113 | Start, | ||
114 | Collect, | ||
115 | GotHeader, | ||
116 | SkipIt, | ||
117 | GotName, | ||
118 | CopyFile, | ||
119 | GotSymlink, | ||
120 | Reset | ||
121 | } state, next_state; | ||
122 | |||
123 | static __initdata char *victim; | ||
124 | static __initdata unsigned count; | ||
125 | static __initdata loff_t this_header, next_header; | ||
126 | |||
127 | static __initdata int dry_run; | ||
128 | |||
129 | static inline void eat(unsigned n) | ||
130 | { | ||
131 | victim += n; | ||
132 | this_header += n; | ||
133 | count -= n; | ||
134 | } | ||
135 | |||
136 | #define N_ALIGN(len) ((((len) + 1) & ~3) + 2) | ||
137 | |||
138 | static __initdata char *collected; | ||
139 | static __initdata int remains; | ||
140 | static __initdata char *collect; | ||
141 | |||
142 | static void __init read_into(char *buf, unsigned size, enum state next) | ||
143 | { | ||
144 | if (count >= size) { | ||
145 | collected = victim; | ||
146 | eat(size); | ||
147 | state = next; | ||
148 | } else { | ||
149 | collect = collected = buf; | ||
150 | remains = size; | ||
151 | next_state = next; | ||
152 | state = Collect; | ||
153 | } | ||
154 | } | ||
155 | |||
156 | static __initdata char *header_buf, *symlink_buf, *name_buf; | ||
157 | |||
158 | static int __init do_start(void) | ||
159 | { | ||
160 | read_into(header_buf, 110, GotHeader); | ||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | static int __init do_collect(void) | ||
165 | { | ||
166 | unsigned n = remains; | ||
167 | if (count < n) | ||
168 | n = count; | ||
169 | memcpy(collect, victim, n); | ||
170 | eat(n); | ||
171 | collect += n; | ||
172 | if ((remains -= n) != 0) | ||
173 | return 1; | ||
174 | state = next_state; | ||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | static int __init do_header(void) | ||
179 | { | ||
180 | if (memcmp(collected, "070701", 6)) { | ||
181 | error("no cpio magic"); | ||
182 | return 1; | ||
183 | } | ||
184 | parse_header(collected); | ||
185 | next_header = this_header + N_ALIGN(name_len) + body_len; | ||
186 | next_header = (next_header + 3) & ~3; | ||
187 | if (dry_run) { | ||
188 | read_into(name_buf, N_ALIGN(name_len), GotName); | ||
189 | return 0; | ||
190 | } | ||
191 | state = SkipIt; | ||
192 | if (name_len <= 0 || name_len > PATH_MAX) | ||
193 | return 0; | ||
194 | if (S_ISLNK(mode)) { | ||
195 | if (body_len > PATH_MAX) | ||
196 | return 0; | ||
197 | collect = collected = symlink_buf; | ||
198 | remains = N_ALIGN(name_len) + body_len; | ||
199 | next_state = GotSymlink; | ||
200 | state = Collect; | ||
201 | return 0; | ||
202 | } | ||
203 | if (S_ISREG(mode) || !body_len) | ||
204 | read_into(name_buf, N_ALIGN(name_len), GotName); | ||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | static int __init do_skip(void) | ||
209 | { | ||
210 | if (this_header + count < next_header) { | ||
211 | eat(count); | ||
212 | return 1; | ||
213 | } else { | ||
214 | eat(next_header - this_header); | ||
215 | state = next_state; | ||
216 | return 0; | ||
217 | } | ||
218 | } | ||
219 | |||
220 | static int __init do_reset(void) | ||
221 | { | ||
222 | while(count && *victim == '\0') | ||
223 | eat(1); | ||
224 | if (count && (this_header & 3)) | ||
225 | error("broken padding"); | ||
226 | return 1; | ||
227 | } | ||
228 | |||
229 | static int __init maybe_link(void) | ||
230 | { | ||
231 | if (nlink >= 2) { | ||
232 | char *old = find_link(major, minor, ino, collected); | ||
233 | if (old) | ||
234 | return (sys_link(old, collected) < 0) ? -1 : 1; | ||
235 | } | ||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static __initdata int wfd; | ||
240 | |||
241 | static int __init do_name(void) | ||
242 | { | ||
243 | state = SkipIt; | ||
244 | next_state = Reset; | ||
245 | if (strcmp(collected, "TRAILER!!!") == 0) { | ||
246 | free_hash(); | ||
247 | return 0; | ||
248 | } | ||
249 | if (dry_run) | ||
250 | return 0; | ||
251 | if (S_ISREG(mode)) { | ||
252 | if (maybe_link() >= 0) { | ||
253 | wfd = sys_open(collected, O_WRONLY|O_CREAT, mode); | ||
254 | if (wfd >= 0) { | ||
255 | sys_fchown(wfd, uid, gid); | ||
256 | sys_fchmod(wfd, mode); | ||
257 | state = CopyFile; | ||
258 | } | ||
259 | } | ||
260 | } else if (S_ISDIR(mode)) { | ||
261 | sys_mkdir(collected, mode); | ||
262 | sys_chown(collected, uid, gid); | ||
263 | sys_chmod(collected, mode); | ||
264 | } else if (S_ISBLK(mode) || S_ISCHR(mode) || | ||
265 | S_ISFIFO(mode) || S_ISSOCK(mode)) { | ||
266 | if (maybe_link() == 0) { | ||
267 | sys_mknod(collected, mode, rdev); | ||
268 | sys_chown(collected, uid, gid); | ||
269 | sys_chmod(collected, mode); | ||
270 | } | ||
271 | } | ||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | static int __init do_copy(void) | ||
276 | { | ||
277 | if (count >= body_len) { | ||
278 | sys_write(wfd, victim, body_len); | ||
279 | sys_close(wfd); | ||
280 | eat(body_len); | ||
281 | state = SkipIt; | ||
282 | return 0; | ||
283 | } else { | ||
284 | sys_write(wfd, victim, count); | ||
285 | body_len -= count; | ||
286 | eat(count); | ||
287 | return 1; | ||
288 | } | ||
289 | } | ||
290 | |||
291 | static int __init do_symlink(void) | ||
292 | { | ||
293 | collected[N_ALIGN(name_len) + body_len] = '\0'; | ||
294 | sys_symlink(collected + N_ALIGN(name_len), collected); | ||
295 | sys_lchown(collected, uid, gid); | ||
296 | state = SkipIt; | ||
297 | next_state = Reset; | ||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | static __initdata int (*actions[])(void) = { | ||
302 | [Start] = do_start, | ||
303 | [Collect] = do_collect, | ||
304 | [GotHeader] = do_header, | ||
305 | [SkipIt] = do_skip, | ||
306 | [GotName] = do_name, | ||
307 | [CopyFile] = do_copy, | ||
308 | [GotSymlink] = do_symlink, | ||
309 | [Reset] = do_reset, | ||
310 | }; | ||
311 | |||
312 | static int __init write_buffer(char *buf, unsigned len) | ||
313 | { | ||
314 | count = len; | ||
315 | victim = buf; | ||
316 | |||
317 | while (!actions[state]()) | ||
318 | ; | ||
319 | return len - count; | ||
320 | } | ||
321 | |||
322 | static void __init flush_buffer(char *buf, unsigned len) | ||
323 | { | ||
324 | int written; | ||
325 | if (message) | ||
326 | return; | ||
327 | while ((written = write_buffer(buf, len)) < len && !message) { | ||
328 | char c = buf[written]; | ||
329 | if (c == '0') { | ||
330 | buf += written; | ||
331 | len -= written; | ||
332 | state = Start; | ||
333 | } else if (c == 0) { | ||
334 | buf += written; | ||
335 | len -= written; | ||
336 | state = Reset; | ||
337 | } else | ||
338 | error("junk in compressed archive"); | ||
339 | } | ||
340 | } | ||
341 | |||
342 | /* | ||
343 | * gzip declarations | ||
344 | */ | ||
345 | |||
346 | #define OF(args) args | ||
347 | |||
348 | #ifndef memzero | ||
349 | #define memzero(s, n) memset ((s), 0, (n)) | ||
350 | #endif | ||
351 | |||
352 | typedef unsigned char uch; | ||
353 | typedef unsigned short ush; | ||
354 | typedef unsigned long ulg; | ||
355 | |||
356 | #define WSIZE 0x8000 /* window size--must be a power of two, and */ | ||
357 | /* at least 32K for zip's deflate method */ | ||
358 | |||
359 | static uch *inbuf; | ||
360 | static uch *window; | ||
361 | |||
362 | static unsigned insize; /* valid bytes in inbuf */ | ||
363 | static unsigned inptr; /* index of next byte to be processed in inbuf */ | ||
364 | static unsigned outcnt; /* bytes in output buffer */ | ||
365 | static long bytes_out; | ||
366 | |||
367 | #define get_byte() (inptr < insize ? inbuf[inptr++] : -1) | ||
368 | |||
369 | /* Diagnostic functions (stubbed out) */ | ||
370 | #define Assert(cond,msg) | ||
371 | #define Trace(x) | ||
372 | #define Tracev(x) | ||
373 | #define Tracevv(x) | ||
374 | #define Tracec(c,x) | ||
375 | #define Tracecv(c,x) | ||
376 | |||
377 | #define STATIC static | ||
378 | #define INIT __init | ||
379 | |||
380 | static void __init flush_window(void); | ||
381 | static void __init error(char *m); | ||
382 | static void __init gzip_mark(void **); | ||
383 | static void __init gzip_release(void **); | ||
384 | |||
385 | #include "../lib/inflate.c" | ||
386 | |||
387 | static void __init gzip_mark(void **ptr) | ||
388 | { | ||
389 | } | ||
390 | |||
391 | static void __init gzip_release(void **ptr) | ||
392 | { | ||
393 | } | ||
394 | |||
395 | /* =========================================================================== | ||
396 | * Write the output window window[0..outcnt-1] and update crc and bytes_out. | ||
397 | * (Used for the decompressed data only.) | ||
398 | */ | ||
399 | static void __init flush_window(void) | ||
400 | { | ||
401 | ulg c = crc; /* temporary variable */ | ||
402 | unsigned n; | ||
403 | uch *in, ch; | ||
404 | |||
405 | flush_buffer(window, outcnt); | ||
406 | in = window; | ||
407 | for (n = 0; n < outcnt; n++) { | ||
408 | ch = *in++; | ||
409 | c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); | ||
410 | } | ||
411 | crc = c; | ||
412 | bytes_out += (ulg)outcnt; | ||
413 | outcnt = 0; | ||
414 | } | ||
415 | |||
416 | static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only) | ||
417 | { | ||
418 | int written; | ||
419 | dry_run = check_only; | ||
420 | header_buf = malloc(110); | ||
421 | symlink_buf = malloc(PATH_MAX + N_ALIGN(PATH_MAX) + 1); | ||
422 | name_buf = malloc(N_ALIGN(PATH_MAX)); | ||
423 | window = malloc(WSIZE); | ||
424 | if (!window || !header_buf || !symlink_buf || !name_buf) | ||
425 | panic("can't allocate buffers"); | ||
426 | state = Start; | ||
427 | this_header = 0; | ||
428 | message = NULL; | ||
429 | while (!message && len) { | ||
430 | loff_t saved_offset = this_header; | ||
431 | if (*buf == '0' && !(this_header & 3)) { | ||
432 | state = Start; | ||
433 | written = write_buffer(buf, len); | ||
434 | buf += written; | ||
435 | len -= written; | ||
436 | continue; | ||
437 | } | ||
438 | if (!*buf) { | ||
439 | buf++; | ||
440 | len--; | ||
441 | this_header++; | ||
442 | continue; | ||
443 | } | ||
444 | this_header = 0; | ||
445 | insize = len; | ||
446 | inbuf = buf; | ||
447 | inptr = 0; | ||
448 | outcnt = 0; /* bytes in output buffer */ | ||
449 | bytes_out = 0; | ||
450 | crc = (ulg)0xffffffffL; /* shift register contents */ | ||
451 | makecrc(); | ||
452 | gunzip(); | ||
453 | if (state != Reset) | ||
454 | error("junk in gzipped archive"); | ||
455 | this_header = saved_offset + inptr; | ||
456 | buf += inptr; | ||
457 | len -= inptr; | ||
458 | } | ||
459 | free(window); | ||
460 | free(name_buf); | ||
461 | free(symlink_buf); | ||
462 | free(header_buf); | ||
463 | return message; | ||
464 | } | ||
465 | |||
466 | extern char __initramfs_start[], __initramfs_end[]; | ||
467 | #ifdef CONFIG_BLK_DEV_INITRD | ||
468 | #include <linux/initrd.h> | ||
469 | #endif | ||
470 | |||
471 | void __init populate_rootfs(void) | ||
472 | { | ||
473 | char *err = unpack_to_rootfs(__initramfs_start, | ||
474 | __initramfs_end - __initramfs_start, 0); | ||
475 | if (err) | ||
476 | panic(err); | ||
477 | #ifdef CONFIG_BLK_DEV_INITRD | ||
478 | if (initrd_start) { | ||
479 | int fd; | ||
480 | printk(KERN_INFO "checking if image is initramfs..."); | ||
481 | err = unpack_to_rootfs((char *)initrd_start, | ||
482 | initrd_end - initrd_start, 1); | ||
483 | if (!err) { | ||
484 | printk(" it is\n"); | ||
485 | unpack_to_rootfs((char *)initrd_start, | ||
486 | initrd_end - initrd_start, 0); | ||
487 | free_initrd_mem(initrd_start, initrd_end); | ||
488 | return; | ||
489 | } | ||
490 | printk("it isn't (%s); looks like an initrd\n", err); | ||
491 | fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 700); | ||
492 | if (fd >= 0) { | ||
493 | sys_write(fd, (char *)initrd_start, | ||
494 | initrd_end - initrd_start); | ||
495 | sys_close(fd); | ||
496 | free_initrd_mem(initrd_start, initrd_end); | ||
497 | } | ||
498 | } | ||
499 | #endif | ||
500 | } | ||
diff --git a/init/main.c b/init/main.c new file mode 100644 index 00000000000..40bf367ffdf --- /dev/null +++ b/init/main.c | |||
@@ -0,0 +1,713 @@ | |||
1 | /* | ||
2 | * linux/init/main.c | ||
3 | * | ||
4 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
5 | * | ||
6 | * GK 2/5/95 - Changed to support mounting root fs via NFS | ||
7 | * Added initrd & change_root: Werner Almesberger & Hans Lermen, Feb '96 | ||
8 | * Moan early if gcc is old, avoiding bogus kernels - Paul Gortmaker, May '96 | ||
9 | * Simplified starting of init: Michael A. Griffith <grif@acm.org> | ||
10 | */ | ||
11 | |||
12 | #define __KERNEL_SYSCALLS__ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/types.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/proc_fs.h> | ||
18 | #include <linux/devfs_fs_kernel.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/syscalls.h> | ||
21 | #include <linux/string.h> | ||
22 | #include <linux/ctype.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/utsname.h> | ||
25 | #include <linux/ioport.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/smp_lock.h> | ||
28 | #include <linux/initrd.h> | ||
29 | #include <linux/hdreg.h> | ||
30 | #include <linux/bootmem.h> | ||
31 | #include <linux/tty.h> | ||
32 | #include <linux/gfp.h> | ||
33 | #include <linux/percpu.h> | ||
34 | #include <linux/kmod.h> | ||
35 | #include <linux/kernel_stat.h> | ||
36 | #include <linux/security.h> | ||
37 | #include <linux/workqueue.h> | ||
38 | #include <linux/profile.h> | ||
39 | #include <linux/rcupdate.h> | ||
40 | #include <linux/moduleparam.h> | ||
41 | #include <linux/kallsyms.h> | ||
42 | #include <linux/writeback.h> | ||
43 | #include <linux/cpu.h> | ||
44 | #include <linux/cpuset.h> | ||
45 | #include <linux/efi.h> | ||
46 | #include <linux/unistd.h> | ||
47 | #include <linux/rmap.h> | ||
48 | #include <linux/mempolicy.h> | ||
49 | #include <linux/key.h> | ||
50 | |||
51 | #include <asm/io.h> | ||
52 | #include <asm/bugs.h> | ||
53 | #include <asm/setup.h> | ||
54 | |||
55 | /* | ||
56 | * This is one of the first .c files built. Error out early | ||
57 | * if we have compiler trouble.. | ||
58 | */ | ||
59 | #if __GNUC__ == 2 && __GNUC_MINOR__ == 96 | ||
60 | #ifdef CONFIG_FRAME_POINTER | ||
61 | #error This compiler cannot compile correctly with frame pointers enabled | ||
62 | #endif | ||
63 | #endif | ||
64 | |||
65 | #ifdef CONFIG_X86_LOCAL_APIC | ||
66 | #include <asm/smp.h> | ||
67 | #endif | ||
68 | |||
69 | /* | ||
70 | * Versions of gcc older than that listed below may actually compile | ||
71 | * and link okay, but the end product can have subtle run time bugs. | ||
72 | * To avoid associated bogus bug reports, we flatly refuse to compile | ||
73 | * with a gcc that is known to be too old from the very beginning. | ||
74 | */ | ||
75 | #if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 95) | ||
76 | #error Sorry, your GCC is too old. It builds incorrect kernels. | ||
77 | #endif | ||
78 | |||
79 | static int init(void *); | ||
80 | |||
81 | extern void init_IRQ(void); | ||
82 | extern void sock_init(void); | ||
83 | extern void fork_init(unsigned long); | ||
84 | extern void mca_init(void); | ||
85 | extern void sbus_init(void); | ||
86 | extern void sysctl_init(void); | ||
87 | extern void signals_init(void); | ||
88 | extern void buffer_init(void); | ||
89 | extern void pidhash_init(void); | ||
90 | extern void pidmap_init(void); | ||
91 | extern void prio_tree_init(void); | ||
92 | extern void radix_tree_init(void); | ||
93 | extern void free_initmem(void); | ||
94 | extern void populate_rootfs(void); | ||
95 | extern void driver_init(void); | ||
96 | extern void prepare_namespace(void); | ||
97 | #ifdef CONFIG_ACPI | ||
98 | extern void acpi_early_init(void); | ||
99 | #else | ||
100 | static inline void acpi_early_init(void) { } | ||
101 | #endif | ||
102 | |||
103 | #ifdef CONFIG_TC | ||
104 | extern void tc_init(void); | ||
105 | #endif | ||
106 | |||
107 | enum system_states system_state; | ||
108 | EXPORT_SYMBOL(system_state); | ||
109 | |||
110 | /* | ||
111 | * Boot command-line arguments | ||
112 | */ | ||
113 | #define MAX_INIT_ARGS CONFIG_INIT_ENV_ARG_LIMIT | ||
114 | #define MAX_INIT_ENVS CONFIG_INIT_ENV_ARG_LIMIT | ||
115 | |||
116 | extern void time_init(void); | ||
117 | /* Default late time init is NULL. archs can override this later. */ | ||
118 | void (*late_time_init)(void); | ||
119 | extern void softirq_init(void); | ||
120 | |||
121 | /* Untouched command line (eg. for /proc) saved by arch-specific code. */ | ||
122 | char saved_command_line[COMMAND_LINE_SIZE]; | ||
123 | |||
124 | static char *execute_command; | ||
125 | |||
126 | /* Setup configured maximum number of CPUs to activate */ | ||
127 | static unsigned int max_cpus = NR_CPUS; | ||
128 | |||
129 | /* | ||
130 | * Setup routine for controlling SMP activation | ||
131 | * | ||
132 | * Command-line option of "nosmp" or "maxcpus=0" will disable SMP | ||
133 | * activation entirely (the MPS table probe still happens, though). | ||
134 | * | ||
135 | * Command-line option of "maxcpus=<NUM>", where <NUM> is an integer | ||
136 | * greater than 0, limits the maximum number of CPUs activated in | ||
137 | * SMP mode to <NUM>. | ||
138 | */ | ||
139 | static int __init nosmp(char *str) | ||
140 | { | ||
141 | max_cpus = 0; | ||
142 | return 1; | ||
143 | } | ||
144 | |||
145 | __setup("nosmp", nosmp); | ||
146 | |||
147 | static int __init maxcpus(char *str) | ||
148 | { | ||
149 | get_option(&str, &max_cpus); | ||
150 | return 1; | ||
151 | } | ||
152 | |||
153 | __setup("maxcpus=", maxcpus); | ||
154 | |||
155 | static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, }; | ||
156 | char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, }; | ||
157 | static const char *panic_later, *panic_param; | ||
158 | |||
159 | extern struct obs_kernel_param __setup_start[], __setup_end[]; | ||
160 | |||
161 | static int __init obsolete_checksetup(char *line) | ||
162 | { | ||
163 | struct obs_kernel_param *p; | ||
164 | |||
165 | p = __setup_start; | ||
166 | do { | ||
167 | int n = strlen(p->str); | ||
168 | if (!strncmp(line, p->str, n)) { | ||
169 | if (p->early) { | ||
170 | /* Already done in parse_early_param? (Needs | ||
171 | * exact match on param part) */ | ||
172 | if (line[n] == '\0' || line[n] == '=') | ||
173 | return 1; | ||
174 | } else if (!p->setup_func) { | ||
175 | printk(KERN_WARNING "Parameter %s is obsolete," | ||
176 | " ignored\n", p->str); | ||
177 | return 1; | ||
178 | } else if (p->setup_func(line + n)) | ||
179 | return 1; | ||
180 | } | ||
181 | p++; | ||
182 | } while (p < __setup_end); | ||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | /* | ||
187 | * This should be approx 2 Bo*oMips to start (note initial shift), and will | ||
188 | * still work even if initially too large, it will just take slightly longer | ||
189 | */ | ||
190 | unsigned long loops_per_jiffy = (1<<12); | ||
191 | |||
192 | EXPORT_SYMBOL(loops_per_jiffy); | ||
193 | |||
194 | static int __init debug_kernel(char *str) | ||
195 | { | ||
196 | if (*str) | ||
197 | return 0; | ||
198 | console_loglevel = 10; | ||
199 | return 1; | ||
200 | } | ||
201 | |||
202 | static int __init quiet_kernel(char *str) | ||
203 | { | ||
204 | if (*str) | ||
205 | return 0; | ||
206 | console_loglevel = 4; | ||
207 | return 1; | ||
208 | } | ||
209 | |||
210 | __setup("debug", debug_kernel); | ||
211 | __setup("quiet", quiet_kernel); | ||
212 | |||
213 | static int __init loglevel(char *str) | ||
214 | { | ||
215 | get_option(&str, &console_loglevel); | ||
216 | return 1; | ||
217 | } | ||
218 | |||
219 | __setup("loglevel=", loglevel); | ||
220 | |||
221 | /* | ||
222 | * Unknown boot options get handed to init, unless they look like | ||
223 | * failed parameters | ||
224 | */ | ||
225 | static int __init unknown_bootoption(char *param, char *val) | ||
226 | { | ||
227 | /* Change NUL term back to "=", to make "param" the whole string. */ | ||
228 | if (val) { | ||
229 | /* param=val or param="val"? */ | ||
230 | if (val == param+strlen(param)+1) | ||
231 | val[-1] = '='; | ||
232 | else if (val == param+strlen(param)+2) { | ||
233 | val[-2] = '='; | ||
234 | memmove(val-1, val, strlen(val)+1); | ||
235 | val--; | ||
236 | } else | ||
237 | BUG(); | ||
238 | } | ||
239 | |||
240 | /* Handle obsolete-style parameters */ | ||
241 | if (obsolete_checksetup(param)) | ||
242 | return 0; | ||
243 | |||
244 | /* | ||
245 | * Preemptive maintenance for "why didn't my mispelled command | ||
246 | * line work?" | ||
247 | */ | ||
248 | if (strchr(param, '.') && (!val || strchr(param, '.') < val)) { | ||
249 | printk(KERN_ERR "Unknown boot option `%s': ignoring\n", param); | ||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | if (panic_later) | ||
254 | return 0; | ||
255 | |||
256 | if (val) { | ||
257 | /* Environment option */ | ||
258 | unsigned int i; | ||
259 | for (i = 0; envp_init[i]; i++) { | ||
260 | if (i == MAX_INIT_ENVS) { | ||
261 | panic_later = "Too many boot env vars at `%s'"; | ||
262 | panic_param = param; | ||
263 | } | ||
264 | if (!strncmp(param, envp_init[i], val - param)) | ||
265 | break; | ||
266 | } | ||
267 | envp_init[i] = param; | ||
268 | } else { | ||
269 | /* Command line option */ | ||
270 | unsigned int i; | ||
271 | for (i = 0; argv_init[i]; i++) { | ||
272 | if (i == MAX_INIT_ARGS) { | ||
273 | panic_later = "Too many boot init vars at `%s'"; | ||
274 | panic_param = param; | ||
275 | } | ||
276 | } | ||
277 | argv_init[i] = param; | ||
278 | } | ||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | static int __init init_setup(char *str) | ||
283 | { | ||
284 | unsigned int i; | ||
285 | |||
286 | execute_command = str; | ||
287 | /* | ||
288 | * In case LILO is going to boot us with default command line, | ||
289 | * it prepends "auto" before the whole cmdline which makes | ||
290 | * the shell think it should execute a script with such name. | ||
291 | * So we ignore all arguments entered _before_ init=... [MJ] | ||
292 | */ | ||
293 | for (i = 1; i < MAX_INIT_ARGS; i++) | ||
294 | argv_init[i] = NULL; | ||
295 | return 1; | ||
296 | } | ||
297 | __setup("init=", init_setup); | ||
298 | |||
299 | extern void setup_arch(char **); | ||
300 | |||
301 | #ifndef CONFIG_SMP | ||
302 | |||
303 | #ifdef CONFIG_X86_LOCAL_APIC | ||
304 | static void __init smp_init(void) | ||
305 | { | ||
306 | APIC_init_uniprocessor(); | ||
307 | } | ||
308 | #else | ||
309 | #define smp_init() do { } while (0) | ||
310 | #endif | ||
311 | |||
312 | static inline void setup_per_cpu_areas(void) { } | ||
313 | static inline void smp_prepare_cpus(unsigned int maxcpus) { } | ||
314 | |||
315 | #else | ||
316 | |||
317 | #ifdef __GENERIC_PER_CPU | ||
318 | unsigned long __per_cpu_offset[NR_CPUS]; | ||
319 | |||
320 | EXPORT_SYMBOL(__per_cpu_offset); | ||
321 | |||
322 | static void __init setup_per_cpu_areas(void) | ||
323 | { | ||
324 | unsigned long size, i; | ||
325 | char *ptr; | ||
326 | /* Created by linker magic */ | ||
327 | extern char __per_cpu_start[], __per_cpu_end[]; | ||
328 | |||
329 | /* Copy section for each CPU (we discard the original) */ | ||
330 | size = ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES); | ||
331 | #ifdef CONFIG_MODULES | ||
332 | if (size < PERCPU_ENOUGH_ROOM) | ||
333 | size = PERCPU_ENOUGH_ROOM; | ||
334 | #endif | ||
335 | |||
336 | ptr = alloc_bootmem(size * NR_CPUS); | ||
337 | |||
338 | for (i = 0; i < NR_CPUS; i++, ptr += size) { | ||
339 | __per_cpu_offset[i] = ptr - __per_cpu_start; | ||
340 | memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start); | ||
341 | } | ||
342 | } | ||
343 | #endif /* !__GENERIC_PER_CPU */ | ||
344 | |||
345 | /* Called by boot processor to activate the rest. */ | ||
346 | static void __init smp_init(void) | ||
347 | { | ||
348 | unsigned int i; | ||
349 | |||
350 | /* FIXME: This should be done in userspace --RR */ | ||
351 | for_each_present_cpu(i) { | ||
352 | if (num_online_cpus() >= max_cpus) | ||
353 | break; | ||
354 | if (!cpu_online(i)) | ||
355 | cpu_up(i); | ||
356 | } | ||
357 | |||
358 | /* Any cleanup work */ | ||
359 | printk(KERN_INFO "Brought up %ld CPUs\n", (long)num_online_cpus()); | ||
360 | smp_cpus_done(max_cpus); | ||
361 | #if 0 | ||
362 | /* Get other processors into their bootup holding patterns. */ | ||
363 | |||
364 | smp_commence(); | ||
365 | #endif | ||
366 | } | ||
367 | |||
368 | #endif | ||
369 | |||
370 | /* | ||
371 | * We need to finalize in a non-__init function or else race conditions | ||
372 | * between the root thread and the init thread may cause start_kernel to | ||
373 | * be reaped by free_initmem before the root thread has proceeded to | ||
374 | * cpu_idle. | ||
375 | * | ||
376 | * gcc-3.4 accidentally inlines this function, so use noinline. | ||
377 | */ | ||
378 | |||
379 | static void noinline rest_init(void) | ||
380 | __releases(kernel_lock) | ||
381 | { | ||
382 | kernel_thread(init, NULL, CLONE_FS | CLONE_SIGHAND); | ||
383 | numa_default_policy(); | ||
384 | unlock_kernel(); | ||
385 | preempt_enable_no_resched(); | ||
386 | cpu_idle(); | ||
387 | } | ||
388 | |||
389 | /* Check for early params. */ | ||
390 | static int __init do_early_param(char *param, char *val) | ||
391 | { | ||
392 | struct obs_kernel_param *p; | ||
393 | |||
394 | for (p = __setup_start; p < __setup_end; p++) { | ||
395 | if (p->early && strcmp(param, p->str) == 0) { | ||
396 | if (p->setup_func(val) != 0) | ||
397 | printk(KERN_WARNING | ||
398 | "Malformed early option '%s'\n", param); | ||
399 | } | ||
400 | } | ||
401 | /* We accept everything at this stage. */ | ||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | /* Arch code calls this early on, or if not, just before other parsing. */ | ||
406 | void __init parse_early_param(void) | ||
407 | { | ||
408 | static __initdata int done = 0; | ||
409 | static __initdata char tmp_cmdline[COMMAND_LINE_SIZE]; | ||
410 | |||
411 | if (done) | ||
412 | return; | ||
413 | |||
414 | /* All fall through to do_early_param. */ | ||
415 | strlcpy(tmp_cmdline, saved_command_line, COMMAND_LINE_SIZE); | ||
416 | parse_args("early options", tmp_cmdline, NULL, 0, do_early_param); | ||
417 | done = 1; | ||
418 | } | ||
419 | |||
420 | /* | ||
421 | * Activate the first processor. | ||
422 | */ | ||
423 | |||
424 | asmlinkage void __init start_kernel(void) | ||
425 | { | ||
426 | char * command_line; | ||
427 | extern struct kernel_param __start___param[], __stop___param[]; | ||
428 | /* | ||
429 | * Interrupts are still disabled. Do necessary setups, then | ||
430 | * enable them | ||
431 | */ | ||
432 | lock_kernel(); | ||
433 | page_address_init(); | ||
434 | printk(KERN_NOTICE); | ||
435 | printk(linux_banner); | ||
436 | setup_arch(&command_line); | ||
437 | setup_per_cpu_areas(); | ||
438 | |||
439 | /* | ||
440 | * Mark the boot cpu "online" so that it can call console drivers in | ||
441 | * printk() and can access its per-cpu storage. | ||
442 | */ | ||
443 | smp_prepare_boot_cpu(); | ||
444 | |||
445 | /* | ||
446 | * Set up the scheduler prior starting any interrupts (such as the | ||
447 | * timer interrupt). Full topology setup happens at smp_init() | ||
448 | * time - but meanwhile we still have a functioning scheduler. | ||
449 | */ | ||
450 | sched_init(); | ||
451 | /* | ||
452 | * Disable preemption - early bootup scheduling is extremely | ||
453 | * fragile until we cpu_idle() for the first time. | ||
454 | */ | ||
455 | preempt_disable(); | ||
456 | build_all_zonelists(); | ||
457 | page_alloc_init(); | ||
458 | printk(KERN_NOTICE "Kernel command line: %s\n", saved_command_line); | ||
459 | parse_early_param(); | ||
460 | parse_args("Booting kernel", command_line, __start___param, | ||
461 | __stop___param - __start___param, | ||
462 | &unknown_bootoption); | ||
463 | sort_main_extable(); | ||
464 | trap_init(); | ||
465 | rcu_init(); | ||
466 | init_IRQ(); | ||
467 | pidhash_init(); | ||
468 | init_timers(); | ||
469 | softirq_init(); | ||
470 | time_init(); | ||
471 | |||
472 | /* | ||
473 | * HACK ALERT! This is early. We're enabling the console before | ||
474 | * we've done PCI setups etc, and console_init() must be aware of | ||
475 | * this. But we do want output early, in case something goes wrong. | ||
476 | */ | ||
477 | console_init(); | ||
478 | if (panic_later) | ||
479 | panic(panic_later, panic_param); | ||
480 | profile_init(); | ||
481 | local_irq_enable(); | ||
482 | #ifdef CONFIG_BLK_DEV_INITRD | ||
483 | if (initrd_start && !initrd_below_start_ok && | ||
484 | initrd_start < min_low_pfn << PAGE_SHIFT) { | ||
485 | printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - " | ||
486 | "disabling it.\n",initrd_start,min_low_pfn << PAGE_SHIFT); | ||
487 | initrd_start = 0; | ||
488 | } | ||
489 | #endif | ||
490 | vfs_caches_init_early(); | ||
491 | mem_init(); | ||
492 | kmem_cache_init(); | ||
493 | numa_policy_init(); | ||
494 | if (late_time_init) | ||
495 | late_time_init(); | ||
496 | calibrate_delay(); | ||
497 | pidmap_init(); | ||
498 | pgtable_cache_init(); | ||
499 | prio_tree_init(); | ||
500 | anon_vma_init(); | ||
501 | #ifdef CONFIG_X86 | ||
502 | if (efi_enabled) | ||
503 | efi_enter_virtual_mode(); | ||
504 | #endif | ||
505 | fork_init(num_physpages); | ||
506 | proc_caches_init(); | ||
507 | buffer_init(); | ||
508 | unnamed_dev_init(); | ||
509 | key_init(); | ||
510 | security_init(); | ||
511 | vfs_caches_init(num_physpages); | ||
512 | radix_tree_init(); | ||
513 | signals_init(); | ||
514 | /* rootfs populating might need page-writeback */ | ||
515 | page_writeback_init(); | ||
516 | #ifdef CONFIG_PROC_FS | ||
517 | proc_root_init(); | ||
518 | #endif | ||
519 | cpuset_init(); | ||
520 | |||
521 | check_bugs(); | ||
522 | |||
523 | acpi_early_init(); /* before LAPIC and SMP init */ | ||
524 | |||
525 | /* Do the rest non-__init'ed, we're now alive */ | ||
526 | rest_init(); | ||
527 | } | ||
528 | |||
529 | static int __initdata initcall_debug; | ||
530 | |||
531 | static int __init initcall_debug_setup(char *str) | ||
532 | { | ||
533 | initcall_debug = 1; | ||
534 | return 1; | ||
535 | } | ||
536 | __setup("initcall_debug", initcall_debug_setup); | ||
537 | |||
538 | struct task_struct *child_reaper = &init_task; | ||
539 | |||
540 | extern initcall_t __initcall_start[], __initcall_end[]; | ||
541 | |||
542 | static void __init do_initcalls(void) | ||
543 | { | ||
544 | initcall_t *call; | ||
545 | int count = preempt_count(); | ||
546 | |||
547 | for (call = __initcall_start; call < __initcall_end; call++) { | ||
548 | char *msg; | ||
549 | |||
550 | if (initcall_debug) { | ||
551 | printk(KERN_DEBUG "Calling initcall 0x%p", *call); | ||
552 | print_fn_descriptor_symbol(": %s()", (unsigned long) *call); | ||
553 | printk("\n"); | ||
554 | } | ||
555 | |||
556 | (*call)(); | ||
557 | |||
558 | msg = NULL; | ||
559 | if (preempt_count() != count) { | ||
560 | msg = "preemption imbalance"; | ||
561 | preempt_count() = count; | ||
562 | } | ||
563 | if (irqs_disabled()) { | ||
564 | msg = "disabled interrupts"; | ||
565 | local_irq_enable(); | ||
566 | } | ||
567 | if (msg) { | ||
568 | printk(KERN_WARNING "error in initcall at 0x%p: " | ||
569 | "returned with %s\n", *call, msg); | ||
570 | } | ||
571 | } | ||
572 | |||
573 | /* Make sure there is no pending stuff from the initcall sequence */ | ||
574 | flush_scheduled_work(); | ||
575 | } | ||
576 | |||
577 | /* | ||
578 | * Ok, the machine is now initialized. None of the devices | ||
579 | * have been touched yet, but the CPU subsystem is up and | ||
580 | * running, and memory and process management works. | ||
581 | * | ||
582 | * Now we can finally start doing some real work.. | ||
583 | */ | ||
584 | static void __init do_basic_setup(void) | ||
585 | { | ||
586 | /* drivers will send hotplug events */ | ||
587 | init_workqueues(); | ||
588 | usermodehelper_init(); | ||
589 | driver_init(); | ||
590 | |||
591 | #ifdef CONFIG_SYSCTL | ||
592 | sysctl_init(); | ||
593 | #endif | ||
594 | |||
595 | /* Networking initialization needs a process context */ | ||
596 | sock_init(); | ||
597 | |||
598 | do_initcalls(); | ||
599 | } | ||
600 | |||
601 | static void do_pre_smp_initcalls(void) | ||
602 | { | ||
603 | extern int spawn_ksoftirqd(void); | ||
604 | #ifdef CONFIG_SMP | ||
605 | extern int migration_init(void); | ||
606 | |||
607 | migration_init(); | ||
608 | #endif | ||
609 | spawn_ksoftirqd(); | ||
610 | } | ||
611 | |||
612 | static void run_init_process(char *init_filename) | ||
613 | { | ||
614 | argv_init[0] = init_filename; | ||
615 | execve(init_filename, argv_init, envp_init); | ||
616 | } | ||
617 | |||
618 | static inline void fixup_cpu_present_map(void) | ||
619 | { | ||
620 | #ifdef CONFIG_SMP | ||
621 | int i; | ||
622 | |||
623 | /* | ||
624 | * If arch is not hotplug ready and did not populate | ||
625 | * cpu_present_map, just make cpu_present_map same as cpu_possible_map | ||
626 | * for other cpu bringup code to function as normal. e.g smp_init() etc. | ||
627 | */ | ||
628 | if (cpus_empty(cpu_present_map)) { | ||
629 | for_each_cpu(i) { | ||
630 | cpu_set(i, cpu_present_map); | ||
631 | } | ||
632 | } | ||
633 | #endif | ||
634 | } | ||
635 | |||
636 | static int init(void * unused) | ||
637 | { | ||
638 | lock_kernel(); | ||
639 | /* | ||
640 | * init can run on any cpu. | ||
641 | */ | ||
642 | set_cpus_allowed(current, CPU_MASK_ALL); | ||
643 | /* | ||
644 | * Tell the world that we're going to be the grim | ||
645 | * reaper of innocent orphaned children. | ||
646 | * | ||
647 | * We don't want people to have to make incorrect | ||
648 | * assumptions about where in the task array this | ||
649 | * can be found. | ||
650 | */ | ||
651 | child_reaper = current; | ||
652 | |||
653 | /* Sets up cpus_possible() */ | ||
654 | smp_prepare_cpus(max_cpus); | ||
655 | |||
656 | do_pre_smp_initcalls(); | ||
657 | |||
658 | fixup_cpu_present_map(); | ||
659 | smp_init(); | ||
660 | sched_init_smp(); | ||
661 | |||
662 | cpuset_init_smp(); | ||
663 | |||
664 | /* | ||
665 | * Do this before initcalls, because some drivers want to access | ||
666 | * firmware files. | ||
667 | */ | ||
668 | populate_rootfs(); | ||
669 | |||
670 | do_basic_setup(); | ||
671 | |||
672 | /* | ||
673 | * check if there is an early userspace init. If yes, let it do all | ||
674 | * the work | ||
675 | */ | ||
676 | if (sys_access((const char __user *) "/init", 0) == 0) | ||
677 | execute_command = "/init"; | ||
678 | else | ||
679 | prepare_namespace(); | ||
680 | |||
681 | /* | ||
682 | * Ok, we have completed the initial bootup, and | ||
683 | * we're essentially up and running. Get rid of the | ||
684 | * initmem segments and start the user-mode stuff.. | ||
685 | */ | ||
686 | free_initmem(); | ||
687 | unlock_kernel(); | ||
688 | system_state = SYSTEM_RUNNING; | ||
689 | numa_default_policy(); | ||
690 | |||
691 | if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0) | ||
692 | printk(KERN_WARNING "Warning: unable to open an initial console.\n"); | ||
693 | |||
694 | (void) sys_dup(0); | ||
695 | (void) sys_dup(0); | ||
696 | |||
697 | /* | ||
698 | * We try each of these until one succeeds. | ||
699 | * | ||
700 | * The Bourne shell can be used instead of init if we are | ||
701 | * trying to recover a really broken machine. | ||
702 | */ | ||
703 | |||
704 | if (execute_command) | ||
705 | run_init_process(execute_command); | ||
706 | |||
707 | run_init_process("/sbin/init"); | ||
708 | run_init_process("/etc/init"); | ||
709 | run_init_process("/bin/init"); | ||
710 | run_init_process("/bin/sh"); | ||
711 | |||
712 | panic("No init found. Try passing init= option to kernel."); | ||
713 | } | ||
diff --git a/init/version.c b/init/version.c new file mode 100644 index 00000000000..3ddc3ceec2f --- /dev/null +++ b/init/version.c | |||
@@ -0,0 +1,33 @@ | |||
1 | /* | ||
2 | * linux/init/version.c | ||
3 | * | ||
4 | * Copyright (C) 1992 Theodore Ts'o | ||
5 | * | ||
6 | * May be freely distributed as part of Linux. | ||
7 | */ | ||
8 | |||
9 | #include <linux/compile.h> | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/uts.h> | ||
12 | #include <linux/utsname.h> | ||
13 | #include <linux/version.h> | ||
14 | |||
15 | #define version(a) Version_ ## a | ||
16 | #define version_string(a) version(a) | ||
17 | |||
18 | int version_string(LINUX_VERSION_CODE); | ||
19 | |||
20 | struct new_utsname system_utsname = { | ||
21 | .sysname = UTS_SYSNAME, | ||
22 | .nodename = UTS_NODENAME, | ||
23 | .release = UTS_RELEASE, | ||
24 | .version = UTS_VERSION, | ||
25 | .machine = UTS_MACHINE, | ||
26 | .domainname = UTS_DOMAINNAME, | ||
27 | }; | ||
28 | |||
29 | EXPORT_SYMBOL(system_utsname); | ||
30 | |||
31 | const char linux_banner[] = | ||
32 | "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@" | ||
33 | LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n"; | ||