Mercurial > hg > aboriginal
view www/design.html @ 45:fd937c731cac
Add g++ to package list.
author | Rob Landley <rob@landley.net> |
---|---|
date | Sun, 17 Dec 2006 17:32:24 -0500 |
parents | f8c588578fa1 |
children | c2becd45f162 |
line wrap: on
line source
<title>Flimsy rationalizations for all of my design mistakes</title> <h2>What is it?</h2> <h2>Firmware Linux is a bootable single file linux system.</h2> <p>Firmware Linux is one file containing a kernel, initramfs, read-only root filesystem, and cryptographic signature. You can boot Linux from this file as if it was a normal kernel image (a slightly modified LILO is required on x86, patches for other bootloaders are a to-do item). You can upgrade your entire OS (and any applications in the root filesystem) atomically, by downloading a new file and pointing your bootloader at it.</p> <p>Firmware Linux is a Linux distro using busybox and uClibc as the basis for a self-hosting development environment. The only gnu utilities used in the build are gcc, binutils, make, and bash. At some point in the future tcc and toybox should be able to replace these, at which point a version of Linux exists that even the FSF can't stick a undeserved GNU/ prefix on.</p> <h2>Packaging</h2> <p>The single file packaging combines a linux kernel, initramfs, squashfs partition, and cryptographic signature.</p> <p>In 2.6, the kernel and initramfs are already combined into a single file. At the start of this file is either the obsolete floppy boot sector (just a stub in 2.6), or an ELF header which has 12 used bytes followed by 8 unused bytes. Either way, we can generally use the 4 bytes starting at offset 12 to store the original length of the kernel image, then append a squashfs root partition to the file, followed by a whole-file cryptographic signature.</p> <p>A User Mode Linux executable or non-x86 ELF image should still run just fine (if loading is controlled by the ELF segments, the appended data is ignored). Note: don't strip the file or the appended data will be lost.</p> <p>Loading an x86 bzImage kernel requires a modified boot loader that can be told the original size of the kernel, rather than querying the current file length which would be too long. Hence the patch to Lilo allowing a "length=xxx" argument in the config file.</p> <p>Upon boot, the kernel runs the initramfs code which finds the firmware file. In the case of User Mode Linux, the symlink /proc/self/exe points to the path of the file. A bootable kernel needs a command line argument of the form firmware=device:/path/to/file (it can lookup the device in /sys/block and create a temporary device node to mount it with; this is in expectation of dynamic major/minor happening sooner or later). Once the file is found, /dev/loop0 is bound to it with an offset (losetup -o, with a value extracted from the 4 bytes stored at offset 12 in the file), and the resulting squashfs is used as the new root partition.</p> <p>The cryptographic signature can be verified on boot, but more importantly it can be verified when upgrading the firmware. New firmware images can be installed beside old firmware, and LILO can be updated with boot options for both firmware, with a default pointing to the _old_ firmware. The lilo -R option sets the command line for the next boot only, and that can be used to boot into the new firmware. The new firmware can run whatever self-diagnostic is desired before permanently changing the default. If the new firmware doesn't boot (or fails its diagnostic), power cycle the machine and the old firmware comes up. (Note that grub does not have an equivalent for LILO's -R option; which would mean that if the new firmware doesn't run, you have a brick.)</p> <h2>Filesystem Layout</h2> <p>Firmware Linux's directory hierarchy is a bit idiosyncratic: some redundant directories have been merged, with symlinks from the standard positions pointing to their new positions. On the bright side, this makes it easy to make the root partition read-only.</p> <h3>Simplifying the $PATH.</h3> <p>The set "bin->usr/bin, sbin->usr/sbin, lib->usr/lib" all serve to consolidate all the executables under /usr. This has a bunch of nice effects: making a a read-only run-from-CD filesystem easier to do, allowing du /usr to show the whole system size, allowing everything outside of there to be mounted noexec, and of course having just one place to look for everything. (Normal executables are in /usr/bin. Root only executables are in /usr/sbin. Libraries are in /usr/lib.)</p> <p>For those of you wondering why /bin and /usr/sbin were split in the first place, the answer is it's because Ken Thompson and Dennis Ritchie ran out of space on the original 2.5 megabyte RK-05 disk pack their root partition lived on in 1971, and leaked the OS into their second RK-05 disk pack where the user home directories lived. When they got more disk space, they created a new direct (/home) and moved all the user home directories there.</p> <p>The real reason we kept it is tradition. The execuse is that the root partition contains early boot stuff and /usr may get mounted later, but these days we use initial ramdisks (initrd and initramfs) to handle that sort of thing. The version skew issues of actually trying to mix and match different versions of /lib/libc.so.* living on a local hard drive with a /usr/bin/* from the network mount are not pretty.</p> <p>I.E. The seperation is just a historical relic, and I've consolidated it in the name of simplicity.</p> <p>The one bit where this can cause a problem is merging /lib with /usr/lib, which means that the same library can show up in the search path twice, and when that happens binutils gets confused and bloats the resulting executables. (They become as big as statically linked, but still refuse to run without opening the shared libraries.) This is really a bug in either binutils or collect2, and has probably been fixed since I first noticed it. In any case, the proper fix is to take /lib out of the binutils search path, which we do. The symlink is left there in case somebody's using dlopen, and for "standards compliance".</p> <p>On a related note, there's no reason for "/opt". After the original Unix leaked into /usr, Unix shipped out into the world in semi-standardized forms (Version 7, System III, the Berkeley Software Distribution...) and sites that installed these wanted places to add their own packages to the system without mixing their additions in with the base system. So they created "/usr/local" and created a third instance of bin/sbin/lib and so on under there. Then Linux distributors wanted a place to install optional packages, and they had /bin, /usr/bin, and /usr/local/bin to choose from, but the problem with each of those is that they were already in use and thus might be cluttered by who knows what. So a new directory was created, /opt, for "optional" packages like firefox or open office.</p> <p>It's only a matter of time before somebody suggests /opt/local, and I'm not humoring this. Executables for everybody go in /usr/bin, ones usable only by root go in /usr/sbin. There's no /usr/local or /opt. /bin and /sbin are symlinks to the corresponding /usr directories, but there's no reason to put them in the $PATH.</p> <h3>Consolidating writeable directories.</h3> <p>All the editable stuff has been moved under "var", starting with symlinking tmp->var/tmp. Although /tmp is much less useful these days than it used to be, some things (like X) still love to stick things like named pipes in there. Long ago in the days of little hard drive space and even less ram, people made extensive use of temporary files and they threw them in /tmp because ~home had an ironclad quota. These days, putting anything in /tmp with a predictable filename is a security issue (symlink attacks, you can be made to overwrite any arbitrary file you have access to). Most temporary files for things like the printer or email migrated to /var/spool (where there are persistent subdirectories with known ownership and permissions) or in the user's home directory under something like "~/.kde".</p> <p>The theoretical difference between /tmp and /var/tmp is that the contents of /var/tmp should definitely be deleted by the system init scripts on every reboot, but the contents of /tmp may be preserved across reboots. Except deleting everyting out of /tmp during a reboot is a good idea anyway, and any program that actually depends on the contents of /tmp being preserved across a reboot is obviously broken, so there's no reason not to symlink them together.</p> <p>(I case it hasn't become apparent yet, there's 30 years of accumulated cruft in the standards, convering a lot of cases that don't apply outside of supercomputing centers where 500 people share accounts on a mainframe that has a dedicated support staff. They serve no purpose on a laptop, let alone an embedded system.)</p> <p>The corner case is /etc, which can be writeable (we symlink it to var/etc) or a read-only part of the / partition. It's really a question of whether you want to update configuration information and user accounts in a running system, or whether that stuff should be fixed before deploying. We're doing some cleanup, but leaving /etc writeable (as a symlink to /var/etc). Firmware Linux symlinks /etc/mtab->/proc/mounts, which is required by modern stuff like shared subtrees. If you want a read-only /etc, use "find /etc -type f | xargs ls -lt" to see what gets updated on the live system. Some specific cases are that /etc/adjtime was moved to /var by LSB and /etc/resolv.conf should be a symlink somewhere writeable.</p> <h3>The resulting mount points</h3> <p>The result of all this is that a running system can have / be mounted read only (with /usr living under that), /var can be ramfs or tmpfs with a tarball extracted to initialize it on boot, /dev can be ramfs/tmpfs managed by udev or mdev (with /dev/pts as devpts under that: note that /dev/shm naturally inherits /dev's tmpfs and some things like User Mode Linux get upset if /dev/shm is mounted noexec), /proc can be procfs, /sys can bs sysfs. Optionally, /home can be be an actual writeable filesystem on a hard drive or the network.</p> <p>Remember to put root's home directory somewhere writeable (I.E. /root should move to either /var/root or /home/root, change the passwd entry to do this), and life is good.</p> </p>