/*
  TMHal.h, 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/TMHal.h,v $
 	Author(s):             Lukas Ruf, lr@lpr.ch
 	Affiliation:           ETH Zuerich, TIK
 	Version:               $Revision: 3044 $
 	Creation Date:         
 	Last Date of Change:   $Date: 2007-07-04 22:16:17 +0200 (Mit, 04 Jul 2007) $      by: $Author: sryffel $
*/

#ifndef __TMHAL_H
#define __TMHAL_H

#include "tm-include.h"
#include "cpu.h"
#include "Exception.h"
#include "TMProtectionDomain.h"

#define MAXNBOFEXCEPTIONS    32
#define MAXNBOFINTERRUPTS    16

/* THREADRETURNADDR is defined inside TMHal.h to allow portability.... :-)
   Stack-Layout on Function entry from C on i386:
    void foo(ARG1,ARG2,...,ARGn);
    Size  Function
      4     ARGn
      ..    ...
      4     ARG2
      4     ARG1
      4     EIP after CALL statement
   ESP points to the lowest byte of the above noted EIP
   
   As in Topsy v1.x (where this port is based on) only two thread arguments
   are provided, the "AutomaticThreadExit" is located after ARG2, i.e. ESP+12
   
   Note, this ThreadReturnAddr is relative to the Stack Pointer
 */
#define THREADRETURNADDR    12


/* Processor Status Register Flags: Called Extended Processor Flags, eflags */

#define PSL_C     0x00000001  /* carry bit */
#define PSL_PF    0x00000004  /* parity bit */
#define PSL_AF    0x00000010  /* bcd carry bit */
#define PSL_Z     0x00000040  /* zero bit */
#define PSL_N     0x00000080  /* negative bit */
#define PSL_T     0x00000100  /* trace enable bit */
#define PSL_I     0x00000200  /* interrupt enable bit */
#define PSL_D     0x00000400  /* string instruction direction bit */
#define PSL_V     0x00000800  /* overflow bit */
#define PSL_IOPL  0x00003000  /* i/o privilege level */
#define PSL_NT    0x00004000  /* nested task bit */
#define PSL_RF    0x00010000  /* resume flag bit */
#define PSL_VM    0x00020000  /* virtual 8086 mode bit */
#define PSL_AC    0x00040000  /* alignment checking */
#define PSL_VIF   0x00080000  /* virtual interrupt enable */
#define PSL_VIP   0x00100000  /* virtual interrupt pending */
#define PSL_ID    0x00200000  /* identification bit */


#define PSL_RESERVED          0x00000002

#define PSL_KERNEL            (PSL_RESERVED | PSL_I)
#define PSL_USER              (PSL_RESERVED | PSL_I)

#define STATUS_INT_ENABLE_KERNEL_PREV PSL_KERNEL
#define STATUS_INT_ENABLE_USER_PREV   PSL_USER

#define INTHANDLER_PRIORITY     KERNEL_PRIORITY_HIGH

/* SchedFlags */
#define SCHEDFLAGS_BLOCKED      1         /* Thread is blocked               */
#define SCHEDFLAGS_RESCHED      2         /* do schedule() afterwards        */
#define SCHEDFLAGS_INISR        0x10000   /* Thread is handling an Interrupt */

/* thread structure from a pointer to somewhere in the kernel mode stack */
#define GET_THREAD(pointer)     (unsigned long)((~(TM_KERNEL_MODE_STACK_SIZE-1)) & (unsigned long)pointer)

/* Temporary mask out Interrupts */
#define ATOMIC_START(flags)               __cli(&flags);
#define ATOMIC_END(flags)                 __restore_flags(flags);

#define LOCK_THREAD(threadPtr, flags)     do { ATOMIC_START(flags); lock(&threadPtr->lock); } while (0)
#define UNLOCK_THREAD(threadPtr, flags)   do { unlock(&threadPtr->lock); ATOMIC_END(flags); } while (0)

/* IPC-Makro */
#define kRECV_GET_MSGPTR(threadPtr)       (threadPtr)->contextPtr->sf->tf_esi  /* original message pointer is stored in %esi */

/*
 * Exception/Trap Stack Frame
 */
typedef struct ProcStackFrame_t
{ 
  int tf_last;      /* pointer to the last Stack Frame or 0 */
  int tf_priority;  /* Priority of the thread               */
  int tf_schedFlags;/* Flags: SCHEDFLAGS_*                  */

  int tf_gs;      /* I include even the new gs and fs selectors, even neither */
  int tf_fs;      /* FreeBSD 2.2.1 nor Linux 2.0.32 do. You never know :-)    */
  int tf_es;
  int tf_ds;
  int tf_pdbr;
  int tf_trapno;
  int tf_edi;
  int tf_esi;
  int tf_ebp;
  int tf_temp_esp;  /* this is esp before the pushal was executed */
  int tf_ebx;
  int tf_edx;
  int tf_ecx;
  int tf_eax;
  /* NOTE: To this location tf_temp_esp is pointing to :-) */
  /* below portion defined in 386 hardware */
  int tf_err;   /* tf_err is defined here so all kind ISRs can use the same */
  int tf_eip;   /*        structure to save the current processor context   */
  int tf_cs;
  int tf_eflags;
  /* below only when crossing rings (e.g. user to kernel) */
  int tf_esp; /* user stack pointer */
  int tf_ss;  /* user stack segment */
}
ProcStackFrame;
typedef ProcStackFrame* ProcStackFramePtr;

