summaryrefslogblamecommitdiffstats
path: root/private/mvdm/softpc.new/base/ccpu386/c_bsic.c
blob: ca248fee81399bf4493ea728e46492fed98df126 (plain) (tree)
















































































































































































































































































































































































                                                                                   
/*[

c_bsic.c

LOCAL CHAR SccsID[]="@(#)c_bsic.c	1.7 09/20/94";

Basic Protected Mode Support and Flag Support.
----------------------------------------------

]*/


#include <insignia.h>

#include <host_def.h>
#include <xt.h>

#include <c_main.h>
#include <c_addr.h>
#include <c_bsic.h>
#include <c_prot.h>
#include <c_seg.h>
#include <c_stack.h>
#include <c_xcptn.h>
#include	<c_reg.h>
#include <c_page.h>


/*
   =====================================================================
   EXTERNAL ROUTINES START HERE.
   =====================================================================
 */


/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* Determine 'super' type from access rights.                         */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
GLOBAL ISM32
descriptor_super_type
       	          
IFN1(
	IU16, AR	/* (I) access rights */
    )


   {
   ISM32 super;

   switch ( super = GET_AR_SUPER(AR) )
      {
   case 0x0: case 0x8: case 0xa: case 0xd:
      /* We have just one bad case */
      return INVALID;

   
   case 0x1: case 0x2: case 0x3:
   case 0x4: case 0x5: case 0x6: case 0x7:
   case 0x9: case 0xb: case 0xc: case 0xe: case 0xf:
      /* system/control segments have one to one mapping */
      return super;
   
   case 0x10: case 0x11: case 0x12: case 0x13:
   case 0x14: case 0x15: case 0x16: case 0x17:
   case 0x18: case 0x19: case 0x1a: case 0x1b:
   case 0x1c: case 0x1d: case 0x1e: case 0x1f:
      /* data/code segments map as if accessed */
      return super | ACCESSED;
      }

   /* We 'know' we never get here, but the C compiler doesn't */
   return 0;
   }

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* Set OF flag after multiple shift or rotate instruction.            */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
GLOBAL VOID
do_multiple_shiftrot_of
       	          
IFN1(
	ISM32, new_of	/* (I) overflow that would be written by last bit
		       shift or rotate */
    )


   {
	SAVED	IBOOL	cold = TRUE;
	SAVED	IBOOL	shiftrot_of_undef = FALSE;

	if( cold )
	{
		/*
		 * Determine whether to have the multiple shift/rotates
		 * OF undefined or calculated by the count == 1 algorithm.
		 * The default is the count == 1 option.
		 */

		shiftrot_of_undef = ( host_getenv( "SHIFTROT_OF_UNDEF" ) != NULL );
		cold = FALSE;
	}
   /*
      There are three possible actions:-

      1) Set OF based on the last bit shift or rotate.

      2) Leave OF unchanged

      3) Set OF to a specific undefined value.
    */

	if( shiftrot_of_undef )
	{
		/* Set undefined flag(s) */
		SET_OF(UNDEFINED_FLAG);
	}
	else
	{
		/* Just like count of one case */
		SET_OF(new_of);
	}
   }

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* Retrieve Intel EFLAGS register value                               */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
GLOBAL IU32
c_getEFLAGS IFN0()
   {
   IU32 flags;

   flags = getFLAGS();   /* get lower word */

   flags = flags | GET_VM() << 17 | GET_RF() << 16;

#ifdef SPC486
   flags = flags | GET_AC() << 18;
#endif /* SPC486 */

   return flags;
   }

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* Retrieve Intel FLAGS register value                                */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
GLOBAL IU32
getFLAGS()
   {
   IU32 flags;

   flags = GET_NT() << 14 | GET_IOPL() << 12 | GET_OF() << 11 |
	   GET_DF() << 10 | GET_IF()   <<  9 | GET_TF() <<  8 |
	   GET_SF() <<  7 | GET_ZF()   <<  6 | GET_AF() <<  4 |
	   GET_PF() <<  2 | GET_CF()         | 0x2;

   return flags;
   }

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* Read a descriptor table at given linear address.                   */
/* Take #PF if descriptor not in linear address space.                */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
GLOBAL VOID
read_descriptor_linear
       	    	               
