Merge pull request #4908 from hamish-milne/feature/savestates-2

Save states
This commit is contained in:
Ben 2020-04-17 21:52:51 +02:00 committed by GitHub
commit c605bb42db
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
354 changed files with 6100 additions and 604 deletions

View file

@ -3,8 +3,10 @@
// Refer to the license.txt file included.
#include <algorithm>
#include "common/archives.h"
#include "common/common_types.h"
#include "common/logging/log.h"
#include "core/global.h"
#include "core/hle/kernel/address_arbiter.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/kernel.h"
@ -14,6 +16,8 @@
////////////////////////////////////////////////////////////////////////////////////////////////////
// Kernel namespace
SERIALIZE_EXPORT_IMPL(Kernel::AddressArbiter)
namespace Kernel {
void AddressArbiter::WaitThread(std::shared_ptr<Thread> thread, VAddr wait_address) {
@ -76,16 +80,18 @@ std::shared_ptr<AddressArbiter> KernelSystem::CreateAddressArbiter(std::string n
return address_arbiter;
}
void AddressArbiter::WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
std::shared_ptr<WaitObject> object) {
ASSERT(reason == ThreadWakeupReason::Timeout);
// Remove the newly-awakened thread from the Arbiter's waiting list.
waiting_threads.erase(std::remove(waiting_threads.begin(), waiting_threads.end(), thread),
waiting_threads.end());
};
ResultCode AddressArbiter::ArbitrateAddress(std::shared_ptr<Thread> thread, ArbitrationType type,
VAddr address, s32 value, u64 nanoseconds) {
auto timeout_callback = [this](ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
std::shared_ptr<WaitObject> object) {
ASSERT(reason == ThreadWakeupReason::Timeout);
// Remove the newly-awakened thread from the Arbiter's waiting list.
waiting_threads.erase(std::remove(waiting_threads.begin(), waiting_threads.end(), thread),
waiting_threads.end());
};
auto timeout_callback = std::dynamic_pointer_cast<WakeupCallback>(shared_from_this());
switch (type) {

View file

@ -6,8 +6,15 @@
#include <memory>
#include <vector>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/version.hpp>
#include "common/common_types.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/result.h"
// Address arbiters are an underlying kernel synchronization object that can be created/used via
@ -30,7 +37,7 @@ enum class ArbitrationType : u32 {
DecrementAndWaitIfLessThanWithTimeout,
};
class AddressArbiter final : public Object {
class AddressArbiter final : public Object, public WakeupCallback {
public:
explicit AddressArbiter(KernelSystem& kernel);
~AddressArbiter() override;
@ -52,6 +59,9 @@ public:
ResultCode ArbitrateAddress(std::shared_ptr<Thread> thread, ArbitrationType type, VAddr address,
s32 value, u64 nanoseconds);
void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
std::shared_ptr<WaitObject> object);
private:
KernelSystem& kernel;
@ -67,6 +77,21 @@ private:
/// Threads waiting for the address arbiter to be signaled.
std::vector<std::shared_ptr<Thread>> waiting_threads;
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& boost::serialization::base_object<Object>(*this);
if (file_version > 0) {
ar& boost::serialization::base_object<WakeupCallback>(*this);
}
ar& name;
ar& waiting_threads;
}
};
} // namespace Kernel
BOOST_CLASS_EXPORT_KEY(Kernel::AddressArbiter)
BOOST_CLASS_VERSION(Kernel::AddressArbiter, 1)
CONSTRUCT_KERNEL_OBJECT(Kernel::AddressArbiter)

View file

@ -2,7 +2,9 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/archives.h"
#include "common/assert.h"
#include "core/global.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/errors.h"
@ -11,6 +13,8 @@
#include "core/hle/kernel/server_port.h"
#include "core/hle/kernel/server_session.h"
SERIALIZE_EXPORT_IMPL(Kernel::ClientPort)
namespace Kernel {
ClientPort::ClientPort(KernelSystem& kernel) : Object(kernel), kernel(kernel) {}

View file

@ -6,6 +6,9 @@
#include <memory>
#include <string>
#include <boost/serialization/export.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/string.hpp>
#include "common/common_types.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/server_port.h"
@ -59,6 +62,20 @@ private:
std::string name; ///< Name of client port (optional)
friend class KernelSystem;
private:
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& boost::serialization::base_object<Object>(*this);
ar& server_port;
ar& max_sessions;
ar& active_sessions;
ar& name;
}
};
} // namespace Kernel
BOOST_CLASS_EXPORT_KEY(Kernel::ClientPort)
CONSTRUCT_KERNEL_OBJECT(Kernel::ClientPort)

View file

@ -2,8 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/archives.h"
#include "common/assert.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/hle_ipc.h"
@ -11,6 +11,8 @@
#include "core/hle/kernel/session.h"
#include "core/hle/kernel/thread.h"
SERIALIZE_EXPORT_IMPL(Kernel::ClientSession)
namespace Kernel {
ClientSession::ClientSession(KernelSystem& kernel) : Object(kernel) {}

View file

@ -6,6 +6,10 @@
#include <memory>
#include <string>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/string.hpp>
#include "common/common_types.h"
#include "core/hle/kernel/object.h"
#include "core/hle/result.h"
@ -46,6 +50,18 @@ public:
/// The parent session, which links to the server endpoint.
std::shared_ptr<Session> parent;
private:
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& boost::serialization::base_object<Object>(*this);
ar& name;
ar& parent;
}
};
} // namespace Kernel
BOOST_CLASS_EXPORT_KEY(Kernel::ClientSession)
CONSTRUCT_KERNEL_OBJECT(Kernel::ClientSession)

View file

@ -3,10 +3,13 @@
// Refer to the license.txt file included.
#include <cstring>
#include "common/archives.h"
#include "core/hle/kernel/config_mem.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
SERIALIZE_EXPORT_IMPL(ConfigMem::Handler)
namespace ConfigMem {
Handler::Handler() {

View file

@ -9,8 +9,11 @@
// bootrom. Because we're not emulating this, and essentially just "stubbing" the functionality, I'm
// putting this as a subset of HLE for now.
#include <boost/serialization/binary_object.hpp>
#include <boost/serialization/export.hpp>
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/memory_ref.h"
#include "common/swap.h"
#include "core/memory.h"
@ -49,13 +52,34 @@ struct ConfigMemDef {
static_assert(sizeof(ConfigMemDef) == Memory::CONFIG_MEMORY_SIZE,
"Config Memory structure size is wrong");
class Handler {
class Handler : public BackingMem {
public:
Handler();
ConfigMemDef& GetConfigMem();
u8* GetPtr() override {
return reinterpret_cast<u8*>(&config_mem);
}
const u8* GetPtr() const override {
return reinterpret_cast<const u8*>(&config_mem);
}
std::size_t GetSize() const override {
return sizeof(config_mem);
}
private:
ConfigMemDef config_mem;
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& boost::serialization::base_object<BackingMem>(*this);
ar& boost::serialization::make_binary_object(&config_mem, sizeof(config_mem));
}
};
} // namespace ConfigMem
BOOST_CLASS_EXPORT_KEY(ConfigMem::Handler)

View file

@ -5,11 +5,14 @@
#include <algorithm>
#include <map>
#include <vector>
#include "common/archives.h"
#include "common/assert.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/thread.h"
SERIALIZE_EXPORT_IMPL(Kernel::Event)
namespace Kernel {
Event::Event(KernelSystem& kernel) : WaitObject(kernel) {}

View file

@ -4,6 +4,9 @@
#pragma once
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/string.hpp>
#include "common/common_types.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/wait_object.h"
@ -49,6 +52,18 @@ private:
std::string name; ///< Name of event (optional)
friend class KernelSystem;
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& boost::serialization::base_object<WaitObject>(*this);
ar& reset_type;
ar& signaled;
ar& name;
}
};
} // namespace Kernel
BOOST_CLASS_EXPORT_KEY(Kernel::Event)
CONSTRUCT_KERNEL_OBJECT(Kernel::Event)

View file

@ -7,6 +7,8 @@
#include <array>
#include <cstddef>
#include <memory>
#include <boost/serialization/array.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include "common/common_types.h"
#include "core/hle/kernel/object.h"
#include "core/hle/result.h"
@ -116,6 +118,15 @@ private:
u16 next_free_slot;
KernelSystem& kernel;
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& objects;
ar& generations;
ar& next_generation;
ar& next_free_slot;
}
};
} // namespace Kernel

View file

