os/dd: primitive fixes

This commit is contained in:
Michael Scire 2019-12-03 19:26:43 -08:00 committed by SciresM
parent b1a9e8d0df
commit ad64cb5212
18 changed files with 276 additions and 65 deletions

View file

@ -132,7 +132,7 @@ namespace ams::boot {
R_ASSERT(svcAttachDeviceAddressSpace(DeviceName_DC, g_dc_das_hnd)); R_ASSERT(svcAttachDeviceAddressSpace(DeviceName_DC, g_dc_das_hnd));
/* Map the framebuffer for the DC as read-only. */ /* Map the framebuffer for the DC as read-only. */
R_ASSERT(svcMapDeviceAddressSpaceAligned(g_dc_das_hnd, CUR_PROCESS_HANDLE, frame_buffer_aligned, FrameBufferSize, FrameBufferPaddr, 1)); R_ASSERT(svcMapDeviceAddressSpaceAligned(g_dc_das_hnd, dd::GetCurrentProcessHandle(), frame_buffer_aligned, FrameBufferSize, FrameBufferPaddr, 1));
} }
} }
@ -142,7 +142,7 @@ namespace ams::boot {
constexpr u64 DeviceName_DC = 2; constexpr u64 DeviceName_DC = 2;
/* Unmap the framebuffer from the DC. */ /* Unmap the framebuffer from the DC. */
R_ASSERT(svcUnmapDeviceAddressSpace(g_dc_das_hnd, CUR_PROCESS_HANDLE, frame_buffer_aligned, FrameBufferSize, FrameBufferPaddr)); R_ASSERT(svcUnmapDeviceAddressSpace(g_dc_das_hnd, dd::GetCurrentProcessHandle(), frame_buffer_aligned, FrameBufferSize, FrameBufferPaddr));
/* Detach address space from the DC. */ /* Detach address space from the DC. */
R_ASSERT(svcDetachDeviceAddressSpace(DeviceName_DC, g_dc_das_hnd)); R_ASSERT(svcDetachDeviceAddressSpace(DeviceName_DC, g_dc_das_hnd));
/* Close the address space. */ /* Close the address space. */

View file

@ -17,3 +17,4 @@
#pragma once #pragma once
#include "dd/dd_io_mappings.hpp" #include "dd/dd_io_mappings.hpp"
#include "dd/dd_process_handle.hpp"

View file

@ -32,4 +32,5 @@ namespace ams::dd {
AMS_ASSERT(io_mapping); AMS_ASSERT(io_mapping);
return io_mapping; return io_mapping;
} }
} }

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <atmosphere/common.hpp>
namespace ams::dd {
::Handle GetCurrentProcessHandle();
}

View file

@ -18,8 +18,10 @@
#include "os/os_common_types.hpp" #include "os/os_common_types.hpp"
#include "os/os_managed_handle.hpp" #include "os/os_managed_handle.hpp"
#include "os/os_process_handle.hpp"
#include "os/os_mutex.hpp" #include "os/os_mutex.hpp"
#include "os/os_condvar.hpp" #include "os/os_condvar.hpp"
#include "os/os_rw_lock.hpp"
#include "os/os_semaphore.hpp" #include "os/os_semaphore.hpp"
#include "os/os_timeout_helper.hpp" #include "os/os_timeout_helper.hpp"
#include "os/os_event.hpp" #include "os/os_event.hpp"

View file

@ -54,10 +54,6 @@ namespace ams::os {
return process_id; return process_id;
} }
NX_INLINE ProcessId GetCurrentProcessId() {
return GetProcessId(CUR_PROCESS_HANDLE);
}
inline constexpr bool operator==(const ProcessId &lhs, const ProcessId &rhs) { inline constexpr bool operator==(const ProcessId &lhs, const ProcessId &rhs) {
return lhs.value == rhs.value; return lhs.value == rhs.value;
} }

View file

