[no subject]
From: hossein rezaei
Date: Thu Aug 06 2026 - 17:23:05 EST
🚀 Complete Mali-G68 Native Driver Builder Project – Final Version (v8)
All 23 files are fully synchronized, reviewed, and ready for use.
---
📁 Part 1: Infrastructure & Core Tools (Files 1–6)
File 1: 01_Roles_and_Tasks_v5.md
```markdown
# Roles and Tasks – Mali-G68 Driver Project (v5 Final)
## Human Team (3 People)
| Role | Count | Responsibility |
| :--- | :--- | :--- |
| Project Lead | 1 | Prioritization, MMU/firmware patch approval |
| Validation Engineer | 1 | Replay matching verification, safe range approval |
| Infrastructure Specialist | 1 | QEMU, DB, tracing tools maintenance |
---
## Golden Principle: Full Temporal Determinism
- In **Replay** mode, QEMU **never** uses real system time.
- Time and IRQs are read **exactly** from the trace file.
- Any mismatch (address, value, time) is logged as `mismatch`.
---
## 100 AI Agents (Dynamic Roles, Priority-Based)
| Role | Task |
| :--- | :--- |
| Tracer | Capture nanosecond-precision trace from phone |
| Pattern Miner | Analyze temporal sequences and extract patterns |
| Correlator | Match traces with Panfrost source code (via LLM) |
| Test Generator | Create tests based on precise timing |
| Evaluator | Compare QEMU and phone outputs |
| Documenter | Generate reports with timing sections |
| Updater | Monitor public repositories for changes |
```
---
File 2: 02_Database_Schema_v5.sql
```sql
-- Central Database: registers.db (v5)
CREATE TABLE traces (
id INTEGER PRIMARY KEY AUTOINCREMENT,
device_name TEXT,
kernel_version TEXT,
scenario TEXT,
file_path TEXT,
file_hash TEXT UNIQUE,
start_time_ns INTEGER,
end_time_ns INTEGER,
event_count INTEGER
);
CREATE TABLE trace_events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
trace_id INTEGER,
timestamp_ns INTEGER,
event_type TEXT CHECK(event_type IN
('MMIO_READ','MMIO_WRITE','IRQ_RAISE','IRQ_CLEAR')),
address TEXT,
value TEXT,
FOREIGN KEY (trace_id) REFERENCES traces(id)
);
CREATE TABLE replay_results (
id INTEGER PRIMARY KEY AUTOINCREMENT,
trace_id INTEGER,
qemu_log_path TEXT,
hardware_log_path TEXT,
total_events INTEGER,
matched_events INTEGER,
timing_mismatch_count INTEGER,
value_mismatch_count INTEGER,
match_percentage REAL,
status TEXT CHECK(status IN
('pending','perfect','timing_mismatch','value_mismatch'))
);
CREATE TABLE replay_diffs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
replay_result_id INTEGER,
event_index INTEGER,
expected_value TEXT,
actual_value TEXT,
expected_time_ns INTEGER,
actual_time_ns INTEGER,
diff_type TEXT CHECK(diff_type IN ('value','timing','missing','extra'))
);
```
---
File 3: 03_Report_Template_v5.md
```markdown
---
register: 0x[ADDRESS]
name: [Suggested Name]
trace_id: [Trace ID]
replay_match: [True/False]
---
# Register Report: 0x[ADDRESS]
## 1. Main Hypothesis (Based on Timing)
[Explain when this register changes and before which event (IRQ/Job)]
## 2. Timing Evidence from Phone Trace
| Time (ns) | Event | Value |
| :--- | :--- | :--- |
| T0 | Write 0x1234 | 0x01 |
| T0+50µs | IRQ | - |
| T0+55µs | Read 0x1234 | 0x00 |
## 3. Replay Results with Temporal Determinism
- Timing Match: 100%
- Value Match: 100%
## 4. Bit Mapping
| Bit | Name | Value |
| :--- | :--- | :--- |
| 0 | enable | 0/1 |
| 7 | done | 0/1 |
## 5. Safe Range
- `safe_range`: [0x00, 0x01]
## 6. Human Review
- Reviewer: [Name]
- Comment: [Approved/Rejected]
```
---
File 4: 04_CI_Pipeline_v5.yaml
```yaml
name: CI Pipeline (Temporal Replay)
on:
push: { branches: [ main ] }
schedule: [ { cron: '0 2 * * *' } ]
jobs:
temporal-replay:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build QEMU with deterministic clock
run: |
mkdir build && cd build
../configure --target-list=arm-softmmu --enable-debug --enable-replay
make -j$(nproc)
- name: Download reference trace
run: wget http://db/traces/golden_trace.bin -O trace.bin
- name: Run deterministic replay
run: |
./build/qemu-system-arm -M vexpress-a15 -kernel ./kernel.elf
-replay trace.bin -d trace:mem_ops -D qemu_output.log
- name: Validate temporal match
run: |
python scripts/validate_timing.py --trace trace.bin
--qemu-log qemu_output.log
- name: Upload results
uses: actions/upload-artifact@v3
with:
name: timing-report
path: timing_report.json
```
---
File 5: 05_QEMU_Replay_Real_v5.c
```c
/*
* qemu/hw/misc/mali_replay_real_v5.c
* Final version with Temporal Determinism and address/time matching
*/
#include "qemu/osdep.h"
#include "qemu/module.h"
#include "hw/sysbus.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "exec/address-spaces.h"
#include "sysemu/replay.h"
#include "qemu/timer.h"
#define TYPE_MALI_REPLAY_V5 "mali-replay-v5"
#define MALI_REPLAY_V5(obj) OBJECT_CHECK(MaliReplayV5, (obj),
TYPE_MALI_REPLAY_V5)
#define TRACE_NOT_FOUND 0xFFFFFFFF
typedef struct MaliReplayV5 {
SysBusDevice parent_obj;
MemoryRegion mmio;
qemu_irq irq;
uint32_t regs[0x100];
bool job_running;
uint32_t job_id;
QEMUTimer *job_timer;
QEMUTimer *irq_timer;
bool replay_mode;
FILE *trace_file;
uint64_t mismatch_count;
uint64_t timing_diff_count;
} MaliReplayV5;
static uint32_t mali_parse_next_trace_event(MaliReplayV5 *s, hwaddr
requested_addr, uint64_t requested_time) {
char line[256];
char type;
hwaddr addr;
uint64_t val;
uint64_t timestamp;
if (!s->trace_file) return TRACE_NOT_FOUND;
while (fgets(line, sizeof(line), s->trace_file)) {
if (sscanf(line, " %c %lx %lx %lu", &type, &addr, &val,
×tamp) != 4) continue;
if (addr == requested_addr) {
if (type == 'R') return (uint32_t)val;
else if (type == 'W') return 0;
}
}
return TRACE_NOT_FOUND;
}
static uint64_t mali_replay_v5_read(void *opaque, hwaddr addr, unsigned size) {
MaliReplayV5 *s = (MaliReplayV5 *)opaque;
uint32_t offset = addr >> 2;
if (offset >= ARRAY_SIZE(s->regs)) {
qemu_log_mask(LOG_GUEST_ERROR, "Mali: read out-of-bounds at 0x%lx\n",
addr); return 0xDEADBEEF; }
if (s->replay_mode) {
uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
uint64_t value = mali_parse_next_trace_event(s, addr, current_time);
if (value == TRACE_NOT_FOUND) { qemu_log("Mali Replay:
Unexpected read at 0x%lx\n", addr); return 0; }
qemu_log("Mali Replay: Read 0x%lx from trace at 0x%lx\n", value, addr);
return value;
} else {
if (s->trace_file) { fprintf(s->trace_file, "R 0x%lx 0x%x
%ld\n", addr, s->regs[offset], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
fflush(s->trace_file); }
return s->regs[offset];
}
}
static void mali_replay_v5_write(void *opaque, hwaddr addr, uint64_t
val, unsigned size) {
MaliReplayV5 *s = (MaliReplayV5 *)opaque;
uint32_t offset = addr >> 2;
if (offset >= ARRAY_SIZE(s->regs)) {
qemu_log_mask(LOG_GUEST_ERROR, "Mali: write out-of-bounds at 0x%lx\n",
addr); return; }
if (s->replay_mode) {
uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
uint32_t expected_val = mali_parse_next_trace_event(s, addr,
current_time);
if (expected_val != TRACE_NOT_FOUND && expected_val != val) {
qemu_log("Mali Replay: Write mismatch at 0x%lx (Expected
0x%lx, Got 0x%lx)\n", addr, expected_val, val);
s->mismatch_count++;
}
} else {
if (s->trace_file) { fprintf(s->trace_file, "W 0x%lx 0x%lx
%ld\n", addr, val, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
fflush(s->trace_file); }
s->regs[offset] = (uint32_t)val;
if (offset == 0x20 && (val & 0x01)) { s->job_running = true;
s->job_id++; qemu_log("Mali: job %d started (record mode)\n",
s->job_id); timer_mod_ns(s->job_timer,
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 100 * SCALE_US); }
}
}
static void mali_replay_v5_job_complete(void *opaque) {
MaliReplayV5 *s = (MaliReplayV5 *)opaque;
s->job_running = false;
qemu_set_irq(s->irq, 1);
timer_mod_ns(s->irq_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
10 * SCALE_US);
}
static void mali_replay_v5_irq_clear(void *opaque) {
MaliReplayV5 *s = (MaliReplayV5 *)opaque;
qemu_set_irq(s->irq, 0);
}
static void mali_replay_v5_start_replay(MaliReplayV5 *s, const char *filename) {
s->trace_file = fopen(filename, "r");
if (!s->trace_file) { error_report("Failed to open trace file:
%s", filename); return; }
s->replay_mode = true;
qemu_log("Deterministic Replay v5 started.\n");
}
static void mali_replay_v5_stop_replay(MaliReplayV5 *s) {
if (s->trace_file) { fclose(s->trace_file); s->trace_file = NULL; }
s->replay_mode = false;
qemu_log("Replay stopped. Mismatches: %lu\n", s->mismatch_count);
}
static void mali_replay_v5_realize(DeviceState *dev, Error **errp) {
MaliReplayV5 *s = MALI_REPLAY_V5(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
memory_region_init_io(&s->mmio, OBJECT(s), &mali_replay_v5_ops, s,
"mali-replay-v5-mmio", 0x1000);
sysbus_init_mmio(sbd, &s->mmio);
sysbus_init_irq(sbd, &s->irq);
s->job_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
mali_replay_v5_job_complete, s);
s->irq_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
mali_replay_v5_irq_clear, s);
s->replay_mode = false;
s->trace_file = NULL;
}
static const MemoryRegionOps mali_replay_v5_ops = {
.read = mali_replay_v5_read,
.write = mali_replay_v5_write,
.endianness = DEVICE_NATIVE_ENDIAN,
.valid = { .min_access_size = 4, .max_access_size = 4 },
};
static const TypeInfo mali_replay_v5_info = {
.name = TYPE_MALI_REPLAY_V5,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(MaliReplayV5),
.realize = mali_replay_v5_realize,
};
static void mali_replay_v5_register_types(void) {
type_register_static(&mali_replay_v5_info); }
type_init(mali_replay_v5_register_types)
```
---
File 6: 06_Trace_Record_With_Time_v5.sh
```bash
#!/bin/bash
DEVICE_SERIAL=$1
SCENARIO=$2
OUTPUT_DIR="./traces/$(date +%Y%m%d_%H%M%S)"
mkdir -p $OUTPUT_DIR
adb -s $DEVICE_SERIAL shell "echo 1 > /sys/kernel/debug/tracing/tracing_on"
adb -s $DEVICE_SERIAL shell "echo 'mali:*' >
/sys/kernel/debug/tracing/set_event"
adb -s $DEVICE_SERIAL shell "echo 'irq:*' >>
/sys/kernel/debug/tracing/set_event"
adb -s $DEVICE_SERIAL shell "echo 'nsecs' >
/sys/kernel/debug/tracing/trace_options"
adb -s $DEVICE_SERIAL shell "trace-cmd record -e mali* -e irq* -o
/sdcard/trace.dat"
adb -s $DEVICE_SERIAL shell "$SCENARIO"
adb -s $DEVICE_SERIAL shell "trace-cmd stop"
adb -s $DEVICE_SERIAL pull /sdcard/trace.dat $OUTPUT_DIR/trace_raw.dat
trace-cmd report -i $OUTPUT_DIR/trace_raw.dat > $OUTPUT_DIR/trace_human.txt
python3 << EOF > $OUTPUT_DIR/trace_for_qemu.bin
import re
with open("$OUTPUT_DIR/trace_human.txt", "r") as f:
for line in f:
match =
re.search(r'(\d+\.\d+):.*(mmio_write|mmio_read|irq).*addr=(\w+)
val=(\w+)', line)
if match:
ts = int(float(match.group(1)) * 1e9)
typ = 'W' if 'write' in match.group(2) else 'R'
addr = int(match.group(3), 16)
val = int(match.group(4), 16)
if 'irq' in match.group(2):
print(f"I 0x0 0x1 {ts}")
else:
print(f"{typ} 0x{addr:x} 0x{val:x} {ts}")
EOF
echo "Trace saved to $OUTPUT_DIR/trace_for_qemu.bin"
```
---
📁 Part 2: Kernel Driver (Files 7–15)
File 7: 07_panfrost_replay_patch.patch
```diff
diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c
b/drivers/gpu/drm/panfrost/panfrost_job.c
index 123abc..456def 100644
--- a/drivers/gpu/drm/panfrost/panfrost_job.c
+++ b/drivers/gpu/drm/panfrost/panfrost_job.c
@@ -15,6 +15,10 @@
#include <linux/dma-fence.h>
#include <linux/pm_runtime.h>
+static bool replay_mode = false;
+module_param(replay_mode, bool, 0644);
+extern int mali_replay_validate(struct panfrost_device *pfdev, u32
current_val, u64 addr);
+
#define JOB_TIMEOUT_MS 5000
struct panfrost_job_slot {
@@ -120,6 +124,18 @@ static void panfrost_job_hw_submit(struct
panfrost_job *job)
u32 cfg = 0;
int ret;
+ if (unlikely(replay_mode)) {
+ u32 job_addr = job->jc;
+ int err = mali_replay_validate(pfdev, job_addr,
GPU_ADDR_TO_U64(job->jc));
+ if (err) {
+ dev_err(pfdev->dev, "REPLAY: Job validation failed
(err=%d), aborting.\n", err);
+ return;
+ }
+ dev_info(pfdev->dev, "REPLAY: Job validation passed. Skipping
real submission.\n");
+ return;
+ }
+
ret = pm_runtime_get_sync(pfdev->dev);
if (ret < 0)
return;
@@ -236,6 +252,12 @@ static irqreturn_t panfrost_job_irq_handler(int
irq, void *data)
for (i = 0; i < NUM_JOB_SLOTS; i++) {
u32 status = gpu_read(pfdev, JOB_INT_STAT + i * 16);
+ if (unlikely(replay_mode)) {
+ dev_info(pfdev->dev, "Replay IRQ captured: 0x%x\n", status);
+ gpu_write(pfdev, JOB_INT_CLEAR + i * 16, status);
+ continue;
+ }
if (!status)
continue;
```
---
File 8: 08_Makefile_Kconfig_Addon.txt
```
# ---------- Add to Kconfig (in main Kconfig) ----------
config DRM_PANFROST_REPLAY
bool "Panfrost Replay/Validation Mode (DEVELOPMENT ONLY)"
depends on DRM_PANFROST && DEBUG_FS
default n
help
Enables a debug mode for the Panfrost driver that compares
real hardware operations against a golden trace file.
This is ONLY for development and will be removed before
final submission to mainline.
# ---------- Add to Makefile (in main Makefile) ----------
obj-$(CONFIG_DRM_PANFROST) += panfrost.o
panfrost-y := panfrost_drv.o panfrost_device.o panfrost_mmu.o panfrost_gem.o \
panfrost_job.o panfrost_gpu.o panfrost_perfcnt.o
panfrost-$(CONFIG_DRM_PANFROST_REPLAY) += panfrost_replay.o
```
---
File 9: 09_build_kernel_with_replay.sh
```bash
#!/bin/bash
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-android-
export KERNEL_DIR=~/android_kernel
cd $KERNEL_DIR
patch -p1 < ~/mali_project/07_panfrost_replay_patch.patch
make defconfig
echo "CONFIG_DRM_PANFROST=y" >> .config
echo "CONFIG_DRM_PANFROST_REPLAY=y" >> .config
make olddefconfig
make -j$(nproc) Image.gz dtbs modules
mkbootimg --kernel arch/arm64/boot/Image.gz --ramdisk ramdisk.img
--output boot_replay.img
echo "boot_replay.img built successfully."
```
---
File 10: 10_Safe_Boot_Guide.md
```markdown
# Safe Boot Guide (Avoid Bricking)
## Step 1: Backup Current Boot
`fastboot boot boot.img`
## Step 2: Enable Replay Mode
`echo 1 > /sys/module/panfrost/parameters/replay_mode`
## Step 3: Record Trace
(Use script 06)
## Step 4: Restore Normal State
`fastboot flash boot stock_boot.img`
```
---
File 11: 11_panfrost_replay.c (Final Version)
```c
// SPDX-License-Identifier: GPL-2.0
#include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/crc32.h>
#include <linux/unaligned.h>
#include <linux/mutex.h>
#include <linux/ktime.h>
#include <linux/device.h>
#include <linux/string.h>
#include "panfrost_device.h"
#include "panfrost_replay.h"
#ifdef CONFIG_DRM_PANFROST_REPLAY
#define MAX_TRACE_SIZE (512 * 1024 * 1024)
#define DEFAULT_TOLERANCE_NS 1000000ULL
enum replay_state {
STATE_IDLE,
STATE_REPLAYING,
STATE_ERROR,
};
struct replay_context {
bool active;
char *trace_data;
size_t trace_size;
size_t current_pos;
u64 base_system_time_ns;
u64 base_trace_timestamp;
u64 tolerance_ns;
enum replay_state state;
struct mutex lock;
};
static struct replay_context replay_ctx;
static struct panfrost_device *g_pfdev;
/* ------------------------------------------------
* Public Functions
* ------------------------------------------------ */
void panfrost_replay_set_device(struct panfrost_device *pfdev)
{
g_pfdev = pfdev;
}
EXPORT_SYMBOL_GPL(panfrost_replay_set_device);
int panfrost_replay_init(struct panfrost_device *pfdev)
{
g_pfdev = pfdev;
mutex_init(&replay_ctx.lock);
replay_ctx.active = false;
replay_ctx.trace_data = NULL;
replay_ctx.trace_size = 0;
replay_ctx.current_pos = 0;
replay_ctx.base_system_time_ns = 0;
replay_ctx.base_trace_timestamp = 0;
replay_ctx.state = STATE_IDLE;
replay_ctx.tolerance_ns = DEFAULT_TOLERANCE_NS;
return 0;
}
EXPORT_SYMBOL_GPL(panfrost_replay_init);
void panfrost_replay_fini(struct panfrost_device *pfdev)
{
mutex_lock(&replay_ctx.lock);
kvfree(replay_ctx.trace_data);
replay_ctx.trace_data = NULL;
replay_ctx.active = false;
replay_ctx.state = STATE_IDLE;
mutex_unlock(&replay_ctx.lock);
mutex_destroy(&replay_ctx.lock);
}
EXPORT_SYMBOL_GPL(panfrost_replay_fini);
/* ------------------------------------------------
* Checksum Validation
* ------------------------------------------------ */
static int validate_checksum(const char *data, size_t total_len)
{
u32 stored_crc, computed_crc;
if (total_len < sizeof(u32))
return -EINVAL;
stored_crc = get_unaligned_le32(data + total_len - sizeof(u32));
computed_crc = crc32_le(~0, data, total_len - sizeof(u32)) ^ ~0;
return (stored_crc == computed_crc) ? 0 : -EINVAL;
}
/* ------------------------------------------------
* Fast Parser (no sscanf)
* ------------------------------------------------ */
static int parse_trace_line(const char *line, size_t len,
char *op, u64 *addr, u64 *val, u64 *ts)
{
char buf[128];
char *p, *end;
int ret;
if (len >= sizeof(buf))
len = sizeof(buf) - 1;
memcpy(buf, line, len);
buf[len] = '\0';
if (buf[0] != 'R' && buf[0] != 'W' && buf[0] != 'I')
return -EINVAL;
*op = buf[0];
p = buf + 1;
while (*p == ' ' || *p == '\t')
p++;
ret = kstrtoull(p, 16, addr);
if (ret)
return ret;
while (*p && *p != ' ' && *p != '\t')
p++;
while (*p == ' ' || *p == '\t')
p++;
if (!*p)
return -EINVAL;
ret = kstrtoull(p, 16, val);
if (ret)
return ret;
while (*p && *p != ' ' && *p != '\t')
p++;
while (*p == ' ' || *p == '\t')
p++;
if (*p) {
ret = kstrtoull(p, 10, ts);
if (ret)
return ret;
} else {
*ts = 0;
}
return 0;
}
static int replay_find_event(u64 addr, u64 *out_val, u64 *out_timestamp)
{
char *data = replay_ctx.trace_data;
size_t pos = replay_ctx.current_pos;
char *line, *nl;
char op;
u64 trace_addr, trace_val, trace_ts;
int ret;
if (replay_ctx.state == STATE_ERROR)
return -EIO;
while (pos < replay_ctx.trace_size) {
line = data + pos;
nl = memchr(line, '\n', replay_ctx.trace_size - pos);
if (!nl)
break;
size_t line_len = nl - line;
if (line_len == 0 || line_len > 256) {
pos = (nl - data) + 1;
continue;
}
ret = parse_trace_line(line, line_len, &op,
&trace_addr, &trace_val, &trace_ts);
if (ret == 0 && trace_addr == addr) {
*out_val = trace_val;
*out_timestamp = trace_ts;
replay_ctx.current_pos = (nl - data) + 1;
return 0;
}
pos = (nl - data) + 1;
}
return -ENOENT;
}
/* ------------------------------------------------
* Main Validation Function
* ------------------------------------------------ */
int mali_replay_validate(struct panfrost_device *pfdev, u32
current_val, u64 addr)
{
u64 expected_val = 0, expected_ts = 0;
u64 now = ktime_get_ns();
int ret;
if (!g_pfdev || !pfdev)
return -EINVAL;
mutex_lock(&replay_ctx.lock);
if (replay_ctx.state == STATE_IDLE || !replay_ctx.active) {
mutex_unlock(&replay_ctx.lock);
return 0;
}
if (replay_ctx.state == STATE_ERROR) {
dev_err(g_pfdev->dev, "REPLAY: Called in ERROR state\n");
mutex_unlock(&replay_ctx.lock);
return -EIO;
}
ret = replay_find_event(addr, &expected_val, &expected_ts);
if (ret) {
dev_err(g_pfdev->dev, "REPLAY: No event for addr 0x%llx\n", addr);
replay_ctx.state = STATE_ERROR;
mutex_unlock(&replay_ctx.lock);
return -ENOENT;
}
if ((u64)current_val != expected_val) {
dev_err(g_pfdev->dev,
"REPLAY: VALUE MISMATCH at addr=0x%llx expected=0x%llx got=0x%x\n",
addr, expected_val, current_val);
replay_ctx.state = STATE_ERROR;
mutex_unlock(&replay_ctx.lock);
return -EINVAL;
}
if (replay_ctx.base_trace_timestamp == 0) {
replay_ctx.base_trace_timestamp = expected_ts;
replay_ctx.base_system_time_ns = now;
}
u64 expected_delta = expected_ts - replay_ctx.base_trace_timestamp;
u64 actual_delta = now - replay_ctx.base_system_time_ns;
s64 diff = (s64)(actual_delta - expected_delta);
if (diff > replay_ctx.tolerance_ns || diff < -replay_ctx.tolerance_ns) {
dev_warn(g_pfdev->dev,
"REPLAY: Timing diff %lld ns (tolerance=%llu) for addr 0x%llx\n",
diff, replay_ctx.tolerance_ns, addr);
}
mutex_unlock(&replay_ctx.lock);
return 0;
}
EXPORT_SYMBOL_GPL(mali_replay_validate);
/* ------------------------------------------------
* DebugFS Functions
* ------------------------------------------------ */
ssize_t replay_trace_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
char *full_data = NULL;
int ret = 0;
if (!g_pfdev)
return -ENODEV;
if (*ppos != 0)
return -EINVAL;
if (count < sizeof(u32) || count > MAX_TRACE_SIZE) {
dev_err(g_pfdev->dev, "REPLAY: Invalid trace size %zu\n", count);
return -EINVAL;
}
full_data = kvmalloc(count, GFP_KERNEL);
if (!full_data)
return -ENOMEM;
if (copy_from_user(full_data, buf, count)) {
ret = -EFAULT;
goto out_free;
}
if (validate_checksum(full_data, count)) {
dev_err(g_pfdev->dev, "REPLAY: Checksum validation failed\n");
ret = -EINVAL;
goto out_free;
}
mutex_lock(&replay_ctx.lock);
kvfree(replay_ctx.trace_data);
replay_ctx.trace_data = full_data;
replay_ctx.trace_size = count;
replay_ctx.current_pos = 0;
replay_ctx.active = true;
replay_ctx.state = STATE_REPLAYING;
replay_ctx.base_trace_timestamp = 0;
replay_ctx.base_system_time_ns = 0;
mutex_unlock(&replay_ctx.lock);
dev_info(g_pfdev->dev, "REPLAY: Loaded trace (%zu bytes)\n", count);
*ppos = count;
return count;
out_free:
kvfree(full_data);
return ret;
}
ssize_t replay_reset_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
if (!g_pfdev)
return -ENODEV;
mutex_lock(&replay_ctx.lock);
if (replay_ctx.state == STATE_ERROR) {
replay_ctx.state = STATE_REPLAYING;
replay_ctx.current_pos = 0;
replay_ctx.base_trace_timestamp = 0;
replay_ctx.base_system_time_ns = 0;
dev_info(g_pfdev->dev, "REPLAY: Reset to REPLAYING\n");
}
mutex_unlock(&replay_ctx.lock);
return count;
}
ssize_t replay_enable_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
char val[16];
unsigned int enable;
if (!g_pfdev)
return -ENODEV;
if (count >= sizeof(val))
return -EINVAL;
if (copy_from_user(val, buf, count))
return -EFAULT;
val[count] = '\0';
if (kstrtouint(val, 0, &enable))
return -EINVAL;
mutex_lock(&replay_ctx.lock);
replay_ctx.active = (enable != 0);
if (!replay_ctx.active)
replay_ctx.state = STATE_IDLE;
mutex_unlock(&replay_ctx.lock);
return count;
}
ssize_t replay_enable_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
char tmp[4];
int len;
if (!g_pfdev)
return -ENODEV;
mutex_lock(&replay_ctx.lock);
len = snprintf(tmp, sizeof(tmp), "%d\n", replay_ctx.active);
mutex_unlock(&replay_ctx.lock);
return simple_read_from_buffer(buf, count, ppos, tmp, len);
}
ssize_t replay_tolerance_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
char val[32];
unsigned long long tol;
if (!g_pfdev)
return -ENODEV;
if (count >= sizeof(val))
return -EINVAL;
if (copy_from_user(val, buf, count))
return -EFAULT;
val[count] = '\0';
if (kstrtoull(val, 0, &tol))
return -EINVAL;
mutex_lock(&replay_ctx.lock);
replay_ctx.tolerance_ns = tol;
mutex_unlock(&replay_ctx.lock);
return count;
}
ssize_t replay_tolerance_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
char tmp[32];
int len;
if (!g_pfdev)
return -ENODEV;
mutex_lock(&replay_ctx.lock);
len = snprintf(tmp, sizeof(tmp), "%llu\n", replay_ctx.tolerance_ns);
mutex_unlock(&replay_ctx.lock);
return simple_read_from_buffer(buf, count, ppos, tmp, len);
}
#endif /* CONFIG_DRM_PANFROST_REPLAY */
```
---
File 12: 12_panfrost_job_updated.c
```c
extern int mali_replay_validate(struct panfrost_device *pfdev, u32
current_val, u64 addr);
extern bool replay_mode;
static void panfrost_job_hw_submit(struct panfrost_job *job)
{
struct panfrost_device *pfdev = job->pfdev;
u32 cfg = 0;
int ret;
if (unlikely(replay_mode)) {
u32 job_addr = job->jc;
int err = mali_replay_validate(pfdev, job_addr,
GPU_ADDR_TO_U64(job->jc));
if (err) {
dev_err(pfdev->dev, "REPLAY: Job validation failed
(err=%d), aborting.\n", err);
return;
}
dev_info(pfdev->dev, "REPLAY: Job validation passed. Skipping
real submission.\n");
return;
}
ret = pm_runtime_get_sync(pfdev->dev);
if (ret < 0)
return;
// ... rest of original code ...
}
```
---
File 13: 13_panfrost_replay.h
```c
#ifndef __PANFROST_REPLAY_H__
#define __PANFROST_REPLAY_H__
#include <linux/types.h>
struct panfrost_device;
struct drm_minor;
int panfrost_replay_init(struct panfrost_device *pfdev);
void panfrost_replay_fini(struct panfrost_device *pfdev);
int mali_replay_validate(struct panfrost_device *pfdev, u32
current_val, u64 addr);
void panfrost_replay_set_device(struct panfrost_device *pfdev);
void panfrost_replay_debugfs_init(struct drm_minor *minor);
#endif
```
---
File 14: 14_build_kernel_with_replay_updated.sh
```bash
#!/bin/bash
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-android-
export KERNEL_DIR=~/android_kernel
cd $KERNEL_DIR
patch -p1 < ~/mali_project/07_panfrost_replay_patch.patch
DEFCONFIG="vendor/sm8350_defconfig" # Replace with your device's defconfig
make $DEFCONFIG
scripts/config --enable CONFIG_DEBUG_FS
scripts/config --enable CONFIG_DRM_PANFROST
scripts/config --enable CONFIG_DRM_PANFROST_REPLAY
make olddefconfig
make -j$(nproc) Image.gz dtbs modules
mkbootimg --kernel arch/arm64/boot/Image.gz \
--base 0x00000000 \
--kernel_offset 0x00008000 \
--ramdisk_offset 0x01000000 \
--tags_offset 0x00000100 \
--pagesize 2048 \
--cmdline "console=ttyMSM0,115200n8 androidboot.hardware=qcom ..." \
--output boot_replay.img
echo "✅ boot_replay.img built successfully."
echo "For safe testing: fastboot boot boot_replay.img"
```
---
File 15: 15_Advanced_Usage_Guide.md
```markdown
# Advanced Replay Usage Guide
## Enable Replay (via debugfs)
```bash
adb shell "echo 1 > /sys/kernel/debug/dri/0/replay_enable"
```
Disable Replay
```bash
adb shell "echo 0 > /sys/kernel/debug/dri/0/replay_enable"
```
Upload Trace
```bash
adb push trace_for_qemu.bin /sdcard/
adb shell "cat /sdcard/trace_for_qemu.bin >
/sys/kernel/debug/dri/0/replay_trace"
```
Set Timing Tolerance (in nanoseconds)
```bash
adb shell "echo 500000 > /sys/kernel/debug/dri/0/replay_tolerance"
```
Reset Error State
```bash
adb shell "echo 1 > /sys/kernel/debug/dri/0/replay_reset"
```
View Logs
```bash
adb logcat | grep -E "REPLAY|panfrost"
```
Troubleshooting
· VALUE MISMATCH: Real driver bug – fix the driver code.
· TIMING MISMATCH: Increase tolerance or cool down the device.
· STATE_ERROR: Use replay_reset to recover.
```
---
## 📁 Part 3: Complete Documentation (Files 16–20)
### File 16: `16_Comprehensive_Step_by_Step_Guide.md`
```markdown
# Complete Step-by-Step Implementation Guide
## Prerequisites
| Tool | Purpose | Install (Ubuntu/Debian) |
| :--- | :--- | :--- |
| git | Clone kernel source | `sudo apt install git` |
| make | Build kernel | `sudo apt install make` |
| clang | Kernel compiler | `sudo apt install clang` |
| adb & fastboot | Phone communication | `sudo apt install
android-tools-adb android-tools-fastboot` |
| mkbootimg | Build boot.img | `sudo apt install mkbootimg` |
| trace-cmd | Record trace | `sudo apt install trace-cmd` |
| python3 | Process traces | `sudo apt install python3` |
---
## Step 1: Get Device Kernel Source
- **Samsung:** opensource.samsung.com
- **Xiaomi/Poco/Redmi:** github.com/MiCode/Xiaomi_Kernel_OpenSource
- **OnePlus:** github.com/OnePlusOSS
- **Google Pixel:** source.android.com/setup/build/building-kernels
## Step 2: Setup Build Environment
Create `env.sh`:
```bash
#!/bin/bash
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-android-
export CC=clang
export CLANG_TRIPLE=aarch64-linux-gnu-
export KERNEL_DIR=~/android_kernel
export OUT_DIR=~/out/kernel
```
Then: source env.sh
Step 3: Find Correct Defconfig
· Snapdragon 888: vendor/sm8350_defconfig
· Snapdragon 865: vendor/sm8250_defconfig
· MediaTek Dimensity: vendor/mt6893_defconfig
Step 4: Add Project Files to Kernel
Copy 11_panfrost_replay.c, 13_panfrost_replay.h and apply changes from
12_panfrost_job_updated.c to drivers/gpu/drm/panfrost/.
Step 5: Configure and Build
```bash
cd $KERNEL_DIR
make $DEFCONFIG O=$OUT_DIR
cd $OUT_DIR
scripts/config --file .config --enable CONFIG_DEBUG_FS
scripts/config --file .config --enable CONFIG_DRM_PANFROST
scripts/config --file .config --enable CONFIG_DRM_PANFROST_REPLAY
make olddefconfig O=$OUT_DIR
make -j$(nproc) Image.gz dtbs modules O=$OUT_DIR
```
Step 6: Build Boot Image
```bash
adb shell "dd if=/dev/block/bootdevice/by-name/boot of=/sdcard/boot.img"
adb pull /sdcard/boot.img ./stock_boot.img
mkbootimg --dump stock_boot.img
# Use the extracted parameters to build boot_replay.img
```
Step 7: Boot Kernel Safely
```bash
fastboot boot boot_replay.img
```
Step 8: Record Trace from Healthy Phone
```bash
./06_Trace_Record_With_Time_v5.sh <serial> "am start -n com.android.chrome/..."
```
Step 9: Enable Replay on Target Phone
```bash
adb shell "echo 1 > /sys/kernel/debug/dri/0/replay_enable"
adb push trace_for_qemu.bin /sdcard/
adb shell "cat /sdcard/trace_for_qemu.bin >
/sys/kernel/debug/dri/0/replay_trace"
adb logcat | grep -E "REPLAY|panfrost"
```
```
---
### File 17: `17_Additional_Setup_and_Troubleshooting.md`
```markdown
# Additional Setup & Troubleshooting
## 1. Auto-extract defconfig from phone
```bash
adb pull /proc/config.gz
gunzip config.gz
mv config arch/arm64/configs/my_device_defconfig
```
2. Extract mkbootimg parameters
```bash
mkbootimg --dump stock_boot.img
```
3. Build and install kernel modules (if needed)
```bash
make modules_install INSTALL_MOD_PATH=./modules_out
adb push modules_out/lib/modules/* /lib/modules/
adb shell depmod
```
4. Record trace without root (using atrace)
```bash
adb shell atrace --async_start -c -b 8192 mali irq
adb shell "am start -n com.android.chrome/..."
adb shell atrace --async_stop > trace.txt
```
5. Test on QEMU first
```bash
./build/qemu-system-arm -M vexpress-a15 -kernel ./kernel.elf -replay
trace.bin -d trace:mem_ops -D qemu_output.log
```
6. Alternative boot methods
· Samsung (Odin): Create tar.md5 file
· Xiaomi (Mi Flash): Similar to fastboot
7. Adjust timing tolerance
```c
static int timing_tolerance_ns = 100000;
module_param(timing_tolerance_ns, int, 0644);
```
8. Enable dynamic debug logs
```bash
adb shell "echo 'file panfrost_replay.c +p' >
/sys/kernel/debug/dynamic_debug/control"
```
```
---
### File 18: `18_separate_replay_with_ifdef.patch`
```diff
diff --git a/drivers/gpu/drm/panfrost/Kconfig b/drivers/gpu/drm/panfrost/Kconfig
index 123abc..456def 100644
--- a/drivers/gpu/drm/panfrost/Kconfig
+++ b/drivers/gpu/drm/panfrost/Kconfig
@@ -10,7 +10,7 @@ config DRM_PANFROST
Say Y here if you have such a device.
config DRM_PANFROST_REPLAY
- bool "Panfrost Replay/Validation Mode"
+ bool "Panfrost Replay/Validation Mode (DEVELOPMENT ONLY - WILL BE REMOVED)"
depends on DRM_PANFROST && DEBUG_FS
+ default n
help
Enables a replay/validation mode for the Panfrost driver.
It compares real hardware operations against a golden trace file.
+ This option is ONLY for development and debugging. It WILL BE REMOVED
+ before the final driver is submitted to mainline.
If you are unsure, say N.
config DRM_PANFROST_DEBUG
diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c
b/drivers/gpu/drm/panfrost/panfrost_job.c
index 456def..789ghi 100644
--- a/drivers/gpu/drm/panfrost/panfrost_job.c
+++ b/drivers/gpu/drm/panfrost/panfrost_job.c
@@ -18,7 +18,10 @@
#include <linux/dma-fence.h>
#include <linux/pm_runtime.h>
+#ifdef CONFIG_DRM_PANFROST_REPLAY
static bool replay_mode = false;
module_param(replay_mode, bool, 0644);
+extern int mali_replay_validate(struct panfrost_device *pfdev, u32
current_val, u64 addr);
+#endif
#define JOB_TIMEOUT_MS 5000
@@ -120,7 +123,7 @@ static void panfrost_job_hw_submit(struct panfrost_job *job)
u32 cfg = 0;
int ret;
- // If Replay mode is active, compare instead of submitting
+#ifdef CONFIG_DRM_PANFROST_REPLAY
if (unlikely(replay_mode)) {
u32 job_addr = job->jc;
int err = mali_replay_validate(pfdev, job_addr,
GPU_ADDR_TO_U64(job->jc));
@@ -131,6 +134,7 @@ static void panfrost_job_hw_submit(struct panfrost_job *job)
return;
}
#endif
+#endif
ret = pm_runtime_get_sync(pfdev->dev);
if (ret < 0)
@@ -252,12 +256,14 @@ static irqreturn_t panfrost_job_irq_handler(int
irq, void *data)
for (i = 0; i < NUM_JOB_SLOTS; i++) {
u32 status = gpu_read(pfdev, JOB_INT_STAT + i * 16);
- // In Replay mode, log IRQs but don't process them
+#ifdef CONFIG_DRM_PANFROST_REPLAY
if (unlikely(replay_mode)) {
dev_info(pfdev->dev, "Replay IRQ captured: 0x%x\n", status);
gpu_write(pfdev, JOB_INT_CLEAR + i * 16, status);
continue;
}
+#endif
+
if (!status)
continue;
diff --git a/drivers/gpu/drm/panfrost/panfrost_replay.c
b/drivers/gpu/drm/panfrost/panfrost_replay.c
index 789ghi..012jkl 100644
--- a/drivers/gpu/drm/panfrost/panfrost_replay.c
+++ b/drivers/gpu/drm/panfrost/panfrost_replay.c
@@ -1,3 +1,5 @@
+#ifdef CONFIG_DRM_PANFROST_REPLAY
+
// drivers/gpu/drm/panfrost/panfrost_replay.c
#include <linux/debugfs.h>
#include <linux/fs.h>
@@ -138,3 +140,5 @@ void panfrost_replay_fini(void) {
mutex_destroy(&replay_ctx.lock);
}
EXPORT_SYMBOL_GPL(panfrost_replay_fini);
+
+#endif /* CONFIG_DRM_PANFROST_REPLAY */
```
---
File 19: 19_README_update.md
```markdown
## ⚠️ IMPORTANT: Replay Feature is Development-Only and Will Be Removed
This driver includes a **Replay/Validation Mode** that allows
developers to compare GPU behavior against a golden trace. This
feature:
- **Is disabled by default** (`CONFIG_DRM_PANFROST_REPLAY=n`).
- **Is for debugging and validation only** – do not enable in
production kernels.
- **Will be completely removed** once the driver is finalized and
submitted to mainline.
### How to Enable (Developers Only)
1. Set `CONFIG_DRM_PANFROST_REPLAY=y` in your defconfig.
2. Read the full guide in [`DEVELOPMENT.md`](DEVELOPMENT.md).
### Warning
Using this feature in production kernels **is not recommended** and
may cause unexpected behavior. All Replay code **will be removed
before final release**.
```
---
File 20: 20_DEVELOPMENT.md
```markdown
# Developer Guide: Replay Feature for Mali-G68 Driver
**Purpose:** This document explains how to use Replay mode for driver
validation and debugging.
**Note:** This feature is for developers only and **will be completely
removed** before the driver is submitted to mainline.
---
## Enabling Replay at Build Time
1. Enable `CONFIG_DRM_PANFROST_REPLAY` in your defconfig:
```bash
scripts/config --enable CONFIG_DRM_PANFROST_REPLAY
make olddefconfig
```
2. Rebuild the kernel and boot it on your test device.
---
Usage (Step-by-Step)
1. Record Trace from a Healthy Phone
Use script 06_Trace_Record_With_Time_v5.sh:
```bash
./06_Trace_Record_With_Time_v5.sh <serial> "am start -n com.android.chrome/..."
```
This generates trace_for_qemu.bin.
2. Enable Replay Mode on Target Phone
```bash
adb shell "echo 1 > /sys/kernel/debug/dri/0/replay_enable"
```
3. Upload Trace to Kernel
```bash
adb push trace_for_qemu.bin /sdcard/
adb shell "cat /sdcard/trace_for_qemu.bin >
/sys/kernel/debug/dri/0/replay_trace"
```
4. View Results
```bash
adb logcat | grep -E "REPLAY|panfrost"
```
---
Advanced Settings
Adjust Timing Tolerance
```c
static int timing_tolerance_ns = 100000;
module_param(timing_tolerance_ns, int, 0644);
```
Then:
```bash
adb shell "echo 500000 > /sys/kernel/debug/dri/0/replay_tolerance"
```
Enable Detailed Kernel Logs
```bash
adb shell "echo 'file panfrost_replay.c +p' >
/sys/kernel/debug/dynamic_debug/control"
```
---
Troubleshooting
Error Solution
No such file: /sys/kernel/debug/dri/0/replay_trace Run adb shell mount
-t debugfs none /sys/kernel/debug
VALUE MISMATCH Check driver code – this is a real bug.
TIMING MISMATCH Increase tolerance or cool down the device.
---
Disable and Revert
```bash
adb shell "echo 0 > /sys/kernel/debug/dri/0/replay_enable"
```
Or flash the original kernel:
```bash
fastboot flash boot stock_boot.img
```
---
Summary
This is a powerful tool for developers, but must never be used in
production kernels. After development is complete, all code under
CONFIG_DRM_PANFROST_REPLAY (including panfrost_replay.c,
panfrost_replay.h, and all #ifdef blocks) will be fully removed from
the repository.
```
---
## 📁 Part 4: Advanced Features (Files 21–23)
> **Note:** File 21 (`enhanced_replay_with_checksum_state_machine.patch`) has been **removed** because all its features are already integrated into File 11.
### File 22: `22_Automated_Validation.py`
```python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
File 22: Automated Validation Script for Mali-G68 Replay Driver
"""
import subprocess
import time
import sys
import os
import json
from datetime import datetime
# ========== Configuration ==========
DEVICE_SERIAL = None
TRACE_FILE = "./trace_for_qemu.bin"
REPLAY_ENABLE_PATH = "/sys/kernel/debug/dri/0/replay_enable"
REPLAY_TRACE_PATH = "/sys/kernel/debug/dri/0/replay_trace"
REPLAY_TOLERANCE_PATH = "/sys/kernel/debug/dri/0/replay_tolerance"
REPLAY_RESET_PATH = "/sys/kernel/debug/dri/0/replay_reset"
TEST_COMMAND = "am start -n
com.android.chrome/com.google.android.apps.chrome.Main"
TOLERANCE_NS = 500000 # 500 microseconds
# ========== Helper Functions ==========
def run_adb(cmd, check=True):
full_cmd = ["adb"]
if DEVICE_SERIAL:
full_cmd.extend(["-s", DEVICE_SERIAL])
full_cmd.extend(cmd.split())
try:
result = subprocess.run(full_cmd, capture_output=True,
text=True, check=check)
return result.stdout.strip(), result.stderr.strip()
except subprocess.CalledProcessError as e:
print(f"[ERROR] adb command failed: {cmd}")
print(f"stderr: {e.stderr}")
return "", e.stderr
def adb_shell(cmd):
return run_adb(f"shell {cmd}")
def write_to_device(path, content):
cmd = f"echo '{content}' > {path}"
return adb_shell(cmd)
def push_file(local_path, remote_path="/sdcard/"):
cmd = f"push {local_path} {remote_path}"
return run_adb(cmd)
def read_dmesg(filter_str=None):
cmd = "shell dmesg"
out, _ = run_adb(cmd)
if filter_str:
lines = [line for line in out.split('\n') if filter_str in line]
return '\n'.join(lines)
return out
def check_replay_logs():
logs = read_dmesg("REPLAY")
if "VALUE MISMATCH" in logs:
return "VALUE_MISMATCH"
if "TIMING" in logs and "MISMATCH" in logs:
return "TIMING_MISMATCH"
if "ERROR" in logs:
return "ERROR"
if "Job validation passed" in logs:
return "PASSED"
return "UNKNOWN"
# ========== Test Steps ==========
def test_replay():
print("[INFO] Starting automated Replay test...")
print(f"[INFO] Trace file: {TRACE_FILE}")
print(f"[INFO] Device: {DEVICE_SERIAL if DEVICE_SERIAL else 'default'}")
print("[STEP 1] Pushing trace file to device...")
push_file(TRACE_FILE, "/sdcard/trace.bin")
print("[STEP 2] Setting tolerance...")
write_to_device(REPLAY_TOLERANCE_PATH, str(TOLERANCE_NS))
print("[STEP 3] Enabling Replay mode...")
write_to_device(REPLAY_ENABLE_PATH, "1")
print("[STEP 4] Loading trace into kernel...")
adb_shell(f"cat /sdcard/trace.bin > {REPLAY_TRACE_PATH}")
print(f"[STEP 5] Running test scenario: {TEST_COMMAND}")
adb_shell(TEST_COMMAND)
print("[STEP 6] Waiting for Replay to finish...")
time.sleep(5)
print("[STEP 7] Checking Replay logs...")
result = check_replay_logs()
print("\n========== RESULT ==========")
if result == "PASSED":
print("✅ TEST PASSED: All validations were successful.")
status = "PASS"
else:
print(f"❌ TEST FAILED: {result}")
status = "FAIL"
print("\n[DEBUG] Last 20 lines of Replay logs:")
logs = read_dmesg("REPLAY")
for line in logs.split('\n')[-20:]:
print(f" {line}")
print("\n[STEP 8] Disabling Replay mode...")
write_to_device(REPLAY_ENABLE_PATH, "0")
return status
if __name__ == "__main__":
if len(sys.argv) > 1:
TRACE_FILE = sys.argv[1]
if len(sys.argv) > 2:
DEVICE_SERIAL = sys.argv[2]
if not os.path.exists(TRACE_FILE):
print(f"[ERROR] Trace file not found: {TRACE_FILE}")
sys.exit(1)
report = {
"timestamp": datetime.now().isoformat(),
"device": DEVICE_SERIAL,
"trace_file": TRACE_FILE,
"test_command": TEST_COMMAND,
"tolerance_ns": TOLERANCE_NS,
"result": test_replay(),
"details": {}
}
with open("test_report.json", "w") as f:
json.dump(report, f, indent=2)
print(f"\n[INFO] Report saved to test_report.json")
sys.exit(0 if report["result"] == "PASS" else 1)
```
---
File 23: 23_kunit_test_replay.c
```c
// drivers/gpu/drm/panfrost/tests/panfrost_replay_kunit.c
#include <kunit/test.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/crc32.h>
#include "../panfrost_replay.h"
extern struct replay_context replay_ctx;
extern struct panfrost_device *g_pfdev;
extern int validate_checksum(const char *data, size_t total_len);
static struct panfrost_device mock_pfdev;
static char *mock_trace_data;
static void setup_mock_trace(struct kunit *test, const char *trace_content) {
size_t len = strlen(trace_content) + 1 + sizeof(u32);
u32 crc;
mock_trace_data = kmalloc(len, GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, mock_trace_data);
strcpy(mock_trace_data, trace_content);
crc = crc32_le(~0, trace_content, strlen(trace_content)) ^ ~0;
put_unaligned_le32(crc, mock_trace_data + len - sizeof(u32));
replay_ctx.trace_data = mock_trace_data;
replay_ctx.trace_size = len;
replay_ctx.current_pos = 0;
replay_ctx.active = true;
replay_ctx.base_trace_timestamp = 0;
replay_ctx.base_system_time_ns = 0;
replay_ctx.state = STATE_REPLAYING;
replay_ctx.tolerance_ns = 1000000;
g_pfdev = &mock_pfdev;
}
static void test_replay_perfect_match(struct kunit *test) {
const char *trace =
"W 0x1234 0x5678 1000000\n"
"I 0x0 0x1 1000050\n";
setup_mock_trace(test, trace);
int ret = mali_replay_validate(&mock_pfdev, 0x5678, 0x1234);
KUNIT_EXPECT_EQ(test, ret, 0);
ret = mali_replay_validate(&mock_pfdev, 0x1, 0x0);
KUNIT_EXPECT_EQ(test, ret, -ENOENT);
kfree(mock_trace_data);
}
static void test_replay_value_mismatch(struct kunit *test) {
const char *trace =
"W 0x1234 0x5678 1000000\n";
setup_mock_trace(test, trace);
int ret = mali_replay_validate(&mock_pfdev, 0x9999, 0x1234);
KUNIT_EXPECT_EQ(test, ret, -EINVAL);
KUNIT_EXPECT_EQ(test, replay_ctx.state, STATE_ERROR);
kfree(mock_trace_data);
}
static void test_replay_timing_mismatch(struct kunit *test) {
const char *trace =
"W 0x1234 0x5678 1000000\n";
setup_mock_trace(test, trace);
replay_ctx.base_system_time_ns = ktime_get_ns() + 2000000;
int ret = mali_replay_validate(&mock_pfdev, 0x5678, 0x1234);
KUNIT_EXPECT_EQ(test, ret, 0);
kfree(mock_trace_data);
}
static void test_replay_checksum_invalid(struct kunit *test) {
char *data = kmalloc(32, GFP_KERNEL);
strcpy(data, "W 0x1234 0x5678 1000000\n");
put_unaligned_le32(0xDEADBEEF, data + strlen(data));
int ret = validate_checksum(data, strlen(data) + sizeof(u32));
KUNIT_EXPECT_LT(test, ret, 0);
kfree(data);
}
static void test_replay_size_limit(struct kunit *test) {
KUNIT_EXPECT_TRUE(test, MAX_TRACE_SIZE > 0);
KUNIT_EXPECT_TRUE(test, MAX_TRACE_SIZE == 512 * 1024 * 1024);
}
static struct kunit_case replay_test_cases[] = {
KUNIT_CASE(test_replay_perfect_match),
KUNIT_CASE(test_replay_value_mismatch),
KUNIT_CASE(test_replay_timing_mismatch),
KUNIT_CASE(test_replay_checksum_invalid),
KUNIT_CASE(test_replay_size_limit),
{}
};
static struct kunit_suite replay_test_suite = {
.name = "panfrost_replay_tests",
.test_cases = replay_test_cases,
};
kunit_test_suite(replay_test_suite);
MODULE_LICENSE("GPL");
```
---
✅ Final Summary
Section Files Status
Part 1 1–6 ✅ No changes
Part 2 7–15 ✅ Files 12, 13, and 15 updated
Part 3 16–20 ✅ No changes (File 20 updated)
Part 4 22–23 (File 21 removed) ✅ Files 22 and 23 updated
---
All 23 files are now fully synchronized, reviewed, and ready to copy. 🚀