Synopsis

This document describes how to setup a working UML completely from scratch (no preloaded filesystems) without needing root access. Anywhere.

Why on earth would you want to do that?

Because it can be done.

Who are you?

Stephen Oberholtzer, aka Stevie-O.

Wait, that's not the way you should do X!

You're probably right. Especially if X is a config setting when building the kernel. I wasn't going for perfect. I was going for something that works.

This all seems like a lot of work that involves several unnecessary steps.

That's correct. Some of these steps could be avoided (for example, I could provide prebuilt binaries of the UML kernel.) But where's the fun in that?

You could also probably speed up the kernel compilation by NOT building in support for every filesystem ever created, ever.


What you'll need

You'll need several things in order to make this work. If you have all of that covered, we may begin.
  1. My test shell didn't have locale stuff enabled, which is bad, because for this stuff to work right, you need to be using a UTF-8 character encoding. The locales package was installed, and localedef was there (it's part of the libc6 package in Debian), but no locales had been built.
    cd ~ wget http://ftp.us.debian.org/debian/pool/main/g/glibc/locales_2.3.2.ds1-22_all.deb dpkg -x locales_2.3.2.ds1-22_all.deb mylocales # after some tweaking I learned that locale-gen tries to run the following # localedef -i en_US -c -f UTF-8 -A /etc/locale.alias en_US.UTF-8 # after some more fiddling and googling I found that localedef doesn't play # nicely unless you do certain tricks. The trailing slash at the end of the # following command line is crucial: I18NPATH=~/mylocales/usr/share/i18n/ localedef -i en_US -c -f UTF-8 -A /etc/locale.alias ~/mylocales/en_US.UTF-8/ # see http://gentoo-wiki.com/Talk:HOWTO_localedef
    I then put the following into my .bash_profile:
    export LANG=en_US.UTF-8 export LOCPATH=~/mylocales
    Then I logged out and logged back in.

    I had to do two more things to really make it all work:

  2. Decide how big you want your virtual drive to be. I suggest 512MB-1024MB. Partman has trouble autopartitioning 512MB drives, so if you want to auto partition, use 1024.
  3. Create the virtual drive. (Replace 1024 with the number of MB you want your drive to be.)
    dd if=/dev/zero of=uml-drive bs=1M count=1024
    This will probably take a while; don't worry unless you don't get something back that looks like:
    1024+0 records in
    1024+0 records out
    
    Except that instead of 1024, it will say whatever you put for the 'count=' value.
  4. Download the files you're going to need.
  5. Extract the ISO helper.
    tar jxf iso-perl-stuff.tar.bz2 # or iso-perl-stuff-5.5.tar.bz2 if you have an older perl
  6. Extract the initrd from the CD image.
    perl -Iiso-perl-stuff iso-perl-stuff/isocat.pl debian-testing-i386-netinst.iso /install/2.6/initrd.gz > uml-initrd.gz
  7. Extract the Linux kernel source and the UML patch.
    tar jxf linux-2.6.15.6.tar.bz2 bunzip2 uml-2.6.15-bs3-tls.patch.bz2
  8. Optionally get worried when you see a message saying
    tar: pax_global_header: Unknown file type 'g', extracted as normal file
  9. Start building your kernel.
    1. Enter the directory.
      cd linux-2.6.15.6
    2. Patch the kernel to add TLS support.
      patch -p1 < ../uml-2.6.15-bs3-tls.patch
    3. Make sure it knows you're doing UML.
      export ARCH=um
    4. Now it's time to tweak things.
      make menuconfig
      • UML-specific options: (if you don't see this, you forgot to do export ARCH=um)
        • Y to CONFIG_BINFMT_MISC ("Kernel support for MISC binaries")
        • Y to CONFIG_HOSTFS ("Host filesystem")
        • Y to CONFIG_MCONSOLE_EXEC ("Management console 'exec' support')
        • Y to CONFIG_MAGIC_SYSQR ("Magic SysRq key")
        • Under Host processor type, make sure you choose Pentium-Pro (assuming your shell is on an x86 system)
      • General Setup:
        • N to "BSD Process Accounting version 3"
        • N to "Configure standard kernel features"
        • N to "Optimize for size"
        • Y to everything else here.
      • Loadable Module Support
        • N to "Enable loadable module support".
      • Block Devices
        • Turn everything on here
      • Networking
        • Y to Networking Support
        • Y to EVERYTHING under Networking Options, except:
          • N to ARP Daemon support
          • N to the various options for debugging (watch out for the Simple Example in the QoS section)
          • N to Asynchronous Transfer Mode (ATM)
          • N to DECnet
          • N to IPX
          • N to Appletalk
          • N to CCITT X.25
          • N to LAPB Data Link Driver
          • N to Acorn
          • N to WAN Router
          • Be absolutely certain you specify N to the Network Testing/Packet Generator option
        • N to Amateur Radio support
        • N to IRDA support
        • N to Bluetooth support
        • N to Generic IEEE 802.11 support
      • Character Devices
        • N to Legacy (BSD) PTY support
        • N to Sound support
        • N to Disable Watchdog Shutdown on Close
        • N to iomem emulation driver
        • Y to everything else here
        • Default main console initialization: "fd:0,fd:1"
        • Default console channel initialization: "pts"
        • Default serial line channel initialization: "pty"
      • Block Devices
        • N to ATA over Ethernet support
        • Y to everything else here, especially "Virtual block device"
      • UML Network Devices
        • N to pcap device! Note: You can actually choose Y here, but your kernel won't compile unless the pcap headers are installed. Furthermore, you'd need root in order to attach to an interface, in which case (a) why are you reading this document?, and (b) the tun/tap interface is easier to manage.
        • Y to everything else in here, especially SLiRP
      • Network Device Support
        • Don't turn on WAN Interface support
        • Turn on all the PPP crap
        • Turn on TUN/TAP
      • Connector
        • Turn it all on
      • Filesystems
        • N to ext2 execute in place support
        • N to XFS Realtime support
        • N to all those debugging options (including Stats in proc/fs/reiserfs)
        • N to NTFS write support as well, unless you really want it
        • N to Allow direct I/O on NFS files
        • N to Use a default NLS (on SMB file system support)
        • N to CIFS Experimental Features
        • N to NCP file system support (unless you're planning to mount some NetWare drive images)
        • N to 96-bit Coda identifiers
        • No point in saying Y to Advanced partition selection until the eloop driver (which supports partition tables on loopback mounts) goes mainline.
        • Leave Native Language Support alone.
        • Y to everything else
      • Security Options
        • N to both of these unless you want to try out SELinux or something :)
      • Cryptographic options
        • I don't think you need to turn any of these on, but it should be safe to do so
      • Library routines
        • Y to all of these
      • Multi-device support (RAID and LVM)
        • N to Multipath I/O support
        • N to Faulty test module
        • N to Multipath Target
        • Y to everything else
      • Kernel hacking
        • N to command-line arguments in TT mode
      • Finally, save your configuration.
    5. Build the kernel:
      make
    6. Go get a pizza (or compile eggdrop.)
    7. Return to the place from whence you came.
      ln linux .. cd ..
  10. Setup uml_mconsole.
    tar jxf uml_utilities_20060216.tar.bz2 cd tools-20060216 make
    Of course, this didn't work on my system. It needed some encouragement. (Back in the main dir)
    wget http://ftp.us.debian.org/debian/pool/main/r/readline5/libreadline5-dev_5.1-6_i386.deb dpkg -x libreadline5-dev_5.1-6_i386.deb readline-dev export CFLAGS="-I$PWD/readline/usr/include -L$PWD/readline-dev/usr/lib" cd tools-20060216/mconsole make ln uml_mconsole ../..
  11. Setup SLiRP.
  12. Start installing Debian!
    ./linux mem=64M ubd0=uml-drive ubd2r=debian-testing-i386-netinst.iso eth0=slirp,,./slirp root=/dev/ram rw ramdisk=10240 initrd=uml-initrd.gz netcfg/disable_dhcp=true hw-detect/start_pmcia=false debian-installer/probe/usb=false
    Be sure to put your terminal program into UTF-8 mode. Also, if you're running under screen, you'll want screen to know you're really in a UTF-8 locale (LANG=en_US.UTF8). Furthermore, older versions of screen are just totally hopeless and will always screw up the first few lines of output. Live with it.
    This will be pretty straightforward, except at the beginning. Pay attention! Here is how to configure the network: Partitioning: ubda is your virtual drive. Use that.

    Once that stuff is done, you should be good to go for a while. (A long while. For example, now would probably be a good time to take a nap. (This will be especially slow because if you're reading this document, you're almost certainly running under skas0 mode, which is a lot less efficient than skas3+sysemu.)

    Update: jdike has informed me that sysemu was mainlined as of 2.6.14. Cool.

    When the time comes, it will ask you if you want to install GRUB to the master boot record. Choose to Go Back. You will find yourself back at the main menu; choose "Continue without boot loader".

    When you get to the prompt warning you that it's time to reboot, you need to pay close attention. When the UML reboots and says "UML running in (SKAS0|SKAS3|TT) mode", hit Control-C to stop it.

  13. Boot your new system!

    ./linux mem=64M ubd0=uml-drive eth0=slirp,,./slirp root=/dev/ubda1 ro
    It will run for a while and then you'll get a pile of messages that look like this:
    [42949410.210000] Virtual console 3 assigned device '/dev/pts/282'
    [42949410.270000] Virtual console 4 assigned device '/dev/pts/283'
    [42949410.270000] Virtual console 5 assigned device '/dev/pts/284'
    [42949410.270000] Virtual console 6 assigned device '/dev/pts/285'
    [42949410.320000] Virtual console 1 assigned device '/dev/pts/286'
    [42949410.320000] Virtual console 2 assigned device '/dev/pts/287'
    
    Find the one that says 'Virtual console 1' and then run
    screen /dev/pts/whatever
    and hit Enter.