Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions os/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,24 @@ HSA runtime and its libraries complete, the PM4-emulation probe answered), Lemon
running `onebit` models on HRX0 and the NPU, HRX kernels compiling into `/data/cache/hrx-jit` and
being reused after a reboot, Lemonade's Vulkan backends on RADV, `llamacpp-hrx`, Lemonade's ROCm downloads for gfx1151, the Wi-Fi chip, and the speed of all of it.

## The v2 base (Ubuntu + apt)

Everything above describes `os/mini`: one BusyBox image that runs from RAM, updated by reflashing the
stick. `os/v2/` is the same appliance on a minimal Ubuntu 26.04 root filesystem with systemd, where what
we ship are `.deb` packages from the signed repository on `1bit.gg/apt` and the update path is
`apt update && apt upgrade` - with the previous kernel and the cached debs as the rollback. The kernel,
the EC board driver and ryzenadj are packages too; the live medium is the root filesystem as a squashfs
with a tmpfs overlay, and `1bit-install` writes three partitions (ESP, `1BIT-ROOT`, `1BIT-DATA`) instead
of unpacking everything into a RAM image.

```sh
os/v2/proto.sh <work-dir> <engine-stage> <lemonade-prefix> # everything, in one command
os/v2/README.md # what each piece is, and what is proven
```

`os/mini` keeps shipping until v2 passes the same checks on hardware. Both images keep the same `/data`
layout and the same installer behaviour, so an owner's runbook does not change.

## Next

- A Loom kernel cache built ahead of time, so the first boot needs no compile.
Expand Down
143 changes: 143 additions & 0 deletions os/v2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
<!--
Copyright 2026 bong-water-water-bong
SPDX-License-Identifier: Apache-2.0

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
# 1bit OS v2 — the appliance on a minimal Ubuntu base, updated with `apt`

`os/mini` builds the BusyBox image that ships today: everything in RAM, a reflash to update. v2 keeps the
same appliance — Lemonade Server by AMD, running on the 1bit engine, our kernel, Secure Boot through the
enrolled MOK — on a **minimal Ubuntu 26.04 root filesystem with systemd**, where everything we ship is a
`.deb` from our own signed repository and `apt update && apt upgrade` is the update path.

The design and the reasons are in `~/briefs/TOSAPT-DESIGN.md`; this file is what is in the tree and how to
reproduce it. `os/mini` keeps shipping until v2 passes the same checks on hardware.

## Build it

```sh
# 1. the packages. A release build produces the two inputs: an engine stage (scripts/package-linux.sh's
# tarball, or a build tree with ENGINE_BUILD=<dir>) and a Lemonade prefix (bin/lemond, bin/resources).
# KERNEL_STAGE is the release kernel as it sits on the build machine:
# <dir>/boot/{vmlinuz,System.map,config}-<kver> and <dir>/lib/modules/<kver>/
os/v2/mkdebs.sh <engine-stage> <lemonade-prefix> v2026.43 <out-debs> [archive-keyring.gpg]
# KERNEL_STAGE=<dir> ENGINE_BUILD=<build dir>

# 2. the apt repository those debs are published from (signed: Release, Release.gpg, InRelease)
os/v2/mkrepo.sh <out-debs> <repo-dir> [gnupg-home] [key-id]

# 3. a root filesystem from one Ubuntu snapshot (pin.txt) that apt-installs 1bit-appliance from it
os/v2/mkrootfs.sh <repo-dir> <rootfs-dir> [ssh-key.pub]

# 4. the live medium: one image to dd onto a stick
os/v2/mklive.sh <rootfs-dir> <data-seed-dir> <out.img> [mok.priv mok.pem]

# 5. the two tests (no hardware, no GPU: QEMU)
os/v2/vmtest-v2.sh <rootfs-dir> <data-seed-dir> [ssh-key] # the appliance, from a rootfs
os/v2/vmtest-install-v2.sh <rootfs-dir> <data-seed-dir> <work-dir> [mok.priv mok.pem] # live + install
```

`os/v2/proto.sh` runs 1..5 in one command against a throwaway signing key, which is what a lane without
the operator's key uses. `os/v2/diag-v2.sh` boots the rootfs and asks the guest what failed — it is a
debugging tool, it judges nothing.

