syscalls: introduce dispatcher class
[openpower-isa.git] / src / openpower / syscalls / __init__.py
1 import ctypes
2 import functools
3 import inspect
4 import json
5 import pathlib
6
7
8 class Dispatcher:
9 def __init__(self, guest, host, logger=None, table=None):
10 if table is None:
11 path = pathlib.Path(inspect.getfile(self.__class__))
12 path = (path.parent / "syscalls.json")
13 with open(path, "r", encoding="UTF-8") as stream:
14 table = json.load(stream)
15 if not isinstance(table, dict):
16 raise ValueError("dict instance expected")
17 if "sysnums" not in table or "sysargs" not in table:
18 raise ValueError("sysnums and sysargs keys expected")
19
20 if logger is None:
21 logger = lambda *args, **kwargs: None
22
23 def i386(sysnums):
24 yield from sysnums["x86-32"]["i386"].items()
25
26 def amd64(sysnums):
27 yield from sysnums["x86-64"]["common"].items()
28 yield from sysnums["x86-64"]["64"].items()
29
30 def ppc(sysnums):
31 yield from sysnums["ppc"]["nospu"].items()
32 yield from sysnums["ppc"]["common"].items()
33 yield from sysnums["ppc"]["32"].items()
34
35 def ppc64(sysnums):
36 yield from sysnums["ppc"]["nospu"].items()
37 yield from sysnums["ppc"]["common"].items()
38 yield from sysnums["ppc"]["64"].items()
39
40 arch = {
41 "i386": i386,
42 "amd64": amd64,
43 "ppc": ppc,
44 "ppc64": ppc64,
45 }
46 sysnums = table["sysnums"]
47 sysargs = table["sysargs"]
48
49 self.__guest = dict(arch[guest](sysnums))
50 self.__host = dict(arch[host](sysnums))
51 self.__parameters = sysargs
52 self.__logger = logger
53 self.__libc = ctypes.CDLL(None)
54
55 return super().__init__()
56
57 def __getattr__(self, identifier):
58 return functools.partial(self.__call__, identifier=identifier)
59
60 def __call__(self, *arguments, identifier=None):
61 if isinstance(identifier, int):
62 identifier = str(identifier)
63 if identifier not in self.__guest:
64 raise KeyError(identifier)
65 entry = self.__guest[identifier][1][0]
66 identifier = self.__guest[identifier][0]
67 else:
68 if not isinstance(identifier, str):
69 raise ValueError(identifier)
70 entry = identifier
71 if not entry.startswith(("compat_sys_", "sys_")):
72 entry = f"sys_{entry}"
73
74 if ((identifier not in self.__guest) or
75 (identifier not in self.__host)):
76 raise KeyError(identifier)
77
78 parameters = tuple(self.__parameters[entry].items())
79 if len(arguments) != len(parameters):
80 raise ValueError("conflict between arguments and parameters")
81
82 guest = int(self.__guest[identifier])
83 host = int(self.__host[identifier])
84 self.__logger(f"{identifier} {guest} => {host}")
85 for index in range(len(arguments)):
86 value = arguments[index]
87 if not isinstance(value, int):
88 raise ValueError("integer argument expected")
89 name = parameters[index][0]
90 ctype = parameters[index][1]
91 self.__logger(f" 0x{value:016x} {name} ({ctype})")
92
93 syscall = self.__libc.syscall
94 syscall.restype = ctypes.c_long
95 syscall.argtypes = ([ctypes.c_long] * len(arguments))
96
97 return int(syscall(ctypes.c_ulong(host)))