mirror of
https://github.com/YusufOzmen01/quest-kexec.git
synced 2026-10-26 19:37:39 +00:00
Initial Quest Pro ARM64 kexec release
This commit is contained in:
26 files changed
+5031
No files matched your search
Executable
+66
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Pack a static ARM64 BusyBox and init.sh into a gzip newc initramfs."""
|
||||
import argparse
|
||||
import gzip
|
||||
import stat
|
||||
import struct
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def archive(entries):
|
||||
data = bytearray()
|
||||
for ino, (name, mode, contents, major, minor) in enumerate(entries, 1):
|
||||
name = name.encode() + b"\0"
|
||||
fields = (ino, mode, 0, 0, 1, 0, len(contents), 0, 0, major, minor, len(name), 0)
|
||||
data += b"070701" + "".join(f"{x:08x}" for x in fields).encode() + name
|
||||
data += b"\0" * (-len(data) % 4)
|
||||
data += contents
|
||||
data += b"\0" * (-len(data) % 4)
|
||||
data += b"\0" * (-len(data) % 512)
|
||||
return bytes(data)
|
||||
|
||||
|
||||
def check_static_arm64(path):
|
||||
b = path.read_bytes()
|
||||
if b[:6] != b"\x7fELF\x02\x01" or struct.unpack_from("<H", b, 18)[0] != 183:
|
||||
raise SystemExit(f"{path}: not a little-endian ARM64 ELF")
|
||||
off = struct.unpack_from("<Q", b, 32)[0]
|
||||
size, count = struct.unpack_from("<HH", b, 54)
|
||||
if any(struct.unpack_from("<I", b, off + i * size)[0] == 3 for i in range(count)):
|
||||
raise SystemExit(f"{path}: must be statically linked")
|
||||
return b
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser(description=__doc__)
|
||||
ap.add_argument("--busybox", type=Path, required=True)
|
||||
ap.add_argument("--output", type=Path, required=True)
|
||||
ap.add_argument("--init", type=Path, default=Path(__file__).with_name("init.sh"))
|
||||
ap.add_argument("--extra", action="append", default=[], metavar="SRC:DEST",
|
||||
help="add a static ARM64 binary, e.g. modeset:bin/modeset")
|
||||
a = ap.parse_args()
|
||||
dirs = ("bin", "sbin", "dev", "dev/pts", "proc", "sys", "config", "etc", "root", "tmp")
|
||||
entries = [(d, stat.S_IFDIR | 0o755, b"", 0, 0) for d in dirs]
|
||||
entries += [
|
||||
("bin/busybox", stat.S_IFREG | 0o755, check_static_arm64(a.busybox), 0, 0),
|
||||
("init", stat.S_IFREG | 0o755, a.init.read_bytes(), 0, 0),
|
||||
("dev/console", stat.S_IFCHR | 0o600, b"", 5, 1),
|
||||
("dev/kmsg", stat.S_IFCHR | 0o600, b"", 1, 11),
|
||||
("dev/null", stat.S_IFCHR | 0o666, b"", 1, 3),
|
||||
("etc/passwd", stat.S_IFREG | 0o644, b"root::0:0:root:/root:/bin/sh\n", 0, 0),
|
||||
("etc/group", stat.S_IFREG | 0o644, b"root:x:0:\n", 0, 0),
|
||||
]
|
||||
for spec in a.extra:
|
||||
src, dest = spec.split(":", 1)
|
||||
entries.append((dest, stat.S_IFREG | 0o755, check_static_arm64(Path(src)), 0, 0))
|
||||
entries.append(("TRAILER!!!", 0, b"", 0, 0))
|
||||
data = gzip.compress(archive(entries), mtime=0)
|
||||
if len(data) > 0x200000:
|
||||
raise SystemExit(f"initramfs is {len(data)} bytes; the staging layout allows 2 MiB")
|
||||
a.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
a.output.write_bytes(data)
|
||||
print(f"{a.output}: {len(data)} bytes")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
# Download, verify and build a static ARM64 BusyBox.
|
||||
# Usage: busybox.sh <output-binary>
|
||||
set -euo pipefail
|
||||
VER=1.36.1
|
||||
SHA=b8cc24c9574d809e7279c3be349795c5d5ceb6fdf19ca709f80cde50e47de314
|
||||
OUT=$(realpath -m "$1")
|
||||
WORK=$(dirname "$OUT")/busybox-build
|
||||
CROSS=${CROSS_COMPILE:-aarch64-linux-gnu-}
|
||||
mkdir -p "$WORK"
|
||||
cd "$WORK"
|
||||
[ -f busybox-$VER.tar.bz2 ] ||
|
||||
curl -fL -o busybox-$VER.tar.bz2 https://busybox.net/downloads/busybox-$VER.tar.bz2
|
||||
echo "$SHA busybox-$VER.tar.bz2" | sha256sum -c -
|
||||
rm -rf busybox-$VER
|
||||
tar xjf busybox-$VER.tar.bz2
|
||||
cd busybox-$VER
|
||||
M="make ARCH=arm64 CROSS_COMPILE=$CROSS"
|
||||
$M defconfig >/dev/null
|
||||
# Static, and drop tc: it doesn't build against current kernel headers.
|
||||
sed -i 's/^# CONFIG_STATIC is not set/CONFIG_STATIC=y/; s/^CONFIG_TC=y/# CONFIG_TC is not set/' .config
|
||||
$M oldconfig </dev/null >/dev/null 2>&1 || true
|
||||
grep -q '^CONFIG_STATIC=y' .config
|
||||
$M -j"$(nproc)" >/dev/null
|
||||
cp busybox "$OUT"
|
||||
echo "$OUT"
|
||||
Executable
+75
@@ -0,0 +1,75 @@
|
||||
#!/bin/busybox sh
|
||||
# RAM-only init: USB Ethernet (ECM) gadget with a BusyBox telnet shell.
|
||||
# The headset is 10.42.0.2; udhcpd hands the host 10.42.0.1.
|
||||
# Nothing here mounts a block device.
|
||||
export PATH=/bin:/sbin
|
||||
export HOME=/root
|
||||
export TERM=vt100
|
||||
/bin/busybox --install -s /bin
|
||||
mount -t proc proc /proc
|
||||
mount -t sysfs sysfs /sys
|
||||
mount -t devtmpfs devtmpfs /dev
|
||||
mkdir -p /dev/pts /config /tmp
|
||||
mount -t devpts devpts /dev/pts
|
||||
mount -t configfs configfs /config
|
||||
mount -t tmpfs tmpfs /tmp
|
||||
exec >/dev/kmsg 2>&1
|
||||
|
||||
log() { echo "qkx-init: $*"; }
|
||||
# /proc/qkx_bootdone comes from the target kernel patches: 'd' disarms the
|
||||
# boot watchdog, 'k' is a keepalive, 'r' forces a log-preserving warm reset.
|
||||
bootdone() { [ -w /proc/qkx_bootdone ] && echo "$1" > /proc/qkx_bootdone; }
|
||||
|
||||
log "reached $(uname -r)"
|
||||
|
||||
g=/config/usb_gadget/qkx
|
||||
mkdir -p "$g/strings/0x409" "$g/configs/c.1/strings/0x409" "$g/functions/ecm.usb0"
|
||||
echo 0x1d6b > "$g/idVendor"
|
||||
echo 0x0105 > "$g/idProduct"
|
||||
echo QKX-RAM > "$g/strings/0x409/serialnumber"
|
||||
echo 'quest-pro-kexec' > "$g/strings/0x409/manufacturer"
|
||||
echo 'RAM-only USB Ethernet shell' > "$g/strings/0x409/product"
|
||||
echo 'ECM' > "$g/configs/c.1/strings/0x409/configuration"
|
||||
echo 250 > "$g/configs/c.1/MaxPower"
|
||||
# Fixed MACs keep the host interface name stable across boots.
|
||||
echo 02:51:4b:58:00:02 > "$g/functions/ecm.usb0/dev_addr"
|
||||
echo 02:51:4b:58:00:01 > "$g/functions/ecm.usb0/host_addr"
|
||||
ln -s "$g/functions/ecm.usb0" "$g/configs/c.1/ecm.usb0"
|
||||
|
||||
udc=
|
||||
for _ in 1 2 3 4 5 6 7 8 9 10; do
|
||||
for c in /sys/class/udc/*; do
|
||||
[ -e "$c" ] || continue
|
||||
echo "${c##*/}" > "$g/UDC" && udc=$c && break 2
|
||||
done
|
||||
log "waiting for UDC"
|
||||
bootdone k
|
||||
sleep 1
|
||||
done
|
||||
if [ -z "$udc" ]; then
|
||||
log "no UDC; forcing warm reset so the log survives"
|
||||
bootdone r
|
||||
while :; do sleep 60; done
|
||||
fi
|
||||
log "bound ${udc##*/}"
|
||||
# Keep the DWC3 glue device out of runtime suspend.
|
||||
echo on > "$udc/device/../power/control" 2>/dev/null
|
||||
|
||||
ifconfig lo 127.0.0.1 up
|
||||
ifconfig usb0 10.42.0.2 netmask 255.255.255.0 up
|
||||
cat > /tmp/udhcpd.conf <<EOC
|
||||
interface usb0
|
||||
start 10.42.0.1
|
||||
end 10.42.0.1
|
||||
max_leases 1
|
||||
lease_file /tmp/udhcpd.leases
|
||||
option subnet 255.255.255.0
|
||||
option lease 86400
|
||||
EOC
|
||||
touch /tmp/udhcpd.leases
|
||||
udhcpd /tmp/udhcpd.conf
|
||||
telnetd -l /bin/sh -p 23
|
||||
|
||||
bootdone d
|
||||
log "ready: telnet 10.42.0.2"
|
||||
while :; do sleep 3600; done
|
||||
Reference in new issue
Block a user