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:
Joey Yakimowich-Payne 2018-07-01 21:17:43 +09:00
commit d599f38f0d

View file

@ -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