From 93382ff2419b84fb1ec50d913d67c80d86e3687e Mon Sep 17 00:00:00 2001 From: xXJsonDeruloXx Date: Wed, 30 Sep 2026 07:53:12 -0400 Subject: [PATCH] fix: report Adreno 840v2 as the A840 the runtime's Turnip knows --- tools/linuxfs/preload/kgslid.c | 58 ++++++++++++++++++++++++++++++++++ tools/linuxfs/preload/netif.c | 3 ++ 2 files changed, 61 insertions(+) create mode 100644 tools/linuxfs/preload/kgslid.c diff --git a/tools/linuxfs/preload/kgslid.c b/tools/linuxfs/preload/kgslid.c new file mode 100644 index 000000000..3dee629d1 --- /dev/null +++ b/tools/linuxfs/preload/kgslid.c @@ -0,0 +1,58 @@ +/* + * Adreno revisions the runtime's Turnip does not know, reported as the revision it does. + * + * Retail SM8850 phones report their A840 as chip_id 0x44050A21 (KGSL gpu_model "Adreno840v2"). + * Mesa only lists 0x44050A31, so the runtime's glibc Turnip refuses the device outright + * ("device (chip_id = 44050A21, gpu_id = 6860) is unsupported") and gamescope exits before Steam + * starts. Banners-Turnip fixes its own builds by registering the v2 id on the same A840 GPU info + * (patches/a840v2.py); answering KGSL's device-info query with the known id has the same effect + * on any Turnip in the session, including the one the runtime was built with. A driver that + * already knows the v2 id resolves the rewritten one to the same entry. + * + * Only the KGSL device-info property is touched. Its layout is the kernel's uapi (msm_kgsl.h). + */ +#define _GNU_SOURCE 1 +#include +#include + +struct kgsl_devinfo { + unsigned int device_id; + unsigned int chip_id; + unsigned int mmu_enabled; + unsigned long gmem_gpubaseaddr; + unsigned int gpu_id; + size_t gmem_sizebytes; +}; + +struct kgsl_device_getproperty { + unsigned int type; + void *value; + size_t sizebytes; +}; + +#define KGSL_IOC_TYPE 0x09 +#define IOCTL_KGSL_DEVICE_GETPROPERTY _IOWR(KGSL_IOC_TYPE, 0x2, struct kgsl_device_getproperty) +#define KGSL_PROP_DEVICE_INFO 0x1 + +static const struct { + unsigned int reported; + unsigned int known; +} CHIP_IDS[] = { + {0x44050A21, 0x44050A31}, /* Adreno 840v2 -> Adreno 840 */ +}; + +void bl_kgsl_chip_id_fixup(unsigned long request, void *arg, int rc) { + if (rc != 0 || request != IOCTL_KGSL_DEVICE_GETPROPERTY || arg == NULL) return; + struct kgsl_device_getproperty *prop = arg; + if (prop->type != KGSL_PROP_DEVICE_INFO || prop->value == NULL + || prop->sizebytes < sizeof(struct kgsl_devinfo)) { + return; + } + struct kgsl_devinfo *info = prop->value; + for (size_t i = 0; i < sizeof(CHIP_IDS) / sizeof(CHIP_IDS[0]); i++) { + if (info->chip_id == CHIP_IDS[i].reported) { + info->chip_id = CHIP_IDS[i].known; + return; + } + } +} diff --git a/tools/linuxfs/preload/netif.c b/tools/linuxfs/preload/netif.c index 4b79c3f3f..f4de289d9 100644 --- a/tools/linuxfs/preload/netif.c +++ b/tools/linuxfs/preload/netif.c @@ -349,6 +349,8 @@ static int is_link_query(unsigned long request) { || request == SIOCGIFBRDADDR; } +void bl_kgsl_chip_id_fixup(unsigned long request, void *arg, int rc); /* kgslid.c */ + /* Every DRM and evdev call comes through here, so the lookup is done once. Two threads racing * to store it store the same pointer. */ int ioctl(int fd, unsigned long request, ...) { @@ -361,6 +363,7 @@ int ioctl(int fd, unsigned long request, ...) { if (real == NULL) real = (ioctl_fn) dlsym(RTLD_NEXT, "ioctl"); int rc = real(fd, request, arg); + bl_kgsl_chip_id_fixup(request, arg, rc); if (arg == NULL || !is_link_query(request)) return rc; int saved = errno; if (answer_ifreq(request, (struct ifreq *) arg, rc)) return 0;