summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/powerpc
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-25 10:22:05 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-25 10:29:06 +0200
commit8bf101c06cc4bbb57db2475b467b8f74ede33067 (patch)
treeda84908a7239e9044553331f5041f211c8107fd6 /c/src/lib/libbsp/powerpc
parentb07da56e148821c97ecb4efcdd32a4705b8d9aca (diff)
downloadrtems-8bf101c06cc4bbb57db2475b467b8f74ede33067.tar.bz2
bsp/virtex4: Move mmu.c to bsps
This patch is a part of the BSP source reorganization. Update #3285.
Diffstat (limited to 'c/src/lib/libbsp/powerpc')
-rw-r--r--c/src/lib/libbsp/powerpc/virtex4/Makefile.am2
-rw-r--r--c/src/lib/libbsp/powerpc/virtex4/mmu/mmu.c567
2 files changed, 1 insertions, 568 deletions
diff --git a/c/src/lib/libbsp/powerpc/virtex4/Makefile.am b/c/src/lib/libbsp/powerpc/virtex4/Makefile.am
index 97c94107c9..e8c4222059 100644
--- a/c/src/lib/libbsp/powerpc/virtex4/Makefile.am
+++ b/c/src/lib/libbsp/powerpc/virtex4/Makefile.am
@@ -38,7 +38,7 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/dev/serial/printk-dummy.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/powerpc/virtex4/irq/irq_init.c
# mmu
-librtemsbsp_a_SOURCES += mmu/mmu.c
+librtemsbsp_a_SOURCES += ../../../../../../bsps/powerpc/virtex4/start/mmu.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/cache/cache.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/clock/clock-ppc403.c
diff --git a/c/src/lib/libbsp/powerpc/virtex4/mmu/mmu.c b/c/src/lib/libbsp/powerpc/virtex4/mmu/mmu.c
deleted file mode 100644
index 92b4dbde38..0000000000
--- a/c/src/lib/libbsp/powerpc/virtex4/mmu/mmu.c
+++ /dev/null
@@ -1,567 +0,0 @@
-/**
- * @file
- *
- * @ingroup Virtex4MMU
- *
- * @brief Implementation of routines to manipulate the PPC 405 mmu.
- *
- * Since this is a real-time OS we want to stay away from
- * software TLB replacement.
- */
-/*
- * Authorship
- * ----------
- * This software was created by
- * Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
- * Stanford Linear Accelerator Center, Stanford University.
- * and was transcribed for the PPC 405 by
- * R. Claus <claus@slac.stanford.edu>, 2012,
- * Stanford Linear Accelerator Center, Stanford University,
- *
- * Acknowledgement of sponsorship
- * ------------------------------
- * This software was produced by
- * the Stanford Linear Accelerator Center, Stanford University,
- * under Contract DE-AC03-76SFO0515 with the Department of Energy.
- *
- * Government disclaimer of liability
- * ----------------------------------
- * Neither the United States nor the United States Department of Energy,
- * nor any of their employees, makes any warranty, express or implied, or
- * assumes any legal liability or responsibility for the accuracy,
- * completeness, or usefulness of any data, apparatus, product, or process
- * disclosed, or represents that its use would not infringe privately owned
- * rights.
- *
- * Stanford disclaimer of liability
- * --------------------------------
- * Stanford University makes no representations or warranties, express or
- * implied, nor assumes any liability for the use of this software.
- *
- * Stanford disclaimer of copyright
- * --------------------------------
- * Stanford University, owner of the copyright, hereby disclaims its
- * copyright and all other rights in this software. Hence, anyone may
- * freely use it for any purpose without restriction.
- *
- * Maintenance of notices
- * ----------------------
- * In the interest of clarity regarding the origin and status of this
- * SLAC software, this and all the preceding Stanford University notices
- * are to remain affixed to any copy or derivative of this software made
- * or distributed by the recipient and are to be affixed to any copy of
- * software made or distributed by the recipient that contains a copy or
- * derivative of this software.
- *
- * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
- */
-
-/* 405 MSR definitions; note that there are *substantial* differences
- * compared to classic powerpc; in particular, IS/DS are *different*
- * from IR/DR.
- *
- * Also: To disable/enable all external interrupts, CE and EE must both be
- * controlled.
- */
-#include <rtems.h>
-#include <rtems/bspIo.h>
-#include <rtems/powerpc/powerpc.h>
-#include <inttypes.h>
-#include <stdio.h>
-
-#include <bsp/mmu.h>
-
-
-#ifdef DEBUG
-#define STATIC
-#else
-#define STATIC static
-#endif
-
-
-bsp_tlb_entry_t* bsp_mmu_cache = 0;
-
-
-/* Since it is likely that these routines are used during
- * early initialization when stdio is not available yet
- * we provide a helper that resorts to 'printk()'
- */
-static void
-myprintf(FILE *f, char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
-
- if (!f || !_impure_ptr->__sdidinit) {
- /* Might be called at an early stage when stdio is not yet initialized. */
- vprintk(fmt,ap);
- } else {
- vfprintf(f,fmt,ap);
- }
- va_end(ap);
-}
-
-
-void
-bsp_mmu_dump_cache(FILE *f)
-{
- bsp_tlb_idx_t idx;
- if ( !bsp_mmu_cache ) {
- myprintf(stderr,"MMU TLB cache not initialized\n");
- return;
- }
- for ( idx=0; idx<NTLBS; idx++ ) {
- bsp_tlb_entry_t *tlb = bsp_mmu_cache + idx;
- if ( !tlb->hi.v )
- continue;
- myprintf(f, "#%2i: EA 0x%08x .. 0x%08x, TID 0x%03x, EU0 0x%01x\n",
- idx,
- tlb->hi.epn << 10,
- (tlb->hi.epn << 10) + (1024<<(2*tlb->hi.size))-1,
- tlb->id.tid,
- tlb->hi.att);
- myprintf(f, " PA 0x%08"PRIx32" .. 0x%08"PRIx32", PERM 0x%03x, WIMG 0x%02x\n",
- tlb->lo.rpn << 10,
- (tlb->lo.rpn << 10) + (1024<<(2*tlb->hi.size))-1,
- tlb->lo.perm,
- tlb->lo.wimg);
- }
-}
-
-static void
-fetch(bsp_tlb_idx_t key, bsp_tlb_entry_t* tlb)
-{
- register uint32_t tmp;
- __asm__ volatile ("mfpid %[tmp] \n\t"
- "stw %[tmp],0(%[tlb]) \n\t"
- "tlbrehi %[tmp],%[key] \n\t"
- "stw %[tmp],4(%[tlb]) \n\t"
- "tlbrelo %[tmp],%[key] \n\t"
- "stw %[tmp],8(%[tlb]) \n\t"
- "sync \n\t"
- : [tmp]"=&r"(tmp)
- : [key]"r"(key),
- [tlb]"b"(tlb)
- );
-}
-
-
-static void
-store(bsp_tlb_idx_t key, bsp_tlb_entry_t* tlb)
-{
- register uint32_t tmp;
- __asm__ volatile ("lwz %[tmp],0(%[tlb]) \n\t"
- "mtpid %[tmp] \n\t"
- "lwz %[tmp],4(%[tlb]) \n\t"
- "tlbwehi %[tmp],%[key] \n\t"
- "lwz %[tmp],8(%[tlb]) \n\t"
- "tlbwelo %[tmp],%[key] \n\t"
- : [tmp]"=&r"(tmp)
- : [tlb]"b"(tlb),
- [key]"r"(key)
- );
-}
-
-
-static void
-commit(void)
-{
- __asm__ volatile("isync \n\t");
-}
-
-
-/*
- * Read a TLB entry from the hardware and store the current settings in the
- * bsp_mmu_cache[] structure.
- *
- * The routine can perform this operation quietly or
- * print information to a file.
- *
- * 'idx': which TLB entry to access.
- * 'quiet': perform operation silently (no info printed)
- * if nonzero.
- * 'f': open FILE where to print information. May be
- * NULL in which case 'stdout' is used.
- *
- * RETURNS:
- * 0: success; TLB entry is VALID
- * +1: success but TLB entry is INVALID
- * < 0: error (-1: invalid argument)
- * (-2: driver not initialized)
- */
-int
-bsp_mmu_update(bsp_tlb_idx_t key, bool quiet, FILE *f)
-{
- rtems_interrupt_level lvl;
- bsp_tlb_entry_t* tlb;
- bsp_tlb_idx_t idx;
-
- idx = key;
-
- if ( idx < 0 || idx > NTLBS-1 )
- return -1;
-
- if (!bsp_mmu_cache)
- return -2;
-
- tlb = bsp_mmu_cache + idx;
-
- rtems_interrupt_disable(lvl);
-
- fetch(idx, tlb);
-
- rtems_interrupt_enable(lvl);
-
- if ( tlb->hi.v ) {
- if ( !quiet ) {
-/*
- "TLB Entry # 0 spans EA range 0x00000000 - 0x00000000
- "Mapping: VA [TID 0x00 / EPN 0x00000] -> RPN 0x00000"
- "Size: TSIZE 0x0 (4^sz KB = 000000 KB = 0x00000000 B)
- "Attributes: PERM 0x00 (ex/wr/zsel) WIMG 0x00 EU0 0x0"
-*/
- myprintf(f,
- "TLB Entry # %2d spans EA range 0x%08x - 0x%08x\n",
- idx,
- (tlb->hi.epn << 10),
- (tlb->hi.epn << 10) + (1024<<(2*tlb->hi.size)) - 1
- );
-
- myprintf(f,
- "Mapping: VA [TID 0x%02x / EPN 0x%05x] -> RPN 0x%05"PRIx32"\n",
- tlb->id.tid, tlb->hi.epn, tlb->lo.rpn
- );
- myprintf(f,
- "Size: TSIZE 0x%x (4^sz KB = %6d KB = 0x%08x B)\n",
- tlb->hi.size, (1<<(2*tlb->hi.size)), (1024<<(2*tlb->hi.size))
- );
- myprintf(f,
- "Attributes: PERM 0x%02x (ex/wr/zsel) WIMG 0x%02x EU0 0x%01x\n",
- tlb->lo.perm, tlb->lo.wimg, tlb->hi.att
- );
- }
- } else {
- if ( !quiet ) {
- myprintf(f,
- "TLB Entry # %2d <OFF> (size 0x%x = 0x%xb)\n",
- idx, tlb->hi.size, (1024<<(2*tlb->hi.size))
- );
- }
- return 1;
- }
- return 0;
-}
-
-/* Initialize cache. Should be done only once although this is not enforced.
- *
- * RETURNS: zero on success, nonzero on error; in this case the driver will
- * refuse to change TLB entries (other than disabling them).
- */
-int
-bsp_mmu_initialize()
-{
- static bsp_tlb_entry_t mmu_cache[NTLBS];
- bsp_tlb_entry_t* tlb = mmu_cache; /* Should malloc if it's not too early */
- rtems_interrupt_level lvl;
-
- bsp_tlb_idx_t idx;
- rtems_interrupt_disable(lvl);
- for (idx=0; idx<NTLBS; tlb++, idx++)
- {
- fetch(idx, tlb);
- }
- rtems_interrupt_enable(lvl);
-
- bsp_mmu_cache = mmu_cache;
- return 0;
-}
-
-/* Find first free TLB entry by examining all entries' valid bit. The first
- * entry without the valid bit set is returned.
- *
- * RETURNS: A free TLB entry number. -1 if no entry can be found.
- */
-bsp_tlb_idx_t
-bsp_mmu_find_first_free()
-{
- bsp_tlb_idx_t idx;
- bsp_tlb_entry_t entry;
-
- for (idx=0; idx<NTLBS; idx++) {
- register uint32_t tmp;
- __asm__ volatile ("tlbrehi %[tmp],%[idx] \n\t"
- "stw %[tmp],4(%[tlb]) \n\t" /* entry.hi */
- "sync \n\t"
- : [tmp]"=&r"(tmp)
- : [idx]"r"(idx),
- [tlb]"b"(&entry)
- : "memory"
- );
- if (!(entry.hi.v))
- break;
- }
- return (idx < NTLBS) ? idx : -1;
-}
-
-/*
- * Write TLB entry (can also be used to disable an entry).
- *
- * The routine checks against the cached data in
- * bsp_mmu_cache[] to prevent the user from generating
- * overlapping entries.
- *
- * 'idx': TLB entry # to manipulate
- * 'ea': Effective address (must be page aligned)
- * 'pa': Physical address (must be page aligned)
- * 'sz': Page size selector; page size is
- * 1024 * 2^(2*sz) bytes.
- * 'sz' may also be one of the following:
- * - page size in bytes ( >= 1024 ); the selector
- * value is then computed by this routine.
- * However, 'sz' must be a valid page size
- * or -1 will be returned.
- * - a value < 0 to invalidate/disable the
- * TLB entry.
- * 'flgs': Page's little-endian & user-defined flags, permissions and attributes
- * 'tid': Translation ID
- *
- * RETURNS: 0 on success, nonzero on error:
- *
- * >0: requested mapping would overlap with
- * existing mapping in other entry. Return
- * value gives conflicting entry + 1; i.e.,
- * if a value of 4 is returned then the request
- * conflicts with existing mapping in entry 3.
- * -1: invalid argument
- * -3: driver not initialized (or initialization failed).
- * <0: other error
- */
-bsp_tlb_idx_t
-bsp_mmu_write(bsp_tlb_idx_t idx, uint32_t ea, uint32_t pa, uint sz,
- uint32_t flgs, uint32_t tid)
-{
- bsp_tlb_entry_t tlb;
- uint32_t msk;
- bsp_tlb_idx_t lkup;
- rtems_interrupt_level lvl;
-
- if ( sz >= 1024 ) {
- /* Assume they literally specify a size */
- msk = sz;
- sz = 0;
- while ( msk != (1024u<<(2*sz)) ) {
- if ( ++sz > 7 ) {
- return -1;
- }
- }
- /* OK, acceptable */
- }
-
- msk = sz > 0 ? (1024u<<(2*sz)) - 1 : 0;
-
- if ( !bsp_mmu_cache && sz > 0 ) {
- myprintf(stderr,"MMU driver not initialized; refusing to enable any entry\n");
- return -3;
- }
-
- if ( (ea & msk) || (pa & msk) ) {
- myprintf(stderr,"Misaligned EA (%08x) or PA (%08x) (mask is %08x)\n", ea, pa, msk);
- return -1;
- }
-
- if ( idx < 0 || idx > NTLBS-1 )
- return -1;
-
- if ( sz > 7 ) {
- myprintf(stderr,"Invalid size %u = %08x = %u KB\n", sz, 1024u<<(2*sz), (1024u<<(2*sz))/1024);
- return -1;
- }
-
- if ( sz >=0 ) {
- lkup = bsp_mmu_match(ea, sz, tid);
-
- if ( lkup < -1 ) {
- /* some error */
- return lkup;
- }
- if ( (lkup >= 0) && (lkup != idx) && (bsp_mmu_cache[lkup].hi.v != 0) ) {
- myprintf(stderr,"TLB #%i overlaps with requested mapping\n", lkup);
- bsp_mmu_update( lkup, false, stderr);
- return lkup+1;
- }
- }
-
- /* OK to proceed */
- tlb.id.tid = tid;
- tlb.hi.v = sz >= 0;
- tlb.hi.size = sz;
- tlb.hi.epn = (ea & (0xfffffc00 << (sz + sz))) >> 10;
- tlb.lo.rpn = (pa & (0xfffffc00 << (sz + sz))) >> 10;
- tlb.hi.att = (flgs & MMU_M_ATTR) >> MMU_V_ATTR;
- tlb.lo.perm = (flgs & MMU_M_PERM) >> MMU_V_PERM;
- tlb.lo.wimg = (flgs & MMU_M_PROP) >> MMU_V_PROP;
-
- rtems_interrupt_disable(lvl);
-
- store(idx, &tlb);
-
- commit();
-
- rtems_interrupt_enable(lvl);
-
- /* update cache */
- bsp_mmu_update(idx, true, 0);
-
- return 0;
-}
-
-/*
- * Check if a ea/sz/tid mapping overlaps with an existing entry.
- *
- * 'ea': The Effective Address to match against
- * 'sz': The 'logarithmic' size selector; the page size
- * is 1024*2^(2*sz).
- * 'tid': The TID to match against
- *
- * RETURNS:
- * >= 0: index of the TLB entry that already provides a mapping
- * which overlaps within the ea range.
- * -1: SUCCESS (no conflicting entry found)
- * <=-2: ERROR (invalid input)
- */
-bsp_tlb_idx_t
-bsp_mmu_match(uint32_t ea, int sz, uint32_t tid)
-{
- bsp_tlb_idx_t idx;
- uint32_t m,a;
- bsp_tlb_entry_t* tlb;
-
- if ( sz < 0 || sz > 7 )
- return -4;
-
- sz = (1024<<(2*sz));
-
- if ( !bsp_mmu_cache ) {
- /* cache not initialized */
- return -3;
- }
-
- if ( ea & (sz-1) ) {
- /* misaligned ea */
- return -2;
- }
-
- for ( idx=0, tlb=bsp_mmu_cache; idx<NTLBS; idx++, tlb++ ) {
- if ( ! tlb->hi.v )
- continue;
- if ( tlb->id.tid && tlb->id.tid != tid )
- continue;
- /* TID matches a valid entry */
- m = (1024<<(2*tlb->hi.size)) - 1;
- /* calculate starting address of this entry */
- a = tlb->hi.epn << 10;
- if ( ea <= a + m && ea + sz -1 >= a ) {
- /* overlap */
- return idx;
- }
- }
- return -1;
-}
-
-/* Find TLB index that maps 'ea/tid' combination
- *
- * 'ea': Effective address to match against
- * 'tid': The TID to match against
- *
- * RETURNS: index 'key' which indicates whether
- * the mapping was found.
- *
- * On error (no mapping) -1 is returned.
- */
-bsp_tlb_idx_t
-bsp_mmu_find(uint32_t ea, uint32_t tid)
-{
- rtems_interrupt_level lvl;
- register uint32_t pid;
- register bsp_tlb_idx_t idx;
- register int failure;
-
- rtems_interrupt_disable(lvl);
-
- __asm__ volatile ("mfpid %[pid] \n\t" /* Save PID */
- "mtpid %[tid] \n\t"
- "tlbsx. %[idx],0,%[ea] \n\t" /* Failure changes the index reg randomly. */
- "mfcr %[failure] \n\t"
- "mtpid %[pid] \n\t" /* Restore PID */
- : [pid]"=r"(pid),
- [idx]"=&r"(idx),
- [failure]"=&r"(failure)
- : [tid]"r"(tid),
- [ea]"r"(ea)
- : "cc"
- );
-
- rtems_interrupt_enable(lvl);
-
- return (failure & 0x20000000) ? idx : -1;
-}
-
-/* Mark TLB entry as invalid ('disabled').
- *
- * 'key': TLB entry (index).
- *
- * RETURNS: zero on success, nonzero on error (TLB unchanged).
- *
- * NOTE: If a TLB entry is disabled the associated
- * entry in bsp_mmu_cache[] is also
- * marked as disabled.
- */
-int
-bsp_mmu_invalidate(bsp_tlb_idx_t key)
-{
- bsp_tlb_idx_t k0;
- rtems_interrupt_level lvl;
- bsp_tlb_entry_t tlb;
- uint32_t msr;
-
- /* Minimal guard against bad key */
- if ( key < 0 || key > NTLBS-1 )
- return -1;
-
- _CPU_MSR_GET(msr);
-
- /* While address translation is enabled... */
- if (msr & (PPC_MSR_IR | PPC_MSR_DR))
- {
- /* Must not invalidate page 0 which holds vectors, text etc... */
- k0 = bsp_mmu_find(0, 0);
- if ( -1 == k0 ) {
- myprintf(stderr,"No mapping for address 0 found\n");
- return -2;
- }
-
- /* NOTE: we assume PID is ignored */
- if ( k0 == key ) {
- myprintf(stderr,"Cannot invalidate page holding address 0 (always needed)\n");
- return -3;
- }
- }
-
- rtems_interrupt_disable(lvl);
-
- fetch(key, &tlb);
-
- /* Invalidate old entries */
- tlb.hi.v = 0;
-
- store(key, &tlb);
-
- commit();
-
- /* update cache */
- bsp_mmu_cache[ key ].hi.v = tlb.hi.v;
-
- rtems_interrupt_enable(lvl);
-
- return 0;
-}