feat: add three-profile STEM container workflow
This commit is contained in:
+250
-129
@@ -1,162 +1,283 @@
|
||||
# Kontenery i debug
|
||||
|
||||
`rvctl` integruje workspace z narzędziem `rv32i-hazard3-student-env`.
|
||||
Środowisko ma dwa profile kontenerów:
|
||||
Ten dokument opisuje wdrożony kontrakt kontenerów i jawnie wskazuje pozostałe
|
||||
etapy. Pełne
|
||||
uzasadnienie, przepływ ucznia i kolejność wdrożenia są w
|
||||
`doc/architecture-plan.md`.
|
||||
|
||||
- `rv32i` - docelowe środowisko RISC-V/Hazard3 z `nvim`, `tmux`,
|
||||
`gdb-multiarch`, toolchainem RISC-V i symulatorem Hazard3.
|
||||
- `host` - natywne środowisko na architekturze hosta z `clang`, `gcc`, `gdb`,
|
||||
opcjonalnie `lldb`, `valgrind`, `nvim` i `tmux`.
|
||||
Stan obecny:
|
||||
|
||||
Profile są uruchamiane jako oddzielne usługi `docker compose`, więc zależności
|
||||
RISC-V i zależności natywnego debugowania nie mieszają się ze sobą.
|
||||
- `stemctl` uruchamia trzy profile przez rootless Podman;
|
||||
- repo środowiska zawiera wieloetapowy `Dockerfile` i Compose z dokładnie
|
||||
trzema usługami; gotowych obrazów nie publikujemy;
|
||||
- profil RP2350 zawiera oba toolchainy, Pico SDK, FreeRTOS, OpenOCD i picotool;
|
||||
- `rvctl`, `host` i `rv32i` pozostają aliasami okresu zgodności.
|
||||
|
||||
## Szybki przepływ
|
||||
## Profile docelowe
|
||||
|
||||
| Profil | Alias przejściowy | Service | Target Dockerfile | Targety |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `native-amd64` | `host` | `native-amd64` | `native-amd64-final` | `native` |
|
||||
| `hazard3-sim` | `rv32i` | `hazard3-sim` | `hazard3-sim-final` | `hazard3-baremetal`; `hazard3-freertos` po BSP timer/IRQ |
|
||||
| `rp2350` | brak | `rp2350` | `rp2350-final` | `rp2350-rv`, `rp2350-arm` |
|
||||
|
||||
Wszystkie targety dziedziczą stage `dev-ui-base`. Nie jest on osobnym
|
||||
kontenerem roboczym.
|
||||
|
||||
## Jednolity kontrakt CLI
|
||||
|
||||
```bash
|
||||
./rvctl env list
|
||||
./rvctl env sync
|
||||
./rvctl env build rv32i
|
||||
./rvctl env build host
|
||||
stemctl env list
|
||||
stemctl env ensure native-amd64
|
||||
stemctl env ensure hazard3-sim
|
||||
stemctl env ensure rp2350
|
||||
|
||||
./rvctl debug rv32i inf bss 1
|
||||
./rvctl debug host inf bss 1
|
||||
./rvctl run host inf bss 1
|
||||
./rvctl shell rv32i inf bss
|
||||
./rvctl shell host inf bss
|
||||
stemctl build native-amd64 inf bss 1
|
||||
stemctl test native-amd64 inf bss 1
|
||||
stemctl run native-amd64 inf bss 1
|
||||
stemctl debug native-amd64 inf bss 1
|
||||
|
||||
stemctl build hazard3-sim inf bss 1 --target hazard3-baremetal
|
||||
stemctl test hazard3-sim inf bss 1 --target hazard3-baremetal
|
||||
stemctl run hazard3-sim inf bss 1
|
||||
stemctl debug hazard3-sim inf bss 1
|
||||
|
||||
stemctl build rp2350 inf bss 1 --target rp2350-rv
|
||||
stemctl deploy rp2350 inf bss 1 --target rp2350-rv --device /dev/bus/usb/001/006
|
||||
stemctl debug rp2350 inf bss 1 --target rp2350-rv --device /dev/bus/usb/001/006
|
||||
```
|
||||
|
||||
Jeżeli `workspace.json` ma ustawione domyślne wartości `defaults.series`,
|
||||
`defaults.card` i `defaults.task`, można używać krótszych komend:
|
||||
|
||||
```bash
|
||||
./rvctl debug rv32i
|
||||
./rvctl debug host
|
||||
./rvctl debug rv32i 4
|
||||
./rvctl debug host 4
|
||||
```
|
||||
|
||||
## `env list`
|
||||
|
||||
Pokazuje dostępne profile i bieżący katalog narzędzia:
|
||||
|
||||
```bash
|
||||
./rvctl env list
|
||||
```
|
||||
|
||||
Typowy wynik:
|
||||
Selektory `series card task` są opcjonalne, jeśli ustawiono wartości domyślne.
|
||||
Każda akcja obsługuje:
|
||||
|
||||
```text
|
||||
profile service image status purpose
|
||||
rv32i env edu-inf/rv32i-hazard3-env:latest ready RV32I/Hazard3 nvim + gdb-multiarch
|
||||
host host edu-inf/rv32i-hazard3-host-env:latest ready native host clang/gcc + gdb/lldb
|
||||
--instance NAME
|
||||
--target NAME
|
||||
--editor nvim|vim
|
||||
--dry-run
|
||||
```
|
||||
|
||||
## `env sync`
|
||||
`debug` dodatkowo może przyjąć `--pane TARGET` i `--device PATH`. `deploy`
|
||||
przyjmuje `--device PATH` oraz `--backend probe|bootsel`. `probe list --json`
|
||||
ma stabilny format maszynowy, a akcje zapisują maszynowy `result.json`.
|
||||
|
||||
Klonuje albo aktualizuje repo środowiska do:
|
||||
`deploy` jest capability wyłącznie targetów sprzętowych RP2350. W
|
||||
`hazard3-sim` artefakt ładuje `run` albo `debug`; osobne `deploy` zwraca
|
||||
`unsupported`.
|
||||
|
||||
## Capabilities zamiast wyjątków w kodzie
|
||||
|
||||
Launcher nie powinien zawierać warunków typu „jeśli profil rv32i, uruchom ten
|
||||
konkretny skrypt”. Profil publikuje capabilities i adaptery:
|
||||
|
||||
```json
|
||||
{
|
||||
"profile": "rp2350",
|
||||
"targets": ["rp2350-rv", "rp2350-arm"],
|
||||
"actions": {
|
||||
"build": {"requires": []},
|
||||
"test": {"requires": []},
|
||||
"run": {"requires": ["matching-deploy-record"]},
|
||||
"debug": {"requires": ["probe"]},
|
||||
"deploy": {"requires": ["probe"]},
|
||||
"shell": {"requires": []}
|
||||
},
|
||||
"debug_backends": ["openocd"],
|
||||
"devices": ["debug-probe", "target-usb-optional"]
|
||||
}
|
||||
```
|
||||
|
||||
Karta deklaruje target, a profil dostarcza implementację. Brak capability jest
|
||||
normalnym, maszynowo czytelnym wynikiem `unsupported`, nie awarią launchera.
|
||||
|
||||
## Wspólny interfejs w kontenerze
|
||||
|
||||
Każdy profil zapewnia kanoniczny dispatcher:
|
||||
|
||||
```text
|
||||
~/dev/workspace/rv/tools/rv32i-hazard3-student-env
|
||||
/usr/local/bin/stem-entry
|
||||
/usr/local/bin/stem-card
|
||||
```
|
||||
|
||||
Komenda:
|
||||
Dispatcher przyjmuje `build/test/run/debug/deploy`; manifest może zwrócić
|
||||
`unsupported`, jeżeli akcja nie ma sensu dla targetu.
|
||||
Skrypty korzystają wyłącznie z manifestu karty i zmiennych kontraktowych:
|
||||
|
||||
```text
|
||||
STEM_WORKSPACE=/workspace
|
||||
STEM_PROFILE=hazard3-sim
|
||||
STEM_TARGET=hazard3-freertos
|
||||
STEM_CARD=inf/bss
|
||||
STEM_TASK=task1
|
||||
STEM_INSTANCE=hazard3-sim-inf-bss-t1
|
||||
STEM_STATE_DIR=/workspace/.stem/instances/<instance>
|
||||
STEM_ARTIFACT_DIR=/workspace/.stem/artifacts/<profile>/<target>/<task>
|
||||
```
|
||||
|
||||
Stare `RV_*` są czytane wyłącznie jako fallback w okresie migracji.
|
||||
|
||||
## Montowania
|
||||
|
||||
Minimalny zestaw:
|
||||
|
||||
| Źródło hosta | Cel | Tryb |
|
||||
| --- | --- | --- |
|
||||
| repo karty | `/workspace` | `rw` |
|
||||
| cache profilu | `/cache` | `rw`, osobny named volume |
|
||||
| `$XDG_RUNTIME_DIR/stem` | ta sama krótka ścieżka | `rw` |
|
||||
| konkretne urządzenie probe | urządzenie | tylko profil `rp2350` |
|
||||
|
||||
Nie montujemy:
|
||||
|
||||
- `$HOME/.ssh`;
|
||||
- pliku tokenów;
|
||||
- całego `/dev`;
|
||||
- socketu Docker/Podman;
|
||||
- katalogu domowego hosta;
|
||||
- repo innych uczniów.
|
||||
|
||||
Repo jest własnością użytkownika hosta. Rootless Podman uruchamia kontener z
|
||||
mapowaniem UID/GID (`keep-id` albo równoważnym), żeby artefakty nie powstawały
|
||||
jako root.
|
||||
|
||||
## Layout tmuxa i Neovima
|
||||
|
||||
W każdym profilu po `debug` powstaje ten sam układ:
|
||||
|
||||
```text
|
||||
work
|
||||
├─ pane 0 (góra): jeden Neovim
|
||||
│ ├─ okno lewe: Termdebug/GDB dashboard
|
||||
│ └─ okno prawe: edytor źródeł i nvim-dap
|
||||
└─ pane 1 (dół): bash w /workspace
|
||||
```
|
||||
|
||||
Lewa i prawa część są oknami Neovima, nie osobnymi pane'ami tmuxa. Hazard3
|
||||
trzyma symulator w ukrytym oknie tmuxa `tb`. Prefix tmuxa to `Ctrl-s`. Neovim
|
||||
ma identyczne mapowania Termdebug i nvim-dap.
|
||||
Opis backendu GDB pochodzi z jednego target descriptor, dzięki czemu oba
|
||||
frontendy nie rozjeżdżają się.
|
||||
|
||||
## Debugger według profilu
|
||||
|
||||
### `native-amd64`
|
||||
|
||||
- GDB jest backendem domyślnym;
|
||||
- LLDB pozostaje dostępny ręcznie w shellu; wspólny interfejs Termdebug używa GDB;
|
||||
- przed debugowaniem powstaje build `-g3 -O0`;
|
||||
- `test` uruchamia co najmniej ASan i UBSan.
|
||||
|
||||
### `hazard3-sim`
|
||||
|
||||
- obecny codzienny backend: `fast-rsp`, jawnie opisany jako uproszczony;
|
||||
- docelowy, planowany backend: `fast-dm`, czyli GDB RSP -> APB/DMI ->
|
||||
prawdziwy DM Hazard3;
|
||||
- gate zgodności: OpenOCD + JTAG remote-bitbang;
|
||||
- planowany simulatorowy BSP FreeRTOS ma używać timera 1 kHz, czyli ticka co
|
||||
150 000 cykli przy zegarze gościa 150 MHz; nie jest jeszcze wdrożony.
|
||||
|
||||
### `rp2350`
|
||||
|
||||
- OpenOCD/probe dla targetów RISC-V i ARM;
|
||||
- picotool dla informacji, resetu i operacji wspieranych przez RP2350;
|
||||
- `deploy` zawsze raportuje probe, target, artefakt i jego SHA-256;
|
||||
- launcher nie wybiera pierwszego przypadkowego probe, gdy widocznych jest
|
||||
kilka urządzeń.
|
||||
|
||||
Zewnętrzny debug probe i natywne USB płytki są rozdzielone. Standardowy
|
||||
debug/flash używa stabilnego probe, który nie re-enumeruje się przy resecie
|
||||
targetu. BOOTSEL/picotool jest opcjonalną, krótkotrwałą akcją z tego samego
|
||||
profilu: launcher wykrywa bieżący węzeł USB przed każdą fazą i ponownie po
|
||||
re-enumeracji. Nie przekazuje całego `/dev`. Build i test offline nie wymagają
|
||||
żadnego urządzenia.
|
||||
|
||||
`run rp2350` wymaga zgodnego rekordu ostatniego deploy dla wybranej płytki i
|
||||
artefaktu. Bez niego odmawia wykonania, chyba że użytkownik jawnie zaakceptuje
|
||||
istniejący firmware. Zapobiega to testowaniu starego programu.
|
||||
|
||||
## Instancje i sockety MCP
|
||||
|
||||
Stabilna nazwa logiczna:
|
||||
|
||||
```text
|
||||
<profile>-<series>-<card>-<task>
|
||||
```
|
||||
|
||||
Aktualny container ID jest pobierany z `podman inspect`. Pełne nazwy logiczne
|
||||
są w labels i registry, a sockety używają krótkich kluczy:
|
||||
|
||||
```text
|
||||
$XDG_RUNTIME_DIR/stem/<thread-key>/<instance-key>/<cid12>/t.sock
|
||||
$XDG_RUNTIME_DIR/stem/<thread-key>/<instance-key>/<cid12>/n.sock
|
||||
$XDG_RUNTIME_DIR/stem/<thread-key>/<instance-key>/current
|
||||
```
|
||||
|
||||
Klucze wątku i instancji mają 12 znaków, `cid12` jest prefiksem bieżącego ID.
|
||||
Registry przechowuje pełne wartości. Host i kontener używają tej samej ścieżki,
|
||||
a całkowita długość musi być mniejsza lub równa 100 bajtów, pozostawiając
|
||||
zapas względem linuksowego limitu `sun_path`.
|
||||
|
||||
Wrapper MCP otrzymuje `instance`, sprawdza label kontenera, aktualny ID i typ
|
||||
socketu. Dopiero wtedy łączy się z tmuxem albo Neovimem. Pozwala to Codexowi
|
||||
obsługiwać kilka kontenerów bez przypadkowego wejścia do starej sesji.
|
||||
|
||||
Publiczne wejścia launchera to `stemctl mcp tmux INSTANCE` oraz
|
||||
`stemctl mcp nvim INSTANCE`. Hostowy wrapper wykonuje wyłącznie resolver i
|
||||
`podman exec`; sam serwer wraz z przypiętymi zależnościami działa wewnątrz
|
||||
zweryfikowanego kontenera. Neovim MCP publikuje również stan i komendy
|
||||
Termdebug/nvim-dap.
|
||||
|
||||
MCP nie jest czwartym kontenerem. Bridge jest częścią `dev-ui-base`, a hostowy
|
||||
resolver jest częścią `stem-launcher`.
|
||||
|
||||
## Cykl życia
|
||||
|
||||
```bash
|
||||
./rvctl env sync
|
||||
./rvctl env sync --dry-run
|
||||
stemctl start hazard3-sim inf bss 1
|
||||
stemctl status hazard3-sim --instance hazard3-sim-inf-bss-t1
|
||||
stemctl attach hazard3-sim --instance hazard3-sim-inf-bss-t1
|
||||
stemctl stop hazard3-sim --instance hazard3-sim-inf-bss-t1
|
||||
stemctl rm hazard3-sim --instance hazard3-sim-inf-bss-t1
|
||||
```
|
||||
|
||||
Jeżeli tego repo jeszcze nie ma w workspace, `rvctl` używa fallbacku z
|
||||
`~/dev/edu/repos/rv/rv32i-hazard3-env`, o ile jest dostępny.
|
||||
`start` jest idempotentne dla zgodnej instancji. Jeżeli zmienił się lokalny ID
|
||||
wyniku builda albo konfiguracja targetu, launcher odtwarza kontener.
|
||||
`stop/start` zachowuje container ID; `rm/start` tworzy nowy ID i nowy katalog
|
||||
socketów. Stan karty pozostaje na hoście.
|
||||
|
||||
## `env build`
|
||||
## Zdalny komputer
|
||||
|
||||
Buduje wybrany profil kontenera:
|
||||
Na komputer ucznia wchodzimy przez SSH z kluczem i uruchamiamy `stemctl` tam:
|
||||
|
||||
```bash
|
||||
./rvctl env build rv32i
|
||||
./rvctl env build host
|
||||
ssh uczen-lab
|
||||
cd ~/dev/workspace/stem/tools/stem-launcher
|
||||
./stemctl status hazard3-sim --instance hazard3-sim-inf-bss-t1
|
||||
./stemctl debug hazard3-sim inf bss 1
|
||||
```
|
||||
|
||||
Wariant `--dry-run` pokazuje dokładną komendę bez uruchamiania Dockera:
|
||||
GDB, UART i MCP nasłuchują na loopback albo Unix socketach. Jeżeli potrzebny
|
||||
jest dostęp z komputera nauczyciela, launcher generuje jawne polecenie tunelu
|
||||
SSH. Nie otwiera portów na `0.0.0.0`.
|
||||
|
||||
```bash
|
||||
./rvctl env build host --dry-run
|
||||
```
|
||||
## Budowanie i cache
|
||||
|
||||
## `debug`
|
||||
`dev-ui-base` zawiera przypięte binaria/dependencies UI, lecz nie zawiera
|
||||
często zmienianych `configs/` i entrypointów. Trzy toolchainowe stage'e
|
||||
dziedziczą z niego, instalują ciężkie SDK/kompilatory, a dopiero finalne stage'e
|
||||
kopiują konfigurację UI i skrypty. Kod karty jest montowany, nie kopiowany.
|
||||
Zmiana entrypointu, dashboardu albo mapowania klawisza nie może invalidować
|
||||
warstwy pobierającej toolchain.
|
||||
|
||||
Uruchamia debugowanie zadania w wybranym profilu.
|
||||
## Status implementacji
|
||||
|
||||
```bash
|
||||
./rvctl debug rv32i inf bss 1
|
||||
./rvctl debug host inf bss 1
|
||||
```
|
||||
|
||||
W profilu `rv32i` startuje środowisko Hazard3: symulator, `gdb-multiarch` i
|
||||
`nvim` w sesji `tmux`.
|
||||
|
||||
W profilu `host` wybrane źródło C jest kompilowane natywnie z debug info, a
|
||||
potem uruchamiane w `gdb` obok `nvim`.
|
||||
Ten profil jest przeznaczony dla tasków C z funkcją `main`; taski czysto
|
||||
asemblerskie nadal debugujemy w profilu `rv32i`.
|
||||
|
||||
Przydatne warianty:
|
||||
|
||||
```bash
|
||||
./rvctl debug rv32i bss 4
|
||||
./rvctl debug host bss 4
|
||||
./rvctl debug host 4 --editor vim
|
||||
./rvctl debug host 4 --instance host-bss-t4
|
||||
./rvctl debug rv32i 4 --pane 0
|
||||
./rvctl debug rv32i 4 pane node:0
|
||||
./rvctl debug host 4 --dry-run
|
||||
```
|
||||
|
||||
`--pane TARGET` oraz forma `pane TARGET` wysyłają wygenerowaną komendę do
|
||||
istniejącego panelu tmuxa na hoście przez `tmux send-keys`. Skróty targetów:
|
||||
|
||||
- `0` - panel `0` w bieżącym oknie,
|
||||
- `node:0` - okno `node`, panel `0`,
|
||||
- `%3` albo `:node.0` - natywny target tmuxa.
|
||||
|
||||
## `run`
|
||||
|
||||
Na razie `run` jest wdrożone dla profilu `host`. Buduje wybrany task natywnie i
|
||||
uruchamia wynikowy program:
|
||||
|
||||
```bash
|
||||
./rvctl run host inf bss 1
|
||||
./rvctl run host 4
|
||||
```
|
||||
|
||||
Dla profilu `rv32i` używamy obecnie `debug rv32i`, bo przepływ RISC-V zakłada
|
||||
symulator Hazard3 i GDB.
|
||||
|
||||
## `shell`
|
||||
|
||||
Otwiera shell w wybranym profilu kontenera z podmontowaną kartą:
|
||||
|
||||
```bash
|
||||
./rvctl shell rv32i inf bss
|
||||
./rvctl shell host inf bss
|
||||
```
|
||||
|
||||
## Selektory
|
||||
|
||||
Komendy `debug`, `run` i `shell` używają tych samych skrótów co `tasks`:
|
||||
|
||||
```bash
|
||||
./rvctl debug host 1
|
||||
./rvctl debug host bss 1
|
||||
./rvctl debug host inf bss 1
|
||||
```
|
||||
|
||||
`rvctl` rozwiązuje `1` do właściwego zadania, na przykład
|
||||
`task1_bss`, na podstawie plików w `src/tasks`.
|
||||
|
||||
## Starsza komenda
|
||||
|
||||
`tmux-container` zostaje jako alias kompatybilności dla starszego trybu
|
||||
shellowego. Nowe przykłady powinny używać `debug`, `run`, `shell` i `env`.
|
||||
| Element | Status |
|
||||
| --- | --- |
|
||||
| `native-amd64` | wdrożony i sprawdzony z ASan/UBSan |
|
||||
| `hazard3-sim` | wdrożony dla bare metal; `fast-dm` i BSP FreeRTOS są następne |
|
||||
| `rp2350` | wdrożony; FreeRTOS 1 kHz buduje ELF/UF2 dla RV i ARM, hardware gate wymaga ACL probe |
|
||||
| `stemctl` | wdrożony; `rvctl` jest wrapperem zgodności |
|
||||
| pobieranie kart z Git | istnieje w `rvctl` |
|
||||
| `build/test/run/debug/deploy` | wdrożony dispatcher manifestu i `result.json` |
|
||||
| sockety tmux/nvim | wdrożone z `thread12/instance12/container12` i resolverem |
|
||||
| zdalny SSH | kontrakt zaprojektowany, smoke test do dodania |
|
||||
|
||||
Reference in New Issue
Block a user