Recent Linux on Intel IXP4xx Systems
Latest test on 2023-05-30 (kernel v6.1.29 with OpenWrt rootfs)

Avila

Cambria IXP43x reference design

The IXP4xx is a series of XScale ARM chips from Intel that was created as part of their legacy when acquireing Digitals StrongARM line. This SoC has an ARMv5TE Big Endian ISA. It can sometimes be hard to find the right tools. The typical userspace is built using OpenWrt or OpenEmbedded.

As of kernel v6.1 we finalized modernization of the IXP4xx port in the Linux kernel to use device tree and modern drivers for the entire set of systems supported by the Linux kernel boardfiles, and the boardfiles were consequently deleted.

A major reason why IXP4xx silicon is still produced and deployed is the operating conditions. If you look at for example the Gateworks Cambria GW2358-4 network processor (apparently still for sale for new designs in 2017) you notice the strictly military operating conditions:

It is pretty easy for an experienced ARM kernel hacker to get any of these devices running with the latest kernel and full hardware support. Most of the heavy lifting is already done and landed upstream.

The UARTs on the IXP4xx uses 115200 baud.

Getting OpenWRT up on it

At one point IXP4xx support was been deleted from OpenWrt, but we brought it back on 2023-10-25. It is now once again part of the OpenWrt code repository.

It is pretty straight forward to build and develop on the latest OpenWrt for IXP4xx:

Booting the mainline kernel with OpenWrt

It can be really handy to be able to boot the mainline (upstream) Linux kernel for developing proper patches and submitting, so naturally I have a way to do this. It's not as trivial as using or flashing OpenWrt and requires UART access and TFTP boot of the kernel, but if you are convenient with this, here is how to do it:

You need a proper toolchain in your $PATH, I just generally use the one that is generated from OpenWrt (available in the main menuconfig). Here is for example this big-endian ARMv4 GCC 12.3.0 toolchain for XScale that was created using OpenWrt.

Just like OpenWrt I compulsively use Makefile scripting to build my images. Using this works like so:

USRobotics USR8200

As the USRobotics router has users, I have tried to create a device tree and a test image for it.

Files:

Links:

Boot the zImage like this:

  ip_address -l 192.168.1.35 -h 192.168.1.2
  load -r -v -b 0x00080000 -h 192.168.1.2 zImage-usr8200
  exec 0x00080000

Gateworks Avila GW2348-4

Break into Redboot by hammering CTRL+C as soon as you plug in the power and see a + appear in the console.

The flash needs one big consecutive space to use for the combined Linux kernel and rootfs. I have repartitioned my flash because the "linux" partition could not fit my kernel.

I did it like this:

  RedBoot> fis list
  Name              FLASH addr  Mem addr    Length      Entry point
  RedBoot           0x50000000  0x50000000  0x00080000  0x00000000
  zimage            0x50080000  0x01600000  0x00160000  0x01600000
  ramdisk           0x501E0000  0x00800000  0x002C0000  0x00800000
  FIS directory     0x50FE0000  0x50FE0000  0x0001F000  0x00000000
  RedBoot config    0x50FFF000  0x50FFF000  0x00001000  0x00000000
  RedBoot> fis unlock zimage
  ... Unlock from 0x50080000-0x501e0000: ...........
  RedBoot> fis delete zimage
  Delete image 'zimage' - continue (y/n)? y
  ... Erase from 0x50080000-0x501e0000: ...........
  ... Unlock from 0x50fe0000-0x51000000: .
  ... Erase from 0x50fe0000-0x51000000: .
  ... Program from 0x03fd0000-0x03ff0000 at 0x50fe0000: .
  ... Lock from 0x50fe0000-0x51000000: .
  RedBoot> fis unlock ramdisk
  ... Unlock from 0x501e0000-0x504a0000: ......................
  RedBoot> fis delete ramdisk
  Delete image 'ramdisk' - continue (y/n)? y
  ... Erase from 0x501e0000-0x504a0000: ......................
  ... Unlock from 0x50fe0000-0x51000000: .
  ... Erase from 0x50fe0000-0x51000000: .
  ... Program from 0x03fd0000-0x03ff0000 at 0x50fe0000: .
  ... Lock from 0x50fe0000-0x51000000: .
  RedBoot> fis create -b 0x00080000 -l 0x00400000 -s 0x00400000 -f 0x50080000 -e 0x00080000 -r 0x00080000 -n linux
  ... Unlock from 0x50fe0000-0x51000000: .
  ... Erase from 0x50fe0000-0x51000000: .
  ... Program from 0x03fd0000-0x03ff0000 at 0x50fe0000: .
  ... Lock from 0x50fe0000-0x51000000: .
  RedBoot> fis create -b 0x00080000 -l 0xb60000 -s 0x00400000 -f 0x50480000 -e 0x00031000 -r 0x00080000 -n rootfs
  ... Unlock from 0x50fe0000-0x51000000: .
  ... Erase from 0x50fe0000-0x51000000: .
  ... Program from 0x03fd0000-0x03ff0000 at 0x50fe0000: .
  ... Lock from 0x50fe0000-0x51000000: .
  RedBoot> fis list
  Name              FLASH addr  Mem addr    Length      Entry point
  RedBoot           0x50000000  0x50000000  0x00080000  0x00000000
  linux             0x50080000  0x00080000  0x00400000  0x00080000
  rootfs            0x50480000  0x00080000  0x00B60000  0x00031000
  FIS directory     0x50FE0000  0x50FE0000  0x0001F000  0x00000000
  RedBoot config    0x50FFF000  0x50FFF000  0x00001000  0x00000000

