Skip to content

Instantly share code, notes, and snippets.

@IntegralPilot
Last active December 30, 2025 15:00
Show Gist options
  • Select an option

  • Save IntegralPilot/85c355124fe54e670e6d5586c7a07826 to your computer and use it in GitHub Desktop.

Select an option

Save IntegralPilot/85c355124fe54e670e6d5586c7a07826 to your computer and use it in GitHub Desktop.
Booting macOS Kernel 14.7.7 on t6030 via m1n1

Booting macOS Kernel 14.7.7 on t6030 via m1n1

Prerequisites & Warnings

Important: Apple has stopped signing 14.7.7 (23H723), which is the primary build used for this testing.

The next best build to use is 14.8.3 (23J220), as it has a KDK with a matching build number. However, you must use the same macOS version and KDK version.

Warning: If you use 14.8.3, the binary patches (offsets) listed in Section 3, Step 8 and the symbol offsets in Section 4 will likely require modification. I suspect the core kernel functions haven't changed much, but this has not been tested.

Requirements:

  • Target Device: A Mac with t6030 (or similar) architecture.
  • Host Device: Can be a Mac or another OS (Linux), provided it can run Python and serial tools.

1. Setup the Target

Perform these steps on the target Mac.

  1. Open Disk Utility.
  2. From the top bar, select View -> Show All Devices.
  3. Select your internal disk (usually named "Apple SSD...").
  4. Add a new partition (not volume) to this disk. Approximately 40GB is sufficient. Format it as Mac OS Extended (Journaled).
  5. Select the primary APFS container for the internal disk.
  6. Add a new volume (not partition) to this container.
  7. Download Mist: https://github.com/ninxsoft/Mist.
  8. In Mist, select Installers and locate 14.7.7 (23H723). Click the disk icon to download and install it to the partition created in Step 4.
  9. Shut down the target. Hold the power button until "Loading startup options" appears, then select the 14.7.7 Installer.
  10. In the installer, select the new volume created in Step 6 as the destination.
  11. Once installed, boot into the new volume and complete the setup assistant.
  12. Install Xcode Command Line Tools and a Rust toolchain on the 14.7.7 volume.
  13. Install the KDK for 23H723 (if you are using 14.8.3 it must be 23J220) on the 14.7.7 volume (available from Apple Developer Downloads).
  14. Clone the m1n1 repository: https://github.com/AsahiLinux/m1n1.
  15. Modify src/chickens_everest.c. Add the following code inside init_t6030_everest, immediately below UNUSED(rev);:
    msr(s3_1_c15_c1_5, 0x3uL);
    msr(s3_4_c15_c14_6, 0x3uL);
    
    reg_mask(S3_4_C15_C12_1, 0x0, 0x1e);
    (Note: This performs register operations that the kernel attempts to do later; we must do them here so we can NOP them out in the kernel).
  16. Build m1n1 and copy build/m1n1.bin to /Users/Shared on the target.
  17. Open Terminal and change directory to the kernel folder:
    cd /Library/Developer/KDKs/KDK_14.7.7_23H723.kdk/System/Library/Kernels
  18. Run the following command to create a custom kernel collection:
    kmutil create -z -n boot -a arm64e -B ~/dev.kc.macho -V development \
      -k kernel.development.t6030 \
      -r ../Extensions \
      -x $(kmutil inspect -V release --no-header | grep -v "SEPHiber" | awk '{print " -b "$1; }')
  19. Transfer the following files to the Host machine (e.g., via AirDrop):
    • The resulting kernel collection: ~/dev.kc.macho.development
    • The kernel DWARF file: ./kernel.development.t6030.dSYM/Contents/Resources/DWARF/kernel.development.t6030
  20. Reboot the target into 1TR (One True Recovery) by holding the power button during boot.
  21. Select the 14.7.7 volume options.
  22. Open Terminal in Recovery and run:
    bputil -nkcas
    csrutil disable
  23. Configure the custom boot object (replace [YourVolumeName] with your volume name):
    kmutil configure-boot \
      -c /Volumes/[YourVolumeName]/Users/Shared/m1n1.bin \
      --raw \
      --entry-point 2048 \
      --lowest-virtual-address 0 \
      -v /Volumes/[YourVolumeName]
  24. Reboot the target normally. It should boot into m1n1 and display "Waiting for proxy...".
  25. Shut down the target by holding the power button for 10 seconds.

