diff --git a/modules/pcjs/lib/debugger.js b/modules/pcjs/lib/debugger.js index c2ccf41c2..957132292 100644 --- a/modules/pcjs/lib/debugger.js +++ b/modules/pcjs/lib/debugger.js @@ -1821,6 +1821,21 @@ if (DEBUGGER) { } }; + Debugger.SYSDESCS = { + 0x0100: ["tss286", false], + 0x0200: ["ldt", false], + 0x0300: ["busy tss286", false], + 0x0400: ["call gate", true], + 0x0500: ["task gate", true], + 0x0600: ["int gate286", true], + 0x0700: ["trap gate286", true], + 0x0900: ["tss386", false], + 0x0B00: ["busy tss386", false], + 0x0C00: ["call gate386", true], + 0x0E00: ["int gate386", true], + 0x0F00: ["trap gate386", true] + }; + /** * dumpDesc(s) * @@ -1862,34 +1877,10 @@ if (DEBUGGER) { if (seg.type & X86.DESC.ACC.TYPE.ACCESSED) sType += ",accessed"; } else { - switch(seg.type) { - case X86.DESC.ACC.TYPE.TSS: - sType = "tss"; - break; - case X86.DESC.ACC.TYPE.LDT: - sType = "ldt"; - break; - case X86.DESC.ACC.TYPE.TSS_BUSY: - sType = "busy tss"; - break; - case X86.DESC.ACC.TYPE.GATE_CALL: - sType = "call gate"; - fGate = true; - break; - case X86.DESC.ACC.TYPE.GATE_TASK: - sType = "task gate"; - fGate = true; - break; - case X86.DESC.ACC.TYPE.GATE_INT: - sType = "int gate"; - fGate = true; - break; - case X86.DESC.ACC.TYPE.GATE_TRAP: - sType = "trap gate"; - fGate = true; - break; - default: - break; + var sysDesc = Debugger.SYSDESCS[seg.type]; + if (sysDesc) { + sType = sysDesc[0]; + fGate = sysDesc[1]; } } diff --git a/modules/pcjs/lib/x86.js b/modules/pcjs/lib/x86.js index 2d884e780..68956860c 100644 --- a/modules/pcjs/lib/x86.js +++ b/modules/pcjs/lib/x86.js @@ -91,8 +91,8 @@ var X86 = { MP: 0x0002, // monitor processor extension (ie, coprocessor) EM: 0x0004, // emulate processor extension TS: 0x0008, // task switch indicator - ON: 0xfff0, // on the 80286, these bits are always on (TODO: Verify) - MASK: 0xffff // these are the only (MSW) bits that the 80286 can access (within CR0) + ON: 0xFFF0, // on the 80286, these bits are always on (TODO: Verify) + MASK: 0xFFFF // these are the only (MSW) bits that the 80286 can access (within CR0) }, ET: 0x00000010, // coprocessor type (80287 or 80387); always 1 on post-80386 CPUs PG: 0x80000000|0 // 0: paging disabled @@ -100,7 +100,7 @@ var X86 = { SEL: { RPL: 0x0003, // requested privilege level (0-3) LDT: 0x0004, // table indicator (0: GDT, 1: LDT) - MASK: 0xfff8 // table index + MASK: 0xFFF8 // table index }, DESC: { // Descriptor Table Entry LIMIT: { // LIMIT bits 0-15 (or OFFSET if this is an INTERRUPT or TRAP gate) @@ -111,12 +111,12 @@ var X86 = { }, ACC: { // bit definitions for the access word (offset 0x4) OFFSET: 0x4, - BASE1623: 0x00ff, // (not used if this a TASK, INTERRUPT or TRAP gate; bits 0-5 are parm count for CALL gates) + BASE1623: 0x00FF, // (not used if this a TASK, INTERRUPT or TRAP gate; bits 0-5 are parm count for CALL gates) TYPE: { OFFSET: 0x5, - MASK: 0x1f00, + MASK: 0x1F00, SEG: 0x1000, - NONSEG: 0x0f00, + NONSEG: 0x0F00, /* * The following bits apply only when SEG is set */ @@ -130,21 +130,26 @@ var X86 = { * The following are all the possible (valid) types (well, except for the variations * of DATA and CODE where the ACCESSED bit (0x0100) may also be set) */ - TSS: 0x0100, + TSS286: 0x0100, LDT: 0x0200, - TSS_BUSY: 0x0300, + TSS286_BUSY: 0x0300, GATE_CALL: 0x0400, GATE_TASK: 0x0500, - GATE_INT: 0x0600, - GATE_TRAP: 0x0700, + GATE286_INT: 0x0600, + GATE286_TRAP: 0x0700, + TSS386: 0x0900, // 80386 and up + TSS386_BUSY: 0x0B00, // 80386 and up + GATE386_CALL: 0x0C00, // 80386 and up + GATE386_INT: 0x0E00, // 80386 and up + GATE386_TRAP: 0x0F00, // 80386 and up DATA_READONLY: 0x1000, DATA_WRITABLE: 0x1200, DATA_EXPDOWN_READONLY: 0x1400, DATA_EXPDOWN_WRITABLE: 0x1600, CODE_EXECONLY: 0x1800, - CODE_READABLE: 0x1a00, - CODE_CONFORMING: 0x1c00, - CODE_CONFORMING_READABLE: 0x1e00 + CODE_READABLE: 0x1A00, + CODE_CONFORMING: 0x1C00, + CODE_CONFORMING_READABLE: 0x1E00 }, DPL: { MASK: 0x6000, @@ -155,7 +160,7 @@ var X86 = { }, EXT: { // descriptor extension word (reserved on the 80286; "must be zero") OFFSET: 0x6, - LIMIT1619: 0x000f, + LIMIT1619: 0x000F, AVAIL: 0x0010, // NOTE: set in various descriptors in OS/2 /* * The BIG bit is known as the D bit for code segments; when set, all addresses and operands @@ -167,52 +172,80 @@ var X86 = { */ BIG: 0x0040, // clear if default operand/address size is 16-bit, set if 32-bit LIMITPAGES: 0x0080, // clear if limit granularity is bytes, set if limit granularity is 4Kb pages - BASE2431: 0xff00 + BASE2431: 0xFF00 }, INVALID: 0 // use X86.DESC.INVALID for invalid DESC values }, LADDR: { // linear address PDE: { // index of page directory entry - MASK: 0xffc00000|0, + MASK: 0xFFC00000|0, SHIFT: 20 // (addr & DIR.MASK) >>> DIR.SHIFT yields a page directory offset (ie, index * 4) }, PTE: { // index of page table entry - MASK: 0x003ff000, + MASK: 0x003FF000, SHIFT: 10 // (addr & PAGE.MASK) >>> PAGE.SHIFT yields a page table offset (ie, index * 4) }, - OFFSET: 0x00000fff + OFFSET: 0x00000FFF }, PTE: { - FRAME: 0xfffff000|0, + FRAME: 0xFFFFF000|0, DIRTY: 0x00000040, // page has been modified ACCESSED: 0x00000020, // page has been accessed USER: 0x00000004, // set for user level (CPL 3), clear for supervisor level (CPL 0-2) READWRITE: 0x00000002, // set for read/write, clear for read-only (affects CPL 3 only) PRESENT: 0x00000001 // set for present page, clear for not-present page }, - TSS: { + TSS286: { PREV_TSS: 0x00, CPL0_SP: 0x02, // start of values altered by task switches CPL0_SS: 0x04, CPL1_SP: 0x06, CPL1_SS: 0x08, - CPL2_SP: 0x0a, - CPL2_SS: 0x0c, - TASK_IP: 0x0e, + CPL2_SP: 0x0A, + CPL2_SS: 0x0C, + TASK_IP: 0x0E, TASK_PS: 0x10, TASK_AX: 0x12, TASK_CX: 0x14, TASK_DX: 0x16, TASK_BX: 0x18, - TASK_SP: 0x1a, - TASK_BP: 0x1c, - TASK_SI: 0x1e, + TASK_SP: 0x1A, + TASK_BP: 0x1C, + TASK_SI: 0x1E, TASK_DI: 0x20, TASK_ES: 0x22, TASK_CS: 0x24, TASK_SS: 0x26, TASK_DS: 0x28, // end of values altered by task switches - TASK_LDT: 0x2a + TASK_LDT: 0x2A + }, + TSS386: { + PREV_TSS: 0x00, + CPL0_ESP: 0x04, // start of values altered by task switches + CPL0_SS: 0x08, + CPL1_ESP: 0x0c, + CPL1_SS: 0x10, + CPL2_ESP: 0x14, + CPL2_SS: 0x18, + TASK_CR3: 0x1C, // (not in TSS286) + TASK_EIP: 0x20, + TASK_PS: 0x24, + TASK_EAX: 0x28, + TASK_ECX: 0x2C, + TASK_EDX: 0x30, + TASK_EBX: 0x34, + TASK_ESP: 0x38, + TASK_EBP: 0x3C, + TASK_ESI: 0x40, + TASK_EDI: 0x44, + TASK_ES: 0x48, + TASK_CS: 0x4C, + TASK_SS: 0x50, + TASK_DS: 0x54, + TASK_FS: 0x58, // (not in TSS286) + TASK_GS: 0x5C, // (not in TSS286) end of values altered by task switches + TASK_LDT: 0x60, + TASK_IOPM: 0x64 // (not in TSS286) }, /* * Processor Exception Interrupts @@ -260,7 +293,7 @@ var X86 = { EXT: 0x0001, IDT: 0x0002, LDT: 0x0004, - MASK: 0xfff8 // index of corresponding entry in GDT, LDT or IDT + MASK: 0xFFF8 // index of corresponding entry in GDT, LDT or IDT }, RESULT: { /* diff --git a/modules/pcjs/lib/x86func.js b/modules/pcjs/lib/x86func.js index 5c20b437b..83ff55571 100644 --- a/modules/pcjs/lib/x86func.js +++ b/modules/pcjs/lib/x86func.js @@ -1244,7 +1244,7 @@ X86.fnIRET = function IRET() if (this.regCR0 & X86.CR0.MSW.PE) { if (this.regPS & X86.PS.NT) { var addrNew = this.segTSS.base; - var sel = this.getShort(addrNew + X86.TSS.PREV_TSS); + var sel = this.getShort(addrNew + X86.TSS286.PREV_TSS); this.segCS.switchTSS(sel, false); return; } @@ -1651,7 +1651,7 @@ X86.fnLTR = function LTR(dst, src) this.opFlags |= X86.OPFLAG.NOWRITE; if (this.segTSS.load(dst) !== X86.ADDR_INVALID) { this.setShort(this.segTSS.addrDesc + X86.DESC.ACC.OFFSET, this.segTSS.acc |= X86.DESC.ACC.TYPE.LDT); - this.segTSS.type = X86.DESC.ACC.TYPE.TSS_BUSY; + this.segTSS.type = X86.DESC.ACC.TYPE.TSS286_BUSY; } this.nStepCycles -= (17 + (this.regEA === X86.ADDR_INVALID? 0 : 2)); return dst; diff --git a/modules/pcjs/lib/x86seg.js b/modules/pcjs/lib/x86seg.js index d959f6ea2..2fc68fd3f 100644 --- a/modules/pcjs/lib/x86seg.js +++ b/modules/pcjs/lib/x86seg.js @@ -554,7 +554,7 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress) } fGate = false; } - else if (type == X86.DESC.ACC.TYPE.TSS) { + else if (type == X86.DESC.ACC.TYPE.TSS286) { if (!this.switchTSS(sel, fCall)) { base = addrDesc = X86.ADDR_INVALID; break; @@ -567,13 +567,13 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress) nFaultError = sel; if (rpl < this.cpl) rpl = this.cpl; // set RPL to max(RPL,CPL) for call gates } - else if (type == X86.DESC.ACC.TYPE.GATE_INT) { + else if (type == X86.DESC.ACC.TYPE.GATE286_INT) { fGate = true; regPSMask = ~(X86.PS.NT | X86.PS.TF | X86.PS.IF); nFaultError = sel | X86.ERRCODE.EXT; cpu.assert(!(acc & 0x1f)); } - else if (type == X86.DESC.ACC.TYPE.GATE_TRAP) { + else if (type == X86.DESC.ACC.TYPE.GATE286_TRAP) { fGate = true; regPSMask = ~(X86.PS.NT | X86.PS.TF); nFaultError = sel | X86.ERRCODE.EXT; @@ -618,7 +618,7 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress) regSP += 2; } addrTSS = cpu.segTSS.base; - offSP = (this.cpl << 2) + X86.TSS.CPL0_SP; + offSP = (this.cpl << 2) + X86.TSS286.CPL0_SP; offSS = offSP + 2; regSSPrev = cpu.getSS(); regSPPrev = cpu.getSP(); @@ -692,7 +692,7 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress) } } else if (this.id == X86Seg.ID.TSS) { - if (!selMasked || type != X86.DESC.ACC.TYPE.TSS && type != X86.DESC.ACC.TYPE.TSS_BUSY) { + if (!selMasked || type != X86.DESC.ACC.TYPE.TSS286 && type != X86.DESC.ACC.TYPE.TSS286_BUSY) { if (!fSuppress) X86.fnFault.call(cpu, X86.EXCEPTION.TS_FAULT, sel, true); base = addrDesc = X86.ADDR_INVALID; break; @@ -702,7 +702,7 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress) /* * For LSL, we must support any descriptor marked X86.DESC.ACC.TYPE.SEG, as well as TSS and LDT descriptors. */ - if (!(type & X86.DESC.ACC.TYPE.SEG) && type > X86.DESC.ACC.TYPE.TSS_BUSY) { + if (!(type & X86.DESC.ACC.TYPE.SEG) && type > X86.DESC.ACC.TYPE.TSS286_BUSY) { base = addrDesc = X86.ADDR_INVALID; break; } @@ -761,11 +761,11 @@ X86Seg.prototype.switchTSS = function switchTSS(selNew, fNest) /* * TODO: Verify that it is (always) correct to require that the BUSY bit be currently set. */ - if (cpu.segTSS.type != X86.DESC.ACC.TYPE.TSS_BUSY) { + if (cpu.segTSS.type != X86.DESC.ACC.TYPE.TSS286_BUSY) { X86.fnFault.call(cpu, X86.EXCEPTION.TS_FAULT, selNew, true); return false; } - cpu.setShort(cpu.segTSS.addrDesc + X86.DESC.ACC.OFFSET, (cpu.segTSS.acc & ~X86.DESC.ACC.TYPE.TSS_BUSY) | X86.DESC.ACC.TYPE.TSS); + cpu.setShort(cpu.segTSS.addrDesc + X86.DESC.ACC.OFFSET, (cpu.segTSS.acc & ~X86.DESC.ACC.TYPE.TSS286_BUSY) | X86.DESC.ACC.TYPE.TSS286); } if (cpu.segTSS.load(selNew) === X86.ADDR_INVALID) { @@ -777,66 +777,66 @@ X86Seg.prototype.switchTSS = function switchTSS(selNew, fNest) this.dbg.message((fNest? "Task switch" : "Task return") + ": TR " + str.toHexWord(selOld) + " (%" + str.toHex(addrOld, 6) + "), new TR " + str.toHexWord(selNew) + " (%" + str.toHex(addrNew, 6) + ")"); } if (fNest === false) { - if (cpu.segTSS.type != X86.DESC.ACC.TYPE.TSS_BUSY) { + if (cpu.segTSS.type != X86.DESC.ACC.TYPE.TSS286_BUSY) { X86.fnFault.call(cpu, X86.EXCEPTION.GP_FAULT, selNew, true); return false; } } else { - if (cpu.segTSS.type == X86.DESC.ACC.TYPE.TSS_BUSY) { + if (cpu.segTSS.type == X86.DESC.ACC.TYPE.TSS286_BUSY) { X86.fnFault.call(cpu, X86.EXCEPTION.GP_FAULT, selNew, true); return false; } - cpu.setShort(cpu.segTSS.addrDesc + X86.DESC.ACC.OFFSET, cpu.segTSS.acc |= X86.DESC.ACC.TYPE.TSS_BUSY); - cpu.segTSS.type = X86.DESC.ACC.TYPE.TSS_BUSY; + cpu.setShort(cpu.segTSS.addrDesc + X86.DESC.ACC.OFFSET, cpu.segTSS.acc |= X86.DESC.ACC.TYPE.TSS286_BUSY); + cpu.segTSS.type = X86.DESC.ACC.TYPE.TSS286_BUSY; } /* * Update the old TSS */ - cpu.setShort(addrOld + X86.TSS.TASK_IP, cpu.getIP()); - cpu.setShort(addrOld + X86.TSS.TASK_PS, cpu.getPS()); - cpu.setShort(addrOld + X86.TSS.TASK_AX, cpu.regEAX); - cpu.setShort(addrOld + X86.TSS.TASK_CX, cpu.regECX); - cpu.setShort(addrOld + X86.TSS.TASK_DX, cpu.regEDX); - cpu.setShort(addrOld + X86.TSS.TASK_BX, cpu.regEBX); - cpu.setShort(addrOld + X86.TSS.TASK_SP, cpu.getSP()); - cpu.setShort(addrOld + X86.TSS.TASK_BP, cpu.regEBP); - cpu.setShort(addrOld + X86.TSS.TASK_SI, cpu.regESI); - cpu.setShort(addrOld + X86.TSS.TASK_DI, cpu.regEDI); - cpu.setShort(addrOld + X86.TSS.TASK_ES, cpu.segES.sel); - cpu.setShort(addrOld + X86.TSS.TASK_CS, cpu.segCS.sel); - cpu.setShort(addrOld + X86.TSS.TASK_SS, cpu.segSS.sel); - cpu.setShort(addrOld + X86.TSS.TASK_DS, cpu.segDS.sel); + cpu.setShort(addrOld + X86.TSS286.TASK_IP, cpu.getIP()); + cpu.setShort(addrOld + X86.TSS286.TASK_PS, cpu.getPS()); + cpu.setShort(addrOld + X86.TSS286.TASK_AX, cpu.regEAX); + cpu.setShort(addrOld + X86.TSS286.TASK_CX, cpu.regECX); + cpu.setShort(addrOld + X86.TSS286.TASK_DX, cpu.regEDX); + cpu.setShort(addrOld + X86.TSS286.TASK_BX, cpu.regEBX); + cpu.setShort(addrOld + X86.TSS286.TASK_SP, cpu.getSP()); + cpu.setShort(addrOld + X86.TSS286.TASK_BP, cpu.regEBP); + cpu.setShort(addrOld + X86.TSS286.TASK_SI, cpu.regESI); + cpu.setShort(addrOld + X86.TSS286.TASK_DI, cpu.regEDI); + cpu.setShort(addrOld + X86.TSS286.TASK_ES, cpu.segES.sel); + cpu.setShort(addrOld + X86.TSS286.TASK_CS, cpu.segCS.sel); + cpu.setShort(addrOld + X86.TSS286.TASK_SS, cpu.segSS.sel); + cpu.setShort(addrOld + X86.TSS286.TASK_DS, cpu.segDS.sel); /* * Reload all registers from the new TSS; it's important to reload the LDTR sooner * rather than later, so that as segment registers are reloaded, any LDT selectors will * will be located in the correct table. */ - cpu.segLDT.load(cpu.getShort(addrNew + X86.TSS.TASK_LDT)); - cpu.setPS(cpu.getShort(addrNew + X86.TSS.TASK_PS) | (fNest? X86.PS.NT : 0)); + cpu.segLDT.load(cpu.getShort(addrNew + X86.TSS286.TASK_LDT)); + cpu.setPS(cpu.getShort(addrNew + X86.TSS286.TASK_PS) | (fNest? X86.PS.NT : 0)); cpu.assert(!fNest || !!(cpu.regPS & X86.PS.NT)); - cpu.regEAX = cpu.getShort(addrNew + X86.TSS.TASK_AX); - cpu.regECX = cpu.getShort(addrNew + X86.TSS.TASK_CX); - cpu.regEDX = cpu.getShort(addrNew + X86.TSS.TASK_DX); - cpu.regEBX = cpu.getShort(addrNew + X86.TSS.TASK_BX); - cpu.regEBP = cpu.getShort(addrNew + X86.TSS.TASK_BP); - cpu.regESI = cpu.getShort(addrNew + X86.TSS.TASK_SI); - cpu.regEDI = cpu.getShort(addrNew + X86.TSS.TASK_DI); - cpu.segES.load(cpu.getShort(addrNew + X86.TSS.TASK_ES)); - cpu.segDS.load(cpu.getShort(addrNew + X86.TSS.TASK_DS)); - cpu.setCSIP(cpu.getShort(addrNew + X86.TSS.TASK_IP), cpu.getShort(addrNew + X86.TSS.TASK_CS)); + cpu.regEAX = cpu.getShort(addrNew + X86.TSS286.TASK_AX); + cpu.regECX = cpu.getShort(addrNew + X86.TSS286.TASK_CX); + cpu.regEDX = cpu.getShort(addrNew + X86.TSS286.TASK_DX); + cpu.regEBX = cpu.getShort(addrNew + X86.TSS286.TASK_BX); + cpu.regEBP = cpu.getShort(addrNew + X86.TSS286.TASK_BP); + cpu.regESI = cpu.getShort(addrNew + X86.TSS286.TASK_SI); + cpu.regEDI = cpu.getShort(addrNew + X86.TSS286.TASK_DI); + cpu.segES.load(cpu.getShort(addrNew + X86.TSS286.TASK_ES)); + cpu.segDS.load(cpu.getShort(addrNew + X86.TSS286.TASK_DS)); + cpu.setCSIP(cpu.getShort(addrNew + X86.TSS286.TASK_IP), cpu.getShort(addrNew + X86.TSS286.TASK_CS)); - var offSS = X86.TSS.TASK_SS; - var offSP = X86.TSS.TASK_SP; + var offSS = X86.TSS286.TASK_SS; + var offSP = X86.TSS286.TASK_SP; if (this.cpl < cplOld) { - offSP = (this.cpl << 2) + X86.TSS.CPL0_SP; + offSP = (this.cpl << 2) + X86.TSS286.CPL0_SP; offSS = offSP + 2; } cpu.setSS(cpu.getShort(addrNew + offSS), true); cpu.setSP(cpu.getShort(addrNew + offSP)); - if (fNest) cpu.setShort(addrNew + X86.TSS.PREV_TSS, selOld); + if (fNest) cpu.setShort(addrNew + X86.TSS286.PREV_TSS, selOld); cpu.regCR0 |= X86.CR0.MSW.TS; return true;