Gabe Black has uploaded this change for review. (
https://gem5-review.googlesource.com/c/public/gem5/+/57197 )
Change subject: arch-x86: Implement a portion of protected mode far call.
......................................................................
arch-x86: Implement a portion of protected mode far call.
This does not implement calling through a task gate or an available TSS,
nor does it implement a far call in long mode. It also only implements
the version of the far call instruction which has its far pointer in an
immediate value.
It would be fairly straightforward to implement the version which gets
its operand from memory, but that isn't exercised by my test program and
is legal in long mode which this implementation wouldn't yet support.
Change-Id: If1e50c97094e8210fb8fd7f55a20d959f91976e6
---
M src/arch/x86/isa/decoder/one_byte_opcodes.isa
M src/arch/x86/microcode/general_purpose/control_transfer/call.ucode
M src/arch/x86/ucasmlib/arch/x86/microops/regop.py
3 files changed, 163 insertions(+), 4 deletions(-)
diff --git a/src/arch/x86/isa/decoder/one_byte_opcodes.isa
b/src/arch/x86/isa/decoder/one_byte_opcodes.isa
index 6dc9311..6254bb6 100644
--- a/src/arch/x86/isa/decoder/one_byte_opcodes.isa
+++ b/src/arch/x86/isa/decoder/one_byte_opcodes.isa
@@ -323,7 +323,7 @@
0x2: decode MODE_SUBMODE {
0x0: UD2();
0x3, 0x4: CALL_FAR_REAL(Iz);
- default: WarnUnimpl::call_far_Ap();
+ default: CALL_FAR(Iz);
}
0x3: WarnUnimpl::fwait(); //aka wait
0x4: decode MODE_SUBMODE {
diff --git
a/src/arch/x86/microcode/general_purpose/control_transfer/call.ucode
b/src/arch/x86/microcode/general_purpose/control_transfer/call.ucode
index e25a82c..268dde2 100644
--- a/src/arch/x86/microcode/general_purpose/control_transfer/call.ucode
+++ b/src/arch/x86/microcode/general_purpose/control_transfer/call.ucode
@@ -33,6 +33,8 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+include "macros/segmentation.ucode"
+
def macroop CALL_NEAR
{
.args 'I'
@@ -96,6 +98,144 @@
wripi t1, 0
};
+def macroop CALL_FAR
+{
+ .args 'I'
+ .function_call
+ .control_indirect
+
+ limm t8, imm, dataSize=8
+
+ # Multiply the data size by 8 to get the size of the offset in bits.
+ limm t9, dsz, dataSize=8
+ slli t9, t9, 3, dataSize=8
+
+ # Extract the offset from the far pointer.
+ zext t2, t8, t9, dataSize=8
+ # Extract the selector from the far pointer.
+ srl t8, t8, t9, dataSize=8
+ zexti t3, t8, 15, dataSize=8
+
+ br RomLabel("callFarWork")
+};
+
+def rom
+{
+extern callFarWork:
+ rdip t7
+
+ m_read_descriptor desc="t1", selector="t3"
+
+ # Check the "S" bit to determine whether this is a user or system
segment.
+ srli t0, t1, 13, flags=(ECF,), dataSize=8
+
+ br "call_far_handle_system_segment", flags=(nCECF,)
+
+ rdsel t8, cs, dataSize=8
+ st t8, ss, [1, t0, rsp], "-env.dataSize", addressSize=ssz
+ st t7, ss, [1, t0, rsp], "-(2 * env.dataSize)", addressSize=ssz
+
+ chks t3, t3, t1, CSCheck, dataSize=8
+ wrdl cs, t1, t3
+ wrsel cs, t3
+ wrip t0, t2
+
+ subi rsp, rsp, "2 * env.dataSize", dataSize=ssz
+
+ eret
+
+call_far_handle_system_segment:
+
+ # Extract the type field from the descriptor.
+ srli t8, t1, 40, dataSize=8
+
+ # Check if it's a task gate.
+ xori t0, t8, 0x5, dataSize=8, flags=(EZF,)
+ panic "Far call to task gate not implemented", flags=(CEZF,)
+
+ # Check if it's an available TSS.
+ andi t9, t8, 0x7, dataSize=8
+ xori t0, t9, 0x1, dataSize=8, flags=(EZF,)
+ panic "Far call to TSS not implemented", flags=(CEZF,)
+
+ # At this point, it's either a call gate, or there should be a fault.
+ chks t3, t3, t1, CallGateCheck, dataSize=8
+
+ # Put the paramater count in t15.
+ srli t15, t1, 16, dataSize=8
+
+ bsr RomLabel("legacyModeProcessGate")
+
+ # Do we not need to worry about params at all?
+ br "call_far_push_return_info", flags=(CEZF,)
+
+ # We might need to copy params. What is the operand size?
+ br "call_far_dsz_is_4", flags=(CECF,)
+
+ # Mask the params count, and see if it's zero.
+ andi t15, t15, 0x1f, dataSize=8, flags=(EZF,)
+ br "call_far_done_with_params_dsz_2", flags=(CEZF,)
+
+ # Copy all the params.
+call_far_params_loop_dsz_2:
+ subi t5, t5, 2, dataSize=ssz
+ subi t15, t15, 1, dataSize=8, flags=(EZF,)
+ ld t9, ss, [2, t15, rsp], 0, dataSize=2, addressSize=ssz
+ st t9, hs, [1, t0, t5], 0, dataSize=2, addressSize=ssz
+ br "call_far_params_loop_dsz_2", flags=(nCEZF,)
+
+call_far_done_with_params_dsz_2:
+ # Set EZF again so it will show that there was a privilege change.
+ andi t0, t0, 0, flags=(EZF,)
+ br "call_far_push_return_info_dsz_4"
+
+call_far_dsz_is_4:
+
+ # Mask the params count, and see if it's zero.
+ andi t15, t15, 0x1f, dataSize=8, flags=(EZF,)
+ br "call_far_done_with_params_dsz_4", flags=(CEZF,)
+
+ # Copy all the params.
+call_far_params_loop_dsz_4:
+ subi t5, t5, 4, dataSize=ssz
+ subi t15, t15, 1, dataSize=8, flags=(EZF,)
+ ld t9, ss, [4, t15, rsp], 0, dataSize=4, addressSize=ssz
+ st t9, hs, [1, t0, t5], 0, dataSize=4, addressSize=ssz
+ br "call_far_params_loop_dsz_4", flags=(nCEZF,)
+
+call_far_done_with_params_dsz_4:
+ # Set EZF again so it will show that there was a privilege change.
+ andi t0, t0, 0, flags=(EZF,)
+ br "call_far_push_return_info_dsz_4"
+
+ # We didn't have to copy params, but we still have to set the return
info.
+call_far_push_return_info:
+ br "call_far_push_return_info_dsz_4", flags=(CECF,)
+
+call_far_push_return_info_dsz_2:
+ st t3, hs, [1, t0, t5], -2, dataSize=2, addressSize=ssz
+ st t7, hs, [1, t0, t5], -4, dataSize=2, addressSize=ssz
+ subi t5, t5, 4, dataSize=ssz
+
+call_far_push_return_info_dsz_4:
+ st t3, hs, [1, t0, t5], -4, dataSize=4, addressSize=ssz
+ st t7, hs, [1, t0, t5], -8, dataSize=4, addressSize=ssz
+ subi t5, t5, 8, dataSize=ssz
+
+ # Did we change privilege?
+ br "call_far_update_ESP", flags=(nCEZF,)
+
+ # Yes, so we need to update ss.
+ m_copy_seg_info dest="ss", source="hs", temp_reg="t8"
+
+call_far_update_ESP:
+ mov rsp, rsp, t5
+
+ wrip t0, t2, dataSize=8
+
+ eret
+};
+
def macroop CALL_FAR_REAL
{
.args 'I'
diff --git a/src/arch/x86/ucasmlib/arch/x86/microops/regop.py
b/src/arch/x86/ucasmlib/arch/x86/microops/regop.py
index 52c9ddf..7b6225e 100644
--- a/src/arch/x86/ucasmlib/arch/x86/microops/regop.py
+++ b/src/arch/x86/ucasmlib/arch/x86/microops/regop.py
@@ -1260,9 +1260,10 @@
}
break;
case SegCallGateCheck:
- fault = std::make_shared<GenericISA::M5PanicFault>(
- "CS checks for far "
- "calls/jumps through call gates not implemented.\\n");
+ if (desc.s != 0 || (desc.type & mask(3)) != 0x4 ||
+ desc.dpl < m5reg.cpl || desc.dpl < selector.rpl) {
+ fault = std::make_shared<GeneralProtection>(selector);
+ }
break;
case SegSoftIntGateCheck:
// Check permissions.
--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/57197
To unsubscribe, or for help writing mail filters, visit
https://gem5-review.googlesource.com/settings
Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: If1e50c97094e8210fb8fd7f55a20d959f91976e6
Gerrit-Change-Number: 57197
Gerrit-PatchSet: 1
Gerrit-Owner: Gabe Black <gabe.bl...@gmail.com>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list -- gem5-dev@gem5.org
To unsubscribe send an email to gem5-dev-le...@gem5.org
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s