@ -19,6 +19,11 @@
namespace ams::os { namespace ams::os {
enum class ConditionVariableStatus {
TimedOut = 0,
Success = 1,
};
class ConditionVariable { class ConditionVariable {
NON_COPYABLE(ConditionVariable); NON_COPYABLE(ConditionVariable);
NON_MOVEABLE(ConditionVariable); NON_MOVEABLE(ConditionVariable);
@ -29,40 +34,36 @@ namespace ams::os {
condvarInit(&cv); condvarInit(&cv);
} }
Result TimedWait(::Mutex *m, u64 timeout) { ConditionVariableStatus TimedWait(::Mutex *m, u64 timeout) {
return condvarWaitTimeout(&cv, m, timeout); if (timeout > 0) {
/* Abort on any error other than timed out/success. */
R_TRY_CATCH(condvarWaitTimeout(&this->cv, m, timeout)) {
R_CATCH(svc::ResultTimedOut) { return ConditionVariableStatus::TimedOut; }
} R_END_TRY_CATCH_WITH_ASSERT;
return ConditionVariableStatus::Success;
}
return ConditionVariableStatus::TimedOut;
} }
Result Wait(::Mutex *m) { void Wait(::Mutex *m) {
return condvarWait(&cv, m); R_ASSERT(condvarWait(&this->cv, m));
} }
Result TimedWait(os::Mutex *m, u64 timeout) { ConditionVariableStatus TimedWait(os::Mutex *m, u64 timeout) {
return TimedWait(m->GetMutex(), timeout); return this->TimedWait(m->GetMutex(), timeout);
} }
Result Wait(os::Mutex *m) { void Wait(os::Mutex *m) {
return Wait(m->GetMutex()); return this->Wait(m->GetMutex());
} }
Result Wake(int num) { void Signal() {
return condvarWake(&cv, num); condvarWakeOne(&this->cv);
} }
Result WakeOne() { void Broadcast() {
return condvarWakeOne(&cv); condvarWakeAll(&this->cv);
}
Result WakeAll() {
return condvarWakeAll(&cv);
}
Result Signal() {
return this->WakeOne();
}
Result Broadcast() {
return this->WakeAll();
} }
}; };

View file

@ -35,21 +35,22 @@ namespace ams::os {
NON_COPYABLE(MessageQueue); NON_COPYABLE(MessageQueue);
NON_MOVEABLE(MessageQueue); NON_MOVEABLE(MessageQueue);
private: private:
util::TypedStorage<impl::WaitableObjectList, sizeof(util::IntrusiveListNode), alignof(util::IntrusiveListNode)> waitable_object_list_storage; util::TypedStorage<impl::WaitableObjectList, sizeof(util::IntrusiveListNode), alignof(util::IntrusiveListNode)> waitlist_not_empty;
util::TypedStorage<impl::WaitableObjectList, sizeof(util::IntrusiveListNode), alignof(util::IntrusiveListNode)> waitlist_not_full;
Mutex queue_lock; Mutex queue_lock;
ConditionVariable cv_not_full; ConditionVariable cv_not_full;
ConditionVariable cv_not_empty; ConditionVariable cv_not_empty;
std::unique_ptr<uintptr_t[]> buffer; std::unique_ptr<uintptr_t[]> buffer;
size_t capacity; size_t capacity;
size_t count = 0; size_t count;
size_t offset = 0; size_t offset;
private: private:
bool IsFull() const { constexpr inline bool IsFull() const {
return this->count >= this->capacity; return this->count >= this->capacity;
} }
bool IsEmpty() const { constexpr inline bool IsEmpty() const {
return this->count == 0; return this->count == 0;
} }

View file

@ -0,0 +1,28 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "os_managed_handle.hpp"
namespace ams::os {
::Handle GetCurrentProcessHandle();
NX_INLINE ProcessId GetCurrentProcessId() {
return GetProcessId(GetCurrentProcessHandle());
}
}

View file

@ -0,0 +1,89 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "os_common_types.hpp"
namespace ams::os {
class ReadWriteLock {
NON_COPYABLE(ReadWriteLock);
NON_MOVEABLE(ReadWriteLock);
private:
::RwLock r;
public:
ReadWriteLock() {
rwlockInit(&this->r);
}
bool IsWriteLockHeldByCurrentThread() const {
return rwlockIsWriteLockHeldByCurrentThread(const_cast<::RwLock *>(&this->r));
}
bool IsLockOwner() const {
return rwlockIsOwnedByCurrentThread(const_cast<::RwLock *>(&this->r));
}
void AcquireReadLock() {
rwlockReadLock(&this->r);
}
void ReleaseReadLock() {
rwlockReadUnlock(&this->r);
}
bool TryAcquireReadLock() {
return rwlockTryReadLock(&this->r);
}
void AcquireWriteLock() {
rwlockWriteLock(&this->r);
}
void ReleaseWriteLock() {
rwlockWriteUnlock(&this->r);
}
bool TryAcquireWriteLock() {
return rwlockTryWriteLock(&this->r);
}
void lock_shared() {
this->AcquireReadLock();
}
void unlock_shared() {
this->ReleaseReadLock();
}
bool try_lock_shared() {
return this->TryAcquireReadLock();
}
void lock() {
this->AcquireWriteLock();
}
void unlock() {
this->ReleaseWriteLock();
}
bool try_lock() {
return this->TryAcquireWriteLock();
}
};
}

View file

@ -41,7 +41,7 @@ namespace ams::os {
return (tick * 625) / 12; return (tick * 625) / 12;
} }
bool TimedOut() const { inline bool TimedOut() const {
if (this->end_tick == 0) { if (this->end_tick == 0) {
return true; return true;
} }
@ -49,7 +49,7 @@ namespace ams::os {
return armGetSystemTick() >= this->end_tick; return armGetSystemTick() >= this->end_tick;
} }
u64 NsUntilTimeout() const { inline u64 NsUntilTimeout() const {
u64 diff = TickToNs(this->end_tick - armGetSystemTick()); u64 diff = TickToNs(this->end_tick - armGetSystemTick());
if (this->TimedOut()) { if (this->TimedOut()) {

View file

@ -31,7 +31,7 @@ namespace ams::map {
uintptr_t cur_base = 0; uintptr_t cur_base = 0;
AddressSpaceInfo address_space; AddressSpaceInfo address_space;
R_TRY(GetProcessAddressSpaceInfo(&address_space, CUR_PROCESS_HANDLE)); R_TRY(GetProcessAddressSpaceInfo(&address_space, dd::GetCurrentProcessHandle()));
cur_base = address_space.aslr_base; cur_base = address_space.aslr_base;
do { do {
@ -57,7 +57,7 @@ namespace ams::map {
uintptr_t cur_base = 0, cur_end = 0; uintptr_t cur_base = 0, cur_end = 0;
AddressSpaceInfo address_space; AddressSpaceInfo address_space;
R_TRY(GetProcessAddressSpaceInfo(&address_space, CUR_PROCESS_HANDLE)); R_TRY(GetProcessAddressSpaceInfo(&address_space, dd::GetCurrentProcessHandle()));
cur_base = address_space.aslr_base; cur_base = address_space.aslr_base;
cur_end = cur_base + size; cur_end = cur_base + size;

View file

@ -25,13 +25,25 @@ namespace ams::os::impl {
private: private:
MessageQueue *message_queue; MessageQueue *message_queue;
private: private:
TriBool IsSignaledImpl() const { constexpr inline TriBool IsSignaledImpl() const {
if constexpr (WaitKind == MessageQueueWaitKind::ForNotEmpty) { if constexpr (WaitKind == MessageQueueWaitKind::ForNotEmpty) {
/* ForNotEmpty. */ /* ForNotEmpty. */
return this->message_queue->IsEmpty() ? TriBool::False : TriBool::True; return this->message_queue->IsEmpty() ? TriBool::False : TriBool::True;
} else /* if constexpr (WaitKind == MessageQueueWaitKind::ForNotFull) */ { } else if constexpr (WaitKind == MessageQueueWaitKind::ForNotFull) {
/* ForNotFull */ /* ForNotFull */
return this->message_queue->IsFull() ? TriBool::False : TriBool::True; return this->message_queue->IsFull() ? TriBool::False : TriBool::True;
} else {
static_assert(WaitKind != WaitKind);
}
}
constexpr inline WaitableObjectList &GetObjectList() const {
if constexpr (WaitKind == MessageQueueWaitKind::ForNotEmpty) {
return GetReference(this->message_queue->waitlist_not_empty);
} else if constexpr (WaitKind == MessageQueueWaitKind::ForNotFull) {
return GetReference(this->message_queue->waitlist_not_full);
} else {
static_assert(WaitKind != WaitKind);
} }
} }
public: public:
@ -46,14 +58,14 @@ namespace ams::os::impl {
virtual TriBool LinkToObjectList() override { virtual TriBool LinkToObjectList() override {
std::scoped_lock lk(this->message_queue->queue_lock); std::scoped_lock lk(this->message_queue->queue_lock);
GetReference(this->message_queue->waitable_object_list_storage).LinkWaitableHolder(*this); this->GetObjectList().LinkWaitableHolder(*this);
return this->IsSignaledImpl(); return this->IsSignaledImpl();
} }
virtual void UnlinkFromObjectList() override { virtual void UnlinkFromObjectList() override {
std::scoped_lock lk(this->message_queue->queue_lock); std::scoped_lock lk(this->message_queue->queue_lock);
GetReference(this->message_queue->waitable_object_list_storage).UnlinkWaitableHolder(*this); this->GetObjectList().UnlinkWaitableHolder(*this);
} }
}; };

View file

@ -31,7 +31,7 @@ namespace ams::os::impl {
} }
} }
void WakeupAllThreads() { void BroadcastAllThreads() {
for (WaitableHolderBase &holder_base : this->object_list) { for (WaitableHolderBase &holder_base : this->object_list) {
holder_base.GetManager()->SignalAndWakeupThread(nullptr); holder_base.GetManager()->SignalAndWakeupThread(nullptr);
} }

View file

@ -90,7 +90,7 @@ namespace ams::os {
if (this->counter != cur_counter) { if (this->counter != cur_counter) {
break; break;
} }
if (R_FAILED(this->cv.TimedWait(&this->lock, timeout_helper.NsUntilTimeout()))) { if (this->cv.TimedWait(&this->lock, timeout_helper.NsUntilTimeout()) == ConditionVariableStatus::TimedOut) {
return false; return false;
} }
} }

View file

@ -17,12 +17,14 @@
namespace ams::os { namespace ams::os {
MessageQueue::MessageQueue(std::unique_ptr<uintptr_t[]> buf, size_t c): buffer(std::move(buf)), capacity(c) { MessageQueue::MessageQueue(std::unique_ptr<uintptr_t[]> buf, size_t c): buffer(std::move(buf)), capacity(c), count(0), offset(0) {
new (GetPointer(this->waitable_object_list_storage)) impl::WaitableObjectList(); new (GetPointer(this->waitlist_not_empty)) impl::WaitableObjectList();
new (GetPointer(this->waitlist_not_full)) impl::WaitableObjectList();
} }
MessageQueue::~MessageQueue() { MessageQueue::~MessageQueue() {
GetReference(this->waitable_object_list_storage).~WaitableObjectList(); GetReference(this->waitlist_not_empty).~WaitableObjectList();
GetReference(this->waitlist_not_full).~WaitableObjectList();
} }
void MessageQueue::SendInternal(uintptr_t data) { void MessageQueue::SendInternal(uintptr_t data) {
@ -53,7 +55,7 @@ namespace ams::os {
return data; return data;
} }
uintptr_t MessageQueue::PeekInternal() { inline uintptr_t MessageQueue::PeekInternal() {
/* Ensure we don't corrupt the queue, but this should never happen. */ /* Ensure we don't corrupt the queue, but this should never happen. */
AMS_ASSERT(this->count > 0); AMS_ASSERT(this->count > 0);
@ -70,7 +72,8 @@ namespace ams::os {
/* Send, signal. */ /* Send, signal. */
this->SendInternal(data); this->SendInternal(data);
this->cv_not_empty.WakeAll(); this->cv_not_empty.Broadcast();
GetReference(this->waitlist_not_empty).SignalAllThreads();
} }
bool MessageQueue::TrySend(uintptr_t data) { bool MessageQueue::TrySend(uintptr_t data) {
@ -81,7 +84,8 @@ namespace ams::os {
/* Send, signal. */ /* Send, signal. */
this->SendInternal(data); this->SendInternal(data);
this->cv_not_empty.WakeAll(); this->cv_not_empty.Broadcast();
GetReference(this->waitlist_not_empty).SignalAllThreads();
return true; return true;
} }
@ -94,12 +98,13 @@ namespace ams::os {
return false; return false;
} }
this->cv_not_full.TimedWait(&this->queue_lock, timeout); this->cv_not_full.TimedWait(&this->queue_lock, timeout_helper.NsUntilTimeout());
} }
/* Send, signal. */ /* Send, signal. */
this->SendInternal(data); this->SendInternal(data);
this->cv_not_empty.WakeAll(); this->cv_not_empty.Broadcast();
GetReference(this->waitlist_not_empty).SignalAllThreads();
return true; return true;
} }
@ -113,7 +118,8 @@ namespace ams::os {
/* Send, signal. */ /* Send, signal. */
this->SendNextInternal(data); this->SendNextInternal(data);
this->cv_not_empty.WakeAll(); this->cv_not_empty.Broadcast();
GetReference(this->waitlist_not_empty).SignalAllThreads();
} }
bool MessageQueue::TrySendNext(uintptr_t data) { bool MessageQueue::TrySendNext(uintptr_t data) {
@ -124,7 +130,8 @@ namespace ams::os {
/* Send, signal. */ /* Send, signal. */
this->SendNextInternal(data); this->SendNextInternal(data);
this->cv_not_empty.WakeAll(); this->cv_not_empty.Broadcast();
GetReference(this->waitlist_not_empty).SignalAllThreads();
return true; return true;
} }
@ -137,12 +144,13 @@ namespace ams::os {
return false; return false;
} }
this->cv_not_full.TimedWait(&this->queue_lock, timeout); this->cv_not_full.TimedWait(&this->queue_lock, timeout_helper.NsUntilTimeout());
} }
/* Send, signal. */ /* Send, signal. */
this->SendNextInternal(data); this->SendNextInternal(data);
this->cv_not_empty.WakeAll(); this->cv_not_empty.Broadcast();
GetReference(this->waitlist_not_empty).SignalAllThreads();
return true; return true;
} }
@ -156,8 +164,10 @@ namespace ams::os {
/* Receive, signal. */ /* Receive, signal. */
*out = this->ReceiveInternal(); *out = this->ReceiveInternal();
this->cv_not_full.WakeAll(); this->cv_not_full.Broadcast();
GetReference(this->waitlist_not_full).SignalAllThreads();
} }
bool MessageQueue::TryReceive(uintptr_t *out) { bool MessageQueue::TryReceive(uintptr_t *out) {
/* Acquire mutex, wait receivable. */ /* Acquire mutex, wait receivable. */
std::scoped_lock lock(this->queue_lock); std::scoped_lock lock(this->queue_lock);
@ -168,7 +178,8 @@ namespace ams::os {
/* Receive, signal. */ /* Receive, signal. */
*out = this->ReceiveInternal(); *out = this->ReceiveInternal();
this->cv_not_full.WakeAll(); this->cv_not_full.Broadcast();
GetReference(this->waitlist_not_full).SignalAllThreads();
return true; return true;
} }
@ -181,12 +192,13 @@ namespace ams::os {
return false; return false;
} }
this->cv_not_empty.TimedWait(&this->queue_lock, timeout); this->cv_not_empty.TimedWait(&this->queue_lock, timeout_helper.NsUntilTimeout());
} }
/* Receive, signal. */ /* Receive, signal. */
*out = this->ReceiveInternal(); *out = this->ReceiveInternal();
this->cv_not_full.WakeAll(); this->cv_not_full.Broadcast();
GetReference(this->waitlist_not_full).SignalAllThreads();
return true; return true;
} }
@ -224,7 +236,7 @@ namespace ams::os {
return false; return false;
} }
this->cv_not_empty.TimedWait(&this->queue_lock, timeout); this->cv_not_empty.TimedWait(&this->queue_lock, timeout_helper.NsUntilTimeout());
} }
/* Peek. */ /* Peek. */

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
namespace ams {
namespace {
constexpr inline ::Handle GetCurrentProcessHandleImpl() {
return CUR_PROCESS_HANDLE;
}
}
namespace os {
::Handle __attribute__((const)) GetCurrentProcessHandle() {
return GetCurrentProcessHandleImpl();
}
}
namespace dd {
::Handle __attribute__((const)) GetCurrentProcessHandle() {
return GetCurrentProcessHandleImpl();
}
}
}

