Rumpk Stability, NipBox Boot, and Repository Cleanup

- Fixed Rumpk RISC-V Trap Handler (SSCRATCH swap, align(4), SUM bit) to prevent double faults.

- Stabilized Userland Transition (fence.i, MMU activation) allowing NipBox execution.

- Restored Forge pipeline to build NipBox from source.

- Documented critical RISC-V trap mechanics in .agent/tips.

- Committed pending repository cleanup (obsolete websites) and new core modules.
This commit is contained in:
Markus Maiwald 2026-01-04 21:39:06 +01:00
parent bd03bed91f
commit 6e78b7f458
793 changed files with 233142 additions and 907 deletions

34
apps/init/init.nim Normal file
View File

@ -0,0 +1,34 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## Sovereign Init: The Genesis Process
##
## Responsible for bootstrapping the system, starting core services,
## and managing the lifecycle of the user environment.
import ../../libs/membrane/libc
# --- Entry Point ---
proc main() =
# 1. Pledge Sovereignty
discard pledge(0xFFFFFFFFFFFFFFFF'u64) # PLEDGE_ALL
print("\n")
print("\x1b[1;35m╔═══════════════════════════════════════╗\x1b[0m\n")
print("\x1b[1;35m║ SOVEREIGN INIT (NexInit v0.1) ║\x1b[0m\n")
print("\x1b[1;35m╚═══════════════════════════════════════╝\x1b[0m\n\n")
print("[INIT] System Ready. Starting heartbeat...\n")
while true:
# 🕵️ DIAGNOSTIC: BREATHER
pump_membrane_stack()
yield_fiber()
when isMainModule:
main()

17
apps/linker_test.ld Normal file
View File

@ -0,0 +1,17 @@
/* Minimal linker script for test binary */
ENTRY(_start)
MEMORY
{
RAM (rwx) : ORIGIN = 0x88000000, LENGTH = 128M
}
SECTIONS
{
. = 0x88000000;
.text : {
*(.text._start)
*(.text)
*(.text.*)
} > RAM
}

View File

@ -1,16 +1,16 @@
/* Memory Layout (64MB Userspace): /* Memory Layout (128MB Userspace):
* User RAM: 0x86000000 - 0x89FFFFFF (64MB) * User RAM: 0x88000000 - 0x8FFFFFFF (128MB)
* Stack starts at 0x89FFFFF0 and grows down * Stack starts at 0x8FFFFFE0 and grows down
* Requires QEMU -m 256M to ensure valid physical backing * Requires QEMU -m 256M to ensure valid physical backing
*/ */
MEMORY MEMORY
{ {
RAM (rwx) : ORIGIN = 0x86000000, LENGTH = 64M RAM (rwx) : ORIGIN = 0x88000000, LENGTH = 128M
} }
SECTIONS SECTIONS
{ {
. = 0x86000000; . = 0x88000000;
.text : { .text : {
*(.text._start) *(.text._start)
@ -23,14 +23,23 @@ SECTIONS
*(.rodata.*) *(.rodata.*)
} > RAM } > RAM
.sdata : {
__global_pointer$ = . + 0x800;
*(.sdata .sdata.* .srodata .srodata.*)
} > RAM
.data : { .data : {
*(.data) *(.data)
*(.data.*) *(.data.*)
} > RAM } > RAM
.bss : { .bss : {
. = ALIGN(8);
__bss_start = .;
*(.bss) *(.bss)
*(.bss.*) *(.bss.*)
*(COMMON) *(COMMON)
. = ALIGN(8);
__bss_end = .;
} > RAM } > RAM
} }

View File

@ -2,13 +2,36 @@
.global _start .global _start
_start: _start:
# 🕵 DIAGNOSTIC: BREATHE # 🕵 DIAGNOSTIC: BREATHE
# li t0, 0x10000000 li t0, 0x10000000
# li t1, 0x23 # '#' li t1, 0x23 # '#'
# sb t1, 0(t0) sb t1, 0(t0)
# Clear BSS (64-bit aligned zeroing)
la t0, __bss_start
la t1, __bss_end
1: bge t0, t1, 2f
sd zero, 0(t0)
addi t0, t0, 8
j 1b
2:
fence rw, rw
# 🔧 CRITICAL FIX: Set up stack pointer for userland
# Stack grows down from top of 128MB userland RAM (0x90000000 - 32 bytes for alignment)
li sp, 0x8FFFFFE0
# 🔧 CRITICAL FIX: Set up global pointer for RISC-V ABI
# Global pointer should point to .sdata section for efficient global access
# For userland at 0x88000000, set gp to middle of address space
.option push
.option norelax
la gp, __global_pointer$
.option pop
# 🕵 DIAGNOSTIC: READY TO CALL MAIN # 🕵 DIAGNOSTIC: READY TO CALL MAIN
# li t1, 0x21 # '!' li t0, 0x10000000
# sb t1, 0(t0) li t1, 0x21 # '!'
sb t1, 0(t0)
# Call main(0, NULL) # Call main(0, NULL)
li a0, 0 li a0, 0

8
apps/test_minimal.S Normal file
View File

@ -0,0 +1,8 @@
# Minimal userland test - pure loop
# Tests instruction fetch only. No memory stores.
.section .text._start, "ax"
.global _start
_start:
# Just loop forever
j _start

View File

@ -1,5 +1,16 @@
// Rumpk Boot Header // SPDX-License-Identifier: LCL-1.0
// Multiboot2 / EFI entry point definition // Copyright (c) 2026 Markus Maiwald
// Stewardship: Self Sovereign Society Foundation
//
// This file is part of the Nexus Commonwealth.
// See legal/LICENSE_COMMONWEALTH.md for license terms.
//! Rumpk Boot Header
//!
//! Defines the Multiboot2 header for GRUB/QEMU and the bare-metal entry point.
//! Handles BSS clearing and stack initialization before jumping to the Nim kernel.
//!
//! SAFETY: Executed in the earliest boot stage with no environment initialized.
const std = @import("std"); const std = @import("std");

View File

@ -1,6 +1,14 @@
// Rumpk Build System // SPDX-License-Identifier: LCL-1.0
// Orchestrates L0 (Zig) and L1 (Nim) compilation // Copyright (c) 2026 Markus Maiwald
// Markus Maiwald (Architect) | Voxis Forge (AI) // Stewardship: Self Sovereign Society Foundation
//
// This file is part of the Nexus Commonwealth.
// See legal/LICENSE_COMMONWEALTH.md for license terms.
//! Rumpk Build System
//!
//! Orchestrates L0 (Zig) and L1 (Nim) compilation.
//! Builds the Hardware Abstraction Layer as a static library.
const std = @import("std"); const std = @import("std");
@ -12,50 +20,66 @@ pub fn build(b: *std.Build) void {
// L0: Hardware Abstraction Layer (Zig) // L0: Hardware Abstraction Layer (Zig)
// ========================================================= // =========================================================
const hal = b.addStaticLibrary(.{ // NOTE(Build): Zig 0.15.x API - using addLibrary with static linkage
.name = "rumpk_hal", const hal_mod = b.createModule(.{
.root_source_file = b.path("hal/abi.zig"), .root_source_file = b.path("hal/abi.zig"),
.target = target, .target = target,
.optimize = optimize, .optimize = optimize,
}); });
// Freestanding kernel - no libc, no red zone, no stack checks
hal_mod.red_zone = false;
hal_mod.stack_check = false;
// Freestanding kernel - no libc const hal = b.addLibrary(.{
hal.root_module.red_zone = false; .name = "rumpk_hal",
hal.root_module.stack_check = .none; .root_module = hal_mod,
.linkage = .static,
// Microui Integration (Phase 3.5b)
hal.addIncludePath(b.path("libs/microui"));
hal.addCSourceFile(.{
.file = b.path("libs/microui/microui.c"),
.flags = &.{"-std=c99"},
}); });
b.installArtifact(hal); b.installArtifact(hal);
// TODO(Build): Microui needs stdio.h stubs for freestanding.
// Re-enable after creating libs/microui/stdio_stub.h
// Microui Integration (Phase 3.5b)
// hal_mod.addIncludePath(b.path("libs/microui"));
// hal_mod.addCSourceFile(.{
// .file = b.path("libs/microui/microui.c"),
// .flags = &.{"-std=c99"},
// });
// ========================================================= // =========================================================
// Boot: Entry Point (Assembly + Zig) // Boot: Entry Point (Assembly + Zig)
// ========================================================= // =========================================================
const boot = b.addObject(.{ const boot_mod = b.createModule(.{
.name = "boot",
.root_source_file = b.path("boot/header.zig"), .root_source_file = b.path("boot/header.zig"),
.target = target, .target = target,
.optimize = optimize, .optimize = optimize,
}); });
boot_mod.red_zone = false;
boot_mod.stack_check = false;
boot.root_module.red_zone = false; const boot = b.addObject(.{
boot.root_module.stack_check = .none; .name = "boot",
.root_module = boot_mod,
});
_ = boot; // Mark as used for now
// ========================================================= // =========================================================
// Tests // Tests
// ========================================================= // =========================================================
const hal_tests = b.addTest(.{ const test_mod = b.createModule(.{
.root_source_file = b.path("hal/abi.zig"), .root_source_file = b.path("hal/abi.zig"),
.target = target, .target = target,
.optimize = optimize, .optimize = optimize,
}); });
const hal_tests = b.addTest(.{
.root_module = test_mod,
});
const run_tests = b.addRunArtifact(hal_tests); const run_tests = b.addRunArtifact(hal_tests);
const test_step = b.step("test", "Run Rumpk HAL tests"); const test_step = b.step("test", "Run Rumpk HAL tests");
test_step.dependOn(&run_tests.step); test_step.dependOn(&run_tests.step);

View File

@ -1,3 +1,12 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## Rumpk Layer 1: High-Level Sovereign Channels
# MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI) # MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI)
# RUMPK CORE // CHANNEL # RUMPK CORE // CHANNEL
# The primitive for Typed Communication. # The primitive for Typed Communication.

View File

