1
0
Files
2022-09-29 17:59:04 +03:00

250 lines
4.5 KiB
C

#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/immu.h>
#include <sys/mman.h>
#include <sys/sysmp.h>
#include <sys/pda.h>
/*
* Unit test for executing instructions out of data areas.
*
*/
#define PASS 1
#define FAIL 0
#define Message if (Verbose) printf
#define Debug if (Dbg) printf
int Verbose = 0;
int No_mprotect = 0;
int Dbg = 0;
int Iterations = 5;
int func1();
static int pagesize;
#undef NBPP
#undef NBPC
#define NBPP pagesize
#define NBPC pagesize
main(int argc, char *argv[])
{
int c;
int errflg = 0;
pagesize = getpagesize();
while ((c = getopt(argc, argv, "vndi:")) != -1)
switch (c) {
case 'v':
Verbose++;
break;
case 'n':
No_mprotect++;
break;
case 'd':
Dbg++;
break;
case 'i':
Iterations = atoi(optarg);
break;
case '?':
errflg++;
break;
}
if (errflg) {
fprintf(stderr, "Usage: mexec [-v] [-n]\n");
exit(1);
}
if (Verbose)
fprintf(stderr, "WARNING: running with verbose on tends to invalidate the results since\ncalling into the kernel for the writes can invalidate the i cache\n\n");
while (Iterations--) {
if (Unit_tests() == FAIL) {
printf("\n*** UNIT TESTS FAILED ***\n\n");
exit(1);
}
}
printf("mexec: All tests passed\n");
exit(0);
}
/*
* buffer in bss where instructions will be stored.
*/
char buf[512];
#define FUNC_SIZE 100 /* can't do sizeof(func), so we guess */
#define FUNC1_VALUE 42
#define FUNC2_VALUE 24
int func1();
int func2();
Unit_tests()
{
int errors = 0;
int (*func_ptr)();
int num_cpus, cpu;
struct pda_stat *pdap;
num_cpus = do_sysmp(MP_NPROCS);
pdap = (struct pda_stat *)malloc(sizeof(struct pda_stat) * num_cpus);
do_sysmp(MP_STAT, pdap);
/*
* Go to each cpu, one at a time, and try a simple test
*/
for (cpu = 0; cpu < num_cpus; cpu++) {
if ((pdap[cpu].p_flags & PDAF_ENABLED) == 0)
continue;
do_sysmp(MP_MUSTRUN, cpu);
Message("Running on cpu %d now...\n", cpu);
Message("Executing func1 out of bss...\n");
memcpy(buf, func1, FUNC_SIZE);
func_ptr = (int(*)())buf;
do_mprotect(buf, FUNC_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC);
if (func_ptr() != FUNC1_VALUE) {
fprintf(stderr, "case 1: func1 returned wrong value on cpu %d\n",
cpu);
errors++;
}
Message("Executing func2 out of bss...\n");
memcpy(buf, func2, FUNC_SIZE);
do_mprotect(buf, FUNC_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC);
if (func_ptr() != FUNC2_VALUE) {
fprintf(stderr, "case 1: func2 returned wrong value on cpu %d\n",
cpu);
errors++;
}
}
/*
* Now try dirty'ing the i-cache on each cpu, then changing it one.
* Then go back and the others to make sure they got flushed as
* well.
*/
Message("Dirty all caches, then change on one...\n");
memcpy(buf, func1, FUNC_SIZE);
func_ptr = (int(*)())buf;
do_mprotect(buf, FUNC_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC);
for (cpu = 0; cpu < num_cpus; cpu++) {
if ((pdap[cpu].p_flags & PDAF_ENABLED) == 0)
continue;
do_sysmp(MP_MUSTRUN, cpu);
Message("Running on cpu %d now...\n", cpu);
if (func_ptr() != FUNC1_VALUE) {
fprintf(stderr, "case 2: func1 returned wrong value on cpu %d\n",
cpu);
errors++;
}
}
Message("Changing to func2...\n");
memcpy(buf, func2, FUNC_SIZE);
func_ptr = (int(*)())buf;
do_mprotect(buf, FUNC_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC);
Message("Checking all cpus for func2 code...\n");
for (cpu = 0; cpu < num_cpus; cpu++) {
if ((pdap[cpu].p_flags & PDAF_ENABLED) == 0)
continue;
do_sysmp(MP_MUSTRUN, cpu);
Message("Running on cpu %d now...\n", cpu);
if (func_ptr() != FUNC2_VALUE) {
fprintf(stderr, "case 2: func2 returned wrong value on cpu %d\n",
cpu);
errors++;
}
}
if (errors)
return FAIL;
else
return PASS;
}
/*
* Round addr to page boundary and adjust len as a convenience to the
* caller. Also check for errors.
*/
do_mprotect(caddr_t addr, size_t len, int prot)
{
int offset;
/*
* To see whether the tests are really generating stale i-cache
* entries, it's useful to shut off the mprotects and make sure
* the tests fail.
*/
if (No_mprotect)
return;
offset = (ulong)addr & POFFMASK;
addr = (caddr_t)((ulong)addr & ~POFFMASK);
len += offset;
if (mprotect(addr, len, prot) == -1) {
fprintf(stderr, "mprotect(0x%x, 0x%x, 0x%x) failed\n",
addr, len, prot);
perror("mprotect");
}
}
do_sysmp(cmd, arg1)
int cmd, arg1;
{
int rval;
if ((rval = sysmp(cmd, arg1)) == -1) {
fprintf(stderr, "sysmp failed, cmd 0x%x, arg 0x%x\n",
cmd, arg1);
perror("sysmp");
}
return rval;
}
func1()
{
return FUNC1_VALUE;
}
func2()
{
return FUNC2_VALUE;
}