In this article Jeff looks at a useful and perhaps little known feature of Linux—the ability to pass command line parameters to the kernel during system startup.
Consider the following situations:
Scenario 1: You are installing Linux from CDROM, but the kernel isn't using the correct I/O address for your CD-ROM drive. You can correct this by recompiling the kernel, but to build the kernel you first need to install Linux from CD-ROM...
Scenario 2: You made a change to the system startup script rc.local and now your system hangs while booting. How can you fix the error without reinstalling Linux?
Scenario 3: You'd like to experiment with the various VGA console video modes available without having to recompile the kernel each time.
Scenario 4: You've just written a large application that runs well on your system. How well would it run on a friend's machine that has only 4MB of RAM and no floating point coprocessor?
One solution to each of these problems is provided by Linux and its ability to pass command line parameters to the kernel. Unfortunately, these options are not well documented, (some of the HOWTOs mention certain options in passing, e.g., the SCSI HOWTO mentions some SCSI related options) and a number of them have been added relatively recently. We'll explore them in this article.
In order to understand how command line parameters fit into the scheme of things, let's briefly look at what happens when Linux boots.
For those who aren't afraid to look at kernel source code, I'll mention some of the relevant files. The filenames given are relative to wherever you have installed the kernel source, usually /usr/src/linux. Therefore, a reference to the file boot/bootsect.S should be found in /usr/src/linux/boot/bootsect.S. This information is valid for Linux kernel version 1.2.
Starting from power on, the PC ROM BIOS routines load boot code from floppy or hard disk. If booting from hard disk, this is usually the boot loader installed by LILO. If booting fJ5m floppy, it is the code in the file boot/bootsect.S. This in turn loads the code found in boot/setup.S and runs it. This module reads some information from the BIOS (the VGA mode, amount of memory, etc.) and makes note of it for later use. It will be needed later as the BIOS routines will not (normally) be used once the kernel starts up.
The setup code next switches to protected (32-bit) mode, then loads and runs the code found in boot/head.S. (Actually, for compressed kernels, which is always the case in recent kernels, the kernel proper is first uncompressed using the code found in zBoot/head.S). This sets up more of the 32-bit environment, gets the command-line parameters (usually from LILO), and passes them to the routine start_kernel.
Up to now everything was written in assembly language. At this point we now switch to the function start_kernel, written in C, found in the file init/main.c. This is the code that does most of the option parsing, saving information on a number of kernel-specific parameters in global variables so that they can be used by the kernel when needed.
Any other parameters given as “name=value” pairs are passed as arguments and environment variables to the next process.
This first kernel process now sets some things up for multitasking, and makes the first call to the fork system call, creating a new process; we are now multitasking. The original (parent) process becomes the “idle process” which is executed whenever there are no processes ready to run. The child process (which has process id 1) calls the program init. (It actually looks in a number of places, including /etc/init, /bin/init, /sbin/init, /etc/rc, and finally /bin/sh.) The init program then starts up all of the initial system processes such as getty and other daemons, and shortly we have a login prompt on the console.
There are a number of important options that can be set when compiling the Linux kernel. These include the root device, swap device, and VGA video mode. The toplevel Makefile allows setting most of these.
The problem with this method is that recompiling the kernel is somewhat time-consuming (at least on my machine; do you have a 100MHz Pentium?). You must also modify the standard Makefile, and remember to continue to do so when upgrading to newer kernels.
The rdev command was written long ago to make it easier to set some of these important kernel options without a recompile. The program directly patches the appropriate variables in a kernel image. These are at fixed addresses (defined in boot/bootsect.S).
While using rdev is fast, it is still somewhat inconvenient in that you have to remember to run it after building each kernel. It is also limited in the options that can be changed. We can do better.
If you are using the LILO (LInux LOader) program to boot Linux (usually from hard disk), then you can pass command-line options to the kernel at boot time. Typically these are set in the configuration file /etc/lilo.conf.
This is the most flexible method. It allows you, for example, to boot different kernels or boot the same kernel with different options.
Most options are passed by LILO on to the kernel; one useful option is parsed and handled by LILO itself. ,The console video mode for VGA displays can be set using a command-line option of the form:
where mode can be one of:
“normal” for the default 80-column by 24-line display,
“extended” or “ext” for 80 columns by 50 lines,
“ask” to prompt the user at boot up time for the mode to use, or
a decimal number to select various other modes, dependent on the type of VGA card (for example, on my Trident VGA card, mode 6 is 132x30).
Let's now look at the specific options supported by the Linux kernel. These affect the behavior of the kernel itself and are not passed on to the init program.
Some of these options accept a numeric value, parsed by a simplified version of the strtoul library function. Values can be given in decimal (e.g., 1234), octal (e.g., 01234) or hexadecimal (e.g., 0x1234), and should be separated by spaces. Let's now examine each of the options.
This option sets the root device; the device used as the root (“/”) filesystem; when booting. It accepts a value from a hard-coded list of common devices: /dev/hda..b (IDE hard disks), /dev/sda..e (SCSI disks), /dev/fd (floppy), and /dev/xda..b (XT hard disks). These are mapped into the corresponding major and minor device numbers.
This option indicates that the root filesystem should be mounted readonly. Typically this is done in order to run fsck on bootup.
This option is the converse of the previous one, indicating that the root filesystem should be mounted for both read and write, the normal case once a Linux system has been booted.
This option sets the kernel logging level to 10, rather than the default value of 7. It sets the global variable “console_loglevel”. Currently this make no visible difference; apparently there is no kemel code that displays messages at levels higher than 7.
This sets the global variable “hlt_works_ok” to 0. When Linux is idle, it runs the previously mentioned idle process in a loop (found in kernel/sys.c). Having the idle process periodically execute a hlt (halt) instruction reduces power consumption on some machines, most notably laptops. However, a few users have reported problems with the kilt instruction on certain machines, so it can be disabled with this option.
Incidently, I routinely use this option on my desktop system; I find that it significantly reduces the level of bus noise picked up on my sound card.
This option sets the global variable “hard_math” to 0. It forces the kernel to use co-processor emulation, even if one is installed. This can be useful if you suspect hardware problems with your co-processor or if you want to measure performance without a math chip.
This option specifies to the kernel the highest memory address to use (specified in bytes). Normally Linux uses all of the available memory. This feature can be useful for simulating machines with less memory or debugging cache problems on machines with lots of memory. As an experiment, try booting your machine with less memory, say 2MB, to highlight the difference memory makes. As another experiment, see what happens if you lie and tell Linux you have more memory than is installed...
reserve=port, size. . .
This option reserves I/O ports; it marks them as used so they will not be probed by device drivers that do autoprobing. This may be needed on certain systems that have unusual hardware or device conflicts.
This option sets the size of the RAM disk, in bytes.
The next group of options are specific to individual kernel device drivers. I won't describe each of them in detail, because some of them are rather specialized and are documented elsewhere.
This option is for setting up Ethernet interfaces. It allows setting parameters such as the interrupt request number and base address. The meaning of the parameters varies somewhat depending on the type of interface card. The Ethernet HOWTO document describes these in detail.
This option sets the highest Logical Unit Number to be used for SCSI devices. Valid values are 1 through S. This may be needed if autoprobing of the SCSI bus causes problems on your system.
hd=cylinders, heads, sectors
This option sets the hard disk geometry for SCSI or IDE disks. Normally Linux obtains these from the BIOS; the command line option can be used to override those if they are not correct.
This option is for setting SCSI tape driver parameters. The file drivers/scsi/README.st describes these in detail.
This option sets the interrupt request line to be used for the bus mouse driver.
stOx=parameters tmc8xx=parameters stOx=parameters tl28=parameters pasl6=parameters ncr5380=parameters ncr5380=parameters ahal52x=parameters
These are all options for setting up the various SCSI host adaptors supported by the Linux kernel. See the SCSI HOWTO for more information.
xd=type, irq,i/o base_address,dma_channel
This option sets the XT hard disk driver parameters. See the comments in the file drivers/block/xd.c for more information.
mcd=port, irq, workaround_bug
This sets up the Mitsumi CD-ROM interface. The first two parameters are the base I/O address for the controller and the interrupt request. The third option sets a delay value used to work around problems with some Mitsumi drives.
These options set up the sound driver. The parameter encoding is explained in the file drivers/sound/Readme.linux.
This command sets the parameters for the SoundBlaster/Panasonic CD-ROM driver. See the file drivers/block/README.stpod for details.
Any other options are passed on to init in its argv array and as environment variables. For example, LILO passes the argument “auto” if the system was booted without a manually entered command line. The command “single” will instruct init to boot up Linux in single-user mode.
Here is how to see what options were passed to init:
% ps -awww | grep init 1 con S 0:03 init auto
The proc filesystem also lets you look at the environment passed to init, which always has process ID number 1:
% cat /proc/l/environ | tr t'\O'' "\n" HOME=/ TERM=conl32x30