mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-21 12:59:14 +12:00
metal: initial support
This commit is contained in:
parent
29d9ed7224
commit
f0547d1a71
167 changed files with 28839 additions and 1271 deletions
|
@ -33,8 +33,8 @@ namespace Audio {
|
|||
SampleFormat format;
|
||||
SourceType sourceType;
|
||||
|
||||
bool fromQueue = false; // Is this buffer from the buffer queue or an embedded buffer?
|
||||
bool hasPlayedOnce = false; // Has the buffer been played at least once before?
|
||||
bool fromQueue = false; // Is this buffer from the buffer queue or an embedded buffer?
|
||||
bool hasPlayedOnce = false; // Has the buffer been played at least once before?
|
||||
|
||||
bool operator<(const Buffer& other) const {
|
||||
// Lower ID = Higher priority
|
||||
|
@ -136,7 +136,7 @@ namespace Audio {
|
|||
const auto counter0 = dspRam.region0.frameCounter;
|
||||
const auto counter1 = dspRam.region1.frameCounter;
|
||||
|
||||
// Handle wraparound cases first
|
||||
// HandleType wraparound cases first
|
||||
if (counter0 == 0xffff && counter1 != 0xfffe) {
|
||||
return 1;
|
||||
} else if (counter1 == 0xffff && counter0 != 0xfffe) {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
namespace Common {
|
||||
class CapstoneDisassembler {
|
||||
csh handle; // Handle to our disassembler object
|
||||
csh handle; // HandleType to our disassembler object
|
||||
cs_insn* instructions = nullptr; // Pointer to instruction object
|
||||
bool initialized = false;
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "helpers.hpp"
|
||||
#include "memory.hpp"
|
||||
#include "result.hpp"
|
||||
|
@ -15,13 +16,13 @@
|
|||
using Result::HorizonResult;
|
||||
|
||||
namespace PathType {
|
||||
enum : u32 {
|
||||
Invalid = 0,
|
||||
Empty = 1,
|
||||
Binary = 2,
|
||||
ASCII = 3,
|
||||
UTF16 = 4,
|
||||
};
|
||||
enum : u32 {
|
||||
Invalid = 0,
|
||||
Empty = 1,
|
||||
Binary = 2,
|
||||
ASCII = 3,
|
||||
UTF16 = 4,
|
||||
};
|
||||
}
|
||||
|
||||
namespace ArchiveID {
|
||||
|
@ -42,83 +43,81 @@ namespace ArchiveID {
|
|||
UserSaveData2 = 0x567890B4,
|
||||
};
|
||||
|
||||
static std::string toString(u32 id) {
|
||||
switch (id) {
|
||||
case SelfNCCH: return "SelfNCCH";
|
||||
case SaveData: return "SaveData";
|
||||
case ExtSaveData: return "ExtSaveData";
|
||||
case SharedExtSaveData: return "SharedExtSaveData";
|
||||
case SystemSaveData: return "SystemSaveData";
|
||||
case SDMC: return "SDMC";
|
||||
case SDMCWriteOnly: return "SDMC (Write-only)";
|
||||
case SavedataAndNcch: return "Savedata & NCCH (archive 0x2345678A)";
|
||||
default: return "Unknown archive";
|
||||
}
|
||||
}
|
||||
}
|
||||
static std::string toString(u32 id) {
|
||||
switch (id) {
|
||||
case SelfNCCH: return "SelfNCCH";
|
||||
case SaveData: return "SaveData";
|
||||
case ExtSaveData: return "ExtSaveData";
|
||||
case SharedExtSaveData: return "SharedExtSaveData";
|
||||
case SystemSaveData: return "SystemSaveData";
|
||||
case SDMC: return "SDMC";
|
||||
case SDMCWriteOnly: return "SDMC (Write-only)";
|
||||
case SavedataAndNcch: return "Savedata & NCCH (archive 0x2345678A)";
|
||||
default: return "Unknown archive";
|
||||
}
|
||||
}
|
||||
} // namespace ArchiveID
|
||||
|
||||
struct FSPath {
|
||||
u32 type = PathType::Invalid;
|
||||
u32 type = PathType::Invalid;
|
||||
|
||||
std::vector<u8> binary; // Path data for binary paths
|
||||
std::string string; // Path data for ASCII paths
|
||||
std::u16string utf16_string;
|
||||
std::vector<u8> binary; // Path data for binary paths
|
||||
std::string string; // Path data for ASCII paths
|
||||
std::u16string utf16_string;
|
||||
|
||||
FSPath() {}
|
||||
FSPath() {}
|
||||
|
||||
FSPath(u32 type, const std::vector<u8>& vec) : type(type) {
|
||||
switch (type) {
|
||||
case PathType::Binary:
|
||||
binary = std::move(vec);
|
||||
break;
|
||||
FSPath(u32 type, const std::vector<u8>& vec) : type(type) {
|
||||
switch (type) {
|
||||
case PathType::Binary: binary = std::move(vec); break;
|
||||
|
||||
case PathType::ASCII:
|
||||
string.resize(vec.size() - 1); // -1 because of the null terminator
|
||||
std::memcpy(string.data(), vec.data(), vec.size() - 1); // Copy string data
|
||||
break;
|
||||
case PathType::ASCII:
|
||||
string.resize(vec.size() - 1); // -1 because of the null terminator
|
||||
std::memcpy(string.data(), vec.data(), vec.size() - 1); // Copy string data
|
||||
break;
|
||||
|
||||
case PathType::UTF16: {
|
||||
const size_t size = vec.size() / sizeof(u16) - 1; // Character count. -1 because null terminator here too
|
||||
utf16_string.resize(size);
|
||||
std::memcpy(utf16_string.data(), vec.data(), size * sizeof(u16));
|
||||
break;
|
||||
}
|
||||
; }
|
||||
}
|
||||
case PathType::UTF16: {
|
||||
const size_t size = vec.size() / sizeof(u16) - 1; // Character count. -1 because null terminator here too
|
||||
utf16_string.resize(size);
|
||||
std::memcpy(utf16_string.data(), vec.data(), size * sizeof(u16));
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct FilePerms {
|
||||
u32 raw;
|
||||
u32 raw;
|
||||
|
||||
FilePerms(u32 val) : raw(val) {}
|
||||
bool read() const { return (raw & 1) != 0; }
|
||||
bool write() const { return (raw & 2) != 0; }
|
||||
bool create() const { return (raw & 4) != 0; }
|
||||
FilePerms(u32 val) : raw(val) {}
|
||||
bool read() const { return (raw & 1) != 0; }
|
||||
bool write() const { return (raw & 2) != 0; }
|
||||
bool create() const { return (raw & 4) != 0; }
|
||||
};
|
||||
|
||||
class ArchiveBase;
|
||||
struct FileSession {
|
||||
ArchiveBase* archive = nullptr;
|
||||
FILE* fd = nullptr; // File descriptor for file sessions that require them.
|
||||
FSPath path;
|
||||
FSPath archivePath;
|
||||
u32 priority = 0; // TODO: What does this even do
|
||||
bool isOpen;
|
||||
ArchiveBase* archive = nullptr;
|
||||
FILE* fd = nullptr; // File descriptor for file sessions that require them.
|
||||
FSPath path;
|
||||
FSPath archivePath;
|
||||
u32 priority = 0; // TODO: What does this even do
|
||||
bool isOpen;
|
||||
|
||||
FileSession(ArchiveBase* archive, const FSPath& filePath, const FSPath& archivePath, FILE* fd, bool isOpen = true) :
|
||||
archive(archive), path(filePath), archivePath(archivePath), fd(fd), isOpen(isOpen), priority(0) {}
|
||||
FileSession(ArchiveBase* archive, const FSPath& filePath, const FSPath& archivePath, FILE* fd, bool isOpen = true)
|
||||
: archive(archive), path(filePath), archivePath(archivePath), fd(fd), isOpen(isOpen), priority(0) {}
|
||||
|
||||
// For cloning a file session
|
||||
FileSession(const FileSession& other) : archive(other.archive), path(other.path),
|
||||
archivePath(other.archivePath), fd(other.fd), isOpen(other.isOpen), priority(other.priority) {}
|
||||
// For cloning a file session
|
||||
FileSession(const FileSession& other)
|
||||
: archive(other.archive), path(other.path), archivePath(other.archivePath), fd(other.fd), isOpen(other.isOpen), priority(other.priority) {}
|
||||
};
|
||||
|
||||
struct ArchiveSession {
|
||||
ArchiveBase* archive = nullptr;
|
||||
FSPath path;
|
||||
bool isOpen;
|
||||
ArchiveBase* archive = nullptr;
|
||||
FSPath path;
|
||||
bool isOpen;
|
||||
|
||||
ArchiveSession(ArchiveBase* archive, const FSPath& filePath, bool isOpen = true) : archive(archive), path(filePath), isOpen(isOpen) {}
|
||||
ArchiveSession(ArchiveBase* archive, const FSPath& filePath, bool isOpen = true) : archive(archive), path(filePath), isOpen(isOpen) {}
|
||||
};
|
||||
|
||||
struct DirectoryEntry {
|
||||
|
@ -156,106 +155,104 @@ struct DirectorySession {
|
|||
using FileDescriptor = std::optional<FILE*>;
|
||||
|
||||
class ArchiveBase {
|
||||
public:
|
||||
struct FormatInfo {
|
||||
u32 size; // Archive size
|
||||
u32 numOfDirectories; // Number of directories
|
||||
u32 numOfFiles; // Number of files
|
||||
bool duplicateData; // Whether to duplicate data or not
|
||||
};
|
||||
public:
|
||||
struct FormatInfo {
|
||||
u32 size; // Archive size
|
||||
u32 numOfDirectories; // Number of directories
|
||||
u32 numOfFiles; // Number of files
|
||||
bool duplicateData; // Whether to duplicate data or not
|
||||
};
|
||||
|
||||
protected:
|
||||
using Handle = u32;
|
||||
protected:
|
||||
using HandleType = u32;
|
||||
|
||||
static constexpr FileDescriptor NoFile = nullptr;
|
||||
static constexpr FileDescriptor FileError = std::nullopt;
|
||||
Memory& mem;
|
||||
static constexpr FileDescriptor NoFile = nullptr;
|
||||
static constexpr FileDescriptor FileError = std::nullopt;
|
||||
Memory& mem;
|
||||
|
||||
// Returns if a specified 3DS path in UTF16 or ASCII format is safe or not
|
||||
// A 3DS path is considered safe if its first character is '/' which means we're not trying to access anything outside the root of the fs
|
||||
// And if it doesn't contain enough instances of ".." (Indicating "climb up a folder" in filesystems) to let the software climb up the directory tree
|
||||
// And access files outside of the emulator's app data folder
|
||||
template <u32 format>
|
||||
bool isPathSafe(const FSPath& path) {
|
||||
static_assert(format == PathType::ASCII || format == PathType::UTF16);
|
||||
using String = typename std::conditional<format == PathType::UTF16, std::u16string, std::string>::type; // String type for the path
|
||||
using Char = typename String::value_type; // Char type for the path
|
||||
// Returns if a specified 3DS path in UTF16 or ASCII format is safe or not
|
||||
// A 3DS path is considered safe if its first character is '/' which means we're not trying to access anything outside the root of the fs
|
||||
// And if it doesn't contain enough instances of ".." (Indicating "climb up a folder" in filesystems) to let the software climb up the directory
|
||||
// tree And access files outside of the emulator's app data folder
|
||||
template <u32 format>
|
||||
bool isPathSafe(const FSPath& path) {
|
||||
static_assert(format == PathType::ASCII || format == PathType::UTF16);
|
||||
using String = typename std::conditional<format == PathType::UTF16, std::u16string, std::string>::type; // String type for the path
|
||||
using Char = typename String::value_type; // Char type for the path
|
||||
|
||||
String pathString, dots;
|
||||
if constexpr (std::is_same<String, std::u16string>()) {
|
||||
pathString = path.utf16_string;
|
||||
dots = u"..";
|
||||
} else {
|
||||
pathString = path.string;
|
||||
dots = "..";
|
||||
}
|
||||
String pathString, dots;
|
||||
if constexpr (std::is_same<String, std::u16string>()) {
|
||||
pathString = path.utf16_string;
|
||||
dots = u"..";
|
||||
} else {
|
||||
pathString = path.string;
|
||||
dots = "..";
|
||||
}
|
||||
|
||||
// If the path string doesn't begin with / then that means it's accessing outside the FS root, which is invalid & unsafe
|
||||
if (pathString[0] != Char('/')) return false;
|
||||
// If the path string doesn't begin with / then that means it's accessing outside the FS root, which is invalid & unsafe
|
||||
if (pathString[0] != Char('/')) return false;
|
||||
|
||||
// Counts how many folders sans the root our file is nested under.
|
||||
// If it's < 0 at any point of parsing, then the path is unsafe and tries to crawl outside our file sandbox.
|
||||
// If it's 0 then this is the FS root.
|
||||
// If it's > 0 then we're in a subdirectory of the root.
|
||||
int level = 0;
|
||||
// Counts how many folders sans the root our file is nested under.
|
||||
// If it's < 0 at any point of parsing, then the path is unsafe and tries to crawl outside our file sandbox.
|
||||
// If it's 0 then this is the FS root.
|
||||
// If it's > 0 then we're in a subdirectory of the root.
|
||||
int level = 0;
|
||||
|
||||
// Split the string on / characters and see how many of the substrings are ".."
|
||||
size_t pos = 0;
|
||||
while ((pos = pathString.find(Char('/'))) != String::npos) {
|
||||
String token = pathString.substr(0, pos);
|
||||
pathString.erase(0, pos + 1);
|
||||
// Split the string on / characters and see how many of the substrings are ".."
|
||||
size_t pos = 0;
|
||||
while ((pos = pathString.find(Char('/'))) != String::npos) {
|
||||
String token = pathString.substr(0, pos);
|
||||
pathString.erase(0, pos + 1);
|
||||
|
||||
if (token == dots) {
|
||||
level--;
|
||||
if (level < 0) return false;
|
||||
} else {
|
||||
level++;
|
||||
}
|
||||
}
|
||||
if (token == dots) {
|
||||
level--;
|
||||
if (level < 0) return false;
|
||||
} else {
|
||||
level++;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
virtual std::string name() = 0;
|
||||
virtual u64 getFreeBytes() = 0;
|
||||
virtual HorizonResult createFile(const FSPath& path, u64 size) = 0;
|
||||
virtual HorizonResult deleteFile(const FSPath& path) = 0;
|
||||
public:
|
||||
virtual std::string name() = 0;
|
||||
virtual u64 getFreeBytes() = 0;
|
||||
virtual HorizonResult createFile(const FSPath& path, u64 size) = 0;
|
||||
virtual HorizonResult deleteFile(const FSPath& path) = 0;
|
||||
|
||||
virtual Rust::Result<FormatInfo, HorizonResult> getFormatInfo(const FSPath& path) {
|
||||
Helpers::panic("Unimplemented GetFormatInfo for %s archive", name().c_str());
|
||||
// Return a dummy struct just to avoid the UB of not returning anything, even if we panic
|
||||
return Ok(FormatInfo{ .size = 0, .numOfDirectories = 0, .numOfFiles = 0, .duplicateData = false });
|
||||
}
|
||||
virtual Rust::Result<FormatInfo, HorizonResult> getFormatInfo(const FSPath& path) {
|
||||
Helpers::panic("Unimplemented GetFormatInfo for %s archive", name().c_str());
|
||||
// Return a dummy struct just to avoid the UB of not returning anything, even if we panic
|
||||
return Ok(FormatInfo{.size = 0, .numOfDirectories = 0, .numOfFiles = 0, .duplicateData = false});
|
||||
}
|
||||
|
||||
virtual HorizonResult createDirectory(const FSPath& path) {
|
||||
Helpers::panic("Unimplemented CreateDirectory for %s archive", name().c_str());
|
||||
return Result::FS::AlreadyExists;
|
||||
}
|
||||
virtual HorizonResult createDirectory(const FSPath& path) {
|
||||
Helpers::panic("Unimplemented CreateDirectory for %s archive", name().c_str());
|
||||
return Result::FS::AlreadyExists;
|
||||
}
|
||||
|
||||
// Returns nullopt if opening the file failed, otherwise returns a file descriptor to it (nullptr if none is needed)
|
||||
virtual FileDescriptor openFile(const FSPath& path, const FilePerms& perms) = 0;
|
||||
virtual Rust::Result<ArchiveBase*, HorizonResult> openArchive(const FSPath& path) = 0;
|
||||
// Returns nullopt if opening the file failed, otherwise returns a file descriptor to it (nullptr if none is needed)
|
||||
virtual FileDescriptor openFile(const FSPath& path, const FilePerms& perms) = 0;
|
||||
virtual Rust::Result<ArchiveBase*, HorizonResult> openArchive(const FSPath& path) = 0;
|
||||
|
||||
virtual Rust::Result<DirectorySession, HorizonResult> openDirectory(const FSPath& path) {
|
||||
Helpers::panic("Unimplemented OpenDirectory for %s archive", name().c_str());
|
||||
return Err(Result::FS::FileNotFoundAlt);
|
||||
}
|
||||
virtual Rust::Result<DirectorySession, HorizonResult> openDirectory(const FSPath& path) {
|
||||
Helpers::panic("Unimplemented OpenDirectory for %s archive", name().c_str());
|
||||
return Err(Result::FS::FileNotFoundAlt);
|
||||
}
|
||||
|
||||
virtual void format(const FSPath& path, const FormatInfo& info) {
|
||||
Helpers::panic("Unimplemented Format for %s archive", name().c_str());
|
||||
}
|
||||
virtual void format(const FSPath& path, const FormatInfo& info) { Helpers::panic("Unimplemented Format for %s archive", name().c_str()); }
|
||||
|
||||
virtual HorizonResult renameFile(const FSPath& oldPath, const FSPath& newPath) {
|
||||
virtual HorizonResult renameFile(const FSPath& oldPath, const FSPath& newPath) {
|
||||
Helpers::panic("Unimplemented RenameFile for %s archive", name().c_str());
|
||||
return Result::Success;
|
||||
}
|
||||
}
|
||||
|
||||
// Read size bytes from a file starting at offset "offset" into a certain buffer in memory
|
||||
// Returns the number of bytes read, or nullopt if the read failed
|
||||
virtual std::optional<u32> readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) = 0;
|
||||
// Read size bytes from a file starting at offset "offset" into a certain buffer in memory
|
||||
// Returns the number of bytes read, or nullopt if the read failed
|
||||
virtual std::optional<u32> readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) = 0;
|
||||
|
||||
ArchiveBase(Memory& mem) : mem(mem) {}
|
||||
ArchiveBase(Memory& mem) : mem(mem) {}
|
||||
};
|
||||
|
||||
struct ArchiveResource {
|
||||
|
@ -263,4 +260,4 @@ struct ArchiveResource {
|
|||
u32 clusterSize; // Size of a cluster in bytes
|
||||
u32 partitionCapacityInClusters;
|
||||
u32 freeSpaceInClusters;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
#pragma once
|
||||
#include "helpers.hpp"
|
||||
|
||||
using Handle = u32;
|
||||
using HandleType = u32;
|
||||
|
||||
namespace KernelHandles {
|
||||
enum : u32 {
|
||||
Max = 0xFFFF7FFF, // Max handle the kernel can automagically allocate
|
||||
Max = 0xFFFF7FFF, // Max handle the kernel can automagically allocate
|
||||
|
||||
// Hardcoded handles
|
||||
CurrentThread = 0xFFFF8000, // Used by the original kernel
|
||||
CurrentProcess = 0xFFFF8001, // Used by the original kernel
|
||||
AC, // Something network related
|
||||
ACT, // Handles NNID accounts
|
||||
AM, // Application manager
|
||||
APT, // App Title something service?
|
||||
BOSS, // Streetpass stuff?
|
||||
CAM, // Camera service
|
||||
CECD, // More Streetpass stuff?
|
||||
CFG_U, // CFG service (Console & region info)
|
||||
CurrentThread = 0xFFFF8000, // Used by the original kernel
|
||||
CurrentProcess = 0xFFFF8001, // Used by the original kernel
|
||||
AC, // Something network related
|
||||
ACT, // Handles NNID accounts
|
||||
AM, // Application manager
|
||||
APT, // App Title something service?
|
||||
BOSS, // Streetpass stuff?
|
||||
CAM, // Camera service
|
||||
CECD, // More Streetpass stuff?
|
||||
CFG_U, // CFG service (Console & region info)
|
||||
CFG_I,
|
||||
CFG_S, // Used by most system apps in lieu of cfg:u
|
||||
CSND, // Plays audio directly from PCM samples
|
||||
|
@ -50,10 +50,10 @@ namespace KernelHandles {
|
|||
MinServiceHandle = AC,
|
||||
MaxServiceHandle = Y2R,
|
||||
|
||||
GSPSharedMemHandle = MaxServiceHandle + 1, // Handle for the GSP shared memory
|
||||
GSPSharedMemHandle = MaxServiceHandle + 1, // HandleType for the GSP shared memory
|
||||
FontSharedMemHandle,
|
||||
CSNDSharedMemHandle,
|
||||
APTCaptureSharedMemHandle, // Shared memory for display capture info,
|
||||
APTCaptureSharedMemHandle, // Shared memory for display capture info,
|
||||
HIDSharedMemHandle,
|
||||
|
||||
MinSharedMemHandle = GSPSharedMemHandle,
|
||||
|
@ -61,17 +61,13 @@ namespace KernelHandles {
|
|||
};
|
||||
|
||||
// Returns whether "handle" belongs to one of the OS services
|
||||
static constexpr bool isServiceHandle(Handle handle) {
|
||||
return handle >= MinServiceHandle && handle <= MaxServiceHandle;
|
||||
}
|
||||
static constexpr bool isServiceHandle(HandleType handle) { return handle >= MinServiceHandle && handle <= MaxServiceHandle; }
|
||||
|
||||
// Returns whether "handle" belongs to one of the OS services' shared memory areas
|
||||
static constexpr bool isSharedMemHandle(Handle handle) {
|
||||
return handle >= MinSharedMemHandle && handle <= MaxSharedMemHandle;
|
||||
}
|
||||
static constexpr bool isSharedMemHandle(HandleType handle) { return handle >= MinSharedMemHandle && handle <= MaxSharedMemHandle; }
|
||||
|
||||
// Returns the name of a handle as a string based on the given handle
|
||||
static const char* getServiceName(Handle handle) {
|
||||
static const char* getServiceName(HandleType handle) {
|
||||
switch (handle) {
|
||||
case AC: return "AC";
|
||||
case ACT: return "ACT";
|
||||
|
@ -110,4 +106,4 @@ namespace KernelHandles {
|
|||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace KernelHandles
|
||||
|
|
|
@ -34,22 +34,22 @@ class Kernel {
|
|||
static_assert(appResourceLimits.maxThreads <= 63, "The waitlist system is built on the premise that <= 63 threads max can be active");
|
||||
|
||||
std::vector<KernelObject> objects;
|
||||
std::vector<Handle> portHandles;
|
||||
std::vector<Handle> mutexHandles;
|
||||
std::vector<Handle> timerHandles;
|
||||
std::vector<HandleType> portHandles;
|
||||
std::vector<HandleType> mutexHandles;
|
||||
std::vector<HandleType> timerHandles;
|
||||
|
||||
// Thread indices, sorted by priority
|
||||
std::vector<int> threadIndices;
|
||||
|
||||
Handle currentProcess;
|
||||
Handle mainThread;
|
||||
HandleType currentProcess;
|
||||
HandleType mainThread;
|
||||
int currentThreadIndex;
|
||||
Handle srvHandle; // Handle for the special service manager port "srv:"
|
||||
Handle errorPortHandle; // Handle for the err:f port used for displaying errors
|
||||
HandleType srvHandle; // HandleType for the special service manager port "srv:"
|
||||
HandleType errorPortHandle; // HandleType for the err:f port used for displaying errors
|
||||
|
||||
u32 arbiterCount;
|
||||
u32 threadCount; // How many threads in our thread pool have been used as of now (Up to 32)
|
||||
u32 aliveThreadCount; // How many of these threads are actually alive?
|
||||
u32 threadCount; // How many threads in our thread pool have been used as of now (Up to 32)
|
||||
u32 aliveThreadCount; // How many of these threads are actually alive?
|
||||
ServiceManager serviceManager;
|
||||
|
||||
// Top 8 bits are the major version, bottom 8 are the minor version
|
||||
|
@ -58,29 +58,29 @@ class Kernel {
|
|||
// Shows whether a reschedule will be need
|
||||
bool needReschedule = false;
|
||||
|
||||
Handle makeArbiter();
|
||||
Handle makeProcess(u32 id);
|
||||
Handle makePort(const char* name);
|
||||
Handle makeSession(Handle port);
|
||||
Handle makeThread(u32 entrypoint, u32 initialSP, u32 priority, ProcessorID id, u32 arg,ThreadStatus status = ThreadStatus::Dormant);
|
||||
Handle makeMemoryBlock(u32 addr, u32 size, u32 myPermission, u32 otherPermission);
|
||||
HandleType makeArbiter();
|
||||
HandleType makeProcess(u32 id);
|
||||
HandleType makePort(const char* name);
|
||||
HandleType makeSession(HandleType port);
|
||||
HandleType makeThread(u32 entrypoint, u32 initialSP, u32 priority, ProcessorID id, u32 arg, ThreadStatus status = ThreadStatus::Dormant);
|
||||
HandleType makeMemoryBlock(u32 addr, u32 size, u32 myPermission, u32 otherPermission);
|
||||
|
||||
public:
|
||||
public:
|
||||
// Needs to be public to be accessible to the APT/HID services
|
||||
Handle makeEvent(ResetType resetType, Event::CallbackType callback = Event::CallbackType::None);
|
||||
HandleType makeEvent(ResetType resetType, Event::CallbackType callback = Event::CallbackType::None);
|
||||
// Needs to be public to be accessible to the APT/DSP services
|
||||
Handle makeMutex(bool locked = false);
|
||||
HandleType makeMutex(bool locked = false);
|
||||
// Needs to be public to be accessible to the service manager port
|
||||
Handle makeSemaphore(u32 initialCount, u32 maximumCount);
|
||||
Handle makeTimer(ResetType resetType);
|
||||
HandleType makeSemaphore(u32 initialCount, u32 maximumCount);
|
||||
HandleType makeTimer(ResetType resetType);
|
||||
void pollTimers();
|
||||
|
||||
// Signals an event, returns true on success or false if the event does not exist
|
||||
bool signalEvent(Handle e);
|
||||
bool signalEvent(HandleType e);
|
||||
// Run the callback for "special" events that have callbacks
|
||||
void runEventCallback(Event::CallbackType callback);
|
||||
|
||||
void clearEvent(Handle e) {
|
||||
void clearEvent(HandleType e) {
|
||||
KernelObject* object = getObject(e, KernelObjectType::Event);
|
||||
if (object != nullptr) {
|
||||
object->getData<Event>()->fired = false;
|
||||
|
@ -99,19 +99,19 @@ public:
|
|||
bool shouldWaitOnObject(KernelObject* object);
|
||||
void releaseMutex(Mutex* moo);
|
||||
void cancelTimer(Timer* timer);
|
||||
void signalTimer(Handle timerHandle, Timer* timer);
|
||||
void signalTimer(HandleType timerHandle, Timer* timer);
|
||||
u64 getWakeupTick(s64 ns);
|
||||
|
||||
// Wake up the thread with the highest priority out of all threads in the waitlist
|
||||
// Returns the index of the woken up thread
|
||||
// Do not call this function with an empty waitlist!!!
|
||||
int wakeupOneThread(u64 waitlist, Handle handle);
|
||||
void wakeupAllThreads(u64 waitlist, Handle handle);
|
||||
int wakeupOneThread(u64 waitlist, HandleType handle);
|
||||
void wakeupAllThreads(u64 waitlist, HandleType handle);
|
||||
|
||||
std::optional<Handle> getPortHandle(const char* name);
|
||||
std::optional<HandleType> getPortHandle(const char* name);
|
||||
void deleteObjectData(KernelObject& object);
|
||||
|
||||
KernelObject* getProcessFromPID(Handle handle);
|
||||
KernelObject* getProcessFromPID(HandleType handle);
|
||||
s32 getCurrentResourceValue(const KernelObject* limit, u32 resourceName);
|
||||
u32 getMaxForResource(const KernelObject* limit, u32 resourceName);
|
||||
u32 getTLSPointer();
|
||||
|
@ -178,22 +178,22 @@ public:
|
|||
void waitSynchronizationN();
|
||||
|
||||
// File operations
|
||||
void handleFileOperation(u32 messagePointer, Handle file);
|
||||
void closeFile(u32 messagePointer, Handle file);
|
||||
void flushFile(u32 messagePointer, Handle file);
|
||||
void readFile(u32 messagePointer, Handle file);
|
||||
void writeFile(u32 messagePointer, Handle file);
|
||||
void getFileSize(u32 messagePointer, Handle file);
|
||||
void openLinkFile(u32 messagePointer, Handle file);
|
||||
void setFileSize(u32 messagePointer, Handle file);
|
||||
void setFilePriority(u32 messagePointer, Handle file);
|
||||
void handleFileOperation(u32 messagePointer, HandleType file);
|
||||
void closeFile(u32 messagePointer, HandleType file);
|
||||
void flushFile(u32 messagePointer, HandleType file);
|
||||
void readFile(u32 messagePointer, HandleType file);
|
||||
void writeFile(u32 messagePointer, HandleType file);
|
||||
void getFileSize(u32 messagePointer, HandleType file);
|
||||
void openLinkFile(u32 messagePointer, HandleType file);
|
||||
void setFileSize(u32 messagePointer, HandleType file);
|
||||
void setFilePriority(u32 messagePointer, HandleType file);
|
||||
|
||||
// Directory operations
|
||||
void handleDirectoryOperation(u32 messagePointer, Handle directory);
|
||||
void closeDirectory(u32 messagePointer, Handle directory);
|
||||
void readDirectory(u32 messagePointer, Handle directory);
|
||||
void handleDirectoryOperation(u32 messagePointer, HandleType directory);
|
||||
void closeDirectory(u32 messagePointer, HandleType directory);
|
||||
void readDirectory(u32 messagePointer, HandleType directory);
|
||||
|
||||
public:
|
||||
public:
|
||||
Kernel(CPU& cpu, Memory& mem, GPU& gpu, const EmulatorConfig& config);
|
||||
void initializeFS() { return serviceManager.initializeFS(); }
|
||||
void setVersion(u8 major, u8 minor);
|
||||
|
@ -209,7 +209,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
Handle makeObject(KernelObjectType type) {
|
||||
HandleType makeObject(KernelObjectType type) {
|
||||
if (handleCounter > KernelHandles::Max) [[unlikely]] {
|
||||
Helpers::panic("Hlep we somehow created enough kernel objects to overflow this thing");
|
||||
}
|
||||
|
@ -219,12 +219,10 @@ public:
|
|||
return handleCounter++;
|
||||
}
|
||||
|
||||
std::vector<KernelObject>& getObjects() {
|
||||
return objects;
|
||||
}
|
||||
std::vector<KernelObject>& getObjects() { return objects; }
|
||||
|
||||
// Get pointer to the object with the specified handle
|
||||
KernelObject* getObject(Handle handle) {
|
||||
KernelObject* getObject(HandleType handle) {
|
||||
// Accessing an object that has not been created
|
||||
if (handle >= objects.size()) [[unlikely]] {
|
||||
return nullptr;
|
||||
|
@ -234,7 +232,7 @@ public:
|
|||
}
|
||||
|
||||
// Get pointer to the object with the specified handle and type
|
||||
KernelObject* getObject(Handle handle, KernelObjectType type) {
|
||||
KernelObject* getObject(HandleType handle, KernelObjectType type) {
|
||||
if (handle >= objects.size() || objects[handle].type != type) [[unlikely]] {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -246,4 +244,4 @@ public:
|
|||
|
||||
void sendGPUInterrupt(GPUInterrupt type) { serviceManager.sendGPUInterrupt(type); }
|
||||
void clearInstructionCache();
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,98 +1,102 @@
|
|||
#pragma once
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
|
||||
#include "fs/archive_base.hpp"
|
||||
#include "handles.hpp"
|
||||
#include "helpers.hpp"
|
||||
#include "result/result.hpp"
|
||||
|
||||
enum class KernelObjectType : u8 {
|
||||
AddressArbiter, Archive, Directory, File, MemoryBlock, Process, ResourceLimit, Session, Dummy,
|
||||
// Bundle waitable objects together in the enum to let the compiler optimize certain checks better
|
||||
Event, Mutex, Port, Semaphore, Timer, Thread
|
||||
AddressArbiter,
|
||||
Archive,
|
||||
Directory,
|
||||
File,
|
||||
MemoryBlock,
|
||||
Process,
|
||||
ResourceLimit,
|
||||
Session,
|
||||
Dummy,
|
||||
// Bundle waitable objects together in the enum to let the compiler optimize certain checks better
|
||||
Event,
|
||||
Mutex,
|
||||
Port,
|
||||
Semaphore,
|
||||
Timer,
|
||||
Thread
|
||||
};
|
||||
|
||||
enum class ResourceLimitCategory : int {
|
||||
Application = 0,
|
||||
SystemApplet = 1,
|
||||
LibraryApplet = 2,
|
||||
Misc = 3
|
||||
};
|
||||
enum class ResourceLimitCategory : int { Application = 0, SystemApplet = 1, LibraryApplet = 2, Misc = 3 };
|
||||
|
||||
// Reset types (for use with events and timers)
|
||||
enum class ResetType {
|
||||
OneShot = 0, // When the primitive is signaled, it will wake up exactly one thread and will clear itself automatically.
|
||||
Sticky = 1, // When the primitive is signaled, it will wake up all threads and it won't clear itself automatically.
|
||||
Pulse = 2, // Only meaningful for timers: same as ONESHOT but it will periodically signal the timer instead of just once.
|
||||
OneShot = 0, // When the primitive is signaled, it will wake up exactly one thread and will clear itself automatically.
|
||||
Sticky = 1, // When the primitive is signaled, it will wake up all threads and it won't clear itself automatically.
|
||||
Pulse = 2, // Only meaningful for timers: same as ONESHOT but it will periodically signal the timer instead of just once.
|
||||
};
|
||||
|
||||
enum class ArbitrationType {
|
||||
Signal = 0,
|
||||
WaitIfLess = 1,
|
||||
DecrementAndWaitIfLess = 2,
|
||||
WaitIfLessTimeout = 3,
|
||||
DecrementAndWaitIfLessTimeout = 4
|
||||
};
|
||||
enum class ArbitrationType { Signal = 0, WaitIfLess = 1, DecrementAndWaitIfLess = 2, WaitIfLessTimeout = 3, DecrementAndWaitIfLessTimeout = 4 };
|
||||
|
||||
enum class ProcessorID : s32 {
|
||||
AllCPUs = -1,
|
||||
Default = -2,
|
||||
|
||||
AppCore = 0,
|
||||
Syscore = 1,
|
||||
New3DSExtra1 = 2,
|
||||
New3DSExtra2 = 3
|
||||
AllCPUs = -1,
|
||||
Default = -2,
|
||||
|
||||
AppCore = 0,
|
||||
Syscore = 1,
|
||||
New3DSExtra1 = 2,
|
||||
New3DSExtra2 = 3
|
||||
};
|
||||
|
||||
struct AddressArbiter {};
|
||||
|
||||
struct ResourceLimits {
|
||||
Handle handle;
|
||||
HandleType handle;
|
||||
|
||||
s32 currentCommit = 0;
|
||||
s32 currentCommit = 0;
|
||||
};
|
||||
|
||||
struct Process {
|
||||
// Resource limits for this process
|
||||
ResourceLimits limits;
|
||||
// Process ID
|
||||
u32 id;
|
||||
// Resource limits for this process
|
||||
ResourceLimits limits;
|
||||
// Process ID
|
||||
u32 id;
|
||||
|
||||
Process(u32 id) : id(id) {}
|
||||
Process(u32 id) : id(id) {}
|
||||
};
|
||||
|
||||
struct Event {
|
||||
// Some events (for now, only the DSP semaphore events) need to execute a callback when signalled
|
||||
// This enum stores what kind of callback they should execute
|
||||
enum class CallbackType : u32 {
|
||||
None, DSPSemaphore,
|
||||
};
|
||||
// Some events (for now, only the DSP semaphore events) need to execute a callback when signalled
|
||||
// This enum stores what kind of callback they should execute
|
||||
enum class CallbackType : u32 {
|
||||
None,
|
||||
DSPSemaphore,
|
||||
};
|
||||
|
||||
u64 waitlist; // A bitfield where each bit symbolizes if the thread with thread with the corresponding index is waiting on the event
|
||||
ResetType resetType = ResetType::OneShot;
|
||||
CallbackType callback = CallbackType::None;
|
||||
bool fired = false;
|
||||
u64 waitlist; // A bitfield where each bit symbolizes if the thread with thread with the corresponding index is waiting on the event
|
||||
ResetType resetType = ResetType::OneShot;
|
||||
CallbackType callback = CallbackType::None;
|
||||
bool fired = false;
|
||||
|
||||
Event(ResetType resetType) : resetType(resetType), waitlist(0) {}
|
||||
Event(ResetType resetType, CallbackType cb) : resetType(resetType), waitlist(0), callback(cb) {}
|
||||
Event(ResetType resetType) : resetType(resetType), waitlist(0) {}
|
||||
Event(ResetType resetType, CallbackType cb) : resetType(resetType), waitlist(0), callback(cb) {}
|
||||
};
|
||||
|
||||
struct Port {
|
||||
static constexpr u32 maxNameLen = 11;
|
||||
static constexpr u32 maxNameLen = 11;
|
||||
|
||||
char name[maxNameLen + 1] = {};
|
||||
bool isPublic = false; // Setting name=NULL creates a private port not accessible from svcConnectToPort.
|
||||
char name[maxNameLen + 1] = {};
|
||||
bool isPublic = false; // Setting name=NULL creates a private port not accessible from svcConnectToPort.
|
||||
|
||||
Port(const char* name) {
|
||||
// If the name is empty (ie the first char is the null terminator) then the port is private
|
||||
isPublic = name[0] != '\0';
|
||||
std::strncpy(this->name, name, maxNameLen);
|
||||
}
|
||||
Port(const char* name) {
|
||||
// If the name is empty (ie the first char is the null terminator) then the port is private
|
||||
isPublic = name[0] != '\0';
|
||||
std::strncpy(this->name, name, maxNameLen);
|
||||
}
|
||||
};
|
||||
|
||||
struct Session {
|
||||
Handle portHandle; // The port this session is subscribed to
|
||||
Session(Handle portHandle) : portHandle(portHandle) {}
|
||||
HandleType portHandle; // The port this session is subscribed to
|
||||
Session(HandleType portHandle) : portHandle(portHandle) {}
|
||||
};
|
||||
|
||||
enum class ThreadStatus {
|
||||
|
@ -115,14 +119,14 @@ struct Thread {
|
|||
u32 arg;
|
||||
ProcessorID processorID;
|
||||
ThreadStatus status;
|
||||
Handle handle; // OS handle for this thread
|
||||
int index; // Index of the thread. 0 for the first thread, 1 for the second, and so on
|
||||
HandleType handle; // OS handle for this thread
|
||||
int index; // Index of the thread. 0 for the first thread, 1 for the second, and so on
|
||||
|
||||
// The waiting address for threads that are waiting on an AddressArbiter
|
||||
u32 waitingAddress;
|
||||
|
||||
// For WaitSynchronization(N): A vector of objects this thread is waiting for
|
||||
std::vector<Handle> waitList;
|
||||
std::vector<HandleType> waitList;
|
||||
// For WaitSynchronizationN: Shows whether the object should wait for all objects in the wait list or just one
|
||||
bool waitAll;
|
||||
// For WaitSynchronizationN: The "out" pointer
|
||||
|
@ -141,88 +145,86 @@ struct Thread {
|
|||
};
|
||||
|
||||
static const char* kernelObjectTypeToString(KernelObjectType t) {
|
||||
switch (t) {
|
||||
case KernelObjectType::AddressArbiter: return "address arbiter";
|
||||
case KernelObjectType::Archive: return "archive";
|
||||
case KernelObjectType::Directory: return "directory";
|
||||
case KernelObjectType::Event: return "event";
|
||||
case KernelObjectType::File: return "file";
|
||||
case KernelObjectType::MemoryBlock: return "memory block";
|
||||
case KernelObjectType::Port: return "port";
|
||||
case KernelObjectType::Process: return "process";
|
||||
case KernelObjectType::ResourceLimit: return "resource limit";
|
||||
case KernelObjectType::Session: return "session";
|
||||
case KernelObjectType::Mutex: return "mutex";
|
||||
case KernelObjectType::Semaphore: return "semaphore";
|
||||
case KernelObjectType::Thread: return "thread";
|
||||
case KernelObjectType::Dummy: return "dummy";
|
||||
default: return "unknown";
|
||||
}
|
||||
switch (t) {
|
||||
case KernelObjectType::AddressArbiter: return "address arbiter";
|
||||
case KernelObjectType::Archive: return "archive";
|
||||
case KernelObjectType::Directory: return "directory";
|
||||
case KernelObjectType::Event: return "event";
|
||||
case KernelObjectType::File: return "file";
|
||||
case KernelObjectType::MemoryBlock: return "memory block";
|
||||
case KernelObjectType::Port: return "port";
|
||||
case KernelObjectType::Process: return "process";
|
||||
case KernelObjectType::ResourceLimit: return "resource limit";
|
||||
case KernelObjectType::Session: return "session";
|
||||
case KernelObjectType::Mutex: return "mutex";
|
||||
case KernelObjectType::Semaphore: return "semaphore";
|
||||
case KernelObjectType::Thread: return "thread";
|
||||
case KernelObjectType::Dummy: return "dummy";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
struct Mutex {
|
||||
u64 waitlist; // Refer to the getWaitlist function below for documentation
|
||||
Handle ownerThread = 0; // Index of the thread that holds the mutex if it's locked
|
||||
Handle handle; // Handle of the mutex itself
|
||||
u32 lockCount; // Number of times this mutex has been locked by its daddy. 0 = not locked
|
||||
bool locked;
|
||||
u64 waitlist; // Refer to the getWaitlist function below for documentation
|
||||
HandleType ownerThread = 0; // Index of the thread that holds the mutex if it's locked
|
||||
HandleType handle; // HandleType of the mutex itself
|
||||
u32 lockCount; // Number of times this mutex has been locked by its daddy. 0 = not locked
|
||||
bool locked;
|
||||
|
||||
Mutex(bool lock, Handle handle) : locked(lock), waitlist(0), lockCount(lock ? 1 : 0), handle(handle) {}
|
||||
Mutex(bool lock, HandleType handle) : locked(lock), waitlist(0), lockCount(lock ? 1 : 0), handle(handle) {}
|
||||
};
|
||||
|
||||
struct Semaphore {
|
||||
u64 waitlist; // Refer to the getWaitlist function below for documentation
|
||||
s32 availableCount;
|
||||
s32 maximumCount;
|
||||
u64 waitlist; // Refer to the getWaitlist function below for documentation
|
||||
s32 availableCount;
|
||||
s32 maximumCount;
|
||||
|
||||
Semaphore(s32 initialCount, s32 maximumCount) : availableCount(initialCount), maximumCount(maximumCount), waitlist(0) {}
|
||||
Semaphore(s32 initialCount, s32 maximumCount) : availableCount(initialCount), maximumCount(maximumCount), waitlist(0) {}
|
||||
};
|
||||
|
||||
struct Timer {
|
||||
u64 waitlist; // Refer to the getWaitlist function below for documentation
|
||||
ResetType resetType = ResetType::OneShot;
|
||||
|
||||
u64 fireTick; // CPU tick the timer will be fired
|
||||
u64 interval; // Number of ns until the timer fires for the second and future times
|
||||
bool fired; // Has this timer been signalled?
|
||||
bool running; // Is this timer running or stopped?
|
||||
u64 fireTick; // CPU tick the timer will be fired
|
||||
u64 interval; // Number of ns until the timer fires for the second and future times
|
||||
bool fired; // Has this timer been signalled?
|
||||
bool running; // Is this timer running or stopped?
|
||||
|
||||
Timer(ResetType type) : resetType(type), fireTick(0), interval(0), waitlist(0), fired(false), running(false) {}
|
||||
};
|
||||
|
||||
struct MemoryBlock {
|
||||
u32 addr = 0;
|
||||
u32 size = 0;
|
||||
u32 myPermission = 0;
|
||||
u32 otherPermission = 0;
|
||||
bool mapped = false;
|
||||
u32 addr = 0;
|
||||
u32 size = 0;
|
||||
u32 myPermission = 0;
|
||||
u32 otherPermission = 0;
|
||||
bool mapped = false;
|
||||
|
||||
MemoryBlock(u32 addr, u32 size, u32 myPerm, u32 otherPerm) : addr(addr), size(size), myPermission(myPerm), otherPermission(otherPerm),
|
||||
mapped(false) {}
|
||||
MemoryBlock(u32 addr, u32 size, u32 myPerm, u32 otherPerm)
|
||||
: addr(addr), size(size), myPermission(myPerm), otherPermission(otherPerm), mapped(false) {}
|
||||
};
|
||||
|
||||
// Generic kernel object class
|
||||
struct KernelObject {
|
||||
Handle handle = 0; // A u32 the OS will use to identify objects
|
||||
void* data = nullptr;
|
||||
KernelObjectType type;
|
||||
HandleType handle = 0; // A u32 the OS will use to identify objects
|
||||
void* data = nullptr;
|
||||
KernelObjectType type;
|
||||
|
||||
KernelObject(Handle handle, KernelObjectType type) : handle(handle), type(type) {}
|
||||
KernelObject(HandleType handle, KernelObjectType type) : handle(handle), type(type) {}
|
||||
|
||||
// Our destructor does not free the data in order to avoid it being freed when our std::vector is expanded
|
||||
// Thus, the kernel needs to delete it when appropriate
|
||||
~KernelObject() {}
|
||||
// Our destructor does not free the data in order to avoid it being freed when our std::vector is expanded
|
||||
// Thus, the kernel needs to delete it when appropriate
|
||||
~KernelObject() {}
|
||||
|
||||
template <typename T>
|
||||
T* getData() {
|
||||
return static_cast<T*>(data);
|
||||
}
|
||||
template <typename T>
|
||||
T* getData() {
|
||||
return static_cast<T*>(data);
|
||||
}
|
||||
|
||||
const char* getTypeName() const {
|
||||
return kernelObjectTypeToString(type);
|
||||
}
|
||||
const char* getTypeName() const { return kernelObjectTypeToString(type); }
|
||||
|
||||
// Retrieves a reference to the waitlist for a specified object
|
||||
// Retrieves a reference to the waitlist for a specified object
|
||||
// We return a reference because this function is only called in the kernel threading internals
|
||||
// We want the kernel to be able to easily manage waitlists, by reading/parsing them or setting/clearing bits.
|
||||
// As we mention in the definition of the "Event" struct, the format for wailists is very simple and made to be efficient.
|
||||
|
@ -238,8 +240,7 @@ struct KernelObject {
|
|||
case KernelObjectType::Timer: return getData<Timer>()->waitlist;
|
||||
|
||||
// This should be unreachable once we fully implement sync objects
|
||||
default: [[unlikely]]
|
||||
Helpers::panic("Called GetWaitList on kernel object without a waitlist (Type: %s)", getTypeName());
|
||||
default: [[unlikely]] Helpers::panic("Called GetWaitList on kernel object without a waitlist (Type: %s)", getTypeName());
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
#include "crypto/aes_engine.hpp"
|
||||
#include "handles.hpp"
|
||||
#include "helpers.hpp"
|
||||
#include "loader/ncsd.hpp"
|
||||
#include "loader/3dsx.hpp"
|
||||
#include "loader/ncsd.hpp"
|
||||
#include "services/region_codes.hpp"
|
||||
|
||||
namespace PhysicalAddrs {
|
||||
|
@ -38,7 +38,7 @@ namespace VirtualAddrs {
|
|||
DefaultStackSize = 0x4000,
|
||||
|
||||
NormalHeapStart = 0x08000000,
|
||||
LinearHeapStartOld = 0x14000000, // If kernel version < 0x22C
|
||||
LinearHeapStartOld = 0x14000000, // If kernel version < 0x22C
|
||||
LinearHeapEndOld = 0x1C000000,
|
||||
|
||||
LinearHeapStartNew = 0x30000000,
|
||||
|
@ -76,37 +76,36 @@ namespace KernelMemoryTypes {
|
|||
PERMISSION_W = 1 << 1,
|
||||
PERMISSION_X = 1 << 2
|
||||
};
|
||||
|
||||
|
||||
// I assume this is referring to a single piece of allocated memory? If it's for pages, it makes no sense.
|
||||
// If it's for multiple allocations, it also makes no sense
|
||||
struct MemoryInfo {
|
||||
u32 baseAddr; // Base process virtual address. Used as a paddr in lockedMemoryInfo instead
|
||||
u32 baseAddr; // Base process virtual address. Used as a paddr in lockedMemoryInfo instead
|
||||
u32 size; // Of what?
|
||||
u32 perms; // Is this referring to a single page or?
|
||||
u32 state;
|
||||
|
||||
u32 end() { return baseAddr + size; }
|
||||
MemoryInfo(u32 baseAddr, u32 size, u32 perms, u32 state) : baseAddr(baseAddr), size(size)
|
||||
, perms(perms), state(state) {}
|
||||
MemoryInfo(u32 baseAddr, u32 size, u32 perms, u32 state) : baseAddr(baseAddr), size(size), perms(perms), state(state) {}
|
||||
};
|
||||
|
||||
// Shared memory block for HID, GSP:GPU etc
|
||||
struct SharedMemoryBlock {
|
||||
u32 paddr; // Physical address of this block's memory
|
||||
u32 size; // Size of block
|
||||
u32 handle; // The handle of the shared memory block
|
||||
bool mapped; // Has this block been mapped at least once?
|
||||
u32 paddr; // Physical address of this block's memory
|
||||
u32 size; // Size of block
|
||||
u32 handle; // The handle of the shared memory block
|
||||
bool mapped; // Has this block been mapped at least once?
|
||||
|
||||
SharedMemoryBlock(u32 paddr, u32 size, u32 handle) : paddr(paddr), size(size), handle(handle), mapped(false) {}
|
||||
};
|
||||
}
|
||||
} // namespace KernelMemoryTypes
|
||||
|
||||
class Memory {
|
||||
u8* fcram;
|
||||
u8* dspRam; // Provided to us by Audio
|
||||
u8* vram; // Provided to the memory class by the GPU class
|
||||
|
||||
u64& cpuTicks; // Reference to the CPU tick counter
|
||||
u64& cpuTicks; // Reference to the CPU tick counter
|
||||
using SharedMemoryBlock = KernelMemoryTypes::SharedMemoryBlock;
|
||||
|
||||
// Our dynarmic core uses page tables for reads and writes with 4096 byte pages
|
||||
|
@ -116,19 +115,21 @@ class Memory {
|
|||
std::vector<KernelMemoryTypes::MemoryInfo> memoryInfo;
|
||||
|
||||
std::array<SharedMemoryBlock, 5> sharedMemBlocks = {
|
||||
SharedMemoryBlock(0, 0, KernelHandles::FontSharedMemHandle), // Shared memory for the system font (size is 0 because we read the size from the cmrc filesystem
|
||||
SharedMemoryBlock(0, 0x1000, KernelHandles::GSPSharedMemHandle), // GSP shared memory
|
||||
SharedMemoryBlock(0, 0x1000, KernelHandles::HIDSharedMemHandle), // HID shared memory
|
||||
SharedMemoryBlock(0, 0x3000, KernelHandles::CSNDSharedMemHandle), // CSND shared memory
|
||||
SharedMemoryBlock(
|
||||
0, 0, KernelHandles::FontSharedMemHandle
|
||||
), // Shared memory for the system font (size is 0 because we read the size from the cmrc filesystem
|
||||
SharedMemoryBlock(0, 0x1000, KernelHandles::GSPSharedMemHandle), // GSP shared memory
|
||||
SharedMemoryBlock(0, 0x1000, KernelHandles::HIDSharedMemHandle), // HID shared memory
|
||||
SharedMemoryBlock(0, 0x3000, KernelHandles::CSNDSharedMemHandle), // CSND shared memory
|
||||
SharedMemoryBlock(0, 0xE7000, KernelHandles::APTCaptureSharedMemHandle), // APT Capture Buffer memory
|
||||
};
|
||||
};
|
||||
|
||||
public:
|
||||
public:
|
||||
static constexpr u32 pageShift = 12;
|
||||
static constexpr u32 pageSize = 1 << pageShift;
|
||||
static constexpr u32 pageMask = pageSize - 1;
|
||||
static constexpr u32 totalPageCount = 1 << (32 - pageShift);
|
||||
|
||||
|
||||
static constexpr u32 FCRAM_SIZE = u32(128_MB);
|
||||
static constexpr u32 FCRAM_APPLICATION_SIZE = u32(64_MB);
|
||||
static constexpr u32 FCRAM_PAGE_COUNT = FCRAM_SIZE / pageSize;
|
||||
|
@ -138,7 +139,7 @@ public:
|
|||
static constexpr u32 DSP_CODE_MEMORY_OFFSET = u32(0_KB);
|
||||
static constexpr u32 DSP_DATA_MEMORY_OFFSET = u32(256_KB);
|
||||
|
||||
private:
|
||||
private:
|
||||
std::bitset<FCRAM_PAGE_COUNT> usedFCRAMPages;
|
||||
std::optional<u32> findPaddr(u32 size);
|
||||
u64 timeSince3DSEpoch();
|
||||
|
@ -147,9 +148,9 @@ private:
|
|||
// Report a retail unit without JTAG
|
||||
static constexpr u32 envInfo = 1;
|
||||
|
||||
// Stored in Configuration Memory starting @ 0x1FF80060
|
||||
// Stored in Configuration Memory starting @ 0x1FF80060
|
||||
struct FirmwareInfo {
|
||||
u8 unk; // Usually 0 according to 3DBrew
|
||||
u8 unk; // Usually 0 according to 3DBrew
|
||||
u8 revision;
|
||||
u8 minor;
|
||||
u8 major;
|
||||
|
@ -167,8 +168,8 @@ private:
|
|||
|
||||
public:
|
||||
u16 kernelVersion = 0;
|
||||
u32 usedUserMemory = u32(0_MB); // How much of the APPLICATION FCRAM range is used (allocated to the appcore)
|
||||
u32 usedSystemMemory = u32(0_MB); // Similar for the SYSTEM range (reserved for the syscore)
|
||||
u32 usedUserMemory = u32(0_MB); // How much of the APPLICATION FCRAM range is used (allocated to the appcore)
|
||||
u32 usedSystemMemory = u32(0_MB); // Similar for the SYSTEM range (reserved for the syscore)
|
||||
|
||||
Memory(u64& cpuTicks, const EmulatorConfig& config);
|
||||
void reset();
|
||||
|
@ -197,28 +198,20 @@ private:
|
|||
u8* getFCRAM() { return fcram; }
|
||||
|
||||
// Total amount of OS-only FCRAM available (Can vary depending on how much FCRAM the app requests via the cart exheader)
|
||||
u32 totalSysFCRAM() {
|
||||
return FCRAM_SIZE - FCRAM_APPLICATION_SIZE;
|
||||
}
|
||||
u32 totalSysFCRAM() { return FCRAM_SIZE - FCRAM_APPLICATION_SIZE; }
|
||||
|
||||
// Amount of OS-only FCRAM currently available
|
||||
u32 remainingSysFCRAM() {
|
||||
return totalSysFCRAM() - usedSystemMemory;
|
||||
}
|
||||
u32 remainingSysFCRAM() { return totalSysFCRAM() - usedSystemMemory; }
|
||||
|
||||
// Physical FCRAM index to the start of OS FCRAM
|
||||
// We allocate the first part of physical FCRAM for the application, and the rest to the OS. So the index for the OS = application ram size
|
||||
u32 sysFCRAMIndex() {
|
||||
return FCRAM_APPLICATION_SIZE;
|
||||
}
|
||||
u32 sysFCRAMIndex() { return FCRAM_APPLICATION_SIZE; }
|
||||
|
||||
enum class BatteryLevel {
|
||||
Empty = 0, AlmostEmpty, OneBar, TwoBars, ThreeBars, FourBars
|
||||
};
|
||||
enum class BatteryLevel { Empty = 0, AlmostEmpty, OneBar, TwoBars, ThreeBars, FourBars };
|
||||
u8 getBatteryState(bool adapterConnected, bool charging, BatteryLevel batteryLevel) {
|
||||
u8 value = static_cast<u8>(batteryLevel) << 2; // Bits 2:4 are the battery level from 0 to 5
|
||||
if (adapterConnected) value |= 1 << 0; // Bit 0 shows if the charger is connected
|
||||
if (charging) value |= 1 << 1; // Bit 1 shows if we're charging
|
||||
u8 value = static_cast<u8>(batteryLevel) << 2; // Bits 2:4 are the battery level from 0 to 5
|
||||
if (adapterConnected) value |= 1 << 0; // Bit 0 shows if the charger is connected
|
||||
if (charging) value |= 1 << 1; // Bit 1 shows if we're charging
|
||||
|
||||
return value;
|
||||
}
|
||||
|
@ -240,9 +233,7 @@ private:
|
|||
}
|
||||
|
||||
// Returns whether "addr" is aligned to a page (4096 byte) boundary
|
||||
static constexpr bool isAligned(u32 addr) {
|
||||
return (addr & pageMask) == 0;
|
||||
}
|
||||
static constexpr bool isAligned(u32 addr) { return (addr & pageMask) == 0; }
|
||||
|
||||
// Allocate "size" bytes of RAM starting from FCRAM index "paddr" (We pick it ourself if paddr == 0)
|
||||
// And map them to virtual address "vaddr" (We also pick it ourself if vaddr == 0).
|
||||
|
@ -253,8 +244,9 @@ private:
|
|||
// isMap: Shows whether this is a reserve operation, that allocates memory and maps it to the addr space, or if it's a map operation,
|
||||
// which just maps memory from paddr to vaddr without hassle. The latter is useful for shared memory mapping, the "map" ControlMemory, op, etc
|
||||
// Returns the vaddr the FCRAM was mapped to or nullopt if allocation failed
|
||||
std::optional<u32> allocateMemory(u32 vaddr, u32 paddr, u32 size, bool linear, bool r = true, bool w = true, bool x = true,
|
||||
bool adjustsAddrs = false, bool isMap = false);
|
||||
std::optional<u32> allocateMemory(
|
||||
u32 vaddr, u32 paddr, u32 size, bool linear, bool r = true, bool w = true, bool x = true, bool adjustsAddrs = false, bool isMap = false
|
||||
);
|
||||
KernelMemoryTypes::MemoryInfo queryMemory(u32 vaddr);
|
||||
|
||||
// For internal use
|
||||
|
@ -266,7 +258,7 @@ private:
|
|||
// The kernel has a second permission parameter in MapMemoryBlock but not sure what's used for
|
||||
// TODO: Find out
|
||||
// Returns a pointer to the FCRAM block used for the memory if allocation succeeded
|
||||
u8* mapSharedMemory(Handle handle, u32 vaddr, u32 myPerms, u32 otherPerms);
|
||||
u8* mapSharedMemory(HandleType handle, u32 vaddr, u32 myPerms, u32 otherPerms);
|
||||
|
||||
// Mirrors the page mapping for "size" bytes starting from sourceAddress, to "size" bytes in destAddress
|
||||
// All of the above must be page-aligned.
|
||||
|
|
|
@ -119,9 +119,10 @@ class MainWindow : public QMainWindow {
|
|||
void sendMessage(const EmulatorMessage& message);
|
||||
void dispatchMessage(const EmulatorMessage& message);
|
||||
|
||||
// Tracks whether we are using an OpenGL-backed renderer or a Vulkan-backed renderer
|
||||
// Tracks whether we are using an OpenGL-backed renderer, a Vulkan-backed renderer or a Metal-backed renderer
|
||||
bool usingGL = false;
|
||||
bool usingVk = false;
|
||||
bool usingMtl = false;
|
||||
|
||||
// Variables to keep track of whether the user is controlling the 3DS analog stick with their keyboard
|
||||
// This is done so when a gamepad is connected, we won't automatically override the 3DS analog stick settings with the gamepad's state
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include <array>
|
||||
#include <span>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
|
||||
#include "PICA/pica_vertex.hpp"
|
||||
#include "PICA/regs.hpp"
|
||||
|
@ -17,6 +17,7 @@ enum class RendererType : s8 {
|
|||
OpenGL = 1,
|
||||
Vulkan = 2,
|
||||
Software = 3,
|
||||
Metal = 4,
|
||||
};
|
||||
|
||||
class GPU;
|
||||
|
|
32
include/renderer_mtl/renderer_mtl.hpp
Normal file
32
include/renderer_mtl/renderer_mtl.hpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
#include <Metal/Metal.hpp>
|
||||
#include <QuartzCore/QuartzCore.hpp>
|
||||
|
||||
#include "renderer.hpp"
|
||||
|
||||
class GPU;
|
||||
|
||||
class RendererMTL final : public Renderer {
|
||||
public:
|
||||
RendererMTL(GPU& gpu, const std::array<u32, regNum>& internalRegs, const std::array<u32, extRegNum>& externalRegs);
|
||||
~RendererMTL() override;
|
||||
|
||||
void reset() override;
|
||||
void display() override;
|
||||
void initGraphicsContext(SDL_Window* window) override;
|
||||
void clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control) override;
|
||||
void displayTransfer(u32 inputAddr, u32 outputAddr, u32 inputSize, u32 outputSize, u32 flags) override;
|
||||
void textureCopy(u32 inputAddr, u32 outputAddr, u32 totalBytes, u32 inputSize, u32 outputSize, u32 flags) override;
|
||||
void drawVertices(PICA::PrimType primType, std::span<const PICA::Vertex> vertices) override;
|
||||
void screenshot(const std::string& name) override;
|
||||
void deinitGraphicsContext() override;
|
||||
|
||||
#ifdef PANDA3DS_FRONTEND_QT
|
||||
virtual void initGraphicsContext([[maybe_unused]] GL::Context* context) override {}
|
||||
#endif
|
||||
|
||||
private:
|
||||
CA::MetalLayer* metalLayer;
|
||||
|
||||
MTL::Device* device;
|
||||
MTL::CommandQueue* commandQueue;
|
||||
};
|
|
@ -8,7 +8,7 @@
|
|||
#include "result/result.hpp"
|
||||
|
||||
class ACService {
|
||||
Handle handle = KernelHandles::AC;
|
||||
HandleType handle = KernelHandles::AC;
|
||||
Memory& mem;
|
||||
MAKE_LOG_FUNCTION(log, acLogger)
|
||||
|
||||
|
@ -25,10 +25,10 @@ class ACService {
|
|||
void setClientVersion(u32 messagePointer);
|
||||
|
||||
bool connected = false;
|
||||
std::optional<Handle> disconnectEvent = std::nullopt;
|
||||
std::optional<HandleType> disconnectEvent = std::nullopt;
|
||||
|
||||
public:
|
||||
ACService(Memory& mem) : mem(mem) {}
|
||||
void reset();
|
||||
void handleSyncRequest(u32 messagePointer);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include "result/result.hpp"
|
||||
|
||||
class ACTService {
|
||||
Handle handle = KernelHandles::ACT;
|
||||
HandleType handle = KernelHandles::ACT;
|
||||
Memory& mem;
|
||||
MAKE_LOG_FUNCTION(log, actLogger)
|
||||
|
||||
|
@ -15,8 +15,8 @@ class ACTService {
|
|||
void generateUUID(u32 messagePointer);
|
||||
void getAccountDataBlock(u32 messagePointer);
|
||||
|
||||
public:
|
||||
public:
|
||||
ACTService(Memory& mem) : mem(mem) {}
|
||||
void reset();
|
||||
void handleSyncRequest(u32 messagePointer);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include "result/result.hpp"
|
||||
|
||||
class AMService {
|
||||
Handle handle = KernelHandles::AM;
|
||||
HandleType handle = KernelHandles::AM;
|
||||
Memory& mem;
|
||||
MAKE_LOG_FUNCTION(log, amLogger)
|
||||
|
||||
|
@ -15,8 +15,8 @@ class AMService {
|
|||
void getPatchTitleInfo(u32 messagePointer);
|
||||
void listTitleInfo(u32 messagePointer);
|
||||
|
||||
public:
|
||||
public:
|
||||
AMService(Memory& mem) : mem(mem) {}
|
||||
void reset();
|
||||
void handleSyncRequest(u32 messagePointer);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,19 +1,17 @@
|
|||
#pragma once
|
||||
#include <optional>
|
||||
|
||||
#include "applets/applet_manager.hpp"
|
||||
#include "helpers.hpp"
|
||||
#include "kernel_types.hpp"
|
||||
#include "logger.hpp"
|
||||
#include "memory.hpp"
|
||||
#include "result/result.hpp"
|
||||
|
||||
#include "applets/applet_manager.hpp"
|
||||
|
||||
// Yay, more circular dependencies
|
||||
class Kernel;
|
||||
|
||||
enum class ConsoleModel : u32 {
|
||||
Old3DS, New3DS
|
||||
};
|
||||
enum class ConsoleModel : u32 { Old3DS, New3DS };
|
||||
|
||||
// https://www.3dbrew.org/wiki/NS_and_APT_Services#Command
|
||||
namespace APT::Transitions {
|
||||
|
@ -41,13 +39,13 @@ namespace APT::Transitions {
|
|||
}
|
||||
|
||||
class APTService {
|
||||
Handle handle = KernelHandles::APT;
|
||||
HandleType handle = KernelHandles::APT;
|
||||
Memory& mem;
|
||||
Kernel& kernel;
|
||||
|
||||
std::optional<Handle> lockHandle = std::nullopt;
|
||||
std::optional<Handle> notificationEvent = std::nullopt;
|
||||
std::optional<Handle> resumeEvent = std::nullopt;
|
||||
std::optional<HandleType> lockHandle = std::nullopt;
|
||||
std::optional<HandleType> notificationEvent = std::nullopt;
|
||||
std::optional<HandleType> resumeEvent = std::nullopt;
|
||||
|
||||
ConsoleModel model = ConsoleModel::Old3DS;
|
||||
Applets::AppletManager appletManager;
|
||||
|
@ -99,8 +97,8 @@ class APTService {
|
|||
|
||||
u32 screencapPostPermission;
|
||||
|
||||
public:
|
||||
public:
|
||||
APTService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel), appletManager(mem) {}
|
||||
void reset();
|
||||
void handleSyncRequest(u32 messagePointer);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include "result/result.hpp"
|
||||
|
||||
class BOSSService {
|
||||
Handle handle = KernelHandles::BOSS;
|
||||
HandleType handle = KernelHandles::BOSS;
|
||||
Memory& mem;
|
||||
MAKE_LOG_FUNCTION(log, bossLogger)
|
||||
|
||||
|
@ -17,7 +17,7 @@ class BOSSService {
|
|||
void getNewArrivalFlag(u32 messagePointer);
|
||||
void getNsDataIdList(u32 messagePointer, u32 commandWord);
|
||||
void getOptoutFlag(u32 messagePointer);
|
||||
void getStorageEntryInfo(u32 messagePointer); // Unknown what this is, name taken from Citra
|
||||
void getStorageEntryInfo(u32 messagePointer); // Unknown what this is, name taken from Citra
|
||||
void getTaskIdList(u32 messagePointer);
|
||||
void getTaskInfo(u32 messagePointer);
|
||||
void getTaskServiceStatus(u32 messagePointer);
|
||||
|
@ -35,8 +35,9 @@ class BOSSService {
|
|||
void unregisterTask(u32 messagePointer);
|
||||
|
||||
s8 optoutFlag;
|
||||
public:
|
||||
|
||||
public:
|
||||
BOSSService(Memory& mem) : mem(mem) {}
|
||||
void reset();
|
||||
void handleSyncRequest(u32 messagePointer);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
class Kernel;
|
||||
|
||||
class CAMService {
|
||||
using Event = std::optional<Handle>;
|
||||
using Event = std::optional<HandleType>;
|
||||
|
||||
struct Port {
|
||||
Event bufferErrorInterruptEvent = std::nullopt;
|
||||
|
@ -26,7 +26,7 @@ class CAMService {
|
|||
}
|
||||
};
|
||||
|
||||
Handle handle = KernelHandles::CAM;
|
||||
HandleType handle = KernelHandles::CAM;
|
||||
Memory& mem;
|
||||
Kernel& kernel;
|
||||
MAKE_LOG_FUNCTION(log, camLogger)
|
||||
|
@ -56,4 +56,4 @@ class CAMService {
|
|||
CAMService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
|
||||
void reset();
|
||||
void handleSyncRequest(u32 messagePointer);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
#include <optional>
|
||||
|
||||
#include "helpers.hpp"
|
||||
#include "kernel_types.hpp"
|
||||
#include "logger.hpp"
|
||||
|
@ -9,19 +10,19 @@
|
|||
class Kernel;
|
||||
|
||||
class CECDService {
|
||||
Handle handle = KernelHandles::CECD;
|
||||
HandleType handle = KernelHandles::CECD;
|
||||
Memory& mem;
|
||||
Kernel& kernel;
|
||||
MAKE_LOG_FUNCTION(log, cecdLogger)
|
||||
|
||||
std::optional<Handle> infoEvent;
|
||||
std::optional<HandleType> infoEvent;
|
||||
|
||||
// Service commands
|
||||
void getInfoEventHandle(u32 messagePointer);
|
||||
void openAndRead(u32 messagePointer);
|
||||
|
||||
public:
|
||||
public:
|
||||
CECDService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
|
||||
void reset();
|
||||
void handleSyncRequest(u32 messagePointer);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -10,13 +10,13 @@
|
|||
class Kernel;
|
||||
|
||||
class CSNDService {
|
||||
Handle handle = KernelHandles::CSND;
|
||||
HandleType handle = KernelHandles::CSND;
|
||||
Memory& mem;
|
||||
Kernel& kernel;
|
||||
MAKE_LOG_FUNCTION(log, csndLogger)
|
||||
|
||||
u8* sharedMemory = nullptr;
|
||||
std::optional<Handle> csndMutex = std::nullopt;
|
||||
std::optional<HandleType> csndMutex = std::nullopt;
|
||||
size_t sharedMemSize = 0;
|
||||
bool initialized = false;
|
||||
|
||||
|
@ -30,7 +30,5 @@ class CSNDService {
|
|||
void reset();
|
||||
void handleSyncRequest(u32 messagePointer);
|
||||
|
||||
void setSharedMemory(u8* ptr) {
|
||||
sharedMemory = ptr;
|
||||
}
|
||||
};
|
||||
void setSharedMemory(u8* ptr) { sharedMemory = ptr; }
|
||||
};
|
||||
|
|
|
@ -8,15 +8,15 @@
|
|||
// Please forgive me for how everything in this file is named
|
||||
// "dlp:SRVR" is not a nice name to work with
|
||||
class DlpSrvrService {
|
||||
Handle handle = KernelHandles::DLP_SRVR;
|
||||
HandleType handle = KernelHandles::DLP_SRVR;
|
||||
Memory& mem;
|
||||
MAKE_LOG_FUNCTION(log, dlpSrvrLogger)
|
||||
|
||||
// Service commands
|
||||
void isChild(u32 messagePointer);
|
||||
|
||||
public:
|
||||
public:
|
||||
DlpSrvrService(Memory& mem) : mem(mem) {}
|
||||
void reset();
|
||||
void handleSyncRequest(u32 messagePointer);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
class Kernel;
|
||||
|
||||
class DSPService {
|
||||
Handle handle = KernelHandles::DSP;
|
||||
HandleType handle = KernelHandles::DSP;
|
||||
Memory& mem;
|
||||
Kernel& kernel;
|
||||
Audio::DSPCore* dsp = nullptr;
|
||||
|
@ -24,7 +24,7 @@ class DSPService {
|
|||
static constexpr size_t pipeCount = 8;
|
||||
|
||||
// DSP service event handles
|
||||
using DSPEvent = std::optional<Handle>;
|
||||
using DSPEvent = std::optional<HandleType>;
|
||||
|
||||
DSPEvent semaphoreEvent;
|
||||
DSPEvent interrupt0;
|
||||
|
@ -82,4 +82,4 @@ class DSPService {
|
|||
void triggerInterrupt1();
|
||||
|
||||
ComponentDumpResult dumpComponent(const std::filesystem::path& path);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
class Kernel;
|
||||
|
||||
class FSService {
|
||||
Handle handle = KernelHandles::FS;
|
||||
HandleType handle = KernelHandles::FS;
|
||||
Memory& mem;
|
||||
Kernel& kernel;
|
||||
|
||||
|
@ -38,9 +38,9 @@ class FSService {
|
|||
SystemSaveDataArchive systemSaveData;
|
||||
|
||||
ArchiveBase* getArchiveFromID(u32 id, const FSPath& archivePath);
|
||||
Rust::Result<Handle, HorizonResult> openArchiveHandle(u32 archiveID, const FSPath& path);
|
||||
Rust::Result<Handle, HorizonResult> openDirectoryHandle(ArchiveBase* archive, const FSPath& path);
|
||||
std::optional<Handle> openFileHandle(ArchiveBase* archive, const FSPath& path, const FSPath& archivePath, const FilePerms& perms);
|
||||
Rust::Result<HandleType, HorizonResult> openArchiveHandle(u32 archiveID, const FSPath& path);
|
||||
Rust::Result<HandleType, HorizonResult> openDirectoryHandle(ArchiveBase* archive, const FSPath& path);
|
||||
std::optional<HandleType> openFileHandle(ArchiveBase* archive, const FSPath& path, const FSPath& archivePath, const FilePerms& perms);
|
||||
FSPath readPath(u32 type, u32 pointer, u32 size);
|
||||
|
||||
const EmulatorConfig& config;
|
||||
|
@ -81,7 +81,7 @@ class FSService {
|
|||
// Used for set/get priority: Not sure what sort of priority this is referring to
|
||||
u32 priority;
|
||||
|
||||
public:
|
||||
public:
|
||||
FSService(Memory& mem, Kernel& kernel, const EmulatorConfig& config)
|
||||
: mem(mem), saveData(mem), sharedExtSaveData_nand(mem, "../SharedFiles/NAND", true), extSaveData_sdmc(mem, "SDMC"), sdmc(mem),
|
||||
sdmcWriteOnly(mem, true), selfNcch(mem), ncch(mem), userSaveData1(mem, ArchiveID::UserSaveData1),
|
||||
|
@ -91,4 +91,4 @@ public:
|
|||
void handleSyncRequest(u32 messagePointer);
|
||||
// Creates directories for NAND, ExtSaveData, etc if they don't already exist. Should be executed after loading a new ROM.
|
||||
void initializeFilesystem();
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
#include <cstring>
|
||||
#include <optional>
|
||||
|
||||
#include "PICA/gpu.hpp"
|
||||
#include "helpers.hpp"
|
||||
#include "kernel_types.hpp"
|
||||
|
@ -9,12 +10,12 @@
|
|||
#include "result/result.hpp"
|
||||
|
||||
enum class GPUInterrupt : u8 {
|
||||
PSC0 = 0, // Memory fill completed
|
||||
PSC1 = 1, // ?
|
||||
VBlank0 = 2, // ?
|
||||
VBlank1 = 3, // ?
|
||||
PPF = 4, // Display transfer finished
|
||||
P3D = 5, // Command list processing finished
|
||||
PSC0 = 0, // Memory fill completed
|
||||
PSC1 = 1, // ?
|
||||
VBlank0 = 2, // ?
|
||||
VBlank1 = 3, // ?
|
||||
PPF = 4, // Display transfer finished
|
||||
P3D = 5, // Command list processing finished
|
||||
DMA = 6
|
||||
};
|
||||
|
||||
|
@ -22,17 +23,17 @@ enum class GPUInterrupt : u8 {
|
|||
class Kernel;
|
||||
|
||||
class GPUService {
|
||||
Handle handle = KernelHandles::GPU;
|
||||
HandleType handle = KernelHandles::GPU;
|
||||
Memory& mem;
|
||||
GPU& gpu;
|
||||
Kernel& kernel;
|
||||
u32& currentPID; // Process ID of the current process
|
||||
u8* sharedMem; // Pointer to GSP shared memory
|
||||
u32& currentPID; // Process ID of the current process
|
||||
u8* sharedMem; // Pointer to GSP shared memory
|
||||
|
||||
// At any point in time only 1 process has privileges to use rendering functions
|
||||
// This is the PID of that process
|
||||
u32 privilegedProcess;
|
||||
std::optional<Handle> interruptEvent;
|
||||
std::optional<HandleType> interruptEvent;
|
||||
|
||||
// Number of threads registered via RegisterInterruptRelayQueue
|
||||
u32 gspThreadCount = 0;
|
||||
|
@ -62,8 +63,8 @@ class GPUService {
|
|||
|
||||
// Used for saving and restoring GPU state via ImportDisplayCaptureInfo
|
||||
struct CaptureInfo {
|
||||
u32 leftFramebuffer; // Left framebuffer VA
|
||||
u32 rightFramebuffer; // Right framebuffer VA (Top screen only)
|
||||
u32 leftFramebuffer; // Left framebuffer VA
|
||||
u32 rightFramebuffer; // Right framebuffer VA (Top screen only)
|
||||
u32 format;
|
||||
u32 stride;
|
||||
};
|
||||
|
@ -106,15 +107,14 @@ class GPUService {
|
|||
FramebufferUpdate* getTopFramebufferInfo() { return getFramebufferInfo(0); }
|
||||
FramebufferUpdate* getBottomFramebufferInfo() { return getFramebufferInfo(1); }
|
||||
|
||||
public:
|
||||
GPUService(Memory& mem, GPU& gpu, Kernel& kernel, u32& currentPID) : mem(mem), gpu(gpu),
|
||||
kernel(kernel), currentPID(currentPID) {}
|
||||
public:
|
||||
GPUService(Memory& mem, GPU& gpu, Kernel& kernel, u32& currentPID) : mem(mem), gpu(gpu), kernel(kernel), currentPID(currentPID) {}
|
||||
void reset();
|
||||
void handleSyncRequest(u32 messagePointer);
|
||||
void requestInterrupt(GPUInterrupt type);
|
||||
void setSharedMem(u8* ptr) {
|
||||
sharedMem = ptr;
|
||||
if (ptr != nullptr) { // Zero-fill shared memory in case the process tries to read stale service data or vice versa
|
||||
if (ptr != nullptr) { // Zero-fill shared memory in case the process tries to read stale service data or vice versa
|
||||
std::memset(ptr, 0, 0x1000);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,14 +6,14 @@
|
|||
#include "result/result.hpp"
|
||||
|
||||
class LCDService {
|
||||
Handle handle = KernelHandles::LCD;
|
||||
HandleType handle = KernelHandles::LCD;
|
||||
Memory& mem;
|
||||
MAKE_LOG_FUNCTION(log, gspLCDLogger)
|
||||
|
||||
// Service commands
|
||||
|
||||
public:
|
||||
public:
|
||||
LCDService(Memory& mem) : mem(mem) {}
|
||||
void reset();
|
||||
void handleSyncRequest(u32 messagePointer);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -38,7 +38,7 @@ namespace HID::Keys {
|
|||
class Kernel;
|
||||
|
||||
class HIDService {
|
||||
Handle handle = KernelHandles::HID;
|
||||
HandleType handle = KernelHandles::HID;
|
||||
Memory& mem;
|
||||
Kernel& kernel;
|
||||
u8* sharedMem = nullptr; // Pointer to HID shared memory
|
||||
|
@ -60,7 +60,7 @@ class HIDService {
|
|||
bool gyroEnabled;
|
||||
bool touchScreenPressed;
|
||||
|
||||
std::array<std::optional<Handle>, 5> events;
|
||||
std::array<std::optional<HandleType>, 5> events;
|
||||
|
||||
MAKE_LOG_FUNCTION(log, hidLogger)
|
||||
|
||||
|
@ -141,9 +141,7 @@ class HIDService {
|
|||
touchScreenPressed = true;
|
||||
}
|
||||
|
||||
void releaseTouchScreen() {
|
||||
touchScreenPressed = false;
|
||||
}
|
||||
void releaseTouchScreen() { touchScreenPressed = false; }
|
||||
|
||||
bool isTouchScreenPressed() { return touchScreenPressed; }
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "memory.hpp"
|
||||
|
||||
class HTTPService {
|
||||
Handle handle = KernelHandles::HTTP;
|
||||
HandleType handle = KernelHandles::HTTP;
|
||||
Memory& mem;
|
||||
MAKE_LOG_FUNCTION(log, httpLogger)
|
||||
|
||||
|
@ -20,4 +20,4 @@ class HTTPService {
|
|||
HTTPService(Memory& mem) : mem(mem) {}
|
||||
void reset();
|
||||
void handleSyncRequest(u32 messagePointer);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -15,7 +15,7 @@ class IRUserService {
|
|||
CirclePadPro = 1,
|
||||
};
|
||||
|
||||
Handle handle = KernelHandles::IR_USER;
|
||||
HandleType handle = KernelHandles::IR_USER;
|
||||
Memory& mem;
|
||||
Kernel& kernel;
|
||||
MAKE_LOG_FUNCTION(log, irUserLogger)
|
||||
|
@ -29,7 +29,7 @@ class IRUserService {
|
|||
void requireConnection(u32 messagePointer);
|
||||
void sendIrnop(u32 messagePointer);
|
||||
|
||||
using IREvent = std::optional<Handle>;
|
||||
using IREvent = std::optional<HandleType>;
|
||||
|
||||
IREvent connectionStatusEvent = std::nullopt;
|
||||
IREvent receiveEvent = std::nullopt;
|
||||
|
@ -58,4 +58,4 @@ class IRUserService {
|
|||
IRUserService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
|
||||
void reset();
|
||||
void handleSyncRequest(u32 messagePointer);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
class Kernel;
|
||||
|
||||
class LDRService {
|
||||
Handle handle = KernelHandles::LDR_RO;
|
||||
HandleType handle = KernelHandles::LDR_RO;
|
||||
Memory& mem;
|
||||
Kernel& kernel;
|
||||
MAKE_LOG_FUNCTION(log, ldrLogger)
|
||||
|
@ -22,8 +22,8 @@ class LDRService {
|
|||
void loadCRR(u32 messagePointer);
|
||||
void unloadCRO(u32 messagePointer);
|
||||
|
||||
public:
|
||||
public:
|
||||
LDRService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
|
||||
void reset();
|
||||
void handleSyncRequest(u32 messagePointer);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace MCU {
|
||||
class HWCService {
|
||||
Handle handle = KernelHandles::MCU_HWC;
|
||||
HandleType handle = KernelHandles::MCU_HWC;
|
||||
Memory& mem;
|
||||
MAKE_LOG_FUNCTION(log, mcuLogger)
|
||||
|
||||
|
@ -21,4 +21,4 @@ namespace MCU {
|
|||
void reset();
|
||||
void handleSyncRequest(u32 messagePointer);
|
||||
};
|
||||
} // namespace MCU
|
||||
} // namespace MCU
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
class Kernel;
|
||||
|
||||
class MICService {
|
||||
Handle handle = KernelHandles::MIC;
|
||||
HandleType handle = KernelHandles::MIC;
|
||||
Memory& mem;
|
||||
Kernel& kernel;
|
||||
MAKE_LOG_FUNCTION(log, micLogger)
|
||||
|
@ -29,15 +29,15 @@ class MICService {
|
|||
void unmapSharedMem(u32 messagePointer);
|
||||
void theCaptainToadFunction(u32 messagePointer);
|
||||
|
||||
u8 gain = 0; // How loud our microphone input signal is
|
||||
u8 gain = 0; // How loud our microphone input signal is
|
||||
bool micEnabled = false;
|
||||
bool shouldClamp = false;
|
||||
bool currentlySampling = false;
|
||||
|
||||
std::optional<Handle> eventHandle;
|
||||
std::optional<HandleType> eventHandle;
|
||||
|
||||
public:
|
||||
public:
|
||||
MICService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
|
||||
void reset();
|
||||
void handleSyncRequest(u32 messagePointer);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
class NDMService {
|
||||
enum class ExclusiveState : u32 { None = 0, Infrastructure = 1, LocalComms = 2, StreetPass = 3, StreetPassData = 4 };
|
||||
|
||||
Handle handle = KernelHandles::NDM;
|
||||
HandleType handle = KernelHandles::NDM;
|
||||
Memory& mem;
|
||||
MAKE_LOG_FUNCTION(log, ndmLogger)
|
||||
|
||||
|
@ -25,8 +25,8 @@ class NDMService {
|
|||
|
||||
ExclusiveState exclusiveState = ExclusiveState::None;
|
||||
|
||||
public:
|
||||
public:
|
||||
NDMService(Memory& mem) : mem(mem) {}
|
||||
void reset();
|
||||
void handleSyncRequest(u32 messagePointer);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "memory.hpp"
|
||||
|
||||
class NewsUService {
|
||||
Handle handle = KernelHandles::NEWS_U;
|
||||
HandleType handle = KernelHandles::NEWS_U;
|
||||
Memory& mem;
|
||||
MAKE_LOG_FUNCTION(log, newsLogger)
|
||||
|
||||
|
@ -15,4 +15,4 @@ class NewsUService {
|
|||
NewsUService(Memory& mem) : mem(mem) {}
|
||||
void reset();
|
||||
void handleSyncRequest(u32 messagePointer);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
class Kernel;
|
||||
|
||||
class NFCService {
|
||||
Handle handle = KernelHandles::NFC;
|
||||
HandleType handle = KernelHandles::NFC;
|
||||
Memory& mem;
|
||||
Kernel& kernel;
|
||||
MAKE_LOG_FUNCTION(log, nfcLogger)
|
||||
|
@ -34,7 +34,7 @@ class NFCService {
|
|||
};
|
||||
|
||||
// Kernel events signaled when an NFC tag goes in and out of range respectively
|
||||
std::optional<Handle> tagInRangeEvent, tagOutOfRangeEvent;
|
||||
std::optional<HandleType> tagInRangeEvent, tagOutOfRangeEvent;
|
||||
|
||||
AmiiboDevice device;
|
||||
Old3DSAdapterStatus adapterStatus;
|
||||
|
@ -63,4 +63,4 @@ class NFCService {
|
|||
void handleSyncRequest(u32 messagePointer);
|
||||
|
||||
bool loadAmiibo(const std::filesystem::path& path);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -6,15 +6,15 @@
|
|||
#include "result/result.hpp"
|
||||
|
||||
class NIMService {
|
||||
Handle handle = KernelHandles::NIM;
|
||||
HandleType handle = KernelHandles::NIM;
|
||||
Memory& mem;
|
||||
MAKE_LOG_FUNCTION(log, nimLogger)
|
||||
|
||||
// Service commands
|
||||
void initialize(u32 messagePointer);
|
||||
|
||||
public:
|
||||
public:
|
||||
NIMService(Memory& mem) : mem(mem) {}
|
||||
void reset();
|
||||
void handleSyncRequest(u32 messagePointer);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -10,13 +10,13 @@
|
|||
class Kernel;
|
||||
|
||||
class NwmUdsService {
|
||||
Handle handle = KernelHandles::NWM_UDS;
|
||||
HandleType handle = KernelHandles::NWM_UDS;
|
||||
Memory& mem;
|
||||
Kernel& kernel;
|
||||
MAKE_LOG_FUNCTION(log, nwmUdsLogger)
|
||||
|
||||
bool initialized = false;
|
||||
std::optional<Handle> eventHandle = std::nullopt;
|
||||
std::optional<HandleType> eventHandle = std::nullopt;
|
||||
|
||||
// Service commands
|
||||
void initializeWithVersion(u32 messagePointer);
|
||||
|
@ -25,4 +25,4 @@ class NwmUdsService {
|
|||
NwmUdsService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
|
||||
void reset();
|
||||
void handleSyncRequest(u32 messagePointer);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -28,10 +28,10 @@
|
|||
#include "services/mcu/mcu_hwc.hpp"
|
||||
#include "services/mic.hpp"
|
||||
#include "services/ndm.hpp"
|
||||
#include "services/nwm_uds.hpp"
|
||||
#include "services/news_u.hpp"
|
||||
#include "services/nfc.hpp"
|
||||
#include "services/nim.hpp"
|
||||
#include "services/nwm_uds.hpp"
|
||||
#include "services/ptm.hpp"
|
||||
#include "services/soc.hpp"
|
||||
#include "services/ssl.hpp"
|
||||
|
@ -46,15 +46,15 @@ class ServiceManager {
|
|||
Memory& mem;
|
||||
Kernel& kernel;
|
||||
|
||||
std::optional<Handle> notificationSemaphore;
|
||||
std::optional<HandleType> notificationSemaphore;
|
||||
|
||||
MAKE_LOG_FUNCTION(log, srvLogger)
|
||||
|
||||
ACService ac;
|
||||
ACService ac;
|
||||
ACTService act;
|
||||
AMService am;
|
||||
AMService am;
|
||||
APTService apt;
|
||||
BOSSService boss;
|
||||
BOSSService boss;
|
||||
CAMService cam;
|
||||
CECDService cecd;
|
||||
CFGService cfg;
|
||||
|
@ -74,7 +74,7 @@ class ServiceManager {
|
|||
NewsUService news_u;
|
||||
NFCService nfc;
|
||||
NwmUdsService nwm_uds;
|
||||
NIMService nim;
|
||||
NIMService nim;
|
||||
PTMService ptm;
|
||||
SOCService soc;
|
||||
SSLService ssl;
|
||||
|
@ -97,7 +97,7 @@ class ServiceManager {
|
|||
void handleSyncRequest(u32 messagePointer);
|
||||
|
||||
// Forward a SendSyncRequest IPC message to the service with the respective handle
|
||||
void sendCommandToService(u32 messagePointer, Handle handle);
|
||||
void sendCommandToService(u32 messagePointer, HandleType handle);
|
||||
|
||||
// Wrappers for communicating with certain services
|
||||
void sendGPUInterrupt(GPUInterrupt type) { gsp_gpu.requestInterrupt(type); }
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "memory.hpp"
|
||||
|
||||
class SOCService {
|
||||
Handle handle = KernelHandles::SOC;
|
||||
HandleType handle = KernelHandles::SOC;
|
||||
Memory& mem;
|
||||
MAKE_LOG_FUNCTION(log, socLogger)
|
||||
|
||||
|
@ -14,8 +14,8 @@ class SOCService {
|
|||
// Service commands
|
||||
void initializeSockets(u32 messagePointer);
|
||||
|
||||
public:
|
||||
public:
|
||||
SOCService(Memory& mem) : mem(mem) {}
|
||||
void reset();
|
||||
void handleSyncRequest(u32 messagePointer);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
#pragma once
|
||||
#include <random>
|
||||
|
||||
#include "helpers.hpp"
|
||||
#include "kernel_types.hpp"
|
||||
#include "logger.hpp"
|
||||
#include "memory.hpp"
|
||||
|
||||
#include <random>
|
||||
|
||||
class SSLService {
|
||||
Handle handle = KernelHandles::SSL;
|
||||
HandleType handle = KernelHandles::SSL;
|
||||
Memory& mem;
|
||||
MAKE_LOG_FUNCTION(log, sslLogger)
|
||||
|
||||
std::mt19937 rng; // Use a Mersenne Twister for RNG since this service is supposed to have better rng than just rand()
|
||||
std::mt19937 rng; // Use a Mersenne Twister for RNG since this service is supposed to have better rng than just rand()
|
||||
bool initialized;
|
||||
|
||||
// Service commands
|
||||
|
@ -22,4 +22,4 @@ class SSLService {
|
|||
SSLService(Memory& mem) : mem(mem) {}
|
||||
void reset();
|
||||
void handleSyncRequest(u32 messagePointer);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
#include <array>
|
||||
#include <optional>
|
||||
|
||||
#include "helpers.hpp"
|
||||
#include "kernel_types.hpp"
|
||||
#include "logger.hpp"
|
||||
|
@ -10,18 +11,15 @@
|
|||
class Kernel;
|
||||
|
||||
class Y2RService {
|
||||
Handle handle = KernelHandles::Y2R;
|
||||
HandleType handle = KernelHandles::Y2R;
|
||||
Memory& mem;
|
||||
Kernel& kernel;
|
||||
MAKE_LOG_FUNCTION(log, y2rLogger)
|
||||
|
||||
std::optional<Handle> transferEndEvent;
|
||||
std::optional<HandleType> transferEndEvent;
|
||||
bool transferEndInterruptEnabled;
|
||||
|
||||
enum class BusyStatus : u32 {
|
||||
NotBusy = 0,
|
||||
Busy = 1
|
||||
};
|
||||
enum class BusyStatus : u32 { NotBusy = 0, Busy = 1 };
|
||||
|
||||
enum class InputFormat : u32 {
|
||||
YUV422_Individual8 = 0,
|
||||
|
@ -31,24 +29,14 @@ class Y2RService {
|
|||
YUV422_Batch = 4,
|
||||
};
|
||||
|
||||
enum class OutputFormat : u32 {
|
||||
RGB32 = 0,
|
||||
RGB24 = 1,
|
||||
RGB15 = 2,
|
||||
RGB565 = 3
|
||||
};
|
||||
enum class OutputFormat : u32 { RGB32 = 0, RGB24 = 1, RGB15 = 2, RGB565 = 3 };
|
||||
|
||||
// Clockwise rotation
|
||||
enum class Rotation : u32 {
|
||||
None = 0,
|
||||
Rotate90 = 1,
|
||||
Rotate180 = 2,
|
||||
Rotate270 = 3
|
||||
};
|
||||
enum class Rotation : u32 { None = 0, Rotate90 = 1, Rotate180 = 2, Rotate270 = 3 };
|
||||
|
||||
enum class BlockAlignment : u32 {
|
||||
Line = 0, // Output buffer's pixels are arranged linearly. Used when outputting to the framebuffer.
|
||||
Block8x8 = 1, // Output buffer's pixels are morton swizzled. Used when outputting to a GPU texture.
|
||||
Line = 0, // Output buffer's pixels are arranged linearly. Used when outputting to the framebuffer.
|
||||
Block8x8 = 1, // Output buffer's pixels are morton swizzled. Used when outputting to a GPU texture.
|
||||
};
|
||||
|
||||
// https://github.com/citra-emu/citra/blob/ac9d72a95ca9a60de8d39484a14aecf489d6d016/src/core/hle/service/cam/y2r_u.cpp#L33
|
||||
|
@ -60,7 +48,7 @@ class Y2RService {
|
|||
{{0x12A, 0x1CA, 0x88, 0x36, 0x21C, -0x1F04, 0x99C, -0x2421}}, // ITU_Rec709_Scaling
|
||||
}};
|
||||
|
||||
CoefficientSet conversionCoefficients; // Current conversion coefficients
|
||||
CoefficientSet conversionCoefficients; // Current conversion coefficients
|
||||
|
||||
InputFormat inputFmt;
|
||||
OutputFormat outputFmt;
|
||||
|
@ -113,8 +101,8 @@ class Y2RService {
|
|||
void startConversion(u32 messagePointer);
|
||||
void stopConversion(u32 messagePointer);
|
||||
|
||||
public:
|
||||
public:
|
||||
Y2RService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
|
||||
void reset();
|
||||
void handleSyncRequest(u32 messagePointer);
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue