svc_generator.py 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716
  1. # SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
  2. # SPDX-License-Identifier: GPL-2.0-or-later
  3. # Raw SVC definitions from the kernel.
  4. #
  5. # Avoid modifying the prototypes; see below for how to customize generation
  6. # for a given typename.
  7. SVCS = [
  8. [0x01, "Result SetHeapSize(Address* out_address, Size size);"],
  9. [0x02, "Result SetMemoryPermission(Address address, Size size, MemoryPermission perm);"],
  10. [0x03, "Result SetMemoryAttribute(Address address, Size size, uint32_t mask, uint32_t attr);"],
  11. [0x04, "Result MapMemory(Address dst_address, Address src_address, Size size);"],
  12. [0x05, "Result UnmapMemory(Address dst_address, Address src_address, Size size);"],
  13. [0x06, "Result QueryMemory(Address out_memory_info, PageInfo* out_page_info, Address address);"],
  14. [0x07, "void ExitProcess();"],
  15. [0x08, "Result CreateThread(Handle* out_handle, ThreadFunc func, Address arg, Address stack_bottom, int32_t priority, int32_t core_id);"],
  16. [0x09, "Result StartThread(Handle thread_handle);"],
  17. [0x0A, "void ExitThread();"],
  18. [0x0B, "void SleepThread(int64_t ns);"],
  19. [0x0C, "Result GetThreadPriority(int32_t* out_priority, Handle thread_handle);"],
  20. [0x0D, "Result SetThreadPriority(Handle thread_handle, int32_t priority);"],
  21. [0x0E, "Result GetThreadCoreMask(int32_t* out_core_id, uint64_t* out_affinity_mask, Handle thread_handle);"],
  22. [0x0F, "Result SetThreadCoreMask(Handle thread_handle, int32_t core_id, uint64_t affinity_mask);"],
  23. [0x10, "int32_t GetCurrentProcessorNumber();"],
  24. [0x11, "Result SignalEvent(Handle event_handle);"],
  25. [0x12, "Result ClearEvent(Handle event_handle);"],
  26. [0x13, "Result MapSharedMemory(Handle shmem_handle, Address address, Size size, MemoryPermission map_perm);"],
  27. [0x14, "Result UnmapSharedMemory(Handle shmem_handle, Address address, Size size);"],
  28. [0x15, "Result CreateTransferMemory(Handle* out_handle, Address address, Size size, MemoryPermission map_perm);"],
  29. [0x16, "Result CloseHandle(Handle handle);"],
  30. [0x17, "Result ResetSignal(Handle handle);"],
  31. [0x18, "Result WaitSynchronization(int32_t* out_index, Address handles, int32_t num_handles, int64_t timeout_ns);"],
  32. [0x19, "Result CancelSynchronization(Handle handle);"],
  33. [0x1A, "Result ArbitrateLock(Handle thread_handle, Address address, uint32_t tag);"],
  34. [0x1B, "Result ArbitrateUnlock(Address address);"],
  35. [0x1C, "Result WaitProcessWideKeyAtomic(Address address, Address cv_key, uint32_t tag, int64_t timeout_ns);"],
  36. [0x1D, "void SignalProcessWideKey(Address cv_key, int32_t count);"],
  37. [0x1E, "int64_t GetSystemTick();"],
  38. [0x1F, "Result ConnectToNamedPort(Handle* out_handle, Address name);"],
  39. [0x20, "Result SendSyncRequestLight(Handle session_handle);"],
  40. [0x21, "Result SendSyncRequest(Handle session_handle);"],
  41. [0x22, "Result SendSyncRequestWithUserBuffer(Address message_buffer, Size message_buffer_size, Handle session_handle);"],
  42. [0x23, "Result SendAsyncRequestWithUserBuffer(Handle* out_event_handle, Address message_buffer, Size message_buffer_size, Handle session_handle);"],
  43. [0x24, "Result GetProcessId(uint64_t* out_process_id, Handle process_handle);"],
  44. [0x25, "Result GetThreadId(uint64_t* out_thread_id, Handle thread_handle);"],
  45. [0x26, "void Break(BreakReason break_reason, Address arg, Size size);"],
  46. [0x27, "Result OutputDebugString(Address debug_str, Size len);"],
  47. [0x28, "void ReturnFromException(Result result);"],
  48. [0x29, "Result GetInfo(uint64_t* out, InfoType info_type, Handle handle, uint64_t info_subtype);"],
  49. [0x2A, "void FlushEntireDataCache();"],
  50. [0x2B, "Result FlushDataCache(Address address, Size size);"],
  51. [0x2C, "Result MapPhysicalMemory(Address address, Size size);"],
  52. [0x2D, "Result UnmapPhysicalMemory(Address address, Size size);"],
  53. [0x2E, "Result GetDebugFutureThreadInfo(LastThreadContext* out_context, uint64_t* out_thread_id, Handle debug_handle, int64_t ns);"],
  54. [0x2F, "Result GetLastThreadInfo(LastThreadContext* out_context, Address* out_tls_address, uint32_t* out_flags);"],
  55. [0x30, "Result GetResourceLimitLimitValue(int64_t* out_limit_value, Handle resource_limit_handle, LimitableResource which);"],
  56. [0x31, "Result GetResourceLimitCurrentValue(int64_t* out_current_value, Handle resource_limit_handle, LimitableResource which);"],
  57. [0x32, "Result SetThreadActivity(Handle thread_handle, ThreadActivity thread_activity);"],
  58. [0x33, "Result GetThreadContext3(Address out_context, Handle thread_handle);"],
  59. [0x34, "Result WaitForAddress(Address address, ArbitrationType arb_type, int32_t value, int64_t timeout_ns);"],
  60. [0x35, "Result SignalToAddress(Address address, SignalType signal_type, int32_t value, int32_t count);"],
  61. [0x36, "void SynchronizePreemptionState();"],
  62. [0x37, "Result GetResourceLimitPeakValue(int64_t* out_peak_value, Handle resource_limit_handle, LimitableResource which);"],
  63. [0x39, "Result CreateIoPool(Handle* out_handle, IoPoolType which);"],
  64. [0x3A, "Result CreateIoRegion(Handle* out_handle, Handle io_pool, PhysicalAddress physical_address, Size size, MemoryMapping mapping, MemoryPermission perm);"],
  65. [0x3C, "void KernelDebug(KernelDebugType kern_debug_type, uint64_t arg0, uint64_t arg1, uint64_t arg2);"],
  66. [0x3D, "void ChangeKernelTraceState(KernelTraceState kern_trace_state);"],
  67. [0x40, "Result CreateSession(Handle* out_server_session_handle, Handle* out_client_session_handle, bool is_light, Address name);"],
  68. [0x41, "Result AcceptSession(Handle* out_handle, Handle port);"],
  69. [0x42, "Result ReplyAndReceiveLight(Handle handle);"],
  70. [0x43, "Result ReplyAndReceive(int32_t* out_index, Address handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns);"],
  71. [0x44, "Result ReplyAndReceiveWithUserBuffer(int32_t* out_index, Address message_buffer, Size message_buffer_size, Address handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns);"],
  72. [0x45, "Result CreateEvent(Handle* out_write_handle, Handle* out_read_handle);"],
  73. [0x46, "Result MapIoRegion(Handle io_region, Address address, Size size, MemoryPermission perm);"],
  74. [0x47, "Result UnmapIoRegion(Handle io_region, Address address, Size size);"],
  75. [0x48, "Result MapPhysicalMemoryUnsafe(Address address, Size size);"],
  76. [0x49, "Result UnmapPhysicalMemoryUnsafe(Address address, Size size);"],
  77. [0x4A, "Result SetUnsafeLimit(Size limit);"],
  78. [0x4B, "Result CreateCodeMemory(Handle* out_handle, Address address, Size size);"],
  79. [0x4C, "Result ControlCodeMemory(Handle code_memory_handle, CodeMemoryOperation operation, uint64_t address, uint64_t size, MemoryPermission perm);"],
  80. [0x4D, "void SleepSystem();"],
  81. [0x4E, "Result ReadWriteRegister(uint32_t* out_value, PhysicalAddress address, uint32_t mask, uint32_t value);"],
  82. [0x4F, "Result SetProcessActivity(Handle process_handle, ProcessActivity process_activity);"],
  83. [0x50, "Result CreateSharedMemory(Handle* out_handle, Size size, MemoryPermission owner_perm, MemoryPermission remote_perm);"],
  84. [0x51, "Result MapTransferMemory(Handle trmem_handle, Address address, Size size, MemoryPermission owner_perm);"],
  85. [0x52, "Result UnmapTransferMemory(Handle trmem_handle, Address address, Size size);"],
  86. [0x53, "Result CreateInterruptEvent(Handle* out_read_handle, int32_t interrupt_id, InterruptType interrupt_type);"],
  87. [0x54, "Result QueryPhysicalAddress(PhysicalMemoryInfo* out_info, Address address);"],
  88. [0x55, "Result QueryIoMapping(Address* out_address, Size* out_size, PhysicalAddress physical_address, Size size);"],
  89. [0x56, "Result CreateDeviceAddressSpace(Handle* out_handle, uint64_t das_address, uint64_t das_size);"],
  90. [0x57, "Result AttachDeviceAddressSpace(DeviceName device_name, Handle das_handle);"],
  91. [0x58, "Result DetachDeviceAddressSpace(DeviceName device_name, Handle das_handle);"],
  92. [0x59, "Result MapDeviceAddressSpaceByForce(Handle das_handle, Handle process_handle, uint64_t process_address, Size size, uint64_t device_address, uint32_t option);"],
  93. [0x5A, "Result MapDeviceAddressSpaceAligned(Handle das_handle, Handle process_handle, uint64_t process_address, Size size, uint64_t device_address, uint32_t option);"],
  94. [0x5C, "Result UnmapDeviceAddressSpace(Handle das_handle, Handle process_handle, uint64_t process_address, Size size, uint64_t device_address);"],
  95. [0x5D, "Result InvalidateProcessDataCache(Handle process_handle, uint64_t address, uint64_t size);"],
  96. [0x5E, "Result StoreProcessDataCache(Handle process_handle, uint64_t address, uint64_t size);"],
  97. [0x5F, "Result FlushProcessDataCache(Handle process_handle, uint64_t address, uint64_t size);"],
  98. [0x60, "Result DebugActiveProcess(Handle* out_handle, uint64_t process_id);"],
  99. [0x61, "Result BreakDebugProcess(Handle debug_handle);"],
  100. [0x62, "Result TerminateDebugProcess(Handle debug_handle);"],
  101. [0x63, "Result GetDebugEvent(Address out_info, Handle debug_handle);"],
  102. [0x64, "Result ContinueDebugEvent(Handle debug_handle, uint32_t flags, Address thread_ids, int32_t num_thread_ids);"],
  103. [0x65, "Result GetProcessList(int32_t* out_num_processes, Address out_process_ids, int32_t max_out_count);"],
  104. [0x66, "Result GetThreadList(int32_t* out_num_threads, Address out_thread_ids, int32_t max_out_count, Handle debug_handle);"],
  105. [0x67, "Result GetDebugThreadContext(Address out_context, Handle debug_handle, uint64_t thread_id, uint32_t context_flags);"],
  106. [0x68, "Result SetDebugThreadContext(Handle debug_handle, uint64_t thread_id, Address context, uint32_t context_flags);"],
  107. [0x69, "Result QueryDebugProcessMemory(Address out_memory_info, PageInfo* out_page_info, Handle process_handle, Address address);"],
  108. [0x6A, "Result ReadDebugProcessMemory(Address buffer, Handle debug_handle, Address address, Size size);"],
  109. [0x6B, "Result WriteDebugProcessMemory(Handle debug_handle, Address buffer, Address address, Size size);"],
  110. [0x6C, "Result SetHardwareBreakPoint(HardwareBreakPointRegisterName name, uint64_t flags, uint64_t value);"],
  111. [0x6D, "Result GetDebugThreadParam(uint64_t* out_64, uint32_t* out_32, Handle debug_handle, uint64_t thread_id, DebugThreadParam param);"],
  112. [0x6F, "Result GetSystemInfo(uint64_t* out, SystemInfoType info_type, Handle handle, uint64_t info_subtype);"],
  113. [0x70, "Result CreatePort(Handle* out_server_handle, Handle* out_client_handle, int32_t max_sessions, bool is_light, Address name);"],
  114. [0x71, "Result ManageNamedPort(Handle* out_server_handle, Address name, int32_t max_sessions);"],
  115. [0x72, "Result ConnectToPort(Handle* out_handle, Handle port);"],
  116. [0x73, "Result SetProcessMemoryPermission(Handle process_handle, uint64_t address, uint64_t size, MemoryPermission perm);"],
  117. [0x74, "Result MapProcessMemory(Address dst_address, Handle process_handle, uint64_t src_address, Size size);"],
  118. [0x75, "Result UnmapProcessMemory(Address dst_address, Handle process_handle, uint64_t src_address, Size size);"],
  119. [0x76, "Result QueryProcessMemory(Address out_memory_info, PageInfo* out_page_info, Handle process_handle, uint64_t address);"],
  120. [0x77, "Result MapProcessCodeMemory(Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size);"],
  121. [0x78, "Result UnmapProcessCodeMemory(Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size);"],
  122. [0x79, "Result CreateProcess(Handle* out_handle, Address parameters, Address caps, int32_t num_caps);"],
  123. [0x7A, "Result StartProcess(Handle process_handle, int32_t priority, int32_t core_id, uint64_t main_thread_stack_size);"],
  124. [0x7B, "Result TerminateProcess(Handle process_handle);"],
  125. [0x7C, "Result GetProcessInfo(int64_t* out_info, Handle process_handle, ProcessInfoType info_type);"],
  126. [0x7D, "Result CreateResourceLimit(Handle* out_handle);"],
  127. [0x7E, "Result SetResourceLimitLimitValue(Handle resource_limit_handle, LimitableResource which, int64_t limit_value);"],
  128. [0x7F, "void CallSecureMonitor(SecureMonitorArguments args);"],
  129. [0x90, "Result MapInsecureMemory(Address address, Size size);"],
  130. [0x91, "Result UnmapInsecureMemory(Address address, Size size);"],
  131. ]
  132. # These use a custom ABI, and therefore require custom wrappers
  133. SKIP_WRAPPERS = {
  134. 0x20: "SendSyncRequestLight",
  135. 0x42: "ReplyAndReceiveLight",
  136. 0x7F: "CallSecureMonitor",
  137. }
  138. BIT_32 = 0
  139. BIT_64 = 1
  140. REG_SIZES = [4, 8]
  141. SUFFIX_NAMES = ["64From32", "64"]
  142. TYPE_SIZES = {
  143. # SVC types
  144. "ArbitrationType": 4,
  145. "BreakReason": 4,
  146. "CodeMemoryOperation": 4,
  147. "DebugThreadParam": 4,
  148. "DeviceName": 4,
  149. "HardwareBreakPointRegisterName": 4,
  150. "Handle": 4,
  151. "InfoType": 4,
  152. "InterruptType": 4,
  153. "IoPoolType": 4,
  154. "KernelDebugType": 4,
  155. "KernelTraceState": 4,
  156. "LimitableResource": 4,
  157. "MemoryMapping": 4,
  158. "MemoryPermission": 4,
  159. "PageInfo": 4,
  160. "ProcessActivity": 4,
  161. "ProcessInfoType": 4,
  162. "Result": 4,
  163. "SignalType": 4,
  164. "SystemInfoType": 4,
  165. "ThreadActivity": 4,
  166. # Arch-specific types
  167. "ilp32::LastThreadContext": 16,
  168. "ilp32::PhysicalMemoryInfo": 16,
  169. "ilp32::SecureMonitorArguments": 32,
  170. "lp64::LastThreadContext": 32,
  171. "lp64::PhysicalMemoryInfo": 24,
  172. "lp64::SecureMonitorArguments": 64,
  173. # Generic types
  174. "bool": 1,
  175. "int32_t": 4,
  176. "int64_t": 8,
  177. "uint32_t": 4,
  178. "uint64_t": 8,
  179. "void": 0,
  180. }
  181. TYPE_REPLACEMENTS = {
  182. "Address": ["uint32_t", "uint64_t"],
  183. "LastThreadContext": ["ilp32::LastThreadContext", "lp64::LastThreadContext"],
  184. "PhysicalAddress": ["uint64_t", "uint64_t"],
  185. "PhysicalMemoryInfo": ["ilp32::PhysicalMemoryInfo", "lp64::PhysicalMemoryInfo"],
  186. "SecureMonitorArguments": ["ilp32::SecureMonitorArguments", "lp64::SecureMonitorArguments"],
  187. "Size": ["uint32_t", "uint64_t"],
  188. "ThreadFunc": ["uint32_t", "uint64_t"],
  189. }
  190. # Statically verify that the hardcoded sizes match the intended
  191. # sizes in C++.
  192. def emit_size_check():
  193. lines = []
  194. for type, size in TYPE_SIZES.items():
  195. if type != "void":
  196. lines.append(f"static_assert(sizeof({type}) == {size});")
  197. return "\n".join(lines)
  198. # Replaces a type with an arch-specific one, if it exists.
  199. def substitute_type(name, bitness):
  200. if name in TYPE_REPLACEMENTS:
  201. return TYPE_REPLACEMENTS[name][bitness]
  202. else:
  203. return name
  204. class Argument:
  205. def __init__(self, type_name, var_name, is_output, is_outptr, is_address):
  206. self.type_name = type_name
  207. self.var_name = var_name
  208. self.is_output = is_output
  209. self.is_outptr = is_outptr
  210. self.is_address = is_address
  211. # Parses C-style string declarations for SVCs.
  212. def parse_declaration(declaration, bitness):
  213. return_type, rest = declaration.split(" ", 1)
  214. func_name, rest = rest.split("(", 1)
  215. arg_names, rest = rest.split(")", 1)
  216. argument_types = []
  217. return_type = substitute_type(return_type, bitness)
  218. assert return_type in TYPE_SIZES, f"Unknown type '{return_type}'"
  219. if arg_names:
  220. for arg_name in arg_names.split(", "):
  221. type_name, var_name = arg_name.replace("*", "").split(" ", 1)
  222. # All outputs must contain out_ in the name.
  223. is_output = var_name == "out" or var_name.find("out_") != -1
  224. # User-pointer outputs are not written to registers.
  225. is_outptr = is_output and arg_name.find("*") == -1
  226. # Special handling is performed for output addresses to avoid awkwardness
  227. # in conversion for the 32-bit equivalents.
  228. is_address = is_output and not is_outptr and \
  229. type_name in ["Address", "Size"]
  230. type_name = substitute_type(type_name, bitness)
  231. assert type_name in TYPE_SIZES, f"Unknown type '{type_name}'"
  232. argument_types.append(
  233. Argument(type_name, var_name, is_output, is_outptr, is_address))
  234. return (return_type, func_name, argument_types)
  235. class RegisterAllocator:
  236. def __init__(self, num_regs, byte_size, parameter_count):
  237. self.registers = {}
  238. self.num_regs = num_regs
  239. self.byte_size = byte_size
  240. self.parameter_count = parameter_count
  241. # Mark the given register as allocated, for use in layout
  242. # calculation if the NGRN exceeds the ABI parameter count.
  243. def allocate(self, i):
  244. assert i not in self.registers, f"Register R{i} already allocated"
  245. self.registers[i] = True
  246. return i
  247. # Calculate the next available location for a register;
  248. # the NGRN has exceeded the ABI parameter count.
  249. def allocate_first_free(self):
  250. for i in range(0, self.num_regs):
  251. if i in self.registers:
  252. continue
  253. self.allocate(i)
  254. return i
  255. assert False, "No registers available"
  256. # Add a single register at the given NGRN.
  257. # If the index exceeds the ABI parameter count, try to find a
  258. # location to add it. Returns the output location and increment.
  259. def add_single(self, ngrn):
  260. if ngrn >= self.parameter_count:
  261. return (self.allocate_first_free(), 0)
  262. else:
  263. return (self.allocate(ngrn), 1)
  264. # Add registers at the given NGRN for a data type of
  265. # the given size. Returns the output locations and increment.
  266. def add(self, ngrn, data_size, align=True):
  267. if data_size <= self.byte_size:
  268. r, i = self.add_single(ngrn)
  269. return ([r], i)
  270. regs = []
  271. inc = ngrn % 2 if align else 0
  272. remaining_size = data_size
  273. while remaining_size > 0:
  274. r, i = self.add_single(ngrn + inc)
  275. regs.append(r)
  276. inc += i
  277. remaining_size -= self.byte_size
  278. return (regs, inc)
  279. def reg_alloc(bitness):
  280. if bitness == 0:
  281. # aapcs32: 4 4-byte registers
  282. return RegisterAllocator(8, 4, 4)
  283. elif bitness == 1:
  284. # aapcs64: 8 8-byte registers
  285. return RegisterAllocator(8, 8, 8)
  286. # Converts a parsed SVC declaration into register lists for
  287. # the return value, outputs, and inputs.
  288. def get_registers(parse_result, bitness):
  289. output_alloc = reg_alloc(bitness)
  290. input_alloc = reg_alloc(bitness)
  291. return_type, _, arguments = parse_result
  292. return_write = []
  293. output_writes = []
  294. input_reads = []
  295. input_ngrn = 0
  296. output_ngrn = 0
  297. # Run the input calculation.
  298. for arg in arguments:
  299. if arg.is_output and not arg.is_outptr:
  300. input_ngrn += 1
  301. continue
  302. regs, increment = input_alloc.add(
  303. input_ngrn, TYPE_SIZES[arg.type_name], align=True)
  304. input_reads.append([arg.type_name, arg.var_name, regs])
  305. input_ngrn += increment
  306. # Include the return value if this SVC returns a value.
  307. if return_type != "void":
  308. regs, increment = output_alloc.add(
  309. output_ngrn, TYPE_SIZES[return_type], align=False)
  310. return_write.append([return_type, regs])
  311. output_ngrn += increment
  312. # Run the output calculation.
  313. for arg in arguments:
  314. if not arg.is_output or arg.is_outptr:
  315. continue
  316. regs, increment = output_alloc.add(
  317. output_ngrn, TYPE_SIZES[arg.type_name], align=False)
  318. output_writes.append(
  319. [arg.type_name, arg.var_name, regs, arg.is_address])
  320. output_ngrn += increment
  321. return (return_write, output_writes, input_reads)
  322. # Collects possibly multiple source registers into the named C++ value.
  323. def emit_gather(sources, name, type_name, reg_size):
  324. get_fn = f"GetReg{reg_size*8}"
  325. if len(sources) == 1:
  326. s, = sources
  327. line = f"{name} = Convert<{type_name}>({get_fn}(system, {s}));"
  328. return [line]
  329. var_type = f"std::array<uint{reg_size*8}_t, {len(sources)}>"
  330. lines = [
  331. f"{var_type} {name}_gather{{}};"
  332. ]
  333. for i in range(0, len(sources)):
  334. lines.append(
  335. f"{name}_gather[{i}] = {get_fn}(system, {sources[i]});")
  336. lines.append(f"{name} = Convert<{type_name}>({name}_gather);")
  337. return lines
  338. # Produces one or more statements which assign the named C++ value
  339. # into possibly multiple registers.
  340. def emit_scatter(destinations, name, reg_size):
  341. set_fn = f"SetReg{reg_size*8}"
  342. reg_type = f"uint{reg_size*8}_t"
  343. if len(destinations) == 1:
  344. d, = destinations
  345. line = f"{set_fn}(system, {d}, Convert<{reg_type}>({name}));"
  346. return [line]
  347. var_type = f"std::array<{reg_type}, {len(destinations)}>"
  348. lines = [
  349. f"auto {name}_scatter = Convert<{var_type}>({name});"
  350. ]
  351. for i in range(0, len(destinations)):
  352. lines.append(
  353. f"{set_fn}(system, {destinations[i]}, {name}_scatter[{i}]);")
  354. return lines
  355. def emit_lines(lines, indent=' '):
  356. output_lines = []
  357. first = True
  358. for line in lines:
  359. if line and not first:
  360. output_lines.append(indent + line)
  361. else:
  362. output_lines.append(line)
  363. first = False
  364. return "\n".join(output_lines)
  365. # Emit a C++ function to wrap a guest SVC.
  366. def emit_wrapper(wrapped_fn, suffix, register_info, arguments, byte_size):
  367. return_write, output_writes, input_reads = register_info
  368. lines = [
  369. f"static void SvcWrap_{wrapped_fn}{suffix}(Core::System& system) {{"
  370. ]
  371. # Get everything ready.
  372. for return_type, _ in return_write:
  373. lines.append(f"{return_type} ret{{}};")
  374. if return_write:
  375. lines.append("")
  376. for output_type, var_name, _, is_address in output_writes:
  377. output_type = "uint64_t" if is_address else output_type
  378. lines.append(f"{output_type} {var_name}{{}};")
  379. for input_type, var_name, _ in input_reads:
  380. lines.append(f"{input_type} {var_name}{{}};")
  381. if output_writes or input_reads:
  382. lines.append("")
  383. for input_type, var_name, sources in input_reads:
  384. lines += emit_gather(sources, var_name, input_type, byte_size)
  385. if input_reads:
  386. lines.append("")
  387. # Build the call.
  388. call_arguments = ["system"]
  389. for arg in arguments:
  390. if arg.is_output and not arg.is_outptr:
  391. call_arguments.append(f"&{arg.var_name}")
  392. else:
  393. call_arguments.append(arg.var_name)
  394. line = ""
  395. if return_write:
  396. line += "ret = "
  397. line += f"{wrapped_fn}{suffix}({', '.join(call_arguments)});"
  398. lines.append(line)
  399. if return_write or output_writes:
  400. lines.append("")
  401. # Write back the return value and outputs.
  402. for _, destinations in return_write:
  403. lines += emit_scatter(destinations, "ret", byte_size)
  404. for _, var_name, destinations, _ in output_writes:
  405. lines += emit_scatter(destinations, var_name, byte_size)
  406. # Finish.
  407. return emit_lines(lines) + "\n}"
  408. COPYRIGHT = """\
  409. // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
  410. // SPDX-License-Identifier: GPL-2.0-or-later
  411. // This file is automatically generated using svc_generator.py.
  412. """
  413. PROLOGUE_H = """
  414. #pragma once
  415. namespace Core {
  416. class System;
  417. }
  418. #include "common/common_types.h"
  419. #include "core/hle/kernel/svc_types.h"
  420. #include "core/hle/result.h"
  421. namespace Kernel::Svc {
  422. // clang-format off
  423. """
  424. EPILOGUE_H = """
  425. // clang-format on
  426. // Custom ABI.
  427. Result ReplyAndReceiveLight(Core::System& system, Handle handle, uint32_t* args);
  428. Result ReplyAndReceiveLight64From32(Core::System& system, Handle handle, uint32_t* args);
  429. Result ReplyAndReceiveLight64(Core::System& system, Handle handle, uint32_t* args);
  430. Result SendSyncRequestLight(Core::System& system, Handle session_handle, uint32_t* args);
  431. Result SendSyncRequestLight64From32(Core::System& system, Handle session_handle, uint32_t* args);
  432. Result SendSyncRequestLight64(Core::System& system, Handle session_handle, uint32_t* args);
  433. void CallSecureMonitor(Core::System& system, lp64::SecureMonitorArguments* args);
  434. void CallSecureMonitor64From32(Core::System& system, ilp32::SecureMonitorArguments* args);
  435. void CallSecureMonitor64(Core::System& system, lp64::SecureMonitorArguments* args);
  436. // Defined in svc_light_ipc.cpp.
  437. void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system);
  438. void SvcWrap_ReplyAndReceiveLight64(Core::System& system);
  439. void SvcWrap_SendSyncRequestLight64From32(Core::System& system);
  440. void SvcWrap_SendSyncRequestLight64(Core::System& system);
  441. // Defined in svc_secure_monitor_call.cpp.
  442. void SvcWrap_CallSecureMonitor64From32(Core::System& system);
  443. void SvcWrap_CallSecureMonitor64(Core::System& system);
  444. // Perform a supervisor call by index.
  445. void Call(Core::System& system, u32 imm);
  446. } // namespace Kernel::Svc
  447. """
  448. PROLOGUE_CPP = """
  449. #include <type_traits>
  450. #include "core/arm/arm_interface.h"
  451. #include "core/core.h"
  452. #include "core/hle/kernel/k_process.h"
  453. #include "core/hle/kernel/svc.h"
  454. namespace Kernel::Svc {
  455. static uint32_t GetReg32(Core::System& system, int n) {
  456. return static_cast<uint32_t>(system.CurrentArmInterface().GetReg(n));
  457. }
  458. static void SetReg32(Core::System& system, int n, uint32_t result) {
  459. system.CurrentArmInterface().SetReg(n, static_cast<uint64_t>(result));
  460. }
  461. static uint64_t GetReg64(Core::System& system, int n) {
  462. return system.CurrentArmInterface().GetReg(n);
  463. }
  464. static void SetReg64(Core::System& system, int n, uint64_t result) {
  465. system.CurrentArmInterface().SetReg(n, result);
  466. }
  467. // Like bit_cast, but handles the case when the source and dest
  468. // are differently-sized.
  469. template <typename To, typename From>
  470. requires(std::is_trivial_v<To> && std::is_trivially_copyable_v<From>)
  471. static To Convert(const From& from) {
  472. To to{};
  473. if constexpr (sizeof(To) >= sizeof(From)) {
  474. std::memcpy(&to, &from, sizeof(From));
  475. } else {
  476. std::memcpy(&to, &from, sizeof(To));
  477. }
  478. return to;
  479. }
  480. // clang-format off
  481. """
  482. EPILOGUE_CPP = """
  483. // clang-format on
  484. void Call(Core::System& system, u32 imm) {
  485. auto& kernel = system.Kernel();
  486. kernel.EnterSVCProfile();
  487. if (GetCurrentProcess(system.Kernel()).Is64BitProcess()) {
  488. Call64(system, imm);
  489. } else {
  490. Call32(system, imm);
  491. }
  492. kernel.ExitSVCProfile();
  493. }
  494. } // namespace Kernel::Svc
  495. """
  496. def emit_call(bitness, names, suffix):
  497. bit_size = REG_SIZES[bitness]*8
  498. indent = " "
  499. lines = [
  500. f"static void Call{bit_size}(Core::System& system, u32 imm) {{",
  501. f"{indent}switch (static_cast<SvcId>(imm)) {{"
  502. ]
  503. for _, name in names:
  504. lines.append(f"{indent}case SvcId::{name}:")
  505. lines.append(f"{indent*2}return SvcWrap_{name}{suffix}(system);")
  506. lines.append(f"{indent}default:")
  507. lines.append(
  508. f"{indent*2}LOG_CRITICAL(Kernel_SVC, \"Unknown SVC {{:x}}!\", imm);")
  509. lines.append(f"{indent*2}break;")
  510. lines.append(f"{indent}}}")
  511. lines.append("}")
  512. return "\n".join(lines)
  513. def build_fn_declaration(return_type, name, arguments):
  514. arg_list = ["Core::System& system"]
  515. for arg in arguments:
  516. type_name = "uint64_t" if arg.is_address else arg.type_name
  517. pointer = "*" if arg.is_output and not arg.is_outptr else ""
  518. arg_list.append(f"{type_name}{pointer} {arg.var_name}")
  519. return f"{return_type} {name}({', '.join(arg_list)});"
  520. def build_enum_declarations():
  521. lines = ["enum class SvcId : u32 {"]
  522. indent = " "
  523. for imm, decl in SVCS:
  524. _, name, _ = parse_declaration(decl, BIT_64)
  525. lines.append(f"{indent}{name} = {hex(imm)},")
  526. lines.append("};")
  527. return "\n".join(lines)
  528. def main():
  529. arch_fw_declarations = [[], []]
  530. svc_fw_declarations = []
  531. wrapper_fns = []
  532. names = []
  533. for imm, decl in SVCS:
  534. return_type, name, arguments = parse_declaration(decl, BIT_64)
  535. if imm not in SKIP_WRAPPERS:
  536. svc_fw_declarations.append(
  537. build_fn_declaration(return_type, name, arguments))
  538. names.append([imm, name])
  539. for bitness in range(2):
  540. byte_size = REG_SIZES[bitness]
  541. suffix = SUFFIX_NAMES[bitness]
  542. for imm, decl in SVCS:
  543. if imm in SKIP_WRAPPERS:
  544. continue
  545. parse_result = parse_declaration(decl, bitness)
  546. return_type, name, arguments = parse_result
  547. register_info = get_registers(parse_result, bitness)
  548. wrapper_fns.append(
  549. emit_wrapper(name, suffix, register_info, arguments, byte_size))
  550. arch_fw_declarations[bitness].append(
  551. build_fn_declaration(return_type, name + suffix, arguments))
  552. call_32 = emit_call(BIT_32, names, SUFFIX_NAMES[BIT_32])
  553. call_64 = emit_call(BIT_64, names, SUFFIX_NAMES[BIT_64])
  554. enum_decls = build_enum_declarations()
  555. with open("svc.h", "w") as f:
  556. f.write(COPYRIGHT)
  557. f.write(PROLOGUE_H)
  558. f.write("\n".join(svc_fw_declarations))
  559. f.write("\n\n")
  560. f.write("\n".join(arch_fw_declarations[BIT_32]))
  561. f.write("\n\n")
  562. f.write("\n".join(arch_fw_declarations[BIT_64]))
  563. f.write("\n\n")
  564. f.write(enum_decls)
  565. f.write(EPILOGUE_H)
  566. with open("svc.cpp", "w") as f:
  567. f.write(COPYRIGHT)
  568. f.write(PROLOGUE_CPP)
  569. f.write(emit_size_check())
  570. f.write("\n\n")
  571. f.write("\n\n".join(wrapper_fns))
  572. f.write("\n\n")
  573. f.write(call_32)
  574. f.write("\n\n")
  575. f.write(call_64)
  576. f.write(EPILOGUE_CPP)
  577. print(f"Done (emitted {len(names)} definitions)")
  578. if __name__ == "__main__":
  579. main()