/*
  TMProtectionDomain.c, Copyright  (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/Threads/Attic/TMProtectionDomain.c,v $
	Author(s):             Christian Conrad
	Affiliation:           ETH Zuerich, TIK
	Version:               $Revision: 2922 $
	Creation Date:         
	Last Date of Change:   $Date: 2007-03-19 17:48:52 +0100 (Mon, 19 Mär 2007) $      by: $Author: baderma $
*/


#include "tm-include.h"
#include "TMProtectionDomain.h"
#include "Syscall.h"
#include "Lock.h"
#include "Memory.h"
#include "Support.h"
#include "TMThread.h"
#include "tailq.h"
#include "Assert.h"

#include "vm_domain.h"

/* Global variables */
HashList	pdomHashList;			/* Hash list of all PDs */
List			pdomList;					/* List which contains all PDs */
LockDesc	pdomLockDesc;      /* lock to protect those lists */
Lock			pdomLock = &pdomLockDesc;


/* init PD (create list & hash and init lock) */
int pdInit(void)
{
  lockInit(pdomLock);
  pdomHashList = hashListNew();
  if (pdomHashList == NULL)
  {
    return PDFAIL;
  }
  pdomList = listNew();
  if (pdomList == NULL)
  {
    return PDFAIL;
  }
  return PDOK;
}

int pdAdd(pdom_t addPD)
{
  ASSERT(addPD != NULL);
  // enter the id in the same hash list used fo threadIds
  lock(pdomLock);
  //-CJ	printf("XXX TMProtectionDomain: adding PDId: %i\n", (int) pdId);
  if ((hashListAdd( pdomHashList, addPD, 0) != HASHOK) ||
      (listAddInFront( pdomList, addPD, NULL) != LIST_OK))
  {
    unlock(pdomLock);
    return PDFAIL;
  }
  unlock(pdomLock);
  return PDOK;
}

/* creates a new protection domain */
pdom_t pdCreate(ThreadId parentPDId, char* name,
                address_t start, address_t end,
                ThreadPermission permission, ThreadPriority priority)
{
  /* 1) allocate a new pdom_entry and set name, Id, protection and   *
   *    prority.
   * 2) add PD to hash and list                                      *
   * 3) allocate new vm_domain and let the MM create this domain     *
   *    (initilize vm_map and call PMap to create a new table set)   *
   * 4) return pointer to protection domain if successfull           */
  pdom_t	newPD;
  int			err,
  pdId;


  // allocate new PD and get unique Id
  err = hmAlloc((address_t*)&newPD, sizeof(pdom_entry_t) );
  if (err != HM_ALLOCOK)
  {
    return NULL;
  }
  pdId = newPD->pdId = getThPdomId(0);

  // init the list of threads within this PD
  TAILQ_INIT(&(newPD->container));

  // enter the id in the same hash list used fo threadIds
  lock(pdomLock);
  printf("XXX TMProtectionDomain: adding PDId: %i\n", (int) pdId);
  if ( (pdId == 0) ||	(hashListAdd( pdomHashList, newPD, pdId) != HASHOK) ||
       (listAddInFront( pdomList, newPD, NULL) != LIST_OK))
  {
    unlock(pdomLock);
    hmFree((address_t)newPD);
    return NULL;
  }
  unlock(pdomLock);

  // copy information to PD
  str_ncpy(newPD->name, name, MAXNAMESIZE - 1);
  newPD->permission = permission;
  newPD->parent_pdId = parentPDId;
  newPD->priority = priority;

  // call to MM to set up memory management information
  vm_domain_init(newPD, start, end);

  // we are done!
  return newPD;
}


/* destroys a protction domain */
int pdDestroy(ThreadId pdId)
{
  /* 1) kill all Threads within this domain                          *
   * 2) use vmFreeAll to free all asociated regions                  *
   * 3) release the memory structures used by this domain (call MM)  *
   * 4) release memory used for pdom_entry                           *
   * 5) remove PD from list & hash                                   *
   * 6) return PDOK if suceessfull else return PDFAIL                */
  Thread			*thisThread;
  pdom_t			thisPD;
  int					err;


  if (hashListGet( pdomHashList, (void**)(&thisPD),
                   pdId) != HASHOK)
  {
    return PDFAIL;
  }
  while (TAILQ_EMPTY(&(thisPD->container)) == FALSE )
  {
    thisThread = TAILQ_FIRST(&(thisPD->container));
    TAILQ_REMOVE(&(thisPD->container), thisThread, pdCont);
    err = tmKill(thisThread->id);
    if (err != TM_OK)
    {
      return PDFAIL;
    }
  }
  vmFreeAll(pdId);
  vm_domain_destroy(&thisPD->vm_space);
  lock(pdomLock);
  err = hashListRemove(pdomHashList, pdId);
  if (err != HASHOK)
  {
    return PDFAIL;
  }
  err = listRemove(pdomList, thisPD, NULL);
  if (err != LIST_OK)
  {
    return PDFAIL;
  }
  unlock(pdomLock);
  err = hmFree(thisPD);
  if (err != HM_ALLOCOK)
  {
    return PDFAIL;
  }

  return PDOK;
}


pdom_t getPDbyId(ThreadId pdId)
{
  pdom_t	myPD;


  hashListGet( pdomHashList, (void**)(&myPD), pdId);
  // hashListGet writes NULL to myPD if look up failed, so we do not
  // have to catch that here
  return myPD;
}


/* for debugging purposes prints the contents of the PD structure */
void pdPrint(ThreadId pdId)
{
  pdom_t			thisPD;

  if (hashListGet( pdomHashList, (void**)(&thisPD),
                   pdId) != HASHOK)
  {
    WARNING("no such Protection Domain");
    return;
  }

  printf("Protection-Domain (id: %li)\n PD\t\t: %p\n pdId\t\t: %li\n parent_pdId\t: %li\n",
         pdId, thisPD, thisPD->pdId, thisPD->parent_pdId);
  printf(" name\t\t: %s\n vm_space\t: %p\n permission\t: %x\n priority\t: %i\n container\t: %p\n",
         thisPD->name, &thisPD->vm_space, thisPD->permission, thisPD->priority, &thisPD->container);
}
