| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716 |
- # SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
- # SPDX-License-Identifier: GPL-2.0-or-later
- # Raw SVC definitions from the kernel.
- #
- # Avoid modifying the prototypes; see below for how to customize generation
- # for a given typename.
- SVCS = [
- [0x01, "Result SetHeapSize(Address* out_address, Size size);"],
- [0x02, "Result SetMemoryPermission(Address address, Size size, MemoryPermission perm);"],
- [0x03, "Result SetMemoryAttribute(Address address, Size size, uint32_t mask, uint32_t attr);"],
- [0x04, "Result MapMemory(Address dst_address, Address src_address, Size size);"],
- [0x05, "Result UnmapMemory(Address dst_address, Address src_address, Size size);"],
- [0x06, "Result QueryMemory(Address out_memory_info, PageInfo* out_page_info, Address address);"],
- [0x07, "void ExitProcess();"],
- [0x08, "Result CreateThread(Handle* out_handle, ThreadFunc func, Address arg, Address stack_bottom, int32_t priority, int32_t core_id);"],
- [0x09, "Result StartThread(Handle thread_handle);"],
- [0x0A, "void ExitThread();"],
- [0x0B, "void SleepThread(int64_t ns);"],
- [0x0C, "Result GetThreadPriority(int32_t* out_priority, Handle thread_handle);"],
- [0x0D, "Result SetThreadPriority(Handle thread_handle, int32_t priority);"],
- [0x0E, "Result GetThreadCoreMask(int32_t* out_core_id, uint64_t* out_affinity_mask, Handle thread_handle);"],
- [0x0F, "Result SetThreadCoreMask(Handle thread_handle, int32_t core_id, uint64_t affinity_mask);"],
- [0x10, "int32_t GetCurrentProcessorNumber();"],
- [0x11, "Result SignalEvent(Handle event_handle);"],
- [0x12, "Result ClearEvent(Handle event_handle);"],
- [0x13, "Result MapSharedMemory(Handle shmem_handle, Address address, Size size, MemoryPermission map_perm);"],
- [0x14, "Result UnmapSharedMemory(Handle shmem_handle, Address address, Size size);"],
- [0x15, "Result CreateTransferMemory(Handle* out_handle, Address address, Size size, MemoryPermission map_perm);"],
- [0x16, "Result CloseHandle(Handle handle);"],
- [0x17, "Result ResetSignal(Handle handle);"],
- [0x18, "Result WaitSynchronization(int32_t* out_index, Address handles, int32_t num_handles, int64_t timeout_ns);"],
- [0x19, "Result CancelSynchronization(Handle handle);"],
- [0x1A, "Result ArbitrateLock(Handle thread_handle, Address address, uint32_t tag);"],
- [0x1B, "Result ArbitrateUnlock(Address address);"],
- [0x1C, "Result WaitProcessWideKeyAtomic(Address address, Address cv_key, uint32_t tag, int64_t timeout_ns);"],
- [0x1D, "void SignalProcessWideKey(Address cv_key, int32_t count);"],
- [0x1E, "int64_t GetSystemTick();"],
- [0x1F, "Result ConnectToNamedPort(Handle* out_handle, Address name);"],
- [0x20, "Result SendSyncRequestLight(Handle session_handle);"],
- [0x21, "Result SendSyncRequest(Handle session_handle);"],
- [0x22, "Result SendSyncRequestWithUserBuffer(Address message_buffer, Size message_buffer_size, Handle session_handle);"],
- [0x23, "Result SendAsyncRequestWithUserBuffer(Handle* out_event_handle, Address message_buffer, Size message_buffer_size, Handle session_handle);"],
- [0x24, "Result GetProcessId(uint64_t* out_process_id, Handle process_handle);"],
- [0x25, "Result GetThreadId(uint64_t* out_thread_id, Handle thread_handle);"],
- [0x26, "void Break(BreakReason break_reason, Address arg, Size size);"],
- [0x27, "Result OutputDebugString(Address debug_str, Size len);"],
- [0x28, "void ReturnFromException(Result result);"],
- [0x29, "Result GetInfo(uint64_t* out, InfoType info_type, Handle handle, uint64_t info_subtype);"],
- [0x2A, "void FlushEntireDataCache();"],
- [0x2B, "Result FlushDataCache(Address address, Size size);"],
- [0x2C, "Result MapPhysicalMemory(Address address, Size size);"],
- [0x2D, "Result UnmapPhysicalMemory(Address address, Size size);"],
- [0x2E, "Result GetDebugFutureThreadInfo(LastThreadContext* out_context, uint64_t* out_thread_id, Handle debug_handle, int64_t ns);"],
- [0x2F, "Result GetLastThreadInfo(LastThreadContext* out_context, Address* out_tls_address, uint32_t* out_flags);"],
- [0x30, "Result GetResourceLimitLimitValue(int64_t* out_limit_value, Handle resource_limit_handle, LimitableResource which);"],
- [0x31, "Result GetResourceLimitCurrentValue(int64_t* out_current_value, Handle resource_limit_handle, LimitableResource which);"],
- [0x32, "Result SetThreadActivity(Handle thread_handle, ThreadActivity thread_activity);"],
- [0x33, "Result GetThreadContext3(Address out_context, Handle thread_handle);"],
- [0x34, "Result WaitForAddress(Address address, ArbitrationType arb_type, int32_t value, int64_t timeout_ns);"],
- [0x35, "Result SignalToAddress(Address address, SignalType signal_type, int32_t value, int32_t count);"],
- [0x36, "void SynchronizePreemptionState();"],
- [0x37, "Result GetResourceLimitPeakValue(int64_t* out_peak_value, Handle resource_limit_handle, LimitableResource which);"],
- [0x39, "Result CreateIoPool(Handle* out_handle, IoPoolType which);"],
- [0x3A, "Result CreateIoRegion(Handle* out_handle, Handle io_pool, PhysicalAddress physical_address, Size size, MemoryMapping mapping, MemoryPermission perm);"],
- [0x3C, "void KernelDebug(KernelDebugType kern_debug_type, uint64_t arg0, uint64_t arg1, uint64_t arg2);"],
- [0x3D, "void ChangeKernelTraceState(KernelTraceState kern_trace_state);"],
- [0x40, "Result CreateSession(Handle* out_server_session_handle, Handle* out_client_session_handle, bool is_light, Address name);"],
- [0x41, "Result AcceptSession(Handle* out_handle, Handle port);"],
- [0x42, "Result ReplyAndReceiveLight(Handle handle);"],
- [0x43, "Result ReplyAndReceive(int32_t* out_index, Address handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns);"],
- [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);"],
- [0x45, "Result CreateEvent(Handle* out_write_handle, Handle* out_read_handle);"],
- [0x46, "Result MapIoRegion(Handle io_region, Address address, Size size, MemoryPermission perm);"],
- [0x47, "Result UnmapIoRegion(Handle io_region, Address address, Size size);"],
- [0x48, "Result MapPhysicalMemoryUnsafe(Address address, Size size);"],
- [0x49, "Result UnmapPhysicalMemoryUnsafe(Address address, Size size);"],
- [0x4A, "Result SetUnsafeLimit(Size limit);"],
- [0x4B, "Result CreateCodeMemory(Handle* out_handle, Address address, Size size);"],
- [0x4C, "Result ControlCodeMemory(Handle code_memory_handle, CodeMemoryOperation operation, uint64_t address, uint64_t size, MemoryPermission perm);"],
- [0x4D, "void SleepSystem();"],
- [0x4E, "Result ReadWriteRegister(uint32_t* out_value, PhysicalAddress address, uint32_t mask, uint32_t value);"],
- [0x4F, "Result SetProcessActivity(Handle process_handle, ProcessActivity process_activity);"],
- [0x50, "Result CreateSharedMemory(Handle* out_handle, Size size, MemoryPermission owner_perm, MemoryPermission remote_perm);"],
- [0x51, "Result MapTransferMemory(Handle trmem_handle, Address address, Size size, MemoryPermission owner_perm);"],
- [0x52, "Result UnmapTransferMemory(Handle trmem_handle, Address address, Size size);"],
- [0x53, "Result CreateInterruptEvent(Handle* out_read_handle, int32_t interrupt_id, InterruptType interrupt_type);"],
- [0x54, "Result QueryPhysicalAddress(PhysicalMemoryInfo* out_info, Address address);"],
- [0x55, "Result QueryIoMapping(Address* out_address, Size* out_size, PhysicalAddress physical_address, Size size);"],
- [0x56, "Result CreateDeviceAddressSpace(Handle* out_handle, uint64_t das_address, uint64_t das_size);"],
- [0x57, "Result AttachDeviceAddressSpace(DeviceName device_name, Handle das_handle);"],
- [0x58, "Result DetachDeviceAddressSpace(DeviceName device_name, Handle das_handle);"],
- [0x59, "Result MapDeviceAddressSpaceByForce(Handle das_handle, Handle process_handle, uint64_t process_address, Size size, uint64_t device_address, uint32_t option);"],
- [0x5A, "Result MapDeviceAddressSpaceAligned(Handle das_handle, Handle process_handle, uint64_t process_address, Size size, uint64_t device_address, uint32_t option);"],
- [0x5C, "Result UnmapDeviceAddressSpace(Handle das_handle, Handle process_handle, uint64_t process_address, Size size, uint64_t device_address);"],
- [0x5D, "Result InvalidateProcessDataCache(Handle process_handle, uint64_t address, uint64_t size);"],
- [0x5E, "Result StoreProcessDataCache(Handle process_handle, uint64_t address, uint64_t size);"],
- [0x5F, "Result FlushProcessDataCache(Handle process_handle, uint64_t address, uint64_t size);"],
- [0x60, "Result DebugActiveProcess(Handle* out_handle, uint64_t process_id);"],
- [0x61, "Result BreakDebugProcess(Handle debug_handle);"],
- [0x62, "Result TerminateDebugProcess(Handle debug_handle);"],
- [0x63, "Result GetDebugEvent(Address out_info, Handle debug_handle);"],
- [0x64, "Result ContinueDebugEvent(Handle debug_handle, uint32_t flags, Address thread_ids, int32_t num_thread_ids);"],
- [0x65, "Result GetProcessList(int32_t* out_num_processes, Address out_process_ids, int32_t max_out_count);"],
- [0x66, "Result GetThreadList(int32_t* out_num_threads, Address out_thread_ids, int32_t max_out_count, Handle debug_handle);"],
- [0x67, "Result GetDebugThreadContext(Address out_context, Handle debug_handle, uint64_t thread_id, uint32_t context_flags);"],
- [0x68, "Result SetDebugThreadContext(Handle debug_handle, uint64_t thread_id, Address context, uint32_t context_flags);"],
- [0x69, "Result QueryDebugProcessMemory(Address out_memory_info, PageInfo* out_page_info, Handle process_handle, Address address);"],
- [0x6A, "Result ReadDebugProcessMemory(Address buffer, Handle debug_handle, Address address, Size size);"],
- [0x6B, "Result WriteDebugProcessMemory(Handle debug_handle, Address buffer, Address address, Size size);"],
- [0x6C, "Result SetHardwareBreakPoint(HardwareBreakPointRegisterName name, uint64_t flags, uint64_t value);"],
- [0x6D, "Result GetDebugThreadParam(uint64_t* out_64, uint32_t* out_32, Handle debug_handle, uint64_t thread_id, DebugThreadParam param);"],
- [0x6F, "Result GetSystemInfo(uint64_t* out, SystemInfoType info_type, Handle handle, uint64_t info_subtype);"],
- [0x70, "Result CreatePort(Handle* out_server_handle, Handle* out_client_handle, int32_t max_sessions, bool is_light, Address name);"],
- [0x71, "Result ManageNamedPort(Handle* out_server_handle, Address name, int32_t max_sessions);"],
- [0x72, "Result ConnectToPort(Handle* out_handle, Handle port);"],
- [0x73, "Result SetProcessMemoryPermission(Handle process_handle, uint64_t address, uint64_t size, MemoryPermission perm);"],
- [0x74, "Result MapProcessMemory(Address dst_address, Handle process_handle, uint64_t src_address, Size size);"],
- [0x75, "Result UnmapProcessMemory(Address dst_address, Handle process_handle, uint64_t src_address, Size size);"],
- [0x76, "Result QueryProcessMemory(Address out_memory_info, PageInfo* out_page_info, Handle process_handle, uint64_t address);"],
- [0x77, "Result MapProcessCodeMemory(Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size);"],
- [0x78, "Result UnmapProcessCodeMemory(Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size);"],
- [0x79, "Result CreateProcess(Handle* out_handle, Address parameters, Address caps, int32_t num_caps);"],
- [0x7A, "Result StartProcess(Handle process_handle, int32_t priority, int32_t core_id, uint64_t main_thread_stack_size);"],
- [0x7B, "Result TerminateProcess(Handle process_handle);"],
- [0x7C, "Result GetProcessInfo(int64_t* out_info, Handle process_handle, ProcessInfoType info_type);"],
- [0x7D, "Result CreateResourceLimit(Handle* out_handle);"],
- [0x7E, "Result SetResourceLimitLimitValue(Handle resource_limit_handle, LimitableResource which, int64_t limit_value);"],
- [0x7F, "void CallSecureMonitor(SecureMonitorArguments args);"],
- [0x90, "Result MapInsecureMemory(Address address, Size size);"],
- [0x91, "Result UnmapInsecureMemory(Address address, Size size);"],
- ]
- # These use a custom ABI, and therefore require custom wrappers
- SKIP_WRAPPERS = {
- 0x20: "SendSyncRequestLight",
- 0x42: "ReplyAndReceiveLight",
- 0x7F: "CallSecureMonitor",
- }
- BIT_32 = 0
- BIT_64 = 1
- REG_SIZES = [4, 8]
- SUFFIX_NAMES = ["64From32", "64"]
- TYPE_SIZES = {
- # SVC types
- "ArbitrationType": 4,
- "BreakReason": 4,
- "CodeMemoryOperation": 4,
- "DebugThreadParam": 4,
- "DeviceName": 4,
- "HardwareBreakPointRegisterName": 4,
- "Handle": 4,
- "InfoType": 4,
- "InterruptType": 4,
- "IoPoolType": 4,
- "KernelDebugType": 4,
- "KernelTraceState": 4,
- "LimitableResource": 4,
- "MemoryMapping": 4,
- "MemoryPermission": 4,
- "PageInfo": 4,
- "ProcessActivity": 4,
- "ProcessInfoType": 4,
- "Result": 4,
- "SignalType": 4,
- "SystemInfoType": 4,
- "ThreadActivity": 4,
- # Arch-specific types
- "ilp32::LastThreadContext": 16,
- "ilp32::PhysicalMemoryInfo": 16,
- "ilp32::SecureMonitorArguments": 32,
- "lp64::LastThreadContext": 32,
- "lp64::PhysicalMemoryInfo": 24,
- "lp64::SecureMonitorArguments": 64,
- # Generic types
- "bool": 1,
- "int32_t": 4,
- "int64_t": 8,
- "uint32_t": 4,
- "uint64_t": 8,
- "void": 0,
- }
- TYPE_REPLACEMENTS = {
- "Address": ["uint32_t", "uint64_t"],
- "LastThreadContext": ["ilp32::LastThreadContext", "lp64::LastThreadContext"],
- "PhysicalAddress": ["uint64_t", "uint64_t"],
- "PhysicalMemoryInfo": ["ilp32::PhysicalMemoryInfo", "lp64::PhysicalMemoryInfo"],
- "SecureMonitorArguments": ["ilp32::SecureMonitorArguments", "lp64::SecureMonitorArguments"],
- "Size": ["uint32_t", "uint64_t"],
- "ThreadFunc": ["uint32_t", "uint64_t"],
- }
- # Statically verify that the hardcoded sizes match the intended
- # sizes in C++.
- def emit_size_check():
- lines = []
- for type, size in TYPE_SIZES.items():
- if type != "void":
- lines.append(f"static_assert(sizeof({type}) == {size});")
- return "\n".join(lines)
- # Replaces a type with an arch-specific one, if it exists.
- def substitute_type(name, bitness):
- if name in TYPE_REPLACEMENTS:
- return TYPE_REPLACEMENTS[name][bitness]
- else:
- return name
- class Argument:
- def __init__(self, type_name, var_name, is_output, is_outptr, is_address):
- self.type_name = type_name
- self.var_name = var_name
- self.is_output = is_output
- self.is_outptr = is_outptr
- self.is_address = is_address
- # Parses C-style string declarations for SVCs.
- def parse_declaration(declaration, bitness):
- return_type, rest = declaration.split(" ", 1)
- func_name, rest = rest.split("(", 1)
- arg_names, rest = rest.split(")", 1)
- argument_types = []
- return_type = substitute_type(return_type, bitness)
- assert return_type in TYPE_SIZES, f"Unknown type '{return_type}'"
- if arg_names:
- for arg_name in arg_names.split(", "):
- type_name, var_name = arg_name.replace("*", "").split(" ", 1)
- # All outputs must contain out_ in the name.
- is_output = var_name == "out" or var_name.find("out_") != -1
- # User-pointer outputs are not written to registers.
- is_outptr = is_output and arg_name.find("*") == -1
- # Special handling is performed for output addresses to avoid awkwardness
- # in conversion for the 32-bit equivalents.
- is_address = is_output and not is_outptr and \
- type_name in ["Address", "Size"]
- type_name = substitute_type(type_name, bitness)
- assert type_name in TYPE_SIZES, f"Unknown type '{type_name}'"
- argument_types.append(
- Argument(type_name, var_name, is_output, is_outptr, is_address))
- return (return_type, func_name, argument_types)
- class RegisterAllocator:
- def __init__(self, num_regs, byte_size, parameter_count):
- self.registers = {}
- self.num_regs = num_regs
- self.byte_size = byte_size
- self.parameter_count = parameter_count
- # Mark the given register as allocated, for use in layout
- # calculation if the NGRN exceeds the ABI parameter count.
- def allocate(self, i):
- assert i not in self.registers, f"Register R{i} already allocated"
- self.registers[i] = True
- return i
- # Calculate the next available location for a register;
- # the NGRN has exceeded the ABI parameter count.
- def allocate_first_free(self):
- for i in range(0, self.num_regs):
- if i in self.registers:
- continue
- self.allocate(i)
- return i
- assert False, "No registers available"
- # Add a single register at the given NGRN.
- # If the index exceeds the ABI parameter count, try to find a
- # location to add it. Returns the output location and increment.
- def add_single(self, ngrn):
- if ngrn >= self.parameter_count:
- return (self.allocate_first_free(), 0)
- else:
- return (self.allocate(ngrn), 1)
- # Add registers at the given NGRN for a data type of
- # the given size. Returns the output locations and increment.
- def add(self, ngrn, data_size, align=True):
- if data_size <= self.byte_size:
- r, i = self.add_single(ngrn)
- return ([r], i)
- regs = []
- inc = ngrn % 2 if align else 0
- remaining_size = data_size
- while remaining_size > 0:
- r, i = self.add_single(ngrn + inc)
- regs.append(r)
- inc += i
- remaining_size -= self.byte_size
- return (regs, inc)
- def reg_alloc(bitness):
- if bitness == 0:
- # aapcs32: 4 4-byte registers
- return RegisterAllocator(8, 4, 4)
- elif bitness == 1:
- # aapcs64: 8 8-byte registers
- return RegisterAllocator(8, 8, 8)
- # Converts a parsed SVC declaration into register lists for
- # the return value, outputs, and inputs.
- def get_registers(parse_result, bitness):
- output_alloc = reg_alloc(bitness)
- input_alloc = reg_alloc(bitness)
- return_type, _, arguments = parse_result
- return_write = []
- output_writes = []
- input_reads = []
- input_ngrn = 0
- output_ngrn = 0
- # Run the input calculation.
- for arg in arguments:
- if arg.is_output and not arg.is_outptr:
- input_ngrn += 1
- continue
- regs, increment = input_alloc.add(
- input_ngrn, TYPE_SIZES[arg.type_name], align=True)
- input_reads.append([arg.type_name, arg.var_name, regs])
- input_ngrn += increment
- # Include the return value if this SVC returns a value.
- if return_type != "void":
- regs, increment = output_alloc.add(
- output_ngrn, TYPE_SIZES[return_type], align=False)
- return_write.append([return_type, regs])
- output_ngrn += increment
- # Run the output calculation.
- for arg in arguments:
- if not arg.is_output or arg.is_outptr:
- continue
- regs, increment = output_alloc.add(
- output_ngrn, TYPE_SIZES[arg.type_name], align=False)
- output_writes.append(
- [arg.type_name, arg.var_name, regs, arg.is_address])
- output_ngrn += increment
- return (return_write, output_writes, input_reads)
- # Collects possibly multiple source registers into the named C++ value.
- def emit_gather(sources, name, type_name, reg_size):
- get_fn = f"GetReg{reg_size*8}"
- if len(sources) == 1:
- s, = sources
- line = f"{name} = Convert<{type_name}>({get_fn}(system, {s}));"
- return [line]
- var_type = f"std::array<uint{reg_size*8}_t, {len(sources)}>"
- lines = [
- f"{var_type} {name}_gather{{}};"
- ]
- for i in range(0, len(sources)):
- lines.append(
- f"{name}_gather[{i}] = {get_fn}(system, {sources[i]});")
- lines.append(f"{name} = Convert<{type_name}>({name}_gather);")
- return lines
- # Produces one or more statements which assign the named C++ value
- # into possibly multiple registers.
- def emit_scatter(destinations, name, reg_size):
- set_fn = f"SetReg{reg_size*8}"
- reg_type = f"uint{reg_size*8}_t"
- if len(destinations) == 1:
- d, = destinations
- line = f"{set_fn}(system, {d}, Convert<{reg_type}>({name}));"
- return [line]
- var_type = f"std::array<{reg_type}, {len(destinations)}>"
- lines = [
- f"auto {name}_scatter = Convert<{var_type}>({name});"
- ]
- for i in range(0, len(destinations)):
- lines.append(
- f"{set_fn}(system, {destinations[i]}, {name}_scatter[{i}]);")
- return lines
- def emit_lines(lines, indent=' '):
- output_lines = []
- first = True
- for line in lines:
- if line and not first:
- output_lines.append(indent + line)
- else:
- output_lines.append(line)
- first = False
- return "\n".join(output_lines)
- # Emit a C++ function to wrap a guest SVC.
- def emit_wrapper(wrapped_fn, suffix, register_info, arguments, byte_size):
- return_write, output_writes, input_reads = register_info
- lines = [
- f"static void SvcWrap_{wrapped_fn}{suffix}(Core::System& system) {{"
- ]
- # Get everything ready.
- for return_type, _ in return_write:
- lines.append(f"{return_type} ret{{}};")
- if return_write:
- lines.append("")
- for output_type, var_name, _, is_address in output_writes:
- output_type = "uint64_t" if is_address else output_type
- lines.append(f"{output_type} {var_name}{{}};")
- for input_type, var_name, _ in input_reads:
- lines.append(f"{input_type} {var_name}{{}};")
- if output_writes or input_reads:
- lines.append("")
- for input_type, var_name, sources in input_reads:
- lines += emit_gather(sources, var_name, input_type, byte_size)
- if input_reads:
- lines.append("")
- # Build the call.
- call_arguments = ["system"]
- for arg in arguments:
- if arg.is_output and not arg.is_outptr:
- call_arguments.append(f"&{arg.var_name}")
- else:
- call_arguments.append(arg.var_name)
- line = ""
- if return_write:
- line += "ret = "
- line += f"{wrapped_fn}{suffix}({', '.join(call_arguments)});"
- lines.append(line)
- if return_write or output_writes:
- lines.append("")
- # Write back the return value and outputs.
- for _, destinations in return_write:
- lines += emit_scatter(destinations, "ret", byte_size)
- for _, var_name, destinations, _ in output_writes:
- lines += emit_scatter(destinations, var_name, byte_size)
- # Finish.
- return emit_lines(lines) + "\n}"
- COPYRIGHT = """\
- // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
- // SPDX-License-Identifier: GPL-2.0-or-later
- // This file is automatically generated using svc_generator.py.
- """
- PROLOGUE_H = """
- #pragma once
- namespace Core {
- class System;
- }
- #include "common/common_types.h"
- #include "core/hle/kernel/svc_types.h"
- #include "core/hle/result.h"
- namespace Kernel::Svc {
- // clang-format off
- """
- EPILOGUE_H = """
- // clang-format on
- // Custom ABI.
- Result ReplyAndReceiveLight(Core::System& system, Handle handle, uint32_t* args);
- Result ReplyAndReceiveLight64From32(Core::System& system, Handle handle, uint32_t* args);
- Result ReplyAndReceiveLight64(Core::System& system, Handle handle, uint32_t* args);
- Result SendSyncRequestLight(Core::System& system, Handle session_handle, uint32_t* args);
- Result SendSyncRequestLight64From32(Core::System& system, Handle session_handle, uint32_t* args);
- Result SendSyncRequestLight64(Core::System& system, Handle session_handle, uint32_t* args);
- void CallSecureMonitor(Core::System& system, lp64::SecureMonitorArguments* args);
- void CallSecureMonitor64From32(Core::System& system, ilp32::SecureMonitorArguments* args);
- void CallSecureMonitor64(Core::System& system, lp64::SecureMonitorArguments* args);
- // Defined in svc_light_ipc.cpp.
- void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system);
- void SvcWrap_ReplyAndReceiveLight64(Core::System& system);
- void SvcWrap_SendSyncRequestLight64From32(Core::System& system);
- void SvcWrap_SendSyncRequestLight64(Core::System& system);
- // Defined in svc_secure_monitor_call.cpp.
- void SvcWrap_CallSecureMonitor64From32(Core::System& system);
- void SvcWrap_CallSecureMonitor64(Core::System& system);
- // Perform a supervisor call by index.
- void Call(Core::System& system, u32 imm);
- } // namespace Kernel::Svc
- """
- PROLOGUE_CPP = """
- #include <type_traits>
- #include "core/arm/arm_interface.h"
- #include "core/core.h"
- #include "core/hle/kernel/k_process.h"
- #include "core/hle/kernel/svc.h"
- namespace Kernel::Svc {
- static uint32_t GetReg32(Core::System& system, int n) {
- return static_cast<uint32_t>(system.CurrentArmInterface().GetReg(n));
- }
- static void SetReg32(Core::System& system, int n, uint32_t result) {
- system.CurrentArmInterface().SetReg(n, static_cast<uint64_t>(result));
- }
- static uint64_t GetReg64(Core::System& system, int n) {
- return system.CurrentArmInterface().GetReg(n);
- }
- static void SetReg64(Core::System& system, int n, uint64_t result) {
- system.CurrentArmInterface().SetReg(n, result);
- }
- // Like bit_cast, but handles the case when the source and dest
- // are differently-sized.
- template <typename To, typename From>
- requires(std::is_trivial_v<To> && std::is_trivially_copyable_v<From>)
- static To Convert(const From& from) {
- To to{};
- if constexpr (sizeof(To) >= sizeof(From)) {
- std::memcpy(&to, &from, sizeof(From));
- } else {
- std::memcpy(&to, &from, sizeof(To));
- }
- return to;
- }
- // clang-format off
- """
- EPILOGUE_CPP = """
- // clang-format on
- void Call(Core::System& system, u32 imm) {
- auto& kernel = system.Kernel();
- kernel.EnterSVCProfile();
- if (GetCurrentProcess(system.Kernel()).Is64BitProcess()) {
- Call64(system, imm);
- } else {
- Call32(system, imm);
- }
- kernel.ExitSVCProfile();
- }
- } // namespace Kernel::Svc
- """
- def emit_call(bitness, names, suffix):
- bit_size = REG_SIZES[bitness]*8
- indent = " "
- lines = [
- f"static void Call{bit_size}(Core::System& system, u32 imm) {{",
- f"{indent}switch (static_cast<SvcId>(imm)) {{"
- ]
- for _, name in names:
- lines.append(f"{indent}case SvcId::{name}:")
- lines.append(f"{indent*2}return SvcWrap_{name}{suffix}(system);")
- lines.append(f"{indent}default:")
- lines.append(
- f"{indent*2}LOG_CRITICAL(Kernel_SVC, \"Unknown SVC {{:x}}!\", imm);")
- lines.append(f"{indent*2}break;")
- lines.append(f"{indent}}}")
- lines.append("}")
- return "\n".join(lines)
- def build_fn_declaration(return_type, name, arguments):
- arg_list = ["Core::System& system"]
- for arg in arguments:
- type_name = "uint64_t" if arg.is_address else arg.type_name
- pointer = "*" if arg.is_output and not arg.is_outptr else ""
- arg_list.append(f"{type_name}{pointer} {arg.var_name}")
- return f"{return_type} {name}({', '.join(arg_list)});"
- def build_enum_declarations():
- lines = ["enum class SvcId : u32 {"]
- indent = " "
- for imm, decl in SVCS:
- _, name, _ = parse_declaration(decl, BIT_64)
- lines.append(f"{indent}{name} = {hex(imm)},")
- lines.append("};")
- return "\n".join(lines)
- def main():
- arch_fw_declarations = [[], []]
- svc_fw_declarations = []
- wrapper_fns = []
- names = []
- for imm, decl in SVCS:
- return_type, name, arguments = parse_declaration(decl, BIT_64)
- if imm not in SKIP_WRAPPERS:
- svc_fw_declarations.append(
- build_fn_declaration(return_type, name, arguments))
- names.append([imm, name])
- for bitness in range(2):
- byte_size = REG_SIZES[bitness]
- suffix = SUFFIX_NAMES[bitness]
- for imm, decl in SVCS:
- if imm in SKIP_WRAPPERS:
- continue
- parse_result = parse_declaration(decl, bitness)
- return_type, name, arguments = parse_result
- register_info = get_registers(parse_result, bitness)
- wrapper_fns.append(
- emit_wrapper(name, suffix, register_info, arguments, byte_size))
- arch_fw_declarations[bitness].append(
- build_fn_declaration(return_type, name + suffix, arguments))
- call_32 = emit_call(BIT_32, names, SUFFIX_NAMES[BIT_32])
- call_64 = emit_call(BIT_64, names, SUFFIX_NAMES[BIT_64])
- enum_decls = build_enum_declarations()
- with open("svc.h", "w") as f:
- f.write(COPYRIGHT)
- f.write(PROLOGUE_H)
- f.write("\n".join(svc_fw_declarations))
- f.write("\n\n")
- f.write("\n".join(arch_fw_declarations[BIT_32]))
- f.write("\n\n")
- f.write("\n".join(arch_fw_declarations[BIT_64]))
- f.write("\n\n")
- f.write(enum_decls)
- f.write(EPILOGUE_H)
- with open("svc.cpp", "w") as f:
- f.write(COPYRIGHT)
- f.write(PROLOGUE_CPP)
- f.write(emit_size_check())
- f.write("\n\n")
- f.write("\n\n".join(wrapper_fns))
- f.write("\n\n")
- f.write(call_32)
- f.write("\n\n")
- f.write(call_64)
- f.write(EPILOGUE_CPP)
- print(f"Done (emitted {len(names)} definitions)")
- if __name__ == "__main__":
- main()
|