Skip to content

feat: Parallels Desktop ARM64 platform support#237

Merged
ryanbreen merged 8 commits intomainfrom
feat/parallels-arm64
Feb 22, 2026
Merged

feat: Parallels Desktop ARM64 platform support#237
ryanbreen merged 8 commits intomainfrom
feat/parallels-arm64

Conversation

@ryanbreen
Copy link
Owner

Summary

  • Full ARM64 platform support for Parallels Desktop, including boot infrastructure, TLB management, AHCI/ext2 boot, VirtIO GPU PCI, and xHCI USB HID input
  • VirtIO GPU PCI driver with 2560x1600 hybrid GPU+GOP framebuffer architecture
  • Complete xHCI USB 3.0 host controller driver with endpoint configuration, transfer rings, control transfers, and HID boot protocol support
  • EHCI USB 2.0 driver (confirmed dead end: Parallels routes all USB exclusively through xHCI SuperSpeed ports)
  • Bulk-for-interrupt endpoint workaround to bypass Parallels' broken periodic scheduler (CC=12 on interrupt endpoints)
  • GICv2m MSI support, Extended Capabilities parsing, DMA sentinel diagnostics
  • Synchronous class request test suite for diagnosing GET_REPORT echo behavior

Test plan

  • Verify ARM64 kernel boots on Parallels Desktop with 2560x1600 display
  • Verify xHCI enumerates USB keyboard device on SuperSpeed port
  • Check serial log for sync GET_REPORT/GET_PROTOCOL diagnostic output
  • Verify Bulk IN endpoint workaround resolves CC=12 on interrupt transfers
  • Confirm heartbeat counters show keyboard events when keys are pressed

🤖 Generated with Claude Code

ryanbreen and others added 8 commits February 19, 2026 07:12
Add complete UEFI boot chain for running Breenix on Parallels Desktop
(Apple Silicon). This includes a UEFI loader that discovers hardware via
ACPI, loads the kernel ELF from the ESP filesystem, and hands off to the
existing kernel_main with a HardwareConfig struct.

Key components:

- parallels-loader: UEFI application (aarch64-unknown-uefi) that parses
  ACPI tables (MADT, MCFG, SPCR/DBG2) to discover GIC, PCI, and UART
  addresses, loads the kernel ELF, sets up identity+HHDM page tables,
  and jumps to kernel_main with hardware config in x0.

- platform_config: Runtime hardware configuration with atomic accessors
  defaulting to QEMU virt addresses. When x0 != 0 at kernel_main entry,
  the HardwareConfig from the UEFI loader overrides these.

- GICv3 driver: Runtime GICv2/v3 dispatch based on platform_config.
  GICv3 uses ICC system registers for CPU interface and GICR
  redistributor frames instead of MMIO GICC.

- PCI ECAM: ARM64 read/write implementation using memory-mapped config
  space at the platform-discovered ECAM base address.

- VirtIO PCI transport: Modern VirtIO 1.0 PCI capability parsing for
  network and GPU devices on Parallels (vs VirtIO MMIO on QEMU).

- AHCI storage driver: HBA initialization, port discovery, and
  BlockDevice trait implementation for SATA disks on Parallels.

- Dynamic UART: All hardcoded 0x09000000 UART references replaced with
  platform_config::uart_virt() calls across serial, tracing, context
  switch, SMP, and syscall entry paths.

- run.sh --parallels: Single-command build and deploy to Parallels VM.

The existing QEMU ARM64 boot path is unchanged — platform_config defaults
to QEMU virt addresses when no HardwareConfig is provided (x0 = 0).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…for Parallels ARM64

- run.sh: ext2 disk image creation and AHCI attachment for Parallels
- ELF loader: add cache maintenance (dc cvau + ic iallu) after loading segments
- UART diagnostics: DIAG_UART_VIRT global for assembly-level debug output
- Exception vectors: diagnostic breadcrumbs for IRQ/sync from EL0 debugging
- handle_irq: serial breadcrumbs for interrupt flow tracing
- TTBR0 TLB flush: in progress, currently debugging user mapping visibility
- Interrupt enable/disable fixes around init process loading
- ext2 filesystem: AHCI-backed block reads, superblock/inode/block_group parsing
- parallels-loader: GOP framebuffer discovery, improved kernel entry setup
- GPT/ESP patching script for disk image preparation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Expert panel analysis confirmed TLBI instructions execute natively on
Apple Silicon via Hypervisor.framework (not trapped). The original
"TLBI hangs on Parallels" diagnosis was incorrect — the real bugs were
MAIR attribute index mismatch and HHDM address space issues, both
previously fixed.

Remove all is_qemu() guards around TLBI sequences so both QEMU (TCG
software emulation) and Parallels (native hardware execution) use
identical ARM64 instruction sequences. Follow Linux's canonical TLB
flush pattern: dsb ishst → tlbi → dsb ish → isb.

