Ever heard about the bifferboard? It is a small RDC x86 SoC with 150MHz 486 compatible CPU, 8MB flash and 32MB RAM, ethernet and TTL serial line and a few GPIOs. It comes with very tiny loader called biffboot. Quite natural target for coreboot and u-boot. My flatmate purchased one but never had actually time to do anything with that so here it comes.
As on any other system, best would be to get some datasheets describing in great details everything about the system. Luckily Prochip, Russian company offers on FTP quite complete SDK even with the GPL redboot sources together with JTAG tools datasheets. The board has 64Mbit flash soldered, and of course producing a little brick is always an option.
Internally the system has PCI bus with USB, Network and NB and SB. Checking the redboot sources it turns out that system initialization is actually quite simple. Setup few registers for memory enable timer1 for system SDRAM refresh, enable flash decoding (chipselect). On SB front, just assign IRQs to PCI routers and USB and network and possibly enable the ROMCS write decoding. Yeah and just set level/edge in ELCR 😉 and write BIOS IRQs into the PCI registers. Plus assign few PCI BARs for EHCI/OHCI and network and set serial to internal decode and you are done. No need to worry about the CMOS because there is none.
I have taken the emulation/qemu-x86 as the base, because I really did not need any fancy structures, all initialization is just couple of PCI writes. It is still unknown if CPU can do CAR setup and this target uses romcc. First thingie to do was implementing a bootblock.c which enables whole decode of flash rom. Second step was to fill all init into the romstage.c. Third step was to fill the PCI BIOS IRQs in ramstage as well as filling the system resources like maximum RAM size and PCI MMIO and IO regions.
Ready to flash and boot. Flash but how? The biffboot enables flashing everything except the last 64KB of itself and flashrom has no support for this system (yet). Also I did not want to have a pernament little brick and the bifferboard has a JTAG connector and schematics for the JTAG, which is just buffered Xilinx parallel cable. You can even buy a debrick set (hw + sw) on the bifferboard page for 20 quids, but it would mean to purchase it separately and nearly with the price of whole system.
I did a soldering and produced a JTAG adapter which agreed with schematics and was on purely software side again. The RDC Loader is a Windows application which can be used to flash stuff using the JTAG. My flash was not listed, but there were some similar which gave me hope that could flash it. Now what? I examined the RDC DLL and found out that in Windows 98 version it was doing straight port 0x378 IO. Great time to write a short iopl(3) / ioperm wrapper and run the wine emulator on second coreboot board with parallel port.
With everything ready there was a time similar to big bang, the first try of everything. First connect JTAG and double check all wires, then check again, because if magic smoke escapes out of the chips (which was added there during manufacture process apparently) the magic would be broken and would leave me very sad. Now power on, magic stays inside chips.
Now run the wine wrapper with the application. It does not complain about unconnected JTAG… scan the PCI bus… oh it works! A flashing time! It takes long to move a progress bar but still something is happening. Ah it worked too! Now do reset and run… Yes coreboot is here, and it seems to die quite at the end where all tables are being generated.
It prints just couple of strange letters as last message. I knew what it was. Of course it was just GDB protocol. I seem to get some exception and we still have GDB enabled as default. I really need to push a change to turn it off to receive human readable exception at first. Now re-flash with gdb disabled and check again. Exception 6, unknown opcode 0f a2.
Examing the fail address with objdump we see the culprit immediately. It is the cpuid in the SMBios tables generator (CPU table). Yeah I believe not many 486 had CPUID, lets disable quickly the SmBios tables and re-flash. Boots gets a bit further and it seems to die inside the SeaBIOS.
Now what? I checked the resources and realized that I forgot to add flash resource thus making PCI devices memory BARs overlap flash memory. Same happened for IO ports which overlaped legacy resources, but it still hung. Luckily the JTAG is also an integrated debugger. There was still couple of places in SeaBIOS with CPUID stuff, and one particular hidden in the header which took me some time to find. But it still does not work.
Failing instruction 0f 31 RDTSC. Now it gets interesting. SeaBIOS seems to calibarate the TSC using timer2 and uses TSC for the timekeeping. Rest of the evening is spent to rewrite this using just low accuracy timer1. Late in the night I got “No bootable devices found” which sounds as the best error message I could get! (Yeah Sven likes that too).
Next evening it is a boot Linux time. I want to boot from USB stick (which is not possible from biffboot) using syslinux to boot some custom compiled kernel. SeaBIOS loads syslinux, it loads kernel and… nothing.
JTAG is quite handy… HLT quite early not even running in 0xC0000000 range. I forgot to mention that I tried to load bzImage, most likely it fails in that pre-boot stage. I study the kernel sources and realize even if I enabled early printk’s they go to INT 10H which means I cannot see them.
I quickly hack the function to send it to serial and got this back:
Unable to boot – please use a kernel appropriate to your CPU.
Hm even if cross compiled with ARCH=i386 the menuconfig default was i586. Fix it. Boot again. Linux complains about missing FPU. Oh really a CPU from the past. Turn on FPU emulation in kernel boot again. And nothing again. JTAG came handy again and it fails with invalid opcode again. This time a CMOV instruction. It seems a misc.c file misses -march=i386 and gcc is using CMOV there. After fixing this I got kernel to boot ending with kernel panic.
Something wrong with interrupts. Linux complains that it is unable to route IRQ for OHCI/EHCI and I intended to use USB as rootfs. After short research I realize coreboot writes 0 to PCI 0x3c (BIOS IRQ reg) and I really need to call assign_pci_irq in the ramstage.
After fixing this system finally boots. Sunday trip to visit the parents is partly a flashrom time too, making myself present in living room and not watching TV and hacking flashrom instead (during evening hours again). Afternoon spent fixing sisters car central lock system and fixing unrelated parents radio remote controller. Yeah hacking time all around the clock. Back to flashrom again.
Rule #1 make sure your datasheet matches your chip. I googled the datasheet and found some different one and I even check if the chip’s name under a sticker on board matches. After some time in desperate move I google for full chip name again with last “B” included.
It turns out that the B/T variant of EN29LV640 is something completely different. The chip has a standard JEDEC command set but requires word access (16 bit) for that. The 8bit mode with BYTE# signal grounded is used on bifferboard. The chip probing worked with 8 bit mode and erase too. I even managed to erase the chip. But unable to program anything. The JEDEC toggle bit toggle for eternity and examining the dumps I managed to write first nibble of the byte programmed and also second byte is zero… It sounds fishy but I tried many different things but still no chip programming. Late in the evening I found some kernel module which has biffboot config space writes and they use the 8bit sequence, BUT the programming is in WORD mode, programming two bytes at one.
Fixing flashrom. Verified. Fixing flashrom again, because this “B” variant has non-uniform sectors at the start of the flash.
Now what? Xvilka is working on Vortex86 which is much faster x86 SoC from DMP, but it seems that it has very similar NB and SB. Most likely merging a code is a option here. As for the SeaBIOS programming TSC emulation using timer2 could produce better timming functions even without TSC (task for near future maybe).
As the ultimate goal, maybe reviving the coreboot + u-boot from last April would be nice option here.