November 14, 2024

Porting Kyu to the Zynq - Round 2 -- proper startup

After getting it to link cleanly, we booted it and we get this:
Filename 'bitcoin.bin'.
Load address: 0x20000000
Bytes transferred = 210848 (337a0 hex)
## Starting application at 0x20000000 ...
TJT in mmu_set_ttbr, page table: 20038000
 set TTBCR to 0, read back: 00000000
 set TTBR0 to 2003800b, read back: 2003800b
 set TTBR1 to 2003800b, read back: 2003800b
 set DACR to ffffffff, read back: ffffffff
TJT mmu_set_ttbr finished
That is something. It does run and we do print some messages.
Thes messages come from mmu_set_ttbr() in armv7/mmu.c
It is tempting to focus on those messages, but in truth, the problem lies someplace after they get printed. Some trial and error will tell us where. Also it is worth remembering that I have not yet properly mapped out ram (the start and end address).

Cheat and use the BBB startup

The file armv7/locore.S is the assembly language startup file. It has a bunch of special code that sets up the MMU to allow multiple cores to work properly. The trick is to force it to use the BBB startup code which is simple and seems to always work for a single core (the BBB is a single core processor). I do this and the startup gets much farther:
## Starting application at 0x20000000 ...
TJT in mmu_set_ttbr, page table: 20038000
 set TTBCR to 0, read back: 00000000
 set TTBR0 to 2003800b, read back: 2003800b
 set TTBR1 to 2003800b, read back: 2003800b
 set DACR to ffffffff, read back: ffffffff
TJT mmu_set_ttbr finished
  ======================== We made it to kyu_startup!
orig SCTLR = 08c5187f
orig ACTLR = 00000047
orig    SP = 1eb3fc08
orig TTBR0 = 1eff0000
orig TTBR1 = 00010000
orig TTBCR = 00000000
orig DACR  = ffffffff
SCTLR = 08c5187d
ACTLR = 00000047
Kyu starting with stack: 1eb3fbf8
Kyu starting with cpsr: 600f00d3
board_hardware_init - sp: 1eb3fbe8
board_hardware_init - cpsr: 600f00d3
-- Cache init --
...
...
ARM cache line size: 32
PANIC: ran outa ram

We need to properly initialize the amount of ram

The panic comes from ram_alloc() in armv7/ram.c -- let's investigate how we called ram_init() to get this module initialized. This should be called from some routine in board.c -- and not surprisingly, we don't call it at all.

On both the Ebaz and the Antminer S9, ram starts at address 0. The Ebaz has 256M of it. The Antminer usually has 512M, but I have one board with 1024M. We could poke around and try to figure out how much ram we actually have -- and this would really be a good idea in the long term. But to get moving along right now, we could just use 256M, which honestly is more than ample for most anything.

So we add code to tell it that ram starts at 0 and to probe for size. We see:

Probing for amount of ram
Found 512 M of ram
.....
RAM 512M total starting at 00000000
Kyu image size: 538109168 bytes
kernel end: 2012e4f0
PANIC: Kernel lost after ram

Sort out address aliasing and a data abort

Well, that is a heck of a big Kyu image size. The story here is that we have 512M of ram. The kernel load address of 0x2000_0000 is just after the end of ram, and is an address that gets aliased to 0!

Now I am getting data aborts from memset() when it tries to write a byte to either 0013_0000 or 2020_0000, both of which seem like entirely proper addresses to me. The data abort is telling me that an access to memory at that address is illegal. Perhaps this is all about MMU mappings.

I cycle power and interrupt the boot to get into U-Boot and use the "md" command to dump memory. I have no trouble dumping either address given above. And I verify by experiment that 1fff_0000 and 3fff_0000 are aliases, just as I thought. One useful tidbit (from bdinfo) is:

ethaddr     = 00:0a:35:00:01:22
As I remember, U-Boot runs with the MMU turned off. My guess is that the BBB startup I am using is turning the MMU on, but not initializing it in a way that plays well with the Zynq. I copy the BBB startup to be a ZYNQ startup and comment out the calls to set up the MMU, now I get something entirely new.

Illegal instruction (sdiv)

I get an illegal instruction when it tries to execute the "sdiv" instruction. (I will note that the address reported is the instruction after the illegal instruction.) This is signed division. Could it be that the ARM core in the Zynq cannot execute this? Apparently it cannot. The Zynq has an "Cortex-A9 MPCore" processor, and some searching indicates we ain't got no sdiv or udiv. So, the trick will be running gcc with the proper flags. (The call was being generated in etimer() by the way. This change is in Makefile.inc

Success at last

We rebuild and Hooray! we get to the Kyu prompt.

Starting board initialization for the Zynq
CPU clock 66 Mhz
Resetting CPU clock
CPU clock 66 Mhz
Delay for 10 ms = 42623
 -- Cache timings:
 - Cpu running at 66 Mhz
 100K:   8144   8144   8144   8144 per 1K =    81
  20K:   1629   1629   1629   1629 per 1K =    81
   1K:     81     81     81     81 per 1K =    81
Enabling interrupts
RAM 506M+ available starting at 205b0000
Kyu version 0.9.5 for zynq, Compiled by tom: Thu Nov 14 08:27:30 PM MST 2024 running
Kyu (opi), ready >
Hitting return gives me a newline without a return. And we would like to chang the prompt to say "zynq" not "opi".
These are easy fixes, we do them and call it a day.
Kyu (zynq), ready>

Feedback? Questions? Drop me a line!

Tom's Computer Info / tom@mmto.org