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 a835c6cdd..078f6a301 100644 --- a/tools/linuxfs/preload/netif.c +++ b/tools/linuxfs/preload/netif.c @@ -349,6 +349,7 @@ 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 */ int bl_kgsl_poll(int (*real)(int, unsigned long, void *), int fd, unsigned long request, void *arg, int *rc) __attribute__((visibility("hidden"))); @@ -364,8 +365,8 @@ int ioctl(int fd, unsigned long request, ...) { if (real == NULL) real = (ioctl_fn) dlsym(RTLD_NEXT, "ioctl"); int rc; - if (bl_kgsl_poll(real, fd, request, arg, &rc)) return rc; - rc = real(fd, request, arg); + if (!bl_kgsl_poll(real, fd, request, arg, &rc)) 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;