`MIRROR=<url>` overrides the pinned snapshot in `mkrootfs.sh` for one run. That exists for a
`snapshot.ubuntu.com` outage (it 503'd for an hour on 25 Oct); a release build is the pinned snapshot.

## The packages

| Package | What is in it |
|---|---|
| `1bit-engine` | `/opt/1bit`: the engine, the HRX `llama-server` and its libraries, the ds4 programs, the sealed NPU kernel sets, `1bit-selftest`, `1bit-release-check`, `/etc/1bit/engine.conf` |
| `1bit-lemonade` | `/opt/lemonade`: our build of Lemonade Server (`lemond`, the CLI, the web app) and its unit |
| `1bit-kernel-image-<kver>` | `/boot/{vmlinuz,System.map,config}-<kver>`; its postinst runs `update-initramfs`. The **kver is in the name**, so an upgrade keeps the previous kernel installed — that is the rollback |
| `1bit-kernel-modules-<kver>` | every module for `<kver>`, including the out-of-tree EC board driver (MOK-signed) and its source under `/usr/src/1bit-ec-<ver>` |
| `1bit-ryzenadj` | `/usr/bin/ryzenadj`, built from the pinned v0.19.0 source, which ships beside it (LGPL-3.0) |
| `1bit-appliance` | the meta/config package: units, banner, autologin, network, `/data`, first boot, apt source, `/usr/share/licenses/1bit-os`. `Depends:` the six above |
| `1bit-archive-keyring` | the public half of the key that signs `1bit.gg/apt` |

Two things the packages must get right, both learned the hard way and both checked by `mkdebs.sh`:

- **The engine's own libraries are found beside it.** `scripts/pack-elf.sh`'s `pack_localize` runs over the
package (`ENGINE_BUILD`), so `libllama-server-impl.so`, `libhrx`, `libloomc`, `libomp` are in the package
and `RUNPATH` is `$ORIGIN`. A build-machine path in a package is a package that does not load (#549).
- **Signed, or Secure Boot refuses it.** `mkdebs.sh` fails if the EC module is unsigned or built for another
kernel, and if the kernel image carries no signature (`sbverify --list` → `signature 1`).

## Trust and the boot chain

```
firmware (db) -> shim (Microsoft-signed) -> grubx64.efi (our MOK) -> vmlinuz (our MOK) -> initramfs-tools
\-> ec_su_axb35.ko (our MOK, module-signing OID)
```

`apt` trusts `1bit.gg/apt` through `signed-by=/usr/share/keyrings/1bit-archive-keyring.gpg` and nothing
else: no `apt-key`, no `[trusted=yes]`. An install copies the medium's own signed chain, so the machine's
MOK enrolment is never touched by installing.

## The live medium, and what an install writes

`mklive.sh` writes one disk image, in the same three partitions an installed box has:

| | live medium | after `1bit-install /dev/nvme0n1 --yes` |
|---|---|---|
| 1 | 512 MB ESP `1BIT-OS`: shim, our grub, kernel + initramfs, `grub.cfg` | the same, with a `grub.cfg` for the disk |
| 2 | squashfs, `PARTLABEL=1BIT-LIVE` — the whole root filesystem, read-only | ext4 `1BIT-ROOT` = `min(64 GB, max(24 GB, 25 %))`, the squashfs unpacked, `/boot`, `fstab` by label |
| 3 | ext4 `1BIT-DATA` — models, backends, config, keys | the same content, copied from the medium |

The live system is the squashfs with a tmpfs overlay: an initramfs-tools script
(`scripts/local-bottom/1bit-live`) mounts it, so userspace has nothing custom at boot and a live boot
cannot write the medium. `1bit-install` refuses before writing anything — no `--yes`, a partition instead
of a disk, a removable device, the disk the live boot runs from, a disk with something mounted, a missing
GPT tool — prints the disk and waits 10 s, exactly as the `os/mini` installer does (`#539`).

## What is proven, and where

`vmtest-v2.sh` runs the checks **inside** the guest (a test-only oneshot unit writes its transcript to
`/data` and powers the machine off); the host reads that transcript, so no port forwarding decides a
verdict. `vmtest-install-v2.sh` does the same for the live medium and then boots the installed disk alone.

| What | How |
|---|---|
| all seven packages install and are the release's | `dpkg-query -W '1bit-*'` in the guest |
| the banner, `/data` on its own disk, `1bit-selftest` | guest transcript |
| the engine runs; `llama-server`'s own libraries resolve | `1bit --help`, `ldd` on the packaged `llama-server` |
| our kernel package produced `vmlinuz` **and** `initrd.img` | `/boot` in the guest |
| Lemonade: key generated, 401 without it, the GGUF listed, one chat answered | `curl` against `127.0.0.1:13305` |
| apt answers from the repository, and the shipped source is `1bit.gg/apt` with `signed-by` | `apt-get update`, `apt-cache policy`, the `.list` |
| `1bit-release-check`: every row passes except the sealed-NPU one (a dev stage carries no sealed sets) | its own output |
| the live medium boots the squashfs with the overlay; all six refusals; the install writes three partitions with the kernel in `/boot`, `fstab` by label and the live marker gone | `vmtest-install-v2.sh` pass 1 |
| the installed disk boots alone: INSTALLED banner, first-boot marker and own SSH keys, `/data` on its disk, Lemonade 401 + GGUF + chat, `1bit-selftest` reports INSTALLED | `vmtest-install-v2.sh` pass 2 |

The VM boots **OVMF** (EFI, Secure Boot off) rather than a legacy BIOS, so `/sys/firmware/efi` exists and
the `secureboot` row answers; enrolling the MOK is the machine's step, not a VM's.

## Known gaps

- **The ROCm userspace is not packaged.** The engine's HIP path (`llama-server`, `ds4`) links
`libamdhip64`, rocBLAS, hipBLASLt, the HSA runtime and `libamd_comgr` from the SDK the build machine had.
Ubuntu 26.04 has packages for them (`libamdhip64-7`, `libhipblaslt1`, `librocblas*`), but gfx1201
support against the distro's ROCm is a hardware question, so the engine's `Depends` do not name them yet
and a VM (no GPU) cannot settle it. The engine's *own* libraries are packaged and resolve — that is what
`vmtest-v2` asserts.
- **A development stage has no sealed NPU sets**, so `1bit-release-check`'s `sealed` row fails by
construction in these runs (the VM has no NPU either). A release stage always carries them.
- The v2 rootfs in these runs came from the archive mirror, not the pinned snapshot, because
`snapshot.ubuntu.com` was 503. `pin.txt` is unchanged and is what a release build uses.

## Licence

The scripts here are Apache-2.0, like the rest of this repository. What the packages carry is in
`os/LICENSES.md`; each package ships its own licences under `/usr/share/doc/<package>/` and the aggregate
under `/usr/share/licenses/1bit-os/`.
3 changes: 3 additions & 0 deletions os/v2/debian/1bit-appliance/conffiles
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/etc/1bit/power
/etc/issue
/etc/motd
14 changes: 14 additions & 0 deletions os/v2/debian/1bit-appliance/control
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Package: 1bit-appliance
Version: @VERSION@
Architecture: amd64
Maintainer: 1bit <packages@1bit.gg>
Section: metapackages
Priority: optional
Depends: 1bit-engine (= @VERSION@), 1bit-lemonade (= @VERSION@), 1bit-archive-keyring, systemd, openssh-server, systemd-resolved, initramfs-tools
Replaces: base-files
Description: 1bit OS, Lemonade Server appliance - meta and configuration package
Turns a minimal Ubuntu into the appliance: the units that start
Lemonade and the engine, the console banner, autologin, the network
and /data mount, the fans and power profile, the first-boot setup
and the signed apt repository this box updates from. Lemonade
Server by AMD, running on the 1bit engine.
26 changes: 26 additions & 0 deletions os/v2/debian/1bit-appliance/files/etc/1bit/power
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Copyright 2026 bong-water-water-bong
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# 1bit OS power profile (read by 1bit-board from 1bit-board.service). Defaults are the development
# box's: the appliance is the same board and pad class. SKIP_POWER=1 leaves power alone entirely.
# The fan trip points are the first thing to revisit on a hotter unit.
MODE=performance
FAST_LIMIT=90000
SLOW_LIMIT=90000
SLOW_TIME=5
TCTL_LIMIT=105000
BOOST_TEMP=70
BOOST_LEVEL=4
LEVEL5_TEMP=82
SKIP_POWER=0
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Our own signed repository: the engine, Lemonade, the kernel and modules, the board tools and the
# appliance meta package. Trust comes from the keyring file alone (signed-by), never from apt-key or
# [trusted=yes].
deb [signed-by=/usr/share/keyrings/1bit-archive-keyring.gpg] https://1bit.gg/apt stable main
8 changes: 8 additions & 0 deletions os/v2/debian/1bit-appliance/files/etc/issue
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
1bit OS, Lemonade Server appliance
Lemonade Server by AMD, running on the 1bit engine

Lemonade ................ http://<this-box>:13305 (API key: /etc/1bit/lemonade.env)
1bit-release-check ...... PASS/FAIL for this boot, one line per check
1bit-selftest ........... prove the engine answers
1bit-board status ....... fans and power, on the boards we know
apt update && apt upgrade the box updates from 1bit.gg/apt
14 changes: 14 additions & 0 deletions os/v2/debian/1bit-appliance/files/etc/motd
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
1bit OS, Lemonade Server appliance
Lemonade Server by AMD, running on the 1bit engine

The console is root, on this machine. What is here, and what to run:

1bit-release-check PASS/FAIL for this boot (mode, kernel, Secure Boot, GPU, NPU,
Lemonade with its key, the catalog entries, a chat, the licences)
1bit-selftest the engine answers, and where it ran
lemonade list the models; models go in /data/models
journalctl -u 1bit-lemonade -f Lemonade's log
apt update && apt upgrade update from 1bit.gg/apt (signed repository)

The models, Lemonade's backends and configuration, and the SSH keys live on the 1BIT-DATA
partition, mounted at /data: they survive an update, a reinstall of the system does not touch them.
19 changes: 19 additions & 0 deletions os/v2/debian/1bit-appliance/files/etc/profile.d/1bit.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright 2026 bong-water-water-bong
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# PATH for the appliance's own commands, and nothing else that could surprise a login shell.
case ":$PATH:" in
*:/opt/1bit:*) ;;
*) PATH="/opt/1bit:/opt/lemonade/bin:$PATH"; export PATH ;;
esac
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright 2026 bong-water-water-bong
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Every wired interface does DHCP: the appliance is reached over the network (Lemonade on 13305).
[Match]
Name=en* eth*

