Adding virtual disks to User Mode Linux

Running out of disk space

Well my good ‘friend’ with their inappropriately provisioned Linux VPS  that runs UML (User Mode Linux) inside of it, ran into an issue where he needed to add a second virtual disk device.

Creating the disk file is no big issue, adding a whopping 1GB is pretty simple!

Using the ‘dd’ command it is trivial to make a 1GB file like this:

dd if=/dev/zero of=node1_swap.ubda bs=1M count=1024

And then just append it to the script that they are using to run the UML:

/virtual/kernel ubda=/virtual/node1.ubda mem=384M eth0=slirp,,/virtual/sl1.sh

to this:

/virtual/kernel ubda=/virtual/node1.ubda ubdb=/virtual/node1_swap.ubda mem=384M eth0=slirp,,/virtual/sl1.sh

Of course the real fun comes from trying to find the devices.  Having to dig around I found that the device major is 98 for the UBD’s and that they incrament by 16, so that the first 3 devices are as follows:

mknod /dev/ubda b 98 0
mknod /dev/ubdb b 98 16
mknod /dev/ubdc b 98 32

Adding to that, you can partition them, and then they break out like this:

mknod /dev/ubda1 b 98 1
mknod /dev/ubda2 b 98 2
mknod /dev/ubda3 b 98 3
mknod /dev/ubdb1 b 98 17
mknod /dev/ubdb2 b 98 18

You get the idea.

With the disk added you can partition the ubd like a normal disk

node1:~# fdisk /dev/ubdb

Command (m for help): p

Disk /dev/ubdb: 1073 MB, 1073741824 bytes
128 heads, 32 sectors/track, 512 cylinders
Units = cylinders of 4096 * 512 = 2097152 bytes

Device Boot Start End Blocks Id System
/dev/ubdb1 1 245 501744 83 Linux
/dev/ubdb2 246 512 546816 82 Linux swap / Solaris

etc etc.  And yes, you can then format, mount and all that.

First let’s setup the swap:

mkswap /dev/ubdb2
swapon /dev/ubdb2

Now let’s format the additional /tmp partition

node1:~# mke2fs /dev/ubdb1
mke2fs 1.40-WIP (14-Nov-2006)
Filesystem label=
OS type: Linux
Block size=1024 (log=0)
Fragment size=1024 (log=0)
125488 inodes, 501744 blocks
25087 blocks (5.00%) reserved for the super user
First data block=1
Maximum filesystem blocks=67633152
62 block groups
8192 blocks per group, 8192 fragments per group
2024 inodes per group
Superblock backups stored on blocks:
8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409

Writing inode tables: done
Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 24 mounts or
180 days, whichever comes first. Use tune2fs -c or -i to override.

Now adding the following to the /etc/fstab so it’ll automatically mount the /tmp directory and add the swap:

/dev/ubdb1 /tmp ext2 defaults 0 0
/dev/ubdb2 none swap defaults 0 0

Now he’s got a dedicated swap partition, and a separate /tmp filesystem.

Starting on an ELF cross compiler for Windows

I’m using Slackware 4.0 as a starting point, so it’s Binutils 2.9.1 and GCC 2.7.2.3 .. I verified that I can build a static hello world executable, and it runs! …

However Linux 2.0.40 has the same issue, it starts to decompress, and triggers a reboot in both Qemu and PCem.  Going in circles I guess.  I suppose the next step is to use the exact version they have in Slackware to see if Qemu can actually run that pre-built kernel, and if I can create one via cross compiling.

I should add that on Debian 7.1 I got GCC 2.7.2.3 running, and it too produces the exact same thing.

Not that I think anyone cares, but here is my pre-built toolchain with some source (The binutils was built under Linux, using a MinGW cross compiler) elfgcc_2.0.40.7z

Cross compiled Linux 1.0.9!

Linux 1.0.9 running!

Linux 1.0.9 running!

After getting Linux 0.98 to compile, I thought I’d take a stab at Linux 1.0.  I vaugely recall when it was released, and I just remember a much larger push to 1.1.  So I guess it really comes as no surprise that in the Linux kernel archives, there is simply the 1.0 tar, and 9 patch files.

I went ahead, and patched up the release, and then tried to build with GCC 2.3.3.  This however proved not to be up to the task, as 2.3.3 has issues with some of the assembly macros, so delving into the readme shows that you need to use GCC 2.4.5 or higher.  Since I wanted to keep at least the tools on par, I went ahead and build 2.4.5, and once more again used the gcc driver from 2.6.3.  I further ended up relying on headers, and checking tool versions from Debian 0.91, which also revealed that they were still using GAS 1.38 back then.

