summaryrefslogtreecommitdiff
path: root/md/writeup/raspberry5_baremetal_helloworld.md
blob: 6d31ca60dc4af113b48538f81b0828029e68c4ce (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
title: Raspberry 5 baremetal Hello World example
keywords:raspi5,asm,c,kernel,arm64

# Raspberry 5 baremetal Hello World example

## Intro

Here is base example that will allow to print out message to serial console,
and debug application. This example is picked up from variouse resources to
make easy start into baremetal programming for raspi5, similar route is for
all other models. All commands are tested from raspi4, adjust sources 
for your system. 

## Source code

### boot.S

```
.section ".text.boot"

.global _start

_start:
    // read cpu id, stop slave cores
    mrs     x1, mpidr_el1
    and     x1, x1, #3
    cbz     x1, 2f
    // cpu id > 0, stop
1:  wfe
    b       1b
2:  // cpu id == 0

    // set top of stack just before our code (stack grows to a lower address per AAPCS64)
    ldr     x1, =_start
    mov     sp, x1

    // clear bss
    ldr     x1, =__bss_start
    ldr     w2, =__bss_size
3:  cbz     w2, 4f
    str     xzr, [x1], #8
    sub     w2, w2, #1
    cbnz    w2, 3b

    // jump to C code, should not return
4:  bl      main
    // for failsafe, halt this core too
    b       1b

```

### kernel.c

```c
void main()
{
	while (1) {

	}
}
```

### Makefile
```Makefile
TOOLCHAIN=aarch64-linux-gnu-
AS = ${TOOLCHAIN}as
LD = ${TOOLCHAIN}ld
SRCS = $(wildcard *.c)
OBJS = $(SRCS:.c=.o)
CFLAGS = -Wall -O2 -ffreestanding
CC=$(TOOLCHAIN)gcc

all: clean kernel8.img

boot.o: boot.S
	${CC} ${CFLAGS} -c boot.S -o boot.o 

%.o: %.c
	${CC} ${CFLAGS} -c $< -o $@

kernel8.img: boot.o ${OBJS}
	${LD} boot.o ${OBJS} -T linker.ld -o kernel8.elf
	${TOOLCHAIN}objcopy -O binary kernel8.elf kernel8.img

clean:
	rm -rf *.o *.img *.elf
```


### linker.ld
```ld
SECTIONS
{
    . = 0x80000;     /* Kernel load address for AArch64 */
    .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) }
    .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) }
    PROVIDE(_data = .);
    .data : { *(.data .data.* .gnu.linkonce.d*) }
    .bss (NOLOAD) : {
        . = ALIGN(16);
        __bss_start = .;
        *(.bss .bss.*)
        *(COMMON)
        __bss_end = .;
    }
    _end = .;

   /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) }
}
__bss_size = (__bss_end - __bss_start)>>3;
```

### config.txt
```
arm_64bit=1
kernel=kernel8.img
enable_jtag_gpio=1
```

### Compile source code
```sh
make
```

### Prepare for a boot

Create usual distro of your like. 
Mount sdcard and backup original configs and original kernel. 

```sh
cd /mnt/dir
cp config.txt config.txt.bkp
cp kernel8.img kernel8.img.original
```

Copy kerne8.img and config.txt

```sh
cp /project/dir/config.txt /mnt/dir
cp /project/dir/kernel8.img /mnt/dir
```


## Debugging with OpenOCD+GDB

The default openocd doesn't configration for raspi5.

### OpenOCD config for bcm2712.cfg

If OpenOCD doesn't have the raspi5 config by default here is one 
that suppose to work. Copy it for example in default openocd script location in:

```
/usr/share/openocd/scripts/target/
```


```tcl
# SPDX-License-Identifier: GPL-2.0-or-later

# The Broadcom BCM2712 used in Raspberry Pi 5
# No documentation was found on Broadcom website

# Partial information is available in Raspberry Pi website:
# https://www.raspberrypi.com/documentation/computers/processors.html#bcm2712

# v1.0 initial revision - trejan on forums.raspberrypi.com

if { [info exists CHIPNAME] } {
        set  _CHIPNAME $CHIPNAME
} else {
        set  _CHIPNAME bcm2712
}

if { [info exists CHIPCORES] } {
        set _cores $CHIPCORES
} else {
        set _cores 4
}

if { [info exists USE_SMP] } {
        set _USE_SMP $USE_SMP
} else {
        set _USE_SMP 0
}

if { [info exists DAP_TAPID] } {
        set _DAP_TAPID $DAP_TAPID
} else {
        set _DAP_TAPID 0x4ba00477
}

transport select swd

swd newdap $_CHIPNAME cpu -expected-id $_DAP_TAPID -irlen 4
adapter speed 4000

dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu

# MEM-AP for direct access
target create $_CHIPNAME.ap mem_ap -dap $_CHIPNAME.dap -ap-num 0

# these addresses are obtained from the ROM table via 'dap info 0' command
set _DBGBASE {0x80010000 0x80110000 0x80210000 0x80310000}
set _CTIBASE {0x80020000 0x80120000 0x80220000 0x80320000}

set _smp_command "target smp"

for { set _core 0 } { $_core < $_cores } { incr _core } {
        set _CTINAME $_CHIPNAME.cti$_core
        set _TARGETNAME $_CHIPNAME.cpu$_core

        cti create $_CTINAME -dap $_CHIPNAME.dap -ap-num 0 -baseaddr [lindex $_CTIBASE $_core]
        target create $_TARGETNAME aarch64 -dap $_CHIPNAME.dap -ap-num 0 -dbgbase [lindex $_DBGBASE $_core] -cti $_CTINAME

        set _smp_command "$_smp_command $_TARGETNAME"
}

if {$_USE_SMP} {
        eval $_smp_command
}

# default target is cpu0
targets $_CHIPNAME.cpu0
```

Connecting pico probe and doint step by step analysis of basic loop

### Running OpenOCD 

Start openocd server

```sh
openocd -f interface/cmsis-dap.cfg -f target/bcm2712.cfg
```

Start gdb or gdb-multiarch

```sh
gdb
```

Restart the raspi5 with prepared files on sdcard

and run inside gdb shell

```sh
tar ext :3333
```

 you should be connected to the openocd jtag session now press Ctrl+C

## Links

https://www.raspberrypi.com/documentation/computers/config_txt.html  
https://wiki.osdev.org/Raspberry_Pi_Bare_Bones  
https://www.rpi4os.com/part1-bootstrapping/  
https://www.valvers.com/open-software/raspberry-pi/bare-metal-programming-in-c-part-1/  
https://www.raspberrypi.com/documentation/microcontrollers/debug-probe.html  
https://macoy.me/blog/programming/RaspberryPi5Debugging  
https://gist.github.com/tnishinaga/219122a5f1e3973668ee78c0fb1c7bf9  
https://forums.raspberrypi.com/viewtopic.php?p=2172522#p2172522  
https://github.com/DSERIOUSGUY/HobOS  
https://developer.arm.com/documentation/ka006096/latest/  
https://github.com/raspberrypi/firmware  
https://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_mono/ld.html#SEC6