#include "insignia.h" #include "host_def.h" /* * SoftPC Revision 3.0 * * Title : Global variable definitions * * Description : Contains definitions for registers and general * variables required by all modules. * * Author : Henry Nash * * Notes : None * */ /* * static char SccsID[]="@(#)xt.c 1.22 01/23/95 Copyright Insignia Solutions Ltd."; */ /* * O/S include files. */ #include #include TypesH /* * SoftPC include files */ #include "xt.h" #include CpuH #include "sas.h" /* * ============================================================================ * Global data * ============================================================================ */ /* specific CPU variables. */ word cpu_interrupt_map; /* Bit map of ints outstanding */ half_word cpu_int_translate[16]; /* this will go very soon! */ /* * * The current usage is: * * 0 - Hardware interrupt * 1-7 - Not Used * 8 - Software Int - set by cpu_sw_interrupt() - REMOVED! * 9 - Trap * 10 - Reset IP after a POP/MOV CS. * 11 - Trap flag changed - this has delay. * 12-15 - Not Used */ word cpu_int_delay; /* Delay before pending interrupt */ int trap_delay_count; /* * The lock flag prevents the Interrupt Controller Adapter from being * called from a signal handler while it is already active in the mainline. */ half_word ica_lock; /* * The actual CCPU registers */ #if defined(CCPU) && !defined(CPU_30_STYLE) #ifndef MAC_LIKE reg A; /* Accumulator */ reg B; /* Base */ reg C; /* Count */ reg D; /* Data */ reg BP; /* Base pointer */ reg SI; /* Source Index */ reg DI; /* Destination Index */ #endif /* MAC_LIKE */ reg SP; /* Stack Pointer */ reg IP; /* Instruction Pointer */ reg CS; /* Code Segment */ reg DS; /* Data Segment */ reg SS; /* Stack Segment */ reg ES; /* Extra Segment */ /* Code Segment Register */ half_word CS_AR; /* Access Rights Byte */ sys_addr CS_base; /* Base Address */ word CS_limit; /* Segment 'size' */ int CPL; /* Current Privilege Level */ /* Data Segment Register */ half_word DS_AR; /* Access Rights Byte */ sys_addr DS_base; /* Base Address */ word DS_limit; /* Segment 'size' */ /* Stack Segment Register */ half_word SS_AR; /* Access Rights Byte */ sys_addr SS_base; /* Base Address */ word SS_limit; /* Segment 'size' */ /* Extra Segment Register */ half_word ES_AR; /* Access Rights Byte */ sys_addr ES_base; /* Base Address */ word ES_limit; /* Segment 'size' */ /* Global Descriptor Table Register */ sys_addr GDTR_base; /* Base Address */ word GDTR_limit; /* Segment 'size' */ /* Interrupt Descriptor Table Register */ sys_addr IDTR_base; /* Base Address */ word IDTR_limit; /* Segment 'size' */ /* Local Descriptor Table Register */ reg LDTR; /* Selector */ sys_addr LDTR_base; /* Base Address */ word LDTR_limit; /* Segment 'size' */ /* Task Register */ reg TR; /* Selector */ sys_addr TR_base; /* Base Address */ word TR_limit; /* Segment 'size' */ mreg MSW; /* Machine Status Word */ int STATUS_CF; int STATUS_SF; int STATUS_ZF; int STATUS_AF; int STATUS_OF; int STATUS_PF; int STATUS_TF; int STATUS_IF; int STATUS_DF; int STATUS_NT; int STATUS_IOPL; #endif /* defined(CCPU) && !defined(CPU_30_STYLE) */ /* * Global Flags and variables */ int verbose; /* TRUE => trace instructions */ /* * Misc. Prot Mode support routines which are independant of CPU type * --------------------------------- */ #ifdef CPU_30_STYLE #ifndef GISP_CPU /* GISP has its own versions of these internal to the CPU */ #define GET_SELECTOR_INDEX_TIMES8(x) ((x) & 0xfff8) #define GET_SELECTOR_TI(x) (((x) & 0x0004) >> 2) #if defined(CPU_40_STYLE) #if defined(PROD) && !defined(CCPU) #undef effective_addr GLOBAL LIN_ADDR effective_addr IFN2(IU16, seg, IU32, off) { return (*(Cpu.EffectiveAddr))(seg, off); } #endif /* PROD & !CCPU */ #else /* !CPU_40_STYLE */ #if !(defined(NTVDM) && defined(MONITOR)) /* MS NT monitor has own effective_addr fn */ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ /* Calculate effective address. */ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ GLOBAL LIN_ADDR effective_addr IFN2(IU16, seg, IU32, off) { LIN_ADDR descr_addr; DESCR entry; if ((!getPE()) || getVM()) { return ((LIN_ADDR)seg << 4) + off; } else { #if defined(SWIN_CPU_OPTS) || defined(CPU_40_STYLE) LIN_ADDR base; if (Cpu_find_dcache_entry( seg, &base )) { /* Cache Hit!! */ return base + off; } #endif /* SWIN_CPU_OPTS or CPU_40_STYLE*/ if ( selector_outside_table(seg, &descr_addr) == 1 ) { /* * This is probably not a major disaster, just a result * of the fact that after protected mode is invoked it * will take say 5-10 instructions for an application * to update all the segment registers. We just * maintain real mode semantics while this error occurs. */ return ((LIN_ADDR)seg << 4) + off; } else { read_descriptor(descr_addr, &entry); return entry.base + off; } } } #endif /* !(NTVDM & MONITOR) */ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ /* Read a decriptor table entry from memory. */ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ #endif /* !CPU_40_STYLE */ GLOBAL void read_descriptor IFN2(LIN_ADDR, addr, DESCR *, descr) { IU32 first_dword, 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 decriptor with minimum interaction with memory */ #if defined(NTVDM) && defined(CPU_40_STYLE) /* On NT, this routine can be called from non-CPU threads, so we don't */ /* want to use SAS at all. Instead, we rely on NtGetPtrToLinAddrByte, */ /* which is provided by the CPU and is safe for multi-threading. We are*/ /* also relying on the fact the NT is always little-endian. */ { IU32 *desc_addr = (IU32 *) NtGetPtrToLinAddrByte(addr); first_dword = *desc_addr; second_dword = *(desc_addr + 1); } #else first_dword = sas_dw_at(addr); second_dword = sas_dw_at(addr+4); #endif /* load attributes and access rights */ descr->AR = (second_dword >> 8) & 0xff; /* unpack the base */ descr->base = (first_dword >> 16) | #ifdef SPC386 (second_dword & 0xff000000) | #endif (second_dword << 16 & 0xff0000 ); /* unpack the limit */ #ifndef SPC386 descr->limit = first_dword & 0xffff; #else limit = (first_dword & 0xffff) | (second_dword & 0x000f0000); if ( second_dword & 0x00800000 ) /* check bit 23 */ { /* Granularity Bit Set. Limit is expressed in pages (4k bytes), convert to byte limit */ limit = limit << 12 | 0xfff; } descr->limit = limit; #endif /* ifndef SPC386 else */ } #if !(defined(NTVDM) && defined(MONITOR)) /* MS NT monitor has own selector_outside_table fn */ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ /* Check if selector outside bounds of GDT or LDT */ /* Return 1 for outside table, 0 for inside table. */ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ GLOBAL boolean selector_outside_table IFN2(IU16, selector, LIN_ADDR *, descr_addr) { /* selector (I) selector to be checked */ /* descr_addr (O) address of related descriptor */ LIN_ADDR 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 > getGDT_LIMIT() ) return 1; *descr_addr = getGDT_BASE() + offset; } else { /* LDT - trap invalid LDT or outside table */ if ( getLDT_SELECTOR() == 0 || offset + 7 > getLDT_LIMIT() ) return 1; *descr_addr = getLDT_BASE() + offset; } return 0; } #endif /* !(NTVDM & MONITOR) */ #endif /* !GISP_CPU */ #endif /* CPU_30_STYLE */ /* * The following is a table lookup for finding parity of a byte */ #if !defined(MAC_LIKE) && !defined(CPU_30_STYLE) half_word pf_table[] = { 1, /* 00 */ 0, /* 01 */ 0, /* 02 */ 1, /* 03 */ 0, /* 04 */ 1, /* 05 */ 1, /* 06 */ 0, /* 07 */ 0, /* 08 */ 1, /* 09 */ 1, /* 0a */ 0, /* 0b */ 1, /* 0c */ 0, /* 0d */ 0, /* 0e */ 1, /* 0f */ 0, /* 10 */ 1, /* 11 */ 1, /* 12 */ 0, /* 13 */ 1, /* 14 */ 0, /* 15 */ 0, /* 16 */ 1, /* 17 */ 1, /* 18 */ 0, /* 19 */ 0, /* 1a */ 1, /* 1b */ 0, /* 1c */ 1, /* 1d */ 1, /* 1e */ 0, /* 1f */ 0, /* 20 */ 1, /* 21 */ 1, /* 22 */ 0, /* 23 */ 1, /* 24 */ 0, /* 25 */ 0, /* 26 */ 1, /* 27 */ 1, /* 28 */ 0, /* 29 */ 0, /* 2a */ 1, /* 2b */ 0, /* 2c */ 1, /* 2d */ 1, /* 2e */ 0, /* 2f */ 1, /* 30 */ 0, /* 31 */ 0, /* 32 */ 1, /* 33 */ 0, /* 34 */ 1, /* 35 */ 1, /* 36 */ 0, /* 37 */ 0, /* 38 */ 1, /* 39 */ 1, /* 3a */ 0, /* 3b */ 1, /* 3c */ 0, /* 3d */ 0, /* 3e */ 1, /* 3f */ 0, /* 40 */ 1, /* 41 */ 1, /* 42 */ 0, /* 43 */ 1, /* 44 */ 0, /* 45 */ 0, /* 46 */ 1, /* 47 */ 1, /* 48 */ 0, /* 49 */ 0, /* 4a */ 1, /* 4b */ 0, /* 4c */ 1, /* 4d */ 1, /* 4e */ 0, /* 4f */ 1, /* 50 */ 0, /* 51 */ 0, /* 52 */ 1, /* 53 */ 0, /* 54 */ 1, /* 55 */ 1, /* 56 */ 0, /* 57 */ 0, /* 58 */ 1, /* 59 */ 1, /* 5a */ 0, /* 5b */ 1, /* 5c */ 0, /* 5d */ 0, /* 5e */ 1, /* 5f */ 1, /* 60 */ 0, /* 61 */ 0, /* 62 */ 1, /* 63 */ 0, /* 64 */ 1, /* 65 */ 1, /* 66 */ 0, /* 67 */ 0, /* 68 */ 1, /* 69 */ 1, /* 6a */ 0, /* 6b */ 1, /* 6c */ 0, /* 6d */ 0, /* 6e */ 1, /* 6f */ 0, /* 70 */ 1, /* 71 */ 1, /* 72 */ 0, /* 73 */ 1, /* 74 */ 0, /* 75 */ 0, /* 76 */ 1, /* 77 */ 1, /* 78 */ 0, /* 79 */ 0, /* 7a */ 1, /* 7b */ 0, /* 7c */ 1, /* 7d */ 1, /* 7e */ 0, /* 7f */ 0, /* 80 */ 1, /* 81 */ 1, /* 82 */ 0, /* 83 */ 1, /* 84 */ 0, /* 85 */ 0, /* 86 */ 1, /* 87 */ 1, /* 88 */ 0, /* 89 */ 0, /* 8a */ 1, /* 8b */ 0, /* 8c */ 1, /* 8d */ 1, /* 8e */ 0, /* 8f */ 1, /* 90 */ 0, /* 91 */ 0, /* 92 */ 1, /* 93 */ 0, /* 94 */ 1, /* 95 */ 1, /* 96 */ 0, /* 97 */ 0, /* 98 */ 1, /* 99 */ 1, /* 9a */ 0, /* 9b */ 1, /* 9c */ 0, /* 9d */ 0, /* 9e */ 1, /* 9f */ 1, /* a0 */ 0, /* a1 */ 0, /* a2 */ 1, /* a3 */ 0, /* a4 */ 1, /* a5 */ 1, /* a6 */ 0, /* a7 */ 0, /* a8 */ 1, /* a9 */ 1, /* aa */ 0, /* ab */ 1, /* ac */ 0, /* ad */ 0, /* ae */ 1, /* af */ 0, /* b0 */ 1, /* b1 */ 1, /* b2 */ 0, /* b3 */ 1, /* b4 */ 0, /* b5 */ 0, /* b6 */ 1, /* b7 */ 1, /* b8 */ 0, /* b9 */ 0, /* ba */ 1, /* bb */ 0, /* bc */ 1, /* bd */ 1, /* be */ 0, /* bf */ 1, /* c0 */ 0, /* c1 */ 0, /* c2 */ 1, /* c3 */ 0, /* c4 */ 1, /* c5 */ 1, /* c6 */ 0, /* c7 */ 0, /* c8 */ 1, /* c9 */ 1, /* ca */ 0, /* cb */ 1, /* cc */ 0, /* cd */ 0, /* ce */ 1, /* cf */ 0, /* d0 */ 1, /* d1 */ 1, /* d2 */ 0, /* d3 */ 1, /* d4 */ 0, /* d5 */ 0, /* d6 */ 1, /* d7 */ 1, /* d8 */ 0, /* d9 */ 0, /* da */ 1, /* db */ 0, /* dc */ 1, /* dd */ 1, /* de */ 0, /* df */ 0, /* e0 */ 1, /* e1 */ 1, /* e2 */ 0, /* e3 */ 1, /* e4 */ 0, /* e5 */ 0, /* e6 */ 1, /* e7 */ 1, /* e8 */ 0, /* e9 */ 0, /* ea */ 1, /* eb */ 0, /* ec */ 1, /* ed */ 1, /* ee */ 0, /* ef */ 1, /* f0 */ 0, /* f1 */ 0, /* f2 */ 1, /* f3 */ 0, /* f4 */ 1, /* f5 */ 1, /* f6 */ 0, /* f7 */ 0, /* f8 */ 1, /* f9 */ 1, /* fa */ 0, /* fb */ 1, /* fc */ 0, /* fd */ 0, /* fe */ 1 /* ff */ }; #endif /* !defined(MAC_LIKE) && !defined(CPU_30_STYLE) */ /*( *========================== CsIsBig =================================== * CsIsBig * * Purpose * This function returns true if the indicated code segment is a 32 bit * one, and false if it isn't. * * Input * csVal The selector to check * * Outputs * None. * * Description * Look at the descriptor. )*/ GLOBAL IBOOL CsIsBig IFN1(IU16, csVal) { #ifdef SPC386 LIN_ADDR base, offset; /* Of the descriptor to use */ if(getVM() || !getPE()) { return(FALSE); /* no 32 bit CS in V86 or real modes */ } else { offset = csVal & (~7); /* remove the RPL and TI gives offset */ if (csVal & 4) { /* check TI bit */ base = getLDT_BASE(); } else { base = getGDT_BASE(); } /* * Return true if the big bit in the descriptor is set. */ return(sas_hw_at(base + offset + 6) & 0x40); } #else /* SPC386 */ return (FALSE); #endif /* SPC386 */ }