universalisos/kernel/docs/KDEV_PROVIDER.md
Fábio Coutada 4960a14096 kernel: update 58 existing source files
- Update Makefile for new source files
- Fix include paths
- Update kernel docs
2026-07-15 15:31:50 +01:00

6.2 KiB

UniversalisOS KDEV Provider Framework (armv7/core)

PikeOS kdev_prov.c replica: the provider half of the kdev driver/provider split, complementing the driver half in core/uos_kdev.{h,cpp} (kdev_drv.c).

Why it exists

The original uos_kdev framework is a driver registry: each driver self-registers into .uos_drv and carries its own init/open/close/.... There was no class-level provider owning a pool of device instances with reference-counted open/close — the PikeOS pattern where a shared device (console, pci-mgr, clock) is set up once on first open and torn down on last close. This adds that half without disturbing the existing driver registry.

What's implemented

  • .uos_prov linker section (armv7 linker.ld) parallel to .uos_drv.
  • uos_prov_desc_t { name, prov_id, *ops, max_dev } + UOS_PROV_REGISTER(name, &desc) macro placing a pointer in .uos_prov.
  • uos_prov_ops_t { init, open, close, read, write, ioctl } — class hooks, any member may be NULL.
  • Discovery: uos_kdev_prov_init_all() (walk + call init), uos_kdev_prov_ find(prov_id), uos_kdev_prov_count().
  • Refcounted instances: a static table (UOS_KDEV_MAX_INSTANCES=16) keyed by (prov_id, dev_id). uos_kdev_open() binds on first open (calls provider open) and bumps on later opens; uos_kdev_close() decrements and calls the provider close teardown exactly once on the last close, then frees the slot. Return codes: -1 unknown provider, -2 dev_id out of range, -3 table full, -4 provider open failed, -5 close underflow/not-open.
  • Built-in console provider (UOS_PROV_ID_CONSOLE=5) as a worked example with a functional write path.
  • uos_kdev_prov_demo() prints [kdev-prov] OK after asserting all semantics.

Wiring / gotcha

kernel.cpp calls uos_kdev_prov_demo() immediately after uos_cfg_materialize() and before uos_cfg_run_guests(). The later D-3..D-5 cluster (IRQ/Time/KDEV-driver/VFP/SMP) sits past uos_cfg_run_guests(), which does not return to the linear sequence on the current armv7 boot path — so the pre-existing KDEV driver demo is also not reached there. If run_guests is ever made to return, move the provider demo back into that cluster next to the driver demo.

riscv/aarch64 are unaffected: they compile core via the core-objs-y allowlist (empty), so uos_kdev_prov.cpp is armv7-only, and the .uos_prov section only exists in the armv7 linker script.

Verification (ad-hoc, not suite green)

  • Banned-token scrub (p4_/P4_) on the new files: 0.
  • make ARCH=armv7 PLATFORM=qemu-arm-virt clean build + QEMU boot → [kdev-prov] OK with: registered=1, init "console", find(CONSOLE) FOUND, open(CONSOLE,1)= rc2 (range), openx2 refcount=2 open_calls=1, closex2 refcount 2->1->0 close_calls=1, close(underflow)=rc5, console write ok. No aborts/panic.
  • Non-regression: aarch64-linux + aarch64-classic builds clean.

Boot-verification caveat (2026-07-13): the ARMv7 link/boot is currently blocked by an unrelated, in-progress concurrent session — a new kernel/src/core/arch_init.h (x86_64 bring-up header) collides by filename with arch/armv7/inc/arch_init.h on the -Isrc/core include path, and kernel.cpp now references arch_exceptions_init/arch_init that ARMv7 does not define yet. The PROV-2 compile units (uos_kdev_prov.cpp, cfg_parser.cpp) build clean; the failure is entirely in the concurrent session's arch_* symbols. Per the parity ledger these files are off-limits, so boot verification of PROV-2 must wait until that header collision is resolved (e.g. rename the x86_64 header to core/arch_init_x86_64.h or gate it by ARCH).

Open items

  • PROV-2: DONE — the active instance-pool cap is now config-driven via the UniversalisOS manifest lane instead of the hardcoded UOS_KDEV_MAX_INSTANCES:
    • system_model.kdev_max_instances (sysmodel.h) carries the cap; it defaults to UOS_CFG_KDEV_MAX_INSTANCES_DFLT (16) and is overridden by a top-level <KdevProviderTable MaxInstances="N"/> element in the embedded manifest (boot-simple.xml, parsed by cfg_parser.cpp).
    • UOS_KDEV_MAX_INSTANCES is now the static allocation bound (64, the freestanding hard max for the instance table); the active cap is clamped to it via uos_kdev_prov_configure() / uos_kdev_prov_apply_config(), which the demo calls before exercising the pool. inst_find/inst_alloc are bounded by the active cap, not the hard max.
    • boot-simple.xml exercises this with <KdevProviderTable MaxInstances="8"/>; the demo prints pool cap = 8 (alloc bound 64) and the CFG banner prints kdev provider pool cap=8.
    • The original "mycelium codegen" framing is the follow-on: mycelium can later emit the same MaxInstances value into the generated manifest; the kernel consumes it identically through the existing parser. No kernel build dependency on mycelium was introduced (the kernel embeds boot-simple.xml directly via cfg_blob.S).
  • PROV-3: DONE — per-instance read/write/ioctl routing helpers (uos_kdev_read/uos_kdev_write/uos_kdev_ioctl) mirror open/close and return -5 (not open) / -1 (unsupported) appropriately; exercised by the console write and clock read in the demo.

Files

  • kernel/src/core/uos_kdev_prov.h — provider descriptor, ops, register macro, open/close/refcount API, read/write/ioctl routing, demo prototype.
  • kernel/src/core/uos_kdev_prov.cpp — section walk, instance table, refcounted open/close, console + clock providers, [kdev-prov] OK demo.
  • kernel/src/arch/armv7/linker.ld.uos_prov section in the data PHDR.
  • kernel/src/core/kernel.cppuos_kdev_prov_demo() call site (live path, before uos_cfg_run_guests()).
  • kernel/src/core/config/sysmodel.hkdev_max_instances field + UOS_CFG_KDEV_MAX_INSTANCES_DFLT default.
  • kernel/src/core/config/cfg_parser.cpp<KdevProviderTable MaxInstances> handler + manifest default + CFG banner line.
  • kernel/src/core/config/boot-simple.xml<KdevProviderTable MaxInstances="8"/>.
  • kernel/src/core/uos_time.cpp — ARMv7 backend of uos_arch_time_now() / uos_arch_time_freq() (CNTPCT physical counter), the missing P-1 deliverable that the clock provider depends on.