diff --git a/nx/Makefile b/nx/Makefile index dd4e4b9b..3fd2b632 100644 --- a/nx/Makefile +++ b/nx/Makefile @@ -24,7 +24,7 @@ VERSION := $(LIBNX_MAJOR).$(LIBNX_MINOR).$(LIBNX_PATCH) #--------------------------------------------------------------------------------- TARGET := nx #BUILD := build -SOURCES := source/kernel source/services +SOURCES := source/kernel source/services source/heap DATA := data INCLUDES := include diff --git a/nx/include/switch.h b/nx/include/switch.h index b67c8f48..21dd8886 100644 --- a/nx/include/switch.h +++ b/nx/include/switch.h @@ -12,6 +12,9 @@ extern "C" { #include #include #include +#include + +#include #include diff --git a/nx/include/switch/heap.h b/nx/include/switch/heap.h new file mode 100644 index 00000000..1092774c --- /dev/null +++ b/nx/include/switch/heap.h @@ -0,0 +1,2 @@ +void* heapAllocPages(size_t size); +void* heapAlloc(size_t size); diff --git a/nx/include/switch/kernel/tmem.h b/nx/include/switch/kernel/tmem.h new file mode 100644 index 00000000..bbc96a3d --- /dev/null +++ b/nx/include/switch/kernel/tmem.h @@ -0,0 +1,10 @@ +typedef struct { + Handle MemHandle; + size_t Size; +} TransferMemory; + +typedef enum { + PERM_NONE = 0, + PERM_R = 1, + PERM_RW = 3 +} Permission; diff --git a/nx/include/switch/svc.h b/nx/include/switch/svc.h index 93fff431..97acc218 100644 --- a/nx/include/switch/svc.h +++ b/nx/include/switch/svc.h @@ -20,6 +20,7 @@ static inline void* armGetTls(void) { Result svcQueryMemory(u32 *meminfo_ptr, u32 *pageinfo, u64 addr); Result svcCloseHandle(Handle handle); +Result svcCreateTransferMemory(Handle* out, void* addr, size_t size, u32 perm); Result svcWaitSynchronization(s32* index, const Handle* handles, s32 handleCount, u64 timeout); Result svcConnectToNamedPort(Handle* session, const char* name); Result svcSendSyncRequest(Handle session); diff --git a/nx/source/heap/heap.c b/nx/source/heap/heap.c new file mode 100644 index 00000000..dc1f0187 --- /dev/null +++ b/nx/source/heap/heap.c @@ -0,0 +1,89 @@ +// Copyright 2017 plutoo +// Worst heap ever xD +#include + +typedef struct HeapHeader HeapHeader; + +typedef enum { + USED = 0x55534544, + FREE = 0x46524545 +} HeapState; + +struct HeapHeader { + size_t State; + size_t Size; + HeapHeader* Next; + HeapHeader* Prev; +}; + +static HeapHeader g_LastFree; + +void heapInit(void* base, size_t size) { + // Called by crt0. + HeapHeader* hdr = (HeapHeader*) base; + + hdr->Next = &g_LastFree; + hdr->Prev = &g_LastFree; + hdr->Size = size - sizeof(HeapHeader); + hdr->State = FREE; + + g_LastFree.Next = hdr; + g_LastFree.Prev = hdr; +} + +void* heapAllocPages(size_t size) { + void* ptr = heapAlloc(size + 0x1000); + + if (ptr != NULL) { + ptr = (void*) ((((uintptr_t) ptr) + 0xFFF) &~ 0xFFF); + } + + return ptr; +} + +void* heapAlloc(size_t size) { + size = (size + 15) &~ 15; + + HeapHeader* hdr = &g_LastFree; + + while ((hdr = hdr->Next) != &g_LastFree) { + if (hdr->Size >= size) { + size_t rem = hdr->Size - size; + + if (rem < sizeof(HeapHeader)) { + size = hdr->Size; + rem = 0; + } + + hdr->State = USED; + hdr->Size = size; + + hdr->Prev->Next = hdr->Next; + hdr->Next->Prev = hdr->Prev; + + if (rem != 0) { + HeapHeader* rem_hdr = (HeapHeader*) (((uintptr_t)(hdr + 1)) + size); + rem_hdr->State = FREE; + rem_hdr->Size = rem - sizeof(HeapHeader); + + rem_hdr->Next = g_LastFree.Next; + rem_hdr->Prev = &g_LastFree; + g_LastFree.Next = rem_hdr; + } + + return (void*) (((uintptr_t) hdr) + sizeof(HeapHeader)); + } + } + + return NULL; +} + +void heapFree(void* ptr) { + HeapHeader* hdr = (HeapHeader*) (((uintptr_t) ptr) - sizeof(HeapHeader)); + hdr->State = FREE; + + hdr->Next = g_LastFree.Next; + g_LastFree.Next = hdr; + hdr->Prev = &g_LastFree; +} + diff --git a/nx/source/kernel/svc.s b/nx/source/kernel/svc.s index cbb27e63..be3d9de0 100644 --- a/nx/source/kernel/svc.s +++ b/nx/source/kernel/svc.s @@ -24,6 +24,14 @@ SVC_BEGIN svcCloseHandle ret SVC_END +SVC_BEGIN svcCreateTransferMemory + str x0, [sp, #-16]! + svc 0x15 + ldr x2, [sp], #16 + str w1, [x2] + ret +SVC_END + SVC_BEGIN svcWaitSynchronization str x0, [sp, #-16]! svc 0x18 diff --git a/nx/source/kernel/tmem.c b/nx/source/kernel/tmem.c new file mode 100644 index 00000000..3a8aca08 --- /dev/null +++ b/nx/source/kernel/tmem.c @@ -0,0 +1,21 @@ +#include + +Result tmemCreate(TransferMemory* t, size_t size, Permission perm) { + t->Size = size; + + Result rc = 0; + void* addr = heapAllocPages(size); + + if (addr == NULL) + rc = -1; + + if (R_SUCCEEDED(rc)) { + rc = svcCreateTransferMemory(&t->MemHandle, addr, size, perm); + } + + return rc; +} + +Result tmemClose(TransferMemory* t) { + return svcCloseHandle(t->MemHandle); +} diff --git a/nx/source/services/bsd.c b/nx/source/services/bsd.c new file mode 100644 index 00000000..5533a2cd --- /dev/null +++ b/nx/source/services/bsd.c @@ -0,0 +1,39 @@ +// Copyright 2017 plutoo +#include + +static Handle g_bsdHandle = -1; + +Result bsdInitialize(TransferMemory* tmem) { + Result rc = smGetService(&g_bsdHandle, "bsd:s"); + + if (R_FAILED(rc)) { + rc = smGetService(&g_bsdHandle, "bsd:u"); + } + + if (R_SUCCEEDED(rc)) { + IpcCommand c; + ipcInitialize(&c); + ipcSendPid(&c); + ipcSendHandleCopy(&c, tmem->MemHandle); + + struct { + u64 magic; + u64 cmd_id; + u64 unk[5]; + u64 tmem_sz; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 0; + raw->unk[0] = 0; + raw->unk[1] = 0; + raw->unk[2] = 0; + raw->unk[3] = 0; + raw->unk[4] = 0; + raw->tmem_sz = tmem->Size; + } + + return rc; +}