January 6, 2021

EBAZ4205 Bitcoin miner board - Boot

The boot process for the Xilinux XC7Z010 is described here as I work it out. Chapter 29 of the TRM discusses OCM (on chip memory) which includes a 128K bootrom section.

Also OCM provides 256K of ram. The TRM states that the BootROM memory is not visible to the user. OCM is initially mapped into two areas of the address map. 192K sits at address zero and the other 64K sits at the highest memory addresses. Initially the high memory is used by the bootROM, but once the first stage loader has been moved to OCM and transfered to, this may be used. The address mapping may then be flipped so that all of OCM is mapped to the highest addresses as a contiguous 256K section, i.e.

0xffc0000 to 0xffffffff
Statements are made that the OCM is designed to support the full clock rate of the processor (667 Mhz), so perhaps the BootROM sets up the clock to run at the full rate.

After reset, CPU0 runs BootROM code and CPU1 executes the WFE instruction. As they say, CPU1 "parks itself" using the WFE instruction. The BootROM looks for a Boot Image Header on the boot device, and then loads a FSBL (first stage boot loader) into OCM and branches to it.

The chip can boot from several devices, as per jumper settings

There are 4 versions of Master boot mode. They say that the FSBL may be an ELF image.

Bootgen

Xilinx provides a utility called "bootgen", with source available from their Github. It writes the bootimage, generating the header.

I'll note that my flash image begins with

00000000 feff ffea feff ffea feff ffea feff ffea
00000010 feff ffea feff ffea feff ffea feff ffea
00000020 6655 99aa 584e 4c58 0000 0000 0000 0101   fU  XNLX
00000030 0017 0000 1080 0100 0000 0000 0000 0000
00000040 1080 0100 0100 0000 2045 16fc 0000 0000            E
00000050 0000 0000 0000 0000 0000 0000 0000 0000
00000060 0000 0000 0000 0000 0000 0000 0000 0000
00000070 0000 0000 0000 0000 0000 0000 0000 0000
00000080 0000 0000 0000 0000 0000 0000 0000 0000
00000090 0000 0000 0000 0000 c008 0000 800c 0000
Note that feffffea can be viewed a a little endian 32 bit object, in which case it becomes 0xeafffffe. Note that this is repeated 8 times. What this is is 8 "boot vectors" and this is the ARM "jump to self" instruction being loaded into each of them (i.e. a single instruction "spin" loop).

The boot header is described in the TRM in section 6.3.2. The 8 vector entries are noted

The register initialization is 256 pairs of address and data words that can be used to set MIO mux values, clocks, and such.
In our case these are all ffff ffff 0000 0000
An address value of ffff ffff indicates end of list, so this is not doing anything in our case.

Indeed, inspection of the image shows code starting at 0x1700. The length is well under the limit of 192K (196,608 bytes).

Image and Partition headers

These are described in a different manual (in Appendix A of the Zynq-7000 software developers guide.

Here is the image header:

000008c0 0000 0201 0300 0000 2003 0000 4002 0000               @
000008d0 0000 0000 ffff ffff ffff ffff ffff ffff
000008e0 ffff ffff ffff ffff ffff ffff ffff ffff
000008f0 ffff ffff ffff ffff ffff ffff ffff ffff
Here is the partition header:
00000c80 0460 0000 0460 0000 0460 0000 0000 0000    `   `   `
00000c90 0000 0000 c005 0000 1000 0000 0100 0000
00000ca0 0000 0000 4002 0000 0000 0000 0000 0000       @
00000cb0 0000 0000 0000 0000 0000 0000 e2d7 feff

Feedback? Questions? Drop me a line!

Tom's Computer Info / tom@mmto.org