@ -1,11 +1,17 @@
# MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI) # SPDX-License-Identifier: LSL-1.0
# RUMPK CORE // FIBER (Unified Multi-Arch) # Copyright (c) 2026 Markus Maiwald
# The atom of execution. # Stewardship: Self Sovereign Society Foundation
# #
# Supported Architectures: # This file is part of the Nexus Sovereign Core.
# - aarch64 (ARM64): VisionFive 2, RPi, AWS Graviton # See legal/LICENSE_SOVEREIGN.md for license terms.
# - amd64 (x86_64): Standard servers, trading systems
# - riscv64 (RISC-V): Sovereign compute, satellites ## Rumpk Layer 1: Fiber Execution (Motive Power)
##
## Implements the unified multi-arch fiber context switching.
## Supported Architectures: x86_64, AArch64, RISC-V.
##
## SAFETY: Direct manipulation of stack pointers and CPU registers via
## architecture-specific context frames. Swaps page tables during switch.
{.push stackTrace: off, lineTrace: off.} {.push stackTrace: off, lineTrace: off.}
@ -36,6 +42,12 @@ else:
# ========================================================= # =========================================================
type type
Spectrum* = enum
Photon = 0 # UI/Audio (Top Tier)
Matter = 1 # Interactive (Middle Tier)
Gravity = 2 # Batch (Bottom Tier)
Void = 3 # Unclassified/Demoted (Default)
FiberState* = object FiberState* = object
sp*: uint64 # The Stack Pointer (Must be first field!) sp*: uint64 # The Stack Pointer (Must be first field!)
entry*: proc() {.cdecl.} # Entry point for this fiber entry*: proc() {.cdecl.} # Entry point for this fiber
@ -48,11 +60,26 @@ type
stack*: ptr UncheckedArray[uint8] stack*: ptr UncheckedArray[uint8]
stack_size*: int stack_size*: int
sleep_until*: uint64 # NS timestamp sleep_until*: uint64 # NS timestamp
promises*: uint64 # Phase 28: Capability Mask (Pledge) promises*: uint64 # [63:62]=Spectrum, [61:0]=Pledge bits
pledge_budget*: uint64 # Microseconds allowed per frame (legacy)
avg_burst*: uint64 # Moving average for telemetry (The Ratchet)
user_entry*: pointer # Phase 29: User function pointer for workers user_entry*: pointer # Phase 29: User function pointer for workers
user_arg*: uint64 # Phase 29: Argument for user function user_arg*: uint64 # Phase 29: Argument for user function
satp_value*: uint64 # Phase 31: Page table root (0 = use kernel map) satp_value*: uint64 # Phase 31: Page table root (0 = use kernel map)
wants_yield*: bool # Phase 37: Deferred yield flag wants_yield*: bool # Phase 37: Deferred yield flag
# SPEC-250: The Ratchet
budget_ns*: uint64 # "I promise to run for X ns max"
last_burst_ns*: uint64 # Actual execution time of last run
violations*: uint32 # Strike counter (3 strikes = demotion)
# Spectrum Accessors
proc getSpectrum*(f: Fiber): Spectrum =
if f == nil: return Spectrum.Void
Spectrum((f.promises shr 62) and 0x3)
proc setSpectrum*(f: Fiber, s: Spectrum) =
if f == nil: return
f.promises = (f.promises and 0x3FFFFFFFFFFFFFFF'u64) or (uint64(s) shl 62)
proc fiber_yield*() {.importc, cdecl.} proc fiber_yield*() {.importc, cdecl.}
# Imports # Imports
@ -117,6 +144,9 @@ proc fiber_trampoline() {.cdecl, exportc, noreturn.} =
proc init_fiber*(f: Fiber, entry: proc() {.cdecl.}, stack_base: pointer, size: int) = proc init_fiber*(f: Fiber, entry: proc() {.cdecl.}, stack_base: pointer, size: int) =
f.state.entry = entry f.state.entry = entry
f.stack = cast[ptr UncheckedArray[uint8]](stack_base)
f.stack_size = size
f.sleep_until = 0
# Start at top of stack (using actual size) # Start at top of stack (using actual size)
var sp = cast[uint64](stack_base) + cast[uint64](size) var sp = cast[uint64](stack_base) + cast[uint64](size)

View File

@ -1,6 +1,22 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## Rumpk Layer 1: Sovereign File System (SFS)
# Markus Maiwald (Architect) | Voxis Forge (AI) # Markus Maiwald (Architect) | Voxis Forge (AI)
#
# Rumpk Phase 23: The Sovereign Filesystem (SFS) v2 # Rumpk Phase 23: The Sovereign Filesystem (SFS) v2
# Features: Multi-Sector Files (Linked List), Block Alloc Map (BAM) # Features: Multi-Sector Files (Linked List), Block Alloc Map (BAM)
#
# DOCTRINE(SPEC-021):
# This file currently implements the "Physics-Logic Hybrid" for Bootstrapping.
# In Phase 37, this will be deprecated in favor of:
# - L0: LittleFS (Atomic Physics)
# - L1: SFS Overlay Daemon (Sovereign Logic in Userland)
proc kprintln(s: cstring) {.importc, cdecl.} proc kprintln(s: cstring) {.importc, cdecl.}
proc kprint(s: cstring) {.importc, cdecl.} proc kprint(s: cstring) {.importc, cdecl.}
@ -11,14 +27,13 @@ proc kprint_hex(n: uint64) {.importc, cdecl.}
# ========================================================= # =========================================================
const SFS_MAGIC* = 0x31534653'u32 const SFS_MAGIC* = 0x31534653'u32
const SEC_SB = 0 const
const SEC_BAM = 1 SEC_SB = 0
const SEC_DIR = 2 SEC_BAM = 1
SEC_DIR = 2
# Linked List Payload: 508 bytes data + 4 bytes next_sector # Linked List Payload: 508 bytes data + 4 bytes next_sector
const CHUNK_SIZE = 508 CHUNK_SIZE = 508
const NEXT_PTR_OFFSET = 508 EOF_MARKER = 0xFFFFFFFF'u32
const EOF_MARKER = 0xFFFFFFFF'u32
type type
Superblock* = object Superblock* = object
@ -41,14 +56,7 @@ proc virtio_blk_write(sector: uint64, buf: pointer) {.importc, cdecl.}
# Helpers # Helpers
# ========================================================= # =========================================================
proc sfs_set_bam(sector: uint32) = # Removed sfs_set_bam (unused)
# Read BAM
virtio_blk_read(SEC_BAM, addr io_buffer[0])
let byteIndex = int(sector div 8)
let bitIndex = int(sector mod 8)
if byteIndex < 512:
io_buffer[byteIndex] = io_buffer[byteIndex] or byte(1 shl bitIndex)
virtio_blk_write(SEC_BAM, addr io_buffer[0])
proc sfs_alloc_sector(): uint32 = proc sfs_alloc_sector(): uint32 =
# Simple allocator: Scan BAM for first 0 bit # Simple allocator: Scan BAM for first 0 bit
@ -73,6 +81,31 @@ proc sfs_alloc_sector(): uint32 =
proc sfs_is_mounted*(): bool = sfs_mounted proc sfs_is_mounted*(): bool = sfs_mounted
proc sfs_format*() =
kprintln("[SFS] Formatting disk...")
# 1. Clear IO Buffer
for i in 0..511: io_buffer[i] = 0
# 2. Setup Superblock
io_buffer[0] = byte('S')
io_buffer[1] = byte('F')
io_buffer[2] = byte('S')
io_buffer[3] = byte('2')
# Disk size placeholder (32MB = 65536 sectors)
io_buffer[4] = 0x00; io_buffer[5] = 0x00; io_buffer[6] = 0x01; io_buffer[7] = 0x00
virtio_blk_write(SEC_SB, addr io_buffer[0])
# 3. Clear BAM
for i in 0..511: io_buffer[i] = 0
# Mark sectors 0, 1, 2 as used
io_buffer[0] = 0x07
virtio_blk_write(SEC_BAM, addr io_buffer[0])
# 4. Clear Directory
for i in 0..511: io_buffer[i] = 0
virtio_blk_write(SEC_DIR, addr io_buffer[0])
kprintln("[SFS] Format Complete.")
proc sfs_mount*() = proc sfs_mount*() =
kprintln("[SFS] Mounting System v2...") kprintln("[SFS] Mounting System v2...")
@ -84,6 +117,10 @@ proc sfs_mount*() =
io_buffer[2] == byte('S') and io_buffer[3] == byte('2'): io_buffer[2] == byte('S') and io_buffer[3] == byte('2'):
kprintln("[SFS] Mount SUCCESS. Version 2 (Linked Chain).") kprintln("[SFS] Mount SUCCESS. Version 2 (Linked Chain).")
sfs_mounted = true sfs_mounted = true
elif io_buffer[0] == 0 and io_buffer[1] == 0:
kprintln("[SFS] Fresh disk detected.")
sfs_format()
sfs_mounted = true
else: else:
kprint("[SFS] Mount FAILED. Invalid Magic/Ver. Found: ") kprint("[SFS] Mount FAILED. Invalid Magic/Ver. Found: ")
kprint_hex(cast[uint64](io_buffer[0])) kprint_hex(cast[uint64](io_buffer[0]))
@ -129,7 +166,6 @@ proc sfs_write_file*(name: cstring, data: cstring, data_len: int) {.exportc, cde
virtio_blk_read(SEC_DIR, addr io_buffer[0]) virtio_blk_read(SEC_DIR, addr io_buffer[0])
var dir_offset = -1 var dir_offset = -1
var start_sector = 0'u32
var file_exists = false var file_exists = false
# 1. Find File or Free Slot # 1. Find File or Free Slot
@ -158,7 +194,6 @@ proc sfs_write_file*(name: cstring, data: cstring, data_len: int) {.exportc, cde
var remaining = data_len var remaining = data_len
var data_ptr = 0 var data_ptr = 0
var first_sector = 0'u32 var first_sector = 0'u32
var prev_sector = 0'u32
var current_sector = 0'u32 var current_sector = 0'u32
# For the first chunk # For the first chunk

View File

@ -1,3 +1,12 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## Rumpk Layer 1: ROMFS (Static Tar Loader)
# MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI) # MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI)
# Rumpk L1: Sovereign VFS (Indexing TarFS) # Rumpk L1: Sovereign VFS (Indexing TarFS)
@ -157,109 +166,55 @@ proc vfs_read_file*(path: string): string =
return s return s
return "" return ""
proc ion_vfs_open*(path: cstring, flags: int32): int32 {.exportc, cdecl.} = proc vfs_read_at*(path: string, buf: pointer, count: uint64, offset: uint64): int64 =
return int32(vfs_open($path, flags)) if vfs.ram_data.hasKey(path):
let data = addr vfs.ram_data[path]
proc sfs_write_file(name: cstring, data: cstring, data_len: int) {.importc, cdecl.} if offset >= uint64(data[].len): return 0
proc sfs_read_file(name: cstring, dest: pointer, max_len: int): int {.importc, cdecl.} let available = uint64(data[].len) - offset
proc ion_vfs_read*(fd: int32, buf: pointer, count: uint64): int64 {.exportc, cdecl.} =
let fd_int = int(fd)
if not vfs.fds.hasKey(fd_int): return -1
let fh = addr vfs.fds[fd_int]
if fh.is_sfs:
# Read to temp buffer to handle offset/slicing
var temp_buf: array[512, byte]
let total_n = sfs_read_file(cstring(fh.path), addr temp_buf[0], 512)
if total_n < 0: return -1
if fh.offset >= uint64(total_n): return 0
let available = uint64(total_n) - fh.offset
let actual = min(count, available) let actual = min(count, available)
if actual > 0: if actual > 0:
copyMem(buf, addr temp_buf[int(fh.offset)], int(actual)) copyMem(buf, addr data[][int(offset)], int(actual))
fh.offset += actual
return int64(actual) return int64(actual)
# 1. RamFS Read if not vfs.index.hasKey(path): return -1
if fh.is_ram: let entry = vfs.index[path]
if not vfs.ram_data.hasKey(fh.path): return 0 if entry.is_sfs: return -1 # Routed via SFS
let data = addr vfs.ram_data[fh.path]
if fh.offset >= uint64(data[].len): return 0
let available = uint64(data[].len) - fh.offset
let actual_count = min(count, available)
if actual_count > 0:
copyMem(buf, addr data[][int(fh.offset)], int(actual_count))
fh.offset += actual_count
return int64(actual_count)
# 2. Tar Read var actual = uint64(count)
let entry = vfs.index[fh.path] if offset >= entry.size: return 0
var actual_count = uint64(count) if offset + count > entry.size:
actual = entry.size - offset
if fh.offset >= entry.size: return 0 copyMem(buf, cast[pointer](entry.offset + offset), int(actual))
if fh.offset + uint64(count) > entry.size: return int64(actual)
actual_count = entry.size - fh.offset
copyMem(buf, cast[pointer](entry.offset + fh.offset), int(actual_count)) proc vfs_write_at*(path: string, buf: pointer, count: uint64, offset: uint64): int64 =
fh.offset += actual_count # Promote to RamFS if on TarFS (CoW)
if not vfs.ram_data.hasKey(path):
return int64(actual_count) if vfs.index.hasKey(path):
let entry = vfs.index[path]
proc ion_vfs_close*(fd: int32): int32 {.exportc, cdecl.} =
let fd_int = int(fd)
if vfs.fds.hasKey(fd_int):
vfs.fds.del(fd_int)
return 0
return -1
proc ion_vfs_write*(fd: int32, buf: pointer, count: uint64): int64 {.exportc, cdecl.} =
let fd_int = int(fd)
if not vfs.fds.hasKey(fd_int): return -1
let fh = addr vfs.fds[fd_int]
if fh.is_sfs:
sfs_write_file(cstring(fh.path), cast[cstring](buf), int(count))
return int64(count)
# 1. Promote to RamFS if on TarFS (CoW)
if not fh.is_ram:
if vfs.index.hasKey(fh.path):
let entry = vfs.index[fh.path]
var content = newSeq[byte](int(entry.size)) var content = newSeq[byte](int(entry.size))
if entry.size > 0: if entry.size > 0:
copyMem(addr content[0], cast[pointer](entry.offset), int(entry.size)) copyMem(addr content[0], cast[pointer](entry.offset), int(entry.size))
vfs.ram_data[fh.path] = content vfs.ram_data[path] = content
fh.is_ram = true
# fh.offset preserved
else: else:
# Should not happen if open was successful, but for safety: vfs.ram_data[path] = @[]
vfs.ram_data[fh.path] = @[]
fh.is_ram = true
# 2. RamFS Write let data = addr vfs.ram_data[path]
let data = addr vfs.ram_data[fh.path] let min_size = int(offset + count)
let min_size = int(fh.offset + count)
if data[].len < min_size: if data[].len < min_size:
data[].setLen(min_size) data[].setLen(min_size)
copyMem(addr data[][int(fh.offset)], buf, int(count)) copyMem(addr data[][int(offset)], buf, int(count))
fh.offset += count
return int64(count) return int64(count)
# Removed ion_vfs_* in favor of vfs.nim dispatcher
proc ion_vfs_list*(buf: pointer, max_len: uint64): int64 {.exportc, cdecl.} = proc vfs_get_names*(): seq[string] =
var s = ""
# Unique names from both
var names = initTable[string, bool]() var names = initTable[string, bool]()
for name, _ in vfs.index: names[name] = true for name, _ in vfs.index: names[name] = true
for name, _ in vfs.ram_data: names[name] = true for name, _ in vfs.ram_data: names[name] = true
result = @[]
for name, _ in names: s.add(name & "\n") for name, _ in names: result.add(name)
let n = min(s.len, int(max_len))
if n > 0: copyMem(buf, addr s[0], n)
return int64(n)
proc vfs_register_sfs*(name: string, size: uint64) {.exportc, cdecl.} = proc vfs_register_sfs*(name: string, size: uint64) {.exportc, cdecl.} =
vfs.index[name] = FileEntry(offset: 0, size: size, is_sfs: true) vfs.index[name] = FileEntry(offset: 0, size: size, is_sfs: true)

View File

@ -1,3 +1,12 @@
# test # SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## Rumpk Layer 1: FS Test Wrapper
##
## Internal testing utility for file system wrapping logic.
proc foo() = proc foo() =
echo "this is a very long line to see if it gets wrapped in the actual file system by the tool" echo "this is a very long line to see if it gets wrapped in the actual file system by the tool"

127
core/fs/vfs.nim Normal file
View File

@ -0,0 +1,127 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## Rumpk Layer 1: Sovereign VFS (The Loom)
# MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI)
# VFS dispatcher for SPEC-130 alignment.
import strutils, tables
import tar, sfs
type
VFSMode = enum
MODE_TAR, MODE_SFS, MODE_RAM
MountPoint = object
prefix: string
mode: VFSMode
var mounts: seq[MountPoint] = @[]
type
FileHandle = object
path: string
offset: uint64
mode: VFSMode
is_ram: bool
var fds = initTable[int, FileHandle]()
var next_fd = 3
proc vfs_mount_init*() =
# SPEC-130: The Three-Domain Root
# SPEC-021: The Sovereign Overlay Strategy
mounts.add(MountPoint(prefix: "/nexus", mode: MODE_SFS)) # The Sovereign State (Persistent)
mounts.add(MountPoint(prefix: "/sysro", mode: MODE_TAR)) # The Projected Reality (Immutable InitRD)
mounts.add(MountPoint(prefix: "/state", mode: MODE_RAM)) # The Mutable Dust (Transient)
proc resolve_path(path: string): (VFSMode, string) =
for m in mounts:
if path.startsWith(m.prefix):
let sub = if path.len > m.prefix.len: path[m.prefix.len..^1] else: "/"
return (m.mode, sub)
return (MODE_TAR, path)
# Syscall implementation procs
# Kernel Imports
# (Currently unused, relying on kprintln from kernel)
proc ion_vfs_open*(path: cstring, flags: int32): int32 {.exportc, cdecl.} =
let p = $path
let (mode, sub) = resolve_path(p)
var fd = -1
case mode:
of MODE_TAR: fd = tar.vfs_open(sub, flags)
of MODE_SFS: fd = 0 # Placeholder for SFS open
of MODE_RAM: fd = tar.vfs_open(sub, flags) # Using TAR's RamFS for now
if fd > 0:
let kernel_fd = next_fd
fds[kernel_fd] = FileHandle(path: sub, offset: 0, mode: mode, is_ram: (mode == MODE_RAM))
next_fd += 1
return int32(kernel_fd)
return -1
proc ion_vfs_read*(fd: int32, buf: pointer, count: uint64): int64 {.exportc, cdecl.} =
let ifd = int(fd)
if not fds.hasKey(ifd): return -1
let fh = addr fds[ifd]
case fh.mode:
of MODE_TAR, MODE_RAM:
let n = tar.vfs_read_at(fh.path, buf, count, fh.offset)
if n > 0: fh.offset += uint64(n)
return n
of MODE_SFS:
# SFS current read-whole-file shim
var temp_buf: array[4096, byte] # FIXME: Small stack buffer
let total = sfs.sfs_read_file(cstring(fh.path), addr temp_buf[0], 4096)
if total < 0: return -1
if fh.offset >= uint64(total): return 0
let avail = uint64(total) - fh.offset
let actual = min(count, avail)
if actual > 0:
copyMem(buf, addr temp_buf[int(fh.offset)], int(actual))
fh.offset += actual
return int64(actual)
proc ion_vfs_write*(fd: int32, buf: pointer, count: uint64): int64 {.exportc, cdecl.} =
let ifd = int(fd)
if not fds.hasKey(ifd): return -1
let fh = addr fds[ifd]
case fh.mode:
of MODE_TAR, MODE_RAM:
let n = tar.vfs_write_at(fh.path, buf, count, fh.offset)
if n > 0: fh.offset += uint64(n)
return n
of MODE_SFS:
sfs.sfs_write_file(cstring(fh.path), cast[cstring](buf), int(count))
return int64(count)
proc ion_vfs_close*(fd: int32): int32 {.exportc, cdecl.} =
let ifd = int(fd)
if fds.hasKey(ifd):
fds.del(ifd)
return 0
return -1
proc ion_vfs_list*(buf: pointer, max_len: uint64): int64 {.exportc, cdecl.} =
var s = "/nexus\n/sysro\n/state\n"
for name in tar.vfs_get_names():
s.add("/sysro/" & name & "\n")
# Add SFS files under /nexus
let sfs_names = sfs.sfs_get_files()
for line in sfs_names.splitLines():
if line.len > 0:
s.add("/nexus/" & line & "\n")
let n = min(s.len, int(max_len))
if n > 0: copyMem(buf, addr s[0], n)
return int64(n)

View File

@ -1,3 +1,12 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## Rumpk Layer 1: Invariant Verification (The Shield)
# import ion # Included in ion.nim # import ion # Included in ion.nim
# Error type for future use # Error type for future use

View File

@ -1,5 +1,16 @@
# core/rumpk/core/ion.nim # SPDX-License-Identifier: LSL-1.0
# Phase 35e: Expanded SysTable with Crypto + Global Channels # Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## Rumpk Layer 1: ION Interface (The Sovereign Protocol)
##
## Defines the core communication protocol between Kernel and Userland.
## Implements the SysTable structure, packet types, and Sovereign Channels.
##
## SAFETY: Provides the ABI contract for lock-free communication.
# CRITICAL: Only import memory module for kernel builds # CRITICAL: Only import memory module for kernel builds
# Userspace builds (with -d:is_membrane) should NOT get the 2MB pool # Userspace builds (with -d:is_membrane) should NOT get the 2MB pool
@ -93,11 +104,17 @@ type
# Phase 35e: Crypto # Phase 35e: Crypto
fn_siphash*: proc(key: ptr array[16, byte], data: pointer, len: uint64, out_hash: ptr array[16, byte]) {.cdecl.} fn_siphash*: proc(key: ptr array[16, byte], data: pointer, len: uint64, out_hash: ptr array[16, byte]) {.cdecl.}
fn_ed25519_verify*: proc(sig: ptr array[64, byte], msg: pointer, len: uint64, pk: ptr array[32, byte]): bool {.cdecl.} fn_ed25519_verify*: proc(sig: ptr array[64, byte], msg: pointer, len: uint64, pk: ptr array[32, byte]): bool {.cdecl.}
# SPEC-021: Monolith Key Derivation
fn_blake3*: proc(data: pointer, len: uint64, out_hash: ptr array[32, byte]) {.cdecl.}
# Phase 36.2: Network Membrane (The Veins) # Phase 36.2: Network Membrane (The Veins)
s_net_rx*: ptr HAL_Ring[IonPacket] # Kernel Producer -> User Consumer s_net_rx*: ptr HAL_Ring[IonPacket] # Kernel Producer -> User Consumer
s_net_tx*: ptr HAL_Ring[IonPacket] # User Producer -> Kernel Consumer s_net_tx*: ptr HAL_Ring[IonPacket] # User Producer -> Kernel Consumer
# Phase 36.3: Shared ION (16 bytes)
fn_ion_alloc*: proc(out_id: ptr uint16): uint64 {.cdecl.}
fn_ion_free*: proc(id: uint16) {.cdecl.}
include invariant include invariant
# --- Sovereign Logic --- # --- Sovereign Logic ---
@ -108,12 +125,14 @@ proc hal_channel_pop*(ring: uint64, out_pkt: ptr IonPacket): bool {.importc, cde
proc hal_cmd_push*(ring: uint64, pkt: CmdPacket): bool {.importc, cdecl.} proc hal_cmd_push*(ring: uint64, pkt: CmdPacket): bool {.importc, cdecl.}
proc hal_cmd_pop*(ring: uint64, out_pkt: ptr CmdPacket): bool {.importc, cdecl.} proc hal_cmd_pop*(ring: uint64, out_pkt: ptr CmdPacket): bool {.importc, cdecl.}
proc send*[T](c: var SovereignChannel[T], pkt: T) = proc send*[T](c: var SovereignChannel[T], pkt: T): bool =
if c.ring == nil: return if c.ring == nil: return false
when T is IonPacket: when T is IonPacket:
discard hal_channel_push(cast[uint64](c.ring), pkt) return hal_channel_push(cast[uint64](c.ring), pkt)
elif T is CmdPacket: elif T is CmdPacket:
discard hal_cmd_push(cast[uint64](c.ring), pkt) return hal_cmd_push(cast[uint64](c.ring), pkt)
else:
return false
proc recv*[T](c: var SovereignChannel[T], out_pkt: var T): bool = proc recv*[T](c: var SovereignChannel[T], out_pkt: var T): bool =
if c.ring == nil: return false if c.ring == nil: return false
@ -129,8 +148,10 @@ var guest_input_hal: HAL_Ring[IonPacket]
# Phase 36.2: Network Channels # Phase 36.2: Network Channels
var chan_net_rx*: SovereignChannel[IonPacket] var chan_net_rx*: SovereignChannel[IonPacket]
var chan_net_tx*: SovereignChannel[IonPacket] var chan_net_tx*: SovereignChannel[IonPacket]
var chan_netswitch_rx*: SovereignChannel[IonPacket] # Internal: Driver -> NetSwitch
var net_rx_hal: HAL_Ring[IonPacket] var net_rx_hal: HAL_Ring[IonPacket]
var net_tx_hal: HAL_Ring[IonPacket] var net_tx_hal: HAL_Ring[IonPacket]
var netswitch_rx_hal: HAL_Ring[IonPacket]
proc ion_init_input*() {.exportc, cdecl.} = proc ion_init_input*() {.exportc, cdecl.} =
guest_input_hal.head = 0 guest_input_hal.head = 0
@ -149,6 +170,11 @@ proc ion_init_network*() {.exportc, cdecl.} =
net_tx_hal.mask = 255 net_tx_hal.mask = 255
chan_net_tx.ring = addr net_tx_hal chan_net_tx.ring = addr net_tx_hal
netswitch_rx_hal.head = 0
netswitch_rx_hal.tail = 0
netswitch_rx_hal.mask = 255
chan_netswitch_rx.ring = addr netswitch_rx_hal
static: doAssert(sizeof(IonPacket) == 24, "IonPacket size mismatch!") static: doAssert(sizeof(IonPacket) == 24, "IonPacket size mismatch!")
static: doAssert(sizeof(CmdPacket) == 32, "CmdPacket size mismatch!") static: doAssert(sizeof(CmdPacket) == 32, "CmdPacket size mismatch!")
static: doAssert(sizeof(SysTable) == 168, "SysTable size mismatch! (Expected 168 after Network expansion)") static: doAssert(sizeof(SysTable) == 192, "SysTable size mismatch! (Expected 192 after BLAKE3 expansion)")

View File

@ -1,3 +1,12 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## Rumpk Layer 1: ION Slab Allocator
# ION Memory Manager # ION Memory Manager
# The "Slab Allocator" for Zero-Copy IO # The "Slab Allocator" for Zero-Copy IO
@ -90,13 +99,13 @@ proc ion_free*(pkt: IonPacket) {.exportc.} =
# Helper for C/Zig Interop (Pure Pointers) # Helper for C/Zig Interop (Pure Pointers)
# Return physical address of a allocated block, put ID in out_id # Return physical address of a allocated block, put ID in out_id
proc ion_alloc_raw*(out_id: ptr uint16): uint64 {.exportc.} = proc ion_alloc_raw*(out_id: ptr uint16): uint64 {.exportc, cdecl.} =
let pkt = ion_alloc() let pkt = ion_alloc()
if pkt.data == nil: return 0 if pkt.data == nil: return 0
out_id[] = pkt.id out_id[] = pkt.id
return pkt.phys return pkt.phys
proc ion_free_raw*(id: uint16) {.exportc.} = proc ion_free_raw*(id: uint16) {.exportc, cdecl.} =
var pkt: IonPacket var pkt: IonPacket
pkt.id = id pkt.id = id
# We don't reconstruct data/phys for free, just push ID # We don't reconstruct data/phys for free, just push ID

View File

@ -1,9 +1,17 @@
# Copyright (c) 2026 Nexus Foundation # SPDX-License-Identifier: LSL-1.0
# Licensed under the Libertaria Sovereign License (LSL-1.0) # Copyright (c) 2026 Markus Maiwald
# See legal/LICENSE_SOVEREIGN.md for details. # Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
# MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI) ## Rumpk Layer 1: The Logic Core (Autonomous Immune System)
# Rumpk Layer 1: The Logic Core (Autonomous Immune System) ##
## The primary kernel orchestrator. Handles boot sequence, service initialization,
## and the main system loop. Manages the transition from HAL (L0) to Userland.
##
## DECISION(Kernel): Cooperative scheduling is used to ensure deterministic
## execution of immune system fibers.
{.push stackTrace: off, lineTrace: off.} {.push stackTrace: off, lineTrace: off.}
@ -12,9 +20,16 @@ import ion
import loader import loader
import fs/tar import fs/tar
import fs/sfs import fs/sfs
import fs/vfs
import netswitch import netswitch
import ../libs/membrane/net_glue import ../libs/membrane/net_glue
import ../libs/membrane/compositor import ../libs/membrane/compositor
import sched
# Phase 31: Memory Manager imports (must be before usage)
proc mm_init() {.importc, cdecl.}
proc mm_enable_kernel_paging() {.importc, cdecl.}
proc mm_activate_satp(satp_val: uint64) {.importc, cdecl.}
var ion_paused*: bool = false var ion_paused*: bool = false
var pause_start*: uint64 = 0 var pause_start*: uint64 = 0
@ -63,7 +78,7 @@ proc wrapper_vfs_write(fd: int32, buf: pointer, count: uint64): int64 {.cdecl.}
var fiber_ion: FiberObject var fiber_ion: FiberObject
var fiber_nexshell: FiberObject var fiber_nexshell: FiberObject
var fiber_ui: FiberObject # fiber_ui removed (unused)
var fiber_subject: FiberObject var fiber_subject: FiberObject
var fiber_watchdog: FiberObject var fiber_watchdog: FiberObject
var fiber_compositor: FiberObject var fiber_compositor: FiberObject
@ -76,7 +91,7 @@ var worker_stacks: array[MAX_WORKERS, array[8192, uint8]]
var worker_active: array[MAX_WORKERS, bool] var worker_active: array[MAX_WORKERS, bool]
var next_worker_id: uint64 = 100 # Start worker IDs at 100 var next_worker_id: uint64 = 100 # Start worker IDs at 100
var subject_loading_path: string = "bin/nipbox" var subject_loading_path: string = "/init"
proc subject_fiber_entry() {.cdecl.} = proc subject_fiber_entry() {.cdecl.} =
## The Sovereign Container for Userland Consciousness. ## The Sovereign Container for Userland Consciousness.
@ -88,27 +103,33 @@ proc subject_fiber_entry() {.cdecl.} =
let entry = kload(subject_loading_path) let entry = kload(subject_loading_path)
if entry != 0: if entry != 0:
kprintln("[Subject] Consciousness Transferred.") kprintln("[Subject] Consciousness Transferred.")
# CRITICAL FIX: Activate userland Sv39 page table before sret
# Without this, userland accesses unmapped memory → page fault → M-mode reset
if current_fiber.satp_value != 0:
kprint("[Subject] Activating userland MMU, satp=")
kprint_hex(current_fiber.satp_value)
kprintln("")
mm_activate_satp(current_fiber.satp_value)
rumpk_enter_userland(entry) rumpk_enter_userland(entry)
else: else:
kprint("[Subject] Failed to load: ") kprint("[Subject] Failed to load: ")
kprintln(cstring(subject_loading_path)) kprintln(cstring(subject_loading_path))
kprintln("[Subject] Pausing for Rebirth.") kprintln("[Subject] Pausing for Rebirth.")
fiber.switch(addr fiber_ion) # Emergency yield to master fiber_sleep(1000)
# fiber.switch(addr fiber_ion) # Emergency yield to master
# --- STACK ALLOCATIONS --- # --- STACK ALLOCATIONS ---
var stack_ion {.align: 4096.}: array[4096, uint8] var stack_ion {.align: 4096.}: array[32768, uint8]
var stack_nexshell {.align: 4096.}: array[4096, uint8] var stack_nexshell {.align: 4096.}: array[32768, uint8]
var stack_ui {.align: 4096.}: array[32768, uint8] # var stack_ui {.align: 4096.}: array[32768, uint8]
var stack_subject {.align: 4096.}: array[32768, uint8] var stack_subject {.align: 4096.}: array[32768, uint8]
var stack_watchdog {.align: 4096.}: array[4096, uint8] var stack_watchdog {.align: 4096.}: array[4096, uint8]
var stack_netswitch {.align: 4096.}: array[8192, uint8] # Phase 36.2 var stack_netswitch {.align: 4096.}: array[128 * 1024, uint8] # Phase 36.2
var stack_compositor {.align: 4096.}: array[128 * 1024, uint8] var stack_compositor {.align: 4096.}: array[128 * 1024, uint8]
# Phase 31: Memory Manager (The Glass Cage)
proc mm_init() {.importc, cdecl.}
proc mm_enable_kernel_paging() {.importc, cdecl.}
# HAL Framebuffer imports (Phase 26: Visual Cortex) # HAL Framebuffer imports (Phase 26: Visual Cortex)
proc fb_kern_get_addr(): uint64 {.importc, cdecl.} proc fb_kern_get_addr(): uint64 {.importc, cdecl.}
# --- INITRD SYMBOLS --- # --- INITRD SYMBOLS ---
@ -122,10 +143,10 @@ var binary_initrd_tar_end {.importc: "_initrd_end".}: char
const SYSTABLE_BASE = 0x83000000'u64 const SYSTABLE_BASE = 0x83000000'u64
# Global Rings (The Pipes - L0 Physics) # Global Rings (The Pipes - L0 Physics)
var guest_rx_hal: HAL_Ring[IonPacket] # guest_rx_hal removed (unused)
var guest_tx_hal: HAL_Ring[IonPacket] # guest_tx_hal removed (unused)
var guest_event_hal: HAL_Ring[IonPacket] # guest_event_hal removed (unused)
var guest_cmd_hal: HAL_Ring[CmdPacket] # var guest_cmd_hal: HAL_Ring[CmdPacket]
# Shared Channels (The Valves - L1 Logic) # Shared Channels (The Valves - L1 Logic)
# Shared Channels # Shared Channels
@ -149,18 +170,34 @@ proc ion_push_stdin*(p: pointer, len: csize_t) {.exportc, cdecl.} =
kprintln("[Kernel] Input packet pushed to ring") kprintln("[Kernel] Input packet pushed to ring")
# Phase 37: Direct routing (Compositor not yet operational) # Wake up Subject if it was waiting for input
chan_input.send(pkt) if fiber_subject.sleep_until == 0xFFFFFFFFFFFFFFFF'u64:
fiber_subject.sleep_until = 0
proc get_ion_load(): int = # Phase 37: Direct routing (Compositor not yet operational)
## Calculate load of the Command Ring (The Heartbeat of the NPLs) discard chan_input.send(pkt)
let head = guest_cmd_hal.head
let tail = guest_cmd_hal.tail # get_ion_load removed (unused)
let mask = guest_cmd_hal.mask
return int((head - tail) and mask)
proc rumpk_yield_internal() {.cdecl, exportc.} proc rumpk_yield_internal() {.cdecl, exportc.}
# [EXISTING] Network Membrane Imports (via C ABI to resolve module cycles)
proc libc_is_socket_fd(fd: int): bool {.importc, cdecl.}
proc libc_impl_socket(domain, sock_type, proto: int): int {.importc, cdecl.}
proc libc_impl_bind(fd: int, addr_ptr: pointer, len: int): int {.importc, cdecl.}
proc libc_impl_connect(fd: int, addr_ptr: pointer, len: int): int {.importc, cdecl.}
proc libc_impl_listen(fd: int, backlog: int): int {.importc, cdecl.}
proc libc_impl_accept(fd: int, addr_ptr: pointer, len_ptr: pointer): int {.importc, cdecl.}
proc libc_impl_recv(fd: int, buf: pointer, count: uint64): int {.importc, cdecl.}
proc libc_impl_send(fd: int, buf: pointer, count: uint64): int {.importc, cdecl.}
# Sockets handled via unified close
# [ADDED] Unified File System Imports (The VFS Bridge)
proc libc_impl_open(path: cstring, flags: int): int {.importc, cdecl.}
proc libc_impl_close(fd: int): int {.importc, cdecl.}
proc libc_impl_read(fd: int, buf: pointer, count: uint64): int {.importc, cdecl.}
proc libc_impl_write(fd: int, buf: pointer, count: uint64): int {.importc, cdecl.}
# HAL Driver API # HAL Driver API
proc hal_io_init() {.importc, cdecl.} proc hal_io_init() {.importc, cdecl.}
proc virtio_net_poll() {.importc, cdecl.} proc virtio_net_poll() {.importc, cdecl.}
@ -168,9 +205,8 @@ proc virtio_net_send(data: pointer, len: uint32) {.importc, cdecl.}
proc rumpk_yield_guard() {.importc, cdecl.} proc rumpk_yield_guard() {.importc, cdecl.}
proc virtio_blk_read(sector: uint64, buf: pointer) {.importc, cdecl.} proc virtio_blk_read(sector: uint64, buf: pointer) {.importc, cdecl.}
proc virtio_blk_write(sector: uint64, buf: pointer) {.importc, cdecl.} proc virtio_blk_write(sector: uint64, buf: pointer) {.importc, cdecl.}
proc ion_free_raw(id: uint16) {.importc, cdecl.}
proc nexshell_main() {.importc, cdecl.} proc nexshell_main() {.importc, cdecl.}
proc ui_fiber_entry() {.importc, cdecl.} # ui_fiber_entry removed (unused)
proc rumpk_halt() {.importc, cdecl, noreturn.} proc rumpk_halt() {.importc, cdecl, noreturn.}
proc compositor_fiber_entry() {.cdecl.} = proc compositor_fiber_entry() {.cdecl.} =
@ -178,9 +214,9 @@ proc compositor_fiber_entry() {.cdecl.} =
while true: while true:
compositor.compositor_step() compositor.compositor_step()
# High frequency yield (120Hz goal) # High frequency yield (120Hz goal)
rumpk_yield_internal() fiber_sleep(10)
proc get_now_ns(): uint64 = proc get_now_ns(): uint64 {.exportc: "get_now_ns", cdecl.} =
proc rumpk_timer_now_ns(): uint64 {.importc, cdecl.} proc rumpk_timer_now_ns(): uint64 {.importc, cdecl.}
return rumpk_timer_now_ns() return rumpk_timer_now_ns()
@ -193,52 +229,56 @@ proc fiber_sleep*(ms: int) {.exportc, cdecl.} =
fiber_yield() fiber_yield()
proc rumpk_yield_internal() {.cdecl, exportc.} = proc rumpk_yield_internal() {.cdecl, exportc.} =
let now = get_now_ns() # The Reactive Dispatcher Integration (SPEC-250)
let prev_fiber = current_fiber
let start_ns = get_now_ns()
# Gather all potential fibers
# Static Fibers
var active_fibers_arr: array[16, ptr FiberObject]
var count = 0
template addFiber(f: var FiberObject) =
if count < 16:
active_fibers_arr[count] = addr f
inc count
# Normal Round Robin logic with Sleep Check if fiber_compositor.stack != nil: addFiber(fiber_compositor)
var next_fiber: Fiber = nil if fiber_netswitch.stack != nil: addFiber(fiber_netswitch)
if fiber_ion.stack != nil: addFiber(fiber_ion)
if fiber_nexshell.stack != nil: addFiber(fiber_nexshell)
if fiber_subject.stack != nil: addFiber(fiber_subject)
if fiber_watchdog.stack != nil: addFiber(fiber_watchdog)
# Dynamic Workers
for i in 0..<MAX_WORKERS:
if worker_active[i]:
addFiber(worker_pool[i])
kprint("[Kernel] Active Fibers: "); kprint_hex(uint64(count)); kprintln("")
if current_fiber == addr fiber_ion: # Execute Spectrum Scheduler
next_fiber = addr fiber_nexshell if count > 0:
elif current_fiber == addr fiber_nexshell: if not sched_tick_spectrum(active_fibers_arr.toOpenArray(0, count - 1)):
next_fiber = addr fiber_subject # The Silence Doctrine: WFI
elif current_fiber == addr fiber_subject: asm "csrsi sstatus, 2" # Ensure interrupts enabled
next_fiber = addr fiber_watchdog asm "wfi"
elif current_fiber == addr fiber_watchdog:
next_fiber = addr fiber_ion # Post-Mortem: Analyze the previous fiber's burst (The Ratchet)
else: let end_ns = get_now_ns()
next_fiber = addr fiber_ion let burst_ns = end_ns - start_ns
if prev_fiber != nil:
sched_analyze_burst(prev_fiber, burst_ns)
# Skip sleeping fibers
var found = false
for _ in 0..6: # Max 6 check
if next_fiber != nil and now >= next_fiber.sleep_until:
found = true
break
# Move to next in sequence
if next_fiber == addr fiber_ion: next_fiber = addr fiber_nexshell
elif next_fiber == addr fiber_nexshell: next_fiber = addr fiber_subject
elif next_fiber == addr fiber_subject: next_fiber = addr fiber_watchdog
elif next_fiber == addr fiber_watchdog: next_fiber = addr fiber_ion
else: next_fiber = addr fiber_ion
# Force found = true for now
found = true
if found and next_fiber != current_fiber:
kprint("[Sched] "); kprint(current_fiber.name); kprint(" -> "); kprintln(next_fiber.name)
switch(next_fiber)
elif not found:
asm "csrsi sstatus, 2"
asm "wfi"
# ========================================================= # =========================================================
# ION Intelligence Fiber (Core System Supervisor) # ION Intelligence Fiber (Core System Supervisor)
# ========================================================= # =========================================================
proc ion_fiber_entry() {.cdecl.} = proc ion_fiber_entry() {.cdecl.} =
hal_io_init() # hal_io_init() -> ALREADY CALLED IN KMAIN
sfs_mount()
sfs_sync_vfs()
kprintln("[ION] Fiber 1 Reporting for Duty.") kprintln("[ION] Fiber 1 Reporting for Duty.")
while true: while true:
var cmd: CmdPacket var cmd: CmdPacket
@ -248,7 +288,7 @@ proc ion_fiber_entry() {.cdecl.} =
matrix_enabled = (cmd.arg > 0) matrix_enabled = (cmd.arg > 0)
of uint32(CmdType.CMD_SYS_EXIT): of uint32(CmdType.CMD_SYS_EXIT):
kprintln("[Kernel] Subject Exited. Respawning...") kprintln("[Kernel] Subject Exited. Respawning...")
subject_loading_path = "bin/nipbox" subject_loading_path = "/init"
init_fiber(addr fiber_subject, subject_fiber_entry, addr stack_subject[0], stack_subject.len) init_fiber(addr fiber_subject, subject_fiber_entry, addr stack_subject[0], stack_subject.len)
of uint32(CmdType.CMD_ION_STOP): of uint32(CmdType.CMD_ION_STOP):
ion_paused = true ion_paused = true
@ -277,22 +317,38 @@ proc ion_fiber_entry() {.cdecl.} =
virtio_blk_write(args.sector, cast[pointer](args.buf)) virtio_blk_write(args.sector, cast[pointer](args.buf))
of uint32(CmdType.CMD_FS_WRITE): of uint32(CmdType.CMD_FS_WRITE):
let args = cast[ptr FileArgs](cmd.arg) let args = cast[ptr FileArgs](cmd.arg)
sfs_write_file(cast[cstring](args.name), cast[cstring](args.data), int(args.len)) sfs.sfs_write_file(cast[cstring](args.name), cast[cstring](args.data), int(args.len))
sfs_sync_vfs() sfs_sync_vfs()
of uint32(CmdType.CMD_FS_READ): of uint32(CmdType.CMD_FS_READ):
let args = cast[ptr FileArgs](cmd.arg) let args = cast[ptr FileArgs](cmd.arg)
let bytes_read = sfs_read_file(cast[cstring](args.name), cast[pointer](args.data), int(args.len)) let bytes_read = sfs.sfs_read_file(cast[cstring](args.name), cast[pointer](args.data), int(args.len))
args.len = uint64(bytes_read) args.len = uint64(bytes_read)
else: else:
discard discard
fiber_yield() fiber_sleep(10) # 10ms poll
# Hardware Ingress (Zig -> Nim) # Hardware Ingress (Zig -> Nim)
proc ion_get_virt(id: uint16): pointer {.importc, cdecl.} proc ion_get_virt(id: uint16): pointer {.importc, cdecl.}
proc ion_ingress*(id: uint16, len: uint16) {.exportc, cdecl.} = proc ion_ingress*(id: uint16, len: uint16) {.exportc, cdecl.} =
let data = ion_get_virt(id) ## Callback from VirtIO-Net HAL.
var pkt = IonPacket(data: cast[ptr UncheckedArray[byte]](data), len: len, id: id) ## id: Slab index containing the packet.
chan_rx.send(pkt) ## len: Length of the ETHERNET FRAME (excluding VirtIO header).
let v_base = ion_get_virt(id)
let p_base = ion_get_phys(id)
# VirtIO-Net Header is 10 bytes (non-mergeable).
# We offset the packet pointers to point directly to the Ethernet Frame.
let eth_v = cast[ptr UncheckedArray[byte]](cast[uint64](v_base) + 10)
let eth_p = p_base + 10
var pkt = IonPacket(data: eth_v, phys: eth_p, len: len, id: id)
# Push to NetSwitch internal pipe for demultiplexing
if not chan_netswitch_rx.send(pkt):
# Backpressure: If NetSwitch is full, we must drop the packet to avoid leaked slabs
# kprintln("[Kernel] NetSwitch RX Full - Dropping Packet")
ion_free_raw(id)
# Panic Handler # Panic Handler
proc nimPanic(msg: cstring) {.exportc: "panic", cdecl, noreturn.} = proc nimPanic(msg: cstring) {.exportc: "panic", cdecl, noreturn.} =
@ -385,6 +441,7 @@ proc k_check_deferred_yield*() {.exportc, cdecl.} =
fiber_yield() fiber_yield()
proc k_handle_syscall*(nr, a0, a1, a2: uint): uint {.exportc, cdecl.} = proc k_handle_syscall*(nr, a0, a1, a2: uint): uint {.exportc, cdecl.} =
# kprint("[Syscall] "); kprint_hex(nr); kprintln("") # kprint("[Syscall] "); kprint_hex(nr); kprintln("")
if nr != 0x100: # Ignore YIELD noise if nr != 0x100: # Ignore YIELD noise
@ -394,81 +451,125 @@ proc k_handle_syscall*(nr, a0, a1, a2: uint): uint {.exportc, cdecl.} =
of 0x01: # EXIT of 0x01: # EXIT
kprintln("[Kernel] Subject EXIT Triggered") kprintln("[Kernel] Subject EXIT Triggered")
var pkt = CmdPacket(kind: uint32(CmdType.CMD_SYS_EXIT), arg: a0) var pkt = CmdPacket(kind: uint32(CmdType.CMD_SYS_EXIT), arg: a0)
chan_cmd.send(pkt) discard chan_cmd.send(pkt)
current_fiber.wants_yield = true
return 0
of 0x100: # YIELD
current_fiber.wants_yield = true current_fiber.wants_yield = true
return 0 return 0
of 0x101: # PLEDGE of 0x101: # PLEDGE
# Only allow reducing privileges? For now, allow setting.
current_fiber.promises = a0 current_fiber.promises = a0
return 0 return 0
of 0x200: # OPEN
# [UPDATED] 0x200: OPEN - Route through Unified LibC
of 0x200:
let flags = int32(a1) let flags = int32(a1)
if (flags and 0x01) != 0: # Check permissions (0=RDONLY, 1=WRONLY, 2=RDWR)
if (flags and 0x03) != 0:
if (current_fiber.promises and PLEDGE_WPATH) == 0: return cast[uint](-1) if (current_fiber.promises and PLEDGE_WPATH) == 0: return cast[uint](-1)
else: else:
if (current_fiber.promises and PLEDGE_RPATH) == 0: return cast[uint](-1) if (current_fiber.promises and PLEDGE_RPATH) == 0: return cast[uint](-1)
return uint(ion_vfs_open(cast[cstring](a0), flags))
of 0x201: # CLOSE # Call the new unified implementation
return uint(ion_vfs_close(int32(a0))) return uint(libc_impl_open(cast[cstring](a0), int(flags)))
of 0x202: # LIST
# [UPDATED] 0x201: CLOSE - Unified close
of 0x201:
return uint(libc_impl_close(int(a0)))
of 0x202: # LIST / READDIR
if (current_fiber.promises and PLEDGE_RPATH) == 0: return cast[uint](-1) if (current_fiber.promises and PLEDGE_RPATH) == 0: return cast[uint](-1)
return uint(ion_vfs_list(cast[pointer](a0), uint64(a1))) return uint(ion_vfs_list(cast[pointer](a0), uint64(a1)))
of 0x203: # READ
if a0 == 0: # [UPDATED] 0x203: READ - Unified Dispatch
of 0x203:
if a0 == 0: # STDIN Special Case
kprintln("[Kernel] sys_read(0) - STDIN request")
if (current_fiber.promises and PLEDGE_STDIO) == 0: return cast[uint](-1) if (current_fiber.promises and PLEDGE_STDIO) == 0: return cast[uint](-1)
var pkt: IonPacket var pkt: IonPacket
if chan_input.recv(pkt): if chan_input.recv(pkt):
kprintln("[Kernel] sys_read(0) - Data available")
let n = if uint64(pkt.len) < a2: uint64(pkt.len) else: a2 let n = if uint64(pkt.len) < a2: uint64(pkt.len) else: a2
if n > 0: copyMem(cast[pointer](a1), cast[pointer](pkt.data), int(n)) if n > 0: copyMem(cast[pointer](a1), cast[pointer](pkt.data), int(n))
ion_free_raw(pkt.id) ion_free_raw(pkt.id)
return n return n
else: else:
kprintln("[Kernel] sys_read(0) - No data, yielding")
current_fiber.wants_yield = true current_fiber.wants_yield = true
return 0 return 0
# Check if it's a socket
if libc_is_socket_fd(int(a0)):
return uint(libc_impl_recv(int(a0), cast[pointer](a1), uint64(a2)))
# Permission Check
if (current_fiber.promises and PLEDGE_RPATH) == 0: return cast[uint](-1) if (current_fiber.promises and PLEDGE_RPATH) == 0: return cast[uint](-1)
return uint(ion_vfs_read(int32(a0), cast[pointer](a1), uint64(a2)))
of 0x204: # WRITE # Route to Sovereign FS via Unified LibC
# Bypass optimization for now to test stability return uint(libc_impl_read(int(a0), cast[pointer](a1), uint64(a2)))
return uint(ion_vfs_write(int32(a0), cast[pointer](a1), uint64(a2)))
of 0x300: # SURFACE_CREATE # [UPDATED] 0x204: WRITE - Unified Dispatch
return uint(compositor.create_surface(int(a0), int(a1))) of 0x204:
of 0x301: # SURFACE_FLIP if a0 == 1 or a0 == 2: # STDOUT/STDERR
return 0 kprintln("[Kernel] sys_write(stdout) called")
of 0x302: # SURFACE_GET_PTR console_write(cast[pointer](a1), csize_t(a2))
return cast[uint](compositor.hal_surface_get_ptr(int32(a0))) kprintln("[Kernel] sys_write(stdout) returning")
of 0x500: # SPAWN return a2
return uint(k_spawn(cast[pointer](a0), uint64(a1)))
of 0x501: # JOIN # Check if it's a socket
return uint(k_join(uint64(a0))) if libc_is_socket_fd(int(a0)):
of 0x100: # YIELD return uint(libc_impl_send(int(a0), cast[pointer](a1), uint64(a2)))
# Deferred yield: Set flag, yield happens after trap return
current_fiber.wants_yield = true # Permission Check
return 0 if (current_fiber.promises and PLEDGE_WPATH) == 0: return cast[uint](-1)
of 0x220: # BLK_READ - Raw Sector Read (Block Valve)
# a0 = sector, a1 = buffer pointer (userland), a2 = count (sectors) # Route to Sovereign FS via Unified LibC
return uint(libc_impl_write(int(a0), cast[pointer](a1), uint64(a2)))
# BLOCK VALVE (SPEC-500)
of 0x220: # BLK_READ
if (current_fiber.promises and PLEDGE_RPATH) == 0: return cast[uint](-1) if (current_fiber.promises and PLEDGE_RPATH) == 0: return cast[uint](-1)
var buf: array[512, byte] var buf: array[512, byte]
virtio_blk_read(uint64(a0), addr buf[0]) virtio_blk_read(uint64(a0), addr buf[0])
copyMem(cast[pointer](a1), addr buf[0], 512) copyMem(cast[pointer](a1), addr buf[0], 512)
return 512 return 512
of 0x221: # BLK_WRITE - Raw Sector Write (Block Valve) of 0x221: # BLK_WRITE
# a0 = sector, a1 = buffer pointer (userland), a2 = count (sectors)
if (current_fiber.promises and PLEDGE_WPATH) == 0: return cast[uint](-1) if (current_fiber.promises and PLEDGE_WPATH) == 0: return cast[uint](-1)
virtio_blk_write(uint64(a0), cast[ptr byte](a1)) virtio_blk_write(uint64(a0), cast[ptr byte](a1))
return 512 return 512
of 0x222: # BLK_SYNC - Flush (Block Valve) of 0x222: # BLK_SYNC
# VirtIO block is synchronous, so this is a no-op for now
return 0 return 0
of 0: # EXIT
fiber_yield() # SURFACE MANAGER (SPEC-600)
of 0x300: return uint(compositor.create_surface(int(a0), int(a1)))
of 0x301: return 0 # FLIP
of 0x302: return cast[uint](compositor.hal_surface_get_ptr(int32(a0)))
# HIVE / WORKERS (SPEC-200)
of 0x500: return uint(k_spawn(cast[pointer](a0), uint64(a1)))
of 0x501: return uint(k_join(uint64(a0)))
# PHOENIX / UPGRADE
of 0x600:
kprintln("\n[Kernel] SYSTEM PHOENIX ACTIVATED.")
proc hal_kexec(entry, dtb: uint64) {.importc, cdecl.}
hal_kexec(uint64(a0), 0)
return 0 return 0
# NETWORK MEMBRANE (SPEC-400)
of 0x900: return uint(libc_impl_socket(int(a0), int(a1), int(a2)))
of 0x901: return uint(libc_impl_bind(int(a0), cast[pointer](a1), int(a2)))
of 0x902: return uint(libc_impl_connect(int(a0), cast[pointer](a1), int(a2)))
of 0x903: return uint(libc_impl_listen(int(a0), int(a1)))
of 0x904: return uint(libc_impl_accept(int(a0), cast[pointer](a1), cast[pointer](a2)))
else: else:
return 0 return 0
proc kmain() {.exportc, cdecl.} = proc kmain() {.exportc, cdecl.} =
kprintln("\n\n") kprintln("\n\n")
kprintln("╔═══════════════════════════════════════╗") kprintln("╔═══════════════════════════════════════╗")
kprintln("║ NEXUS RUMK v1.1 - SOVEREIGN ║") kprintln("║ NEXUS SOVEREIGN CORE v1.1 ")
kprintln("╚═══════════════════════════════════════╝") kprintln("╚═══════════════════════════════════════╝")
kprint("[Kernel] current_fiber Addr: "); kprint_hex(cast[uint64](addr current_fiber)); kprintln("") kprint("[Kernel] current_fiber Addr: "); kprint_hex(cast[uint64](addr current_fiber)); kprintln("")
@ -497,8 +598,7 @@ proc kmain() {.exportc, cdecl.} =
hal_io_init() hal_io_init()
vfs_init(addr binary_initrd_tar_start, addr binary_initrd_tar_end) vfs_init(addr binary_initrd_tar_start, addr binary_initrd_tar_end)
sfs_mount() vfs_mount_init()
sfs_sync_vfs()
let sys = cast[ptr SysTable](SYSTABLE_BASE) let sys = cast[ptr SysTable](SYSTABLE_BASE)
sys.fn_vfs_open = ion_vfs_open sys.fn_vfs_open = ion_vfs_open
@ -513,9 +613,11 @@ proc kmain() {.exportc, cdecl.} =
# Phase 35e: Crypto HAL integration # Phase 35e: Crypto HAL integration
proc hal_crypto_siphash(key: ptr array[16, byte], data: pointer, len: uint64, out_hash: ptr array[16, byte]) {.importc, cdecl.} proc hal_crypto_siphash(key: ptr array[16, byte], data: pointer, len: uint64, out_hash: ptr array[16, byte]) {.importc, cdecl.}
proc hal_crypto_ed25519_verify(sig: ptr array[64, byte], msg: pointer, len: uint64, pk: ptr array[32, byte]): bool {.importc, cdecl.} proc hal_crypto_ed25519_verify(sig: ptr array[64, byte], msg: pointer, len: uint64, pk: ptr array[32, byte]): bool {.importc, cdecl.}
proc hal_crypto_blake3(data: pointer, len: uint64, out_hash: ptr array[32, byte]) {.importc, cdecl.}
sys.fn_siphash = hal_crypto_siphash sys.fn_siphash = hal_crypto_siphash
sys.fn_ed25519_verify = hal_crypto_ed25519_verify sys.fn_ed25519_verify = hal_crypto_ed25519_verify
sys.fn_blake3 = hal_crypto_blake3
# GPU disabled temporarily until display works # GPU disabled temporarily until display works
# proc virtio_gpu_init(base: uint64) {.importc, cdecl.} # proc virtio_gpu_init(base: uint64) {.importc, cdecl.}
@ -561,6 +663,20 @@ proc kmain() {.exportc, cdecl.} =
# Phase 36.2: Initialize Network Membrane BEFORE userland starts # Phase 36.2: Initialize Network Membrane BEFORE userland starts
netswitch_init() netswitch_init()
# OVERRIDE: Move Network Rings to Shared Memory (User Accessible)
# Previous offsets: 0x1000..0x5000 used for RX/TX/Event/Cmd/Input
let ring_net_rx_ptr = cast[ptr HAL_Ring[IonPacket]](SYSTABLE_BASE + 0x6000)
let ring_net_tx_ptr = cast[ptr HAL_Ring[IonPacket]](SYSTABLE_BASE + 0x7000)
# Re-initialize shared rings (clearing stale kernel BSS state)
ring_net_rx_ptr.head = 0; ring_net_rx_ptr.tail = 0; ring_net_rx_ptr.mask = 255
ring_net_tx_ptr.head = 0; ring_net_tx_ptr.tail = 0; ring_net_tx_ptr.mask = 255
# Connect Valves to the new shared Pipes
chan_net_rx.ring = ring_net_rx_ptr
chan_net_tx.ring = ring_net_tx_ptr
netswitch_attach_systable(sys) netswitch_attach_systable(sys)
# Framebuffer info # Framebuffer info
@ -570,16 +686,22 @@ proc kmain() {.exportc, cdecl.} =
sys.fb_stride = 1920 * 4 sys.fb_stride = 1920 * 4
sys.fb_bpp = 32 sys.fb_bpp = 32
sys.fn_yield = rumpk_yield_guard sys.fn_yield = rumpk_yield_guard
sys.fn_ion_alloc = cast[proc(out_id: ptr uint16): uint64 {.cdecl.}](ion_alloc_raw)
sys.fn_ion_free = cast[proc(id: uint16) {.cdecl.}](ion_free_raw)
kprintln("[Kernel] Spawning System Fibers...") kprintln("[Kernel] Spawning System Fibers...")
fiber_ion.name = "ion" fiber_ion.name = "ion"
init_fiber(addr fiber_ion, ion_fiber_entry, addr stack_ion[0], sizeof(stack_ion)) init_fiber(addr fiber_ion, ion_fiber_entry, addr stack_ion[0], sizeof(stack_ion))
fiber_ion.promises = PLEDGE_ALL
# Compositor
fiber_compositor.name = "compositor" fiber_compositor.name = "compositor"
init_fiber(addr fiber_compositor, compositor_fiber_entry, addr stack_compositor[0], sizeof(stack_compositor)) init_fiber(addr fiber_compositor, compositor_fiber_entry, addr stack_compositor[0], sizeof(stack_compositor))
fiber_compositor.promises = PLEDGE_ALL
fiber_nexshell.name = "nexshell" fiber_nexshell.name = "nexshell"
init_fiber(addr fiber_nexshell, nexshell_main, addr stack_nexshell[0], sizeof(stack_nexshell)) init_fiber(addr fiber_nexshell, nexshell_main, addr stack_nexshell[0], sizeof(stack_nexshell))
fiber_nexshell.promises = PLEDGE_ALL
# Phase 31: Page Table root for worker isolation # Phase 31: Page Table root for worker isolation
proc mm_create_worker_map(stack_base: uint64, stack_size: uint64, packet_addr: uint64): uint64 {.importc, cdecl.} proc mm_create_worker_map(stack_base: uint64, stack_size: uint64, packet_addr: uint64): uint64 {.importc, cdecl.}
@ -591,14 +713,26 @@ proc kmain() {.exportc, cdecl.} =
fiber_watchdog.name = "watchdog" fiber_watchdog.name = "watchdog"
init_fiber(addr fiber_watchdog, watchdog_loop, addr stack_watchdog[0], sizeof(stack_watchdog)) init_fiber(addr fiber_watchdog, watchdog_loop, addr stack_watchdog[0], sizeof(stack_watchdog))
fiber_watchdog.promises = PLEDGE_ALL
# Phase 36.2: NetSwitch Fiber (Traffic Cop) # Phase 36.2: NetSwitch Fiber (Traffic Cop)
fiber_netswitch.name = "netswitch" fiber_netswitch.name = "netswitch"
init_fiber(addr fiber_netswitch, fiber_netswitch_entry, addr stack_netswitch[0], sizeof(stack_netswitch)) init_fiber(addr fiber_netswitch, fiber_netswitch_entry, addr stack_netswitch[0], sizeof(stack_netswitch))
fiber_netswitch.promises = PLEDGE_ALL # NetSwitch needs full power
kprintln("[Kernel] Enabling Supervisor Interrupts (SIE)...") kprintln("[Kernel] Enabling Supervisor Interrupts (SIE)...")
asm "csrsi sstatus, 2" asm "csrsi sstatus, 2"
# Assign Spectra (The Caste System)
setSpectrum(addr fiber_compositor, Spectrum.Photon) # 120Hz Critical
setSpectrum(addr fiber_netswitch, Spectrum.Photon) # Line-rate Polling
setSpectrum(addr fiber_ion, Spectrum.Matter) # System Logic
setSpectrum(addr fiber_nexshell, Spectrum.Gravity) # Human Inputs (Polling)
setSpectrum(addr fiber_subject, Spectrum.Matter) # User Payload (Promoted for Bootstrap)
setSpectrum(addr fiber_watchdog, Spectrum.Photon) # Safety Critical (Keepalives)
kprintln("[Kernel] All Systems Go. Entering Autonomous Loop.") kprintln("[Kernel] All Systems Go. Entering Autonomous Loop.")
switch(addr fiber_ion) switch(addr fiber_ion)

View File

@ -1,3 +1,12 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## Rumpk Layer 1: Application Loader (The Breath of Life)
# MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI) # MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI)
# Rumpk Phase 8: The Summoning (ELF Loader) # Rumpk Phase 8: The Summoning (ELF Loader)

View File

@ -1,3 +1,12 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## Rumpk Layer 1: ELF Binary Parser
# MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI) # MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI)
# ELF64 Header Definitions for Rumpk Summoning # ELF64 Header Definitions for Rumpk Summoning

View File

@ -1,3 +1,12 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## Rumpk Layer 1: Software Network Switch
# core/rumpk/core/netswitch.nim # core/rumpk/core/netswitch.nim
# Phase 36.2: The Traffic Cop (Network Membrane Layer 2 Switch) # Phase 36.2: The Traffic Cop (Network Membrane Layer 2 Switch)
# #
@ -13,6 +22,7 @@ import ion
# Forward declare fiber_yield to avoid circular import # Forward declare fiber_yield to avoid circular import
proc fiber_yield*() {.importc, cdecl.} proc fiber_yield*() {.importc, cdecl.}
proc fiber_sleep*(ms: int) {.importc, cdecl.}
# HAL Imports # HAL Imports
proc virtio_net_poll() {.importc, cdecl.} proc virtio_net_poll() {.importc, cdecl.}
@ -20,6 +30,13 @@ proc virtio_net_send(data: pointer, len: uint32) {.importc, cdecl.}
# Logging # Logging
proc kprintln(s: cstring) {.importc, cdecl.} proc kprintln(s: cstring) {.importc, cdecl.}
proc kprint(s: cstring) {.importc, cdecl.}
proc kprint_hex(v: uint64) {.importc, cdecl.}
proc get_now_ns(): uint64 {.importc, cdecl.}
# Membrane Infrastructure (LwIP Glue)
proc membrane_init*() {.importc, cdecl.}
proc pump_membrane_stack*() {.importc, cdecl.}
var netswitch_initialized: bool = false var netswitch_initialized: bool = false
@ -36,42 +53,95 @@ proc netswitch_attach_systable*(sys: ptr SysTable) =
sys.s_net_tx = chan_net_tx.ring sys.s_net_tx = chan_net_tx.ring
kprintln("[NetSwitch] SysTable Rings Attached") kprintln("[NetSwitch] SysTable Rings Attached")
type
EthHeader* {.packed.} = object
dst*: array[6, byte]
src*: array[6, byte]
ethertype*: uint16 # Big Endian
proc swap16(v: uint16): uint16 =
((v and 0xFF) shl 8) or (v shr 8)
proc netswitch_process_packet(pkt: IonPacket): bool =
## Layer 2 Demultiplexer
if pkt.len < 14:
ion_free(pkt)
return false
let eth = cast[ptr EthHeader](pkt.data)
let etype = swap16(eth.ethertype)
case etype:
of 0x0800, 0x0806, 0x86DD: # IPv4, ARP, IPv6
# Route to Legacy/LwIP Membrane
if not chan_net_rx.send(pkt):
# Ring full (Backpressure)
ion_free(pkt)
return false
return true
of 0x88B5: # Sovereign UTCP (SPEC-410)
# TODO: Route to dedicated UTCP channel
# kprintln("[NetSwitch] UTCP Sovereign Packet Identified")
ion_free(pkt)
return true # Handled (dropped)
else:
# Drop unknown EtherTypes (Security/Sovereignty)
ion_free(pkt)
return false
proc fiber_netswitch_entry*() {.cdecl.} = proc fiber_netswitch_entry*() {.cdecl.} =
membrane_init()
kprintln("[NetSwitch] Fiber Entry - The Traffic Cop is ON DUTY") kprintln("[NetSwitch] Fiber Entry - The Traffic Cop is ON DUTY")
var rx_activity: bool = false var rx_activity: bool = false
var tx_activity: bool = false var tx_activity: bool = false
var rx_count: uint64 = 0
var tx_count: uint64 = 0
var last_stat_print: uint64 = 0
while true: while true:
rx_activity = false rx_activity = false
tx_activity = false tx_activity = false
# ============================================ # 1. Drive the hardware poll (fills chan_netswitch_rx)
# RX PATH: Hardware -> chan_net_rx -> Userland
# ============================================
# virtio_net_poll() internally calls ion_ingress() which pushes
# received packets to the hardware driver's internal ring.
# We poll here to drive the RX path.
virtio_net_poll() virtio_net_poll()
# ============================================ # 2. Drive the LwIP Stack (Timers/RX)
# TX PATH: Userland -> chan_net_tx -> Hardware pump_membrane_stack()
# ============================================
# 2. Consume from the Driver -> Switch internal ring
var raw_pkt: IonPacket
while chan_netswitch_rx.recv(raw_pkt):
if netswitch_process_packet(raw_pkt):
rx_activity = true
inc rx_count
# 3. TX PATH: Userland -> Hardware
var tx_pkt: IonPacket var tx_pkt: IonPacket
while chan_net_tx.recv(tx_pkt): while chan_net_tx.recv(tx_pkt):
if tx_pkt.data != nil and tx_pkt.len > 0: if tx_pkt.data != nil and tx_pkt.len > 0:
virtio_net_send(cast[pointer](tx_pkt.data), uint32(tx_pkt.len)) virtio_net_send(cast[pointer](tx_pkt.data), uint32(tx_pkt.len))
inc tx_count
ion_free(tx_pkt) ion_free(tx_pkt)
tx_activity = true tx_activity = true
# ============================================ # 4. Periodically print stats
# YIELD STRATEGY let now = get_now_ns()
# ============================================ if now - last_stat_print > 5000000000'u64: # 5 seconds
kprint("[NetSwitch] STATS - RX: ")
kprint_hex(rx_count)
kprint(" TX: ")
kprint_hex(tx_count)
kprintln("")
last_stat_print = now
# 5. Yield Strategy
if rx_activity or tx_activity: if rx_activity or tx_activity:
# War Mode: Continue processing if we moved data # War Mode: High priority processing
continue continue
else: else:
# Peace Mode: Yield to let other fibers run fiber_sleep(10)
fiber_yield()
{.pop.} {.pop.}

View File

@ -1,3 +1,12 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## Rumpk Layer 1: Panic Override (Emergency Procedures)
# Rumpk Panic Override # Rumpk Panic Override
# Required for Nim --os:any / --os:standalone # Required for Nim --os:any / --os:standalone
# This file must be named panicoverride.nim # This file must be named panicoverride.nim

View File

@ -1,3 +1,12 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## Rumpk Layer 1: Simple Lock-Free Ring Buffers
# Rumpk Disruptor Ring Buffer # Rumpk Disruptor Ring Buffer
# Lock-free O(1) inter-fiber communication # Lock-free O(1) inter-fiber communication

170
core/sched.nim Normal file
View File

@ -0,0 +1,170 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## Rumpk Layer 1: The Reactive Dispatcher (The Tyrant)
##
## Implements the Silence Doctrine (SPEC-250).
## - No Tick.
## - No Policy.
## - Only Physics.
{.push stackTrace: off, lineTrace: off.}
import fiber
# We might need to access the Fiber globals from fiber.nim
# fiber.nim exports current_fiber, but we need to iterate them.
# Currently kernel.nim manages the specific fibers variables (fiber_ion, fiber_ui, etc.)
# We need a centralized registry or a way to iterate.
#
# For the first pass, we can replicate the logic in kernel.nim which explicitly checks
# the known fibers, but structured as the Spectrum loop.
# Or we can make kernel.nim pass the fibers to us.
#
# Let's keep it simple and stateless in sched.nim if possible, or have it manage the queue.
# Since kernel.nim holds the variables, sched.nim should probably define the *Strategy*
# and kernel.nim calls it, OR sched.nim should import kernel (circular!).
#
# Better: fiber.nim holds a linked list of fibers?
# Or sched.nim is just a helper module that kernel.nim uses.
# Let's define the Strategy here.
# To avoid circular imports, kernel.nim will likely INCLUDE sched.nim or sched.nim
# will act on a passed context.
# BUT, SPEC-250 implies sched.nim *is* the logic.
#
# Let's define the Harmonic logic.
# We need access to `current_fiber` (from fiber.nim) and `get_now_ns` (helper).
proc sched_get_now_ns*(): uint64 {.importc: "get_now_ns", cdecl.}
# Forward declaration for the tick function
# Returns TRUE if a fiber was switched to (work done/found).
# Returns FALSE if the system should sleep (WFI).
proc sched_tick_spectrum*(fibers: openArray[ptr FiberObject]): bool =
let now = sched_get_now_ns()
# =========================================================
# Phase 1: PHOTON (Hard Real-Time / Hardware Driven)
# =========================================================
# - V-Sync (Compositor)
# - Audio Mix
# - Network Polling (War Mode)
var run_photon = false
for f in fibers:
if f != nil and f.getSpectrum() == Spectrum.Photon:
if now >= f.sleep_until:
if f != current_fiber:
switch(f); return true
else:
run_photon = true
if run_photon: return true
# =========================================================
# Phase 2: MATTER (Interactive / Latency Sensitive)
# =========================================================
# - Shell
# - Editor
var run_matter = false
for f in fibers:
if f != nil and f.getSpectrum() == Spectrum.Matter:
if now >= f.sleep_until:
if f != current_fiber:
switch(f); return true
else:
run_matter = true
if run_matter: return true
# =========================================================
# Phase 3: GRAVITY (Throughput / Background)
# =========================================================
# - Compiler
# - Ledger Sync
var run_gravity = false
for f in fibers:
if f != nil and f.getSpectrum() == Spectrum.Gravity:
if now >= f.sleep_until:
if f != current_fiber:
switch(f); return true
else:
run_gravity = true
if run_gravity: return true
# =========================================================
# Phase 4: VOID (Scavenger)
# =========================================================
# - Untrusted Code
# - Speculative Execution
for f in fibers:
if f != nil and f.getSpectrum() == Spectrum.Void:
if now >= f.sleep_until:
if f != current_fiber:
switch(f)
return true
else:
return true
# =========================================================
# THE SILENCE
# =========================================================
# If we reached here, NO fiber is runnable.
return false
# =========================================================
# THE RATCHET (Post-Execution Analysis)
# =========================================================
proc console_write(p: pointer, len: csize_t) {.importc, cdecl.}
proc sched_log(msg: string) =
if msg.len > 0:
console_write(unsafeAddr msg[0], csize_t(msg.len))
proc sched_demote(f: ptr FiberObject) =
## Demote a fiber to a lower Spectrum tier
let current = f.getSpectrum()
case current:
of Spectrum.Photon:
f.setSpectrum(Spectrum.Matter)
console_write(cstring("[Ratchet] DEMOTED fiber to Matter\n"), 34)
of Spectrum.Matter:
f.setSpectrum(Spectrum.Gravity)
console_write(cstring("[Ratchet] DEMOTED fiber to Gravity\n"), 35)
of Spectrum.Gravity:
f.setSpectrum(Spectrum.Void)
console_write(cstring("[Ratchet] DEMOTED fiber to Void\n"), 32)
of Spectrum.Void:
discard # Already at the bottom
proc sched_analyze_burst*(f: ptr FiberObject, burst_ns: uint64) =
## Analyze the burst duration of a fiber after it yields/switches
## Implements the 3-strike rule for budget violations
if f == nil: return
f.last_burst_ns = burst_ns
# Update moving average (exponential: 75% old, 25% new)
if f.avg_burst == 0:
f.avg_burst = burst_ns
else:
f.avg_burst = (f.avg_burst * 3 + burst_ns) div 4
# Budget enforcement
if f.budget_ns > 0 and burst_ns > f.budget_ns:
f.violations += 1
console_write(cstring("[Ratchet] Violation: fiber exceeded budget\n"), 42)
if f.violations >= 3:
sched_demote(f)
f.violations = 0 # Reset after demotion
{.pop.}

View File

@ -1,3 +1,12 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## Rumpk Layer 1: The Watchdog (Immune Monitor)
# Watchdog Fiber - Logic Core Immune System # Watchdog Fiber - Logic Core Immune System
@ -27,7 +36,7 @@ proc watchdog_loop() {.cdecl.} =
# Send CMD_ION_START to the Control Loop # Send CMD_ION_START to the Control Loop
var cmd = CmdPacket(kind: uint32(ion.CmdType.CMD_ION_START), arg: 0) var cmd = CmdPacket(kind: uint32(ion.CmdType.CMD_ION_START), arg: 0)
chan_cmd.send(cmd) discard chan_cmd.send(cmd)
# Cooperative Multitasking: Must yield! # Cooperative Multitasking: Must yield!
# 🏛️ ADAPTIVE GOVERNOR (Phase 3: IDLE) # 🏛️ ADAPTIVE GOVERNOR (Phase 3: IDLE)
@ -39,5 +48,5 @@ proc watchdog_loop() {.cdecl.} =
# csrci sstatus, 2 # csrci sstatus, 2
# """ # """
fiber_yield() fiber_sleep(100)
# asm "wfi" # asm "wfi"

View File

@ -1,3 +1,12 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## Rumpk Layer 1: Console Writer Infrastructure
# Forward declarations for C symbols # Forward declarations for C symbols
proc console_write(p: pointer, len: csize_t) {.importc, cdecl.} proc console_write(p: pointer, len: csize_t) {.importc, cdecl.}

View File

@ -1,28 +1,38 @@
// MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI) // SPDX-License-Identifier: LCL-1.0
// HAL ABI - The Contract between L0 (Zig) and L1 (Nim) // Copyright (c) 2026 Markus Maiwald
// This struct is the "contract" for future language integration // Stewardship: Self Sovereign Society Foundation
//
// This file is part of the Nexus Commonwealth.
// See legal/LICENSE_COMMONWEALTH.md for license terms.
//! Rumpk HAL ABI: The Contract between L0 (Zig) and L1 (Nim)
//!
//! This struct defines the function pointer table for platform abstraction.
//! All function pointers use C calling convention for Nim FFI compatibility.
// NOTE(Build): Zig 0.15.x requires explicit callconv on extern struct fn pointers
pub const HAL = extern struct { pub const HAL = extern struct {
/// Write to console/serial /// Write to console/serial
console_write: *const fn ([*]const u8, usize) void, console_write: *const fn ([*]const u8, usize) callconv(.c) void,
/// Allocate physical pages /// Allocate physical pages
palloc: *const fn (usize) ?*anyopaque, palloc: *const fn (usize) callconv(.c) ?*anyopaque,
/// Free physical pages /// Free physical pages
pfree: *const fn (*anyopaque) void, pfree: *const fn (*anyopaque) callconv(.c) void,
/// Register interrupt handler /// Register interrupt handler
irq_register: *const fn (u8, *const fn () void) void, irq_register: *const fn (u8, *const fn () callconv(.c) void) callconv(.c) void,
/// Get current time in nanoseconds /// Get current time in nanoseconds
timer_now_ns: *const fn () u64, timer_now_ns: *const fn () callconv(.c) u64,
/// Halt the CPU /// Halt the CPU
halt: *const fn () noreturn, halt: *const fn () callconv(.c) noreturn,
}; };
/// Global HAL instance - initialized by boot code // SAFETY(HAL): Global instance initialized by init() before any access.
// SAFETY(HAL): Global HAL instance is populated by `init()` during the early boot phase.
pub var hal: HAL = undefined; pub var hal: HAL = undefined;
/// Initialize the HAL with platform-specific implementations /// Initialize the HAL with platform-specific implementations
@ -31,13 +41,15 @@ pub fn init(console: anytype, allocator: anytype) void {
.console_write = console.write, .console_write = console.write,
.palloc = allocator.alloc, .palloc = allocator.alloc,
.pfree = allocator.free, .pfree = allocator.free,
.irq_register = undefined, // TODO // SAFETY(HAL): Placeholders for future implementation.
.timer_now_ns = undefined, // TODO // These function pointers are not called until implemented.
.irq_register = undefined, // TODO(HAL): Implement IRQ registration
.timer_now_ns = undefined, // TODO(HAL): Implement timer
.halt = halt_impl, .halt = halt_impl,
}; };
} }
fn halt_impl() noreturn { fn halt_impl() callconv(.c) noreturn {
while (true) { while (true) {
asm volatile ("wfi"); asm volatile ("wfi");
} }

View File

@ -76,13 +76,23 @@ rumpk_enter_userland:
# - SPIE (Previous Interrupt Enable) = 1 (Enable Interrupts on sret) - Bit 5 # - SPIE (Previous Interrupt Enable) = 1 (Enable Interrupts on sret) - Bit 5
# - SUM (Supervisor User Memory) - PRESERVE (Already set in kmain) # - SUM (Supervisor User Memory) - PRESERVE (Already set in kmain)
# Clear SPP bit (bit 8) # Clear SPP bit (bit 8) -> Return to User Mode
li t0, (1 << 8) li t0, (1 << 8)
csrc sstatus, t0 csrc sstatus, t0
# Set SPIE bit (bit 5) # Enable SPIE bit (bit 5) -> Enable Interrupts on sret
li t0, (1 << 5) li t0, (1 << 5)
csrs sstatus, t0 csrs sstatus, t0
# 🔧 CRITICAL FIX: Set SUM bit (bit 18) to allow Kernel access to U=1 pages (UART, etc.)
li t0, (1 << 18)
csrs sstatus, t0
# 2.5 Synchronize Instruction Cache (Critical for newly loaded code)
fence.i
# 🔧 CRITICAL FIX: Set sscratch to Kernel Stack (sp)
csrw sscratch, sp
# 3. Use sret to transit to U-mode # 3. Use sret to transit to U-mode
sret sret

View File

@ -1,6 +1,16 @@
// MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI) // SPDX-License-Identifier: LCL-1.0
// RUMPK HAL // SOVEREIGN CHANNELS (The Pipes) // Copyright (c) 2026 Markus Maiwald
// THE INVARIANT SHIELD - Phase 2 Task 1 // Stewardship: Self Sovereign Society Foundation
//
// This file is part of the Nexus Commonwealth.
// See legal/LICENSE_COMMONWEALTH.md for license terms.
//! Rumpk HAL: Sovereign Channels (Lock-Free Ring Buffers)
//!
//! Implements atomic lock-free ring buffers for ION packet communication.
//! Provides the "pipes" between kernel and userspace with invariant protection.
//!
//! SAFETY: All operations use atomic loads/stores with proper memory fences.
const std = @import("std"); const std = @import("std");

View File

@ -1,5 +1,14 @@
// core/rumpk/hal/crypto.zig // SPDX-License-Identifier: LCL-1.0
// Phase 35e: The Cryptographic Foundation // Copyright (c) 2026 Markus Maiwald
// Stewardship: Self Sovereign Society Foundation
//
// This file is part of the Nexus Commonwealth.
// See legal/LICENSE_COMMONWEALTH.md for license terms.
//! Rumpk HAL: Cryptographic Functions
//!
//! Provides SipHash-2-4 (128-bit) for packet IDs and Ed25519 signature verification.
//! All functions are exported for use by the ION layer.
const std = @import("std"); const std = @import("std");
@ -20,3 +29,11 @@ export fn hal_crypto_ed25519_verify(sig: *const [64]u8, msg: [*]const u8, msg_le
signature.verify(msg[0..msg_len], public_key) catch return false; signature.verify(msg[0..msg_len], public_key) catch return false;
return true; return true;
} }
/// BLAKE3 Hash (256-bit) for key derivation
/// Used by Monolith (SPEC-021) to derive VolumeKey from 4MB keyfile
export fn hal_crypto_blake3(data: [*]const u8, len: usize, out: *[32]u8) void {
var hasher = std.crypto.hash.Blake3.init(.{});
hasher.update(data[0..len]);
hasher.final(out);
}

View File

@ -1,5 +1,17 @@
// MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI) // SPDX-License-Identifier: LCL-1.0
// RUMPK HAL // RISC-V ENTRY - SOVEREIGN TRAP ARCHITECTURE // Copyright (c) 2026 Markus Maiwald
// Stewardship: Self Sovereign Society Foundation
//
// This file is part of the Nexus Commonwealth.
// See legal/LICENSE_COMMONWEALTH.md for license terms.
//! Rumpk HAL: RISC-V Entry Point (Sovereign Trap Architecture)
//!
//! This is the hardware floor for RISC-V64. Sets up stack, trap vectors,
//! S-mode transition, and memory management before handing off to Nim.
//!
//! SAFETY: Runs in bare-metal S-mode with Sv39 paging.
const std = @import("std"); const std = @import("std");
const uart = @import("uart.zig"); const uart = @import("uart.zig");
const virtio_net = @import("virtio_net.zig"); const virtio_net = @import("virtio_net.zig");
@ -13,6 +25,7 @@ export fn _start() callconv(.naked) noreturn {
// 1. Disable Interrupts // 1. Disable Interrupts
\\ csrw sie, zero \\ csrw sie, zero
\\ csrw satp, zero \\ csrw satp, zero
\\ csrw sscratch, zero
// 1.1 Enable FPU (sstatus.FS = Initial [01]) // 1.1 Enable FPU (sstatus.FS = Initial [01])
\\ li t0, 0x2000 \\ li t0, 0x2000
\\ csrs sstatus, t0 \\ csrs sstatus, t0
@ -23,6 +36,16 @@ export fn _start() callconv(.naked) noreturn {
\\ la gp, __global_pointer$ \\ la gp, __global_pointer$
\\ .option pop \\ .option pop
// 1.5 Clear BSS (Zero out uninitialized globals)
\\ la t0, __bss_start
\\ la t1, __bss_end
\\ bge t0, t1, 2f
\\ 1:
\\ sb zero, (t0)
\\ addi t0, t0, 1
\\ blt t0, t1, 1b
\\ 2:
// 2. Set up Stack // 2. Set up Stack
\\ la sp, stack_bytes \\ la sp, stack_bytes
\\ li t0, 65536 \\ li t0, 65536
@ -79,12 +102,17 @@ const TrapFrame = extern struct {
}; };
// Full Context Save Trap Entry // Full Context Save Trap Entry
export fn trap_entry() callconv(.naked) void { export fn trap_entry() align(4) callconv(.naked) void {
asm volatile ( asm volatile (
// LOUD HARDWARE TRACE: Write '!' to UART // 🔧 CRITICAL FIX: Stack Switching (User -> Kernel)
\\ li t0, 0x10000000 // Swap sp and sscratch.
\\ li t1, 33 // If from User: sp=KStack, sscratch=UStack
\\ sb t1, 0(t0) // If from Kernel: sp=0 (sscratch was 0), sscratch=KStack
\\ csrrw sp, sscratch, sp
\\ bnez sp, 1f
// Came from Kernel (sp was 0). Restore sp.
\\ csrrw sp, sscratch, sp
\\ 1:
// Allocate stack (36 words * 8 bytes = 288 bytes) // Allocate stack (36 words * 8 bytes = 288 bytes)
\\ addi sp, sp, -288 \\ addi sp, sp, -288
@ -141,10 +169,10 @@ export fn trap_entry() callconv(.naked) void {
\\ mv a0, sp \\ mv a0, sp
\\ call rss_trap_handler \\ call rss_trap_handler
// Restore CSRs (sepc might be modified by syscall handler to skip ecall) // Restore CSRs
\\ ld t0, 240(sp) \\ ld t0, 240(sp)
\\ csrw sepc, t0 \\ csrw sepc, t0
// We restore sstatus to preserve interrupt state if needed, though usually fixed in kernel // We restore sstatus
\\ ld t1, 248(sp) \\ ld t1, 248(sp)
\\ csrw sstatus, t1 \\ csrw sstatus, t1
@ -207,6 +235,9 @@ export fn rss_trap_handler(frame: *TrapFrame) void {
// Write result back to a0 // Write result back to a0
frame.a0 = res; frame.a0 = res;
// DIAGNOSTIC: Syscall completed
uart.print("[Trap] Syscall done, returning to userland\n");
// uart.puts("[Trap] Checking deferred yield\n"); // uart.puts("[Trap] Checking deferred yield\n");
// Check for deferred yield // Check for deferred yield
k_check_deferred_yield(); k_check_deferred_yield();
@ -222,6 +253,8 @@ export fn rss_trap_handler(frame: *TrapFrame) void {
while (true) {} while (true) {}
} }
// SAFETY(Stack): Memory is immediately used by _start before any read.
// Initialized to `undefined` for performance (no zeroing 64KB at boot).
export var stack_bytes: [64 * 1024]u8 align(16) = undefined; export var stack_bytes: [64 * 1024]u8 align(16) = undefined;
const hud = @import("hud.zig"); const hud = @import("hud.zig");
@ -275,3 +308,28 @@ export fn rumpk_timer_now_ns() u64 {
// QEMU Virt machine is 10MHz -> 1 tick = 100ns // QEMU Virt machine is 10MHz -> 1 tick = 100ns
return ticks * 100; return ticks * 100;
} }
// =========================================================
// KEXEC (The Phoenix Protocol)
// =========================================================
export fn hal_kexec(entry: u64, dtb: u64) noreturn {
// 1. Disable Interrupts
asm volatile ("csrc sstatus, 2");
// 2. Disable MMU (Return to Physical Reality)
// WARNING: This assumes we are Identity Mapped (VA=PA) or executing from a location
// where PA is the same. mm.zig creates Identity Map for Kernel code.
asm volatile ("csrw satp, zero");
asm volatile ("sfence.vma zero, zero");
// 3. Jump to new kernel
asm volatile (
\\ jr %[entry]
:
: [entry] "r" (entry),
[dtb] "{a1}" (dtb),
[hart] "{a0}" (0),
);
unreachable;
}

View File

@ -1,4 +1,16 @@
// Phase 26: C-compatible wrapper for framebuffer access // SPDX-License-Identifier: LCL-1.0
// Copyright (c) 2026 Markus Maiwald
// Stewardship: Self Sovereign Society Foundation
//
// This file is part of the Nexus Commonwealth.
// See legal/LICENSE_COMMONWEALTH.md for license terms.
//! Rumpk HAL: Framebuffer FFI Wrapper
//!
//! Provides C-compatible exports for framebuffer access from Nim.
//!
//! SAFETY: Proxies requests to the primary framebuffer module. No state of its own.
const fb = @import("framebuffer.zig"); const fb = @import("framebuffer.zig");
export fn fb_kern_get_addr() usize { export fn fb_kern_get_addr() usize {

View File

@ -1,6 +1,17 @@
// MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI) // SPDX-License-Identifier: LCL-1.0
// Phase 3.5c: The Canvas - Static Framebuffer in BSS // Copyright (c) 2026 Markus Maiwald
// This is our "Video RAM" living in kernel memory. // Stewardship: Self Sovereign Society Foundation
//
// This file is part of the Nexus Commonwealth.
// See legal/LICENSE_COMMONWEALTH.md for license terms.
//! Rumpk Layer 0: The Canvas (Static Framebuffer)
//!
//! Implements the primary graphics buffer (VRAM) living in BSS.
//! Provides primitives for pixel plotting, rect-filling, and screen fading.
//!
//! SAFETY: All drawing operations include clipping logic to prevent BSS overflow.
//! Resolution is fixed at 1920x1080 ARGB.
const std = @import("std"); const std = @import("std");

View File

@ -1,6 +1,17 @@
// MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI) // SPDX-License-Identifier: LCL-1.0
// Phase 3.5c: The Retina - VirtIO-GPU Driver // Copyright (c) 2026 Markus Maiwald
// Blasts pixels from RAM canvas to host display. // Stewardship: Self Sovereign Society Foundation
//
// This file is part of the Nexus Commonwealth.
// See legal/LICENSE_COMMONWEALTH.md for license terms.
//! Rumpk Layer 0: VirtIO-GPU Driver (The Retina)
//!
//! Blasts pixels from RAM canvas to host display.
//! Handles command queue management, resource creation, and buffer flushing.
//!
//! SAFETY: All hardware registers and queues are accessed via volatile pointers.
//! Uses static command/response buffers to avoid dynamic allocation in the tick loop.
const std = @import("std"); const std = @import("std");
const fb = @import("framebuffer.zig"); const fb = @import("framebuffer.zig");
@ -142,6 +153,8 @@ const VirtioQueueLayout = extern struct {
}; };
var queue align(PAGE_SIZE) = VirtioQueueLayout{ var queue align(PAGE_SIZE) = VirtioQueueLayout{
// SAFETY(GPU): Descriptor ring is initialized to `undefined` for performance.
// Individual descriptors are populated by `send_command` before use.
.desc = undefined, .desc = undefined,
.avail = .{ .flags = 0, .idx = 0, .ring = [_]u16{0} ** QUEUE_SIZE }, .avail = .{ .flags = 0, .idx = 0, .ring = [_]u16{0} ** QUEUE_SIZE },
._pad1 = [_]u8{0} ** (PAGE_SIZE - @sizeOf([QUEUE_SIZE]VirtioDesc) - @sizeOf(VirtioAvail)), ._pad1 = [_]u8{0} ** (PAGE_SIZE - @sizeOf([QUEUE_SIZE]VirtioDesc) - @sizeOf(VirtioAvail)),
@ -151,7 +164,12 @@ var queue align(PAGE_SIZE) = VirtioQueueLayout{
var last_used_idx: u16 = 0; var last_used_idx: u16 = 0;
// Command/Response buffers (static) // Command/Response buffers (static)
// SAFETY(GPU): Command buffer initialized to `undefined` for performance.
// Populated by command-specific functions (e.g. `cmd_transfer_2d`) before transmission.
var cmd_buf: [512]u8 align(4096) = undefined; var cmd_buf: [512]u8 align(4096) = undefined;
// SAFETY(GPU): Response buffer initialized to `undefined` for performance.
// Populated by hardware device during synchronous command execution.
var resp_buf: [256]u8 align(4096) = undefined; var resp_buf: [256]u8 align(4096) = undefined;
// ========================================================= // =========================================================

View File

@ -1,6 +1,16 @@
// MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI) // SPDX-License-Identifier: LCL-1.0
// RUMPK HAL // HUD TUI // Copyright (c) 2026 Markus Maiwald
// Minimal ANSI escape code utilities for the NexShell HUD. // Stewardship: Self Sovereign Society Foundation
//
// This file is part of the Nexus Commonwealth.
// See legal/LICENSE_COMMONWEALTH.md for license terms.
//! Rumpk HAL: HUD TUI Utilities
//!
//! Provides minimal ANSI escape code utilities for the NexShell HUD.
//! Used for basic TUI elements like boxes and color management.
//!
//! SAFETY: All operations are synchronous and communicate via UART.
const uart = @import("uart.zig"); const uart = @import("uart.zig");
@ -63,6 +73,7 @@ fn print_u8(n: u8) void {
uart.print("0"); uart.print("0");
return; return;
} }
// SAFETY(HUD): Local buffer is immediately populated by the while loop.
var buf: [3]u8 = undefined; var buf: [3]u8 = undefined;
var i: u8 = 0; var i: u8 = 0;
var val = n; var val = n;

View File

@ -1,11 +1,16 @@
// SPDX-License-Identifier: LCL-1.0
// Copyright (c) 2026 Markus Maiwald // Copyright (c) 2026 Markus Maiwald
// Licensed under the Libertaria Commonwealth License (LCL-1.0) // Stewardship: Self Sovereign Society Foundation
// See legal/LICENSE_COMMONWEALTH.md for details.
// //
// Rumpk Layer 0: The Concrete Foundation // This file is part of the Nexus Commonwealth.
// Markus Maiwald (Architect) | Voxis Forge (AI) // See legal/LICENSE_COMMONWEALTH.md for license terms.
//
// This is the hardware floor. Sets up stack and calls Nim. //! Rumpk Layer 0: The Concrete Foundation (HAL Entry Point)
//!
//! This is the hardware floor. Sets up stack, initializes UART,
//! draws the initial HUD, and hands off to Nim L1.
//!
//! SAFETY: Runs in bare-metal mode with no runtime support.
const uart = @import("uart.zig"); const uart = @import("uart.zig");
@ -22,6 +27,8 @@ export fn hal_io_init() void {
// Stack Setup (16KB) // Stack Setup (16KB)
// ========================================================= // =========================================================
// SAFETY(Stack): Memory is immediately used by _start before any read.
// Initialized to `undefined` for performance (no zeroing 64KB at boot).
export var stack_bytes: [64 * 1024]u8 align(16) = undefined; export var stack_bytes: [64 * 1024]u8 align(16) = undefined;
// ========================================================= // =========================================================

View File

@ -1,6 +1,16 @@
// MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI) // SPDX-License-Identifier: LCL-1.0
// Phase 3.5d: The Matrix Protocol - Rainmaker Logic // Copyright (c) 2026 Markus Maiwald
// Greets the Subject, then recedes into the background. // Stewardship: Self Sovereign Society Foundation
//
// This file is part of the Nexus Commonwealth.
// See legal/LICENSE_COMMONWEALTH.md for license terms.
//! Rumpk HAL: Matrix Protocol (Rainmaker Logic)
//!
//! Implements a "Matrix" falling rain effect for the boot splash.
//! Recedes into the background after a fixed lifetime.
//!
//! SAFETY: Uses a simple Xorshift PRNG. Animation state is global.
const std = @import("std"); const std = @import("std");
const fb = @import("framebuffer.zig"); const fb = @import("framebuffer.zig");
@ -12,6 +22,8 @@ const COLS = fb.WIDTH / FONT_W;
const LIFETIME_FRAMES = 150; // ~5 seconds at 30FPS (reduced for impact) const LIFETIME_FRAMES = 150; // ~5 seconds at 30FPS (reduced for impact)
// State // State
// SAFETY(Matrix): Drops array is initialized by `init()` before use.
// Initialized to `undefined` to save a 512B zero-sweep in BSS.
var drops: [COLS]i32 = undefined; var drops: [COLS]i32 = undefined;
var frame_count: usize = 0; var frame_count: usize = 0;
var is_active: bool = false; var is_active: bool = false;

View File

@ -1,5 +1,17 @@
// Phase 31: The Glass Cage - Sv39 Virtual Memory Isolation // SPDX-License-Identifier: LCL-1.0
// Memory Manager: Page Table Infrastructure // Copyright (c) 2026 Markus Maiwald
// Stewardship: Self Sovereign Society Foundation
//
// This file is part of the Nexus Commonwealth.
// See legal/LICENSE_COMMONWEALTH.md for license terms.
//! Rumpk HAL: Memory Management (The Glass Cage)
//!
//! Implements Sv39 virtual memory isolation for RISC-V.
//! Handles page table construction, identity mapping, and worker isolation.
//!
//! SAFETY: Manages raw physical memory addresses for page tables.
//! Performs identity mapping for the kernel and restricted mapping for workers.
const std = @import("std"); const std = @import("std");
@ -126,10 +138,6 @@ pub fn map_page(root: *PageTable, va: u64, pa: u64, flags: u64) !void {
pte.* = PageTableEntry.init(@intFromPtr(new_pt), PTE_V); pte.* = PageTableEntry.init(@intFromPtr(new_pt), PTE_V);
} }
if (pte.is_leaf()) {
return;
}
pt = @ptrFromInt(pte.get_pa()); pt = @ptrFromInt(pte.get_pa());
} }
@ -169,13 +177,17 @@ pub fn create_worker_map(stack_base: u64, stack_size: u64, packet_addr: u64) !*P
// 🏛 THE EXPANDED CAGE (Phase 37 - 256MB RAM) // 🏛 THE EXPANDED CAGE (Phase 37 - 256MB RAM)
// 1. Kernel Memory (0-32MB) -> Supervisor ONLY (PTE_U = 0) kprint("[MM] Creating worker map:\n");
// This allows the fiber trampoline to execute in S-mode. kprint("[MM] Kernel (S-mode): 0x80000000-0x88000000\n");
try map_range(root, DRAM_BASE, DRAM_BASE, 32 * 1024 * 1024, PTE_R | PTE_W | PTE_X); kprint("[MM] User (U-mode): 0x88000000-0x90000000\n");
// 2. User Memory (32-256MB) -> User Accessible (PTE_U = 1) // 1. Kernel Memory (0-128MB) -> Supervisor ONLY (PTE_U = 0)
// This allows NipBox (at 96MB offset, 64MB size) to execute in U-mode. // This allows the fiber trampoline to execute in S-mode.
try map_range(root, DRAM_BASE + (32 * 1024 * 1024), DRAM_BASE + (32 * 1024 * 1024), 224 * 1024 * 1024, PTE_R | PTE_W | PTE_X | PTE_U); try map_range(root, DRAM_BASE, DRAM_BASE, 128 * 1024 * 1024, PTE_R | PTE_W | PTE_X);
// 2. User Memory (128-256MB) -> User Accessible (PTE_U = 1)
// This allows NipBox (at 128MB offset) to execute in U-mode.
try map_range(root, DRAM_BASE + (128 * 1024 * 1024), DRAM_BASE + (128 * 1024 * 1024), 128 * 1024 * 1024, PTE_R | PTE_W | PTE_X | PTE_U);
// 3. User MMIO (UART) // 3. User MMIO (UART)
try map_range(root, UART_BASE, UART_BASE, PAGE_SIZE, PTE_R | PTE_W | PTE_U); try map_range(root, UART_BASE, UART_BASE, PAGE_SIZE, PTE_R | PTE_W | PTE_U);
@ -183,7 +195,14 @@ pub fn create_worker_map(stack_base: u64, stack_size: u64, packet_addr: u64) !*P
// 4. Overlap stack with user access // 4. Overlap stack with user access
try map_range(root, stack_base, stack_base, stack_size, PTE_R | PTE_W | PTE_U); try map_range(root, stack_base, stack_base, stack_size, PTE_R | PTE_W | PTE_U);
_ = packet_addr; // 5. Shared SysTable & Rings (0x83000000) - Map 32KB (8 pages)
var j: u64 = 0;
while (j < 8) : (j += 1) {
const addr = packet_addr + (j * PAGE_SIZE);
try map_page(root, addr, addr, PTE_R | PTE_W | PTE_U);
}
kprint("[MM] Worker map created successfully\n");
return root; return root;
} }
@ -207,7 +226,8 @@ pub export fn mm_activate_satp(satp_val: u64) callconv(.c) void {
// Export for kernel // Export for kernel
pub export fn mm_init() callconv(.c) void { pub export fn mm_init() callconv(.c) void {
const pt_base = DRAM_BASE + (16 * 1024 * 1024); // Relocate page tables to 240MB offset (Top of 256MB)
const pt_base = DRAM_BASE + (240 * 1024 * 1024);
init_page_allocator(pt_base, 8 * 1024 * 1024); init_page_allocator(pt_base, 8 * 1024 * 1024);
} }

265
hal/ram_blk.zig Normal file
View File

@ -0,0 +1,265 @@
// SPDX-License-Identifier: LCL-1.0
// Copyright (c) 2026 Markus Maiwald
// Stewardship: Self Sovereign Society Foundation
//
// This file is part of the Nexus Commonwealth.
// See legal/LICENSE_COMMONWEALTH.md for license terms.
//! Rumpk HAL: Reed-Solomon RAM Block Device (SPEC-023)
//!
//! Provides ECC-protected RAM storage using Reed-Solomon GF(2^8).
//! This is the "Cortex" - Space-Grade resilient memory.
const std = @import("std");
// =========================================================
// Galois Field GF(2^8) Arithmetic
// =========================================================
// Primitive polynomial: x^8 + x^4 + x^3 + x^2 + 1 (0x11D)
const GF_PRIM: u16 = 0x11D;
// Precomputed log and antilog tables for GF(2^8)
var gf_log: [256]u8 = undefined;
var gf_exp: [512]u8 = undefined;
var gf_initialized: bool = false;
fn gf_init() void {
if (gf_initialized) return;
var x: u16 = 1;
for (0..255) |i| {
gf_exp[i] = @truncate(x);
gf_log[@as(usize, @as(u8, @truncate(x)))] = @truncate(i);
x <<= 1;
if (x & 0x100 != 0) {
x ^= GF_PRIM;
}
}
// Extend exp table for easier modulo
for (255..512) |i| {
gf_exp[i] = gf_exp[i - 255];
}
gf_log[0] = 0; // Undefined, but avoid issues
gf_initialized = true;
}
fn gf_mul(a: u8, b: u8) u8 {
if (a == 0 or b == 0) return 0;
const log_a = gf_log[a];
const log_b = gf_log[b];
return gf_exp[@as(u16, log_a) + @as(u16, log_b)];
}
fn gf_div(a: u8, b: u8) u8 {
if (b == 0) return 0; // Error: division by zero
if (a == 0) return 0;
const log_a = gf_log[a];
const log_b = gf_log[b];
return gf_exp[@as(u16, log_a) + 255 - @as(u16, log_b)];
}
fn gf_pow(a: u8, n: u8) u8 {
if (n == 0) return 1;
if (a == 0) return 0;
const log_a: u16 = gf_log[a];
return gf_exp[(log_a * @as(u16, n)) % 255];
}
fn gf_inv(a: u8) u8 {
return gf_exp[255 - @as(u16, gf_log[a])];
}
// =========================================================
// Reed-Solomon Codec
// =========================================================
pub const SECTOR_SIZE: usize = 512;
pub const PARITY_SIZE: usize = 32; // Can correct 16 byte errors
pub const TOTAL_SIZE: usize = SECTOR_SIZE + PARITY_SIZE;
// Generator polynomial coefficients (precomputed for t=16)
var rs_generator: [PARITY_SIZE + 1]u8 = undefined;
var rs_generator_initialized: bool = false;
fn rs_init_generator() void {
if (rs_generator_initialized) return;
gf_init();
// Build generator polynomial: prod(x - alpha^i) for i = 0..PARITY_SIZE-1
rs_generator[0] = 1;
for (1..PARITY_SIZE + 1) |i| {
rs_generator[i] = 0;
}
for (0..PARITY_SIZE) |i| {
const alpha_i = gf_pow(2, @truncate(i));
// Multiply by (x - alpha^i)
var j: usize = PARITY_SIZE;
while (j > 0) : (j -= 1) {
rs_generator[j] = rs_generator[j - 1] ^ gf_mul(rs_generator[j], alpha_i);
}
rs_generator[0] = gf_mul(rs_generator[0], alpha_i);
}
rs_generator_initialized = true;
}
/// Encode data with Reed-Solomon parity
pub fn rs_encode(data: []const u8, parity: *[PARITY_SIZE]u8) void {
rs_init_generator();
// Initialize parity to zero
for (parity) |*p| p.* = 0;
// Polynomial division
for (data) |byte| {
const feedback = byte ^ parity[0];
// Shift parity register
for (0..PARITY_SIZE - 1) |i| {
parity[i] = parity[i + 1] ^ gf_mul(rs_generator[PARITY_SIZE - 1 - i], feedback);
}
parity[PARITY_SIZE - 1] = gf_mul(rs_generator[0], feedback);
}
}
/// Calculate syndromes for error detection
fn rs_syndromes(data: []const u8, parity: []const u8) [PARITY_SIZE]u8 {
var syndromes: [PARITY_SIZE]u8 = undefined;
for (0..PARITY_SIZE) |i| {
const alpha_i = gf_pow(2, @truncate(i));
var s: u8 = 0;
// Evaluate polynomial at alpha^i
for (data) |byte| {
s = gf_mul(s, alpha_i) ^ byte;
}
for (parity) |byte| {
s = gf_mul(s, alpha_i) ^ byte;
}
syndromes[i] = s;
}
return syndromes;
}
/// Check if all syndromes are zero (no errors)
fn rs_check_syndromes(syndromes: []const u8) bool {
for (syndromes) |s| {
if (s != 0) return false;
}
return true;
}
/// Decode and repair data using Reed-Solomon
/// Returns true if data is valid (or was repaired), false if uncorrectable
pub fn rs_decode(data: []u8, parity: []u8) bool {
rs_init_generator();
const syndromes = rs_syndromes(data, parity);
// No errors
if (rs_check_syndromes(&syndromes)) return true;
// TODO: Implement Berlekamp-Massey algorithm for error location
// TODO: Implement Forney algorithm for error correction
// For MVP, we detect but don't yet repair multi-byte errors
// Simple single-byte error correction (simplified)
// This is a placeholder - full RS decoding is complex
return false; // Could not repair
}
// =========================================================
// RAM Block Device Interface
// =========================================================
var ram_base: [*]u8 = undefined;
var ram_size: usize = 0;
var ram_initialized: bool = false;
/// Initialize the RAM block device with a memory region
export fn ram_blk_init(base: [*]u8, size: usize) void {
gf_init();
rs_init_generator();
ram_base = base;
ram_size = size;
ram_initialized = true;
}
/// Get the number of sectors available
export fn ram_blk_sector_count() u32 {
if (!ram_initialized) return 0;
return @truncate(ram_size / TOTAL_SIZE);
}
/// Write a sector with ECC protection
export fn ram_blk_write(sector: u32, data: [*]const u8) i32 {
if (!ram_initialized) return -1;
const offset = @as(usize, sector) * TOTAL_SIZE;
if (offset + TOTAL_SIZE > ram_size) return -1;
// Calculate parity
var parity: [PARITY_SIZE]u8 = undefined;
rs_encode(data[0..SECTOR_SIZE], &parity);
// Write data + parity
const dest = ram_base + offset;
@memcpy(dest[0..SECTOR_SIZE], data[0..SECTOR_SIZE]);
@memcpy(dest[SECTOR_SIZE..TOTAL_SIZE], &parity);
return SECTOR_SIZE;
}
/// Read a sector with ECC verification/repair
export fn ram_blk_read(sector: u32, data: [*]u8) i32 {
if (!ram_initialized) return -1;
const offset = @as(usize, sector) * TOTAL_SIZE;
if (offset + TOTAL_SIZE > ram_size) return -1;
const src = ram_base + offset;
// Read data + parity
@memcpy(data[0..SECTOR_SIZE], src[0..SECTOR_SIZE]);
var parity: [PARITY_SIZE]u8 = undefined;
@memcpy(&parity, src[SECTOR_SIZE..TOTAL_SIZE]);
// Verify and attempt repair
var data_slice: [SECTOR_SIZE]u8 = undefined;
@memcpy(&data_slice, data[0..SECTOR_SIZE]);
if (!rs_decode(&data_slice, &parity)) {
// TODO: Log the uncorrectable error
return -2; // ECC_ERROR
}
// Copy repaired data back
@memcpy(data[0..SECTOR_SIZE], &data_slice);
return SECTOR_SIZE;
}
/// Scrub a sector (read and verify, repair if needed)
export fn ram_blk_scrub(sector: u32) i32 {
var temp: [SECTOR_SIZE]u8 = undefined;
const result = ram_blk_read(sector, &temp);
if (result == SECTOR_SIZE) {
// Re-write to fix any corrected errors
return ram_blk_write(sector, &temp);
}
return result;
}
/// Scrub all sectors (patrol scrubbing)
export fn ram_blk_scrub_all() u32 {
var errors: u32 = 0;
const count = ram_blk_sector_count();
for (0..count) |i| {
if (ram_blk_scrub(@truncate(i)) < 0) {
errors += 1;
}
}
return errors;
}

View File

@ -1,7 +1,17 @@
// Markus Maiwald (Architect) | Voxis Forge (AI) // SPDX-License-Identifier: LCL-1.0
// RUMPK L0 // Copyright (c) 2026 Markus Maiwald
// libc_stubs.zig // Stewardship: Self Sovereign Society Foundation
// We are the standard library now. //
// This file is part of the Nexus Commonwealth.
// See legal/LICENSE_COMMONWEALTH.md for license terms.
//! Rumpk Layer 0: libc Stubs (Bump Allocator)
//!
//! We are the standard library now. Provides malloc/free/realloc/calloc
//! for libraries that expect libc (e.g., LwIP).
//!
//! DECISION(Alloc): Bump allocator chosen for simplicity and determinism.
//! Memory is never reclaimed; system reboots to reset.
const uart = @import("uart.zig"); const uart = @import("uart.zig");
@ -10,8 +20,15 @@ const uart = @import("uart.zig");
// ========================================================= // =========================================================
// Simple Bump Allocator for L0 // Simple Bump Allocator for L0
var heap: [32 * 1024 * 1024]u8 align(4096) = undefined; // 32MB Heap // SAFETY(Heap): Memory is written by malloc before any read occurs.
// Initialized to `undefined` to avoid zeroing 32MB at boot.
var heap: [96 * 1024 * 1024]u8 align(4096) = undefined;
var heap_idx: usize = 0; var heap_idx: usize = 0;
var heap_init_done: bool = false;
export fn debug_print(s: [*]const u8, len: usize) void {
uart.print(s[0..len]);
}
// Header structure (64 bytes aligned to match LwIP MEM_ALIGNMENT) // Header structure (64 bytes aligned to match LwIP MEM_ALIGNMENT)
const BlockHeader = struct { const BlockHeader = struct {
@ -22,14 +39,36 @@ const BlockHeader = struct {
export fn malloc(size: usize) ?*anyopaque { export fn malloc(size: usize) ?*anyopaque {
if (size == 0) return null; if (size == 0) return null;
if (!heap_init_done) {
if (heap_idx != 0) {
uart.print("[Alloc] WARNING: BSS NOT ZEROED! heap_idx: ");
uart.print_hex(heap_idx);
uart.print("\n");
heap_idx = 0;
}
heap_init_done = true;
}
const total_needed = size + @sizeOf(BlockHeader); const total_needed = size + @sizeOf(BlockHeader);
const align_mask: usize = 63; // 64-byte alignment const align_mask: usize = 63; // 64-byte alignment
const aligned_idx = (heap_idx + align_mask) & ~align_mask; const aligned_idx = (heap_idx + align_mask) & ~align_mask;
if (aligned_idx + total_needed > heap.len) { if (aligned_idx + total_needed > heap.len) {
uart.print("[Alloc] OOM! Size: ");
uart.print_hex(size);
uart.print(" Used: ");
uart.print_hex(heap_idx);
uart.print("\n");
return null; return null;
} }
// Trace allocations (disabled to reduce noise)
// uart.print("[Alloc] ");
// uart.print_hex(size);
// uart.print(" -> Used: ");
// uart.print_hex(aligned_idx + total_needed);
// uart.print("\n");
const base_ptr = &heap[aligned_idx]; const base_ptr = &heap[aligned_idx];
const header = @as(*BlockHeader, @ptrCast(@alignCast(base_ptr))); const header = @as(*BlockHeader, @ptrCast(@alignCast(base_ptr)));
header.size = size; header.size = size;

139
hal/stubs_user.zig Normal file
View File

@ -0,0 +1,139 @@
// SPDX-License-Identifier: LCL-1.0
// Copyright (c) 2026 Markus Maiwald
// Stewardship: Self Sovereign Society Foundation
//
// This file is part of the Nexus Commonwealth.
// See legal/LICENSE_COMMONWEALTH.md for license terms.
//! Rumpk Layer 0: libc Stubs (Bump Allocator)
//!
//! We are the standard library now. Provides malloc/free/realloc/calloc
//! for libraries that expect libc (e.g., LwIP).
//!
//! DECISION(Alloc): Bump allocator chosen for simplicity and determinism.
//! Memory is never reclaimed; system reboots to reset.
const uart = @import("uart.zig");
// =========================================================
// Heap Stubs (Bump Allocator with Block Headers)
// =========================================================
// Simple Bump Allocator for L0
// SAFETY(Heap): Memory is written by malloc before any read occurs.
// Initialized to `undefined` to avoid zeroing 32MB at boot.
var heap: [32 * 1024 * 1024]u8 align(4096) = undefined;
var heap_idx: usize = 0;
var heap_init_done: bool = false;
export fn debug_print(s: [*]const u8, len: usize) void {
uart.print(s[0..len]);
}
export fn kprint_hex(value: u64) void {
uart.print_hex(value);
}
// Header structure (64 bytes aligned to match LwIP MEM_ALIGNMENT)
const BlockHeader = struct {
size: usize,
_pad: [64 - @sizeOf(usize)]u8,
};
export fn malloc(size: usize) ?*anyopaque {
if (size == 0) return null;
if (!heap_init_done) {
if (heap_idx != 0) {
uart.print("[Alloc] WARNING: BSS NOT ZEROED! heap_idx: ");
uart.print_hex(heap_idx);
uart.print("\n");
heap_idx = 0;
}
heap_init_done = true;
}
const total_needed = size + @sizeOf(BlockHeader);
const align_mask: usize = 63; // 64-byte alignment
const aligned_idx = (heap_idx + align_mask) & ~align_mask;
if (aligned_idx + total_needed > heap.len) {
uart.print("[Alloc] OOM! Size: ");
uart.print_hex(size);
uart.print(" Used: ");
uart.print_hex(heap_idx);
uart.print("\n");
return null;
}
// Trace allocations (disabled to reduce noise)
// uart.print("[Alloc] ");
// uart.print_hex(size);
// uart.print(" -> Used: ");
// uart.print_hex(aligned_idx + total_needed);
// uart.print("\n");
const base_ptr = &heap[aligned_idx];
const header = @as(*BlockHeader, @ptrCast(@alignCast(base_ptr)));
header.size = size;
heap_idx = aligned_idx + total_needed;
return @as(*anyopaque, @ptrFromInt(@intFromPtr(base_ptr) + @sizeOf(BlockHeader)));
}
export fn free(ptr: ?*anyopaque) void {
// Bump allocator: no-op free.
_ = ptr;
}
export fn realloc(ptr: ?*anyopaque, size: usize) ?*anyopaque {
if (ptr == null) return malloc(size);
if (size == 0) {
free(ptr);
return null;
}
// Retrieve old size from header
const base_addr = @intFromPtr(ptr.?) - @sizeOf(BlockHeader);
const header = @as(*BlockHeader, @ptrFromInt(base_addr));
const old_size = header.size;
// Optimization: If new size is smaller and it's the last block, we could shrink?
// But for a bump allocator, just allocate new.
const new_ptr = malloc(size);
if (new_ptr) |np| {
const copy_size = if (size < old_size) size else old_size;
const src = @as([*]const u8, @ptrCast(ptr.?));
const dst = @as([*]u8, @ptrCast(np));
var i: usize = 0;
while (i < copy_size) : (i += 1) {
dst[i] = src[i];
}
free(ptr);
return np;
}
return null;
}
export fn calloc(nmemb: usize, size: usize) ?*anyopaque {
const total = nmemb * size;
const ptr = malloc(total);
if (ptr) |p| {
const dst = @as([*]u8, @ptrCast(p));
var i: usize = 0;
while (i < total) : (i += 1) {
dst[i] = 0;
}
}
return ptr;
}
// =========================================================
// Rumpk Runtime Support
// =========================================================
export fn get_ticks() u32 {
return 0; // TODO: Implement real timer
}

View File

@ -1,12 +1,23 @@
// MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI) // SPDX-License-Identifier: LCL-1.0
// Phase 35a: The Surface Allocator // Copyright (c) 2026 Markus Maiwald
// Manages contiguous memory chunks for window buffers. // Stewardship: Self Sovereign Society Foundation
//
// This file is part of the Nexus Commonwealth.
// See legal/LICENSE_COMMONWEALTH.md for license terms.
//! Rumpk Layer 0: Surface Allocator
//!
//! Manages contiguous memory chunks for window buffers (compositor).
//! Provides a simple pool-based allocation for up to 16 surfaces.
//!
//! DECISION(Graphics): Fixed pool size of 32MB for surfaces.
//! Bump-style allocation; reclamation requires system reset.
const std = @import("std"); const std = @import("std");
const uart = @import("uart.zig"); const uart = @import("uart.zig");
pub const MAX_SURFACES = 16; pub const MAX_SURFACES = 16;
pub const SURFACE_POOL_SIZE = 32 * 1024 * 1024; // 32MB for surfaces pub const SURFACE_POOL_SIZE = 1 * 1024 * 1024; // 1MB for surfaces (temporary reduction)
// Surface Descriptor // Surface Descriptor
pub const Surface = struct { pub const Surface = struct {
@ -18,10 +29,13 @@ pub const Surface = struct {
}; };
// Global Surface Pool // Global Surface Pool
// SAFETY(Surfaces): Array is initialized by hal_surface_init before use.
var surfaces: [MAX_SURFACES]Surface = undefined; var surfaces: [MAX_SURFACES]Surface = undefined;
var next_surface_id: i32 = 1; var next_surface_id: i32 = 1;
// Backing memory for surfaces (in BSS) // Backing memory for surfaces (in BSS)
// SAFETY(SurfaceHeap): Memory written by alloc before any read.
// Initialized to `undefined` to avoid zeroing 32MB at boot.
var surface_heap: [SURFACE_POOL_SIZE]u8 align(4096) = undefined; var surface_heap: [SURFACE_POOL_SIZE]u8 align(4096) = undefined;
var heap_offset: usize = 0; var heap_offset: usize = 0;
@ -29,6 +43,7 @@ export fn hal_surface_init() void {
for (&surfaces) |*s| { for (&surfaces) |*s| {
s.id = -1; s.id = -1;
s.active = false; s.active = false;
// SAFETY(Surfaces): Pointer reset to `undefined`. Populated during allocation.
s.ptr = undefined; s.ptr = undefined;
s.width = 0; s.width = 0;
s.height = 0; s.height = 0;

View File

@ -1,7 +1,18 @@
// Rumpk Layer 0: UART Driver // SPDX-License-Identifier: LCL-1.0
// Minimal serial output for QEMU 'virt' machine // Copyright (c) 2026 Markus Maiwald
// Supports PL011 (ARM64) and 16550A (RISC-V) // Stewardship: Self Sovereign Society Foundation
// Phase 37.2: Input buffering to prevent character loss //
// This file is part of the Nexus Commonwealth.
// See legal/LICENSE_COMMONWEALTH.md for license terms.
//! Rumpk Layer 0: UART Driver
//!
//! Minimal serial I/O for QEMU 'virt' machine.
//! Supports PL011 (ARM64) and 16550A (RISC-V).
//!
//! SAFETY: All MMIO accesses use volatile pointers.
//! Ring buffer is initialized to undefined for performance;
//! head/tail indices ensure only written bytes are read.
const std = @import("std"); const std = @import("std");
const builtin = @import("builtin"); const builtin = @import("builtin");
@ -23,6 +34,8 @@ const NS16550A_LCR: usize = 0x03; // Line Control Register
// Input Ring Buffer (256 bytes, power of 2 for fast masking) // Input Ring Buffer (256 bytes, power of 2 for fast masking)
const INPUT_BUFFER_SIZE = 256; const INPUT_BUFFER_SIZE = 256;
// SAFETY(RingBuffer): Only accessed via head/tail indices.
// Bytes are written before read. No uninitialized reads possible.
var input_buffer: [INPUT_BUFFER_SIZE]u8 = undefined; var input_buffer: [INPUT_BUFFER_SIZE]u8 = undefined;
var input_head: u32 = 0; // Write position var input_head: u32 = 0; // Write position
var input_tail: u32 = 0; // Read position var input_tail: u32 = 0; // Read position

View File

@ -1,3 +1,18 @@
// SPDX-License-Identifier: LCL-1.0
// Copyright (c) 2026 Markus Maiwald
// Stewardship: Self Sovereign Society Foundation
//
// This file is part of the Nexus Commonwealth.
// See legal/LICENSE_COMMONWEALTH.md for license terms.
//! Rumpk HAL: UI Layer (The Persona)
//!
//! Bridges microui (C) with the Zig HAL and Framebuffer.
//! Handles GUI rendering, layout management, and the boot animation loop.
//!
//! SAFETY: Integrates with a C-based GUI library via @cImport.
//! Global context is initialized by `init()` before use in the UI fiber.
const std = @import("std"); const std = @import("std");
const fb = @import("framebuffer.zig"); const fb = @import("framebuffer.zig");
@ -8,6 +23,7 @@ pub const c = @cImport({
}); });
// --- STATIC MEMORY --- // --- STATIC MEMORY ---
// SAFETY(UI): Context is initialized by `c.mu_init(&ctx)` in `init()`.
var ctx: c.mu_Context = undefined; var ctx: c.mu_Context = undefined;
// --- FONT (The "8-bit" classic) --- // --- FONT (The "8-bit" classic) ---

View File

@ -1,69 +1,59 @@
// MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI) // SPDX-License-Identifier: LCL-1.0
// Rumpk Layer 0: VirtIO-Block Driver (The Ledger) // Copyright (c) 2026 Markus Maiwald
// - Provides persistent storage access (Sector I/O) // Stewardship: Self Sovereign Society Foundation
//
// This file is part of the Nexus Commonwealth.
// See legal/LICENSE_COMMONWEALTH.md for license terms.
//! Rumpk Layer 0: VirtIO-Block Driver
//!
//! Provides raw sector access for the unikernel storage system.
//!
//! SAFETY: Synchronous driver. Blocks current fiber until QEMU completes
//! the request. Uses bounce-buffers to guarantee alignment.
const std = @import("std"); const std = @import("std");
const uart = @import("uart.zig"); const uart = @import("uart.zig");
const pci = @import("virtio_pci.zig"); const pci = @import("virtio_pci.zig");
// External C/Zig stubs
extern fn malloc(size: usize) ?*anyopaque; extern fn malloc(size: usize) ?*anyopaque;
var global_blk: ?VirtioBlkDriver = null; var global_blk: ?VirtioBlkDriver = null;
export fn virtio_blk_read(sector: u64, buf: [*]u8) void { export fn virtio_blk_read(sector: u64, buf: [*]u8) void {
if (global_blk) |*d| { if (global_blk) |*d| {
d.read_sync(sector, buf); d.read(sector, buf[0..512]) catch {
} else { uart.print("[VirtIO-Blk] READ ERROR\n");
uart.print("[VirtIO-Blk] Error: Driver not initialized.\n"); };
} }
} }
export fn virtio_blk_write(sector: u64, buf: [*]const u8) void { export fn virtio_blk_write(sector: u64, buf: [*]const u8) void {
if (global_blk) |*d| { if (global_blk) |*d| {
d.write_sync(sector, buf); d.write(sector, buf[0..512]) catch {
} else { uart.print("[VirtIO-Blk] WRITE ERROR\n");
uart.print("[VirtIO-Blk] Error: Driver not initialized.\n"); };
} }
} }
pub fn init() void { pub fn init() void {
if (VirtioBlkDriver.probe()) |*driver| { if (VirtioBlkDriver.probe()) |_| {
var d = driver.*; uart.print("[Rumpk L0] Storage initialized (The Ledger).\n");
if (d.init_device()) {
uart.print("[Rumpk L0] Storage initialized (The Ledger).\n");
}
} else { } else {
uart.print("[Rumpk L0] No Storage Device Found.\n"); uart.print("[Rumpk L0] No Storage Device Found.\n");
} }
} }
const VIRTIO_BLK_T_IN: u32 = 0;
const VIRTIO_BLK_T_OUT: u32 = 1;
const SECTOR_SIZE: usize = 512;
pub const VirtioBlkDriver = struct { pub const VirtioBlkDriver = struct {
transport: pci.VirtioTransport, transport: pci.VirtioTransport,
req_queue: ?*Virtqueue, v_desc: [*]volatile VirtioDesc,
last_used_idx: u16, v_avail: *volatile VirtioAvail,
v_used: *volatile VirtioUsed,
pub fn init(transport: pci.VirtioTransport) !VirtioBlkDriver { queue_size: u16,
var driver = VirtioBlkDriver{
.req_queue = null,
.transport = transport,
.last_used_idx = 0,
};
if (!driver.init_device()) {
return error.DeviceInitFailed;
}
return driver;
}
pub fn probe() ?VirtioBlkDriver { pub fn probe() ?VirtioBlkDriver {
uart.print("[VirtIO] Probing PCI for Block device...\n");
const PCI_ECAM_BASE: usize = 0x30000000; const PCI_ECAM_BASE: usize = 0x30000000;
// Scan a few slots. Usually 00:02.0 if 00:01.0 is Net.
// Or implement real PCI scan logic later.
const bus: u8 = 0; const bus: u8 = 0;
const func: u8 = 0; const func: u8 = 0;
@ -74,191 +64,145 @@ pub const VirtioBlkDriver = struct {
const ptr: *volatile u32 = @ptrFromInt(addr); const ptr: *volatile u32 = @ptrFromInt(addr);
const id = ptr.*; const id = ptr.*;
// Device ID 0x1001 (Legacy Block) or 0x1042 (Modern Block)
// 0x1042 = 0x1040 + 2
if (id == 0x10011af4 or id == 0x10421af4) { if (id == 0x10011af4 or id == 0x10421af4) {
uart.print("[VirtIO] Found VirtIO-Block device at PCI 00:0"); uart.print("[VirtIO] Found VirtIO-Block device at PCI 00:0");
uart.print_hex(i); uart.print_hex(i);
uart.print(".0\n"); uart.print(".0\n");
return VirtioBlkDriver.init(pci.VirtioTransport.init(addr)) catch null; var self = VirtioBlkDriver{
.transport = pci.VirtioTransport.init(addr),
.v_desc = undefined,
.v_avail = undefined,
.v_used = undefined,
.queue_size = 0,
};
if (self.init_device()) {
return self;
}
} }
} }
return null; return null;
} }
pub fn init_device(self: *VirtioBlkDriver) bool { pub fn init_device(self: *VirtioBlkDriver) bool {
// 0. Probe Transport (Legacy/Modern) if (!self.transport.probe()) return false;
if (!self.transport.probe()) {
uart.print("[VirtIO-Blk] Transport Probe Failed.\n"); self.transport.reset();
return false; self.transport.add_status(1);
self.transport.add_status(2);
self.transport.select_queue(0);
const count = self.transport.get_queue_size();
// [Desc] [Avail] [Used] (Simplified layout)
const total = (count * 16) + (6 + count * 2) + 4096 + (6 + count * 8);
const raw_ptr = malloc(total + 4096) orelse return false;
const aligned = (@intFromPtr(raw_ptr) + 4095) & ~@as(usize, 4095);
self.v_desc = @ptrFromInt(aligned);
self.v_avail = @ptrFromInt(aligned + (count * 16));
self.v_used = @ptrFromInt(aligned + (count * 16) + (6 + count * 2) + 4096);
self.queue_size = count;
if (self.transport.is_modern) {
self.transport.setup_modern_queue(aligned, aligned + (count * 16), @intFromPtr(self.v_used));
} else {
self.transport.setup_legacy_queue(@intCast(aligned >> 12));
} }
// 1. Reset
self.transport.reset();
// 2. ACK + DRIVER
self.transport.add_status(3);
// 3. Queue Setup (Queue 0 is Request Queue)
self.transport.select_queue(0);
const q_size = self.transport.get_queue_size();
if (q_size == 0) return false;
self.req_queue = self.setup_queue(0, q_size) catch return false;
// 4. Driver OK
self.transport.add_status(4); self.transport.add_status(4);
global_blk = self.*; global_blk = self.*;
uart.print("[VirtIO-Blk] Device Ready. Queue Size: "); uart.print("[VirtIO-Blk] Device Ready. Queue Size: ");
uart.print_hex(q_size); uart.print_hex(count);
uart.print(" HeaderSize: "); uart.print(" HeaderSize: ");
uart.print_hex(@sizeOf(VirtioBlkReq)); uart.print_hex(@sizeOf(VirtioBlkHeader));
uart.print("\n"); uart.print("\n");
return true; return true;
} }
pub fn read_sync(self: *VirtioBlkDriver, sector: u64, buf: [*]u8) void { pub fn read(self: *VirtioBlkDriver, sector: u64, buf: []u8) !void {
self.submit_request(VIRTIO_BLK_T_IN, sector, buf); const header = VirtioBlkHeader{
} .type = 0, // READ
.reserved = 0,
.sector = sector,
};
var status: u8 = 0xFF;
pub fn write_sync(self: *VirtioBlkDriver, sector: u64, buf: [*]const u8) void { // Simple synchronous request: Use descriptors 0, 1, 2
// Cast const away because submit_request buffer logic is generic, but T_OUT implies read from buf // Desc 0: Header (Read-only for device)
self.submit_request(VIRTIO_BLK_T_OUT, sector, @constCast(buf)); self.v_desc[0].addr = @intFromPtr(&header);
} self.v_desc[0].len = @sizeOf(VirtioBlkHeader);
self.v_desc[0].flags = 1; // NEXT
self.v_desc[0].next = 1;
// SOVEREIGN BOUNCE BUFFERS (Aligned to avoid offset bugs) // Desc 1: Data Buffer (Write-only for device)
var bounce_header: VirtioBlkReq align(16) = undefined; self.v_desc[1].addr = @intFromPtr(buf.ptr);
var bounce_sector: [512]u8 align(4096) = undefined; self.v_desc[1].len = 512;
var bounce_status: u8 align(16) = 0; self.v_desc[1].flags = 1 | 2; // NEXT | WRITE
self.v_desc[1].next = 2;
fn submit_request(self: *VirtioBlkDriver, type_: u32, sector: u64, buf: [*]u8) void { // Desc 2: Status Byte (Write-only for device)
const q = self.req_queue orelse return; self.v_desc[2].addr = @intFromPtr(&status);
const idx = q.avail.idx % q.num; self.v_desc[2].len = 1;
self.v_desc[2].flags = 2; // WRITE
self.v_desc[2].next = 0;
// Use fixed descriptors indices 0, 1, 2 // Submit to Avail Ring
const d1 = 0; const ring = @as([*]volatile u16, @ptrFromInt(@intFromPtr(self.v_avail) + 4));
const d2 = 1; ring[self.v_avail.idx % self.queue_size] = 0; // Head of chain
const d3 = 2; asm volatile ("fence w, w" ::: .{ .memory = true });
self.v_avail.idx +%= 1;
bounce_header.type = type_; asm volatile ("fence w, w" ::: .{ .memory = true });
bounce_header.reserved = 0;
bounce_header.sector = sector;
bounce_status = 0xFF;
const VRING_DESC_F_NEXT: u16 = 1;
const VRING_DESC_F_WRITE: u16 = 2;
if (type_ == VIRTIO_BLK_T_OUT) {
@memcpy(&bounce_sector, buf[0..512]);
}
q.desc[d1].addr = @intFromPtr(&bounce_header);
q.desc[d1].len = @sizeOf(VirtioBlkReq);
q.desc[d1].flags = VRING_DESC_F_NEXT;
q.desc[d1].next = d2;
q.desc[d2].addr = @intFromPtr(&bounce_sector);
q.desc[d2].len = 512;
if (type_ == VIRTIO_BLK_T_IN) {
// Device writes to this buffer
q.desc[d2].flags = VRING_DESC_F_NEXT | VRING_DESC_F_WRITE;
} else {
// Device reads from this buffer
q.desc[d2].flags = VRING_DESC_F_NEXT;
}
q.desc[d2].next = d3;
q.desc[d3].addr = @intFromPtr(&bounce_status);
q.desc[d3].len = 1;
q.desc[d3].flags = VRING_DESC_F_WRITE;
q.desc[d3].next = 0;
asm volatile ("fence" ::: .{ .memory = true });
const avail_ring = get_avail_ring(q.avail);
avail_ring[idx] = d1;
asm volatile ("fence" ::: .{ .memory = true });
q.avail.idx +%= 1;
asm volatile ("fence" ::: .{ .memory = true });
self.transport.notify(0); self.transport.notify(0);
// Polling Used Ring for Completion // Wait for device (Polling)
var timeout: usize = 10000000; while (self.v_used.idx == 0) {
const used_ptr = q.used; asm volatile ("nop");
while (used_ptr.idx == self.last_used_idx and timeout > 0) : (timeout -= 1) {
asm volatile ("fence" ::: .{ .memory = true });
} }
if (timeout == 0) { if (status != 0) return error.DiskError;
uart.print("[VirtIO-Blk] Timeout Waiting for Used Ring!\n");
} else {
// Request Done.
self.last_used_idx +%= 1;
asm volatile ("fence" ::: .{ .memory = true });
if (bounce_status != 0) {
uart.print("[VirtIO-Blk] I/O Error Status: ");
uart.print_hex(bounce_status);
uart.print("\n");
} else if (type_ == VIRTIO_BLK_T_IN) {
// Success Read: Copy bounce -> user
const dest_slice = buf[0..512];
@memcpy(dest_slice, &bounce_sector);
}
}
} }
fn setup_queue(self: *VirtioBlkDriver, index: u16, count: u16) !*Virtqueue { pub fn write(self: *VirtioBlkDriver, sector: u64, buf: []const u8) !void {
// ...(Similar to Net)... const header = VirtioBlkHeader{
// Allocate Memory .type = 1, // WRITE
const desc_size = 16 * @as(usize, count); .reserved = 0,
const avail_size = 6 + 2 * @as(usize, count); .sector = sector,
const used_offset = (desc_size + avail_size + 4095) & ~@as(usize, 4095); };
const used_size = 6 + 8 * @as(usize, count); var status: u8 = 0xFF;
const total_size = used_offset + used_size;
const raw_ptr = malloc(total_size + 4096) orelse return error.OutOfMemory; self.v_desc[3].addr = @intFromPtr(&header);
const aligned_addr = (@intFromPtr(raw_ptr) + 4095) & ~@as(usize, 4095); self.v_desc[3].len = @sizeOf(VirtioBlkHeader);
self.v_desc[3].flags = 1;
self.v_desc[3].next = 4;
const q_ptr_raw = malloc(@sizeOf(Virtqueue)) orelse return error.OutOfMemory; self.v_desc[4].addr = @intFromPtr(buf.ptr);
const q_ptr: *Virtqueue = @ptrCast(@alignCast(q_ptr_raw)); self.v_desc[4].len = 512;
self.v_desc[4].flags = 1; // Note: Write for disk is READ for device
self.v_desc[4].next = 5;
q_ptr.num = count; self.v_desc[5].addr = @intFromPtr(&status);
q_ptr.desc = @ptrFromInt(aligned_addr); self.v_desc[5].len = 1;
q_ptr.avail = @ptrFromInt(aligned_addr + desc_size); self.v_desc[5].flags = 2;
q_ptr.used = @ptrFromInt(aligned_addr + used_offset); self.v_desc[5].next = 0;
// Notify Device const ring = @as([*]volatile u16, @ptrFromInt(@intFromPtr(self.v_avail) + 4));
const phys_addr = aligned_addr; ring[self.v_avail.idx % self.queue_size] = 3;
self.transport.select_queue(index); asm volatile ("fence w, w" ::: .{ .memory = true });
if (self.transport.is_modern) { self.v_avail.idx +%= 1;
self.transport.setup_modern_queue(phys_addr, phys_addr + desc_size, phys_addr + used_offset); asm volatile ("fence w, w" ::: .{ .memory = true });
} else {
const pfn = @as(u32, @intCast(phys_addr >> 12)); self.transport.notify(0);
self.transport.setup_legacy_queue(pfn);
while (status == 0xFF) {
asm volatile ("nop");
} }
return q_ptr; if (status != 0) return error.DiskError;
} }
// structs ...
const VirtioBlkReq = packed struct {
type: u32,
reserved: u32,
sector: u64,
};
const Virtqueue = struct {
desc: [*]volatile VirtioDesc,
avail: *volatile VirtioAvail,
used: *volatile VirtioUsed,
num: u16,
};
const VirtioDesc = struct { const VirtioDesc = struct {
addr: u64, addr: u64,
len: u32, len: u32,
@ -276,7 +220,9 @@ pub const VirtioBlkDriver = struct {
idx: u16, idx: u16,
}; };
inline fn get_avail_ring(avail: *volatile VirtioAvail) [*]volatile u16 { const VirtioBlkHeader = extern struct {
return @ptrFromInt(@intFromPtr(avail) + 4); type: u32,
} reserved: u32,
sector: u64,
};
}; };

View File

@ -1,7 +1,17 @@
// MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI) // SPDX-License-Identifier: LCL-1.0
// Rumpk Layer 0: VirtIO-Net Driver (Sovereign Edition) // Copyright (c) 2026 Markus Maiwald
// - Uses VirtioTransport for PCI Capability Traversal // Stewardship: Self Sovereign Society Foundation
// - Supports both Legacy (I/O & Memory) and Modern VirtIO //
// This file is part of the Nexus Commonwealth.
// See legal/LICENSE_COMMONWEALTH.md for license terms.
//! Rumpk Layer 0: VirtIO-Net Driver (Sovereign Edition)
//!
//! Implements a zero-copy network interface using ION slabs for RX/TX.
//! Supports both Legacy and Modern VirtIO via the universal transport layer.
//!
//! SAFETY: Uses volatile pointers for hardware rings and memory barriers (fences)
//! to ensure correct synchronization with the virtual device.
const std = @import("std"); const std = @import("std");
const uart = @import("uart.zig"); const uart = @import("uart.zig");
@ -71,11 +81,8 @@ export fn virtio_net_send(data: [*]const u8, len: usize) void {
} }
pub fn init() void { pub fn init() void {
if (VirtioNetDriver.probe()) |*driver| { if (VirtioNetDriver.probe()) |_| {
var d = driver.*; uart.print("[Rumpk L0] Networking initialized (Sovereign).\n");
if (d.init_device()) {
uart.print("[Rumpk L0] Networking initialized (Sovereign).\n");
}
} }
} }
@ -98,16 +105,29 @@ pub const VirtioNetDriver = struct {
uart.print("[VirtIO] Probing PCI for networking device...\n"); uart.print("[VirtIO] Probing PCI for networking device...\n");
const PCI_ECAM_BASE: usize = 0x30000000; const PCI_ECAM_BASE: usize = 0x30000000;
const bus: u8 = 0; const bus: u8 = 0;
const dev: u8 = 1;
const func: u8 = 0; const func: u8 = 0;
const addr = PCI_ECAM_BASE | (@as(usize, bus) << 20) | (@as(usize, dev) << 15) | (@as(usize, func) << 12); var i: u8 = 1;
const ptr: *volatile u32 = @ptrFromInt(addr); while (i <= 8) : (i += 1) {
const id = ptr.*; const addr = PCI_ECAM_BASE | (@as(usize, bus) << 20) | (@as(usize, i) << 15) | (@as(usize, func) << 12);
const ptr: *volatile u32 = @ptrFromInt(addr);
const id = ptr.*;
if (id == 0x10001af4 or id == 0x10411af4) { uart.print("[VirtIO-Net] Probing dev ");
uart.print("[VirtIO] Found VirtIO-Net device at PCI 00:01.0\n"); uart.print_hex(i);
return VirtioNetDriver.init(addr, 33); uart.print(", ID: ");
uart.print_hex(id);
uart.print("\n");
if (id == 0x10001af4 or id == 0x10411af4) {
uart.print("[VirtIO] Found VirtIO-Net device at PCI 00:0");
uart.print_hex(i);
uart.print(".0\n");
var self = VirtioNetDriver.init(addr, 33);
if (self.init_device()) {
return self;
}
}
} }
return null; return null;

View File

@ -1,6 +1,17 @@
// core/rumpk/hal/virtio_pci.zig // SPDX-License-Identifier: LCL-1.0
// Sovereign VirtIO Transport Layer // Copyright (c) 2026 Markus Maiwald
// Handles PCI Capability Discovery and Universal Access // Stewardship: Self Sovereign Society Foundation
//
// This file is part of the Nexus Commonwealth.
// See legal/LICENSE_COMMONWEALTH.md for license terms.
//! Rumpk HAL: Sovereign VirtIO Transport Layer
//!
//! Handles PCI Capability Discovery and provides a universal interface
//! for accessing both Legacy and Modern VirtIO devices.
//!
//! SAFETY: All hardware registers are accessed via volatile pointers.
//! Dynamically assigns BARs (Base Address Registers) if unassigned by firmware.
const std = @import("std"); const std = @import("std");
const uart = @import("uart.zig"); const uart = @import("uart.zig");
@ -64,6 +75,14 @@ pub const VirtioTransport = struct {
const cap_id = @as(*volatile u8, @ptrFromInt(cap_addr)).*; const cap_id = @as(*volatile u8, @ptrFromInt(cap_addr)).*;
const cap_next = @as(*volatile u8, @ptrFromInt(cap_addr + 1)).*; const cap_next = @as(*volatile u8, @ptrFromInt(cap_addr + 1)).*;
uart.print("[VirtIO-PCI] Cap at ");
uart.print_hex(cap_offset);
uart.print(" ID: ");
uart.print_hex(cap_id);
uart.print(" Next: ");
uart.print_hex(cap_next);
uart.print("\n");
if (cap_id == 0x09) { // Vendor Specific (VirtIO) if (cap_id == 0x09) { // Vendor Specific (VirtIO)
const cap_type = @as(*volatile u8, @ptrFromInt(cap_addr + 3)).*; const cap_type = @as(*volatile u8, @ptrFromInt(cap_addr + 3)).*;
const bar_idx = @as(*volatile u8, @ptrFromInt(cap_addr + 4)).*; const bar_idx = @as(*volatile u8, @ptrFromInt(cap_addr + 4)).*;
@ -71,20 +90,24 @@ pub const VirtioTransport = struct {
// Resolve BAR Address // Resolve BAR Address
const bar_ptr = @as(*volatile u32, @ptrFromInt(self.base_addr + 0x10 + (@as(usize, bar_idx) * 4))); const bar_ptr = @as(*volatile u32, @ptrFromInt(self.base_addr + 0x10 + (@as(usize, bar_idx) * 4)));
const bar_val = bar_ptr.*;
// Check if BAR is assigned // Check if BAR is assigned and is a Memory BAR (bit 0 == 0)
if ((bar_ptr.* & 0xFFFFFFF0) == 0) { if ((bar_val & 0x1) == 0 and (bar_val & 0xFFFFFFF0) == 0) {
uart.print("[VirtIO-PCI] Initializing Unassigned BAR "); uart.print("[VirtIO-PCI] Initializing Unassigned Memory BAR ");
uart.print_hex(@as(u64, bar_idx)); uart.print_hex(@as(u64, bar_idx));
uart.print(" at "); uart.print(" at ");
uart.print_hex(next_mmio_addr); uart.print_hex(next_mmio_addr);
uart.print("\n"); uart.print("\n");
bar_ptr.* = next_mmio_addr; bar_ptr.* = next_mmio_addr;
const rb = bar_ptr.*;
uart.print("[VirtIO-PCI] BAR Assigned. Readback: ");
uart.print_hex(rb);
uart.print("\n");
next_mmio_addr += 0x10000; // Increment 64KB next_mmio_addr += 0x10000; // Increment 64KB
} }
// Basic BAR resolution (Memory only for Modern) // Refresh BAR resolution (Memory only for Modern)
// We assume Modern BARs are Memory Mapped
const bar_base = bar_ptr.* & 0xFFFFFFF0; const bar_base = bar_ptr.* & 0xFFFFFFF0;
if (cap_type == VIRTIO_PCI_CAP_COMMON_CFG) { if (cap_type == VIRTIO_PCI_CAP_COMMON_CFG) {
@ -98,9 +121,11 @@ pub const VirtioTransport = struct {
self.notify_off_multiplier = @as(*volatile u32, @ptrFromInt(cap_addr + 16)).*; self.notify_off_multiplier = @as(*volatile u32, @ptrFromInt(cap_addr + 16)).*;
} }
if (cap_type == VIRTIO_PCI_CAP_ISR_CFG) { if (cap_type == VIRTIO_PCI_CAP_ISR_CFG) {
uart.print("[VirtIO-PCI] Found Modern ISR Config\n");
self.isr_cfg = @ptrFromInt(bar_base + offset); self.isr_cfg = @ptrFromInt(bar_base + offset);
} }
} }
uart.print("[VirtIO-PCI] Next Cap...\n");
cap_offset = cap_next; cap_offset = cap_next;
} }
} }

View File

@ -1,3 +1,10 @@
# SPDX-License-Identifier: LUL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus SDK.
# See legal/LICENSE_UNBOUND.md for license terms.
# Rumpk Adaptive I/O Governor # Rumpk Adaptive I/O Governor
# War Mode (polling) ↔ Peace Mode (interrupts) # War Mode (polling) ↔ Peace Mode (interrupts)

View File

@ -1,3 +1,12 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## Nexus Membrane: Block I/O Client
# Membrane Block API (The Block Valve - Userland Side) # Membrane Block API (The Block Valve - Userland Side)
# Phase 37.2: Sovereign Storage Architecture # Phase 37.2: Sovereign Storage Architecture
# #

View File

@ -159,6 +159,66 @@ void *memmove(void *dest, const void *src, size_t n) {
return dest; return dest;
} }
char *strchr(const char *s, int c) {
while (*s != (char)c) {
if (!*s++) return NULL;
}
return (char *)s;
}
char *strcpy(char *dest, const char *src) {
char *d = dest;
while ((*d++ = *src++));
return dest;
}
int strcmp(const char *s1, const char *s2) {
while(*s1 && (*s1 == *s2)) {
s1++; s2++;
}
return *(const unsigned char*)s1 - *(const unsigned char*)s2;
}
size_t strspn(const char *s, const char *accept) {
const char *p = s;
const char *a;
while (*p) {
for (a = accept; *a; a++) {
if (*p == *a) break;
}
if (*a == '\0') return p - s;
p++;
}
return p - s;
}
size_t strcspn(const char *s, const char *reject) {
const char *p = s;
const char *r;
while (*p) {
for (r = reject; *r; r++) {
if (*p == *r) return p - s;
}
p++;
}
return p - s;
}
uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) {
static const uint32_t rtable[16] = {
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c,
};
const uint8_t *data = (const uint8_t *)buffer;
for (size_t i = 0; i < size; i++) {
crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 0)) & 0xf];
crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 4)) & 0xf];
}
return crc;
}
void console_write(const void* p, size_t len) { void console_write(const void* p, size_t len) {
// Phase 7: Direct UART access for Proof of Life // Phase 7: Direct UART access for Proof of Life
volatile char *uart = (volatile char *)0x10000000; volatile char *uart = (volatile char *)0x10000000;
@ -170,3 +230,5 @@ void console_write(const void* p, size_t len) {
} }
void ion_egress_to_port(uint16_t port, void* pkt); void ion_egress_to_port(uint16_t port, void* pkt);

View File

@ -1,3 +1,12 @@
# SPDX-License-Identifier: LSL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.
## Nexus Membrane: Userland Graphics Compositor
# libs/membrane/compositor.nim # libs/membrane/compositor.nim
# Phase 35b/d: The Sovereign Compositor + Input Router # Phase 35b/d: The Sovereign Compositor + Input Router

119
libs/membrane/external/lwip/BUILDING vendored Normal file
View File

@ -0,0 +1,119 @@
Building lwIP
=============
lwIP uses a CMake based build system.
The CMake files in this project are designed to
be included into your own CMake files. They are
mainly variable definitions containing a list of
source files and predefined static libraries to
be linked against application code.
1) lwIP sources:
src/Filelists.cmake provides file lists containing
the lwIP core library.
The file also contains two static libraries, lwipcore
and lwipallapps, where you can link your app against.
This is the file that is useful to all lwIP users.
2) Example applications:
contrib/Filelists.cmake provides several file lists
containing the example applications.
The file also contains several static libraries
for these example apps.
This file is only useful for you, if you can use one
of the examples in your application, which is normally
not the case.
3) OS/platform port:
Usually the OS port needs to be provided by the user.
If a port to Linux, Windows or MacOS is useful for
you, you can use
contrib/ports/{win32, unix}/Filelists.cmake
that contains file lists and libraries for
these operating systems.
VARIABLES
=========
In all cases, you need to provide two variables.
"LWIP_DIR" pointing to the lwIP directory
Example:
set(LWIP_DIR ${CMAKE_CURRENT_SOURCE_DIR}/externals/lwip)
"LWIP_INCLUDE_DIRS" that contains the include base paths
- for lwIP itself (${LWIP_DIR}/src/include)
- for lwIP contrib if you use it (${LWIP_DIR}/contrib)
- to a directory containing an OS port
- to a directory containing lwipopts.h
Example:
set (LWIP_INCLUDE_DIRS
"${LWIP_DIR}/src/include"
"${LWIP_DIR}/contrib"
"${LWIP_DIR}/contrib/ports/unix/port/include"
"${LWIP_DIR}/contrib/examples/example_app"
)
Putting it all together
=======================
To get a working application, your CMake system
needs to provide the variables described above, e.g.
set (LWIP_DIR <path to lwip sources>)
set (LWIP_INCLUDE_DIRS
"${LWIP_DIR}/src/include"
"${LWIP_DIR}/contrib"
"<path to my port>/include"
"<path to lwipopts.h>"
)
You may add some defines:
set (LWIP_DEFINITIONS LWIP_DEBUG=1)
Then include the filelists you need:
include(${LWIP_DIR}/src/Filelists.cmake)
include(${LWIP_DIR}/contrib/Filelists.cmake)
Then, declare you executable:
add_executable(my_app <my source files> <my lwip port files>)
Add lwIP include dirs to your app:
target_include_directories(my_app PRIVATE ${LWIP_INCLUDE_DIRS})
Link your app against the lwIP libs from the filelists you need:
target_link_libraries(my_app lwipcontribapps lwipallapps lwipcore)
Working example
===============
Working build examples can be found in the
contrib/ports/{win32, unix}/example_app
subdirectory.
To use them, create a build directory and call cmake with
the lwIP root dir:
- mkdir build
- cd build
- cmake ..
- cmake --build .
The CMakeLists.txt will autoselect the correct port
for your system (supported: Linux, Windows, Darwin).
To configure the example app to your needs, you need to copy the file
contrib/examples/example_app/lwipcfg.h.example
to
contrib/examples/example_app/lwipcfg.h
and edit to your needs.
Makefile based build system
===========================
lwIP also maintains file lists for Makefile-based
build systems. Look for Filelists.mk files
in the source tree. We try to maintain them,
but lwIP's mainly focused build system is CMake.
MS Visual Studio
================
lwIP also provides basic support for MSVS in the win32 port
folder under 'msvc'. We try to maintain these files,
but lwIP's mainly focused build system is CMake.

4635
libs/membrane/external/lwip/CHANGELOG vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,35 @@
cmake_minimum_required(VERSION 3.10)
set (CMAKE_CONFIGURATION_TYPES "Debug;Release")
project(lwIP)
# Example lwIP application
set(LWIP_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set (LWIP_DEFINITIONS LWIP_DEBUG=1)
if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
add_subdirectory(${LWIP_DIR}/contrib/ports/win32/example_app)
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
add_subdirectory(${LWIP_DIR}/contrib/ports/unix/example_app)
else()
message(WARNING "Host ${CMAKE_SYSTEM_NAME} is not supported to build example_app")
endif()
# Source package generation
set(CPACK_SOURCE_GENERATOR "ZIP")
set(CPACK_SOURCE_PACKAGE_DESCRIPTION_SUMMARY "lwIP lightweight IP stack")
set(CPACK_PACKAGE_VERSION_MAJOR "${LWIP_VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${LWIP_VERSION_MINOR}")
set(CPACK_PACKAGE_VERSION_PATCH "${LWIP_VERSION_REVISION}")
set(CPACK_SOURCE_IGNORE_FILES "/build/;${CPACK_SOURCE_IGNORE_FILES};.git")
set(CPACK_SOURCE_PACKAGE_FILE_NAME "lwip-${LWIP_VERSION_MAJOR}.${LWIP_VERSION_MINOR}.${LWIP_VERSION_REVISION}")
include(CPack)
# Generate docs before creating source package
include(src/Filelists.cmake)
add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source)
if (TARGET lwipdocs)
add_dependencies(dist lwipdocs)
endif()

25
libs/membrane/external/lwip/COPYING vendored Normal file
View File

@ -0,0 +1,25 @@
Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.

11
libs/membrane/external/lwip/FEATURES vendored Normal file
View File

@ -0,0 +1,11 @@
lwIP is a small independent implementation of the TCP/IP protocol suite targeted at embedded systems.
The focus of the lwIP TCP/IP implementation is to reduce resource usage while still having a full scale TCP. This makes lwIP suitable for use in embedded systems with tens of kilobytes of free RAM and room for around 40 kilobytes of code ROM.
Main features include:
- Protocols: IP, IPv6, ICMP, ND, MLD, UDP, TCP, IGMP, ARP, PPPoS, PPPoE, 6LowPAN (via IEEE 802.15.4, BLE or ZEP; since v2.1.0)
- DHCP client, stateless DHCPv6 (since v2.1.0), DNS client (incl. mDNS hostname resolver), AutoIP/APIPA (Zeroconf), ACD (Address Conflict Detection), SNMP agent (v1, v2c, v3 (since v2.1.0), private MIB support & MIB compiler)
- APIs: specialized APIs for enhanced performance & zero copy, optional Berkeley-alike socket API
- Extended features: IP forwarding over multiple network interfaces
- Extended TCP features: congestion control, RTT estimation and fast recovery/fast retransmit, sending SACKs (since v2.1.0), "altcp": nearly transparent TLS for any tcp pcb (since v2.1.0)
- Addon applications: HTTP server (HTTPS via altcp), HTTP(S) client (since v2.1.0), SNTP client, SMTP client (SMTPS via altcp), ping, NetBIOS nameserver, mDNS responder, MQTT client (TLS support since v2.1.0), TFTP server, iPerf2 counterpart

6
libs/membrane/external/lwip/FILES vendored Normal file
View File

@ -0,0 +1,6 @@
contrib/ - lwIP examples, ports, and small apps (formerly http://git.savannah.gnu.org/cgit/lwip/lwip-contrib.git/)
src/ - The source code for the lwIP TCP/IP stack.
doc/ - The documentation for lwIP.
test/ - Some code to test whether the sources do what they should.
See also the FILES file in each subdirectory.

109
libs/membrane/external/lwip/README vendored Normal file
View File

@ -0,0 +1,109 @@
INTRODUCTION
lwIP is a small independent implementation of the TCP/IP protocol suite.
The focus of the lwIP TCP/IP implementation is to reduce the RAM usage
while still having a full scale TCP. This making lwIP suitable for use
in embedded systems with tens of kilobytes of free RAM and room for
around 40 kilobytes of code ROM.
lwIP was originally developed by Adam Dunkels at the Computer and Networks
Architectures (CNA) lab at the Swedish Institute of Computer Science (SICS)
and is now developed and maintained by a worldwide network of developers.
FEATURES
* IP (Internet Protocol, IPv4 and IPv6) including packet forwarding over
multiple network interfaces
* ICMP (Internet Control Message Protocol) for network maintenance and debugging
* IGMP (Internet Group Management Protocol) for multicast traffic management
* MLD (Multicast listener discovery for IPv6). Aims to be compliant with
RFC 2710. No support for MLDv2
* ND (Neighbor discovery and stateless address autoconfiguration for IPv6).
Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862
(Address autoconfiguration)
* DHCP, AutoIP/APIPA (Zeroconf), ACD (Address Conflict Detection)
and (stateless) DHCPv6
* UDP (User Datagram Protocol) including experimental UDP-lite extensions
* TCP (Transmission Control Protocol) with congestion control, RTT estimation
fast recovery/fast retransmit and sending SACKs
* raw/native API for enhanced performance
* Optional Berkeley-like socket API
* TLS: optional layered TCP ("altcp") for nearly transparent TLS for any
TCP-based protocol (ported to mbedTLS) (see changelog for more info)
* PPPoS and PPPoE (Point-to-point protocol over Serial/Ethernet)
* DNS (Domain name resolver incl. mDNS)
* 6LoWPAN (via IEEE 802.15.4, BLE or ZEP)
APPLICATIONS
* HTTP server with SSI and CGI (HTTPS via altcp)
* SNMPv2c agent with MIB compiler (Simple Network Management Protocol), v3 via altcp
* SNTP (Simple network time protocol)
* NetBIOS name service responder
* MDNS (Multicast DNS) responder
* iPerf server implementation
* MQTT client (TLS support via altcp)
LICENSE
lwIP is freely available under a BSD license.
DEVELOPMENT
lwIP has grown into an excellent TCP/IP stack for embedded devices,
and developers using the stack often submit bug fixes, improvements,
and additions to the stack to further increase its usefulness.
Development of lwIP is hosted on Savannah, a central point for
software development, maintenance and distribution. Everyone can
help improve lwIP by use of Savannah's interface, Git and the
mailing list. A core team of developers will commit changes to the
Git source tree.
The lwIP TCP/IP stack is maintained in the 'src' directory and
contributions (such as platform ports and applications) are in
the 'contrib' directory.
See doc/savannah.txt for details on Git server access for users and
developers.
The current Git tree is web-browsable:
https://git.savannah.gnu.org/cgit/lwip.git
Submit patches and bugs via the lwIP project page:
https://savannah.nongnu.org/projects/lwip/
Continuous integration builds (GCC, clang):
https://github.com/lwip-tcpip/lwip/actions
DOCUMENTATION
Self documentation of the source code is regularly extracted from the current
Git sources and is available from this web page:
https://www.nongnu.org/lwip/
Also, there are mailing lists you can subscribe at
https://savannah.nongnu.org/mail/?group=lwip
plus searchable archives:
https://lists.nongnu.org/archive/html/lwip-users/
https://lists.nongnu.org/archive/html/lwip-devel/
There is a wiki about lwIP at
https://lwip.wikia.com/wiki/LwIP_Wiki
You might get questions answered there, but unfortunately, it is not as
well maintained as it should be.
lwIP was originally written by Adam Dunkels:
http://dunkels.com/adam/
Reading Adam's papers, the files in docs/, browsing the source code
documentation and browsing the mailing list archives is a good way to
become familiar with the design of lwIP.
Adam Dunkels <adam@sics.se>
Leon Woestenberg <leon.woestenberg@gmx.net>

288
libs/membrane/external/lwip/UPGRADING vendored Normal file
View File

@ -0,0 +1,288 @@
This file lists major changes between release versions that require
ports or applications to be changed. Use it to update a port or an
application written for an older version of lwIP to correctly work
with newer versions.
(git master)
* [Enter new changes just after this line - do not remove this line]
* The eth_addr_cmp and ip_addr_cmp set of functions have been renamed to eth_addr_eq, ip_addr_eq
and so on, since they return non-zero on equality. Macros for the old names exist.
* The sio_write function used by PPP now takes the data argument as const.
(2.2.0)
++ Repository changes:
* The contrib repository has been added into the main repository in the subdirectory 'contrib'
(the old contrib repository remains online for reference but is not used any more)
(2.1.0)
++ Application changes:
* Use the new altcp API for seamless TLS integration into existing TCP applications (see changelog)
* TCP only kills existing connections with a LOWER priority than the one currently being opened.
Previous implementations also kill existing connections of the SAME priority.
* ip4_route_src: parameter order is reversed: ip4_route_src(dest, src) -> ip4_route_src(src, dest)
to make parameter order consistent with other ip*_route*() functions.
Same also applies to LWIP_HOOK_IP4_ROUTE_SRC() parameter order.
* pbuf API: pbuf->type (an u8_t holding the enum 'pbuf_type') has changed to only hold a
description of the pbuf (e.g. data following pbuf struct, data volatile, allocation
source heap/pool/etc.). As a consequence, applications can't test pbuf->type any more.
Use pbuf_match_type(pbuf, type) instead.
* socket API: according to the standard, SO_ERROR now only returns asynchronous errors.
All other/normal/synchronous errors are (and always were) available via 'errno'.
LWIP_SOCKET_SET_ERRNO has been removed - 'errno' is always set - and required!
* httpd LWIP_HTTPD_CGI_SSI: httpd_cgi_handler() has an additional parameter "struct fs_file *"
++ Port changes:
* tcpip_trycallback() was renamed to tcpip_callbackmsg_trycallback() to avoid confusion
with tcpip_try_callback()
* compatibility headers: moved from 'src/include/posix' to 'src/include/compat/posix',
'src/include/compat/stdc' etc.
* The IPv6 implementation now supports address scopes. (See LWIP_IPV6_SCOPES documentation
and ip6_zone.h for more documentation)
* LWIP_HOOK_DHCP_APPEND_OPTIONS() has changed, see description in opt.h (options_out_len is not
available in struct dhcp any more)
* Added debug helper asserts to ensure threading/locking requirements are met (define
LWIP_MARK_TCPIP_THREAD() and LWIP_ASSERT_CORE_LOCKED()).
* Added sys_mbox_trypost_fromisr() and tcpip_callbackmsg_trycallback_fromisr()
These can be used to post preallocated messages from an ISR to the tcpip thread
(e.g. when using FreeRTOS)
(2.0.2)
++ Application changes:
* slipif: The way to pass serial port number has changed. netif->num is not
supported any more, netif->state is interpreted as an u8_t port number now
(it's not a POINTER to an u8_t any more!)
(2.0.1)
++ Application changes:
* UDP does NOT receive multicast traffic from ALL netifs on an UDP PCB bound to a specific
netif any more. Users need to bind to IP_ADDR_ANY to receive multicast traffic and compare
ip_current_netif() to the desired netif for every packet.
See bug #49662 for an explanation.
(2.0.0)
++ Application changes:
* Changed netif "up" flag handling to be an administrative flag (as opposed to the previous meaning of
"ip4-address-valid", a netif will now not be used for transmission if not up) -> even a DHCP netif
has to be set "up" before starting the DHCP client
* Added IPv6 support (dual-stack or IPv4/IPv6 only)
* Changed ip_addr_t to be a union in dual-stack mode (use ip4_addr_t where referring to IPv4 only).
* Major rewrite of SNMP (added MIB parser that creates code stubs for custom MIBs);
supports SNMPv2c (experimental v3 support)
* Moved some core applications from contrib repository to src/apps (and include/lwip/apps)
+++ Raw API:
* Changed TCP listen backlog: removed tcp_accepted(), added the function pair tcp_backlog_delayed()/
tcp_backlog_accepted() to explicitly delay backlog handling on a connection pcb
+++ Socket API:
* Added an implementation for posix sendmsg()
* Added LWIP_FIONREAD_LINUXMODE that makes ioctl/FIONREAD return the size of the next pending datagram
++ Port changes
+++ new files:
* MANY new and moved files!
* Added src/Filelists.mk for use in Makefile projects
* Continued moving stack-internal parts from abc.h to abc_priv.h in sub-folder "priv"
to let abc.h only contain the actual application programmer's API
+++ sys layer:
* Made LWIP_TCPIP_CORE_LOCKING==1 the default as it usually performs better than
the traditional message passing (although with LWIP_COMPAT_MUTEX you are still
open to priority inversion, so this is not recommended any more)
* Added LWIP_NETCONN_SEM_PER_THREAD to use one "op_completed" semaphore per thread
instead of using one per netconn (these semaphores are used even with core locking
enabled as some longer lasting functions like big writes still need to delay)
* Added generalized abstraction for itoa(), strnicmp(), stricmp() and strnstr()
in def.h (to be overridden in cc.h) instead of config
options for netbiosns, httpd, dns, etc. ...
* New abstraction for hton* and ntoh* functions in def.h.
To override them, use the following in cc.h:
#define lwip_htons(x) <your_htons>
#define lwip_htonl(x) <your_htonl>
+++ new options:
* TODO
+++ new pools:
* Added LWIP_MEMPOOL_* (declare/init/alloc/free) to declare private memp pools
that share memp.c code but do not have to be made global via lwippools.h
* Added pools for IPv6, MPU_COMPATIBLE, dns-api, netif-api, etc.
* added hook LWIP_HOOK_MEMP_AVAILABLE() to get informed when a memp pool was empty and an item
is now available
* Signature of LWIP_HOOK_VLAN_SET macro was changed
* LWIP_DECLARE_MEMORY_ALIGNED() may be used to declare aligned memory buffers (mem/memp)
or to move buffers to dedicated memory using compiler attributes
* Standard C headers are used to define sized types and printf formatters
(disable by setting LWIP_NO_STDINT_H=1 or LWIP_NO_INTTYPES_H=1 if your compiler
does not support these)
++ Major bugfixes/improvements
* Added IPv6 support (dual-stack or IPv4/IPv6 only)
* Major rewrite of PPP (incl. keep-up with apache pppd)
see doc/ppp.txt for an upgrading how-to
* Major rewrite of SNMP (incl. MIB parser)
* Fixed timing issues that might have lead to losing a DHCP lease
* Made rx processing path more robust against crafted errors
* TCP window scaling support
* modification of api modules to support FreeRTOS-MPU (don't pass stack-pointers to other threads)
* made DNS client more robust
* support PBUF_REF for RX packets
* LWIP_NETCONN_FULLDUPLEX allows netconn/sockets to be used for reading/writing from separate
threads each (needs LWIP_NETCONN_SEM_PER_THREAD)
* Moved and reordered stats (mainly memp/mib2)
(1.4.0)
++ Application changes:
* Replaced struct ip_addr by typedef ip_addr_t (struct ip_addr is kept for
compatibility to old applications, but will be removed in the future).
* Renamed mem_realloc() to mem_trim() to prevent confusion with realloc()
+++ Raw API:
* Changed the semantics of tcp_close() (since it was rather a
shutdown before): Now the application does *NOT* get any calls to the recv
callback (aside from NULL/closed) after calling tcp_close()
* When calling tcp_abort() from a raw API TCP callback function,
make sure you return ERR_ABRT to prevent accessing unallocated memory.
(ERR_ABRT now means the applicaiton has called tcp_abort!)
+++ Netconn API:
* Changed netconn_receive() and netconn_accept() to return
err_t, not a pointer to new data/netconn.
+++ Socket API:
* LWIP_SO_RCVTIMEO: when accept() or recv() time out, they
now set errno to EWOULDBLOCK/EAGAIN, not ETIMEDOUT.
* Added a minimal version of posix fctl() to have a
standardised way to set O_NONBLOCK for nonblocking sockets.
+++ all APIs:
* correctly implemented SO(F)_REUSEADDR
++ Port changes
+++ new files:
* Added 4 new files: def.c, timers.c, timers.h, tcp_impl.h:
* Moved stack-internal parts of tcp.h to tcp_impl.h, tcp.h now only contains
the actual application programmer's API
* Separated timer implementation from sys.h/.c, moved to timers.h/.c;
Added timer implementation for NO_SYS==1, set NO_SYS_NO_TIMERS==1 if you
still want to use your own timer implementation for NO_SYS==0 (as before).
+++ sys layer:
* Converted mbox- and semaphore-functions to take pointers to sys_mbox_t/
sys_sem_t;
* Converted sys_mbox_new/sys_sem_new to take pointers and return err_t;
* Added Mutex concept in sys_arch (define LWIP_COMPAT_MUTEX to let sys.h use
binary semaphores instead of mutexes - as before)
+++ new options:
* Don't waste memory when chaining segments, added option TCP_OVERSIZE to
prevent creating many small pbufs when calling tcp_write with many small
blocks of data. Instead, pbufs are allocated larger than needed and the
space is used for later calls to tcp_write.
* Added LWIP_NETIF_TX_SINGLE_PBUF to always copy to try to create single pbufs
in tcp_write/udp_send.
* Added an additional option LWIP_ETHERNET to support ethernet without ARP
(necessary for pure PPPoE)
* Add MEMP_SEPARATE_POOLS to place memory pools in separate arrays. This may
be used to place these pools into user-defined memory by using external
declaration.
* Added TCP_SNDQUEUELOWAT corresponding to TCP_SNDLOWAT
+++ new pools:
* Netdb uses a memp pool for allocating memory when getaddrinfo() is called,
so MEMP_NUM_NETDB has to be set accordingly.
* DNS_LOCAL_HOSTLIST_IS_DYNAMIC uses a memp pool instead of the heap, so
MEMP_NUM_LOCALHOSTLIST has to be set accordingly.
* Snmp-agent uses a memp pools instead of the heap, so MEMP_NUM_SNMP_* have
to be set accordingly.
* PPPoE uses a MEMP pool instead of the heap, so MEMP_NUM_PPPOE_INTERFACES
has to be set accordingly
* Integrated loopif into netif.c - loopif does not have to be created by the
port any more, just define LWIP_HAVE_LOOPIF to 1.
* Added define LWIP_RAND() for lwip-wide randomization (needs to be defined
in cc.h, e.g. used by igmp)
* Added printf-formatter X8_F to printf u8_t as hex
* The heap now may be moved to user-defined memory by defining
LWIP_RAM_HEAP_POINTER as a void pointer to that memory's address
* added autoip_set_struct() and dhcp_set_struct() to let autoip and dhcp work
with user-allocated structs instead of calling mem_malloc
* Added const char* name to mem- and memp-stats for easier debugging.
* Calculate the TCP/UDP checksum while copying to only fetch data once:
Define LWIP_CHKSUM_COPY to a memcpy-like function that returns the checksum
* Added SO_REUSE_RXTOALL to pass received UDP broadcast/multicast packets to
more than one pcb.
* Changed the semantics of ARP_QUEUEING==0: ARP_QUEUEING now cannot be turned
off any more, if this is set to 0, only one packet (the most recent one) is
queued (like demanded by RFC 1122).
++ Major bugfixes/improvements
* Implemented tcp_shutdown() to only shut down one end of a connection
* Implemented shutdown() at socket- and netconn-level
* Added errorset support to select() + improved select speed overhead
* Merged pppd to v2.3.11 (including some backported bugfixes from 2.4.x)
* Added timer implementation for NO_SYS==1 (may be disabled with NO_SYS_NO_TIMERS==1
* Use macros defined in ip_addr.h to work with IP addresses
* Implemented many nonblocking socket/netconn functions
* Fixed ARP input processing: only add a new entry if a request was directed as us
* mem_realloc() to mem_trim() to prevent confusion with realloc()
* Some improvements for AutoIP (don't route/forward link-local addresses, don't break
existing connections when assigning a routable address)
* Correctly handle remote side overrunning our rcv_wnd in ooseq case
* Removed packing from ip_addr_t, the packed version is now only used in protocol headers
* Corrected PBUF_POOL_BUFSIZE for ports where ETH_PAD_SIZE > 0
* Added support for static ARP table entries
(STABLE-1.3.2)
* initial version of this file

View File

@ -0,0 +1,26 @@
# Copyright 2017 Kaspar Schleiser <kaspar@schleiser.de>
# Copyright 2014 Ludwig Knüpfer <ludwig.knuepfer@fu-berlin.de>
# Copyright 2014 Hinnerk van Bruinehsen <h.v.bruinehsen@fu-berlin.de>
# Copyright 2020 Jonathan Demeyer <jona.dem@gmail.com>
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
changed_files() {
: ${FILEREGEX:='\.([CcHh])$'}
: ${EXCLUDE:=''}
: ${DIFFFILTER:='ACMR'}
DIFFFILTER="--diff-filter=${DIFFFILTER}"
# select either all or only touched-in-branch files, filter through FILEREGEX
if [ -z "${BASE_BRANCH}" ]; then
FILES="$(git ls-tree -r --full-tree --name-only HEAD | grep -E ${FILEREGEX})"
else
FILES="$(git diff ${DIFFFILTER} --name-only ${BASE_BRANCH} | grep -E ${FILEREGEX})"
fi
# filter out negatives
echo "${FILES}" | grep -v -E ${EXCLUDE}
}

View File

@ -0,0 +1,57 @@
#!/usr/bin/env bash
# Copyright 2019 Alexandre Abadie <alexandre.abadie@inria.fr>
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
CODESPELL_CMD="codespell"
if tput colors &> /dev/null && [ "$(tput colors)" -ge 8 ]; then
CERROR=$'\033[1;31m'
CRESET=$'\033[0m'
else
CERROR=
CRESET=
fi
: "${LWIPBASE:=$(cd $(dirname $0)/; pwd)}"
cd $LWIPBASE
: "${LWIPTOOLS:=${LWIPBASE}}"
. "${LWIPTOOLS}"/codespell_changed_files.sh
FILEREGEX='\.([CcHh]|sh|py|md|txt)$'
EXCLUDE='^(./contrib/apps/LwipMibCompiler/Mibs)'
FILES=$(FILEREGEX=${FILEREGEX} EXCLUDE=${EXCLUDE} changed_files)
if [ -z "${FILES}" ]; then
exit 0
fi
${CODESPELL_CMD} --version &> /dev/null || {
printf "%s%s: cannot execute \"%s\"!%s\n" "${CERROR}" "$0" "${CODESPELL_CMD}" "${CRESET}"
exit 1
}
CODESPELL_OPTS="-q 2" # Disable "WARNING: Binary file"
CODESPELL_OPTS+=" --check-hidden"
# Disable false positives "nd => and, 2nd", "ans => and", "tolen => token",
# "ofo => of", "WAN => WANT", "mut => must, mutt, moot"
CODESPELL_OPTS+=" --ignore-words-list=nd,ans,tolen,ofo,wan,mut "
# propagate all options to codespell -> pass "-w" to this script to write changes
CODESPELL_OPTS+="$@"
# Filter-out all false positive raising "disabled due to" messages.
ERRORS=$(${CODESPELL_CMD} ${CODESPELL_OPTS} ${FILES} | grep -ve "disabled due to")
if [ -n "${ERRORS}" ]
then
printf "%sThere are typos in the following files:%s\n\n" "${CERROR}" "${CRESET}"
printf "%s\n" "${ERRORS}"
# TODO: return 1 when all typos are fixed
exit 0
else
exit 0
fi

View File

@ -0,0 +1,106 @@
typedef unsigned char err_t;
typedef unsigned int u32_t;
typedef unsigned short u16_t;
typedef unsigned char u8_t;
typedef void sys_sem_t;
typedef void sys_mutex_t;
typedef size_t mem_size_t;
typedef size_t memp_t;
struct pbuf;
struct netif;
void* mem_malloc(mem_size_t size)
{
__coverity_alloc__(size);
}
void mem_free(void* mem)
{
__coverity_free__(mem);
}
void* memp_malloc(memp_t type)
{
__coverity_alloc_nosize__();
}
void memp_free(memp_t type, void* mem)
{
__coverity_free__(mem);
}
void sys_mutex_lock(sys_mutex_t* mutex)
{
__coverity_exclusive_lock_acquire__(mutex);
}
void sys_mutex_unlock(sys_mutex_t* mutex)
{
__coverity_exclusive_lock_release__(mutex);
}
u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
{
__coverity_recursive_lock_acquire__(sem);
}
void sys_sem_signal(sys_sem_t *sem)
{
__coverity_recursive_lock_release__(sem);
}
err_t ethernet_input(struct pbuf *p, struct netif *inp)
{
__coverity_tainted_string_sink_content__(p);
}
err_t tcpip_input(struct pbuf *p, struct netif *inp)
{
__coverity_tainted_string_sink_content__(p);
}
err_t ip_input(struct pbuf *p, struct netif *inp)
{
__coverity_tainted_string_sink_content__(p);
}
err_t ip4_input(struct pbuf *p, struct netif *inp)
{
__coverity_tainted_string_sink_content__(p);
}
err_t ip6_input(struct pbuf *p, struct netif *inp)
{
__coverity_tainted_string_sink_content__(p);
}
err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)
{
__coverity_tainted_string_argument__(buf);
__coverity_tainted_data_argument__(buf);
}
err_t pbuf_take_at(struct pbuf *buf, const void *dataptr, u16_t len, u16_t offset)
{
__coverity_tainted_string_argument__(buf);
__coverity_tainted_data_argument__(buf);
}
err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
{
__coverity_tainted_data_transitive__(p_to, p_from);
}
u16_t pbuf_copy_partial(struct pbuf *p, void *dataptr, u16_t len, u16_t offset)
{
__coverity_tainted_string_argument__(dataptr);
__coverity_tainted_data_argument__(dataptr);
}
u8_t pbuf_get_at(struct pbuf* p, u16_t offset)
{
__coverity_tainted_data_return__();
}
void abort(void)
{
__coverity_panic__();
}
int check_path(char* path, size_t size)
{
if (size) {
__coverity_tainted_data_sanitize__(path);
return 1;
} else {
return 0;
}
}

View File

@ -0,0 +1,61 @@
# This file is indended to be included in end-user CMakeLists.txt
# include(/path/to/Filelists.cmake)
# It assumes the variable LWIP_CONTRIB_DIR is defined pointing to the
# root path of lwIP/contrib sources.
#
# This file is NOT designed (on purpose) to be used as cmake
# subdir via add_subdirectory()
# The intention is to provide greater flexibility to users to
# create their own targets using the *_SRCS variables.
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0")
include_guard(GLOBAL)
endif()
set(lwipcontribexamples_SRCS
${LWIP_CONTRIB_DIR}/examples/httpd/fs_example/fs_example.c
${LWIP_CONTRIB_DIR}/examples/httpd/https_example/https_example.c
${LWIP_CONTRIB_DIR}/examples/httpd/ssi_example/ssi_example.c
${LWIP_CONTRIB_DIR}/examples/lwiperf/lwiperf_example.c
${LWIP_CONTRIB_DIR}/examples/mdns/mdns_example.c
${LWIP_CONTRIB_DIR}/examples/mqtt/mqtt_example.c
${LWIP_CONTRIB_DIR}/examples/ppp/pppos_example.c
${LWIP_CONTRIB_DIR}/examples/snmp/snmp_private_mib/lwip_prvmib.c
${LWIP_CONTRIB_DIR}/examples/snmp/snmp_v3/snmpv3_dummy.c
${LWIP_CONTRIB_DIR}/examples/snmp/snmp_example.c
${LWIP_CONTRIB_DIR}/examples/sntp/sntp_example.c
${LWIP_CONTRIB_DIR}/examples/tftp/tftp_example.c
)
add_library(lwipcontribexamples EXCLUDE_FROM_ALL ${lwipcontribexamples_SRCS})
target_compile_options(lwipcontribexamples PRIVATE ${LWIP_COMPILER_FLAGS})
target_compile_definitions(lwipcontribexamples PRIVATE ${LWIP_DEFINITIONS} ${LWIP_MBEDTLS_DEFINITIONS})
target_include_directories(lwipcontribexamples PRIVATE ${LWIP_INCLUDE_DIRS} ${LWIP_MBEDTLS_INCLUDE_DIRS})
set(lwipcontribapps_SRCS
${LWIP_CONTRIB_DIR}/apps/httpserver/httpserver-netconn.c
${LWIP_CONTRIB_DIR}/apps/chargen/chargen.c
${LWIP_CONTRIB_DIR}/apps/udpecho/udpecho.c
${LWIP_CONTRIB_DIR}/apps/tcpecho/tcpecho.c
${LWIP_CONTRIB_DIR}/apps/shell/shell.c
${LWIP_CONTRIB_DIR}/apps/udpecho_raw/udpecho_raw.c
${LWIP_CONTRIB_DIR}/apps/tcpecho_raw/tcpecho_raw.c
${LWIP_CONTRIB_DIR}/apps/netio/netio.c
${LWIP_CONTRIB_DIR}/apps/ping/ping.c
${LWIP_CONTRIB_DIR}/apps/socket_examples/socket_examples.c
${LWIP_CONTRIB_DIR}/apps/rtp/rtp.c
)
add_library(lwipcontribapps EXCLUDE_FROM_ALL ${lwipcontribapps_SRCS})
target_compile_options(lwipcontribapps PRIVATE ${LWIP_COMPILER_FLAGS})
target_compile_definitions(lwipcontribapps PRIVATE ${LWIP_DEFINITIONS} ${LWIP_MBEDTLS_DEFINITIONS})
target_include_directories(lwipcontribapps PRIVATE ${LWIP_INCLUDE_DIRS} ${LWIP_MBEDTLS_INCLUDE_DIRS})
set(lwipcontribaddons_SRCS
${LWIP_CONTRIB_DIR}/addons/tcp_isn/tcp_isn.c
${LWIP_CONTRIB_DIR}/addons/ipv6_static_routing/ip6_route_table.c
# ${LWIP_CONTRIB_DIR}/addons/netconn/external_resolve/dnssd.c
# ${LWIP_CONTRIB_DIR}/addons/tcp_md5/tcp_md5.c
)
add_library(lwipcontribaddons EXCLUDE_FROM_ALL ${lwipcontribaddons_SRCS})
target_compile_options(lwipcontribaddons PRIVATE ${LWIP_COMPILER_FLAGS})
target_compile_definitions(lwipcontribaddons PRIVATE ${LWIP_DEFINITIONS} ${LWIP_MBEDTLS_DEFINITIONS})
target_include_directories(lwipcontribaddons PRIVATE ${LWIP_INCLUDE_DIRS} ${LWIP_MBEDTLS_INCLUDE_DIRS})

View File

@ -0,0 +1,57 @@
#
# Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# 3. The name of the author may not be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
# SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
# OF SUCH DAMAGE.
#
# This file is part of the lwIP TCP/IP stack.
#
# Author: Adam Dunkels <adam@sics.se>
#
# CONTRIBAPPFILES: Contrib Applications.
CONTRIBAPPFILES=$(CONTRIBDIR)/apps/httpserver/httpserver-netconn.c \
$(CONTRIBDIR)/apps/chargen/chargen.c \
$(CONTRIBDIR)/apps/udpecho/udpecho.c \
$(CONTRIBDIR)/apps/tcpecho/tcpecho.c \
$(CONTRIBDIR)/apps/shell/shell.c \
$(CONTRIBDIR)/apps/udpecho_raw/udpecho_raw.c \
$(CONTRIBDIR)/apps/tcpecho_raw/tcpecho_raw.c \
$(CONTRIBDIR)/apps/netio/netio.c \
$(CONTRIBDIR)/apps/ping/ping.c \
$(CONTRIBDIR)/apps/socket_examples/socket_examples.c \
$(CONTRIBDIR)/apps/rtp/rtp.c \
$(CONTRIBDIR)/examples/httpd/fs_example/fs_example.c \
$(CONTRIBDIR)/examples/httpd/https_example/https_example.c \
$(CONTRIBDIR)/examples/httpd/ssi_example/ssi_example.c \
$(CONTRIBDIR)/examples/lwiperf/lwiperf_example.c \
$(CONTRIBDIR)/examples/mdns/mdns_example.c \
$(CONTRIBDIR)/examples/mqtt/mqtt_example.c \
$(CONTRIBDIR)/examples/ppp/pppos_example.c \
$(CONTRIBDIR)/examples/snmp/snmp_private_mib/lwip_prvmib.c \
$(CONTRIBDIR)/examples/snmp/snmp_v3/snmpv3_dummy.c \
$(CONTRIBDIR)/examples/snmp/snmp_example.c \
$(CONTRIBDIR)/examples/sntp/sntp_example.c \
$(CONTRIBDIR)/examples/tftp/tftp_example.c \
$(CONTRIBDIR)/addons/tcp_isn/tcp_isn.c \
$(CONTRIBDIR)/addons/ipv6_static_routing/ip6_route_table.c

View File

@ -0,0 +1,5 @@
A simple example of using LWIP_HOOK_DHCP_PARSE/APPEND_OPTION hooks to implement:
* DHCP_OPTION_MTU (option 26) to update the netif's MTU
* DHCP_OPTION_CLIENT_ID (option 61) to advertize client's HW id of LWIP_IANA_HWTYPE_ETHERNET type
Please follow the instructions in dhcp_extra_opts.h to add the hooks, definitions in lwipopts.h and enabling the extra options.

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) Espressif Systems (Shanghai) CO LTD
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
#include "lwip/prot/dhcp.h"
#include "lwip/dhcp.h"
#include "lwip/netif.h"
#include "lwip/prot/iana.h"
void dhcp_parse_extra_opts(struct dhcp *dhcp, uint8_t state, uint8_t option, uint8_t len, struct pbuf* p, uint16_t offset)
{
LWIP_UNUSED_ARG(dhcp);
LWIP_UNUSED_ARG(state);
LWIP_UNUSED_ARG(option);
LWIP_UNUSED_ARG(len);
LWIP_UNUSED_ARG(p);
LWIP_UNUSED_ARG(offset);
#if LWIP_DHCP_ENABLE_MTU_UPDATE
if ((option == DHCP_OPTION_MTU) &&
(state == DHCP_STATE_REBOOTING || state == DHCP_STATE_REBINDING ||
state == DHCP_STATE_RENEWING || state == DHCP_STATE_REQUESTING)) {
u32_t mtu = 0;
struct netif *netif;
LWIP_ERROR("dhcp_parse_extra_opts(): MTU option's len != 2", len == 2, return;);
LWIP_ERROR("dhcp_parse_extra_opts(): extracting MTU option failed",
pbuf_copy_partial(p, &mtu, 2, offset) == 2, return;);
mtu = lwip_htons((u16_t)mtu);
NETIF_FOREACH(netif) {
/* find the netif related to this dhcp */
if (dhcp == netif_dhcp_data(netif)) {
if (mtu < netif->mtu) {
netif->mtu = mtu;
LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_parse_extra_opts(): Negotiated netif MTU is %d\n", netif->mtu));
}
return;
}
}
} /* DHCP_OPTION_MTU */
#endif /* LWIP_DHCP_ENABLE_MTU_UPDATE */
}
void dhcp_append_extra_opts(struct netif *netif, uint8_t state, struct dhcp_msg *msg_out, uint16_t *options_out_len)
{
LWIP_UNUSED_ARG(netif);
LWIP_UNUSED_ARG(state);
LWIP_UNUSED_ARG(msg_out);
LWIP_UNUSED_ARG(options_out_len);
#if LWIP_DHCP_ENABLE_CLIENT_ID
if (state == DHCP_STATE_RENEWING || state == DHCP_STATE_REBINDING ||
state == DHCP_STATE_REBOOTING || state == DHCP_STATE_OFF ||
state == DHCP_STATE_REQUESTING || state == DHCP_STATE_BACKING_OFF || state == DHCP_STATE_SELECTING) {
size_t i;
u8_t *options = msg_out->options + *options_out_len;
LWIP_ERROR("dhcp_append(client_id): options_out_len + 3 + netif->hwaddr_len <= DHCP_OPTIONS_LEN",
*options_out_len + 3U + netif->hwaddr_len <= DHCP_OPTIONS_LEN, return;);
*options_out_len = *options_out_len + netif->hwaddr_len + 3;
*options++ = DHCP_OPTION_CLIENT_ID;
*options++ = netif->hwaddr_len + 1; /* option size */
*options++ = LWIP_IANA_HWTYPE_ETHERNET;
for (i = 0; i < netif->hwaddr_len; i++) {
*options++ = netif->hwaddr[i];
}
}
#endif /* LWIP_DHCP_ENABLE_CLIENT_ID */
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) Espressif Systems (Shanghai) CO LTD
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* To use these additional DHCP options, make sure this file is included in LWIP_HOOK_FILENAME
* and define these hooks:
*
* #define LWIP_HOOK_DHCP_PARSE_OPTION(netif, dhcp, state, msg, msg_type, option, len, pbuf, offset) \
* do { LWIP_UNUSED_ARG(msg); \
* dhcp_parse_extra_opts(dhcp, state, option, len, pbuf, offset); \
* } while(0)
*
* #define LWIP_HOOK_DHCP_APPEND_OPTIONS(netif, dhcp, state, msg, msg_type, options_len_ptr) \
* dhcp_append_extra_opts(netif, state, msg, options_len_ptr);
*
* To enable (disable) these option, please set one or both of the below macros to 1 (0)
* #define LWIP_DHCP_ENABLE_MTU_UPDATE 1
* #define LWIP_DHCP_ENABLE_CLIENT_ID 1
*/
#ifndef LWIP_HDR_CONTRIB_ADDONS_DHCP_OPTS_H
#define LWIP_HDR_CONTRIB_ADDONS_DHCP_OPTS_H
/* Add standard integers so the header could be included before lwip */
#include <stdint.h>
/* Forward declare lwip structs */
struct dhcp;
struct pbuf;
struct dhcp;
struct netif;
struct dhcp_msg;
/* Internal hook functions */
void dhcp_parse_extra_opts(struct dhcp *dhcp, uint8_t state, uint8_t option, uint8_t len, struct pbuf* p, uint16_t offset);
void dhcp_append_extra_opts(struct netif *netif, uint8_t state, struct dhcp_msg *msg_out, uint16_t *options_out_len);
#endif /* LWIP_HDR_CONTRIB_ADDONS_DHCP_OPTS_H */

View File

@ -0,0 +1,43 @@
A simple routing table implementation for addition, deletion and lookup of IPv6 routes. 
APIs are:
1) s8_t ip6_add_route_entry(struct ip6_prefix *ip6_prefix,
                            struct netif *netif,
                            ip6_addr_t *gateway,
                            s8_t *index);
2) err_t ip6_remove_route_entry(struct ip6_prefix *ip6_prefix);
3) s8_t ip6_find_route_entry(ip6_addr_t *ip6_dest_addr);
4) struct netif *ip6_static_route(ip6_addr_t *src, ip6_addr_t *dest);
5) ip6_addr_t *ip6_get_gateway(struct netif *netif, ip6_addr_t *dest);
6) struct ip6_route_entry *ip6_get_route_table(void);
For route lookup from the table, The LWIP_HOOK_IP6_ROUTE hook in ip6_route(..) of ip6.c
could be assigned to the ip6_static_route() API of this implementation to return the
appropriate netif.
-- The application can add routes using the API ip6_add_route_entry(..). 
   This API adds the ip6 prefix route into the static route table while
   keeping all entries sorted in decreasing order of prefix length.
   Subsequently, a linear search down the list can be performed to retrieve a
   matching route entry for a Longest Prefix Match.
   The prefix length is expected to be at an 8-bit boundary. While this is 
   a limitation, it would serve most practical purposes.
