Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rpi3 baremetal #3

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions rpi3/00_simple/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
kernel8.*
.gdbinit
*.o
15 changes: 15 additions & 0 deletions rpi3/00_simple/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#
# Simplest bootloader example (prints hello world on serial port, UART0, then echos what you type at it)
#

all: clean kernel8.elf

# note the target is rpi3_bl in this directory
kernel8.elf: simple.go rpi3_bl.o
tinygo build --target=rpi3_bl -target 'rpi3_bl.json' -ldflags 'rpi3_bl.o' -o kernel8.elf .

rpi3_bl.o: rpi3_bl.S
clang --target=aarch64-elf -c rpi3_bl.S

clean:
rm kernel8.elf kernel8.img *.o >/dev/null 2>/dev/null || true
5 changes: 5 additions & 0 deletions rpi3/00_simple/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module interrupts

go 1.11

require github.com/tinygo-org/tinygo v0.7.1 // indirect
16 changes: 16 additions & 0 deletions rpi3/00_simple/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 h1:oMCHnXa6CCCafdPDbMh/lWRhRByN0VFLvv+g+ayx1SI=
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/marcinbor85/gohex v0.0.0-20180128172054-7a43cd876e46 h1:wXG2bA8fO7Vv7lLk2PihFMTqmbT173Tje39oKzQ50Mo=
github.com/marcinbor85/gohex v0.0.0-20180128172054-7a43cd876e46/go.mod h1:Pb6XcsXyropB9LNHhnqaknG/vEwYztLkQzVCHv8sQ3M=
github.com/tinygo-org/tinygo v0.7.1 h1:DbKW4LglJLr9L3zykwFkUR/974mVwZEtnSeOzUsslRQ=
github.com/tinygo-org/tinygo v0.7.1/go.mod h1:lw4bWjN/+Nm/9ypTo6BgAlYNLS9GrpP7Rw5g0bWAwew=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190227180812-8dcc6e70cdef h1:ymc9FeDom3RIEA3coKokSllBB1hRcMT0tZ1W3Jf9Ids=
golang.org/x/tools v0.0.0-20190227180812-8dcc6e70cdef/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
tinygo.org/x/go-llvm v0.0.0-20190224120431-7707ae5d1261 h1:rJS2Hga39YAnm7DE4qrPm6Dr/67EOojL0XPzvbEeBiw=
tinygo.org/x/go-llvm v0.0.0-20190224120431-7707ae5d1261/go.mod h1:fv1F0BSNpxMfCL0zF3M4OPFbgYHnhtB6ST0HvUtu/LE=
69 changes: 69 additions & 0 deletions rpi3/00_simple/rpi3_bl.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
.section ".text.boot_bl"

//
// The bootloader changes execution state for bootloaded code to EL2 if that is
// needed. This is after execution switches to the bootloaded code, and it drops
// to EL1 once the stack is setup ok.
//

// startup parameters are:
// x0 - start address (also in PC)
// x1 - stack ptr
// x2 - heap ptr
// x3 - unix time
.global _start
//set the sp for el1, but we have to have the fp space so subtract 16 (two 64bit ptr)
sub x1,x1,#16
msr sp_el1, x1


// enable CNTP for EL1
mrs x27, cnthctl_el2
orr x27, x27, #3
msr cnthctl_el2, x27
msr cntvoff_el2, xzr

// enable AArch64 in EL1
mov x27, #(1 << 31) // AArch64
orr x27, x27, #(1 << 1) // SWIO hardwired on Pi3
msr hcr_el2, x27
mrs x27, hcr_el2

// system control register
mov x4, #0x0800
movk x4, #0x30d0, lsl #16
msr sctlr_el1, x4

//insert default vectors for core 0
ldr x27, =vectors
msr vbar_el1, x27

// change execution level to EL1
mov x27, #0x3c5 //5! not 4! we have our own stack
msr spsr_el2, x27
adr x27, 1f
msr elr_el2, x27
eret

