/*
  TMError.c, Copyright  (c) by Lukas Ruf, lr@lpr.ch,
  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/ia32/TMError.c,v $
 	Author(s):             Lukas Ruf, lr@lpr.ch
 	Affiliation:           ETH Zuerich, TIK
 	Version:               $Revision: 3047 $
 	Creation Date:         
 	Last Date of Change:   $Date: 2007-07-13 19:51:13 +0200 (Fre, 13 Jul 2007) $      by: $Author: sryffel $
*/
#include "Assert.h"

#include "TMError.h"
#include "Threads.h"
#include "Messages.h"
#include "TMHal.h"
#include "TMIPC.h"
#include "TMScheduler.h"
#include "TMThread.h"

#include "Video.h"

#ifdef APIC
# include "TMHalApic.h"
#endif

void general_protection_exeption_handler(ThreadId currentThread);
void invalid_opcode_exeption_handler(ThreadId currentThread);

/* tmInstallErrorHandlers() is the point where the specialized Error Handlers
   could be initialized using
   tmInstallInterruptHandler() and 
   tmInstallExceptionHandler() 
   as defined in TMHal.c.
 
   I do not provide Installation of specialized ErrorHandlers, as Topsy v1.0
   does neither :-)
 
   Original Topsy Implementation installs at this point the ClockDriver 
   tmClockHandler(). I do not so, as the Clock Handler is not an Error Handler.
 
   I do provide an Installation of a Clock Handler in 
   TMHal.c/tmInstallExceptionCode().
 */
void tmInstallErrorHandlers(void)
{
  tmSetInterruptHandler(T_IR_00,tmClockHandler,NULL);
  
  tmSetExceptionHandler(T_EX_06, invalid_opcode_exeption_handler);
  tmSetExceptionHandler(T_EX_0D, general_protection_exeption_handler);
#ifdef APIC
  // Set APIC-Error ISR
  tmSetInterruptHandler(APIC_IR_ERRIV, ApicErrorISR, NULL);
#endif
#ifdef APIC_SPIV_HANDLING_ISR
  // Specify the Spurious interrupt handler
  tmSetInterruptHandler(APIC_IR_SPIV, ApicSpivISR, NULL);
#endif
}

void tmError(ThreadId currentThread, char* errorString)
{
  int eflags;
  Message msg;
  Thread* threadPtr = getTHbyId(currentThread);

  msg.id = TM_KILL;
  msg.from = TMTHREADID;
  msg.msg.tmKill.id = currentThread;

  WARNING(errorString);
  
  if (currentThread == TMTHREADID)
  {
    DisplayContext("",threadPtr->contextPtr);
    PANIC("error in the Thread Management thread");
  } 
  // asm("hlt");

  /* Set us asleep */
  LOCK_THREAD(threadPtr, eflags);
  {
    tmHalThreadSetBlocked(threadPtr, ACTIVE); 
  }
  UNLOCK_THREAD(threadPtr, eflags);

  /* immediate in-kernel delivery without syscall
   * kSend does a schedule after the message arrived
   */

  kSend(TMTHREADID, &msg);
}

void general_protection_exeption_handler(ThreadId currentThread)
{
  int tf_err; 
  Thread* threadPtr;

  /* get the faulting thread */
  threadPtr = __get_thread_from_esp();
  ASSERT(threadPtr != NULL && threadPtr->pdPtr != NULL);

  tf_err = threadPtr->contextPtr->sf->tf_err;

  printf("Faulting eip=%p\n", threadPtr->contextPtr->sf->tf_eip);

  if (tf_err != 0) {
    printf("Fault occured while loading segment descriptor 0x%x\n", tf_err);
  }
  else
  {
    
  }


  tmError(currentThread, "General Protection Exception");
}

void invalid_opcode_exeption_handler(ThreadId currentThread)
{
  tmError(currentThread, "Invalid Opcode Exception");
}

