/*
    Copyright 2001 (c) by Silvio Dragone & David Reist,
    Swiss Federal Institute of Technology,
    Computer Engineering and Networks Laboratory.
 
    TOPSY -- A Teachable Operating System.
             Implementation of a tiny and simple
             micro kernel for teaching purposes.
 
    For further information, please visit http://www.tik.ee.ethz.ch/~topsy
 
    This software is provided under the terms of the GNU General Public 
    Licence. A full copy of the GNU GPL is provided in the file COPYING 
    found in the development root of Topsy.
*/
/*
	
    File:                  $Source: /home/ruf/cvs_Topsy/cvs/Topsy/Memory/sa1100/MMDirectMapping.c,v $
    Affiliation:           ETH Zuerich, TIK
    Version:               $Revision: 2922 $
    Last Date of Change:   $Date: 2007-03-19 17:48:52 +0100 (Mon, 19 Mär 2007) $  by: $Author: baderma $
 
*/

#include "MMMapping.h"
#include "Threads.h"
#include "Support.h"
#include "SupportSA1100.h"
#include "tt.h"
#include "cpu.h"
#include "Topsy.h"

Error mmInitMemoryMapping(struct vm_segmap* segMapPtr)
{
  /* we fill the Page Translation Tables to provide the user with 64*4k memory from 1M-256K-1 to 1M-1 within the KUSEG.
   * Mapped regions have individual access restrictions (members of 'full access domain' & 'restricted domain'),
   * unmapped regions have no access rights (members of 'no access domain').
   */

  unsigned int tt_base, tt_l1_entry, tt_l2_entry, i, current_TT_L2_base,
  dac_value, id;

  unsigned int* ptr;

  ioConsolePutString("\ninit memory mapping... ");

  /* Domains: 15..0, each has a 2bit entry with
   * 0b00 - no access
   * 0b01 - Client (access permissions checked)
   * 0b10 - unpredictable, do not use!!!
   * 0b11 - Manager (access permissions not checked)
   */
  dac_value = 0x0000001C;
  /* Domain 3..15:                      : not used                      => no access at all                          */
  /* Domain 2    : TT_DOMAIN_RESTRICTED : mapped restricted region      => access rights are checked                 */
  /* Domain 1    : TT_DOMAIN_FULLACCESS : mapped full accessible region => full access, no access rights are checked */
  /* Domain 0    : TT_DOMAIN_NOACCESS   : not mapped region             => no access at all                          */

  id = getPRID();
  if ((id & PRID_IXP1200_MASK) == (PRID_IXP1200 & PRID_IXP1200_MASK))
  {
    /* IXP1200 core found */
    ioConsolePutString("\nTopsy is running on an IXP1200 (SA1100 core), revision ");
    ioConsolePutHexInt((id & (Register)0xF)); // it works, but fix the output format, please!
    ioConsolePutString("\nWARNING: THIS IS AN UNRELEASED TOPSY VERSION!");
    ioConsolePutString("\nANY ACCESS TO NON-MAPPED ADDRESSES MAY DESTROY THE FLASH MEMORY!!!\n");

    tt_base = (TT_L1_BASE & 0xffffC000);  /* just to be sure the 14 low bits are zero */

    setTTBase(tt_base);                   /* set TT (L1) Base register                */

    setDAC(dac_value);                    /* set domain access control register       */

    current_TT_L2_base = TT_L2_BASE; /* address of the current TT L2 base, we start with the real TT L2 base */

    /* we fill up the whole TT L1 with no access domain (Domain 0) entries for access control */
    tt_l1_entry = ((current_TT_L2_base) & 0xfffffC00) /* points to the 1st L2 Table Base */
                  | TT_DOMAIN_NOACCESS
                  | TT_IMP_IMPDEF
                  | TT_L1_DESCRIPTOR_COARSE;

    for (i=0; i < TT_L1_SIZE; i++)
    {
      setTTL1Entry(TT_L1_BASE, i , tt_l1_entry);
    }

    /* we fill up the 1st L2 Table. All non-mapped regions/pages are mapped here, but not allowed to access any page */

    tt_l2_entry = (((NASEG_BASE & 0xfffff000) /* we point to No Access Segment */
                    | TT_AP3_PERM_NO           /* the whole NASEG has no access rights at all! */
                    | TT_AP2_PERM_NO
                    | TT_AP1_PERM_NO
                    | TT_AP0_PERM_NO)
                   & ~TT_CACHABLE
                   & ~TT_BUFFERABLE)
                  | TT_L2_DESCRIPTOR_SMALL;

    for (i = 0; i < TT_L2_SIZE; i++)
    {
      setTTL2Entry(current_TT_L2_base, i, tt_l2_entry);
      tt_l2_entry += PAGESIZE;
    }

    /* now we fill the No Access Region with never ending loops, just to be sure nothing illegal can be done */
    for (i = 0; i < 1024*1024; i+=4)
    {
      ptr = NASEG_BASE + i;
      *ptr = 0xEAFFFFFE; /* loop forever, we should never come to this asm instruction because of the no access rights of this region,
      													* if domain rights are working some time later! */
    }

    current_TT_L2_base += TT_L2_SIZE * 4;


    /* now we set up mapped TT_L1 and TT_L2 entries to map all used regions */

    /* map EXCSEG to SRAM */
    tt_l1_entry = ((current_TT_L2_base) & 0xfffffC00)
                  | TT_DOMAIN_RESTRICTED
                  | TT_IMP_IMPDEF
                  | TT_L1_DESCRIPTOR_COARSE;

    tt_l2_entry = (((EXCSEG_PHYS_BASE & 0xfffff000)
                    | TT_AP3_PERM_UNO
                    | TT_AP2_PERM_UNO
                    | TT_AP1_PERM_UNO
                    | TT_AP0_PERM_UNO)
                   & ~TT_CACHABLE
                   & ~TT_BUFFERABLE)
                  | TT_L2_DESCRIPTOR_SMALL;


    setTTL1Entry(TT_L1_BASE, EXCSEG_BASE >> 20, tt_l1_entry);
    for (i = 0; i < TT_L2_SIZE; i++)
    {
      setTTL2Entry(current_TT_L2_base, i, tt_l2_entry);
      tt_l2_entry += PAGESIZE;
    }

    current_TT_L2_base += TT_L2_SIZE * 4;

#if 1
    /*** map SRAM 1MB up to 2MB directly (for uEngines Stuff ***/

    // 0x10100000 - 0x101FFFFF
    tt_l1_entry = ((current_TT_L2_base) & 0xfffffC00)
                  | TT_DOMAIN_RESTRICTED
                  | TT_IMP_IMPDEF
                  | TT_L1_DESCRIPTOR_COARSE;

    tt_l2_entry = ((( (SRAM_BASE + 1024 * 1024) & 0xfffff000)
                    | TT_AP3_PERM_UNO
                    | TT_AP2_PERM_UNO
                    | TT_AP1_PERM_UNO
                    | TT_AP0_PERM_UNO)
                   & ~TT_CACHABLE
                   & ~TT_BUFFERABLE)
                  | TT_L2_DESCRIPTOR_SMALL;


    setTTL1Entry(TT_L1_BASE, ((SRAM_BASE + 1024 * 1024) & 0xfffff000) >> 20, tt_l1_entry);
    for (i = 0; i < TT_L2_SIZE; i++)
    {
      setTTL2Entry(current_TT_L2_base, i, tt_l2_entry);
      tt_l2_entry += PAGESIZE;
    }

    current_TT_L2_base += TT_L2_SIZE * 4;
#endif

#if 1
    /*** map slow port directly ***/

    // 0x3840000 - 0x384FFFFF
    tt_l1_entry = ((current_TT_L2_base) & 0xfffffC00)
                  | TT_DOMAIN_RESTRICTED
                  | TT_IMP_IMPDEF
                  | TT_L1_DESCRIPTOR_COARSE;

    setTTL1Entry(TT_L1_BASE, SLOW_PORT_BASE >> 20, tt_l1_entry);
    tt_l2_entry = (((SLOW_PORT_BASE & 0xfffff000)
                    | TT_AP3_PERM_UNO | TT_AP2_PERM_UNO | TT_AP1_PERM_UNO
                    | TT_AP0_PERM_UNO) & ~TT_CACHABLE & ~TT_BUFFERABLE) | TT_L2_DESCRIPTOR_SMALL;
    for (i = 0; i < TT_L2_SIZE; i++)
    {
      setTTL2Entry(current_TT_L2_base, i, tt_l2_entry);
      tt_l2_entry += PAGESIZE;
    }
    current_TT_L2_base += TT_L2_SIZE * 4;

    // 0x3850000 - 0x385FFFFF
    tt_l1_entry = ((current_TT_L2_base) & 0xfffffC00)
                  | TT_DOMAIN_RESTRICTED
                  | TT_IMP_IMPDEF
                  | TT_L1_DESCRIPTOR_COARSE;

    setTTL1Entry(TT_L1_BASE, (SLOW_PORT_BASE + 1048576L) >> 20, tt_l1_entry);
    tt_l2_entry = ((( (SLOW_PORT_BASE + 1048576L ) & 0xfffff000)
                    | TT_AP3_PERM_UNO | TT_AP2_PERM_UNO | TT_AP1_PERM_UNO
                    | TT_AP0_PERM_UNO) & ~TT_CACHABLE & ~TT_BUFFERABLE) | TT_L2_DESCRIPTOR_SMALL;
    for (i = 0; i < TT_L2_SIZE; i++)
    {
      setTTL2Entry(current_TT_L2_base, i, tt_l2_entry);
      tt_l2_entry += PAGESIZE;
    }
    current_TT_L2_base += TT_L2_SIZE * 4;

    /*** end map slow port ***/
#endif

#if 1
    /*** map uEngines CSR (B000 0000 - B000280) and CSRs (B000 4000 - B000
     * 6800) and FBI CSRs (B004 000 - ?) by mapping all memeroy from B000 0000
     * - B00F FFFF directly ***/
    // 0xB000000 - 0xB00FFFFF
    tt_l1_entry = ((current_TT_L2_base) & 0xfffffC00)
                  | TT_DOMAIN_RESTRICTED
                  | TT_IMP_IMPDEF
                  | TT_L1_DESCRIPTOR_COARSE;

    setTTL1Entry(TT_L1_BASE, UENGBASE >> 20, tt_l1_entry);
    tt_l2_entry = (((UENGBASE & 0xfffff000)
                    | TT_AP3_PERM_UNO | TT_AP2_PERM_UNO | TT_AP1_PERM_UNO
                    | TT_AP0_PERM_UNO) & ~TT_CACHABLE & ~TT_BUFFERABLE) | TT_L2_DESCRIPTOR_SMALL;
    for (i = 0; i < TT_L2_SIZE; i++)
    {
      setTTL2Entry(current_TT_L2_base, i, tt_l2_entry);
      tt_l2_entry += PAGESIZE;
    }
    current_TT_L2_base += TT_L2_SIZE * 4;
#endif

    /* map PCIREGSEG directly */
    tt_l1_entry = ((current_TT_L2_base) & 0xfffffC00)
                  | TT_DOMAIN_RESTRICTED
                  | TT_IMP_IMPDEF
                  | TT_L1_DESCRIPTOR_COARSE;

    tt_l2_entry = (((PCIREGSEG_BASE & 0xfffff000)
                    | TT_AP3_PERM_UNO
                    | TT_AP2_PERM_UNO
                    | TT_AP1_PERM_UNO
                    | TT_AP0_PERM_UNO )
                   & ~TT_CACHABLE
                   & ~TT_BUFFERABLE)
                  | TT_L2_DESCRIPTOR_SMALL;


    setTTL1Entry(TT_L1_BASE, PCIREGSEG_BASE >> 20, tt_l1_entry);
    for (i = 0; i < TT_L2_SIZE; i++)
    {
      setTTL2Entry(current_TT_L2_base, i, tt_l2_entry);
      tt_l2_entry += PAGESIZE;
    }
    current_TT_L2_base += TT_L2_SIZE * 4;


    /* map REGSEG directly */
    tt_l1_entry = ((current_TT_L2_base) & 0xfffffC00)
                  | TT_DOMAIN_RESTRICTED
                  | TT_IMP_IMPDEF
                  | TT_L1_DESCRIPTOR_COARSE;

    tt_l2_entry = (((REGSEG_BASE & 0xfffff000)
                    | TT_AP3_PERM_UNO
                    | TT_AP2_PERM_UNO
                    | TT_AP1_PERM_UNO
                    | TT_AP0_PERM_UNO )
                   & ~TT_CACHABLE
                   & ~TT_BUFFERABLE)
                  | TT_L2_DESCRIPTOR_SMALL;

    setTTL1Entry(TT_L1_BASE, REGSEG_BASE >> 20, tt_l1_entry);

    for (i = 0; i < TT_L2_SIZE; i++)
    {
      setTTL2Entry(current_TT_L2_base, i, tt_l2_entry);
      tt_l2_entry += PAGESIZE;
    }
    current_TT_L2_base += TT_L2_SIZE * 4;


    /* map TT_L1 and TT_L2 to DRAM */
    tt_l1_entry = ((current_TT_L2_base) & 0xfffffC00)
                  | TT_DOMAIN_RESTRICTED
                  | TT_IMP_IMPDEF
                  | TT_L1_DESCRIPTOR_COARSE;

    tt_l2_entry = (((TT_L1_BASE & 0xfffff000)
                    | TT_AP3_PERM_UNO
                    | TT_AP2_PERM_UNO
                    | TT_AP1_PERM_UNO
                    | TT_AP0_PERM_UNO )
                   & ~TT_CACHABLE
                   & ~TT_BUFFERABLE)
                  | TT_L2_DESCRIPTOR_SMALL;

    setTTL1Entry(TT_L1_BASE, TT_L1_BASE >> 20, tt_l1_entry);

    for (i = 0; i < TT_L2_SIZE; i++)
    {
      setTTL2Entry(current_TT_L2_base, i, tt_l2_entry);
      tt_l2_entry += PAGESIZE;
    }
    current_TT_L2_base += TT_L2_SIZE * 4;


    /* map K0SEG to DRAM */
    tt_l1_entry = ((current_TT_L2_base) & 0xfffffC00)
                  | TT_DOMAIN_RESTRICTED
                  | TT_IMP_IMPDEF
                  | TT_L1_DESCRIPTOR_COARSE;

    tt_l2_entry = (((K0SEG_BASE & 0xfffff000)
                    | TT_AP3_PERM_UNO
                    | TT_AP2_PERM_UNO
                    | TT_AP1_PERM_UNO
                    | TT_AP0_PERM_UNO)
                   & ~TT_CACHABLE
                   & ~TT_BUFFERABLE)
                  | TT_L2_DESCRIPTOR_SMALL;

    setTTL1Entry(TT_L1_BASE, K0SEG_BASE >> 20, tt_l1_entry);



    for (i = 0; i < TT_L2_SIZE; i++)
    {
      setTTL2Entry(current_TT_L2_base, i, tt_l2_entry);
      tt_l2_entry += PAGESIZE;
    }
    current_TT_L2_base += TT_L2_SIZE * 4;


    /* map K1SEG to DRAM */
    tt_l1_entry = ((current_TT_L2_base) & 0xfffffC00)
                  | TT_DOMAIN_RESTRICTED
                  | TT_IMP_IMPDEF
                  | TT_L1_DESCRIPTOR_COARSE;

    tt_l2_entry = (((K1SEG_BASE & 0xfffff000)
                    | TT_AP3_PERM_UNO
                    | TT_AP2_PERM_UNO
                    | TT_AP1_PERM_UNO
                    | TT_AP0_PERM_UNO)
                   & ~TT_CACHABLE
                   & ~TT_BUFFERABLE)
                  | TT_L2_DESCRIPTOR_SMALL;

    setTTL1Entry(TT_L1_BASE, K1SEG_BASE >> 20, tt_l1_entry);

    for (i = 0; i < TT_L2_SIZE; i++)
    {
      setTTL2Entry(current_TT_L2_base, i, tt_l2_entry);
      tt_l2_entry += PAGESIZE;
    }
    current_TT_L2_base += TT_L2_SIZE * 4;


    /* map K2SEG to DRAM */
    tt_l1_entry = ((current_TT_L2_base) & 0xfffffC00)
                  | TT_DOMAIN_RESTRICTED
                  | TT_IMP_IMPDEF
                  | TT_L1_DESCRIPTOR_COARSE;

    tt_l2_entry = (((K2SEG_BASE & 0xfffff000)
                    | TT_AP3_PERM_UNO
                    | TT_AP2_PERM_UNO
                    | TT_AP1_PERM_UNO
                    | TT_AP0_PERM_UNO)
                   & ~TT_CACHABLE
                   & ~TT_BUFFERABLE)
                  | TT_L2_DESCRIPTOR_SMALL;

    setTTL1Entry(TT_L1_BASE, K2SEG_BASE >> 20, tt_l1_entry);

    for (i = 0; i < TT_L2_SIZE; i++)
    {
      setTTL2Entry(current_TT_L2_base, i, tt_l2_entry);
      tt_l2_entry += PAGESIZE;
    }
    current_TT_L2_base += TT_L2_SIZE * 4;


    /* map KUSEG to DRAM */
    tt_l1_entry = ((current_TT_L2_base) & 0xfffffC00)
                  | TT_DOMAIN_FULLACCESS
                  | TT_IMP_IMPDEF
                  | TT_L1_DESCRIPTOR_COARSE;

    tt_l2_entry = (((KUSEG_BASE & 0xfffff000)
                    | TT_AP3_PERM_URW           /* the whole KUSEG has RW access rights for user! */
                    | TT_AP2_PERM_URW
                    | TT_AP1_PERM_URW
                    | TT_AP0_PERM_URW)
                   & ~TT_CACHABLE
                   & ~TT_BUFFERABLE)
                  | TT_L2_DESCRIPTOR_SMALL;

    setTTL1Entry(TT_L1_BASE, KUSEG_BASE >> 20, tt_l1_entry);

    for (i = 0; i < TT_L2_SIZE; i++)
    {
      setTTL2Entry(current_TT_L2_base, i, tt_l2_entry);
      tt_l2_entry += PAGESIZE;
    }

    ioConsolePutString("\nMMU map TTL1 and TTL2 set\n");

    /* now we set up a mini abort handler for debugging */

    /* mov a0, #0xC0 */
    /*      ptr  = 0x10000020;*/ /* data abort */
    /*      *ptr = 0xE3A000C0; */

    /* mov a0, a0, lsl #8 */
    /*      ptr  = 0x10000024; */
    /*      *ptr = 0xE1A00400; */

    /* add a0, a0, #0x12 */
    /*      ptr  = 0x10000028; */
    /*      *ptr = 0xE2800012; */

    /* mov a0, a0, lsl #16*/
    /*      ptr  = 0x1000002C;*/
    /*      *ptr = 0xE1A00800;*/

    /* mov pc, a0*/
    /*      ptr  = 0x10000030;*/
    /*      *ptr = 0xE1A0F000;*/

    flush_tlb(); /* TLB needs to be flushed each time before MMU is enabled or disabled! */

    enableMMU(); /* WARNING: code must be at same location before and after MMU enabling to execute properly! */

    ioConsolePutString("\nMMU init done\n");

  }
  else
  {
    /* core could not be identified */
    PANIC("MMDirectMapping.c: Unable to boot up! Unknown core");
    return MM_INITMEMORYMAPPINGFAILED;
  }

  /* we do not copy user code and data because we use the bootstrap program (cygmon) to load the user to it's region! */

  return MM_INITMEMORYMAPPINGOK;
}