## getting the stack and fp in order, we subtracted 16 from x1 earlier in bootloader
## note that we store 0 for the link and ret values because we are at the
## bottom of the stack and want stack to correctly show in GDB and similar
1:
# fp to bottom of frame
add x27, x1, #16
mov x29, x27

#shove values in based on top of stack
str xzr, [sp, #8]
str xzr, [sp, #16]

//sp points to top of stack (for Bootloaded code 0x30000 - 0x20)
//fp points to bottom (x29) (for Bootloaded code 0x30000 - 0x10)

//tell hardware that EL0 has own stack
//msr SPSel, #1

// jump to go code
bl mainFromBootloader
// for failsafe, halt this core too
wfe
4 changes: 4 additions & 0 deletions rpi3/00_simple/rpi3_bl.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"inherits": ["rpi3"],
"linkerscript": "rpi3_bl.ld"
}
19 changes: 19 additions & 0 deletions rpi3/00_simple/rpi3_bl.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
SECTIONS
{
. = 0x10000;
.text : { KEEP(*(.text.boot_bl)) *(.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*) *(.text.boot)}
}
__bss_size = (__bss_end - __bss_start)>>3;
13 changes: 13 additions & 0 deletions rpi3/00_simple/simple.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package main

import (
dev "device/rpi3"
)

func main() {
print("hello world!\nechoing what you type\n")
for {
c := dev.UART0Getc()
dev.UART0Send(c)
}
}
2 changes: 2 additions & 0 deletions rpi3/01_blinker/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
kernel8.*
*.o
15 changes: 15 additions & 0 deletions rpi3/01_blinker/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#
# Use interrupts to blink the light on the RPI3.
#

all: clean kernel8.elf

# note the target is rpi3_bl in this directory
kernel8.elf: clean rpi3_bl.o
tinygo build --target=rpi3_bl.json -target 'rpi3_bl.json' -ldflags 'rpi3_bl.o' -o kernel8.elf .

rpi3_bl.o: rpi3_bl.S
clang --target=aarch64-elf -c rpi3_bl.S

clean:
rm kernel8.elf kernel8.img *.o >/dev/null 2>/dev/null || true
38 changes: 38 additions & 0 deletions rpi3/01_blinker/blinker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package main

import (
dev "device/rpi3"
)

var on = false
var interval uint32

// it's more than a little unclear that the values passed to this
// interrupt handler are ever going to be useful
func blinker(_ uint32, _ uint64) uint32 {
dev.LEDSet(on)
on = !on
print("set LED to ", on, "\n")
return interval
}

func main() {
hi, lo := dev.GetRPIID()
if hi == 0 && lo == 0 {
print("you are running on QEMU so you aren't going to see any lights blinking...\n")
}

freq := dev.CounterFreq() //getting my freq on
print("frequency per second is:")
dev.UART0Hex(freq) //this number is number of ticks/sec

//sets the timer for N secs, where N is multiplier
interval = 1 * freq
dev.SetCounterTargetInterval(interval, blinker)
dev.Core0CounterToCore0Irq()
dev.EnableCounter()
dev.EnableTimerIRQ()
for {
dev.WaitForInterrupt()
}
}
69 changes: 69 additions & 0 deletions rpi3/01_blinker/rpi3_bl.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
.section ".text.boot_bl"

//
// The bootloader changes execution state for bootloaded code to EL2 if that is
// needed. This is after execution switches to the bootloaded code, and it drops
// to EL1 once the stack is setup ok.
//

// startup parameters are:
// x0 - start address (also in PC)
// x1 - stack ptr
// x2 - heap ptr
// x3 - unix time
.global _start
//set the sp for el1, but we have to have the fp space so subtract 16 (two 64bit ptr)
sub x1,x1,#16
msr sp_el1, x1


// enable CNTP for EL1
mrs x27, cnthctl_el2
orr x27, x27, #3
msr cnthctl_el2, x27
msr cntvoff_el2, xzr

// enable AArch64 in EL1
mov x27, #(1 << 31) // AArch64
orr x27, x27, #(1 << 1) // SWIO hardwired on Pi3
msr hcr_el2, x27
mrs x27, hcr_el2

// system control register
mov x4, #0x0800
movk x4, #0x30d0, lsl #16
msr sctlr_el1, x4

//insert default vectors for core 0
ldr x27, =vectors
msr vbar_el1, x27

// change execution level to EL1
mov x27, #0x3c5 //5! not 4! we have our own stack
msr spsr_el2, x27
adr x27, 1f
msr elr_el2, x27
eret

## getting the stack and fp in order, we subtracted 16 from x1 earlier in bootloader
## note that we store 0 for the link and ret values because we are at the
## bottom of the stack and want stack to correctly show in GDB and similar
1:
# fp to bottom of frame
add x27, x1, #16
mov x29, x27

#shove values in based on top of stack
str xzr, [sp, #8]
str xzr, [sp, #16]

//sp points to top of stack (for Bootloaded code 0x30000 - 0x20)
//fp points to bottom (x29) (for Bootloaded code 0x30000 - 0x10)

//tell hardware that EL0 has own stack
//msr SPSel, #1

// jump to go code
bl mainFromBootloader
// for failsafe, halt this core too
wfe
4 changes: 4 additions & 0 deletions rpi3/01_blinker/rpi3_bl.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"inherits": ["rpi3"],
"linkerscript": "rpi3_bl.ld"
}
19 changes: 19 additions & 0 deletions rpi3/01_blinker/rpi3_bl.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
SECTIONS
{
. = 0x10000;
.text : { KEEP(*(.text.boot_bl)) *(.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*) *(.text.boot)}
}
__bss_size = (__bss_end - __bss_start)>>3;
2 changes: 2 additions & 0 deletions rpi3/02_delays/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
kernel8.*
*.o
15 changes: 15 additions & 0 deletions rpi3/02_delays/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#
# Use the bootloader to test our delays.
#

all: clean kernel8.elf

# note the target is rpi3_bl in this directory
kernel8.elf: rpi3_bl.o
tinygo build -target 'rpi3_bl.json' -ldflags 'rpi3_bl.o' -no-debug -o kernel8.elf .

rpi3_bl.o: rpi3_bl.S
clang --target=aarch64-elf -c rpi3_bl.S

clean:
rm kernel8.elf kernel8.img *.o >/dev/null 2>/dev/null || true
51 changes: 51 additions & 0 deletions rpi3/02_delays/delays.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package main

import (
dev "device/rpi3"
)

var interval uint32

// not sure how useful the current value is, but the virtual timer should
// have increased by exactly interval (or very close to it)
// return the amount of time to wait for the next call to this callback
// return 0 if you don't want it anymore
func myHandler(current uint32, virtualTimer uint64) uint32 {
print("my handler, current: ")
dev.UART0Hex(current)
print("my handler, virtual timer: ")
dev.UART0Hex64(virtualTimer)
return interval
}

func main() {
dev.UART0TimeDateString(dev.Now())
print("\n")
testDelays()
// dev.BComTimerInit(interval)
// dev.EnableInterruptController()
// dev.EnableTimerIRQ()
//
// for {
// dev.WaitForInterrupt()
// }
dev.Abort()
}

func testDelays() {
print("Waiting 3000000 CPU cycles (ARM CPU): ")
dev.WaitCycles(3000000)
print("OK\n")

print("Waiting 3000000 microsec (ARM CPU): ")
dev.WaitMuSec(3000000)
print("OK\n")

print("Waiting 3000000 microsec (BCM System Timer): ")
if dev.SysTimer() == 0 {
print("Not available\n")
} else {
dev.WaitMuSecST(3000000)
print("OK\n")
}
}
Loading