mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
369 lines
9.4 KiB
369 lines
9.4 KiB
/*[
|
|
|
|
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);
|
|
}
|