[Network]
DHCP=yes
IPv6AcceptRA=yes
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright 2026 bong-water-water-bong
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# The console is the appliance's face: autologin root on tty1, the banner above it. Same behaviour as
# the BusyBox image had, done the systemd way.
[Service]
ExecStart=
ExecStart=-/sbin/agetty --autologin root --noclear %I $TERM
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright 2026 bong-water-water-bong
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# A fresh install has no SSH host keys yet: 1bit-first-boot generates them, so sshd must not start
# before it has. Ordering only - this drop-in never disables ssh.
[Unit]
Wants=1bit-first-boot.service
After=1bit-first-boot.service
30 changes: 30 additions & 0 deletions os/v2/debian/1bit-appliance/files/usr/lib/1bit/ensure-env.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/bin/sh
# Copyright 2026 bong-water-water-bong
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# First-boot state Lemonade cannot start without: the API key. Idempotent, so it runs as the service's
# ExecStartPre on every boot and the key never changes underneath the owner.
set -u
env=/etc/1bit/lemonade.env
[ -s "$env" ] && exit 0
mkdir -p /etc/1bit
key=$(head -c 32 /dev/urandom | od -An -tx1 | tr -d ' \n')
umask 077
{
echo "# 1bit OS: Lemonade's environment. The API key is what release-check's lemonade row needs."
echo "LEMONADE_API_KEY=$key"
echo "LEMONADE_ADMIN_API_KEY=$key"
} > "$env"
chmod 600 "$env"
echo "1bit: wrote $env with a new LEMONADE_API_KEY"
26 changes: 26 additions & 0 deletions os/v2/debian/1bit-appliance/files/usr/lib/1bit/first-boot.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/bin/sh
# Copyright 2026 bong-water-water-bong
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# First boot of an installed 1bit OS: own SSH host keys, and the marker release-check reads for the
# mode row. On a live boot /etc/1bit/live exists instead and this is skipped by the unit's condition.
set -u
mkdir -p /etc/1bit
if [ ! -s /etc/ssh/ssh_host_ed25519_key ]; then
ssh-keygen -q -t ed25519 -N '' -f /etc/ssh/ssh_host_ed25519_key
fi
# the live image's public key is not this machine's identity
: > /etc/1bit/installed
if [ -s /etc/1bit/live ]; then rm -f /etc/1bit/live; fi
echo "1bit: first boot on this machine (SSH host key generated, /etc/1bit/installed written)"
Loading
Loading