/*
* Address Probing for M68k/ColdFire
*/
#include <bsp.h>
#include <string.h>
#include <rtems/m68k/sim.h>
#if (M68K_COLDFIRE_ARCH == 1)
# define EXCEPTION_FRAME_PC_OFFSET "4"
#else
# define EXCEPTION_FRAME_PC_OFFSET "2"
#endif
typedef int (*MemProber)(void *from, void *to);
int memProbeByte(void *from, void *to);
int memProbeShort(void *from, void *to);
int memProbeLong(void *from, void *to);
int memProbeCatcher(void);
rtems_status_code bspExtMemProbe(void *addr, int write, int size, void *pval);
__asm__(
".text\n"
"memProbeByte: \n"
" move.l %sp@(4),%a0\n"
" move.b %a0@,%d0 \n"
" move.l %sp@(8),%a0\n"
" move.b %d0,%a0@ \n"
" bra.b 1f \n"
"memProbeShort: \n"
" move.l %sp@(4),%a0\n"
" move.w %a0@,%d0 \n"
" move.l %sp@(8),%a0\n"
" move.w %d0,%a0@ \n"
" bra.b 1f \n"
"memProbeLong: \n"
" move.l %sp@(4),%a0\n"
" move.l %a0@,%d0 \n"
" move.l %sp@(8),%a0\n"
" move.l %d0,%a0@ \n"
"1: nop \n"
" moveq.l #1,%d0 \n"
" rts \n"
"memProbeCatcher: \n"
" move.l #1f,%d0 \n"
" move.l %d0,%sp@(" EXCEPTION_FRAME_PC_OFFSET ")\n"
" rte \n"
"1: clr.l %d0 \n"
" rts \n"
);
rtems_status_code
bspExtMemProbe(void *addr, int write, int size, void *pval)
{
rtems_status_code rval=RTEMS_SUCCESSFUL;
rtems_interrupt_level level;
unsigned long buf;
MemProber probe;
void *saveVector;
void **exceptionPointer;
void *vbr;
/*
* Sanity check
*/
switch (size) {
case sizeof(char): probe=memProbeByte; break;
case sizeof(short): probe=memProbeShort; break;
case sizeof(long): probe=memProbeLong; break;
default: return RTEMS_INVALID_SIZE;
}
/*
* use a buffer to make sure we don't end up probing 'pval'.
*/
if (write && pval)
memcpy(&buf, pval, size);
/*
* Get location of access fault exception
*/
m68k_get_vbr(vbr);
exceptionPointer = (void **)((char *)vbr + (2 * 4));
/*
* Probe!
*/
rtems_interrupt_disable(level);
saveVector = *exceptionPointer;
*exceptionPointer = memProbeCatcher;
if (write) {
if (probe(&buf, addr) == 0)
rval = RTEMS_INVALID_ADDRESS;
}
else {
if (probe(addr, &buf) == 0)
rval = RTEMS_INVALID_ADDRESS;
}
*exceptionPointer = saveVector;
rtems_interrupt_enable(level);
if (!write && pval && (rval == RTEMS_SUCCESSFUL))
memcpy(pval, &buf, size);
return rval;
}