Rewrite the memory management code for Nintendo Switch
The first implementation was naive and did not account for multiple memory allocations. However, this implementation may still be incomplete. Currently, when running applications, the code runs fine. When the application is exited via code (the end of the program is reached or quit() is called), the Switch will crash. Not sure why this happens, but I suspect it is from Nim memory allocations. I suspect the memory allocations because when I compile the helloworld application without any Nim allocations (just C function calls) and use `--gc:none` as a compile option, the application exits fine.
This commit is contained in:
parent
b61e69202b
commit
d599f38f0d
1 changed files with 61 additions and 23 deletions
|
|
@ -83,39 +83,77 @@ elif defined(genode):
|
||||||
elif defined(nintendoswitch):
|
elif defined(nintendoswitch):
|
||||||
import nintendoswitch/switch_memory
|
import nintendoswitch/switch_memory
|
||||||
|
|
||||||
var
|
type
|
||||||
stack: pointer
|
PSwitchBlock = ptr NSwitchBlock
|
||||||
|
NSwitchBlock {.pure, inheritable.} = object
|
||||||
|
realSize: int
|
||||||
|
heap: pointer # pointer to main heap alloc
|
||||||
|
heapMirror: pointer # pointer to virtmem mapped heap
|
||||||
|
|
||||||
proc alignSize(size: int): int =
|
proc alignSize(size: int): int =
|
||||||
(size + 0x00000FFF) and not 0x00000FFF
|
## Align a size integer to be in multiples of PageSize
|
||||||
|
## The nintendo switch will not allocate memory that is not
|
||||||
|
## aligned to 0x1000 bytes and will just crash.
|
||||||
|
(size + (PageSize - 1)) and not (PageSize - 1)
|
||||||
|
|
||||||
proc freeMem(p: pointer, msize: int) =
|
proc freeMem(p: pointer) =
|
||||||
let size = alignSize(msize)
|
# Retrieve the switch block data from the pointer we set before
|
||||||
discard svcUnmapMemory(p, stack, size.uint64)
|
let nswitchDescrPos = cast[ByteAddress](p) -% sizeof(NSwitchBlock)
|
||||||
virtmemFreeMap(p, size.csize)
|
let nswitchBlock = cast[PSwitchBlock](nswitchDescrPos)
|
||||||
free(stack)
|
|
||||||
|
|
||||||
proc osAllocPages(msize: int): pointer {.inline.} =
|
discard svcUnmapMemory(
|
||||||
let size = alignSize(msize)
|
nswitchBlock.heapMirror, nswitchBlock.heap, nswitchBlock.realSize.uint64
|
||||||
stack = memalign(0x1000, size)
|
)
|
||||||
result = virtmemReserveMap(size.csize)
|
virtmemFreeMap(nswitchBlock.heapMirror, nswitchBlock.realSize.csize)
|
||||||
let rc = svcMapMemory(result, stack, size.uint64)
|
free(nswitchBlock.heap)
|
||||||
|
|
||||||
|
template allocPages(size: int, outOfMemoryStmt: untyped): untyped =
|
||||||
|
let realSize = alignSize(size + sizeof(NSwitchBlock))
|
||||||
|
|
||||||
|
let heap = memalign(PageSize, realSize)
|
||||||
|
let heapMirror = virtmemReserveMap(realSize.csize)
|
||||||
|
result = heapMirror
|
||||||
|
|
||||||
|
let rc = svcMapMemory(heapMirror, heap, realSize.uint64)
|
||||||
if rc.uint32 != 0:
|
if rc.uint32 != 0:
|
||||||
freeMem(result, size)
|
discard svcUnmapMemory(heapMirror, heap, realSize.uint64)
|
||||||
|
virtmemFreeMap(heapMirror, realSize.csize)
|
||||||
|
free(heap)
|
||||||
|
outOfMemoryStmt
|
||||||
|
|
||||||
|
# What we are doing here in the following section is
|
||||||
|
# allocating memory for ourselves so that we can store
|
||||||
|
# extra data in the mapped memory (our switch pointers)
|
||||||
|
|
||||||
|
let pos = cast[int](result)
|
||||||
|
|
||||||
|
var new_pos = cast[ByteAddress](pos) +% (PageSize - (pos %% PageSize))
|
||||||
|
if (new_pos-pos) < sizeof(NSwitchBlock):
|
||||||
|
new_pos = new_pos +% PageSize
|
||||||
|
# set result to be the original size requirement
|
||||||
|
result = cast[pointer](new_pos)
|
||||||
|
|
||||||
|
let nswitchDescrPos = cast[ByteAddress](result) -% sizeof(NSwitchBlock)
|
||||||
|
|
||||||
|
# We need to store this in a pointer obj so that the data sticks
|
||||||
|
# at the address
|
||||||
|
var nswitchDescr = cast[PSwitchBlock](nswitchDescrPos)
|
||||||
|
nswitchDescr.realSize = realSize
|
||||||
|
nswitchDescr.heap = heap
|
||||||
|
nswitchDescr.heapMirror = heapMirror
|
||||||
|
|
||||||
|
|
||||||
|
proc osAllocPages(size: int): pointer {.inline.} =
|
||||||
|
allocPages(size):
|
||||||
raiseOutOfMem()
|
raiseOutOfMem()
|
||||||
|
|
||||||
proc osTryAllocPages(msize: int): pointer {.inline.} =
|
proc osTryAllocPages(size: int): pointer {.inline.} =
|
||||||
let size = alignSize(msize)
|
allocPages(size):
|
||||||
stack = memalign(0x1000, size)
|
return nil
|
||||||
result = virtmemReserveMap(size.csize)
|
|
||||||
let rc = svcMapMemory(result, stack, size.uint64)
|
|
||||||
if rc.uint32 != 0:
|
|
||||||
freeMem(result, size)
|
|
||||||
result = nil
|
|
||||||
|
|
||||||
proc osDeallocPages(p: pointer, size: int) {.inline.} =
|
proc osDeallocPages(p: pointer, size: int) {.inline.} =
|
||||||
when reallyOsDealloc:
|
when reallyOsDealloc:
|
||||||
freeMem(p, size)
|
freeMem(p)
|
||||||
|
|
||||||
elif defined(posix):
|
elif defined(posix):
|
||||||
const
|
const
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue