/*
   MMMain.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/MMMain.c,v $
	Author(s):             George Fankhauser
	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 "MMMain.h"
#include "Topsy.h"
#include "Messages.h"
#include "Syscall.h"
#include "Threads.h"
#include "MMHeapMemory.h"
#include "MMVirtualMemory.h"
#include "HashList.h"
#include "HashList.h"
#include "TMThread.h"
#include "Support.h"


void mmMain(ThreadArg arg)
{
  Message						msg, reply;
  Address						address;
  ThreadId					expectedFrom;
  Thread*						threadPtr;

  //-CJ  Debug("Entering mmMain()");

  reply.from = MMTHREADID; /* sent always from this thread */

  while (TRUE)
  {
    expectedFrom = ANY;
    CLEAR_MSGENV(reply);

    if (tmMsgRecv(&expectedFrom, ANYMSGTYPE, &msg, INFINITY) ==
        TM_MSGRECVFAILED)
      PANIC("message receive error!");

    switch (msg.id)
    {
    case VM_ALLOC:
      reply.id = VM_ALLOCREPLY;
      reply.msg.vmAllocReply.errorCode =
        mmVmAlloc(&address, msg.msg.vmAlloc.size, msg.from);
      reply.msg.vmAllocReply.address = address;
      tmMsgSend(msg.from, &reply);
      break;
    case VM_UNALLOC:
      reply.id = VM_FREEREPLY;
      reply.msg.vmFreeReply.errorCode =
        mmVmFree(msg.msg.vmFree.address, msg.from);
      tmMsgSend(msg.from, &reply);
      break;
    case VM_PROTECT:
      reply.id = VM_PROTECTREPLY;
      reply.msg.vmProtectReply.errorCode = mmVmProtect(
                                             msg.msg.vmProtect.startAddress,
                                             msg.msg.vmProtect.size,
                                             msg.msg.vmProtect.pmode,
                                             msg.from);
      tmMsgSend(msg.from, &reply);
      break;
    case VM_MOVE:				/* must be a kernel thread */
      reply.id = VM_MOVEREPLY;
      if ( (threadPtr = getTHbyId(msg.from)) == NULL)
      {
        PANIC("thread lookup error!");
      }
      if (THREAD_PERMISSION(threadPtr) == KERNEL)
      {
        address = msg.msg.vmMove.address;
        reply.msg.vmMoveReply.errorCode = mmVmMove(&address,
                                          msg.msg.vmMove.newOwner);
        reply.msg.vmMoveReply.address = address;
      }
      else
      {
        reply.msg.vmMoveReply.errorCode = VM_MOVEFAILED;
      }
      tmMsgSend(msg.from, &reply);
      break;
    case VM_CLEANUP:			/* must be a kernel thread */
      if ( (threadPtr = getTHbyId(msg.from)) == NULL)
      {
        PANIC("thread lookup error!");
      }
      if (THREAD_PERMISSION(threadPtr) == KERNEL)
      {
        mmVmCleanup(msg.msg.vmCleanup.threadId);
      }
      /* this kernel internal message does not reply */
      break;
    case TM_KILLREPLY:
      /* simply digest Message (coming from tmThread) */
      break;
    default:
      reply.id = UNKNOWN_SYSCALL;
      tmMsgSend(msg.from, &reply);
      break;
    }
  }
}
