Building U-boot 2014 on FreeBSD

I'm upgrading the U-boot version used for Wandboard by Crochet-BSD.    The first step is to upgrade the Device Tree Compiler (DTC); there are instructions here.

Once you have the U-boot 2014 source, the build is trivial:

gmake SED=gsed HOSTCC=cc CROSS_COMPILE=armv6-freebsd- wandboard_quad_config
gmake SED=gsed HOSTCC=cc CROSS_COMPILE=armv6-freebsd-

 

Building u-boot for Chromebook

I got interested in building Crochet images for Chromebook.  The first step, naturally is to build U-boot for Chromebook.

In order to build U-boot, you'll need to have already installed

  • gmake
  • gcc

You can get these from the ports tree.  You'll also need xdev, the FreeBSD cross-compiler toolkit.

I started with the latest U-boot 2014 source, which I got here.  The latest U-boot requires DTC 1.4.  I'm on FreeBSD 10, which has a much older DTC.

To build the latest DTC:

git clone git://git.kernel.org/pub/scm/utils/dtc/dtc.git
cd dtc
gmake CC=gcc
cp dtc /usr/bin

Once we have DTC 1.4, we can build U-boot.

wget ftp://ftp.denx.de/pub/u-boot/u-boot-2014.07.tar.bz2
tar zxvf u-boot-2014.07.tar.bz2
cd u-boot-2014.07
gmake SED=gsed HOSTCC=cc CROSS_COMPILE=armv6-freebsd- snow_config
gmake SED=gsed HOSTCC=cc CROSS_COMPILE=armv6-freebsd-

The U-boot binary image is "u-boot.bin". To burn the U-boot binary to a SD card:

sudo dd if=u-boot.bin of=/dev/rdisk1

The next challenge is the file system. The file system on the Chromebook looks like this:

       start        size    part  contents
           0           1          PMBR (Boot GUID: E780FED6-7991-B94B-B622-FA7541BE9FBB)
           1           1          Pri GPT header
           2          32          Pri GPT table
     8671232    21295104       1  Label: "STATE"
                                  Type: Linux data
                                  UUID: D5488177-EB19-3243-8D7C-D6E4F01DB5B3
       20480       32768       2  Label: "KERN-A"
                                  Type: ChromeOS kernel
                                  UUID: 47715F23-7DD6-5545-93DC-3807D1CD4AFD
                                  Attr: priority=0 tries=0 successful=0
     4476928     4194304       3  Label: "ROOT-A"
                                  Type: ChromeOS rootfs
                                  UUID: BE1064FF-EC28-E64B-B3A1-A5C176D57C0F
       53248       32768       4  Label: "KERN-B"
                                  Type: ChromeOS kernel
                                  UUID: 5D200D96-1F52-804C-83A7-AD8081E8ACD4
                                  Attr: priority=1 tries=0 successful=1
      282624     4194304       5  Label: "ROOT-B"
                                  Type: ChromeOS rootfs
                                  UUID: D0795A2A-1D0D-4140-9F57-F87AEF399C44
       16448           1       6  Label: "KERN-C"
                                  Type: ChromeOS kernel
                                  UUID: E8A703B8-E0A5-964D-9508-D88DE336D003
                                  Attr: priority=0 tries=15 successful=0
       16449           1       7  Label: "ROOT-C"
                                  Type: ChromeOS rootfs
                                  UUID: 7A947ABA-E723-8440-9A07-0EC394C85195
       86016       32768       8  Label: "OEM"
                                  Type: Linux data
                                  UUID: 173B3C97-CDCF-F849-99E7-7614C6C0F9FD
       16450           1       9  Label: "reserved"
                                  Type: ChromeOS reserved
                                  UUID: CD83D43A-4FC8-4849-B0DD-368E9C3819BA
       16451           1      10  Label: "reserved"
                                  Type: ChromeOS reserved
                                  UUID: 344D3149-A5C2-B44B-A65C-2DFD59758FC5
          64       16384      11  Label: "RWFW"
                                  Type: ChromeOS firmware
                                  UUID: D9B79232-94AD-A143-9C49-F947BFA2491E
      249856       32768      12  Label: "EFI-SYSTEM"
                                  Type: EFI System Partition
                                  UUID: E780FED6-7991-B94B-B622-FA7541BE9FBB
    30777311          32          Sec GPT table
    30777343           1          Sec GPT header

There is a good description of the Chromium OS file system here.  The size parameter is in sectors, which are usually 512 bytes each.  So, for example the state partition is 10GB in size.  KERN-A is 16MB in size, and ROOT-A is 2GB.