2. Setup the Host

Perform these steps on the host machine.

  1. Install Xcode Command Line Tools and a Rust toolchain.
  2. Clone the m1n1 repository: https://github.com/AsahiLinux/m1n1.
  3. Apply the same patch to src/chickens_everest.c as described in Section 1, Step 15.
  4. Apply this patch: https://patch-diff.githubusercontent.com/raw/AsahiLinux/m1n1/pull/515.diff
  5. Build m1n1.

3. Boot Process

  1. Connect the Host and Target via USB-C (do not use the USB-C port closest to the magsafe on the target).
  2. Boot the Target. It should start m1n1 and await the proxy.
  3. On the Host: Identify the USB serial devices:
    ls /dev/cu.*
    You should see two devices like /dev/cu.usbmodemXXXXXX. One ends in 1 (the m1n1 interface) and the other in 3 (the serial log interface).
  4. Export the m1n1 device variable:
    export M1N1DEVICE=/dev/cu.usbmodem[...1]
  5. In the host's m1n1 folder, chainload and run the guest. Replace [DWARF_PATH] and [KC_PATH] with the locations of the files you copied in Section 1, Step 19:
    python3 proxyclient/tools/chainload.py -r build/m1n1.bin && \
    python3 proxyclient/tools/run_guest.py -S -s [DWARF_PATH] [KC_PATH] -- "debug=0x14e serial=3 -enable-kprintf-spam wdt=-1 clpc=0 keepsyms=1"
  6. You will drop into a Python REPL prompt.
  7. Open a new terminal window on the host to monitor logs:
    picocom -b 115200 /dev/cu.usbmodem[...3]
  8. Back in the REPL prompt: Press ^D (Ctrl+D) to continue execution.
  9. Watch the log output. As soon as you see a line resembling:
    [cpu6] Pass: msr [REG], [VAL] = [VAL] (OK) ([REG_NAME])
    
    Rapidly press ^C (Ctrl+C) in the REPL window to interrupt.
  10. You should now be in the Hypervisor shell. Verify you stopped at the correct point.
    • Correct: The last log line resembles the format above.
    • Incorrect: If the last log is [cpu6] Pass: msr s3_0_c15_c2_4, x13 = 1e004000 (OK) (s3_0_c15_c2_4), you have gone too far.
  11. Apply the in-memory binary patches by running the following Python commands in the REPL:
    init_base = hv.resolve_symbol('com.apple.kernel:_arm_init')
    config_base = hv.resolve_symbol('com.apple.kernel:_configure_misc_apple_regs')
    recount_base = hv.resolve_symbol("com.apple.kernel:_recount_transition")
    
    # NOP instructions
    write32(hv_translate(init_base + 0x7D0), 0xd503201f)
    write32(hv_translate(config_base + 0xc8), 0xd503201f)
    write32(hv_translate(config_base + 0xc8 + 0x4), 0xd503201f)
    write32(hv_translate(config_base + 0xc8 + 0x8), 0xd503201f)
    write32(hv_translate(recount_base) + 0x34, 0xd503201f)
    Note: Ask if these offsets are confusing or fail on build 14.8.3.
  12. Type hv.cont and press Enter.

4. Observed Issues

The boot process is non-deterministic. It may hang immediately, reach a mostly full progress bar, or start various userspace daemons before failing. There is usually no visual panic indication on the device; check the picocom terminal for logs.

Hypothesis

I suspect AppleT6030PMGR is a primary culprit. When testing with minimal kexts and adding them back one by one, this driver appeared to trigger memory corruption, leading to random panics in other drivers. However, AppleT6030PMGR is also required to push the boot process forward; without it, the boot hangs earlier. It is possible that the absence of this driver simply prevents the boot from reaching the stage where the corruption from a different driver occurs. I strongly believe that it is in one of the T6030 specific kexts, at least, where the root cause lies, as m1n1 works fine on M1 & M2 devices.