@ -16,6 +16,47 @@
namespace Kernel {
class HLERequestContext::ThreadCallback : public Kernel::WakeupCallback {
public:
ThreadCallback(std::shared_ptr<HLERequestContext> context_,
std::shared_ptr<HLERequestContext::WakeupCallback> callback_)
: context(std::move(context_)), callback(std::move(callback_)) {}
void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
std::shared_ptr<WaitObject> object) {
ASSERT(thread->status == ThreadStatus::WaitHleEvent);
if (callback) {
callback->WakeUp(thread, *context, reason);
}
auto& process = thread->owner_process;
// We must copy the entire command buffer *plus* the entire static buffers area, since
// the translation might need to read from it in order to retrieve the StaticBuffer
// target addresses.
std::array<u32_le, IPC::COMMAND_BUFFER_LENGTH + 2 * IPC::MAX_STATIC_BUFFERS> cmd_buff;
Memory::MemorySystem& memory = context->kernel.memory;
memory.ReadBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(),
cmd_buff.size() * sizeof(u32));
context->WriteToOutgoingCommandBuffer(cmd_buff.data(), *process);
// Copy the translated command buffer back into the thread's command buffer area.
memory.WriteBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(),
cmd_buff.size() * sizeof(u32));
}
private:
ThreadCallback() = default;
std::shared_ptr<HLERequestContext::WakeupCallback> callback{};
std::shared_ptr<HLERequestContext> context{};
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& boost::serialization::base_object<Kernel::WakeupCallback>(*this);
ar& callback;
ar& context;
}
friend class boost::serialization::access;
};
SessionRequestHandler::SessionInfo::SessionInfo(std::shared_ptr<ServerSession> session,
std::unique_ptr<SessionDataBase> data)
: session(std::move(session)), data(std::move(data)) {}
@ -33,34 +74,16 @@ void SessionRequestHandler::ClientDisconnected(std::shared_ptr<ServerSession> se
connected_sessions.end());
}
std::shared_ptr<Event> HLERequestContext::SleepClientThread(const std::string& reason,
std::chrono::nanoseconds timeout,
WakeupCallback&& callback) {
std::shared_ptr<Event> HLERequestContext::SleepClientThread(
const std::string& reason, std::chrono::nanoseconds timeout,
std::shared_ptr<WakeupCallback> callback) {
// Put the client thread to sleep until the wait event is signaled or the timeout expires.
thread->wakeup_callback = [context = *this,
callback](ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
std::shared_ptr<WaitObject> object) mutable {
ASSERT(thread->status == ThreadStatus::WaitHleEvent);
callback(thread, context, reason);
auto& process = thread->owner_process;
// We must copy the entire command buffer *plus* the entire static buffers area, since
// the translation might need to read from it in order to retrieve the StaticBuffer
// target addresses.
std::array<u32_le, IPC::COMMAND_BUFFER_LENGTH + 2 * IPC::MAX_STATIC_BUFFERS> cmd_buff;
Memory::MemorySystem& memory = context.kernel.memory;
memory.ReadBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(),
cmd_buff.size() * sizeof(u32));
context.WriteToOutgoingCommandBuffer(cmd_buff.data(), *process);
// Copy the translated command buffer back into the thread's command buffer area.
memory.WriteBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(),
cmd_buff.size() * sizeof(u32));
};
thread->wakeup_callback = std::make_shared<ThreadCallback>(shared_from_this(), callback);
auto event = kernel.CreateEvent(Kernel::ResetType::OneShot, "HLE Pause Event: " + reason);
thread->status = ThreadStatus::WaitHleEvent;
thread->wait_objects = {event};
event->AddWaitingThread(SharedFrom(thread));
event->AddWaitingThread(thread);
if (timeout.count() > 0)
thread->WakeAfterDelay(timeout.count());
@ -68,8 +91,10 @@ std::shared_ptr<Event> HLERequestContext::SleepClientThread(const std::string& r
return event;
}
HLERequestContext::HLERequestContext() : kernel(Core::Global<KernelSystem>()) {}
HLERequestContext::HLERequestContext(KernelSystem& kernel, std::shared_ptr<ServerSession> session,
Thread* thread)
std::shared_ptr<Thread> thread)
: kernel(kernel), session(std::move(session)), thread(thread) {
cmd_buf[0] = 0;
}
@ -98,8 +123,9 @@ void HLERequestContext::AddStaticBuffer(u8 buffer_id, std::vector<u8> data) {
static_buffers[buffer_id] = std::move(data);
}
ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf,
Process& src_process) {
ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(
const u32_le* src_cmdbuf, std::shared_ptr<Process> src_process_) {
auto& src_process = *src_process_;
IPC::Header header{src_cmdbuf[0]};
std::size_t untranslated_size = 1u + header.normal_params_size;
@ -158,7 +184,7 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* sr
}
case IPC::DescriptorType::MappedBuffer: {
u32 next_id = static_cast<u32>(request_mapped_buffers.size());
request_mapped_buffers.emplace_back(kernel.memory, src_process, descriptor,
request_mapped_buffers.emplace_back(kernel.memory, src_process_, descriptor,
src_cmdbuf[i], next_id);
cmd_buf[i++] = next_id;
break;
@ -170,7 +196,7 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* sr
if (should_record) {
std::vector<u32> translated_cmdbuf{cmd_buf.begin(), cmd_buf.begin() + command_size};
kernel.GetIPCRecorder().SetRequestInfo(SharedFrom(thread), std::move(untranslated_cmdbuf),
kernel.GetIPCRecorder().SetRequestInfo(thread, std::move(untranslated_cmdbuf),
std::move(translated_cmdbuf));
}
@ -248,7 +274,7 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf,
if (should_record) {
std::vector<u32> translated_cmdbuf{dst_cmdbuf, dst_cmdbuf + command_size};
kernel.GetIPCRecorder().SetReplyInfo(SharedFrom(thread), std::move(untranslated_cmdbuf),
kernel.GetIPCRecorder().SetReplyInfo(thread, std::move(untranslated_cmdbuf),
std::move(translated_cmdbuf));
}
@ -262,13 +288,15 @@ MappedBuffer& HLERequestContext::GetMappedBuffer(u32 id_from_cmdbuf) {
void HLERequestContext::ReportUnimplemented() const {
if (kernel.GetIPCRecorder().IsEnabled()) {
kernel.GetIPCRecorder().SetHLEUnimplemented(SharedFrom(thread));
kernel.GetIPCRecorder().SetHLEUnimplemented(thread);
}
}
MappedBuffer::MappedBuffer(Memory::MemorySystem& memory, const Process& process, u32 descriptor,
VAddr address, u32 id)
: memory(&memory), id(id), address(address), process(&process) {
MappedBuffer::MappedBuffer() : memory(&Core::Global<Core::System>().Memory()) {}
MappedBuffer::MappedBuffer(Memory::MemorySystem& memory, std::shared_ptr<Process> process,
u32 descriptor, VAddr address, u32 id)
: memory(&memory), id(id), address(address), process(std::move(process)) {
IPC::MappedBufferDescInfo desc{descriptor};
size = desc.size;
perms = desc.perms;
@ -287,3 +315,5 @@ void MappedBuffer::Write(const void* src_buffer, std::size_t offset, std::size_t
}
} // namespace Kernel
SERIALIZE_EXPORT_IMPL(Kernel::HLERequestContext::ThreadCallback)

View file

@ -11,7 +11,12 @@
#include <string>
#include <vector>
#include <boost/container/small_vector.hpp>
#include <boost/serialization/assume_abstract.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/unique_ptr.hpp>
#include <boost/serialization/vector.hpp>
#include "common/common_types.h"
#include "common/serialization/boost_small_vector.hpp"
#include "common/swap.h"
#include "core/hle/ipc.h"
#include "core/hle/kernel/object.h"
@ -68,6 +73,11 @@ public:
/// in each service must inherit from this.
struct SessionDataBase {
virtual ~SessionDataBase() = default;
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {}
friend class boost::serialization::access;
};
protected:
@ -90,15 +100,33 @@ protected:
std::shared_ptr<ServerSession> session;
std::unique_ptr<SessionDataBase> data;
private:
SessionInfo() = default;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& session;
ar& data;
}
friend class boost::serialization::access;
};
/// List of sessions that are connected to this handler. A ServerSession whose server endpoint
/// is an HLE implementation is kept alive by this list for the duration of the connection.
std::vector<SessionInfo> connected_sessions;
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& connected_sessions;
}
friend class boost::serialization::access;
};
// NOTE: The below classes are ephemeral and don't need serialization
class MappedBuffer {
public:
MappedBuffer(Memory::MemorySystem& memory, const Process& process, u32 descriptor,
MappedBuffer(Memory::MemorySystem& memory, std::shared_ptr<Process> process, u32 descriptor,
VAddr address, u32 id);
// interface for service
@ -122,9 +150,21 @@ private:
Memory::MemorySystem* memory;
u32 id;
VAddr address;
const Process* process;
std::size_t size;
std::shared_ptr<Process> process;
u32 size;
IPC::MappedBufferPermissions perms;
MappedBuffer();
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& id;
ar& address;
ar& process;
ar& size;
ar& perms;
}
friend class boost::serialization::access;
};
/**
@ -156,9 +196,10 @@ private:
* id of the memory interface and let kernel convert it back to client vaddr. No real unmapping is
* needed in this case, though.
*/
class HLERequestContext {
class HLERequestContext : public std::enable_shared_from_this<HLERequestContext> {
public:
HLERequestContext(KernelSystem& kernel, std::shared_ptr<ServerSession> session, Thread* thread);
HLERequestContext(KernelSystem& kernel, std::shared_ptr<ServerSession> session,
std::shared_ptr<Thread> thread);
~HLERequestContext();
/// Returns a pointer to the IPC command buffer for this request.
@ -174,8 +215,17 @@ public:
return session;
}
using WakeupCallback = std::function<void(
std::shared_ptr<Thread> thread, HLERequestContext& context, ThreadWakeupReason reason)>;
class WakeupCallback {
public:
virtual ~WakeupCallback() = default;
virtual void WakeUp(std::shared_ptr<Thread> thread, HLERequestContext& context,
ThreadWakeupReason reason) = 0;
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int) {}
friend class boost::serialization::access;
};
/**
* Puts the specified guest thread to sleep until the returned event is signaled or until the
@ -190,7 +240,7 @@ public:
*/
std::shared_ptr<Event> SleepClientThread(const std::string& reason,
std::chrono::nanoseconds timeout,
WakeupCallback&& callback);
std::shared_ptr<WakeupCallback> callback);
/**
* Resolves a object id from the request command buffer into a pointer to an object. See the
@ -230,24 +280,42 @@ public:
MappedBuffer& GetMappedBuffer(u32 id_from_cmdbuf);
/// Populates this context with data from the requesting process/thread.
ResultCode PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf, Process& src_process);
ResultCode PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf,
std::shared_ptr<Process> src_process);
/// Writes data from this context back to the requesting process/thread.
ResultCode WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process) const;
/// Reports an unimplemented function.
void ReportUnimplemented() const;
class ThreadCallback;
friend class ThreadCallback;
private:
KernelSystem& kernel;
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
std::shared_ptr<ServerSession> session;
Thread* thread;
std::shared_ptr<Thread> thread;
// TODO(yuriks): Check common usage of this and optimize size accordingly
boost::container::small_vector<std::shared_ptr<Object>, 8> request_handles;
// The static buffers will be created when the IPC request is translated.
std::array<std::vector<u8>, IPC::MAX_STATIC_BUFFERS> static_buffers;
// The mapped buffers will be created when the IPC request is translated
boost::container::small_vector<MappedBuffer, 8> request_mapped_buffers;
HLERequestContext();
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& cmd_buf;
ar& session;
ar& thread;
ar& request_handles;
ar& static_buffers;
ar& request_mapped_buffers;
}
friend class boost::serialization::access;
};
} // namespace Kernel
BOOST_CLASS_EXPORT_KEY(Kernel::HLERequestContext::ThreadCallback)

View file

@ -4,6 +4,7 @@
#include <algorithm>
#include "common/alignment.h"
#include "common/memory_ref.h"
#include "core/core.h"
#include "core/hle/ipc.h"
#include "core/hle/kernel/handle_table.h"
@ -71,7 +72,7 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy
if (handle == CurrentThread) {
object = src_thread;
} else if (handle == CurrentProcess) {
object = SharedFrom(src_process);
object = src_process;
} else if (handle != 0) {
object = src_process->handle_table.GetGeneric(handle);
if (descriptor == IPC::DescriptorType::MoveHandle) {
@ -193,28 +194,29 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy
// TODO(Subv): Perform permission checks.
// Reserve a page of memory before the mapped buffer
auto reserve_buffer = std::make_unique<u8[]>(Memory::PAGE_SIZE);
std::shared_ptr<BackingMem> reserve_buffer =
std::make_shared<BufferMem>(Memory::PAGE_SIZE);
dst_process->vm_manager.MapBackingMemoryToBase(
Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, reserve_buffer.get(),
Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, reserve_buffer,
Memory::PAGE_SIZE, Kernel::MemoryState::Reserved);
auto buffer = std::make_unique<u8[]>(num_pages * Memory::PAGE_SIZE);
memory.ReadBlock(*src_process, source_address, buffer.get() + page_offset, size);
std::shared_ptr<BackingMem> buffer =
std::make_shared<BufferMem>(num_pages * Memory::PAGE_SIZE);
memory.ReadBlock(*src_process, source_address, buffer->GetPtr() + page_offset, size);
// Map the page(s) into the target process' address space.
target_address =
dst_process->vm_manager
.MapBackingMemoryToBase(Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE,
buffer.get(), num_pages * Memory::PAGE_SIZE,
Kernel::MemoryState::Shared)
buffer, buffer->GetSize(), Kernel::MemoryState::Shared)
.Unwrap();
cmd_buf[i++] = target_address + page_offset;
// Reserve a page of memory after the mapped buffer
dst_process->vm_manager.MapBackingMemoryToBase(
Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, reserve_buffer.get(),
Memory::PAGE_SIZE, Kernel::MemoryState::Reserved);
Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, reserve_buffer,
reserve_buffer->GetSize(), Kernel::MemoryState::Reserved);
mapped_buffer_context.push_back({permissions, size, source_address,
target_address + page_offset, std::move(buffer),

View file

@ -6,6 +6,7 @@
#include <memory>
#include <vector>
#include <boost/serialization/shared_ptr.hpp>
#include "common/common_types.h"
#include "core/hle/ipc.h"
#include "core/hle/kernel/thread.h"
@ -24,8 +25,20 @@ struct MappedBufferContext {
VAddr source_address;
VAddr target_address;
std::unique_ptr<u8[]> buffer;
std::unique_ptr<u8[]> reserve_buffer;
std::shared_ptr<BackingMem> buffer;
std::shared_ptr<BackingMem> reserve_buffer;
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& permissions;
ar& size;
ar& source_address;
ar& target_address;
ar& buffer;
ar& reserve_buffer;
}
friend class boost::serialization::access;
};
/// Performs IPC command buffer translation from one process to another.

View file

@ -52,7 +52,7 @@ void Recorder::RegisterRequest(const std::shared_ptr<Kernel::ClientSession>& cli
RequestRecord record = {/* id */ ++record_count,
/* status */ RequestStatus::Sent,
/* client_process */ GetObjectInfo(client_thread->owner_process),
/* client_process */ GetObjectInfo(client_thread->owner_process.get()),
/* client_thread */ GetObjectInfo(client_thread.get()),
/* client_session */ GetObjectInfo(client_session.get()),
/* client_port */ GetObjectInfo(client_session->parent->port.get()),
@ -82,7 +82,7 @@ void Recorder::SetRequestInfo(const std::shared_ptr<Kernel::Thread>& client_thre
record.translated_request_cmdbuf = std::move(translated_cmdbuf);
if (server_thread) {
record.server_process = GetObjectInfo(server_thread->owner_process);
record.server_process = GetObjectInfo(server_thread->owner_process.get());
record.server_thread = GetObjectInfo(server_thread.get());
} else {
record.is_hle = true;

View file

@ -2,6 +2,11 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/unordered_map.hpp>
#include <boost/serialization/vector.hpp>
#include "common/archives.h"
#include "common/serialization/atomic.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/config_mem.h"
#include "core/hle/kernel/handle_table.h"
@ -22,6 +27,8 @@ KernelSystem::KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing,
u32 num_cores, u8 n3ds_mode)
: memory(memory), timing(timing),
prepare_reschedule_callback(std::move(prepare_reschedule_callback)) {
std::generate(memory_regions.begin(), memory_regions.end(),
[] { return std::make_shared<MemoryRegionInfo>(); });
MemoryInit(system_mode, n3ds_mode);
resource_limits = std::make_unique<ResourceLimitList>(*this);
@ -58,24 +65,23 @@ std::shared_ptr<Process> KernelSystem::GetCurrentProcess() const {
void KernelSystem::SetCurrentProcess(std::shared_ptr<Process> process) {
current_process = process;
SetCurrentMemoryPageTable(&process->vm_manager.page_table);
SetCurrentMemoryPageTable(process->vm_manager.page_table);
}
void KernelSystem::SetCurrentProcessForCPU(std::shared_ptr<Process> process, u32 core_id) {
if (current_cpu->GetID() == core_id) {
current_process = process;
SetCurrentMemoryPageTable(&process->vm_manager.page_table);
SetCurrentMemoryPageTable(process->vm_manager.page_table);
} else {
stored_processes[core_id] = process;
thread_managers[core_id]->cpu->PageTableChanged(&process->vm_manager.page_table);
thread_managers[core_id]->cpu->SetPageTable(process->vm_manager.page_table);
}
}
void KernelSystem::SetCurrentMemoryPageTable(Memory::PageTable* page_table) {
void KernelSystem::SetCurrentMemoryPageTable(std::shared_ptr<Memory::PageTable> page_table) {
memory.SetCurrentPageTable(page_table);
if (current_cpu != nullptr) {
// Notify the CPU the page table in memory has changed
current_cpu->PageTableChanged(page_table);
current_cpu->SetPageTable(page_table);
}
}
@ -150,4 +156,29 @@ void KernelSystem::ResetThreadIDs() {
next_thread_id = 0;
}
template <class Archive>
void KernelSystem::serialize(Archive& ar, const unsigned int file_version) {
ar& memory_regions;
ar& named_ports;
// current_cpu set externally
// NB: subsystem references and prepare_reschedule_callback are constant
ar&* resource_limits.get();
ar& next_object_id;
ar&* timer_manager.get();
ar& next_process_id;
ar& process_list;
ar& current_process;
// NB: core count checked in 'core'
for (auto& thread_manager : thread_managers) {
ar&* thread_manager.get();
}
ar& config_mem_handler;
ar& shared_page_handler;
ar& stored_processes;
ar& next_thread_id;
// Deliberately don't include debugger info to allow debugging through loads
}
SERIALIZE_IMPL(KernelSystem)
} // namespace Kernel

View file

@ -132,7 +132,8 @@ public:
*/
ResultVal<std::shared_ptr<Thread>> CreateThread(std::string name, VAddr entry_point,
u32 priority, u32 arg, s32 processor_id,
VAddr stack_top, Process& owner_process);
VAddr stack_top,
std::shared_ptr<Process> owner_process);
/**
* Creates a semaphore.
@ -213,7 +214,7 @@ public:
void SetCurrentProcess(std::shared_ptr<Process> process);
void SetCurrentProcessForCPU(std::shared_ptr<Process> process, u32 core_id);
void SetCurrentMemoryPageTable(Memory::PageTable* page_table);
void SetCurrentMemoryPageTable(std::shared_ptr<Memory::PageTable> page_table);
void SetCPUs(std::vector<std::shared_ptr<ARM_Interface>> cpu);
@ -236,11 +237,11 @@ public:
IPCDebugger::Recorder& GetIPCRecorder();
const IPCDebugger::Recorder& GetIPCRecorder() const;
MemoryRegionInfo* GetMemoryRegion(MemoryRegion region);
std::shared_ptr<MemoryRegionInfo> GetMemoryRegion(MemoryRegion region);
void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping);
std::array<MemoryRegionInfo, 3> memory_regions;
std::array<std::shared_ptr<MemoryRegionInfo>, 3> memory_regions{};
/// Adds a port to the named port table
void AddNamedPort(std::string name, std::shared_ptr<ClientPort> port);
@ -291,12 +292,16 @@ private:
std::vector<std::unique_ptr<ThreadManager>> thread_managers;
std::unique_ptr<ConfigMem::Handler> config_mem_handler;
std::unique_ptr<SharedPage::Handler> shared_page_handler;
std::shared_ptr<ConfigMem::Handler> config_mem_handler;
std::shared_ptr<SharedPage::Handler> shared_page_handler;
std::unique_ptr<IPCDebugger::Recorder> ipc_recorder;
u32 next_thread_id;
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version);
};
} // namespace Kernel

View file

@ -71,32 +71,32 @@ void KernelSystem::MemoryInit(u32 mem_type, u8 n3ds_mode) {
// the sizes specified in the memory_region_sizes table.
VAddr base = 0;
for (int i = 0; i < 3; ++i) {
memory_regions[i].Reset(base, memory_region_sizes[mem_type][i]);
memory_regions[i]->Reset(base, memory_region_sizes[mem_type][i]);
base += memory_regions[i].size;
base += memory_regions[i]->size;
}
// We must've allocated the entire FCRAM by the end
ASSERT(base == (is_new_3ds ? Memory::FCRAM_N3DS_SIZE : Memory::FCRAM_SIZE));
config_mem_handler = std::make_unique<ConfigMem::Handler>();
config_mem_handler = std::make_shared<ConfigMem::Handler>();
auto& config_mem = config_mem_handler->GetConfigMem();
config_mem.app_mem_type = reported_mem_type;
config_mem.app_mem_alloc = memory_region_sizes[reported_mem_type][0];
config_mem.sys_mem_alloc = memory_regions[1].size;
config_mem.base_mem_alloc = memory_regions[2].size;
config_mem.sys_mem_alloc = memory_regions[1]->size;
config_mem.base_mem_alloc = memory_regions[2]->size;
shared_page_handler = std::make_unique<SharedPage::Handler>(timing);
shared_page_handler = std::make_shared<SharedPage::Handler>(timing);
}
MemoryRegionInfo* KernelSystem::GetMemoryRegion(MemoryRegion region) {
std::shared_ptr<MemoryRegionInfo> KernelSystem::GetMemoryRegion(MemoryRegion region) {
switch (region) {
case MemoryRegion::APPLICATION:
return &memory_regions[0];
return memory_regions[0];
case MemoryRegion::SYSTEM:
return &memory_regions[1];
return memory_regions[1];
case MemoryRegion::BASE:
return &memory_regions[2];
return memory_regions[2];
default:
UNREACHABLE();
}
@ -147,7 +147,7 @@ void KernelSystem::HandleSpecialMapping(VMManager& address_space, const AddressM
return;
}
u8* target_pointer = memory.GetPhysicalPointer(area->paddr_base + offset_into_region);
auto target_pointer = memory.GetPhysicalRef(area->paddr_base + offset_into_region);
// TODO(yuriks): This flag seems to have some other effect, but it's unknown what
MemoryState memory_state = mapping.unk_flag ? MemoryState::Static : MemoryState::IO;
@ -160,20 +160,16 @@ void KernelSystem::HandleSpecialMapping(VMManager& address_space, const AddressM
}
void KernelSystem::MapSharedPages(VMManager& address_space) {
auto cfg_mem_vma =
address_space
.MapBackingMemory(Memory::CONFIG_MEMORY_VADDR,
reinterpret_cast<u8*>(&config_mem_handler->GetConfigMem()),
Memory::CONFIG_MEMORY_SIZE, MemoryState::Shared)
.Unwrap();
auto cfg_mem_vma = address_space
.MapBackingMemory(Memory::CONFIG_MEMORY_VADDR, {config_mem_handler},
Memory::CONFIG_MEMORY_SIZE, MemoryState::Shared)
.Unwrap();
address_space.Reprotect(cfg_mem_vma, VMAPermission::Read);
auto shared_page_vma =
address_space
.MapBackingMemory(Memory::SHARED_PAGE_VADDR,
reinterpret_cast<u8*>(&shared_page_handler->GetSharedPage()),
Memory::SHARED_PAGE_SIZE, MemoryState::Shared)
.Unwrap();
auto shared_page_vma = address_space
.MapBackingMemory(Memory::SHARED_PAGE_VADDR, {shared_page_handler},
Memory::SHARED_PAGE_SIZE, MemoryState::Shared)
.Unwrap();
address_space.Reprotect(shared_page_vma, VMAPermission::Read);
}

View file

@ -6,7 +6,9 @@
#include <optional>
#include <boost/icl/interval_set.hpp>
#include <boost/serialization/set.hpp>
#include "common/common_types.h"
#include "common/serialization/boost_interval_set.hpp"
namespace Kernel {
@ -60,6 +62,16 @@ struct MemoryRegionInfo {
* @param size the size of the region to free.
*/
void Free(u32 offset, u32 size);
private:
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& base;
ar& size;
ar& used;
ar& free_blocks;
}
};
} // namespace Kernel

View file

@ -4,14 +4,18 @@
#include <map>
#include <vector>
#include "common/archives.h"
#include "common/assert.h"
#include "core/core.h"
#include "core/global.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/mutex.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/thread.h"
SERIALIZE_EXPORT_IMPL(Kernel::Mutex)
namespace Kernel {
void ReleaseThreadMutexes(Thread* thread) {

View file

@ -6,6 +6,10 @@
#include <memory>
#include <string>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/string.hpp>
#include "common/common_types.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/wait_object.h"
@ -58,6 +62,16 @@ public:
private:
KernelSystem& kernel;
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& boost::serialization::base_object<WaitObject>(*this);
ar& lock_count;
ar& priority;
ar& name;
ar& holding_thread;
}
};
/**
@ -67,3 +81,6 @@ private:
void ReleaseThreadMutexes(Thread* thread);
} // namespace Kernel
BOOST_CLASS_EXPORT_KEY(Kernel::Mutex)
CONSTRUCT_KERNEL_OBJECT(Kernel::Mutex)

View file

@ -7,7 +7,12 @@
#include <atomic>
#include <memory>
#include <string>
#include <boost/serialization/access.hpp>
#include <boost/serialization/assume_abstract.hpp>
#include <boost/serialization/export.hpp>
#include "common/common_types.h"
#include "common/serialization/atomic.h"
#include "core/global.h"
#include "core/hle/kernel/kernel.h"
namespace Kernel {
@ -64,6 +69,12 @@ public:
private:
std::atomic<u32> object_id;
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& object_id;
}
};
template <typename T>
@ -87,3 +98,13 @@ inline std::shared_ptr<T> DynamicObjectCast(std::shared_ptr<Object> object) {
}
} // namespace Kernel
BOOST_SERIALIZATION_ASSUME_ABSTRACT(Kernel::Object)
#define CONSTRUCT_KERNEL_OBJECT(T) \
namespace boost::serialization { \
template <class Archive> \
void load_construct_data(Archive& ar, T* t, const unsigned int file_version) { \
::new (t) T(Core::Global<Kernel::KernelSystem>()); \
} \
}

View file

@ -4,9 +4,14 @@
#include <algorithm>
#include <memory>
#include <boost/serialization/array.hpp>
#include <boost/serialization/bitset.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include "common/archives.h"
#include "common/assert.h"
#include "common/common_funcs.h"
#include "common/logging/log.h"
#include "common/serialization/boost_vector.hpp"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/process.h"
@ -15,8 +20,34 @@
#include "core/hle/kernel/vm_manager.h"
#include "core/memory.h"
SERIALIZE_EXPORT_IMPL(Kernel::Process)
SERIALIZE_EXPORT_IMPL(Kernel::CodeSet)
namespace Kernel {
template <class Archive>
void Process::serialize(Archive& ar, const unsigned int file_version) {
ar& boost::serialization::base_object<Object>(*this);
ar& handle_table;
ar& codeset; // TODO: Replace with apploader reference
ar& resource_limit;
ar& svc_access_mask;
ar& handle_table_size;
ar&(boost::container::vector<AddressMapping, boost::container::dtl::static_storage_allocator<
AddressMapping, 8, 0, true>>&)address_mappings;
ar& flags.raw;
ar& kernel_version;
ar& ideal_processor;
ar& status;
ar& process_id;
ar& vm_manager;
ar& memory_used;
ar& memory_region;
ar& tls_slots;
}
SERIALIZE_IMPL(Process)
std::shared_ptr<CodeSet> KernelSystem::CreateCodeSet(std::string name, u64 program_id) {
auto codeset{std::make_shared<CodeSet>(*this)};
@ -191,7 +222,7 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u32 size, VMAPermission per
std::fill(kernel.memory.GetFCRAMPointer(interval.lower()),
kernel.memory.GetFCRAMPointer(interval.upper()), 0);
auto vma = vm_manager.MapBackingMemory(interval_target,
kernel.memory.GetFCRAMPointer(interval.lower()),
kernel.memory.GetFCRAMRef(interval.lower()),
interval_size, memory_state);
ASSERT(vma.Succeeded());
vm_manager.Reprotect(vma.Unwrap(), perms);
@ -219,7 +250,7 @@ ResultCode Process::HeapFree(VAddr target, u32 size) {
// Free heaps block by block
CASCADE_RESULT(auto backing_blocks, vm_manager.GetBackingBlocksForRange(target, size));
for (const auto [backing_memory, block_size] : backing_blocks) {
memory_region->Free(kernel.memory.GetFCRAMOffset(backing_memory), block_size);
memory_region->Free(kernel.memory.GetFCRAMOffset(backing_memory.GetPtr()), block_size);
}
ResultCode result = vm_manager.UnmapRange(target, size);
@ -263,9 +294,9 @@ ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission p
}
}
u8* backing_memory = kernel.memory.GetFCRAMPointer(physical_offset);
auto backing_memory = kernel.memory.GetFCRAMRef(physical_offset);
std::fill(backing_memory, backing_memory + size, 0);
std::fill(backing_memory.GetPtr(), backing_memory.GetPtr() + size, 0);
auto vma = vm_manager.MapBackingMemory(target, backing_memory, size, MemoryState::Continuous);
ASSERT(vma.Succeeded());
vm_manager.Reprotect(vma.Unwrap(), perms);
@ -403,8 +434,7 @@ ResultCode Process::Unmap(VAddr target, VAddr source, u32 size, VMAPermission pe
Kernel::Process::Process(KernelSystem& kernel)
: Object(kernel), handle_table(kernel), vm_manager(kernel.memory), kernel(kernel) {
kernel.memory.RegisterPageTable(&vm_manager.page_table);
kernel.memory.RegisterPageTable(vm_manager.page_table);
}
Kernel::Process::~Process() {
// Release all objects this process owns first so that their potential destructor can do clean
@ -413,7 +443,7 @@ Kernel::Process::~Process() {
// memory etc.) even if they are still referenced by other processes.
handle_table.Clear();
kernel.memory.UnregisterPageTable(&vm_manager.page_table);
kernel.memory.UnregisterPageTable(vm_manager.page_table);
}
std::shared_ptr<Process> KernelSystem::GetProcessById(u32 process_id) const {

View file

@ -11,6 +11,10 @@
#include <string>
#include <vector>
#include <boost/container/static_vector.hpp>
#include <boost/serialization/array.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/vector.hpp>
#include "common/bit_field.h"
#include "common/common_types.h"
#include "core/hle/kernel/handle_table.h"
@ -25,6 +29,16 @@ struct AddressMapping {
u32 size;
bool read_only;
bool unk_flag;
private:
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& address;
ar& size;
ar& read_only;
ar& unk_flag;
}
};
union ProcessFlags {
@ -59,6 +73,15 @@ public:
std::size_t offset = 0;
VAddr addr = 0;
u32 size = 0;
private:
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& offset;
ar& addr;
ar& size;
}
};
std::string GetTypeName() const override {
@ -106,6 +129,18 @@ public:
std::string name;
/// Title ID corresponding to the process
u64 program_id;
private:
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& boost::serialization::base_object<Object>(*this);
ar& memory;
ar& segments;
ar& entrypoint;
ar& name;
ar& program_id;
}
};
class Process final : public Object {
@ -167,7 +202,7 @@ public:
u32 memory_used = 0;
MemoryRegionInfo* memory_region = nullptr;
std::shared_ptr<MemoryRegionInfo> memory_region = nullptr;
/// The Thread Local Storage area is allocated as processes create threads,
/// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part
@ -195,5 +230,14 @@ public:
private:
KernelSystem& kernel;
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version);
};
} // namespace Kernel
BOOST_CLASS_EXPORT_KEY(Kernel::CodeSet)
BOOST_CLASS_EXPORT_KEY(Kernel::Process)
CONSTRUCT_KERNEL_OBJECT(Kernel::CodeSet)
CONSTRUCT_KERNEL_OBJECT(Kernel::Process)

View file

@ -3,10 +3,13 @@
// Refer to the license.txt file included.
#include <cstring>
#include "common/archives.h"
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/hle/kernel/resource_limit.h"
SERIALIZE_EXPORT_IMPL(Kernel::ResourceLimit)
namespace Kernel {
ResourceLimit::ResourceLimit(KernelSystem& kernel) : Object(kernel) {}

View file

@ -6,6 +6,10 @@
#include <array>
#include <memory>
#include <boost/serialization/array.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/string.hpp>
#include "common/common_types.h"
#include "core/hle/kernel/object.h"
@ -110,6 +114,35 @@ public:
/// Current CPU time that the processes in this category are utilizing
s32 current_cpu_time = 0;
private:
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& boost::serialization::base_object<Object>(*this);
// NB most of these aren't used at all currently, but we're adding them here for forwards
// compatibility
ar& name;
ar& max_priority;
ar& max_commit;
ar& max_threads;
ar& max_events;
ar& max_mutexes;
ar& max_semaphores;
ar& max_timers;
ar& max_shared_mems;
ar& max_address_arbiters;
ar& max_cpu_time;
ar& current_commit;
ar& current_threads;
ar& current_events;
ar& current_mutexes;
ar& current_semaphores;
ar& current_timers;
ar& current_shared_mems;
ar& current_address_arbiters;
ar& current_cpu_time;
}
};
class ResourceLimitList {
@ -126,6 +159,15 @@ public:
private:
std::array<std::shared_ptr<ResourceLimit>, 4> resource_limits;
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& resource_limits;
}
};
} // namespace Kernel
BOOST_CLASS_EXPORT_KEY(Kernel::ResourceLimit)
CONSTRUCT_KERNEL_OBJECT(Kernel::ResourceLimit)

View file

@ -2,12 +2,15 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/archives.h"
#include "common/assert.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/semaphore.h"
#include "core/hle/kernel/thread.h"
SERIALIZE_EXPORT_IMPL(Kernel::Semaphore)
namespace Kernel {
Semaphore::Semaphore(KernelSystem& kernel) : WaitObject(kernel) {}

View file

@ -5,6 +5,9 @@
#pragma once
#include <string>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/string.hpp>
#include <queue>
#include "common/common_types.h"
#include "core/hle/kernel/object.h"
@ -43,6 +46,19 @@ public:
* @return The number of free slots the semaphore had before this call
*/
ResultVal<s32> Release(s32 release_count);
private:
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& boost::serialization::base_object<WaitObject>(*this);
ar& max_count;
ar& available_count;
ar& name;
}
};
} // namespace Kernel
BOOST_CLASS_EXPORT_KEY(Kernel::Semaphore)
CONSTRUCT_KERNEL_OBJECT(Kernel::Semaphore)

