mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-11-10 09:44:13 +00:00
run_guest.py: Add options to run external scripts:
-m <script> Run a script in hypervisor context prior to starting the guest. This is essentially the same as the shell context. -c <code> Run a literal string of code prior to starting the guest. -S Start a shell instead of directly starting the guest. Use `start` to actually begin guest execution. This also adds a couple example scripts under hv/. Signed-off-by: Hector Martin <marcan@marcan.st>
This commit is contained in:
parent
a3558c86d7
commit
edbe471804
5 changed files with 111 additions and 90 deletions
4
proxyclient/hv/README.md
Normal file
4
proxyclient/hv/README.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
## m1n1 hypervisor scripts
|
||||
|
||||
This directory contains scripts that can be executed to configure the hypervisor using the `-m`
|
||||
option to `run_guest.py`.
|
4
proxyclient/hv/trace_agx.py
Normal file
4
proxyclient/hv/trace_agx.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
# SPDX-License-Identifier: MIT
|
||||
|
||||
trace_device("/arm-io/gfx-asc")
|
||||
trace_device("/arm-io/sgx")
|
24
proxyclient/hv/trace_all.py
Normal file
24
proxyclient/hv/trace_all.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
# SPDX-License-Identifier: MIT
|
||||
|
||||
# Map the entire MMIO range as traceable
|
||||
map_sw(0x2_00000000,
|
||||
0x2_00000000 | hv.SPTE_TRACE_READ | hv.SPTE_TRACE_WRITE,
|
||||
0x5_00000000)
|
||||
|
||||
# Skip some noisy devices
|
||||
try:
|
||||
trace_device("/arm-io/usb-drd0", False)
|
||||
except KeyError:
|
||||
pass
|
||||
try:
|
||||
trace_device("/arm-io/usb-drd1", False)
|
||||
except KeyError:
|
||||
pass
|
||||
trace_device("/arm-io/uart2", False)
|
||||
trace_device("/arm-io/error-handler", False)
|
||||
trace_device("/arm-io/aic", False)
|
||||
trace_device("/arm-io/spi1", False)
|
||||
trace_device("/arm-io/pmgr", False)
|
||||
|
||||
# Re-map the vuart, which the first map_sw undid...
|
||||
map_vuart()
|
|
@ -1,5 +1,5 @@
|
|||
# SPDX-License-Identifier: MIT
|
||||
import sys, traceback, struct, array, bisect, os, signal
|
||||
import sys, traceback, struct, array, bisect, os, signal, runpy
|
||||
from construct import *
|
||||
from enum import IntEnum, IntFlag
|
||||
|
||||
|
@ -113,6 +113,17 @@ class HV:
|
|||
self._sigint_pending = False
|
||||
self.vm_hooks = []
|
||||
self.interrupt_map = {}
|
||||
self.shell_locals = {
|
||||
"hv": self,
|
||||
"iface": self.iface,
|
||||
"p": self.p,
|
||||
"u": self.u,
|
||||
}
|
||||
|
||||
for attr in dir(self):
|
||||
a = getattr(self, attr)
|
||||
if callable(a):
|
||||
self.shell_locals[attr] = getattr(self, attr)
|
||||
|
||||
def unmap(self, ipa, size):
|
||||
assert self.p.hv_map(ipa, 0, size, 0) >= 0
|
||||
|
@ -415,20 +426,8 @@ class HV:
|
|||
self._sigint_pending = False
|
||||
self._stepping = False
|
||||
|
||||
locals = {
|
||||
"hv": self,
|
||||
"iface": self.iface,
|
||||
"p": self.p,
|
||||
"u": self.u,
|
||||
}
|
||||
|
||||
for attr in dir(self):
|
||||
a = getattr(self, attr)
|
||||
if callable(a):
|
||||
locals[attr] = getattr(self, attr)
|
||||
|
||||
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||
ret = shell.run_shell(locals, "Entering debug shell", "Returning from exception")
|
||||
ret = shell.run_shell(self.shell_locals, "Entering debug shell", "Returning from exception")
|
||||
signal.signal(signal.SIGINT, self._handle_sigint)
|
||||
|
||||
if ret is None:
|
||||
|
@ -451,20 +450,8 @@ class HV:
|
|||
self._sigint_pending = False
|
||||
self._stepping = False
|
||||
|
||||
locals = {
|
||||
"hv": self,
|
||||
"iface": self.iface,
|
||||
"p": self.p,
|
||||
"u": self.u,
|
||||
}
|
||||
|
||||
for attr in dir(self):
|
||||
a = getattr(self, attr)
|
||||
if callable(a):
|
||||
locals[attr] = getattr(self, attr)
|
||||
|
||||
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||
ret = shell.run_shell(locals, "Entering panic shell", "Returning from exception")
|
||||
ret = shell.run_shell(self.shell_locals, "Entering panic shell", "Returning from exception")
|
||||
signal.signal(signal.SIGINT, self._handle_sigint)
|
||||
|
||||
self.p.exit(0)
|
||||
|
@ -576,6 +563,21 @@ class HV:
|
|||
|
||||
self.vbar_el1 = vbar
|
||||
|
||||
def trace_device(self, path, trace=True):
|
||||
node = self.adt[path]
|
||||
for index in range(len(node.reg)):
|
||||
addr, size = node.get_reg(index)
|
||||
if trace:
|
||||
print(f"Trace: 0x{addr:x} [0x{size:x}] ({path})")
|
||||
self.map_sw(addr, addr | self.SPTE_TRACE_READ | self.SPTE_TRACE_WRITE, size)
|
||||
else:
|
||||
print(f"Pass: 0x{addr:x} [0x{size:x}] ({path})")
|
||||
if addr & 0x3fff or size & 0x3fff:
|
||||
print(f"Note: unaligned, using software passthrough")
|
||||
self.map_sw(addr, addr, size)
|
||||
else:
|
||||
self.map_hw(addr, addr, size)
|
||||
|
||||
def init(self):
|
||||
self.adt = load_adt(self.u.get_adt())
|
||||
self.iodev = self.p.iodev_whoami()
|
||||
|
@ -597,44 +599,8 @@ class HV:
|
|||
self.iface.set_event_handler(EVENT.MMIOTRACE, self.handle_mmiotrace)
|
||||
self.iface.set_event_handler(EVENT.IRQTRACE, self.handle_irqtrace)
|
||||
|
||||
#self.map_sw(0x2_00000000,
|
||||
#0x2_00000000 | self.SPTE_TRACE_READ | self.SPTE_TRACE_WRITE,
|
||||
#0x5_00000000)
|
||||
|
||||
self.map_hw(0x2_00000000, 0x2_00000000, 0x5_00000000)
|
||||
|
||||
for path, log in (
|
||||
("/arm-io/usb-drd0", False),
|
||||
("/arm-io/usb-drd1", False),
|
||||
("/arm-io/uart2", False),
|
||||
("/arm-io/error-handler", False),
|
||||
("/arm-io/aic", False),
|
||||
("/arm-io/spi1", False),
|
||||
("/arm-io/pmgr", False),
|
||||
("/arm-io/gfx-asc", True),
|
||||
("/arm-io/sgx", True),
|
||||
):
|
||||
node = self.adt[path]
|
||||
for index in range(len(node.reg)):
|
||||
addr, size = node.get_reg(index)
|
||||
if addr & 0x3fff:
|
||||
new_addr = addr & ~0x3fff
|
||||
print(f"WARNING: aligning address 0x{addr:x} -> 0x{new_addr:x}")
|
||||
size += addr - new_addr
|
||||
addr = new_addr
|
||||
|
||||
if size & 0x3fff:
|
||||
new_size = (size + 0x3fff) & ~0x3fff
|
||||
print(f"WARNING: aligning size 0x{size:x} -> 0x{new_size:x}")
|
||||
size = new_size
|
||||
|
||||
if log:
|
||||
print(f"Trace: 0x{addr:x} [0x{size:x}] ({path})")
|
||||
self.map_sw(addr, addr | self.SPTE_TRACE_READ | self.SPTE_TRACE_WRITE, size)
|
||||
else:
|
||||
print(f"Pass: 0x{addr:x} [0x{size:x}] ({path})")
|
||||
self.map_hw(addr, addr, size)
|
||||
|
||||
# trace IRQs
|
||||
aic_phandle = getattr(self.adt["/arm-io/aic"], "AAPL,phandle")
|
||||
for path in (
|
||||
|
@ -649,26 +615,6 @@ class HV:
|
|||
#self.trace_irq(node.name, irq, 1, self.IRQTRACE_IRQ)
|
||||
pass
|
||||
|
||||
# Sync PMGR stuff
|
||||
#self.map_sw(0x2_3b700000,
|
||||
#0x2_3b700000 | self.SPTE_TRACE_READ | self.SPTE_TRACE_WRITE | self.SPTE_SYNC_TRACE,
|
||||
#0x8000)
|
||||
|
||||
_pmu = {}
|
||||
|
||||
def wh(base, off, data, width):
|
||||
print(f"W {base:x}+{off:x}:{width} = 0x{data:x}: Dangerous write")
|
||||
_pmu[base + off] = (data & 0xff0f) | ((data & 0xf) << 4)
|
||||
|
||||
def rh(base, off, width):
|
||||
data = self.p.read32(base + off)
|
||||
ret = _pmu.setdefault(base + off, data)
|
||||
print(f"R {base:x}+{off:x}:{width} = 0x{data:x} -> 0x{ret:x}")
|
||||
return ret
|
||||
|
||||
for addr in (0x23b700420, 0x23d280098, 0x23d280088, 0x23d280090):
|
||||
self.map_hook(addr, 4, write=wh, read=rh)
|
||||
|
||||
hcr = HCR(self.u.mrs(HCR_EL2))
|
||||
if self.novm:
|
||||
hcr.VM = 0
|
||||
|
@ -706,7 +652,7 @@ class HV:
|
|||
self.u.msr(APVMKEYHI_EL2, 0x697665596F755570)
|
||||
self.u.msr(APSTS_EL12, 1)
|
||||
|
||||
self.p.hv_map_vuart(0x2_35200000, getattr(IODEV, self.iodev.name + "_SEC"))
|
||||
self.map_vuart()
|
||||
|
||||
actlr = ACTLR(self.u.mrs(ACTLR_EL12))
|
||||
actlr.EnMDSB = 1
|
||||
|
@ -714,6 +660,26 @@ class HV:
|
|||
|
||||
self.setup_adt()
|
||||
|
||||
def map_vuart(self):
|
||||
self.p.hv_map_vuart(0x2_35200000, getattr(IODEV, self.iodev.name + "_SEC"))
|
||||
|
||||
def map_essential(self):
|
||||
# Things we always map/take over, for the hypervisor to work
|
||||
_pmu = {}
|
||||
|
||||
def wh(base, off, data, width):
|
||||
print(f"W {base:x}+{off:x}:{width} = 0x{data:x}: Dangerous write")
|
||||
_pmu[base + off] = (data & 0xff0f) | ((data & 0xf) << 4)
|
||||
|
||||
def rh(base, off, width):
|
||||
data = self.p.read32(base + off)
|
||||
ret = _pmu.setdefault(base + off, data)
|
||||
print(f"R {base:x}+{off:x}:{width} = 0x{data:x} -> 0x{ret:x}")
|
||||
return ret
|
||||
|
||||
for addr in (0x23b700420, 0x23d280098, 0x23d280088, 0x23d280090):
|
||||
self.map_hook(addr, 4, write=wh, read=rh)
|
||||
|
||||
def setup_adt(self):
|
||||
self.adt["product"].product_name += " on m1n1 hypervisor"
|
||||
self.adt["product"].product_description += " on m1n1 hypervisor"
|
||||
|
@ -892,23 +858,32 @@ class HV:
|
|||
# Kick the proxy to break out of the hypervisor
|
||||
self.iface.dev.write(b"!")
|
||||
|
||||
def run_script(self, path):
|
||||
self.shell_locals = runpy.run_path(path, init_globals=self.shell_locals, run_name="<hv_script>")
|
||||
|
||||
def run_code(self, code):
|
||||
exec(code, self.shell_locals)
|
||||
|
||||
def start(self):
|
||||
print(f"Disabling other iodevs...")
|
||||
print("Disabling other iodevs...")
|
||||
for iodev in IODEV:
|
||||
if iodev != self.iodev:
|
||||
print(f" - {iodev!s}")
|
||||
self.p.iodev_set_usage(iodev, 0)
|
||||
|
||||
print(f"Improving logo...")
|
||||
print("Doing essential MMIO remaps...")
|
||||
self.map_essential()
|
||||
|
||||
print("Improving logo...")
|
||||
self.p.fb_improve_logo()
|
||||
|
||||
print(f"Shutting down framebuffer...")
|
||||
print("Shutting down framebuffer...")
|
||||
self.p.fb_shutdown()
|
||||
|
||||
print(f"Enabling SPRR...")
|
||||
print("Enabling SPRR...")
|
||||
self.u.msr(SPRR_CONFIG_EL1, 1)
|
||||
|
||||
print(f"Enabling GXF...")
|
||||
print("Enabling GXF...")
|
||||
self.u.msr(GXF_CONFIG_EL1, 1)
|
||||
|
||||
print(f"Jumping to entrypoint at 0x{self.entry:x}")
|
||||
|
|
|
@ -7,6 +7,9 @@ import argparse, pathlib
|
|||
|
||||
parser = argparse.ArgumentParser(description='Run a Mach-O payload under the hypervisor')
|
||||
parser.add_argument('-s', '--symbols', type=pathlib.Path)
|
||||
parser.add_argument('-m', '--script', type=pathlib.Path, action='append')
|
||||
parser.add_argument('-c', '--command', action="append")
|
||||
parser.add_argument('-S', '--shell', action="store_true")
|
||||
parser.add_argument('payload', type=pathlib.Path)
|
||||
parser.add_argument('boot_args', default=[], nargs="*")
|
||||
args = parser.parse_args()
|
||||
|
@ -14,6 +17,7 @@ args = parser.parse_args()
|
|||
from m1n1.proxy import *
|
||||
from m1n1.proxyutils import *
|
||||
from m1n1.utils import *
|
||||
from m1n1.shell import run_shell
|
||||
from m1n1.hv import HV
|
||||
|
||||
iface = UartInterface()
|
||||
|
@ -33,4 +37,14 @@ symfile = None
|
|||
if args.symbols:
|
||||
symfile = args.symbols.open("rb")
|
||||
hv.load_macho(args.payload.open("rb"), symfile=symfile)
|
||||
hv.start()
|
||||
|
||||
for i in args.script:
|
||||
hv.run_script(i)
|
||||
|
||||
for i in args.command:
|
||||
hv.run_code(i)
|
||||
|
||||
if args.shell:
|
||||
run_shell(hv.shell_locals, "Entering hypervisor shell. Type `start` to start the guest.")
|
||||
else:
|
||||
hv.start()
|
||||
|
|
Loading…
Reference in a new issue