X86: Implement the sysret instruction in long mode.
authorGabe Black <gblack@eecs.umich.edu>
Wed, 25 Feb 2009 18:17:54 +0000 (10:17 -0800)
committerGabe Black <gblack@eecs.umich.edu>
Wed, 25 Feb 2009 18:17:54 +0000 (10:17 -0800)
src/arch/x86/isa/decoder/two_byte_opcodes.isa
src/arch/x86/isa/insts/general_purpose/system_calls.py

index 887b5bb14313d3a4b17e2b491ea9957a5c09796b..fa49c55d3bebf684de4b9c92c5bc5cb91a00ebfb 100644 (file)
                 0x05: SyscallInst::syscall('xc->syscall(Rax)', IsSyscall);
 #endif
                 0x06: clts();
-                //sandpile.org says (AMD) after sysret, so I might want to check
-                //if that means amd64 or AMD machines
-                0x07: loadall_or_sysret();
+                0x07: decode MODE_SUBMODE {
+                    0x0: decode OPSIZE {
+                        // Return to 64 bit mode.
+                        0x8: Inst::SYSRET_TO_64();
+                        // Return to compatibility mode.
+                        default: Inst::SYSRET_TO_COMPAT();
+                    }
+                    default: Inst::SYSRET_NON_64();
+                }
             }
             0x01: decode OPCODE_OP_BOTTOM3 {
                 0x0: invd();
index bb08282d2ed565ac37244d249fa81cb38cb51461..67607d5f8cb2b6c6fd2404b2f30ad586f9d55bfb 100644 (file)
@@ -156,12 +156,80 @@ def macroop SYSCALL_LEGACY
 {
     panic "The syscall instruction isn't implemented in legacy mode."
 };
+
+def macroop SYSRET_TO_64
+{
+    # All 1s.
+    limm t1, "(uint64_t)(-1)"
+
+    rdval t3, star
+    srli t3, t3, 48, dataSize=8
+    ori t3, t3, 3, dataSize=1
+
+    # Set rflags to r11 with RF and VM cleared.
+    limm t4, "~(RFBit | VMBit)"
+    and t4, t4, r11, dataSize=8
+    wrflags t4, t0
+
+    # Set up CS.
+    addi t4, t3, 16, dataSize=8
+    wrsel cs, t4
+    wrbase cs, t0, dataSize=8
+    wrlimit cs, t1, dataSize=4
+    # Not writable, read/execute-able, not expandDown,
+    # dpl=3, defaultSize=0, long mode
+    limm t4, ((0 << 0) | (1 << 1) | (0 << 2) | \
+              (3 << 3) | (0 << 5) | (1 << 6))
+    wrattr cs, t4
+
+    # Only the selector is changed for SS.
+    addi t4, t3, 8, dataSize=8
+    wrsel ss, t4
+
+    # Set the RIP back.
+    wrip rcx, t0, dataSize=8
+};
+
+def macroop SYSRET_TO_COMPAT
+{
+    # All 1s.
+    limm t1, "(uint64_t)(-1)"
+
+    rdval t3, star
+    srli t3, t3, 48, dataSize=8
+    ori t3, t3, 3, dataSize=1
+
+    # Set rflags to r11 with RF and VM cleared.
+    limm t4, "~(RFBit | VMBit)"
+    and t4, t4, r11, dataSize=8
+    wrflags t4, t0
+
+    # Set up CS.
+    wrsel cs, t3
+    wrbase cs, t0, dataSize=8
+    wrlimit cs, t1, dataSize=4
+    # Not writable, read/execute-able, not expandDown,
+    # dpl=3, defaultSize=1, not long mode
+    limm t4, ((0 << 0) | (1 << 1) | (0 << 2) | \
+              (3 << 3) | (1 << 5) | (0 << 6))
+    wrattr cs, t4
+
+    # Only the selector is changed for SS.
+    addi t4, t3, 8, dataSize=8
+    wrsel ss, t4
+
+    # Set the RIP back.
+    wrip rcx, t0, dataSize=8
+};
+
+def macroop SYSRET_NON_64
+{
+    panic "The sysret instruction isn't implemented in legacy mode."
+};
 '''
 #let {{
 #    class SYSENTER(Inst):
 #       "GenFault ${new UnimpInstFault}"
 #    class SYSEXIT(Inst):
 #       "GenFault ${new UnimpInstFault}"
-#    class SYSRET(Inst):
-#       "GenFault ${new UnimpInstFault}"
 #}};