Files
Acelogic 1510d8c6ce Snapintosh public release
An EL2 monitor/hypervisor and toolchain that boots macOS 27 on the ASUS A16
(Snapdragon X2 Elite), with an Adreno Metal plug-in and IOGPU kext, and
air2ir3, an AIR to Mesa ir3 shader compiler.

MIT, with GPL-2.0 components listed in LICENSE and THIRD_PARTY_NOTICES.md.
No Apple, Qualcomm, ASUS or Microsoft binaries are included.
2026-10-21 21:26:36 -04:00

100 lines
5.1 KiB
C

/* SPDX-License-Identifier: MIT */
#pragma once
#include <stdint.h>
/* Exact change witness for the monitor's 4K table arena (SNAP_USER_TREE_MEMO).
*
* One word per arena page: bits 63..16 hold the page's write generation, the
* value of the arena clock when the page was last noted; bits 15..0 hold a
* content summary owned by the user-view walker. The owner must note a page
* before any byte of it can change by any path (descriptor store, allocator
* zeroing, mapped-pointer transaction), and note it as allocated whenever the
* table allocator hands it out. Only allocator-issued pages are eligible, so
* directly carved monitor storage is never summarized or trusted. A note never
* makes a stale claim current: it advances the clock and clears the summary.
* Clock saturation permanently disables every claim. The caller serializes all
* notes, walks and syncs under one service lock; no claim survives a note. */
#include "../compat/monitor-arena.h"
#define SPRR_TABLE_MEMO_PAGES MONITOR_ARENA_PAGES
#define SPRR_TABLE_MEMO_POOL UINT64_C(0x8000) /* issued by the table allocator */
#define SPRR_TABLE_MEMO_SCAN UINT64_C(0x4000) /* summary describes current bytes */
#define SPRR_TABLE_MEMO_HAS9 UINT64_C(0x0004) /* at least one class9 leaf */
#define SPRR_TABLE_MEMO_LEVEL UINT64_C(0x0003) /* level the summary was taken at */
#define SPRR_TABLE_MEMO_EMPTY_SHIFT 3 /* 7 bits: empty eight-word groups */
#define SPRR_TABLE_MEMO_CLOCK_MAX ((UINT64_C(1)<<48)-1)
/* A transaction whose ordinal is a multiple of this recomputes everything and
* checks every claim it would otherwise have used. Setting force makes the next
* memo transaction do the same (for callers verifying their own no-op proofs). */
#define SPRR_TABLE_MEMO_SAMPLE 64u
struct sprr_table_memo_stats {
uint64_t calls; /* memo transactions: all-CPU refreshes and one-CPU syncs */
uint64_t samples; /* transactions fully recomputed against their claims */
uint64_t checked; /* individual claims verified by those samples */
uint64_t mismatches; /* claims contradicted by recomputation (must stay zero) */
uint64_t scan_hits; /* refresh (pass3) level3 scans replaced by a summary */
uint64_t scan_misses; /* refresh (pass3) level3 scans performed */
uint64_t copy_hits; /* private destination pages proven current, not compared */
uint64_t copy_misses; /* private destination pages decoded and compared */
uint64_t notes; /* page write notes (changed descriptors, mapped pages) */
uint64_t allocations; /* allocator issues */
uint64_t errors; /* notes outside the arena or with a bad configuration */
uint64_t walk_hits; /* one-CPU proof-miss (pass2) level3 scans replaced */
uint64_t walk_misses; /* one-CPU proof-miss (pass2) level3 scans performed */
uint64_t forced; /* claim-checking recomputations requested through force */
};
struct sprr_table_memo {
uint64_t base, pages, clock, force;
struct sprr_table_memo_stats stats;
uint64_t page[SPRR_TABLE_MEMO_PAGES];
};
static inline int sprr_table_memo_usable(const struct sprr_table_memo *m)
{
return m && m->pages && m->pages<=SPRR_TABLE_MEMO_PAGES && !(m->base&4095) &&
m->clock<SPRR_TABLE_MEMO_CLOCK_MAX && !m->stats.errors;
}
static inline void sprr_table_memo_touch(struct sprr_table_memo *m,uint64_t pa,uint64_t keep)
{
if(pa<m->base || (pa-m->base)/4096>=m->pages || m->pages>SPRR_TABLE_MEMO_PAGES) {
/* Outside the arena nothing can be summarized, so nothing goes stale.
* Count it: callers only note allocated table storage. */
if(m->stats.errors!=UINT64_MAX)m->stats.errors++;
return;
}
uint64_t *w=&m->page[(pa-m->base)/4096];
if(m->clock<SPRR_TABLE_MEMO_CLOCK_MAX)m->clock++;
*w=(m->clock<<16)|(*w&keep);
}
/* Before a changed descriptor store or a writable mapping of the page. */
static inline void sprr_table_memo_note(struct sprr_table_memo *m,uint64_t pa)
{
sprr_table_memo_touch(m,pa,SPRR_TABLE_MEMO_POOL);
if(m->stats.notes!=UINT64_MAX)m->stats.notes++;
}
#if SNAP_FINE_LOCKS
#include "../compat/fine-lock.h"
/* sprr_table_memo_note for a converted call: the global clock and counters
* by atomic RMW (saturating as above); the page word belongs to the root
* whose stripe the caller holds. */
static inline void sprr_table_memo_note_fine(struct sprr_table_memo *m,uint64_t pa)
{
if(pa<m->base || (pa-m->base)/4096>=m->pages || m->pages>SPRR_TABLE_MEMO_PAGES) {
fine_sat_add(&m->stats.errors,1,UINT64_MAX);
return;
}
uint64_t clock=fine_sat_add(&m->clock,1,SPRR_TABLE_MEMO_CLOCK_MAX);
uint64_t *w=&m->page[(pa-m->base)/4096];
*w=(clock<<16)|(*w&SPRR_TABLE_MEMO_POOL);
fine_sat_add(&m->stats.notes,1,UINT64_MAX);
}
#endif
/* Whenever the table allocator issues (and zeroes) the page. */
static inline void sprr_table_memo_alloc(struct sprr_table_memo *m,uint64_t pa)
{
sprr_table_memo_touch(m,pa,0);
if(pa>=m->base && (pa-m->base)/4096<m->pages && m->pages<=SPRR_TABLE_MEMO_PAGES)
m->page[(pa-m->base)/4096]|=SPRR_TABLE_MEMO_POOL;
if(m->stats.allocations!=UINT64_MAX)m->stats.allocations++;
}