The History of ARM Linux
I reserve the right to make mistakes in here - this is from memory!

Initial port

ARM Linux started out in the Summer of 1994 as a one-man port of a 1.0.x kernel to the Acorn A5000. The aim was to get a Unix OS running on the A5000, and not to any thoughts of integrating the result back into Linus' kernel tree. In those days, the kernel was not portable in any respect (indeed, the port was started before the kernel even knew about the SPARC, MIPS, Alpha or M68K architectures).

Unpacking The Source

Initially, the kernel sources were unpacked onto an ADFS hard drive, converting the filenames and directories from foo.c to c.foo. When there were too many files (such as the kernel includes) in a single directory (ADFS has a limit of 77 files per directory), the directory was split into two separate directories (eg, include1 and include2). The original makefiles initially were kept, but they used GNU make extensions which were incompatible with the Acorn make utility (amu).

Norcroft C (with very long command line) was used to compile this kernel. Eventually, an alias was set up for compiling Linux-related programs, called 'gcc'! There wasn't GCC for ARM back then, and certainly not a set of binutils for ARM, so cross-compilation was out of the question. After attempting to compile a couple of kernel files, it was clear that there was something missing - autoconf.h. Also, the inline functions in the header files were discovered...

Kernel Configuration

The kernel configuration was a nightmare - no configure script to automatically generate the required configuration. A very basic kernel configuration was installed by editing the original GNU Makefiles (and removing the GNU extensions) and editing header files (yuck!)

This basic configuration did not include any networking (in fact, it didn't even require the drivers/net/ or the net/ trees), SCSI or block drivers.

Kernel compilation

Each section of the kernel was compiled up separately - fs, kernel, ipc. As the inline functions in the header files were discovered, they were removed and put into a separate directory called `inclib'. The Linux memory management system (mm) had to be re-written since the memory management hardware does its mappings `the wrong way round' - it is told where to map a physical page into the logical address space, not where to map a logical page to a physical page. Very little time was spent initially on the MM system, especially as there were drivers to sort out as well.

Drivers were less of a problem - although the A5000 has PC-like floppy, IDE, serial and parallel port hardware, it does not have a VGA adapter as such - there isn't character generator hardware but instead a frame buffer. There isn't a keyboard controller, but a serial port to talk to the keyboard. A new set of very basic console and keyboard support code was written, and the original PC Linux code discarded.

Any assembler such as the kernel entry points had to be interpreted and re-written.

Linking

Once all the modules had been compiled, an attempt was made to link the kernel. This attempt was expected to fail, and indeed it did. It provided a list of undefined symbols, which then indicate the areas of the kernel that needed more work.

After a month of hacking, Linux finally booted and was asking for a root disk. A root disk requires a block device, but the kernel didn't contain any. The Linux floppy driver was singled out for some work, and after tripping over a hardware mismatch between the PC and Acorn hardware, the kernel could control the floppy drive. The kernel still wasn't useful without the root disk!

Root disks...

How to create a root disk: you need a kernel (yep, got that), and a system (erm, no, that requires a root disk), ahhh. That sounds like a catch-22 situation, but not all that bad since it has a difference, or rather a way out. Linux already runs on one platform, so find a friendly PC user with Linux installed (Thanks Jez) to create a root disk for you but without any programs on. The disk just contained the /dev special device entries, since the ARM cannot run PC code.

After several nights disturbing the other residents of my digs due to the floppy drives chug-chug-chug noise), I managed to get the kernel to mount its first root filesystem.

The kernel now boots and mounts its root filesystem. But it's still useless! It hasn't got anything to run! It needs at least a shell. Ok, so what does sunsite have to offer? Smash (small shell) written as a university project by X#*!X#*!X#*!X! It's not a feature packed shell, but it's a start. It does, however, require a C library.

This idea was shelved for a while and an alternative approach taken - why not put the shell into the kernel? That way, you don't need a C library! So a very basic small shell was created that the kernel could run if it didn't find an init daemon or a shell on the filesystem to run. It had very simple commands - cp, rm, mkdir, rmdir, mount, umount, and it wouldn't even allow you to run a command from the filesystem.

The first binaries

A C library was needed, and a very small and basic C library was created using the Acorn DDE. The whole of this static C library was written from scratch, attempting to support everything that smash required - stdio, string and a few Unix specifics thrown in for good measure.

Once smash was working, the command set was improved - using the GNU fileutils and textutils packages (which were also compiled using Norcroft) caused the C library to grow. Later, some of the util-linux package was added.

By this time, the root disk was looking slightly respectable, but the system still wasn't useful - all it was capable of was copying and manipulating files. There wasn't even an editor for it!

More binaries were added over time, but progress was slow. It was time to get a proper C library together, with GCC and binutils.

Linux C Library, Compilers and Binutils

At the start of 1995, GCC 2.6.1 supported the ARM processors, but binutils (gas 940921 from Richard Earnshaw) was lacking. Binutils didn't have any architecture-independent support for Linux either. Since GCC had a hope of working, it was cross-compiled on a Solbourne at Southampton University. cc1 was tested with some trivial code and the result was ARM code. This was the first package done.

Binutils didn't have particularly brilliant support for ARM - it didn't link the bl instruction properly. However, after several attempts at fixing this (I hadn't even looked into the GNU binutils package before), these problems were fixed. It did unfortunately take a significant amount of time to sort out a reasonable set of tools.

Once the obvious problems had been cured, it was time to try cross-compiling a very simple program - a couple of trivial assembler files that called the Linux system calls and checking that they ran.

Later kernels

This part isn't written yet, but here are a couple of archives of the source code to the original Linux bootloader and kernel, both of which were compiled native in the RISC OS environment. To unarchive these, either use !ArcFS, !SparkPlug, !Spark, (all RISC OS utilities) or get a copy of the GPL NSpark by Andy Duplain and others

Linux Kernel source V1.1.59+ (RISC OS Spark file archive)
Boot Loader for V1.1.59+ (RISC OS Spark file archive)

more later...