IFN2(
	IU32, addr,	/* (I) Linear address of descriptor */
	CPU_DESCR *, descr	/* (O) Pntr to our internal descriptor structure */
    )


   {
   IU32 first_dword;
   IU32 second_dword;
   IU32 limit;

   /*
      The format of a 286 descriptor is:-

	 ===========================
      +1 |        LIMIT 15-0       | +0
	 ===========================
      +3 |        BASE 15-0        | +2
	 ===========================
      +5 |     AR     | BASE 23-16 | +4
	 ===========================
      +7 |         RESERVED        | +6
	 ===========================
   */

   /*
      The format of a 386 descriptor is:-

	 =============================        AR  = Access Rights.
      +1 |         LIMIT 15-0        | +0     AVL = Available.
	 =============================        D   = Default Operand
      +3 |         BASE 15-0         | +2           Size, = 0 16-bit
	 =============================                    = 1 32-bit.
      +5 |      AR     | BASE 23-16  | +4     G   = Granularity,
	 =============================                 = 0 byte limit
	 |             | | | |A|LIMIT|                 = 1 page limit.
      +7 | BASE 31-24  |G|D|0|V|19-16| +6
	 |             | | | |L|     |
	 =============================

   */

   /* read in descriptor with minimum interaction with memory */
   first_dword  = spr_read_dword(addr);
   second_dword = spr_read_dword(addr+4);

   /* load attributes and access rights */
   descr->AR = second_dword >> 8 & WORD_MASK;

   /* unpack the base */
   descr->base = (first_dword >> 16) | 
		 (second_dword << 16 & 0xff0000 ) |
		 (second_dword & 0xff000000);

   /* unpack the limit */
   limit = (first_dword & WORD_MASK) | (second_dword & 0xf0000);

   if ( second_dword & BIT23_MASK )
      {
      /* Granularity Bit Set. Limit is expressed in pages
	 (4k bytes), convert to byte limit */
      limit = limit << 12 | 0xfff;
      }
   descr->limit = limit;
   }

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* Check for null selector                                            */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
GLOBAL BOOL
selector_is_null
       	          
IFN1(
	IU16, selector	/* selector to be checked */
    )


   {
   if ( GET_SELECTOR_INDEX(selector) == 0 && GET_SELECTOR_TI(selector) == 0 )
      return TRUE;
   return FALSE;
   }

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* Check if selector outside bounds of GDT                            */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
GLOBAL BOOL
selector_outside_GDT
       	    	               
IFN2(
	IU16, selector,	/* (I) selector to be checked */
	IU32 *, descr_addr	/* (O) address of related descriptor */
    )


   {
   IU16 offset;

   offset = GET_SELECTOR_INDEX_TIMES8(selector);

   /* make sure GDT then trap NULL selector or outside table */
   if ( GET_SELECTOR_TI(selector) == 1 ||
	offset == 0 || offset + 7 > GET_GDT_LIMIT() )
      return TRUE;
   
   *descr_addr = GET_GDT_BASE() + offset;
   return FALSE;
   }

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* Check if selector outside bounds of GDT or LDT                     */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
GLOBAL BOOL
selector_outside_GDT_LDT
       	    	               
IFN2(
	IU16, selector,	/* (I) selector to be checked */
	IU32 *, descr_addr	/* (O) address of related descriptor */
    )


   {
   IU16 offset;

   offset = GET_SELECTOR_INDEX_TIMES8(selector);

   /* choose a table */
   if ( GET_SELECTOR_TI(selector) == 0 )
      {
      /* GDT - trap NULL selector or outside table */
      if ( offset == 0 || offset + 7 > GET_GDT_LIMIT() )
	 return TRUE;
      *descr_addr = GET_GDT_BASE() + offset;
      }
   else
      {
      /* LDT - trap invalid LDT or outside table */
#ifndef DONT_CLEAR_LDTR_ON_INVALID
      if ( GET_LDT_SELECTOR() <= 3 || offset + 7 > GET_LDT_LIMIT() )
#else
      if ( GET_LDT_SELECTOR() == 0 || offset + 7 > GET_LDT_LIMIT() )
#endif /* DONT_CLEAR_LDTR_ON_INVALID */
	 return TRUE;
      *descr_addr = GET_LDT_BASE() + offset;
      }
   
   return FALSE;
   }

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* Store new value in Intel EFLAGS register.                          */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
GLOBAL VOID
c_setEFLAGS
                 
IFN1(
	IU32, flags
    )


   {
   setFLAGS(flags);   /* set lower word */

   SET_RF((flags & BIT16_MASK) != 0);

   if ( GET_CPL() == 0 )
      SET_VM((flags & BIT17_MASK) != 0);

#ifdef SPC486
   SET_AC((flags & BIT18_MASK) != 0);
#endif /* SPC486 */
   }

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* Store new value in Intel FLAGS register                            */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
GLOBAL VOID
setFLAGS
                 
IFN1(
	IU32, flags
    )


   {
   SET_CF((flags & BIT0_MASK) != 0);
   SET_PF((flags & BIT2_MASK) != 0);
   SET_AF((flags & BIT4_MASK) != 0);
   SET_ZF((flags & BIT6_MASK) != 0);
   SET_SF((flags & BIT7_MASK) != 0);
   SET_TF((flags & BIT8_MASK) != 0);
   SET_DF((flags & BIT10_MASK) != 0);
   SET_OF((flags & BIT11_MASK) != 0);

   /* IF only updated if CPL <= IOPL */
   if ( GET_CPL() <= GET_IOPL() )
      SET_IF((flags & BIT9_MASK) != 0);

   SET_NT((flags & BIT14_MASK) != 0);

   /* IOPL only updated at highest privilege */
   if ( GET_CPL() == 0 )
      SET_IOPL((flags >> 12) & 3);
   }