/*
    MMDirectMapping.c, Copyright  (c) by George Fankhauser,
    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/mips/MMDirectMapping.c,v $
 	Author(s):             George Fankhauser
 	Affiliation:           ETH Zuerich, TIK
 	Version:               $Revision: 2936 $
 	Creation Date:         
 	Last Date of Change:   $Date: 2007-03-21 15:23:42 +0100 (Mit, 21 Mär 2007) $      by: $Author: baderma $
	
*/

#include "MMMapping.h"
#include "Threads.h"
#include "Support.h"
#include "SupportMIPS.h"
#include "tlb.h"
#include "cpu.h"

#include "vm_bootup.h"

Error mmInitMemoryMapping(struct vm_segmap* segmap)
{
  /* to simulate a directmapped memory on a paged machine we fill
   * the TLB to provide the user with 64*4k memory from 4k to (256+4)k - 1.
   * Pages from [PHYSMEM-256k, PHYSMEM] are mapped to [4, 260k].
   * Page Table Entries are set to valid and global.
   * (setting up a *real* virtual memory system is lot harder) 
   */
  Register lo, hi;
  unsigned int i = 0;
  unsigned long int lo0 = 0, lo1 = 0;

  /* start at 0x00001000 to leave page zero invalid (nil pointer catcher) */
  hi = KUSEG_BASE+PAGESIZE;

  if ( getPRID() == PRID_R3K )
  {
    /* R3k TLB */
    ioConsolePutString("Topsy is running on a mips R3k machine\n");
    lo = ((PHYSMEM-USERMEM+PHYS_BASE) & TLB_LO_PFN_MASK_R3k) |
         TLB_VALID_R3k | TLB_GLOBAL_R3k | TLB_DIRTY_R3k;
    for (i = 0; i < TLB_SIZE_R3k; i++)
    {
      setR3kTLBEntry(lo, hi, i);
      hi += PAGESIZE;
      lo += PAGESIZE; /* yes, physical pages */
    }
  }
  else
  {
    /* R4k TLB */
    ioConsolePutString("Topsy is running on a mips R4k machine\n");
    lo = (((PHYSMEM-USERMEM+PHYS_BASE)>>TLB_LO_PFN_SHIFT_R4k) & TLB_LO_PFN_MASK_R4k)
         | TLB_CACHED_R4k | TLB_DIRTY_R4k | TLB_VALID_R4k | TLB_GLOBAL_R4k;

    lo0 = 0 | TLB_GLOBAL_R4k;
    lo1 = lo;

    for (i = 0; i < TLB_USER_SIZE_R4k; i++)
    {
      setR4kTLBEntry(lo0, lo1, hi, i);
      hi += (PAGESIZE<<1);
      lo += (PAGESIZE>>6); /* yes, physical pages */
      lo0 = lo;
      lo += (PAGESIZE>>6);
      lo1 = lo;
    }

    lo1 = 0 | TLB_GLOBAL_R4k;
    setR4kTLBEntry(lo0, lo1, hi, i);
    hi += (PAGESIZE<<2);

    lo0 = 0 | TLB_GLOBAL_R4k;
    for (i = (TLB_USER_SIZE_R4k+1); i < TLB_SIZE_R4k; i++)
    {
      setR4kTLBEntry(lo0, lo0, hi, i);
    }

    /* set number of wired TLB entries */
    setR4kTLBWired(TLB_SAFE_SIZE_R4k);
  }

  /* once the mapping is done, copy user code and data */
  printf("mmInitMemoryMapping: copy user code from %p to %p size %#lx\n",
         segmap->optsegment, (Address)0x1000, segmap->optsegmentsize);
  byteCopy((Address)0x1000, segmap->optsegment, segmap->optsegmentsize);

  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 = (PHYSMEM-USERMEM); /* 768kB */
  }
  else if (space == USER)
  {
    *addressPtr = (Address)KUSEG_BASE + PAGESIZE; /* zero page invalid */
    *sizePtr = USERMEM;           /* 256kB */
  }
  else
    return MM_ADDRESSSPACERANGEFAILED;
  return MM_ADDRESSSPACERANGEOK;
}
