/*
    Copyright 2001 (c) by Boris Lutz,
    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/VMemory/sa1100/Attic/vm_hal.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 "types.h"
#include "Support.h"
#include "Memory.h"
#include "vm.h"
#include "vm_calls.h"
#include "kalloc_api.h"
#include "vm_hal.h"
#include "cpu.h"
#include "Assert.h"
#include "MemoryLayout.h"


/*** internal function prototypes ***/
int mapSpecialDmap(struct vm_map* vm_map, struct vm_pmap* vm_pmap,
                   address_t physStart, address_t virtStart, size_t mapSize, int flags);


address_t getSegStart (int type)
{
  if (type == KERNEL)
  {
    // Kernel need some pages for special mappings (eg. pmap_copy)
    return (address_t) 0x00010000;
  }
  else
  {
    return (address_t) 0x00001000;
  }
}


address_t getSegEnd (int type)
{
  if (type == KERNEL)
  {
    return (address_t) 0xFFFFFFFF;
  }
  else
  {
    return (address_t) 0xcFFFFFFF;
  }
}


int mapSpecialRegions(struct vm_map* vm_map, struct vm_pmap* vm_pmap, int flags)
{
  int err;
  err = mapSpecialDmap(vm_map, vm_pmap, (address_t)SA_TIMER_BASE,
                       (address_t)SA_TIMER_BASE, PAGESIZE, flags);
  if (err != VM_OK)
    return err;
  err = mapSpecialDmap(vm_map, vm_pmap, (address_t)SA_UART_BASE,
                       (address_t)SA_UART_BASE, PAGESIZE, flags);
  if (err != VM_OK)
    return err;
  err = mapSpecialDmap(vm_map, vm_pmap, (address_t)XSCALE_CSR_BASE,
                       (address_t)XSCALE_CSR_BASE, PAGESIZE, flags&~MSR_MAP_HLV);
  if (err != VM_OK)
    return err;
  err = mapSpecialDmap(vm_map, vm_pmap, (address_t)EXCSEG_PHYS_BASE,
                       (address_t)EXCSEG_BASE,  EXCSEG_SIZE, flags&~MSR_MAP_HLV);
  if (err != VM_OK)
    return err;

  if ( !(flags & MSR_IN_KERNEL) )
  {
    // map kernelsegment directly if not in kernel
    err = mapSpecialDmap(vm_map, vm_pmap, (address_t)KERNEL_BASE,
                         (address_t)KERNEL_BASE, ONE_MEG, flags);
    if (err != VM_OK)
      return err;
  }
  return VM_OK;
}



int mapSpecialDmap(struct vm_map* vm_map, struct vm_pmap* vm_pmap,
                   address_t physStart, address_t virtStart, size_t mapSize, int flags)
{
  int							err;
  size_t					len;
  RegionPtr_t			mapReg;
  unsigned char 	*regArg;



  if ( (flags & MSR_MAP_HLV) )
  {
    len = 4 + sizeof(size_t) + sizeof(address_t);		// length of argument vect
    mapReg = km_alloc(sizeof(Region_t) + len, KM_MEMORY);
    if (mapReg == NULL)
      return VM_FAILED;
    mapReg->start = virtStart;
    mapReg->end   = virtStart + mapSize - 1;
    mapReg->cur   = mapReg->max = VM_ACCESS_NONE;		// kernel access only
    mapReg->type  = VM_MANAGER_DMAP;

    // set up argument (physical start & size)
    regArg = mapReg->obj_arg.arg;
    *regArg++ = sizeof(address_t);		// length of 1st argument (phys address)
    *regArg++ = VM_DMAPPED_PHYSADDR;	// type of 1st argument
    byteCopy(regArg, &physStart, sizeof(address_t));	// copy 1st argument
    regArg += sizeof(address_t);			// point to 2nd argument
    *regArg++ = sizeof(size_t);				// length of 2nd argument (size)
    *regArg++ = VM_DMAPPED_SIZE;			// type of 2nd argument
    byteCopy(regArg, &mapSize, sizeof(size_t));	// copy argument
    regArg += sizeof(size_t);					// next (to make sure & for debugging)
    mapReg->obj_arg.argsize = len;		// total length of all arguments
    ASSERT( len == (int)((address_t)regArg - (address_t)mapReg->obj_arg.arg) );

    err = vm_region_add(vm_map, vm_pmap, mapReg);
    if (err != VM_OK)
      return err;
    km_free(mapReg);
  }

  if ( (flags & MSR_MAP_LLV) )
  {
    //-CJ		printf("mapSpecialDmap: phys %p virt %p size %#lx\n",
    //-CJ				physStart, virtStart, mapSize);
    err = vm_pmap_region_enter(vm_pmap, physStart, virtStart, mapSize, VM_ACCESS_NONE);
    if (err != VM_OK)
      return err;
  }

  return VM_OK;
}
