alloc.nim 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2017 Emery Hemingway
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. # Low level dataspace allocator for Genode.
  10. # For interacting with dataspaces outside of the
  11. # standard library see the Genode Nimble package.
  12. when not defined(genode):
  13. {.error: "Genode only module".}
  14. when not declared(GenodeEnv):
  15. import genode/env
  16. type RamDataspaceCapability {.
  17. importcpp: "Genode::Ram_dataspace_capability", pure.} = object
  18. type
  19. Map = object
  20. attachment: pointer
  21. size: int
  22. ds: RamDataspaceCapability
  23. SlabMeta = object
  24. next: ptr MapSlab
  25. ds: RamDataspaceCapability
  26. MapSlab = object
  27. meta: SlabMeta
  28. maps: array[1,Map]
  29. const SlabBackendSize = 4096
  30. proc ramAvail(env: GenodeEnv): int {.
  31. importcpp: "#->pd().avail_ram().value".}
  32. ## Return number of bytes available for allocation.
  33. proc capsAvail(env: GenodeEnv): int {.
  34. importcpp: "#->pd().avail_caps().value".}
  35. ## Return the number of available capabilities.
  36. ## Each dataspace allocation consumes a capability.
  37. proc allocDataspace(env: GenodeEnv; size: int): RamDataspaceCapability {.
  38. importcpp: "#->pd().alloc(@)".}
  39. ## Allocate a dataspace and its capability.
  40. proc attachDataspace(env: GenodeEnv; ds: RamDataspaceCapability): pointer {.
  41. importcpp: "#->rm().attach(@)".}
  42. ## Attach a dataspace into the component address-space.
  43. proc detachAddress(env: GenodeEnv; p: pointer) {.
  44. importcpp: "#->rm().detach(@)".}
  45. ## Detach a dataspace from the component address-space.
  46. proc freeDataspace(env: GenodeEnv; ds: RamDataspaceCapability) {.
  47. importcpp: "#->pd().free(@)".}
  48. ## Free a dataspace.
  49. proc newMapSlab(): ptr MapSlab =
  50. let
  51. ds = runtimeEnv.allocDataspace SlabBackendSize
  52. p = runtimeEnv.attachDataspace ds
  53. result = cast[ptr MapSlab](p)
  54. result.meta.ds = ds
  55. iterator items(s: ptr MapSlab): ptr Map =
  56. let mapCount = (SlabBackendSize - sizeof(SlabMeta)) div sizeof(Map)
  57. for i in 0 ..< mapCount:
  58. yield s.maps[i].addr
  59. var slabs: ptr MapSlab
  60. proc osAllocPages(size: int): pointer =
  61. if slabs.isNil:
  62. slabs = newMapSlab()
  63. var
  64. slab = slabs
  65. map: ptr Map
  66. let mapCount = (SlabBackendSize - sizeof(SlabMeta)) div sizeof(Map)
  67. block findFreeMap:
  68. while true:
  69. # lookup first free spot in slabs
  70. for m in slab.items:
  71. if m.attachment.isNil:
  72. map = m
  73. break findFreeMap
  74. if slab.meta.next.isNil:
  75. slab.meta.next = newMapSlab()
  76. # tack a new slab on the tail
  77. slab = slab.meta.next
  78. # move to next slab in linked list
  79. map.ds = runtimeEnv.allocDataspace size
  80. map.size = size
  81. map.attachment = runtimeEnv.attachDataspace map.ds
  82. result = map.attachment
  83. proc osTryAllocPages(size: int): pointer =
  84. if runtimeEnv.ramAvail() >= size and runtimeEnv.capsAvail() > 4:
  85. result = osAllocPages size
  86. proc osDeallocPages(p: pointer; size: int) =
  87. var slab = slabs
  88. while not slab.isNil:
  89. # lookup first free spot in slabs
  90. for m in slab.items:
  91. if m.attachment == p:
  92. if m.size != size:
  93. echo "cannot partially detach dataspace"
  94. rawQuit -1
  95. runtimeEnv.detachAddress m.attachment
  96. runtimeEnv.freeDataspace m.ds
  97. m[] = Map()
  98. return
  99. slab = slab.meta.next