View file

@ -3,14 +3,22 @@
// Refer to the license.txt file included.
#include <tuple>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/vector.hpp>
#include "common/archives.h"
#include "common/assert.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/server_port.h"
#include "core/hle/kernel/server_session.h"
#include "core/hle/kernel/thread.h"
SERIALIZE_EXPORT_IMPL(Kernel::ServerPort)
namespace Kernel {
ServerPort::ServerPort(KernelSystem& kernel) : WaitObject(kernel) {}
@ -48,4 +56,13 @@ KernelSystem::PortPair KernelSystem::CreatePortPair(u32 max_sessions, std::strin
return std::make_pair(std::move(server_port), std::move(client_port));
}
template <class Archive>
void ServerPort::serialize(Archive& ar, const unsigned int file_version) {
ar& boost::serialization::base_object<WaitObject>(*this);
ar& name;
ar& pending_sessions;
ar& hle_handler;
}
SERIALIZE_IMPL(ServerPort)
} // namespace Kernel

View file

@ -7,8 +7,10 @@
#include <memory>
#include <string>
#include <tuple>
#include <boost/serialization/export.hpp>
#include "common/common_types.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/server_session.h"
#include "core/hle/kernel/wait_object.h"
#include "core/hle/result.h"
@ -60,6 +62,14 @@ public:
bool ShouldWait(const Thread* thread) const override;
void Acquire(Thread* thread) override;
private:
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version);
};
} // namespace Kernel
BOOST_CLASS_EXPORT_KEY(Kernel::ServerPort)
CONSTRUCT_KERNEL_OBJECT(Kernel::ServerPort)

