Gabe Black has uploaded this change for review. ( https://gem5-review.googlesource.com/c/public/gem5/+/56326 )

Change subject: arch-x86: Implement legacy mode interrupts.
......................................................................

arch-x86: Implement legacy mode interrupts.

Change-Id: Ib20f1a45d67c610176101820451ea1662ce17507
---
M src/arch/x86/faults.cc
M src/arch/x86/isa/insts/romutil.py
2 files changed, 336 insertions(+), 6 deletions(-)



diff --git a/src/arch/x86/faults.cc b/src/arch/x86/faults.cc
index 6a567c7..65ec273 100644
--- a/src/arch/x86/faults.cc
+++ b/src/arch/x86/faults.cc
@@ -85,8 +85,7 @@
         if (m5reg.mode == LongMode) {
             entry = extern_label_longModeInterruptWithError;
         } else {
-            panic("Legacy mode interrupts with error codes "
-                    "aren't implemented.");
+            entry = extern_label_legacyModeInterruptWithError;
         }
         tc->setIntReg(INTREG_MICRO(15), errorCode);
     }
diff --git a/src/arch/x86/isa/insts/romutil.py b/src/arch/x86/isa/insts/romutil.py
index 847b9c4..6741a29 100644
--- a/src/arch/x86/isa/insts/romutil.py
+++ b/src/arch/x86/isa/insts/romutil.py
@@ -24,7 +24,7 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-intCodeTemplate = '''
+longIntCodeTemplate = '''
 def rom
 {
     # This vectors the CPU into an interrupt handler in long mode.
@@ -176,20 +176,324 @@
 };
 '''

+intCodeTemplate = '''
+def rom
+{
+    # This vectors the CPU into an interrupt handler in legacy mode.
+ # On entry, t1 is set to the vector of the interrupt and t7 is the current
+    # ip. We need that because rdip returns the next ip.
+    extern %(startLabel)s:
+
+    #
+    # Get the interrupt, trap, or task gate descriptor from the IDT
+    #
+
+    # Load the gate descriptor from the IDT
+    slli t4, t1, 3, dataSize=8
+    ld t4, idtr, [1, t0, t4], dataSize=8, addressSize=8, atCPL0=True
+
+    # Make sure the descriptor is a legal gate.
+    chks t1, t4, %(gateCheckType)s, dataSize=8
+
+    # Stick the target offset in t9.
+    wrdh t9, t4, t0, dataSize=8
+
+    # Check the gate type.
+    srli t2, t4, 40, dataSize=8
+    andi t2, t2, 0xf, dataSize=8
+    xori t2, t2, 0x5, flags=(EZF,), dataSize=8
+
+ panic "Protected mode interrupt through a task gate not implemented.", \
+            flags=(CEZF,)
+
+    #
+    # Get the target CS descriptor using the selector in the gate
+    # descriptor.
+    #
+    srli t10, t4, 16, dataSize=8
+    andi t5, t10, 0xF8, dataSize=8
+    andi t0, t10, 0x4, flags=(EZF,), dataSize=2
+    br rom_local_label("%(startLabel)s_globalCS"), flags=(CEZF,)
+    ld t3, tsl, [1, t0, t5], dataSize=8, addressSize=8, atCPL0=True
+    br rom_local_label("%(startLabel)s_processCS")
+%(startLabel)s_globalCS:
+    ld t3, tsg, [1, t0, t5], dataSize=8, addressSize=8, atCPL0=True
+%(startLabel)s_processCS:
+    andi t13, t10, 0xff, dataSize=8
+    chks t13, t3, IntCSCheck, dataSize=8
+    wrdl hs, t3, t13, dataSize=8
+
+    #
+    # Figure out stack stuff.
+    #
+
+    # Determine the operand size. ECF will be 1 if 32 bit, and 0 if 16 bit.
+    srli t0, t4, 44, flags=(ECF,), dataSize=8
+
+    rdsel t1, cs, dataSize=8
+
+    # Check if we're changing privelege level. At this point we can assume
+    # we're going to a DPL that's less than or equal to the CPL.
+    rdattr t10, cs, dataSize=8
+    andi t10, t10, 0x3, dataSize=8
+    rdattr t5, hs, dataSize=8
+    andi t5, t5, 0x3, dataSize=8
+    sub t0, t5, t10, flags=(EZF,), dataSize=8
+
+    # We shouldn't modify CS here, but we need to so we have the right
+    # permissions for the stack accesses further down.
+    wrsel cs, t13, dataSize=8
+    wrdl cs, t3, t13, dataSize=8
+
+    br rom_local_label("%(startLabel)s_noStackSwitch"), flags=(CEZF,)
+
+    # Get the new ESP from the TSS
+    ld t6, tr, [8, t10, t0], 4, dataSize=4, addressSize=8, atCPL0=True
+    # Get the new SS from the TSS
+    ld t8, tr, [8, t10, t0], 8, dataSize=2, addressSize=8, atCPL0=True
+
+    # Go get the stack segment descriptor
+    # Check for a null selector.
+    andi t0, t8, 0xFC, flags=(EZF,), dataSize=8
+    fault "std::make_shared<GeneralProtection>(0)", flags=(CEZF,)
+    # Extract the index.
+    andi t11, t8, 0xF8, dataSize=8
+    # Check if this is a global or local descriptor.
+    andi t0, t8, 0x4, flags=(EZF,), dataSize=2
+    br rom_local_label("%(startLabel)s_globalSS"), flags=(CEZF,)
+    ld t12, tsl, [1, t0, t11], dataSize=8, addressSize=8, atCPL0=True
+    br rom_local_label("%(startLabel)s_processSS")
+%(startLabel)s_globalSS:
+    ld t12, tsg, [1, t0, t11], dataSize=8, addressSize=8, atCPL0=True
+%(startLabel)s_processSS:
+    chks t8, t12, SSCheck, dataSize=8
+    wrdl hs, t12, t8, dataSize=8
+
+    # Find the size of stack addresses based on this new descriptor.
+    rdattr t14, hs, dataSize=8
+    andi t0, t14, 0x8, flags=(EZF,), dataSize=8
+
+    br rom_local_label("%(startLabel)s_sszIs4Switched"), flags=(nCEZF,)
+ br rom_local_label("%(startLabel)s_sszIs2DszIs4Switched"), flags=(CECF,)
+
+    # ssz = 2, dsz = 2
+
+    # Make sure the space on the stack is accessible.
+    cda hs, [1, t0, t6], -1, dataSize=1, addressSize=2
+    cda hs, [1, t0, t6], -10 - %(errorCodeSize)d / 2, \
+            dataSize=1, addressSize=2
+
+    # Point of no return.
+    rdsel t2, ss, dataSize=8
+    st t2, hs, [1, t0, t6], -2, dataSize=2, addressSize=2
+    st rsp, hs, [1, t0, t6], -4, dataSize=2, addressSize=2
+    rflags t10, dataSize=8
+    st t10, hs, [1, t0, t6], -6, dataSize=2, addressSize=2
+    st t1, hs, [1, t0, t6], -8, dataSize=2, addressSize=2
+    st t7, hs, [1, t0, t6], -10, dataSize=2, addressSize=2
+    mov rsp, rsp, t6, dataSize=4
+    subi rsp, rsp, 10 + %(errorCodeSize)d / 2, dataSize=2
+    wrdl ss, t12, t8, dataSize=8
+    wrsel ss, t8, dataSize=8
+    %(errorCodeCode)s, dataSize=2, addressSize=2
+
+    br rom_local_label("%(startLabel)s_doneWithStack")
+
+%(startLabel)s_sszIs2DszIs4Switched:
+
+    # ssz = 2, dsz = 4
+
+    # Make sure the space on the stack is accessible.
+    cda hs, [1, t0, t6], -1, dataSize=1, addressSize=2
+    cda hs, [1, t0, t6], -20 - %(errorCodeSize)d, \
+            dataSize=1, addressSize=2
+
+    # Point of no return.
+    rdsel t2, ss, dataSize=8
+    st t2, hs, [1, t0, t6], -4, dataSize=4, addressSize=2
+    st rsp, hs, [1, t0, t6], -8, dataSize=4, addressSize=2
+    rflags t10, dataSize=8
+    st t10, hs, [1, t0, t6], -12, dataSize=4, addressSize=2
+    st t1, hs, [1, t0, t6], -16, dataSize=4, addressSize=2
+    st t7, hs, [1, t0, t6], -20, dataSize=4, addressSize=2
+    mov rsp, rsp, t6, dataSize=4
+    subi rsp, rsp, 20 + %(errorCodeSize)d, dataSize=2
+    wrdl ss, t12, t8, dataSize=8
+    wrsel ss, t8, dataSize=8
+    %(errorCodeCode)s, dataSize=4, addressSize=2
+
+    br rom_local_label("%(startLabel)s_doneWithStack")
+
+%(startLabel)s_sszIs4Switched:
+ br rom_local_label("%(startLabel)s_sszIs4DszIs4Switched"), flags=(CECF,)
+
+    # ssz = 4, dsz = 2
+
+    # Make sure the space on the stack is accessible.
+    cda hs, [1, t0, t6], -1, dataSize=1, addressSize=4
+    cda hs, [1, t0, t6], -10 - %(errorCodeSize)d / 2, \
+            dataSize=1, addressSize=4
+
+    # Point of no return.
+    rdsel t2, ss, dataSize=8
+    st t2, hs, [1, t0, t6], -2, dataSize=2, addressSize=4
+    st rsp, hs, [1, t0, t6], -4, dataSize=2, addressSize=4
+    rflags t10, dataSize=8
+    st t10, hs, [1, t0, t6], -6, dataSize=2, addressSize=4
+    st t12, hs, [1, t0, t6], -8, dataSize=2, addressSize=4
+    st t7, hs, [1, t0, t6], -10, dataSize=2, addressSize=4
+    subi rsp, t6, 10 + %(errorCodeSize)d / 2, dataSize=4
+    wrdl ss, t12, t8, dataSize=8
+    wrsel ss, t8, dataSize=8
+    %(errorCodeCode)s, dataSize=2, addressSize=4
+
+    br rom_local_label("%(startLabel)s_doneWithStack")
+
+%(startLabel)s_sszIs4DszIs4Switched:
+
+    # ssz = 4, dsz = 4
+
+    # Make sure the space on the stack is accessible.
+    cda hs, [1, t0, t6], -1, dataSize=1, addressSize=4
+    cda hs, [1, t0, t6], -20 - %(errorCodeSize)d, \
+            dataSize=1, addressSize=4
+
+    # Point of no return.
+    rdsel t2, ss, dataSize=8
+    st t2, hs, [1, t0, t6], -4, dataSize=4, addressSize=4
+    st rsp, hs, [1, t0, t6], -8, dataSize=4, addressSize=4
+    rflags t10, dataSize=8
+    st t10, hs, [1, t0, t6], -12, dataSize=4, addressSize=4
+    st t1, hs, [1, t0, t6], -16, dataSize=4, addressSize=4
+    st t7, hs, [1, t0, t6], -20, dataSize=4, addressSize=4
+    subi rsp, t6, 20 + %(errorCodeSize)d, dataSize=4
+    wrdl ss, t12, t8, dataSize=8
+    wrsel ss, t8, dataSize=8
+    %(errorCodeCode)s, dataSize=2, addressSize=4
+
+    br rom_local_label("%(startLabel)s_doneWithStack")
+
+
+%(startLabel)s_noStackSwitch:
+
+    # Find the size of stack addresses based on the stack descriptor.
+    rdattr t14, ss, dataSize=8
+    andi t0, t14, 0x8, flags=(EZF,), dataSize=8
+
+    br rom_local_label("%(startLabel)s_sszIs4"), flags=(nCEZF,)
+    br rom_local_label("%(startLabel)s_sszIs2DszIs4"), flags=(CECF,)
+
+    # Make sure the space on the stack is accessible.
+    cda ss, [1, t0, rsp], -1, dataSize=1, addressSize=2
+    cda ss, [1, t0, rsp], -6 - %(errorCodeSize)d / 2, \
+            dataSize=1, addressSize=2
+
+    # Point of no return.
+    rflags t10, dataSize=8
+    st t10, ss, [1, t0, t6], -2, dataSize=2, addressSize=2
+    st t1, ss, [1, t0, t6], -4, dataSize=2, addressSize=2
+    st t7, ss, [1, t0, t6], -6, dataSize=2, addressSize=2
+    subi rsp, rsp, 6 + %(errorCodeSize)d / 2, dataSize=2
+    %(errorCodeCode)s, dataSize=2, addressSize=2
+
+    br rom_local_label("%(startLabel)s_doneWithStack")
+
+%(startLabel)s_sszIs2DszIs4:
+
+    # ssz = 2, dsz = 4
+
+    # Make sure the space on the stack is accessible.
+    cda ss, [1, t0, rsp], -1, dataSize=1, addressSize=2
+    cda ss, [1, t0, rsp], -12 - %(errorCodeSize)d, \
+            dataSize=1, addressSize=2
+
+    # Point of no return.
+    rflags t10, dataSize=8
+    st t10, ss, [1, t0, rsp], -4, dataSize=4, addressSize=2
+    st t1, ss, [1, t0, rsp], -8, dataSize=4, addressSize=2
+    st t7, ss, [1, t0, rsp], -12, dataSize=4, addressSize=2
+    subi rsp, rsp, 12 + %(errorCodeSize)d, dataSize=2
+    %(errorCodeCode)s, dataSize=4, addressSize=2
+
+    br rom_local_label("%(startLabel)s_doneWithStack")
+
+%(startLabel)s_sszIs4:
+    br rom_local_label("%(startLabel)s_sszIs4DszIs4"), flags=(CECF,)
+
+    # ssz = 4, dsz = 2
+
+    # Make sure the space on the stack is accessible.
+    cda ss, [1, t0, rsp], -1, dataSize=1, addressSize=4
+    cda ss, [1, t0, rsp], -6 - %(errorCodeSize)d / 2, \
+            dataSize=1, addressSize=4
+
+    # Point of no return.
+    rflags t10, dataSize=8
+    st t10, ss, [1, t0, rsp], -2, dataSize=2, addressSize=4
+    st t1, ss, [1, t0, rsp], -4, dataSize=2, addressSize=4
+    st t7, ss, [1, t0, rsp], -6, dataSize=2, addressSize=4
+    subi rsp, rsp, 6 + %(errorCodeSize)d / 2, dataSize=4
+    %(errorCodeCode)s, dataSize=2, addressSize=4
+
+    br rom_local_label("%(startLabel)s_doneWithStack")
+
+%(startLabel)s_sszIs4DszIs4:
+
+    # ssz = 4, dsz = 4
+
+    # Make sure the space on the stack is accessible.
+    cda ss, [1, t0, rsp], -1, dataSize=1, addressSize=4
+    cda ss, [1, t0, rsp], -12 - %(errorCodeSize)d, \
+            dataSize=1, addressSize=4
+
+    # Point of no return.
+    rflags t10, dataSize=8
+    st t10, ss, [1, t0, rsp], -4, dataSize=4, addressSize=4
+    st t1, ss, [1, t0, rsp], -8, dataSize=4, addressSize=4
+    st t7, ss, [1, t0, rsp], -12, dataSize=4, addressSize=4
+    subi rsp, rsp, 12 + %(errorCodeSize)d, dataSize=4
+    %(errorCodeCode)s, dataSize=4, addressSize=4
+
+    br rom_local_label("%(startLabel)s_doneWithStack")
+
+%(startLabel)s_doneWithStack:
+
+    wrip t0, t9, dataSize=8
+
+    # Set IF to the lowest bit of the original gate type.
+    # The type field of the original gate starts at bit 40.
+
+    # Set the TF, NT, RF, and VM bits. We'll flip them at the end.
+    limm t6, "(TFBit | NTBit | RFBit | VMBit)", dataSize=8
+    or t10, t10, t6, dataSize=8
+    srli t5, t4, 40, dataSize=8
+    srli t7, t10, 9, dataSize=8
+    xor t5, t7, t5, dataSize=8
+    andi t5, t5, 1, dataSize=8
+    slli t5, t5, 9, dataSize=8
+    or t6, t5, t6, dataSize=8
+
+    # Put the results into rflags
+    wrflags t6, t10
+
+    eret
+};
+'''
+
 microcode = \
-intCodeTemplate % {\
+longIntCodeTemplate % {\
     "startLabel" : "longModeInterrupt",
     "gateCheckType" : "IntGateCheck",
     "errorCodeSize" : 0,
     "errorCodeCode" : ""
 } + \
-intCodeTemplate % {\
+longIntCodeTemplate % {\
     "startLabel" : "longModeSoftInterrupt",
     "gateCheckType" : "SoftIntGateCheck",
     "errorCodeSize" : 0,
     "errorCodeCode" : ""
 } + \
-intCodeTemplate % {\
+longIntCodeTemplate % {\
     "startLabel" : "longModeInterruptWithError",
     "gateCheckType" : "IntGateCheck",
     "errorCodeSize" : 8,
@@ -197,6 +501,24 @@
     st t15, hs, [1, t0, t6], dataSize=8, addressSize=8
     '''
 } + \
+intCodeTemplate % {\
+    "startLabel" : "legacyModeInterrupt",
+    "gateCheckType" : "IntGateCheck",
+    "errorCodeSize" : 0,
+    "errorCodeCode" : "#"
+} + \
+intCodeTemplate % {\
+    "startLabel" : "legacyModeSoftInterrupt",
+    "gateCheckType" : "SoftIntGateCheck",
+    "errorCodeSize" : 0,
+    "errorCodeCode" : "#"
+} + \
+intCodeTemplate % {\
+    "startLabel" : "legacyModeInterruptWithError",
+    "gateCheckType" : "IntGateCheck",
+    "errorCodeSize" : 4,
+    "errorCodeCode" : 'st t15, ss, [1, t0, rsp]'
+} + \
 '''
 def rom
 {

--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/56326
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: Ib20f1a45d67c610176101820451ea1662ce17507
Gerrit-Change-Number: 56326
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

Reply via email to