Files
bare-operating-system/packages/bare-os-booter/lib/boot/bare-os-kernel-loader.js
T
2026-08-18 18:11:28 -04:00

440 lines
13 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import b4a from 'b4a'
import Hyperdrive from 'hyperdrive'
import { parseMbr } from 'bare-os-protocol'
import {
getKernelCapabilityWords,
readKernelCapabilityWord,
BARE_OS_KERNEL_FEATURE_BITS_DOC,
BARE_OS_KERNEL_CAPABILITY_WIRE_VERSION,
BARE_OS_KERNEL_CAPABILITY_WORDS_JSON_KEY,
BARE_OS_KERNEL_FEATURES_STOCK_WORD_PRIMARY
} from 'bare-os-protocol'
import {
KERNEL_CAPABILITY_SEED_STRICT_ROWS,
buildStockKernelCapabilityWords
} from './bare-os-capability-registry.js'
import { maybeSynthesizePeerSeedCapabilityInfo } from './bare-os-peer-system-seed.js'
/** Splash lines while block 0 / MBR is in flight (avoids a silent multiminute wait). */
const MBR_READ_HEARTBEAT_MS = 10_000
/**
* @param {import('./swarm-disk.js').SwarmDisk} disk
* @param {{ log: (s: string) => void }} splash
*/
async function readBlock0WithProgress(disk, splash) {
const iv = setInterval(() => {
const n = disk.peers?.size ?? 0
splash.log(
n > 0
? `MBR: still waiting for block 0 (${n} peer${n === 1 ? '' : 's'} connected)…`
: 'MBR: no Hyperswarm peers yet — run the system seeder or check network / HYPERSWARM_BOOTSTRAP'
)
}, MBR_READ_HEARTBEAT_MS)
try {
return await disk.read(0)
} finally {
clearInterval(iv)
}
}
/**
* @param {import('corestore').default} store
* @param {import('hyperswarm').default} swarm
* @param {typeof Hyperdrive} HyperdriveCtor
* @param {import('./swarm-disk.js').SwarmDisk} disk
* @param {ReturnType<import('./boot-splash.js').createBootSplash>} splash
* @param {string} keyHex
* @returns {Promise<Uint8Array>}
*/
export async function loadOsFromOfflineLkg(
store,
swarm,
HyperdriveCtor,
disk,
splash,
keyHex
) {
const hostEnv = globalThis.process?.env
splash.setPhase('Offline LKG: opening system Hyperdrive…')
const hex = String(keyHex).replace(/^0x/i, '').toLowerCase().trim()
let key
try {
key = b4a.from(hex, 'hex')
} catch {
throw new Error('BARE_OS_LKG_SYSTEM_KEY_HEX: invalid hex')
}
if (key.length !== 32) {
throw new Error(
'BARE_OS_LKG_SYSTEM_KEY_HEX: expected 32-byte Hyperdrive key (64 hex chars)'
)
}
disk.drive = new HyperdriveCtor(store, key)
await disk.drive.ready()
disk.mbrKeysHex = [hex]
swarm.join(disk.drive.discoveryKey)
try {
await swarm.flush()
} catch {
/* ignore */
}
disk.seedCapabilityInfo = {
role: 'offline-lkg',
doc: BARE_OS_KERNEL_FEATURE_BITS_DOC,
featureBitsDoc: BARE_OS_KERNEL_FEATURE_BITS_DOC,
kernelCapabilityWireVersion: BARE_OS_KERNEL_CAPABILITY_WIRE_VERSION,
[BARE_OS_KERNEL_CAPABILITY_WORDS_JSON_KEY]: buildStockKernelCapabilityWords(
BARE_OS_KERNEL_FEATURES_STOCK_WORD_PRIMARY
),
protocol: 'bare-os-v1',
note: 'offline boot; bare_os.capabilities RPC not used'
}
let initSource = null
splash.setPhase('Offline LKG: resolving /boot/init.js…')
for (let i = 0; i < 90; i++) {
initSource = await disk.drive.get('/boot/init.js')
if (initSource) break
await new Promise((r) => setTimeout(r, 200))
}
if (!initSource) {
throw new Error(
'Offline LKG: /boot/init.js missing in local Corestore — boot online once to replicate'
)
}
const lazyPd =
hostEnv?.BARE_OS_LAZY_PERSONAL_DRIVE === '1' ||
hostEnv?.BARE_OS_LAZY_PERSONAL_DRIVE === 'true'
if (!lazyPd) {
splash.setPhase('Mounting personal Hyperdrive…')
await disk.initPersonalDrive(store, swarm, HyperdriveCtor)
splash.log('Personal drive ready')
}
splash.setPhase('Starting shell…')
splash.prepareForKernel()
return initSource
}
/**
* Network + drive setup only (must finish within boot timeout). Does not run the
* interactive kernel — that can take arbitrarily long.
* @returns {Promise<Uint8Array>}
*/
export async function loadOsFromPeers(disk, store, swarm, splash) {
const hostEnv = globalThis.process?.env
const skipCap =
hostEnv?.BARE_OS_SEED_RPC_HANDSHAKE === '0' ||
hostEnv?.BARE_OS_SEED_RPC_HANDSHAKE === 'false'
if (!skipCap && disk.peers.size > 0) {
splash.setPhase('Seed capability handshake…')
try {
const cap = await disk.rpc('bare_os', 'capabilities', [], 4000)
disk.seedCapabilityInfo =
cap && typeof cap === 'object' ? cap : { raw: cap }
const strict =
hostEnv?.BARE_OS_SEED_CAP_STRICT === '1' ||
hostEnv?.BARE_OS_SEED_CAP_STRICT === 'true'
if (strict) {
const words = getKernelCapabilityWords(cap)
if (!words) {
throw new Error(
'BARE_OS_SEED_CAP_STRICT: seeder capabilities missing kernelCapabilityWords (wire v2)'
)
}
for (const [key, need] of KERNEL_CAPABILITY_SEED_STRICT_ROWS) {
const got = readKernelCapabilityWord(words, key) >>> 0
const n = need >>> 0
if ((got & n) !== n) {
throw new Error(
`BARE_OS_SEED_CAP_STRICT: seeder kernelCapabilityWords.${key} does not cover stock booter requirements`
)
}
}
}
try {
disk.seedReplicationStatus = await disk.rpc(
'bare_os',
'replication_status',
[],
3000
)
} catch {
disk.seedReplicationStatus = null
}
try {
disk.seedManifestHints = await disk.rpc(
'bare_os',
'manifest_hints',
[],
3000
)
} catch {
disk.seedManifestHints = null
}
try {
disk.seedPeerHealth = await disk.rpc('bare_os', 'peer_health', [], 3000)
} catch {
disk.seedPeerHealth = null
}
try {
disk.seedStagingSlot = await disk.rpc(
'bare_os',
'staging_slot',
[],
3000
)
} catch {
disk.seedStagingSlot = null
}
try {
disk.seedReplicationQueue = await disk.rpc(
'bare_os',
'replication_queue',
[],
3000
)
} catch {
disk.seedReplicationQueue = null
}
try {
disk.seedCapabilityAttestation = await disk.rpc(
'bare_os',
'capability_attestation',
[],
3000
)
} catch {
disk.seedCapabilityAttestation = null
}
try {
disk.seedMbrLayout = await disk.rpc('bare_os', 'mbr_layout', [], 3000)
} catch {
disk.seedMbrLayout = null
}
try {
disk.seedSnapshotHints = await disk.rpc(
'bare_os',
'snapshot_hints',
[],
3000
)
} catch {
disk.seedSnapshotHints = null
}
try {
disk.seedPeerFirewallStats = await disk.rpc(
'bare_os',
'peer_firewall_stats',
[],
3000
)
} catch {
disk.seedPeerFirewallStats = null
}
try {
disk.seedReplicationPlan = await disk.rpc(
'bare_os',
'replication_plan',
[],
2000
)
} catch {
disk.seedReplicationPlan = null
}
try {
disk.seedDhtBootstrapHint = await disk.rpc(
'bare_os',
'dht_bootstrap_hint',
[],
2000
)
} catch {
disk.seedDhtBootstrapHint = null
}
try {
disk.seedSnapshotChain = await disk.rpc(
'bare_os',
'snapshot_chain',
[],
2000
)
} catch {
disk.seedSnapshotChain = null
}
try {
disk.seedMirrorCompactionHint = await disk.rpc(
'bare_os',
'mirror_compaction_hint',
[],
2000
)
} catch {
disk.seedMirrorCompactionHint = null
}
try {
disk.seedUpdaterState = await disk.rpc(
'bare_os',
'updater_state',
[],
2000
)
} catch {
disk.seedUpdaterState = null
}
try {
disk.seedBlindPeerTopologyV2 = await disk.rpc(
'bare_os',
'blind_peer_topology_v2',
[],
2000
)
} catch {
disk.seedBlindPeerTopologyV2 = null
}
try {
disk.seedCompactPing = await disk.rpc(
'bare_os',
'compact_ping',
[],
1500
)
} catch {
disk.seedCompactPing = null
}
const wave7Rpc = [
['corestore_stats', 'seedCorestoreStats'],
['snapshot_manifest_slice', 'seedSnapshotManifestSlice'],
['mirror_drive_hint_v2', 'seedMirrorDriveHintV2'],
['hrpc_registry_summary', 'seedHrpcRegistrySummary'],
['protomux_capability_ad', 'seedProtomuxCapabilityAd'],
['dht_address_book', 'seedDhtAddressBook'],
['replication_throttle_hint', 'seedReplicationThrottleHint'],
['bundlebee_stage', 'seedBundlebeeStage'],
['http_dht_proxy_hint', 'seedHttpDhtProxyHint']
]
const wave8Rpc = [
['protomux_rpc_pool_hint', 'seedProtomuxRpcPoolHint'],
['hyperblob_store_hint', 'seedHyperblobStoreHint'],
['signing_request_queue_hint', 'seedSigningRequestQueueHint'],
['core_storage_layout_hint', 'seedCoreStorageLayoutHint'],
['mirror_drive_compaction_v3', 'seedMirrorDriveCompactionV3'],
['bundlebee_cli_stage', 'seedBundlebeeCliStage'],
['ready_guard_v2', 'seedReadyGuardV2'],
['blind_relay_circuit_hint', 'seedBlindRelayCircuitHint'],
['http_dht_proxy_routes', 'seedHttpDhtProxyRoutes']
]
const denyRpcRaw = String(
hostEnv?.BARE_OS_BOOT_POLICY_DENY_SEED_RPC_METHODS ?? ''
).trim()
const denyRpc = new Set(
denyRpcRaw
.split(/[\s,]+/)
.map((s) => s.trim())
.filter(Boolean)
)
for (const [method, key] of [...wave7Rpc, ...wave8Rpc]) {
if (denyRpc.has(method)) {
disk[key] = null
continue
}
try {
disk[key] = await disk.rpc('bare_os', method, [], 2000)
} catch {
disk[key] = null
}
}
} catch (e) {
disk.seedCapabilityInfo = { error: (e && e.message) || String(e) }
if (
hostEnv?.BARE_OS_SEED_CAP_FAIL === '1' ||
hostEnv?.BARE_OS_SEED_CAP_FAIL === 'true'
) {
throw e
}
}
}
splash.setPhase('Reading MBR from swarm…')
const mbrMaxAttempts = 6
const mbrRetryDelayMs = 400
let mbr = /** @type {Uint8Array | null} */ (null)
/** @type {Uint8Array[] | null} */
let mbrKeys = null
let lastMbrErr = ''
for (let attempt = 1; attempt <= mbrMaxAttempts; attempt++) {
try {
splash.log(
attempt === 1
? 'Loading block 0 (MBR)'
: `MBR read retry ${attempt - 1}/${mbrMaxAttempts - 1}…`
)
const block = await readBlock0WithProgress(disk, splash)
const { keys } = parseMbr(block)
if (!keys.length) throw new Error('MBR has no drive keys')
mbr = block
mbrKeys = keys
lastMbrErr = ''
break
} catch (e) {
lastMbrErr = (e && e.message) || String(e)
splash.log(`MBR read failed (${attempt}/${mbrMaxAttempts}): ${lastMbrErr}`)
if (attempt < mbrMaxAttempts) {
await new Promise((r) => setTimeout(r, mbrRetryDelayMs))
}
}
}
if (!mbr || !mbrKeys) {
throw new Error(
'MBR unavailable after ' + mbrMaxAttempts + ' attempts: ' + lastMbrErr
)
}
disk.mbrKeysHex = mbrKeys.map((k) => b4a.toString(k, 'hex'))
disk.bootMbr512 = new Uint8Array(mbr)
let initSource = null
for (const driveKey of mbrKeys) {
try {
const hex = b4a.toString(driveKey, 'hex')
splash.setPhase('Opening system Hyperdrive…')
splash.log(`Drive key ${hex.slice(0, 16)}…`)
disk.drive = new Hyperdrive(store, driveKey)
await disk.drive.ready()
splash.setPhase('Replicating with peers…')
for (const peer of disk.peers) {
disk.drive.replicate(peer.mux.stream, { live: true, download: true })
}
swarm.join(disk.drive.discoveryKey)
const done = disk.drive.findingPeers()
swarm.flush().then(done, done)
splash.setPhase('Downloading /boot/init.js…')
for (let i = 0; i < 30; i++) {
initSource = await disk.drive.get('/boot/init.js')
if (initSource) break
await new Promise((r) => setTimeout(r, 200))
}
if (initSource) break
splash.log('Kernel not on this key — trying next MBR entry')
} catch (err) {
splash.log(`Drive error: ${err?.message ?? err}`)
}
}
if (!initSource) throw new Error('Kernel not found after replication')
maybeSynthesizePeerSeedCapabilityInfo(disk, hostEnv)
const lazyPd =
hostEnv?.BARE_OS_LAZY_PERSONAL_DRIVE === '1' ||
hostEnv?.BARE_OS_LAZY_PERSONAL_DRIVE === 'true'
if (!lazyPd) {
splash.setPhase('Mounting personal Hyperdrive…')
await disk.initPersonalDrive(store, swarm, Hyperdrive)
splash.log('Personal drive ready')
}
splash.setPhase('Starting shell…')
splash.prepareForKernel()
return initSource
}