View file

@ -3,7 +3,10 @@
// Refer to the license.txt file included.
#include <tuple>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/vector.hpp>
#include "common/archives.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/hle_ipc.h"
@ -11,8 +14,22 @@
#include "core/hle/kernel/session.h"
#include "core/hle/kernel/thread.h"
SERIALIZE_EXPORT_IMPL(Kernel::ServerSession)
namespace Kernel {
template <class Archive>
void ServerSession::serialize(Archive& ar, const unsigned int file_version) {
ar& boost::serialization::base_object<WaitObject>(*this);
ar& name;
ar& parent;
ar& hle_handler;
ar& pending_requesting_threads;
ar& currently_handling;
ar& mapped_buffer_context;
}
SERIALIZE_IMPL(ServerSession)
ServerSession::ServerSession(KernelSystem& kernel) : WaitObject(kernel), kernel(kernel) {}
ServerSession::~ServerSession() {
// This destructor will be called automatically when the last ServerSession handle is closed by
@ -68,14 +85,15 @@ ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread) {
// If this ServerSession has an associated HLE handler, forward the request to it.
if (hle_handler != nullptr) {
std::array<u32_le, IPC::COMMAND_BUFFER_LENGTH + 2 * IPC::MAX_STATIC_BUFFERS> cmd_buf;
Kernel::Process* current_process = thread->owner_process;
auto current_process = thread->owner_process;
kernel.memory.ReadBlock(*current_process, thread->GetCommandBufferAddress(), cmd_buf.data(),
cmd_buf.size() * sizeof(u32));
Kernel::HLERequestContext context(kernel, SharedFrom(this), thread.get());
context.PopulateFromIncomingCommandBuffer(cmd_buf.data(), *current_process);
auto context =
std::make_shared<Kernel::HLERequestContext>(kernel, SharedFrom(this), thread);
context->PopulateFromIncomingCommandBuffer(cmd_buf.data(), current_process);
hle_handler->HandleSyncRequest(context);
hle_handler->HandleSyncRequest(*context);
ASSERT(thread->status == Kernel::ThreadStatus::Running ||
thread->status == Kernel::ThreadStatus::WaitHleEvent);
@ -83,7 +101,7 @@ ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread) {
// put the thread to sleep then the writing of the command buffer will be deferred to the
// wakeup callback.
if (thread->status == Kernel::ThreadStatus::Running) {
context.WriteToOutgoingCommandBuffer(cmd_buf.data(), *current_process);
context->WriteToOutgoingCommandBuffer(cmd_buf.data(), *current_process);
kernel.memory.WriteBlock(*current_process, thread->GetCommandBufferAddress(),
cmd_buf.data(), cmd_buf.size() * sizeof(u32));
}

View file

@ -6,10 +6,12 @@
#include <memory>
#include <string>
#include <boost/serialization/export.hpp>
#include "common/assert.h"
#include "common/common_types.h"
#include "core/hle/kernel/ipc.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/session.h"
#include "core/hle/kernel/wait_object.h"
#include "core/hle/result.h"
#include "core/memory.h"
@ -103,6 +105,13 @@ private:
friend class KernelSystem;
KernelSystem& kernel;
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version);
};
} // namespace Kernel
BOOST_CLASS_EXPORT_KEY(Kernel::ServerSession)
CONSTRUCT_KERNEL_OBJECT(Kernel::ServerSession)

View file

@ -2,11 +2,22 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <boost/serialization/shared_ptr.hpp>
#include "common/archives.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/server_session.h"
#include "core/hle/kernel/session.h"
#include "core/hle/kernel/thread.h"
SERIALIZE_IMPL(Kernel::Session)
namespace Kernel {
Session::Session() {}
Session::~Session() {}
template <class Archive>
void Session::serialize(Archive& ar, const unsigned int file_version) {
ar& client;
ar& server;
ar& port;
}
} // namespace Kernel

View file

@ -5,6 +5,7 @@
#pragma once
#include <memory>
#include <boost/serialization/access.hpp>
#include "core/hle/kernel/object.h"
namespace Kernel {
@ -24,5 +25,10 @@ public:
ClientSession* client = nullptr; ///< The client endpoint of the session.
ServerSession* server = nullptr; ///< The server endpoint of the session.
std::shared_ptr<ClientPort> port; ///< The port that this session is associated with (optional).
private:
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version);
};
} // namespace Kernel

View file

@ -3,12 +3,15 @@
// Refer to the license.txt file included.
#include <cstring>
#include "common/archives.h"
#include "common/logging/log.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/memory.h"
SERIALIZE_EXPORT_IMPL(Kernel::SharedMemory)
namespace Kernel {
SharedMemory::SharedMemory(KernelSystem& kernel) : Object(kernel), kernel(kernel) {}
@ -38,13 +41,13 @@ ResultVal<std::shared_ptr<SharedMemory>> KernelSystem::CreateSharedMemory(
if (address == 0) {
// We need to allocate a block from the Linear Heap ourselves.
// We'll manually allocate some memory from the linear heap in the specified region.
MemoryRegionInfo* memory_region = GetMemoryRegion(region);
auto memory_region = GetMemoryRegion(region);
auto offset = memory_region->LinearAllocate(size);
ASSERT_MSG(offset, "Not enough space in region to allocate shared memory!");
std::fill(memory.GetFCRAMPointer(*offset), memory.GetFCRAMPointer(*offset + size), 0);
shared_memory->backing_blocks = {{memory.GetFCRAMPointer(*offset), size}};
shared_memory->backing_blocks = {{memory.GetFCRAMRef(*offset), size}};
shared_memory->holding_memory += MemoryRegionInfo::Interval(*offset, *offset + size);
shared_memory->linear_heap_phys_offset = *offset;
@ -75,7 +78,7 @@ std::shared_ptr<SharedMemory> KernelSystem::CreateSharedMemoryForApplet(
auto shared_memory{std::make_shared<SharedMemory>(*this)};
// Allocate memory in heap
MemoryRegionInfo* memory_region = GetMemoryRegion(MemoryRegion::SYSTEM);
auto memory_region = GetMemoryRegion(MemoryRegion::SYSTEM);
auto backing_blocks = memory_region->HeapAllocate(size);
ASSERT_MSG(!backing_blocks.empty(), "Not enough space in region to allocate shared memory!");
shared_memory->holding_memory = backing_blocks;
@ -86,7 +89,7 @@ std::shared_ptr<SharedMemory> KernelSystem::CreateSharedMemoryForApplet(
shared_memory->other_permissions = other_permissions;
for (const auto& interval : backing_blocks) {
shared_memory->backing_blocks.push_back(
{memory.GetFCRAMPointer(interval.lower()), interval.upper() - interval.lower()});
{memory.GetFCRAMRef(interval.lower()), interval.upper() - interval.lower()});
std::fill(memory.GetFCRAMPointer(interval.lower()),
memory.GetFCRAMPointer(interval.upper()), 0);
}

View file

@ -6,7 +6,11 @@
#include <string>
#include <utility>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/string.hpp>
#include "common/common_types.h"
#include "common/memory_ref.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/process.h"
#include "core/hle/result.h"
@ -86,7 +90,7 @@ private:
/// during creation.
PAddr linear_heap_phys_offset = 0;
/// Backing memory for this shared memory block.
std::vector<std::pair<u8*, u32>> backing_blocks;
std::vector<std::pair<MemoryRef, u32>> backing_blocks;
/// Size of the memory block. Page-aligned.
u32 size = 0;
/// Permission restrictions applied to the process which created the block.
@ -104,6 +108,24 @@ private:
friend class KernelSystem;
KernelSystem& kernel;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& boost::serialization::base_object<Object>(*this);
ar& linear_heap_phys_offset;
ar& backing_blocks;
ar& size;
ar& permissions;
ar& other_permissions;
ar& owner_process;
ar& base_address;
ar& name;
ar& holding_memory;
}
friend class boost::serialization::access;
};
} // namespace Kernel
BOOST_CLASS_EXPORT_KEY(Kernel::SharedMemory)
CONSTRUCT_KERNEL_OBJECT(Kernel::SharedMemory)

View file

@ -4,6 +4,7 @@
#include <chrono>
#include <cstring>
#include "common/archives.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/kernel/shared_page.h"
@ -13,6 +14,19 @@
////////////////////////////////////////////////////////////////////////////////////////////////////
SERIALIZE_EXPORT_IMPL(SharedPage::Handler)
namespace boost::serialization {
template <class Archive>
void load_construct_data(Archive& ar, SharedPage::Handler* t, const unsigned int) {
::new (t) SharedPage::Handler(Core::System::GetInstance().CoreTiming());
}
template void load_construct_data<iarchive>(iarchive& ar, SharedPage::Handler* t,
const unsigned int);
} // namespace boost::serialization
namespace SharedPage {
static std::chrono::seconds GetInitTime() {

View file

@ -13,9 +13,13 @@
#include <chrono>
#include <ctime>
#include <memory>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/binary_object.hpp>
#include <boost/serialization/export.hpp>
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/memory_ref.h"
#include "common/swap.h"
#include "core/memory.h"
@ -82,7 +86,7 @@ struct SharedPageDef {
static_assert(sizeof(SharedPageDef) == Memory::SHARED_PAGE_SIZE,
"Shared page structure size is wrong");
class Handler {
class Handler : public BackingMem {
public:
Handler(Core::Timing& timing);
@ -96,6 +100,18 @@ public:
SharedPageDef& GetSharedPage();
u8* GetPtr() override {
return reinterpret_cast<u8*>(&shared_page);
}
const u8* GetPtr() const override {
return reinterpret_cast<const u8*>(&shared_page);
}
std::size_t GetSize() const override {
return sizeof(shared_page);
}
private:
u64 GetSystemTime() const;
void UpdateTimeCallback(u64 userdata, int cycles_late);
@ -104,6 +120,22 @@ private:
std::chrono::seconds init_time;
SharedPageDef shared_page;
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& boost::serialization::base_object<BackingMem>(*this);
ar& boost::serialization::make_binary_object(&shared_page, sizeof(shared_page));
}
friend class boost::serialization::access;
};
} // namespace SharedPage
namespace boost::serialization {
template <class Archive>
void load_construct_data(Archive& ar, SharedPage::Handler* t, const unsigned int);
} // namespace boost::serialization
BOOST_CLASS_EXPORT_KEY(SharedPage::Handler)

View file

@ -282,7 +282,7 @@ void SVC::ExitProcess() {
// Stop all the process threads that are currently waiting for objects.
auto& thread_list = kernel.GetCurrentThreadManager().GetThreadList();
for (auto& thread : thread_list) {
if (thread->owner_process != current_process.get())
if (thread->owner_process != current_process)
continue;
if (thread.get() == kernel.GetCurrentThreadManager().GetCurrentThread())
@ -403,6 +403,76 @@ ResultCode SVC::CloseHandle(Handle handle) {
return kernel.GetCurrentProcess()->handle_table.Close(handle);
}
static ResultCode ReceiveIPCRequest(Kernel::KernelSystem& kernel, Memory::MemorySystem& memory,
std::shared_ptr<ServerSession> server_session,
std::shared_ptr<Thread> thread);
class SVC_SyncCallback : public Kernel::WakeupCallback {
public:
explicit SVC_SyncCallback(bool do_output_) : do_output(do_output_) {}
void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
std::shared_ptr<WaitObject> object) {
if (reason == ThreadWakeupReason::Timeout) {
thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
return;
}
ASSERT(reason == ThreadWakeupReason::Signal);
thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
// The wait_all case does not update the output index.
if (do_output) {
thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get()));
}
}
private:
bool do_output;
SVC_SyncCallback() = default;
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& boost::serialization::base_object<Kernel::WakeupCallback>(*this);
ar& do_output;
}
friend class boost::serialization::access;
};
class SVC_IPCCallback : public Kernel::WakeupCallback {
public:
explicit SVC_IPCCallback(Core::System& system_) : system(system_) {}
void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
std::shared_ptr<WaitObject> object) {
ASSERT(thread->status == ThreadStatus::WaitSynchAny);
ASSERT(reason == ThreadWakeupReason::Signal);
ResultCode result = RESULT_SUCCESS;
if (object->GetHandleType() == HandleType::ServerSession) {
auto server_session = DynamicObjectCast<ServerSession>(object);
result = ReceiveIPCRequest(system.Kernel(), system.Memory(), server_session, thread);
}
thread->SetWaitSynchronizationResult(result);
thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get()));
}
private:
Core::System& system;
SVC_IPCCallback() : system(Core::Global<Core::System>()) {}
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& boost::serialization::base_object<Kernel::WakeupCallback>(*this);
}
friend class boost::serialization::access;
};
/// Wait for a handle to synchronize, timeout after the specified nanoseconds
ResultCode SVC::WaitSynchronization1(Handle handle, s64 nano_seconds) {
auto object = kernel.GetCurrentProcess()->handle_table.Get<WaitObject>(handle);
@ -426,21 +496,7 @@ ResultCode SVC::WaitSynchronization1(Handle handle, s64 nano_seconds) {
// Create an event to wake the thread up after the specified nanosecond delay has passed
thread->WakeAfterDelay(nano_seconds);
thread->wakeup_callback = [](ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
std::shared_ptr<WaitObject> object) {
ASSERT(thread->status == ThreadStatus::WaitSynchAny);
if (reason == ThreadWakeupReason::Timeout) {
thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
return;
}
ASSERT(reason == ThreadWakeupReason::Signal);
thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
// WaitSynchronization1 doesn't have an output index like WaitSynchronizationN, so we
// don't have to do anything else here.
};
thread->wakeup_callback = std::make_shared<SVC_SyncCallback>(false);
system.PrepareReschedule();
@ -515,20 +571,7 @@ ResultCode SVC::WaitSynchronizationN(s32* out, VAddr handles_address, s32 handle
// Create an event to wake the thread up after the specified nanosecond delay has passed
thread->WakeAfterDelay(nano_seconds);
thread->wakeup_callback = [](ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
std::shared_ptr<WaitObject> object) {
ASSERT(thread->status == ThreadStatus::WaitSynchAll);
if (reason == ThreadWakeupReason::Timeout) {
thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
return;
}
ASSERT(reason == ThreadWakeupReason::Signal);
thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
// The wait_all case does not update the output index.
};
thread->wakeup_callback = std::make_shared<SVC_SyncCallback>(false);
system.PrepareReschedule();
@ -575,20 +618,7 @@ ResultCode SVC::WaitSynchronizationN(s32* out, VAddr handles_address, s32 handle
// Create an event to wake the thread up after the specified nanosecond delay has passed
thread->WakeAfterDelay(nano_seconds);
thread->wakeup_callback = [](ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
std::shared_ptr<WaitObject> object) {
ASSERT(thread->status == ThreadStatus::WaitSynchAny);
if (reason == ThreadWakeupReason::Timeout) {
thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
return;
}
ASSERT(reason == ThreadWakeupReason::Signal);
thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get()));
};
thread->wakeup_callback = std::make_shared<SVC_SyncCallback>(true);
system.PrepareReschedule();
@ -730,22 +760,7 @@ ResultCode SVC::ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_co
thread->wait_objects = std::move(objects);
thread->wakeup_callback = [& kernel = this->kernel, &memory = this->memory](
ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
std::shared_ptr<WaitObject> object) {
ASSERT(thread->status == ThreadStatus::WaitSynchAny);
ASSERT(reason == ThreadWakeupReason::Signal);
ResultCode result = RESULT_SUCCESS;
if (object->GetHandleType() == HandleType::ServerSession) {
auto server_session = DynamicObjectCast<ServerSession>(object);
result = ReceiveIPCRequest(kernel, memory, server_session, thread);
}
thread->SetWaitSynchronizationResult(result);
thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get()));
};
thread->wakeup_callback = std::make_shared<SVC_IPCCallback>(system);
system.PrepareReschedule();
@ -916,7 +931,7 @@ ResultCode SVC::CreateThread(Handle* out_handle, u32 entry_point, u32 arg, VAddr
CASCADE_RESULT(std::shared_ptr<Thread> thread,
kernel.CreateThread(name, entry_point, priority, arg, processor_id, stack_top,
*current_process));
current_process));
thread->context->SetFpscr(FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO |
FPSCR_ROUND_TOZERO); // 0x03C00000
@ -1025,7 +1040,7 @@ ResultCode SVC::GetProcessIdOfThread(u32* process_id, Handle thread_handle) {
if (thread == nullptr)
return ERR_INVALID_HANDLE;
const std::shared_ptr<Process> process = SharedFrom(thread->owner_process);
const std::shared_ptr<Process> process = thread->owner_process;
ASSERT_MSG(process != nullptr, "Invalid parent process for thread={:#010X}", thread_handle);
@ -1592,6 +1607,7 @@ void SVC::CallSVC(u32 immediate) {
"Running threads from exiting processes is unimplemented");
const FunctionDef* info = GetSVCInfo(immediate);
LOG_TRACE(Kernel_SVC, "calling {}", info->name);
if (info) {
if (info->func) {
(this->*(info->func))();
@ -1619,3 +1635,6 @@ void SVCContext::CallSVC(u32 immediate) {
}
} // namespace Kernel
SERIALIZE_EXPORT_IMPL(Kernel::SVC_SyncCallback)
SERIALIZE_EXPORT_IMPL(Kernel::SVC_IPCCallback)

View file

@ -5,6 +5,7 @@
#pragma once
#include <memory>
#include <boost/serialization/export.hpp>
#include "common/common_types.h"
namespace Core {
@ -25,4 +26,10 @@ private:
std::unique_ptr<SVC> impl;
};
class SVC_SyncCallback;
class SVC_IPCCallback;
} // namespace Kernel
BOOST_CLASS_EXPORT_KEY(Kernel::SVC_SyncCallback)
BOOST_CLASS_EXPORT_KEY(Kernel::SVC_IPCCallback)

View file

@ -280,6 +280,26 @@ private:
}
};
template <typename SVCT>
struct WrapPass<SVCT, ResultCode /*empty for T, Ts...*/> {
// Call function R(Context::svc)(Us...) and transfer the return value to registers
template <typename... Us>
static void Call(Context& context, SVCT svc, Us... u) {
static_assert(std::is_same_v<SVCT, ResultCode (Context::*)(Us...)>);
if constexpr (std::is_void_v<ResultCode>) {
(context.*svc)(u...);
} else {
ResultCode r = (context.*svc)(u...);
if (r.IsError()) {
LOG_ERROR(Kernel_SVC, "level={} summary={} module={} description={}",
r.level.ExtractValue(r.raw), r.summary.ExtractValue(r.raw),
r.module.ExtractValue(r.raw), r.description.ExtractValue(r.raw));
}
SetParam<INDEX_RETURN, ResultCode, ResultCode, Us...>(context, r);
}
}
};
template <typename T>
struct WrapHelper;

View file

@ -6,10 +6,13 @@
#include <list>
#include <unordered_map>
#include <vector>
#include <boost/serialization/string.hpp>
#include "common/archives.h"
#include "common/assert.h"
#include "common/common_types.h"
#include "common/logging/log.h"
#include "common/math_util.h"
#include "common/serialization/boost_flat_set.h"
#include "core/arm/arm_interface.h"
#include "core/arm/skyeye_common/armstate.h"
#include "core/core.h"
@ -23,8 +26,34 @@
#include "core/hle/result.h"
#include "core/memory.h"
SERIALIZE_EXPORT_IMPL(Kernel::Thread)
namespace Kernel {
template <class Archive>
void Thread::serialize(Archive& ar, const unsigned int file_version) {
ar& boost::serialization::base_object<WaitObject>(*this);
ar&* context.get();
ar& thread_id;
ar& status;
ar& entry_point;
ar& stack_top;
ar& nominal_priority;
ar& current_priority;
ar& last_running_ticks;
ar& processor_id;
ar& tls_address;
ar& held_mutexes;
ar& pending_mutexes;
ar& owner_process;
ar& wait_objects;
ar& wait_address;
ar& name;
ar& wakeup_callback;
}
SERIALIZE_IMPL(Thread)
bool Thread::ShouldWait(const Thread* thread) const {
return status != ThreadStatus::Dead;
}
@ -34,7 +63,7 @@ void Thread::Acquire(Thread* thread) {
}
Thread::Thread(KernelSystem& kernel, u32 core_id)
: WaitObject(kernel), context(kernel.GetThreadManager(core_id).NewContext()),
: WaitObject(kernel), context(kernel.GetThreadManager(core_id).NewContext()), core_id(core_id),
thread_manager(kernel.GetThreadManager(core_id)) {}
Thread::~Thread() {}
@ -75,7 +104,7 @@ void Thread::Stop() {
void ThreadManager::SwitchContext(Thread* new_thread) {
Thread* previous_thread = GetCurrentThread();
Process* previous_process = nullptr;
std::shared_ptr<Process> previous_process = nullptr;
Core::Timing& timing = kernel.timing;
@ -107,7 +136,7 @@ void ThreadManager::SwitchContext(Thread* new_thread) {
new_thread->status = ThreadStatus::Running;
if (previous_process != current_thread->owner_process) {
kernel.SetCurrentProcessForCPU(SharedFrom(current_thread->owner_process), cpu->GetID());
kernel.SetCurrentProcessForCPU(current_thread->owner_process, cpu->GetID());
}
cpu->LoadContext(new_thread->context);
@ -164,7 +193,7 @@ void ThreadManager::ThreadWakeupCallback(u64 thread_id, s64 cycles_late) {
// Invoke the wakeup callback before clearing the wait objects
if (thread->wakeup_callback)
thread->wakeup_callback(ThreadWakeupReason::Timeout, thread, nullptr);
thread->wakeup_callback->WakeUp(ThreadWakeupReason::Timeout, thread, nullptr);
// Remove the thread from each of its waiting objects' waitlists
for (auto& object : thread->wait_objects)
@ -282,10 +311,9 @@ static void ResetThreadContext(const std::unique_ptr<ARM_Interface::ThreadContex
context->SetCpsr(USER32MODE | ((entry_point & 1) << 5)); // Usermode and THUMB mode
}
ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(std::string name, VAddr entry_point,
u32 priority, u32 arg,
s32 processor_id, VAddr stack_top,
Process& owner_process) {
ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(
std::string name, VAddr entry_point, u32 priority, u32 arg, s32 processor_id, VAddr stack_top,
std::shared_ptr<Process> owner_process) {
// Check if priority is in ranged. Lowest priority -> highest priority id.
if (priority > ThreadPrioLowest) {
LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority);
@ -299,7 +327,7 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(std::string name,
// TODO(yuriks): Other checks, returning 0xD9001BEA
if (!Memory::IsValidVirtualAddress(owner_process, entry_point)) {
if (!Memory::IsValidVirtualAddress(*owner_process, entry_point)) {
LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:08x}", name, entry_point);
// TODO: Verify error
return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
@ -322,17 +350,17 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(std::string name,
thread->wait_address = 0;
thread->name = std::move(name);
thread_managers[processor_id]->wakeup_callback_table[thread->thread_id] = thread.get();
thread->owner_process = &owner_process;
thread->owner_process = owner_process;
// Find the next available TLS index, and mark it as used
auto& tls_slots = owner_process.tls_slots;
auto& tls_slots = owner_process->tls_slots;
auto [available_page, available_slot, needs_allocation] = GetFreeThreadLocalSlot(tls_slots);
if (needs_allocation) {
// There are no already-allocated pages with free slots, lets allocate a new one.
// TLS pages are allocated from the BASE region in the linear heap.
MemoryRegionInfo* memory_region = GetMemoryRegion(MemoryRegion::BASE);
auto memory_region = GetMemoryRegion(MemoryRegion::BASE);
// Allocate some memory from the end of the linear heap for this region.
auto offset = memory_region->LinearAllocate(Memory::PAGE_SIZE);
@ -341,17 +369,17 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(std::string name,
"Not enough space in region to allocate a new TLS page for thread");
return ERR_OUT_OF_MEMORY;
}
owner_process.memory_used += Memory::PAGE_SIZE;
owner_process->memory_used += Memory::PAGE_SIZE;
tls_slots.emplace_back(0); // The page is completely available at the start
available_page = tls_slots.size() - 1;
available_slot = 0; // Use the first slot in the new page
auto& vm_manager = owner_process.vm_manager;
auto& vm_manager = owner_process->vm_manager;
// Map the page to the current process' address space.
vm_manager.MapBackingMemory(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE,
memory.GetFCRAMPointer(*offset), Memory::PAGE_SIZE,
memory.GetFCRAMRef(*offset), Memory::PAGE_SIZE,
MemoryState::Locked);
}
@ -360,7 +388,7 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(std::string name,
thread->tls_address = Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE +
available_slot * Memory::TLS_ENTRY_SIZE;
memory.ZeroBlock(owner_process, thread->tls_address, Memory::TLS_ENTRY_SIZE);
memory.ZeroBlock(*owner_process, thread->tls_address, Memory::TLS_ENTRY_SIZE);
// TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
// to initialize the context
@ -407,7 +435,7 @@ std::shared_ptr<Thread> SetupMainThread(KernelSystem& kernel, u32 entry_point, u
// Initialize new "main" thread
auto thread_res =
kernel.CreateThread("main", entry_point, priority, 0, owner_process->ideal_processor,
Memory::HEAP_VADDR_END, *owner_process);
Memory::HEAP_VADDR_END, owner_process);
std::shared_ptr<Thread> thread = std::move(thread_res).Unwrap();

View file

@ -9,6 +9,10 @@
#include <unordered_map>
#include <vector>
#include <boost/container/flat_set.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/unordered_map.hpp>
#include <boost/serialization/vector.hpp>
#include "common/common_types.h"
#include "common/thread_queue_list.h"
#include "core/arm/arm_interface.h"
@ -57,6 +61,20 @@ enum class ThreadWakeupReason {
Timeout // The thread was woken up due to a wait timeout.
};
class Thread;
class WakeupCallback {
public:
virtual ~WakeupCallback() = default;
virtual void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
std::shared_ptr<WaitObject> object) = 0;
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int) {}
friend class boost::serialization::access;
};
class ThreadManager {
public:
explicit ThreadManager(Kernel::KernelSystem& kernel, u32 core_id);
@ -140,6 +158,15 @@ private:
friend class Thread;
friend class KernelSystem;
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& current_thread;
ar& ready_queue;
ar& wakeup_callback_table;
ar& thread_list;
}
};
class Thread final : public WaitObject {
@ -276,30 +303,34 @@ public:
VAddr tls_address; ///< Virtual address of the Thread Local Storage of the thread
/// Mutexes currently held by this thread, which will be released when it exits.
boost::container::flat_set<std::shared_ptr<Mutex>> held_mutexes;
boost::container::flat_set<std::shared_ptr<Mutex>> held_mutexes{};
/// Mutexes that this thread is currently waiting for.
boost::container::flat_set<std::shared_ptr<Mutex>> pending_mutexes;
boost::container::flat_set<std::shared_ptr<Mutex>> pending_mutexes{};
Process* owner_process; ///< Process that owns this thread
std::shared_ptr<Process> owner_process{}; ///< Process that owns this thread
/// Objects that the thread is waiting on, in the same order as they were
// passed to WaitSynchronization1/N.
std::vector<std::shared_ptr<WaitObject>> wait_objects;
std::vector<std::shared_ptr<WaitObject>> wait_objects{};
VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address
std::string name;
std::string name{};
using WakeupCallback = void(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
std::shared_ptr<WaitObject> object);
// Callback that will be invoked when the thread is resumed from a waiting state. If the thread
// was waiting via WaitSynchronizationN then the object will be the last object that became
// available. In case of a timeout, the object will be nullptr.
std::function<WakeupCallback> wakeup_callback;
std::shared_ptr<WakeupCallback> wakeup_callback{};
const u32 core_id;
private:
ThreadManager& thread_manager;
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version);
};
/**
@ -314,3 +345,22 @@ std::shared_ptr<Thread> SetupMainThread(KernelSystem& kernel, u32 entry_point, u
std::shared_ptr<Process> owner_process);
} // namespace Kernel
BOOST_CLASS_EXPORT_KEY(Kernel::Thread)
namespace boost::serialization {
template <class Archive>
inline void save_construct_data(Archive& ar, const Kernel::Thread* t,
const unsigned int file_version) {
ar << t->core_id;
}
template <class Archive>
inline void load_construct_data(Archive& ar, Kernel::Thread* t, const unsigned int file_version) {
u32 core_id;
ar >> core_id;
::new (t) Kernel::Thread(Core::Global<Kernel::KernelSystem>(), core_id);
}
} // namespace boost::serialization

View file

@ -4,6 +4,7 @@
#include <cinttypes>
#include <unordered_map>
#include "common/archives.h"
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/core.h"
@ -12,6 +13,8 @@
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/timer.h"
SERIALIZE_EXPORT_IMPL(Kernel::Timer)
namespace Kernel {
Timer::Timer(KernelSystem& kernel)

View file

@ -4,6 +4,8 @@
#pragma once
#include <boost/serialization/string.hpp>
#include <boost/serialization/unordered_map.hpp>
#include "common/common_types.h"
#include "core/core_timing.h"
#include "core/hle/kernel/object.h"
@ -33,6 +35,13 @@ private:
friend class Timer;
friend class KernelSystem;
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& next_timer_callback_id;
ar& timer_callback_table;
}
};
class Timer final : public WaitObject {
@ -103,6 +112,21 @@ private:
TimerManager& timer_manager;
friend class KernelSystem;
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& boost::serialization::base_object<WaitObject>(*this);
ar& reset_type;
ar& initial_delay;
ar& interval_delay;
ar& signaled;
ar& name;
ar& callback_id;
}
};
} // namespace Kernel
BOOST_CLASS_EXPORT_KEY(Kernel::Timer)
CONSTRUCT_KERNEL_OBJECT(Kernel::Timer)

View file

@ -27,7 +27,8 @@ bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const {
type != next.type) {
return false;
}
if (type == VMAType::BackingMemory && backing_memory + size != next.backing_memory) {
if (type == VMAType::BackingMemory &&
backing_memory.GetPtr() + size != next.backing_memory.GetPtr()) {
return false;
}
if (type == VMAType::MMIO && paddr + size != next.paddr) {
@ -36,7 +37,8 @@ bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const {
return true;
}
VMManager::VMManager(Memory::MemorySystem& memory) : memory(memory) {
VMManager::VMManager(Memory::MemorySystem& memory)
: memory(memory), page_table(std::make_shared<Memory::PageTable>()) {
Reset();
}
@ -50,8 +52,7 @@ void VMManager::Reset() {
initial_vma.size = MAX_ADDRESS;
vma_map.emplace(initial_vma.base, initial_vma);
page_table.pointers.fill(nullptr);
page_table.attributes.fill(Memory::PageType::Unmapped);
page_table->Clear();
UpdatePageTableForVMA(initial_vma);
}
@ -64,7 +65,7 @@ VMManager::VMAHandle VMManager::FindVMA(VAddr target) const {
}
}
ResultVal<VAddr> VMManager::MapBackingMemoryToBase(VAddr base, u32 region_size, u8* memory,
ResultVal<VAddr> VMManager::MapBackingMemoryToBase(VAddr base, u32 region_size, MemoryRef memory,
u32 size, MemoryState state) {
// Find the first Free VMA.
@ -93,9 +94,9 @@ ResultVal<VAddr> VMManager::MapBackingMemoryToBase(VAddr base, u32 region_size,
return MakeResult<VAddr>(target);
}
ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* memory, u32 size,
MemoryState state) {
ASSERT(memory != nullptr);
ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, MemoryRef memory,
u32 size, MemoryState state) {
ASSERT(memory.GetPtr() != nullptr);
// This is the appropriately sized VMA that will turn into our allocation.
CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size));
@ -351,20 +352,20 @@ VMManager::VMAIter VMManager::MergeAdjacent(VMAIter iter) {
void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
switch (vma.type) {
case VMAType::Free:
memory.UnmapRegion(page_table, vma.base, vma.size);
memory.UnmapRegion(*page_table, vma.base, vma.size);
break;
case VMAType::BackingMemory:
memory.MapMemoryRegion(page_table, vma.base, vma.size, vma.backing_memory);
memory.MapMemoryRegion(*page_table, vma.base, vma.size, vma.backing_memory);
break;
case VMAType::MMIO:
memory.MapIoRegion(page_table, vma.base, vma.size, vma.mmio_handler);
memory.MapIoRegion(*page_table, vma.base, vma.size, vma.mmio_handler);
break;
}
}
ResultVal<std::vector<std::pair<u8*, u32>>> VMManager::GetBackingBlocksForRange(VAddr address,
u32 size) {
std::vector<std::pair<u8*, u32>> backing_blocks;
ResultVal<std::vector<std::pair<MemoryRef, u32>>> VMManager::GetBackingBlocksForRange(VAddr address,
u32 size) {
std::vector<std::pair<MemoryRef, u32>> backing_blocks;
VAddr interval_target = address;
while (interval_target != address + size) {
auto vma = FindVMA(interval_target);
@ -375,7 +376,7 @@ ResultVal<std::vector<std::pair<u8*, u32>>> VMManager::GetBackingBlocksForRange(
VAddr interval_end = std::min(address + size, vma->second.base + vma->second.size);
u32 interval_size = interval_end - interval_target;
u8* backing_memory = vma->second.backing_memory + (interval_target - vma->second.base);
auto backing_memory = vma->second.backing_memory + (interval_target - vma->second.base);
backing_blocks.push_back({backing_memory, interval_size});
interval_target += interval_size;

View file

@ -8,7 +8,11 @@
#include <memory>
#include <utility>
#include <vector>
#include <boost/serialization/map.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/split_member.hpp>
#include "common/common_types.h"
#include "common/memory_ref.h"
#include "core/hle/result.h"
#include "core/memory.h"
#include "core/mmio.h"
@ -71,7 +75,7 @@ struct VirtualMemoryArea {
// Settings for type = BackingMemory
/// Pointer backing this VMA. It will not be destroyed or freed when the VMA is removed.
u8* backing_memory = nullptr;
MemoryRef backing_memory{};
// Settings for type = MMIO
/// Physical address of the register area this VMA maps to.
@ -80,6 +84,20 @@ struct VirtualMemoryArea {
/// Tests if this area can be merged to the right with `next`.
bool CanBeMergedWith(const VirtualMemoryArea& next) const;
private:
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& base;
ar& size;
ar& type;
ar& permissions;
ar& meminfo_state;
ar& backing_memory;
ar& paddr;
ar& mmio_handler;
}
};
/**
@ -134,7 +152,7 @@ public:
* @param state MemoryState tag to attach to the VMA.
* @returns The address at which the memory was mapped.
*/
ResultVal<VAddr> MapBackingMemoryToBase(VAddr base, u32 region_size, u8* memory, u32 size,
ResultVal<VAddr> MapBackingMemoryToBase(VAddr base, u32 region_size, MemoryRef memory, u32 size,
MemoryState state);
/**
* Maps an unmanaged host memory pointer at a given address.
@ -144,7 +162,8 @@ public:
* @param size Size of the mapping.
* @param state MemoryState tag to attach to the VMA.
*/
ResultVal<VMAHandle> MapBackingMemory(VAddr target, u8* memory, u32 size, MemoryState state);
ResultVal<VMAHandle> MapBackingMemory(VAddr target, MemoryRef memory, u32 size,
MemoryState state);
/**
* Maps a memory-mapped IO region at a given address.
@ -186,11 +205,12 @@ public:
void LogLayout(Log::Level log_level) const;
/// Gets a list of backing memory blocks for the specified range
ResultVal<std::vector<std::pair<u8*, u32>>> GetBackingBlocksForRange(VAddr address, u32 size);
ResultVal<std::vector<std::pair<MemoryRef, u32>>> GetBackingBlocksForRange(VAddr address,
u32 size);
/// Each VMManager has its own page table, which is set as the main one when the owning process
/// is scheduled.
Memory::PageTable page_table;
std::shared_ptr<Memory::PageTable> page_table;
private:
using VMAIter = decltype(vma_map)::iterator;
@ -229,5 +249,12 @@ private:
void UpdatePageTableForVMA(const VirtualMemoryArea& vma);
Memory::MemorySystem& memory;
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& vma_map;
ar& page_table;
}
friend class boost::serialization::access;
};
} // namespace Kernel

View file

@ -4,6 +4,7 @@
#include <algorithm>
#include <utility>
#include "common/archives.h"
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/hle/kernel/errors.h"
@ -16,6 +17,15 @@
namespace Kernel {
template <class Archive>
void WaitObject::serialize(Archive& ar, const unsigned int file_version) {
ar& boost::serialization::base_object<Object>(*this);
ar& waiting_threads;
// NB: hle_notifier *not* serialized since it's a callback!
// Fortunately it's only used in one place (DSP) so we can reconstruct it there
}
SERIALIZE_IMPL(WaitObject)
void WaitObject::AddWaitingThread(std::shared_ptr<Thread> thread) {
auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
if (itr == waiting_threads.end())
@ -80,7 +90,7 @@ void WaitObject::WakeupAllWaitingThreads() {
// Invoke the wakeup callback before clearing the wait objects
if (thread->wakeup_callback)
thread->wakeup_callback(ThreadWakeupReason::Signal, thread, SharedFrom(this));
thread->wakeup_callback->WakeUp(ThreadWakeupReason::Signal, thread, SharedFrom(this));
for (auto& object : thread->wait_objects)
object->RemoveWaitingThread(thread.get());

View file

@ -7,6 +7,9 @@
#include <functional>
#include <memory>
#include <vector>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/vector.hpp>
#include "common/common_types.h"
#include "core/hle/kernel/object.h"
@ -62,6 +65,11 @@ private:
/// Function to call when this object becomes available
std::function<void()> hle_notifier;
private:
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version);
};
// Specialization of DynamicObjectCast for WaitObjects

View file

@ -6,6 +6,7 @@
#include <new>
#include <utility>
#include <boost/serialization/access.hpp>
#include "common/assert.h"
#include "common/bit_field.h"
#include "common/common_funcs.h"
@ -225,6 +226,13 @@ union ResultCode {
constexpr bool IsError() const {
return is_error.ExtractValue(raw) == 1;
}
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& raw;
}
friend class boost::serialization::access;
};
constexpr bool operator==(const ResultCode& a, const ResultCode& b) {

View file

@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <vector>
#include "common/archives.h"
#include "common/common_types.h"
#include "common/logging/log.h"
#include "core/core.h"
@ -179,4 +180,15 @@ void InstallInterfaces(Core::System& system) {
std::make_shared<AC_U>(ac)->InstallAsService(service_manager);
}
template <class Archive>
void Module::serialize(Archive& ar, const unsigned int) {
ar& ac_connected;
ar& close_event;
ar& connect_event;
ar& disconnect_event;
// default_config is never written to
}
} // namespace Service::AC
SERIALIZE_IMPL(Service::AC::Module)

View file

@ -153,6 +153,11 @@ protected:
std::shared_ptr<Kernel::Event> close_event;
std::shared_ptr<Kernel::Event> connect_event;
std::shared_ptr<Kernel::Event> disconnect_event;
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version);
friend class boost::serialization::access;
};
void InstallInterfaces(Core::System& system);

View file

@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/archives.h"
#include "core/hle/service/ac/ac_i.h"
namespace Service::AC {
@ -33,3 +34,5 @@ AC_I::AC_I(std::shared_ptr<Module> ac) : Module::Interface(std::move(ac), "ac:i"
}
} // namespace Service::AC
SERIALIZE_EXPORT_IMPL(Service::AC::AC_I)

View file

@ -12,6 +12,12 @@ namespace Service::AC {
class AC_I final : public Module::Interface {
public:
explicit AC_I(std::shared_ptr<Module> ac);
private:
SERVICE_SERIALIZATION(AC_I, ac, Module)
};
} // namespace Service::AC
BOOST_CLASS_EXPORT_KEY(Service::AC::AC_I)
BOOST_SERIALIZATION_CONSTRUCT(Service::AC::AC_I)

View file

@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/archives.h"
#include "core/hle/service/ac/ac_u.h"
namespace Service::AC {
@ -33,3 +34,5 @@ AC_U::AC_U(std::shared_ptr<Module> ac) : Module::Interface(std::move(ac), "ac:u"
}
} // namespace Service::AC
SERIALIZE_EXPORT_IMPL(Service::AC::AC_U)

View file

@ -12,6 +12,12 @@ namespace Service::AC {
class AC_U final : public Module::Interface {
public:
explicit AC_U(std::shared_ptr<Module> ac);
private:
SERVICE_SERIALIZATION(AC_U, ac, Module)
};
} // namespace Service::AC
BOOST_CLASS_EXPORT_KEY(Service::AC::AC_U)
BOOST_SERIALIZATION_CONSTRUCT(Service::AC::AC_U)

View file

@ -20,9 +20,14 @@ public:
Interface(std::shared_ptr<Module> act, const char* name);
~Interface();
private:
protected:
std::shared_ptr<Module> act;
};
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {}
friend class boost::serialization::access;
};
void InstallInterfaces(Core::System& system);

View file

@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/archives.h"
#include "core/hle/service/act/act_a.h"
namespace Service::ACT {
@ -24,3 +25,5 @@ ACT_A::ACT_A(std::shared_ptr<Module> act) : Module::Interface(std::move(act), "a
}
} // namespace Service::ACT
SERIALIZE_EXPORT_IMPL(Service::ACT::ACT_A)

View file

@ -11,6 +11,12 @@ namespace Service::ACT {
class ACT_A final : public Module::Interface {
public:
explicit ACT_A(std::shared_ptr<Module> act);
private:
SERVICE_SERIALIZATION(ACT_A, act, Module)
};
} // namespace Service::ACT
BOOST_CLASS_EXPORT_KEY(Service::ACT::ACT_A)
BOOST_SERIALIZATION_CONSTRUCT(Service::ACT::ACT_A)

View file

@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/archives.h"
#include "core/hle/service/act/act_u.h"
namespace Service::ACT {
@ -20,3 +21,5 @@ ACT_U::ACT_U(std::shared_ptr<Module> act) : Module::Interface(std::move(act), "a
}
} // namespace Service::ACT
SERIALIZE_EXPORT_IMPL(Service::ACT::ACT_U)

View file

@ -11,6 +11,12 @@ namespace Service::ACT {
class ACT_U final : public Module::Interface {
public:
explicit ACT_U(std::shared_ptr<Module> act);
private:
SERVICE_SERIALIZATION(ACT_U, act, Module)
};
} // namespace Service::ACT
BOOST_CLASS_EXPORT_KEY(Service::ACT::ACT_U)
BOOST_SERIALIZATION_CONSTRUCT(Service::ACT::ACT_U)

View file

@ -1053,7 +1053,7 @@ void Module::Interface::BeginImportProgram(Kernel::HLERequestContext& ctx) {
// Citra will store contents out to sdmc/nand
const FileSys::Path cia_path = {};
auto file = std::make_shared<Service::FS::File>(
am->system, std::make_unique<CIAFile>(media_type), cia_path);
am->kernel, std::make_unique<CIAFile>(media_type), cia_path);
am->cia_installing = true;
@ -1080,7 +1080,7 @@ void Module::Interface::BeginImportProgramTemporarily(Kernel::HLERequestContext&
// contents out to sdmc/nand
const FileSys::Path cia_path = {};
auto file = std::make_shared<Service::FS::File>(
am->system, std::make_unique<CIAFile>(FS::MediaType::NAND), cia_path);
am->kernel, std::make_unique<CIAFile>(FS::MediaType::NAND), cia_path);
am->cia_installing = true;
@ -1482,11 +1482,13 @@ void Module::Interface::GetMetaDataFromCia(Kernel::HLERequestContext& ctx) {
rb.PushMappedBuffer(output_buffer);
}
Module::Module(Core::System& system) : system(system) {
Module::Module(Core::System& system) : kernel(system.Kernel()) {
ScanForAllTitles();
system_updater_mutex = system.Kernel().CreateMutex(false, "AM::SystemUpdaterMutex");
}
Module::Module(Kernel::KernelSystem& kernel) : kernel(kernel) {}
Module::~Module() = default;
void InstallInterfaces(Core::System& system) {

View file

@ -9,9 +9,14 @@
#include <memory>
#include <string>
#include <vector>
#include <boost/serialization/array.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/vector.hpp>
#include "common/common_types.h"
#include "common/construct.h"
#include "core/file_sys/cia_container.h"
#include "core/file_sys/file_backend.h"
#include "core/global.h"
#include "core/hle/kernel/mutex.h"
#include "core/hle/result.h"
#include "core/hle/service/service.h"
@ -557,11 +562,13 @@ public:
*/
void GetMetaDataFromCia(Kernel::HLERequestContext& ctx);
private:
protected:
std::shared_ptr<Module> am;
};
private:
explicit Module(Kernel::KernelSystem& kernel);
/**
* Scans the for titles in a storage medium for listing.
* @param media_type the storage medium to scan
@ -573,12 +580,32 @@ private:
*/
void ScanForAllTitles();
Core::System& system;
Kernel::KernelSystem& kernel;
bool cia_installing = false;
std::array<std::vector<u64_le>, 3> am_title_list;
std::shared_ptr<Kernel::Mutex> system_updater_mutex;
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& cia_installing;
ar& am_title_list;
ar& system_updater_mutex;
}
template <class Archive>
static void load_construct(Archive& ar, Module* t, const unsigned int file_version) {
::new (t) Module(Core::Global<Kernel::KernelSystem>());
}
template <class Archive>
void save_construct(Archive& ar, const unsigned int file_version) const {}
friend class ::construct_access;
friend class boost::serialization::access;
};
void InstallInterfaces(Core::System& system);
} // namespace Service::AM
BOOST_SERIALIZATION_CONSTRUCT(Service::AM::Module);

View file

@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/archives.h"
#include "core/hle/service/am/am_app.h"
namespace Service::AM {
@ -26,3 +27,5 @@ AM_APP::AM_APP(std::shared_ptr<Module> am) : Module::Interface(std::move(am), "a
}
} // namespace Service::AM
SERIALIZE_EXPORT_IMPL(Service::AM::AM_APP)

View file

@ -11,6 +11,12 @@ namespace Service::AM {
class AM_APP final : public Module::Interface {
public:
explicit AM_APP(std::shared_ptr<Module> am);
private:
SERVICE_SERIALIZATION(AM_APP, am, Module)
};
} // namespace Service::AM
BOOST_CLASS_EXPORT_KEY(Service::AM::AM_APP)
BOOST_SERIALIZATION_CONSTRUCT(Service::AM::AM_APP)

View file

@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/archives.h"
#include "core/hle/service/am/am_net.h"
namespace Service::AM {
@ -123,3 +124,5 @@ AM_NET::AM_NET(std::shared_ptr<Module> am) : Module::Interface(std::move(am), "a
}
} // namespace Service::AM
SERIALIZE_EXPORT_IMPL(Service::AM::AM_NET)

View file

@ -11,6 +11,12 @@ namespace Service::AM {
class AM_NET final : public Module::Interface {
public:
explicit AM_NET(std::shared_ptr<Module> am);
private:
SERVICE_SERIALIZATION(AM_NET, am, Module)
};
} // namespace Service::AM
BOOST_CLASS_EXPORT_KEY(Service::AM::AM_NET)
BOOST_SERIALIZATION_CONSTRUCT(Service::AM::AM_NET)

View file

@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/archives.h"
#include "core/hle/service/am/am_sys.h"
namespace Service::AM {
@ -71,3 +72,5 @@ AM_SYS::AM_SYS(std::shared_ptr<Module> am) : Module::Interface(std::move(am), "a
}
} // namespace Service::AM
SERIALIZE_EXPORT_IMPL(Service::AM::AM_SYS)

View file

@ -11,6 +11,12 @@ namespace Service::AM {
class AM_SYS final : public Module::Interface {
public:
explicit AM_SYS(std::shared_ptr<Module> am);
private:
SERVICE_SERIALIZATION(AM_SYS, am, Module)
};
} // namespace Service::AM
BOOST_CLASS_EXPORT_KEY(Service::AM::AM_SYS)
BOOST_SERIALIZATION_CONSTRUCT(Service::AM::AM_SYS)

View file

@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/archives.h"
#include "core/hle/service/am/am_u.h"
namespace Service::AM {
@ -83,3 +84,5 @@ AM_U::AM_U(std::shared_ptr<Module> am) : Module::Interface(std::move(am), "am:u"
}
} // namespace Service::AM
SERIALIZE_EXPORT_IMPL(Service::AM::AM_U)

View file

@ -11,6 +11,12 @@ namespace Service::AM {
class AM_U final : public Module::Interface {
public:
explicit AM_U(std::shared_ptr<Module> am);
private:
SERVICE_SERIALIZATION(AM_U, am, Module)
};
} // namespace Service::AM
BOOST_CLASS_EXPORT_KEY(Service::AM::AM_U)
BOOST_SERIALIZATION_CONSTRUCT(Service::AM::AM_U)

View file

@ -10,6 +10,8 @@
#include "core/hle/service/apt/ns.h"
#include "core/hle/service/cfg/cfg.h"
SERVICE_CONSTRUCT_IMPL(Service::APT::AppletManager)
namespace Service::APT {
enum class AppletPos { Application = 0, Library = 1, System = 2, SysLibrary = 3, Resident = 4 };

View file

@ -6,8 +6,12 @@
#include <array>
#include <memory>
#include <optional>
#include <vector>
#include <boost/serialization/array.hpp>
#include <boost/serialization/optional.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/vector.hpp>
#include "core/global.h"
#include "core/hle/kernel/event.h"
#include "core/hle/result.h"
#include "core/hle/service/fs/archive.h"
@ -84,6 +88,17 @@ struct MessageParameter {
SignalType signal = SignalType::None;
std::shared_ptr<Kernel::Object> object = nullptr;
std::vector<u8> buffer;
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& sender_id;
ar& destination_id;
ar& signal;
ar& object;
ar& buffer;
}
friend class boost::serialization::access;
};
/// Holds information about the parameters used in StartLibraryApplet
@ -161,6 +176,16 @@ public:
u64 current_title_id;
FS::MediaType current_media_type;
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& next_title_id;
ar& next_media_type;
ar& current_title_id;
ar& current_media_type;
}
friend class boost::serialization::access;
};
ApplicationJumpParameters GetApplicationJumpParameters() const {
@ -169,7 +194,8 @@ public:
private:
/// Parameter data to be returned in the next call to Glance/ReceiveParameter.
std::optional<MessageParameter> next_parameter;
// NOTE: A bug in gcc prevents serializing std::optional
boost::optional<MessageParameter> next_parameter;
static constexpr std::size_t NumAppletSlot = 4;
@ -199,6 +225,20 @@ private:
title_id = 0;
attributes.raw = 0;
}
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& applet_id;
ar& slot;
ar& title_id;
ar& registered;
ar& loaded;
ar& attributes.raw;
ar& notification_event;
ar& parameter_event;
}
friend class boost::serialization::access;
};
ApplicationJumpParameters app_jump_parameters{};
@ -216,6 +256,18 @@ private:
SignalType library_applet_closing_command;
Core::System& system;
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& next_parameter;
ar& app_jump_parameters;
ar& applet_slots;
ar& library_applet_closing_command;
}
friend class boost::serialization::access;
};
} // namespace Service::APT
SERVICE_CONSTRUCT(Service::APT::AppletManager)