One interesting note while building piggback, which takes the compressed system object, and wraps it in an object file, is that it directly uses the magic “0x00640107”, which is for a later “Linux/i386 impure executable (OMAGIC)” filetype.  But because my binutils is so ancient, I needed to change it to “0x00000107” so that the linker would recognize it as a “386 executable not stripped” file.  As always when having no idea what I was doing, it was easier to have it make an empty object file, set the type for 12345678 and look for where it occurs in the data stream, and just match it with a known object file.  As you can see, it worked.

I don’t know if it is of any interest, but the kernel source, along with a binary is available to download linux-1.0.9.7z, and the same goes for GCC gcc-2.4.5.7z.

And of course, you’ll want the latest download, which includes the pre-built tools, qemu, and build environment to get you started.

User Mode Linux revisited (UML) aka SLiRP networking

So my uh ‘friend’ that got into trouble when he found out that his ‘dedicated’ machine turned out to be a VM which he couldn’t launch nested KVM VM’s, and instead found that User Mode Linux (UML), would allow them to run their touchy ancient Linux application in a psudo VM/Container.  Well they finally bit the bullet and decided to move to something better.

And by better, it was cheaper.  And why was it cheaper?  Because it is even a more restricted VM.

Great.

So naturally the panic call was made, because TUN/TAP networking was not permitted in this new VM.  So what to do.

Well, keeping in mind how Qemu gets around this problem, it binds in a copy of SLiRP.  And it turns out that UML can actually call SLiRP directly!  So cool we have an ‘out’.  First things first, we need SLiRP on the host machine.  I’m old, so that means I build it from source.That means I’m downloading slirp-1.0.16.tar.gz, along with the 1.0.17 patch.  I’m not sure if I need to go into how to extract source, patch, running configure and compiling.

One thing of note is that you really really really want to set the “FULL_BOLT” option either in the Makefile, or in config.h

With SLiRP built, I just copy it into /usr/local/bin .. I’m sure there is packages and stuff out there, but heh I’m old.

OK next up I make a small script to call SLiRP, in this case, I’m going to redirect port 80 directly into the VM.  And for a test port 2323 which then goes into port 23 (why not ssh? .. sigh don’t go there).

So my script looks like this:

#!/bin/sh
/usr/local/bin/slirp “redir 80 80” “redir 23 2323”

Pretty simple right?  I’m using a script as there will be more than one VM, so relying on .slirprc isn’t a solution for me.

./linux-2.6.24-rc7 ubd0=junk.ubda eth0=slirp,,/virtual/sl.sh

And away we go!

Inside the VM we can configure it with the usual SLiRP config:

ifconfig eth0 10.0.2.15 255.255.255.0
route add default gw 10.0.2.2

And now we can access the internal http server!

Add in some magic to /etc/resolv.conf such as:

nameserver 10.0.2.3

and it’ll automatically use whatever the host is configured to do.

Torbjörn Granlund’s Excellent resource on running free OS’s on Qemu

Ever get tired of x86 on x86?  yeah me too.

How to solve that problem?

Simple, grab QEMU, and jump off into all those cool RISC processors of the 1990’s that were going to save us all from the WINTEL hegemony!

Lots of instructions, samples, images, and hints here:

https://gmplib.org/~tege/qemu.html

It’s really more comprehensive than I’ve sat down to do, so yeah it’s awesome!

Supported platforms include:

mips32,mips64,sparc32,sparc64,ppc32,ppc64,arm32,arm64,s390x,alpha

Cross compiling Linux 0.95c+ & 0.96c from Windows

So first thing is to build GCC 2…  I couldn’t find any of the Linux patches for 2.0, 2.1 or 2.2.. I only tried to build 2.0 from source as targeting a.out i386 but it looks like the 2.0 files on the FSF’s site are missing files?

Anyways GCC 2.3.3 actually includes builtin support of Linux!  I was able to build most of it, but just like GCC 2.5.8 for OS/2 EMX, But this time I used the gcc driver from GCC 2.6.3, which added support for Windows NT 3.5 native builds, and I now had my GCC cross compiler!

D:\aoutgcc\src>gcc2 -v -c hi.c -o hi
gcc version 2.6.3 -Linux 2.3.3
cpp2 -lang-c -v -undef -D__GNUC__=2 -Dunix -Di386 -Dlinux -D__unix__ -D__i386__ -D__linux__ -D__unix -D__i386 -D__linux hi.c C:\Temp\cca09324.i
GNU CPP version 2.3.3 (80386, BSD syntax)
cc12 C:\Temp\cca09324.i -quiet -dumpbase hi.c -version -o C:\Temp\cca09324.s
GNU C version 2.3.3 (80386, BSD syntax) compiled by GNU C version 5.1.0.
a386 -o hi C:\Temp\cca09324.s

 

Thankfully the prior binutils and assembler I was using in my GCC 1.40 cross compiler, still cooperated just fine, and I could happily build and link just fine.

