mirror of
https://github.com/YusufOzmen01/quest-kexec.git
synced 2026-10-26 19:37:39 +00:00
Generalize documentation for Meta Quest headsets
This commit is contained in:
4 files changed
+205
-139
No files matched your search
+50
-29
@@ -1,9 +1,12 @@
|
||||
# Build
|
||||
# Build guide
|
||||
|
||||
There are two kernel builds:
|
||||
> This project currently has tested settings only for Meta Quest Pro.
|
||||
|
||||
- **Android kernel:** used to compile `quest_kexec.ko`
|
||||
- **Target kernel:** the patched kernel booted by kexec
|
||||
Two kernel trees are used:
|
||||
|
||||
1. The **Android kernel tree** builds `quest_kexec.ko` for the kernel currently
|
||||
running on the headset.
|
||||
2. The **target kernel tree** builds the custom kernel entered by kexec.
|
||||
|
||||
## Requirements
|
||||
|
||||
@@ -11,59 +14,70 @@ Install:
|
||||
|
||||
- Clang and LLD
|
||||
- `aarch64-linux-gnu-` GCC/binutils
|
||||
- `adb`, Python 3, `dtc`, `fdtput`, `curl`, `make`
|
||||
- `adb`
|
||||
- Python 3
|
||||
- `dtc` and `fdtput`
|
||||
- `curl`, `make` and standard build tools
|
||||
|
||||
## 1. Build the Android kernel tree
|
||||
## Android kernel and loader module
|
||||
|
||||
The loader must match the kernel reported by:
|
||||
Check the running version:
|
||||
|
||||
```sh
|
||||
adb shell uname -r
|
||||
```
|
||||
|
||||
For OS build `51503870024400340`, use Meta kernel commit:
|
||||
|
||||
```text
|
||||
fa2e480a85c6adbcc73dfc4f0ab0728781e14584
|
||||
```
|
||||
|
||||
Save the running config:
|
||||
Use matching source and save the device config:
|
||||
|
||||
```sh
|
||||
mkdir -p android-out
|
||||
adb exec-out 'su -c "zcat /proc/config.gz"' > android-out/.config
|
||||
```
|
||||
|
||||
Disable the automatic git suffix, then build `Image modules`. A full modules
|
||||
build is needed for a correct `Module.symvers`.
|
||||
For the tested Quest Pro release, the source commit is:
|
||||
|
||||
```text
|
||||
fa2e480a85c6adbcc73dfc4f0ab0728781e14584
|
||||
```
|
||||
|
||||
Build the kernel and modules so that `Module.symvers` contains the correct
|
||||
symbol CRCs:
|
||||
|
||||
```sh
|
||||
SRC=/path/to/android-kernel-source
|
||||
OUT=$PWD/android-out
|
||||
LOCAL=-g49638c7a8637
|
||||
|
||||
$SRC/scripts/config --file "$OUT/.config" --disable LOCALVERSION_AUTO
|
||||
|
||||
make -C "$SRC" O="$OUT" ARCH=arm64 CC=clang LD=ld.lld HOSTCC=clang \
|
||||
CROSS_COMPILE=aarch64-linux-gnu- CLANG_TRIPLE=aarch64-linux-gnu- \
|
||||
LOCALVERSION=-g49638c7a8637 olddefconfig
|
||||
LOCALVERSION="$LOCAL" olddefconfig
|
||||
|
||||
make -C "$SRC" O="$OUT" ARCH=arm64 CC=clang LD=ld.lld HOSTCC=clang \
|
||||
CROSS_COMPILE=aarch64-linux-gnu- CLANG_TRIPLE=aarch64-linux-gnu- \
|
||||
LOCALVERSION=-g49638c7a8637 KCFLAGS=-I$SRC/drivers/pinctrl \
|
||||
LOCALVERSION="$LOCAL" KCFLAGS=-I$SRC/drivers/pinctrl \
|
||||
-j"$(nproc)" Image modules
|
||||
```
|
||||
|
||||
## 2. Build the kexec and log modules
|
||||
Build the kexec and log modules:
|
||||
|
||||
```sh
|
||||
make module KDIR="$OUT" LOCALVERSION=-g49638c7a8637
|
||||
modinfo -F vermagic module/quest_kexec.ko
|
||||
make module KDIR="$OUT" LOCALVERSION="$LOCAL"
|
||||
```
|
||||
|
||||
The vermagic must start with the output of `adb shell uname -r`.
|
||||
Verify the result:
|
||||
|
||||
## 3. Build the target kernel
|
||||
```sh
|
||||
modinfo -F vermagic module/quest_kexec.ko
|
||||
adb shell uname -r
|
||||
```
|
||||
|
||||
Use the patched kernel fork:
|
||||
The release strings must match.
|
||||
|
||||
## Target kernel
|
||||
|
||||
For the tested Quest Pro kernel:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/YusufOzmen01/oculus-linux-kernel
|
||||
@@ -71,7 +85,7 @@ cd oculus-linux-kernel
|
||||
git checkout oculus-quest-pro-kernel-master
|
||||
```
|
||||
|
||||
Build it using the Quest Pro config. The target needs at least:
|
||||
Build a raw ARM64 `Image` using the headset config. Required options include:
|
||||
|
||||
```text
|
||||
CONFIG_LOCALVERSION_AUTO=n
|
||||
@@ -82,13 +96,20 @@ CONFIG_PRINTK_TIME=y
|
||||
CONFIG_LOG_BUF_SHIFT=20
|
||||
```
|
||||
|
||||
The result must be a raw ARM64 `Image`.
|
||||
For another Quest model or kernel release, see
|
||||
[HOW_TO_PORT.md](HOW_TO_PORT.md).
|
||||
|
||||
## 4. Build the initramfs
|
||||
## Initramfs
|
||||
|
||||
From this repository:
|
||||
|
||||
```sh
|
||||
make initramfs
|
||||
```
|
||||
|
||||
This downloads and verifies BusyBox 1.36.1, builds it statically for ARM64 and
|
||||
creates `out/initramfs.gz`.
|
||||
This downloads and verifies BusyBox 1.36.1, cross-builds it statically for
|
||||
ARM64 and writes:
|
||||
|
||||
```text
|
||||
out/initramfs.gz
|
||||
```
|
||||
+42
-54
@@ -1,68 +1,56 @@
|
||||
# Port a custom Quest Pro kernel
|
||||
# Porting to another Meta Quest kernel
|
||||
|
||||
This project is for Quest Pro only. Porting here means adapting another Quest
|
||||
Pro 4.19 kernel release, not another headset or SoC.
|
||||
This implementation has only been tested on Meta Quest Pro. Other Quest models
|
||||
use different SoCs, device trees, memory maps and hardware handoff states.
|
||||
|
||||
## 1. Start from the matching Meta source
|
||||
## Same headset, newer kernel
|
||||
|
||||
Find the Meta source commit for the headset OS version. Keep a clean copy for
|
||||
building the Android loader module.
|
||||
1. Get the source matching the new Android release.
|
||||
2. Build `quest_kexec.ko` against its exact config, local version and
|
||||
`Module.symvers`.
|
||||
3. Apply the patches under `kernel/patches/` to the new target source.
|
||||
4. Resolve conflicts carefully in the affected drivers.
|
||||
5. Capture a fresh runtime device tree with `tools/capture.sh`.
|
||||
6. Test first with the supplied RAM-only initramfs.
|
||||
|
||||
## 2. Apply the target patches
|
||||
Important target areas include:
|
||||
|
||||
The maintained kernel fork already contains the changes. For another source
|
||||
revision, apply the patches in order:
|
||||
- ARM64 entry and CPU startup
|
||||
- GIC and SMMU inherited state
|
||||
- RPMh and interconnect voting
|
||||
- display clocks and power domains
|
||||
- USB controller and PHY handoff
|
||||
- AOP/QMP mailbox adoption
|
||||
- SPMI and charger state
|
||||
- retained logging and watchdog recovery
|
||||
|
||||
```sh
|
||||
git am /path/to/quest-pro-kexec/kernel/patches/*.patch
|
||||
```
|
||||
## Another Quest headset
|
||||
|
||||
Resolve conflicts by behavior, not by blindly choosing one side. The important
|
||||
areas are:
|
||||
Do not reuse the Quest Pro physical addresses or device names without checking
|
||||
them. At minimum, determine:
|
||||
|
||||
- ARM64 entry and SMP/GIC state
|
||||
- apps SMMU and msm_bus/RPMh
|
||||
- display clocks/GDSCs/SDE
|
||||
- DWC3 and USB PHY
|
||||
- AOP QMP adoption
|
||||
- SPMI stale IRQ cleanup
|
||||
- camera CPAS/CDM
|
||||
- SMB5 charger handoff
|
||||
- retained log and boot watchdog
|
||||
- target Image, initramfs and DTB staging addresses
|
||||
- safe retained-log RAM
|
||||
- target kernel text offset and maximum image size
|
||||
- CPU, GIC and SMMU setup
|
||||
- USB controller and UDC name
|
||||
- watchdog behavior
|
||||
- platform-device names used by loader shutdown callbacks
|
||||
- AOP/mailbox protocol used by that SoC
|
||||
|
||||
## 3. Keep the required target command line
|
||||
Update `module/loader.c`, `module/transition.S`, `tools/prepare.py` and the target
|
||||
kernel patches for the new board.
|
||||
|
||||
`tools/prep.sh` adds:
|
||||
## First test
|
||||
|
||||
```text
|
||||
rdinit=/init nokaslr qkx_qmp_adopt=1
|
||||
initcall_blacklist=virtual_sensor_driver_init
|
||||
```
|
||||
Keep the first target small:
|
||||
|
||||
Do not use loader-side QMP disconnect. Taking the AP/AOP link down caused a PMIC
|
||||
reset. The target must adopt the inherited link instead.
|
||||
- static BusyBox initramfs
|
||||
- no block-device mounts
|
||||
- USB Ethernet only
|
||||
- retained kernel log enabled
|
||||
|
||||
## 4. Keep the staging layout
|
||||
Verify CPUs, USB and basic device probing before adding a larger userspace.
|
||||
|
||||
```text
|
||||
Image 0x90080000
|
||||
initramfs 0x93000000
|
||||
DTB 0x93200000
|
||||
retained log 0x9ba80000 (64 KiB)
|
||||
```
|
||||
|
||||
The Image memory size must be at most `0x2f80000`. Initramfs and DTB must each
|
||||
fit in 2 MiB.
|
||||
|
||||
## 5. Test in small steps
|
||||
|
||||
First boot with the supplied RAM-only initramfs. Check:
|
||||
|
||||
```sh
|
||||
getconf _NPROCESSORS_ONLN
|
||||
ls /dev/dri
|
||||
ip addr show usb0
|
||||
dmesg | grep -E 'qkxqmp|QPNP SMB5|cam_hw_cdm_init'
|
||||
```
|
||||
|
||||
Only move to a larger userspace after the basic target is repeatable.
|
||||
Do not disconnect the AOP QMP link on Quest Pro. The tested implementation
|
||||
adopts the inherited link with `qkx_qmp_adopt=1`.
|
||||
+39
-23
@@ -1,64 +1,83 @@
|
||||
# Use
|
||||
# Usage guide
|
||||
|
||||
## 1. Capture the running device state
|
||||
> These steps are tested on Meta Quest Pro with rooted Android.
|
||||
|
||||
Boot rooted Android and connect ADB:
|
||||
## Prepare
|
||||
|
||||
Build the modules, target `Image` and initramfs first. See
|
||||
[HOW_TO_BUILD.md](HOW_TO_BUILD.md).
|
||||
|
||||
Boot Android, enable ADB and confirm root:
|
||||
|
||||
```sh
|
||||
adb shell 'su -c id'
|
||||
```
|
||||
|
||||
Capture the current device information:
|
||||
|
||||
```sh
|
||||
tools/capture.sh out/captured
|
||||
```
|
||||
|
||||
This reads the runtime device tree, iomem, command line and kernel config. It
|
||||
does not modify the device.
|
||||
This is read-only. It captures the runtime device tree, iomem, command line and
|
||||
kernel configuration.
|
||||
|
||||
Use the runtime tree from `/proc/device-tree`. The original
|
||||
`/sys/firmware/fdt` blob is not safe for this handoff.
|
||||
|
||||
## 2. Prepare the payload
|
||||
## Create the payload
|
||||
|
||||
```sh
|
||||
tools/prep.sh out/captured /path/to/target/Image \
|
||||
out/initramfs.gz out/payload
|
||||
```
|
||||
|
||||
## 3. Boot it
|
||||
## Boot
|
||||
|
||||
```sh
|
||||
tools/run.sh out/payload
|
||||
```
|
||||
|
||||
The script freshly pushes and verifies the module, Image, initramfs and DTB.
|
||||
All device files are placed under `/data/local/tmp`.
|
||||
The script copies the module, Image, initramfs and DTB to `/data/local/tmp`,
|
||||
runs `sync`, verifies their hashes and starts kexec.
|
||||
|
||||
## 4. Connect to the shell
|
||||
## Connect to BusyBox
|
||||
|
||||
Find the new Ethernet interface with `ip link`. Then:
|
||||
The initramfs exposes USB Ethernet with:
|
||||
|
||||
- headset: `10.42.0.2`
|
||||
- host: `10.42.0.1`
|
||||
|
||||
Find the new interface:
|
||||
|
||||
```sh
|
||||
ip link
|
||||
```
|
||||
|
||||
NetworkManager can normally obtain the address from the headset:
|
||||
|
||||
```sh
|
||||
nmcli device connect <interface>
|
||||
tools/shell.sh
|
||||
```
|
||||
|
||||
If DHCP is unavailable:
|
||||
If DHCP does not work:
|
||||
|
||||
```sh
|
||||
sudo ip addr add 10.42.0.1/24 dev <interface>
|
||||
tools/shell.sh
|
||||
```
|
||||
|
||||
Run one command without telnet:
|
||||
Run one command without an interactive shell:
|
||||
|
||||
```sh
|
||||
python3 tools/qkx_sh.py 'uname -a'
|
||||
```
|
||||
|
||||
## 5. Return to Android
|
||||
## Return to Android
|
||||
|
||||
```sh
|
||||
tools/return-android.sh
|
||||
```
|
||||
|
||||
## Logs
|
||||
## Read logs
|
||||
|
||||
After Android returns:
|
||||
|
||||
@@ -66,13 +85,10 @@ After Android returns:
|
||||
tools/read-log.sh
|
||||
```
|
||||
|
||||
This loads `marker_read.ko` and prints the target's retained RAM log.
|
||||
|
||||
To capture Android kernel messages over the existing USB gadget before kexec:
|
||||
To capture Android kernel logs over its existing USB gadget before a run:
|
||||
|
||||
```sh
|
||||
tools/load-usb-log.sh 60
|
||||
```
|
||||
|
||||
`usb_log.ko` hooks the active gadget's EP0 callback and intentionally cannot be
|
||||
unloaded safely. Reboot Android to remove it.
|
||||
`usb_log.ko` intentionally remains installed until Android reboots.
|
||||
@@ -1,61 +1,102 @@
|
||||
# Quest Pro kexec
|
||||
# Meta Quest kexec
|
||||
|
||||
A RAM-only ARM64 kexec loader for Meta Quest Pro.
|
||||
An experimental ARM64 kexec implementation for Meta Quest headsets.
|
||||
|
||||
It boots a patched Linux kernel from rooted Android without flashing a
|
||||
partition. The included initramfs starts a BusyBox shell over USB Ethernet.
|
||||
It starts a custom Linux kernel from rooted Android without flashing a
|
||||
partition. The included RAM-only initramfs provides a BusyBox shell over USB
|
||||
Ethernet.
|
||||
|
||||
## Current status
|
||||
> **Note:** This project has only been developed and tested on Meta Quest Pro.
|
||||
> Other Quest headsets require device-specific kernel and loader work.
|
||||
|
||||
Tested on Quest Pro OS build `51503870024400340`.
|
||||
|
||||
Working:
|
||||
## What works on Quest Pro
|
||||
|
||||
- all 8 CPUs
|
||||
- DRM and both panels
|
||||
- USB Ethernet
|
||||
- USB Ethernet shell
|
||||
- AOP/QMP handoff
|
||||
- syncboss
|
||||
- camera CPAS/CDM
|
||||
- SPMI and SMB5 charging
|
||||
|
||||
The patched kernel is in the `oculus-quest-pro-kernel-master` branch of:
|
||||
The tested kernel changes are available in:
|
||||
|
||||
https://github.com/YusufOzmen01/oculus-linux-kernel
|
||||
|
||||
The same changes are also included as patch files in `kernel/patches/`.
|
||||
Patch copies are also included under `kernel/patches/`.
|
||||
|
||||
## Layout
|
||||
## Basic build
|
||||
|
||||
- `module/` — kexec module and log modules
|
||||
- `initramfs/` — BusyBox USB-network initramfs
|
||||
- `tools/` — capture, prepare, run and shell scripts
|
||||
- `kernel/patches/` — Quest Pro target-kernel changes
|
||||
- `HOW_TO_BUILD.md` — build instructions
|
||||
- `HOW_TO_USE.md` — boot and shell instructions
|
||||
- `HOW_TO_PORT.md` — adapting another Quest Pro kernel
|
||||
- `TROUBLESHOOTING.md` — common failures
|
||||
Install Clang/LLD, an `aarch64-linux-gnu-` toolchain, Python 3, `adb`, `dtc`,
|
||||
`fdtput`, `curl` and `make`.
|
||||
|
||||
## Network shell
|
||||
Build the kexec modules against the exact Android kernel running on the headset:
|
||||
|
||||
The initramfs exposes one ECM USB function:
|
||||
```sh
|
||||
make module KDIR=/path/to/android-kernel-out \
|
||||
LOCALVERSION=-g49638c7a8637
|
||||
```
|
||||
|
||||
- headset: `10.42.0.2`
|
||||
- host: `10.42.0.1`
|
||||
- shell: `telnet 10.42.0.2`
|
||||
Build the BusyBox USB-network initramfs:
|
||||
|
||||
The target runs DHCP, so NetworkManager can normally configure the host
|
||||
interface automatically.
|
||||
```sh
|
||||
make initramfs
|
||||
```
|
||||
|
||||
See [HOW_TO_BUILD.md](HOW_TO_BUILD.md) for preparing the Android and target
|
||||
kernel trees.
|
||||
|
||||
## Basic usage
|
||||
|
||||
With rooted Android running:
|
||||
|
||||
```sh
|
||||
# Capture the current runtime device tree and kernel information
|
||||
tools/capture.sh out/captured
|
||||
|
||||
# Prepare the target payload
|
||||
tools/prep.sh out/captured /path/to/target/Image \
|
||||
out/initramfs.gz out/payload
|
||||
|
||||
# Push, verify and boot it
|
||||
tools/run.sh out/payload
|
||||
```
|
||||
|
||||
Connect to the shell after USB Ethernet appears:
|
||||
|
||||
```sh
|
||||
nmcli device connect <interface>
|
||||
tools/shell.sh
|
||||
```
|
||||
|
||||
Return to Android:
|
||||
|
||||
```sh
|
||||
tools/return-android.sh
|
||||
```
|
||||
|
||||
See [HOW_TO_USE.md](HOW_TO_USE.md) for more information.
|
||||
|
||||
## Logs
|
||||
|
||||
Read a retained target-kernel log after Android returns:
|
||||
|
||||
```sh
|
||||
tools/read-log.sh
|
||||
```
|
||||
|
||||
Capture Android kernel logs through its current USB gadget:
|
||||
|
||||
```sh
|
||||
tools/load-usb-log.sh 60
|
||||
```
|
||||
|
||||
## Safety
|
||||
|
||||
This is experimental. A bad handoff can reboot or lock the headset.
|
||||
A failed handoff can reboot or lock the headset. The supplied scripts only copy
|
||||
files to `/data/local/tmp`; they do not flash, format or mount partitions.
|
||||
|
||||
The included scripts only copy files to `/data/local/tmp`. They do not flash,
|
||||
format or mount partitions.
|
||||
|
||||
Always build `quest_kexec.ko` against the exact Android kernel currently running
|
||||
on the headset. Never force-load a module with the wrong ABI.
|
||||
Never force-load a module built for a different Android kernel.
|
||||
|
||||
## License
|
||||
|
||||
|
||||
Reference in new issue
Block a user