68bef552b7e3eb1163cbf2f50469b993160bd6f6
[openpower-isa.git] / src / openpower / syscalls / __init__.py
1 import ctypes
2 import inspect
3 import json
4 import pathlib
5
6
7 class Syscall:
8 def __init__(self, entry, guest, host, parameters):
9 if not isinstance(entry, str):
10 raise ValueError(entry)
11 if not isinstance(guest, int):
12 raise ValueError(guest)
13 if not isinstance(parameters, tuple):
14 raise ValueError(parameters)
15
16 self.__entry = entry
17 self.__guest = guest
18 self.__host = host
19 self.__parameters = parameters
20
21 return super().__init__()
22
23 @property
24 def entry(self):
25 return self.__entry
26
27 @property
28 def guest(self):
29 return self.__guest
30
31 @property
32 def host(self):
33 return self.__host
34
35 def __repr__(self):
36 return f"{self.__class__.__name__}({self.entry} {self.guest}=>{self.host})"
37
38 def __call__(self, *arguments):
39 if len(arguments) != len(self.__parameters):
40 raise ValueError("conflict between arguments and parameters")
41
42 for index in range(len(arguments)):
43 value = arguments[index]
44 if not isinstance(value, int):
45 raise ValueError("integer argument expected")
46
47 libc = ctypes.CDLL(None)
48 syscall = libc.syscall
49 restype = syscall.restype
50 argtypes = syscall.argtypes
51 syscall.restype = ctypes.c_long
52 syscall.argtypes = ([ctypes.c_long] * len(arguments))
53 res = int(syscall(ctypes.c_ulong(self.host), *map(ctypes.c_ulong, arguments)))
54 syscall.restype = restype
55 syscall.argtypes = argtypes
56 return res
57
58
59 class UnimplementedSyscall(Syscall):
60 def __init__(self, guest):
61 return super().__init__(entry="sys_ni_syscall", guest=guest, host=-1, parameters=tuple())
62
63
64 class UnknownSyscall(Syscall):
65 def __init__(self, entry, guest):
66 return super().__init__(entry=entry, guest=guest, host=-1, parameters=tuple())
67
68 def __call__(self, *arguments):
69 raise NotImplemented
70
71
72 class Dispatcher:
73 def __init__(self, guest, host, logger=None, table=None):
74 if table is None:
75 path = (pathlib.Path(__file__).parent / "syscalls.json")
76 with open(path, "r", encoding="UTF-8") as stream:
77 table = json.load(stream)
78 if not isinstance(table, dict):
79 raise ValueError("dict instance expected")
80 if "sysnums" not in table or "sysargs" not in table:
81 raise ValueError("sysnums and sysargs keys expected")
82
83 if logger is None:
84 logger = lambda *args, **kwargs: None
85
86 def i386(sysnums):
87 yield from sysnums["x86-32"]["i386"].items()
88
89 def amd64(sysnums):
90 yield from sysnums["x86-64"]["common"].items()
91 yield from sysnums["x86-64"]["64"].items()
92
93 def ppc(sysnums):
94 yield from sysnums["ppc"]["nospu"].items()
95 yield from sysnums["ppc"]["common"].items()
96 yield from sysnums["ppc"]["32"].items()
97
98 def ppc64(sysnums):
99 yield from sysnums["ppc"]["nospu"].items()
100 yield from sysnums["ppc"]["common"].items()
101 yield from sysnums["ppc"]["64"].items()
102
103 def riscv32(sysnums):
104 yield from sysnums["generic"]["arch32"].items()
105
106 def riscv64(sysnums):
107 yield from sysnums["generic"]["arch64"].items()
108
109 arch = {
110 "i386": i386,
111 "amd64": amd64,
112 "ppc": ppc,
113 "ppc64": ppc64,
114 "riscv32": riscv32,
115 "riscv64": riscv64,
116 }
117 sysnums = table["sysnums"]
118 sysargs = table["sysargs"]
119
120 self.__guest = dict(arch[guest](sysnums))
121 self.__host = dict(arch[host](sysnums))
122 self.__parameters = sysargs
123 self.__logger = logger
124 self.__libc = ctypes.CDLL(None)
125
126 return super().__init__()
127
128 def __iter__(self):
129 identifiers = sorted(map(int, filter(str.isnumeric, self.__guest)))
130 for identifier in identifiers:
131 entry = self.__guest[str(identifier)][1][0]
132 name = self.__guest[str(identifier)][0]
133 syscall = getattr(self, entry, None)
134 if syscall is None:
135 if entry == "sys_ni_syscall":
136 syscall = UnimplementedSyscall(guest=identifier)
137 else:
138 syscall = UnknownSyscall(entry=entry, guest=identifier)
139 yield syscall
140
141 def __getitem__(self, identifier):
142 if not isinstance(identifier, int):
143 raise ValueError(identifier)
144
145 identifier = str(identifier)
146 entry = self.__guest[identifier][1][0]
147
148 return getattr(self, entry)
149
150 def __getattr__(self, entry):
151 if entry.startswith("compat_sys_"):
152 identifier = entry[len("compat_sys_"):]
153 elif entry.startswith("sys_"):
154 identifier = entry[len("sys_"):]
155 else:
156 raise AttributeError(entry)
157
158 if entry not in self.__parameters:
159 raise AttributeError(entry)
160
161 if identifier not in self.__guest:
162 raise AttributeError(entry)
163
164 if identifier not in self.__host:
165 raise AttributeError(entry)
166
167 guest = int(self.__guest[identifier])
168 host = int(self.__host[identifier])
169 parameters = tuple(self.__parameters[entry].items())
170
171 return Syscall(entry=entry, guest=guest, host=host, parameters=parameters)
172
173 def __call__(self, identifier, *arguments):
174 syscall = self[identifier]
175
176 return syscall(*arguments)