Below is a list of issues observed over 13 recorded boot attempts. For each issue (each time it happened) I captured the full panic log and all serial output during bootup and can provide it if you want to compare or are interested. Note that for all of them, attempting to continue once XNU trapped our debugger, resulted in a later SERROR (different from the SERROR with no panic described in #1 below).

1. SERROR (3 occurrences)

A severe hardware/memory bus error. The hypervisor catches this and drops to a shell. There is no standard panic log. The last visible logs are always the same and involve launchd:

[System Event] ... [Event: xpcroleaccountd] Doing boot task
[System Event] ... [Event: init_featureflags] Doing boot task

2. Kernel Data Abort in com.apple.filesystems.apfs (2 occurrences)

Backtrace:

  1. _kernel_bootstrap_thread
  2. _bsd_init
  3. _vfs_mountroot
  4. com.apple.filesystems.apfs (Offset 0xae614)
  5. com.apple.filesystems.apfs (Offset 0xab1a4)
    • ...followed by offsets 0x53ac0, 0x378bc, 0x132698, 0x10b8c, 0x10fe4, 0x10e14

3. PAN Assertion Failure (2 occurrences)

Error: copyio.c:94 Assertion failed: __builtin_arm_rsr("pan") != 0

The Kernel expects Privileged Access Never (PAN) to be enabled, but it is 0. I've checked and it seems m1n1 handles PAN correctly, so this suggests kernel state corruption. This may be triggered by an early userspace daemon causing a fatal exception it shouldn't, leading the kernel to attempt a backtrace before killing the process when the kernel is in an unstable or too early state. Or, it could be handelling this exception is expected for the kernel at this stage, but the kernel's internal state is corrupted leading to the faulty check.

Backtrace:

  1. _handle_breakpoint
  2. _exception_triage_thread -> _thread_exception_return
  3. user_take_ast -> ast_taken_user -> _bsd_ast
  4. _postsig_locked -> _exit_with_reason -> _proc_prepareexit
  5. _backtrace_user
  6. _copyin OR _copy_validate

4. Invalid Spinlock (1 occurrence)

Error: Invalid spinlock [address]: <0x0...0> @locks_arm.c:343

Triggered by tccd (Transparency, Consent, and Control daemon) during a syscall.

Backtrace:

  1. [within tccd]
  2. _unix_syscall
  3. _sys_ulock_wait -> _sys_ulock_wait2 -> _ull_get

5. Kernel Data Abort in AppleS5L8940XI2C (1 occurrence)

Happens on IOConfigThread during service matching.

Backtrace:

  1. IOConfigThread
  2. IOService::doServiceMatch -> probeCandidates -> startCandidate
  3. [within AppleS5L8940XI2C]
  4. IOFilterInterruptEventSource
  5. IOInterruptEventSource::registerInterruptHandler

6. ApplePPM Interrupt Error (1 occurrence)

Error: ApplePPM: ... "readPTDEntry returned 0xe00002c7" @ApplePPMPTDManager.cpp:289

(Note: 0xe00002c7 is kIOReturnUnsupported)

Backtrace:

  1. IOInterruptEventSource::checkForWork
  2. [within ApplePMGR]
  3. [within ApplePassthroughPPM]
  4. _Assert

7. ApplePMGR Clock Gate Error (1 occurrence)

Error: ApplePMGR: ... REQUIRE failed: die < _target->_dieCount" @ApplePMGR.cpp:14454

Backtrace:

  1. IOConfigThread -> IOService::doServiceMatch -> probeCandidates -> startCandidate
  2. [within AppleS8000DWI]
  3. [within ApplePMGR]
  4. _panic

8. PAC Failure (1 occurrence)

Error: PAC failure from kernel with IA key while authing x16...

Backtrace:

  1. fleh_dispatch64_common -> _fleh_irq -> _sleh_irq
  2. [within AppleInterruptControllerV3] (Actual PAC failure occurs here)
  3. fleh_dispatch64_common -> _fleh_synchronous -> _sleh_synchronus
  4. _handle_pac_fail -> _sleh_synchronous_sp1 -> _Assert

9. Kalloc Modified After Free (1 occurrence)

Error: [data.kalloc.64]: element modified after free...

Backtrace:

  1. IOService::pmDriverCallout -> IOService::driverSetPowerStateEv
  2. [within AppleSEPManager]
  3. IOCommandGate::runAction -> [within AppleSEPManager]
  4. IODTNVRAM::getProperty -> copyProperty -> copyPropertySymbol -> copyPropertyWithGUIDAndName
  5. keyWithGuidAndCString -> __ZN8OSSymbol11withCStringEPKc
  6. _kalloc_etc -> zalloc_item -> zalloc_log -> _Assert

I strongly believe all of these are caused by some underlying memory or state corruption caused by a kext, as it's completely random which one will occur each boot, and they all seem to be related to memory/state issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment