2
0

virtual_windows.odin 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. #+build windows
  2. #+private
  3. package mem_virtual
  4. foreign import Kernel32 "system:Kernel32.lib"
  5. LPSYSTEM_INFO :: ^SYSTEM_INFO
  6. SYSTEM_INFO :: struct {
  7. using DUMMYUNIONNAME: struct #raw_union {
  8. dwOemId: u32,
  9. using DUMMYSTRUCTNAME:struct {
  10. wProcessorArchitecture: u16,
  11. wReserved: u16,
  12. },
  13. },
  14. dwPageSize: u32,
  15. lpMinimumApplicationAddress: rawptr,
  16. lpMaximumApplicationAddress: rawptr,
  17. dwActiveProcessorMask: uint,
  18. dwNumberOfProcessors: u32,
  19. dwProcessorType: u32,
  20. dwAllocationGranularity: u32,
  21. wProcessorLevel: u16,
  22. wProcessorRevision: u16,
  23. }
  24. MEM_COMMIT :: 0x00001000
  25. MEM_RESERVE :: 0x00002000
  26. MEM_RESET :: 0x00080000
  27. MEM_RESET_UNDO :: 0x01000000
  28. MEM_LARGE_PAGES :: 0x20000000
  29. MEM_PHYSICAL :: 0x00400000
  30. MEM_TOP_DOWN :: 0x00100000
  31. MEM_WRITE_WATCH :: 0x00200000
  32. MEM_DECOMMIT :: 0x00004000
  33. MEM_RELEASE :: 0x00008000
  34. MEM_COALESCE_PLACEHOLDERS :: 0x00000001
  35. MEM_PRESERVE_PLACEHOLDER :: 0x00000002
  36. PAGE_EXECUTE :: 0x10
  37. PAGE_EXECUTE_READ :: 0x20
  38. PAGE_EXECUTE_READWRITE :: 0x40
  39. PAGE_EXECUTE_WRITECOPY :: 0x80
  40. PAGE_NOACCESS :: 0x01
  41. PAGE_READONLY :: 0x02
  42. PAGE_READWRITE :: 0x04
  43. PAGE_WRITECOPY :: 0x08
  44. PAGE_TARGETS_INVALID :: 0x40000000
  45. PAGE_TARGETS_NO_UPDATE :: 0x40000000
  46. SECTION_MAP_WRITE :: 0x0002
  47. SECTION_MAP_READ :: 0x0004
  48. FILE_MAP_WRITE :: SECTION_MAP_WRITE
  49. FILE_MAP_READ :: SECTION_MAP_READ
  50. ERROR_INVALID_ADDRESS :: 487
  51. ERROR_COMMITMENT_LIMIT :: 1455
  52. @(default_calling_convention="system")
  53. foreign Kernel32 {
  54. GetSystemInfo :: proc(lpSystemInfo: LPSYSTEM_INFO) ---
  55. VirtualAlloc :: proc(lpAddress: rawptr, dwSize: uint, flAllocationType: u32, flProtect: u32) -> rawptr ---
  56. VirtualFree :: proc(lpAddress: rawptr, dwSize: uint, dwFreeType: u32) -> b32 ---
  57. VirtualProtect :: proc(lpAddress: rawptr, dwSize: uint, flNewProtect: u32, lpflOldProtect: ^u32) -> b32 ---
  58. GetLastError :: proc() -> u32 ---
  59. CreateFileMappingW :: proc(
  60. hFile: rawptr,
  61. lpFileMappingAttributes: rawptr,
  62. flProtect: u32,
  63. dwMaximumSizeHigh: u32,
  64. dwMaximumSizeLow: u32,
  65. lpName: [^]u16,
  66. ) -> rawptr ---
  67. MapViewOfFile :: proc(
  68. hFileMappingObject: rawptr,
  69. dwDesiredAccess: u32,
  70. dwFileOffsetHigh: u32,
  71. dwFileOffsetLow: u32,
  72. dwNumberOfBytesToMap: uint,
  73. ) -> rawptr ---
  74. }
  75. _reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
  76. result := VirtualAlloc(nil, size, MEM_RESERVE, PAGE_READWRITE)
  77. if result == nil {
  78. err = .Out_Of_Memory
  79. return
  80. }
  81. data = ([^]byte)(result)[:size]
  82. return
  83. }
  84. _commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
  85. result := VirtualAlloc(data, size, MEM_COMMIT, PAGE_READWRITE)
  86. if result == nil {
  87. switch err := GetLastError(); err {
  88. case 0:
  89. return .Invalid_Argument
  90. case ERROR_INVALID_ADDRESS, ERROR_COMMITMENT_LIMIT:
  91. return .Out_Of_Memory
  92. }
  93. return .Out_Of_Memory
  94. }
  95. return nil
  96. }
  97. _decommit :: proc "contextless" (data: rawptr, size: uint) {
  98. VirtualFree(data, size, MEM_DECOMMIT)
  99. }
  100. _release :: proc "contextless" (data: rawptr, size: uint) {
  101. VirtualFree(data, 0, MEM_RELEASE)
  102. }
  103. _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) -> bool {
  104. pflags: u32
  105. pflags = PAGE_NOACCESS
  106. switch flags {
  107. case {}: pflags = PAGE_NOACCESS
  108. case {.Read}: pflags = PAGE_READONLY
  109. case {.Read, .Write}: pflags = PAGE_READWRITE
  110. case {.Write}: pflags = PAGE_WRITECOPY
  111. case {.Execute}: pflags = PAGE_EXECUTE
  112. case {.Execute, .Read}: pflags = PAGE_EXECUTE_READ
  113. case {.Execute, .Read, .Write}: pflags = PAGE_EXECUTE_READWRITE
  114. case {.Execute, .Write}: pflags = PAGE_EXECUTE_WRITECOPY
  115. case:
  116. return false
  117. }
  118. old_protect: u32
  119. ok := VirtualProtect(data, size, pflags, &old_protect)
  120. return bool(ok)
  121. }
  122. _platform_memory_init :: proc() {
  123. sys_info: SYSTEM_INFO
  124. GetSystemInfo(&sys_info)
  125. DEFAULT_PAGE_SIZE = max(DEFAULT_PAGE_SIZE, uint(sys_info.dwPageSize))
  126. // is power of two
  127. assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
  128. }
  129. _map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) {
  130. page_flags: u32
  131. if flags == {.Read} {
  132. page_flags = PAGE_READONLY
  133. } else if flags == {.Write} {
  134. page_flags = PAGE_READWRITE
  135. } else if flags == {.Read, .Write} {
  136. page_flags = PAGE_READWRITE
  137. } else {
  138. page_flags = PAGE_NOACCESS
  139. }
  140. maximum_size := transmute([2]u32)size
  141. handle := CreateFileMappingW(rawptr(fd), nil, page_flags, maximum_size[1], maximum_size[0], nil)
  142. if handle == nil {
  143. return nil, .Map_Failure
  144. }
  145. desired_access: u32
  146. if .Read in flags {
  147. desired_access |= FILE_MAP_READ
  148. }
  149. if .Write in flags {
  150. desired_access |= FILE_MAP_WRITE
  151. }
  152. file_data := MapViewOfFile(handle, desired_access, 0, 0, uint(size))
  153. return ([^]byte)(file_data)[:size], nil
  154. }