/*
 * Task State Structure for 32bit CPUs
 *  see Chapter 6 of the "Intel® 64 and IA-32 Architectures 
 *  Software Developer’s Manual Volume 3A: System Programming Guide, Part 1"
 */
typedef struct TSS_t
{
  int tss_prev_tss;       /* Previous Task Link */
  int tss_esp0;           /* Ring 0 Stack */
  int tss_ss0;            
  int tss_esp1;           /* Ring 1 Stack */
  int tss_ss1;            
  int tss_esp2;           /* Ring 2 Stack */
  int tss_ss2;
  int tss_pdbr;
  int tss_eip;
  int tss_eflags;
  int tss_eax;            /* Registers */
  int tss_ecx;
  int tss_edx;
  int tss_ebx;
  int tss_esp;
  int tss_ebp;
  int tss_esi;
  int tss_edi;        
  int tss_es;             /* Segment Selectors */
  int tss_cs;
  int tss_ss;
  int tss_ds;
  int tss_fs;
  int tss_gs;    
  int tss_ldt_sel;        /* Segment Selector to the LDT */
  unsigned short tss_T;   /* Debug Trap Flag */
  unsigned short tss_io_map_base;
}
TSS;
typedef TSS* TSSPtr;

/*
 * ProcContext 
 *  holds architecture dependent datastructures of a Thread
 */
typedef struct ProcContext_t
{
  ProcStackFramePtr sf;   /* Stack Frame Pointer: points to the stack frame on the Kernel Mode Stack */
  TSSPtr cpu_tss;         /* TSS Pointer: points to the TSS of the CPU executing the Process */
  
  int proc_esp0;          /* Stack Pointer on the Kernel Mode Stack */
  int proc_ss0;           /* Segment Selector on the Kernel Mode Stack */
}
ProcContext;
//typedef ProcContext* ProcContextPtr;


/* Saving and restoring current thread context (assembler procedures) */
void saveContext(ProcContextPtr contextPtr);
void restoreContext(ProcContextPtr contextPtr);
void __restoreContext(ProcContextPtr contextPtr);
void restoreContextEnd();

/* operations on the thread context are machine dependent and
 * encapsulated in the following functions. On CISC machines
 * most of these ops must be implemented using the current SP of
 * the context.
 */

/*
intDispatcher: LR 980501 / is called from IRQ.c --> needs definition
 */
void intDispatcher(ProcStackFramePtr frame);

/* LR 19980609: set Machine Dependencies on Proc Context */
void tmSetMachineDependentRegisters(ProcContextPtr contextPtr, pdom_t	destPD);
/* LR 20010213: adjust Machine Dependencies at the end  */
void tmAdjustMachineDependentRegisters(ProcContextPtr contextPtr, AddressSpace space);

void tmSetReturnValue(ProcContextPtr contextPtr, Register value);
void tmSetStackPointer(ProcContextPtr contextPtr, Register value);
void tmSetReturnAddress(ProcContextPtr contextPtr, Register value, Address stackPointer, Address stackPageBase);
void tmSetProgramCounter(ProcContextPtr contextPtr, Register value);
void tmSetStatusRegister(ProcContextPtr contextPtr, Register value);
void tmSetFramePointer(ProcContextPtr contextPtr, Register value);
void tmSetArgument0(ProcContextPtr contextPtr, Register value, Address stackPointer, Address stackPageBase);
void tmSetArgument1(ProcContextPtr contextPtr, Register value, Address stackPointer, Address stackPageBase);

void enableInterruptInContext( InterruptId intId, ProcContextPtr contextPtr);
void disableInterruptInContext( InterruptId intId, ProcContextPtr contextPtr);
void enableAllInterruptsInContext( ProcContextPtr contextPtr);

/* installs code by copying generalExceptionHandler()'s and
 * UTLBMissHandler()'s code at certain mips specific addresses
 */
void tmInstallExceptionCode();

/* Syscall exception handler (set per default as exception handler) */
void syscallExceptionHandler(ThreadId threadId);

/* Automatic exit of a thread when stack underflow occurs */
void automaticThreadExit();
void endAutomaticThreadExit();

void msgAdjust(ThreadPtr pFromOrToThread, Message *msg, Boolean ToKernel);

void moveMessageToPD(Thread* threadPtr, Message* msgPtr, Message* destPtr);

void powerSaver();
void busyIdle();

/* HAL-Thread handling: Stacks, Thread and Context structures */
int tmHalInit(void);
int tmHalInitThread(Thread* *threadPtr, ThreadId destPDId, ThreadId tmPDId, Address* stackBaseAddress, Address* stackBaseMappedAt, size_t* stackSize, int flags);
int tmHalDestroyThread(Thread* threadPtr, ThreadId destPDId, ThreadId tmPDId);
int tmHalCleanupAfterThreadBuild(Thread* threadPtr, Address stackBaseMappedAt, int flags);

/* HAL-Thread handling: Scheduling */
typedef enum { TIMER_INT, PAGE_FAULT, MSG_RECV, MSG_SEND, ACTIVE } BlockCause;
int tmHalThreadSetReady(ThreadPtr threadPtr, BlockCause hint);
int tmHalThreadSetBlocked(ThreadPtr threadPtr, BlockCause hint);
void tmHalThreadSetResched(ThreadPtr threadPtr, BlockCause hint);
void tmHalThreadYield(ThreadPtr threadPtr, BlockCause hint);
SchedStatus tmHalThreadGetSchedStatus(ThreadPtr threadPtr, BlockCause hint);
void tmHalIpcResetPendingFlag(Thread* threadPtr);

Thread* __get_thread_from_esp(void);


#endif

