Linux 2.6 Distribution for LOADLIN
I have done some experiments and changed the earlier distribution from Linux 2.4 to Linux 2.6. The goal is still to be able to load the kernel and root filesystem with LOADLIN from DOS on a 386 system.
A notable change is that the /dev filesystem is now populated automatically by the kernel using devtmpfs. The VGA/VESA framebuffer console has also been enabled. It seems it is not possible to use the newer "libata" drivers for IDE/ATA hard drive access on a 386 so the older drivers are used. By default the latest 2.6 kernels also try to load the kernel at 16MB address, but this has been changed to 1MB to support systems with less RAM.
The following specific software versions are used:
* linux-2.6.39.4
* gcc-4.9.4
* busybox-1.37.0
* uClibc-ng-1.0.51
* binutils-2.32
Note that I have ran the compilation on a modern Slackware 15.0 system with GCC 11.2 and some adjustments were required to force usage of older C++ when building the GCC 4.9 cross toolchain. I also added the $MAKE_JOBS variable to significantly speed up compilation time for modern multi-core CPUs.
Get the necessary scripts, configuration and patches here to make it yourself. Or just get the completed kernel and root filesystem here.
Once again, for easy reference, here is the script to compile everything:
#!/bin/bash set -e TARGET="i386-linux-uclibc" # PREFIX="${HOME}/opt/gcc-${TARGET}/" PREFIX="`pwd`/gcc-${TARGET}/" SYSROOT="${PREFIX}/${TARGET}/sysroot" MAKE_JOBS="-j32" GCC_SRC="gcc-4.9.4.tar.bz2" BINUTILS_SRC="binutils-2.32.tar.xz" UCLIBC_SRC="uClibc-ng-1.0.51.tar.xz" LINUX_SRC="linux-2.6.39.4.tar.xz" BUSYBOX_SRC="busybox-1.37.0.tar.bz2" export PATH="${PREFIX}bin:$PATH" # Prepare Prefix and System Root if [ -d "$SYSROOT" ]; then echo "Old system root directory detected, please remove it." exit 1 else mkdir -p "$SYSROOT/usr" fi # Prepare Build Directories: if [ -d build ]; then echo "Old build directory detected, please remove it." exit 1 else mkdir -p build/binutils mkdir -p build/gcc-stage1 mkdir -p build/gcc-stage2 mkdir -p build/uclibc mkdir -p build/linux mkdir -p build/busybox fi # Unpack Sources: if [ -d source ]; then cd source tar -xvjf "$GCC_SRC" tar -xvJf "$BINUTILS_SRC" tar -xvJf "$UCLIBC_SRC" -C ../build/uclibc tar -xvJf "$LINUX_SRC" -C ../build/linux tar -xvjf "$BUSYBOX_SRC" -C ../build/busybox cd - else echo "No source directory, please download sources." exit 1 fi # Patch Linux 2.6 timeconst.pl cd build/linux/linux-*/kernel if fgrep --silent "defined(@val)" timeconst.pl; then patch -p 0 < ../../../../timeconst.pl.patch fi cd - # Patch Linux 2.6 ptrace.h cd build/linux/linux-*/arch/x86/include/asm if fgrep --silent "extern long syscall_trace_enter" ptrace.h; then patch -p 0 < ../../../../../../../ptrace.h.patch fi cd - # Install Linux 2.6 Headers: cd build/linux/linux-* make ARCH=i386 defconfig make ARCH=i386 INSTALL_HDR_PATH="$SYSROOT/usr" headers_install cd - # Build binutils: cd build/binutils ../../source/binutils-*/configure --target="$TARGET" --prefix="$PREFIX" --with-sysroot="$SYSROOT" --disable-werror --enable-languages=c,c++ --enable-shared --without-newlib --disable-libgomp --enable-fast-install=N/A make all-{binutils,gas,ld} $MAKE_JOBS make install-{binutils,ld,gas} cd - # Build Stage 1 GCC4 (Without libgcc): cd build/gcc-stage1 CXXFLAGS="--std=c++03 -g -O2" ../../source/gcc-*/configure --target=$TARGET --prefix=$PREFIX --with-sysroot=$SYSROOT --with-cpu=i386 --disable-fast-install --disable-werror --disable-multilib --enable-languages=c --without-headers --disable-shared --disable-libssp --disable-libmudflap --with-newlib --disable-c99 --disable-libgomp CXXFLAGS="--std=c++03 -g -O2" make all-gcc $MAKE_JOBS make install-gcc cd - # Install uClibc headers: cd build/uclibc/uClibc-* cp -v ../../../config-uclibc .config sed -i -e "s%KERNEL_HEADERS=.*%KERNEL_HEADERS=\"$SYSROOT/usr/include/\"%" .config make ARCH=i386 PREFIX="$SYSROOT" install_headers cd - # Build Stage 1 GCC4 (libgcc): cd build/gcc-stage1 CXXFLAGS="--std=c++03 -g -O2" make all-target-libgcc $MAKE_JOBS make install-target-libgcc cd - # Build uClibc: cd build/uclibc/uClibc-* make ARCH=i386 PREFIX="$SYSROOT" $MAKE_JOBS make ARCH=i386 PREFIX="$SYSROOT" install cd - # Build Stage 2 GCC4: cd build/gcc-stage2 CXXFLAGS="--std=c++11 -g -O2" ../../source/gcc-*/configure --target=$TARGET --prefix=$PREFIX --with-sysroot=$SYSROOT --with-cpu=i386 --enable-fast-install=N/A --disable-werror --enable-languages=c,c++ --enable-shared --without-newlib --disable-libgomp CXXFLAGS="--std=c++11 -g -O2" make all-{gcc,target-libgcc,target-libstdc++-v3} $MAKE_JOBS make install-{gcc,target-libgcc,target-libstdc++-v3} cd - # Build Linux 2.6: cd build/linux/linux-* cp -v ../../../config-linux .config make ARCH=i386 CROSS_COMPILE=i386-linux-uclibc- bzImage $MAKE_JOBS cp -v ./arch/x86/boot/bzImage ../../../bzImage cd - # Build Busybox: cd build/busybox/busybox-* cp -v ../../../config-busybox .config make CROSS_COMPILE=i386-linux-uclibc- $MAKE_JOBS cd -
Once again, here is the script to make the root filesystem:
#!/bin/bash set -e ROOTFS="`pwd`/rootfs/" TARGET="i386-linux-uclibc" # PREFIX="${HOME}/opt/gcc-${TARGET}/" PREFIX="`pwd`/gcc-${TARGET}/" SYSROOT="${PREFIX}/${TARGET}/sysroot" export PATH="${PREFIX}bin:$PATH" if [ -d "$ROOTFS" ]; then echo "Old root FS directory detected, please remove it." exit 1 fi mkdir -p "$ROOTFS" # Install Busybox: cd build/busybox/busybox-* make CROSS_COMPILE=i386-linux-uclibc- CONFIG_PREFIX="$ROOTFS" install cd - # Create some essential directories: cd "$ROOTFS" mkdir -v etc mkdir -v etc/init.d mkdir -v lib mkdir -v proc mkdir -v sys mkdir -v tmp mkdir -v root mkdir -v dev cd - # Initial rc.S: cat > rcS <<EOF #!/bin/sh mount -t proc /proc /proc mount -t tmpfs /tmp /tmp loadkmap < /etc/no-latin1.bmap hostname busybox EOF mv -v rcS "$ROOTFS/etc/init.d/" # Initial inittab: cat > inittab <<EOF ::sysinit:/etc/init.d/rcS ::respawn:-/bin/sh ::ctrlaltdel:/sbin/reboot ::shutdown:/bin/umount -a -r ::restart:/sbin/init EOF mv -v inittab "$ROOTFS/etc/" # Copy this system's keymap: loadkeys -b /usr/share/kbd/keymaps/i386/qwerty/no-latin1.map.gz > "$ROOTFS/etc/no-latin1.bmap" # Make everything root user: sudo chown -v -R root:root "$ROOTFS" # SetUID on busybox binary: sudo chmod +s "$ROOTFS/bin/busybox" # Make rcS executable: sudo chmod +x "$ROOTFS/etc/init.d/rcS" # Make Compressed ROM archive: mkfs.cramfs rootfs rootfs.cramfs
LOADLIN is typically used like this, after renaming the files to DOS format:
loadlin.exe bzimage initrd=rootfs
QEMU also works, in graphical mode:
qemu-system-i386 -kernel bzImage -initrd rootfs.cramfs
Or QEMU using the serial console directly to the terminal:
qemu-system-i386 -kernel bzImage -initrd rootfs.cramfs -append "earlycon=uart8250,io,0x3f8,115200n8 console=ttyS0" -serial mon:stdio -nographic
Here is also a demo video.