The partition ids for ChromeOS kernel and rootfs, are "fe3a2a5d-4f32-41a7-b725-accc3285a309" and "3cb8e202-3b7e-47dd-8a3c-7ff2a13cfcec" respectively.  The partition ids for ChromeOS are documented here.

 

Cross-compiling NetBSD on FreeBSD-10

I was curious to see how difficult it would be to compile NetBSD on FreeBSD 10.  Once you have the source, there is a build.sh script which is very helpful.  The build is as simple as:

./build.sh -m i386 tools
./build.sh -m i386 kernel=GENERIC release

In my case I have both clang and gcc installed.  I believe the cross-compile tools were built with clang.  The resulting gcc cross-compiler "i486--netbsdelf-gcc" was used to build the NetBSD source.

The generated binaries appear in obj/releasedir/i386/binary/

Enabling i2c on FreeBSD Wandboard

FreeBSD-11 has support for i2c on Wandboard.

The working boot image is here, and the boot log is here.

In order to enable it, there were three steps

  • Enable the kernel options
  • Update the files.imx6 file
  • Create the DTS mappings

The kerne config for Wandboard-Quad is here, however, most of the kernel options for Wandboard Quad are in the IMX6 config. The kernel options to enable are:

device fsliic # Freescale i2c/iic
device iic # iic protocol
device iicbus # iic bus

The files files.imx6 contains the mappings between the devices in the conf file, and the files to compile for that device.  In order to compile in the fsliic device for Freescale, I need to enable the mapping for it, so that /sys/arm/freescale/imx/i2c.c is compiled in.

arm/freescale/imx/i2c.c optional fsliic

Finally, I need to update the DTS files.  The file wandboard-quad.dts contains the device mappings for wandboard quad. However, similar to the kernel configuration, all the real mappings are in imx6.dtsi.  There are three i2c controllers on the wandboard quad, so I added these mappings:

i2c@021a0000 {

#address-cells = <1>;

#size-cells = <0>;

compatible = "fsl,imx-i2c";

reg = <0x021a0000 0x4000>;

interrupt-parent = <&gic>; interrupts = <68>;

};

i2c@021a4000 {

#address-cells = <1>;

#size-cells = <0>;

compatible = "fsl,imx-i2c";

reg = <0x021a4000 0x4000>;

interrupt-parent = <&gic>; interrupts = <69>;

};

i2c@021a8000 {

#address-cells = <1>;

#size-cells = <0>;

compatible = "fsl,imx-i2c";

reg = <0x021a8000 0x4000>;

interrupt-parent = <&gic>; interrupts = <70>;

};

The memory locations (0x21a000, 0x21a4000, 0x21a8000) as well as the interrupts (68,69,70) come from the IMX6 documentation.  This line

compatible = "fsl,imx-i2c";

is the line that the i2c.c driver uses in probe() to determine that this hardware is a compatible Freescale IMX i2c device.

Once the kernel is compiled and started it will detect the 3 iic devices.  The relevant lines from the boot log are:

iichb0: <I2C bus controller> mem 0x21a0000-0x21a3fff irq 68 on simplebus2
iicbus0: <OFW I2C bus> on iichb0
iic0: <I2C generic I/O> on iicbus0
iichb1: <I2C bus controller> mem 0x21a4000-0x21a7fff irq 69 on simplebus2
iicbus1: <OFW I2C bus> on iichb1
iic1: <I2C generic I/O> on iicbus1
iichb2: <I2C bus controller> mem 0x21a8000-0x21abfff irq 70 on simplebus2
iicbus2: <OFW I2C bus> on iichb2
iic2: <I2C generic I/O> on iicbus2

You should have 3 iic devices in the /dev/ directory

crw------- 1 root wheel 0x20 Jul 6 01:23 iic0
crw------- 1 root wheel 0x21 Jul 6 01:23 iic1
crw------- 1 root wheel 0x22 Jul 6 01:23 iic2

You can check which devices are specified in the dts file, using ofwdump.

