mirror of
https://github.com/odin-lang/Odin.git
synced 2026-07-31 02:07:40 -04:00
117 lines
3.3 KiB
Odin
117 lines
3.3 KiB
Odin
#+private
|
|
package runtime
|
|
|
|
import "base:intrinsics"
|
|
|
|
VIRTUAL_MEMORY_SUPPORTED :: true
|
|
|
|
SYS_munmap :: uintptr(73)
|
|
SYS_mremap :: uintptr(411)
|
|
|
|
PROT_READ :: 0x01
|
|
PROT_WRITE :: 0x02
|
|
|
|
MAP_PRIVATE :: 0x0002
|
|
MAP_ANONYMOUS :: 0x1000
|
|
|
|
// The following features are specific to NetBSD only.
|
|
/*
|
|
* Alignment (expressed in log2). Must be >= log2(PAGE_SIZE) and
|
|
* < # bits in a pointer (32 or 64).
|
|
*/
|
|
// #define MAP_ALIGNED(n) ((int)((unsigned int)(n) << MAP_ALIGNMENT_SHIFT))
|
|
MAP_ALIGNMENT_SHIFT :: 24
|
|
|
|
_init_virtual_memory :: proc "contextless" () {
|
|
page_size = _get_page_size()
|
|
}
|
|
|
|
_get_page_size :: proc "contextless" () -> int {
|
|
// This is a fallback value if the auxiliary vector does not supply it.
|
|
DEFAULT_PAGE_SIZE :: 4096
|
|
|
|
if value, found := _get_auxiliary(.AT_PAGESZ); found {
|
|
return int(value.a_val)
|
|
} else {
|
|
return DEFAULT_PAGE_SIZE
|
|
}
|
|
}
|
|
|
|
_get_superpage_size :: proc "contextless" () -> int {
|
|
// NOTE(Feoramund): I am uncertain if NetBSD has direct support for superpages.
|
|
return 0
|
|
}
|
|
|
|
_allocate_virtual_memory :: proc "contextless" (size: int) -> rawptr {
|
|
result, ok := __netbsd_sys_mmap(nil, uint(size), PROT_READ|PROT_WRITE, i32(MAP_ANONYMOUS|MAP_PRIVATE), -1, 0, 0)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return rawptr(result)
|
|
}
|
|
|
|
_allocate_virtual_memory_superpage :: proc "contextless" () -> rawptr {
|
|
return nil
|
|
}
|
|
|
|
_allocate_virtual_memory_aligned :: proc "contextless" (size: int, alignment: int) -> rawptr {
|
|
// NOTE: Unlike FreeBSD, the NetBSD man pages do not indicate that
|
|
// `MAP_ALIGNED` can cause this to fail, so we don't try a second time with
|
|
// manual alignment.
|
|
map_aligned_n: u32
|
|
if alignment > page_size {
|
|
map_aligned_n = u32(intrinsics.count_trailing_zeros(uintptr(alignment)) << MAP_ALIGNMENT_SHIFT)
|
|
}
|
|
result, ok := __netbsd_sys_mmap(nil, uint(size), PROT_READ|PROT_WRITE, i32(MAP_ANONYMOUS|MAP_PRIVATE|map_aligned_n), -1, 0, 0)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return rawptr(result)
|
|
}
|
|
|
|
_free_virtual_memory :: proc "contextless" (ptr: rawptr, size: int) {
|
|
intrinsics.syscall_bsd(SYS_munmap, uintptr(ptr), uintptr(size))
|
|
}
|
|
|
|
_resize_virtual_memory :: proc "contextless" (ptr: rawptr, old_size: int, new_size: int, alignment: int) -> rawptr {
|
|
// NetBSD will not abide by `new_size` and `old_size` not being a multiple
|
|
// of the page size when remapping.
|
|
old_size_in_pages := old_size / page_size
|
|
if old_size % page_size != 0 {
|
|
old_size_in_pages += 1
|
|
}
|
|
new_size_in_pages := new_size / page_size
|
|
if new_size % page_size != 0 {
|
|
new_size_in_pages += 1
|
|
}
|
|
old_size_rounded := old_size_in_pages * page_size
|
|
new_size_rounded := new_size_in_pages * page_size
|
|
|
|
flags := uintptr(0)
|
|
if alignment > page_size {
|
|
flags = intrinsics.count_trailing_zeros(uintptr(alignment)) << MAP_ALIGNMENT_SHIFT
|
|
}
|
|
|
|
if result, ok := intrinsics.syscall_bsd(SYS_mremap, uintptr(ptr), uintptr(old_size_rounded), uintptr(new_size_rounded), 0, flags); ok {
|
|
return rawptr(result)
|
|
}
|
|
|
|
// It may not have been possible to extend the old address space.
|
|
// Try to allocate a new mapping and copy the old data.
|
|
new_ptr: rawptr
|
|
if alignment > page_size {
|
|
new_ptr = _allocate_virtual_memory_aligned(new_size, alignment)
|
|
} else {
|
|
new_ptr = _allocate_virtual_memory(new_size)
|
|
}
|
|
|
|
if new_ptr == nil {
|
|
// Memory allocation failed.
|
|
return nil
|
|
}
|
|
|
|
intrinsics.mem_copy_non_overlapping(new_ptr, ptr, min(old_size, new_size))
|
|
_free_virtual_memory(ptr, old_size)
|
|
return rawptr(new_ptr)
|
|
}
|