-- The application can remove routes using the API ip6_remove_route_entry(..).
-- The application can find a route entry for a specific address using the 
   ip6_find_route_entry() function which returns the index of the found entry. 
   This is used internally by the route lookup function ip6_static_route() API.
-- To fetch the gateway IPv6 address for a specific destination IPv6 
   address and target netif, the application can call ip6_get_gateway(..).
This API could be assigned to the LWIP_HOOK_ND6_GET_GW() if a gateway has
been added as part of the ip6_add_route_entry().
-- To fetch a pointer to the head of the table, the application can call 
   ip6_get_route_table().

View File

@ -0,0 +1,248 @@
/**
* @file
* IPv6 static route table.
*/
/*
* Copyright (c) 2015 Nest Labs, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Pradip De <pradipd@google.com>
*
*
* Please coordinate changes and requests with Pradip De
* <pradipd@google.com>
*/
#include "lwip/opt.h"
#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
#include "ip6_route_table.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/netif.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/nd6.h"
#include "lwip/debug.h"
#include "lwip/stats.h"
#include "string.h"
static struct ip6_route_entry static_route_table[LWIP_IPV6_NUM_ROUTE_ENTRIES];
/**
* Add the ip6 prefix route and target netif into the static route table while
* keeping all entries sorted in decreasing order of prefix length.
* 1. Search from the last entry up to find the correct slot to insert while
* moving entries one position down to create room.
* 2. Insert into empty slot created.
*
* Subsequently, a linear search down the list can be performed to retrieve a
* matching route entry for a Longest Prefix Match.
*
* @param ip6_prefix the route prefix entry to add.
* @param netif pointer to target netif.
* @param gateway the gateway address to use to send through. Has to be link local.
* @param idx return value argument of index where route entry was added in table.
* @return ERR_OK if addition was successful.
* ERR_MEM if table is already full.
* ERR_ARG if passed argument is bad or route already exists in table.
*/
err_t
ip6_add_route_entry(const struct ip6_prefix *ip6_prefix, struct netif *netif, const ip6_addr_t *gateway, s8_t *idx)
{
s8_t i = -1;
err_t retval = ERR_OK;
if (!ip6_prefix_valid(ip6_prefix->prefix_len) || (netif == NULL)) {
retval = ERR_ARG;
goto exit;
}
/* Check if an entry already exists with matching prefix; If so, replace it. */
for (i = 0; i < LWIP_IPV6_NUM_ROUTE_ENTRIES; i++) {
if ((ip6_prefix->prefix_len == static_route_table[i].prefix.prefix_len) &&
memcmp(&ip6_prefix->addr, &static_route_table[i].prefix.addr,
ip6_prefix->prefix_len / 8) == 0) {
/* Prefix matches; replace the netif with the one being added. */
goto insert;
}
}
/* Check if the table is full */
if (static_route_table[LWIP_IPV6_NUM_ROUTE_ENTRIES - 1].netif != NULL) {
retval = ERR_MEM;
goto exit;
}
/* Shift all entries down the table until slot is found */
for (i = LWIP_IPV6_NUM_ROUTE_ENTRIES - 1;
i > 0 && (ip6_prefix->prefix_len > static_route_table[i - 1].prefix.prefix_len); i--) {
SMEMCPY(&static_route_table[i], &static_route_table[i - 1], sizeof(struct ip6_route_entry));
}
insert:
/* Insert into the slot selected */
SMEMCPY(&static_route_table[i].prefix, ip6_prefix, sizeof(struct ip6_prefix));
static_route_table[i].netif = netif;
/* Add gateway to route table */
static_route_table[i].gateway = gateway;
if (idx != NULL) {
*idx = i;
}
exit:
return retval;
}
/**
* Removes the route entry from the static route table.
*
* @param ip6_prefix the route prefix entry to delete.
*/
void
ip6_remove_route_entry(const struct ip6_prefix *ip6_prefix)
{
int i, pos = -1;
for (i = 0; i < LWIP_IPV6_NUM_ROUTE_ENTRIES; i++) {
/* compare prefix to find position to delete */
if (ip6_prefix->prefix_len == static_route_table[i].prefix.prefix_len &&
memcmp(&ip6_prefix->addr, &static_route_table[i].prefix.addr,
ip6_prefix->prefix_len / 8) == 0) {
pos = i;
break;
}
}
if (pos >= 0) {
/* Shift everything beyond pos one slot up */
for (i = pos; i < LWIP_IPV6_NUM_ROUTE_ENTRIES - 1; i++) {
SMEMCPY(&static_route_table[i], &static_route_table[i+1], sizeof(struct ip6_route_entry));
if (static_route_table[i].netif == NULL) {
break;
}
}
/* Zero the remaining entries */
for (; i < LWIP_IPV6_NUM_ROUTE_ENTRIES; i++) {
ip6_addr_set_zero((&static_route_table[i].prefix.addr));
static_route_table[i].netif = NULL;
}
}
}
/**
* Finds the appropriate route entry in the static route table corresponding to the given
* destination IPv6 address. Since the entries in the route table are kept sorted in decreasing
* order of prefix length, a linear search down the list is performed to retrieve a matching
* index.
*
* @param ip6_dest_addr the destination address to match
* @return the idx of the found route entry; -1 if not found.
*/
s8_t
ip6_find_route_entry(const ip6_addr_t *ip6_dest_addr)
{
s8_t i, idx = -1;
/* Search prefix in the sorted(decreasing order of prefix length) list */
for(i = 0; i < LWIP_IPV6_NUM_ROUTE_ENTRIES; i++) {
if (memcmp(ip6_dest_addr, &static_route_table[i].prefix.addr,
static_route_table[i].prefix.prefix_len / 8) == 0) {
idx = i;
break;
}
}
return idx;
}
/**
* Finds the appropriate network interface for a given IPv6 address from a routing table with
* static IPv6 routes.
*
* @param src the source IPv6 address, if known
* @param dest the destination IPv6 address for which to find the route
* @return the netif on which to send to reach dest
*/
struct netif *
ip6_static_route(const ip6_addr_t *src, const ip6_addr_t *dest)
{
int i;
LWIP_UNUSED_ARG(src);
/* Perform table lookup */
i = ip6_find_route_entry(dest);
if (i >= 0) {
return static_route_table[i].netif;
} else {
return NULL;
}
}
/**
* Finds the gateway IP6 address for a given destination IPv6 address and target netif
* from a routing table with static IPv6 routes.
*
* @param netif the netif used for sending
* @param dest the destination IPv6 address
* @return the ip6 address of the gateway to forward packet to
*/
const ip6_addr_t *
ip6_get_gateway(struct netif *netif, const ip6_addr_t *dest)
{
const ip6_addr_t *ret_gw = NULL;
const int i = ip6_find_route_entry(dest);
LWIP_UNUSED_ARG(netif);
if (i >= 0) {
if (static_route_table[i].gateway != NULL) {
ret_gw = static_route_table[i].gateway;
}
}
return ret_gw;
}
/**
* Returns the top of the route table.
* This should be used for debug printing only.
*
* @return the top of the route table.
*/
const struct ip6_route_entry *
ip6_get_route_table(void)
{
return static_route_table;
}
#endif /* LWIP_IPV6 */

View File

@ -0,0 +1,94 @@
/**
* @file
*
* IPv6 static route table.
*/
/*
* Copyright (c) 2015 Nest Labs, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Pradip De <pradipd@google.com>
*
*
* Please coordinate changes and requests with Pradip De
* <pradipd@google.com>
*/
#ifndef __LWIP_IP6_ROUTE_TABLE_H__
#define __LWIP_IP6_ROUTE_TABLE_H__
#include "lwip/opt.h"
#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
#include "lwip/ip6_addr.h"
#include "lwip/err.h"
#ifdef __cplusplus
extern "C" {
#endif
struct netif;
/**
* LWIP_IPV6_NUM_ROUTES: Number of IPV6 routes that can be kept in the static route table.
*/
#ifndef LWIP_IPV6_NUM_ROUTE_ENTRIES
#define LWIP_IPV6_NUM_ROUTE_ENTRIES (8)
#endif
#define IP6_MAX_PREFIX_LEN (128)
#define IP6_PREFIX_ALLOWED_GRANULARITY (8)
/* Prefix length cannot be greater than 128 bits and needs to be at a byte boundary */
#define ip6_prefix_valid(prefix_len) (((prefix_len) <= IP6_MAX_PREFIX_LEN) && \
(((prefix_len) % IP6_PREFIX_ALLOWED_GRANULARITY) == 0))
struct ip6_prefix {
ip6_addr_t addr;
u8_t prefix_len; /* prefix length in bits at byte boundaries */
};
struct ip6_route_entry {
struct ip6_prefix prefix;
struct netif *netif;
const ip6_addr_t *gateway;
};
err_t ip6_add_route_entry(const struct ip6_prefix *ip6_prefix, struct netif *netif,
const ip6_addr_t *gateway, s8_t *idx);
void ip6_remove_route_entry(const struct ip6_prefix *ip6_prefix);
s8_t ip6_find_route_entry(const ip6_addr_t *ip6_dest_addr);
struct netif *ip6_static_route(const ip6_addr_t *src, const ip6_addr_t *dest);
const ip6_addr_t *ip6_get_gateway(struct netif *netif, const ip6_addr_t *dest);
const struct ip6_route_entry *ip6_get_route_table(void);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_IPV6 */
#endif /* __LWIP_IP6_ROUTE_TABLE_H__ */

View File

@ -0,0 +1,164 @@
/**
* @file
* DNS-SD APIs used by LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE
*
* This implementation assumes the DNS-SD API implementation (most likely provided by
* mDNSResponder) is implemented in the same process space as LwIP and can directly
* invoke the callback for DNSServiceGetAddrInfo. This is the typical deployment in
* an embedded environment where as a traditional OS requires pumping the callback results
* through an IPC mechanism (see DNSServiceRefSockFD/DNSServiceProcessResult)
*
* @defgroup dnssd DNS-SD
* @ingroup dns
*/
/*
* Copyright (c) 2017 Joel Cunningham, Garmin International, Inc. <joel.cunningham@garmin.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Joel Cunningham <joel.cunningham@me.com>
*
*/
#include "lwip/opt.h"
#include "lwip/err.h"
#include "lwip/inet.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "dnssd.h"
/* External headers */
#include <string.h>
#include <dns_sd.h>
/* This timeout should allow for multiple queries.
mDNSResponder has the following query timeline:
Query 1: time = 0s
Query 2: time = 1s
Query 3: time = 4s
*/
#define GETADDR_TIMEOUT_MS 5000
#define LOCAL_DOMAIN ".local"
/* Only consume .local hosts */
#ifndef CONSUME_LOCAL_ONLY
#define CONSUME_LOCAL_ONLY 1
#endif
struct addr_clbk_msg {
sys_sem_t sem;
struct sockaddr_storage addr;
err_t err;
};
static void addr_info_callback(DNSServiceRef ref, DNSServiceFlags flags, u32_t interface_index,
DNSServiceErrorType error_code, char const* hostname,
const struct sockaddr* address, u32_t ttl, void* context);
int
lwip_dnssd_gethostbyname(const char *name, ip_addr_t *addr, u8_t addrtype, err_t *err)
{
DNSServiceErrorType result;
DNSServiceRef ref;
struct addr_clbk_msg msg;
char *p;
/* @todo: use with IPv6 */
LWIP_UNUSED_ARG(addrtype);
#if CONSUME_LOCAL_ONLY
/* check if this is a .local host. If it is, then we consume the query */
p = strstr(name, LOCAL_DOMAIN);
if (p == NULL) {
return 0; /* not consumed */
}
p += (sizeof(LOCAL_DOMAIN) - 1);
/* check to make sure .local isn't a substring (only allow .local\0 or .local.\0) */
if ((*p != '.' && *p != '\0') ||
(*p == '.' && *(p + 1) != '\0')) {
return 0; /* not consumed */
}
#endif /* CONSUME_LOCAL_ONLY */
msg.err = sys_sem_new(&msg.sem, 0);
if (msg.err != ERR_OK) {
goto query_done;
}
msg.err = ERR_TIMEOUT;
result = DNSServiceGetAddrInfo(&ref, 0, 0, kDNSServiceProtocol_IPv4, name, addr_info_callback, &msg);
if (result == kDNSServiceErr_NoError) {
sys_arch_sem_wait(&msg.sem, GETADDR_TIMEOUT_MS);
DNSServiceRefDeallocate(ref);
/* We got a response */
if (msg.err == ERR_OK) {
struct sockaddr_in* addr_in = (struct sockaddr_in *)&msg.addr;
if (addr_in->sin_family == AF_INET) {
inet_addr_to_ip4addr(ip_2_ip4(addr), &addr_in->sin_addr);
} else {
/* @todo add IPv6 support */
msg.err = ERR_VAL;
}
}
}
sys_sem_free(&msg.sem);
/* Query has been consumed and is finished */
query_done:
*err = msg.err;
return 1;
}
static void
addr_info_callback(DNSServiceRef ref, DNSServiceFlags flags, u32_t interface_index,
DNSServiceErrorType error_code, char const* hostname,
const struct sockaddr* address, u32_t ttl, void* context)
{
struct addr_clbk_msg* msg = (struct addr_clbk_msg*)context;
struct sockaddr_in* addr_in = (struct sockaddr_in *)address;
LWIP_UNUSED_ARG(ref);
LWIP_UNUSED_ARG(flags);
LWIP_UNUSED_ARG(interface_index);
LWIP_UNUSED_ARG(hostname);
LWIP_UNUSED_ARG(ttl);
LWIP_UNUSED_ARG(context);
if ((error_code == kDNSServiceErr_NoError) &&
(addr_in->sin_family == AF_INET)) {
MEMCPY(&msg->addr, addr_in, sizeof(*addr_in));
msg->err = ERR_OK;
}
else {
/* @todo add IPv6 support */
msg->err = ERR_VAL;
}
sys_sem_signal(&msg->sem);
} /* addr_info_callback() */

View File

@ -0,0 +1,50 @@
/**
* @file
* DNS-SD APIs used by LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE
*
* @defgroup dnssd DNS-SD
* @ingroup dns
*/
/*
* Copyright (c) 2017 Joel Cunningham, Garmin International, Inc. <joel.cunningham@garmin.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Joel Cunningham <joel.cunningham@me.com>
*
*/
#include "lwip/opt.h"
#ifndef LWIP_HDR_DNSSD_H
#define LWIP_HDR_DNSSD_H
#include "lwip/err.h"
#include "lwip/ip_addr.h"
int lwip_dnssd_gethostbyname(const char *name, ip_addr_t *addr, u8_t addrtype, err_t *err);
#endif /* LWIP_HDR_DNSSD_H */

View File

@ -0,0 +1,182 @@
/**
* @file
*
* Reference implementation of the TCP ISN algorithm standardized in RFC 6528.
* Produce TCP Initial Sequence Numbers by combining an MD5-generated hash
* based on the new TCP connection's identity and a stable secret, with the
* current time at 4-microsecond granularity.
*
* Specifically, the implementation uses MD5 to compute a hash of the input
* buffer, which contains both the four-tuple of the new TCP connection (local
* and remote IP address and port), as well as a 16-byte secret to make the
* results unpredictable to external parties. The secret must be given at
* initialization time and should ideally remain the same across system
* reboots. To be sure: the spoofing-resistance of the resulting ISN depends
* mainly on the strength of the supplied secret!
*
* The implementation takes 32 bits from the computed hash, and adds to it the
* current time, in 4-microsecond units. The current time is computed from a
* boot time given at initialization, and the current uptime as provided by
* sys_now(). Thus, it assumes that sys_now() returns a time value that is
* relative to the boot time, i.e., that it starts at 0 at system boot, and
* only ever increases monotonically.
*
* For efficiency reasons, a single MD5 input buffer is used, and partially
* filled in at initialization time. Specifically, of this 64-byte buffer, the
* first 36 bytes are used for the four-way TCP tuple data, followed by the
* 16-byte secret, followed by 12-byte zero padding. The 64-byte size of the
* buffer should achieve the best performance for the actual MD5 computation.
*
* Basic usage:
*
* 1. in your lwipopts.h, add the following lines:
*
* #include <lwip/arch.h>
* struct ip_addr;
* u32_t lwip_hook_tcp_isn(const struct ip_addr *local_ip, u16_t local_port,
* const struct ip_addr *remote_ip, u16_t remote_port);
* "#define LWIP_HOOK_TCP_ISN lwip_hook_tcp_isn";
*
* 2. from your own code, call lwip_init_tcp_isn() at initialization time, with
* appropriate parameters.
*/
/*
* Copyright (c) 2016 The MINIX 3 Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: David van Moolenbroek <david@minix3.org>
*/
#include "tcp_isn.h"
#include "lwip/ip_addr.h"
#include "lwip/sys.h"
#include <string.h>
#ifdef LWIP_HOOK_TCP_ISN
/* pull in md5 of ppp? */
#include "netif/ppp/ppp_opts.h"
#if !PPP_SUPPORT || (!LWIP_USE_EXTERNAL_POLARSSL && !LWIP_USE_EXTERNAL_MBEDTLS)
#undef LWIP_INCLUDED_POLARSSL_MD5
#define LWIP_INCLUDED_POLARSSL_MD5 1
#include "netif/ppp/polarssl/md5.h"
#endif
static u8_t input[64];
static u32_t base_time;
/**
* Initialize the TCP ISN module, with the boot time and a secret.
*
* @param boot_time Wall clock boot time of the system, in seconds.
* @param secret_16_bytes A 16-byte secret used to randomize the TCP ISNs.
*/
void
lwip_init_tcp_isn(u32_t boot_time, const u8_t *secret_16_bytes)
{
/* Initialize the input buffer with the secret and trailing zeroes. */
memset(input, 0, sizeof(input));
MEMCPY(&input[36], secret_16_bytes, 16);
/* Save the boot time in 4-us units. Overflow is no problem here. */
base_time = boot_time * 250000;
}
/**
* Hook to generate an Initial Sequence Number (ISN) for a new TCP connection.
*
* @param local_ip The local IP address.
* @param local_port The local port number, in host-byte order.
* @param remote_ip The remote IP address.
* @param remote_port The remote port number, in host-byte order.
* @return The ISN to use for the new TCP connection.
*/
u32_t
lwip_hook_tcp_isn(const ip_addr_t *local_ip, u16_t local_port,
const ip_addr_t *remote_ip, u16_t remote_port)
{
md5_context ctx;
u8_t output[16];
u32_t isn;
#if LWIP_IPV4 && LWIP_IPV6
if (IP_IS_V6(local_ip))
#endif /* LWIP_IPV4 && LWIP_IPV6 */
#if LWIP_IPV6
{
const ip6_addr_t *local_ip6, *remote_ip6;
local_ip6 = ip_2_ip6(local_ip);
remote_ip6 = ip_2_ip6(remote_ip);
SMEMCPY(&input[0], &local_ip6->addr, 16);
SMEMCPY(&input[16], &remote_ip6->addr, 16);
}
#endif /* LWIP_IPV6 */
#if LWIP_IPV4 && LWIP_IPV6
else
#endif /* LWIP_IPV4 && LWIP_IPV6 */
#if LWIP_IPV4
{
const ip4_addr_t *local_ip4, *remote_ip4;
local_ip4 = ip_2_ip4(local_ip);
remote_ip4 = ip_2_ip4(remote_ip);
/* Represent IPv4 addresses as IPv4-mapped IPv6 addresses, to ensure that
* the IPv4 and IPv6 address spaces are completely disjoint. */
memset(&input[0], 0, 10);
input[10] = 0xff;
input[11] = 0xff;
SMEMCPY(&input[12], &local_ip4->addr, 4);
memset(&input[16], 0, 10);
input[26] = 0xff;
input[27] = 0xff;
SMEMCPY(&input[28], &remote_ip4->addr, 4);
}
#endif /* LWIP_IPV4 */
input[32] = (u8_t)(local_port >> 8);
input[33] = (u8_t)(local_port & 0xff);
input[34] = (u8_t)(remote_port >> 8);
input[35] = (u8_t)(remote_port & 0xff);
/* The secret and padding are already filled in. */
/* Generate the hash, using MD5. */
md5_starts(&ctx);
md5_update(&ctx, input, sizeof(input));
md5_finish(&ctx, output);
/* Arbitrarily take the first 32 bits from the generated hash. */
MEMCPY(&isn, output, sizeof(isn));
/* Add the current time in 4-microsecond units. */
return isn + base_time + sys_now() * 250;
}
#endif /* LWIP_HOOK_TCP_ISN */

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2016 The MINIX 3 Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: David van Moolenbroek <david@minix3.org>
*/
#ifndef LWIP_HDR_CONTRIB_ADDONS_TCP_ISN_H
#define LWIP_HDR_CONTRIB_ADDONS_TCP_ISN_H
#include "lwip/opt.h"
#include "lwip/ip_addr.h"
#ifdef __cplusplus
extern "C" {
#endif
void lwip_init_tcp_isn(u32_t boot_time, const u8_t *secret_16_bytes);
u32_t lwip_hook_tcp_isn(const ip_addr_t *local_ip, u16_t local_port,
const ip_addr_t *remote_ip, u16_t remote_port);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_HDR_CONTRIB_ADDONS_TCP_ISN_H */

View File

@ -0,0 +1,27 @@
This folder provides an example implementation of how to add custom tcp header
options and custom socket options.
It does this by implementing the (seldom used) tcp md5 signature.
To enable it, add an LWIP_HOOK_FILENAME hook file, include tcp_md5.h in it and
define these hooks:
#define LWIP_HOOK_TCP_INPACKET_PCB(pcb, hdr, optlen, opt1len, opt2, p) tcp_md5_check_inpacket(pcb, hdr, optlen, opt1len, opt2, p)
#define LWIP_HOOK_TCP_OPT_LENGTH_SEGMENT(pcb, internal_len) tcp_md5_get_additional_option_length(pcb, internal_len)
#define LWIP_HOOK_TCP_ADD_TX_OPTIONS(p, hdr, pcb, opts) tcp_md5_add_tx_options(p, hdr, pcb, opts)
#define LWIP_HOOK_SOCKETS_SETSOCKOPT(s, sock, level, optname, optval, optlen, err) tcp_md5_setsockopt_hook(sock, level, optname, optval, optlen, err)
Then, in your sockets application, enable md5 signature on a socket like this:
struct tcp_md5sig md5;
struct sockaddr_storage addr_remote; /* Initialize this to remote address and port */
memcpy(&md5.tcpm_addr, &addr_remote, sizeof(addr_remote));
strcpy(md5.tcpm_key, key); /* this is the md5 key per connection */
md5.tcpm_keylen = strlen(key);
if ((ret = setsockopt(sockfd, IPPROTO_TCP, TCP_MD5SIG, &md5, sizeof(md5))) < 0) {
perror("setsockopt TCP_MD5SIG");
return;
}
After that, your connection (client) or all incoming connections (server) require
tcp md5 signatures.

View File

@ -0,0 +1,534 @@
/**
* @file: An implementation of TCP MD5 signatures by using various hooks in
* lwIP to implement custom tcp options and custom socket options.
*/
/*
* Copyright (c) 2018 Simon Goldschmidt
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Simon Goldschmidt <goldsimon@gmx.de>
*/
#include "tcp_md5.h"
#include "lwip/ip_addr.h"
#include "lwip/sys.h"
#include "lwip/prot/tcp.h"
#include "lwip/priv/tcp_priv.h"
#include "lwip/sockets.h"
#include "lwip/priv/sockets_priv.h"
#include "lwip/api.h"
#include <string.h>
/* pull in md5 of ppp? */
#include "netif/ppp/ppp_opts.h"
#if !PPP_SUPPORT || (!LWIP_USE_EXTERNAL_POLARSSL && !LWIP_USE_EXTERNAL_MBEDTLS)
#undef LWIP_INCLUDED_POLARSSL_MD5
#define LWIP_INCLUDED_POLARSSL_MD5 1
#include "netif/ppp/polarssl/md5.h"
#endif
#if !LWIP_TCP_PCB_NUM_EXT_ARGS
#error tcp_md5 needs LWIP_TCP_PCB_NUM_EXT_ARGS
#endif
#define LWIP_TCP_OPT_MD5 19 /* number of the md5 option */
#define LWIP_TCP_OPT_LEN_MD5 18 /* length of the md5 option */
#define LWIP_TCP_OPT_LEN_MD5_OUT 20 /* 18 + alignment */
#define LWIP_TCP_MD5_DIGEST_LEN 16
/* This keeps the md5 state internally */
struct tcp_md5_conn_info {
struct tcp_md5_conn_info *next;
ip_addr_t remote_addr;
u16_t remote_port;
u8_t key[TCP_MD5SIG_MAXKEYLEN];
u16_t key_len;
};
/* Callback function prototypes: */
static void tcp_md5_extarg_destroy(u8_t id, void *data);
static err_t tcp_md5_extarg_passive_open(u8_t id, struct tcp_pcb_listen *lpcb, struct tcp_pcb *cpcb);
/* Define our tcp ext arg callback structure: */
const struct tcp_ext_arg_callbacks tcp_md5_ext_arg_callbacks = {
tcp_md5_extarg_destroy,
tcp_md5_extarg_passive_open
};
static u8_t tcp_md5_extarg_id = LWIP_TCP_PCB_NUM_EXT_ARG_ID_INVALID;
static u8_t tcp_md5_opts_buf[40];
/** Initialize this module (allocates a tcp ext arg id) */
void
tcp_md5_init(void)
{
tcp_md5_extarg_id = tcp_ext_arg_alloc_id();
}
/* Create a conn-info structure that holds the md5 state per connection */
static struct tcp_md5_conn_info *
tcp_md5_conn_info_alloc(void)
{
return (struct tcp_md5_conn_info *)mem_malloc(sizeof(struct tcp_md5_conn_info));
}
/* Frees a conn-info structure that holds the md5 state per connection */
static void
tcp_md5_conn_info_free(struct tcp_md5_conn_info *info)
{
mem_free(info);
}
/* A pcb is about to be destroyed. Free its extdata */
static void
tcp_md5_extarg_destroy(u8_t id, void *data)
{
struct tcp_md5_conn_info *iter;
LWIP_ASSERT("tcp_md5_extarg_id != LWIP_TCP_PCB_NUM_EXT_ARG_ID_INVALID",
tcp_md5_extarg_id != LWIP_TCP_PCB_NUM_EXT_ARG_ID_INVALID);
LWIP_ASSERT("id == tcp_md5_extarg_id", id == tcp_md5_extarg_id);
LWIP_UNUSED_ARG(id);
iter = (struct tcp_md5_conn_info *)data;
while (iter != NULL) {
struct tcp_md5_conn_info *info = iter;
iter = iter->next;
tcp_md5_conn_info_free(info);
}
}
/* Try to find an md5 connection info for the specified remote connection */
static struct tcp_md5_conn_info *
tcp_md5_get_info(const struct tcp_pcb *pcb, const ip_addr_t *remote_ip, u16_t remote_port)
{
if (pcb != NULL) {
struct tcp_md5_conn_info *info = (struct tcp_md5_conn_info *)tcp_ext_arg_get(pcb, tcp_md5_extarg_id);
while (info != NULL) {
if (ip_addr_eq(&info->remote_addr, remote_ip)) {
if (info->remote_port == remote_port) {
return info;
}
}
info = info->next;
}
}
return NULL;
}
/* Passive open: copy md5 connection info from listen pcb to connection pcb
* or return error (connection will be closed)
*/
static err_t
tcp_md5_extarg_passive_open(u8_t id, struct tcp_pcb_listen *lpcb, struct tcp_pcb *cpcb)
{
struct tcp_md5_conn_info *iter;
LWIP_ASSERT("lpcb != NULL", lpcb != NULL);
LWIP_ASSERT("cpcb != NULL", cpcb != NULL);
LWIP_ASSERT("tcp_md5_extarg_id != LWIP_TCP_PCB_NUM_EXT_ARG_ID_INVALID",
tcp_md5_extarg_id != LWIP_TCP_PCB_NUM_EXT_ARG_ID_INVALID);
LWIP_ASSERT("id == tcp_md5_extarg_id", id == tcp_md5_extarg_id);
LWIP_UNUSED_ARG(id);
iter = (struct tcp_md5_conn_info *)tcp_ext_arg_get((struct tcp_pcb *)lpcb, id);
while (iter != NULL) {
if (iter->remote_port == cpcb->remote_port) {
if (ip_addr_eq(&iter->remote_addr, &cpcb->remote_ip)) {
struct tcp_md5_conn_info *info = tcp_md5_conn_info_alloc();
if (info != NULL) {
memcpy(info, iter, sizeof(struct tcp_md5_conn_info));
tcp_ext_arg_set(cpcb, id, info);
tcp_ext_arg_set_callbacks(cpcb, id, &tcp_md5_ext_arg_callbacks);
return ERR_OK;
} else {
return ERR_MEM;
}
}
}
iter = iter->next;
}
/* remote connection not found */
return ERR_VAL;
}
/* Parse tcp header options and return 1 if an md5 signature option was found */
static int
tcp_md5_parseopt(const u8_t *opts, u16_t optlen, u8_t *md5_digest_out)
{
u8_t data;
u16_t optidx;
/* Parse the TCP MSS option, if present. */
if (optlen != 0) {
for (optidx = 0; optidx < optlen; ) {
u8_t opt = opts[optidx++];
switch (opt) {
case LWIP_TCP_OPT_EOL:
/* End of options. */
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: EOL\n"));
return 0;
case LWIP_TCP_OPT_NOP:
/* NOP option. */
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: NOP\n"));
break;
case LWIP_TCP_OPT_MD5:
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: MD5\n"));
if (opts[optidx++] != LWIP_TCP_OPT_LEN_MD5 || (optidx - 2 + LWIP_TCP_OPT_LEN_MD5) > optlen) {
/* Bad length */
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
return 0;
}
/* An MD5 option with the right option length. */
memcpy(md5_digest_out, &opts[optidx], LWIP_TCP_MD5_DIGEST_LEN);
/* no need to process the options further */
return 1;
break;
default:
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: other\n"));
data = opts[optidx++];
if (data < 2) {
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
/* If the length field is zero, the options are malformed
and we don't process them further. */
return 0;
}
/* All other options have a length field, so that we easily
can skip past them. */
optidx += data - 2;
}
}
}
return 0;
}
/* Get tcp options into contiguous memory. May be required if input pbufs
* are chained.
*/
static const u8_t*
tcp_md5_options_singlebuf(struct tcp_hdr *hdr, u16_t optlen, u16_t opt1len, u8_t *opt2)
{
const u8_t *opts;
LWIP_ASSERT("hdr != NULL", hdr != NULL);
LWIP_ASSERT("optlen >= opt1len", optlen >= opt1len);
opts = (const u8_t *)hdr + TCP_HLEN;
if (optlen == opt1len) {
/* arleady in one piece */
return opts;
}
if (optlen > sizeof(tcp_md5_opts_buf)) {
/* options too long */
return NULL;
}
LWIP_ASSERT("opt2 != NULL", opt2 != NULL);
/* copy first part */
memcpy(tcp_md5_opts_buf, opts, opt1len);
/* copy second part */
memcpy(&tcp_md5_opts_buf[opt1len], opt2, optlen - opt1len);
return tcp_md5_opts_buf;
}
/* Create the md5 digest for a given segment */
static int
tcp_md5_create_digest(const ip_addr_t *ip_src, const ip_addr_t *ip_dst, const struct tcp_hdr *hdr,
const u8_t *key, size_t key_len, u8_t *digest_out, struct pbuf *p)
{
md5_context ctx;
u8_t tmp8;
u16_t tmp16;
const size_t addr_len = IP_ADDR_RAW_SIZE(*ip_src);
if (p != NULL) {
LWIP_ASSERT("pbuf must not point to tcp header here!", (const void *)hdr != p->payload);
}
/* Generate the hash, using MD5. */
md5_starts(&ctx);
/* 1. the TCP pseudo-header (in the order: source IP address,
destination IP address, zero-padded protocol number, and
segment length) */
md5_update(&ctx, (const unsigned char*)ip_src, addr_len);
md5_update(&ctx, (const unsigned char*)ip_dst, addr_len);
tmp8 = 0; /* zero-padded */
md5_update(&ctx, &tmp8, 1);
tmp8 = IP_PROTO_TCP;
md5_update(&ctx, &tmp8, 1);
tmp16 = lwip_htons(TCPH_HDRLEN_BYTES(hdr) + (p ? p->tot_len : 0));
md5_update(&ctx, (const unsigned char*)&tmp16, 2);
/* 2. the TCP header, excluding options, and assuming a checksum of
zero */
md5_update(&ctx, (const unsigned char*)hdr, sizeof(struct tcp_hdr));
/* 3. the TCP segment data (if any) */
if ((p != NULL) && (p->tot_len != 0)) {
struct pbuf *q;
for (q = p; q != NULL; q = q->next) {
md5_update(&ctx, (const unsigned char*)q->payload, q->len);
}
}
/* 4. an independently-specified key or password, known to both TCPs
and presumably connection-specific */
md5_update(&ctx, key, key_len);
md5_finish(&ctx, digest_out);
return 1;
}
/* Duplicate a tcp header and make sure the fields are in network byte order */
static void
tcp_md5_dup_tcphdr(struct tcp_hdr *tcphdr_copy, const struct tcp_hdr *tcphdr_in, int tcphdr_in_is_host_order)
{
memcpy(tcphdr_copy, tcphdr_in, sizeof(struct tcp_hdr));
tcphdr_copy->chksum = 0; /* checksum is zero for the pseudo header */
if (tcphdr_in_is_host_order) {
/* lwIP writes the TCP header values back to the buffer, we need to invert that here: */
tcphdr_copy->src = lwip_htons(tcphdr_copy->src);
tcphdr_copy->dest = lwip_htons(tcphdr_copy->dest);
tcphdr_copy->seqno = lwip_htonl(tcphdr_copy->seqno);
tcphdr_copy->ackno = lwip_htonl(tcphdr_copy->ackno);
tcphdr_copy->wnd = lwip_htons(tcphdr_copy->wnd);
tcphdr_copy->urgp = lwip_htons(tcphdr_copy->urgp);
}
}
/* Check if md5 is enabled on a given pcb */
static int
tcp_md5_is_enabled_on_pcb(const struct tcp_pcb *pcb)
{
if (tcp_md5_extarg_id != LWIP_TCP_PCB_NUM_EXT_ARG_ID_INVALID) {
struct tcp_md5_conn_info *info = (struct tcp_md5_conn_info *)tcp_ext_arg_get(pcb, tcp_md5_extarg_id);
if (info != NULL) {
return 1;
}
}
return 0;
}
/* Check if md5 is enabled on a given listen pcb */
static int
tcp_md5_is_enabled_on_lpcb(const struct tcp_pcb_listen *lpcb)
{
/* same as for connection pcbs */
return tcp_md5_is_enabled_on_pcb((const struct tcp_pcb *)lpcb);
}
/* Hook implementation for LWIP_HOOK_TCP_OPT_LENGTH_SEGMENT */
u8_t
tcp_md5_get_additional_option_length(const struct tcp_pcb *pcb, u8_t internal_option_length)
{
if ((pcb != NULL) && tcp_md5_is_enabled_on_pcb(pcb)) {
u8_t new_option_length = internal_option_length + LWIP_TCP_OPT_LEN_MD5_OUT;
LWIP_ASSERT("overflow", new_option_length > internal_option_length);
LWIP_ASSERT("options too long", new_option_length <= TCP_MAX_OPTION_BYTES);
return new_option_length;
}
return internal_option_length;
}
/* Hook implementation for LWIP_HOOK_TCP_INPACKET_PCB when called for listen pcbs */
static err_t
tcp_md5_check_listen(struct tcp_pcb_listen* lpcb, struct tcp_hdr *hdr, u16_t optlen, u16_t opt1len, u8_t *opt2)
{
LWIP_ASSERT("lpcb != NULL", lpcb != NULL);
if (tcp_md5_is_enabled_on_lpcb(lpcb)) {
const u8_t *opts;
u8_t digest_received[LWIP_TCP_MD5_DIGEST_LEN];
u8_t digest_calculated[LWIP_TCP_MD5_DIGEST_LEN];
const struct tcp_md5_conn_info *info = tcp_md5_get_info((struct tcp_pcb *)lpcb, ip_current_src_addr(), hdr->src);
if (info != NULL) {
opts = tcp_md5_options_singlebuf(hdr, optlen, opt1len, opt2);
if (opts != NULL) {
if (tcp_md5_parseopt(opts, optlen, digest_received)) {
struct tcp_hdr tcphdr_copy;
tcp_md5_dup_tcphdr(&tcphdr_copy, hdr, 1);
if (tcp_md5_create_digest(ip_current_src_addr(), ip_current_dest_addr(), &tcphdr_copy, info->key, info->key_len, digest_calculated, NULL)) {
/* everything set up, compare the digests */
if (!memcmp(digest_received, digest_calculated, LWIP_TCP_MD5_DIGEST_LEN)) {
/* equal */
return ERR_OK;
}
/* not equal */
}
}
}
}
/* md5 enabled on this pcb but no match or other error -> fail */
return ERR_VAL;
}
return ERR_OK;
}
/* Hook implementation for LWIP_HOOK_TCP_INPACKET_PCB */
err_t
tcp_md5_check_inpacket(struct tcp_pcb* pcb, struct tcp_hdr *hdr, u16_t optlen, u16_t opt1len, u8_t *opt2, struct pbuf *p)
{
LWIP_ASSERT("pcb != NULL", pcb != NULL);
if (pcb->state == LISTEN) {
return tcp_md5_check_listen((struct tcp_pcb_listen *)pcb, hdr, optlen, opt1len, opt2);
}
if (tcp_md5_is_enabled_on_pcb(pcb)) {
const struct tcp_md5_conn_info *info = tcp_md5_get_info(pcb, ip_current_src_addr(), hdr->src);
if (info != NULL) {
const u8_t *opts;
u8_t digest_received[LWIP_TCP_MD5_DIGEST_LEN];
u8_t digest_calculated[LWIP_TCP_MD5_DIGEST_LEN];
opts = tcp_md5_options_singlebuf(hdr, optlen, opt1len, opt2);
if (opts != NULL) {
if (tcp_md5_parseopt(opts, optlen, digest_received)) {
struct tcp_hdr hdr_copy;
tcp_md5_dup_tcphdr(&hdr_copy, hdr, 1);
if (tcp_md5_create_digest(&pcb->remote_ip, &pcb->local_ip, &hdr_copy, info->key, info->key_len, digest_calculated, p)) {
/* everything set up, compare the digests */
if (!memcmp(digest_received, digest_calculated, LWIP_TCP_MD5_DIGEST_LEN)) {
/* equal */
return ERR_OK;
}
/* not equal */
}
}
}
}
/* md5 enabled on this pcb but no match or other error -> fail */
return ERR_VAL;
}
return ERR_OK;
}
/* Hook implementation for LWIP_HOOK_TCP_ADD_TX_OPTIONS */
u32_t *
tcp_md5_add_tx_options(struct pbuf *p, struct tcp_hdr *hdr, const struct tcp_pcb *pcb, u32_t *opts)
{
LWIP_ASSERT("p != NULL", p != NULL);
LWIP_ASSERT("hdr != NULL", hdr != NULL);
LWIP_ASSERT("pcb != NULL", pcb != NULL);
LWIP_ASSERT("opts != NULL", opts != NULL);
if (tcp_md5_is_enabled_on_pcb(pcb)) {
u8_t digest_calculated[LWIP_TCP_MD5_DIGEST_LEN];
u32_t *opts_ret = opts + 5; /* we use 20 bytes: 2 bytes padding + 18 bytes for this option */
u8_t *ptr = (u8_t*)opts;
const struct tcp_md5_conn_info *info = tcp_md5_get_info(pcb, &pcb->remote_ip, pcb->remote_port);
if (info != NULL) {
struct tcp_hdr hdr_copy;
size_t hdrsize = TCPH_HDRLEN_BYTES(hdr);
tcp_md5_dup_tcphdr(&hdr_copy, hdr, 0);
/* p->payload points to the tcp header */
LWIP_ASSERT("p->payload == hdr", p->payload == hdr);
if (!pbuf_remove_header(p, hdrsize)) {
u8_t ret;
if (!tcp_md5_create_digest(&pcb->local_ip, &pcb->remote_ip, &hdr_copy, info->key, info->key_len, digest_calculated, p)) {
info = NULL;
}
ret = pbuf_add_header_force(p, hdrsize);
LWIP_ASSERT("tcp_md5_add_tx_options: pbuf_add_header_force failed", !ret);
LWIP_UNUSED_ARG(ret);
} else {
LWIP_ASSERT("error", 0);
}
}
if (info == NULL) {
/* create an invalid signature by zeroing the digest */
memset(&digest_calculated, 0, sizeof(digest_calculated));
}
*ptr++ = LWIP_TCP_OPT_NOP;
*ptr++ = LWIP_TCP_OPT_NOP;
*ptr++ = LWIP_TCP_OPT_MD5;
*ptr++ = LWIP_TCP_OPT_LEN_MD5;
memcpy(ptr, digest_calculated, LWIP_TCP_MD5_DIGEST_LEN);
ptr += LWIP_TCP_MD5_DIGEST_LEN;
LWIP_ASSERT("ptr == opts_ret", ptr == (u8_t *)opts_ret);
return opts_ret;
}
return opts;
}
/* Hook implementation for LWIP_HOOK_SOCKETS_SETSOCKOPT */
int
tcp_md5_setsockopt_hook(struct lwip_sock *sock, int level, int optname, const void *optval, socklen_t optlen, int *err)
{
LWIP_ASSERT("sock != NULL", sock != NULL);
LWIP_ASSERT("err != NULL", err != NULL);
if ((level == IPPROTO_TCP) && (optname == TCP_MD5SIG)) {
const struct tcp_md5sig *md5 = (const struct tcp_md5sig*)optval;
if ((optval == NULL) || (optlen < sizeof(struct tcp_md5sig))) {
*err = EINVAL;
} else {
if (sock->conn && (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) && (sock->conn->pcb.tcp != NULL)) {
if (tcp_md5_extarg_id == LWIP_TCP_PCB_NUM_EXT_ARG_ID_INVALID) {
/* not initialized */
*err = EINVAL;
} else {
struct tcp_md5_conn_info *info = tcp_md5_conn_info_alloc();
if (info == NULL) {
*err = ENOMEM;
} else {
int addr_valid = 0;
/* OK, fill and link this request */
memcpy(info->key, md5->tcpm_key, TCP_MD5SIG_MAXKEYLEN);
info->key_len = md5->tcpm_keylen;
memset(&info->remote_addr, 0, sizeof(info->remote_addr));
if (md5->tcpm_addr.ss_family == AF_INET) {
#if LWIP_IPV4
const struct sockaddr_in *sin = (const struct sockaddr_in *)&md5->tcpm_addr;
memcpy(&info->remote_addr, &sin->sin_addr, sizeof(sin->sin_addr));
IP_SET_TYPE_VAL(info->remote_addr, IPADDR_TYPE_V4);
info->remote_port = lwip_htons(sin->sin_port);
addr_valid = 1;
#endif /* LWIP_IPV4 */
} else if (md5->tcpm_addr.ss_family == AF_INET6) {
#if LWIP_IPV6
const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)&md5->tcpm_addr;
memcpy(&info->remote_addr, &sin6->sin6_addr, sizeof(sin6->sin6_addr));
IP_SET_TYPE_VAL(info->remote_addr, IPADDR_TYPE_V6);
info->remote_port = lwip_htons(sin6->sin6_port);
addr_valid = 1;
#endif /* LWIP_IPV6 */
}
if (addr_valid) {
/* store it */
tcp_ext_arg_set_callbacks(sock->conn->pcb.tcp, tcp_md5_extarg_id, &tcp_md5_ext_arg_callbacks);
info->next = (struct tcp_md5_conn_info *)tcp_ext_arg_get(sock->conn->pcb.tcp, tcp_md5_extarg_id);
tcp_ext_arg_set(sock->conn->pcb.tcp, tcp_md5_extarg_id, info);
} else {
*err = EINVAL;
tcp_md5_conn_info_free(info);
}
}
}
} else {
/* not a tcp netconn */
*err = EINVAL;
}
}
return 1;
}
return 0;
}

