USB Armory MkII Tutorial 4

6 minute read

Published:

How to Use USB Armory Mk II (Part 4: GoTEE + Bear Metal Execution + Cache management)

Build GoTEE

export TARGET=usbarmory

# Update TamaGo Dependencies
# Try updating the TamaGo module to the latest version:
cd GoTEE-example/nonsecure_os_go
go get -u github.com/usbarmory/tamago@latest
go mod tidy
cd ..


make nonsecure_os_go
make trusted_applet_go
make trusted_os

Unplug and replug usbarmoy

cd ~/Desktop/GoTEE-example/bin
sudo $HOME/go/bin/armory-boot-usb -i trusted_os_usbarmory.imx

Bring up the USB network on your host

# find the new interface (often usb0 or an enx* name)
ip link


# result
# USB-Ethernet gadget is enx1a5589a26942 (that’s the typical “enx…” name Linux gives to USB NICs
enx1a5589a26942: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN mode DEFAULT group default qlen 1000
    link/ether 1a:55:89:a2:69:42 brd ff:ff:ff:ff:ff:ff
# pick the USB NIC
IF=enx1a5589a26942

# clean slate + set your host IP
sudo ip addr flush dev $IF
sudo ip addr add 10.0.0.2/24 dev $IF
sudo ip link set $IF up

# quick check
ip addr show dev $IF
ping -c 3 10.0.0.1

If ping works, SSH in:

ssh gotee@10.0.0.1

ssh issue

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256:MNlLQ8Py8VcK4h3RxDwak2BFxDO6asF9vFY2CY8fPdA.
Please contact your system administrator.
Add correct host key in /home/lizeren/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /home/lizeren/.ssh/known_hosts:8
  remove with:
  ssh-keygen -f "/home/lizeren/.ssh/known_hosts" -R "10.0.0.1"
Host key for 10.0.0.1 has changed and you have requested strict checking.
Host key verification failed.

GoTEE unikernel generates a new SSH host key each time you boot it, so it no longer matches the one stored from a previous session.

You can safely remove the old key and reconnect:

ssh-keygen -f "/home/lizeren/.ssh/known_hosts" -R "10.0.0.1"

Then try again:

ssh gotee@10.0.0.1

Go application: Cache + Performance Counter

add this code to nonsecure_os_go/ and named it cache_timer.go

//go:build tamago && arm

package main

import (
    "github.com/usbarmory/tamago/arm"
)

func CacheTimerDemo() {
    cpu := arm.CPU{}
    cpu.EnableSMP()
    cpu.EnableCache()
    cpu.InitGenericTimers(0, 0)

    start := cpu.Counter()
    for i := 0; i < 1_000_000; i++ {}
    end := cpu.Counter()

    cpu.FlushDataCache()
    cpu.FlushInstructionCache()
    println("Cycle counter delta:", end-start)
}

now rebuild the GoTEE

cd GoTEE-example


export TARGET=usbarmory
make nonsecure_os_go
make trusted_applet_go
make trusted_os
#don't forget to unplug and replug the USB Armory
sudo $HOME/go/bin/armory-boot-usb -i bin/trusted_os_usbarmory.imx

# pick the USB NIC
IF=enx1a5589a26942

# clean slate + set your host IP
sudo ip addr flush dev $IF
sudo ip addr add 10.0.0.2/24 dev $IF
sudo ip link set $IF up

ssh-keygen -f "/home/lizeren/.ssh/known_hosts" -R "10.0.0.1"
ssh gotee@10.0.0.1

Now inside the GoTEE command shell, run

gotee						 # TrustZone example w/ TamaGo unikernels

Yuo should see the performance counter output.

Cycle counter delta: 35560

Examine cache disable

//go:build tamago && arm

package gotee

import (
	"log"
	"github.com/usbarmory/tamago/arm"
)

func CacheTimerDemo() {
	cpu := arm.CPU{}
	cpu.EnableSMP()
	cpu.EnableCache()
	cpu.InitGenericTimers(0, 0)

	// Create a memory array to access
	const arraySize = 1000
	data := make([]uint32, arraySize)
	
	// Initialize the array
	for i := 0; i < arraySize; i++ {
		data[i] = uint32(i)
	}

	// ===== Measure WITH cache enabled =====
	log.Println("=== Testing WITH cache enabled ===")
	
	start := cpu.Counter()
	var sum uint32
	for i := 0; i < 10000; i++ {
		sum += data[i%arraySize]  // Memory access
	}
	end := cpu.Counter()
	
	cyclesWithCache := end - start
	log.Println("Cycles WITH cache:", cyclesWithCache)
	log.Println("Sum (to prevent optimization):", sum)

	// ===== Disable cache and flush =====
	log.Println("\n=== Disabling cache ===")
	cpu.FlushDataCache()
	cpu.FlushInstructionCache()
	cpu.DisableCache()
	log.Println("Cache disabled")

	// ===== Measure WITHOUT cache =====
	log.Println("\n=== Testing WITHOUT cache ===")
	
	start = cpu.Counter()
	sum = 0
	for i := 0; i < 10000; i++ {
		sum += data[i%arraySize]  // Same memory access pattern
	}
	end = cpu.Counter()
	
	cyclesWithoutCache := end - start
	log.Println("Cycles WITHOUT cache:", cyclesWithoutCache)
	log.Println("Sum (to prevent optimization):", sum)

	// ===== Compare results =====
	log.Println("\n=== Comparison ===")
	log.Println("Cycles WITH cache:   ", cyclesWithCache)
	log.Println("Cycles WITHOUT cache:", cyclesWithoutCache)
	if cyclesWithoutCache > cyclesWithCache {
		slowdown := float64(cyclesWithoutCache) / float64(cyclesWithCache)
		log.Printf("Cache disabled is %.2fx slower\n", slowdown)
	}

	// Get CPU mode
	mode := cpu.Mode()
	log.Println("CPU current mode is:", mode)
}

Flush + Reload

https://github.com/lizeren/usbarmory-gotee/blob/main/trusted_os_usbarmory/internal/cache_timer.go