Independent C# bootstrap kernel
This x86_64 bare-metal kernel has no Cosmos SDK, runtime, HAL, driver, scheduler,
patcher or source dependency. The C# files contain the boot policy, bounded UART,
memory-map validation, physical-page allocator, GDT/TSS/IDT construction,
exception diagnostics and 32-bit framebuffer access. native.c contains only
Limine request/storage declarations and instruction wrappers; entry.S contains
the entry, descriptor reload and exception trampolines C# cannot express. Their
paths are Native/native.c and Native/entry.S.
The Limine request identifiers and the x86_64 descriptor design were checked
against this project's own historical Rust implementation at commit 1139821
(kernel/src/boot.rs, kernel/src/arch/x86_64.rs). They have been reimplemented
in C#/C/assembly without copying or renaming Cosmos code. Limine remains an
external BSD-2-Clause bootloader; its public boot protocol is 0BSD. The bflat
Zero standard library and compiler remain external MIT tooling.
Build C# with pinned bflat 8.0.2, --os:linux --arch:x64 --stdlib:zero --target:Shared -c, and
-i:xfe_native so P/Invoke resolves to the local xfe_* symbols directly.
Compile native.c and entry.S for x86_64 ELF with Clang, -mno-red-zone,
-ffreestanding, -fno-stack-protector, and link with the independent runtime
object and a linker script retaining all .limine_requests* sections. The ELF
entry is _start; no libc, dynamic loader or managed host process is used.
Exports: XfeKernelMain(NativeBootInfo*), XfeHandleInterrupt(InterruptFrame*).
The kernel calls the optional partial method Kernel.OnKernelReady() after
real boot self-tests pass. An application implementation in the same namespace
and partial class can provide that method. No existing Kernel project is edited.
Bootstrap limits are explicit: one BSP, inherited bootloader page tables, physical allocation below 8 GiB, 4 KiB contiguous pages, no managed allocation, 32 single-BSP kernel threads, no SMP execution, no user-mode isolation, no storage or network. Memory above the allocator cap is counted as ignored. Only usable memory entries are allocated; bootloader-reclaimable, firmware and executable regions remain reserved. Runtime memory bridges mask IRQs around mutation, which provides single-BSP exclusion rather than an SMP lock. Release checks page ownership and rejects a duplicate release; it does not protect callers from unmapping a still-used allocation.
Serial success markers are emitted after actual C# checks, including zero/reuse/ ownership/contiguous page checks, SGDT/SIDT readback, returning INT3 through our IDT and SSE-preserving trampoline, and a framebuffer pixel readback. Presence of this source or an ELF object alone is not an accepted boot result.
Thread scheduling is single-BSP, with 32 slots and a calibrated periodic LAPIC timer. Context switches preserve System V nonvolatile registers, the real stack, FS base and complete enabled x87/SSE state. OSXSAVE is disabled; AVX/YMM/ZMM are not enabled or promised. New stacks have unmapped guards at both ends. Every thread also owns a separate guarded 64 KiB IRQ stack; the scheduler changes TSS IST3 with interrupts masked before changing context. Asynchronous IRQs preserve the System V 128-byte red zone used by the unchanged Microsoft native runtime archives, and suspended IRQ frames belong to their outgoing thread. The native preemption probe never yields or calls a helper: two threads' independent FS, XMM15 and all sixteen red-zone qwords must survive at least three actual LAPIC ticks and real context switches. Events use generation-tagged handles and real park/wake with manual/auto reset, timeout and close rejection. Full .NET GC hijacking uses the Microsoft runtime's real helper on captured contexts; a missing or inconvenient helper does not count as GC safety.
The 8042 driver initializes keyboard/mouse only after actual ACKs and polls real device bytes on LAPIC ticks. PS/2 set-1 translation and three-byte mouse packets enter a 256-report queue. Overflow or parity/timeout clears stale reports and emits an explicit loss report. USB HID, IME and wheel negotiation are not enabled. The same pure decoder source is linked into host regressions; those regressions are separate from actual guest device acceptance.
xfe_runtime_utc_filetime() double-samples the live CMOS RTC, bounds UIP polling,
validates power/data fields and date ranges, handles BCD/binary and 12/24-hour
modes, and uses century register 0x32 when valid. With an absent century it uses
the explicit 1970/2069 pivot. Read failure returns zero. This is not a fixed build
date or host callback. QEMU must use RTC base=utc; physical RTC timezone conventions
remain to be verified before claiming that physical machine's UTC accuracy.
The virtual-memory arena uses two empty PML4 slots at low canonical address
0x0000200000000000, covering 1 TiB and up to 256 live reservations. Reserve
records an address range without allocating RAM; commit creates zeroed 4 KiB
supervisor RW/NX PTEs. Decommit clears PTEs, invalidates the local TLB and returns
data pages and empty kernel-owned page-table pages. Release requires the original
whole reservation. Protection accepts read=1, write=2, execute=4 and rejects W+X;
CR0.WP and EFER.NXE enforce the policy. The boot self-test intentionally triggers
two unmapped guard reads, a read-only write and an NX instruction fetch, returning
only when the expected CR2, RIP and page-fault error bits match. It also checks
zeroed commits and complete page reclamation. Existing and mixed-range commits
preserve old pages; failed commits roll back only newly added pages. Physical
release validates both ownership and exact allocation block boundaries, rejecting
partial or cross-block frees. Only four-level paging and single-BSP
edits are supported. No AP TLB shootdown or user-process memory domain is claimed.
The C ABI for the separate .NET module is xfe_runtime_alloc_pages(ulong)
returning a zeroed 4 KiB-aligned HHDM pointer, xfe_runtime_free_pages(void*,ulong)
returning 1 on success, xfe_runtime_write(byte*,ulong),
xfe_runtime_mono_ns(), xfe_runtime_clock_ready(),
xfe_runtime_framebuffer_info(NativeFrameSurface*) and xfe_runtime_halt(byte*).
Counts for allocation/release are pages, not bytes. The surface structure is a
56-byte sequential value (two ulong fields followed by ten uint fields). Logs
accept at most 1 MiB; fatal reasons read at most 256 bytes. These exports exchange
no managed references. The TSC clock uses an explicit CPUID crystal/ratio or
bounded PIT channel-2 calibration. A non-invariant TSC is identified in the boot
log: elapsed-time accuracy across frequency changes is not promised.
To link Zero and .NET together, all Zero compiler/runtime symbols must be
prefixed and its __modules, __managedcode and __unbox sections separated
from the real runtime module tables. Restore only xfe_* imports and the C ABI
exports. Map the Zero references SystemNative_Abort/SystemNative_Malloc to
xfe_zero_abort/xfe_zero_malloc; do not bind either module to the other's
Rhp* implementations or share Zero objects with the full .NET GC.