From 3ab6bb86168e0f6061f32496c1d7cc5d12dab031 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Wed, 6 Mar 2024 16:45:12 -0500 Subject: [PATCH] Rolled my own virtual memory baseline interface Mostly use the core library's functionality but wanted a nicer wrap for my use case --- code/grime_virtual_memory.odin | 112 +++++++++++++++++++++++++++++++++ code/grime_vmem_windows.odin | 32 ++++++++++ 2 files changed, 144 insertions(+) create mode 100644 code/grime_virtual_memory.odin create mode 100644 code/grime_vmem_windows.odin diff --git a/code/grime_virtual_memory.odin b/code/grime_virtual_memory.odin new file mode 100644 index 0000000..bc9d415 --- /dev/null +++ b/code/grime_virtual_memory.odin @@ -0,0 +1,112 @@ +/* Virtual Memory OS Interface +This is an alternative to the virtual core library provided by odin, suppport setting the base address among other things. +*/ +package sectr + +import core_virtual "core:mem/virtual" +import "core:os" + +VirtualMemoryRegionHeader :: struct { + committed : uint, + reserved : uint, + reserve_start : [^]byte, +} + +VirtualMemoryRegion :: struct { + using base_address : ^VirtualMemoryRegionHeader +} + +virtual_get_page_size :: proc "contextless" () -> int { + @static page_size := 0 + if page_size == 0 { + page_size = os.get_page_size() + } + return page_size +} + +virtual_reserve_remaining :: proc "contextless" ( using vmem : VirtualMemoryRegion ) -> uint { + header_offset := cast(uint) (uintptr(reserve_start) - uintptr(vmem.base_address)) + return reserved - header_offset +} + +@(require_results) +virtual_commit :: proc "contextless" ( using vmem : VirtualMemoryRegion, size : uint ) -> ( alloc_error : AllocatorError ) +{ + if size < committed { + return .None + } + + page_size := uint(virtual_get_page_size()) + to_commit := memory_align_formula( size, page_size ) + + alloc_error = core_virtual.commit( base_address, to_commit ) + if alloc_error != .None { + return alloc_error + } + + base_address.committed = size + return alloc_error +} + +virtual_decommit :: proc "contextless" ( vmem : VirtualMemoryRegion, size : uint ) { + core_virtual.decommit( vmem.base_address, size ) +} + +virtual_protect :: proc "contextless" ( vmem : VirtualMemoryRegion, region : []byte, flags : VirtualProtectFlags ) -> b32 +{ + page_size := virtual_get_page_size() + + if len(region) % page_size != 0 { + return false + } + + return cast(b32) core_virtual.protect( raw_data(region), len(region), flags ) +} + +@(require_results) +virtual_reserve :: proc "contextless" ( base_address : uintptr, size : uint ) -> ( VirtualMemoryRegion, AllocatorError ) { + page_size := uint(virtual_get_page_size()) + to_reserve := memory_align_formula( size, page_size ) + return virtual__reserve( base_address, to_reserve ) +} + +@(require_results) +virtual_reserve_and_commit :: proc "contextless" ( + base_address : uintptr, reserve_size, commit_size : uint +) -> ( vmem : VirtualMemoryRegion, alloc_error : AllocatorError ) +{ + if reserve_size < commit_size { + alloc_error = .Invalid_Argument + return + } + + vmem, alloc_error = virtual_reserve( base_address, reserve_size ) + if alloc_error != .None { + return + } + + alloc_error = virtual_commit( vmem, commit_size ) + return +} + +virtual_release :: proc "contextless" ( vmem : VirtualMemoryRegion ) { + core_virtual.release( vmem.base_address, vmem.reserved ) +} + +// If the OS is not windows, we just use the library's interface which does not support base_address. +when ODIN_OS != OS_Type.Windows { + +virtual__reserve :: proc "contextless" ( base_address : uintptr, size : uint ) -> ( vmem : VirtualMemoryRegion, alloc_error : AllocatorError ) +{ + // Ignoring the base address, add an os specific impl if you want it. + data : []byte + data, alloc_error := core_virtual.reserve( size ) or_return + + vmem.base_address := cast( ^VirtualMemoryRegionHeader ) raw_data(data) + vmem.reserve_start = memory_after_header(vmem.base_address) + vmem.reserved = len(data) + vmem.committed = 0 + return +} + +} // END: ODIN_OS != runtime.Odin_OS_Type.Windows diff --git a/code/grime_vmem_windows.odin b/code/grime_vmem_windows.odin new file mode 100644 index 0000000..b16b918 --- /dev/null +++ b/code/grime_vmem_windows.odin @@ -0,0 +1,32 @@ +/* Windows Virtual Memory +Windows is the only os getting special vmem definitions +since I want full control of it for debug purposes. +*/ +package sectr + +import "core:mem/virtual" +import win32 "core:sys/windows" + +when ODIN_OS == OS_Type.Windows { + +@(require_results) +virtual__reserve :: +proc "contextless" ( base_address : uintptr, size : uint ) -> ( vmem : VirtualMemoryRegion, alloc_error : AllocatorError ) +{ + header_size :: cast(uint) size_of(VirtualMemoryRegion) + + result := win32.VirtualAlloc( rawptr(base_address), header_size + size, win32.MEM_RESERVE, win32.PAGE_READWRITE ) + if result == nil { + alloc_error = .Out_Of_Memory + return + } + + vmem.base_address = cast(^VirtualMemoryRegionHeader) result + vmem.reserve_start = memory_after_header(vmem.base_address) + vmem.reserved = size + vmem.committed = 0 + alloc_error = .None + return +} + +} // END: ODIN_OS == runtime.Odin_OS_Type.Windows