[CommandHipc(8)] // 9.0.0+ // ParseTimeZoneBinary(buffer<nn::time::TimeZoneBinary, 0x21> timeZoneBinary) -> buffer<nn::time::TimeZoneRule, 0x16> public ResultCode ParseTimeZoneBinary(ServiceCtx context) { (ulong bufferPosition, ulong bufferSize) = context.Request.GetBufferType0x21(); ulong timeZoneRuleBufferPosition = context.Request.ReceiveBuff[0].Position; ulong timeZoneRuleBufferSize = context.Request.ReceiveBuff[0].Size; if (timeZoneRuleBufferSize != 0x4000) { // TODO: find error code here Logger.Error?.Print(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{timeZoneRuleBufferSize:x} (expected 0x4000)"); throw new InvalidOperationException(); } ResultCode result; byte[] temp = new byte[bufferSize]; context.Memory.Read(bufferPosition, temp); using (MemoryStream timeZoneBinaryStream = new MemoryStream(temp)) { using (WritableRegion region = context.Memory.GetWritableRegion(timeZoneRuleBufferPosition, Unsafe.SizeOf <TimeZoneRule>())) { ref TimeZoneRule rule = ref MemoryMarshal.Cast <byte, TimeZoneRule>(region.Memory.Span)[0]; result = _timeZoneManager.ParseTimeZoneRuleBinary(ref rule, timeZoneBinaryStream); } }
// Read(u32 fd) -> (i32 ret, u32 bsd_errno, buffer<i8, 0x22, 0> message) public ResultCode Read(ServiceCtx context) { int fd = context.RequestData.ReadInt32(); (ulong receivePosition, ulong receiveLength) = context.Request.GetBufferType0x22(); WritableRegion receiveRegion = context.Memory.GetWritableRegion(receivePosition, (int)receiveLength); LinuxError errno = LinuxError.EBADF; IFileDescriptor file = _context.RetrieveFileDescriptor(fd); int result = -1; if (file != null) { errno = file.Read(out result, receiveRegion.Memory.Span); if (errno == LinuxError.SUCCESS) { SetResultErrno(file, result); receiveRegion.Dispose(); } } return(WriteBsdResult(context, result, errno)); }
// RecvFrom(u32 sock, u32 flags) -> (i32 ret, u32 bsd_errno, u32 addrlen, buffer<i8, 0x22, 0> message, buffer<nn::socket::sockaddr_in, 0x22, 0x10>) public ResultCode RecvFrom(ServiceCtx context) { int socketFd = context.RequestData.ReadInt32(); BsdSocketFlags socketFlags = (BsdSocketFlags)context.RequestData.ReadInt32(); (ulong receivePosition, ulong receiveLength) = context.Request.GetBufferType0x22(0); (ulong sockAddrOutPosition, ulong sockAddrOutSize) = context.Request.GetBufferType0x22(1); WritableRegion receiveRegion = context.Memory.GetWritableRegion(receivePosition, (int)receiveLength); LinuxError errno = LinuxError.EBADF; ISocket socket = _context.RetrieveSocket(socketFd); int result = -1; if (socket != null) { errno = socket.ReceiveFrom(out result, receiveRegion.Memory.Span, receiveRegion.Memory.Span.Length, socketFlags, out IPEndPoint endPoint); if (errno == LinuxError.SUCCESS) { SetResultErrno(socket, result); receiveRegion.Dispose(); context.Memory.Write(sockAddrOutPosition, BsdSockAddr.FromIPEndPoint(endPoint)); } } return(WriteBsdResult(context, result, errno)); }
// DoHandshakeGetServerCert() -> (u32, u32, buffer<bytes, 6>) public ResultCode DoHandshakeGetServerCert(ServiceCtx context) { if (_connection == null) { return(ResultCode.NoSocket); } ResultCode result = _connection.Handshake(_hostName); if (result == ResultCode.Success) { if (_getServerCertChain) { using (WritableRegion region = context.Memory.GetWritableRegion(context.Request.ReceiveBuff[0].Position, (int)context.Request.ReceiveBuff[0].Size)) { result = _connection.GetServerCertificate(_hostName, region.Memory.Span, out uint bufferSize, out uint certificateCount); context.ResponseData.Write(bufferSize); context.ResponseData.Write(certificateCount); } } else { context.ResponseData.Write(0); context.ResponseData.Write(0); } } return(result); }
private static int SerializeAddrInfos(ServiceCtx context, ulong responseBufferPosition, ulong responseBufferSize, IPHostEntry hostEntry, int port) { ulong originalBufferPosition = responseBufferPosition; ulong bufferPosition = originalBufferPosition; byte[] hostName = Encoding.ASCII.GetBytes(hostEntry.HostName + '\0'); using (WritableRegion region = context.Memory.GetWritableRegion(responseBufferPosition, (int)responseBufferSize)) { Span <byte> data = region.Memory.Span; for (int i = 0; i < hostEntry.AddressList.Length; i++) { IPAddress ip = hostEntry.AddressList[i]; if (ip.AddressFamily != AddressFamily.InterNetwork) { continue; } // NOTE: 0 = Any AddrInfoSerializedHeader header = new AddrInfoSerializedHeader(ip, 0); AddrInfo4 addr = new AddrInfo4(ip, (short)port); AddrInfoSerialized info = new AddrInfoSerialized(header, addr, null, hostEntry.HostName); data = info.Write(data); } uint sentinel = 0; MemoryMarshal.Write(data, ref sentinel); data = data[sizeof(uint)..];
[CommandHipc(9)] // 3.0.0+ // GetReleasedAudioInBuffersAuto() -> (u32 count, buffer<u64, 0x22> tags) public ResultCode GetReleasedAudioInBuffersAuto(ServiceCtx context) { (long position, long size) = context.Request.GetBufferType0x22(); using (WritableRegion outputRegion = context.Memory.GetWritableRegion((ulong)position, (int)size)) { ResultCode result = _impl.GetReleasedBuffers(MemoryMarshal.Cast <byte, ulong>(outputRegion.Memory.Span), out uint releasedCount); context.ResponseData.Write(releasedCount); return(result); } }
// GetReleasedAudioOutBuffers() -> (u32 count, buffer<u64, 6> tags) public ResultCode GetReleasedAudioOutBuffers(ServiceCtx context) { long position = context.Request.ReceiveBuff[0].Position; long size = context.Request.ReceiveBuff[0].Size; using (WritableRegion outputRegion = context.Memory.GetWritableRegion((ulong)position, (int)size)) { ResultCode result = _impl.GetReleasedBuffers(MemoryMarshal.Cast <byte, ulong>(outputRegion.Memory.Span), out uint releasedCount); context.ResponseData.Write(releasedCount); return(result); } }
// GetCertificates(buffer<CaCertificateId, 5> ids) -> (u32 certificates_count, buffer<bytes, 6> certificates) public ResultCode GetCertificates(ServiceCtx context) { ReadOnlySpan <CaCertificateId> ids = MemoryMarshal.Cast <byte, CaCertificateId>(context.Memory.GetSpan(context.Request.SendBuff[0].Position, (int)context.Request.SendBuff[0].Size)); if (!BuiltInCertificateManager.Instance.TryGetCertificates(ids, out BuiltInCertificateManager.CertStoreEntry[] entries)) { throw new InvalidOperationException(); } if (ComputeCertificateBufferSizeRequired(entries) > context.Request.ReceiveBuff[0].Size) { return(ResultCode.InvalidCertBufSize); } using (WritableRegion region = context.Memory.GetWritableRegion(context.Request.ReceiveBuff[0].Position, (int)context.Request.ReceiveBuff[0].Size)) { Span <byte> rawData = region.Memory.Span; Span <BuiltInCertificateInfo> infos = MemoryMarshal.Cast <byte, BuiltInCertificateInfo>(rawData)[..entries.Length];
// Write(buffer<bytes, 5>) -> s32 public ResultCode Write(ServiceCtx context) { if (_connection == null) { return(ResultCode.NoSocket); } // We don't dispose as this isn't supposed to be modified WritableRegion region = context.Memory.GetWritableRegion(context.Request.SendBuff[0].Position, (int)context.Request.SendBuff[0].Size); // TODO: Better error management. ResultCode result = _connection.Write(out int writtenCount, region.Memory); if (result == ResultCode.Success) { context.ResponseData.Write(writtenCount); } return(result); }
// LoadTimeZoneRule(nn::time::LocationName locationName) -> buffer<nn::time::TimeZoneRule, 0x16> public ResultCode LoadTimeZoneRule(ServiceCtx context) { ulong bufferPosition = context.Request.ReceiveBuff[0].Position; ulong bufferSize = context.Request.ReceiveBuff[0].Size; if (bufferSize != 0x4000) { // TODO: find error code here Logger.Error?.Print(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{bufferSize:x} (expected 0x4000)"); throw new InvalidOperationException(); } string locationName = StringUtils.ReadInlinedAsciiString(context.RequestData, 0x24); using (WritableRegion region = context.Memory.GetWritableRegion(bufferPosition, Unsafe.SizeOf <TimeZoneRule>())) { ref TimeZoneRule rules = ref MemoryMarshal.Cast <byte, TimeZoneRule>(region.Memory.Span)[0]; return(_timeZoneContentManager.LoadTimeZoneRule(ref rules, locationName)); }
// Peek() -> (s32, buffer<bytes, 6>) public ResultCode Peek(ServiceCtx context) { if (_connection == null) { return(ResultCode.NoSocket); } ResultCode result; using (WritableRegion region = context.Memory.GetWritableRegion(context.Request.ReceiveBuff[0].Position, (int)context.Request.ReceiveBuff[0].Size)) { // TODO: Better error management. result = _connection.Peek(out int peekCount, region.Memory); if (result == ResultCode.Success) { context.ResponseData.Write(peekCount); } } return(result); }
// GetSockOpt(u32 socket, u32 level, u32 option_name) -> (i32 ret, u32 bsd_errno, u32, buffer<unknown, 0x22, 0>) public ResultCode GetSockOpt(ServiceCtx context) { int socketFd = context.RequestData.ReadInt32(); SocketOptionLevel level = (SocketOptionLevel)context.RequestData.ReadInt32(); BsdSocketOption option = (BsdSocketOption)context.RequestData.ReadInt32(); (ulong bufferPosition, ulong bufferSize) = context.Request.GetBufferType0x22(); WritableRegion optionValue = context.Memory.GetWritableRegion(bufferPosition, (int)bufferSize); LinuxError errno = LinuxError.EBADF; ISocket socket = _context.RetrieveSocket(socketFd); if (socket != null) { errno = socket.GetSocketOption(option, level, optionValue.Memory.Span); if (errno == LinuxError.SUCCESS) { optionValue.Dispose(); } } return(WriteBsdResult(context, 0, errno)); }
public ResultCode Initialize(ref AudioRendererConfiguration parameter, uint processHandle, CpuAddress workBuffer, ulong workBufferSize, int sessionId, ulong appletResourceId, IVirtualMemoryManager memoryManager) { if (!BehaviourContext.CheckValidRevision(parameter.Revision)) { return(ResultCode.OperationFailed); } if (GetWorkBufferSize(ref parameter) > workBufferSize) { return(ResultCode.WorkBufferTooSmall); } Debug.Assert(parameter.RenderingDevice == AudioRendererRenderingDevice.Dsp && parameter.ExecutionMode == AudioRendererExecutionMode.Auto); Logger.Info?.Print(LogClass.AudioRenderer, $"Initializing with REV{BehaviourContext.GetRevisionNumber(parameter.Revision)}"); _behaviourContext.SetUserRevision(parameter.Revision); _sampleRate = parameter.SampleRate; _sampleCount = parameter.SampleCount; _mixBufferCount = parameter.MixBufferCount; _voiceChannelCountMax = Constants.VoiceChannelCountMax; _upsamplerCount = parameter.SinkCount + parameter.SubMixBufferCount; _appletResourceId = appletResourceId; _memoryPoolCount = parameter.EffectCount + parameter.VoiceCount * Constants.VoiceWaveBufferCount; _executionMode = parameter.ExecutionMode; _sessionId = sessionId; MemoryManager = memoryManager; if (memoryManager is IRefCounted rc) { rc.IncrementReferenceCount(); } WorkBufferAllocator workBufferAllocator; _workBufferRegion = MemoryManager.GetWritableRegion(workBuffer, (int)workBufferSize); _workBufferRegion.Memory.Span.Fill(0); _workBufferMemoryPin = _workBufferRegion.Memory.Pin(); workBufferAllocator = new WorkBufferAllocator(_workBufferRegion.Memory); PoolMapper poolMapper = new PoolMapper(processHandle, false); poolMapper.InitializeSystemPool(ref _dspMemoryPoolState, workBuffer, workBufferSize); _mixBuffer = workBufferAllocator.Allocate <float>(_sampleCount * (_voiceChannelCountMax + _mixBufferCount), 0x10); if (_mixBuffer.IsEmpty) { return(ResultCode.WorkBufferTooSmall); } Memory <float> upSamplerWorkBuffer = workBufferAllocator.Allocate <float>(Constants.TargetSampleCount * (_voiceChannelCountMax + _mixBufferCount) * _upsamplerCount, 0x10); if (upSamplerWorkBuffer.IsEmpty) { return(ResultCode.WorkBufferTooSmall); } _depopBuffer = workBufferAllocator.Allocate <float>((ulong)BitUtils.AlignUp(parameter.MixBufferCount, Constants.BufferAlignment), Constants.BufferAlignment); if (_depopBuffer.IsEmpty) { return(ResultCode.WorkBufferTooSmall); } // Invalidate DSP cache on what was currently allocated with workBuffer. AudioProcessorMemoryManager.InvalidateDspCache(_dspMemoryPoolState.Translate(workBuffer, workBufferAllocator.Offset), workBufferAllocator.Offset); Debug.Assert((workBufferAllocator.Offset % Constants.BufferAlignment) == 0); Memory <VoiceState> voices = workBufferAllocator.Allocate <VoiceState>(parameter.VoiceCount, VoiceState.Alignment); if (voices.IsEmpty) { return(ResultCode.WorkBufferTooSmall); } foreach (ref VoiceState voice in voices.Span) { voice.Initialize(); } // A pain to handle as we can't have VoiceState*, use indices to be a bit more safe Memory <int> sortedVoices = workBufferAllocator.Allocate <int>(parameter.VoiceCount, 0x10); if (sortedVoices.IsEmpty) { return(ResultCode.WorkBufferTooSmall); } // Clear memory (use -1 as it's an invalid index) sortedVoices.Span.Fill(-1); Memory <VoiceChannelResource> voiceChannelResources = workBufferAllocator.Allocate <VoiceChannelResource>(parameter.VoiceCount, VoiceChannelResource.Alignment); if (voiceChannelResources.IsEmpty) { return(ResultCode.WorkBufferTooSmall); } for (uint id = 0; id < voiceChannelResources.Length; id++) { ref VoiceChannelResource voiceChannelResource = ref voiceChannelResources.Span[(int)id]; voiceChannelResource.Id = id; voiceChannelResource.IsUsed = false; }
/// <summary> /// Performs a full data copy between two textures, reading and writing guest memory directly. /// The textures must have a matching layout, size, and bytes per pixel. /// </summary> /// <param name="src">The source texture</param> /// <param name="dst">The destination texture</param> /// <param name="w">Copy width</param> /// <param name="h">Copy height</param> /// <param name="bpp">Bytes per pixel</param> private void UnscaledFullCopy(TwodTexture src, TwodTexture dst, int w, int h, int bpp) { var srcCalculator = new OffsetCalculator( w, h, src.Stride, src.LinearLayout, src.MemoryLayout.UnpackGobBlocksInY(), src.MemoryLayout.UnpackGobBlocksInZ(), bpp); (int _, int srcSize) = srcCalculator.GetRectangleRange(0, 0, w, h); var memoryManager = _channel.MemoryManager; ulong srcGpuVa = src.Address.Pack(); ulong dstGpuVa = dst.Address.Pack(); ReadOnlySpan <byte> srcSpan = memoryManager.GetSpan(srcGpuVa, srcSize, true); int width; int height = src.Height; if (src.LinearLayout) { width = src.Stride / bpp; } else { width = src.Width; } // If the copy is not equal to the width and height of the texture, we will need to copy partially. // It's worth noting that it has already been established that the src and dst are the same size. if (w == width && h == height) { memoryManager.Write(dstGpuVa, srcSpan); } else { using WritableRegion dstRegion = memoryManager.GetWritableRegion(dstGpuVa, srcSize, true); Span <byte> dstSpan = dstRegion.Memory.Span; if (src.LinearLayout) { int stride = src.Stride; int offset = 0; int lineSize = width * bpp; for (int y = 0; y < height; y++) { srcSpan.Slice(offset, lineSize).CopyTo(dstSpan.Slice(offset)); offset += stride; } } else { // Copy with the block linear layout in mind. // Recreate the offset calculate with bpp 1 for copy. int stride = w * bpp; srcCalculator = new OffsetCalculator( stride, h, 0, false, src.MemoryLayout.UnpackGobBlocksInY(), src.MemoryLayout.UnpackGobBlocksInZ(), 1); int strideTrunc = BitUtils.AlignDown(stride, 16); ReadOnlySpan <Vector128 <byte> > srcVec = MemoryMarshal.Cast <byte, Vector128 <byte> >(srcSpan); Span <Vector128 <byte> > dstVec = MemoryMarshal.Cast <byte, Vector128 <byte> >(dstSpan); for (int y = 0; y < h; y++) { int x = 0; srcCalculator.SetY(y); for (; x < strideTrunc; x += 16) { int offset = srcCalculator.GetOffset(x) >> 4; dstVec[offset] = srcVec[offset]; } for (; x < stride; x++) { int offset = srcCalculator.GetOffset(x); dstSpan[offset] = srcSpan[offset]; } } } } }