root@wandboard:/dev # ofwdump -a
Node 0x38:
Node 0xa8: cpus
Node 0xd4: cpu@0
Node 0x190: aliases
Node 0x1bc: soc@00000000
Node 0x230: generic-interrupt-controller@00a00100
Node 0x2cc: mp_tmr0@00a00200
Node 0x348: l2-cache@00a02000
Node 0x3d0: aips@02000000
Node 0x458: ccm@020c4000
Node 0x4b4: anatop@020c8000
Node 0x520: timer@02098000
Node 0x594: gpio@0209c000
Node 0x668: gpio@020a0000
Node 0x71c: gpio@020a4000
Node 0x7f0: gpio@020a8000
Node 0x8a4: gpio@020ac000
Node 0x958: gpio@020b0000
Node 0xa0c: gpio@020b4000
Node 0xac0: serial@02020000
Node 0xb4c: serial@021e8000
Node 0xbdc: serial@021ec000
Node 0xc6c: serial@021f0000
Node 0xcfc: serial@021f4000
Node 0xd8c: usbphy@020c9000
Node 0xe2c: usbphy@020ca000
Node 0xed0: aips@02100000
Node 0xf58: ethernet@02188000
Node 0xfec: usb@02184000
Node 0x1088: usb@02184200
Node 0x1124: usb@02184400
Node 0x11b4: usb@02184600
Node 0x1244: usbmisc@02184800
Node 0x12c4: usdhc@02190000
Node 0x1368: usdhc@02194000
Node 0x1404: usdhc@02198000
Node 0x14a8: usdhc@0219c000
Node 0x1538: i2c@021a0000
Node 0x15d0: i2c@021a4000
Node 0x1668: i2c@021a8000
Node 0x1700: ocotp@021bc000
Node 0x1750: memory
Node 0x1774: chosen

You can also check that the iic modules are compiled into the kernel, using kldstat

root@wandboard:/usr/home/tom # kldstat -v | grep iic
131 i2c/iicbus
13 iichb/iicbus
12 iicbus/iic
55 iichb/ofw_iicbus
54 iicbb/ofw_iicbus

Once you have a device connected to the wandboard, you can use the i2c command to access the devices.

 

6502 Assembler

