mirror of
https://github.com/patchzyy/wiicompiled
synced 2026-09-10 09:11:52 -04:00
feature: add apple silicon native macOS support (#81)
* feature: add apple silicon native macOS support - #81 * (macos): Fix crash This fixes a crash when viewing the rear camera * fix(macos): keep interpolated presentation on main thread * fix(macos): supply Retro-WFC payload during setup * perf(windows): compile out flat-memory fallback check * remove duplicate smoke test * test(macos): name and focus host platform tests * fix(macos): validate Retro-WFC payload cache * fix(payload): preserve staged file access failures * Limit flat-page checks to variable-page hosts --------- Co-authored-by: patchzyy <64382339+patchzyy@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
#include "host_context.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace {
|
||||
// The worker yields twice; each return to the scheduler must preserve both
|
||||
// context identities and the worker's continuation point.
|
||||
HostContext::Handle g_scheduler = nullptr;
|
||||
HostContext::Handle g_worker = nullptr;
|
||||
int g_steps = 0;
|
||||
|
||||
void Worker(void*)
|
||||
{
|
||||
if (!HostContext::IsCurrent(g_worker)) {
|
||||
std::abort();
|
||||
}
|
||||
++g_steps;
|
||||
HostContext::Switch(g_scheduler);
|
||||
if (!HostContext::IsCurrent(g_worker)) {
|
||||
std::abort();
|
||||
}
|
||||
++g_steps;
|
||||
HostContext::Switch(g_scheduler);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int main()
|
||||
{
|
||||
if (!HostContext::InitializeScheduler(&g_scheduler) ||
|
||||
!HostContext::IsCurrent(g_scheduler)) {
|
||||
return 1;
|
||||
}
|
||||
g_worker = HostContext::Create(64 * 1024, Worker, nullptr);
|
||||
if (!g_worker) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
HostContext::Switch(g_worker);
|
||||
if (g_steps != 1 || !HostContext::IsCurrent(g_scheduler)) {
|
||||
return 1;
|
||||
}
|
||||
HostContext::Switch(g_worker);
|
||||
if (g_steps != 2 || !HostContext::IsCurrent(g_scheduler)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
HostContext::Destroy(g_worker);
|
||||
HostContext::ShutdownScheduler(g_scheduler);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
extern "C" void mkw_co_switch(void** targetSp, void** sourceSp);
|
||||
extern "C" void* mkw_co_init(void* stackTop, void (*entry)(void*), void* argument);
|
||||
|
||||
namespace {
|
||||
// Exercise the raw AArch64 context ABI independently of HostContext so a
|
||||
// callee-saved-register or stack-frame regression is localized to this layer.
|
||||
|
||||
std::array<std::byte, 64 * 1024> g_workerStack{};
|
||||
void* g_schedulerSp = nullptr;
|
||||
void* g_workerSp = nullptr;
|
||||
std::vector<int> g_events;
|
||||
|
||||
void Worker(void*) {
|
||||
g_events.push_back(1);
|
||||
mkw_co_switch(&g_schedulerSp, &g_workerSp);
|
||||
g_events.push_back(2);
|
||||
mkw_co_switch(&g_schedulerSp, &g_workerSp);
|
||||
std::abort();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main() {
|
||||
g_workerSp = mkw_co_init(g_workerStack.data() + g_workerStack.size(), Worker, nullptr);
|
||||
if (!g_workerSp) {
|
||||
std::cerr << "failed to create AArch64 context frame\n";
|
||||
return 1;
|
||||
}
|
||||
mkw_co_switch(&g_workerSp, &g_schedulerSp);
|
||||
if (g_events != std::vector<int>{1}) {
|
||||
std::cerr << "worker did not yield to scheduler\n";
|
||||
return 1;
|
||||
}
|
||||
mkw_co_switch(&g_workerSp, &g_schedulerSp);
|
||||
if (g_events != std::vector<int>{1, 2}) {
|
||||
std::cerr << "worker did not resume from saved context\n";
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
#include "guest_flat_memory.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <unistd.h>
|
||||
|
||||
int main() {
|
||||
GuestFlat::Initialize({
|
||||
{0x00000000u, 0x4000u, GuestFlat::Backing::Mem1},
|
||||
{0x80000000u, 0x4000u, GuestFlat::Backing::Mem1},
|
||||
{0x10000000u, 0x4000u, GuestFlat::Backing::Mem2},
|
||||
{0x90000000u, 0x4000u, GuestFlat::Backing::Mem2},
|
||||
});
|
||||
if (!GuestFlat::IsActive()) {
|
||||
std::cerr << "guest address space did not become active\n";
|
||||
return 1;
|
||||
}
|
||||
if (GuestFlat::RequiresCheckedAccess() !=
|
||||
(static_cast<size_t>(getpagesize()) > GuestFlat::kGuestPageSize)) {
|
||||
std::cerr << "guest access mode does not reflect the host page size\n";
|
||||
return 1;
|
||||
}
|
||||
auto* mem1Physical = GuestFlat::HostPointer(0x00000000u);
|
||||
auto* mem1Cached = GuestFlat::HostPointer(0x80000000u);
|
||||
auto* mem2Physical = GuestFlat::HostPointer(0x10000000u);
|
||||
auto* mem2Cached = GuestFlat::HostPointer(0x90000000u);
|
||||
if (!mem1Physical || !mem1Cached || !mem2Physical || !mem2Cached) {
|
||||
std::cerr << "missing host alias\n";
|
||||
return 1;
|
||||
}
|
||||
if (GuestFlat::HostPointer(0x4000u) != nullptr ||
|
||||
GuestFlat::HostPointer(0xa0000000u) != nullptr) {
|
||||
std::cerr << "unmapped guest address resolved to host memory\n";
|
||||
return 1;
|
||||
}
|
||||
mem1Physical[7] = 0x5a;
|
||||
mem2Cached[9] = 0xa5;
|
||||
const auto* guest = reinterpret_cast<const uint8_t*>(GuestFlat::kFixedFlatGuestBase);
|
||||
if (mem1Cached[7] != 0x5a || guest[0x80000007u] != 0x5a ||
|
||||
mem2Physical[9] != 0xa5 || guest[0x10000009u] != 0xa5) {
|
||||
std::cerr << "guest aliases are not coherent\n";
|
||||
return 1;
|
||||
}
|
||||
auto* guestWritable = reinterpret_cast<uint8_t*>(GuestFlat::kFixedFlatGuestBase);
|
||||
guestWritable[0x80000008u] = 0x3c;
|
||||
guestWritable[0x1000000au] = 0xc3;
|
||||
if (mem1Physical[8] != 0x3c || mem2Cached[10] != 0xc3) {
|
||||
std::cerr << "guest writes were not visible through host aliases\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
GuestFlat::Initialize({
|
||||
{0x00000000u, 0x4000u, GuestFlat::Backing::Mem1},
|
||||
{0x80000000u, 0x4000u, GuestFlat::Backing::Mem1},
|
||||
{0x10000000u, 0x4000u, GuestFlat::Backing::Mem2},
|
||||
{0x90000000u, 0x4000u, GuestFlat::Backing::Mem2},
|
||||
});
|
||||
try {
|
||||
GuestFlat::Initialize({{0x00000000u, 0x8000u, GuestFlat::Backing::Mem1}});
|
||||
std::cerr << "guest address space accepted a different layout\n";
|
||||
return 1;
|
||||
} catch (const std::runtime_error&) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#include "platform/host_platform.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
if (!RuntimePlatform::ExecutableDirectory()) {
|
||||
std::cerr << "unable to resolve the current executable directory\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
const auto userData = RuntimePlatform::ApplicationDataDirectory("WiiCompiledPlatformPathsTest");
|
||||
if (userData.filename() != "WiiCompiledPlatformPathsTest") {
|
||||
std::cerr << "application-data directory lost its application name: " << userData << '\n';
|
||||
return 1;
|
||||
}
|
||||
if (RuntimePlatform::LogDirectory("WiiCompiledPlatformPathsTest") != userData / "Logs") {
|
||||
std::cerr << "log directory is not derived from application data\n";
|
||||
return 1;
|
||||
}
|
||||
#if defined(__APPLE__)
|
||||
if (userData.parent_path().filename() != "Application Support" ||
|
||||
userData.parent_path().parent_path().filename() != "Library") {
|
||||
std::cerr << "macOS application-data directory is not under ~/Library/Application Support: "
|
||||
<< userData << '\n';
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user