1
0
mirror of https://github.com/antonblanchard/microwatt.git synced 2026-02-11 02:30:11 +00:00
Files
antonblanchard.microwatt/tests/reservation/reservation.c
Paul Mackerras 18120f153d MMU: Implement a vestigial partition table
This implements a 1-entry partition table, so that instead of getting
the process table base address from the PRTBL SPR, the MMU now reads
the doubleword pointed to by the PTCR register plus 8 to get the
process table base address.  The partition table entry is cached.

Having the PTCR and the vestigial partition table reduces the amount
of software change required in Linux for Microwatt support.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
2021-06-17 22:19:23 +10:00

272 lines
5.7 KiB
C

#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "console.h"
extern unsigned long callit(unsigned long arg1, unsigned long arg2,
unsigned long (*fn)(unsigned long, unsigned long));
extern unsigned long do_lqarx(unsigned long src, unsigned long regs);
extern unsigned long do_lqarx_bad(unsigned long src, unsigned long regs);
extern unsigned long do_stqcx(unsigned long dst, unsigned long regs);
#define DSISR 18
#define DAR 19
#define SRR0 26
#define SRR1 27
#define PID 48
#define SPRG0 272
#define SPRG1 273
static inline unsigned long mfspr(int sprnum)
{
long val;
__asm__ volatile("mfspr %0,%1" : "=r" (val) : "i" (sprnum));
return val;
}
static inline void mtspr(int sprnum, unsigned long val)
{
__asm__ volatile("mtspr %0,%1" : : "i" (sprnum), "r" (val));
}
static inline void store_pte(unsigned long *p, unsigned long pte)
{
__asm__ volatile("stdbrx %1,0,%0" : : "r" (p), "r" (pte) : "memory");
}
void print_string(const char *str)
{
for (; *str; ++str)
putchar(*str);
}
void print_hex(unsigned long val, int ndigits)
{
int i, x;
for (i = (ndigits - 1) * 4; i >= 0; i -= 4) {
x = (val >> i) & 0xf;
if (x >= 10)
putchar(x + 'a' - 10);
else
putchar(x + '0');
}
}
// i < 100
void print_test_number(int i)
{
print_string("test ");
putchar(48 + i/10);
putchar(48 + i%10);
putchar(':');
}
#define DO_LARX(instr, addr, val) __asm__ volatile(instr " %0,0,%1" : "=r" (val) : "r" (addr))
#define DO_STCX(instr, addr, val, cc) __asm__ volatile(instr " %2,0,%1; mfcr %0" : "=r" (cc) \
: "r" (addr), "r" (val) : "cr0", "memory");
int resv_test_1(void)
{
unsigned long x, val, cc = 0;
int count;
x = 1234;
for (count = 0; count < 1000; ++count) {
DO_LARX("ldarx", &x, val);
DO_STCX("stdcx.", &x, 5678, cc);
if (cc & 0x20000000)
break;
}
/* ldarx/stdcx. should succeed eventually */
if (count == 1000)
return 1;
if (x != 5678)
return 2;
for (count = 0; count < 1000; ++count) {
DO_LARX("lwarx", &x, val);
DO_STCX("stwcx.", &x, 9876, cc);
if (cc & 0x20000000)
break;
}
/* lwarx/stwcx. should succeed eventually */
if (count == 1000)
return 3;
if (x != 9876)
return 4;
for (count = 0; count < 1000; ++count) {
DO_LARX("lharx", &x, val);
DO_STCX("sthcx.", &x, 3210, cc);
if (cc & 0x20000000)
break;
}
/* lharx/sthcx. should succeed eventually */
if (count == 1000)
return 5;
if (x != 3210)
return 6;
return 0;
}
unsigned long do_larx(unsigned long size, unsigned long addr)
{
unsigned long val;
switch (size) {
case 1:
DO_LARX("lbarx", addr, val);
break;
case 2:
DO_LARX("lharx", addr, val);
break;
case 4:
DO_LARX("lwarx", addr, val);
break;
case 8:
DO_LARX("ldarx", addr, val);
break;
}
return 0;
}
unsigned long do_stcx(unsigned long size, unsigned long addr)
{
unsigned long val = 0, cc;
switch (size) {
case 1:
DO_STCX("stbcx.", addr, val, cc);
break;
case 2:
DO_STCX("sthcx.", addr, val, cc);
break;
case 4:
DO_STCX("stwcx.", addr, val, cc);
break;
case 8:
DO_STCX("stdcx.", addr, val, cc);
break;
}
return 0;
}
int resv_test_2(void)
{
unsigned long x[3];
unsigned long offset, j, size, ret;
x[0] = 1234;
x[1] = x[2] = 0;
for (j = 0; j <= 3; ++j) {
size = 1 << j;
for (offset = 0; offset < 16; ++offset) {
ret = callit(size, (unsigned long)&x[0] + offset, do_larx);
if (ret == 0 && (offset & (size - 1)) != 0)
return j + 1;
if (ret == 0x600) {
if ((offset & (size - 1)) == 0)
return j + 0x10;
} else if (ret)
return ret;
ret = callit(size, (unsigned long)&x[0] + offset, do_stcx);
if (ret == 0 && (offset & (size - 1)) != 0)
return j + 0x20;
if (ret == 0x600) {
if ((offset & (size - 1)) == 0)
return j + 0x30;
} else if (ret)
return ret;
}
}
return 0;
}
/* test lqarx/stqcx */
int resv_test_3(void)
{
unsigned long x[4] __attribute__((__aligned__(16)));
unsigned long y[2], regs[2];
unsigned long ret, offset;
int count;
x[0] = 0x7766554433221100ul;
x[1] = 0xffeeddccbbaa9988ul;
y[0] = 0x0badcafef00dd00dul;
y[1] = 0xdeadbeef07070707ul;
for (count = 0; count < 1000; ++count) {
ret = callit((unsigned long)x, (unsigned long)regs, do_lqarx);
if (ret)
return ret | 1;
ret = callit((unsigned long)x, (unsigned long)y, do_stqcx);
if (ret < 0x10000)
return ret | 2;
if (ret & 0x20000000)
break;
}
if (count == 1000)
return 3;
if (x[0] != y[1] || x[1] != y[0])
return 4;
if (regs[1] != 0x7766554433221100ul || regs[0] != 0xffeeddccbbaa9988ul)
return 5;
ret = callit((unsigned long)x, (unsigned long)regs, do_stqcx);
if (ret < 0x10000 || (ret & 0x20000000))
return ret | 12;
/* test alignment interrupts */
for (offset = 0; offset < 16; ++offset) {
ret = callit((unsigned long)x + offset, (unsigned long)regs, do_lqarx);
if (ret == 0 && (offset & 15) != 0)
return 6;
if (ret == 0x600) {
if ((offset & 15) == 0)
return ret + 7;
} else if (ret)
return ret;
ret = callit((unsigned long)x + offset, (unsigned long)y, do_stqcx);
if (ret >= 0x10000 && (offset & 15) != 0)
return 8;
if (ret == 0x600) {
if ((offset & 15) == 0)
return ret + 9;
} else if (ret < 0x10000)
return ret;
}
/* test illegal interrupt for bad lqarx case */
ret = callit((unsigned long)x, (unsigned long)regs, do_lqarx_bad);
if (ret != 0x700 || !(mfspr(SRR1) & 0x80000))
return ret + 10;
return 0;
}
int fail = 0;
void do_test(int num, int (*test)(void))
{
int ret;
print_test_number(num);
ret = test();
if (ret == 0) {
print_string("PASS\r\n");
} else {
fail = 1;
print_string("FAIL ");
print_hex(ret, 4);
print_string("\r\n");
}
}
int main(void)
{
console_init();
do_test(1, resv_test_1);
do_test(2, resv_test_2);
do_test(3, resv_test_3);
return fail;
}