diff --git a/.dagger/main.go b/.dagger/main.go
index 1359f9d..c16adae 100644
--- a/.dagger/main.go
+++ b/.dagger/main.go
@@ -1,39 +1,34 @@
// Dagger CI module for Cairn — the Kyanite baseboard-management software stack.
//
-// Builds use a single StageX image (reproducible, minimal) that provides the Go
-// toolchain. The Go runtime is cross-compiled with the TamaGo compiler
-// (GOOS=tamago GOARCH=arm64). The ASPEED AST2700 arm64 SoC/board support lives
-// in a TamaGo fork that is not yet upstream, so the fork and the tamago-go
-// compiler are passed in as directories and wired up with an in-container
-// go.work alongside the shared core module.
+// Builds use a single StageX image (reproducible, minimal). The Go runtime is
+// cross-compiled with the TamaGo compiler (GOOS=tamago GOARCH=arm64), installed
+// in-container from the upstream tamago-go release. The ASPEED AST2700 SoC/board
+// support and the other Kyanite modules are fetched from public GitHub and wired
+// up with an in-container go.work; every source directory defaults to its
+// kyanitecomputer repository, so the whole flow builds from public sources with
+// no local checkouts. Pass --
to override any source for local development.
//
// The AST2700 boots via its BootMCU (RISC-V RV32), which prepares DRAM and loads
// the CA35 payload. The `image` function builds that BootMCU firmware from the
-// aspeed-mcu-runtime Rust sources, builds the cairn CA35 payload, and stitches a
+// mcu-runtime Rust sources, builds the cairn CA35 payload, and stitches a
// complete SPI flash image with imgtools (in tools/imgtools) using the bmc-pb
// prebuilts (Caliptra, DDR training, DP FW) for the selected silicon revision.
-// The image-stitching logic lives here in cairn; aspeed-mcu-runtime is consumed
-// only as the Rust runtime source.
//
// NOTE: the generated Dagger SDK glue (dagger.gen.go, internal/dagger) is not
// committed; run `dagger develop` once to regenerate it before invoking these
// functions.
//
-// Usage (from the cairn repo root). Common inputs:
+// Usage (from the cairn repo root) — no arguments needed:
//
-// CORE="--tamago ../tamago --tamago-go ../../tamago/tamago-go --core ../core --scree ../scree --nats-server ../nats-server --aspeed-go ../aspeed-go --lneto ../lneto --schema ../schema"
-//
-// dagger call build $CORE
-// dagger call test $CORE
-// dagger call ci $CORE
-// dagger call image $CORE \
-// --aspeed-mcu-runtime ../aspeed-mcu-runtime --aspeed-rs ../aspeed-rs \
-// --aspeed-data ../aspeed-data --bmc-pb ../bmc-pb \
-// --silicon a1 export --path ./out
+// dagger call build export --path ./bin # CA35 payload ELF
+// dagger call test # host unit tests
+// dagger call ci # build + test
+// dagger call image --bmc-pb ../bmc-pb --silicon a1 export --path ./out
//
+// Only the A1 image needs --bmc-pb (the non-redistributable vendor prebuilts).
// The AST2700-A2 image (FLSH container + signed ATMN SoC manifest) is built by
-// tools/a2/gen-a2-image.sh, not by this dagger function — see that script and
-// the A1-ONLY note on Image below.
+// tools/a2/gen-a2-image.sh, not by this dagger function — the manifest signing
+// uses the vendor cptra_imgtool and is not reproducible in-container.
package main
import (
@@ -59,16 +54,42 @@ const (
// the CA35 secondary-init path). Override for other silicon/board variants.
defaultBuildTags = "linkcpuinit,ast2700dcscm"
- // BootMCU (RISC-V RV32) firmware, built from the aspeed-mcu-runtime Rust
- // sources. These match aspeed-mcu-runtime's own build parameters.
+ // BootMCU (RISC-V RV32) firmware, built from the mcu-runtime Rust
+ // sources. These match mcu-runtime's own build parameters.
bootmcuTarget = "riscv32imc-unknown-none-elf"
bootmcuBin = "rot_ast2700_bootmcu"
// No portable_atomic_unsafe_assume_single_core cfg: app-rot deliberately
// uses portable-atomic's critical-section provider (riscv
// critical-section-single-hart), which is mutually exclusive with that cfg.
bootmcuFlags = "-C link-arg=-Tmemory.x -C link-arg=-Tlink.x -C link-arg=--nmagic"
+
+ // Public source defaults. When a source directory is not passed explicitly,
+ // it is fetched from the kyanitecomputer GitHub org so the whole flow builds
+ // from public sources with no local checkouts. Override any -- for
+ // local development.
+ orgGit = "https://github.com/kyanitecomputer/"
+ branchMain = "main"
+ tamagoRef = "aspeed" // tamago fork branch carrying AST2700 support
+ natsServerRef = "fs-interface" // nats-server fork branch (custom storage provider)
+ lnetoRepo = "https://github.com/soypat/lneto"
+ lnetoRef = "8407e075f12a4beaf0d64eda3dede1f8023644b8" // commit cairn builds against (provides x/netdev)
+
+ // The TamaGo compiler is installed from the upstream release (no fork). The
+ // linux-amd64 tarball unpacks to /usr/local/tamago-go with the go binary at
+ // /usr/local/tamago-go/bin/go.
+ tamagoGoURL = "https://github.com/usbarmory/tamago-go/releases/download/tamago-go1.27.1/tamago-go1.27.1.linux-amd64.tar.gz"
+ tamagoGoBin = "/usr/local/tamago-go/bin"
)
+// orRepo returns dir when supplied, otherwise the tree of a kyanitecomputer
+// repository branch — the default that lets builds run from public sources.
+func orRepo(dir *dagger.Directory, repo, ref string) *dagger.Directory {
+ if dir != nil {
+ return dir
+ }
+ return dag.Git(orgGit + repo).Branch(ref).Tree()
+}
+
// Cairn is the Dagger module root.
type Cairn struct{}
@@ -79,7 +100,6 @@ type Cairn struct{}
func (m *Cairn) base(
src *dagger.Directory,
tamago *dagger.Directory,
- tamagoGo *dagger.Directory,
core *dagger.Directory,
scree *dagger.Directory,
natsServer *dagger.Directory,
@@ -87,6 +107,17 @@ func (m *Cairn) base(
lneto *dagger.Directory,
schema *dagger.Directory,
) *dagger.Container {
+ // Resolve any source not supplied by the caller from public GitHub.
+ tamago = orRepo(tamago, "tamago", tamagoRef)
+ core = orRepo(core, "core", branchMain)
+ scree = orRepo(scree, "scree", branchMain)
+ natsServer = orRepo(natsServer, "nats-server", natsServerRef)
+ aspeedGo = orRepo(aspeedGo, "aspeed-go", branchMain)
+ schema = orRepo(schema, "schema", branchMain)
+ if lneto == nil {
+ lneto = dag.Git(lnetoRepo).Commit(lnetoRef).Tree()
+ }
+
goCache := dag.CacheVolume("cairn-go-mod")
goBuild := dag.CacheVolume("cairn-go-build")
@@ -100,10 +131,13 @@ func (m *Cairn) base(
From(stagexPallet).
WithMountedCache("/go/pkg/mod", goCache).
WithMountedCache("/root/.cache/go-build", goBuild).
+ // Install the TamaGo compiler from the upstream release tarball
+ // (unpacks to /usr/local/tamago-go).
+ WithMountedFile("/tmp/tamago-go.tar.gz", dag.HTTP(tamagoGoURL)).
+ WithExec([]string{"tar", "-xzf", "/tmp/tamago-go.tar.gz", "-C", "/"}).
WithDirectory("/build/cairn", src).
WithDirectory("/build/core", core).
WithDirectory("/build/tamago", tamago).
- WithDirectory("/build/tamago-go", tamagoGo).
WithDirectory("/build/scree", scree).
WithDirectory("/build/nats-server", natsServer).
WithDirectory("/build/aspeed-go", aspeedGo).
@@ -115,13 +149,13 @@ func (m *Cairn) base(
WithEnvVariable("GOOS", "tamago").
WithEnvVariable("GOARCH", "arm64").
WithEnvVariable("GOOSPKG", "github.com/usbarmory/tamago").
- WithEnvVariable("PATH", "/build/tamago-go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin").
+ WithEnvVariable("PATH", tamagoGoBin+":/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin").
WithWorkdir("/build/cairn")
}
// elf cross-compiles the AST2700 DC-SCM EVB ELF into /out/cairn.elf.
-func (m *Cairn) elf(src, tamago, tamagoGo, core, scree, natsServer, aspeedGo, lneto, schema *dagger.Directory) *dagger.Container {
- return m.base(src, tamago, tamagoGo, core, scree, natsServer, aspeedGo, lneto, schema).
+func (m *Cairn) elf(src, tamago, core, scree, natsServer, aspeedGo, lneto, schema *dagger.Directory) *dagger.Container {
+ return m.base(src, tamago, core, scree, natsServer, aspeedGo, lneto, schema).
WithExec([]string{"mkdir", "-p", "/out"}).
WithExec([]string{
"go", "build", "-trimpath",
@@ -136,16 +170,22 @@ func (m *Cairn) elf(src, tamago, tamagoGo, core, scree, natsServer, aspeedGo, ln
func (m *Cairn) Build(
// +defaultPath="."
src *dagger.Directory,
+ // +optional
tamago *dagger.Directory,
- tamagoGo *dagger.Directory,
+ // +optional
core *dagger.Directory,
+ // +optional
scree *dagger.Directory,
+ // +optional
natsServer *dagger.Directory,
+ // +optional
aspeedGo *dagger.Directory,
+ // +optional
lneto *dagger.Directory,
+ // +optional
schema *dagger.Directory,
) *dagger.File {
- return m.elf(src, tamago, tamagoGo, core, scree, natsServer, aspeedGo, lneto, schema).File("/out/cairn.elf")
+ return m.elf(src, tamago, core, scree, natsServer, aspeedGo, lneto, schema).File("/out/cairn.elf")
}
// Test runs the host unit tests (Linux userspace, user_linux build tag).
@@ -153,16 +193,22 @@ func (m *Cairn) Test(
ctx context.Context,
// +defaultPath="."
src *dagger.Directory,
+ // +optional
tamago *dagger.Directory,
- tamagoGo *dagger.Directory,
+ // +optional
core *dagger.Directory,
+ // +optional
scree *dagger.Directory,
+ // +optional
natsServer *dagger.Directory,
+ // +optional
aspeedGo *dagger.Directory,
+ // +optional
lneto *dagger.Directory,
+ // +optional
schema *dagger.Directory,
) (string, error) {
- return m.base(src, tamago, tamagoGo, core, scree, natsServer, aspeedGo, lneto, schema).
+ return m.base(src, tamago, core, scree, natsServer, aspeedGo, lneto, schema).
WithEnvVariable("GOOS", "linux").
WithEnvVariable("GOARCH", "amd64").
WithExec([]string{"go", "test", "-tags", "user_linux", "./..."}).
@@ -174,9 +220,9 @@ func (m *Cairn) Test(
// AST2700 SPI flash image except the BootMCU firmware, which is either provided
// as a prebuilt (see Image's bootMcuFmc) or built from Rust by bootMCU below.
func (m *Cairn) imageContainer(
- src, tamago, tamagoGo, core, scree, natsServer, aspeedGo, lneto, schema, bmcPb *dagger.Directory,
+ src, tamago, core, scree, natsServer, aspeedGo, lneto, schema, bmcPb *dagger.Directory,
) *dagger.Container {
- return m.base(src, tamago, tamagoGo, core, scree, natsServer, aspeedGo, lneto, schema).
+ return m.base(src, tamago, core, scree, natsServer, aspeedGo, lneto, schema).
WithDirectory("/build/bmc-pb", bmcPb).
WithExec([]string{"mkdir", "-p", "/out"}).
// Build the imgtools stitcher as a host (linux/amd64) binary — it runs
@@ -191,27 +237,27 @@ func (m *Cairn) imageContainer(
WithEnvVariable("GOARCH", "arm64")
}
-// bootMCUFirmwareELF builds the BootMCU firmware ELF from the aspeed-mcu-runtime
+// bootMCUFirmwareELF builds the BootMCU firmware ELF from the mcu-runtime
// Rust sources in the StageX Rust image (pinned/overridable via rustImage).
// StageX ships a rustup-less toolchain with no prebuilt riscv32 std, so core is
// built via -Zbuild-std (RUSTC_BOOTSTRAP unlocks it on the pinned stable
-// toolchain) — the same approach aspeed-mcu-runtime's own CI uses.
+// toolchain) — the same approach mcu-runtime's own CI uses.
func (m *Cairn) bootMCUFirmwareELF(
rustImage string,
- aspeedMcuRuntime, aspeedRs, aspeedData *dagger.Directory,
+ mcuRuntime, aspeedRs, aspeedData *dagger.Directory,
) *dagger.File {
cargoCache := dag.CacheVolume("cairn-cargo-registry")
- elf := "/build/aspeed-mcu-runtime/app-rot/target/" +
+ elf := "/build/mcu-runtime/app-rot/target/" +
bootmcuTarget + "/release/" + bootmcuBin
return dag.Container().
From(rustImage).
WithEnvVariable("CARGO_HOME", "/usr/local/cargo").
WithEnvVariable("RUSTC_BOOTSTRAP", "1").
WithMountedCache("/usr/local/cargo/registry", cargoCache).
- WithDirectory("/build/aspeed-mcu-runtime", aspeedMcuRuntime).
+ WithDirectory("/build/mcu-runtime", mcuRuntime).
WithDirectory("/build/aspeed-rs", aspeedRs).
WithDirectory("/build/aspeed-data", aspeedData).
- WithWorkdir("/build/aspeed-mcu-runtime/app-rot").
+ WithWorkdir("/build/mcu-runtime/app-rot").
WithEnvVariable("RUSTFLAGS", bootmcuFlags).
WithExec([]string{"cargo", "build",
"--target", bootmcuTarget,
@@ -242,7 +288,7 @@ func (m *Cairn) bootMCU(ctr *dagger.Container, firmware *dagger.File) *dagger.Co
//
// The BootMCU firmware is either supplied prebuilt via bootMcuFmc (skips the
// Rust build — useful where the StageX Rust image is unavailable) or built from
-// the aspeed-mcu-runtime Rust sources (requires aspeedMcuRuntime/aspeedRs/
+// the mcu-runtime Rust sources (requires mcuRuntime/aspeedRs/
// aspeedData and a musl-compatible StageX rustImage; core is built via
// -Zbuild-std, so no prebuilt riscv32 std is needed).
//
@@ -260,19 +306,27 @@ func (m *Cairn) Image(
ctx context.Context,
// +defaultPath="."
src *dagger.Directory,
+ // bmcPb holds the non-redistributable vendor prebuilts (Caliptra FW, DDR
+ // training, DP FW); it must be supplied — there is no public default.
+ bmcPb *dagger.Directory,
+ // +optional
tamago *dagger.Directory,
- tamagoGo *dagger.Directory,
+ // +optional
core *dagger.Directory,
+ // +optional
scree *dagger.Directory,
+ // +optional
natsServer *dagger.Directory,
+ // +optional
aspeedGo *dagger.Directory,
+ // +optional
lneto *dagger.Directory,
+ // +optional
schema *dagger.Directory,
- bmcPb *dagger.Directory,
// +optional
bootMcuFmc *dagger.File,
// +optional
- aspeedMcuRuntime *dagger.Directory,
+ mcuRuntime *dagger.Directory,
// +optional
aspeedRs *dagger.Directory,
// +optional
@@ -283,7 +337,7 @@ func (m *Cairn) Image(
silicon string,
// +default="32M"
imageSize string,
- // +default="cairn_ast2700.bin"
+ // +default="cairn_ast2700_a1.bin"
outputName string,
// +default=""
buildTags string,
@@ -304,23 +358,24 @@ func (m *Cairn) Image(
imageSize = "32M"
}
if outputName == "" {
- outputName = "cairn_ast2700.bin"
+ outputName = "cairn_ast2700_a1.bin"
}
if buildTags == "" {
buildTags = defaultBuildTags
}
pb := "/build/bmc-pb/ast2700" + silicon
- ctr := m.imageContainer(src, tamago, tamagoGo, core, scree, natsServer, aspeedGo, lneto, schema, bmcPb)
+ ctr := m.imageContainer(src, tamago, core, scree, natsServer, aspeedGo, lneto, schema, bmcPb)
- // BootMCU firmware: use the prebuilt FMC when provided, else build from Rust.
+ // BootMCU firmware: use the prebuilt FMC when provided, else build from the
+ // Rust sources (resolved from public GitHub when not supplied).
if bootMcuFmc != nil {
ctr = ctr.WithFile("/out/rot_ast2700_bootmcu.fmc.bin", bootMcuFmc)
} else {
- if aspeedMcuRuntime == nil || aspeedRs == nil || aspeedData == nil {
- return nil, fmt.Errorf("image: building the BootMCU needs --aspeed-mcu-runtime, --aspeed-rs and --aspeed-data (or supply --boot-mcu-fmc)")
- }
- firmware := m.bootMCUFirmwareELF(rustImage, aspeedMcuRuntime, aspeedRs, aspeedData)
+ firmware := m.bootMCUFirmwareELF(rustImage,
+ orRepo(mcuRuntime, "mcu-runtime", branchMain),
+ orRepo(aspeedRs, "aspeed-rs", branchMain),
+ orRepo(aspeedData, "aspeed-data", branchMain))
ctr = m.bootMCU(ctr, firmware)
}
@@ -360,19 +415,25 @@ func (m *Cairn) Ci(
ctx context.Context,
// +defaultPath="."
src *dagger.Directory,
+ // +optional
tamago *dagger.Directory,
- tamagoGo *dagger.Directory,
+ // +optional
core *dagger.Directory,
+ // +optional
scree *dagger.Directory,
+ // +optional
natsServer *dagger.Directory,
+ // +optional
aspeedGo *dagger.Directory,
+ // +optional
lneto *dagger.Directory,
+ // +optional
schema *dagger.Directory,
) (string, error) {
- if _, err := m.elf(src, tamago, tamagoGo, core, scree, natsServer, aspeedGo, lneto, schema).Sync(ctx); err != nil {
+ if _, err := m.elf(src, tamago, core, scree, natsServer, aspeedGo, lneto, schema).Sync(ctx); err != nil {
return "", fmt.Errorf("build: %w", err)
}
- if _, err := m.Test(ctx, src, tamago, tamagoGo, core, scree, natsServer, aspeedGo, lneto, schema); err != nil {
+ if _, err := m.Test(ctx, src, tamago, core, scree, natsServer, aspeedGo, lneto, schema); err != nil {
return "", fmt.Errorf("test: %w", err)
}
return "build: ok\ntest: ok", nil
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..071f839
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,33 @@
+name: CI
+
+# Builds and tests Cairn entirely from public sources. The Dagger `ci` function
+# fetches the TamaGo fork, the shared Kyanite modules and the tamago-go compiler
+# release from public GitHub, cross-compiles the AST2700 payload and runs the
+# host unit tests — so this workflow needs no secrets and no extra inputs.
+
+on:
+ push:
+ branches: [main]
+ pull_request:
+ branches: [main]
+
+permissions:
+ contents: read
+
+concurrency:
+ group: ci-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ ci:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+
+ - name: Build + test (dagger call ci)
+ uses: dagger/dagger-for-github@27b130bf0f79a7f6fbbbe0fbca6760dc9bb40a77 # v8.4.1
+ with:
+ version: "0.21.9"
+ verb: call
+ args: ci
diff --git a/AGENTS.md b/AGENTS.md
index 01d5e9e..3684636 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -22,14 +22,19 @@ implementing the `pkg/bmcdev` interface and reuses `pkg/` and `core/` unchanged.
## Build & test
+Dagger is the only build interface; it fetches the TamaGo fork, the shared
+Kyanite modules and the tamago-go compiler release from public GitHub, so builds
+need no local checkouts. Override any source with `--` for local work.
+
```sh
-make build # TamaGo ELF -> bin/cairn.elf (needs TAMAGO set to a tamago-go binary)
-make test # host unit tests (user_linux tag)
-dagger call ci # reproducible CI (build + test)
+dagger call build export --path ./bin # TamaGo ELF -> bin/cairn.elf
+dagger call test # host unit tests (user_linux tag)
+dagger call ci # build + test (what CI runs)
```
-Compiles with `GOOS=tamago GOARCH=arm64`. The AST2700 SoC/board support comes
-from a TamaGo fork wired in via a local (git-ignored) `go.work`.
+Compiles with `GOOS=tamago GOARCH=arm64`. The A1 SPI image is
+`dagger call image --bmc-pb --silicon a1`; the A2 image (vendor-signed
+FLSH container, not reproducible in-container) is `tools/a2/gen-a2-image.sh`.
## Conventions
diff --git a/Makefile b/Makefile
deleted file mode 100644
index 963eefe..0000000
--- a/Makefile
+++ /dev/null
@@ -1,162 +0,0 @@
-# Cairn (ASPEED AST2700 DC-SCM) TamaGo build system.
-#
-# Produces:
-# bin/cairn.elf TamaGo ELF for the AST2700 DC-SCM EVB (arm64, linked for DRAM)
-#
-# Layout: each hardware platform lives under target// and holds its
-# entry point (main.go) plus any non-upstream boot assets. The AST2700 DC-SCM
-# platform is target/ast2700-dcscm-evb. CA35 bring-up and the DRAM image load
-# are handled by the board's BootMCU + the upstream TamaGo board package, so no
-# in-tree boot stub is required (unlike vein's FSL91030 flashboot.S).
-#
-# NOTE: this is the base scaffold. The RUNTIME_TEXT load address below is
-# provisional (DRAM base + 64 KB) and must be confirmed against the BootMCU
-# payload load address during hardware enablement.
-
-# ---------------------------------------------------------------------------
-# Toolchain
-# ---------------------------------------------------------------------------
-TAMAGO ?= tamago
-ifeq ($(shell command -v $(TAMAGO) 2>/dev/null),)
-$(error TamaGo compiler '$(TAMAGO)' not found. Set the TAMAGO environment variable to your tamago-go binary)
-endif
-
-READELF ?= llvm-readelf
-
-# ---------------------------------------------------------------------------
-# Build settings
-# ---------------------------------------------------------------------------
-GOARCH = arm64
-GOOS = tamago
-GOOSPKG = github.com/usbarmory/tamago
-
-# GOARM64 pins the ARMv8 baseline. The AST2700 CA35 cores are Cortex-A35, which
-# implement ARMv8.0-A and do NOT provide FEAT_LSE (large-system atomics). Pin it
-# explicitly to v8.0 so the compiler never emits LSE instructions (CAS/LDADD/…),
-# which are UNDEFINED on this core and trap synchronously. Do not rely on the
-# toolchain default: go1.27 keeps it at v8.0, but a future bump to v8.1+ would
-# silently emit unconditional LSE atomics and brick the CA35 payload.
-GOARM64 = v8.0
-
-GOENV = GOOS=$(GOOS) GOARCH=$(GOARCH) GOARM64=$(GOARM64) GOOSPKG=$(GOOSPKG) GOTOOLCHAIN=local
-
-# Platform directory: entry point + platform code.
-TARGET = target/ast2700-dcscm-evb
-
-# CA35-view DRAM text base. The payload links 64 MB into DRAM
-# (RamStart 0x400000000 + 0x4000000), leaving ~960 MB heap between the binary
-# end and the stack — the layout proven by the cmd/nats validation.
-RUNTIME_TEXT = 0x404000000
-ALIGN = 0x1000
-
-# Build tags. linkcpuinit brings up the CA35 secondary-init path; ast2700dcscm
-# selects the DC-SCM board package. Override BOARD_TAG for other silicon.
-BOARD_TAG ?= ast2700dcscm
-TAGS = linkcpuinit,$(BOARD_TAG)
-
-# Set VIDEO=1 to compile in the DisplayPort framebuffer console. This enables
-# the ast2700video feature and redirects the runtime printk hook onto the
-# on-screen console via linkprintk (the board package's own printk must be
-# disabled, which linkprintk does).
-ifeq ($(VIDEO),1)
-TAGS := $(TAGS),ast2700video,linkprintk
-endif
-
-# FACETUI=1 (or TAGS_EXTRA=facetui) embeds the facet SPA bundle in the web UI.
-# The Dagger UI build populates target/.../webui/build/ before enabling this.
-ifeq ($(FACETUI),1)
-TAGS := $(TAGS),facetui
-endif
-ifneq ($(TAGS_EXTRA),)
-TAGS := $(TAGS),$(TAGS_EXTRA)
-endif
-
-# ---------------------------------------------------------------------------
-# Output
-# ---------------------------------------------------------------------------
-BIN_DIR = bin
-ELF = $(BIN_DIR)/cairn.elf
-
-# ---------------------------------------------------------------------------
-# Targets
-# ---------------------------------------------------------------------------
-.PHONY: all clean build flashdiag flashdiag-dma test imgtools help
-
-all: build
-
-$(BIN_DIR):
- @mkdir -p $(BIN_DIR)
-
-# Build the TamaGo ELF for the AST2700 DC-SCM EVB. DRAM is prepared by the
-# BootMCU, so this is linked for the CA35 DRAM view.
-build: $(BIN_DIR)
- @echo "Building Cairn ELF (AST2700 DC-SCM EVB)..."
- $(GOENV) $(TAMAGO) build \
- -trimpath \
- -tags $(TAGS) \
- -ldflags "-T $(RUNTIME_TEXT) -R $(ALIGN)" \
- -o $(ELF) \
- ./$(TARGET)
- @echo "Built: $(ELF)"
- @$(READELF) -h $(ELF) | grep -i "entry point"
-
-# Read-only FMC/SPI-NOR hardware diagnostic payload. Same link layout as the
-# normal payload, but the `flashdiag` tag makes it run the probe suite and idle
-# instead of booting. Stitch it into a flashable image exactly like the normal
-# payload, e.g.:
-#
-# dagger call image --build-tags "linkcpuinit,ast2700dcscm,flashdiag" \
-# --silicon a1 ... export --path .
-#
-# Add `flashdiagdma` to the tag list to also run the (opt-in) DMA-scaling probe.
-FLASHDIAG_ELF = $(BIN_DIR)/cairn-flashdiag.elf
-FLASHDIAG_TAGS = $(BOARD_TAG),linkcpuinit,flashdiag$(if $(TAGS_EXTRA),$(comma)$(TAGS_EXTRA))
-comma := ,
-flashdiag: $(BIN_DIR)
- @echo "Building Cairn flash-diagnostic ELF (tags: $(FLASHDIAG_TAGS))..."
- $(GOENV) $(TAMAGO) build \
- -trimpath \
- -tags $(FLASHDIAG_TAGS) \
- -ldflags "-T $(RUNTIME_TEXT) -R $(ALIGN)" \
- -o $(FLASHDIAG_ELF) \
- ./$(TARGET)
- @echo "Built: $(FLASHDIAG_ELF)"
- @$(READELF) -h $(FLASHDIAG_ELF) | grep -i "entry point"
-
-flashdiag-dma: TAGS_EXTRA := flashdiagdma
-flashdiag-dma: flashdiag
-
-# Host unit tests (Linux userspace).
-test:
- $(TAMAGO) test -tags user_linux ./... || true
-
-# Build the host image-stitching tool. The full SPI flash image (BootMCU + this
-# payload + bmc-pb prebuilts) is produced by `dagger call image`, which also
-# builds the BootMCU Rust firmware; imgtools is the stitcher it invokes.
-imgtools: $(BIN_DIR)
- GOWORK=off $(TAMAGO) build -C tools/imgtools -o $(abspath $(BIN_DIR))/imgtools .
- @echo "Built: $(BIN_DIR)/imgtools"
-
-clean:
- @rm -rf $(BIN_DIR)
- @echo "Clean complete"
-
-help:
- @echo "Cairn (ASPEED AST2700 DC-SCM) TamaGo - Build System"
- @echo ""
- @echo "Hardware: ASPEED AST2700 (dual Cortex-A35, arm64)"
- @echo "DRAM: 1 GB, CA35 view at 0x400000000"
- @echo ""
- @echo "Targets:"
- @echo " build Build TamaGo ELF for the AST2700 DC-SCM EVB (default)"
- @echo " test Run host tests (user_linux tag)"
- @echo " imgtools Build the host image-stitching tool"
- @echo " clean Remove build artifacts"
- @echo ""
- @echo "Full SPI flash image (A1): dagger call image ... --silicon a1"
- @echo "Full SPI flash image (A2): tools/a2/gen-a2-image.sh (FLSH + signed manifest)"
- @echo ""
- @echo "Environment variables:"
- @echo " TAMAGO Path to tamago-go binary (default: $(TAMAGO))"
- @echo " READELF LLVM readelf (default: llvm-readelf)"
- @echo " BOARD_TAG Board build tag (default: ast2700dcscm)"
diff --git a/README.md b/README.md
index f705a47..7125ee4 100644
--- a/README.md
+++ b/README.md
@@ -62,17 +62,33 @@ Cairn follows the same embedded-friendly conventions as vein:
## Build
-The AST2700 arm64 SoC/board support lives in a TamaGo fork that is not yet
-upstream. Until it lands, `go.work` redirects `github.com/usbarmory/tamago` to
-that fork (`../tamago`).
+Everything is built with [Dagger](https://dagger.io), which fetches the TamaGo
+fork (AST2700 support), the shared Kyanite modules and the tamago-go compiler
+release from public GitHub — so the whole flow builds from public sources with
+no local checkouts and no toolchain setup beyond Dagger:
```bash
-make build # AST2700 DC-SCM EVB ELF → bin/cairn.elf
-make test # host unit tests (user_linux tag)
+dagger call build export --path ./bin # AST2700 DC-SCM EVB ELF → bin/cairn.elf
+dagger call test # host unit tests (user_linux tag)
+dagger call ci # build + test (what CI runs)
```
-Requires the TamaGo compiler (`TAMAGO=/path/to/tamago-go/bin/go`) and
-`llvm-readelf`.
+Pass `--` (e.g. `--core ../core`, `--tamago ../tamago`) to build against a
+local checkout instead of the public default.
+
+### Full SPI flash image
+
+```bash
+# A1: fully reproducible, in-container. --bmc-pb supplies the vendor prebuilts
+# (Caliptra FW, DDR training, DP FW), which are not redistributable.
+dagger call image --bmc-pb ../bmc-pb --silicon a1 export --path ./out
+
+# A2: FLSH container + vendor-signed ATMN SoC manifest. The manifest signing
+# uses the vendor cptra_imgtool and is not reproducible in-container, so it runs
+# on the host — see tools/a2/gen-a2-image.sh.
+CPTRA_IMGTOOL=../cptra_imgtool PREBUILT=/path/to/a2-prebuilts \
+ tools/a2/gen-a2-image.sh
+```
## Module
diff --git a/dagger.json b/dagger.json
index f97acd9..7761a0c 100644
--- a/dagger.json
+++ b/dagger.json
@@ -1,6 +1,6 @@
{
"name": "cairn",
- "engineVersion": "v0.21.6",
+ "engineVersion": "v0.21.9",
"sdk": {
"source": "go"
},
diff --git a/tools/a2/cairn-a2-manifest.toml b/tools/a2/cairn-a2-manifest.toml
index 097d0a0..547e34e 100644
--- a/tools/a2/cairn-a2-manifest.toml
+++ b/tools/a2/cairn-a2-manifest.toml
@@ -59,7 +59,7 @@ mldsa_priv_key = "own-man-mldsa-priv-key.bin"
[image_runtime_list]
caliptra_file = "caliptra-fw.bin"
-# MCU runtime (BootMCU FMC): our aspeed-mcu-runtime Rust BootMCU, built for A2
+# MCU runtime (BootMCU FMC): our mcu-runtime Rust BootMCU, built for A2
# (linked at 0x14B80000) by gen-a2-image.sh. Override with MCU_RUNTIME_BIN to
# use a prebuilt binary (e.g. vendor Zephyr).
mcu_file = "ast2700-mcu-runtime.bin"
diff --git a/tools/a2/gen-a2-image.sh b/tools/a2/gen-a2-image.sh
index 756645e..5ed54a5 100755
--- a/tools/a2/gen-a2-image.sh
+++ b/tools/a2/gen-a2-image.sh
@@ -79,19 +79,30 @@ mkdir -p "$OUT" "$STAGE"
rm -f "$OUT/$IMAGE_NAME"
echo "==> 1/4 build cairn CA35 payload"
-# Forward VIDEO=1 (framebuffer console) and FACETUI=1 (embed the facet SPA).
-CAIRN_TAGS=""
-if [ -n "${FACETUI:-}" ]; then
- CAIRN_TAGS="facetui"
-fi
+# Cross-compile the CA35 payload ELF with the host TamaGo compiler. The CA35
+# cores are Cortex-A35 (ARMv8.0-A, no FEAT_LSE), so pin GOARM64=v8.0 to keep the
+# compiler from emitting large-system atomics (which trap on this core). The
+# payload links at the CA35-view DRAM text base (0x404000000). VIDEO=1 compiles
+# in the DisplayPort framebuffer console; FACETUI=1 embeds the facet SPA.
+build_payload() {
+ ( cd "$CAIRN" && GOOS=tamago GOARCH=arm64 GOARM64=v8.0 \
+ GOOSPKG=github.com/usbarmory/tamago GOTOOLCHAIN=local \
+ "$TAMAGO" build -trimpath -tags "$1" \
+ -ldflags "-T 0x404000000 -R 0x1000" -o "$2" ./target/ast2700-dcscm-evb )
+}
if [ "$DIAG" = "1" ]; then
- DIAG_EXTRA="$CAIRN_TAGS"
- [ "$DIAGDMA" = "1" ] && DIAG_EXTRA="${DIAG_EXTRA:+$DIAG_EXTRA,}flashdiagdma"
- [ "$DIAGWRITE" = "1" ] && DIAG_EXTRA="${DIAG_EXTRA:+$DIAG_EXTRA,}flashdiagwrite"
- echo " DIAG build: make flashdiag TAGS_EXTRA=$DIAG_EXTRA"
- ( cd "$CAIRN" && TAMAGO="$TAMAGO" TAGS_EXTRA="$DIAG_EXTRA" make flashdiag )
+ # Read-only FMC/SPI-NOR hardware diagnostic payload (flashdiag tag).
+ TAGS="ast2700dcscm,linkcpuinit,flashdiag"
+ [ "$DIAGDMA" = "1" ] && TAGS="$TAGS,flashdiagdma"
+ [ "$DIAGWRITE" = "1" ] && TAGS="$TAGS,flashdiagwrite"
+ [ -n "${FACETUI:-}" ] && TAGS="$TAGS,facetui"
+ echo " DIAG build: tags=$TAGS"
+ build_payload "$TAGS" "$PAYLOAD_ELF"
else
- ( cd "$CAIRN" && TAMAGO="$TAMAGO" VIDEO="${VIDEO:-}" TAGS_EXTRA="$CAIRN_TAGS" make build )
+ TAGS="linkcpuinit,ast2700dcscm"
+ [ "${VIDEO:-}" = "1" ] && TAGS="$TAGS,ast2700video,linkprintk"
+ [ -n "${FACETUI:-}" ] && TAGS="$TAGS,facetui"
+ build_payload "$TAGS" "$PAYLOAD_ELF"
fi
llvm-objcopy -O binary "$PAYLOAD_ELF" "$STAGE/cairn.payload.bin"
@@ -136,7 +147,7 @@ for f in caliptra-fw.bin \
done
# The MCU runtime (BootMCU FMC, FLSH id 3). By default we build our own
-# aspeed-mcu-runtime Rust BootMCU for A2 from source. A2 links the FMC at GSRAM
+# mcu-runtime Rust BootMCU for A2 from source. A2 links the FMC at GSRAM
# base 0x14B80000 (the A2 ROM loads it there, with no ASTH header); the A1
# default links at 0x14B80A00 and faults the instant the A2 ROM jumps to it —
# the firmware loads (Ff=0000) and is entered (J=0000) but every absolute
@@ -144,9 +155,9 @@ done
# the A2 layout (link/ast2700-bootmcu-a2.x) when AST2700_BOOTMCU_A2 is set.
#
# Set MCU_RUNTIME_BIN to override with a prebuilt binary (e.g. vendor Zephyr, or
-# a pre-built FMC); set MCU_RUNTIME_SRC to point at a different aspeed-mcu-runtime
+# a pre-built FMC); set MCU_RUNTIME_SRC to point at a different mcu-runtime
# checkout.
-MCU_RUNTIME_SRC="${MCU_RUNTIME_SRC:-$CAIRN/../aspeed-mcu-runtime}"
+MCU_RUNTIME_SRC="${MCU_RUNTIME_SRC:-$CAIRN/../mcu-runtime}"
if [ -n "${MCU_RUNTIME_BIN:-}" ]; then
echo " MCU runtime (prebuilt): $MCU_RUNTIME_BIN"
cp "$MCU_RUNTIME_BIN" "$STAGE/ast2700-mcu-runtime.bin"
@@ -159,7 +170,7 @@ elif [ -d "$MCU_RUNTIME_SRC/app-rot" ]; then
llvm-objcopy -O binary "$MCU_ELF" "$STAGE/ast2700-mcu-runtime.bin"
else
echo "ERROR: no MCU runtime: set MCU_RUNTIME_BIN to a prebuilt FMC, or" >&2
- echo " MCU_RUNTIME_SRC to an aspeed-mcu-runtime checkout to build ours." >&2
+ echo " MCU_RUNTIME_SRC to an mcu-runtime checkout to build ours." >&2
exit 1
fi