Files
Snapintosh/tools/test-native-select.c
T
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

106 lines
5.0 KiB
C

/* SPDX-License-Identifier: MIT */
/* compat/native-select.h, the O(1) variant selection the EL0/EL1 boundary and
* the SPRR write handlers call: every (UPERM, PPERM, regime) state against an
* independent model of which variant must be live, the register writes each
* call makes (none when the variant is unchanged), and refusals. */
#include <stdio.h>
#include <stdint.h>
#include <string.h>
static uint64_t ttbr0_writes[64],ttbr1_writes[64];
static unsigned ttbr0_count,ttbr1_count;
#define NATIVE_WRITE_TTBR0(v) (ttbr0_writes[ttbr0_count++&63]=(v))
#define NATIVE_WRITE_TTBR1(v) (ttbr1_writes[ttbr1_count++&63]=(v))
#include "native-select.h"
static unsigned checks,failures;
#define CHECK(x) do{checks++;if(!(x)){failures++;printf("line %d: %s\n",__LINE__,#x);}}while(0)
#define UP SPRR_UPERM_INITIAL
#define PP SPRR_PPERM_INITIAL
#define TPRO SPRR_UPERM_TPRO_WRITE
static const uint64_t T0[2][2]={{0x1000|(UINT64_C(0x104)<<48),0x2000|(UINT64_C(0x105)<<48)},
{0x3000|(UINT64_C(0x106)<<48),0x4000|(UINT64_C(0x107)<<48)}};
static const uint64_t T1[2]={0x5000,0x6000};
/* The model: the variant hardware must walk for this state. */
static unsigned want_w(uint64_t up,uint64_t pp,int el0){return !!((el0 ? up : pp)&TPRO);}
static unsigned want_k(uint64_t pp){return !!(pp&0x100);}
static void reset(void){ttbr0_count=ttbr1_count=0;}
static void test_uninstalled(void)
{
struct native_cpu n;memset(&n,0,sizeof n);reset();
CHECK(native_select(&n,1) && native_select(&n,0));
CHECK(native_set_uperm(&n,UP|TPRO,1) && native_set_pperm(&n,PP|TPRO|0x100,0));
/* Nothing installed, nothing written; the state is still tracked. */
CHECK(!ttbr0_count && !ttbr1_count && n.uperm==(UP|TPRO) && n.pperm==(PP|TPRO|0x100) && !n.el0);
CHECK(n.selects==4 && !n.flips && !n.errors);
}
static void test_install(void)
{
for(unsigned mask=0;mask<16;mask++) {
uint64_t up=UP|((mask&1) ? TPRO:0),pp=PP|((mask&2) ? TPRO:0)|((mask&4) ? 0x100:0);
int el0=!!(mask&8);
/* Over a CPU that ran another address space in the same state. */
struct native_cpu n;memset(&n,0,sizeof n);
CHECK(native_install(&n,T0,T1,up,pp,el0));
uint64_t other[2][2]={{0x7000,0x7000},{0x8000,0x8000}},flips=n.flips;reset();
unsigned w=want_w(up,pp,el0),k=want_k(pp);
/* It names the variant for the caller's sequence and writes nothing. */
CHECK(native_install(&n,(const uint64_t (*)[2])other,0,up,pp,el0)==other[w][k]);
CHECK(native_install(&n,T0,T1,up,pp,el0)==T0[w][k] && !ttbr0_count && !ttbr1_count);
CHECK(n.w==w && n.k==k && n.el0==(uint32_t)el0 && n.installed && n.flips==flips);
CHECK(n.ttbr1[0]==T1[0] && n.ttbr1[1]==T1[1]);
CHECK(native_install(&n,T0,0,up,pp,el0) && !n.ttbr1[0] && !n.ttbr1[1]);
}
}
/* Every call against the model from every state: writes only on a change. */
static void test_transitions(void)
{
for(unsigned from=0;from<16;from++)for(unsigned op=0;op<3;op++)for(unsigned arg=0;arg<8;arg++) {
uint64_t up=UP|((from&1) ? TPRO:0),pp=PP|((from&2) ? TPRO:0)|((from&4) ? 0x100:0);
int el0=!!(from&8);
struct native_cpu n;memset(&n,0,sizeof n);
CHECK(native_install(&n,T0,T1,up,pp,el0));
unsigned w0=n.w,k0=n.k;uint64_t flips=n.flips;reset();
int next_el0=!!(arg&4);int ok;
if(op==0) {ok=native_select(&n,next_el0);}
else if(op==1) {up=UP|((arg&1) ? TPRO:0);ok=native_set_uperm(&n,up,next_el0);}
else {pp=PP|((arg&1) ? TPRO:0)|((arg&2) ? 0x100:0);ok=native_set_pperm(&n,pp,next_el0);}
unsigned w=want_w(up,pp,next_el0),k=want_k(pp);
CHECK(ok && n.w==w && n.k==k && n.el0==(uint32_t)next_el0 && n.uperm==up && n.pperm==pp);
int changed=w!=w0 || k!=k0;
CHECK(ttbr0_count==(unsigned)changed && (!changed || ttbr0_writes[0]==T0[w][k]));
CHECK(ttbr1_count==(unsigned)(k!=k0) && (k==k0 || ttbr1_writes[0]==T1[k]));
CHECK(n.flips==flips+(uint64_t)changed && !n.errors);
}
}
static void test_refusal_and_uninstall(void)
{
uint64_t t0[2][2];memcpy(t0,T0,sizeof t0);t0[1][0]=0;
struct native_cpu n;memset(&n,0,sizeof n);reset();
CHECK(native_install(&n,(const uint64_t (*)[2])t0,T1,UP,PP,1));
/* The missing variant is refused (terminal for the caller) without a write. */
reset();
CHECK(!native_set_uperm(&n,UP|TPRO,1) && n.errors==1 && !ttbr0_count && !ttbr1_count);
CHECK(n.w==0);
/* An install whose reset variant is missing is refused and uninstalls. */
CHECK(!native_install(&n,(const uint64_t (*)[2])t0,T1,UP|TPRO,PP,1) && !n.installed && n.errors==2);
memset(&n,0,sizeof n);CHECK(native_install(&n,T0,T1,UP,PP,0));
native_uninstall(&n);reset();
CHECK(native_set_pperm(&n,PP|TPRO|0x100,0) && native_select(&n,1) && !ttbr0_count && !ttbr1_count);
CHECK(!n.installed && !n.errors);
}
int main(void)
{
test_uninstalled();test_install();test_transitions();test_refusal_and_uninstall();
printf("%s: native variant selection, %u checks, %u failures\n",failures ? "FAIL":"PASS",checks,failures);
return failures!=0;
}