diff --git a/src/arch/x86/isa/decoder/one_byte_opcodes.isa b/src/arch/x86/isa/decoder/one_byte_opcodes.isa --- a/src/arch/x86/isa/decoder/one_byte_opcodes.isa +++ b/src/arch/x86/isa/decoder/one_byte_opcodes.isa @@ -381,33 +381,29 @@ default: UD2(); } } - format WarnUnimpl { - 0x19: decode OPCODE_OP_BOTTOM3 { - // The second parameter here should be of size b, but - // immediate sizes are determined elsewhere and this would - // confuse the instruction type specialization code. - 0x0: Inst::ENTER(Iw,Iw); - 0x1: Inst::LEAVE(); - 0x2: ret_far_Iw(); + + 0x19: decode OPCODE_OP_BOTTOM3 { + // The second parameter here should be of size b, but + // immediate sizes are determined elsewhere and this would + // confuse the instruction type specialization code. + format WarnUnimpl { 0x0: Inst::ENTER(Iw,Iw); } + format WarnUnimpl { 0x1: Inst::LEAVE(); } + format WarnUnimpl { 0x2: ret_far_Iw(); } + format WarnUnimpl { 0x3: decode MODE_SUBMODE { 0x3, 0x4: ret_far_real(); default: Inst::RET_FAR(); } - 0x4: int3(); - 0x5: decode FullSystemInt default int_Ib() { - 0: decode IMMEDIATE { - // Really only the LSB matters, but the decoder - // will sign extend it, and there's no easy way to - // specify only checking the first byte. - 0xffffffffffffff80: - SyscallInst::int80('xc->syscall(Rax)', - IsSyscall, IsNonSpeculative, IsSerializeAfter); - } - } + } + 0x4: INT3(); + 0x5: INT_IB(); + format WarnUnimpl { 0x6: decode MODE_SUBMODE { 0x0: Inst::UD2(); default: into(); } + } + format WarnUnimpl { 0x7: decode MODE_SUBMODE { 0x4: Inst::IRET_REAL(); 0x3: Inst::IRET_VIRT(); diff --git a/src/arch/x86/isa/insts/general_purpose/control_transfer/interrupts_and_exceptions.py b/src/arch/x86/isa/insts/general_purpose/control_transfer/interrupts_and_exceptions.py --- a/src/arch/x86/isa/insts/general_purpose/control_transfer/interrupts_and_exceptions.py +++ b/src/arch/x86/isa/insts/general_purpose/control_transfer/interrupts_and_exceptions.py @@ -218,6 +218,210 @@ wrip t0, t1, dataSize=ssz }; +def macroop INT3 { + ## Make the default data size of pops 64 bits in 64 bit mode + #.adjust_env oszIn64Override + + limm t1, 0x03, dataSize=8 + + br rom_label("intLongWork") +}; + +def macroop INT_IB { + # Make the default data size of pops 64 bits in 64 bit mode + .adjust_env oszIn64Override + + # temp_int_n_vector = byte-sized interrupt vector specified in the instruc- + # tion, zero-extended to 64 bits + mov t1, t0, t0, dataSize=8 + limm t1, imm, dataSize=1 + + br rom_label("intLongWork") +}; + +def rom +{ + extern intLongWork: + + # t1 = temp_int_n_vector + # t2 = temp_idt_desc + # t3 = temp_idt_desc.segment + # t4 = temp_RIP + # t5 = m5 handy reg + # t6 = temp_CPL + # t8 = CS + + # Read the handy m5 register for use later + rdm5reg t5 + + # in long mode? + andi t0, t5, 0xE, flags=(EZF,) + panic "INTX is implented in long mode only!", flags=(nCEZF,) + + # temp_desc=READ_MEM.q [idt:temp_int_n_vector*16] + ld t2, idtr, [16, t1, t0], dataSize=8, atCPL0=True + + # temp_RIP = temp_idt_desc.offset + limm t4, 0xFFFF00000000FFFF, dataSize=8 + and t4, t4, t2, dataSize=8 + srli t9, t4, 32, dataSize=8 + or t4, t4, t9, dataSize=8 + + # temp_upper = READ_MEM.q [idt:temp_int_n_vector*16+8] + ld t3, idtr, [16, t1, t0], 8, dataSize=4, atCPL0=True + + # temp_RIP = tempRIP + (temp_upper SHL 32) + slli t3, t3, 32, dataSize=8 + or t4, t4, t3, dataSize=8 + + # Check if the RIP is canonical. + srai t9, t4, 47, flags=(EZF,), dataSize=ssz + # if t9 isn't 0 or -1, it wasn't canonical. + br rom_local_label("checkRipFallThrough"), flags=(CEZF,) + addi t0, t9, 1, flags=(EZF,), dataSize=ssz + fault "new GeneralProtection(0)", flags=(nCEZF,) + + checkRipFallThrough: + + # t3 = temp_idt_desc.segment + limm t3, 0x00000000FFFF0000 + and t3, t3, t2 + srli t3, t3, 16 + + #### + #### Read in the info for the new CS segment. + #### + + # CS = READ_DESCRIPTOR (temp_CS, iret_chk) + andi t0, t3, 0xFC, flags=(EZF,), dataSize=2 + br rom_local_label("processCSDescriptor"), flags=(CEZF,) + andi t6, t3, 0xF8, dataSize=8 + andi t0, t3, 0x4, flags=(EZF,), dataSize=2 + br rom_local_label("globalCSDescriptor"), flags=(CEZF,) + ld t8, tsl, [1, t0, t6], dataSize=8, atCPL0=True + br rom_local_label("processCSDescriptor") + globalCSDescriptor: + ld t8, tsg, [1, t0, t6], dataSize=8, atCPL0=True + processCSDescriptor: + chks t3, t6, dataSize=8 + + # now t8 = CS + + #store the old rsp + mov t9, rsp, rsp, dataSize=8 + + # store old_SS + limm t1, 0x0, dataSize=8 + rdsel t1, ss + + # IF(CS.attr.conforming==1) + limm t7, "(1L<<42)", dataSize=8 + and t0, t8, t7, flags=(EZF,), dataSize=8 + br rom_local_label("NonConforming"), flags=(CEZF,) + br rom_local_label("NoPrivilegeLevelChange") + + NonConforming: + #temp_CPL = CS.attr.dpl (* 16) + limm t6, "(1L<<45) | (1L<<46)", dataSize=8 + and t6, t6, t8, dataSize=8 + srli t6, t6, 41, dataSize=8 + + # IF (CPL==temp_CPL) + andi t7, t5, 0x30, dataSize=8 + sub t0, t6, t7, flags=(EZF,), dataSize=8 + br rom_local_label("NoPrivilegeLevelChange"), flags=(CEZF,) + + # PrivilegeLevelChange: + + #IF (ist_index>0) + limm t7, "(1L<<34) | (1L<<33) | (1L<<32)", dataSize=8 + and t7, t2, t7, flags=(EZF,), dataSize=8 + br rom_local_label("NoIndex"), flags=(CEZF,) + + #temp_RSP = READ_MEM.q [tss:ist_index*8+28] + srli t7, t7, 29, dataSize=8 + ld rsp, tr, [1, t0, t7], 28, dataSize=8, atCPL0=True + br rom_local_label ("IndexFallThrough") + NoIndex: + #temp_RSP = READ_MEM.q [tss:new_cpl*8+4] + srli t6, t6, 4, dataSize=8 + ld rsp, tr, [8, t6, t0], 4, dataSize=8, atCPL0=True + + #temp_SS_desc.sel = NULL + new_cp + wrsel ss, t6 + + IndexFallThrough: + + br rom_local_label("PrivilegeLevelFallThrough") + + NoPrivilegeLevelChange: + + # IF (temp_idt_desc.ist!=0) + limm t7, "(1L<<34) | (1L<<33) | (1L<<32)", dataSize=8 + and t7, t2, t7, flags=(EZF,), dataSize=8 + br rom_local_label("SwitchStackPointerFallThrough"), flags=(CEZF,) + + # RSP = READ_MEM.q [tss:ist_index*8+28] + srli t7, t7, 29, dataSize=8 + ld rsp, tr, [1, t0, t7], 28, dataSize=8, atCPL0=True + + SwitchStackPointerFallThrough: + + PrivilegeLevelFallThrough: + + # RSP = RSP AND 0xFFFFFFFFFFFFFFF0 + limm t7, 0xFFFFFFFFFFFFFFF0, dataSize=8 + and rsp, rsp, t7, dataSize=8 + + # store old_CS + mov t7, t0, t0, dataSize=8 + rdsel t7, cs + + # Update CS + wrdl cs, t8, t3 + wrsel cs, t3 + + # PUSH.q old_SS + st t1, ss, [1, t0, rsp], "-1*env.stackSize", dataSize=8 + # PUSH.q old_RSP + st t9, ss, [1, t0, rsp], "-2*env.stackSize", dataSize=8 + # PUSH.v old_RFLAGS + rflags t1, dataSize=8 + st t1, ss, [1, t0, rsp], "-3*env.stackSize", dataSize=8 + # PUSH.v old_CS + st t7, ss, [1, t0, rsp], "-4*env.stackSize", dataSize=8 + # PUSH.v next_RIP + rdip t9 + st t9, ss, [1, t0, rsp], "-5*env.stackSize", dataSize=8 + + subi rsp, rsp, "5*env.stackSize" + + #TODO rip check + + #RFLAGS.VM,NT,TF,RF cleared + limm t7, "~(VMBit | NTBit | TFBit | RFBit)", dataSize=8 + and t1, t1, t7, dataSize=8 + + # RFLAGS.IF cleared if interrupt gate + limm t7, "(1L<<42) | (1L<<41) | (1L<<40)", dataSize=8 + limm t9, "(1L<<42) | (1L<<41)", dataSize=8 + and t7, t7, t2, dataSize=8 + xor t0, t7, t9, dataSize=8, flags=(EZF,) + br rom_local_label("InterruptGateFallThrough"), flags=(nCEZF,) + + limm t7, "~IFBit", dataSize=8 + and t1, t1, t7, dataSize=8 + + InterruptGateFallThrough: + + wrflags t1, t0 + + #RIP = temp_RIP + wrip t0, t4, dataSize=ssz + + eret +}; + def macroop IRET_VIRT { panic "Virtual mode iret isn't implemented!" };