Skip to content

Internals

Andrea Barisani edited this page Feb 6, 2025 · 124 revisions

Key concepts

  • 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.

Go language and library support

The GOOS=tamago target maintains full language and standard library support, see the following page for all compatibility notes:

Go distribution changes

  • 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.

Go runtime changes

Default memory layout (AMD64)

  +----------------------------------+ 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

Default memory layout (ARM)

  +----------------------------------+ 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

Direct memory access (DMA)

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.

Interrupts

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)
	}
}

Interrupts (AMD64)

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:

Interrupts (ARM)

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:

Board support packages

Processor support packages

Applications

External drivers

Clone this wiki locally