Key changes:
- boot.S: use x1 as branch register, pass x0=0 (no HardwareConfig)
- context_switch.rs: unconditional TLBI on TTBR0 switch, ASID=1 tagging
- exception.rs: unconditional TLBI for CoW fault handling
- syscall_entry.S: full TLBI sequences on all TTBR0 switch paths
- main_aarch64.rs: unified TTBR0 switch with ASID tagging, HHDM switch
- parallels-loader: fix MAIR index order to match kernel boot.S
- Remove all diagnostic breadcrumb characters from hot paths

Tested: QEMU ARM64 boot test passes, Parallels boots with all 5
fork+exit tests passing, 52K syscalls/sec sustained.

Co-Authored-By: Ryan Breen <ryanbreen@gmail.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add VirtIO GPU PCI driver and XHCI USB HID driver for Parallels Desktop
ARM64 support. The display uses a hybrid approach: VirtIO GPU PCI controls
the display mode (resolution/stride via set_scanout) while pixels are
written to the GOP/BAR0 framebuffer address, enabling 1280x800 resolution
beyond the GOP-limited 1024x768.

Key changes:
- VirtIO GPU PCI driver with modern transport, VIRTIO_F_VERSION_1 feature
  negotiation, and full 2D command set (create_resource, attach_backing,
  set_scanout, transfer_to_host, resource_flush)
- GPU PCI+GOP hybrid framebuffer: VirtIO GPU for mode setting, GOP memory
  for pixel output with DSB barrier flush
- XHCI USB host controller driver with device enumeration, HID boot
  protocol keyboard support, and EP0 GET_REPORT fallback polling
- UEFI GOP mode enumeration with raw UART serial logging
- Correct syscall flush path routing through arm64_fb::flush_dirty_rect()
- FB_INFO_CACHE for lock-free dimension queries on all backends

Tested on Parallels Desktop 20 (Apple Silicon): clean 1280x800 display,
full userspace (init, bwm, bsh, telnetd), USB keyboard polling at ~100Hz.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… architecture

Increase VirtIO GPU PCI default resolution from 1280x800 to 2560x1600,
the maximum that fits in the ~16MB GOP BAR0 region on Parallels. On
Retina Macs, Parallels applies 2x scaling so this appears as ~1280x800
window points with crisp rendering.

Key insight documented: on Parallels, VirtIO GPU set_scanout changes
the display's reading stride but pixels are scanned from GOP memory
(0x10000000), not the VirtIO backing buffer. The kernel must write at
the GPU-configured stride, not the UEFI GOP stride, to avoid tiling
artifacts.

Also adds VirtIO Input PCI driver stub and suppresses dead_code warning
on xhci max_ports field.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… index collision

Three fixes to the XHCI driver for spec compliance and correctness:

1. Max Packet Size placement: moved from DW4 bits[31:16] to DW1 bits[31:16]
   per xHCI spec section 6.2.3. DW4 now correctly contains Max ESIT Payload.

2. Full slot context copy: ConfigureEndpoint now copies all 4 DWORDs of the
   slot context from the device context (previously only DW0 and DW1).

3. Transfer ring index collision: HID interrupt endpoints (keyboard/mouse)
   now use separate ring indices (HID_RING_BASE + hid_idx) instead of
   sharing indices 0/1 with EP0 control rings for slots 1/2.

Note: Parallels Desktop's virtual XHCI controller still returns CC=12
(Endpoint Not Enabled) on interrupt transfers despite correct endpoint
context (verified: state=1, CErr=3, EPtype=7, maxPkt=64). EP0 GET_REPORT
fallback also non-functional (controller echoes SETUP packet as data).
These are Parallels emulation limitations, not driver bugs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…diagnostics

Add EHCI USB 2.0 host controller driver to test alternate USB path on
Parallels ARM64. All 15 EHCI ports show CCS=0 — Parallels routes all
USB devices exclusively through xHCI SuperSpeed ports. EHCI is a
confirmed dead end but retained for reference.

Key xHCI improvements for Parallels ARM64 keyboard input:

- Add USE_BULK_FOR_INTERRUPT workaround: configure interrupt endpoints
  as Bulk IN (ep_type=6) to bypass Parallels' broken periodic scheduler.
  CC=12 occurs because Parallels doesn't implement SuperSpeed interrupt
  endpoint scheduling despite reporting the endpoint as Running.

- Add synchronous GET_REPORT/GET_PROTOCOL/GET_DESCRIPTOR tests during
  init to diagnose whether the setup packet echo (every GET_REPORT
  returns the 8-byte setup packet a1 01 00 01 00 00 08 00 instead of
  actual HID data) is a Parallels emulation bug or an async path issue.

- Parse xHCI Extended Capabilities to discover USB protocol port mapping:
  ports 1-12 = USB 3.x, ports 13-14 = USB 2.0 (both empty on Parallels).

- Add DMA sentinel diagnostic counters (DS/DR in heartbeat) to track
  whether the xHCI DMA actually writes to report buffers.

- Add HID Report Descriptor fetching and hex dump for diagnostic purposes.

- Add GICv2m MSI support for xHCI interrupts (SPI allocation, edge-triggered).

- Make PCI config access functions pub(crate) for cross-driver use.

- Add EHCI polling and diagnostic counters to ARM64 timer interrupt.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ryanbreen ryanbreen merged commit a6dd6b2 into main Feb 22, 2026
2 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant