/* StarForth — Steady-State Virtual Machine Runtime Copyright (c) 2023–2025 Robert A. James All rights reserved. This file is part of the StarForth project. Licensed under the StarForth License, Version 1.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at: https://github.com/star.4th@proton.me/StarForth/LICENSE.txt This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and noninfringement. See the License for the specific language governing permissions and limitations under the License. */ /** * vm_uuid.c - 128-bit VM identifiers (FABRIC-0.md punch list item 3.8) * * See vm_uuid.h for the design rationale (no RNG source exists on any of * the three ISAs uniformly, so this is deterministic, not random). */ #include "starkernel/vm_uuid.h" #ifdef __STARKERNEL__ #include #define VM_UUID_POOL_SIZE 16 static uint64_t vm_uuid_prng_state = 0; static int vm_uuid_seeded = 0; static VMUuid vm_uuid_pool[VM_UUID_POOL_SIZE]; static size_t vm_uuid_pool_pos = VM_UUID_POOL_SIZE; /* "empty": first next() call refills */ VMUuid vm_uuid_hera(void) { VMUuid id; id.hi = 0; id.lo = 0; return id; } int vm_uuid_is_hera(VMUuid id) { return id.hi == 0 && id.lo == 0; } VMUuid vm_uuid_none(void) { VMUuid id; id.hi = 0xFFFFFFFFFFFFFFFFULL; id.lo = 0xFFFFFFFFFFFFFFFFULL; return id; } int vm_uuid_is_none(VMUuid id) { return id.hi == 0xFFFFFFFFFFFFFFFFULL && id.lo == 0xFFFFFFFFFFFFFFFFULL; } int vm_uuid_equal(VMUuid a, VMUuid b) { return a.hi == b.hi && a.lo == b.lo; } /* splitmix64 -- public-domain, well-known, minimal. Deterministic given a * seed; not cryptographically random, not claimed to be. */ static uint64_t splitmix64_next(uint64_t *state) { uint64_t z = (*state += 0x9E3779B97F4A7C15ULL); z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9ULL; z = (z ^ (z >> 27)) * 0x94D049BB133111EBULL; return z ^ (z >> 31); } static void vm_uuid_pool_refill(void) { size_t i; for (i = 0; i < VM_UUID_POOL_SIZE; i++) { uint64_t hi = splitmix64_next(&vm_uuid_prng_state); uint64_t lo = splitmix64_next(&vm_uuid_prng_state); /* RFC 4122 version 4 / variant bits -- cosmetic shape only, not a * claim these are cryptographically random. */ hi = (hi & 0xFFFFFFFFFFFF0FFFULL) | 0x0000000000004000ULL; lo = (lo & 0x3FFFFFFFFFFFFFFFULL) | 0x8000000000000000ULL; vm_uuid_pool[i].hi = hi; vm_uuid_pool[i].lo = lo; } vm_uuid_pool_pos = 0; } void vm_uuid_pool_init(uint64_t seed) { vm_uuid_prng_state = seed; vm_uuid_seeded = 1; vm_uuid_pool_refill(); } VMUuid vm_uuid_next(void) { VMUuid id; if (!vm_uuid_seeded) { /* Safety net, not the intended path -- callers should seed from the * Mama capsule's content hash before the first non-Hera VM birth. */ vm_uuid_pool_init(0x9E3779B97F4A7C15ULL); } if (vm_uuid_pool_pos >= VM_UUID_POOL_SIZE) { vm_uuid_pool_refill(); } id = vm_uuid_pool[vm_uuid_pool_pos]; vm_uuid_pool_pos++; return id; } void vm_uuid_format(VMUuid id, char *buf) { static const char hex[] = "0123456789abcdef"; int pos = 0; int i; uint64_t halves[2]; /* Group boundaries per RFC 4122: 8-4-4-4-12 hex digits, dashes after * digit 8, 12, 16, 20 (of 32 total). hi supplies digits 0-15, lo * supplies digits 16-31. */ halves[0] = id.hi; halves[1] = id.lo; for (i = 0; i < 32; i++) { uint64_t v = (i < 16) ? halves[0] : halves[1]; int shift = (15 - (i % 16)) * 4; buf[pos++] = hex[(v >> shift) & 0xF]; if (i == 7 || i == 11 || i == 15 || i == 19) buf[pos++] = '-'; } buf[pos] = '\0'; } #endif /* __STARKERNEL__ */