pi

package
v0.0.0-...-d73fcdd Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 7, 2022 License: BSD-3-Clause, BSD-3-Clause Imports: 4 Imported by: 0

README

TamaGo - bare metal Go for ARM SoCs - Raspberry Pi Support

tamago | https://github.com/f-secure-foundry/tamago

Copyright (c) the pi/pi2/pizero package authors

TamaGo gopher

Contributors

Kenneth Bell

Introduction

TamaGo is a framework that enables compilation and execution of unencumbered Go applications on bare metal ARM System-on-Chip (SoC) components.

The pi package provides support for the Raspberry Pi series of Single Board Computer.

Documentation

For more information about TamaGo see its repository and project wiki.

For the underlying driver support for this board see package bcm2835.

The package API documentation can be found on pkg.go.dev.

Supported hardware

SoC Board SoC package Board package
BCM2835 Pi Zero bcm2835 pi/pizero
BCM2835 Pi 1 Model A+ (v1.2) bcm2835 pi/pi1
BCM2835 Pi 1 Model B+ (v1.2) bcm2835 pi/pi1
BCM2836 Pi 2 Model B (v1.1) bcm2835 pi/pi2

Compiling

Go applications are simply required to import, the relevant board package to ensure that hardware initialization and runtime support takes place:

import (
    _ "github.com/f-secure-foundry/tamago/board/raspberrypi/pi2"
)

OR

import (
    _ "github.com/f-secure-foundry/tamago/board/raspberrypi/pi1"
)

OR

import (
    _ "github.com/f-secure-foundry/tamago/board/raspberrypi/pizero"
)

Build the TamaGo compiler (or use the latest binary release):

wget https://github.com/f-secure-foundry/tamago-go/archive/refs/tags/latest.zip
unzip latest.zip
cd tamago-go-latest/src && ./all.bash
cd ../bin && export TAMAGO=`pwd`/go

Go applications can be compiled as usual, using the compiler built in the previous step, but with the addition of the following flags/variables and ensuring that the required SoC and board packages are available in GOPATH:

GO_EXTLINK_ENABLED=0 CGO_ENABLED=0 GOOS=tamago GOARM=5 GOARCH=arm \
  ${TAMAGO} build -ldflags "-T 0x00010000  -E _rt0_arm_tamago -R 0x1000"

GOARM & Examples

The GOARM environment variable must be set according to the Raspberry Pi model:

Model GOARM Example
Zero 5 https://github.com/f-secure-foundry/tamago-example-pizero
1A+ 5 https://github.com/prusnak/tamago-example-pi1
1B+ 5 https://github.com/prusnak/tamago-example-pi1
2B 7 https://github.com/kenbell/tamago-example-pi2

NOTE: The Pi Zero and Pi 1 are ARMv6, but do not have support for all floating point instructions the Go compiler generates with GOARM=6. Using GOARM=5 causes Go to include a software floating point implementation.

Executing

There are two options for executing compiled binaries. The direct approach is to convert Go binaries to emulate the Linux boot protocol and have the Pi firmware load and execute the binary as a Linux kernel. The U-boot method enables ELF binaries to be loaded and executed directly.

In both cases a minimal set of Raspberry Pi firmware must be present on the SD card that initializes the Raspberry Pi using the VideoCore GPU. The following minimum files are required:

  • bootcode.bin
  • fixup.dat
  • start.elf

These files are available here.

Direct

Linux kernels are expected to have executable code as the first bytes of the binary. The Go compiler does not natively support creating such binaries, so a stub is generated and pre-pended that will jump to the Go entrypoint. In this way, the Linux boot protocol is satisfied.

The example projects (linked above) use the direct approach. The GNU cross-compiler toolchain is required. This method is in some ways more complex, but the Makefile code from the examples can be used as an example implementation.

  1. Build the Go ELF binary as normal
  2. Use objcopy from the GNU cross-compiler toolchain to convert the binary to 'bin' format
  3. Extract the entrypoint from the ELF format file
  4. Compile a stub that will jump to the real entrypoint
  5. Prepend the stub with sufficient padding for alignment
  6. Configure the Pi to treat the binary as the Linux kernel to load

In the examples, this code performs steps 1-5:

$(CROSS_COMPILE)objcopy -j .text -j .rodata -j .shstrtab -j .typelink \
    -j .itablink -j .gopclntab -j .go.buildinfo -j .noptrdata -j .data \
    -j .bss --set-section-flags .bss=alloc,load,contents \
    -j .noptrbss --set-section-flags .noptrbss=alloc,load,contents\
    $(APP) -O binary $(APP).o
${CROSS_COMPILE}gcc -D ENTRY_POINT=`${CROSS_COMPILE}readelf -e $(APP) | grep Entry | sed 's/.*\(0x[a-zA-Z0-9]*\).*/\1/'` -c boot.S -o boot.o
${CROSS_COMPILE}objcopy boot.o -O binary stub.o
# Truncate pads the stub out to correctly align the binary
# 32768 = 0x10000 (TEXT_START) - 0x8000 (Default kernel load address)
truncate -s 32768 stub.o
cat stub.o $(APP).o > $(APP).bin

