docs: reorganise -- current reference gathered, finished work archived, superseded and dead ideas marked as such
docs/CLAUDE.md Phase 2, 2026-10-14. All moves by git mv; every archived file carries a header saying what it is, why, and where to look instead. - docs/reference/ (new): roadmap and versioning policy, M7.1, word-ACL design, kernel args, hosted acceptance test, dictionary, primitives, ontology, L8 table -- previously spread over docs/, docs/lithosananke/ and docs/03-architecture/. - docs/working/archive/historical/: finished work (session plan, test-gap audit, birthing plan, fix write-ups, the January architecture draft). - docs/working/archive/superseded/: the Hermes-VM Tripod docs and July Hermes designs (-> FABRIC-3.5/3.6), the StarForth roadmap, every working doc already flagged superseded or obsolete. - docs/working/archive/dead/: the hal_* target contract (never adopted), L4Re, metrics-and-knobs. - Papers and proposals into docs/working/papers/. - References rewritten across the repo (not logs/, not docs/patent/); CLAUDE.md's documentation section rewritten. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
1a4b163861
commit
7aed588f78
@@ -1,201 +0,0 @@
|
||||
// Moved from docs/src/platform-integration/L4RE_DICTIONARY_ALLOCATION.adoc to docs/working/scratch/src/platform-integration/L4RE_DICTIONARY_ALLOCATION.adoc on 2026-06-16 (docs reorg Phase 2)
|
||||
== Dictionary Allocation Strategy for L4Re
|
||||
:toc: left
|
||||
:toc-title: Contents
|
||||
:toclevels: 3
|
||||
xref:../README.adoc[← Back to Documentation Index]
|
||||
|
||||
|
||||
|
||||
=== Current Implementation
|
||||
|
||||
StarForth currently uses `+malloc()+` and `+free()+` from the host C
|
||||
library for dictionary entry allocation:
|
||||
|
||||
* *Location*: `+src/dictionary_management.c:228+`
|
||||
* *Function*: `+vm_create_word()+` uses `+malloc(total)+` to allocate
|
||||
DictEntry structures
|
||||
* *Cleanup*: `+FORGET+` uses `+free(e)+` to deallocate entries (line 554
|
||||
in defining_words.c)
|
||||
|
||||
This works fine for hosted environments but creates a dependency on libc
|
||||
heap allocator.
|
||||
|
||||
=== Why This Matters for L4Re/StarshipOS
|
||||
|
||||
==== Issues with Current Approach:
|
||||
|
||||
[arabic]
|
||||
. *Heap Dependency*: Requires full malloc implementation in L4Re
|
||||
environment
|
||||
. *Non-Deterministic*: Heap fragmentation and unpredictable allocation
|
||||
behavior
|
||||
. *Separate Address Space*: Dictionary entries live outside VM memory
|
||||
model
|
||||
. *Hard to Introspect*: Can’t dump entire VM state as single memory
|
||||
region
|
||||
|
||||
==== Benefits of VM-Based Allocation:
|
||||
|
||||
[arabic]
|
||||
. *Zero External Dependencies*: No libc malloc needed
|
||||
. *Deterministic*: Simple bump allocator, predictable behavior
|
||||
. *Unified Address Space*: Everything in one 5MB VM memory region
|
||||
. *Easy Snapshots*: Can serialize entire VM state
|
||||
. *Better for Microkernel*: Aligns with L4Re dataspace model
|
||||
|
||||
=== Recommended Approach for L4Re
|
||||
|
||||
==== Strategy: Conditional Compilation
|
||||
|
||||
Add a compile-time flag to switch between malloc and VM-based
|
||||
allocation:
|
||||
|
||||
[source,c]
|
||||
----
|
||||
// In dictionary_management.c
|
||||
#ifdef STARFORTH_VM_DICT_ALLOC
|
||||
/* VM-based allocation (for L4Re/embedded) */
|
||||
DictEntry *entry = dict_alloc_from_vm(vm, total);
|
||||
#else
|
||||
/* Standard malloc (for hosted environments) */
|
||||
DictEntry *entry = (DictEntry *) malloc(total);
|
||||
#endif
|
||||
----
|
||||
|
||||
==== Memory Layout (VM-Based Mode):
|
||||
|
||||
....
|
||||
vm->memory[0...VM_MEMORY_SIZE] (5MB):
|
||||
┌──────────────────────────────────────────┐
|
||||
│ Dictionary Headers (256KB) │ ← dict_headers_used grows up
|
||||
│ - DictEntry structures │
|
||||
│ - Allocated via dict_alloc() │
|
||||
├──────────────────────────────────────────┤
|
||||
│ User Data & Code (variable) │ ← HERE grows up
|
||||
│ - Compiled definitions │
|
||||
│ - Variables, constants │
|
||||
│ - String literals │
|
||||
├──────────────────────────────────────────┤
|
||||
│ Block Storage (remainder) │
|
||||
│ - 1KB blocks for Forth block system │
|
||||
└──────────────────────────────────────────┘
|
||||
....
|
||||
|
||||
==== Implementation Steps:
|
||||
|
||||
[arabic]
|
||||
. *Add Dictionary Allocator* (256KB bump allocator at `+memory[0]+`):
|
||||
|
||||
[source,c]
|
||||
----
|
||||
static DictEntry *dict_alloc_from_vm(VM *vm, size_t total_bytes) {
|
||||
/* Align to cell_t boundary */
|
||||
size_t align = sizeof(cell_t);
|
||||
total_bytes = (total_bytes + align - 1) & ~(align - 1);
|
||||
|
||||
/* Check space */
|
||||
if (vm->dict_headers_used + total_bytes > DICT_HEADERS_MAX) {
|
||||
vm->error = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Allocate from VM memory */
|
||||
DictEntry *entry = (DictEntry *)(vm->memory + vm->dict_headers_used);
|
||||
vm->dict_headers_used += total_bytes;
|
||||
return entry;
|
||||
}
|
||||
----
|
||||
|
||||
[arabic, start=2]
|
||||
. *Update FORGET* (no individual frees, just rewind):
|
||||
|
||||
[source,c]
|
||||
----
|
||||
/* Instead of free(e) loop, rewind allocator */
|
||||
size_t target_offset = (uint8_t*)target - vm->memory;
|
||||
vm->dict_headers_used = target_offset;
|
||||
----
|
||||
|
||||
[arabic, start=3]
|
||||
. *Adjust VM Initialization*:
|
||||
|
||||
[source,c]
|
||||
----
|
||||
vm->dict_headers_used = 0; /* Headers start at memory[0] */
|
||||
vm->here = DICT_HEADERS_MAX; /* User data starts at 256KB */
|
||||
----
|
||||
|
||||
[arabic, start=4]
|
||||
. *No Changes to Fast-Lookup Cache*: Cache buckets still use malloc for
|
||||
the pointer arrays, but entries themselves are in VM memory.
|
||||
|
||||
==== Testing Strategy:
|
||||
|
||||
[source,bash]
|
||||
----
|
||||
# Test with standard malloc (current):
|
||||
make clean && make test
|
||||
|
||||
# Test with VM-based allocation:
|
||||
make clean
|
||||
CFLAGS="-DSTARFORTH_VM_DICT_ALLOC" make test
|
||||
|
||||
# Test L4Re minimal build:
|
||||
make clean
|
||||
CFLAGS="-DSTARFORTH_MINIMAL -DSTARFORTH_VM_DICT_ALLOC" make rpi4-cross
|
||||
----
|
||||
|
||||
=== Current Status
|
||||
|
||||
*Decision*: Keep using `+malloc()+` for now, document the abstraction
|
||||
point clearly.
|
||||
|
||||
*Rationale*:
|
||||
|
||||
* Current implementation is stable and well-tested
|
||||
* L4Re port can implement the switch when needed
|
||||
* Abstraction layer is simple and well-defined
|
||||
* No performance difference between approaches
|
||||
|
||||
*Action Items for L4Re Port*:
|
||||
|
||||
[arabic]
|
||||
. Define `+STARFORTH_VM_DICT_ALLOC+` in L4Re build
|
||||
. Implement `+dict_alloc_from_vm()+` function
|
||||
. Update `+FORGET+` to use rewind instead of free loop
|
||||
. Test with full test suite
|
||||
. Verify no memory leaks in microkernel environment
|
||||
|
||||
=== Minimal Code Changes Needed
|
||||
|
||||
The switch to VM-based allocation requires changes to only 3 functions:
|
||||
|
||||
[arabic]
|
||||
. *`+vm_create_word()+`* - Use `+dict_alloc_from_vm()+` instead of
|
||||
`+malloc()+`
|
||||
. *`+dictionary_word_forget()+`* - Rewind `+dict_headers_used+` instead
|
||||
of `+free()+` loop
|
||||
. *`+vm_init()+`* - Initialize `+dict_headers_used+` and offset `+HERE+`
|
||||
|
||||
Add to `+VM+` struct in `+include/vm.h+`:
|
||||
|
||||
[source,c]
|
||||
----
|
||||
size_t dict_headers_used; /* Bytes used for dictionary headers (VM mode only) */
|
||||
----
|
||||
|
||||
*Estimated effort*: 4 hours to implement + 2 hours testing = *6 hours
|
||||
total*
|
||||
|
||||
=== References
|
||||
|
||||
* Current malloc usage: `+src/dictionary_management.c:228+`
|
||||
* Current free usage: `+src/word_source/defining_words.c:554+`
|
||||
* Fast-lookup cache: `+src/dictionary_management.c:43-67+` (unchanged)
|
||||
* L4Re dataspace docs: `+docs/L4RE_INTEGRATION.md+`
|
||||
|
||||
'''''
|
||||
|
||||
*Author*: R. A. James *Date*: 2025-10-01 *Status*: Documented,
|
||||
implementation deferred to L4Re port
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,191 +0,0 @@
|
||||
// Moved from docs/src/platform-integration/l_4_re_blkio_endpoints.adoc to docs/working/scratch/src/platform-integration/l_4_re_blkio_endpoints.adoc on 2026-06-16 (docs reorg Phase 2)
|
||||
== StarForth Block I/O — L4Re Porting Endpoints
|
||||
:toc: left
|
||||
:toc-title: Contents
|
||||
:toclevels: 3
|
||||
xref:../README.adoc[← Back to Documentation Index]
|
||||
|
||||
|
||||
|
||||
This document explains how the existing `+blkio+` API maps cleanly onto
|
||||
L4Re, what you need to implement, and where your VM and Forth block
|
||||
words connect. The idea is: the *northbound API never changes*; you only
|
||||
swap in different backends (dataspace or IPC service) when porting to
|
||||
L4Re.
|
||||
|
||||
'''''
|
||||
|
||||
=== 1. Northbound API (unchanged)
|
||||
|
||||
Your VM and block words always call:
|
||||
|
||||
[source,c]
|
||||
----
|
||||
int blkio_open (blkio_dev_t *dev, const blkio_vtable_t *vt, const blkio_params_t *p);
|
||||
int blkio_close(blkio_dev_t *dev);
|
||||
int blkio_read (blkio_dev_t *dev, uint32_t fblock, void *dst);
|
||||
int blkio_write(blkio_dev_t *dev, uint32_t fblock, const void *src);
|
||||
int blkio_flush(blkio_dev_t *dev);
|
||||
int blkio_info (blkio_dev_t *dev, blkio_info_t *out);
|
||||
----
|
||||
|
||||
No matter what backend you use, these remain stable. That’s your ABI.
|
||||
|
||||
'''''
|
||||
|
||||
=== 2. In-process L4Re Dataspace Backend
|
||||
|
||||
Use when your VM can directly attach a dataspace. This gives you the
|
||||
fastest path: no IPC.
|
||||
|
||||
*Symbols you implement:*
|
||||
|
||||
[source,c]
|
||||
----
|
||||
size_t blkio_l4ds_state_size(void);
|
||||
int blkio_l4ds_init_state(void *state_mem, size_t state_len,
|
||||
l4_cap_idx_t ds_cap,
|
||||
l4_addr_t attach_addr,
|
||||
l4_size_t attach_size,
|
||||
uint32_t total_blocks,
|
||||
uint32_t fbs,
|
||||
uint8_t read_only,
|
||||
void **out_opaque);
|
||||
const blkio_vtable_t *blkio_l4ds_vtable(void);
|
||||
----
|
||||
|
||||
*State struct:*
|
||||
|
||||
[source,c]
|
||||
----
|
||||
typedef struct {
|
||||
l4_cap_idx_t ds; /* dataspace cap */
|
||||
void *base; /* attached VA */
|
||||
l4_size_t size; /* mapped length */
|
||||
uint32_t fbs; /* block size */
|
||||
uint32_t blocks; /* #blocks */
|
||||
uint8_t ro;
|
||||
} blkio_l4ds_state_t;
|
||||
----
|
||||
|
||||
*Ops:*
|
||||
|
||||
* `+open+`: `+l4re_rm_attach()+` dataspace, derive block count.
|
||||
* `+read/write+`: `+memcpy+` from attached region.
|
||||
* `+flush+`: NOP (or `+l4re_ds_op+` if needed).
|
||||
* `+close+`: `+l4re_rm_detach()+`.
|
||||
|
||||
'''''
|
||||
|
||||
=== 3. Out-of-process Block Server (IPC Backend)
|
||||
|
||||
Use when storage is owned by a different task (e.g., AHCI, NVMe, eMMC
|
||||
server).
|
||||
|
||||
*Client-side symbols:*
|
||||
|
||||
[source,c]
|
||||
----
|
||||
size_t blkio_l4svc_state_size(void);
|
||||
int blkio_l4svc_init_state(void *state_mem, size_t state_len,
|
||||
l4_cap_idx_t server_cap,
|
||||
l4_cap_idx_t bounce_ds,
|
||||
uint32_t fbs,
|
||||
uint8_t read_only,
|
||||
void **out_opaque);
|
||||
const blkio_vtable_t *blkio_l4svc_vtable(void);
|
||||
----
|
||||
|
||||
*IPC protocol (example):*
|
||||
|
||||
[source,c]
|
||||
----
|
||||
enum bsvc_op {
|
||||
BSVC_INFO = 1,
|
||||
BSVC_READ = 2,
|
||||
BSVC_WRITE = 3,
|
||||
BSVC_FLUSH = 4,
|
||||
BSVC_PING = 5
|
||||
};
|
||||
----
|
||||
|
||||
Transport choices:
|
||||
|
||||
* Shared dataspace (preferred): server + client map the same page(s).
|
||||
* Inline IPC (simpler, less efficient): block payload in IPC message.
|
||||
|
||||
*Ops mapping:*
|
||||
|
||||
* `+read+`: send op + fblock, server fills shared buffer.
|
||||
* `+write+`: copy into shared buffer, send op + fblock.
|
||||
* `+info+`: query block size, count, flags.
|
||||
|
||||
'''''
|
||||
|
||||
=== 4. Factory Helpers on L4Re
|
||||
|
||||
You can add overloads to `+blkio_factory+` for clarity:
|
||||
|
||||
[source,c]
|
||||
----
|
||||
int blkio_factory_open_l4ds (blkio_dev_t *dev, l4_cap_idx_t ds_cap, uint32_t fbs, uint8_t ro);
|
||||
int blkio_factory_open_file (blkio_dev_t *dev, const char *path, uint32_t fbs, uint8_t ro);
|
||||
int blkio_factory_open_l4svc(blkio_dev_t *dev, l4_cap_idx_t server_cap, l4_cap_idx_t bounce_ds, uint32_t fbs, uint8_t ro);
|
||||
----
|
||||
|
||||
This way `+main.c+` can pick a backend cleanly depending on CLI args and
|
||||
environment.
|
||||
|
||||
'''''
|
||||
|
||||
=== 5. CLI Semantics on L4Re
|
||||
|
||||
* `+--disk-img=<path>+` → Either:
|
||||
** VFS+file server that returns a dataspace → *l4ds backend*
|
||||
** Or connect to a block server → *l4svc backend*
|
||||
* `+--ram-disk=<MB>+` → Allocate RAM dataspace, use *l4ds backend*.
|
||||
|
||||
Fallback: if no `+--disk-img+`, create RAM disk from allocator.
|
||||
|
||||
'''''
|
||||
|
||||
=== 6. Composite Backends (RAM + Disk, 4 KiB packing)
|
||||
|
||||
Your design needs:
|
||||
|
||||
* Blocks 0–1023 → RAM backend.
|
||||
* Blocks ≥1024 → Disk backend.
|
||||
* All wrapped in a composite vtable that dispatches based on `+fblock+`.
|
||||
|
||||
Later: add an outer wrapper that packs 3×1 KiB + 1 KiB metadata into 4
|
||||
KiB pages for device alignment. Still the same five ops.
|
||||
|
||||
'''''
|
||||
|
||||
== TL;DR — Endpoints to Implement for L4Re
|
||||
|
||||
*New backends:*
|
||||
|
||||
[source,c]
|
||||
----
|
||||
/* In-proc dataspace */
|
||||
blkio_l4ds_state_size();
|
||||
blkio_l4ds_init_state(...);
|
||||
blkio_l4ds_vtable();
|
||||
|
||||
/* IPC client/server */
|
||||
blkio_l4svc_state_size();
|
||||
blkio_l4svc_init_state(...);
|
||||
blkio_l4svc_vtable();
|
||||
----
|
||||
|
||||
*Optional factory helpers:*
|
||||
|
||||
[source,c]
|
||||
----
|
||||
blkio_factory_open_l4ds(...);
|
||||
blkio_factory_open_l4svc(...);
|
||||
----
|
||||
|
||||
*Everything else stays the same*: VM calls only `+blkio_read+`,
|
||||
`+blkio_write+`, etc. You swap backends, not call sites.
|
||||
Reference in New Issue
Block a user