update docs
This commit is contained in:
@@ -0,0 +1,276 @@
|
||||
# Internal storage and machine settings
|
||||
|
||||
Development reference and historical context. For current operating instructions, use the [user manual](../README.md). Acceptance applies only to the source and artifacts identified in each record.
|
||||
|
||||
|
||||
[Documentation index](README.md) · [Boot images](boot.md) · [Recovery](recovery.md)
|
||||
|
||||
The internal NVMe supplies the Pi's firmware boot files, independent recovery,
|
||||
and machine settings. SYSTEM remains a separate removable cartridge. Ordinary
|
||||
user files belong on DATA, not internal storage. No physical disk is written by
|
||||
any build command below; Pi/NVMe boot and power-loss tests remain deferred.
|
||||
|
||||
## Build the complete disk image
|
||||
|
||||
Build the component images first, in this order:
|
||||
|
||||
```sh
|
||||
make kernel
|
||||
make initramfs
|
||||
make boot-volume BOOT_MODE=production
|
||||
make recovery
|
||||
make internal-image
|
||||
```
|
||||
|
||||
The result is `out/fds-internal.img`, a **complete GPT disk image**. Its versioned
|
||||
build directory contains `layout.json`, source payload checksums, and readback
|
||||
verification. This differs from `out/fds-boot.img` (a raw FAT partition) and
|
||||
`out/fds-recovery.img` (a raw EROFS partition).
|
||||
|
||||
| Partition | Format | Default allocation | Purpose |
|
||||
| --- | --- | --- | --- |
|
||||
| 1: FDS_BOOT | FAT32, EFI system type | 512 MiB | Pi firmware, kernel, DTBs, configuration and initramfs |
|
||||
| 2: FDS_RECOVERY | EROFS | 1 GiB | Complete independent maintenance system |
|
||||
| 3: FDS_INTERNAL | ext4 | 256 MiB | Machine settings and explicitly saved diagnostics |
|
||||
|
||||
The builder pads the recovery partition without changing its EROFS contents,
|
||||
aligns partitions to 1 MiB, writes both GPT copies, verifies each payload, and
|
||||
checks the table independently with `sfdisk`. Internal ext4 is fully initialized
|
||||
before deployment. It contains root-owned `config/` and private `diagnostics/`.
|
||||
Unused capacity beyond this initial layout is not automatically expanded.
|
||||
|
||||
For a 2 GiB recovery allocation or larger settings partition:
|
||||
|
||||
```sh
|
||||
./image/build-internal --recovery-mib 2048 --internal-mib 512
|
||||
```
|
||||
|
||||
Output directories supplied with `--output-directory` must already exist and be
|
||||
empty. The builder accepts ordinary image files, never a host block-device
|
||||
output. Final hardware provisioning and identity checks belong to the physical
|
||||
acceptance procedure; do not confuse a partition payload with the complete disk.
|
||||
|
||||
## Install the internal disk when hardware is available
|
||||
|
||||
This is a **deferred physical procedure**. The image and virtual NVMe workflow
|
||||
are software-tested; writing and booting the user's actual NVMe still require
|
||||
the hardware. Installation erases the selected disk, including any existing
|
||||
machine settings. Retain backups before replacing an existing installation.
|
||||
|
||||
Use an NVMe enclosure or another Linux machine that can access the target drive
|
||||
while the Pi is off. First verify a downloaded release using a separately trusted
|
||||
public key as described in [Release signatures](releases.md). Its complete disk
|
||||
is named `fds-internal-0.1.0.img`; a local build uses `out/fds-internal.img`.
|
||||
Use the complete disk image, not the separate BOOT or RECOVERY payload.
|
||||
|
||||
List disks before and after connecting the intended drive:
|
||||
|
||||
```sh
|
||||
lsblk -d -o NAME,PATH,MODEL,SERIAL,SIZE,TRAN,LOG-SEC
|
||||
ls -l /dev/disk/by-id/
|
||||
```
|
||||
|
||||
Match the physical model, serial and capacity. Choose a persistent **whole-disk**
|
||||
`/dev/disk/by-id/` path without a `-partN` suffix; never guess a `/dev/sdX` name.
|
||||
Unmount every target partition and disable any swap on it. Do not select the
|
||||
workstation's system disk. The current images require 512-byte logical sectors
|
||||
and a disk at least as large as the image; 4 KiB logical-sector media is not
|
||||
supported by this layout.
|
||||
|
||||
Open Bash (`bash`), replace both paths below, then run the block. It checks the
|
||||
selected disk again, requires a typed confirmation, writes and reads back the
|
||||
complete image, and relocates the backup GPT when the disk is larger than the
|
||||
image. It does not expand any partition or filesystem.
|
||||
|
||||
```bash
|
||||
(
|
||||
set -euo pipefail
|
||||
fds_image="$PWD/out/fds-internal.img"
|
||||
fds_disk=/dev/disk/by-id/REPLACE_WITH_THE_TARGET_DISK
|
||||
[[ -f "$fds_image" && -s "$fds_image" && -b "$fds_disk" ]]
|
||||
[[ $(lsblk -dnro TYPE "$fds_disk") == disk ]]
|
||||
[[ $(sudo blockdev --getss "$fds_disk") == 512 ]]
|
||||
fds_bytes=$(stat -Lc %s "$fds_image")
|
||||
(( $(sudo blockdev --getsize64 "$fds_disk") >= fds_bytes ))
|
||||
lsblk -p -o NAME,TYPE,MODEL,SERIAL,SIZE,MOUNTPOINTS "$fds_disk"
|
||||
if lsblk -nrpo MOUNTPOINTS "$fds_disk" | grep '[^[:space:]]' >/dev/null; then
|
||||
echo 'Target has mounted filesystems or swap; stop and release them first.' >&2
|
||||
exit 1
|
||||
fi
|
||||
if lsblk -nrpo TYPE "$fds_disk" | grep -Ev '^(disk|part)$' >/dev/null; then
|
||||
echo 'Target has device-mapper or other active descendants; stop.' >&2
|
||||
exit 1
|
||||
fi
|
||||
read -r -p "Type ERASE $fds_disk to erase this disk: " fds_confirmation
|
||||
[[ "$fds_confirmation" == "ERASE $fds_disk" ]]
|
||||
sudo dd if="$fds_image" of="$fds_disk" bs=4M conv=fsync status=progress
|
||||
sudo blockdev --flushbufs "$fds_disk"
|
||||
sudo cmp -n "$fds_bytes" "$fds_image" "$fds_disk"
|
||||
sudo sfdisk --lock=yes --relocate gpt-bak-std "$fds_disk"
|
||||
sudo sfdisk --verify "$fds_disk"
|
||||
sudo blockdev --flushbufs "$fds_disk"
|
||||
)
|
||||
```
|
||||
|
||||
Every command must succeed. The byte comparison occurs before relocating GPT,
|
||||
because relocation intentionally changes disk-table headers. GNU `dd`'s `fsync`
|
||||
flushes output before it returns; `sfdisk`'s `gpt-bak-std` moves the backup header
|
||||
to the end of the target. See the [GNU dd manual](https://www.gnu.org/s/coreutils/manual/html_node/dd-invocation.html)
|
||||
and [sfdisk manual](https://man7.org/linux/man-pages/man8/sfdisk.8.html).
|
||||
These commands use the already documented coreutils, diffutils and util-linux
|
||||
host tools; they do not add a target daemon.
|
||||
|
||||
Confirm that the disk shows `FDS_BOOT`, `FDS_RECOVERY` and `FDS_INTERNAL` in that
|
||||
order using `lsblk -o NAME,PARTLABEL,FSTYPE,MOUNTPOINTS`. Unmount anything the
|
||||
desktop automatically mounted, then safely disconnect the enclosure and install
|
||||
the NVMe in the powered-off Pi. Follow [EEPROM preparation](eeprom.md) for the
|
||||
separately reviewed NVMe boot settings.
|
||||
|
||||
Prepare the **first SYSTEM cartridge on the workstation** using the same guarded
|
||||
write block, with its two path assignments changed to the chosen SYSTEM image
|
||||
and a different, empty USB cartridge disk. For a local build select
|
||||
`out/fds-system-cli.img` or `out/fds-system-development.img`; release files are
|
||||
`fds-system-cli-0.1.0.img` and `fds-system-development-0.1.0.img`. They are
|
||||
alternative complete GPT images, each containing one `FDS_SYSTEM` partition.
|
||||
Readback and backup-GPT relocation apply to this disk too. Check its partition
|
||||
label, safely disconnect it, and insert exactly one SYSTEM cartridge in the Pi
|
||||
before normal boot. Subsequent cartridge creation and updates can use FDS's
|
||||
confirmed [media workflow](media-tools.md) after bay calibration.
|
||||
|
||||
On the first physical boot, check `fds info`, `fds machine status`, and
|
||||
`fds bays`. The supplied bay map is empty until calibration. Follow
|
||||
[physical acceptance](stress-testing.md) to measure ports, test the Dasung
|
||||
display, and record actual boot/shutdown behavior before relying on the machine.
|
||||
|
||||
## Configure the machine before building
|
||||
|
||||
Copy `config/machine/` to your own directory. It contains three files:
|
||||
|
||||
- `machine.toml`: `format = 1` and a short human-readable `name`.
|
||||
- `bays.toml`: the measured controller/port map described in
|
||||
[Cartridges and bay calibration](cartridges.md).
|
||||
- `hardware-catalog.toml`: optional USB identification names using the same schema
|
||||
as the base catalog. Entries are data and cannot run commands.
|
||||
|
||||
The supplied bay map is deliberately empty because the physical wiring has not
|
||||
been measured. Do not invent Pi USB paths. USB 2 and USB 3 companion ports need
|
||||
explicit aliases for the same bay.
|
||||
|
||||
```sh
|
||||
cp -a config/machine out/my-machine
|
||||
# Edit the three files in out/my-machine using your editor.
|
||||
make internal-image MACHINE_CONFIG=out/my-machine
|
||||
```
|
||||
|
||||
The builder compiles a native host copy of `fds` and uses the same strict parser
|
||||
as the target system. You can also validate or pack settings yourself:
|
||||
|
||||
```sh
|
||||
cargo build --locked --offline --release --target x86_64-unknown-linux-gnu -p fds-cli
|
||||
./target/x86_64-unknown-linux-gnu/release/fds machine validate out/my-machine
|
||||
./target/x86_64-unknown-linux-gnu/release/fds machine pack out/my-machine out/my-machine.json
|
||||
```
|
||||
|
||||
The three source files become one atomic `config/machine.json` document on
|
||||
FDS_INTERNAL. Names, lengths, bay aliases, catalog fields and unknown keys are
|
||||
validated before use. Do not put passwords or private keys in this configuration:
|
||||
its active snapshot is readable by the local FDS user.
|
||||
|
||||
## What happens at boot
|
||||
|
||||
The `machine-config` native s6 oneshot precedes `cartridged`. It does **not**
|
||||
precede the console or Dasung controller. It accepts exactly one non-removable
|
||||
NVMe disk with the three named partitions in the order above. USB lookalikes are
|
||||
ignored; multiple eligible NVMe disks are rejected instead of choosing by name.
|
||||
|
||||
The settings partition must be clean ext4 with the expected label. Loading uses
|
||||
`ro,noload,nosuid,nodev,noexec` in a private mount namespace, validates the entire
|
||||
settings bundle, copies it into `/run/fds/machine/`, and unmounts. No filesystem
|
||||
repair, journal replay, cache compilation or persistent write occurs during
|
||||
normal boot. The cartridge service uses that snapshot throughout this boot,
|
||||
including after a service restart.
|
||||
|
||||
If internal storage is missing, unclean, invalid or ambiguous, the service records
|
||||
an explanation and uses the immutable image's `/etc/fds/` defaults. The console
|
||||
still opens. Check the actual source before treating bays as calibrated:
|
||||
|
||||
```sh
|
||||
fds machine status
|
||||
fds --json machine status
|
||||
fds machine export /tmp/current-machine
|
||||
```
|
||||
|
||||
Export creates a new directory with the three editable source files. It never
|
||||
overwrites an existing directory. The status source is `internal_nvme` or
|
||||
`image_defaults`. A temporarily unavailable NVMe is not adopted later in the same
|
||||
boot; resolve the issue and reboot to load its settings. This prevents changing
|
||||
bay identities underneath active cartridge operations.
|
||||
|
||||
## Update settings from recovery
|
||||
|
||||
Bring the edited source directory on a DATA cartridge. At the local root
|
||||
`RECOVERY#` console, identify its bay with `fds bays`; healthy DATA is mounted
|
||||
read-only under `/run/fds/media/NN`. For example, if it is in BAY 02:
|
||||
|
||||
```sh
|
||||
fds machine validate /run/fds/media/02/my-machine
|
||||
fds machine install /run/fds/media/02/my-machine
|
||||
fds reboot
|
||||
```
|
||||
|
||||
Installation is restricted to root in the recovery image. It writes the complete
|
||||
validated bundle atomically, saves the old bytes as `config/previous.json`,
|
||||
flushes and unmounts the internal filesystem, and reports success only after
|
||||
those steps. A reboot activates the new settings. The currently running bay map
|
||||
is unchanged, so active media does not move to a different bay mid-operation.
|
||||
Keep a copy of your previous source directory on DATA or the build host to
|
||||
reinstall it if the new calibration is wrong.
|
||||
|
||||
An invalid existing JSON document can be replaced this way. Wrong ownership,
|
||||
symlinks, an unclean filesystem or a damaged directory require offline filesystem
|
||||
maintenance first. Recovery does not automatically repair internal NVMe; its
|
||||
`fds recovery repair` command is deliberately limited to DATA cartridges.
|
||||
|
||||
## Save and retrieve diagnostics
|
||||
|
||||
Logs and boot records stay in RAM by default. Root may explicitly save a file
|
||||
of up to 16 MiB. Saved names cannot contain paths, and existing names are refused.
|
||||
These operations mount internal ext4 only for the operation and then unmount it.
|
||||
For example, from recovery:
|
||||
|
||||
```sh
|
||||
fds --json boot-profile >/tmp/boot.json
|
||||
fds machine store boot-first.json /tmp/boot.json
|
||||
fds --json bays >/tmp/cartridge-inventory.json
|
||||
fds machine store cartridges-first.json /tmp/cartridge-inventory.json
|
||||
bash /usr/share/fds/capture-hardware /tmp/hardware-capture
|
||||
tar -C /tmp -czf /tmp/hardware-capture.tar.gz hardware-capture
|
||||
fds machine store hardware-first.tar.gz /tmp/hardware-capture.tar.gz
|
||||
fds machine fetch boot-first.json /tmp/retrieved-boot.json
|
||||
```
|
||||
|
||||
Use distinct names for subsequent sessions. A failed flush or unmount is an
|
||||
error, not a successful save. These are machine diagnostics; do not use this
|
||||
facility as ordinary user storage. The saved cartridge inventory is a persistent
|
||||
diagnostic snapshot, including metadata already inspected during this boot.
|
||||
Retrieve it with `fds machine fetch cartridges-first.json /tmp/saved-inventory.json`.
|
||||
The daemon's live metadata cache remains volatile and is rebuilt from currently
|
||||
attached devices; saved snapshots are never used to authorize media actions.
|
||||
Together, explicit boot reports, inventory snapshots and hardware captures provide
|
||||
the boot history, cached metadata and diagnostics assigned to FDS_INTERNAL in
|
||||
master-plan section 12, without adding internal writes to startup or shutdown.
|
||||
|
||||
## Dependencies and validation
|
||||
|
||||
No new target package or Rust crate is required. The host image-tool prefix adds
|
||||
`e2fsprogs` for ext4 creation, inspection and validation; it already supplies FAT
|
||||
and EROFS tools. A private unprivileged user namespace gives created files root
|
||||
ownership without requiring a root build session.
|
||||
|
||||
`make internal-test` exercises the actual packaged runtime in ARM VMs with
|
||||
virtual NVMe. Acceptance evidence belongs in [M12 validation](m12-validation.md);
|
||||
a passing VM does not verify the Pi EEPROM, PCIe path or physical flash durability.
|
||||
|
||||
The Linux [ext4 mount documentation](https://www.kernel.org/doc/html/latest/admin-guide/ext4.html)
|
||||
explains why read-only loading also disables journal replay. Filesystem creation
|
||||
options follow the upstream [mke2fs manual](https://man7.org/linux/man-pages/man8/mke2fs.8.html).
|
||||
Reference in New Issue
Block a user