caller.py: implement a pile of syscalls
authorJacob Lifshay <programmerjake@gmail.com>
Sun, 3 Dec 2023 08:49:08 +0000 (00:49 -0800)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Wed, 13 Dec 2023 09:34:40 +0000 (09:34 +0000)
this implements read, mmap, mmap2, brk, openat, uname, and newuname.

it also stubs out munmap, mprotect, and pkey_mprotect so programs
don't crash cpython.

src/openpower/decoder/isa/caller.py
src/openpower/decoder/isa/mem.py

index 8bbd7bb195fc7f0b66b4bb9d296e56454f3496db..2cf113e56ad2463ad91bd472a26e28094d8a41d6 100644 (file)
@@ -17,6 +17,9 @@ from collections import namedtuple
 from copy import deepcopy
 from functools import wraps
 import os
+import errno
+import struct
+from openpower.syscalls import ppc_flags
 import sys
 from elftools.elf.elffile import ELFFile  # for isinstance
 
@@ -1183,6 +1186,80 @@ class SyscallEmulator(openpower.syscalls.Dispatcher):
         except OSError as e:
             return -e.errno
 
+    def sys_read(self, fd, buf, count, *rest):
+        buf = self.__isacaller.mem.get_ctypes(buf, count, is_write=True)
+        try:
+            return os.readv(fd, [buf])
+        except OSError as e:
+            return -e.errno
+
+    def sys_mmap(self, addr, length, prot, flags, fd, offset, *rest):
+        return self.__isacaller.mem.mmap_syscall(
+            addr, length, prot, flags, fd, offset, is_mmap2=False)
+
+    def sys_mmap2(self, addr, length, prot, flags, fd, offset, *rest):
+        return self.__isacaller.mem.mmap_syscall(
+            addr, length, prot, flags, fd, offset, is_mmap2=True)
+
+    def sys_brk(self, addr, *rest):
+        return self.__isacaller.mem.brk_syscall(addr)
+
+    def sys_munmap(self, addr, length, *rest):
+        return -errno.ENOSYS  # TODO: implement
+
+    def sys_mprotect(self, addr, length, prot, *rest):
+        return -errno.ENOSYS  # TODO: implement
+
+    def sys_pkey_mprotect(self, addr, length, prot, pkey, *rest):
+        return -errno.ENOSYS  # TODO: implement
+
+    def sys_openat(self, dirfd, pathname, flags, mode, *rest):
+        try:
+            path = self.__isacaller.mem.read_cstr(pathname)
+        except (ValueError, MemException):
+            return -errno.EFAULT
+        try:
+            if dirfd == ppc_flags.AT_FDCWD:
+                return os.open(path, flags, mode)
+            else:
+                return os.open(path, flags, mode, dir_fd=dirfd)
+        except OSError as e:
+            return -e.errno
+
+    def _uname(self):
+        uname = os.uname()
+        sysname = b'Linux'
+        nodename = uname.nodename.encode()
+        release = b'5.6.0-1-powerpc64le'
+        version = b'#1 SMP Debian 5.6.7-1 (2020-04-29)'
+        machine = b'ppc64le'
+        domainname = b''
+        return sysname, nodename, release, version, machine, domainname
+
+    def sys_uname(self, buf, *rest):
+        s = struct.Struct("<65s65s65s65s65s")
+        try:
+            buf = self.__isacaller.mem.get_ctypes(buf, s.size, is_write=True)
+        except (ValueError, MemException):
+            return -errno.EFAULT
+        sysname, nodename, release, version, machine, domainname = \
+            self._uname()
+        s.pack_into(buf, 0, sysname, nodename, release, version, machine)
+        return 0
+
+    def sys_newuname(self, buf, *rest):
+        name_len = ppc_flags.__NEW_UTS_LEN + 1
+        s = struct.Struct("<%ds%ds%ds%ds%ds%ds" % ((name_len,) * 6))
+        try:
+            buf = self.__isacaller.mem.get_ctypes(buf, s.size, is_write=True)
+        except (ValueError, MemException):
+            return -errno.EFAULT
+        sysname, nodename, release, version, machine, domainname = \
+            self._uname()
+        s.pack_into(buf, 0,
+                    sysname, nodename, release, version, machine, domainname)
+        return 0
+
 
 class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
     # decoder2 - an instance of power_decoder2
index a2a84c53fc6a40a4272b8f94e02050a33499d97b..ddb3b886c9cb75e68d1d99665e1d995f73a6006d 100644 (file)
@@ -301,6 +301,23 @@ class MemCommon:
         lines = "\n".join(lines)
         log(f"\n{name}:\n{lines}\n", kind=kind)
 
+    def read_cstr(self, addr):
+        """ returns a `bytearray` for the c string starting at addr, the
+        returned `bytearray` doesn't contain the nul terminator.
+
+        modifying the returned `bytearray` doesn't modify bytes in `self`
+        -- it is a copy.
+        """
+        retval = bytearray()
+        while True:
+            b = self.ld(addr, width=1)
+            if b:
+                retval.append(b)
+                addr += 1
+            else:
+                break
+        return retval
+
 
 class Mem(MemCommon):
     def __init__(self, row_bytes=8, initial_mem=None, misaligned_ok=False):