-
Notifications
You must be signed in to change notification settings - Fork 55
Internals
-
Go applications built with TamaGo run on bare metal, without any underlying OS. All required support is provided by the Go runtime and driver packages, also written in Go.
-
When hardware initialization is provided (like in the imx6ul package), the compiled binaries can be directly executed by the processor, without any need for a 3rd party bootloader. This completely eliminates any non-Go dependency.
-
Due to its design TamaGo also allows user space execution.
The GOOS=tamago
target maintains full language and standard library support,
see the following page for all compatibility notes:
-
TamaGo modifications to the original Go distribution are minimal to ease maintainability and potential upstream acceptance.
-
TamaGo support is implemented with a clean separation from other OSes, all modifications are conditional to compilation option
GOOS=tamago
and do not affect other architectures.
-
Board support packages are required to define the following functions to support the runtime:
- cpuinit: pre-runtime CPU initialization
- runtime.hwinit: early runtime hardware initialization
- runtime.printk: standard output (e.g. serial console)
- runtime.initRNG and runtime.getRandomData: random number generation initialization and retrieval
- runtime.nanotime1: system time in nanoseconds
- runtime.ramStart, runtime.ramSize and runtime.ramStackOffset: RAM layout
-
The memory allocation is identical to plan9 with the exception of the brk call which is not required.
-
There is no support for threads, just like for Go js/wasm support, and locking is identical to js/wasm.
-
The only supported, and required, syscall is write which allows only stdout and stderr file descriptors.
-
The crypto/rand support is delegated to the supporting SoC driver, for example with the imx6ul packages support for the RNGB True Random Number Generator or amd64 use of RDRAND.
-
The file system support is identical to NaCl and provides a volatile in-memory emulated disk, the file descriptor support is therefore also identical to NaCl to support it.
-
Network I/O through Go own net package requires the application to set an external Socket function, see imx-enet or virtio-net for examples.
-
The testing environment for AMD64, ARM and RISCV64 architectures runs under Linux natively or using qemu-system-x86_64, qemu-system-arm and qemu-system-riscv64 via binfmt_misc respectively.
+----------------------------------+ 0x00000000
| |
| |
+----------------------------------+ 0x00009000
| |
| PAGE TABLES (16 kB) |
| |
+----------------------------------+ 0x0000d000
| |
| UNUSED |
| |
+----------------------------------+ runtime.ramStart + 0x10000 (64 kB)
| |
| .text |
| |
| .noptrdata |
| Go application |
| .data |
| |
| .bss |
| |
| .noptrbss |
| |
+----------------------------------+
| |
| HEAP |
| |
+----------------------------------+ runtime.g0.stack.lo (runtime.go.stack.hi - 0x10000)
| |
| STACK |
| |
+----------------------------------+ runtime.go.stack.hi (runtime.ramStart + runtime.ramSize - runtime.ramStackOffset)
| |
| UNUSED |
| |
+----------------------------------+ runtime.ramStart + runtime.ramSize
| |
| UNUSED |
| |
+----------------------------------+ 0xc0000000
| |
| UNCACHEABLE |
| |
+----------------------------------+ 0xffffffff
+----------------------------------+ 0x00000000
| |
| |
+----------------------------------+ runtime.ramStart (default for runtime.vecTableStart)
| |
| EXCEPTION VECTOR TABLE (16 kB) |
| |
+----------------------------------+ runtime.ramStart + 0x4000 (16 kB)
| |
| L1 PAGE TABLE (16 kB) |
| |
+----------------------------------+ runtime.ramStart + 0x8000 (32 kB)
| |
| EXCEPTION STACK (16 kB) |
| |
+----------------------------------+ runtime.ramStart + 0xC000 (48 kB)
| |
| L2 PAGE TABLE (16 kB) |
| |
+----------------------------------+ runtime.ramStart + 0x10000 (64 kB)
| |
| .text |
| |
| .noptrdata |
| Go application |
| .data |
| |
| .bss |
| |
| .noptrbss |
| |
+----------------------------------+
| |
| HEAP |
| |
+----------------------------------+ runtime.g0.stack.lo (runtime.go.stack.hi - 0x10000)
| |
| STACK |
| |
+----------------------------------+ runtime.go.stack.hi (runtime.ramStart + runtime.ramSize - runtime.ramStackOffset)
| |
| UNUSED |
| |
+----------------------------------+ runtime.ramStart + runtime.ramSize
| |
| |
+----------------------------------+ 0xffffffff
The dma provides primitives for direct memory allocation.
Such DMA areas can be defined outside Go runtime, to prevent any GC operation on it and allow its use for transfers with hardware peripherals.
+----------------------------------+ mem.dmaStart
| |
| DMA BUFFERS |
| |
+----------------------------------+ mem.dmaStart + mem.dmaSize
As an example the imx6ul package uses the 128KB On-Chip RAM (also known as iRAM) for DMA transfers.
Board packages and applications are free to
override
ramStart
and ramSize
as well as
re-initialize
DMA buffers if more space is required.
The handling of interrupts is
achieved by GOOS=tamago
specific runtime.WakeG
which implements a pure Go
assembly procedure to wake a sleeping goroutine.
In combination with runtime.GetG
, which obtains the current goroutine
pointer, this allows to park an arbitrary goroutine and asynchronously wake it
from an execution context outside the Go runtime, such as an interrupt service
routine (ISR) vector.
This enables the following pattern to implement ISRs:
func ServiceInterrupts(isr func(id int)) {
irqHandlerG, _ = runtime.GetG()
// irqHandlerG gets registered to be woken up by runtime.WakeG with
// architecture specific code, see tamago/{amd64|arm}/irq.{go|s}
for {
// re-enable interrupts after we get parked
go irq_enable()
// sleep indefinitely until woken up by runtime.WakeG
time.Sleep(math.MaxInt64)
// handle interrupts
isr(id)
}
}
On AMD/Intel 64-bit architecture interrupts are supported with the following helpers:
-
Package apic, provides a driver for Intel Local (LAPIC) and I/O (IOAPIC) Advanced Programmable Interrupt Controllers.
-
Function ServiceInterrupts, which allows registration of a goroutine as IRQ handler.
The following projects provide an example use of such helpers:
- VirtIO networking interrupt handling in tamago-example.
On the ARM architecture interrupts are supported with the following helpers:
-
Package gic, provides a driver for the ARM Generic Interrupt Controller.
-
Function ServiceInterrupts, allows registration of a goroutine as IRQ handler.
-
Peripheral drivers functions to enable specific controller IRQs as needed, such as NXP ENET Ethernet driver.
The following projects provide an example use of such helpers:
-
Ethernet and USB interrupt handling in tamago-example.
-
TrustZone Watchdog enabling, and servicing in GoTEE-example.
- USB armory: usbarmory
- MCIMX6ULL-EVK: mx6ullevk
- Raspberry Pi: pi
- SiFive Unleashed: sifive_u
- QEMU microvm: qemu/microvm
- Firecracker microvm: firecracker/microvm