From e1633a53b9ff23a0852b900aa6dd4b4ce70fbafa Mon Sep 17 00:00:00 2001 From: Dmitry Selyutin Date: Mon, 18 Sep 2023 22:22:07 +0300 Subject: [PATCH] syscalls: introduce dispatcher class --- src/openpower/syscalls/__init__.py | 97 ++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/src/openpower/syscalls/__init__.py b/src/openpower/syscalls/__init__.py index e69de29b..28a05cc7 100644 --- a/src/openpower/syscalls/__init__.py +++ b/src/openpower/syscalls/__init__.py @@ -0,0 +1,97 @@ +import ctypes +import functools +import inspect +import json +import pathlib + + +class Dispatcher: + def __init__(self, guest, host, logger=None, table=None): + if table is None: + path = pathlib.Path(inspect.getfile(self.__class__)) + path = (path.parent / "syscalls.json") + with open(path, "r", encoding="UTF-8") as stream: + table = json.load(stream) + if not isinstance(table, dict): + raise ValueError("dict instance expected") + if "sysnums" not in table or "sysargs" not in table: + raise ValueError("sysnums and sysargs keys expected") + + if logger is None: + logger = lambda *args, **kwargs: None + + def i386(sysnums): + yield from sysnums["x86-32"]["i386"].items() + + def amd64(sysnums): + yield from sysnums["x86-64"]["common"].items() + yield from sysnums["x86-64"]["64"].items() + + def ppc(sysnums): + yield from sysnums["ppc"]["nospu"].items() + yield from sysnums["ppc"]["common"].items() + yield from sysnums["ppc"]["32"].items() + + def ppc64(sysnums): + yield from sysnums["ppc"]["nospu"].items() + yield from sysnums["ppc"]["common"].items() + yield from sysnums["ppc"]["64"].items() + + arch = { + "i386": i386, + "amd64": amd64, + "ppc": ppc, + "ppc64": ppc64, + } + sysnums = table["sysnums"] + sysargs = table["sysargs"] + + self.__guest = dict(arch[guest](sysnums)) + self.__host = dict(arch[host](sysnums)) + self.__parameters = sysargs + self.__logger = logger + self.__libc = ctypes.CDLL(None) + + return super().__init__() + + def __getattr__(self, identifier): + return functools.partial(self.__call__, identifier=identifier) + + def __call__(self, *arguments, identifier=None): + if isinstance(identifier, int): + identifier = str(identifier) + if identifier not in self.__guest: + raise KeyError(identifier) + entry = self.__guest[identifier][1][0] + identifier = self.__guest[identifier][0] + else: + if not isinstance(identifier, str): + raise ValueError(identifier) + entry = identifier + if not entry.startswith(("compat_sys_", "sys_")): + entry = f"sys_{entry}" + + if ((identifier not in self.__guest) or + (identifier not in self.__host)): + raise KeyError(identifier) + + parameters = tuple(self.__parameters[entry].items()) + if len(arguments) != len(parameters): + raise ValueError("conflict between arguments and parameters") + + guest = int(self.__guest[identifier]) + host = int(self.__host[identifier]) + self.__logger(f"{identifier} {guest} => {host}") + for index in range(len(arguments)): + value = arguments[index] + if not isinstance(value, int): + raise ValueError("integer argument expected") + name = parameters[index][0] + ctype = parameters[index][1] + self.__logger(f" 0x{value:016x} {name} ({ctype})") + + syscall = self.__libc.syscall + syscall.restype = ctypes.c_long + syscall.argtypes = ([ctypes.c_long] * len(arguments)) + + return int(syscall(ctypes.c_ulong(host))) -- 2.30.2