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.
589 lines
18 KiB
589 lines
18 KiB
/*[
|
|
|
|
c_tsksw.c
|
|
|
|
LOCAL CHAR SccsID[]="@(#)c_tsksw.c 1.11 03/03/95";
|
|
|
|
Task Switch Support.
|
|
--------------------
|
|
|
|
]*/
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <insignia.h>
|
|
|
|
#include <host_def.h>
|
|
|
|
#include <xt.h>
|
|
#include CpuH
|
|
#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_tsksw.h>
|
|
#include <c_page.h>
|
|
#include <mov.h>
|
|
#include <fault.h>
|
|
|
|
/*[
|
|
|
|
The 286 TSS is laid out as follows:-
|
|
|
|
=============================
|
|
| Back Link to TSS Selector | +00 =
|
|
| SP for CPL 0 | +02 *
|
|
| SS for CPL 0 | +04 *
|
|
| SP for CPL 1 | +06 * Initial Stacks (STATIC)
|
|
| SS for CPL 1 | +08 *
|
|
| SP for CPL 2 | +0a *
|
|
| SS for CPL 2 | +0c *
|
|
| IP | +0e =
|
|
| FLAG Register | +10 =
|
|
| AX | +12 =
|
|
| CX | +14 =
|
|
| DX | +16 =
|
|
| BX | +18 =
|
|
| SP | +1a = Current State (DYNAMIC)
|
|
| BP | +1c =
|
|
| SI | +1e =
|
|
| DI | +20 =
|
|
| ES | +22 =
|
|
| CS | +24 =
|
|
| SS | +26 =
|
|
| DS | +28 =
|
|
| Task LDT Selector | +2a *
|
|
=============================
|
|
|
|
The 386 TSS is laid out as follows:-
|
|
|
|
===========================================
|
|
| 0 | Back Link | +00 =
|
|
| ESP for CPL 0 | +04 *
|
|
| 0 | SS for CPL 0 | +08 *
|
|
| ESP for CPL 1 | +0c *
|
|
| 0 | SS for CPL 1 | +10 *
|
|
| ESP for CPL 2 | +14 *
|
|
| 0 | SS for CPL 2 | +18 *
|
|
| CR3 | +1c *
|
|
| EIP | +20 =
|
|
| EFLAG | +24 =
|
|
| EAX | +28 =
|
|
| ECX | +2c =
|
|
| EDX | +30 =
|
|
| EBX | +34 =
|
|
| ESP | +38 =
|
|
| EBP | +3c =
|
|
| ESI | +40 =
|
|
| EDI | +44 =
|
|
| 0 | ES | +48 =
|
|
| 0 | CS | +4c =
|
|
| 0 | SS | +50 =
|
|
| 0 | DS | +54 =
|
|
| 0 | FS | +58 =
|
|
| 0 | GS | +5c =
|
|
| 0 | LDT Selector | +60 *
|
|
| I/O Map Base Addr. | 0 |T| +64 *
|
|
|-----------------------------------------|
|
|
| ... |
|
|
|-----------------------------------------|
|
|
| I/O Permission Bit Map | +I/O Map Base Addr.
|
|
| |
|
|
|11111111| |
|
|
===========================================
|
|
|
|
]*/
|
|
|
|
/*
|
|
Prototype our internal functions.
|
|
*/
|
|
LOCAL VOID load_LDT_in_task_switch
|
|
|
|
IPT1(
|
|
IU16, tss_selector
|
|
|
|
);
|
|
|
|
LOCAL VOID load_data_seg_new_task
|
|
|
|
IPT2(
|
|
ISM32, indx,
|
|
IU16, selector
|
|
|
|
);
|
|
|
|
|
|
#define IP_OFFSET_IN_286_TSS 0x0e
|
|
#define IP_OFFSET_IN_386_TSS 0x20
|
|
|
|
#define CR3_OFFSET_IN_386_TSS 0x1c
|
|
|
|
#define LOCAL_BRK_ENABLE 0x155 /* LE,L3,L2,L1 and L0 bits of DCR */
|
|
|
|
/*
|
|
=====================================================================
|
|
INTERNAL FUNCTIONS STARTS HERE.
|
|
=====================================================================
|
|
*/
|
|
|
|
|
|
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
|
/* Load LDT selector during a task switch. */
|
|
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
|
LOCAL VOID
|
|
load_LDT_in_task_switch
|
|
|
|
IFN1(
|
|
IU16, tss_selector
|
|
)
|
|
|
|
|
|
{
|
|
IU16 selector;
|
|
IU32 descr_addr;
|
|
CPU_DESCR entry;
|
|
|
|
/* The selector is already loaded into LDTR */
|
|
selector = GET_LDT_SELECTOR();
|
|
|
|
/* A null selector can be left alone */
|
|
if ( !selector_is_null(selector) )
|
|
{
|
|
/* must be in GDT */
|
|
if ( selector_outside_GDT(selector, &descr_addr) )
|
|
{
|
|
SET_LDT_SELECTOR(0); /* invalidate selector */
|
|
TS(tss_selector, FAULT_LOADLDT_SELECTOR);
|
|
}
|
|
|
|
read_descriptor_linear(descr_addr, &entry);
|
|
|
|
/* is it really a LDT segment */
|
|
if ( descriptor_super_type(entry.AR) != LDT_SEGMENT )
|
|
{
|
|
SET_LDT_SELECTOR(0); /* invalidate selector */
|
|
TS(tss_selector, FAULT_LOADLDT_NOT_AN_LDT);
|
|
}
|
|
|
|
/* must be present */
|
|
if ( GET_AR_P(entry.AR) == NOT_PRESENT )
|
|
{
|
|
SET_LDT_SELECTOR(0); /* invalidate selector */
|
|
TS(tss_selector, FAULT_LOADLDT_NOTPRESENT);
|
|
}
|
|
|
|
/* ok, good selector, load register */
|
|
SET_LDT_BASE(entry.base);
|
|
SET_LDT_LIMIT(entry.limit);
|
|
}
|
|
}
|
|
|
|
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
|
/* Load a Data Segment Register (DS, ES, FS, GS) during */
|
|
/* a Task Switch . */
|
|
/* Take #GP(selector) if segment not valid */
|
|
/* Take #NP(selector) if segment not present */
|
|
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
|
LOCAL VOID
|
|
load_data_seg_new_task
|
|
|
|
IFN2(
|
|
ISM32, indx, /* Segment Register identifier */
|
|
IU16, selector /* value to be loaded */
|
|
)
|
|
|
|
|
|
{
|
|
load_data_seg(indx, selector);
|
|
|
|
/* Reload pseudo descriptors if V86 Mode */
|
|
if ( GET_VM() == 1 )
|
|
load_pseudo_descr(indx);
|
|
}
|
|
|
|
|
|
/*
|
|
=====================================================================
|
|
EXTERNAL ROUTINES STARTS HERE.
|
|
=====================================================================
|
|
*/
|
|
|
|
|
|
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
|
/* Switch tasks */
|
|
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
|
GLOBAL VOID
|
|
switch_tasks
|
|
|
|
IFN5(
|
|
BOOL, returning, /* (I) if true doing return from task */
|
|
BOOL, nesting, /* (I) if true switch with nesting */
|
|
IU16, TSS_selector, /* (I) selector for new task */
|
|
IU32, descr, /* (I) memory address of new task descriptor */
|
|
IU32, return_ip /* (I) offset to restart old task at */
|
|
)
|
|
|
|
|
|
{
|
|
IU16 old_tss; /* components of old descriptor */
|
|
IU8 old_AR;
|
|
IU32 old_descr;
|
|
|
|
CPU_DESCR new_tss; /* components of new descriptor */
|
|
|
|
IU32 tss_addr; /* variables used to put/get TSS state */
|
|
IU32 next_addr;
|
|
IU32 flags;
|
|
ISM32 save_cpl;
|
|
IU8 T_byte; /* Byte holding the T bit */
|
|
|
|
IU32 ss_descr; /* variables defining new SS and CS values */
|
|
CPU_DESCR ss_entry;
|
|
IU16 new_cs;
|
|
IU32 cs_descr;
|
|
CPU_DESCR cs_entry;
|
|
|
|
IU32 pdbr; /* New value for PDBR */
|
|
|
|
if ( GET_TR_SELECTOR() == 0 )
|
|
TS(TSS_selector, FAULT_SWTASK_NULL_TR_SEL);
|
|
|
|
/* get new TSS info. */
|
|
read_descriptor_linear(descr, &new_tss);
|
|
|
|
/* calc address of descriptor related to old TSS */
|
|
old_tss = GET_TR_SELECTOR();
|
|
old_descr = GET_GDT_BASE() + GET_SELECTOR_INDEX_TIMES8(old_tss);
|
|
old_AR = spr_read_byte(old_descr+5);
|
|
|
|
/* SAVE OUTGOING STATE */
|
|
|
|
if ( GET_TR_AR_SUPER() == XTND_BUSY_TSS )
|
|
{
|
|
/* check outgoing TSS is large enough to save current state */
|
|
if ( GET_TR_LIMIT() < 0x67 )
|
|
{
|
|
TS(TSS_selector, FAULT_SWTASK_BAD_TSS_SIZE_1);
|
|
}
|
|
|
|
tss_addr = GET_TR_BASE();
|
|
next_addr = tss_addr + CR3_OFFSET_IN_386_TSS;
|
|
|
|
spr_write_dword(next_addr, GET_CR(3));
|
|
next_addr += 4;
|
|
|
|
spr_write_dword(next_addr, return_ip);
|
|
next_addr += 4;
|
|
|
|
flags = c_getEFLAGS();
|
|
if ( returning )
|
|
flags = flags & ~BIT14_MASK; /* clear NT */
|
|
spr_write_dword(next_addr, (IU32)flags);
|
|
#ifdef PIG
|
|
/* Note the possibility of unknown flags "pushed" */
|
|
record_flags_addr(next_addr);
|
|
#endif /* PIG */
|
|
next_addr += 4;
|
|
|
|
spr_write_dword(next_addr, GET_EAX());
|
|
next_addr += 4;
|
|
spr_write_dword(next_addr, GET_ECX());
|
|
next_addr += 4;
|
|
spr_write_dword(next_addr, GET_EDX());
|
|
next_addr += 4;
|
|
spr_write_dword(next_addr, GET_EBX());
|
|
next_addr += 4;
|
|
spr_write_dword(next_addr, GET_ESP());
|
|
next_addr += 4;
|
|
spr_write_dword(next_addr, GET_EBP());
|
|
next_addr += 4;
|
|
spr_write_dword(next_addr, GET_ESI());
|
|
next_addr += 4;
|
|
spr_write_dword(next_addr, GET_EDI());
|
|
next_addr += 4;
|
|
spr_write_word(next_addr, GET_ES_SELECTOR());
|
|
next_addr += 4;
|
|
spr_write_word(next_addr, GET_CS_SELECTOR());
|
|
next_addr += 4;
|
|
spr_write_word(next_addr, GET_SS_SELECTOR());
|
|
next_addr += 4;
|
|
spr_write_word(next_addr, GET_DS_SELECTOR());
|
|
next_addr += 4;
|
|
spr_write_word(next_addr, GET_FS_SELECTOR());
|
|
next_addr += 4;
|
|
spr_write_word(next_addr, GET_GS_SELECTOR());
|
|
}
|
|
else /* 286 TSS */
|
|
{
|
|
/* check outgoing TSS is large enough to save current state */
|
|
if ( GET_TR_LIMIT() < 0x29 )
|
|
{
|
|
TS(TSS_selector, FAULT_SWTASK_BAD_TSS_SIZE_2);
|
|
}
|
|
|
|
tss_addr = GET_TR_BASE();
|
|
next_addr = tss_addr + IP_OFFSET_IN_286_TSS;
|
|
|
|
spr_write_word(next_addr, (IU16)return_ip);
|
|
next_addr += 2;
|
|
|
|
flags = getFLAGS();
|
|
if ( returning )
|
|
flags = flags & ~BIT14_MASK; /* clear NT */
|
|
spr_write_word(next_addr, (IU16)flags);
|
|
#ifdef PIG
|
|
/* Note the possibility of unknown flags "pushed" */
|
|
record_flags_addr(next_addr);
|
|
#endif /* PIG */
|
|
next_addr += 2;
|
|
|
|
spr_write_word(next_addr, GET_AX());
|
|
next_addr += 2;
|
|
spr_write_word(next_addr, GET_CX());
|
|
next_addr += 2;
|
|
spr_write_word(next_addr, GET_DX());
|
|
next_addr += 2;
|
|
spr_write_word(next_addr, GET_BX());
|
|
next_addr += 2;
|
|
spr_write_word(next_addr, GET_SP());
|
|
next_addr += 2;
|
|
spr_write_word(next_addr, GET_BP());
|
|
next_addr += 2;
|
|
spr_write_word(next_addr, GET_SI());
|
|
next_addr += 2;
|
|
spr_write_word(next_addr, GET_DI());
|
|
next_addr += 2;
|
|
spr_write_word(next_addr, GET_ES_SELECTOR());
|
|
next_addr += 2;
|
|
spr_write_word(next_addr, GET_CS_SELECTOR());
|
|
next_addr += 2;
|
|
spr_write_word(next_addr, GET_SS_SELECTOR());
|
|
next_addr += 2;
|
|
spr_write_word(next_addr, GET_DS_SELECTOR());
|
|
}
|
|
|
|
/* LOAD TASK REGISTER */
|
|
|
|
/* mark incoming TSS as busy */
|
|
new_tss.AR |= BIT1_MASK;
|
|
spr_write_byte(descr+5, (IU8)new_tss.AR);
|
|
|
|
/* update task register */
|
|
SET_TR_SELECTOR(TSS_selector);
|
|
SET_TR_BASE(new_tss.base);
|
|
SET_TR_LIMIT(new_tss.limit);
|
|
SET_TR_AR_SUPER(descriptor_super_type(new_tss.AR));
|
|
tss_addr = GET_TR_BASE();
|
|
|
|
/* save back link if nesting, else make outgoing TSS available */
|
|
if ( nesting )
|
|
{
|
|
spr_write_word(tss_addr, old_tss);
|
|
}
|
|
else
|
|
{
|
|
/* mark old TSS as available */
|
|
old_AR = old_AR & ~BIT1_MASK;
|
|
spr_write_byte(old_descr+5, old_AR);
|
|
}
|
|
|
|
/* Note: Exceptions now happen in the incoming task */
|
|
|
|
/* EXTRACT NEW STATE */
|
|
|
|
if ( GET_TR_AR_SUPER() == XTND_BUSY_TSS )
|
|
{
|
|
/* check new TSS is large enough to extract new state from */
|
|
if ( GET_TR_LIMIT() < 0x67 )
|
|
TS(TSS_selector, FAULT_SWTASK_BAD_TSS_SIZE_3);
|
|
|
|
next_addr = tss_addr + CR3_OFFSET_IN_386_TSS;
|
|
pdbr = (IU32)spr_read_dword(next_addr);
|
|
if ( pdbr != GET_CR(CR_PDBR) )
|
|
{
|
|
/* Only reload PDBR if diferent */
|
|
MOV_CR(CR_PDBR, pdbr);
|
|
}
|
|
|
|
next_addr = tss_addr + IP_OFFSET_IN_386_TSS;
|
|
|
|
SET_EIP(spr_read_dword(next_addr)); next_addr += 4;
|
|
|
|
flags = (IU32)spr_read_dword(next_addr); next_addr += 4;
|
|
save_cpl = GET_CPL();
|
|
SET_CPL(0); /* act like highest privilege to set all flags */
|
|
c_setEFLAGS(flags);
|
|
SET_CPL(save_cpl);
|
|
|
|
if ( flags & BIT17_MASK )
|
|
fprintf(stderr, "(Task Switch)Entering V86 Mode.\n");
|
|
|
|
SET_EAX(spr_read_dword(next_addr)); next_addr += 4;
|
|
SET_ECX(spr_read_dword(next_addr)); next_addr += 4;
|
|
SET_EDX(spr_read_dword(next_addr)); next_addr += 4;
|
|
SET_EBX(spr_read_dword(next_addr)); next_addr += 4;
|
|
SET_ESP(spr_read_dword(next_addr)); next_addr += 4;
|
|
SET_EBP(spr_read_dword(next_addr)); next_addr += 4;
|
|
SET_ESI(spr_read_dword(next_addr)); next_addr += 4;
|
|
SET_EDI(spr_read_dword(next_addr)); next_addr += 4;
|
|
|
|
SET_ES_SELECTOR(spr_read_word(next_addr)); next_addr += 4;
|
|
SET_CS_SELECTOR(spr_read_word(next_addr)); next_addr += 4;
|
|
SET_SS_SELECTOR(spr_read_word(next_addr)); next_addr += 4;
|
|
SET_DS_SELECTOR(spr_read_word(next_addr)); next_addr += 4;
|
|
SET_FS_SELECTOR(spr_read_word(next_addr)); next_addr += 4;
|
|
SET_GS_SELECTOR(spr_read_word(next_addr)); next_addr += 4;
|
|
|
|
SET_LDT_SELECTOR(spr_read_word(next_addr)); next_addr += 4;
|
|
T_byte = spr_read_byte(next_addr);
|
|
}
|
|
else /* 286 TSS */
|
|
{
|
|
/* check new TSS is large enough to extract new state from */
|
|
if ( GET_TR_LIMIT() < 0x2b )
|
|
TS(TSS_selector, FAULT_SWTASK_BAD_TSS_SIZE_4);
|
|
|
|
next_addr = tss_addr + IP_OFFSET_IN_286_TSS;
|
|
|
|
SET_EIP(spr_read_word(next_addr)); next_addr += 2;
|
|
|
|
flags = (IU32)spr_read_word(next_addr); next_addr += 2;
|
|
save_cpl = GET_CPL();
|
|
SET_CPL(0); /* act like highest privilege to set all flags */
|
|
setFLAGS(flags);
|
|
SET_VM(0);
|
|
SET_CPL(save_cpl);
|
|
|
|
SET_AX(spr_read_word(next_addr)); next_addr += 2;
|
|
SET_CX(spr_read_word(next_addr)); next_addr += 2;
|
|
SET_DX(spr_read_word(next_addr)); next_addr += 2;
|
|
SET_BX(spr_read_word(next_addr)); next_addr += 2;
|
|
SET_SP(spr_read_word(next_addr)); next_addr += 2;
|
|
SET_BP(spr_read_word(next_addr)); next_addr += 2;
|
|
SET_SI(spr_read_word(next_addr)); next_addr += 2;
|
|
SET_DI(spr_read_word(next_addr)); next_addr += 2;
|
|
|
|
SET_ES_SELECTOR(spr_read_word(next_addr)); next_addr += 2;
|
|
SET_CS_SELECTOR(spr_read_word(next_addr)); next_addr += 2;
|
|
SET_SS_SELECTOR(spr_read_word(next_addr)); next_addr += 2;
|
|
SET_DS_SELECTOR(spr_read_word(next_addr)); next_addr += 2;
|
|
SET_FS_SELECTOR(0);
|
|
SET_GS_SELECTOR(0);
|
|
|
|
SET_LDT_SELECTOR(spr_read_word(next_addr));
|
|
T_byte = 0;
|
|
}
|
|
|
|
/* invalidate cache entries for segment registers */
|
|
SET_CS_AR_R(0); SET_CS_AR_W(0);
|
|
SET_DS_AR_R(0); SET_DS_AR_W(0);
|
|
SET_ES_AR_R(0); SET_ES_AR_W(0);
|
|
SET_SS_AR_R(0); SET_SS_AR_W(0);
|
|
SET_FS_AR_R(0); SET_FS_AR_W(0);
|
|
SET_GS_AR_R(0); SET_GS_AR_W(0);
|
|
|
|
/* update NT bit */
|
|
if ( nesting )
|
|
SET_NT(1);
|
|
else
|
|
if ( !returning )
|
|
SET_NT(0);
|
|
|
|
/* update TS */
|
|
SET_CR(CR_STAT, GET_CR(CR_STAT) | BIT3_MASK);
|
|
|
|
/* kill local breakpoints */
|
|
SET_DR(DR_DCR, GET_DR(DR_DCR) & ~LOCAL_BRK_ENABLE);
|
|
|
|
/* set up trap on T-bit */
|
|
if ( T_byte & BIT0_MASK )
|
|
{
|
|
SET_DR(DR_DSR, GET_DR(DR_DSR) | DSR_BT_MASK);
|
|
}
|
|
|
|
/* ERROR CHECKING */
|
|
|
|
/* check new LDT and load hidden cache if ok */
|
|
load_LDT_in_task_switch(TSS_selector);
|
|
|
|
if ( GET_VM() == 1 )
|
|
{
|
|
SET_CPL(3); /* set V86 privilege level */
|
|
/* CS selector requires no checks */
|
|
}
|
|
else
|
|
{
|
|
/* change CPL to that of incoming code segment */
|
|
SET_CPL(GET_SELECTOR_RPL(GET_CS_SELECTOR()));
|
|
|
|
/* check new code selector... */
|
|
new_cs = GET_CS_SELECTOR();
|
|
if ( selector_outside_GDT_LDT(new_cs, &cs_descr) )
|
|
TS(new_cs, FAULT_SWTASK_BAD_CS_SELECTOR);
|
|
|
|
read_descriptor_linear(cs_descr, &cs_entry);
|
|
|
|
/* check type and privilege of new cs selector */
|
|
switch ( descriptor_super_type(cs_entry.AR) )
|
|
{
|
|
case CONFORM_NOREAD_CODE:
|
|
case CONFORM_READABLE_CODE:
|
|
/* check code is present */
|
|
if ( GET_AR_P(cs_entry.AR) == NOT_PRESENT )
|
|
NP(new_cs, FAULT_SWTASK_CONFORM_CS_NP);
|
|
|
|
/* privilege check requires DPL <= CPL */
|
|
if ( GET_AR_DPL(cs_entry.AR) > GET_CPL() )
|
|
TS(new_cs, FAULT_SWTASK_ACCESS_1);
|
|
break;
|
|
|
|
case NONCONFORM_NOREAD_CODE:
|
|
case NONCONFORM_READABLE_CODE:
|
|
/* check code is present */
|
|
if ( GET_AR_P(cs_entry.AR) == NOT_PRESENT )
|
|
NP(new_cs, FAULT_SWTASK_NOCONFORM_CS_NP);
|
|
|
|
/* privilege check requires DPL == CPL */
|
|
if ( GET_AR_DPL(cs_entry.AR) != GET_CPL() )
|
|
TS(new_cs, FAULT_SWTASK_ACCESS_2);
|
|
break;
|
|
|
|
default:
|
|
TS(new_cs, FAULT_SWTASK_BAD_SEG_TYPE);
|
|
}
|
|
}
|
|
|
|
/* code ok, load hidden cache */
|
|
load_CS_cache(new_cs, cs_descr, &cs_entry);
|
|
#if 0
|
|
/* retain operand size from gate until first instruction fetch */
|
|
if ( GET_CS_AR_X() == USE16 )
|
|
SET_OPERAND_SIZE(USE16);
|
|
else /* USE32 */
|
|
SET_OPERAND_SIZE(USE32);
|
|
#endif
|
|
|
|
/* check new SS and load if ok */
|
|
if ( GET_VM() == 1 )
|
|
{
|
|
/* SS selector requires no checks */
|
|
load_stack_seg(GET_SS_SELECTOR());
|
|
load_pseudo_descr(SS_REG);
|
|
}
|
|
else
|
|
{
|
|
validate_SS_on_stack_change(GET_CPL(), GET_SS_SELECTOR(),
|
|
&ss_descr, &ss_entry);
|
|
load_SS_cache(GET_SS_SELECTOR(), ss_descr, &ss_entry);
|
|
}
|
|
|
|
/* finally check new DS, ES, FS and GS */
|
|
load_data_seg_new_task(DS_REG, GET_DS_SELECTOR());
|
|
load_data_seg_new_task(ES_REG, GET_ES_SELECTOR());
|
|
load_data_seg_new_task(FS_REG, GET_FS_SELECTOR());
|
|
load_data_seg_new_task(GS_REG, GET_GS_SELECTOR());
|
|
}
|