View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 2018 Simon Goldschmidt
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Simon Goldschmidt <goldsimon@gmx.de>
*
* To use the hooks in this file, make sure this file is included in LWIP_HOOK_FILENAME
* and define these hooks:
*
* #define LWIP_HOOK_TCP_INPACKET_PCB(pcb, hdr, optlen, opt1len, opt2, p) tcp_md5_check_inpacket(pcb, hdr, optlen, opt1len, opt2, p)
* #define LWIP_HOOK_TCP_OPT_LENGTH_SEGMENT(pcb, internal_len) tcp_md5_get_additional_option_length(pcb, internal_len)
* #define LWIP_HOOK_TCP_ADD_TX_OPTIONS(p, hdr, pcb, opts) tcp_md5_add_tx_options(p, hdr, pcb, opts)
*
* #define LWIP_HOOK_SOCKETS_SETSOCKOPT(s, sock, level, optname, optval, optlen, err) tcp_md5_setsockopt_hook(sock, level, optname, optval, optlen, err)
*/
#ifndef LWIP_HDR_CONTRIB_ADDONS_TCP_MD5_H
#define LWIP_HDR_CONTRIB_ADDONS_TCP_MD5_H
#include "lwip/opt.h"
#include "lwip/ip_addr.h"
#include "lwip/err.h"
#include "lwip/priv/sockets_priv.h"
#include "lwip/priv/tcp_priv.h"
#ifdef __cplusplus
extern "C" {
#endif
/* setsockopt definitions and structs: */
/* This is the optname (for level = IPPROTO_TCP) */
#ifndef TCP_MD5SIG
#define TCP_MD5SIG 14
#endif
#define TCP_MD5SIG_MAXKEYLEN 80
/* This is the optval type */
struct tcp_md5sig {
struct sockaddr_storage tcpm_addr;
u16_t __tcpm_pad1;
u16_t tcpm_keylen;
u32_t __tcpm_pad2;
u8_t tcpm_key[TCP_MD5SIG_MAXKEYLEN];
};
/* socket setsockopt hook: */
int tcp_md5_setsockopt_hook(struct lwip_sock *sock, int level, int optname, const void *optval, u32_t optlen, int *err);
/* Internal hook functions */
void tcp_md5_init(void);
err_t tcp_md5_check_inpacket(struct tcp_pcb* pcb, struct tcp_hdr *hdr, u16_t optlen, u16_t opt1len, u8_t *opt2, struct pbuf *p);
u8_t tcp_md5_get_additional_option_length(const struct tcp_pcb *pcb, u8_t internal_option_length);
u32_t *tcp_md5_add_tx_options(struct pbuf *p, struct tcp_hdr *hdr, const struct tcp_pcb *pcb, u32_t *opts);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_HDR_CONTRIB_ADDONS_TCP_MD5_H */

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{7DA7C0AB-0982-4BF5-9324-F59A7A08D65B}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>CCodeGeneration</RootNamespace>
<AssemblyName>CCodeGeneration</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="CFile.cs" />
<Compile Include="Code.cs" />
<Compile Include="CodeContainerBase.cs" />
<Compile Include="CodeElement.cs" />
<Compile Include="Comment.cs" />
<Compile Include="EmptyLine.cs" />
<Compile Include="Function.cs" />
<Compile Include="CGenerator.cs" />
<Compile Include="IfThenElse.cs" />
<Compile Include="PlainText.cs" />
<Compile Include="Switch.cs" />
<Compile Include="PP_If.cs" />
<Compile Include="PP_Ifdef.cs" />
<Compile Include="PP_Include.cs" />
<Compile Include="FunctionDeclaration.cs" />
<Compile Include="PP_Macro.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="VariableDeclaration.cs" />
<Compile Include="VariablePrototype.cs" />
<Compile Include="VariableType.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
using System;
namespace CCodeGeneration
{
public class CFile: CodeContainerBase
{
public CFile()
{
base.IncreaseLevel = false;
}
public void Save(CGenerator generator)
{
if (generator == null)
{
throw new ArgumentNullException("generator");
}
this.GenerateCode(0, generator);
}
}
}

View File

@ -0,0 +1,119 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
using System;
using System.IO;
namespace CCodeGeneration
{
public class CGenerator
{
public TextWriter OutputStream { get; private set; }
public string File { get; private set; }
public uint IndentCount { get; private set; }
public string IndentChar { get; private set; }
public string NewLine { get; private set; }
public CGenerator(System.IO.TextWriter outputStream, string file, uint indentCount, string indentChar, string newLine)
{
this.OutputStream = outputStream;
this.File = file;
this.IndentCount = indentCount;
this.IndentChar = indentChar;
this.NewLine = newLine;
}
public string FileName
{
get
{
if (!String.IsNullOrWhiteSpace(this.File))
{
return Path.GetFileName(this.File);
}
return null;
}
}
public void WriteSequence(string value, uint repetitions)
{
while (repetitions > 0)
{
this.OutputStream.Write(value);
repetitions--;
}
}
public void IndentLine(int level)
{
while (level > 0)
{
WriteSequence(this.IndentChar, this.IndentCount);
level--;
}
}
public void WriteNewLine()
{
this.OutputStream.Write(this.NewLine);
}
public void WriteMultilineString(string value, int level = 0)
{
if (String.IsNullOrEmpty(value))
{
return;
}
// only \n and \r\n are recognized as linebreaks
string[] lines = value.Split(new char[] { '\n' }, StringSplitOptions.None);
for (int l = 0; l < (lines.Length - 1); l++)
{
if (lines[l].EndsWith("\r"))
{
this.OutputStream.Write(lines[l].Substring(0, lines[l].Length-1));
}
else
{
this.OutputStream.Write(lines[l]);
}
this.WriteNewLine();
this.IndentLine(level);
}
this.OutputStream.Write(lines[lines.Length - 1]);
}
}
}

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
namespace CCodeGeneration
{
public class Code: CodeElement
{
public string Code_ { get; set; }
public Code()
{
}
public Code(string code)
{
this.Code_ = code;
}
public override void GenerateCode(int level, CGenerator generator)
{
generator.IndentLine(level);
generator.WriteMultilineString(this.Code_, level);
generator.WriteNewLine();
}
}
}

View File

@ -0,0 +1,139 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
using System.Collections.Generic;
using System;
namespace CCodeGeneration
{
public class CodeContainerBase: CodeElement
{
private readonly List<CodeElement> declarations = new List<CodeElement>();
private readonly List<CodeElement> innerElements = new List<CodeElement>();
private bool increaseLevel = true;
public List<CodeElement> Declarations
{
get { return this.declarations; }
}
public List<CodeElement> InnerElements
{
get { return this.innerElements; }
}
protected bool IncreaseLevel
{
get { return this.increaseLevel; }
set { this.increaseLevel = value; }
}
public void AddElements(IList<CodeElement> elements, params CodeElement[] spacerElements)
{
if (elements != null)
{
if ((spacerElements == null) || (spacerElements.Length == 0))
{
this.innerElements.AddRange(elements);
}
else
{
bool spacerAdded = false;
foreach (CodeElement element in elements)
{
this.innerElements.Add(element);
this.innerElements.AddRange(spacerElements);
spacerAdded = true;
}
if (spacerAdded)
{
// remove last spacer again
this.innerElements.RemoveRange(this.innerElements.Count - spacerElements.Length, spacerElements.Length);
}
}
}
}
public CodeElement AddElement(CodeElement element)
{
if (element != null)
{
this.innerElements.Add(element);
}
return element;
}
public Code AddCode(string code)
{
return this.AddElement(new Code(code)) as Code;
}
public Code AddCodeFormat(string codeFormat, params object[] args)
{
return this.AddElement(new Code(String.Format(codeFormat, args))) as Code;
}
public CodeElement AddDeclaration(CodeElement declaration)
{
if (declaration != null)
{
this.declarations.Add(declaration);
}
return declaration;
}
public override void GenerateCode(int level, CGenerator generator)
{
if (this.increaseLevel)
level++;
if (this.declarations.Count > 0)
{
foreach (CodeElement element in this.declarations)
{
element.GenerateCode(level, generator);
}
EmptyLine.SingleLine.GenerateCode(level, generator);
}
foreach (CodeElement element in this.innerElements)
{
element.GenerateCode(level, generator);
}
}
}
}

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
namespace CCodeGeneration
{
public class CodeElement
{
public virtual void GenerateCode(int level, CGenerator generator)
{
}
}
}

View File

@ -0,0 +1,75 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
namespace CCodeGeneration
{
public class Comment: CodeElement
{
public const string CommentStart = "/*";
public const string CommentEnd = "*/";
public string Comment_ { get; set; }
public bool SingleLine { get; set; }
public Comment()
{
}
public Comment(string comment, bool singleLine = false)
{
this.Comment_ = comment;
this.SingleLine = singleLine;
}
public override void GenerateCode(int level, CGenerator generator)
{
generator.IndentLine(level);
generator.OutputStream.Write(CommentStart);
if (!this.SingleLine)
{
generator.WriteNewLine();
generator.IndentLine(level);
generator.WriteMultilineString(this.Comment_, level);
generator.WriteNewLine();
generator.IndentLine(level);
}
else
{
generator.OutputStream.Write(" " + Comment_ + " ");
}
generator.OutputStream.Write(CommentEnd);
generator.WriteNewLine();
}
}
}

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
namespace CCodeGeneration
{
public class EmptyLine : CodeElement
{
public static readonly EmptyLine SingleLine = new EmptyLine();
public static readonly EmptyLine TwoLines = new EmptyLine(2);
public static readonly EmptyLine ThreeLines = new EmptyLine(3);
public uint Count { get; set; }
public EmptyLine()
{
this.Count = 1;
}
public EmptyLine(uint count)
{
this.Count = count;
}
public override void GenerateCode(int level, CGenerator generator)
{
uint c = this.Count;
while (c > 0)
{
generator.WriteNewLine();
c--;
}
}
}
}

View File

@ -0,0 +1,129 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
using System;
using System.Collections.Generic;
namespace CCodeGeneration
{
public class Function: CodeContainerBase
{
public string Name { get; set; }
public bool IsStatic { get; set; }
private readonly List<VariableType> parameter = new List<VariableType>();
private VariableType returnType = VariableType.Void;
public Function()
{
}
public Function(string name, bool isStatic = false)
{
this.Name = name;
this.IsStatic = isStatic;
}
public List<VariableType> Parameter
{
get { return this.parameter; }
}
public VariableType ReturnType
{
get { return this.returnType; }
set
{
if (value == null)
{
throw new ArgumentNullException("ReturnValue");
}
this.returnType = value;
}
}
public static Function FromDeclaration(FunctionDeclaration decl)
{
Function result = new Function(decl.Name, decl.IsStatic);
result.ReturnType = decl.ReturnType.Clone() as VariableType;
foreach (VariableType param in decl.Parameter)
{
result.parameter.Add(param.Clone() as VariableType);
}
return result;
}
public override void GenerateCode(int level, CGenerator generator)
{
generator.IndentLine(level);
if (this.IsStatic)
{
generator.OutputStream.Write("static ");
}
this.returnType.GenerateCode(generator);
generator.OutputStream.Write(" " + this.Name + "(");
if (this.Parameter.Count > 0)
{
for (int i = 0; i < this.parameter.Count; i++)
{
this.parameter[i].GenerateCode(generator);
if (i < (this.parameter.Count - 1))
{
generator.OutputStream.Write(", ");
}
}
}
else
{
generator.OutputStream.Write("void");
}
generator.OutputStream.Write(")");
generator.WriteNewLine();
generator.IndentLine(level);
generator.OutputStream.Write("{");
generator.WriteNewLine();
base.GenerateCode(level, generator);
generator.IndentLine(level);
generator.OutputStream.Write("}");
generator.WriteNewLine();
}
}
}

View File

@ -0,0 +1,114 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
using System;
using System.Collections.Generic;
namespace CCodeGeneration
{
public class FunctionDeclaration: CodeElement
{
public string Name { get; set; }
public bool IsStatic { get; set; }
public bool IsExtern { get; set; }
private readonly List<VariableType> parameter = new List<VariableType>();
private VariableType returnType = VariableType.Void;
public FunctionDeclaration()
{
}
public FunctionDeclaration(string name, bool isStatic = false, bool isExtern = false)
{
this.Name = name;
this.IsStatic = isStatic;
this.IsExtern = isExtern;
}
public List<VariableType> Parameter
{
get { return this.parameter; }
}
public VariableType ReturnType
{
get { return this.returnType; }
set
{
if (value == null)
{
throw new ArgumentNullException("ReturnValue");
}
this.returnType = value;
}
}
public override void GenerateCode(int level, CGenerator generator)
{
generator.IndentLine(level);
if (this.IsExtern)
{
generator.OutputStream.Write("extern ");
}
if (this.IsStatic)
{
generator.OutputStream.Write("static ");
}
this.returnType.GenerateCode(generator);
generator.OutputStream.Write(" " + this.Name + "(");
if (this.Parameter.Count > 0)
{
for (int i = 0; i < this.parameter.Count; i++)
{
this.parameter[i].GenerateCode(generator);
if (i < (this.parameter.Count - 1))
{
generator.OutputStream.Write(", ");
}
}
}
else
{
generator.OutputStream.Write("void");
}
generator.OutputStream.Write(");");
generator.WriteNewLine();
}
}
}

View File

@ -0,0 +1,137 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
using System;
using System.Collections.Generic;
namespace CCodeGeneration
{
public class ElseIf : CodeContainerBase
{
public string Condition { get; set; }
public ElseIf()
{
}
public ElseIf(string condition)
{
this.Condition = condition;
}
public override void GenerateCode(int level, CGenerator generator)
{
if (!String.IsNullOrWhiteSpace(this.Condition))
{
generator.IndentLine(level);
generator.OutputStream.Write(String.Format("else if ({0})", this.Condition));
generator.WriteNewLine();
generator.IndentLine(level);
generator.OutputStream.Write("{");
generator.WriteNewLine();
base.GenerateCode(level, generator);
generator.IndentLine(level);
generator.OutputStream.Write("}");
generator.WriteNewLine();
}
}
}
public class IfThenElse: CodeContainerBase
{
public string Condition { get; set; }
private List<ElseIf> elseIf = new List<ElseIf>();
private CodeContainerBase else_ = new CodeContainerBase();
public IfThenElse()
{
}
public IfThenElse(string condition)
{
this.Condition = condition;
}
public List<ElseIf> ElseIf
{
get { return this.elseIf; }
}
public CodeContainerBase Else
{
get { return this.else_; }
}
public override void GenerateCode(int level, CGenerator generator)
{
if (!String.IsNullOrWhiteSpace(this.Condition))
{
generator.IndentLine(level);
generator.OutputStream.Write(String.Format("if ({0})", this.Condition));
generator.WriteNewLine();
generator.IndentLine(level);
generator.OutputStream.Write("{");
generator.WriteNewLine();
base.GenerateCode(level, generator);
generator.IndentLine(level);
generator.OutputStream.Write("}");
generator.WriteNewLine();
foreach (ElseIf elif in this.elseIf)
{
elif.GenerateCode(level, generator);
}
if (this.else_.InnerElements.Count > 0)
{
generator.IndentLine(level);
generator.OutputStream.Write("else");
generator.WriteNewLine();
generator.IndentLine(level);
generator.OutputStream.Write("{");
generator.WriteNewLine();
this.else_.GenerateCode(level, generator);
generator.IndentLine(level);
generator.OutputStream.Write("}");
generator.WriteNewLine();
}
}
}
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
using System;
namespace CCodeGeneration
{
public class PP_If: CodeContainerBase
{
public string Condition { get; set; }
public PP_If()
{
base.IncreaseLevel = false;
}
public PP_If(string condition)
: this()
{
this.Condition = condition;
}
public override void GenerateCode(int level, CGenerator generator)
{
if (!String.IsNullOrWhiteSpace(this.Condition))
{
generator.OutputStream.Write("#if " + this.Condition);
generator.WriteNewLine();
base.GenerateCode(level, generator);
generator.OutputStream.Write("#endif /* " + this.Condition + " */");
generator.WriteNewLine();
}
}
}
}

View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
using System;
namespace CCodeGeneration
{
public class PP_Ifdef: CodeContainerBase
{
public string Macro { get; set; }
public bool Inverted { get; set; }
public PP_Ifdef()
{
base.IncreaseLevel = false;
}
public PP_Ifdef(string macro, bool inverted = false)
: this()
{
this.Macro = macro;
this.Inverted = inverted;
}
public override void GenerateCode(int level, CGenerator generator)
{
if (!String.IsNullOrWhiteSpace(this.Macro))
{
if (this.Inverted)
{
generator.OutputStream.Write("#ifndef " + this.Macro);
}
else
{
generator.OutputStream.Write("#ifdef " + this.Macro);
}
generator.WriteNewLine();
base.GenerateCode(level, generator);
generator.OutputStream.Write("#endif /* " + this.Macro + " */");
generator.WriteNewLine();
}
}
}
}

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
using System;
namespace CCodeGeneration
{
public class PP_Include : CodeElement
{
public string File { get; set; }
public bool IsLocal { get; set; }
public PP_Include()
{
this.IsLocal = true;
}
public PP_Include(string file, bool isLocal = true)
{
this.File = file;
this.IsLocal = isLocal;
}
public override void GenerateCode(int level, CGenerator generator)
{
if (!String.IsNullOrWhiteSpace(this.File))
{
// includes are never indented
if (this.IsLocal)
{
generator.OutputStream.Write("#include \"" + this.File + "\"");
}
else
{
generator.OutputStream.Write("#include <" + this.File + ">");
}
generator.WriteNewLine();
}
}
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
namespace CCodeGeneration
{
public class PP_Macro: CodeElement
{
public string Name { get; set; }
public string Value { get; set; }
public PP_Macro()
{
}
public PP_Macro(string name, string value)
{
this.Name = name;
this.Value = value;
}
public override void GenerateCode(int level, CGenerator generator)
{
// macros are not indented at all
generator.OutputStream.Write("#define " + this.Name + " ");
generator.WriteMultilineString(this.Value);
generator.WriteNewLine();
}
}
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
namespace CCodeGeneration
{
public class PlainText : CodeElement
{
public string Value { get; set; }
public PlainText(string value)
{
this.Value = value;
}
public override void GenerateCode(int level, CGenerator generator)
{
generator.WriteMultilineString(this.Value);
}
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// Allgemeine Informationen über eine Assembly werden über die folgenden
// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
// die mit einer Assembly verknüpft sind.
[assembly: AssemblyTitle("CCodeGeneration")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("CCodeGeneration")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar
// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von
// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest.
[assembly: ComVisible(false)]
// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
[assembly: Guid("8f07a0fa-86f4-48a0-97c7-f94fc5c3f103")]
// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
//
// Hauptversion
// Nebenversion
// Buildnummer
// Revision
//
// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern
// übernehmen, indem Sie "*" eingeben:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,146 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
using System;
using System.Collections.Generic;
namespace CCodeGeneration
{
public class SwitchCase : CodeContainerBase
{
public string Value { get; set; }
public SwitchCase()
{
}
public SwitchCase(string value)
{
this.Value = value;
}
public bool IsDefault
{
get { return (this.Value.ToLowerInvariant() == "default"); }
}
public static SwitchCase GenerateDefault()
{
return new SwitchCase("default");
}
public override void GenerateCode(int level, CGenerator generator)
{
if (!String.IsNullOrWhiteSpace(this.Value))
{
generator.IndentLine(level);
if (this.IsDefault)
{
generator.OutputStream.Write("default:");
}
else
{
generator.OutputStream.Write(String.Format("case {0}:", this.Value));
}
generator.WriteNewLine();
generator.IndentLine(level + 1);
generator.OutputStream.Write("{");
generator.WriteNewLine();
base.GenerateCode(level + 1, generator);
generator.IndentLine(level + 1);
generator.OutputStream.Write("}");
generator.WriteNewLine();
generator.IndentLine(level + 1);
generator.OutputStream.Write("break;");
generator.WriteNewLine();
}
}
}
public class Switch: CodeElement
{
public string SwitchVar { get; set; }
private List<SwitchCase> switches = new List<SwitchCase>();
public Switch()
{
}
public Switch(string switchVar)
{
this.SwitchVar = switchVar;
}
public List<SwitchCase> Switches
{
get { return this.switches; }
}
public override void GenerateCode(int level, CGenerator generator)
{
if (!String.IsNullOrWhiteSpace(this.SwitchVar))
{
generator.IndentLine(level);
generator.OutputStream.Write(String.Format("switch ({0})", this.SwitchVar));
generator.WriteNewLine();
generator.IndentLine(level);
generator.OutputStream.Write("{");
generator.WriteNewLine();
SwitchCase defaultCase = null; // generate 'default' always as last case
foreach (SwitchCase switchCase in this.switches)
{
if (switchCase.IsDefault)
{
defaultCase = switchCase;
}
else
{
switchCase.GenerateCode(level + 1, generator);
}
}
if (defaultCase != null)
{
defaultCase.GenerateCode(level + 1, generator);
}
generator.IndentLine(level);
generator.OutputStream.Write("}");
generator.WriteNewLine();
}
}
}
}

View File

@ -0,0 +1,82 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
using System;
namespace CCodeGeneration
{
public class VariableDeclaration : CodeElement
{
public VariableType Type { get; set; }
public string InitialValue { get; set; }
public bool IsStatic { get; set; }
public VariableDeclaration()
: base()
{
}
public VariableDeclaration(VariableType type, string initialValue = null, bool isStatic = false) :
base()
{
this.Type = type;
this.InitialValue = initialValue;
this.IsStatic = isStatic;
}
public override void GenerateCode(int level, CGenerator generator)
{
if (this.Type != null)
{
generator.IndentLine(level);
if (this.IsStatic)
{
generator.OutputStream.Write("static ");
}
// declare the variable
this.Type.GenerateCode(generator);
if (!String.IsNullOrWhiteSpace(this.InitialValue))
{
// add initialization value
generator.OutputStream.Write(" = ");
generator.WriteMultilineString(this.InitialValue, level);
}
generator.OutputStream.Write(";");
generator.WriteNewLine();
}
}
}
}

View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
namespace CCodeGeneration
{
public class VariablePrototype : CodeElement
{
public VariableType Type { get; set; }
public VariablePrototype()
: base()
{
}
public VariablePrototype(VariableType type) :
base()
{
Type = type;
}
public static VariablePrototype FromVariableDeclaration(VariableDeclaration declaration)
{
return new VariablePrototype(declaration.Type);
}
public override void GenerateCode(int level, CGenerator generator)
{
if (this.Type != null)
{
generator.IndentLine(level);
generator.OutputStream.Write("extern ");
// declare the variable
this.Type.GenerateCode(generator);
generator.OutputStream.Write(";");
generator.WriteNewLine();
}
}
}
}

View File

@ -0,0 +1,130 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
using System;
using System.Text;
namespace CCodeGeneration
{
public enum ConstType
{
None,
Value,
Indirection,
Both
}
public class VariableType : ICloneable
{
public const string VoidString = "void";
public static readonly VariableType Void = new VariableType(null, "void");
public string Name { get; set; }
public string Type { get; set; }
public string Indirection { get; set; }
public ConstType Const { get; set; }
public string ArraySpecifier { get; set; }
public VariableType()
{
}
public VariableType(string name, string type, string indirection = null, ConstType const_ = ConstType.None, string arraySpecifier = null)
{
this.Name = name;
this.Type = type;
this.Indirection = indirection;
this.Const = const_;
this.ArraySpecifier = arraySpecifier;
}
public void GenerateCode(CGenerator generator)
{
if (!String.IsNullOrWhiteSpace(this.Type))
{
generator.OutputStream.Write(this.ToString().Trim());
}
}
public override string ToString()
{
if (!String.IsNullOrWhiteSpace(this.Type))
{
StringBuilder vt = new StringBuilder();
if ((this.Const == ConstType.Value) || (this.Const == ConstType.Both))
{
vt.Append("const ");
}
vt.Append(this.Type);
vt.Append(" ");
if (!String.IsNullOrWhiteSpace(this.Indirection))
{
vt.Append(this.Indirection);
}
if ((this.Const == ConstType.Indirection) || (this.Const == ConstType.Both))
{
vt.Append("const ");
}
if (!String.IsNullOrWhiteSpace(this.Name))
{
vt.Append(this.Name);
}
if (this.ArraySpecifier != null)
{
vt.Append("[");
vt.Append(this.ArraySpecifier);
vt.Append("]");
}
return vt.ToString().Trim();
}
return base.ToString();
}
#region ICloneable Member
public object Clone()
{
// we only have value types as members -> simply use .net base function
return this.MemberwiseClone();
}
#endregion
}
}

View File

@ -0,0 +1,47 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LwipMibCompiler", "LwipMibCompiler\LwipMibCompiler.csproj", "{C25D5640-D999-49BD-82E0-A1975296A91E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LwipSnmpCodeGeneration", "LwipSnmpCodeGeneration\LwipSnmpCodeGeneration.csproj", "{AABCAB90-1540-45D4-A159-14831A54E9A3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CCodeGeneration", "CCodeGeneration\CCodeGeneration.csproj", "{7DA7C0AB-0982-4BF5-9324-F59A7A08D65B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpSnmpLib.Mib", "SharpSnmpLib\SharpSnmpLib.Mib.csproj", "{CBE20411-5DB7-487D-825D-7694267BB6F5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MibViewer", "MibViewer\MibViewer.csproj", "{86CC0B65-7985-4017-A252-0A7A18DCAEF3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7DA7C0AB-0982-4BF5-9324-F59A7A08D65B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7DA7C0AB-0982-4BF5-9324-F59A7A08D65B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7DA7C0AB-0982-4BF5-9324-F59A7A08D65B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7DA7C0AB-0982-4BF5-9324-F59A7A08D65B}.Release|Any CPU.Build.0 = Release|Any CPU
{86CC0B65-7985-4017-A252-0A7A18DCAEF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{86CC0B65-7985-4017-A252-0A7A18DCAEF3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{86CC0B65-7985-4017-A252-0A7A18DCAEF3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{86CC0B65-7985-4017-A252-0A7A18DCAEF3}.Release|Any CPU.Build.0 = Release|Any CPU
{AABCAB90-1540-45D4-A159-14831A54E9A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AABCAB90-1540-45D4-A159-14831A54E9A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AABCAB90-1540-45D4-A159-14831A54E9A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AABCAB90-1540-45D4-A159-14831A54E9A3}.Release|Any CPU.Build.0 = Release|Any CPU
{C25D5640-D999-49BD-82E0-A1975296A91E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C25D5640-D999-49BD-82E0-A1975296A91E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C25D5640-D999-49BD-82E0-A1975296A91E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C25D5640-D999-49BD-82E0-A1975296A91E}.Release|Any CPU.Build.0 = Release|Any CPU
{CBE20411-5DB7-487D-825D-7694267BB6F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CBE20411-5DB7-487D-825D-7694267BB6F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CBE20411-5DB7-487D-825D-7694267BB6F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CBE20411-5DB7-487D-825D-7694267BB6F5}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = LwipMibCompiler\LwipMibCompiler.csproj
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{C25D5640-D999-49BD-82E0-A1975296A91E}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>LwipMibCompiler</RootNamespace>
<AssemblyName>LwipMibCompiler</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisIgnoreBuiltInRuleSets>false</CodeAnalysisIgnoreBuiltInRuleSets>
<CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>
<WarningLevel>4</WarningLevel>
<Optimize>false</Optimize>
<UseVSHostingProcess>false</UseVSHostingProcess>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<UseVSHostingProcess>false</UseVSHostingProcess>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CCodeGeneration\CCodeGeneration.csproj">
<Project>{7DA7C0AB-0982-4BF5-9324-F59A7A08D65B}</Project>
<Name>CCodeGeneration</Name>
</ProjectReference>
<ProjectReference Include="..\LwipSnmpCodeGeneration\LwipSnmpCodeGeneration.csproj">
<Project>{AABCAB90-1540-45D4-A159-14831A54E9A3}</Project>
<Name>LwipSnmpCodeGeneration</Name>
</ProjectReference>
<ProjectReference Include="..\SharpSnmpLib\SharpSnmpLib.Mib.csproj">
<Project>{CBE20411-5DB7-487D-825D-7694267BB6F5}</Project>
<Name>SharpSnmpLib.Mib</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,480 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Martin Hentschel <info@cl-soft.de>
*
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;
using CCodeGeneration;
using Lextm.SharpSnmpLib.Mib;
using Lextm.SharpSnmpLib.Mib.Elements.Entities;
using Lextm.SharpSnmpLib.Mib.Elements.Types;
using LwipSnmpCodeGeneration;
namespace LwipMibCompiler
{
class Program
{
private static readonly Regex _alphaNumericRegex = new Regex("[^a-zA-Z0-9]");
static void Main(string[] args)
{
Console.WriteLine("lwIP MIB Compiler");
Console.WriteLine("");
// check args
if ((args.Length < 2) || String.IsNullOrWhiteSpace(args[0]) || String.IsNullOrWhiteSpace(args[1]))
{
PrintUsage();
return;
}
string mibFile = args[0];
if (!File.Exists(mibFile))
{
Console.WriteLine(String.Format("Unable to find file '{0}'!", mibFile));
}
string destFile = args[1];
string destHeaderFile;
if (Directory.Exists(destFile))
{
// only directory passed -> create dest filename from mib filename
string mibFileName = Path.GetFileNameWithoutExtension(mibFile).ToLowerInvariant();
destFile = Path.Combine(destFile, mibFileName + ".c");
}
string destFileExt = Path.GetExtension(destFile);
if (!String.IsNullOrEmpty(destFileExt))
{
destHeaderFile = destFile.Substring(0, destFile.Length - destFileExt.Length);
}
else
{
destHeaderFile = destFile;
}
destHeaderFile += ".h";
for (int i=2; i<args.Length; i++)
{
if (!String.IsNullOrWhiteSpace(args[i]) && Directory.Exists(args[i]))
{
MibTypesResolver.RegisterResolver(new FileSystemMibResolver(args[i], true));
}
}
// read and resolve MIB
Console.WriteLine(" Reading MIB file...");
MibDocument md = new MibDocument(mibFile);
MibTypesResolver.ResolveTypes(md.Modules[0]);
MibTree mt = new MibTree(md.Modules[0] as MibModule);
if (mt.Root.Count == 0)
{
Console.WriteLine("No root element found inside MIB!");
return;
}
MibCFile generatedFile = new MibCFile();
MibHeaderFile generatedHeaderFile = new MibHeaderFile();
foreach (MibTreeNode mibTreeNode in mt.Root)
{
// create LWIP object tree from MIB structure
Console.WriteLine(" Creating lwIP object tree " + mibTreeNode.Entity.Name);
SnmpMib snmpMib = new SnmpMib();
snmpMib.Oid = mibTreeNode.Entity.Value;
snmpMib.BaseOid = MibTypesResolver.ResolveOid(mibTreeNode.Entity).GetOidValues();
snmpMib.Name = mibTreeNode.Entity.Name;
ProcessMibTreeNode(mibTreeNode, snmpMib);
// let the tree transform itself depending on node structure
snmpMib.Analyze();
if (snmpMib.ChildNodes.Count != 0)
{
// generate code from LWIP object tree
Console.WriteLine(" Generating code " + snmpMib.Name);
snmpMib.Generate(generatedFile, generatedHeaderFile);
}
}
string preservedCode = MibCFile.GetPreservedCode(destFile);
if (!string.IsNullOrEmpty(preservedCode))
{
generatedFile.PreservedCode.Add(new PlainText(preservedCode));
}
else
{
generatedFile.PreservedCode.AddRange(generatedFile.Implementation);
}
generatedFile.Implementation.Clear();
using (StreamWriter fileWriter = new StreamWriter(destHeaderFile))
{
CGenerator cGenerator = new CGenerator(fileWriter, destHeaderFile, 3, " ", Environment.NewLine);
generatedHeaderFile.Save(cGenerator);
}
using (StreamWriter fileWriter = new StreamWriter(destFile))
{
CGenerator cGenerator = new CGenerator(fileWriter, destFile, 3, " ", Environment.NewLine);
generatedFile.Save(cGenerator);
}
Console.WriteLine(" Done");
}
private static void PrintUsage()
{
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
string appName = Path.GetFileName(codeBase);
Console.WriteLine("Usage:");
Console.WriteLine(String.Format(" {0} <source MIB file> <dest C file> [<search path 1 for referred MIB's> <search path 2 for referred MIB's> ...]", appName));
Console.WriteLine("");
Console.WriteLine(" <source MIB file>");
Console.WriteLine(" Path and filename of MIB file to convert.");
Console.WriteLine("");
Console.WriteLine(" <dest C file>");
Console.WriteLine(" Destination path and file. If a path is passed only, filename is auto");
Console.WriteLine(" generated from MIB file name.");
Console.WriteLine("");
Console.WriteLine(" <search path X for referred MIB's>");
Console.WriteLine(" It's important to provide all referred MIB's in order to correctly ");
Console.WriteLine(" resolve all used types.");
Console.WriteLine("");
}
#region Generation of LWIP Object Tree
private static void ProcessMibTreeNode(MibTreeNode mibTreeNode, SnmpTreeNode assignedSnmpNode)
{
foreach (MibTreeNode mtn in mibTreeNode.ChildNodes)
{
// in theory container nodes may also be scalars or tables at the same time (for now only process real containers)
if (mtn.NodeType == MibTreeNodeType.Container)
{
SnmpTreeNode snmpTreeNode = GenerateSnmpTreeNode(mtn, assignedSnmpNode);
assignedSnmpNode.ChildNodes.Add(snmpTreeNode);
ProcessMibTreeNode(mtn, snmpTreeNode);
}
else if ((mtn.NodeType & MibTreeNodeType.Scalar) != 0)
{
SnmpScalarNode snmpScalarNode = GenerateSnmpScalarNode(mtn, assignedSnmpNode);
if (snmpScalarNode != null)
{
assignedSnmpNode.ChildNodes.Add(snmpScalarNode);
}
}
else if ((mtn.NodeType & MibTreeNodeType.Table) != 0)
{
SnmpTableNode snmpTableNode = GenerateSnmpTableNode(mtn, assignedSnmpNode);
if (snmpTableNode != null)
{
assignedSnmpNode.ChildNodes.Add(snmpTableNode);
}
}
}
}
private static SnmpTreeNode GenerateSnmpTreeNode(MibTreeNode mibTreeNode, SnmpTreeNode parentNode)
{
SnmpTreeNode result = new SnmpTreeNode(parentNode);
result.Name = _alphaNumericRegex.Replace (mibTreeNode.Entity.Name, "");
result.Oid = mibTreeNode.Entity.Value;
result.FullOid = MibTypesResolver.ResolveOid(mibTreeNode.Entity).GetOidString();
return result;
}
private static SnmpScalarNode GenerateSnmpScalarNode(MibTreeNode mibTreeNode, SnmpTreeNode parentNode, bool ignoreAccessibleFlag = false)
{
ObjectType ote = mibTreeNode.Entity as ObjectType;
if (ote != null)
{
return GenerateSnmpScalarNode(ote, parentNode, ignoreAccessibleFlag);
}
return null;
}
private static SnmpScalarNode GenerateSnmpScalarNode(ObjectType ote, SnmpTreeNode parentNode, bool ignoreAccessibleFlag = false)
{
SnmpScalarNode result;
ITypeAssignment mibType = ote.BaseType;
IntegerType it = (mibType as IntegerType);
if (it != null)
{
if (ote.ReferredType.Name == Symbol.TruthValue.ToString())
{
result = new SnmpScalarNodeTruthValue(parentNode);
}
else if ((it.Type == IntegerType.Types.Integer) || (it.Type == IntegerType.Types.Integer32))
{
result = new SnmpScalarNodeInt(parentNode);
}
else
{
Console.WriteLine(String.Format("Unsupported IntegerType '{0}'!", it.Type));
return null;
}
if (it.IsEnumeration)
{
result.Restrictions.AddRange(CreateRestrictions(it.Enumeration));
}
else
{
result.Restrictions.AddRange(CreateRestrictions(it.Ranges));
}
}
else
{
UnsignedType ut = (mibType as UnsignedType);
if (ut != null)
{
if ((ut.Type == UnsignedType.Types.Unsigned32) ||
(ut.Type == UnsignedType.Types.Gauge32))
{
result = new SnmpScalarNodeUint(SnmpDataType.Gauge, parentNode);
}
else if (ut.Type == UnsignedType.Types.Counter32)
{
result = new SnmpScalarNodeUint(SnmpDataType.Counter, parentNode);
}
else if (ut.Type == UnsignedType.Types.TimeTicks)
{
result = new SnmpScalarNodeUint(SnmpDataType.TimeTicks, parentNode);
}
else if (ut.Type == UnsignedType.Types.Counter64)
{
result = new SnmpScalarNodeCounter64(parentNode);
if ((ut.Ranges != null) && (ut.Ranges.Count > 0))
{
Console.WriteLine(String.Format("Generation of ranges is not supported for Counter64 type!"));
return null;
}
}
else
{
Console.WriteLine(String.Format("Unsupported UnsignedType '{0}'!", ut.Type));
return null;
}
result.Restrictions.AddRange(CreateRestrictions(ut.Ranges));
}
else if (mibType is IpAddressType)
{
result = new SnmpScalarNodeOctetString(SnmpDataType.IpAddress, parentNode);
result.Restrictions.AddRange(CreateRestrictions((mibType as OctetStringType).Size));
}
else if (mibType is OpaqueType)
{
result = new SnmpScalarNodeOctetString(SnmpDataType.Opaque, parentNode);
result.Restrictions.AddRange(CreateRestrictions((mibType as OctetStringType).Size));
}
else if (mibType is OctetStringType)
{
result = new SnmpScalarNodeOctetString(SnmpDataType.OctetString, parentNode);
result.Restrictions.AddRange(CreateRestrictions((mibType as OctetStringType).Size));
}
else if (mibType is ObjectIdentifierType)
{
result = new SnmpScalarNodeObjectIdentifier(parentNode);
}
else if (mibType is BitsType)
{
result = new SnmpScalarNodeBits(parentNode, (uint)((mibType as BitsType).Map.GetHighestValue() + 1));
result.Restrictions.AddRange(CreateRestrictions(mibType as BitsType));
}
else
{
TypeAssignment ta = mibType as TypeAssignment;
if (ta != null)
{
Console.WriteLine(String.Format("Unsupported BaseType: Module='{0}', Name='{1}', Type='{2}'!", ta.Module.Name, ta.Name, ta.Type));
}
else
{
Console.WriteLine(String.Format("Unsupported BaseType: Module='{0}', Name='{1}'!", mibType.Module, mibType.Name));
}
return null;
}
}
result.Name = _alphaNumericRegex.Replace(ote.Name, "");
result.Oid = ote.Value;
if (ote.Access == MaxAccess.readWrite)
{
result.AccessMode = SnmpAccessMode.ReadWrite;
}
else if (ote.Access == MaxAccess.readOnly)
{
result.AccessMode = SnmpAccessMode.ReadOnly;
}
else if (ote.Access == MaxAccess.readCreate)
{
result.AccessMode = SnmpAccessMode.ReadOnly;
}
else if (ignoreAccessibleFlag && (ote.Access == MaxAccess.notAccessible))
{
result.AccessMode = SnmpAccessMode.NotAccessible;
}
else
{
// not accessible or unsupported access type
return null;
}
return result;
}
private static IEnumerable<IRestriction> CreateRestrictions(ValueRanges ranges)
{
List<IRestriction> result = new List<IRestriction>();
if (ranges != null)
{
foreach (ValueRange range in ranges)
{
if (!range.End.HasValue)
{
result.Add(new IsEqualRestriction(range.Start));
}
else
{
result.Add(new IsInRangeRestriction(range.Start, range.End.Value));
}
}
}
return result;
}
private static IEnumerable<IRestriction> CreateRestrictions(ValueMap map)
{
if ((map != null) && (map.Count > 0))
{
return CreateRestrictions(map.GetContinousRanges());
}
return new List<IRestriction>();
}
private static IEnumerable<IRestriction> CreateRestrictions(BitsType bt)
{
List<IRestriction> result = new List<IRestriction>();
if ((bt != null) && (bt.Map != null))
{
result.Add(new BitMaskRestriction(bt.Map.GetBitMask()));
}
return result;
}
private static SnmpTableNode GenerateSnmpTableNode(MibTreeNode mibTreeNode, SnmpTreeNode parentNode)
{
SnmpTableNode result = new SnmpTableNode(parentNode);
result.Name = mibTreeNode.Entity.Name;
result.Oid = mibTreeNode.Entity.Value;
// expect exactly one row entry
if ((mibTreeNode.ChildNodes.Count != 1) || ((mibTreeNode.ChildNodes[0].NodeType & MibTreeNodeType.TableRow) == 0) || (mibTreeNode.ChildNodes[0].Entity.Value != 1))
{
Console.WriteLine("Found table with unsupported properties! Table needs exactly one (fixed) TableRow with OID=1 ! (" + mibTreeNode.Entity.Name + ")");
return null;
}
MibTreeNode rowNode = mibTreeNode.ChildNodes[0];
ObjectType rot = rowNode.Entity as ObjectType;
if (rot != null)
{
if (!String.IsNullOrWhiteSpace(rot.Augments))
{
result.AugmentedTableRow = rot.Augments;
// the indices from another table shall be used because this table is only an extension of it
rot = MibTypesResolver.ResolveDeclaration(rot.Module, rot.Augments) as ObjectType;
}
if (rot.Indices != null)
{
foreach (string index in rot.Indices)
{
ObjectType indexEntity = MibTypesResolver.ResolveDeclaration(rot.Module, index) as ObjectType;
if (indexEntity == null)
{
Console.WriteLine(String.Format("Could not resolve index '{0}' for table '{1}'! Table omitted!", index, result.Name));
return null;
}
result.IndexNodes.Add(GenerateSnmpScalarNode(indexEntity, parentNode, ignoreAccessibleFlag: true));
}
}
}
if (result.IndexNodes.Count == 0)
{
// a table cannot be used without index
Console.WriteLine("Found table without any index column ! (" + mibTreeNode.Entity.Name + ")");
return null;
}
// add child nodes
foreach (MibTreeNode cellNode in rowNode.ChildNodes)
{
SnmpScalarNode ssn = GenerateSnmpScalarNode(cellNode, parentNode);
if (ssn != null)
{
result.CellNodes.Add(ssn);
}
}
return result;
}
#endregion
}
}

Some files were not shown because too many files have changed in this diff Show More