mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
120 lines
3.2 KiB
Nim
120 lines
3.2 KiB
Nim
#
|
|
#
|
|
# Nim's Runtime Library
|
|
# (c) Copyright 2017 Emery Hemingway
|
|
#
|
|
# See the file "copying.txt", included in this
|
|
# distribution, for details about the copyright.
|
|
#
|
|
|
|
# Low level dataspace allocator for Genode.
|
|
# For interacting with dataspaces outside of the
|
|
# standard library see the Genode Nimble package.
|
|
|
|
when not defined(genode):
|
|
{.error: "Genode only module".}
|
|
|
|
when not declared(GenodeEnv):
|
|
include genode/env
|
|
|
|
type DataspaceCapability {.
|
|
importcpp: "Genode::Dataspace_capability", pure.} = object
|
|
|
|
type
|
|
Map = object
|
|
attachment: pointer
|
|
size: int
|
|
ds: DataspaceCapability
|
|
|
|
SlabMeta = object
|
|
next: ptr MapSlab
|
|
ds: DataspaceCapability
|
|
|
|
MapSlab = object
|
|
meta: SlabMeta
|
|
maps: array[1,Map]
|
|
|
|
const SlabBackendSize = 4096
|
|
|
|
proc ramAvail(env: GenodeEnv): int {.
|
|
importcpp: "#->pd().avail_ram().value".}
|
|
## Return number of bytes available for allocation.
|
|
|
|
proc capsAvail(env: GenodeEnv): int {.
|
|
importcpp: "#->pd().avail_caps().value".}
|
|
## Return the number of available capabilities.
|
|
## Each dataspace allocation consumes a capability.
|
|
|
|
proc allocDataspace(env: GenodeEnv; size: int): DataspaceCapability {.
|
|
importcpp: "#->pd().alloc(@)".}
|
|
## Allocate a dataspace and its capability.
|
|
|
|
proc attachDataspace(env: GenodeEnv; ds: DataspaceCapability): pointer {.
|
|
importcpp: "#->rm().attach(@)".}
|
|
## Attach a dataspace into the component address-space.
|
|
|
|
proc detachAddress(env: GenodeEnv; p: pointer) {.
|
|
importcpp: "#->rm().detach(@)".}
|
|
## Detach a dataspace from the component address-space.
|
|
|
|
proc freeDataspace(env: GenodeEnv; ds: DataspaceCapability) {.
|
|
importcpp: "#->pd().free(@)".}
|
|
## Free a dataspace.
|
|
|
|
proc newMapSlab(): ptr MapSlab =
|
|
let
|
|
ds = runtimeEnv.allocDataspace SlabBackendSize
|
|
p = runtimeEnv.attachDataspace ds
|
|
result = cast[ptr MapSlab](p)
|
|
result.meta.ds = ds
|
|
|
|
iterator items(s: ptr MapSlab): ptr Map =
|
|
let mapCount = (SlabBackendSize - sizeof(SlabMeta)) div sizeof(Map)
|
|
for i in 0 ..< mapCount:
|
|
yield s.maps[i].addr
|
|
|
|
var slabs: ptr MapSlab
|
|
|
|
proc osAllocPages(size: int): pointer =
|
|
if slabs.isNil:
|
|
slabs = newMapSlab()
|
|
var
|
|
slab = slabs
|
|
map: ptr Map
|
|
let mapCount = (SlabBackendSize - sizeof(SlabMeta)) div sizeof(Map)
|
|
block findFreeMap:
|
|
while true:
|
|
# lookup first free spot in slabs
|
|
for m in slab.items:
|
|
if m.attachment.isNil:
|
|
map = m
|
|
break findFreeMap
|
|
if slab.meta.next.isNil:
|
|
slab.meta.next = newMapSlab()
|
|
# tack a new slab on the tail
|
|
slab = slab.meta.next
|
|
# move to next slab in linked list
|
|
map.ds = runtimeEnv.allocDataspace size
|
|
map.size = size
|
|
map.attachment = runtimeEnv.attachDataspace map.ds
|
|
result = map.attachment
|
|
|
|
proc osTryAllocPages(size: int): pointer =
|
|
if runtimeEnv.ramAvail() >= size and runtimeEnv.capsAvail() > 4:
|
|
result = osAllocPages size
|
|
|
|
proc osDeallocPages(p: pointer; size: int) =
|
|
var slab = slabs
|
|
while not slab.isNil:
|
|
# lookup first free spot in slabs
|
|
for m in slab.items:
|
|
if m.attachment == p:
|
|
if m.size != size:
|
|
echo "cannot partially detach dataspace"
|
|
quit -1
|
|
runtimeEnv.detachAddress m.attachment
|
|
runtimeEnv.freeDataspace m.ds
|
|
m[] = Map()
|
|
return
|
|
slab = slab.meta.next
|