#include <sys/param.h>
#include <machine/asm.h>
#include <machine/asm_macro.h>
#include <machine/psl.h>
typedef struct label_t {
long val[19];
} label_t;
extern int setjmp(label_t *);
extern void longjmp(label_t *);
static label_t badaddr_jmpbuf;
static uint32_t badaddr_psr;
static uint32_t prom_vbr;
static uint32_t vector_page[512 * 2] __attribute__ ((__aligned__(0x1000)));
static __inline__ uint32_t
get_vbr()
{
uint32_t vbr;
__asm__ volatile ("ldcr %0, %%cr7" : "=r"(vbr));
return vbr;
}
static __inline__ void
set_vbr(uint32_t vbr)
{
__asm__ volatile ("stcr %0, %%cr7" :: "r"(vbr));
}
static void
libsa_fault_handler(void)
{
set_psr(badaddr_psr | PSR_IND);
flush_pipeline();
longjmp(&badaddr_jmpbuf);
}
static __inline__ uint32_t
br(uint32_t delta)
{
return 0xc0000000 | (((int32_t)delta >> 2) & 0x03ffffff);
}
static void
libsa_fault_init()
{
int vec;
uint32_t *insn;
uint32_t br_insn;
prom_vbr = get_vbr();
insn = vector_page;
br_insn = br(prom_vbr - (uint32_t)&vector_page - 4);
for (vec = 512; vec != 0; vec--) {
*insn++ = 0xf4005800;
*insn++ = br_insn;
}
vector_page[3 * 2 + 1] =
br((uint32_t)&libsa_fault_handler -
(uint32_t)&vector_page[3 * 2 + 1]);
}
int
badaddr(void *addr, int len)
{
int rc;
if (vector_page[0] == 0)
libsa_fault_init();
badaddr_psr = get_psr();
set_psr(badaddr_psr | PSR_IND);
set_vbr((uint32_t)&vector_page);
if (setjmp(&badaddr_jmpbuf) == 0) {
switch (len) {
case 1:
(void)*(volatile uint8_t *)addr;
rc = 0;
break;
case 2:
if ((uint32_t)addr & 1)
rc = 1;
else {
(void)*(volatile uint16_t *)addr;
rc = 0;
}
break;
case 4:
if ((uint32_t)addr & 3)
rc = 1;
else {
(void)*(volatile uint32_t *)addr;
rc = 0;
}
break;
default:
rc = 1;
break;
}
} else {
rc = 1;
}
set_vbr(prom_vbr);
flush_pipeline();
set_psr(badaddr_psr);
return rc;
}