blob: 7464a69e9323fb6d77097accba9fd0b07add7e8c [file] [log] [blame]
/*
* Copyright (C) 2022 Alibaba Corporation
* Author: Shuai Xue
*
* This software may be redistributed and/or modified under the terms of
* the GNU General Public License ("GPL") version 2 only as published by the
* Free Software Foundation.
*/
#include <fcntl.h>
#include <time.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <setjmp.h>
#include <signal.h>
#define _GNU_SOURCE 1
#define __USE_GNU 1
#include <sched.h>
#include <sys/syscall.h>
#include <linux/futex.h>
#include "einj.h"
char *progname;
long pagesize;
int Sflag;
typedef struct
{
int num;
/*
* Any unaligned access to memory region with any Device memory type
* attribute generates an Alignment fault. Thus, add a safe padding.
*/
char pad[3];
long long int paddr;
} mpgprot_drv_ctx;
extern unsigned long long vtop(unsigned long long addr, pid_t pid);
#define DEV_NAME "/dev/pgprot_drv"
#define PAGE_SHIFT 12
static mpgprot_drv_ctx *ctx = NULL;
int trigger_write(char *addr)
{
addr[0] = 0x69;
return 0;
}
#define ONE p = (char **)*p;
#define FIVE ONE ONE ONE ONE ONE
#define TEN FIVE FIVE
#define FIFTY TEN TEN TEN TEN TEN
#define HUNDRED FIFTY FIFTY
static int poison = 0;
static int bench = 0;
int main(int argc, char *argv[])
{
int kfd, c;
long long paddr;
void *vaddr;
progname = argv[0];
if (!is_privileged())
exit(1);
while ((c = getopt(argc, argv, "pb")) != -1)
switch (c)
{
case 'p':
poison = 1;
break;
case 'b':
bench = 1;
break;
}
kfd = open(DEV_NAME, O_RDWR | O_NDELAY);
if (kfd < 0)
{
printf("open file %s error: Is the pgprot_drv.ko module loaded?\n", DEV_NAME);
return -1;
}
vaddr = mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, kfd, 0);
if (vaddr == MAP_FAILED)
{
printf("allocate mem fail %d!!!\n", 4096);
exit(1);
}
ctx = (mpgprot_drv_ctx *)vaddr;
printf("check ctx: vaddr = %p, num %d, paddr %llx\n", vaddr, ctx->num, ctx->paddr);
if (bench)
{
struct timeval tv1, tv2;
int memsize = 4096;
int stride = 128;
int size = memsize / stride;
unsigned *indices = malloc(size * sizeof(int));
int i, count, tmp;
struct timezone tz;
char *mem = vaddr;
unsigned long sec, usec;
for (i = 0; i < size; i++)
indices[i] = i;
// trick 2: fill mem with pointer references
for (i = 0; i < size - 1; i++)
*(char **)&mem[indices[i] * stride] = (char *)&mem[indices[i + 1] * stride];
*(char **)&mem[indices[size - 1] * stride] = (char *)&mem[indices[0] * stride];
register char **p = (char **)mem;
tmp = count / 100;
gettimeofday(&tv1, &tz);
for (i = 0; i < tmp; ++i)
{
HUNDRED;
}
gettimeofday(&tv2, &tz);
if (tv2.tv_usec < tv1.tv_usec)
{
usec = 1000000 + tv2.tv_usec - tv1.tv_usec;
sec = tv2.tv_sec - tv1.tv_sec - 1;
}
else
{
usec = tv2.tv_usec - tv1.tv_usec;
sec = tv2.tv_sec - tv1.tv_sec;
}
/* touch pointer p to prevent compiler optimization */
char **touch = p;
printf("Buffer size: %ld KB, stride %d, time %d.%06d s, latency %.2f ns\n",
memsize / 1024, stride, sec, usec, (sec * 1000000 + usec) * 1000.0 / (tmp * 100));
}
if (poison)
{
/* pick from kernel */
long long int paddr = ctx->paddr;
printf("vaddr = %p paddr = %llx\n", vaddr, paddr);
inject_mem_uc(paddr, vaddr, 1);
sleep(3);
trigger_write(vaddr);
}
munmap(ctx, 4096);
return 0;
}