From there it was a matter of fighting the makefiles as for some reason as make calls other makefiles they are not passing variables, so I just cheated, and changed the paths, along with editing the dependencies to finding stuff in a more sane manner.  Plus all the Makefiles have include paths hard coded into the build process as expected.  After fighting for a while, it linked and even better, it runs!

linux-0-96c-71-cross-compiled-from-windows

Linux 0.96c-71 cross compiled from windows

So yeah, using the MCC hard disk image from oldlinux.org and it boots!

Cool stuff, indeed!

As an added bonus I was also able to get 0.97 & 0.98 to compile as well!

Download your copy @ MinGW-aout-linux–001_010_011_012_095_096_097_098.7z.

Linux 0.01 remake

While further searching around on Linux 0.01, I came across DrAcOnUx’s site which features a Linux 0.01 remake!

It’s really great, first off there are several versions in the steps of the evolution of the project:

Linux-0.01-1.x :
– need gcc 1.4
– few change from official linux-0.01, only some bug fix, + minor change to build it in a linux system instead of minix

Linux-0.01-2.x :
– same version as linux-0.01-1.7, which was just ported to work with gcc-2.x and gcc-3.x

linux-0.01-3.x :
– this is the last version
– need gcc-4.x
– use elf binary format instead of a.out, and you have some program working on it

As I actually do have a working GCC 1.40 + Binutils I though it would be great to build his first phase on Windows.  With a little playing around in the makefiles, and the build program to open files in binary mode, I had a kernel!

Linux 0.01 remake

Linux 0.01 remake

Obviously there is issues with the executables that I have from Linux 0.10/Linux 0.11.  But we are mounting the disk, and using the /dev tree devices.  I put the remake versions on my cvsweb to walk though what changed.

Using an older ‘modern’ Linux machine with GCC 4.1 I was able to compile the remake #3 kernel, and even better with the provided disk image from the downloads page it works!


# gcc -v
Using built-in specs.
Target: i486-linux-gnu
Configured with: ../src/configure -v --enable-languages=c,c++,fortran,objc,obj-c++,treelang --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --program-suffix=-4.1 --enable-__cxa_atexit --enable-clocale=gnu --enable-libstdcxx-debug --enable-mpfr --with-tune=i686 --enable-checking=release i486-linux-gnu
Thread model: posix
gcc version 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)

Linux 0.01 remake #3

Linux 0.01 remake #3

For any aspiring software historians out there, this early version of Linux from September of 1991 will be of course VERY interesting!

Linux 0.01 on Qemu!

Well sort of.

Linux 0.01!

Linux 0.01!

I looked at the source again, and for some reason 99% of it compiled without issue.  I recall having all kinds of issues, but clearly I was doing something wrong back then.  At any rate, all I really had to do was modify the commenting style in the 8086 boot block code, and modify the image creation tool to open files in O_BINARY mode for Windows, and I got an image that will boot, then panic because it has issues reading the hard disk.  I tried the seemingly small ‘fix’ from Linux 0.11 but it’s not working.

If anyone cares, I updated the sourceforge download, as MinGW-aout-linux–001_010_011.7z

Linux at 25 years!

As we quickly approach this amazing milestone, I think it’s always interesting to re-visit the roots of Linux, back to the really ancient versions.  Thanks to the hard work of oldlinux.org, the oldest intact Linux source code available is Linux 0.10 from November of 1991.  A popular writeup on 0.10 was up on kerneltrap.org which appears to have been vaporized, but thanks to archvie.org is preserved.

Since this version is complete I thought it would be fun to run it through the Linux 0.11 build process & toolchain to see if I could get a working kernel.  Well I had a few stumbling blocks, the bootblocks and the keyboard assembly driver were giving me issues, and for the sake of time, I went ahead and replaced them with the code from 0.11, and along with minor patching to the IDE disk driver.  I added in a simple line to let me know I was actually booting up my franken 0.10 kernel with Qemu.  Also I found later versions of Qemu work much better with 0.10 regarding the IDE disk.

Linux 0.10 on Qemu, cross compiled on Windows

Linux 0.10 on Qemu, cross compiled on Windows

I know it’s not much to look at but it really is building and running.  I’m using the disk for the 0.11 series, as the userland seems to somewhat work.  It’s very touchy, and prone to crashing as it ‘has a bug in the buffer cache’ that I didn’t feel like trying to track down.  Nobody should be using this for anything serious anyways.

Install the 0.11 a.out GCC 1.40 on Win32 cross environment (I guess you can build them on Linux too if you so desire), and if you have a working MSYS environment you can run ‘make’ and it should give you a kernel.  The command file ‘linux.cmd’ will boot it up, and attach the disk image that I used to test.  There are permission errors, and well.. errors.  0.10 was not able to selfhost, but it should be enough to boot, mount the root, and run stuff like the sample ‘hello world’ program.

For those who like to browse the source, I have a browsable tree here.

And for the 2-3 people who care, here is my updated linux-0.10 source tree hosted on sourceforge.