Error mmMapPages(Page startPage, Page nOfPages, PageStatus pstat)
{
  return MM_MAPPAGESOK;
}


Error mmUnmapPages(Page startPage, Page nOfPages)
{
  return MM_UNMAPPAGESOK;
}


Error mmMovePage(Page from, Page to)
{
  /* direct mapped memory systems can only copy the page */
  byteCopy((Address)(to*LOGICALPAGESIZE), (Address)(from*LOGICALPAGESIZE),
           LOGICALPAGESIZE);
  zeroOut((Address)(from*LOGICALPAGESIZE), LOGICALPAGESIZE);
  return MM_MOVEPAGEOK;
}


Error mmProtectPage(Page page, ProtectionMode pmode)
{
  /* direct mapped memory does nothing */
  return MM_PROTECTPAGEFAILED;
}


Error  mmAddressSpaceRange(AddressSpace space, Address* addressPtr,
                           unsigned long int* sizePtr)
{
  if (space == KERNEL)
  {
    *addressPtr = (Address)K0SEG_BASE;
    *sizePtr = K0SEG_SIZE;
  }
  else if (space == USER)
  {
    *addressPtr = (Address)KUSEG_BASE; // + PAGESIZE; /* zero page invalid */
    *sizePtr = KUSEG_SIZE;
  }
  else
    return MM_ADDRESSSPACERANGEFAILED;
  return MM_ADDRESSSPACERANGEOK;
}

//void setDACEntry(unsigned int* dac_value, unsigned int index, unsigned int access_type)
/* this function used to change access type of a particular domain */
/*{
	if (access_type == 0b00) {
	dac_value = dac_value & ~(0b11<<(index*2)); 
	}
 
	if (access_type == 0b01) {
	dac_value = dac_value & ~(0b0<<(index*2 + 1));
	dac_value = dac_value | (0b1<<(index*2));
	}
 
	if (access_type == 0b10) {
	dac_value = dac_value & (0b1<<(index*2 + 1));
	dac_value = dac_value | ~(0b0<<(index*2));
	}
 
	if (access_type == 0b11) {
	dac_value = dac_value | (0b11<<(index*2)); 
	}
 
	setDAC(dac_value);
	}*/
