isa/caller: return from interrupt upon syscall emulation
authorDmitry Selyutin <ghostmansd@gmail.com>
Sun, 22 Oct 2023 06:29:50 +0000 (09:29 +0300)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Fri, 22 Dec 2023 19:26:21 +0000 (19:26 +0000)
src/openpower/decoder/isa/caller.py

index 84456c2680a504a5f71b5ed1c1d6ba8d01a03ab6..e4f06266c8edb7829875dadea12ff18d3ea59d39 100644 (file)
@@ -1940,7 +1940,7 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
         dec_insn = yield self.dec2.e.do.insn
         return dec_insn & (1 << 20) != 0  # sigh - XFF.spr[-1]?
 
-    def call(self, name):
+    def call(self, name, syscall_emu_active=False):
         """call(opcode) - the primary execution point for instructions
         """
         self.last_st_addr = None  # reset the last known store address
@@ -1988,6 +1988,35 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
             self.halted = True
             return
 
+        # User mode system call emulation consists of several steps:
+        # 1. Detect whether instruction is sc or scv.
+        # 2. Call the HDL implementation which invokes trap.
+        # 3. Reroute the guest system call to host system call.
+        # 4. Force return from the interrupt as if we had guest OS.
+        if ((asmop in ("sc", "scv")) and
+                (self.syscall is not None) and
+                not syscall_emu_active):
+            # Memoize PC and trigger an interrupt
+            if self.respect_pc:
+                pc = self.pc.CIA.value
+            else:
+                pc = self.fake_pc
+            yield from self.call(asmop, syscall_emu_active=True)
+
+            # Reroute the syscall to host OS
+            identifier = self.gpr(0)
+            arguments = map(self.gpr, range(3, 9))
+            result = self.syscall(identifier, *arguments)
+            self.gpr.write(3, result, False, self.namespace["XLEN"])
+
+            # Return from interrupt
+            backup = self.imem.ld(pc, 4, False, True, instr_fetch=True)
+            self.imem.st(pc, 0x4c000024, width=4, swap=True)
+            yield from self.call("rfid", syscall_emu_active=True)
+            self.imem.st(pc, backup, width=4, swap=True)
+        elif ((name in ("rfid", "hrfid")) and syscall_emu_active):
+            asmop = "rfid"
+
         # check illegal instruction
         illegal = False
         if ins_name not in ['mtcrf', 'mtocrf']:
@@ -2053,13 +2082,6 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
             self.update_pc_next()
             return
 
-        # Usermode system call emulation
-        if asmop in ("sc", "scv") and self.syscall is not None:
-            identifier = self.gpr(0)
-            arguments = map(self.gpr, range(3, 9))
-            result = self.syscall(identifier, *arguments)
-            self.gpr.write(3, result, False, self.namespace["XLEN"])
-
         # get elwidths, defaults to 64
         xlen = 64
         ew_src = 64