/* * Ovlymgr.c -- Runtime Overlay Manager for the GDB testsuite. */ #include "ovlymgr.h" #ifdef __SPU__ /* SPU tool chain provides its own overlay manager. */ bool OverlayLoad (unsigned long ovlyno) { } bool OverlayUnload (unsigned long ovlyno) { } #else /* __SPU__ */ /* Local functions and data: */ extern unsigned long _ovly_table[][4]; extern unsigned long _novlys __attribute__ ((section (".data"))); enum ovly_index { VMA, SIZE, LMA, MAPPED}; static void ovly_copy (unsigned long dst, unsigned long src, long size); /* Flush the data and instruction caches at address START for SIZE bytes. Support for each new port must be added here. */ /* FIXME: Might be better to have a standard libgloss function that ports provide that we can then use. Use libgloss instead of newlib since libgloss is the one intended to handle low level system issues. I would suggest something like _flush_cache to avoid the user's namespace but not be completely obscure as other things may need this facility. */ static void FlushCache (void) { #ifdef __M32R__ volatile char *mspr = (char *) 0xfffffff7; *mspr = 1; #endif } /* _ovly_debug_event: * Debuggers may set a breakpoint here, to be notified * when the overlay table has been modified. */ static void _ovly_debug_event (void) { } /* OverlayLoad: * Copy the overlay into its runtime region, * and mark the overlay as "mapped". */ bool OverlayLoad (unsigned long ovlyno) { unsigned long i; if (ovlyno < 0 || ovlyno >= _novlys) exit (-1); /* fail, bad ovly number */ if (_ovly_table[ovlyno][MAPPED]) return TRUE; /* this overlay already mapped -- nothing to do! */ for (i = 0; i < _novlys; i++) if (i == ovlyno) _ovly_table[i][MAPPED] = 1; /* this one now mapped */ else if (_ovly_table[i][VMA] == _ovly_table[ovlyno][VMA]) _ovly_table[i][MAPPED] = 0; /* this one now un-mapped */ ovly_copy (_ovly_table[ovlyno][VMA], _ovly_table[ovlyno][LMA], _ovly_table[ovlyno][SIZE]); FlushCache (); _ovly_debug_event (); return TRUE; } /* OverlayUnload: * Copy the overlay back into its "load" region. * Does NOT mark overlay as "unmapped", therefore may be called * more than once for the same mapped overlay. */ bool OverlayUnload (unsigned long ovlyno) { if (ovlyno < 0 || ovlyno >= _novlys) exit (-1); /* fail, bad ovly number */ if (!_ovly_table[ovlyno][MAPPED]) exit (-1); /* error, can't copy out a segment that's not "in" */ ovly_copy (_ovly_table[ovlyno][LMA], _ovly_table[ovlyno][VMA], _ovly_table[ovlyno][SIZE]); _ovly_debug_event (); return TRUE; } #ifdef __D10V__ #define IMAP0 (*(short *)(0xff00)) #define IMAP1 (*(short *)(0xff02)) #define DMAP (*(short *)(0xff04)) static void D10VTranslate (unsigned long logical, short *dmap, unsigned long **addr) { unsigned long physical; unsigned long seg; unsigned long off; /* to access data, we use the following mapping 0x00xxxxxx: Logical data address segment (DMAP translated memory) 0x01xxxxxx: Logical instruction address segment (IMAP translated memory) 0x10xxxxxx: Physical data memory segment (On-chip data memory) 0x11xxxxxx: Physical instruction memory segment (On-chip insn memory) 0x12xxxxxx: Phisical unified memory segment (Unified memory) */ /* Addresses must be correctly aligned */ if (logical & (sizeof (**addr) - 1)) exit (-1); /* If the address is in one of the two logical address spaces, it is first translated into a physical address */ seg = (logical >> 24); off = (logical & 0xffffffL); switch (seg) { case 0x00: /* in logical data address segment */ if (off <= 0x7fffL) physical = (0x10L << 24) + off; else /* Logical address out side of on-chip segment, not supported */ exit (-1); break; case 0x01: /* in logical instruction address segment */ { short map; if (off <= 0x1ffffL) map = IMAP0; else if (off <= 0x3ffffL) map = IMAP1; else /* Logical address outside of IMAP[01] segment, not supported */ exit (-1); if (map & 0x1000L) { /* Instruction memory */ physical = (0x11L << 24) | off; } else { /* Unified memory */ physical = ((map & 0x7fL) << 17) + (off & 0x1ffffL); if (physical > 0xffffffL) /* Address outside of unified address segment */ exit (-1); physical |= (0x12L << 24); } break; } case 0x10: case 0x11: case 0x12: physical = logical; break; default: exit (-1); /* error */ } seg = (physical >> 24); off = (physical & 0xffffffL); switch (seg) { case 0x10: /* dst is a 15 bit offset into the on-chip memory */ *dmap = 0; *addr = (long *) (0x0000 + ((short)off & 0x7fff)); break; case 0x11: /* dst is an 18-bit offset into the on-chip instruction memory */ *dmap = 0x1000L | ((off & 0x3ffffL) >> 14); *addr = (long *) (0x8000 + ((short)off & 0x3fff)); break; case 0x12: /* dst is a 24-bit offset into unified memory */ *dmap = off >> 14; *addr = (long *) (0x8000 + ((short)off & 0x3fff)); break; default: exit (-1); /* error */ } } #endif /* __D10V__ */ static void ovly_copy (unsigned long dst, unsigned long src, long size) { #ifdef __D10V__ unsigned long *s, *d, tmp; short dmap_src, dmap_dst; short dmap_save; /* all section sizes should by multiples of 4 bytes */ dmap_save = DMAP; D10VTranslate (src, &dmap_src, &s); D10VTranslate (dst, &dmap_dst, &d); while (size > 0) { /* NB: Transfer 4 byte (long) quantites, problems occure when only two bytes are transfered */ DMAP = dmap_src; tmp = *s; DMAP = dmap_dst; *d = tmp; d++; s++; size -= sizeof (tmp); src += sizeof (tmp); dst += sizeof (tmp); if ((src & 0x3fff) == 0) D10VTranslate (src, &dmap_src, &s); if ((dst & 0x3fff) == 0) D10VTranslate (dst, &dmap_dst, &d); } DMAP = dmap_save; #else memcpy ((void *) dst, (void *) src, size); #endif /* D10V */ return; } #endif /* __SPU__ */