import assert from 'node:assert/strict'; import { spawn, spawnSync } from 'node:child_process'; import { randomBytes } from 'node:crypto'; import { copyFileSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; import { dirname, join, relative, resolve } from 'node:path'; import { tmpdir } from 'node:os'; import { fileURLToPath } from 'node:url'; import { setTimeout as delay } from 'node:timers/promises'; import { stopDisposableChild, withDeadline } from '../disposable-child.mjs'; import { frozenSnapshot, hashAt } from './boot-contract-report.mjs'; import { qmpConnect } from './entry-qmp.mjs'; import {createK1080Wait as createRunqueue,k1080WaitInputs as runqueueInputs,k1080WaitManifest as runqueueManifest} from './k1080-wait-overlay.mjs'; import {prepareSchedulerCheck} from './locking-scheduler-check.mjs'; import { metadataCaptures } from './frame-metadata-report.mjs'; import { buddyCaptures } from './buddy-report.mjs'; import { heapCaptures } from './heap-report.mjs'; import {inspectThreadsHost} from './threads-host-report.mjs'; import {inspectThreadsGuardHost} from './threads-guard-host-report.mjs'; import {inspectDeferredWorkReport} from './deferred-work-report.mjs'; import {clockStages,clockCaptures,clockCheckpointPhysicalCaptures} from './clock-proof.mjs'; import {inspectPageFaultsReport,pageFaultsCaptures,pageFaultsCheckpointCaptures} from './page-faults-report.mjs'; import { inspectPageTablesReport,pageTablesCaptures } from './page-tables-report.mjs'; import { dmaCaptures } from './dma-report.mjs'; import { inspectAddressSpacesReport,addressSpacesCaptures } from './address-spaces-report.mjs'; import { inspectMappingReport,mappingCaptures } from './mapping-report.mjs'; import {inspectUserCopyReport,userCopyCaptures}from'./user-copy-report.mjs'; import {inspectExceptionsReport,exceptionsCaptures} from './exceptions-report.mjs'; import {inspectContextSwitchReport,inspectContextSwitchSerial,contextSwitchCases,contextSwitchSymbolNames,contextSwitchPhysicalCaptures,contextSwitchLocalMoves,contextSwitchBoundary} from './context-switch-report.mjs'; import {inspectThreadsReport} from './threads-report.mjs'; import {contextSwitchStages,contextSwitchCaptures,contextSwitchCheckpointPhysicalCaptures} from './context-switch-proof.mjs'; import {contextPriorBinding} from './context-switch-prior-binding.mjs'; import {runqueueStackBounds} from './runqueue-stack-bounds.mjs'; import {runqueueBootstrapStackBounds,runqueueBootstrapStackBinding} from './runqueue-bootstrap-stack-binding.mjs'; import {runqueueStages,runqueueCaptures,runqueueCheckpointPhysicalCaptures} from './runqueue-proof.mjs'; import {runqueuePriorBinding} from './runqueue-prior-binding.mjs'; import {inspectRunqueueReport,inspectRunqueueSerial,runqueueCases,runqueueSymbolNames,runqueuePhysicalCaptures,runqueueLocalMoves,runqueueBoundary} from './runqueue-report.mjs'; import {inspectRunqueueHost} from './runqueue-host-report.mjs'; import {inspectRunqueueGuestServicesHost} from './runqueue-guest-services-host-report.mjs'; import {inspectRunqueueReturnHost} from './runqueue-return-host-report.mjs'; import {inspectRunqueueGuestWakeHost} from './runqueue-guest-wake-host-report.mjs'; import {inspectRunqueueGuestStaleHost} from './runqueue-guest-stale-host-report.mjs'; import {inspectRunqueueImageSpanHost} from './runqueue-image-span-host-report.mjs'; import {inspectRunqueueFileSpanHost} from './runqueue-file-span-host-report.mjs'; import {inspectContextSwitchHost} from './context-switch-host-report.mjs'; import {inspectContextHandoffHost} from './context-handoff-host-report.mjs'; import {inspectContextCompletionHost} from './context-completion-host-report.mjs'; import {inspectContextRetirementHost} from './context-retirement-host-report.mjs'; import {inspectContextInPlaceHost} from './context-in-place-host-report.mjs'; import {inspectContextImageSpanHost} from './context-image-span-host-report.mjs'; import {inspectContextFileSpanHost} from './context-file-span-host-report.mjs'; import {threadsStages,threadsFatalStages,threadsCaptures,threadsCheckpointPhysicalCaptures,threadsFatalPhysicalCaptures} from './threads-proof.mjs'; import {deferredWorkStages,deferredWorkCaptures,deferredWorkCheckpointPhysicalCaptures} from './deferred-work-proof.mjs'; import {deferredPacket} from './deferred-work-network.mjs'; import {lockingStages,lockingCaptures,lockingCheckpointPhysicalCaptures} from './locking-proof.mjs'; import {gicStages,gicCaptures,gicCheckpointPhysicalCaptures} from './gic-proof.mjs'; import {gicBurst} from './gic-network.mjs'; import {k1100PolicyDmaGdbConnect as dmaGdbConnect} from './k1100-policy-dma-gdb.mjs'; import {k1100PolicyMutableSymbols as basePolicySymbols, k1100PolicyStateCaptures as basePolicyCaptures,k1100PolicyStateViews, k1100PolicyPhysicalCaptures} from './k1100-policy-product-proof.mjs'; const k1100PolicyMutableSymbols=[...basePolicySymbols, 'OS_K1090_INVERSION_REPORTED','OS_K1090_BUSY_LOOP_REJECTED', 'OS_K1095_ACCOUNTING_REPORTED','OS_K1095_DOUBLE_CLASS_REJECTED', 'OS_K1100_LATE_WAKE_REFUSALS','OS_K1100_LONG_RUN_REPORTED']; const k1100PolicyStateCaptures=symbols=>[...basePolicyCaptures(symbols), {name:'OS_K1090_INVERSION_REPORTED',val:symbols.OS_K1090_INVERSION_REPORTED.address, size:symbols.OS_K1090_INVERSION_REPORTED.size}, {name:'OS_K1090_BUSY_LOOP_REJECTED',val:symbols.OS_K1090_BUSY_LOOP_REJECTED.address, size:symbols.OS_K1090_BUSY_LOOP_REJECTED.size}, {name:'OS_K1095_ACCOUNTING_REPORTED',val:symbols.OS_K1095_ACCOUNTING_REPORTED.address, size:symbols.OS_K1095_ACCOUNTING_REPORTED.size}, {name:'OS_K1095_DOUBLE_CLASS_REJECTED',val:symbols.OS_K1095_DOUBLE_CLASS_REJECTED.address, size:symbols.OS_K1095_DOUBLE_CLASS_REJECTED.size}, {name:'OS_K1100_LATE_WAKE_REFUSALS',val:symbols.OS_K1100_LATE_WAKE_REFUSALS.address, size:symbols.OS_K1100_LATE_WAKE_REFUSALS.size}, {name:'OS_K1100_LONG_RUN_REPORTED',val:symbols.OS_K1100_LONG_RUN_REPORTED.address, size:symbols.OS_K1100_LONG_RUN_REPORTED.size}]; import {k1100PolicyInputs} from './k1100-policy-overlay.mjs'; import {inspectK1080RecoveryAttestation} from '../../reports/os-implementation/k1080-recovery-report.mjs'; import { dmaNetworkConnect,dmaPacket } from './dma-network.mjs'; import {inspectK1080WaitReport,k1080WaitCases,k1080WaitSymbolNames,k1080WaitPhysicalCaptures,k1080WaitLocalMoves,k1080WaitBoundary} from './k1080-wait-report.mjs'; import {k1080WaitCaptures,k1080WaitCheckpointPlan,k1080WaitCaptureRows,k1080WaitCheckpointPhysicalCaptures} from './k1080-wait-proof.mjs'; import {inspectK1080WaitSerial} from './k1080-wait-prior-serial.mjs'; import {k1080WaitPriorBinding} from './k1080-wait-prior-binding.mjs'; import {nextK1080WaitMarker} from './k1080-wait-serial-cursor.mjs'; import {waitStackBounds as measureWaitStackBounds,waitStackBinding} from './wait-stack-binding.mjs'; import {k1080WaitBatchStackBounds as measureBatchStackBounds,k1080WaitBatchStackBinding} from './k1080-wait-batch-stack-binding.mjs'; import {inspectWaitGuestServicesHost} from './wait-guest-services-host-report.mjs'; import {inspectK1080WaitMainHost} from './k1080-wait-main-host-report.mjs'; import {observeK1080WaitDeferredBatch,k1080WaitDeferredBatchPlan,k1080WaitDeferredBatchLine,k1080WaitDeferredBatchCaptures,inspectK1080WaitDeferredBatches} from './k1080-wait-deferred-handshake.mjs'; import {inspectK1080WaitBatchPlacement} from './k1080-wait-batch-binding.mjs'; const root = resolve(dirname(fileURLToPath(import.meta.url)), '../..'); assert.equal(process.argv.length,3,'usage: node k1080-wait-guests.mjs '); const previousPath=resolve(process.argv[2]); assert.equal(relative(root,previousPath),'reports/os-implementation/K1045-K1060-7GFa7T/report.json'); assert.equal(hashAt(root,relative(root,previousPath)),'adf6405079e3038180fec763764b5d37e4681f479598cc83c4c4874b296429a6'); const canonicalRecovery=JSON.parse(readFileSync(join(root,'reports/os-implementation/K1065-K1080-IwxcBz/recovery-attestation.json'))); inspectK1080RecoveryAttestation(canonicalRecovery,root); const compiledPolicy=JSON.parse(readFileSync(join(root,'reports/os-implementation/K1100-policy-build-preparation-17ZWT1/report.json'))); const spikePath=process.env.TURKOS_K1540_CANDIDATE; assert.ok(spikePath?.startsWith("reports/os-implementation/K1540-partitions-recovery-candidate-")); const spike=JSON.parse(readFileSync(join(root,spikePath))); assert.equal(spike.status,'COMPILED_K1540_PARTITIONS_RECOVERY_CANDIDATE'); for(const artifact of Object.values(spike.artifacts))assert.equal(hashAt(root,artifact.path),artifact.sha256); Object.assign(compiledPolicy.images.product,spike.artifacts); const productBranch=compiledPolicy.branches.find(branch=>branch.profile==='product'); assert.ok(productBranch); productBranch.directory=spike.sourceDirectory; assert.deepEqual(k1100PolicyInputs(root),compiledPolicy.inputsBefore); const protectedBefore = frozenSnapshot(root), inputsBefore = runqueueInputs(root); const parent = join(root, 'reports/os-implementation'); mkdirSync(parent, { recursive: true }); const runDir = mkdtempSync(join(parent, 'K1540-partitions-recovery-matrix-')), runDirectory = relative(root, runDir); const schedulerDirectory=join(runDir,'scheduler-check');mkdirSync(schedulerDirectory);const schedulerPreparation=prepareSchedulerCheck(root,schedulerDirectory); const clean = value => value.split(root).join(''); const artifact = path => ({ path: relative(root, path), sha256: hashAt(root, relative(root, path)) }); const json = (path, value) => writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`); const lifecyclePath=join(runDir,'scoped-lifecycle.json'),lifecycleStartedAt=new Date().toISOString(),lifecycleStart=process.hrtime.bigint(); const ownedGuestChildren=[];let runnerPassed=false,lifecycleFailure=null,guardianSpawned=false; const powerGuardian=spawn('/usr/bin/caffeinate',['-i','-w',String(process.pid)],{stdio:['ignore','ignore','pipe']}); let guardianStderr='';powerGuardian.stderr.on('data',chunk=>{guardianStderr+=chunk;}); const guardianStarted=new Promise((done,fail)=>{powerGuardian.once('spawn',()=>{guardianSpawned=true;done();});powerGuardian.once('error',fail);}); try{ await guardianStarted; const builds = [], branches = [], images = [], loaders = [], symbols = {}, cases = [];let stackBounds,bootstrapStackBounds,waitStackBounds,waitBatchStackBounds; function command(id, executable, argv, env = process.env) { console.log(`RUNQUEUE COMMAND ${id}`); const answer = spawnSync(executable, argv, { cwd: root, encoding: 'utf8', timeout: 120_000, maxBuffer: 40 * 1024 * 1024, env }); const log = join(runDir, `${id}.log`); writeFileSync(log, clean(`${answer.stdout ?? ''}${answer.stderr ?? ''}`)); assert.equal(answer.error, undefined); assert.equal(answer.status, 0, `${id} failed ${relative(root, log)}`); builds.push({ id, executable: clean(executable), argv: argv.map(clean), exitCode: answer.status, log: artifact(log), buildEnv: Object.fromEntries(['RUSTFLAGS', 'TURKOS_RELEASE_IMAGE_BYTES', 'TURKOS_RELEASE_IMAGE_SHA256'].filter(key => env[key] !== undefined).map(key => [key, clean(env[key])])) }); return answer.stdout; } const rustInfo = spawnSync('rustc', ['-vV'], { encoding: 'utf8' }); assert.equal(rustInfo.status, 0); const sysroot = spawnSync('rustc', ['--print', 'sysroot'], { encoding: 'utf8' }); assert.equal(sysroot.status, 0); const llvm = join(sysroot.stdout.trim(), 'lib/rustlib', rustInfo.stdout.match(/^host: (.+)$/m)[1], 'bin'); const target = join(runDir, 'target'), env = { ...process.env, CARGO_TARGET_DIR: target }; delete env.RUSTFLAGS; delete env.CARGO_ENCODED_RUSTFLAGS; delete env.TURKOS_RELEASE_IMAGE_BYTES; delete env.TURKOS_RELEASE_IMAGE_SHA256; const kind='product',selected=compiledPolicy.images.product; for(const key of ['elf','image','nm'])assert.equal(hashAt(root,selected[key].path),selected[key].sha256); const listing=readFileSync(join(root,selected.nm.path),'utf8'); symbols.product=Object.fromEntries([...new Set([...k1080WaitSymbolNames,...k1100PolicyMutableSymbols,'OS_K1100_LANDING_ERROR','OS_K1100_PUBLISHED_CURRENT','OS_K920_RETURN_POOL_GATE','OS_K880_RETURN_POOL_GATE','OS_K900_RETURN_POOL_GATE','OS_K780_RETURN_POOL_GATE','OS_K840_RETURN_POOL_GATE'])].map(name=>{ const match=listing.match(new RegExp('^([a-f0-9]{16}) (?:([a-f0-9]{16}) )?[A-Za-z] '+name+'$','m')); assert.ok(match,'compiled K1100 symbol '+name); return[name,{address:Number.parseInt(match[1],16),size:match[2]?Number.parseInt(match[2],16):null}]; })); for(const[alias,suffix,size]of [['legacyIrqActive','18OS_K660_IRQ_ACTIVE',4],['legacyIrqLast','24OS_K660_IRQ_LAST_COUNTER',8],['centralAuthorityIssuer','21OS_FRAME_AUTHORITY_ID',4]]){ const rows=listing.split(String.fromCharCode(10)).map(line=>line.match(new RegExp('^([a-f0-9]{16}) ([a-f0-9]{16}) [A-Za-z] (_RN.+'+suffix+')$'))).filter(Boolean); assert.equal(rows.length,1);assert.equal(Number.parseInt(rows[0][2],16),size); symbols.product[alias]={name:rows[0][3],address:Number.parseInt(rows[0][1],16),size}; } symbols.product.immutableBytes=symbols.product._rodata_end.address-symbols.product._image_start.address; const timerWait=listing.match(/^([a-f0-9]{16}) ([a-f0-9]{16}) [A-Za-z] OS_K1100_TIMER_STACK_REGISTERS$/m); if(timerWait)symbols[kind].OS_K1100_TIMER_STACK_REGISTERS={address:Number.parseInt(timerWait[1],16),size:Number.parseInt(timerWait[2],16)}; images.push({kind,path:selected.image.path,sha256:selected.image.sha256,elf:selected.elf}); const selectedBranch=compiledPolicy.branches.find(branch=>branch.profile===kind); assert.ok(selectedBranch,'source-bound bootloader branch'); const loaderEnv={...env,TURKOS_RELEASE_IMAGE_BYTES:String(readFileSync(join(root,selected.image.path)).length),TURKOS_RELEASE_IMAGE_SHA256:selected.image.sha256}; command('loader-'+kind,'cargo',['build','--manifest-path',join(root,selectedBranch.directory,'bootloader/Cargo.toml'),'--locked','--offline','--release','--target','aarch64-unknown-uefi','--features','kernel-handoff-test'],loaderEnv); const loaderPath=join(runDir,'loader-'+kind+'.efi'); copyFileSync(join(target,'aarch64-unknown-uefi/release/turkos-bootloader.efi'),loaderPath); loaders.push({kind,...artifact(loaderPath),image:selected.image.path,imageBytes:Number(loaderEnv.TURKOS_RELEASE_IMAGE_BYTES),imageSha256:selected.image.sha256}); const firmwareDir = join(runDir, 'firmware'); mkdirSync(firmwareDir); const firmware = ['edk2-aarch64-code.fd', 'edk2-arm-vars.fd'].map(name => { const path = join(firmwareDir, name); copyFileSync(join('/opt/homebrew/share/qemu', name), path); return artifact(path); }); const fixturesDir = join(runDir, 'fixtures'); mkdirSync(fixturesDir); const blockDisk = join(fixturesDir, 'readonly-block.img'); const gptDisk = Buffer.alloc(1024 * 1024); const crc32 = bytes => { let crc = 0xffffffff; for (const byte of bytes) { crc ^= byte; for (let bit = 0; bit < 8; bit++) crc = (crc >>> 1) ^ ((crc & 1) ? 0xedb88320 : 0); } return (crc ^ 0xffffffff) >>> 0; }; gptDisk[510] = 0x55; gptDisk[511] = 0xaa; gptDisk[446 + 4] = 0xee; gptDisk.writeUInt32LE(1, 446 + 8); gptDisk.writeUInt32LE(2047, 446 + 12); const entries = Buffer.alloc(128 * 128); entries[0] = 0xaa; entries[16] = 1; entries.writeBigUInt64LE(34n, 32); entries.writeBigUInt64LE(100n, 40); entries[2 * 128] = 0xbb; entries[2 * 128 + 16] = 2; entries.writeBigUInt64LE(101n, 2 * 128 + 32); entries.writeBigUInt64LE(2014n, 2 * 128 + 40); entries.copy(gptDisk, 2 * 512); entries.copy(gptDisk, 2015 * 512); const entryCrc = crc32(entries); const makeHeader = (here, alternate, arrayLba) => { const header = Buffer.alloc(512); header.write('EFI PART', 0, 'ascii'); header.writeUInt32LE(0x10000, 8); header.writeUInt32LE(92, 12); header.writeBigUInt64LE(BigInt(here), 24); header.writeBigUInt64LE(BigInt(alternate), 32); header.writeBigUInt64LE(34n, 40); header.writeBigUInt64LE(2014n, 48); header[56] = 0x99; header.writeBigUInt64LE(BigInt(arrayLba), 72); header.writeUInt32LE(128, 80); header.writeUInt32LE(128, 84); header.writeUInt32LE(entryCrc, 88); header.writeUInt32LE(crc32(header.subarray(0, 92)), 16); return header; }; makeHeader(1, 2047, 2).copy(gptDisk, 512); makeHeader(2047, 1, 2015).copy(gptDisk, 2047 * 512); gptDisk[512 + 56] ^= 1; writeFileSync(blockDisk, gptDisk); const blockDiskArtifact = artifact(blockDisk); const qemuVersion = command('qemu-version', 'qemu-system-aarch64', ['--version']).split('\n')[0]; const hostCpu = command('host-cpu', 'sysctl', ['-n', 'machdep.cpu.brand_string']).trim(); function put(id, path, node, name, words) { command(id, 'fdtput', ['-t', 'x', path, node, name, ...words.map(word => word.toString(16))]); } const bases = new Map(); const numaArgs = (mib, profile) => profile === 'one-bank' ? [] : [ '-object', `memory-backend-ram,id=bank0,size=${mib * 3 / 4}M`, '-object', `memory-backend-ram,id=bank1,size=${mib / 4}M`, '-numa', 'node,nodeid=0,cpus=0,memdev=bank0', '-numa', 'node,nodeid=1,memdev=bank1', ]; for (const mib of [256, 512, 1024]) for (const profile of ['one-bank', 'two-banks']) { const path = join(fixturesDir, `base-${profile}-${mib}.dtb`); command(`dtb-${profile}-${mib}`, 'qemu-system-aarch64', ['-machine', `virt-11.1,gic-version=3,dtb-randomness=off,dumpdtb=${path}`, '-accel', 'hvf', '-cpu', 'host', '-smp', '1', '-m', String(mib), ...numaArgs(mib, profile), '-display', 'none']); bases.set(`${profile}-${mib}`, path); } function fixture(row) { const path = join(fixturesDir, `${row.id}.dtb`); copyFileSync(bases.get(`${row.bankProfile}-${row.memoryMiB}`), path); if(row.policyProbeMode!==undefined)put(row.id+'-policy-mode',path,'/chosen','turkos,policy-probe-mode',[row.policyProbeMode]); put(`${row.id}-boot-id`, path, '/chosen', 'turkos,boot-id', [BigInt(`0x${row.bootId.slice(0, 8)}`), BigInt(`0x${row.bootId.slice(8)}`)]); put(`${row.id}-diag-mode`, path, '/chosen', 'turkos,diag-mode', [0]); put(`${row.id}-platform-mode`, path, '/chosen', 'turkos,platform-mode', [0]); put(`${row.id}-metadata-mode`, path, '/chosen', 'turkos,metadata-mode', [0]); put(`${row.id}-dma-mode`,path,'/chosen','turkos,dma-mode',[row.kind==='reset-quarantine'?1:0]); put(`${row.id}-page-fault-mode`,path,'/chosen','turkos,page-fault-mode',[0]); put(`${row.id}-exceptions-mode`,path,'/chosen','turkos,exceptions-mode',[0]); put(`${row.id}-gic-mode`,path,'/chosen','turkos,gic-mode',[0]); put(`${row.id}-threads-mode`,path,'/chosen','turkos,threads-mode',[row.kind==='threads-fatal'?1:0]); if (row.bankProfile === 'two-banks') { const base = 0x40000000, end = base + row.memoryMiB * 1024 * 1024, middle = base + row.memoryMiB * 1024 * 1024 * 3 / 4; const firstEnd = middle - 2 * 1024 * 1024, secondStart = middle + 2 * 1024 * 1024; if (row.kind === 'bank-overlap') { command(`${row.id}-overlap-node`, 'fdtput', ['-c', path, '/turkos-overlap']); command(`${row.id}-overlap-type`, 'fdtput', ['-t', 's', path, '/turkos-overlap', 'device_type', 'memory']); put(`${row.id}-overlap-reg`, path, '/turkos-overlap', 'reg', [0, base + 4096, 0, 4096]); } command(`${row.id}-reserved-root`, 'fdtput', ['-c', path, '/reserved-memory']); put(`${row.id}-reserved-address-cells`, path, '/reserved-memory', '#address-cells', [2]); put(`${row.id}-reserved-size-cells`, path, '/reserved-memory', '#size-cells', [2]); put(`${row.id}-reserved-ranges`, path, '/reserved-memory', 'ranges', []); const node = `/reserved-memory/bank-hole@${firstEnd.toString(16)}`; command(`${row.id}-hole-node`, 'fdtput', ['-c', path, node]); put(`${row.id}-hole-reg`, path, node, 'reg', [0, firstEnd, 0, secondStart - firstEnd]); put(`${row.id}-hole-no-map`, path, node, 'no-map', []); } if (row.kind === 'cycle') { command(`${row.id}-cycle-node`, 'fdtput', ['-c', path, '/turkos-cycle']); put(`${row.id}-cycle-owner`, path, '/turkos-cycle', 'phandle', [0xfffffff0]); put(`${row.id}-cycle-reference`, path, '/turkos-cycle', 'memory-region', [0xfffffff0]); } if (row.kind === 'missing-uart') command(`${row.id}-missing-uart`, 'fdtput', ['-d', path, '/pl011@9000000', 'compatible']); if (row.kind === 'gic-v2') command(`${row.id}-gic-v2`, 'fdtput', ['-t', 's', path, '/intc@8000000', 'compatible', 'arm,cortex-a15-gic']); return path; } json(join(runDir, 'preflight.json'), { branches, images, loaders, symbols, protectedBefore, inputsBefore, hostCpu }); async function guest(specification) { assert.ok(guardianSpawned&&powerGuardian.exitCode===null&&powerGuardian.signalCode===null,'scoped idle-sleep assertion stays alive during guests'); assert.deepEqual(runqueueInputs(root),inputsBefore,'whole source set remains held before each real VM'); const row = { ...specification, bootId: randomBytes(8).toString('hex') }; const sharedFixturePath=join(root,'userspace/tests/service_registry.rs'); const sharedFixtureHash=hashAt(root,'userspace/tests/service_registry.rs'); assert.equal(sharedFixtureHash,spike.fixture.sha256); assert.deepEqual(k1100PolicyInputs(root),compiledPolicy.inputsBefore); const fixturePath = fixture(row), fixtureBytes = readFileSync(fixturePath); console.log(`RUNQUEUE GUEST ${row.id}`); const temporary = mkdtempSync(join(tmpdir(), 'tkplatform-')), directory = join(runDir, row.id); mkdirSync(directory); const image = images.find(image => image.kind === row.profile), imagePath = join(root, image.path), imageBytes = readFileSync(imagePath); const selectedSymbols = symbols[row.profile], immutableBytes = selectedSymbols.immutableBytes; const serialPath = join(temporary, 'serial.log'), socket = join(temporary, 'q.sock'); const argv = ['-machine', 'virt-11.1,gic-version=3,dtb-randomness=off', '-accel', 'hvf', '-cpu', 'host', '-smp', '1', '-m', String(row.memoryMiB), ...numaArgs(row.memoryMiB, row.bankProfile), '-dtb', fixturePath, '-display', 'none', '-monitor', 'none', '-nic', 'none', '-serial', `file:${serialPath}`, '-qmp', `unix:${socket},server=on,wait=off`]; let loader = null; if (row.route === 'direct') argv.push('-kernel', imagePath); else { loader = loaders.find(loader => loader.kind === row.profile); const esp = join(temporary, 'esp'); mkdirSync(join(esp, 'EFI/BOOT'), { recursive: true }); copyFileSync(join(root, loader.path), join(esp, 'EFI/BOOT/BOOTAA64.EFI')); copyFileSync(imagePath, join(esp, 'TURKOS.IMG')); copyFileSync(join(firmwareDir, 'edk2-arm-vars.fd'), join(temporary, 'vars.fd')); argv.push('-drive', `if=pflash,format=raw,readonly=on,file=${join(firmwareDir, 'edk2-aarch64-code.fd')}`, '-drive', `if=pflash,format=raw,file=${join(temporary, 'vars.fd')}`, '-drive', `if=none,id=esp,format=raw,readonly=on,file=fat:${esp}`, '-device', 'virtio-blk-pci,drive=esp,addr=0x1', '-boot', 'order=c'); } const networkSocket=join(temporary,'net.sock'),gdbSocket=join(temporary,'gdb.sock'); argv.push('-global','virtio-mmio.force-legacy=false', '-drive',`if=none,id=k1405block,format=raw,readonly=on,file=${blockDisk}`, '-device','virtio-blk-device,drive=k1405block', '-netdev',`stream,id=dma0,server=on,addr.type=unix,addr.path=${networkSocket}`, '-device','virtio-net-device,netdev=dma0,mac=52:54:00:12:34:56', '-object','rng-random,id=k1465mmiorng,filename=/dev/urandom', '-device','virtio-rng-device,rng=k1465mmiorng', '-object','rng-random,id=k1425rng,filename=/dev/urandom', '-device',row.route==='uefi' ? 'virtio-rng-pci,rng=k1425rng,addr=0x2' : 'virtio-rng-pci,rng=k1425rng,addr=0x1', '-device','pci-bridge,id=k1440outer,addr=0x3,chassis_nr=1', '-device','pci-bridge,id=k1440inner,bus=k1440outer,addr=0x1,chassis_nr=2', '-object','rng-random,id=k1440rng,filename=/dev/urandom', '-device','virtio-rng-pci,rng=k1440rng,bus=k1440inner,addr=0x1', '-device','edu,bus=k1440inner,addr=0x2', '-object','rng-random,id=k1465hotrng,filename=/dev/urandom', '-device','pcie-root-port,id=k1465rp,addr=0x4', '-gdb',`unix:${gdbSocket},server=on,wait=off`); let child,qmp,gdb,network,serial='',stderr='',stage=0;const checkpoints=[],timeline=[];let pageTableCheckpoint=null,exceptionReturnPool=null,userCopyReturnPool=null,pageFaultReturnPool=null,metadataHeapReturnPool=null,addressSpaceReturnPool=null;const addressSpaceCheckpoints=[],mappingCheckpoints=[],userCopyCheckpoints=[],pageFaultsCheckpoints=[],exceptionsCheckpoints=[],gicCheckpoints=[],clockCheckpoints=[],lockingCheckpoints=[],deferredWorkCheckpoints=[],threadsCheckpoints=[],threadsFatalCheckpoints=[],contextSwitchCheckpoints=[],runqueueCheckpoints=[],waitCheckpoints=[],deferredBatches=[];let waitSerialCursor=0;const policyArchives=[];let policyArchiveAt=null,ownedPolicyPages=null,predecessorFinal=null,hostHourStartMs=null,hostHourEndMs=null;let injected=false,hostTx,preexistingIpv6Multicast=0;const injectedEpochs=new Set();let deferredSent=0; async function request(execute,args){const before=qmp.transcript.length;const result=await qmp.request(execute,args);const tx=qmp.transcript.slice(before).find(row=>row.direction==='tx'&&row.message.execute===execute);assert.ok(tx);if(stage)timeline.push({stage,kind:'qmp',id:tx.message.id,execute});return result;} try { child = spawn('qemu-system-aarch64', argv, { stdio: ['ignore', 'ignore', 'pipe'] });ownedGuestChildren.push(child); const exited = new Promise((done, fail) => { child.once('exit', (code, signal) => done({ code, signal })); child.once('error', fail); }); child.stderr.on('data', chunk => { stderr += chunk; }); qmp = await qmpConnect(socket); await qmp.request('query-version'); await qmp.request('human-monitor-command', { 'command-line': 'info numa' }); network=await dmaNetworkConnect(networkSocket); const fatal=row.kind==='exceptions-fatal',threadFatal=row.kind==='threads-fatal',stopped=/TURKOS\/OS\/K640: PASS/; for(const deadline=Date.now()+300000;Date.now()0&&!metadataHeapReturnPool&&serial.includes('TURKOS/OS/K780: RETURN-POOL READY')){ stage=256;await request('stop');assert.equal((await request('query-status')).status,'paused'); if(!gdb)gdb=await dmaGdbConnect(gdbSocket,row=>{if(stage&&row.id!==null)timeline.push({stage,kind:'rsp',id:row.id,direction:row.direction});}); const captures=[],dumps={}; async function capture(name,val,size,symbol=null){const path=join(temporary,name+'.bin');await request('pmemsave',{val,size,filename:path});const saved=join(directory,name+'.bin');copyFileSync(path,saved);captures.push({name,val,size,...(symbol?{symbol}:{})});dumps[name]=artifact(saved);return readFileSync(saved);} const metadata=await capture('metadataReturnEvidence',selectedSymbols.OS_K740_EVIDENCE.address,selectedSymbols.OS_K740_EVIDENCE.size,'OS_K740_EVIDENCE'); const heap=await capture('heapReturnEvidence',selectedSymbols.OS_K780_EVIDENCE.address,selectedSymbols.OS_K780_EVIDENCE.size,'OS_K780_EVIDENCE'); await capture('metadataReusedPage',Number(metadata.readBigUInt64LE(3*8)),4096); await capture('heapReturnedPool',Number(heap.readBigUInt64LE(1*8)),32768); const rspBefore=gdb.batchTranscript.length; await gdb.writeBatchCheckpoint(selectedSymbols.OS_K780_RETURN_POOL_GATE.address); const rsp=gdb.batchTranscript.slice(rspBefore); await request('cont');assert.equal((await request('query-status')).status,'running'); metadataHeapReturnPool={stage:'post-K780-return',captures,dumps,rsp, gateAddress:selectedSymbols.OS_K780_RETURN_POOL_GATE.address};stage=0; } const captureStage=checkpoints.length+1; if(captureStage<=2&&serial.includes(`TURKOS/OS/K800: CAPTURE STAGE=0x${BigInt(captureStage).toString(16).padStart(16,'0')}`)){ stage=captureStage;await request('stop');assert.equal((await request('query-status')).status,'paused'); if(!gdb)gdb=await dmaGdbConnect(gdbSocket,row=>{if(stage&&row.id!==null)timeline.push({stage,kind:'rsp',id:row.id,direction:row.direction});}); const checkpoint={stage,captures:[],dumps:{}}; async function capture(name,val,size,symbol=null){const path=join(temporary,`${name}.bin`);await request('pmemsave',{val,size,filename:path});const saved=join(directory,`${name}.bin`);copyFileSync(path,saved);checkpoint.dumps[name]=artifact(saved);checkpoint.captures.push({name,val,size,...(symbol?{symbol}:{})});} for(const [name,symbol,size]of dmaCaptures)await capture(`dma${stage}${name}`,selectedSymbols[symbol].address,size,symbol); const qbytes=readFileSync(join(root,checkpoint.dumps[`dma${stage}dmaQueues`].path)); for(let index=0;index<4;index++)await capture(`dma${stage}page${index}`,Number(qbytes.readBigUInt64LE(((stage-1)*64+12+index)*8)),4096); if(stage===2){ const expected=dmaPacket(row.bootId,1); let expectedIndex=-1; for(const deadline=Date.now()+5000;Date.now()frame.equals(expected)); if(expectedIndex<0)await delay(20); } assert.ok(expectedIndex>=0,'missing expected DMA packet after bounded IPv6 multicast'); assert.ok(expectedIndex<8,'too many preexisting network frames'); for(const frame of network.received.slice(0,expectedIndex)){ const preexistingIpv6=row.route==='uefi'&& frame[0]===0x33&&frame[1]===0x33&&frame[2]===0xff&& frame.subarray(6,12).equals(Buffer.from([0x52,0x54,0x00,0x12,0x34,0x56]))&& frame[12]===0x86&&frame[13]===0xdd&& (frame.length===78&&frame[20]===58&&frame[54]===135|| frame.length===86&&frame[20]===0&&frame[54]===58&&frame[62]===131); assert.ok(preexistingIpv6,`unexpected preexisting network frame ${frame.toString('hex')}`); preexistingIpv6Multicast++; } hostTx=network.received[expectedIndex]; } await gdb.writeCheckpoint(selectedSymbols.OS_K800_CAPTURE_GATE.address);await request('cont');assert.equal((await request('query-status')).status,'running');checkpoints.push(checkpoint);stage=0; } if(!pageTableCheckpoint&&serial.includes('TURKOS/OS/K820: CAPTURE OWNED-TABLES')){ stage=3;await request('stop');assert.equal((await request('query-status')).status,'paused'); const checkpoint={stage:3,captures:[],dumps:{}}; async function capture(name,val,size,symbol=null){const path=join(temporary,`${name}.bin`);await request('pmemsave',{val,size,filename:path});const saved=join(directory,`${name}.bin`);copyFileSync(path,saved);checkpoint.dumps[name]=artifact(saved);checkpoint.captures.push({name,val,size,...(symbol?{symbol}:{})});} for(const [name,symbol,size]of pageTablesCaptures.filter(([name])=>['pageTableEvidence','pageTableRecords','pageTableRegistryRecords','pageTableAuthorityLive','pageTableEvents','pageTableEventCount'].includes(name)))await capture(`stage${name}`,selectedSymbols[symbol].address,size,symbol); const records=readFileSync(join(root,checkpoint.dumps.stagepageTableRecords.path));const evidence=readFileSync(join(root,checkpoint.dumps.stagepageTableEvidence.path)); for(let index=0;index0)&&spacesStage<=3&&serial.includes(`TURKOS/OS/K840: CAPTURE STAGE=0x${BigInt(spacesStage).toString(16).padStart(16,'0')}`)){ stage=spacesStage+3;await request('stop');assert.equal((await request('query-status')).status,'paused'); const checkpoint={stage:spacesStage,captures:[],dumps:{}}; async function capture(name,val,size,symbol=null){const path=join(temporary,`${name}.bin`);await request('pmemsave',{val,size,filename:path});const saved=join(directory,`${name}.bin`);copyFileSync(path,saved);checkpoint.dumps[name]=artifact(saved);checkpoint.captures.push({name,val,size,...(symbol?{symbol}:{})});} for(const [name,symbol,size]of addressSpacesCaptures)await capture(`spaces${spacesStage}${name}`,selectedSymbols[symbol].address,size,symbol); const owned=readFileSync(join(root,checkpoint.dumps[`spaces${spacesStage}addressSpaceOwned`].path)); for(let index=0;index<32;index++){const address=Number(owned.readBigUInt64LE(index*48));if(address)await capture(`spaces${spacesStage}page${index}`,address,4096);} await gdb.writeCheckpoint(selectedSymbols.OS_K840_CAPTURE_GATE.address);await request('cont');assert.equal((await request('query-status')).status,'running');addressSpaceCheckpoints.push(checkpoint);stage=0; } if(row.policyProbeMode>0&&!addressSpaceReturnPool&&serial.includes('TURKOS/OS/K840: RETURN-POOL READY')){ assert.equal(addressSpaceCheckpoints.length,3); stage=257;await request('stop');assert.equal((await request('query-status')).status,'paused'); const captures=[],dumps={}; async function capture(name,val,size,symbol=null){const path=join(temporary,name+'.bin');await request('pmemsave',{val,size,filename:path});const saved=join(directory,name+'.bin');copyFileSync(path,saved);captures.push({name,val,size,...(symbol?{symbol}:{})});dumps[name]=artifact(saved);return readFileSync(saved);} const evidence=await capture('addressSpaceReturnEvidence',selectedSymbols.OS_K840_EVIDENCE.address,selectedSymbols.OS_K840_EVIDENCE.size,'OS_K840_EVIDENCE'); await capture('addressSpaceReturnedPool',Number(evidence.readBigUInt64LE(38*8)),32*4096); const rspBefore=gdb.batchTranscript.length; await gdb.writeBatchCheckpoint(selectedSymbols.OS_K840_RETURN_POOL_GATE.address); const rsp=gdb.batchTranscript.slice(rspBefore); await request('cont');assert.equal((await request('query-status')).status,'running'); addressSpaceReturnPool={stage:'post-K840-return',captures,dumps,rsp, gateAddress:selectedSymbols.OS_K840_RETURN_POOL_GATE.address};stage=0; } const mappingStage=mappingCheckpoints.length+1; if(mappingStage<=7&&serial.includes(`TURKOS/OS/K860: CAPTURE STAGE=0x${BigInt(mappingStage).toString(16).padStart(16,'0')}`)){ stage=mappingStage+((row.profile==='acceptance'||row.policyProbeMode>0)?6:3);await request('stop');assert.equal((await request('query-status')).status,'paused'); const checkpoint={stage:mappingStage,captures:[],dumps:{}}; async function capture(name,val,size,symbol=null){const path=join(temporary,`${name}.bin`);await request('pmemsave',{val,size,filename:path});const saved=join(directory,`${name}.bin`);copyFileSync(path,saved);checkpoint.dumps[name]=artifact(saved);checkpoint.captures.push({name,val,size,...(symbol?{symbol}:{})});} for(const[name,symbol,size]of mappingCaptures)await capture(`mapping${mappingStage}${name}`,selectedSymbols[symbol].address,size,symbol); const owned=readFileSync(join(root,checkpoint.dumps[`mapping${mappingStage}mappingOwned`].path)); for(let index=0;index<32;index++){const address=Number(owned.readBigUInt64LE(index*48));if(address)await capture(`mapping${mappingStage}page${index}`,address,4096);} await gdb.writeCheckpoint(selectedSymbols.OS_K860_CAPTURE_GATE.address);await request('cont');assert.equal((await request('query-status')).status,'running');mappingCheckpoints.push(checkpoint);stage=0; } const copyStage=userCopyCheckpoints.length; if((row.profile==='acceptance'||row.policyProbeMode>0)&©Stage<=8&&serial.includes(`TURKOS/OS/K880: CAPTURE STAGE=0x${BigInt(copyStage).toString(16).padStart(16,'0')}`)){ stage=copyStage+14;await request('stop');assert.equal((await request('query-status')).status,'paused'); const checkpoint={stage:copyStage,captures:[],dumps:{}}; async function capture(name,val,size,symbol=null){const path=join(temporary,`${name}.bin`);await request('pmemsave',{val,size,filename:path});const saved=join(directory,`${name}.bin`);copyFileSync(path,saved);checkpoint.dumps[name]=artifact(saved);checkpoint.captures.push({name,val,size,...(symbol?{symbol}:{})});} for(const[name,symbol,size]of userCopyCaptures)await capture(`copy${copyStage}${name}`,selectedSymbols[symbol].address,size,symbol); const evidence=readFileSync(join(root,checkpoint.dumps[`copy${copyStage}userCopyEvidence`].path)); await capture(`copy${copyStage}pool`,Number(evidence.readBigUInt64LE(30*8)),32*4096); await gdb.writeCheckpoint(selectedSymbols.OS_K880_CAPTURE_GATE.address);await request('cont');assert.equal((await request('query-status')).status,'running');userCopyCheckpoints.push(checkpoint);stage=0; } const faultStage=pageFaultsCheckpoints.length; if((row.profile==='acceptance'||row.policyProbeMode>0)&&faultStage<=7&&serial.includes(`TURKOS/OS/K900: CAPTURE STAGE=0x${BigInt(faultStage).toString(16).padStart(16,'0')}`)){ stage=faultStage+23;await request('stop');assert.equal((await request('query-status')).status,'paused'); const checkpoint={stage:faultStage,captures:[],dumps:{}}; async function capture(name,val,size,symbol=null){const path=join(temporary,`${name}.bin`);await request('pmemsave',{val,size,filename:path});const saved=join(directory,`${name}.bin`);copyFileSync(path,saved);checkpoint.dumps[name]=artifact(saved);checkpoint.captures.push({name,val,size,...(symbol?{symbol}:{})});} for(const[name,symbol,size]of pageFaultsCheckpointCaptures(faultStage))await capture(`fault${faultStage}${name}`,selectedSymbols[symbol].address,size,symbol); const evidence=readFileSync(join(root,checkpoint.dumps[`fault${faultStage}pageFaultEvidence`].path)); await capture(`fault${faultStage}pool`,Number(evidence.readBigUInt64LE(6*8)),32*4096); await gdb.writeCheckpoint(selectedSymbols.OS_K900_CAPTURE_GATE.address);await request('cont');assert.equal((await request('query-status')).status,'running');pageFaultsCheckpoints.push(checkpoint);stage=0; } if(row.policyProbeMode>0&&!userCopyReturnPool&&serial.includes('TURKOS/OS/K880: RETURN-POOL READY')){ assert.equal(userCopyCheckpoints.length,9); stage=254;await request('stop');assert.equal((await request('query-status')).status,'paused'); const evidence=readFileSync(join(root,userCopyCheckpoints.at(-1).dumps.copy8userCopyEvidence.path)); const val=Number(evidence.readBigUInt64LE(30*8)),size=32*4096; const path=join(temporary,'user-copy-return-pool.bin'); await request('pmemsave',{val,size,filename:path}); const saved=join(directory,'user-copy-return-pool.bin');copyFileSync(path,saved); const rspBefore=gdb.batchTranscript.length; await gdb.writeBatchCheckpoint(selectedSymbols.OS_K880_RETURN_POOL_GATE.address); const rsp=gdb.batchTranscript.slice(rspBefore); await request('cont');assert.equal((await request('query-status')).status,'running'); userCopyReturnPool={stage:'post-K880-return',capture:{name:'userCopyReturnedPool',val,size}, dump:artifact(saved),rsp,gateAddress:selectedSymbols.OS_K880_RETURN_POOL_GATE.address}; stage=0; } if(row.policyProbeMode>0&&!pageFaultReturnPool&&serial.includes('TURKOS/OS/K900: RETURN-POOL READY')){ assert.equal(pageFaultsCheckpoints.length,8); stage=255;await request('stop');assert.equal((await request('query-status')).status,'paused'); const evidence=readFileSync(join(root,pageFaultsCheckpoints.at(-1).dumps.fault7pageFaultEvidence.path)); const val=Number(evidence.readBigUInt64LE(6*8)),size=32*4096; const path=join(temporary,'page-fault-return-pool.bin'); await request('pmemsave',{val,size,filename:path}); const saved=join(directory,'page-fault-return-pool.bin');copyFileSync(path,saved); const rspBefore=gdb.batchTranscript.length; await gdb.writeBatchCheckpoint(selectedSymbols.OS_K900_RETURN_POOL_GATE.address); const rsp=gdb.batchTranscript.slice(rspBefore); await request('cont');assert.equal((await request('query-status')).status,'running'); pageFaultReturnPool={stage:'post-K900-return',capture:{name:'pageFaultReturnedPool',val,size}, dump:artifact(saved),rsp,gateAddress:selectedSymbols.OS_K900_RETURN_POOL_GATE.address}; stage=0; } const exceptionStage=exceptionsCheckpoints.length; if((row.profile==='acceptance'||row.policyProbeMode>0)&&exceptionStage<=(fatal?1:3)&&serial.includes(`TURKOS/OS/K920: CAPTURE STAGE=0x${BigInt(exceptionStage).toString(16).padStart(16,'0')}`)){ stage=exceptionStage+31;await request('stop');assert.equal((await request('query-status')).status,'paused'); const checkpoint={stage:exceptionStage,captures:[],dumps:{}}; async function capture(name,val,size,symbol=null){const path=join(temporary,`${name}.bin`);await request('pmemsave',{val,size,filename:path});const saved=join(directory,`${name}.bin`);copyFileSync(path,saved);checkpoint.dumps[name]=artifact(saved);checkpoint.captures.push({name,val,size,...(symbol?{symbol}:{})});} for(const[name,symbol,size]of exceptionsCaptures)await capture(`exception${exceptionStage}${name}`,selectedSymbols[symbol].address,size,symbol); if(exceptionStage===0){const evidence=readFileSync(join(root,checkpoint.dumps.exception0exceptionEvidence.path));await capture('exception0pool',Number(evidence.readBigUInt64LE(23*8)),32*4096);} const owned=readFileSync(join(root,checkpoint.dumps[`exception${exceptionStage}exceptionOwned`].path)); for(let i=0;i<8;i++){const address=Number(owned.readBigUInt64LE(i*48));if(address)await capture(`exception${exceptionStage}page${i}`,address,4096);} if(exceptionStage===1){const addresses=readFileSync(join(root,checkpoint.dumps.exception1exceptionAddresses.path));await capture('exception1exceptionLiveFrame',Number(addresses.readBigUInt64LE(16)),848);await capture('exception1exceptionLiveIrq',selectedSymbols.OS_K660_IRQ_COUNT.address,8,'OS_K660_IRQ_COUNT');await capture('exception1exceptionLiveActive',selectedSymbols.legacyIrqActive.address,4);} await gdb.writeCheckpoint(selectedSymbols.OS_K920_CAPTURE_GATE.address);await request('cont');assert.equal((await request('query-status')).status,'running');exceptionsCheckpoints.push(checkpoint);stage=0; } if(row.policyProbeMode>0&&!exceptionReturnPool&&serial.includes('TURKOS/OS/K920: RETURN-POOL READY')){ assert.equal(exceptionsCheckpoints.length,4); stage=253; await request('stop');assert.equal((await request('query-status')).status,'paused'); const evidence=readFileSync(join(root,exceptionsCheckpoints[0].dumps.exception0exceptionEvidence.path)); const val=Number(evidence.readBigUInt64LE(23*8)),size=32*4096; const path=join(temporary,'exception-return-pool.bin'); await request('pmemsave',{val,size,filename:path}); const saved=join(directory,'exception-return-pool.bin');copyFileSync(path,saved); const activeVal=Number(evidence.readBigUInt64LE(50*8)); const activePath=join(temporary,'exception-debug-gic-active.bin'); await request('pmemsave',{val:activeVal,size:4,filename:activePath}); const activeSaved=join(directory,'exception-debug-gic-active.bin'); copyFileSync(activePath,activeSaved); const rspBefore=gdb.batchTranscript.length; await gdb.writeBatchCheckpoint(selectedSymbols.OS_K920_RETURN_POOL_GATE.address); const rsp=gdb.batchTranscript.slice(rspBefore); await request('cont');assert.equal((await request('query-status')).status,'running'); exceptionReturnPool={stage:'post-K920-return',capture:{name:'exceptionReturnedPool',val,size}, dump:artifact(saved),debugActive:{capture:{name:'exceptionDebugGicActive', val:activeVal,size:4},dump:artifact(activeSaved)}, rsp,gateAddress:selectedSymbols.OS_K920_RETURN_POOL_GATE.address}; stage=0; } for(const epoch of[1,2])if(!injectedEpochs.has(epoch)&&serial.includes(`TURKOS/OS/K935: RX-BURST EPOCH=0x${BigInt(epoch).toString(16).padStart(16,'0')} WAITING-32-HOST-FRAMES`)){for(const packet of gicBurst(row.bootId,epoch))network.send(packet);injectedEpochs.add(epoch);} const ownStage=gicStages[gicCheckpoints.length]; if((row.profile==='acceptance'||row.policyProbeMode>0)&&ownStage!==undefined&&serial.includes(`TURKOS/OS/K940: CAPTURE STAGE=0x${BigInt(ownStage).toString(16).padStart(16,'0')}`)){ stage=35+gicCheckpoints.length;await request('stop');assert.equal((await request('query-status')).status,'paused'); const checkpoint={stage:ownStage,captures:[],dumps:{}}; async function capture(name,val,size,symbol=null){const path=join(temporary,`${name}.bin`);await request('pmemsave',{val,size,filename:path});const saved=join(directory,`${name}.bin`);copyFileSync(path,saved);checkpoint.dumps[name]=artifact(saved);checkpoint.captures.push({name,val,size,...(symbol?{symbol}:{})});} const ownBlobs={};for(const[name,symbol,size]of gicCaptures){const target=`gic${ownStage}${name}`;await capture(target,selectedSymbols[symbol].address,size,symbol);ownBlobs[name]=readFileSync(join(root,checkpoint.dumps[target].path));} for(const r of gicCheckpointPhysicalCaptures(ownBlobs,selectedSymbols,ownStage))await capture(`gic${ownStage}${r.name}`,r.val,r.size,r.symbol??null); await gdb.writeCheckpoint(selectedSymbols.OS_K940_CAPTURE_GATE.address);await request('cont');assert.equal((await request('query-status')).status,'running');gicCheckpoints.push(checkpoint);stage=0; } const clockStage=clockStages[clockCheckpoints.length]; if((row.profile==='acceptance'||row.policyProbeMode>0)&&clockStage!==undefined&&serial.includes(`TURKOS/OS/K960: CAPTURE STAGE=0x${BigInt(clockStage).toString(16).padStart(16,'0')}`)){ stage=48+clockStage;await request('stop');assert.equal((await request('query-status')).status,'paused'); const checkpoint={stage:clockStage,captures:[],dumps:{}}; async function capture(name,val,size,symbol=null){const path=join(temporary,`${name}.bin`);await request('pmemsave',{val,size,filename:path});const saved=join(directory,`${name}.bin`);copyFileSync(path,saved);checkpoint.dumps[name]=artifact(saved);checkpoint.captures.push({name,val,size,...(symbol?{symbol}:{})});} const ownBlobs={};for(const[name,symbol,size]of clockCaptures){const target=`clock${clockStage}${name}`;await capture(target,selectedSymbols[symbol].address,size,symbol);ownBlobs[target]=readFileSync(join(root,checkpoint.dumps[target].path));} for(const r of clockCheckpointPhysicalCaptures(clockStage,ownBlobs,selectedSymbols))await capture(r.name,r.val,r.size,r.symbol??null); await gdb.writeCheckpoint(selectedSymbols.OS_K960_CAPTURE_GATE.address);await request('cont');assert.equal((await request('query-status')).status,'running');clockCheckpoints.push(checkpoint);stage=0; } const lockingStage=lockingStages[lockingCheckpoints.length]; if((row.profile==='acceptance'||row.policyProbeMode>0)&&lockingStage!==undefined&&serial.includes(`TURKOS/OS/K980: CAPTURE STAGE=0x${BigInt(lockingStage).toString(16).padStart(16,'0')}`)){ stage=57+lockingStage;await request('stop');assert.equal((await request('query-status')).status,'paused'); const checkpoint={stage:lockingStage,captures:[],dumps:{}}; async function capture(name,val,size,symbol=null){const path=join(temporary,`${name}.bin`);await request('pmemsave',{val,size,filename:path});const saved=join(directory,`${name}.bin`);copyFileSync(path,saved);checkpoint.dumps[name]=artifact(saved);checkpoint.captures.push({name,val,size,...(symbol?{symbol}:{})});} const ownBlobs={};for(const[name,symbol,size]of lockingCaptures){const target=`locking${lockingStage}${name}`;await capture(target,selectedSymbols[symbol].address,size,symbol);ownBlobs[target]=readFileSync(join(root,checkpoint.dumps[target].path));} for(const r of lockingCheckpointPhysicalCaptures(lockingStage,ownBlobs,selectedSymbols))await capture(r.name,r.val,r.size,r.symbol??null); await gdb.writeCheckpoint(selectedSymbols.OS_K980_CAPTURE_GATE.address);await request('cont');assert.equal((await request('query-status')).status,'running');lockingCheckpoints.push(checkpoint);stage=0; } const batchPlan=k1080WaitDeferredBatchPlan[deferredBatches.length]; if((row.profile==='acceptance'||row.policyProbeMode>0)&&batchPlan&&serial.includes(k1080WaitDeferredBatchLine(batchPlan))){ assert.equal(deferredSent,batchPlan.before,'actual next input batch follows every prior packet'); assert.equal(stage,0,'private batch protocol has a separate transcript scope'); async function batchCommand(execute,args){ const before=qmp.transcript.length,value=await qmp.request(execute,args); const tx=qmp.transcript.slice(before).find(r=>r.direction==='tx'&&r.message.execute===execute);assert.ok(tx); return{id:tx.message.id,value}; } async function batchCapture(name,val,size,symbol=null){ assert.ok(Number.isSafeInteger(val)&&Number.isSafeInteger(size)&&size>0); assert.ok(val>=0x40000000&&val+size<=0x40000000+row.memoryMiB*1024*1024,'batch capture is inside actual guest RAM'); const path=join(temporary,name+'.bin'),saved=join(directory,name+'.bin'); const response=await batchCommand('pmemsave',{val,size,filename:path});copyFileSync(path,saved); return{name,val,size,...(symbol?{symbol}:{}),artifact:artifact(saved),bytes:readFileSync(saved),qmpId:response.id}; } const batch=await observeK1080WaitDeferredBatch({ordinal:batchPlan.ordinal,bootId:row.bootId,symbols:selectedSymbols, command:batchCommand,capture:batchCapture,sendFrame:frame=>network.send(frame), releaseGate:address=>gdb.writeBatchCheckpoint(address),delay}); deferredBatches.push(batch);deferredSent=batchPlan.target; } if(deferredSent===10&&serial.includes('TURKOS/OS/K1000: WORKER-IO READY NINTH-RX'))network.send(deferredPacket(row.bootId,deferredSent++,1)); const deferredStage=deferredWorkStages[deferredWorkCheckpoints.length]; if((row.profile==='acceptance'||row.policyProbeMode>0)&&deferredStage!==undefined&&serial.includes(`TURKOS/OS/K1000: CAPTURE STAGE=0x${BigInt(deferredStage).toString(16).padStart(16,'0')}`)){ stage=63+deferredStage;await request('stop');assert.equal((await request('query-status')).status,'paused'); const checkpoint={stage:deferredStage,captures:[],dumps:{}}; async function capture(name,val,size,symbol=null){const path=join(temporary,`${name}.bin`);await request('pmemsave',{val,size,filename:path});const saved=join(directory,`${name}.bin`);copyFileSync(path,saved);checkpoint.dumps[name]=artifact(saved);checkpoint.captures.push({name,val,size,...(symbol?{symbol}:{})});} const ownBlobs={};for(const[name,symbol,size]of deferredWorkCaptures){const target=`deferred${deferredStage}${name}`;await capture(target,selectedSymbols[symbol].address,size,symbol);ownBlobs[target]=readFileSync(join(root,checkpoint.dumps[target].path));} for(const r of deferredWorkCheckpointPhysicalCaptures(deferredStage,ownBlobs,selectedSymbols))await capture(r.name,r.val,r.size,r.symbol??null); await gdb.writeCheckpoint(selectedSymbols.OS_K1000_CAPTURE_GATE.address);await request('cont');assert.equal((await request('query-status')).status,'running');deferredWorkCheckpoints.push(checkpoint);stage=0; } const threadStage=threadsStages[threadsCheckpoints.length]; if((row.profile==='acceptance'||row.policyProbeMode>0)&&threadStage!==undefined&&serial.includes(`TURKOS/OS/K1020: CAPTURE STAGE=${BigInt(threadStage).toString(16).padStart(16,'0')}`)){ stage=73+threadStage;await request('stop');assert.equal((await request('query-status')).status,'paused'); const checkpoint={stage:threadStage,captures:[],dumps:{}}; async function capture(name,val,size,symbol=null){const path=join(temporary,`${name}.bin`);await request('pmemsave',{val,size,filename:path});const saved=join(directory,`${name}.bin`);copyFileSync(path,saved);checkpoint.dumps[name]=artifact(saved);checkpoint.captures.push({name,val,size,...(symbol?{symbol}:{})});} const ownBlobs={};for(const[name,symbol,size]of threadsCaptures){const target=`threads${threadStage}${name}`;await capture(target,selectedSymbols[symbol].address,size,symbol);ownBlobs[target]=readFileSync(join(root,checkpoint.dumps[target].path));} for(const r of threadsCheckpointPhysicalCaptures(threadStage,ownBlobs,selectedSymbols))await capture(r.name,r.val,r.size,r.symbol??null); await gdb.writeCheckpoint(selectedSymbols.OS_K1020_CAPTURE_GATE.address);await request('cont');assert.equal((await request('query-status')).status,'running');threadsCheckpoints.push(checkpoint);stage=0; } const threadFatalStage=threadsFatalStages[threadsFatalCheckpoints.length]; if(threadFatal&&threadFatalStage!==undefined&&serial.includes(`TURKOS/OS/K1020: FATAL CAPTURE STAGE=${BigInt(threadFatalStage).toString(16).padStart(16,'0')}`)){ stage=83+threadFatalStage;await request('stop');assert.equal((await request('query-status')).status,'paused'); const checkpoint={stage:threadFatalStage,captures:[],dumps:{}}; async function capture(name,val,size,symbol=null){const path=join(temporary,`${name}.bin`);await request('pmemsave',{val,size,filename:path});const saved=join(directory,`${name}.bin`);copyFileSync(path,saved);checkpoint.dumps[name]=artifact(saved);checkpoint.captures.push({name,val,size,...(symbol?{symbol}:{})});} const ownBlobs={};for(const[name,symbol,size]of threadsCaptures){const target=`threadFatal${threadFatalStage}${name}`;await capture(target,selectedSymbols[symbol].address,size,symbol);ownBlobs[target]=readFileSync(join(root,checkpoint.dumps[target].path));} for(const r of threadsFatalPhysicalCaptures(threadFatalStage,ownBlobs,selectedSymbols))await capture(r.name,r.val,r.size,r.symbol??null); await gdb.writeCheckpoint(selectedSymbols.OS_K1020_FATAL_GATE.address);await request('cont');assert.equal((await request('query-status')).status,'running');threadsFatalCheckpoints.push(checkpoint);stage=0; } const contextStage=contextSwitchStages[contextSwitchCheckpoints.length]; if((row.profile==='acceptance'||row.policyProbeMode>0)&&contextStage!==undefined&&serial.includes(`TURKOS/OS/K1040: CAPTURE STAGE=0x${BigInt(contextStage).toString(16).padStart(16,'0')}`)){ stage=83+contextStage;await request('stop');assert.equal((await request('query-status')).status,'paused'); const checkpoint={stage:contextStage,captures:[],dumps:{}}; async function capture(name,val,size,symbol=null){assert.ok(val>=0x40000000&&val+size<=0x40000000+row.memoryMiB*1024*1024);const path=join(temporary,`${name}.bin`);await request('pmemsave',{val,size,filename:path});const saved=join(directory,`${name}.bin`);copyFileSync(path,saved);checkpoint.dumps[name]=artifact(saved);checkpoint.captures.push({name,val,size,...(symbol?{symbol}:{})});} const ownBlobs={};for(const[name,symbol,size]of[...contextSwitchCaptures,['contextKernelTables','OS_K1020_KERNEL_TABLES',256]]){const target=`context${contextStage}${name}`;await capture(target,selectedSymbols[symbol].address,size,symbol);ownBlobs[target]=readFileSync(join(root,checkpoint.dumps[target].path));} for(const r of contextSwitchCheckpointPhysicalCaptures(contextStage,ownBlobs,selectedSymbols))await capture(r.name,r.val,r.size,r.symbol??null); await gdb.writeCheckpoint(selectedSymbols.OS_K1040_CAPTURE_GATE.address);await request('cont');assert.equal((await request('query-status')).status,'running');contextSwitchCheckpoints.push(checkpoint);stage=0; } const runqueueStage=runqueueStages[runqueueCheckpoints.length]; if((row.profile==='acceptance'||row.policyProbeMode>0)&&runqueueStage!==undefined&&serial.includes(`TURKOS/OS/K1060: CAPTURE STAGE=0x${BigInt(runqueueStage).toString(16).padStart(16,'0')}`)){ stage=99+runqueueCheckpoints.length;await request('stop');assert.equal((await request('query-status')).status,'paused'); const checkpoint={stage:runqueueStage,captures:[],dumps:{}}; async function capture(name,val,size,symbol=null){const path=join(temporary,`${name}.bin`);await request('pmemsave',{val,size,filename:path});const saved=join(directory,`${name}.bin`);copyFileSync(path,saved);checkpoint.dumps[name]=artifact(saved);checkpoint.captures.push({name,val,size,...(symbol?{symbol}:{})});} const ownBlobs={};for(const[name,symbol,size]of[...runqueueCaptures,['runqueueKernelTables','OS_K1020_KERNEL_TABLES',256]]){const target=`runqueue${runqueueStage}${name}`;await capture(target,selectedSymbols[symbol].address,size,symbol);ownBlobs[target]=readFileSync(join(root,checkpoint.dumps[target].path));} for(const r of runqueueCheckpointPhysicalCaptures(runqueueStage,ownBlobs,selectedSymbols))await capture(r.name,r.val,r.size,r.symbol??null); await gdb.writeCheckpoint(selectedSymbols.OS_K1060_CAPTURE_GATE.address);await request('cont');assert.equal((await request('query-status')).status,'running');runqueueCheckpoints.push(checkpoint);stage=0; } const waitPlan=k1080WaitCheckpointPlan[waitCheckpoints.length]; if((row.profile==='acceptance'||row.policyProbeMode>0)&&waitPlan){ const fresh=nextK1080WaitMarker(serial,waitSerialCursor,waitPlan.label); if(fresh){ waitSerialCursor=fresh.end; const occurrence=waitCheckpoints.length; assert.equal(occurrence,waitPlan.occurrence); stage=181+occurrence;await request('stop');assert.equal((await request('query-status')).status,'paused'); const checkpoint={stage:occurrence,label:waitPlan.label,inIrq:waitPlan.inIrq,captures:[],dumps:{}}; async function capture(name,val,size,symbol=null){ assert.ok(Number.isSafeInteger(val)&&Number.isSafeInteger(size)&&size>0); assert.ok(val>=0x40000000&&val+size<=0x40000000+row.memoryMiB*1024*1024,'own physical capture is inside actual guest RAM'); const path=join(temporary,`${name}.bin`);await request('pmemsave',{val,size,filename:path}); const saved=join(directory,`${name}.bin`);copyFileSync(path,saved); checkpoint.dumps[name]=artifact(saved);checkpoint.captures.push({name,val,size,...(symbol?{symbol}:{})}); } const ownBlobs={}; for(const r of k1080WaitCaptureRows(selectedSymbols,'wait'+occurrence)){ await capture(r.name,r.val,r.size,r.symbol); ownBlobs[r.name]=readFileSync(join(root,checkpoint.dumps[r.name].path)); } for(const r of k1080WaitCheckpointPhysicalCaptures(occurrence,ownBlobs,selectedSymbols))await capture(r.name,r.val,r.size,r.symbol??null); await gdb.writeCheckpoint(selectedSymbols.OS_K1080_CAPTURE_GATE.address); await request('cont');assert.equal((await request('query-status')).status,'running'); waitCheckpoints.push(checkpoint);stage=0; } } const ready=(serial.match(/TURKOS\/OS\/K1100: ARCHIVE READY/g)??[]).length; if(ready>policyArchives.length){ assert.equal(ready,policyArchives.length+1,'no missed K1100 physical archive'); await request('stop');assert.equal((await request('query-status')).status,'paused'); const ordinal=ready,state=[],directoryPrefix='policy'+String(ordinal).padStart(3,'0'); for(const capture of k1100PolicyStateCaptures(selectedSymbols)){ const path=join(temporary,directoryPrefix+'-'+capture.name+'.bin'); await request('pmemsave',{val:capture.val,size:capture.size,filename:path}); const saved=join(directory,directoryPrefix+'-'+capture.name+'.bin');copyFileSync(path,saved); state.push({...capture,artifact:artifact(saved)}); } const headerSymbol=selectedSymbols.OS_K1100_CHECKPOINT; const headerPath=join(temporary,directoryPrefix+'-header.bin'); await request('pmemsave',{val:headerSymbol.address,size:headerSymbol.size,filename:headerPath}); const header=readFileSync(headerPath),sequence=header.readBigUInt64LE(0); assert.equal(sequence,BigInt(ordinal)); if(header.readBigUInt64LE(8)===0x3600n){assert.equal(hostHourStartMs,null);hostHourStartMs=performance.now();} if(header.readBigUInt64LE(8)===0x3601n){assert.ok(hostHourStartMs!==null);hostHourEndMs=performance.now();} const savedHeader=join(directory,directoryPrefix+'-header.bin');copyFileSync(headerPath,savedHeader); const blobs=Object.fromEntries(state.map(c=>[c.name,readFileSync(join(root,c.artifact.path))])); const view=k1100PolicyStateViews(blobs,selectedSymbols),evidence=view.OS_K1100_EVIDENCE; const priorAuthority={address:evidence.readBigUInt64LE(22*8),size:Number(evidence.readBigUInt64LE(23*8))}; assert.ok(priorAuthority.address>0n&&priorAuthority.size>0); const owned=view.OS_K1100_OWNED; if(!ownedPolicyPages&&Array.from({length:27},(_,i)=>owned.readBigUInt64LE(i*8)).every(v=>v>0n)) ownedPolicyPages=Array.from({length:27},(_,i)=>Number(owned.readBigUInt64LE(i*8))); const physicalPlan=k1100PolicyPhysicalCaptures(view,selectedSymbols,priorAuthority); if(ownedPolicyPages)for(const[address,i]of ownedPolicyPages.map((v,i)=>[v,i])) if(!physicalPlan.some(p=>p.name==='policyPage'+i))physicalPlan.push({name:'policyPage'+i,val:address,size:4096}); const physical=[]; for(const capture of physicalPlan){ const p=join(temporary,directoryPrefix+'-'+capture.name+'.bin'); await request('pmemsave',{val:capture.val,size:capture.size,filename:p}); const saved=join(directory,directoryPrefix+'-'+capture.name+'.bin');copyFileSync(p,saved); physical.push({...capture,artifact:artifact(saved)}); } const diagnosticScalars={}; for(const name of ['LANDING_ERROR','PUBLISHED_CURRENT']){ const symbol=selectedSymbols['OS_K1100_'+name]; const p=join(temporary,directoryPrefix+'-'+name+'.bin'); await request('pmemsave',{val:symbol.address,size:symbol.size,filename:p}); const saved=join(directory,directoryPrefix+'-'+name+'.bin');copyFileSync(p,saved); diagnosticScalars[name]=artifact(saved); } await gdb.writeSequence(selectedSymbols.OS_K1100_CHECKPOINT_ACK.address,sequence-1n,sequence); await request('cont');assert.equal((await request('query-status')).status,'running'); policyArchives.push({ordinal,sequence:String(sequence),code:'0x'+header.readBigUInt64LE(8).toString(16), counter:String(header.readBigUInt64LE(16)),frequency:String(header.readBigUInt64LE(24)), header:artifact(savedHeader),state,physical,diagnosticScalars}); policyArchiveAt=Date.now(); console.log('POLICY ARCHIVE '+ordinal+' CODE '+policyArchives.at(-1).code); } if(threadFatal&&threadsFatalCheckpoints.length===2&&stopped.test(serial)){await delay(30);serial=readFileSync(serialPath,'utf8');break;} if(fatal&&exceptionsCheckpoints.length===1){await delay(30);serial=readFileSync(serialPath,'utf8');break;} if((stopped.test(serial)&&serial.includes('K1100: DRAFT-ACTUAL-POLICY-RETURN NO-CANONICAL-CLAIM'))||serial.includes('K1100: NEGATIVE EARLY-HOUR DURATION-REJECTED SNAPSHOT-UNCHANGED')||child.exitCode!==null||child.signalCode!==null)break; if(policyArchiveAt&&Date.now()-policyArchiveAt>120000)break; if(hostHourStartMs&&performance.now()-hostHourStartMs>4300000)break; await delay(20); } const serialLog=join(directory,'serial.log');copyFileSync(serialPath,serialLog); if(row.policyProbeMode===2){ assert.ok(serial.includes('TURKOS/OS/K1100: NEGATIVE EARLY-HOUR DURATION-REJECTED SNAPSHOT-UNCHANGED')); assert.ok(!serial.includes('TURKOS/OS/K640: PASS')); assert.ok(!serial.includes('K1100: DRAFT-ACTUAL-POLICY-RETURN NO-CANONICAL-CLAIM')); assert.equal(policyArchives.at(-1)?.code,'0x10'); } else { assert.ok(serial.includes('TURKOS/OS/K640: PASS')); assert.ok(serial.includes('K1100: DRAFT-ACTUAL-POLICY-RETURN NO-CANONICAL-CLAIM')); assert.ok(serial.includes('TURKOS/OS/K1540: PASS')); const gets=[...serial.matchAll(/TURKOS\/OS\/K1540-GET: LBA=0x([a-f0-9]+) USEDIDX=0x([a-f0-9]+) USEDID=0x([a-f0-9]+) USEDLEN=0x([a-f0-9]+) STATUS=0x([a-f0-9]+)/g)]; assert.equal(gets.length,34,'K1540 physical backup GPT recovery read'); const expectedLbas=[1n,2047n]; for(let sector=0n;sector<32n;sector++)expectedLbas.push(2015n+sector); assert.deepEqual(gets.map(get=>BigInt('0x'+get[1])),expectedLbas); for(const [i,get] of gets.entries()){ assert.equal(BigInt('0x'+get[2]),i<2?BigInt(i+1):BigInt((i-2)%4+1)); assert.equal(BigInt('0x'+get[3]),0n); assert.equal(BigInt('0x'+get[4]),513n); assert.equal(BigInt('0x'+get[5]),0n); } assert.ok(serial.includes('TURKOS/OS/K1540-RECOVERY: PHYSICAL=READ BACKUP=32 STATUS=DEGRADED PRIMARY=BAD-CRC MISMATCH=REJECTED MOUNT=UNCHANGED FRAMES=RETURNED')); const inversion=serial.match(/TURKOS\/OS\/K1090: DELAY=0x([a-f0-9]+) WAITER=0x([a-f0-9]+) OWNER=0x([a-f0-9]+) CHAIN=0x([a-f0-9]+)/); assert.ok(inversion,'K1090 physical guest inversion marker'); assert.ok(BigInt('0x'+inversion[1])>0n); assert.equal(BigInt('0x'+inversion[2]),0n); assert.equal(BigInt('0x'+inversion[3]),1n); assert.equal(BigInt('0x'+inversion[4]),1n); assert.equal((serial.match(/TURKOS\/OS\/K1090: PASS/g)??[]).length,1); const reported=policyArchives.at(-1).state.find(row=>row.name==='OS_K1090_INVERSION_REPORTED'); assert.ok(reported); assert.equal(hashAt(root,reported.artifact.path),reported.artifact.sha256); assert.equal(readFileSync(join(root,reported.artifact.path)).readBigUInt64LE(),1n); const busyLoop=policyArchives.at(-1).state.find(row=>row.name==='OS_K1090_BUSY_LOOP_REJECTED'); assert.ok(busyLoop); assert.equal(hashAt(root,busyLoop.artifact.path),busyLoop.artifact.sha256); assert.equal(readFileSync(join(root,busyLoop.artifact.path)).readBigUInt64LE(), BigInt(row.policyProbeMode===5)); assert.equal(serial.includes('TURKOS/OS/K1090: INJECTED-BUSYLOOP-REJECTED LIVE-RECORDS-UNCHANGED'), row.policyProbeMode===5); const accounting=serial.match(/TURKOS\/OS\/K1095: TICKS=0x([a-f0-9]+) CPU-RUNNING=0x([a-f0-9]+) CPU-IDLE=0x([a-f0-9]+) MEMBER-TICKS=0x([a-f0-9]+) SLEEPING=0x([a-f0-9]+)/); assert.ok(accounting,'K1095 physical guest accounting marker'); const [ticks,running,idle,members,sleeping]=accounting.slice(1).map(value=>BigInt('0x'+value)); assert.ok(ticks>0n && sleeping>0n); assert.equal(running+idle,ticks); assert.ok(members>=ticks); assert.equal((serial.match(/TURKOS\/OS\/K1095: PASS/g)??[]).length,1); const accountingReported=policyArchives.at(-1).state.find(row=>row.name==='OS_K1095_ACCOUNTING_REPORTED'); const doubleClass=policyArchives.at(-1).state.find(row=>row.name==='OS_K1095_DOUBLE_CLASS_REJECTED'); for(const item of [accountingReported,doubleClass]){ assert.ok(item); assert.equal(hashAt(root,item.artifact.path),item.artifact.sha256); } assert.equal(readFileSync(join(root,accountingReported.artifact.path)).readBigUInt64LE(),1n); assert.equal(readFileSync(join(root,doubleClass.artifact.path)).readBigUInt64LE(), BigInt(row.policyProbeMode===6)); assert.equal(serial.includes('TURKOS/OS/K1095: INJECTED-DOUBLE-CLASS-REJECTED LIVE-RECORDS-UNCHANGED'), row.policyProbeMode===6); const lateWake=policyArchives.at(-1).state.find(row=>row.name==='OS_K1100_LATE_WAKE_REFUSALS'); const longRun=policyArchives.at(-1).state.find(row=>row.name==='OS_K1100_LONG_RUN_REPORTED'); for(const item of [lateWake,longRun]){ assert.ok(item); assert.equal(hashAt(root,item.artifact.path),item.artifact.sha256); } assert.equal(readFileSync(join(root,lateWake.artifact.path)).readBigUInt64LE(), row.policyProbeMode===7?1000n:0n); assert.equal(readFileSync(join(root,longRun.artifact.path)).readBigUInt64LE(), BigInt(row.policyProbeMode===3)); assert.equal(serial.includes('TURKOS/OS/K1100: LATE-GENERATION-WAKE-STORM-REJECTED ATTEMPTS=0x00000000000003e8 LIVE-RECORDS-UNCHANGED'), row.policyProbeMode===7); assert.equal((serial.match(/TURKOS\/OS\/K1100: PASS/g)??[]).length, Number(row.policyProbeMode===3)); if(row.policyProbeMode===3){ const hour=serial.match(/TURKOS\/OS\/K1100: HOUR-TICKS=0x([a-f0-9]+) CPU-RUNNING=0x([a-f0-9]+) CPU-IDLE=0x([a-f0-9]+) ELAPSED-COUNTER=0x([a-f0-9]+)/); assert.ok(hour); const [ticks,running,idle,elapsed]=hour.slice(1).map(value=>BigInt('0x'+value)); assert.ok(ticks>0n&&elapsed>0n); assert.equal(running+idle,ticks); } assert.equal(policyArchives.at(-1)?.code,'0x400'); await request('stop');assert.equal((await request('query-status')).status,'paused'); const argumentLine=serial.split(String.fromCharCode(10)).find(line=>line.startsWith('TURKOS/OS/K640: ARGUMENTS ')); const argumentMatch=argumentLine?.match(/witness-x0=0x([a-f0-9]{16})/); assert.ok(argumentMatch,'predecessor DTB address comes from actual serial'); const dtbAddress=Number.parseInt(argumentMatch[1],16); const captures=[],dumps={},blobs={},requests=[]; async function predecessorCapture(name,val,size,symbol=null,physical=false){ assert.ok(Number.isSafeInteger(val)&&Number.isSafeInteger(size)&&size>0 &&val>=0&&Number.isSafeInteger(val+size)); if(!physical)assert.ok(val>=0x40000000 &&val+size<=0x40000000+row.memoryMiB*1024*1024); const target=join(temporary,'ancestor-final-'+name+'.bin'),before=qmp.transcript.length; await request('pmemsave',{val,size,filename:target}); const tx=qmp.transcript.slice(before).find(e=>e.direction==='tx'&&e.message.execute==='pmemsave'); assert.ok(tx);const saved=join(directory,'ancestor-final-'+name+'.bin'); copyFileSync(target,saved);const bytes=readFileSync(saved); assert.equal(bytes.length,size); captures.push({name,val,size,...(symbol?{symbol}:{})}); dumps[name]=artifact(saved);blobs[name]=bytes; requests.push({id:tx.message.id,name,val,size,filename:target}); } await predecessorCapture('loadedImage',selectedSymbols._image_start.address,immutableBytes); await predecessorCapture('dtbHeader',dtbAddress,40); const dtbBytes=blobs.dtbHeader.readUInt32BE(4); assert.equal(blobs.dtbHeader.readUInt32BE(0),0xd00dfeed); assert.ok(dtbBytes>=40&&dtbBytes<=2*1024*1024); await predecessorCapture('dtb',dtbAddress,dtbBytes); for(const [name,symbol,size] of [ ['arguments','OS_K640_LOADER_ARGUMENTS',24], ['diagnosticEvidence','OS_K680_EVIDENCE',64], ['runtimeEvidence','OS_K660_RUNTIME_EVIDENCE',72], ['runtimeBaseline','OS_K680_RUNTIME_BASELINE',72], ['baselineIrqCount','OS_K680_BASELINE_IRQ_COUNT',8], ['runtimeIrqCount','OS_K660_IRQ_COUNT',8], ['secretBytes','OS_K680_SECRET_BYTES',Buffer.byteLength('K680-PRIVATE-CANARY-9a7F-DO-NOT-LOG')], ['userState','OS_K680_USER_STATE',40], ['platformEvidence','OS_K700_EVIDENCE',512], ['frameEvidence','OS_K720_EVIDENCE',512], ['frameFreeInventory','OS_K720_FREE_INVENTORY',1024], ['frameLiveInventory','OS_K720_LIVE_INVENTORY',512], ...metadataCaptures,...buddyCaptures,...heapCaptures,...dmaCaptures, ...pageTablesCaptures,...addressSpacesCaptures,...mappingCaptures, ...userCopyCaptures,...pageFaultsCaptures,...exceptionsCaptures, ...gicCaptures,...clockCaptures,...lockingCaptures, ...deferredWorkCaptures,...threadsCaptures,...contextSwitchCaptures, ...runqueueCaptures,...k1080WaitCaptures,...k1080WaitDeferredBatchCaptures]) await predecessorCapture(name,selectedSymbols[symbol].address,size??selectedSymbols[symbol].size,symbol); for(const capture of k1080WaitPhysicalCaptures(blobs,selectedSymbols,row)) await predecessorCapture(capture.name,capture.val,capture.size,capture.symbol??null,true); predecessorFinal={ordinal:policyArchives.length,afterReturn:true,captures,dumps,requests}; json(join(directory,'predecessor-final.json'),predecessorFinal); await request('cont');assert.equal((await request('query-status')).status,'running'); } let stall=null; if(!serial.includes('K1100: DRAFT-ACTUAL-POLICY-RETURN NO-CANONICAL-CLAIM')){ await request('stop'); const registers=String(await request('human-monitor-command',{'command-line':'info registers'})); const registerPath=join(directory,'stalled-registers.log');writeFileSync(registerPath,registers); const state=[]; for(const capture of k1100PolicyStateCaptures(selectedSymbols)){ const path=join(temporary,'stalled-'+capture.name+'.bin'); await request('pmemsave',{val:capture.val,size:capture.size,filename:path}); const saved=join(directory,'stalled-'+capture.name+'.bin');copyFileSync(path,saved); state.push({...capture,artifact:artifact(saved)}); } const scalars={};for(const name of ['CHECKPOINT_ACK','CHECKPOINT_READY','CHECKPOINT_SEQUENCE','PHASE','EXPECTED_VALID','OWNERS_LIVE','TIMER_LIVE','SOURCE_LIVE','IRQ_COUNT']){ const symbol=selectedSymbols['OS_K1100_'+name],capture=state.find(r=>symbol.address>=r.val&&symbol.address+8<=r.val+r.size); assert.ok(capture,name);const bytes=readFileSync(join(root,capture.artifact.path)); scalars[name]=String(bytes.readBigUInt64LE(symbol.address-capture.val)); } for(const name of ['LANDING_ERROR','PUBLISHED_CURRENT']){ const symbol=selectedSymbols['OS_K1100_'+name],path=join(temporary,'stalled-'+name+'.bin'); await request('pmemsave',{val:symbol.address,size:symbol.size,filename:path}); const saved=join(directory,'stalled-'+name+'.bin');copyFileSync(path,saved); scalars[name]=readFileSync(path).toString('hex'); } let timerWait=null; if(selectedSymbols.OS_K1100_TIMER_STACK_REGISTERS){ const symbol=selectedSymbols.OS_K1100_TIMER_STACK_REGISTERS; const path=join(temporary,'stalled-timer-wait.bin'); await request('pmemsave',{val:symbol.address,size:symbol.size,filename:path}); const saved=join(directory,'stalled-timer-wait.bin');copyFileSync(path,saved); timerWait=artifact(saved); } stall={registers:artifact(registerPath),state,scalars,timerWait}; } json(join(directory,'hour-rsp.json'),gdb.hourTranscript); json(join(directory,'whole-rsp.json'),gdb.wholeTranscript); json(join(directory,'qmp.json'),qmp.transcript); json(join(directory,'timeline.json'),timeline); json(join(directory,'wait-checkpoints.json'),waitCheckpoints); json(join(directory,'deferred-batches.json'),deferredBatches); json(join(directory,'ancestor-checkpoints.json'),{ checkpoints,pageTableCheckpoint,addressSpaceCheckpoints,mappingCheckpoints, userCopyCheckpoints,pageFaultsCheckpoints,exceptionsCheckpoints,gicCheckpoints, clockCheckpoints,lockingCheckpoints,deferredWorkCheckpoints,threadsCheckpoints, threadsFatalCheckpoints,contextSwitchCheckpoints,runqueueCheckpoints, waitCheckpoints,deferredBatches,metadataHeapReturnPool,addressSpaceReturnPool,userCopyReturnPool,pageFaultReturnPool,exceptionReturnPool, networkSent:network.sent.map(frame=>frame.toString('base64')), networkReceived:network.received.map(frame=>frame.toString('base64'))}); const diagnostic={schema:'turkos-k1100-policy-product-physical-matrix-spike-diagnostic/v1', status:serial.includes('K1100: NEGATIVE EARLY-HOUR DURATION-REJECTED SNAPSHOT-UNCHANGED')?'EXPECTED_NEGATIVE_REFUSAL':serial.includes('K1100: DRAFT-ACTUAL-POLICY-RETURN NO-CANONICAL-CLAIM')&&serial.includes('K640: PASS')?'GUEST_RETURNED':'GUEST_INCOMPLETE', guestAccepted:false,numericAccepted:false,row,archives:policyArchives,stall, hostHourElapsedSeconds:hostHourStartMs!==null&&hostHourEndMs!==null?(hostHourEndMs-hostHourStartMs)/1000:null, hostHourMeasured:hostHourStartMs!==null&&hostHourEndMs!==null&&hostHourEndMs-hostHourStartMs>=3600000, hourRsp:artifact(join(directory,'hour-rsp.json')), wholeRsp:artifact(join(directory,'whole-rsp.json')), qmp:artifact(join(directory,'qmp.json')), timeline:artifact(join(directory,'timeline.json')), waitProof:artifact(join(directory,'wait-checkpoints.json')), deferredProof:artifact(join(directory,'deferred-batches.json')), ancestorProof:artifact(join(directory,'ancestor-checkpoints.json')), predecessorFinal:predecessorFinal?artifact(join(directory,'predecessor-final.json')):null, sourceBuild:{path:spikePath,sha256:hashAt(root,spikePath)}, deviceFixture:spike.deviceFixture,blockDisk:blockDiskArtifact, sharedFixture:{path:'userspace/tests/service_registry.rs',sha256:sharedFixtureHash, afterSha256:hashAt(root,'userspace/tests/service_registry.rs')}, serial:artifact(serialLog),networkSent:network.sent.length,networkReceived:network.received.length, preexistingIpv6Multicast, waitCheckpoints:waitCheckpoints.length,deferredBatches:deferredBatches.length, exitCode:child.exitCode,exitSignal:child.signalCode}; json(join(directory,'diagnostic.json'),diagnostic); console.log('POLICY DIAGNOSTIC '+JSON.stringify({status:diagnostic.status,archives:policyArchives.length, waitCheckpoints:diagnostic.waitCheckpoints,deferredBatches:diagnostic.deferredBatches,report:relative(root,join(directory,'diagnostic.json'))})); return; } catch (error) { if(qmp){try{await qmp.request('stop');const registers=await qmp.request('human-monitor-command',{'command-line':'info registers'});writeFileSync(join(directory,'failed-registers.log'),registers);}catch{}} if(qmp){for(const[name,symbol,size]of [...k1080WaitDeferredBatchCaptures,...k1080WaitCaptures,...runqueueCaptures,...contextSwitchCaptures,...threadsCaptures,...deferredWorkCaptures,...lockingCaptures,...exceptionsCaptures]){try{await qmp.request('pmemsave',{val:selectedSymbols[symbol].address,size:size??selectedSymbols[symbol].size,filename:join(directory,`failed-${name}.bin`)});}catch{break;}}} if(network){for(const [stem,frames]of [['sent',network.sent],['received',network.received]])frames.forEach((frame,i)=>writeFileSync(join(directory,`failed-host-${stem}-${i}.bin`),frame));} if(gdb){json(join(directory,'failed-rsp.json'),gdb.transcript);json(join(directory,'failed-batch-rsp.json'),gdb.batchTranscript);json(join(directory,'failed-whole-rsp.json'),gdb.wholeTranscript);} json(join(directory,'failed-deferred-batches.json'),deferredBatches); json(join(directory,'failed-timeline.json'),timeline); writeFileSync(join(directory, 'failed-serial.log'), existsSync(serialPath) ? readFileSync(serialPath) : serial); writeFileSync(join(directory, 'failed-stderr.log'), clean(stderr)); if (qmp) json(join(directory, 'failed-qmp.json'), qmp.transcript); json(join(directory, 'failure.json'), { accepted: false, error: clean(error.message) }); throw error; } finally { gdb?.close();network?.close();qmp?.close(); if (child && child.exitCode === null && child.signalCode === null) await stopDisposableChild(child); rmSync(temporary, { recursive: true, force: true }); } } const productCases=k1080WaitCases.filter(row=>row.profile==='product'); assert.equal(productCases.length,12); const selectedProfiles=productCases.filter(row=>row.bankProfile==='one-bank'); assert.equal(selectedProfiles.length,6); const selectedK1540 = process.env.TURKOS_K1540_UEFI_SMOKE ? selectedProfiles.filter(row=>row.route==='uefi').slice(0,1) : process.env.TURKOS_K1540_SMOKE ? selectedProfiles.slice(0,1) : selectedProfiles; for(const base of selectedK1540) { await guest({...base,id:base.id+'-mode-99',policyProbeMode:99}); console.log('K1540 PARTITIONS RECOVERY MATRIX GUEST '+base.id); } runnerPassed=true; }catch(error){lifecycleFailure=String(error.message).split(root).join('');throw error; }finally{ const guestCleanup=[];for(const child of ownedGuestChildren)guestCleanup.push({pid:child.pid??null,signals:await stopDisposableChild(child),exitCode:child.exitCode,exitSignal:child.signalCode}); const guardianCleanup=guardianSpawned?await stopDisposableChild(powerGuardian):[]; const inputsAfter=runqueueInputs(root); const sourceInputsStable=JSON.stringify(inputsAfter)===JSON.stringify(inputsBefore); const allOwnedGuestsStopped=ownedGuestChildren.every(c=>c.exitCode!==null||c.signalCode!==null); const guardianStopped=!guardianSpawned||powerGuardian.exitCode!==null||powerGuardian.signalCode!==null; writeFileSync(lifecyclePath,JSON.stringify({schema:'turkos-wait-scoped-lifecycle/v1',status:runnerPassed&&sourceInputsStable&&allOwnedGuestsStopped&&guardianStopped?'RUNNER_PASSED':'RUNNER_FAILED',startedAt:lifecycleStartedAt,completedAt:new Date().toISOString(),hostElapsedNanoseconds:String(process.hrtime.bigint()-lifecycleStart),sourceInputsStable,inputsBefore,inputsAfter,allOwnedGuestsStopped,guestCleanup,guardian:{executable:'/usr/bin/caffeinate',argv:['-i','-w',String(process.pid)],pid:powerGuardian.pid??null,spawned:guardianSpawned,stopped:guardianStopped,cleanupSignals:guardianCleanup,exitCode:powerGuardian.exitCode,exitSignal:powerGuardian.signalCode,stderr:guardianStderr},globalPowerSettingsChanged:false,failure:lifecycleFailure},null,2)+'\n'); }