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