mirror of
https://github.com/odin-lang/Odin.git
synced 2026-08-24 14:01:37 +00:00
Fix syscall-based virtual memory allocation on NetBSD
This commit is contained in:
@@ -6,7 +6,6 @@ import "base:intrinsics"
|
||||
VIRTUAL_MEMORY_SUPPORTED :: true
|
||||
|
||||
SYS_munmap :: uintptr(73)
|
||||
SYS_mmap :: uintptr(197)
|
||||
SYS_mremap :: uintptr(411)
|
||||
|
||||
PROT_READ :: 0x01
|
||||
@@ -44,7 +43,7 @@ _get_superpage_size :: proc "contextless" () -> int {
|
||||
}
|
||||
|
||||
_allocate_virtual_memory :: proc "contextless" (size: int) -> rawptr {
|
||||
result, ok := intrinsics.syscall_bsd(SYS_mmap, 0, uintptr(size), PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, ~uintptr(0), 0)
|
||||
result, ok := __netbsd_sys_mmap(nil, uint(size), PROT_READ|PROT_WRITE, i32(MAP_ANONYMOUS|MAP_PRIVATE), -1, 0, 0)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
@@ -59,8 +58,11 @@ _allocate_virtual_memory_aligned :: proc "contextless" (size: int, alignment: in
|
||||
// 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 := intrinsics.count_trailing_zeros(uintptr(alignment)) << MAP_ALIGNMENT_SHIFT
|
||||
result, ok := intrinsics.syscall_bsd(SYS_mmap, 0, uintptr(size), PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE|map_aligned_n, ~uintptr(0), 0)
|
||||
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
|
||||
}
|
||||
@@ -72,19 +74,43 @@ _free_virtual_memory :: proc "contextless" (ptr: rawptr, size: int) {
|
||||
}
|
||||
|
||||
_resize_virtual_memory :: proc "contextless" (ptr: rawptr, old_size: int, new_size: int, alignment: int) -> rawptr {
|
||||
if alignment == 0 {
|
||||
// The user does not care about alignment, which is the simpler case.
|
||||
result, ok := intrinsics.syscall_bsd(SYS_mremap, uintptr(ptr), uintptr(old_size), uintptr(new_size), 0)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return rawptr(result)
|
||||
} else {
|
||||
map_aligned_n := intrinsics.count_trailing_zeros(uintptr(alignment)) << MAP_ALIGNMENT_SHIFT
|
||||
result, ok := intrinsics.syscall_bsd(SYS_mremap, uintptr(ptr), uintptr(old_size), uintptr(new_size), map_aligned_n)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
// 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)
|
||||
}
|
||||
|
||||
36
base/runtime/virtual_memory_netbsd_amd64.asm
Normal file
36
base/runtime/virtual_memory_netbsd_amd64.asm
Normal file
@@ -0,0 +1,36 @@
|
||||
bits 64
|
||||
|
||||
%define SYS_mmap 197
|
||||
|
||||
global __netbsd_sys_mmap
|
||||
|
||||
; This is a workaround for NetBSD's standard mmap syscall needing seven
|
||||
; arguments (one of which is useless). The seventh must go on the stack,
|
||||
; and our syscall intrinsics do not currently handle stack-based arguments.
|
||||
section .text
|
||||
__netbsd_sys_mmap:
|
||||
; These are the arguments for SYS_mmap.
|
||||
;
|
||||
; addr: void*
|
||||
; len: size_t
|
||||
; prot: int
|
||||
; flags: int
|
||||
; fd: int
|
||||
; PAD: long (unused)
|
||||
; pos: off_t
|
||||
|
||||
; Move the flags argument into the right register.
|
||||
mov r10, rcx
|
||||
|
||||
mov rax, SYS_mmap
|
||||
syscall
|
||||
|
||||
; Set the DL register to true if the Carry Flag is clear.
|
||||
;
|
||||
; This is where the 2nd return value will be taken from.
|
||||
;
|
||||
; This is valid for the System V AMD64 ABI, as 128-bit return
|
||||
; values may be stored in RAX:RDX.
|
||||
setnb dl
|
||||
|
||||
ret
|
||||
13
base/runtime/virtual_memory_netbsd_amd64.odin
Normal file
13
base/runtime/virtual_memory_netbsd_amd64.odin
Normal file
@@ -0,0 +1,13 @@
|
||||
#+private
|
||||
package runtime
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
foreign import netbsd_asm "virtual_memory_netbsd_amd64.asm"
|
||||
|
||||
@(private="file")
|
||||
c_long :: i32 when size_of(rawptr) == 4 else i64
|
||||
|
||||
foreign netbsd_asm {
|
||||
__netbsd_sys_mmap :: proc "c" (addr: rawptr, len: uint, prot: i32, flags: i32, fd: i32, PAD: c_long, pos: i64) -> (rawptr, bool) ---
|
||||
}
|
||||
23
base/runtime/virtual_memory_netbsd_arm64.asm
Normal file
23
base/runtime/virtual_memory_netbsd_arm64.asm
Normal file
@@ -0,0 +1,23 @@
|
||||
.set SYS_mmap, 197
|
||||
|
||||
.global __netbsd_sys_mmap
|
||||
|
||||
// This is a workaround for NetBSD's standard mmap syscall needing seven
|
||||
// arguments (one of which is useless). The seventh must go on the stack,
|
||||
// and our syscall intrinsics do not currently handle stack-based arguments.
|
||||
.section .text
|
||||
__netbsd_sys_mmap:
|
||||
// These are the arguments for SYS_mmap.
|
||||
//
|
||||
// addr: void*
|
||||
// len: size_t
|
||||
// prot: int
|
||||
// flags: int
|
||||
// fd: int
|
||||
// PAD: long (unused)
|
||||
// pos: off_t
|
||||
|
||||
mov x17, SYS_mmap
|
||||
svc #0
|
||||
|
||||
cset x1, cc
|
||||
13
base/runtime/virtual_memory_netbsd_arm64.odin
Normal file
13
base/runtime/virtual_memory_netbsd_arm64.odin
Normal file
@@ -0,0 +1,13 @@
|
||||
#+private
|
||||
package runtime
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
foreign import netbsd_asm "virtual_memory_netbsd_arm64.asm"
|
||||
|
||||
@(private="file")
|
||||
c_long :: i32 when size_of(rawptr) == 4 else i64
|
||||
|
||||
foreign netbsd_asm {
|
||||
__netbsd_sys_mmap :: proc "c" (addr: rawptr, len: uint, prot: i32, flags: i32, fd: i32, PAD: c_long, pos: i64) -> (rawptr, bool) ---
|
||||
}
|
||||
Reference in New Issue
Block a user