View file

@ -2,6 +2,9 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/vector.hpp>
#include "common/archives.h"
#include "common/common_paths.h"
#include "common/file_util.h"
#include "common/logging/log.h"
@ -26,8 +29,25 @@
#include "core/hw/aes/ccm.h"
#include "core/hw/aes/key.h"
SERVICE_CONSTRUCT_IMPL(Service::APT::Module)
namespace Service::APT {
template <class Archive>
void Module::serialize(Archive& ar, const unsigned int) {
ar& shared_font_mem;
ar& shared_font_loaded;
ar& shared_font_relocated;
ar& lock;
ar& cpu_percent;
ar& unknown_ns_state_field;
ar& screen_capture_buffer;
ar& screen_capture_post_permission;
ar& applet_manager;
}
SERIALIZE_IMPL(Module)
Module::NSInterface::NSInterface(std::shared_ptr<Module> apt, const char* name, u32 max_session)
: ServiceFramework(name, max_session), apt(std::move(apt)) {}

View file

@ -6,9 +6,11 @@
#include <memory>
#include <vector>
#include "common/archives.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"
#include "core/global.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/service/service.h"
@ -65,7 +67,7 @@ public:
NSInterface(std::shared_ptr<Module> apt, const char* name, u32 max_session);
~NSInterface();
private:
protected:
std::shared_ptr<Module> apt;
};
@ -601,9 +603,16 @@ public:
*/
void CheckNew3DS(Kernel::HLERequestContext& ctx);
private:
protected:
bool application_reset_prepared{};
std::shared_ptr<Module> apt;
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& application_reset_prepared;
}
friend class boost::serialization::access;
};
private:
@ -630,8 +639,14 @@ private:
ScreencapPostPermission::CleanThePermission; // TODO(JamePeng): verify the initial value
std::shared_ptr<AppletManager> applet_manager;
template <class Archive>
void serialize(Archive& ar, const unsigned int);
friend class boost::serialization::access;
};
void InstallInterfaces(Core::System& system);
} // namespace Service::APT
SERVICE_CONSTRUCT(Service::APT::Module)