The bootstrap code is something equivalent to this:

    .global _boot

    .text
_boot:
    LDR r1, addr
    BX r1

addr:
    .word ENTRY_POINT

Direct: Configuring the firmware

An example config.txt is:

enable_uart=1
uart_2ndstage=1
dtparam=uart0=on
kernel=example.bin
kernel_address=0x8000
disable_commandline_tags=1
core_freq=250

See http://rpf.io/configtxt for more configuration options.

NOTE: Do not be tempted to set the kernel address to 0x0:

  1. TamaGo places critical data-structures at RAMSTART
  2. The Pi firmware parks all but 1 CPU core in wait-loops, controlled by bytes starting at 0x000000CC (see https://github.com/raspberrypi/tools/blob/master/armstubs/armstub7.S)

Direct: Executing

Copy the binary and config.txt to an SD card alongside the Pi firmware binaries and power-up the Pi.

U-Boot

For the U-Boot method, configure, compile and copy U-Boot onto an existing Raspberry Pi bootable SD card (see above for minimum context of the card).

    cd u-boot

    # Config:
    # - use rpi_0_w_defconfig for Pi Zero
    # - use rpi_defconfig     for Pi 1
    # - use rpi_2_defconfig   for Pi 2
    make rpi_0_w_defconfig

    # Build
    make

    # Copy
    cp u-boot.bin <path_to_sdcard>

U-Boot: Configuring the firmware

The Raspberry Pi firmware must be configured to use U-Boot. Enabling the UART is recommended to diagnose boot issues.

These settings work well in config.txt:

enable_uart=1
uart_2ndstage=1
dtparam=uart0=on
kernel=u-boot.bin
core_freq=250

U-Boot: Executing

Copy the built ELF binary on an existing bootable Raspberry Pi SD card, then launch it from the U-Boot console as follows:

ext2load mmc 0:1 0x8000000 example
bootelf 0x8000000

For non-interactive execution modify the U-Boot configuration accordingly.

Debugging: Standard output

The standard output can be accessed through the UART pins on the Raspberry Pi. A 3.3v USB-to-serial cable, such as the Adafruit USB to TTL Serial Cable can be used. Any suitable terminal emulator can be used to access standard output.

The UART clock is based on the VPU clock in some Pi models, if the UART output appears corrupted, ensure the VPU clock frequency is fixed using core_freq=250 in config.txt.

NOTE: Go outputs 'LF' for newline, for best results use a terminal app capable of mapping 'LF' to 'CRLF' as-needed.

License

tamago | https://github.com/f-secure-foundry/tamago
Copyright (c) F-Secure Corporation

raspberrypi | https://github.com/f-secure-foundry/tamago/tree/master/board/raspberrypi
Copyright (c) the pi package authors

These source files are distributed under the BSD-style license found in the LICENSE file.

The TamaGo logo is adapted from the Go gopher designed by Renee French and licensed under the Creative Commons 3.0 Attributions license. Go Gopher vector illustration by Hugo Arganda.

Documentation

Overview

Package pi provides basic abstraction for support of different models of Raspberry Pi single board computers.

This package is only meant to be used with `GOOS=tamago GOARCH=arm` as supported by the TamaGo framework for bare metal Go on ARM SoCs, see https://github.com/f-secure-foundry/tamago.

Index

Constants

View Source
const (
	PM_BASE = 0x100000

	PM_RSTC = PM_BASE + 0x1c

	PM_WDOG          = PM_BASE + 0x24
	PM_WDOG_RESET    = 0000000000
	PM_WDOG_TIME_SET = 0x000fffff

	PM_PASSWORD              = 0x5a000000
	PM_RSTC_WRCFG_CLR        = 0xffffffcf
	PM_RSTC_WRCFG_SET        = 0x00000030
	PM_RSTC_WRCFG_FULL_RESET = 0x00000020
	PM_RSTC_RESET            = 0x00000102
)

Power Management, Reset controller and Watchdog registers

Variables

View Source
var Watchdog = &watchdog{}

Watchdog can automatically reset the board on lock-up.

A typical example might be to reset the board due to an OOM (Out-Of-Memory) condition. In Go out-of-memory is not recoverable, and halts the CPU - automatic reset of the board can be an appropriate action to take.

To use, start the watchdog with a timeout. Periodically call Reset from your logic (within the timeout). If you fail to call Reset within the timeout, the watchdog interrupt will fire, resetting the board.

Functions

This section is empty.

Types

type Board

type Board interface {
	LED(name string, on bool) (err error)
}

Board provides a basic abstraction over the different models of Pi.

Directories

Path Synopsis
Package pi1 provides hardware initialization, automatically on import, for the Raspberry Pi 1 single board computer.
Package pi1 provides hardware initialization, automatically on import, for the Raspberry Pi 1 single board computer.
Package pi2 provides hardware initialization, automatically on import, for the Raspberry Pi 2 single board computer.
Package pi2 provides hardware initialization, automatically on import, for the Raspberry Pi 2 single board computer.
Package pizero provides hardware initialization, automatically on import, for the Raspberry Pi Zero single board computer.
Package pizero provides hardware initialization, automatically on import, for the Raspberry Pi Zero single board computer.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL