mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-12 09:09:47 +12:00
misc: Improve kernel syscall checks
Fix some stuffs around. Based on kernel 11.14
This commit is contained in:
parent
d0ae5f0546
commit
6d9964c64b
5 changed files with 116 additions and 38 deletions
|
@ -104,6 +104,8 @@ private:
|
|||
std::string getProcessName(u32 pid);
|
||||
const char* resetTypeToString(u32 type);
|
||||
|
||||
int copyStringFromUser(u8 *dst, u32 src, u32 size);
|
||||
|
||||
MAKE_LOG_FUNCTION(log, kernelLogger)
|
||||
MAKE_LOG_FUNCTION(logSVC, svcLogger)
|
||||
MAKE_LOG_FUNCTION(logThread, threadLogger)
|
||||
|
|
|
@ -4,11 +4,13 @@
|
|||
DEFINE_HORIZON_RESULT_MODULE(Result::OS, OS);
|
||||
|
||||
namespace Result::OS {
|
||||
DEFINE_HORIZON_RESULT(InvalidPortName, 20, WrongArgument, Permanent);
|
||||
DEFINE_HORIZON_RESULT(PortNameTooLong, 30, InvalidArgument, Usage);
|
||||
DEFINE_HORIZON_RESULT(InvalidHandle, 1015, WrongArgument, Permanent);
|
||||
DEFINE_HORIZON_RESULT(InvalidCombination, 1006, InvalidArgument, Usage);
|
||||
DEFINE_HORIZON_RESULT(MisalignedAddress, 1009, InvalidArgument, Usage);
|
||||
DEFINE_HORIZON_RESULT(MisalignedSize, 1010, InvalidArgument, Usage);
|
||||
DEFINE_HORIZON_RESULT(MisalignedSize, 1010, InvalidArgument, Usage);\
|
||||
DEFINE_HORIZON_RESULT(InvalidAddress, 1013, InvalidArgument, Usage);
|
||||
DEFINE_HORIZON_RESULT(OutOfRange, 1021, InvalidArgument, Usage);
|
||||
DEFINE_HORIZON_RESULT(Timeout, 1022, StatusChanged, Info);
|
||||
};
|
||||
|
|
|
@ -70,6 +70,25 @@ void Kernel::setVersion(u8 major, u8 minor) {
|
|||
mem.kernelVersion = descriptor; // The memory objects needs a copy because you can read the kernel ver from config mem
|
||||
}
|
||||
|
||||
int Kernel::copyStringFromUser(u8 *dst, u32 src, u32 size) {
|
||||
if (size == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 i;
|
||||
for (i = 0; i < size; i++) {
|
||||
u8 c = mem.read8(src + i);
|
||||
|
||||
*dst++ = c;
|
||||
|
||||
if (c == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
Handle Kernel::makeProcess(u32 id) {
|
||||
const Handle processHandle = makeObject(KernelObjectType::Process);
|
||||
const Handle resourceLimitHandle = makeObject(KernelObjectType::ResourceLimit);
|
||||
|
@ -162,12 +181,23 @@ void Kernel::getSystemTick() {
|
|||
}
|
||||
|
||||
// Result OutputDebugString(const char* str, s32 size)
|
||||
// TODO: Does this actually write an error code in r0 and is the above signature correct?
|
||||
void Kernel::outputDebugString() {
|
||||
const u32 pointer = regs[0];
|
||||
const u32 size = regs[1];
|
||||
const s32 size = regs[1];
|
||||
|
||||
if (size < 0 || ~pointer < size) {
|
||||
regs[0] = Result::OS::OutOfRange;
|
||||
return;
|
||||
}
|
||||
else if (pointer >= 0x40000000) {
|
||||
regs[0] = Result::OS::InvalidAddress;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string message = mem.readString(pointer, size);
|
||||
|
||||
// TODO: Dispatch debug event
|
||||
|
||||
logDebugString("[OutputDebugString] %s\n", message.c_str());
|
||||
regs[0] = Result::Success;
|
||||
}
|
||||
|
@ -198,6 +228,8 @@ void Kernel::getProcessInfo() {
|
|||
return;
|
||||
}
|
||||
|
||||
regs[0] = Result::Success;
|
||||
|
||||
switch (type) {
|
||||
// According to 3DBrew: Amount of private (code, data, heap) memory used by the process + total supervisor-mode
|
||||
// stack size + page-rounded size of the external handle table
|
||||
|
@ -213,9 +245,9 @@ void Kernel::getProcessInfo() {
|
|||
|
||||
default:
|
||||
Helpers::panic("GetProcessInfo: unimplemented type %d", type);
|
||||
regs[0] = Result::Kernel::InvalidEnumValue;
|
||||
break;
|
||||
}
|
||||
|
||||
regs[0] = Result::Success;
|
||||
}
|
||||
|
||||
// Result DuplicateHandle(Handle* out, Handle original)
|
||||
|
@ -231,6 +263,7 @@ void Kernel::duplicateHandle() {
|
|||
regs[1] = ret;
|
||||
} else {
|
||||
Helpers::panic("DuplicateHandle: unimplemented handle type");
|
||||
regs[0] = Result::Kernel::InvalidHandle;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -61,8 +61,16 @@ void Kernel::controlMemory() {
|
|||
if (x)
|
||||
Helpers::panic("ControlMemory: attempted to allocate executable memory");
|
||||
|
||||
if (!isAligned(addr0) || !isAligned(addr1) || !isAligned(size)) {
|
||||
Helpers::panic("ControlMemory: Unaligned parameters\nAddr0: %08X\nAddr1: %08X\nSize: %08X", addr0, addr1, size);
|
||||
if (!isAligned(addr0) || !isAligned(addr1)) [[unlikely]] {
|
||||
Helpers::panic("ControlMemory: Unaligned addresses\nAddr0: %08X\nAddr1: %08X\n", addr0, addr1);
|
||||
regs[0] = Result::OS::MisalignedAddress;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isAligned(size)) [[unlikely]] {
|
||||
Helpers::panic("ControlMemory: Unaligned size\nSize: %08X", size);
|
||||
regs[0] = Result::OS::MisalignedSize;
|
||||
return;
|
||||
}
|
||||
|
||||
logSVC("ControlMemory(addr0 = %08X, addr1 = %08X, size = %08X, operation = %X (%c%c%c)%s\n",
|
||||
|
@ -87,7 +95,10 @@ void Kernel::controlMemory() {
|
|||
Helpers::warn("Ignoring mprotect! Hope nothing goes wrong but if the game accesses invalid memory or crashes then we prolly need to implement this\n");
|
||||
break;
|
||||
|
||||
default: Helpers::panic("ControlMemory: unknown operation %X\n", operation);
|
||||
default:
|
||||
Helpers::panic("ControlMemory: unknown operation %X\n", operation);
|
||||
regs[0] = Result::OS::InvalidCombination;
|
||||
return;
|
||||
}
|
||||
|
||||
regs[0] = Result::Success;
|
||||
|
@ -114,17 +125,37 @@ void Kernel::queryMemory() {
|
|||
void Kernel::mapMemoryBlock() {
|
||||
const Handle block = regs[0];
|
||||
u32 addr = regs[1];
|
||||
const u32 myPerms = regs[2];
|
||||
const u32 otherPerms = regs[3];
|
||||
logSVC("MapMemoryBlock(block = %X, addr = %08X, myPerms = %X, otherPerms = %X\n", block, addr, myPerms, otherPerms);
|
||||
const u32 myPermission = regs[2];
|
||||
const u32 otherPermission = regs[3];
|
||||
logSVC("MapMemoryBlock(block = %X, addr = %08X, myPermission = %X, otherPermission = %X\n", block, addr, myPermission, otherPermission);
|
||||
|
||||
if (!isAligned(addr)) [[unlikely]] {
|
||||
Helpers::panic("MapMemoryBlock: Unaligned address");
|
||||
regs[0] = Result::OS::MisalignedAddress;
|
||||
return;
|
||||
}
|
||||
|
||||
if (myPermission != MemoryPermissions::Read &&
|
||||
myPermission != MemoryPermissions::Write &&
|
||||
myPermission != MemoryPermissions::ReadWrite) [[unlikely]] {
|
||||
Helpers::panic("MapMemoryBlock: Invalid myPermission");
|
||||
regs[0] = Result::OS::InvalidCombination;
|
||||
return;
|
||||
}
|
||||
|
||||
if (otherPermission != MemoryPermissions::None &&
|
||||
otherPermission != MemoryPermissions::Read &&
|
||||
otherPermission != MemoryPermissions::Write &&
|
||||
otherPermission != MemoryPermissions::ReadWrite &&
|
||||
otherPermission != MemoryPermissions::DontCare) [[unlikely]] {
|
||||
Helpers::panic("MapMemoryBlock: Invalid otherPermission");
|
||||
regs[0] = Result::OS::InvalidCombination;
|
||||
return;
|
||||
}
|
||||
|
||||
if (KernelHandles::isSharedMemHandle(block)) {
|
||||
if (block == KernelHandles::FontSharedMemHandle && addr == 0) addr = 0x18000000;
|
||||
u8* ptr = mem.mapSharedMemory(block, addr, myPerms, otherPerms); // Map shared memory block
|
||||
u8* ptr = mem.mapSharedMemory(block, addr, myPermission, otherPermission); // Map shared memory block
|
||||
|
||||
// Pass pointer to shared memory to the appropriate service
|
||||
switch (block) {
|
||||
|
@ -140,10 +171,15 @@ void Kernel::mapMemoryBlock() {
|
|||
std::memcpy(ptr, _shared_font_bin, _shared_font_len);
|
||||
break;
|
||||
|
||||
default: Helpers::panic("Mapping unknown shared memory block: %X", block);
|
||||
default:
|
||||
Helpers::panic("Mapping unknown shared memory block: %X", block);
|
||||
regs[0] = Result::OS::InvalidHandle;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
Helpers::panic("MapMemoryBlock where the handle does not refer to a known piece of kernel shared mem");
|
||||
regs[0] = Result::OS::InvalidHandle;
|
||||
return;
|
||||
}
|
||||
|
||||
regs[0] = Result::Success;
|
||||
|
@ -163,29 +199,25 @@ void Kernel::createMemoryBlock() {
|
|||
u32 otherPermission = mem.read32(regs[13] + 4); // This is placed on the stack rather than r4
|
||||
logSVC("CreateMemoryBlock (addr = %08X, size = %08X, myPermission = %d, otherPermission = %d)\n", addr, size, myPermission, otherPermission);
|
||||
|
||||
// Returns whether a permission is valid
|
||||
auto isPermValid = [](u32 permission) {
|
||||
switch (permission) {
|
||||
case MemoryPermissions::None:
|
||||
case MemoryPermissions::Read:
|
||||
case MemoryPermissions::Write:
|
||||
case MemoryPermissions::ReadWrite:
|
||||
case MemoryPermissions::DontCare:
|
||||
return true;
|
||||
|
||||
default: // Permissions with the executable flag enabled or invalid permissions are not allowed
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Throw error if the size of the shared memory block is not aligned to page boundary
|
||||
if (!isAligned(size)) {
|
||||
regs[0] = Result::OS::MisalignedSize;
|
||||
return;
|
||||
}
|
||||
|
||||
// Throw error if one of the permissions is not valid
|
||||
if (!isPermValid(myPermission) || !isPermValid(otherPermission)) {
|
||||
if (myPermission != MemoryPermissions::Read &&
|
||||
myPermission != MemoryPermissions::Write &&
|
||||
myPermission != MemoryPermissions::ReadWrite) [[unlikely]] {
|
||||
Helpers::panic("MapMemoryBlock: Invalid myPermission");
|
||||
regs[0] = Result::OS::InvalidCombination;
|
||||
return;
|
||||
}
|
||||
|
||||
if (otherPermission != MemoryPermissions::None &&
|
||||
otherPermission != MemoryPermissions::Read &&
|
||||
otherPermission != MemoryPermissions::Write &&
|
||||
otherPermission != MemoryPermissions::ReadWrite) [[unlikely]] {
|
||||
Helpers::panic("MapMemoryBlock: Invalid otherPermission");
|
||||
regs[0] = Result::OS::InvalidCombination;
|
||||
return;
|
||||
}
|
||||
|
@ -195,10 +227,6 @@ void Kernel::createMemoryBlock() {
|
|||
if (addr == 0)
|
||||
Helpers::panic("CreateMemoryBlock: Tried to use addr = 0");
|
||||
|
||||
// Implement "Don't care" permission as RW
|
||||
if (myPermission == MemoryPermissions::DontCare) myPermission = MemoryPermissions::ReadWrite;
|
||||
if (otherPermission == MemoryPermissions::DontCare) otherPermission = MemoryPermissions::ReadWrite;
|
||||
|
||||
regs[0] = Result::Success;
|
||||
regs[1] = makeMemoryBlock(addr, size, myPermission, otherPermission);
|
||||
}
|
|
@ -37,16 +37,29 @@ std::optional<Handle> Kernel::getPortHandle(const char* name) {
|
|||
// Result ConnectToPort(Handle* out, const char* portName)
|
||||
void Kernel::connectToPort() {
|
||||
const u32 handlePointer = regs[0];
|
||||
// Read up to max + 1 characters to see if the name is too long
|
||||
std::string port = mem.readString(regs[1], Port::maxNameLen + 1);
|
||||
logSVC("ConnectToPort(handle pointer = %X, port = \"%s\")\n", handlePointer, port.c_str());
|
||||
const u32 portNameUserPtr = regs[1];
|
||||
|
||||
if (port.size() > Port::maxNameLen) {
|
||||
const u32 PortNameSize = Port::maxNameLen + 1;
|
||||
|
||||
u8 portName[PortNameSize];
|
||||
|
||||
int portSizeRead = copyStringFromUser(portName, portNameUserPtr, PortNameSize);
|
||||
|
||||
if (portSizeRead < 0) {
|
||||
Helpers::panic("ConnectToPort: Port name pointer was invalid\n");
|
||||
regs[0] = Result::OS::InvalidPortName;
|
||||
return;
|
||||
} else if (portSizeRead == PortNameSize && portName[Port::maxNameLen] != '\0') {
|
||||
Helpers::panic("ConnectToPort: Port name too long\n");
|
||||
regs[0] = Result::OS::PortNameTooLong;
|
||||
return;
|
||||
}
|
||||
|
||||
portSizeRead = std::max(portSizeRead, 0);
|
||||
std::string port(portName, portName + portSizeRead - 1);
|
||||
|
||||
logSVC("ConnectToPort(handle pointer = %X, port = \"%s\")\n", handlePointer, port.c_str());
|
||||
|
||||
// Try getting a handle to the port
|
||||
std::optional<Handle> optionalHandle = getPortHandle(port.c_str());
|
||||
if (!optionalHandle.has_value()) [[unlikely]] {
|
||||
|
|
Loading…
Add table
Reference in a new issue