View file

@ -88,10 +88,10 @@ namespace ams::spl::impl {
u32 perm; u32 perm;
public: public:
DeviceAddressSpaceMapHelper(Handle h, u64 dst, u64 src, size_t sz, u32 p) : das_hnd(h), dst_addr(dst), src_addr(src), size(sz), perm(p) { DeviceAddressSpaceMapHelper(Handle h, u64 dst, u64 src, size_t sz, u32 p) : das_hnd(h), dst_addr(dst), src_addr(src), size(sz), perm(p) {
R_ASSERT(svcMapDeviceAddressSpaceAligned(this->das_hnd, CUR_PROCESS_HANDLE, this->src_addr, this->size, this->dst_addr, this->perm)); R_ASSERT(svcMapDeviceAddressSpaceAligned(this->das_hnd, dd::GetCurrentProcessHandle(), this->src_addr, this->size, this->dst_addr, this->perm));
} }
~DeviceAddressSpaceMapHelper() { ~DeviceAddressSpaceMapHelper() {
R_ASSERT(svcUnmapDeviceAddressSpace(this->das_hnd, CUR_PROCESS_HANDLE, this->src_addr, this->size, this->dst_addr)); R_ASSERT(svcUnmapDeviceAddressSpace(this->das_hnd, dd::GetCurrentProcessHandle(), this->src_addr, this->size, this->dst_addr));
} }
}; };
@ -149,7 +149,7 @@ namespace ams::spl::impl {
g_se_mapped_work_buffer_addr = WorkBufferMapBase + (work_buffer_addr % DeviceAddressSpaceAlign); g_se_mapped_work_buffer_addr = WorkBufferMapBase + (work_buffer_addr % DeviceAddressSpaceAlign);
/* Map the work buffer for the SE. */ /* Map the work buffer for the SE. */
R_ASSERT(svcMapDeviceAddressSpaceAligned(g_se_das_hnd, CUR_PROCESS_HANDLE, work_buffer_addr, sizeof(g_work_buffer), g_se_mapped_work_buffer_addr, 3)); R_ASSERT(svcMapDeviceAddressSpaceAligned(g_se_das_hnd, dd::GetCurrentProcessHandle(), work_buffer_addr, sizeof(g_work_buffer), g_se_mapped_work_buffer_addr, 3));
} }
/* RSA OAEP implementation helpers. */ /* RSA OAEP implementation helpers. */