mirror of
https://git.k-space.ee/arti/vt1200.git
synced 2026-10-30 12:03:54 +02:00
131 lines
5.5 KiB
Markdown
131 lines
5.5 KiB
Markdown
# LOADER_CROSS — the boundary between the TFTP transport and the COFF loader
|
||
|
||
Append-only. Each entry starts with a timestamp header.
|
||
|
||
---
|
||
|
||
## 2026-10-18 — COFF loader interface (loader half complete)
|
||
|
||
The loader half is implemented and tested with debugger-poked images. This entry
|
||
is the contract the transport half must satisfy; it is written by the loader
|
||
owner for the transport owner.
|
||
|
||
### What the transport hands over
|
||
|
||
1. **The complete linked COFF image in RAM.** Not the `.obj`; the GSPLNK `-a`
|
||
output (`*.out`), byte-for-byte, 510–774 bytes for the current test apps.
|
||
The transport owns the receive buffer and passes its **bit address** and
|
||
**byte length**. The loader does not allocate or receive the image itself.
|
||
2. **The loader resident at bit `0x01880000`.** The raw
|
||
`dwt/loader/build/loader.bin` (1220 bytes, `.text` size `0x2620` bits) is
|
||
position-dependent; it must be placed exactly there. A transport that
|
||
includes the loader in its own payload must copy it to that address first
|
||
(and must not overwrite it).
|
||
3. **A descriptor** at bit `0x01882C00` (or at an address passed in `A8`).
|
||
Offsets are **bytes**; in the loader's assembly they are bits (+0, +0x10,
|
||
+0x20, +0x40, +0x60):
|
||
|
||
```
|
||
DESC + 0x00 u16 0x4C44 "LD" ) both magic words must match
|
||
DESC + 0x02 u16 0x5231 "R1" )
|
||
DESC + 0x04 u32 buf bit address of the COFF image
|
||
DESC + 0x08 u32 len image length in bytes
|
||
DESC + 0x0C u32 mode 1 = return to caller
|
||
```
|
||
|
||
`mode = 1` is the transport mode. `mode = 0` is the debugger mode: the loader
|
||
restores the interrupted context and jumps to the PC the harness saved; a
|
||
transport must not use it.
|
||
|
||
4. **A call**, using the firmware convention the loader itself uses for
|
||
`create_process`:
|
||
|
||
```
|
||
move a14, -*sp, 1
|
||
movi DESC_ADDR, a14, L ; no descriptor args to push, but keep A14
|
||
calla 01880000h ; A8 = 0 (fixed descriptor) or DESC_ADDR
|
||
```
|
||
|
||
`A8` may be 0 (use the fixed descriptor at `0x01882C00`) or the descriptor's
|
||
bit address. Any other value falls back to the fixed descriptor if it does
|
||
not carry the magic.
|
||
|
||
### What the loader returns
|
||
|
||
* `A8 = RESULT_STATUS`: **0 = success**, otherwise an error code (table below).
|
||
* The **result block** at bit `0x01882D00` (32-bit cells at +0x20 intervals):
|
||
|
||
| offset | meaning |
|
||
|---:|---|
|
||
| `+0x000` | status (same value as `A8`) |
|
||
| `+0x020` | entry passed to `create_process` (bits) |
|
||
| `+0x040` | `.text` paddr / `+0x060` size (bits) |
|
||
| `+0x080` | `.data` paddr / `+0x0A0` size |
|
||
| `+0x0C0` | `.bss` paddr / `+0x0E0` size |
|
||
| `+0x100` | relocation records seen |
|
||
| `+0x120` | PCB returned by `create_process` |
|
||
| `+0x140` | section count |
|
||
| `+0x160` | descriptor length (bytes) |
|
||
| `+0x180` | loader base `0x01880000` |
|
||
|
||
* On success the app is already a **first-class process** (a PCB exists and the
|
||
child is scheduled when the caller yields). The loader does not wait for the
|
||
app and does not return its exit status.
|
||
|
||
### Address policy: the loader picks, the transport does not
|
||
|
||
The transport passes **buffer and length only**. The load address of every
|
||
section comes from the COFF section headers (bit addresses); the entry comes
|
||
from the optional header (`entry`, else `textstart`). There is no
|
||
"load-address" argument. The linked image is position-dependent (GSPLNK
|
||
resolves all references and emits `nreloc = 0`), so the transport must not move
|
||
the sections after the fact and must not send a `.obj`.
|
||
|
||
The loader checks, before copying:
|
||
|
||
* section size is a whole number of 16-bit words;
|
||
* the section bytes are inside `[buf, buf+len)`;
|
||
* `0x100 <= paddr` and `paddr + size <= 0x2000000` bits (4 MiB RAM);
|
||
* no overlap with `[0x01880000,0x01883200)` (loader page) or the COFF buffer;
|
||
* the range lies inside one block of the **global** free list (head bit
|
||
`0x1E8AC0`; block `{u32 size_bits; …; u32 next@+0x20}`, user at `+0x40`).
|
||
|
||
The free-list check is a **check, not a reservation**. The transport should
|
||
choose app link addresses away from the allocator's growth path (the large free
|
||
block starts at byte `0x12191A` and grows upward; the current apps live at byte
|
||
`0x318000`+). The transport's own code, stack and receive buffer must also stay
|
||
out of the target sections; the loader cannot see them.
|
||
|
||
### Status codes
|
||
|
||
| code | meaning |
|
||
|---:|---|
|
||
| 0 | success, child created |
|
||
| 1 | bad descriptor (magic) |
|
||
| 2 | truncated COFF / section headers past `len` |
|
||
| 3 | bad COFF magic (not `0x0090`) |
|
||
| 4 | section size not a whole number of 16-bit words |
|
||
| 5 | target outside RAM |
|
||
| 6 | target overlaps the loader page or the COFF buffer |
|
||
| 7 | relocation records present (unsupported; the input is probably a `.obj`) |
|
||
| 8 | target not inside a global free-list block |
|
||
| 9 | no entry point |
|
||
| 10 | `create_process` returned 0 |
|
||
|
||
### Currently proven
|
||
|
||
* Debugger-poked `marker.coff` (`buf=0x01900000`, `len=510`, mode 0 and mode 1,
|
||
`A8=0` and `A8=DESC`): status 0, PCB `0x003FFBD0`, markers
|
||
`start=018C0000 data=DEADBEEF bss=0`, counter live.
|
||
* Debugger-poked `xhello.coff` (`len=774`, mode 0): status 0, entry
|
||
`0x01840000`, `stage=6`, window visible in `loader_frame2650.png`.
|
||
* `rela.obj` (`len=342`): status 7, `relocs=2`, nothing copied.
|
||
|
||
### Files the transport needs
|
||
|
||
* `dwt/loader/build/loader.bin` — raw loader to place at `0x01880000`.
|
||
* `dwt/loader/coff.py` — the host-side reference parser; the loader's field
|
||
offsets match it.
|
||
* `dwt/notes/LOADER.md` — the full COFF layout, the position-dependence
|
||
evidence and the loader algorithm.
|