Merge remote-tracking branch 'upstream/master' into CRO

This commit is contained in:
Nomi
2023-09-07 20:06:48 +02:00
48 changed files with 4278 additions and 3203 deletions
+2
View File
@@ -170,6 +170,8 @@ public:
return env.totalTicks;
}
void clearCache() { jit->ClearCache(); }
void runFrame() {
env.ticksLeft = ticksPerSec / 60;
+2
View File
@@ -24,6 +24,7 @@ enum class ROMType {
ELF,
NCSD,
CXI,
HB_3DSX,
};
class Emulator {
@@ -99,6 +100,7 @@ class Emulator {
bool loadROM(const std::filesystem::path& path);
bool loadNCSD(const std::filesystem::path& path, ROMType type);
bool load3DSX(const std::filesystem::path& path);
bool loadELF(const std::filesystem::path& path);
bool loadELF(std::ifstream& file);
void initGraphicsContext();
+7
View File
@@ -251,4 +251,11 @@ public:
virtual std::optional<u32> readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) = 0;
ArchiveBase(Memory& mem) : mem(mem) {}
};
struct ArchiveResource {
u32 sectorSize; // Size of a sector in bytes
u32 clusterSize; // Size of a cluster in bytes
u32 partitionCapacityInClusters;
u32 freeSpaceInClusters;
};
+1
View File
@@ -9,6 +9,7 @@ public:
u64 getFreeBytes() override { Helpers::panic("ExtSaveData::GetFreeBytes unimplemented"); return 0; }
std::string name() override { return "ExtSaveData::" + backingFolder; }
HorizonResult createDirectory(const FSPath& path) override;
HorizonResult createFile(const FSPath& path, u64 size) override;
HorizonResult deleteFile(const FSPath& path) override;
+4 -1
View File
@@ -8,13 +8,16 @@ class SDMCArchive : public ArchiveBase {
public:
SDMCArchive(Memory& mem) : ArchiveBase(mem) {}
u64 getFreeBytes() override { Helpers::panic("SDMC::GetFreeBytes unimplemented"); return 0; }
u64 getFreeBytes() override { return 1_GB; }
std::string name() override { return "SDMC"; }
HorizonResult createFile(const FSPath& path, u64 size) override;
HorizonResult deleteFile(const FSPath& path) override;
HorizonResult createDirectory(const FSPath& path) override;
Rust::Result<ArchiveBase*, HorizonResult> openArchive(const FSPath& path) override;
Rust::Result<DirectorySession, HorizonResult> openDirectory(const FSPath& path) override;
FileDescriptor openFile(const FSPath& path, const FilePerms& perms) override;
std::optional<u32> readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) override;
};
+2 -1
View File
@@ -18,7 +18,8 @@ public:
// Returns whether the cart has a RomFS
bool hasRomFS() {
auto cxi = mem.getCXI();
return (cxi != nullptr && cxi->hasRomFS());
auto hb3dsx = mem.get3DSX();
return (cxi != nullptr && cxi->hasRomFS()) || (hb3dsx != nullptr && hb3dsx->hasRomFs());
}
// Returns whether the cart has an ExeFS (All executable carts should have an ExeFS. This is just here to be safe)
+3088 -3085
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -137,7 +137,7 @@ namespace Helpers {
return getBits<offset, bits, ValueT, ValueT>(value);
}
#if defined(HELPERS_APPLE_CLANG) || defined(__ANDROID__)
#if defined(HELPERS_APPLE_CLANG) || defined(__ANDROID__) || !defined(__cpp_lib_bit_cast)
template <class To, class From>
constexpr To bit_cast(const From& from) noexcept {
return *reinterpret_cast<const To*>(&from);
+4
View File
@@ -83,6 +83,9 @@ private:
bool canThreadRun(const Thread& t);
bool shouldWaitOnObject(KernelObject* object);
void releaseMutex(Mutex* moo);
void cancelTimer(Timer* timer);
void signalTimer(Handle timerHandle, Timer* timer);
void updateTimer(Handle timerHandle, Timer* timer);
// Wake up the thread with the highest priority out of all threads in the waitlist
// Returns the index of the woken up thread
@@ -226,4 +229,5 @@ public:
void sendGPUInterrupt(GPUInterrupt type) { serviceManager.sendGPUInterrupt(type); }
void signalDSPEvents() { serviceManager.signalDSPEvents(); }
void clearInstructionCache();
};
+31 -16
View File
@@ -173,6 +173,19 @@ struct Semaphore {
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 startTick; // CPU tick the timer started
u64 currentDelay; // Number of ns until the timer fires next time
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), startTick(0), currentDelay(0), interval(0), waitlist(0), fired(false), running(false) {}
};
struct MemoryBlock {
u32 addr = 0;
u32 size = 0;
@@ -206,21 +219,23 @@ struct KernelObject {
}
// 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.
// Each bit corresponds to a thread index and denotes whether the corresponding thread is waiting on this object
// For example if bit 0 of the wait list is set, then the thread with index 0 is waiting on our object
u64& getWaitlist() {
// This code is actually kinda trash but eh good enough
switch (type) {
case KernelObjectType::Event: return getData<Event>()->waitlist;
case KernelObjectType::Mutex: return getData<Mutex>()->waitlist;
case KernelObjectType::Semaphore: return getData<Mutex>()->waitlist;
case KernelObjectType::Thread: return getData<Thread>()->threadsWaitingForTermination;
// This should be unreachable once we fully implement sync objects
default: [[unlikely]]
// 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.
// Each bit corresponds to a thread index and denotes whether the corresponding thread is waiting on this object
// For example if bit 0 of the wait list is set, then the thread with index 0 is waiting on our object
u64& getWaitlist() {
// This code is actually kinda trash but eh good enough
switch (type) {
case KernelObjectType::Event: return getData<Event>()->waitlist;
case KernelObjectType::Mutex: return getData<Mutex>()->waitlist;
case KernelObjectType::Semaphore: return getData<Mutex>()->waitlist;
case KernelObjectType::Thread: return getData<Thread>()->threadsWaitingForTermination;
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());
}
}
}
}
};
+80
View File
@@ -0,0 +1,80 @@
#pragma once
#include <array>
#include "helpers.hpp"
#include "io_file.hpp"
#include "loader/ncch.hpp"
struct HB3DSX {
// File layout:
// - File header
// - Code, rodata and data relocation table headers
// - Code segment
// - Rodata segment
// - Loadable (non-BSS) part of the data segment
// - Code relocation table
// - Rodata relocation table
// - Data relocation table
// Memory layout before relocations are applied:
// [0..codeSegSize) -> code segment
// [codeSegSize..rodataSegSize) -> rodata segment
// [rodataSegSize..dataSegSize) -> data segment
// Memory layout after relocations are applied: well, however the loader sets it up :)
// The entrypoint is always the start of the code segment.
// The BSS section must be cleared manually by the application.
// File header
struct Header {
// minus char magic[4]
u16 headerSize;
u16 relocHeaderSize;
u32 formatVer;
u32 flags;
// Sizes of the code, rodata and data segments +
// size of the BSS section (uninitialized latter half of the data segment)
u32 codeSegSize, rodataSegSize, dataSegSize, bssSize;
};
// Relocation header: all fields (even extra unknown fields) are guaranteed to be relocation counts.
struct RelocHeader {
u32 absoluteCount; // # of absolute relocations (that is, fix address to post-relocation memory layout)
u32 relativeCount; // # of cross-segment relative relocations (that is, 32bit signed offsets that need to be patched)
// more?
// Relocations are written in this order:
// - Absolute relocs
// - Relative relocs
};
enum class RelocType {
Absolute,
Relative,
};
// Relocation entry: from the current pointer, skip X words and patch Y words
struct Reloc {
u16 skip, patch;
};
// _prm structure
static constexpr std::array<char, 4> PRM_MAGIC = {'_', 'P', 'R', 'M'};
struct PrmStruct {
char magic[4];
u32 pSrvOverride;
u32 aptAppId;
u32 heapSize, linearHeapSize;
u32 pArgList;
u32 runFlags;
};
IOFile file;
static constexpr u32 entrypoint = 0x00100000; // Initial ARM11 PC
u32 romFSSize = 0;
u32 romFSOffset = 0;
bool hasRomFs() const;
std::pair<bool, std::size_t> readRomFSBytes(void *dst, std::size_t offset, std::size_t size);
};
+12
View File
@@ -11,6 +11,7 @@
#include "handles.hpp"
#include "helpers.hpp"
#include "loader/ncsd.hpp"
#include "loader/3dsx.hpp"
#include "services/region_codes.hpp"
namespace PhysicalAddrs {
@@ -167,10 +168,12 @@ public:
void* getReadPointer(u32 address);
void* getWritePointer(u32 address);
std::optional<u32> loadELF(std::ifstream& file);
std::optional<u32> load3DSX(const std::filesystem::path& path);
std::optional<NCSD> loadNCSD(Crypto::AESEngine& aesEngine, const std::filesystem::path& path);
std::optional<NCSD> loadCXI(Crypto::AESEngine& aesEngine, const std::filesystem::path& path);
bool mapCXI(NCSD& ncsd, NCCH& cxi);
bool map3DSX(HB3DSX& hb3dsx, const HB3DSX::Header& header);
u8 read8(u32 vaddr);
u16 read16(u32 vaddr);
@@ -221,6 +224,14 @@ public:
}
}
HB3DSX* get3DSX() {
if (loaded3DSX.has_value()) {
return &loaded3DSX.value();
} else {
return nullptr;
}
}
// Returns whether "addr" is aligned to a page (4096 byte) boundary
static constexpr bool isAligned(u32 addr) {
return (addr & pageMask) == 0;
@@ -256,6 +267,7 @@ public:
// Backup of the game's CXI partition info, if any
std::optional<NCCH> loadedCXI = std::nullopt;
std::optional<HB3DSX> loaded3DSX = std::nullopt;
// File handle for reading the loaded ncch
IOFile CXIFile;
+3
View File
@@ -25,6 +25,9 @@ class CAMService {
void driverInitialize(u32 messagePointer);
void getMaxLines(u32 messagePointer);
void getBufferErrorInterruptEvent(u32 messagePointer);
void setContrast(u32 messagePointer);
void setFrameRate(u32 messagePointer);
void setTransferLines(u32 messagePointer);
public:
CAMService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
+9 -4
View File
@@ -1,4 +1,5 @@
#pragma once
#include "config.hpp"
#include "fs/archive_ext_save_data.hpp"
#include "fs/archive_ncch.hpp"
#include "fs/archive_save_data.hpp"
@@ -9,7 +10,6 @@
#include "kernel_types.hpp"
#include "logger.hpp"
#include "memory.hpp"
#include "result/result.hpp"
// Yay, more circular dependencies
class Kernel;
@@ -40,7 +40,10 @@ class FSService {
std::optional<Handle> openFileHandle(ArchiveBase* archive, const FSPath& path, const FSPath& archivePath, const FilePerms& perms);
FSPath readPath(u32 type, u32 pointer, u32 size);
const EmulatorConfig& config;
// Service commands
void abnegateAccessRight(u32 messagePointer);
void createDirectory(u32 messagePointer);
void createExtSaveData(u32 messagePointer);
void createFile(u32 messagePointer);
@@ -50,12 +53,12 @@ class FSService {
void deleteFile(u32 messagePointer);
void formatSaveData(u32 messagePointer);
void formatThisUserSaveData(u32 messagePointer);
void getArchiveResource(u32 messagePointer);
void getFreeBytes(u32 messagePointer);
void getFormatInfo(u32 messagePointer);
void getPriority(u32 messagePointer);
void getThisSaveDataSecureValue(u32 messagePointer);
void theGameboyVCFunction(u32 messagePointer);
void initialize(u32 messagePointer);
void initializeWithSdkVersion(u32 messagePointer);
void isSdmcDetected(u32 messagePointer);
@@ -64,15 +67,17 @@ class FSService {
void openDirectory(u32 messagePointer);
void openFile(u32 messagePointer);
void openFileDirectly(u32 messagePointer);
void setArchivePriority(u32 messagePointer);
void setPriority(u32 messagePointer);
void setThisSaveDataSecureValue(u32 messagePointer);
// Used for set/get priority: Not sure what sort of priority this is referring to
u32 priority;
public:
FSService(Memory& mem, Kernel& kernel)
FSService(Memory& mem, Kernel& kernel, const EmulatorConfig& config)
: mem(mem), saveData(mem), sharedExtSaveData_nand(mem, "../SharedFiles/NAND", true), extSaveData_sdmc(mem, "SDMC"), sdmc(mem), selfNcch(mem),
ncch(mem), userSaveData1(mem, ArchiveID::UserSaveData1), userSaveData2(mem, ArchiveID::UserSaveData2), kernel(kernel) {}
ncch(mem), userSaveData1(mem, ArchiveID::UserSaveData1), userSaveData2(mem, ArchiveID::UserSaveData2), kernel(kernel), config(config) {}
void reset();
void handleSyncRequest(u32 messagePointer);
+2
View File
@@ -12,7 +12,9 @@ class HTTPService {
bool initialized = false;
// Service commands
void createRootCertChain(u32 messagePointer);
void initialize(u32 messagePointer);
void rootCertChainAddDefaultCert(u32 messagePointer);
public:
HTTPService(Memory& mem) : mem(mem) {}
+1
View File
@@ -17,6 +17,7 @@ class MICService {
// Service commands
void getEventHandle(u32 messagePointer);
void getGain(u32 messagePointer);
void getPower(u32 messagePointer);
void isSampling(u32 messagePointer);
void mapSharedMem(u32 messagePointer);
void setClamp(u32 messagePointer);
+1
View File
@@ -16,6 +16,7 @@ class PTMService {
// Service commands
void configureNew3DSCPU(u32 messagePointer);
void getAdapterState(u32 messagePointer);
void getBatteryChargeState(u32 messagePointer);
void getBatteryLevel(u32 messagePointer);
void getStepHistory(u32 messagePointer);
void getTotalStepCount(u32 messagePointer);
+1
View File
@@ -84,6 +84,7 @@ class ServiceManager {
void receiveNotification(u32 messagePointer);
void registerClient(u32 messagePointer);
void subscribe(u32 messagePointer);
void unsubscribe(u32 messagePointer);
public:
ServiceManager(std::span<u32, 16> regs, Memory& mem, GPU& gpu, u32& currentPID, Kernel& kernel, const EmulatorConfig& config);
+5 -1
View File
@@ -64,10 +64,14 @@ class Y2RService {
// Service commands
void driverInitialize(u32 messagePointer);
void driverFinalize(u32 messagePointer);
void getTransferEndEvent(u32 messagePointer);
void getBlockAlignment(u32 messagePointer);
void getInputLines(u32 messagePointer);
void getInputLineWidth(u32 messagePointer);
void getOutputFormat(u32 messagePointer);
void isBusyConversion(u32 messagePointer);
void pingProcess(u32 messagePointer);
void setTransferEndInterrupt(u32 messagePointer);
void getTransferEndEvent(u32 messagePointer);
void setAlpha(u32 messagePointer);
void setBlockAlignment(u32 messagePointer);