View file

@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/archives.h"
#include "core/hle/service/apt/apt_a.h"
namespace Service::APT {
@ -105,3 +106,5 @@ APT_A::APT_A(std::shared_ptr<Module> apt)
}
} // namespace Service::APT
SERIALIZE_EXPORT_IMPL(Service::APT::APT_A)

View file

@ -11,6 +11,12 @@ namespace Service::APT {
class APT_A final : public Module::APTInterface {
public:
explicit APT_A(std::shared_ptr<Module> apt);
private:
SERVICE_SERIALIZATION(APT_A, apt, Module)
};
} // namespace Service::APT
BOOST_CLASS_EXPORT_KEY(Service::APT::APT_A)
BOOST_SERIALIZATION_CONSTRUCT(Service::APT::APT_A)

View file

@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/archives.h"
#include "core/hle/service/apt/apt_s.h"
namespace Service::APT {
@ -105,3 +106,5 @@ APT_S::APT_S(std::shared_ptr<Module> apt)
}
} // namespace Service::APT
SERIALIZE_EXPORT_IMPL(Service::APT::APT_S)

View file

@ -18,6 +18,12 @@ namespace Service::APT {
class APT_S final : public Module::APTInterface {
public:
explicit APT_S(std::shared_ptr<Module> apt);
private:
SERVICE_SERIALIZATION(APT_S, apt, Module)
};
} // namespace Service::APT
BOOST_CLASS_EXPORT_KEY(Service::APT::APT_S)
BOOST_SERIALIZATION_CONSTRUCT(Service::APT::APT_S)

View file

@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/archives.h"
#include "core/hle/service/apt/apt_u.h"
namespace Service::APT {
@ -102,3 +103,5 @@ APT_U::APT_U(std::shared_ptr<Module> apt)
}
} // namespace Service::APT
SERIALIZE_EXPORT_IMPL(Service::APT::APT_U)

View file

@ -18,6 +18,12 @@ namespace Service::APT {
class APT_U final : public Module::APTInterface {
public:
explicit APT_U(std::shared_ptr<Module> apt);
private:
SERVICE_SERIALIZATION(APT_U, apt, Module)
};
} // namespace Service::APT
BOOST_CLASS_EXPORT_KEY(Service::APT::APT_U)
BOOST_SERIALIZATION_CONSTRUCT(Service::APT::APT_U)

View file

@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/archives.h"
#include "core/hle/service/apt/ns_s.h"
namespace Service::NS {
@ -29,3 +30,5 @@ NS_S::NS_S(std::shared_ptr<Service::APT::Module> apt)
}
} // namespace Service::NS
SERIALIZE_EXPORT_IMPL(Service::NS::NS_S)

View file

@ -14,6 +14,12 @@ namespace Service::NS {
class NS_S final : public Service::APT::Module::NSInterface {
public:
explicit NS_S(std::shared_ptr<Service::APT::Module> apt);
private:
SERVICE_SERIALIZATION(NS_S, apt, Service::APT::Module)
};
} // namespace Service::NS
BOOST_CLASS_EXPORT_KEY(Service::NS::NS_S)
BOOST_SERIALIZATION_CONSTRUCT(Service::NS::NS_S)

View file

@ -5,6 +5,8 @@
#pragma once
#include <memory>
#include <boost/serialization/shared_ptr.hpp>
#include "core/global.h"
#include "core/hle/kernel/event.h"
#include "core/hle/service/service.h"
@ -952,19 +954,42 @@ public:
*/
void GetNsDataNewFlagPrivileged(Kernel::HLERequestContext& ctx);
private:
protected:
std::shared_ptr<Module> boss;
private:
u8 new_arrival_flag;
u8 ns_data_new_flag;
u8 ns_data_new_flag_privileged;
u8 output_flag;
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& new_arrival_flag;
ar& ns_data_new_flag;
ar& ns_data_new_flag_privileged;
ar& output_flag;
}
friend class boost::serialization::access;
};
private:
std::shared_ptr<Kernel::Event> task_finish_event;
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& task_finish_event;
}
friend class boost::serialization::access;
};
void InstallInterfaces(Core::System& system);
} // namespace Service::BOSS
namespace boost::serialization {
template <class Archive>
void load_construct_data(Archive& ar, Service::BOSS::Module* t, const unsigned int) {
::new (t) Service::BOSS::Module(Core::Global<Core::System>());
}
} // namespace boost::serialization

View file

@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/archives.h"
#include "core/hle/service/boss/boss_p.h"
namespace Service::BOSS {
@ -84,3 +85,5 @@ BOSS_P::BOSS_P(std::shared_ptr<Module> boss)
}
} // namespace Service::BOSS
SERIALIZE_EXPORT_IMPL(Service::BOSS::BOSS_P)

View file

@ -11,6 +11,12 @@ namespace Service::BOSS {
class BOSS_P final : public Module::Interface {
public:
explicit BOSS_P(std::shared_ptr<Module> boss);
private:
SERVICE_SERIALIZATION(BOSS_P, boss, Module)
};
} // namespace Service::BOSS
BOOST_CLASS_EXPORT_KEY(Service::BOSS::BOSS_P)
BOOST_SERIALIZATION_CONSTRUCT(Service::BOSS::BOSS_P)

View file

@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/archives.h"
#include "core/hle/service/boss/boss_u.h"
namespace Service::BOSS {
@ -72,3 +73,5 @@ BOSS_U::BOSS_U(std::shared_ptr<Module> boss)
}
} // namespace Service::BOSS
SERIALIZE_EXPORT_IMPL(Service::BOSS::BOSS_U)

View file

@ -11,6 +11,12 @@ namespace Service::BOSS {
class BOSS_U final : public Module::Interface {
public:
explicit BOSS_U(std::shared_ptr<Module> boss);
private:
SERVICE_SERIALIZATION(BOSS_U, boss, Module)
};
} // namespace Service::BOSS
BOOST_CLASS_EXPORT_KEY(Service::BOSS::BOSS_U)
BOOST_SERIALIZATION_CONSTRUCT(Service::BOSS::BOSS_U)

View file

@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <algorithm>
#include "common/archives.h"
#include "common/bit_set.h"
#include "common/logging/log.h"
#include "core/core.h"
@ -20,8 +21,32 @@
#include "core/memory.h"
#include "core/settings.h"
SERVICE_CONSTRUCT_IMPL(Service::CAM::Module)
namespace Service::CAM {
template <class Archive>
void Module::serialize(Archive& ar, const unsigned int) {
ar& cameras;
ar& ports;
ar& is_camera_reload_pending;
if (Archive::is_loading::value) {
for (int i = 0; i < NumCameras; i++) {
LoadCameraImplementation(cameras[i], i);
}
for (std::size_t i = 0; i < ports.size(); i++) {
if (ports[i].is_busy) {
cameras[ports[i].camera_id].impl->StartCapture();
}
if (ports[i].is_receiving) {
StartReceiving(static_cast<int>(i));
}
}
}
}
SERIALIZE_IMPL(Module)
// built-in resolution parameters
constexpr std::array<Resolution, 8> PRESET_RESOLUTION{{
{640, 480, 0, 0, 639, 479}, // VGA

View file

@ -9,8 +9,14 @@
#include <future>
#include <memory>
#include <vector>
#include <boost/serialization/array.hpp>
#include <boost/serialization/deque.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/unique_ptr.hpp>
#include <boost/serialization/version.hpp>
#include "common/common_types.h"
#include "common/swap.h"
#include "core/global.h"
#include "core/hle/result.h"
#include "core/hle/service/service.h"
@ -180,6 +186,18 @@ struct Resolution {
u16 crop_y0;
u16 crop_x1;
u16 crop_y1;
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& width;
ar& height;
ar& crop_x0;
ar& crop_y0;
ar& crop_x1;
ar& crop_y1;
}
friend class boost::serialization::access;
};
struct PackageParameterWithoutContext {
@ -726,7 +744,7 @@ public:
*/
void DriverFinalize(Kernel::HLERequestContext& ctx);
private:
protected:
std::shared_ptr<Module> cam;
};
@ -755,6 +773,16 @@ private:
Effect effect{Effect::None};
OutputFormat format{OutputFormat::YUV422};
Resolution resolution = {0, 0, 0, 0, 0, 0};
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& flip;
ar& effect;
ar& format;
ar& resolution;
}
friend class boost::serialization::access;
};
struct CameraConfig {
@ -762,6 +790,20 @@ private:
std::array<ContextConfig, 2> contexts;
int current_context{0};
FrameRate frame_rate{FrameRate::Rate_15};
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
// For compatibility: put a nullptr here
if (file_version == 0) {
std::unique_ptr<Camera::CameraInterface> x;
ar& x;
}
ar& contexts;
ar& current_context;
ar& frame_rate;
}
friend class boost::serialization::access;
};
struct PortConfig {
@ -798,6 +840,31 @@ private:
u32 dest_size{0}; // the destination size of the receiving process
void Clear();
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& camera_id;
ar& is_active;
ar& is_pending_receiving;
ar& is_busy;
ar& is_receiving;
ar& is_trimming;
ar& x0;
ar& y0;
ar& x1;
ar& y1;
ar& transfer_bytes;
ar& completion_event;
ar& buffer_error_interrupt_event;
ar& vsync_interrupt_event;
ar& vsync_timings;
// Ignore capture_result. In-progress captures might be affected but this is OK.
ar& dest_process;
ar& dest;
ar& dest_size;
}
friend class boost::serialization::access;
};
void LoadCameraImplementation(CameraConfig& camera, int camera_id);
@ -808,6 +875,10 @@ private:
Core::TimingEventType* completion_event_callback;
Core::TimingEventType* vsync_interrupt_event_callback;
std::atomic<bool> is_camera_reload_pending{false};
template <class Archive>
void serialize(Archive& ar, const unsigned int);
friend class boost::serialization::access;
};
std::shared_ptr<Module> GetModule(Core::System& system);
@ -815,3 +886,6 @@ std::shared_ptr<Module> GetModule(Core::System& system);
void InstallInterfaces(Core::System& system);
} // namespace Service::CAM
SERVICE_CONSTRUCT(Service::CAM::Module)
BOOST_CLASS_VERSION(Service::CAM::Module::CameraConfig, 1)

View file

@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/archives.h"
#include "core/hle/service/cam/cam.h"
#include "core/hle/service/cam/cam_c.h"
@ -79,3 +80,5 @@ CAM_C::CAM_C(std::shared_ptr<Module> cam) : Module::Interface(std::move(cam), "c
}
} // namespace Service::CAM
SERIALIZE_EXPORT_IMPL(Service::CAM::CAM_C)

View file

@ -11,6 +11,12 @@ namespace Service::CAM {
class CAM_C final : public Module::Interface {
public:
explicit CAM_C(std::shared_ptr<Module> cam);
private:
SERVICE_SERIALIZATION(CAM_C, cam, Module)
};
} // namespace Service::CAM
BOOST_CLASS_EXPORT_KEY(Service::CAM::CAM_C)
BOOST_SERIALIZATION_CONSTRUCT(Service::CAM::CAM_C)

View file

@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/archives.h"
#include "core/hle/service/cam/cam_q.h"
namespace Service::CAM {
@ -13,3 +14,5 @@ CAM_Q::CAM_Q() : ServiceFramework("cam:q", 1 /*TODO: find the true value*/) {
}
} // namespace Service::CAM
SERIALIZE_EXPORT_IMPL(Service::CAM::CAM_Q)

View file

@ -11,6 +11,11 @@ namespace Service::CAM {
class CAM_Q : public ServiceFramework<CAM_Q> {
public:
CAM_Q();
private:
SERVICE_SERIALIZATION_SIMPLE
};
} // namespace Service::CAM
BOOST_CLASS_EXPORT_KEY(Service::CAM::CAM_Q)

View file

@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/archives.h"
#include "core/hle/service/cam/cam.h"
#include "core/hle/service/cam/cam_s.h"
@ -79,3 +80,5 @@ CAM_S::CAM_S(std::shared_ptr<Module> cam) : Module::Interface(std::move(cam), "c
}
} // namespace Service::CAM
SERIALIZE_EXPORT_IMPL(Service::CAM::CAM_S)

View file

@ -11,6 +11,12 @@ namespace Service::CAM {
class CAM_S final : public Module::Interface {
public:
explicit CAM_S(std::shared_ptr<Module> cam);
private:
SERVICE_SERIALIZATION(CAM_S, cam, Module)
};
} // namespace Service::CAM
BOOST_CLASS_EXPORT_KEY(Service::CAM::CAM_S)
BOOST_SERIALIZATION_CONSTRUCT(Service::CAM::CAM_S)

View file

@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/archives.h"
#include "core/hle/service/cam/cam.h"
#include "core/hle/service/cam/cam_u.h"
@ -79,3 +80,5 @@ CAM_U::CAM_U(std::shared_ptr<Module> cam) : Module::Interface(std::move(cam), "c
}
} // namespace Service::CAM
SERIALIZE_EXPORT_IMPL(Service::CAM::CAM_U)

View file

@ -11,6 +11,12 @@ namespace Service::CAM {
class CAM_U final : public Module::Interface {
public:
explicit CAM_U(std::shared_ptr<Module> cam);
private:
SERVICE_SERIALIZATION(CAM_U, cam, Module)
};
} // namespace Service::CAM
BOOST_CLASS_EXPORT_KEY(Service::CAM::CAM_U)
BOOST_SERIALIZATION_CONSTRUCT(Service::CAM::CAM_U)

View file

@ -2,9 +2,12 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/unique_ptr.hpp>
#include <cryptopp/base64.h>
#include <cryptopp/hmac.h>
#include <cryptopp/sha.h>
#include "common/archives.h"
#include "common/common_paths.h"
#include "common/file_util.h"
#include "common/logging/log.h"
@ -24,8 +27,20 @@
#include "core/hle/service/cfg/cfg.h"
#include "fmt/format.h"
SERVICE_CONSTRUCT_IMPL(Service::CECD::Module)
SERIALIZE_EXPORT_IMPL(Service::CECD::Module)
SERIALIZE_EXPORT_IMPL(Service::CECD::Module::SessionData)
namespace Service::CECD {
template <class Archive>
void Module::serialize(Archive& ar, const unsigned int) {
ar& cecd_system_save_data_archive;
ar& cecinfo_event;
ar& change_state_event;
}
SERIALIZE_IMPL(Module)
using CecDataPathType = Module::CecDataPathType;
using CecOpenMode = Module::CecOpenMode;
using CecSystemInfoType = Module::CecSystemInfoType;
@ -93,7 +108,7 @@ void Module::Interface::Open(Kernel::HLERequestContext& ctx) {
} else {
session_data->file = std::move(file_result).Unwrap();
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(session_data->file->GetSize()); // Return file size
rb.Push<u32>(static_cast<u32>(session_data->file->GetSize())); // Return file size
}
if (path_type == CecDataPathType::MboxProgramId) {
@ -141,8 +156,8 @@ void Module::Interface::Read(Kernel::HLERequestContext& ctx) {
break;
default: // If not directory, then it is a file
std::vector<u8> buffer(write_buffer_size);
const u32 bytes_read =
session_data->file->Read(0, write_buffer_size, buffer.data()).Unwrap();
const u32 bytes_read = static_cast<u32>(
session_data->file->Read(0, write_buffer_size, buffer.data()).Unwrap());
write_buffer.Write(buffer.data(), 0, write_buffer_size);
session_data->file->Close();
@ -184,7 +199,8 @@ void Module::Interface::ReadMessage(Kernel::HLERequestContext& ctx) {
auto message = std::move(message_result).Unwrap();
std::vector<u8> buffer(buffer_size);
const u32 bytes_read = message->Read(0, buffer_size, buffer.data()).Unwrap();
const u32 bytes_read =
static_cast<u32>(message->Read(0, buffer_size, buffer.data()).Unwrap());
write_buffer.Write(buffer.data(), 0, buffer_size);
message->Close();
@ -253,7 +269,8 @@ void Module::Interface::ReadMessageWithHMAC(Kernel::HLERequestContext& ctx) {
auto message = std::move(message_result).Unwrap();
std::vector<u8> buffer(buffer_size);
const u32 bytes_read = message->Read(0, buffer_size, buffer.data()).Unwrap();
const u32 bytes_read =
static_cast<u32>(message->Read(0, buffer_size, buffer.data()).Unwrap());
write_buffer.Write(buffer.data(), 0, buffer_size);
message->Close();
@ -354,8 +371,8 @@ void Module::Interface::Write(Kernel::HLERequestContext& ctx) {
buffer);
}
const u32 bytes_written =
session_data->file->Write(0, buffer.size(), true, buffer.data()).Unwrap();
const u32 bytes_written = static_cast<u32>(
session_data->file->Write(0, buffer.size(), true, buffer.data()).Unwrap());
session_data->file->Close();
rb.Push(RESULT_SUCCESS);
@ -416,7 +433,8 @@ void Module::Interface::WriteMessage(Kernel::HLERequestContext& ctx) {
msg_header.sender_id, msg_header.sender_id2, msg_header.send_count,
msg_header.forward_count, msg_header.user_data);
const u32 bytes_written = message->Write(0, buffer_size, true, buffer.data()).Unwrap();
const u32 bytes_written =
static_cast<u32>(message->Write(0, buffer_size, true, buffer.data()).Unwrap());
message->Close();
rb.Push(RESULT_SUCCESS);
@ -502,7 +520,8 @@ void Module::Interface::WriteMessageWithHMAC(Kernel::HLERequestContext& ctx) {
hmac.CalculateDigest(hmac_digest.data(), message_body.data(), msg_header.body_size);
std::memcpy(buffer.data() + hmac_offset, hmac_digest.data(), hmac_size);
const u32 bytes_written = message->Write(0, buffer_size, true, buffer.data()).Unwrap();
const u32 bytes_written =
static_cast<u32>(message->Write(0, buffer_size, true, buffer.data()).Unwrap());
message->Close();
rb.Push(RESULT_SUCCESS);
@ -744,7 +763,8 @@ void Module::Interface::OpenAndWrite(Kernel::HLERequestContext& ctx) {
cecd->CheckAndUpdateFile(path_type, ncch_program_id, buffer);
}
const u32 bytes_written = file->Write(0, buffer.size(), true, buffer.data()).Unwrap();
const u32 bytes_written =
static_cast<u32>(file->Write(0, buffer.size(), true, buffer.data()).Unwrap());
file->Close();
rb.Push(RESULT_SUCCESS);
@ -793,7 +813,8 @@ void Module::Interface::OpenAndRead(Kernel::HLERequestContext& ctx) {
auto file = std::move(file_result).Unwrap();
std::vector<u8> buffer(buffer_size);
const u32 bytes_read = file->Read(0, buffer_size, buffer.data()).Unwrap();
const u32 bytes_read =
static_cast<u32>(file->Read(0, buffer_size, buffer.data()).Unwrap());
write_buffer.Write(buffer.data(), 0, buffer_size);
file->Close();
@ -924,7 +945,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_
constexpr u32 max_num_boxes = 24;
constexpr u32 name_size = 16; // fixed size 16 characters long
constexpr u32 valid_name_size = 8; // 8 characters are valid, the rest are null
const u32 file_size = file_buffer.size();
const u32 file_size = static_cast<u32>(file_buffer.size());
switch (path_type) {
case CecDataPathType::MboxList: {
@ -1008,7 +1029,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_
std::u16string u16_filename;
// Loop through entries but don't add mboxlist____ to itself.
for (auto i = 0; i < entry_count; i++) {
for (u32 i = 0; i < entry_count; i++) {
u16_filename = std::u16string(entries[i].filename);
file_name = Common::UTF16ToUTF8(u16_filename);
@ -1199,7 +1220,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_
std::string file_name;
std::u16string u16_filename;
for (auto i = 0; i < entry_count; i++) {
for (u32 i = 0; i < entry_count; i++) {
u16_filename = std::u16string(entries[i].filename);
file_name = Common::UTF16ToUTF8(u16_filename);
@ -1217,7 +1238,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_
auto message_result = cecd_system_save_data_archive->OpenFile(message_path, mode);
auto message = std::move(message_result).Unwrap();
const u32 message_size = message->GetSize();
const u32 message_size = static_cast<u32>(message->GetSize());
std::vector<u8> buffer(message_size);
message->Read(0, message_size, buffer.data()).Unwrap();
@ -1291,7 +1312,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_
std::string file_name;
std::u16string u16_filename;
for (auto i = 0; i < entry_count; i++) {
for (u32 i = 0; i < entry_count; i++) {
u16_filename = std::u16string(entries[i].filename);
file_name = Common::UTF16ToUTF8(u16_filename);
@ -1307,7 +1328,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_
auto message_result = cecd_system_save_data_archive->OpenFile(message_path, mode);
auto message = std::move(message_result).Unwrap();
const u32 message_size = message->GetSize();
const u32 message_size = static_cast<u32>(message->GetSize());
std::vector<u8> buffer(message_size);
message->Read(0, message_size, buffer.data()).Unwrap();

Some files were not shown because too many files have changed in this diff Show more