Back in the dark ages (the 1980's), people like myself coded on Apple][ computers.  If you were good you coded in Applesoft BASIC or Integer BASIC. If you were really geeky you coded in Assembly language on the 6502 processor.  The Apple][ OS was coded in assembly language, so if you really wanted to understand what was going on inside your computer, you needed to learn assembly language and you needed to learn about the 6502.

Obviously, the first thing you would do was write your own code to read and write disks.  It was a big deal in those days to be able to copy 5.25" floppies that had games on them.  For the serious geeks, it was much less interesting to play the games, and much more interesting to figure out how to copy them.  One technique game manufacturers used was to write data between the tracks, by moving the drive arm 1/2 tracks and 1/4 tracks.  Another technique was to modify the sector header bytes from the usual $D5 $AA $96 to something else.  This change disabled standard Apple DOS from finding the sectors, and therefore made them unreadable to anyone other than the manufacturer of the game.

In order to be able to inspect disks, read sectors, read between tracks and so on, I wrote a small program that would enable me to inspect disks easily.  I was young, so I simply called the program "M".  You can see the source here.  It's most likely that I used the LISA assembler, judging by the syntax of the source code.  "M" allowed me to put a disk in the floppy drive and then using keyboard commands navigate through the disk and look at the contents, at a byte level.

There are lots of other 6502 assembler programs around the internet, including a nice archive at 6502.org.  I had a lazy Saturday afternoon, so I decided to write an ANTLR4 grammar for LISA assembler.  You can see it here.  This grammar produces Java or C# (if you have the C# ANTLR Target) code which can parse LISA assembler.  It's the first step to writing a Java or C# assembler for 6502 assembly code.

ANTLR has a useful feature where it can parse input and produce LISP-like output showing the fully parsed program.  This feature is primary useful for debugging; it's an easy way to look at the AST in text format.  Here is the LISP-like output from running my ANTLR grammar on "M".  Of course, the parser and lexer that ANTLR produces in Java or C# does not output this LISP-like string, it produces an AST. A proper assembler would then walk that AST and output binary opcodes.

Here is an example of Bubble sort, coded in assembler.  This was cut-pasted from 6502.org.

;THIS SUBROUTINE ARRANGES THE 8-BIT ELEMENTS OF A LIST IN ASCENDING
;ORDER. THE STARTING ADDRESS OF THE LIST IS IN LOCATIONS $30 AND
;$31. THE LENGTH OF THE LIST IS IN THE FIRST BYTE OF THE LIST. LOCATION
;$32 IS USED TO HOLD AN EXCHANGE FLAG.

SORT8 LDY #$00 ;TURN EXCHANGE FLAG OFF (= 0)
STY $32
LDA ($30),Y ;FETCH ELEMENT COUNT
TAX ; AND PUT IT INTO X
INY ;POINT TO FIRST ELEMENT IN LIST
DEX ;DECREMENT ELEMENT COUNT
NXTEL LDA ($30),Y ;FETCH ELEMENT
INY
CMP ($30),Y ;IS IT LARGER THAN THE NEXT ELEMENT?
BCC CHKEND
BEQ CHKEND
;YES. EXCHANGE ELEMENTS IN MEMORY
PHA ; BY SAVING LOW BYTE ON STACK.
LDA ($30),Y ; THEN GET HIGH BYTE AND
DEY ; STORE IT AT LOW ADDRESS
STA ($30),Y
PLA ;PULL LOW BYTE FROM STACK
INY ; AND STORE IT AT HIGH ADDRESS
STA ($30),Y
LDA #$FF ;TURN EXCHANGE FLAG ON (= -1)
STA $32
CHKEND DEX ;END OF LIST?
BNE NXTEL ;NO. FETCH NEXT ELEMENT
BIT $32 ;YES. EXCHANGE FLAG STILL OFF?
BMI SORT8 ;NO. GO THROUGH LIST AGAIN
RTS ;YES. LIST IS NOW ORDERED

The LISP-ish output produced by parsing this with my grammar looks like:

(prog (line (comment ;THIS SUBROUTINE ARRANGES THE 8-BIT ELEMENTS OF A LIST IN ASCENDING)) \n (line (comment ;ORDER.  THE STARTING ADDRESS OF THE LIST IS IN LOCATIONS $30 AND)) \n (line (comment ;$31.  THE LENGTH OF THE LIST IS IN THE FIRST BYTE OF THE LIST.  LOCATION)) \n (line (comment ;$32 IS USED TO HOLD AN EXCHANGE FLAG.)) \n \n (line (instruction (label (name SORT8)) (opcode LDY) (argumentlist (argument (prefix #) (number $00))) (comment ;TURN EXCHANGE FLAG OFF (= 0)))) \n (line (instruction (opcode STY) (argumentlist (argument (number $32))))) \n (line (instruction (opcode LDA) (argumentlist (argument ( (argument (number $30)) )) , (argumentlist (argument (name Y)))) (comment ;FETCH ELEMENT COUNT))) \n (line (instruction (opcode TAX) (comment ; AND PUT IT INTO X))) \n (line (instruction (opcode INY) (comment ;POINT TO FIRST ELEMENT IN LIST))) \n (line (instruction (opcode DEX) (comment ;DECREMENT ELEMENT COUNT))) \n (line (instruction (label (name NXTEL)) (opcode LDA) (argumentlist (argument ( (argument (number $30)) )) , (argumentlist (argument (name Y)))) (comment ;FETCH ELEMENT))) \n (line (instruction (opcode INY))) \n (line (instruction (opcode CMP) (argumentlist (argument ( (argument (number $30)) )) , (argumentlist (argument (name Y)))) (comment ;IS IT LARGER THAN THE NEXT ELEMENT?))) \n (line (instruction (opcode BCC) (argumentlist (argument (name CHKEND))))) \n (line (instruction (opcode BEQ) (argumentlist (argument (name CHKEND))))) \n (line (comment ;YES. EXCHANGE ELEMENTS IN MEMORY)) \n (line (instruction (opcode PHA) (comment ; BY SAVING LOW BYTE ON STACK.))) \n (line (instruction (opcode LDA) (argumentlist (argument ( (argument (number $30)) )) , (argumentlist (argument (name Y)))) (comment ; THEN GET HIGH BYTE AND))) \n (line (instruction (opcode DEY) (comment ; STORE IT AT LOW ADDRESS))) \n (line (instruction (opcode STA) (argumentlist (argument ( (argument (number $30)) )) , (argumentlist (argument (name Y)))))) \n (line (instruction (opcode PLA) (comment ;PULL LOW BYTE FROM STACK))) \n (line (instruction (opcode INY) (comment ; AND STORE IT AT HIGH ADDRESS))) \n (line (instruction (opcode STA) (argumentlist (argument ( (argument (number $30)) )) , (argumentlist (argument (name Y)))))) \n (line (instruction (opcode LDA) (argumentlist (argument (prefix #) (number $FF))) (comment ;TURN EXCHANGE FLAG ON (= -1)))) \n (line (instruction (opcode STA) (argumentlist (argument (number $32))))) \n (line (instruction (label (name CHKEND)) (opcode DEX) (comment ;END OF LIST?))) \n (line (instruction (opcode BNE) (argumentlist (argument (name NXTEL))) (comment ;NO. FETCH NEXT ELEMENT))) \n (line (instruction (opcode BIT) (argumentlist (argument (number $32))) (comment ;YES. EXCHANGE FLAG STILL OFF?))) \n (line (instruction (opcode BMI) (argumentlist (argument (name SORT8))) (comment ;NO. GO THROUGH LIST AGAIN))) \n (line (instruction (opcode RTS) (comment ;YES. LIST IS NOW ORDERED))) \n)

If you have Apple][ code on floppies of your own and you wish to retrieve it, I used a device from here. It worked very well.