diff --git a/probes/idregs.h b/probes/idregs.h index ce1646f..14eb44b 100644 --- a/probes/idregs.h +++ b/probes/idregs.h @@ -72,4 +72,24 @@ static uint64_t id_register(uint32_t crm, uint32_t op2) return v; } + +/* Features this machine does not have, cleared out of the ID registers. + * + * XNU believes what the ID registers say and then uses it. Left alone, the + * Snapdragon advertises SME, so XNU wrote SMCR_EL1 and then `msr TPIDR2_EL0, + * xzr` at 0xfffffe000c245030 -- undefined here, and delivered to EL1 where we + * cannot see it. Every feature we cannot actually support has to be denied at + * the source rather than caught after the fact. */ +#define ID_AA64PFR0_EL1_SVE (0xfUL << 32) +#define ID_AA64PFR1_EL1_SME (0xfUL << 24) + +static uint64_t id_forge(uint32_t crm, uint32_t op2, uint64_t value) +{ + if (crm == 4 && op2 == 0) value &= ~ID_AA64PFR0_EL1_SVE; /* ID_AA64PFR0 */ + if (crm == 4 && op2 == 1) value &= ~ID_AA64PFR1_EL1_SME; /* ID_AA64PFR1 */ + if (crm == 4 && op2 == 4) value = 0; /* ID_AA64ZFR0 */ + if (crm == 4 && op2 == 5) value = 0; /* ID_AA64SMFR0 */ + return value; +} + #endif diff --git a/probes/xnuboot.c b/probes/xnuboot.c index ac3708f..fd8983a 100644 --- a/probes/xnuboot.c +++ b/probes/xnuboot.c @@ -5984,7 +5984,6 @@ int xnuboot_async(uint64_t elr, uint64_t which, const uint64_t *frame) * word and the host reads it as a signed 64-bit value, so a 32-bit -6 arrives * as 0x00000000fffffffa and reads as an EL2 fault with a nonsense ESR. */ static int64_t vcpu_arch_prepare(struct context *c); -static uint64_t id_forge(uint32_t crm,uint32_t op2,uint64_t value); static int secondary_prepare_records(struct context *c); int64_t xnuboot_prepare(void); static int pauth_domain_prepare(struct context *c) @@ -9715,24 +9714,6 @@ static int multipage_fast(struct context *c,const struct sptm_multipage_plan *pl #define SR_CONST_LOWER SYSREG(3, 0, 11, 1, 2) #define SR_CONST_UPPER SYSREG(3, 0, 11, 1, 3) -/* Features this machine does not have, cleared out of the ID registers. - * - * XNU believes what the ID registers say and then uses it. Left alone, the - * Snapdragon advertises SME, so XNU wrote SMCR_EL1 and then `msr TPIDR2_EL0, - * xzr` at 0xfffffe000c245030 -- undefined here, and delivered to EL1 where we - * cannot see it. Every feature we cannot actually support has to be denied at - * the source rather than caught after the fact. */ -#define ID_AA64PFR0_EL1_SVE (0xfUL << 32) -#define ID_AA64PFR1_EL1_SME (0xfUL << 24) - -static uint64_t id_forge(uint32_t crm, uint32_t op2, uint64_t value) -{ - if (crm == 4 && op2 == 0) value &= ~ID_AA64PFR0_EL1_SVE; /* ID_AA64PFR0 */ - if (crm == 4 && op2 == 1) value &= ~ID_AA64PFR1_EL1_SME; /* ID_AA64PFR1 */ - if (crm == 4 && op2 == 4) value = 0; /* ID_AA64ZFR0 */ - if (crm == 4 && op2 == 5) value = 0; /* ID_AA64SMFR0 */ - return value; -} /* AMX is not optional to this kernel. `machine_routines_apple.c:165` decodes * AMXIDR_EL1 as a version: bits 0..5 select versions 1..6, anything set in bits diff --git a/tools/test-idregs.py b/tools/test-idregs.py index 675a31e..da3c7d7 100755 --- a/tools/test-idregs.py +++ b/tools/test-idregs.py @@ -53,7 +53,14 @@ import unittest ROOT = Path(__file__).resolve().parents[1] HEADER = (ROOT / 'probes/idregs.h').read_text() SOURCE = (ROOT / 'probes/xnuboot.c').read_text() -LLVM = Path('/opt/homebrew/opt/llvm/bin') +_LLVM_BIN = os.environ.get('LLVM_BIN') +if _LLVM_BIN: + LLVM = Path(_LLVM_BIN) +elif Path('/opt/homebrew/opt/llvm/bin/llvm-mc').exists(): + LLVM = Path('/opt/homebrew/opt/llvm/bin') +else: + _mc = shutil.which('llvm-mc') + LLVM = Path(_mc).parent if _mc else Path('/usr/bin') # The allocated AArch64 ID registers of op0=3, op1=0, CRn=0, by (CRm, op2): Arm ARM (DDI 0487), the AArch64 # System register index. Everything else in CRm 0-7 is unallocated (CRm=0) or reserved (CRm 1-7). @@ -222,7 +229,8 @@ class Source(unittest.TestCase): self.assertEqual(SOURCE.count(HANDLER), 1) branch = SOURCE[SOURCE.index('if (op0 == 3 && op1 == 0 && crn == 0 && crm < 8 && (iss & 1)) {'):] self.assertTrue(branch[:200].split('\n')[1].strip() == HANDLER) - forge = SOURCE[SOURCE.index('static uint64_t id_forge(uint32_t crm, uint32_t op2, uint64_t value)\n{'):] + forge_src = HEADER if 'static uint64_t id_forge(' in HEADER else SOURCE + forge = forge_src[forge_src.index('static uint64_t id_forge(uint32_t crm, uint32_t op2, uint64_t value)\n{'):] forge = forge[:forge.index('\n}\n')] pairs = {(int(a), int(b)) for a, b in re.findall(r'crm == (\d) && op2 == (\d)', forge)} self.assertEqual(pairs, {(4, 0), (4, 1), (4, 4), (4, 5)})