From d73ce0f593fc9b1dfd482fd6b1b907af7918953d Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Mon, 17 Jan 2022 00:27:23 -0800 Subject: [PATCH] arch-x86: Implement real mode far call. Change-Id: I720a0b0e4aa227171c59804d899baba64b8d320b Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/55623 Reviewed-by: Gabe Black Maintainer: Gabe Black Tested-by: kokoro --- src/arch/x86/isa/decoder/one_byte_opcodes.isa | 6 +- .../general_purpose/control_transfer/call.py | 71 +++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/arch/x86/isa/decoder/one_byte_opcodes.isa b/src/arch/x86/isa/decoder/one_byte_opcodes.isa index e36962154f..64e10bac5e 100644 --- a/src/arch/x86/isa/decoder/one_byte_opcodes.isa +++ b/src/arch/x86/isa/decoder/one_byte_opcodes.isa @@ -305,6 +305,7 @@ 0x1: CQO(rAv,rDv); 0x2: decode MODE_SUBMODE { 0x0: UD2(); + 0x4: CALL_FAR_REAL(Iz); default: WarnUnimpl::call_far_Ap(); } 0x3: WarnUnimpl::fwait(); //aka wait @@ -568,7 +569,10 @@ 0x0: INC(Ev); 0x1: DEC(Ev); 0x2: CALL_NEAR(Ev); - 0x3: WarnUnimpl::call_far_Mp(); + 0x3: decode MODE_SUBMODE { + 0x4: CALL_FAR_REAL(Mz); + default: WarnUnimpl::call_far_Mp(); + } 0x4: JMP(Ev); 0x5: decode MODE_SUBMODE { 0x0: JMP_FAR(Mz); diff --git a/src/arch/x86/isa/insts/general_purpose/control_transfer/call.py b/src/arch/x86/isa/insts/general_purpose/control_transfer/call.py index 8000bc3e2a..8d11256f51 100644 --- a/src/arch/x86/isa/insts/general_purpose/control_transfer/call.py +++ b/src/arch/x86/isa/insts/general_purpose/control_transfer/call.py @@ -92,6 +92,77 @@ def macroop CALL_NEAR_P subi rsp, rsp, dsz, dataSize=ssz wripi t1, 0 }; + +def macroop CALL_FAR_REAL_I { + .function_call + .control_indirect + + limm t1, imm, dataSize=8 + + # Multiply the data size by 8 to get the size of the offset in bits. + limm t3, dsz, dataSize=8 + slli t3, t3, 3, dataSize=8 + + # Extract the selector from the far pointer. + srl t2, t1, t3, dataSize=8 + zexti t2, t2, 15, dataSize=8 + # Extract the offset from the far pointer. + zext t1, t1, t3, dataSize=8 + + # Compute the base. + slli t3, t2, 4, dataSize=8 + + # Make sure pushing the RIP will work after we push cs. + cda ss, [1, t0, rsp], "-env.dataSize * 2", addressSize=ssz + + # Push CS. + rdsel t4, cs, dataSize=8 + st t4, ss, [1, t0, rsp], "-env.dataSize", addressSize=ssz + # Push RIP. + rdip t7 + st t7, ss, [1, t0, rsp], "-env.dataSize * 2", addressSize=ssz + subi rsp, rsp, "env.dataSize * 2", dataSize=ssz + + # Install the new selector, base and RIP values. + wrsel cs, t2, dataSize=2 + wrbase cs, t3, dataSize=8 + wrip t1, t0 +}; + +def macroop CALL_FAR_REAL_M { + .function_call + .control_indirect + + lea t1, seg, sib, disp, dataSize=asz + # Load the selector. + ld t2, seg, [1, t0, t1], dsz, dataSize=2 + # Load the offset. + ld t1, seg, [1, t0, t1] + + # Compute the base. + zexti t3, t2, 15, dataSize=8 + slli t3, t3, 4, dataSize=8 + + # Make sure pushing the RIP will work after we push cs. + cda ss, [1, t0, rsp], "-env.dataSize * 2", addressSize=ssz + + # Push CS. + rdsel t4, cs, dataSize=8 + st t4, ss, [1, t0, rsp], "-env.dataSize", addressSize=ssz + # Push RIP. + rdip t7 + st t7, ss, [1, t0, rsp], "-env.dataSize * 2", addressSize=ssz + subi rsp, rsp, "env.dataSize * 2", dataSize=ssz + + # Install the new selector, base and RIP values. + wrsel cs, t2, dataSize=2 + wrbase cs, t3, dataSize=8 + wrip t1, t0 +}; + +def macroop CALL_FAR_REAL_P { + panic "Far call in real mode doesn't support RIP addressing." +}; ''' #let {{ # class CALL(Inst):