Here I also had to set up the boot script:

  RedBoot> fconfig
  Run script at boot: true
  Boot script:
  .. fis load ramdisk
  .. fis load zimage
  .. exec
  Enter script, terminate with empty line
  >> fis load linux
  >> exec
  >>
  (...)

Just select the default for the rest of the script options.

Next download a kernel to the device and flash it into the "linux" slot, and a rootfs and flash it into the "rootfs" slot:

  RedBoot> ip_address -l 192.168.1.35 -h 192.168.1.2
  RedBoot> load -r -v -b 0x00080000 -h 192.168.1.2 openwrt-ixp4xx-avila-squashfs-kernel.bin
  RedBoot> fis unlock linux
  RedBoot> fis write -f 0x50080000 -b 0x00080000 -l 0x0033791e
  RedBoot> fis lock linux
  RedBoot> load -r -v -b 0x00080000 -h 192.168.1.2 openwrt-ixp4xx-avila-squashfs-rootfs.bin
  RedBoot> fis unlock rootfs
  RedBoot> fis write -f 0x50480000 -b 0x00080000 -l 0x340000
  RedBoot> fis lock rootfs
  RedBoot> reset
After reboot my new OpenWrt kernel and rootfs pops right up!

Gateworks Cambria GW2358-4

Break into Redboot by hammering CTRL+C as soon as you plug in the power and see a + appear in the console.

The flash needs one big consecutive space to use for the combined Linux kernel and rootfs. I have repartitioned my flash because the "linux" partition could not fit my kernel.

I did it like this:

  RedBoot> fis list
  Name              FLASH addr  Mem addr    Length      Entry point
  RedBoot           0x50000000  0x50000000  0x00080000  0x00000000
  linux             0x50080000  0x00031000  0x00100000  0x00031000
  rootfs            0x50180000  0x00031000  0x00180000  0x00031000
  RedBoot> fis unlock linux
  ... Unlock from 0x50080000-0x50180000: ........
  RedBoot> fis delete linux
  Delete image 'linux' - continue (y/n)? y
  ... Erase from 0x50080000-0x50180000: ........
  ... Unlock from 0x51fe0000-0x52000000: .
  ... Erase from 0x51fe0000-0x52000000: .
  ... Program from 0x07fd0000-0x07ff0000 at 0x51fe0000: .
  ... Lock from 0x51fe0000-0x52000000: .
  RedBoot> fis unlock rootfs
  ... Unlock from 0x50180000-0x50300000: ............
  RedBoot> fis delete rootfs
  Delete image 'rootfs' - continue (y/n)? y
  ... Erase from 0x50180000-0x50300000: ............
  ... Unlock from 0x51fe0000-0x52000000: .
  ... Erase from 0x51fe0000-0x52000000: .
  ... Program from 0x07fd0000-0x07ff0000 at 0x51fe0000: .
  ... Lock from 0x51fe0000-0x52000000: .
  RedBoot> fis create -b 0x00080000 -l 0x00400000 -s 0x00400000 -f 0x50080000 -e 0x00080000 -r 0x00080000 -n linux
  ... Unlock from 0x51fe0000-0x52000000: .
  ... Erase from 0x51fe0000-0x52000000: .
  ... Program from 0x07fd0000-0x07ff0000 at 0x51fe0000: .
  ... Lock from 0x51fe0000-0x52000000: .
  RedBoot> fis create -b 0x00080000 -l 0x01b60000 -s 0x00400000 -f 0x50480000 -e 0x00031000 -r 0x00080000 -n rootfs
  ... Unlock from 0x51fe0000-0x52000000: .
  ... Erase from 0x51fe0000-0x52000000: .
  ... Program from 0x07fd0000-0x07ff0000 at 0x51fe0000: .
  ... Lock from 0x51fe0000-0x52000000: .

