static void i80286_data_descriptor_full(i80286_state *cpustate, int reg, UINT16 selector, int cpl, UINT32 trap, UINT16 offset, int size) { if (PM) { UINT16 desc[3]; UINT8 r; UINT32 addr; /* selector format 15..3 number/address in descriptor table 2: 0 global, 1 local descriptor table 1,0: requested privileg level must be higher or same as current privileg level in code selector */ if ((reg != SS) && !IDXTBL(selector)) { cpustate->sregs[reg]=0; cpustate->limit[reg]=0; cpustate->base[reg]=0; cpustate->rights[reg]=0; cpustate->valid[reg]=0; return; } if ((addr = i80286_selector_address(cpustate,selector)) == -1) throw trap; desc[0] = ReadWord(addr); desc[1] = ReadWord(addr+2); desc[2] = ReadWord(addr+4); r = RIGHTS(desc); if (!SEGDESC(r)) throw trap; if (reg == SS) { if (!IDXTBL(selector)) throw trap; if (DPL(r)!=cpl) throw trap; if (RPL(selector)!=cpl) throw trap; if (!RW(r) || CODE(r)) throw trap; if (!PRES(r)) throw TRAP(STACK_FAULT,(IDXTBL(selector)+(trap&1))); } else { if ((DPL(r) < PMAX(cpl,RPL(selector))) && (!CODE(r) || (CODE(r) && !CONF(r)))) throw trap; if (CODE(r) && !READ(r)) throw trap; if (!PRES(r)) throw TRAP(SEG_NOT_PRESENT,(IDXTBL(selector)+(trap&1))); } if (offset+size) { if ((CODE(r) || !EXPDOWN(r)) && ((offset+size-1) > LIMIT(desc))) throw (reg==SS)?TRAP(STACK_FAULT,(trap&1)):trap; if (!CODE(r) && EXPDOWN(r) && ((offset <= LIMIT(desc)) || ((offset+size-1) > 0xffff))) throw (reg==SS)?TRAP(STACK_FAULT,(trap&1)):trap; } SET_ACC(desc); WriteWord(addr+4, desc[2]); cpustate->sregs[reg]=selector; cpustate->limit[reg]=LIMIT(desc); cpustate->base[reg]=BASE(desc); cpustate->rights[reg]=RIGHTS(desc); } else { cpustate->sregs[reg]=selector; cpustate->base[reg]=selector<<4; } cpustate->valid[reg]=1; }
static void iret(struct cpu_thread *thread) { uval mask; uval error; uval fault; uval new_cs; uval eflags; int room; /* handle any callbacks before returning */ if (thread->cb) thread->cb(thread); /* * Ensure the stack is there and readable. * If there is no stack and we are transitioning to the * guest kernel then we have a problem ... */ room = 3 + 2; /* over estimating (for now) */ mask = ((thread->tss.srs.regs.ss & 0x3) == 0x3) ? PTE_US : 0; if (unlikely(!isstackpresent(thread, room, mask, &error, &fault))) { #ifdef INTR_DEBUG hprintf("iret: esp: 0x%lx not mapped (eip 0x%x:0x%lx)\n", fault, thread->tss.srs.regs.cs, thread->tss.eip); #endif if (page_fault(thread, error, fault)) { assert((mask & PTE_US) == 0, "no guest kernel stack"); return; } } thread->tss.eip = pop(thread); new_cs = pop(thread); eflags = pop(thread) & ~EFLAGS_IOPL_MASK; /* FIXME! what eflags are controlled by the partition? */ if (RPL(new_cs) != RPL(thread->tss.srs.regs.cs)) { /* if iret to a diff pl, then pop esp/ss */ uval tmp_esp = pop(thread); thread->tss.srs.regs.ss = pop(thread); thread->tss.gprs.regs.esp = tmp_esp; } thread->tss.srs.regs.cs = new_cs; thread->tss.eflags = eflags | thread->cpu->os->iopl | EFLAGS_IF; if (eflags & EFLAGS_IF) enable_intr(thread); }
static void PREFIX286(_arpl)(i8086_state *cpustate) /* 0x63 */ { UINT16 ModRM, tmp, source; if (!PM) throw TRAP(ILLEGAL_INSTRUCTION,-1); ModRM=FETCHOP; tmp=GetRMWord(ModRM); source=RegWord(ModRM); if (RPL(tmp)<RPL(source)) { cpustate->ZeroVal = 0; PutbackRMWord(ModRM, IDXTBL(tmp)|RPL(source)); } else cpustate->ZeroVal = 1; }
ostrm& json( ostrm &S, const char *A ) { // convert char array to JSON string (handle escape characters) #define RPL(a,b) case a: { S << b; A++; break; } S << "\""; while( *A>0 ) switch( *A ) { RPL('"',"\\\""); RPL('\\',"\\\\"); RPL('/',"\\/"); RPL('\b',"\\b"); RPL('\f',"\\f"); RPL('\n',"\\n"); RPL('\r',"\\r"); RPL('\t',"\\t"); default: S << *A; A++; } S << "\""; return S; }
/* * Handle (synchronous) user traps. These are all reflected * to the current partition, except for the hypervisor reserved * interrupts when they are issued by the partition OS. When * a hypervisor interrupt is generate by a partition application * (ring 3) it is always reflected to the guest OS. */ void trap(struct cpu_thread *thread, uval32 trapno) { uval cpl = RPL(thread->tss.srs.regs.cs); if (likely(trapno >= BASE_HCALL_VECTOR && cpl < 3)) { switch (trapno) { case HCALL_VECTOR: /* hcall */ hcall(thread); break; case HCALL_VECTOR_IRET: /* iret */ iret(thread); break; default: hprintf("%s: int 0x%ulx in reserved range - ignored\n", __func__, trapno); break; } return; } raise_exception(thread, trapno); }
static UINT16 i80286_far_return(i8086_state *cpustate, int iret, int bytes) { UINT16 sel, off, flags = 0; int spaddr; if (PM && NT && iret) { i80286_switch_task(cpustate, ReadWord(cpustate->tr.base+TSS_BACK*2), IRET); return cpustate->flags; } // must be restartable if(PM) i80286_check_permission(cpustate, SS, cpustate->regs.w[SP], (iret?6:4), I80286_READ); spaddr = (cpustate->base[SS] + cpustate->regs.w[SP]) & AMASK; off = ReadWord(spaddr); sel = ReadWord(spaddr+2); if(iret) flags = ReadWord(spaddr+4); if(PM) { UINT16 desc[3], newsp, newss; int addr, r; if ((addr = i80286_selector_address(cpustate,sel)) == -1) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(sel)); if (RPL(sel)<CPL) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(sel)); desc[0] = ReadWord(addr); desc[1] = ReadWord(addr+2); desc[2] = ReadWord(addr+4); r = RIGHTS(desc); if (!CODE(r) || !SEGDESC(r)) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(sel)); if (CONF(r)) { if(DPL(r)>RPL(sel)) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(sel)); } else if (DPL(r)!=RPL(sel)) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(sel)); if (!PRES(r)) throw TRAP(SEG_NOT_PRESENT,IDXTBL(sel)); if (off > LIMIT(desc)) throw TRAP(GENERAL_PROTECTION_FAULT,0); if (CPL<RPL(sel)) { i80286_check_permission(cpustate, SS, cpustate->regs.w[SP]+(iret?6:4)+bytes, 4, I80286_READ); newsp = ReadWord(spaddr+((iret?6:4)+bytes)); newss = ReadWord(spaddr+((iret?8:6)+bytes)); i80286_data_descriptor_full(cpustate, SS, newss, RPL(sel), TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(newss)), 0, 0); cpustate->regs.w[SP] = newsp + bytes; } else cpustate->regs.w[SP] += (iret?6:4) + bytes; SET_ACC(desc); WriteWord(addr+4, desc[2]); cpustate->sregs[CS]=sel; cpustate->limit[CS]=LIMIT(desc); cpustate->base[CS]=BASE(desc); cpustate->rights[CS]=RIGHTS(desc); cpustate->pc=(cpustate->base[CS]+off)&AMASK; // docs say check rpl but windows doesn't like it r = cpustate->rights[DS]; if (i80286_verify(cpustate, cpustate->sregs[DS], I80286_READ, r, 0) || (CODE(r) && CONF(r) ? 0 : (DPL(r) < CPL))) i80286_data_descriptor(cpustate, DS, 0); r = cpustate->rights[ES]; if (i80286_verify(cpustate, cpustate->sregs[ES], I80286_READ, r, 0) || (CODE(r) && CONF(r) ? 0 : (DPL(r) < CPL))) i80286_data_descriptor(cpustate, ES, 0); } else { cpustate->regs.w[SP] += (iret?6:4) + bytes; cpustate->sregs[CS]=sel; cpustate->base[CS]=sel<<4; cpustate->rights[CS]=0x9a; cpustate->limit[CS]=0xffff; cpustate->pc=(cpustate->base[CS]+off)&AMASK; } CHANGE_PC(cpustate->pc); return flags; }
static void PREFIX286(_0fpre)(i8086_state *cpustate) { unsigned next = FETCHOP; UINT16 ModRM, desc[3]; UINT16 tmp, msw, sel; UINT8 r; UINT32 addr; switch (next) { case 0: if (!PM) throw TRAP(ILLEGAL_INSTRUCTION,-1); ModRM=FETCHOP; switch (ModRM&0x38) { case 0: /* sldt */ PutRMWord(ModRM, cpustate->ldtr.sel); break; case 8: /* str */ PutRMWord(ModRM, cpustate->tr.sel); break; case 0x10: /* lldt */ if (CPL!=0) throw TRAP(GENERAL_PROTECTION_FAULT,0); sel=GetRMWord(ModRM); if (TBL(sel)) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(sel)); if (IDXTBL(sel)) { if (IDX(sel)>=cpustate->gdtr.limit) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(sel)); addr = cpustate->gdtr.base + IDX(sel); desc[0] = ReadWord(addr); desc[1] = ReadWord(addr+2); desc[2] = ReadWord(addr+4); r = RIGHTS(desc); if (SEGDESC(r) || (GATE(r) != LDTDESC)) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(sel)); if (!PRES(r)) throw TRAP(SEG_NOT_PRESENT,IDXTBL(sel)); } else { desc[0] = 0; desc[1] = 0; desc[2] = 0; } cpustate->ldtr.sel=sel; cpustate->ldtr.limit=LIMIT(desc); cpustate->ldtr.base=BASE(desc); cpustate->ldtr.rights=RIGHTS(desc); break; case 0x18: /* ltr */ if (CPL!=0) throw TRAP(GENERAL_PROTECTION_FAULT,0); sel=GetRMWord(ModRM); if ((addr = i80286_selector_address(cpustate,sel)) == -1) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(sel)); desc[0] = ReadWord(addr); desc[1] = ReadWord(addr+2); desc[2] = ReadWord(addr+4); r = RIGHTS(desc); if (SEGDESC(r) || (GATE(r) != TSSDESCIDLE)) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(sel)); if (!PRES(r)) throw TRAP(SEG_NOT_PRESENT,IDXTBL(sel)); desc[2] |= 0x200; // mark busy WriteWord(addr+4, desc[2]); cpustate->tr.sel=sel; cpustate->tr.limit=LIMIT(desc); cpustate->tr.base=BASE(desc); cpustate->tr.rights=RIGHTS(desc); break; case 0x20: /* verr */ tmp=GetRMWord(ModRM); if ((addr = i80286_selector_address(cpustate,tmp)) == -1) cpustate->ZeroVal = 1; else { desc[2] = ReadWord(addr+4); r = RIGHTS(desc); cpustate->ZeroVal = i80286_verify(cpustate, tmp, I80286_READ, RIGHTS(desc), 0); cpustate->ZeroVal = cpustate->ZeroVal || (CODE(r) && CONF(r) ? 0 : (DPL(r)<PMAX(RPL(tmp),CPL))); } break; case 0x28: /* verw */ tmp=GetRMWord(ModRM); if ((addr = i80286_selector_address(cpustate,tmp)) == -1) cpustate->ZeroVal = 1; else { desc[2] = ReadWord(addr+4); r = RIGHTS(desc); cpustate->ZeroVal = i80286_verify(cpustate, tmp, I80286_WRITE, RIGHTS(desc), 0); cpustate->ZeroVal = cpustate->ZeroVal || (DPL(r)<PMAX(RPL(tmp),CPL)); } break; default: throw TRAP(ILLEGAL_INSTRUCTION,-1); break; } break; case 1: /* lgdt, lldt in protected mode privilege level 0 required else common protection failure 0xd */ ModRM = FETCHOP; switch (ModRM&0x38) { case 0: /* sgdt */ PutRMWord(ModRM,cpustate->gdtr.limit); PutRMWordOffset(2,cpustate->gdtr.base&0xffff); PutRMWordOffset(4,0xff00|cpustate->gdtr.base>>16); break; case 8: /* sidt */ PutRMWord(ModRM,cpustate->idtr.limit); PutRMWordOffset(2,cpustate->idtr.base&0xffff); PutRMWordOffset(4,0xff00|cpustate->idtr.base>>16); break; case 0x10: /* lgdt */ if (PM&&(CPL!=0)) throw TRAP(GENERAL_PROTECTION_FAULT,0); cpustate->gdtr.limit=GetRMWord(ModRM); cpustate->gdtr.base=GetRMWordOffset(2)|(GetRMByteOffset(4)<<16); break; case 0x18: /* lidt */ if (PM&&(CPL!=0)) throw TRAP(GENERAL_PROTECTION_FAULT,0); cpustate->idtr.limit=GetRMWord(ModRM); cpustate->idtr.base=GetRMWordOffset(2)|(GetRMByteOffset(4)<<16); break; case 0x20: /* smsw */ PutRMWord(ModRM, cpustate->msw); break; case 0x30: /* lmsw */ if (PM&&(CPL!=0)) throw TRAP(GENERAL_PROTECTION_FAULT,0); msw = GetRMWord(ModRM); if (!PM&&(msw&1)) cpustate->sregs[CS] = IDX(cpustate->sregs[CS]); // cheat and set cpl to 0 cpustate->msw=(cpustate->msw&1)|msw; break; default: throw TRAP(ILLEGAL_INSTRUCTION,-1); break; } break; case 2: /* LAR */ if (!PM) throw TRAP(ILLEGAL_INSTRUCTION,-1); ModRM = FETCHOP; tmp=GetRMWord(ModRM); if ((addr = i80286_selector_address(cpustate,tmp)) == -1) cpustate->ZeroVal = 1; else { desc[2] = ReadWord(addr+4); r = RIGHTS(desc); if (DPL(r)>=PMAX(RPL(tmp),CPL)) { cpustate->ZeroVal = 0; // rights are expected to be in upper byte RegWord(ModRM) = r << 8; } else cpustate->ZeroVal = 1; } break; case 3: /* LSL */ if (!PM) throw TRAP(ILLEGAL_INSTRUCTION,-1); ModRM = FETCHOP; tmp=GetRMWord(ModRM); if ((addr = i80286_selector_address(cpustate,tmp)) == -1) cpustate->ZeroVal = 1; else { desc[2] = ReadWord(addr+4); r = RIGHTS(desc); if (!SEGDESC(r) && (GATE(r) >= CALLGATE)) cpustate->ZeroVal = 1; // not valid for gates else if (DPL(r)>=PMAX(RPL(tmp),CPL)) { cpustate->ZeroVal = 0; RegWord(ModRM) = ReadWord(addr); } else cpustate->ZeroVal = 1; } break; case 5: /* loadall */ if (PM&&(CPL!=0)) throw TRAP(GENERAL_PROTECTION_FAULT,0); cpustate->msw = (cpustate->msw&1)|ReadWord(0x806); cpustate->tr.sel = ReadWord(0x816); tmp = ReadWord(0x818); ExpandFlags(tmp); cpustate->flags = tmp; cpustate->flags = CompressFlags(); cpustate->pc = ReadWord(0x81a); cpustate->ldtr.sel = ReadWord(0x81c); cpustate->sregs[DS] = ReadWord(0x81e); cpustate->sregs[SS] = ReadWord(0x820); cpustate->sregs[CS] = ReadWord(0x822); cpustate->sregs[ES] = ReadWord(0x824); cpustate->regs.w[DI] = ReadWord(0x826); cpustate->regs.w[SI] = ReadWord(0x828); cpustate->regs.w[BP] = ReadWord(0x82a); cpustate->regs.w[SP] = ReadWord(0x82c); cpustate->regs.w[BX] = ReadWord(0x82e); cpustate->regs.w[DX] = ReadWord(0x830); cpustate->regs.w[CX] = ReadWord(0x832); cpustate->regs.w[AX] = ReadWord(0x834); // loadall uses base-rights-limit order #define LOADDESC(addr, sreg) { desc[1] = ReadWord(addr); desc[2] = ReadWord(addr+2); desc[0] = ReadWord(addr+4); \ cpustate->base[sreg] = BASE(desc); cpustate->rights[sreg] = RIGHTS(desc); \ cpustate->limit[sreg] = LIMIT(desc); } LOADDESC(0x836, ES); LOADDESC(0x83C, CS); LOADDESC(0x842, SS); LOADDESC(0x848, DS); #undef LOADDESC // void cast supresses warning #define LOADDESC(addr, reg, r) { desc[1] = ReadWord(addr); desc[2] = ReadWord(addr+2); desc[0] = ReadWord(addr+4); \ cpustate->reg.base = BASE(desc); (void)(r); cpustate->reg.limit = LIMIT(desc); } LOADDESC(0x84e, gdtr, 1); LOADDESC(0x854, ldtr, cpustate->ldtr.rights = RIGHTS(desc)); LOADDESC(0x85a, idtr, 1); LOADDESC(0x860, tr, cpustate->tr.rights = RIGHTS(desc)); #undef LOADDESC cpustate->pc = (cpustate->pc + cpustate->base[CS]) & AMASK; CHANGE_PC(cpustate->pc); break; case 6: /* clts */ if (PM&&(CPL!=0)) throw TRAP(GENERAL_PROTECTION_FAULT,0); cpustate->msw&=~8; break; default: throw TRAP(ILLEGAL_INSTRUCTION,-1); break; } }
static void i80286_code_descriptor(i80286_state *cpustate, UINT16 selector, UINT16 offset, int gate) { if (PM) { UINT16 desc[3]; UINT8 r; UINT32 addr; /* selector format 15..3 number/address in descriptor table 2: 0 global, 1 local descriptor table 1,0: requested privileg level must be higher or same as current privileg level in code selector */ if ((addr = i80286_selector_address(cpustate,selector)) == -1) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(selector)); desc[0] = ReadWord(addr); desc[1] = ReadWord(addr+2); desc[2] = ReadWord(addr+4); r = RIGHTS(desc); if (SEGDESC(r)) { if (!CODE(r)) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(selector)); if (CONF(r)) { if(DPL(r)>CPL) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(selector)); } else if ((RPL(selector)>CPL) || (DPL(r)!=CPL)) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(selector)); if (!PRES(r)) throw TRAP(SEG_NOT_PRESENT,IDXTBL(selector)); // this order is important if (offset > LIMIT(desc)) throw TRAP(GENERAL_PROTECTION_FAULT, 0); SET_ACC(desc); WriteWord(addr+4, desc[2]); cpustate->sregs[CS]=IDXTBL(selector) | CPL; cpustate->limit[CS]=LIMIT(desc); cpustate->base[CS]=BASE(desc); cpustate->rights[CS]=RIGHTS(desc); cpustate->pc=cpustate->base[CS]+offset; } else { // systemdescriptor UINT16 gatedesc[3]={0,0,0}; UINT16 gatesel = GATESEL(desc); if (!gate) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(selector)); // tss cs must be segment if (DPL(r) < PMAX(CPL,RPL(selector))) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(selector)); if (!PRES(r)) throw TRAP(SEG_NOT_PRESENT, IDXTBL(selector)); switch (GATE(r)) { case CALLGATE: if ((addr = i80286_selector_address(cpustate,gatesel)) == -1) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(gatesel)); gatedesc[0] = ReadWord(addr); gatedesc[1] = ReadWord(addr+2); gatedesc[2] = ReadWord(addr+4); r = RIGHTS(gatedesc); if (!CODE(r) || !SEGDESC(r)) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(gatesel)); if (DPL(r)>CPL) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(gatesel)); if (!PRES(r)) throw TRAP(SEG_NOT_PRESENT,IDXTBL(gatesel)); if (GATEOFF(desc) > LIMIT(gatedesc)) throw TRAP(GENERAL_PROTECTION_FAULT,0); if (!CONF(r)&&(DPL(r)<CPL)) { // inner call UINT16 tss_ss, tss_sp, oldss, oldsp; UINT32 oldstk; int i; if(gate == JMP) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(gatesel)); // can't jmp to inner tss_ss = ReadWord(cpustate->tr.base+TSS_SS0*2+(DPL(r)*4)); tss_sp = ReadWord(cpustate->tr.base+TSS_SP0*2+(DPL(r)*4)); oldss = cpustate->sregs[SS]; oldsp = cpustate->regs.w[SP]; oldstk = cpustate->base[SS] + oldsp; i80286_data_descriptor_full(cpustate, SS, tss_ss, DPL(r), TRAP(INVALID_TSS,IDXTBL(tss_ss)), tss_sp-8-(GATECNT(desc)*2), 8+(GATECNT(desc)*2)); cpustate->regs.w[SP] = tss_sp; PUSH(oldss); PUSH(oldsp); for (i = GATECNT(desc)-1; i >= 0; i--) PUSH(ReadWord(oldstk+(i*2))); } else i80286_check_permission(cpustate, SS, cpustate->regs.w[SP]-4, 4, I80286_READ); SET_ACC(gatedesc); WriteWord(addr+4, gatedesc[2]); cpustate->sregs[CS]=IDXTBL(gatesel) | DPL(r); cpustate->limit[CS]=LIMIT(gatedesc); cpustate->base[CS]=BASE(gatedesc); cpustate->rights[CS]=RIGHTS(gatedesc); cpustate->pc=(cpustate->base[CS]+GATEOFF(desc))&AMASK; break; case TASKGATE: selector = gatesel; if ((addr = i80286_selector_address(cpustate,selector)) == -1) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(selector)); desc[2] = ReadWord(addr+4); r = RIGHTS(desc); if (SEGDESC(r) || (GATE(r) != TSSDESCIDLE)) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(selector)); case TSSDESCIDLE: i80286_switch_task(cpustate, selector, gate); i80286_load_flags(cpustate, cpustate->flags, CPL); break; default: throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(selector)); } } } else { cpustate->sregs[CS]=selector; cpustate->base[CS]=selector<<4; cpustate->rights[CS]=0x9a; cpustate->limit[CS]=0xffff; cpustate->pc=(cpustate->base[CS]+offset)&AMASK; } }
static void i80286_switch_task(i80286_state *cpustate, UINT16 ntask, int type) { UINT16 ndesc[3], desc[3], ntss[22], otss[22]; UINT8 r, lr; UINT32 naddr, oaddr, ldtaddr; int i; logerror("This program uses TSSs, how rare. Please report this to the developers.\n"); if (TBL(ntask)) throw TRAP(INVALID_TSS,IDXTBL(ntask)); if ((naddr = i80286_selector_address(cpustate,ntask)) == -1) throw TRAP(INVALID_TSS,IDXTBL(ntask)); oaddr = i80286_selector_address(cpustate,cpustate->tr.sel); ndesc[0] = ReadWord(naddr); ndesc[1] = ReadWord(naddr+2); ndesc[2] = ReadWord(naddr+4); desc[2] = ReadWord(oaddr+4); r = RIGHTS(ndesc); if (SEGDESC(r) || ((GATE(r) & ~2) != TSSDESCIDLE)) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(ntask)); if (!PRES(r)) throw TRAP(SEG_NOT_PRESENT, IDXTBL(ntask)); if (LIMIT(ndesc) < 43) throw TRAP(INVALID_TSS,IDXTBL(ntask)); for (i = 0; i < 44; i+=2) ntss[i/2] = ReadWord(BASE(ndesc)+i); cpustate->flags = CompressFlags(); if (type == CALL) WriteWord(BASE(ndesc)+TSS_BACK*2, cpustate->tr.sel); if (type == IRET) cpustate->flags &= ~0x4000; otss[TSS_IP] = cpustate->pc-cpustate->base[CS]; otss[TSS_FLAG] = cpustate->flags; otss[TSS_AX] = cpustate->regs.w[AX]; otss[TSS_CX] = cpustate->regs.w[CX]; otss[TSS_DX] = cpustate->regs.w[DX]; otss[TSS_BX] = cpustate->regs.w[BX]; otss[TSS_SP] = cpustate->regs.w[SP]; otss[TSS_BP] = cpustate->regs.w[BP]; otss[TSS_SI] = cpustate->regs.w[SI]; otss[TSS_DI] = cpustate->regs.w[DI]; otss[TSS_ES] = cpustate->sregs[ES]; otss[TSS_CS] = cpustate->sregs[CS]; otss[TSS_SS] = cpustate->sregs[SS]; otss[TSS_DS] = cpustate->sregs[DS]; otss[TSS_LDT] = cpustate->ldtr.sel; for (i = 14; i < 44; i+=2) WriteWord(cpustate->tr.base+i, otss[i/2]); // jmp does both if (type != CALL) { desc[2] &= ~0x200; // mark idle WriteWord(oaddr+4, desc[2]); } if (type != IRET) { ndesc[2] |= 0x200; WriteWord(naddr+4, ndesc[2]); } cpustate->tr.sel=ntask; cpustate->tr.limit=LIMIT(ndesc); cpustate->tr.base=BASE(ndesc); cpustate->tr.rights=RIGHTS(ndesc); cpustate->flags = ntss[TSS_FLAG]; cpustate->regs.w[AX] = ntss[TSS_AX]; cpustate->regs.w[CX] = ntss[TSS_CX]; cpustate->regs.w[DX] = ntss[TSS_DX]; cpustate->regs.w[BX] = ntss[TSS_BX]; cpustate->regs.w[SP] = ntss[TSS_SP]; cpustate->regs.w[BP] = ntss[TSS_BP]; cpustate->regs.w[SI] = ntss[TSS_SI]; cpustate->regs.w[DI] = ntss[TSS_DI]; if (TBL(ntss[TSS_LDT])) throw TRAP(INVALID_TSS,IDXTBL(ntss[TSS_LDT])); if (IDXTBL(ntss[TSS_LDT])) { if ((ldtaddr = i80286_selector_address(cpustate,ntss[TSS_LDT])) == -1) throw TRAP(INVALID_TSS,IDXTBL(ntss[TSS_LDT])); desc[0] = ReadWord(ldtaddr); desc[1] = ReadWord(ldtaddr+2); desc[2] = ReadWord(ldtaddr+4); lr = RIGHTS(desc); if (SEGDESC(lr) || (GATE(lr) != LDTDESC)) throw TRAP(INVALID_TSS,IDXTBL(ntss[TSS_LDT])); if (!PRES(lr)) throw TRAP(INVALID_TSS,IDXTBL(ntss[TSS_LDT])); cpustate->ldtr.sel=ntss[TSS_LDT]; cpustate->ldtr.limit=LIMIT(desc); cpustate->ldtr.base=BASE(desc); cpustate->ldtr.rights=RIGHTS(desc); } else { cpustate->ldtr.sel=0; cpustate->ldtr.limit=0; cpustate->ldtr.base=0; cpustate->ldtr.rights=0; } if (type == CALL) cpustate->flags |= 0x4000; cpustate->msw |= 8; i80286_data_descriptor_full(cpustate, SS, ntss[TSS_SS], RPL(ntss[TSS_CS]), TRAP(INVALID_TSS,IDXTBL(ntss[TSS_SS])), 0, 0); cpustate->sregs[CS] = IDXTBL(cpustate->sregs[CS]) | RPL(ntss[TSS_CS]); // fixme try { i80286_code_descriptor(cpustate, ntss[TSS_CS], ntss[TSS_IP], 0); } catch(UINT32 e) { int error_code = e & 0xffff; if(error_code == GENERAL_PROTECTION_FAULT) e = TRAP(INVALID_TSS,(e >> 16)); // #NP fault is correct throw e; } i80286_data_descriptor_full(cpustate, ES, ntss[TSS_ES], RPL(ntss[TSS_CS]), TRAP(INVALID_TSS,IDXTBL(ntss[TSS_ES])), 0, 0); i80286_data_descriptor_full(cpustate, DS, ntss[TSS_DS], RPL(ntss[TSS_CS]), TRAP(INVALID_TSS,IDXTBL(ntss[TSS_DS])), 0, 0); }