probes: serve ADRENO_GUEST_BACKLIGHT in SNAP_EDP_BACKLIGHT monitors

-DSNAP_EDP_BACKLIGHT=1 links compat/edp-backlight.c (probes/run.py
OPTIONAL), keeps its state in one zeroed monitor arena page (setup.c;
excluded from transaction publication like the other monitor-only
pages), and dispatches the call from the 0xad16 HVC path. The call is
admitted like ADRENO_GUEST_STOP: EL1, and the HVC word in the loaded
AuxKC's bytes; otherwise EDP_BL_E_ORIGIN. MMIO goes through q1n1's EL2
identity map with a DSB after each access. Every call is recorded as
EV_EDP_BACKLIGHT (60).

Default off. With the org2 desktop run's 122 flags the monitor is
byte-identical with the define absent or 0 (sha256 0d8b9ec3..., the
qualification's monitor_sha256) and 458,536 bytes with it (216 bytes
under the 448 KiB code budget). Hardware: not run.
This commit is contained in:
Acelogic committed 2026-10-24 01:56:59 -04:00
1 parent 7da9adf573
commit 30a815744d
8 files changed
+82 -1

No files matched your search

+2 -1
View File
@@ -128,7 +128,8 @@ MULTI = {'pauth-address': ['probes/pauth-address.S','compat/pauth-native.S'],
'compat/adreno.c', 'compat/adreno-fill.c', 'compat/adreno-ib.c', 'compat/irq-forward.c', 'compat/ans.c', 'compat/ans-window.c', 'compat/nvme-host.c', 'compat/early-stop.c', 'compat/a16-thermal.c', 'probes/memory.S']}
# Units linked only when their opt-in define is in FLAGS, after MULTI's, so a build without the define links exactly
# the objects it always did and its ELF stays byte-identical.
OPTIONAL = {'xnuboot': (('-DSNAP_ADRENO_COHERENT=1', 'compat/adreno-coherent.c'),)}
OPTIONAL = {'xnuboot': (('-DSNAP_ADRENO_COHERENT=1', 'compat/adreno-coherent.c'),
('-DSNAP_EDP_BACKLIGHT=1', 'compat/edp-backlight.c'))}
def optional_sources(name, flags):
+9
View File
@@ -870,6 +870,15 @@ struct guest_net_state {
#define GUEST_NET_POLL2 4u /* q1n1 Q1N1_CALL_POLL2 */
#define GUEST_NET_CALL_E_OP UINT64_C(0xffffffffffffffff) /* Q1N1_CALL_E_OP: an older q1n1 */
#endif
/* SNAP_EDP_BACKLIGHT (compat/edp-backlight.h, agents/brightness): ADRENO_GUEST_BACKLIGHT sets the panel's DPCD
* brightness over the eDP controller's AUX channel for the kext's AdrenoBacklight, admitted like ADRENO_GUEST_STOP.
* Its state is one zeroed monitor page (setup.c). Off, the code is absent and compat/edp-backlight.c is not linked. */
#ifndef SNAP_EDP_BACKLIGHT
#define SNAP_EDP_BACKLIGHT 0
#endif
#if SNAP_EDP_BACKLIGHT
#include "../compat/edp-backlight.h"
#endif
#include "../compat/fast-vector.h"
_Static_assert(FAST_EXIT_CLASSES==FAST_TRAP_CLASSES-1+FAST_CROSS_CLASSES &&
FAST_EXIT_CROSS_SLOT(1)==FAST_TRAP_CLASSES-1,
+5
View File
@@ -455,6 +455,11 @@ struct context {
* monitor arena pages taken at setup (owner 0, never released). */
struct guest_net_state *guest_net;
#endif
#if SNAP_EDP_BACKLIGHT
/* compat/edp-backlight.h: ADRENO_GUEST_BACKLIGHT's state, one monitor
* arena page taken at setup (owner 0, never released). */
struct edp_backlight_state *edp_backlight;
#endif
#if SNAP_FAST_EL0_SYSREG || SNAP_SERVICE_SUBCLASS
/* Appended only under these opt-in defines, inside the page before the
* table arena (asserted below), so define-free layout readers keep every
+4
View File
@@ -576,6 +576,10 @@ static int txn_publish_exclude(void *ctx,uint64_t page)
#if SNAP_GUEST_NET
/* The guest-network state, stored the same way (compat/guest-net-link.h). */
if(page>=(uint64_t)c->guest_net && page-(uint64_t)c->guest_net<GUEST_NET_STATE_PAGES*4096)return 1;
#endif
#if SNAP_EDP_BACKLIGHT
/* ADRENO_GUEST_BACKLIGHT's state page, stored the same way (compat/edp-backlight.h). */
if(page==(uint64_t)c->edp_backlight)return 1;
#endif
for(unsigned cpu=0;cpu<GUEST_CPU_COUNT;cpu++)
for(uint64_t g=0;g<c->vcpus[cpu].guard_count;g++)
+43
View File
@@ -652,3 +652,46 @@ static void guest_net_hvc(struct context *c, uint64_t *frame, uint64_t elr, uint
}
#endif
#if SNAP_EDP_BACKLIGHT
/* compat/edp-backlight.c reaches the eDP controller and dispcc through these, physical addresses in q1n1's EL2
* identity map (Device memory, as the thermal guard's reads). The engine admits only its allow-list
* (edp_bl_mmio_read_ok/edp_bl_mmio_write_ok, proven by tools/test-edp-backlight.c); the barrier orders each access
* before the next, as the controller's FIFO protocol needs. */
static int edp_backlight_read(void *ctx, uint64_t pa, uint32_t *value)
{
(void)ctx;
*value = *(const volatile uint32_t *)pa;
__asm__ volatile("dsb sy" ::: "memory");
return 0;
}
static int edp_backlight_write(void *ctx, uint64_t pa, uint32_t value)
{
(void)ctx;
*(volatile uint32_t *)pa = value;
__asm__ volatile("dsb sy" ::: "memory");
return 0;
}
static uint64_t edp_backlight_clock(void *ctx) {(void)ctx; return service_profile_clock();}
/* ADRENO_GUEST_BACKLIGHT (compat/edp-backlight.h): admitted from EL1 for the HVC the loaded AuxKC's own bytes hold
* (early_stop_guest_caller, as ADRENO_GUEST_STOP). Under the service lock: one AUX transaction at a time, each
* bounded by hz / EDP_BL_AUX_BUDGET_DIV. */
static void edp_backlight_hvc(struct context *c, uint64_t *frame, uint64_t elr, uint64_t spsr)
{
const struct params *p = c->params;
const struct edp_backlight_io io = {c, edp_backlight_read, edp_backlight_write, edp_backlight_clock,
p->clock_host_hz};
uint64_t hvc = elr - 4, pa = guest_pa(hvc), r[4] = {frame[0], frame[1], frame[2], frame[3]};
uint32_t word = 0;
if (pa && p->auxkc.pa_end > p->auxkc.pa_base + 4 && pa >= p->auxkc.pa_base && pa <= p->auxkc.pa_end - 4)
word = *(volatile uint32_t *)pa;
if (early_stop_guest_caller(&p->auxkc, hvc, pa, word, spsr)) {
r[0] = (uint64_t)(int64_t)EDP_BL_E_ORIGIN;
r[1] = r[2] = r[3] = 0;
} else
edp_backlight_call(c->edp_backlight, &io, r);
record(c, EV_EDP_BACKLIGHT, hvc, frame[1] << 32 | (uint32_t)frame[2], r[0] << 32 | (uint32_t)r[3], r[1]);
for (unsigned n = 0; n < 4; n++) frame[n] = r[n];
}
#endif
+5
View File
@@ -217,6 +217,11 @@ struct event {
* control's PMU passes << 16, c = stale[0] << 32 | stale[1] (the controls'
* stale words, each at most 1,024); probes/run.py decodes it */
#endif
#if SNAP_EDP_BACKLIGHT
#define EV_EDP_BACKLIGHT 60 /* ADRENO_GUEST_BACKLIGHT (compat/edp-backlight.h): a = sub-op << 32 | (u32)level asked,
* b = (u32)result << 32 | the panel's level after the call, c = the reply's x1 (ABI |
* state << 8 | detail << 16 | DPCD 0x700..0x703 << 24 | mode << 56); pc = the HVC */
#endif
#define EV_HANDOFF 7 /* a field of the handoff was read: a = offset */
#define EV_WATCHDOG 6 /* the guest ran too long and was taken back */
#define EV_DISPATCH_CMD 8 /* a call that is not an endpoint call:
+8
View File
@@ -90,6 +90,14 @@ int xnuboot_setup(uint64_t work, uint64_t size, uint64_t params, uint64_t out,
for (uint64_t n = 0; n < GUEST_NET_STATE_PAGES * 4096 / 8; n++) ((volatile uint64_t *)c->guest_net)[n] = 0;
__asm__ volatile("" ::: "memory");
c->next_table += GUEST_NET_STATE_PAGES * 4096;
#endif
#if SNAP_EDP_BACKLIGHT
/* compat/edp-backlight.h: one page, zeroed (EDP_BL_STATE_UNPROBED), probed by the first guest call. */
if (c->next_table + 4096 > c->work_end) return 1;
c->edp_backlight = (struct edp_backlight_state *)c->next_table;
for (uint64_t n = 0; n < 4096 / 8; n++) ((volatile uint64_t *)c->edp_backlight)[n] = 0;
__asm__ volatile("" ::: "memory");
c->next_table += 4096;
#endif
if(c->params->early_stop.flags & EARLY_STOP_F_THERMAL) {
if(c->next_table>c->work_end || c->work_end-c->next_table<4096)return 1;
+6
View File
@@ -578,6 +578,12 @@ static int xnuboot_trap_locked(uint64_t *frame, uint64_t esr, uint64_t *elr)
return 0;
}
#endif
#if SNAP_EDP_BACKLIGHT
if (frame[0] == ADRENO_GUEST_BACKLIGHT) {
edp_backlight_hvc(c, frame, *elr, physical_spsr);
return 0;
}
#endif
#if SNAP_ADRENO_IB_ASYNC
if (frame[0] == ADRENO_GUEST_IB_POLL) {
gpu_ib_poll_hvc(c, frame, *elr);