mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-06 22:25:41 +12:00
Lots of kernel work
This commit is contained in:
parent
787397085e
commit
a89c850189
8 changed files with 237 additions and 46 deletions
|
@ -18,6 +18,7 @@ if(NOT SFML_FOUND)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/include/)
|
include_directories(${PROJECT_SOURCE_DIR}/include/)
|
||||||
|
include_directories(${PROJECT_SOURCE_DIR}/include/kernel)
|
||||||
include_directories (${SFML_INCLUDE_DIR})
|
include_directories (${SFML_INCLUDE_DIR})
|
||||||
include_directories (${FMT_INCLUDE_DIR})
|
include_directories (${FMT_INCLUDE_DIR})
|
||||||
include_directories(third_party/elfio/)
|
include_directories(third_party/elfio/)
|
||||||
|
@ -44,11 +45,12 @@ else()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(SOURCE_FILES src/main.cpp src/emulator.cpp src/core/CPU/cpu_dynarmic.cpp src/core/memory.cpp src/core/elf.cpp
|
set(SOURCE_FILES src/main.cpp src/emulator.cpp src/core/CPU/cpu_dynarmic.cpp src/core/memory.cpp src/core/elf.cpp
|
||||||
src/core/kernel.cpp
|
|
||||||
)
|
)
|
||||||
|
set(KERNEL_SOURCE_FILES src/core/kernel/kernel.cpp src/core/kernel/resource_limits.cpp)
|
||||||
set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/opengl.hpp include/termcolor.hpp
|
set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/opengl.hpp include/termcolor.hpp
|
||||||
include/cpu.hpp include/cpu_dynarmic.hpp include/memory.hpp include/kernel.hpp
|
include/cpu.hpp include/cpu_dynarmic.hpp include/memory.hpp include/kernel/kernel.hpp
|
||||||
include/dynarmic_cp15.hpp
|
include/dynarmic_cp15.hpp include/kernel/resource_limits.hpp include/kernel/kernel_types.hpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(THIRD_PARTY_SOURCE_FILES third_party/imgui/imgui.cpp
|
set(THIRD_PARTY_SOURCE_FILES third_party/imgui/imgui.cpp
|
||||||
|
@ -62,7 +64,8 @@ set(THIRD_PARTY_SOURCE_FILES third_party/imgui/imgui.cpp
|
||||||
#add_library(Alber ${HEADER_FILES})
|
#add_library(Alber ${HEADER_FILES})
|
||||||
source_group("Header Files\\Core" FILES ${HEADER_FILES})
|
source_group("Header Files\\Core" FILES ${HEADER_FILES})
|
||||||
source_group("Source Files\\Core" FILES ${SOURCE_FILES})
|
source_group("Source Files\\Core" FILES ${SOURCE_FILES})
|
||||||
|
source_group("Source Files\\Core\\Kernel" FILES ${KERNEL_SOURCE_FILES})
|
||||||
source_group("Source Files\\Third Party" FILES ${THIRD_PARTY_SOURCE_FILES})
|
source_group("Source Files\\Third Party" FILES ${THIRD_PARTY_SOURCE_FILES})
|
||||||
|
|
||||||
add_executable(Alber ${SOURCE_FILES} ${THIRD_PARTY_SOURCE_FILES} ${HEADER_FILES})
|
add_executable(Alber ${SOURCE_FILES} ${KERNEL_SOURCE_FILES} ${THIRD_PARTY_SOURCE_FILES} ${HEADER_FILES})
|
||||||
target_link_libraries(Alber PRIVATE sfml-system sfml-network sfml-graphics sfml-window dynarmic)
|
target_link_libraries(Alber PRIVATE sfml-system sfml-network sfml-graphics sfml-window dynarmic)
|
|
@ -1,22 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <array>
|
|
||||||
#include "helpers.hpp"
|
|
||||||
#include "memory.hpp"
|
|
||||||
|
|
||||||
namespace SVCResult {
|
|
||||||
enum : u32 {
|
|
||||||
Success = 0
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
class Kernel {
|
|
||||||
std::array<u32, 16>& regs;
|
|
||||||
Memory& mem;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Kernel(std::array<u32, 16>& regs, Memory& mem) : regs(regs), mem(mem) {}
|
|
||||||
void serviceSVC(u32 svc);
|
|
||||||
void reset();
|
|
||||||
|
|
||||||
void createAddressArbiter();
|
|
||||||
};
|
|
63
include/kernel/kernel.hpp
Normal file
63
include/kernel/kernel.hpp
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
#pragma once
|
||||||
|
#include <array>
|
||||||
|
#include <limits>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include "kernel_types.hpp"
|
||||||
|
#include "helpers.hpp"
|
||||||
|
#include "memory.hpp"
|
||||||
|
|
||||||
|
class Kernel {
|
||||||
|
std::array<u32, 16>& regs;
|
||||||
|
Memory& mem;
|
||||||
|
|
||||||
|
// The handle number for the next kernel object to be created
|
||||||
|
u32 handleCounter;
|
||||||
|
std::vector<KernelObject> objects;
|
||||||
|
|
||||||
|
u32 currentProcess;
|
||||||
|
|
||||||
|
// Get pointer to the object with the specified handle
|
||||||
|
KernelObject* getObject(u32 handle) {
|
||||||
|
// Accessing an object that has not been created
|
||||||
|
if (handle >= objects.size()) [[unlikely]] {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &objects[handle];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get pointer to the object with the specified handle and type
|
||||||
|
KernelObject* getObject(u32 handle, KernelObjectType type) {
|
||||||
|
if (handle >= objects.size() || objects[handle].type != type) [[unlikely]] {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &objects[handle];
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle makeObject(KernelObjectType type) {
|
||||||
|
if (handleCounter == std::numeric_limits<Handle>::max()) [[unlikely]] {
|
||||||
|
Helpers::panic("Hlep we somehow created enough kernel objects to overflow this thing");
|
||||||
|
}
|
||||||
|
|
||||||
|
objects.push_back(KernelObject(handleCounter, type));
|
||||||
|
printf("Created %s object with handle %d\n", kernelObjectTypeToString(type), handleCounter);
|
||||||
|
return handleCounter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle makeProcess();
|
||||||
|
KernelObject* getProcessFromPID(Handle handle);
|
||||||
|
|
||||||
|
void createAddressArbiter();
|
||||||
|
void getResourceLimit();
|
||||||
|
void getResourceLimitLimitValues();
|
||||||
|
std::string getProcessName(u32 pid);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Kernel(std::array<u32, 16>& regs, Memory& mem) : regs(regs), mem(mem), handleCounter(0) {
|
||||||
|
objects.reserve(512); // Make room for a few objects to avoid further memory allocs later
|
||||||
|
}
|
||||||
|
void serviceSVC(u32 svc);
|
||||||
|
void reset();
|
||||||
|
};
|
75
include/kernel/kernel_types.hpp
Normal file
75
include/kernel/kernel_types.hpp
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
#pragma once
|
||||||
|
#include "helpers.hpp"
|
||||||
|
|
||||||
|
namespace SVCResult {
|
||||||
|
enum : u32 {
|
||||||
|
Success = 0,
|
||||||
|
Failure = 0xFFFFFFFF,
|
||||||
|
// Different calls return a different value
|
||||||
|
BadHandle = 0xD8E007F7,
|
||||||
|
BadHandleAlt = 0xD9001BF7
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace KernelHandles {
|
||||||
|
enum : u32 {
|
||||||
|
CurrentThread = 0xFFFF8000,
|
||||||
|
CurrentProcess = 0xFFFF8001
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class KernelObjectType : u8 {
|
||||||
|
ResourceLimit, Process
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ResourceLimitCategory : int {
|
||||||
|
Application = 0,
|
||||||
|
SystemApplet = 1,
|
||||||
|
LibraryApplet = 2,
|
||||||
|
Misc = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ResourceTypes {
|
||||||
|
PRIORITY = 0,
|
||||||
|
COMMIT = 1,
|
||||||
|
THREAD = 2,
|
||||||
|
EVENT = 3,
|
||||||
|
MUTEX = 4,
|
||||||
|
SEMAPHORE = 5,
|
||||||
|
TIMER = 6,
|
||||||
|
SHARED_MEMORY = 7,
|
||||||
|
ADDRESS_ARBITER = 8,
|
||||||
|
CPU_TIME = 9
|
||||||
|
};
|
||||||
|
|
||||||
|
using Handle = u32;
|
||||||
|
|
||||||
|
struct ResourceLimits {
|
||||||
|
Handle handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ProcessData {
|
||||||
|
// Resource limits for this process
|
||||||
|
ResourceLimits limits;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char* kernelObjectTypeToString(KernelObjectType t) {
|
||||||
|
switch (t) {
|
||||||
|
case KernelObjectType::Process: return "process";
|
||||||
|
case KernelObjectType::ResourceLimit: return "resource limit";
|
||||||
|
default: return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generic kernel object class
|
||||||
|
struct KernelObject {
|
||||||
|
Handle 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) {}
|
||||||
|
|
||||||
|
// 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() {}
|
||||||
|
};
|
2
include/kernel/resource_limits.hpp
Normal file
2
include/kernel/resource_limits.hpp
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
#pragma once
|
||||||
|
#include "kernel_types.hpp"
|
|
@ -1,20 +0,0 @@
|
||||||
#include "kernel.hpp"
|
|
||||||
|
|
||||||
void Kernel::serviceSVC(u32 svc) {
|
|
||||||
switch (svc) {
|
|
||||||
case 0x21: createAddressArbiter(); break;
|
|
||||||
default: Helpers::panic("Unimplemented svc: %x @ %08X", svc, regs[15]); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Kernel::reset() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Result CreateAddressArbiter(Handle* arbiter)
|
|
||||||
// in: r0 -> Pointer to Handle object
|
|
||||||
// out: r0 -> result
|
|
||||||
void Kernel::createAddressArbiter() {
|
|
||||||
printf("Stubbed call to CreateAddressArbiter. Handle address: %08X\n", regs[0]);
|
|
||||||
regs[0] = SVCResult::Success;
|
|
||||||
}
|
|
90
src/core/kernel/kernel.cpp
Normal file
90
src/core/kernel/kernel.cpp
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
#include <cassert>
|
||||||
|
#include "kernel.hpp"
|
||||||
|
#include "kernel_types.hpp"
|
||||||
|
|
||||||
|
void Kernel::serviceSVC(u32 svc) {
|
||||||
|
switch (svc) {
|
||||||
|
case 0x21: createAddressArbiter(); break;
|
||||||
|
case 0x38: getResourceLimit(); break;
|
||||||
|
case 0x39: getResourceLimitLimitValues(); break;
|
||||||
|
default: Helpers::panic("Unimplemented svc: %x @ %08X", svc, regs[15]); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle Kernel::makeProcess() {
|
||||||
|
const Handle processHandle = makeObject(KernelObjectType::Process);
|
||||||
|
const Handle resourceLimitHandle = makeObject(KernelObjectType::ResourceLimit);
|
||||||
|
|
||||||
|
// Allocate data
|
||||||
|
objects[processHandle].data = new ProcessData();
|
||||||
|
const auto processData = static_cast<ProcessData*>(objects[processHandle].data);
|
||||||
|
|
||||||
|
// Link resource limit object with its parent process
|
||||||
|
objects[resourceLimitHandle].data = &processData->limits;
|
||||||
|
processData->limits.handle = resourceLimitHandle;
|
||||||
|
return processHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a pointer to the process indicated by handle, taking into account that 0xFFFF8001 always refers to the current process
|
||||||
|
// Returns nullptr if the handle does not correspond to a process
|
||||||
|
KernelObject* Kernel::getProcessFromPID(Handle handle) {
|
||||||
|
if (handle == KernelHandles::CurrentProcess) [[likely]] {
|
||||||
|
return getObject(currentProcess, KernelObjectType::Process);
|
||||||
|
} else {
|
||||||
|
return getObject(handle, KernelObjectType::Process);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Kernel::reset() {
|
||||||
|
handleCounter = 0;
|
||||||
|
|
||||||
|
for (auto& object : objects) {
|
||||||
|
if (object.data != nullptr) {
|
||||||
|
delete object.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
objects.clear();
|
||||||
|
|
||||||
|
// Make a main process object
|
||||||
|
currentProcess = makeProcess();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Result CreateAddressArbiter(Handle* arbiter)
|
||||||
|
// out: r0 -> result
|
||||||
|
void Kernel::createAddressArbiter() {
|
||||||
|
printf("Stubbed call to CreateAddressArbiter. Handle address: %08X\n", regs[0]);
|
||||||
|
regs[0] = SVCResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Result GetResourceLimit(Handle* resourceLimit, Handle process)
|
||||||
|
// out: r0 -> result
|
||||||
|
void Kernel::getResourceLimit() {
|
||||||
|
const auto handlePointer = regs[0];
|
||||||
|
const auto pid = regs[1];
|
||||||
|
const auto process = getProcessFromPID(pid);
|
||||||
|
|
||||||
|
if (process == nullptr) [[unlikely]] {
|
||||||
|
regs[0] = SVCResult::BadHandle;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto processData = static_cast<ProcessData*>(process->data);
|
||||||
|
|
||||||
|
printf("GetResourceLimit (Handle pointer = %08X, process: %s)\n", handlePointer, getProcessName(pid).c_str());
|
||||||
|
mem.write32(handlePointer, processData->limits.handle);
|
||||||
|
regs[0] = SVCResult::Success;
|
||||||
|
// Is the handle meant to be output through both r1 and memory? Libctru breaks otherwise.
|
||||||
|
regs[1] = processData->limits.handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Kernel::getResourceLimitLimitValues() {
|
||||||
|
Helpers::panic("Trying to getResourceLimitLimitValues from resourceLimit with handle %08X\n", regs[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Kernel::getProcessName(u32 pid) {
|
||||||
|
if (pid == KernelHandles::CurrentProcess) {
|
||||||
|
return "current";
|
||||||
|
} else {
|
||||||
|
Helpers::panic("Attempted to name non-current process");
|
||||||
|
}
|
||||||
|
}
|
0
src/core/kernel/resource_limits.cpp
Normal file
0
src/core/kernel/resource_limits.cpp
Normal file
Loading…
Add table
Reference in a new issue