There was someone on allegrolokalnie who had two of these mini210 for 25zł each. I bought two of them and will be playing with linux. They run S5PV210 CPUs, which are based on an ARM Cortex A8 core (ARMv7-A architecture)
Resources for later:
exynos4-sdk/uboot. The smdkv210 source file looks like it's newer than in SourceLink, and seems to support SDMMC boot.
meta-s5pv210 yocto layer and u-boot fork that it uses. defconfig, U-boot from 2013. [01-10-23]
Documentation/arch/arm/samsung/overview.rst
or hereManufacutrer's distribution DVD downloaded from their onedrive via here
Support is in mainline kernel: mach-s5pv210
Vendor compiler from the DVD: arm-linux-gcc-4.5.1-v6-vfp-20120301.tgz. Alas no u-boot source code or bootloader. Or I have not found it yet. [26.07.23] [30.07.23 note: Manufacturer uses Superboot and provides a binary file that seems to work]
There is GCC4 in manufacturer's DVD A. There is no bootloader there. The manufacturer's DVD has baremetal examples. They are even compiled too.
I've translated the document here and started the precompiled 1.leds_s
example. It indeed does
run.
Steps to reproduce
cd FriendlyARM-210-DVD-A/No OS(裸机程序)/bin/1.leds_s
sudo dd if=210.bin of=/dev/sdb seek=1
[sudo] hasło użytkownika poplar:
32+0 przeczytanych rekordów
32+0 zapisanych rekordów
skopiowane 16384 bajtów (16 kB, 16 KiB), 0,0193907 s, 845 kB/s
After inserting the card into the SD slot, flipping the switch S2 to "SDBOOT" position and booting the board, the 4 leds flash.
I have then verified that the bundled GCC can reproduce the same effect:
poplar@poplar:~/prog/mini210/FriendlyARM-210-DVD-A/No OS(裸机程序)/src$ cp -r 1.leds_s/ ../../../
poplar@poplar:~/prog/mini210/1.leds_s$ export PATH=/opt/FriendlyARM/toolschain/4.5.1/bin/:$PATH
poplar@poplar:~/prog/mini210/1.leds_s$ make
arm-linux-gcc -o start.o start.S -c
arm-linux-ld -Ttext 0x0 -o led.elf start.o
arm-linux-objcopy -O binary led.elf led.bin
arm-linux-objdump -D led.elf > led_elf.dis
gcc mkv210_image.c -o mkmini210
./mkmini210 led.bin 210.bin
poplar@poplar:~/prog/mini210/1.leds_s$
Blast it onto the SD card:
poplar@poplar:~/prog/mini210/1.leds_s$ sudo dd if=210.bin of=/dev/sdb seek=1
32+0 przeczytanych rekordów
32+0 zapisanych rekordów
skopiowane 16384 bajtów (16 kB, 16 KiB), 0,0291652 s, 562 kB/s
After I put the card in the board the leds example booted up just like the precompiled one. Good!
Further examples use BL1.bin and BL2.bin which are presumably first and second stage bootloaders:
Compared with the code in the previous chapter, the code in this chapter has been greatly modified. First, the whole project is divided into two directories: BL1 and BL2. The code under the directory BL1 will be compiled and linked into a file named BL1.bin, and the code under the directory BL2 will be compiled and linked into a file named BL2.bin. . Among them, the link address of the BL1.bin file is 0 (the position-independent code is used, and the program can run in any available memory), and the link address of the BL2.bin file is 0x23E00000 (the position-independent code is not used, all programs must be at that address to function properly). BL1.bin needs to be programmed to sector 1 of the sd card, and BL2.bin needs to be programmed to sector 49 of the sd card. The reason for this programming will be given in the following program explanation. The complete For the programming process, please refer to the programming steps in Section 4 of this chapter. The running process of the whole program is roughly as follows: after the system is powered on, first copy the BL1. Copy BL2.bin at sector 49 in the sd card to address 0x23E00000 of DRAM, and finally jump to this address to continue running.
From the translated document, page 29. BL1 is PIC code for initializing DRAM. BL2 is the second stage bootloader.
Some kernel: android_kernel210 and uboot from the same user uboot_smdk210 (readme dated 2008)
AliExpress listing that comes with a CD with uboot sources: OK210 -> Leads to forum with CD download link. Translated download links
OK210 development board users close disk A link:
http://pan.baidu.com/s/1sjC3Y5B password: neqt
OK210 Development Board User CD B Link:
http://pan.baidu.com/s/1bn2NfjT Password: 1s1w
OK210 Development Board User CD C Link:
http://pan.baidu.com/s/1pJqnzvl Password: mryy
TODO: download via the usual baidu service
Superboot, the vendor bootloader, is described here. \镁光NANDFlash的更新说明.pdf
describes how to use Superboot to boot a zImage+rootfs. superboot210.bin
can be found in the main directory of the B DVD. B directory contains ready made Linux, Android and WinCE images with Superboot config.
It appears here that uboot is able to create the bl1 file and is merged into mainline.
Uboot could likely be booted as BL2. The samsung iROM boot note talks about how to do it... The linked BL1 copies the U-boot from nand to dram and then just jumps to it: like this
#define UBOOT_PHY_BASE 0x23E00000 /* For V210 */
void(*run_uboot)(void) = UBOOT_PHY_BASE;
dvda
and dvdb
respectivelyBlew dvbd/images/Superboot210.bin
to sector 1+ of the sd card, no signs of life. Boot error code: 60%, 50%, 10% (SDMMC checksum error, SDMMC error, UART boot error)
Blew dvdb/images/Linux/rootfs_mini210_256m.img
to sector 1+ of the sd card.. XPWMOUT0 was 60% high for a while
60% duty cycle means SDMMC boot checksum error.
I have made a mistake and confused skip= and seek= options of dd.
After blowing Superboot210.bin
to the SD card:
sudo dd if=Superboot210.bin of=/dev/sdb seek=1
I am greeted by the bootloader:
Booting from SD
ERROR: Media attach failed
ACTION AND OS must be defined
Let's try to build one of the u-boot's. I will go with gotobootloader/u-boot-s5pv210
because I already have it downloaded. Now that I have a working toolchain gcc4 it should build OK.
$ make qt210_config CC=arm-linux-gcc
Generating include/autoconf.mk
cc1: error: unrecognized command line option "-fstack-usage"
Generating include/autoconf.mk.dep
cc1: error: unrecognized command line option "-fstack-usage"
Configuring for qt210 board...
$ make CC=arm-linux-gcc
fails...
-fstack_usage
from include/generated/cc_options.mk
(too old GCC4)include/sha1.h
to lib/sha1.c
void bord_nand_init
in board/samsung/qt210/qt210.c
Stuck on what seems to be ld bug.
Trying the sourcelink repo SourceLink/S5PV210
. Untar'd 14-uboot/u-boot-2016.11-6.tar.gz
which is a bzip2 archive.
$ make smdkv210_defconfig CC=arm-none-linux-gnueabi-gcc LD=arm-none-linux-gnueabi-ld
#
# configuration written to .config
#
poplar@poplar:~/prog/mini210/S5PV210-master/14-uboot/u-boot-2016.11$ make menuconfig
scripts/kconfig/mconf Kconfig
configuration written to .config
*** End of the configuration.
*** Execute 'make' to start the build or try 'make help'.
poplar@poplar:~/prog/mini210/S5PV210-master/14-uboot/u-boot-2016.11$ make smdkv210_defconfig CC=arm-none-linux-gnueabi-gcc LD=arm-none-linux-gnueabi-ld
poplar@poplar:~/prog/mini210/S5PV210-master/14-uboot/u-boot-2016.11$ make CC=arm-none-linux-gnueabi-gcc LD=arm-none-linux-gnueabi-ld
[ ... snip ...]
LD spl/dts/built-in.o
LD spl/fs/built-in.o
LDS spl/u-boot-spl.lds
LD spl/u-boot-spl
OBJCOPY spl/u-boot-spl-nodtb.bin
COPY spl/u-boot-spl.bin
./tools/mksource210spl spl/u-boot-spl.bin spl/smdkv210-spl.bin
cp ./spl/smdkv210-spl.bin ./tmp.bin
truncate ./tmp.bin -c -s 16K
cat ./u-boot.bin >> ./tmp.bin
mv ./tmp.bin ./u-boot-all.bin
cp ./u-boot-all.bin /work/nfs_root
cp: nie można utworzyć zwykłego pliku '/work/nfs_root': Nie ma takiego pliku ani katalogu
make: *** [Makefile:838: combine] Błąd 1
poplar@poplar:~/prog/mini210/S5PV210-master/14-uboot/u-boot-2016.11$ ls
api doc lib snapshot.commit u-boot.cfg
arch drivers Licenses spl u-boot-dtb.bin
board dts MAINTAINERS System.map u-boot.lds
cmd examples Makefile test u-boot.map
common fs net tools u-boot-nodtb.bin
config.mk include post u-boot u-boot.srec
configs Kbuild README u-boot-all.bin u-boot.sym
disk Kconfig scripts u-boot.bin
poplar@poplar:~/prog/mini210/S5PV210-master/14-uboot/u-boot-2016.11$ file u-boot
u-boot: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /usr/lib/ld.so.1, with debug_info, not stripped
poplar@poplar:~/prog/mini210/S5PV210-master/14-uboot/u-boot-2016.11$ file u-boot.bin
u-boot.bin: data
u-boot.bin is just the uboot. u-boot-all.bin is BL1 + uboot, ready to be blown to SD card.
However this fork is explicitly said in the readme to not support sd/mmc boot.
Exynos4-sdk uboot fork. This seems to be older and it will likely need the same sha1 fix and the other fixes like the gotobootloader/u-boot-s5pv210
. It might crash ld as well.
Building: make CC=arm-none-linux-gnueabi-gcc LD=arm-none-linux-gnueabi-ld CROSS_COMPILE=/opt/FriendlyARM/toolschain/4.5.1/bin/arm-none-linux-gnueabi-
This has built a u-boot.bin which needs the SPL.. i will try to merge it with exising SPL-equipped image. That is, u-boot-all.bin
from the previous source tree written to sd-card and then u-boot.bin
from this one written at file offset 0x4000+1sector.
poplar@poplar:~/prog/mini210/exynos4/uboot-master$ cp ../../S5PV210-master/14-uboot/u-boot-2016.11/spl/smdkv210-spl.bin .
poplar@poplar:~/prog/mini210/exynos4/uboot-master$ truncate smdkv210-spl.bin -c -s 16K
poplar@poplar:~/prog/mini210/exynos4/uboot-master$ cp smdkv210-spl.bin u-boot-all.bin
$ cat u-boot.bin >> u-boot-all.bin
poplar@poplar:~/prog/mini210/exynos4/uboot-master$ sudo dd if=u-boot-all.bin of=/dev/sdb seek=1
[sudo] hasło użytkownika poplar:
572+1 przeczytanych rekordów
572+1 zapisanych rekordów
skopiowane 293236 bajtów (293 kB, 286 KiB), 0,175408 s, 1,7 MB/s
poplar@poplar:~/prog/mini210/exynos4/uboot-master$
Im getting a weird error. I don't know what it is because I dont have JTAG on this. I feel like this u-boot does not support SPL booting like that.
Perhaps I can boot that u-boot which does not support sd/mmc (SourceLink) with Superboot and then use that for booting Linux?
I found this PDF which mentions S5PV210 CPU as supported. It seems to be a manual for some debugger. I only skimmed it with ^F but it is a lead. debugger_arm.pdf
23:19 < polprog> hi, ive got a board with an arm cortex a8 (s5pv210) and id like to use opencd with it.. it autodetects one
tap but im not sure what kind of tap is it
23:19 < polprog> Info : JTAG tap: s5pv210.tap tap/device found: 0x1ba00477 (mfg: 0x23b (ARM Ltd), part: 0xba00, ver: 0x1)
23:20 < polprog> I'm looking at files for ti omap in a BeagleBone and it has three taps, one of them is the DAP used for
debugging
23:20 < polprog> what do i need to know to get access to the DAP?
23:21 < PaulFertser> polprog: TI parts are known to lack DAP info ROM tables so you need to manually provide debug base etc,
you should be able to find them in the datasheet/reference manual.
23:22 < PaulFertser> polprog: probably you can find config files for some other jtag software and infer needed values from it.
23:25 < polprog> allright, and then based on that I define the taps in my config file for this cpu?
23:25 < polprog> (its the only device in the chain)
23:26 < PaulFertser> polprog: you likely have just one JTAG tap (according to results of autodetection) and then this TAP is
used as a transport for ARM debug protocols, so you define a DAP on top of it, and then a target CPU on
top of DAP.
23:28 < polprog> got it, thanks!
23:28 < polprog> ill ask questions when i find how some other debugger does it with this cpu
23:29 < PaulFertser> polprog: you can probably just experiment based on data used for similar targets
23:31 < polprog> thats my approach too but the only similar thing i see is samsung_s3*.cfg
23:31 < polprog> ill take a look at these files
23:33 < polprog> these are 920t or 7tdmi or 11 cores
23:34 < polprog> s3c4510.cfg looks the most similar, its arm7tdmi
23:34 < PaulFertser> polprog: just try minimal config. This part might have proper DAP ROM table so might be able to
autodetect dbgbase.
23:34 < PaulFertser> polprog: try defining dap on top of this tap and then cortex_a target.
23:35 < PaulFertser> polprog: like imx51.cfg but without other taps
23:37 < polprog> Info : s5pv210.cpu: hardware has 6 breakpoints, 2 watchpoints
23:38 < polprog> is this from the config or from the DAP ROM?
23:41 < PaulFertser> polprog: very good
23:41 < PaulFertser> polprog: that's from examination of the debug unit that was connected to thanks to info from DAP tables.
23:41 < polprog> i got the romtable under 'dap info'
23:41 < polprog> fantastic
That's correct. Thanks to PaulFerster's suggestion to use the imx51 config i made this .cfg file which eventually gets me access to the memory and registers via gdb.
This is the s5pv210.cfg config file:
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME s5pv210
}
# CoreSight Debug Access Port
if { [info exists DAP_TAPID] } {
set _DAP_TAPID $DAP_TAPID
} else {
set _DAP_TAPID 0x1ba00477
}
jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf \
-expected-id $_DAP_TAPID
set _TARGETNAME $_CHIPNAME.cpu
dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap
And this is how I call oocd:
openocd -f /usr/share/openocd/scripts/interface/jlink.cfg \
-f s5pv210.cfg \
-c "transport select jtag" \
-c "adapter speed 10" \
-c "init" \
-c "scan_chain"
$ ./oocd.sh
Open On-Chip Debugger 0.11.0-rc2
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport "jtag". To override use 'transport select <transport>'.
Warn : Transport "jtag" was already selected
jtag
adapter speed: 10 kHz
Info : J-Link ARM V8 compiled Dec 1 2009 11:42:48
Info : Hardware version: 8.00
Info : VTarget = 3.319 V
Info : clock speed 10 kHz
Info : JTAG tap: s5pv210.cpu tap/device found: 0x1ba00477 (mfg: 0x23b (ARM Ltd), part: 0xba00, ver: 0x1)
Info : s5pv210.cpu: hardware has 6 breakpoints, 2 watchpoints
Info : starting gdb server for s5pv210.cpu on 3333
Info : Listening on port 3333 for gdb connections
TapName Enabled IdCode Expected IrLen IrCap IrMask
-- ------------------- -------- ---------- ---------- ----- ----- ------
0 s5pv210.cpu Y 0x1ba00477 0x1ba00477 4 0x01 0x0f
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Now I can use gdb-multiarch
to connect to the CPU:
(gdb) tar ext :3333
Remote debugging using :3333
warning: No executable has been specified and target does not support
determining executable automatically. Try using the "file" command.
0xc017d14c in ?? ()
(gdb) x/16i $pc
=> 0xc017d14c: mov pc, lr
0xc017d150: mrc 15, 0, r3, cr0, cr0, {1}
0xc017d154: lsr r3, r3, #16
0xc017d158: and r3, r3, #15
0xc017d15c: mov r2, #4
0xc017d160: lsl r2, r2, r3
0xc017d164: mcr 15, 0, r0, cr7, cr10, {1}
0xc017d168: add r0, r0, r2
0xc017d16c: subs r1, r1, r2
0xc017d170: bhi 0xc017d164
0xc017d174: dsb sy
0xc017d178: mov pc, lr
0xc017d17c: mov r2, #0
0xc017d180: ldr r1, [r1, #368] ; 0x170
0xc017d184: orr r0, r0, #89 ; 0x59
0xc017d188: mcr 15, 0, r2, cr13, cr0, {1}
(gdb)
Fuck yeah
SoC user manual is in dvda/Datasheet/S5PV210_UM_REV1.1.pdf
I've assembed an adapter from the serial port header to hook up the ft4232hl board. I'm testing the exynos u-boot fork. With gdb working i can examine where the board gets stuck.
Reaching nowhere and with little debug capabilities I decided to check the whole chain.
The BL1 from the card that I am using, smdkv210-spl.bin
loads the code from SD card sector 49 onwards to address 0x2000_2200
. I tested this by creating a file inf_loop.bin that contains 4 bytes, fe ff ff eb
(bl 0
), and burned the BL1 file to sector 1 onwards and the inf_loop file to sector 49. The debugger shows that the code is stuck at address 0x2000_2200
. And the memory contents match. This also shows that this particular BL1 does not validate check sums.
I've hacked up a new board config in the exynos4 uboot tree. The new board is called mini210 and the most important part is in board/samsung/mini210/config.mk
:
CONFIG_SYS_TEXT_BASE = 0x20002200
This is where the BL1 will load the shit and jump to. This cause the board to emit "OK" from the lowlevel_init.S
file.
sudo dd if= of=/dev/sdb seek=1 # Blow bl1 - only once per card
sudo dd if=u-boot.bin of=/dev/sdb seek=49 # Blow u-boot
# Uboot can be built with `make mini210` provided that the path is set OK.
Immediately after that OK print it jumps to load_uboot
which is a procedure later in the file. The procedure checks if the code needs to be relocated.
load_uboot:
push {lr}
/* when we already run in ram, we don't need to relocate U-Boot.
* and actually, memory controller must be configured before U-Boot
* is running in ram.
*/
ldr r0, =0xff000fff
bic r1, pc, r0 /* r0 <- current base addr of code */
ldr r2, _TEXT_BASE /* r1 <- original base addr in ram */
bic r2, r2, r0 /* r0 <- current base addr of code */
cmp r1, r2 /* compare r0, r1 */
beq after_copy /* r0 == r1 then skip flash copy */
#if defined(CONFIG_EVT1)
/* If BL1 was copied from SD/MMC CH2 */
ldr r0, =0xD0037488
ldr r1, [r0]
ldr r2, =0xEB200000
cmp r1, r2
beq mmcsd_boot
#endif
ldr r0, =INF_REG_BASE
ldr r1, [r0, #INF_REG3_OFFSET]
cmp r1, #BOOT_NAND /* 0x0 => boot device is nand */
beq nand_boot
cmp r1, #BOOT_ONENAND /* 0x1 => boot device is onenand */
beq onenand_boot
cmp r1, #BOOT_MMCSD
beq mmcsd_boot
cmp r1, #BOOT_EMMC
beq emmc_boot
cmp r1, #BOOT_NOR
beq nor_boot
cmp r1, #BOOT_SEC_DEV
beq mmcsd_boot
CONFIG_EVT1 is defined, so the ifdef is placed. 0xD0037488
is the address of the iROM variable V210_SDMMC_BASE
, "Current boot channel." (from iROM app note. 0xEB2000000 is ELFIN_HSMMC_2_BASE
(morons have that as a constant in arch/arm/include/asm/arch-s5pv210/cpu.h
but had to put a magic number in there)
todo: examine what is 0xD0037488 for this board and which HSMMC it uses! Alternatively disable CONFIG_EVT1, i have no idea what it does.
todo: examine how to jump to uboot
Useful note: https://m2m-tele.com/blog/2021/10/24/u-boot-initialization-sequence/
Examining where the fault occurs. The current status is that the exynox u-boot fork, after my modifications, emits the OK prompt. Then the board gets into a fault state. Im unable to set breakpoints, but i can halt the board and single step instructions. I'm debugging it by regenerating u-boot versions with infinite loops where i want to put the breakpoint, recompile, flash to SD and then halt the board to examine register state.
Going after the inf loop when the debugger attaches can be done with resume address
.
Currently trying to locate the fault. Is it in load_uboot?
0x200028d0 <load_uboot>: stmfd sp!, {lr}
0x200028d4 <dbgloop>: bl 0x200028d4 <dbgloop>
0x200028d8 <dbgloop+4>: ldr r0, [pc, #792] ; 0x20002bf8 <phy_last_jump+60>
0x200028dc <dbgloop+8>: bic r1, pc, r0
0x200028e0 <dbgloop+12>: ldr r2, [pc, #-648] ; 0x20002660 <_TEXT_BASE>
0x200028e4 <dbgloop+16>: bic r2, r2, r0
0x200028e8 <dbgloop+20>: cmp r1, r2
=> 0x200028ec <dbgloop+24>: beq 0x2000295c <after_copy>
s5pv210.cpu rev 2, partnum c08, arch f, variant 2, implementor 41
target halted in ARM state due to breakpoint, current mode: Supervisor
cpsr: 0x600001d3 pc: 0x200028e8
MMU: disabled, D-Cache: disabled, I-Cache: enabled
> reg r2
r2 (/32): 0x00002000
> reg r1
r1 (/32): 0x00002000
>
r1 == r2, so beq will be taken. We go to after_copy
0x2000295c <after_copy>: ldmfd sp!, {pc}
ldmfd loads a previous pc from stack and rolls sp back to where it was. next pc value is 0x20002860 - we are back to lowlevel_init:
0x20002860 <lowlevel_init+152>: bl 0x20002b60 <enable_mmu>
entering procedure enable_mmu (..2b60)
(gdb) x/16i enable_mmu
0x20002b60 <enable_mmu>: ldr r5, [pc, #268] ; 0x20002c74 <phy_last_jump+184>
0x20002b64 <enable_mmu+4>: mcr 15, 0, r5, cr3, cr0, {0}
0x20002b68 <enable_mmu+8>: ldr r0, [pc, #264] ; 0x20002c78 <phy_last_jump+188>
0x20002b6c <enable_mmu+12>: ldr r1, [pc, #264] ; 0x20002c7c <phy_last_jump+192>
0x20002b70 <enable_mmu+16>: ldr r2, [pc, #264] ; 0x20002c80 <phy_last_jump+196>
0x20002b74 <enable_mmu+20>: bic r0, r0, r2
0x20002b78 <enable_mmu+24>: orr r1, r0, r1
0x20002b7c <enable_mmu+28>: mcr 15, 0, r1, cr2, cr0, {0} ;; __ allright up to here! __
0x20002b80 <mmu_on>: mrc 15, 0, r0, cr1, cr0, {0}
0x20002b84 <mmu_on+4>: orr r0, r0, #1
0x20002b88 <mmu_on+8>: mcr 15, 0, r0, cr1, cr0, {0} ;; Fault emitted here, or is it? The CPU is in ARM state.
0x20002b8c <mmu_on+12>: nop {0}
0x20002b90 <mmu_on+16>: nop {0}
0x20002b94 <mmu_on+20>: nop {0}
0x20002b98 <mmu_on+24>: nop {0}
0x20002b9c <mmu_on+28>: mov pc, lr
So the u-boot early init code crashes on writing back to coprocessor when enabling MMU. In ARM state the pc is the value of the current instruction address +8 (so, 2 insns ahead). This means the fault is tripped at the mrc instruction at 20002b80.
side quest: in this state it is possible to read the memory at 0x0000_0000 which is the iROM. Can we dump it?
Setting up the tree on Almiraj - i've installed the toolchain compiler arm-linux-gcc-4.5.1-v6-vfp-20120301.tgz on almiraj and copied the mini210/ tree to it.
Unformtunately after a make clean the build did not succeed.
I had to fix the following things:
Apparently
find . -iname Makefile -exec touch \{\} \;
has fixed that and similar errors ... do the makefiles need to be fucking newer for make to actually read them?
arm-none-linux-gnueabi-as: error while loading shared libraries: libz.so.1: cannot open shared object file: No such file or directory
sudo apt-get install lib32z1
After this, the exynos4/u-boot-master tree built correctly.
In the evening I tried to get the reset working, alas no dice.
What works is to halt
the target and resume <addr>
, so my infinite loop at uboot start must be left there for now.
I managed to dump iROM. It's 64kB. Attempting to read over 0x0001_0000 results in a data abort.
> dump_image irom.bin 0x0000000 0x10000
dumped 65536 bytes in 3.987809s (16.049 KiB/s)
> dump_image irom1m.bin 0x0000000 0x100000
data abort at 0x00010000, dfsr = 0x00000008
> dump_image irom.bin 0x0000000 0x10010
data abort at 0x00010000, dfsr = 0x00000008
>
iROM is also mapped from 0xD000_0000 upwards - lets see if we get the same 64kB and then error
> dump_image irom.bin 0xD0000000 0x10010
data abort at 0xd0010000, dfsr = 0x00000008
>
All files have the same sha1sum.
$ sha1sum irom*
1dc4afa153b0d03094c95f7762714d54af0b25c8 irom0000.bin
1dc4afa153b0d03094c95f7762714d54af0b25c8 irom1m.bin
1dc4afa153b0d03094c95f7762714d54af0b25c8 irom.bin
┌─< 0x00000000 2a0000ea b 0xb0
0x000000b0 c8009fe5 ldr r0, [0x00000180] ; [0x180:4]=0
0x000000b4 100f0cee mcr p15, 0, r0, c12, c0, 0
0x000000b8 0000e0e3 mvn r0, 0
0x000000bc 500f01ee mcr p15, 0, r0, c1, c0, 2
0x000000c0 0101a0e3 mov r0, 0x40000000
0x000000c4 100ae8ee vmsr fpexc, r0
0x000000c8 b4009fe5 ldr r0, [0x00000184] ; [0x184:4]=0xe2700000
0x000000cc 0010a0e3 mov r1, 0
0x000000d0 001080e5 str r1, [r0]
0x000000d4 100f11ee mrc p15, 0, r0, c1, c0, 0
0x000000d8 010a80e3 orr r0, r0, 0x1000
0x000000dc 100f01ee mcr p15, 0, r0, c1, c0, 0
0x000000e0 a0009fe5 ldr r0, [0x00000188] ; [0x188:4]=0xd0020010
0x000000e4 a0209fe5 ldr r2, [0x0000018c] ; [0x18c:4]=0xe010a000
0x000000e8 001092e5 ldr r1, [r2]
0x000000ec 9c209fe5 ldr r2, [0x00000190] ; [0x190:4]=0xe010c020
0x000000f0 003092e5 ldr r3, [r2]
0x000000f4 98209fe5 ldr r2, [0x00000194] ; [0x194:4]=0xe010c034
0x000000f8 004092e5 ldr r4, [r2]
0x000000fc 020711e3 tst r1, 0x80000
0x00000100 00f0a011 movne pc, r0
They contain valid and sensible arm-thumb instructions. Some strings:
0x00000458 Insert an OTG cable into the connector!
0x00007ffc Nor Check Sum Error
0x00008014 Uart negotiation Error
0x00008030 Uart Check Sum Error
0x00008048 Uart Data Length Over
0x00008060 Nand RnB Detect Error
0x00008078 Nand ECC Error
0x0000808c Nand Check Sum Error
0x000080a4 OND Check Sum Error
0x000080bc NO Boot Image
0x000080cc SD Init Error
0x000080dc SD checksum Error
0x000080f0 Secure Fail Error
0x00008338 eSSD Init Error
0x0000834c Enumeration TimeOut Error
0x00008368 No input Clock Error
0x00008380 Non Device Mode Error
0x00008398 eSSD Check Sum Error
0x0000c820 0403 0904 1603 5300 7900 7300 7400 6500 ......S.y.s.t.e.
0x0000c830 6d00 2000 4d00 4300 5500 2a03 5300 4500 m. .M.C.U.*.S.E.
0x0000c840 4300 2000 5300 3500 5000 4300 3100 3100 C. .S.5.P.C.1.1.
0x0000c850 3000 2000 5400 6500 7300 7400 2000 4200 0. .T.e.s.t. .B.
0x0000c860 2f00 4400 4600 0000 3200 0000 1e00 0000 /.D.F...2.......
I've imported the currently used BL1 to ghidra. It's quite small. The first thing it does is setting up the MMU. Ghidra decodes ARM Cortex coprocessor acccess nicely. It has some issues with decoding the first few instructions, that radare does not have.
The core implements ARMv7-A architecture, therefore we are using the VMSA memory architecture: Reference manual.
LAB_00000070 XREF[1]: 00000010(j)
00000070 12 00 00 ea b LAB_000000c0
LAB_000000c0 XREF[1]: 00000070(j)
000000c0 eb ff ff ea b FUN_00000074
**************************************************************
* *
* FUNCTION *
**************************************************************
undefined FUN_00000074()
assume LRset = 0x0
assume TMode = 0x0
undefined r0:1 <RETURN>
FUN_00000074 XREF[1]: FUN_00000050:000000c0(c)
00000074 00 00 0f e1 mrs r0,cpsr @ r0 <- current program state register
00000078 1f 10 00 e2 and r1,r0,#0x1f @ r1 <- CPSR & 0x1f ; r1 = operating mode
0000007c 1a 00 31 e3 teq r1,#0x1a @ r1 ?= 0x1a ; operating mode 1A = hypervisor
00000080 1f 00 c0 13 bicne r0,r0,#0x1f @ if ne, r0 <- r0 & ~0x1f ; clear mode
00000084 13 00 80 13 orrne r0,r0,#0x13 @ if ne, r0 <- r0 | 0x13 ; set mode 13 = supervisor
00000088 c0 00 80 e3 orr r0,r0,#0xc0 @ r0 <- r0 | 0xc0 ; set mask F,I = mark IRQ, FIQ
0000008c 00 f0 29 e1 msr cpsr_cf,r0 @ CSPR <- r0 ; set new CSPR
@ This code above disables FIQ and IRQ. If the CPU is not n hypervisor mode, sets supervisor mode.
@ MMU setup
@ P15 registers are desribed in reference manual section B3.17
@ MRC: Cop to ARM, MCR: ARM to COP
@ mcr/mrc <coproc>, {#}<opc1>, <Rt>, <CRn>, <CRm>{, {#}<opc2>}
@ p15 0x00 -- cr1 cr0 0x00 SCTRL, System Control Register
@ p15 0x00 -- cr12 cr0 0x00 VBAR, Vector Base Addres Register
@ p15 0x00 -- cr7 cr5 0x00 ICIALLU, Invalidate all instruction caches to PoU
@ p15 0x00 -- cr7 cr10 0x04 CP15DMB, Data Memory Barrier operation
@ p15 0x00 -- cr7 cr5 0x04 CP15ISB, Instruction Synchronization Barrier operation
00000090 10 0f 11 ee mrc p15,0x0,r0,cr1,cr0,0x0 @ r0 <- SCTRL
00000094 02 0a c0 e3 bic r0,r0,#0x2000 @ r0 <- r0 & ~0x02000
00000098 10 0f 01 ee mcr p15,0x0,r0,cr1,cr0,0x0 @ SCTLR <- r0 ; Unset bit 13: Low exception vectors, base address 0x00000000, remapable
0000009c 78 00 9f e5 ldr r0,[DAT_0000011c] @ r0 <- u32 (0x11c)
000000a0 10 0f 0c ee mcr p15,0x0,r0,cr12,cr0,0x0 @ VBAR <- DAT_0000011c; Load address of vector base addr reg; Remap vectors
000000a4 06 00 00 eb bl FUN_000000c4 undefined FUN_000000c4()
000000a8 1a 00 00 eb bl thunk_FUN_00000128 undefined thunk_FUN_00000128()
000000ac 1b 00 00 eb bl FUN_00000120 undefined FUN_00000120()
000000b0 15 0f 07 ee mcr p15,0x0,r0,cr7,cr5,0x0 @ ICIALLU ; synchronize
000000b4 9a 0f 07 ee mcr p15,0x0,r0,cr7,cr10,0x4 @ CP15DMB ; data memory barrier
000000b8 95 0f 07 ee mcr p15,0x0,r0,cr7,cr5,0x4 @ CP15ISB ; instruction sync barrier
000000bc 1e ff 2f e1 bx lr @ jump to lr.
void FUN_00000074(void){
uint uVar1;
undefined4 uVar2;
undefined4 in_cr0;
undefined4 in_cr12;
uVar1 = coproc_movefrom_Control(); // Disable fiq, irq. Set supervisor mode if not hypervisor
coproc_moveto_Control(uVar1 & 0xffffdfff); //
coprocessor_moveto(0xf,0,0,DAT_0000011c,in_cr12,in_cr0); // Remap vectors
FUN_000000c4(DAT_0000011c); // validate decompiler
thunk_FUN_00000128(); // ..
uVar2 = FUN_00000120(); // ..
coproc_moveto_Invalidate_Entire_Instruction(uVar2); //see disasm above
coproc_moveto_Data_Synchronization(uVar2);
coproc_moveto_Flush_Prefetch_Buffer(uVar2);
return;
}
I will decode what the three functions called inside do later.
I just realized that the SPL i took is actually built from the code in the other uboot tree, so I should build that uboot, since I confirmed the SPL is working. There is no point in trying to adjust the exynos fork to use the other fork's SPL.
The SPL was taken from the S5PV210-master/14-uboot/u-boot-2016.11/
tree.
[2116][polprog@almiraj:~/prog/mini210/S5PV210-master/14-uboot/u-boot-2016.11]$ export PATH=/opt/FriendlyARM/toolschain/4.5.1/bin/:$PATH
[2117][polprog@almiraj:~/prog/mini210/S5PV210-master/14-uboot/u-boot-2016.11]$ make smdkv210_defconfig CC=arm-none-linux-gnueabi-gcc LD=arm-none-linux-gnueabi-ld
HOSTCC scripts/basic/fixdep
HOSTCC scripts/kconfig/conf.o
HOSTCC scripts/kconfig/zconf.tab.o
HOSTLD scripts/kconfig/conf
#
# configuration written to .config
#
[2117][polprog@almiraj:~/prog/mini210/S5PV210-master/14-uboot/u-boot-2016.11]$ make smdkv210_defconfig CC=arm-none-linux-gnueabi-gcc LD=arm-none-linux-gnueabi-ld
[ ... snip ... ]
CC examples/standalone/hello_world.o
LD examples/standalone/hello_world
OBJCOPY examples/standalone/hello_world.srec
OBJCOPY examples/standalone/hello_world.bin
LDS u-boot.lds
LD u-boot
arm-none-linux-gnueabi-ld: warning: creating a DT_TEXTREL in object.
OBJCOPY u-boot.srec
OBJCOPY u-boot-nodtb.bin
./scripts/dtc-version.sh: linia 17: dtc: nie znaleziono polecenia
./scripts/dtc-version.sh: linia 18: dtc: nie znaleziono polecenia
*** Your dtc is too old, please upgrade to dtc 1.4 or newer
make: *** [Makefile:1396: checkdtc] Błąd 1
[2118][polprog@almiraj:~/prog/mini210/S5PV210-master/14-uboot/u-boot-2016.11]$ dtc
bash: dtc: nie znaleziono polecenia
[2119][polprog@almiraj:~/prog/mini210/S5PV210-master/14-uboot/u-boot-2016.11]$ sudo apt install device-tree-compiler
[ went OK ]
[2117][polprog@almiraj:~/prog/mini210/S5PV210-master/14-uboot/u-boot-2016.11]$ make smdkv210_defconfig CC=arm-none-linux-gnueabi-gcc LD=arm-none-linux-gnueabi-ld
[ ... snip ... ]
CC spl/board/samsung/smdkv210/smdkv210.o
AS spl/board/samsung/smdkv210/lowlevel_init.o
LD spl/board/samsung/smdkv210/built-in.o
LD spl/board/samsung/common/built-in.o
CC spl/common/init/board_init.o
LD spl/common/init/built-in.o
LD spl/drivers/built-in.o
LD spl/dts/built-in.o
LD spl/fs/built-in.o
LDS spl/u-boot-spl.lds
LD spl/u-boot-spl
OBJCOPY spl/u-boot-spl-nodtb.bin
COPY spl/u-boot-spl.bin
./tools/mksource210spl spl/u-boot-spl.bin spl/smdkv210-spl.bin
cp ./spl/smdkv210-spl.bin ./tmp.bin
truncate ./tmp.bin -c -s 16K
cat ./u-boot.bin >> ./tmp.bin
mv ./tmp.bin ./u-boot-all.bin
cp ./u-boot-all.bin /work/nfs_root
cp: nie można utworzyć zwykłego pliku '/work/nfs_root': Nie ma takiego pliku ani katalogu
make: *** [Makefile:838: combine] Błąd 1
The tree compiled okay - nfs_root error is due to some garbage hardcoded by sourcelink in the main Makefile (line 833)
Let's try to boot the created binary file and see where it stops using JTAG...
Similar to the exynos one, this u-boot outputs something on CON3 and then jumps into somewhere - halting it with jtag showed it happily executing instructions around 0x1d6a3ad8
0x1d6a3ad8 in ?? ()
(gdb) x/16i $px
Value can't be converted to integer.
(gdb) x/16i $pc
=> 0x1d6a3ad8: andeq r0, r0, r0
0x1d6a3adc: andeq r0, r0, r0
0x1d6a3ae0: andeq r0, r0, r0
0x1d6a3ae4: andeq r0, r0, r0
0x1d6a3ae8: andeq r0, r0, r0
0x1d6a3aec: andeq r0, r0, r0
0x1d6a3af0: andeq r0, r0, r0
0x1d6a3af4: andeq r0, r0, r0
0x1d6a3af8: andeq r0, r0, r0
0x1d6a3afc: andeq r0, r0, r0
0x1d6a3b00: andeq r0, r0, r0
0x1d6a3b04: andeq r0, r0, r0
0x1d6a3b08: andeq r0, r0, r0
0x1d6a3b0c: andeq r0, r0, r0
0x1d6a3b10: andeq r0, r0, r0
0x1d6a3b14: andeq r0, r0, r0
After blowing u-boot-all.bin onto the sd card
$ sudo dd if=u-boot-all.bin of=/dev/sdd seek=1 status=progress
board emits something on CON3 (uart2), which seems to be configured as the console similar to the exynos fork. I cant get the baudrate right, likely because the configured clock speed is wrong, but this is very promising.
Having some issues with the new bootloader i placed a loop very early in the code (arch/arm/cpu/armv7/start.S:save_boot_params
).
The loop landed at u-boot.bin offset 0x350, u-boot-all.bin offset 0xc0, and CPU memory offset 0xd00200c0.
This means that u-boot-all.bin is loaded into 0xd0020000. This is in IRAM, which makes sense, since iROM loads this from SD card.
Now the loaded PIC code (SPL) has to load something from the SD card. Time to place another loop in the code that is in BL2.
d0020000 b loc.reset start.S
d0020060 reset
d00200b0 save_boot_params (empty proc)
d0020064 save_boot_params_ret
* set supervisor mode *
d0020094 bl cpu_init_cp15 d00200b4
d0020098 bl cpu_init_crit
d0020108 lowlevel_init cache_v7_asm.S
clock_init
ddr_init
bl _main
bl copy_bl2_to_ram smdkv210.c !!! plik C, ale nie mamy stosu!!!
0xd0020000 160000ea b loc.reset ; cache.c:15 { ; [01] -r-x section size 1768 named .text
;-- reset
0xd0020060 120000ea b sym.save_boot_params ; start.S:40 b save_boot_params
;-- save_boot_params
0xd00200b0 ebffffea b loc.save_boot_params_ret ; start.S:117 b save_boot_params_ret @ back to my caller
;-- save_boot_params_ret
;; Inicjalizacja - disables FIQ and IRQ. If the CPU is not n hypervisor mode, sets supervisor mode.
0xd0020094 060000eb bl sym.cpu_init_cp15 ; start.S:82 bl cpu_init_cp15 ;[1]
0xd0020098 1a0000eb bl sym.cpu_init_crit ; start.S:84 bl cpu_init_crit ;[2]
;-- cpu_init_crit:
0xd0020108 040000ea b loc.lowlevel_init ; start.S:294 b lowlevel_init @ go setup pll,mux,memory
;-- lowlevel_init:
0xd0020120 0e90a0e1 mov sb, lr ; cache_v7_asm.S:138 bgt inval_levels
0xd0020124 060000eb bl sym.clock_init ; cache_v7_asm.S:140 mov r10, #0 @ swith back to cache level 0 ;[2]
0xd0020128 4c0000eb bl sym.ddr_init ; cache_v7_asm.S:141 mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr ;[3]
0xd002012c 08009fe5 ldr r0, [0xd002013c] ; cache_v7_asm.S:142 dsb st ; [0xd002013c:4]=0xe0200000
0xd0020130 08109fe5 ldr r1, [0xd0020140] ; cache_v7_asm.S:143 isb ; [0xd0020140:4]=0x22222222
0xd0020134 001080e5 str r1, [r0] ; cache_v7_asm.S:144 bx lr
0xd0020138 09f0a0e1 mov pc, sb ; cache_v7_asm.S:148 ARM( stmfd sp!, {r4-r5, r7, r9-r11, lr} )
0xd002009c 1b0000eb bl sym._main ; start.S:88 bl _main ;[3]
;-- _main
0xd0020118 2b0100eb bl sym.copy_bl2_to_ram ; cache_v7_asm.S:136 add r10, r10, #2 @ increment cache number ;[1]
;-- copy_bl2_to_ram:
0xd00205cc 0e32a0e3 mov r3, 0xe0000000 ; smdkv210.c:227 }
0xd00205d0 043093e5 ldr r3, [r3, 4]
0xd00205d4 73402de9 push {r0, r1, r4, r5, r6, lr} ; smdkv210.c:230 {
I've placed a while(1);
at the beginning of copy_bl2_to_ram() (boards/samsung/smdkv210
)and checked that the CPU gets there. Now to see if it goes on.
ill stop here since this is a complicated procedure. perhaps I can make up some function that initializes UART based on that assembly which was printing OK in the exynos uboot and add some printf debugging because the JTAG is still fucked.
Bulding u-boot with verbose mode on (show compiler command lines): make V=1
I pasted uart_asm_init from exynos' forks's lowlevel_init.S (board/samsung/smdkv210/
) into the S5PV210-master fork's lowlevel_init.S. Some defines needed to be fixed up, i did that.
There are two macros left, UART_UBRDIV_VAL
and UART_UDIVSLOT_VAL
. They are hardcoded in the exynos fork in include/configs/smdkv210.h
. Ive gotta calculate their values for the 24MHz clock on the mini210.
The contents of the exynos values are controlled by the clock config:
#if defined(CONFIG_CLK_533_133_100_100)
#define UART_UBRDIV_VAL 26
#define UART_UDIVSLOT_VAL 0x0808
#else
#define UART_UBRDIV_VAL 34
#define UART_UDIVSLOT_VAL 0xDDDD
#endif
The registers in lowlevel_init.S:uart_asm_init
are being set as follows:
UFCON = 0x0
UMCON = 0x0
ULCON = 0x3
UCON = 0x03c5 -> UCONn[10] = 0b0: PCLK is the clock source
UBRDIV = UART_UBRDIV_VAL
UDIVSLOT = UART_UDIVSLOT_VAL
What is PCLK? Seems to be some external clock. UART is in PSYS clock domain (Fig 3-1).
Lickily it's set in board/samsung/smdkv210/smdkv210.c:clock_init
The PSYS clock is set to MCLKPLL = FOUT_MPLL
,
FOUT_MPLL
= 667MHz (P = 12, M = 667, S = 1) in MPLL_CON0
FOUT = MDIV X FIN / (PDIV × 2^(SDIV-1) )
so for our case FOUT = 667 *FIN / 12 * 2^0, = FIN * 667/12 =~ 55.5833
PLL clock feeds are muxed between XXTI and XusbXTI, the mux is controlled by XOM[0] pin. XOM[0] = 0 -> PLLs fed from XXTI (Fig 3-3, page 361)
In our case XOM[0] = 0 according to schematic, and so it is on the PCB.
XXTI = 24MHz here, so this is the default, therefore MOUT_PSYS
= 667MHz. What is the PCLK then? it's MOUT_PSYS *1/DIV_HCLKP * 1/DIV_HCLKP
And according to comments PCLK_PSYS = 66MHz just like the default
What is the UART divider? page 879:
DIV_VAL = UBRDIVn + (num of 1's in UDIVSLOTn)/16
DIV_VAL = (PCLK / (bps x 16)) −1
So for 115200 bps we have to set DIV_VAL to 66e6 / (16*115200) -1 = 34.80 == 35
for UBRDIV = 34
and UDIVSLOT = 0xDDDD
we get
DIV_VAL = 34 + 12/16 = 34.75
, close enough. Within 1% actually.
So these are the values: UBRDIV = 34
and UDIVSLOT = 0xDDDD
.
I've called uart_asm_init from inside lowlevel_init and the board prints the 'O'. I then print 'k' from the end of copy_bl2_to_ram
:
*((volatile int*)(S5PV210_UART_BASE + 0x20 )) = 0x6b6b6b6b; // print k on uart 0
Now that UART works and so does copy_bl2_to_ram, we trace teh execution further. This is the end of SPL:
arch/arc/cpu/armv7/start.S: end of reset
-----------------------------------------------
/* the mask ROM code should have PLL and others stable */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_cp15
#ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY
bl cpu_init_crit
#endif
#endif
bl _main
arch/arm/lib/crt0.S:
----------------------------
ENTRY(_MAIN)
/* modied by Sourcelink */
#ifdef CONFIG_SPL_BUILD
bl copy_bl2_to_ram /* 拷贝BL2到DDR */ /* Copy BL2 to DDR */
ldr pc, =CONFIG_SYS_SDRAM_BASE /* 跳转到DDR的起始地址执行BL2 */ /* Jump to the starting address of DDR to execute BL2 */
#else
bl board_init_f
#endif
ifdef tells us that we will come back here again in the second stage, where board_init_f will be called.
For reference, this is the part in r2. r2 -aarm -b32 -B0xd0020000 spl/u-boot-spl
;-- cpu_init_crit:
┌─< 0xd0020108 020000ea b loc.lowlevel_init ; start.S:294 b lowlevel_init @ go setup pll,mux,memory
│ 0xd002010c 00000000 andeq r0, r0, r0 ; cache_v7_asm.S:132 bge inval_loop2
│ ;-- _main:
│ 0xd0020110 450100eb bl sym.copy_bl2_to_ram ; start.S:294 b lowlevel_init @ go setup pll,mux,memory ;[1]
│ 0xd0020114 02f2a0e3 mov pc, 0x20000000 ; cache_v7_asm.S:134 bge inval_loop1
│ ;-- lowlevel_init:
└─> 0xd0020118 0e90a0e1 mov sb, lr ; cache_v7_asm.S:136 add r10, r10, #2 @ increment cache number
0xd002011c 200000eb bl sym.clock_init ; cache_v7_asm.S:137 cmp r3, r10 ;[2]
0xd0020120 660000eb bl sym.ddr_init ; cache_v7_asm.S:138 bgt inval_levels ;[3]
0xd0020124 030000eb bl loc.uart_asm_init ; cache_v7_asm.S:140 mov r10, #0 @ swith back to cache level
0xd0020128 58009fe5 ldr r0, [0xd0020188] ; cache_v7_asm.S:141 mcr p15, 2, r10, c0, c0, 0 @ select curren
0xd002012c 58109fe5 ldr r1, [0xd002018c] ; cache_v7_asm.S:142 dsb st ; [0xd002018c:4]=0x22222222
0xd0020130 001080e5 str r1, [r0] ; cache_v7_asm.S:143 isb
0xd0020134 09f0a0e1 mov pc, sb ; cache_v7_asm.S:144 bx lr
I want to put a breakpoint here to check if the address actually contains runnable code. The jump is to CONFIG_SYS_SDRAM_BASE
which is 0x2000_0000
, and is where copy_bl2_to_ram
jumps, and it's also the u-boot second stage (./u-boot ELF) text base, but I want to check it anyway.
I put the loop in crt0.S:
#ifdef CONFIG_SPL_BUILD
bl copy_bl2_to_ram /* 拷贝BL2到DDR */ /* Copy BL2 to DDR */
loop: b loop /* mod polprog */
ldr pc, =CONFIG_SYS_SDRAM_BASE /* 跳转到DDR的起始地址执行BL2 */ /* Jump to the starting address of DDR to execute BL2 */
#else
bl board_init_f
#endif
(gdb) tar ext :3333
Remote debugging using :3333
0xd0020124 in ?? ()
(gdb) x/8i $pc
=> 0xd0020124: b 0xd0020124
0xd0020128: mov pc, #536870912 ; 0x20000000
The loop works. What is the memory at 0x2000_0000
? It's empty:
(gdb) x/16i 0x20000000
0x20000000: andeq r0, r0, r0
0x20000004: andeq r0, r0, r0
0x20000008: andeq r0, r0, r0
0x2000000c: andeq r0, r0, r0
0x20000010: andeq r0, r0, r0
0x20000014: andeq r0, r0, r0
0x20000018: andeq r0, r0, r0
0x2000001c: andeq r0, r0, r0
0x20000020: andeq r0, r0, r0
0x20000024: andeq r0, r0, r0
0x20000028: andeq r0, r0, r0
0x2000002c: andeq r0, r0, r0
0x20000030: andeq r0, r0, r0
0x20000034: andeq r0, r0, r0
0x20000038: andeq r0, r0, r0
0x2000003c: andeq r0, r0, r0
Just to make sure I'll dump with oocd...
> halt
MPIDR not in multiprocessor format
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x200001d3 pc: 0xd0020124
MMU: disabled, D-Cache: disabled, I-Cache: enabled
> mdw phys 0x20000000 64
0x20000000: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x20000020: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x20000040: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x20000060: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x20000080: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x200000a0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x200000c0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x200000e0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
Similarly it's full of zeros. But writing to it seems to work
> mww phys 0x20000000 0xebfffffe 1
> mdw phys 0x20000000 64
0x20000000: ebfffffe 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x20000020: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x20000040: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x20000060: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x20000080: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x200000a0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x200000c0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x200000e0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
And after restarting gdb for good measure I can read out the instruction
(gdb) x/4i 0x20000000
0x20000000: bl 0x20000000
0x20000004: andeq r0, r0, r0
0x20000008: andeq r0, r0, r0
0x2000000c: andeq r0, r0, r0
The chip can execute from ram correctly, which means the RAM works:
> resume 0x20000000
> halt
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x200001d3 pc: 0x20000000
MMU: disabled, D-Cache: disabled, I-Cache: enabled
There must be an issue with the BL2 copy routine then. I should debug that.
I decided to try and load the second stage via jtag.
> halt
MPIDR not in multiprocessor format
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x200001d3 pc: 0xd0020124
MMU: disabled, D-Cache: disabled, I-Cache: enabled
> load_image u-boot-2016.11/u-boot.bin 0x20000000 bin
299548 bytes written at address 0x20000000
downloaded 299548 bytes in 110.032898s (2.659 KiB/s)
> mdw phys 0x20000000 32
0x20000000: ea0000be e59ff014 e59ff014 e59ff014 e59ff014 e59ff014 e59ff014 e59ff014
0x20000020: 20000060 200000c0 20000120 20000180 200001e0 20000240 200002a0 deadbeef
0x20000040: 0badc0de e320f000 e320f000 e320f000 e320f000 e320f000 e320f000 e320f000
0x20000060: e51fd028 e58de000 e14fe000 e58de004 e3a0d013 e169f00d e1a0e00f e1b0f00e
The image is loaded
> resume 0x20000000
No signs of life, which means that it must break somewhere in BL2, maybe before setting up the console. The board resets, so there must be some crash happening, but it will take some time without a fully working debugger.
I think i can set breakpoints in openocd (see 10.09.23). Take a closer look at that.
Ive noticed that the BL2 u-boot still contains the mmu init code. This is because the start.S file in arch/arm/cpu/armv7/
was not differentiating between spl and non spl build. After some figthing i managed to get the makefile system to rebuild it when doing an SPL build - I've marked start.o as phony.
arch/arm/cpu/armv7/Makefile:
# start.S needs to be rebuilt every time, it is built once as SPL (-DCONFIG_BUILD_SPL)
# and once as BL2
extra-y := start.o
$(obj)/start.o: .FORCE
.FORCE:
I've moved the extra-y line from the top of the file to here to group all start.S-related declarations to one place.
This causes it to be compiled twice:
$ make -j24 V=1 | grep --color start.o
non-spl build (main u-boot build):
arm-linux-gcc -Wp,-MD,arch/arm/cpu/armv7/.start.o.d -nostdinc -isystem /opt/FriendlyARM/toolschain/4.5.1/lib/gcc/arm-none-linux-gnueabi/4.5.1/include -Iinclude -I./arch/arm/include -include ./include/linux/kconfig.h -D__KERNEL__ -D__UBOOT__ -D__ASSEMBLY__ -g -D__ARM__ -marm -mno-thumb-interwork -mabi=aapcs-linux -mword-relocations -fno-pic -ffunction-sections -fdata-sections -fno-common -ffixed-r9 -msoft-float -pipe -march=armv7-a -D__LINUX_ARM_ARCH__=7 -I./arch/arm/mach-s5pv210/include -c -o arch/arm/cpu/armv7/start.o arch/arm/cpu/armv7/start.S
spl build:
arm-linux-gcc -Wp,-MD,spl/arch/arm/cpu/armv7/.start.o.d -nostdinc -isystem /opt/FriendlyARM/toolschain/4.5.1/lib/gcc/arm-none-linux-gnueabi/4.5.1/include -Iinclude -I./arch/arm/include -include ./include/linux/kconfig.h -D__KERNEL__ -D__UBOOT__ -DCONFIG_SPL_BUILD -D__ASSEMBLY__ -g -D__ARM__ -marm -mno-thumb-interwork -mabi=aapcs-linux -ffunction-sections -fdata-sections -fno-common -ffixed-r9 -msoft-float -pipe -march=armv7-a -D__LINUX_ARM_ARCH__=7 -I./arch/arm/mach-s5pv210/include -c -o spl/arch/arm/cpu/armv7/start.o arch/arm/cpu/armv7/start.S
The difference is that in SPL build, -DCONFIG_SPL_BUILD
is set. This is correct.
Now to adjust start.S to only include the MMU and other init code only when building for SPL.
Current entire code from reset to _main:
/*************************************************************************
*
* Startup Code (reset vector)
*
* Do important init only if we don't start from memory!
* Setup memory and board specific bits prior to relocation.
* Relocate armboot to ram. Setup stack.
*
*************************************************************************/
.globl reset
.globl save_boot_params_ret
#ifdef CONFIG_ARMV7_LPAE
.global switch_to_hypervisor_ret
#endif
reset:
/* Allow the board to save important registers */
b save_boot_params
save_boot_params_ret:
#ifdef CONFIG_SPL_BUILD
#ifdef CONFIG_ARMV7_LPAE
/*
* check for Hypervisor support
*/
mrc p15, 0, r0, c0, c1, 1 @ read ID_PFR1
and r0, r0, #CPUID_ARM_VIRT_MASK @ mask virtualization bits
cmp r0, #(1 << CPUID_ARM_VIRT_SHIFT)
beq switch_to_hypervisor
switch_to_hypervisor_ret:
#endif
/*
* disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,
* except if in HYP mode already
*/
mrs r0, cpsr
and r1, r0, #0x1f @ mask mode bits
teq r1, #0x1a @ test for HYP mode
bicne r0, r0, #0x1f @ clear all mode bits
orrne r0, r0, #0x13 @ set SVC mode
orr r0, r0, #0xc0 @ disable FIQ and IRQ
msr cpsr,r0
/*
* Setup vector:
* (OMAP4 spl TEXT_BASE is not 32 byte aligned.
* Continue to use ROM code vector only in OMAP4 spl)
*/
#if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))
/* Set V=0 in CP15 SCTLR register - for VBAR to point to vector */
mrc p15, 0, r0, c1, c0, 0 @ Read CP15 SCTLR Register
bic r0, #CR_V @ V = 0
mcr p15, 0, r0, c1, c0, 0 @ Write CP15 SCTLR Register
/* Set vector address in CP15 VBAR register */
ldr r0, =_start
mcr p15, 0, r0, c12, c0, 0 @Set VBAR
#endif
/* the mask ROM code should have PLL and others stable */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_cp15
#ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY
bl cpu_init_crit
#endif //!defined(CONFIG_SKIP_LOWLEVEL_INIT)
#endif //!defined(CONFIG_SKIP_LOWLEVEL_INIT_ONLY)
#endif //defined(CONFIG_SPL_BUILD)
bl _main
Finally, the SPL (BL1) and BL2 have different start routines:
Now that we have a fixed u-boot BL2, which does not try to reinit the MMU, let's see if it works.
> load_image u-boot-2016.11/u-boot.bin 0x20000000 bin
299348 bytes written at address 0x20000000
downloaded 299348 bytes in 99.560585s (2.936 KiB/s)
> mdw 0x20000000 32
0x20000000: ea0000be e59ff014 e59ff014 e59ff014 e59ff014 e59ff014 e59ff014 e59ff014
0x20000020: 20000060 200000c0 20000120 20000180 200001e0 20000240 200002a0 deadbeef
0x20000040: 0badc0de e320f000 e320f000 e320f000 e320f000 e320f000 e320f000 e320f000
0x20000060: e51fd028 e58de000 e14fe000 e58de004 e3a0d013 e169f00d e1a0e00f e1b0f00e
> resume 0x20000000
> halt
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x600001d3 pc: 0x19ddc458
MMU: disabled, D-Cache: disabled, I-Cache: enabled
> mdw 0x19ddc458 128
0x19ddc458: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x19ddc478: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x19ddc498: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x19ddc4b8: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x19ddc4d8: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x19ddc4f8: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x19ddc518: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x19ddc538: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x19ddc558: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x19ddc578: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
$ rasm2 -aarm -b32 -d be0000ea # first insn at 0x2000_0000
b 0x300
Looks like something makes it jump into whatever is before the ram, below 0x2000_0000
is marked as 'reserved' in the memory map (despite that we can still read out the memory there, but we cannot write).
It seems that I will have to single step BL2 then. I've changed the JTAG speed to 3000kHz to make loading faster. it now takes 10s instead of 100s.
I can set breakpoints in oocd:
> load_image u-boot-2016.11/u-boot.bin 0x20000000 bin
299348 bytes written at address 0x20000000
downloaded 299348 bytes in 5.555160s (52.624 KiB/s)
> mdw 0x20000000 32
0x20000000: ea0000be e59ff014 e59ff014 e59ff014 e59ff014 e59ff014 e59ff014 e59ff014
0x20000020: 20000060 200000c0 20000120 20000180 200001e0 20000240 200002a0 deadbeef
0x20000040: 0badc0de e320f000 e320f000 e320f000 e320f000 e320f000 e320f000 e320f000
0x20000060: e51fd028 e58de000 e14fe000 e58de004 e3a0d013 e169f00d e1a0e00f e1b0f00e
> help bp
bp [<address> [<asid>] <length> ['hw'|'hw_ctx']]
list or set hardware or software breakpoint
rbp 'all' | address
remove breakpoint
> bp 0x20000300 1 hw
breakpoint set at 0x20000300
> resume 0x20000000
target halted in ARM state due to breakpoint, current mode: Supervisor
cpsr: 0x200001d3 pc: 0x20000300
MMU: disabled, D-Cache: disabled, I-Cache: enabled
0x20000300
is loc.reset
.
Now I will debug BL2 to see where it craps out.
Looks like the issue is early in board_init_f_alloc_reserve
``` cpsr: 0x200001d3 pc: 0x20000b40 MMU: disabled, D-Cache: disabled, I-Cache: enabled
step target halted in ARM state due to breakpoint, current mode: Supervisor cpsr: 0x200001d3 pc: 0x2000a194 MMU: disabled, D-Cache: disabled, I-Cache: enabled bp list bp [
[] ['hw'|'hw_ctx']] rbp 'all' | address rbp all bp 0x20000b44 1 breakpoint set at 0x20000b44 resume halt target halted in ARM state due to debug-request, current mode: Abort cpsr: 0x200001d7 pc: 0x00000010 MMU: disabled, D-Cache: disabled, I-Cache: enabled Data fault registers DFSR: 00001808, DFAR: eafffff8 Instruction fault registers IFSR: 00000000, IFAR: 00000000
```
At this point the sp is still in iROM/iRAM (sp (/32): 0xd0037888
), but this seems to be okay.
The following trace log goes ok:
main
board_init_f_alloc_reserve
board_init_f_init_reserve
memset
board_init_f common/board_f.c
initcall_run_list lib/initcall.c
* multitude of function, each can fail *
I traced it down to initcall_run_list which runs a list of function pointers.
The list of them is in common/board_f.c:847
.
I extracted the list:
offset func ptr function
0x2003bee8 0x2000c51c ... @ .text setup_mon_len,
0x2003beec 0x20028070 p.. @ .text fdtdec_setup,
0x2003bef0 0x20010e38 8.. @ .text initf_malloc,
0x2003bef4 0x2000c658 X.. @ .text initf_console_record,
0x2003bef8 0x2000062c ,.. @ .text arch_cpu_init,
0x2003befc 0x2000c53c <.. @ .text mach_cpu_init,
0x2003bf00 0x2000c770 p.. @ .text initf_dm,
0x2003bf04 0x2000c668 h.. @ .text arch_cpu_init_dm,
0x2003bf08 0x2000c75c \.. @ .text mark_bootstage,
0x2003bf0c 0x200007e4 ... @ .text timer_init,
0x2003bf10 0x2000e3c4 ... @ .text env_init,
0x2003bf14 0x2000c730 0.. @ .text init_baud_rate,
0x2003bf18 0x2001e52c ,.. @ .text serial_init,
0x2003bf1c 0x2000fbc0 ... @ .text console_init_f,
0x2003bf20 0x2002908c ... @ .text display_options,
0x2003bf24 0x2000c514 ... @ .text display_text_info,
0x2003bf28 0x200006a4 ... @ .text print_cpuinfo,
0x2003bf2c 0x2000ca8c ... @ .text show_board_info,
0x2003bf30 0x2000c718 ... @ .text announce_dram_init,
0x2003bf34 0x200016b4 ... @ .text dram_init,
0x2003bf38 0x2000c804 ... @ .text setup_dest_addr,
0x2003bf3c 0x2000c544 D.. @ .text reserve_round_4k,
0x2003bf40 0x2000c55c \.. @ .text reserve_mmu,
0x2003bf44 0x2000c594 ... @ .text reserve_trace,
0x2003bf48 0x2000c59c ... @ .text reserve_uboot,
0x2003bf4c 0x2000c5cc ... @ .text reserve_malloc,
0x2003bf50 0x2000c6e0 ... @ .text reserve_board,
0x2003bf54 0x2000c5e0 ... @ .text setup_machine,
0x2003bf58 0x2000c5e8 ... @ .text reserve_global_data,
0x2003bf5c 0x2000c604 ... @ .text reserve_fdt,
0x2003bf60 0x2000c660 `.. @ .text reserve_arch,
0x2003bf64 0x2000c854 T.. @ .text reserve_stacks,
0x2003bf68 0x2000c7dc ... @ .text setup_dram_config,
0x2003bf6c 0x2000c7a4 ... @ .text show_dram_config,
0x2003bf70 0x2000c650 P.. @ .text display_new_sp,
0x2003bf74 0x2000c6a4 ... @ .text reloc_fdt,
0x2003bf78 0x2000c670 p.. @ .text setup_reloc,
0x2003bf7c ..[ null bytes ].. 00000000
I set a breakpoint at the function pointer call, blx r0
at 0x20025e38
:
92: dbg.initcall_run_list (int32_t arg1);
│ ; arg int32_t arg1 @ r0
│ 0x20025e18 * f8402de9 push {r3, r4, r5, r6, r7, lr} ; smbios.c:305 } ; int initcall_r
│ 0x20025e1c 0060a0e1 mov r6, r0 ; initcall.c:14 { ; arg1
│ 0x20025e20 0050a0e1 mov r5, r0 ; initcall.c:39 return 0; ; arg1
│ ┌─< 0x20025e24 0d0000ea b 0x20025e60 ; initcall.c:17 for (init_fnc_ptr = i
│ │ ; CODE XREF from dbg.initcall_run_list @ 0x20025e6c(x)
│ ┌──> 0x20025e28 044099e5 ldr r4, [sb, 4] ; initcall.c:21 if (gd->flags & GD_F
│ ╎│ 0x20025e2c 014014e2 ands r4, r4, 1
│ ╎│ 0x20025e30 40409915 ldrne r4, [sb, 0x40] ; initcall.c:22 reloc_ofs = gd->rel
│ ╎│ 0x20025e34 043099e5 ldr r3, [sb, 4] ; initcall.c:27 if (gd->flags & GD_F
│ ╎│ 0x20025e38 30ff2fe1 blx r0 ; initcall.c:31 ret = (*init_fnc_ptr
│ ╎│ 0x20025e3c 003050e2 subs r3, r0, 0 ; initcall.c:32 if (ret) {
│ ┌───< 0x20025e40 0600000a beq 0x20025e60
│ │╎│ 0x20025e44 002097e5 ldr r2, [r7] ; initcall.c:33 printf("initcall se
│ │╎│ 0x20025e48 24009fe5 ldr r0, str.initcall_sequence__p_failed_at_call__p__err_d__n ;
│ │╎│ 0x20025e4c 0610a0e1 mov r1, r6
│ │╎│ 0x20025e50 022064e0 rsb r2, r4, r2
│ │╎│ 0x20025e54 d71500eb bl dbg.printf ;[1] ; int printf(const char *format)
│ │╎│ 0x20025e58 0000e0e3 mvn r0, 0 ; initcall.c:36 return -1;
│ │╎│ 0x20025e5c f880bde8 pop {r3, r4, r5, r6, r7, pc}
│ │╎│ ; CODE XREFS from dbg.initcall_run_list @ 0x20025e24(x), 0x20025e40(x)
│ └─└─> 0x20025e60 0570a0e1 mov r7, r5
│ ╎ 0x20025e64 040095e4 ldr r0, [r5], 4 ; initcall.c:17 for (init_fnc_ptr = i
│ ╎ 0x20025e68 000050e3 cmp r0, 0
│ └──< 0x20025e6c edffff1a bne 0x20025e28
└ 0x20025e70 f880bde8 pop {r3, r4, r5, r6, r7, pc} ; initcall.c:40 }
> bp 0x20025e38 1 hw
breakpoint set at 0x20025e38
> step
...
> resume
...
Now I can do step, resume (it will not resume on a breakpoint) every new function and examine r0 to see the next one to be executed:
> reg r0
r0 (/32): 0x2000c6a4
> step; resume;
target halted in ARM state due to breakpoint, current mode: Supervisor
cpsr: 0x600001d3 pc: 0x2000c6a4
MMU: disabled, D-Cache: disabled, I-Cache: enabled
target halted in ARM state due to breakpoint, current mode: Supervisor
cpsr: 0x600001d3 pc: 0x20025e38
MMU: disabled, D-Cache: disabled, I-Cache: enabled
> reg r0
r0 (/32): 0x2000c670
> step; resume;
target halted in ARM state due to breakpoint, current mode: Supervisor
cpsr: 0x600001d3 pc: 0x2000c670
MMU: disabled, D-Cache: disabled, I-Cache: enabled
The entire initcall_run_list goes through. Next is relocation, relocate.S:relocate_code
target halted in ARM state due to breakpoint, current mode: Supervisor
cpsr: 0x600001d3 pc: 0x20000bd0
MMU: disabled, D-Cache: disabled, I-Cache: enabled
> reg r1
r1 (/32): 0x20000000
> reg r0
r0 (/32): 0x3ff78000
>
r0 looks suspicious, its used to calculate the reloc offset. r0 is loaded from #GD_RELOCADDR
, that does not seem valid
0x20000b6c 400099e5 ldr r0, [sb, 0x40] ; crt0.S:119 ldr r0, [r9, #GD_RELOC_OFF] /* r0 = gd->reloc_off */
│ 0x20000b70 00e08ee0 add lr, lr, r0 ; crt0.S:120 add lr, lr, r0
│ 0x20000b74 2c0099e5 ldr r0, [sb, 0x2c] ; crt0.S:124 ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */
└ ┌─< 0x20000b78 130000ea b sym.relocate_code ; crt0.S:125 b relocate_code
┌ 24: sym.relocate_code (int32_t arg1);
│ ; arg int32_t arg1 @ r0
│ 0x20000bcc * 50109fe5 ldr r1, entry0 ; relocate.S:80 ldr r1, =__image_copy_start /* r1 <- SRC &__image_copy_
│ 0x20000bd0 014050e0 subs r4, r0, r1 ; relocate.S:81 subs r4, r0, r1 /* r4 <- relocation offset */ ; arg1
│ ┌─< 0x20000bd4 1100000a beq loc.relocate_done ; relocate.S:82 beq relocate_done /* skip relocation */
│ │ 0x20000bd8 48209fe5 ldr r2, loc.__bss_base ; relocate.S:83 ldr r2, =__image_copy_end /* r2 <- SRC &__image_copy_en
│ │ ;-- copy_loop:
│ │ ; CODE XREF from loc.copy_loop @ +0x10(x)
│ ┌──> 0x20000bdc feffffea b loc.copy_loop ; relocate.S:86 b copy_loop
╎│ 0x20000be0 000cb1e8 ldm r1!, {sl, fp} ; relocate.S:87 ldmia r1!, {r10-r11} /* copy from source address [r1]
╎│ 0x20000be4 000ca0e8 stm r0!, {sl, fp} ; relocate.S:88 stmia r0!, {r10-r11} /* copy to target address [r0]
╎│ 0x20000be8 020051e1 cmp r1, r2 ; relocate.S:89 cmp r1, r2 /* until source end address [r2] */
└──< 0x20000bec faffff3a blo loc.copy_loop ; relocate.S:90 blo copy_loop ; sym.relocate_code+0x10
│ 0x20000bf0 34209fe5 ldr r2, loc.__bss_base ; relocate.S:95 ldr r2, =__rel_dyn_start /* r2 <- SRC &__rel_dyn_start
│ 0x20000bf4 34309fe5 ldr r3, loc._image_binary_end ; relocate.S:96 ldr r3, =__rel_dyn_end /* r3 <- SRC &__rel_dyn_end */
│ ;-- fixloop:
│ ; CODE XREF from loc.fixnext @ +0x4(x)
┌──> 0x20000bf8 0300b2e8 ldm r2!, {r0, r1} ; relocate.S:98 ldmia r2!, {r0-r1} /* (r0,r1) <- (SRC location,fixup)
╎│ 0x20000bfc ff1001e2 and r1, r1, 0xff ; relocate.S:99 and r1, r1, #0xff
╎│ 0x20000c00 170051e3 cmp r1, 0x17 ; relocate.S:100 cmp r1, #23 /* relative fixup? */ ; 23
┌───< 0x20000c04 0300001a bne loc.fixnext ; relocate.S:101 bne fixnext
│╎│ 0x20000c08 040080e0 add r0, r0, r4 ; relocate.S:104 add r0, r0, r4
│╎│ 0x20000c0c 001090e5 ldr r1, [r0] ; relocate.S:105 ldr r1, [r0]
│╎│ 0x20000c10 041081e0 add r1, r1, r4 ; relocate.S:106 add r1, r1, r4
│╎│ 0x20000c14 001080e5 str r1, [r0] ; relocate.S:107 str r1, [r0]
│╎│ ;-- fixnext:
│╎│ ; CODE XREF from loc.fixloop @ +0xc(x)
└───> 0x20000c18 030052e1 cmp r2, r3 ; relocate.S:109 cmp r2, r3
└──< 0x20000c1c f5ffff3a blo loc.fixloop ; relocate.S:110 blo fixloop
│ │ ;-- relocate_done:
│ │ ; CODE XREF from sym.relocate_code @ 0x20000bd4(x)
└ └─> 0x20000c20 1eff2fe1 bx lr ; relocate.S:128 bx lr
at the loop entry r2 = 0x20041858
(no idea what this is, but looks valid). Let's let the loop run, set bp at 0x20000bf0
Why is 0x20000bdc jumping to itself? that will never end... that is in the original source code
Wait, why do I even relocate here? The code is already in RAM. It can run from there. Did I forget to adjust some macro, like GD_RELOCADDR
?
TODO: Fix the stack so its at top or RAM not in iRAM [probably fixed later, this is OK now]
TODO: Fix the reloc stuff, so it does not relocate (r1 must be == r2 at 20000bd0
) [not valid, it normally relocates]
It looks like the code is supposed to relocate, it moves itself by autogenerated constatn GD_REALOCADDR
(u-boot-2016.11/include/generated/generic-asm-offsets.h
) and then reruns the code.. Why is it doing that?
The relocation dest is computed by functions from common/board_f.c:board_init_f
(point 4a in arch/arm/lib/crt0.S
). gd.mon_len
os set to __bss_end
- _start
by setup_mon_len
.
At relocate_code
r0 = gd->relocaddr
is invalid (jtag shows it's 0x3ff78000
). This variable is set in common/board_f.c:setup_dest_addr
and is set to gd->ram_top
:
gd->relocaddr = gd->ram_top;
Given the contents of the init list, setup_dest_addr
is the only place where it's modified. So why is gd->ram_top
invalid? RAM top here is not there.
This is how gd->ram_top
is set and modified in setup_dest_addr
:
#ifdef CONFIG_SYS_SDRAM_BASE
gd->ram_top = CONFIG_SYS_SDRAM_BASE;
#endif
gd->ram_top += get_effective_memsize(); // get_effective_memsize just returns gd->ram_size
gd->ram_top = board_get_usable_ram_top(gd->mon_len); // checks for 4GB wraparound, returns gd->ram_top in most cases (our case)
Likely the error is here, in include/configs/s5pc210_universal.h:22
:
#define CONFIG_SYS_SDRAM_BASE 0x40000000
Our board has SDRAM at 0x2000_0000
. Maybe this is why the SPL fails to copy BL2 to 0x20000000?
TODO: fix that macro, test if r0
is OK at relocate_code
and remove the infinite loop.
u-boot BL2 starts on SD card at offset 16K + 1 sector, because we write u-boot-all.bin to sd card at offset 1 sector.. So BL2 actually gets loaded at 0x20000200.
After fixing the truncate call in the makefile it now works and BL2 boots from the SD card. It still breaks trying to jump to 0x0000000c.
GDB also works now, though still breakpoints do not (have to use hw breakpoints).
The infinite loop is still just before BL2 jump, so every reset the board stops there and waits for me to attach.
(gdb) tar ext :3333
Remote debugging using :3333
warning: remote target does not support file transfer, attempting to access files from local filesystem.
warning: Could not load shared library symbols for *.
Do you need "set solib-search-path" or "set sysroot"?
warning: Unable to find dynamic linker breakpoint function.
GDB will be unable to debug shared library initializers
and track explicitly loaded dynamic code.
0xd0020124 in ?? ()
(gdb) x/2i $pc
=> 0xd0020124: b 0xd0020124
0xd0020128: mov pc, #536870912 ; 0x20000000
(gdb) mon bp 0xd0020128 1 hw
breakpoint set at 0xd0020128
(gdb) mon resume 0xd0020128
target halted in ARM state due to breakpoint, current mode: Supervisor
cpsr: 0x200001d3 pc: 0xd0020128
MMU: disabled, D-Cache: disabled, I-Cache: enabled
(gdb)
The next issue is that the stack pointer is nonsense. It is set to 0x60000000:
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) in crt0.S
in include/configs/smdkv210.h:
#define CONFIG_SYS_SDRAM_BASE 0x20000000 /* modif by Sourcelink */
#define CONFIG_SYS_LOAD_ADDR CONFIG_SYS_SDRAM_BASE + 0x40000000 /* modied by Sourcelink */
#define CONFIG_SYS_INIT_SP_ADDR CONFIG_SYS_LOAD_ADDR /* modied by Sourcelink */
which is way after the ram ends and is actually in DRAM1 which is not existent (DRAM0 is up to 0x3fffffff). The boards have 512MB so that should be set to ram top.
This could be set to something small for now - the actual RAM size is determined by dram_init
(calls get_ram_size
)
I've stopped the program at 0x20000b38, just after sp was set to 0x60000000 and I set sp to 0x20100000 (1MB after ram start). Then I set a breakpoint at 0x20000b78 (just before reloc) and resumed the board.
It printed me the u-boot banner:
###############################
#### Ported by Sourcelink #######
#### Email: Sourcelink@126.com ##
###############################
U-Boot 2016.11 (Oct 08 2023 - 19:02:38 +0200) for SMDKV210
CPU : S5PV210@1000MHz
Model: Samsung SMDKV210 based on S5PV210
Board: SMDKV210
DRAM: 1 GiB
I've removed the infinite loop in the relocation loop. Now when i skip past the SPL infinite loop (only thing that makes the debugger work) the board boots up successfully to command prompt:
Ok
###############################
#### Ported by Sourcelink #######
#### Email: Sourcelink@126.com ##
###############################
U-Boot 2016.11 (Oct 08 2023 - 20:12:13 +0200) for SMDKV210
CPU : S5PV210@1000MHz
Model: Samsung SMDKV210 based on S5PV210
Board: SMDKV210
DRAM: 1 GiB
NAND: 1024 MiB
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
Net: dm9000
Warning: dm9000 (eth0) using random MAC address - 8a:31:8f:97:f2:e5
SMDKV210 # help
? - alias for 'help'
base - print or set address offset
bdinfo - print Board Info structure
boot - boot default, i.e., run 'bootcmd'
bootd - boot default, i.e., run 'bootcmd'
Some todos left (in roughly most to least important order):
mini210
board (they are in smdkv210
now) - done: . Changes are in $workdir/mini210/u-boot-2016.11-nowy
Next: Try to build vendor's linux and boot it up.
I've made a new copy of the sourcelink u-boot from my working directory (so not exactly clean, as it had my minor changes already) and started to port my changes to a new board "mini210".
Adding a new board to u-boot boils down to:
Create new files:
- board/friendlyarm/mini210/mini210.c
copied from board/samsung/smdkv210/smdkv210.c
- board/friendlyarm/mini210/Kconfig
copied from board/samsung/smdkv210/smdkv210.c
with respective changes
- board/friendlyarm/mini210/Makefile
copied from similar path above
- configs/mini210_defconfig
copied from configs/smdkv210_defconfig
- include/configs/mini210.h
copied from include/configs/smdkv210.h
Append source "board/friendlyarm/mini210/Kconfig"
to arch/arm/mach-s5pv210/Kconfig
Append
+ config TARGET_MINI210
+ bool "Support FriendlyArm mini210 board"
+ select OF_CONTROL
endchoice
to above mach-s5pv210/Kconfig.
See schulz' presentation for more details.
Todos done: port to a separate board: mini210_defconfig; upload to github.