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