Resolving Booting Problems on your TS-7800

Sometimes you can find yourself pulling out your hair when trying to get your board to boot. Here is a list of the ones I have stumbled into, how you can identify them and how you fix them.

unrecognized/unsupported machine ID

Technologic Systems unfortunately fell into the same trap that all ARM board manufacturers insist on doing, they completely messed up on registering an ARM Linux offical machine ID. This means then when Linux boots, it thinks it is booting on a hardware platform it knows nothing about, and so aborts.

To fix this, once you have compiled your kernel, you use the tool devio (you will need to compile from source if you are not a Debian-esque user) and have a script that is similar to:

alex@berk:~$ cat /usr/src/ts7800/prep-kernel
#!/bin/sh
(
  devio 'wl 0xe3a01c06,4' 'wl 0xe3811074,4'
  cat /usr/src/ts7800/ts78xx.git/arch/arm/boot/zImage
) > /usr/src/ts7800/zImage.fixup
exit 0

After running the above script, you will find a new file ('/usr/src/ts7800/zImage.fixup') that you should use instead to run on your TS-7800. For those curious what it does, it loads into the ARM register r1 the expected machine ID for the TS-7800 (0x0674 aka 1652), plastering over the incorrect value the TS-BOOTROM places into there just prior to running the Linux kernel.

Alternatively, this can be changed for good in the MBR. A quick look in the MBRs provided by Technologic Systems shows a value of 0x020E at offset 0x00D0, and this is the value displayed by a kernel with full debugging when it refuses to boot. By using a hex editor and changing that value to 0x0674 the kernel binaries no longer hacking for forced loading of the machine ID but it is still functional with such a kernel. So far this solution has not been checked with any of the kernels provided by Technologic Systems and for those the original MBRs might still be the best choice.

Linux Uncompressing Works, then Nothing

This could be a number of things:

Large Kernel and/or initrd Does Not Work

Techologic Systems borked up the Master Boot Record for both the NAND and the SD card. They mis-entered the partition table information so that for the NAND the maximum kernel size is 3MB (0x1800*512) and the initrd is 1.5MB (0x0c00*512) whilst for the SD card the limits are 4MB kernel (0x2000*512) and 3MB (0x1800*512) initrd); when either of these blobs are too large then the code simply truncates the kernel/initrd; part of the fun is that an image setup on the SD works but when burnt to the NAND it does not.

There is no real reason why you cannot have a 4MB kernel and 4MB initrd (there is probably no real reason why you cannot go for a single 20MB kernel and initramfs combo) so Catalin and I, well actually Catalin was the brains on this one, over Jabber one evening pulled apart the SD and NAND MBR using the information on the CHDK wiki in regards to disassembling code with GNU tools. In short the magical command we were looking for was

$ objdump -m arm --disassembler-options=force-thumb -b binary -D flash-mbr.dd

This would spit out the disassembled code to stdout. Now what can be done is simply to disassemble the SD ('sd-mbr.dd') and NAND ('flash-mbr.dd') MBR's and then diff them, here 'diff -y' was the most useful mode, the interesting bit starts at 0x01be for 64 bytes where the partition table starts, all the actual code leading up to it is effectively identical.

N.B. because the code is written using ARM Thumb, everything is in 16bit blocks and not 32bit blocks so pay careful attention to reading the output of the disassembler. Read the partition table in 32bit chunks in your head (aka two lines at a time) and it is in 16bit atomic little-endian format

It really is now just a case of using a hexeditor to amend the flash-mbr.dd binary to have the correct partition sizes. To by hand decode what the MBR states it's good to refer to the Wikipedia MBR decoding table.

| | NAND MBR | | SD MBR | |
| | ------------ | | ---------- | -
| | start (0x1c6 + N*0x010) | length (0x1ca + N*0x010) | start | length | | part1 | 0x01000000 | 0x18000000 | 0x01000000 | 0x20000000 | | part2 | 0x21000000 | 0x0c000000 | 0x21000000 | 0x18000000 |

Where 'N' can be 0 though to 3 inclusive, for partitions one to four respectively. Because of the 16bit endian fun, when stored 0xaabbccdd, it's actual value to us is 0xccddaabb which is why the start/length values look weird.

So to fix the MBR, you should put in both the 'sd-mbr.dd' file and 'flash-mbr.dd' file at the offets 0x1ca and 0x1da the value 0x20000000. If you want to be really clever, you could rewrite the whole partition table, and for example join the first two partitions so that you can dump initrd and just go with a single 8MB kernel+initramfs. If you do this for the NAND though remember to pass to the kernel the 'mtdparts=...' parameter as described at the top of drivers/mtd/cmdlinepart.c.

If using a partition table editor, with a MBR provided by Technologic Systems, the first two partitions will be of type 0xDA. A series of tests showed clearly that the MBR loads the partitions of this type, in the order they are placed in the partition table. The first one found will be also executed, so the kernel must be placed in it, and the remaining ones are simply loaded into memory before the kernel is started. By having just one partition of type 0xDA, a kernel without initrd can be safely used, but the command line must be properly tweaked to insure the correct root partition is used and the proper init script is executed.

A safer alternative to a hex editor, especially when needing to change the partition table for the NAND, is to temporarily write it to an empty SD card and use a partition table editor to do all the required changes. Than it can be copied back from the SD card to the NAND.

For reasons of interest, you might find it interesting and useful that TS posted the source code to the MBR on the TS7000 mailing list.

Eugh, Do You Have to Make It So Complicated?

Yes...

$ wget ftp://ftp.embeddedarm.com/ts-arm-sbc/ts-7800-linux/binaries/ts-images/sd-mbr.dd
$ dd if=/dev/zero of=wibble bs=1M count=`<size>`
$ dd if=sd-mbr.dd of=wibble bs=512 conv=notrunc
# losetup -f wibble
# fdisk /dev/loop0    <----- or if you prefer the more friendly cfdisk (N.B. first partition must start at offset 128kB)
# losetup -d /dev/loop0
$ dd if=wibble of=sd-mbr.new.dd bs=512 count=1

Or alternatively edit the SD card directly, the above is more useful for the NAND.