Next download a kernel to the device and flash it into the "linux" slot, and a rootfs and flash it into the "rootfs" slot:

  RedBoot> ip_address -l 192.168.1.35 -h 192.168.1.2
  RedBoot> load -r -v -b 0x00080000 -h 192.168.1.2 openwrt-ixp4xx-cambria-squashfs-kernel.bin
  Raw file loaded 0x00080000-0x0033ac8a, assumed entry at 0x00080000
  RedBoot> fis unlock linux
  RedBoot> fis write -f 0x50080000 -b 0x00080000 -l 0x0033ac8a
  RedBoot> fis lock linux
  RedBoot> load -r -v -b 0x00080000 -h 192.168.1.2 openwrt-ixp4xx-cambria-squashfs-rootfs.bin
  RedBoot> fis unlock rootfs
  RedBoot> fis write -f 0x50480000 -b 0x00080000 -l 0x002a0000
  RedBoot> fis lock rootfs
  RedBoot> reset

Notice how the lengths of the images are adjusted to the downloaded files. I'm sorry that I don't know any better way to flash the kernel and rootfs on these devices.

After reboot my new OpenWrt kernel and rootfs pops right up!

NSLU2

NSLU2

LUCI on the NSLU2 running an OpenWrt snapshot

The Linksys NSLU2 also known as "the slug" is a NAS box which has ethernet and two USB 2.0 plugs to run USB disk enclosures for storage. The simplicity of this platform created a huge hobbyist hacking community in the mid-2000s.

NSLU2 is one of the device that will be resurrected into OpenWrt. I have pre-release images here that makes it possible to use kernel v6.1 from 2023-06-09, with a snapshot of OpenWrt along with LuCI and KSMBD on the NSLU2 booting from an external hard drive or USB stick:

  • IXP4xx rootfs - format a hard drive or USB stick with one partition (/dev/sda1) and format that partition with ext4. Then extract this rootfs into that partion. Plug the device into the USB 2.0 port of the NSLU2 (the port closest to the power plug). This rootfs has been processed to not start odhcpd, dnsmasq or firewall.
  • openwrt-ixp4xx-nslu2-squashfs-factory.bin a firmware to be flashed into the flash using the upslug2 tool like this:
    • Hold down reset key and turn device on, wait until the LED turns red, release reset key and the LED starts blinking red. If the LED starts blinking yellow instead, try to just boot the device normally (to userspace) once and then retry.
    • On your host on the same network:
      upslug2 -d enp7s0 -i openwrt-ixp4xx-nslu2-squashfs-factory.bin

This version of OpenWrt will just grab a IP number from DHCP so you can check your router to see which IP it got.

You can create a local share on the hard drive by getting onto the NSLU2 with ssh root@192.168.1.n and do something like:

    mkdir ksmbd
    chown nobody ksmbd
    chgrp nogroup ksmbd
  
Then set up the share using the LuCI Web UI or by logging in to the router and editing /etc/config/ksmbd

I booted this early on from device tree on 2021-11-30 for a test, this is the dmesg!

Vulcan

A zImage for the Vulcan an IXP425-based single-board computer.

IXP4xx Kernel TODO

  • Switch to using device tree only (fixed for kernel v5.18)
  • Define some static clocks in the device tree
  • Get rid of the no-clock framework hacks in drivers/usb/gadget/udc/pxa25x_udc.c

OpenWRT TODO

  • Resurrect IXP4xx support using kernel v6.1

Links