Przeglądaj źródła

Merge pull request #4357 from beaumccartney/mach-vm-apis

bindings, types, and constants for some mach vm apis
Laytan 10 miesięcy temu
rodzic
commit
16eac6c844
1 zmienionych plików z 514 dodań i 18 usunięć
  1. 514 18
      core/sys/darwin/mach_darwin.odin

+ 514 - 18
core/sys/darwin/mach_darwin.odin

@@ -1,29 +1,525 @@
 package darwin
 
-foreign import pthread "system:System.framework"
+foreign import mach "system:System.framework"
 
 import "core:c"
+import "base:intrinsics"
 
-// NOTE(tetra): Unclear whether these should be aligned 16 or not.
-// However all other sync primitives are aligned for robustness.
-// I cannot currently align these though.
-// See core/sys/unix/pthread_linux.odin/pthread_t.
-task_t :: distinct u64
-semaphore_t :: distinct u64
+kern_return_t :: distinct c.int
 
-kern_return_t :: distinct u64
-thread_act_t :: distinct u64
+mach_port_t :: distinct c.uint
+vm_map_t :: mach_port_t
+mem_entry_name_port_t :: mach_port_t
+ipc_space_t :: mach_port_t
+thread_t :: mach_port_t
+task_t :: mach_port_t
+semaphore_t :: mach_port_t
+
+vm_size_t :: distinct c.uintptr_t
+
+vm_address_t :: vm_offset_t
+vm_offset_t :: distinct c.uintptr_t
+
+// NOTE(beau): typedefed to int in the original headers
+boolean_t :: b32
+
+vm_prot_t :: distinct c.int
+
+vm_inherit_t :: distinct c.uint
+
+mach_port_name_t :: distinct c.uint
+
+sync_policy_t :: distinct c.int
 
 @(default_calling_convention="c")
-foreign pthread {
-	mach_task_self :: proc() -> task_t ---
+foreign mach {
+	mach_task_self :: proc() -> mach_port_t ---
+
+	semaphore_create :: proc(task: task_t, semaphore: ^semaphore_t, policy: Sync_Policy, value: c.int) -> Kern_Return ---
+	semaphore_destroy :: proc(task: task_t, semaphore: semaphore_t) -> Kern_Return ---
+
+	semaphore_signal :: proc(semaphore: semaphore_t) -> Kern_Return ---
+	semaphore_signal_all :: proc(semaphore: semaphore_t) -> Kern_Return ---
+	semaphore_signal_thread :: proc(semaphore: semaphore_t, thread: thread_t) -> Kern_Return ---
+
+	semaphore_wait :: proc(semaphore: semaphore_t) -> Kern_Return ---
+
+	vm_allocate :: proc (target_task : vm_map_t, address: ^vm_address_t, size: vm_size_t, flags: VM_Flags) -> Kern_Return ---
+
+	vm_deallocate :: proc(target_task: vm_map_t, address: vm_address_t, size: vm_size_t) -> Kern_Return ---
+
+	vm_map :: proc(
+		target_task:    vm_map_t,
+		address:        ^vm_address_t,
+		size:           vm_size_t,
+		mask:           vm_address_t,
+		flags:          VM_Flags,
+		object:         mem_entry_name_port_t,
+		offset:         vm_offset_t,
+		copy:           boolean_t,
+		cur_protection,
+		max_protection: VM_Prot_Flags,
+		inheritance:    VM_Inherit,
+	) -> Kern_Return ---
+
+	mach_make_memory_entry :: proc(
+		target_task:   vm_map_t,
+		size:          ^vm_size_t,
+		offset:        vm_offset_t,
+		permission:    VM_Prot_Flags,
+		object_handle: ^mem_entry_name_port_t,
+		parent_entry:  mem_entry_name_port_t,
+	) -> Kern_Return ---
+
+	mach_port_deallocate :: proc(
+		task: ipc_space_t,
+		name: mach_port_name_t,
+	) -> Kern_Return ---
+
+	vm_page_size: vm_size_t
+}
+
+Kern_Return :: enum kern_return_t {
+	Success,
+
+	/* Specified address is not currently valid.
+	 */
+	Invalid_Address,
+
+	/* Specified memory is valid, but does not permit the
+	 * required forms of access.
+	 */
+	Protection_Failure,
+
+	/* The address range specified is already in use, or
+	 * no address range of the size specified could be
+	 * found.
+	 */
+	No_Space,
+
+	/* The function requested was not applicable to this
+	 * type of argument, or an argument is invalid
+	 */
+	Invalid_Argument,
+
+	/* The function could not be performed.  A catch-all.
+	 */
+	Failure,
+
+	/* A system resource could not be allocated to fulfill
+	 * this request.  This failure may not be permanent.
+	 */
+	Resource_Shortage,
+
+	/* The task in question does not hold receive rights
+	 * for the port argument.
+	 */
+	Not_Receiver,
+
+	/* Bogus access restriction.
+	 */
+	No_Access,
+
+	/* During a page fault, the target address refers to a
+	 * memory object that has been destroyed.  This
+	 * failure is permanent.
+	 */
+	Memory_Failure,
+
+	/* During a page fault, the memory object indicated
+	 * that the data could not be returned.  This failure
+	 * may be temporary; future attempts to access this
+	 * same data may succeed, as defined by the memory
+	 * object.
+	 */
+	Memory_Error,
+
+	/* The receive right is already a member of the portset.
+	 */
+	Already_In_Set,
+
+	/* The receive right is not a member of a port set.
+	 */
+	Not_In_Set,
+
+	/* The name already denotes a right in the task.
+	 */
+	Name_Exists,
+
+	/* The operation was aborted.  Ipc code will
+	 * catch this and reflect it as a message error.
+	 */
+	Aborted,
+
+	/* The name doesn't denote a right in the task.
+	 */
+	Invalid_Name,
+
+	/* Target task isn't an active task.
+	 */
+	Invalid_Task,
+
+	/* The name denotes a right, but not an appropriate right.
+	 */
+	Invalid_Right,
+
+	/* A blatant range error.
+	 */
+	Invalid_Value,
+
+	/* Operation would overflow limit on user-references.
+	 */
+	URefs_Overflow,
+
+	/* The supplied (port) capability is improper.
+	 */
+	Invalid_Capability,
+
+	/* The task already has send or receive rights
+	 * for the port under another name.
+	 */
+	Right_Exists,
+
+	/* Target host isn't actually a host.
+	 */
+	Invalid_Host,
+
+	/* An attempt was made to supply "precious" data
+	 * for memory that is already present in a
+	 * memory object.
+	 */
+	Memory_Present,
+
+	/* A page was requested of a memory manager via
+	 * memory_object_data_request for an object using
+	 * a MEMORY_OBJECT_COPY_CALL strategy, with the
+	 * VM_PROT_WANTS_COPY flag being used to specify
+	 * that the page desired is for a copy of the
+	 * object, and the memory manager has detected
+	 * the page was pushed into a copy of the object
+	 * while the kernel was walking the shadow chain
+	 * from the copy to the object. This error code
+	 * is delivered via memory_object_data_error
+	 * and is handled by the kernel (it forces the
+	 * kernel to restart the fault). It will not be
+	 * seen by users.
+	 */
+	Memory_Data_Moved,
+
+	/* A strategic copy was attempted of an object
+	 * upon which a quicker copy is now possible.
+	 * The caller should retry the copy using
+	 * vm_object_copy_quickly. This error code
+	 * is seen only by the kernel.
+	 */
+	Memory_Restart_Copy,
+
+	/* An argument applied to assert processor set privilege
+	 * was not a processor set control port.
+	 */
+	Invalid_Processor_Set,
+
+	/* The specified scheduling attributes exceed the thread's
+	 * limits.
+	 */
+	Policy_Limit,
+
+	/* The specified scheduling policy is not currently
+	 * enabled for the processor set.
+	 */
+	Invalid_Policy,
+
+	/* The external memory manager failed to initialize the
+	 * memory object.
+	 */
+	Invalid_Object,
+
+	/* A thread is attempting to wait for an event for which
+	 * there is already a waiting thread.
+	 */
+	Already_Waiting,
+
+	/* An attempt was made to destroy the default processor
+	 * set.
+	 */
+	Default_Set,
+
+	/* An attempt was made to fetch an exception port that is
+	 * protected, or to abort a thread while processing a
+	 * protected exception.
+	 */
+	Exception_Protected,
+
+	/* A ledger was required but not supplied.
+	 */
+	Invalid_Ledger,
+
+	/* The port was not a memory cache control port.
+	 */
+	Invalid_Memory_Control,
+
+	/* An argument supplied to assert security privilege
+	 * was not a host security port.
+	 */
+	Invalid_Security,
 
-	semaphore_create :: proc(task: task_t, semaphore: ^semaphore_t, policy, value: c.int) -> kern_return_t ---
-	semaphore_destroy :: proc(task: task_t, semaphore: semaphore_t) -> kern_return_t ---
+	/* thread_depress_abort was called on a thread which
+	 * was not currently depressed.
+	 */
+	Not_Depressed,
 
-	semaphore_signal :: proc(semaphore: semaphore_t) -> kern_return_t ---
-	semaphore_signal_all :: proc(semaphore: semaphore_t) -> kern_return_t ---
-	semaphore_signal_thread :: proc(semaphore: semaphore_t, thread: thread_act_t) -> kern_return_t ---
-	
-	semaphore_wait :: proc(semaphore: semaphore_t) -> kern_return_t ---
+	/* Object has been terminated and is no longer available
+	 */
+	Terminated,
+
+	/* Lock set has been destroyed and is no longer available.
+	 */
+	Lock_Set_Destroyed,
+
+	/* The thread holding the lock terminated before releasing
+	 * the lock
+	 */
+	Lock_Unstable,
+
+	/* The lock is already owned by another thread
+	 */
+	Lock_Owned,
+
+	/* The lock is already owned by the calling thread
+	 */
+	Lock_Owned_Self,
+
+	/* Semaphore has been destroyed and is no longer available.
+	 */
+	Semaphore_Destroyed,
+
+	/* Return from RPC indicating the target server was
+	 * terminated before it successfully replied
+	 */
+	Rpc_Server_Terminated,
+
+	/* Terminate an orphaned activation.
+	 */
+	RPC_Terminate_Orphan,
+
+	/* Allow an orphaned activation to continue executing.
+	 */
+	RPC_Continue_Orphan,
+
+	/* Empty thread activation (No thread linked to it)
+	 */
+	Not_Supported,
+
+	/* Remote node down or inaccessible.
+	 */
+	Node_Down,
+
+	/* A signalled thread was not actually waiting. */
+	Not_Waiting,
+
+	/* Some thread-oriented operation (semaphore_wait) timed out
+	 */
+	Operation_Timed_Out,
+
+	/* During a page fault, indicates that the page was rejected
+	 * as a result of a signature check.
+	 */
+	Codesign_Error,
+
+	/* The requested property cannot be changed at this time.
+	 */
+	Policy_Static,
+
+	/* The provided buffer is of insufficient size for the requested data.
+	 */
+	Insufficient_Buffer_Size,
+
+	/* Denied by security policy
+	 */
+	Denied,
+
+	/* The KC on which the function is operating is missing
+	 */
+	Missing_KC,
+
+	/* The KC on which the function is operating is invalid
+	 */
+	Invalid_KC,
+
+	/* A search or query operation did not return a result
+	 */
+	Not_Found,
+
+	/* Maximum return value allowable
+	 */
+	Return_Max               = 0x100,
 }
+
+/*
+ * VM allocation flags:
+ *
+ * VM_FLAGS_FIXED
+ *      (really the absence of VM_FLAGS_ANYWHERE)
+ *	Allocate new VM region at the specified virtual address, if possible.
+ *
+ * VM_FLAGS_ANYWHERE
+ *	Allocate new VM region anywhere it would fit in the address space.
+ *
+ * VM_FLAGS_PURGABLE
+ *	Create a purgable VM object for that new VM region.
+ *
+ * VM_FLAGS_4GB_CHUNK
+ *	The new VM region will be chunked up into 4GB sized pieces.
+ *
+ * VM_FLAGS_NO_PMAP_CHECK
+ *	(for DEBUG kernel config only, ignored for other configs)
+ *	Do not check that there is no stale pmap mapping for the new VM region.
+ *	This is useful for kernel memory allocations at bootstrap when building
+ *	the initial kernel address space while some memory is already in use.
+ *
+ * VM_FLAGS_OVERWRITE
+ *	The new VM region can replace existing VM regions if necessary
+ *	(to be used in combination with VM_FLAGS_FIXED).
+ *
+ * VM_FLAGS_NO_CACHE
+ *	Pages brought in to this VM region are placed on the speculative
+ *	queue instead of the active queue.  In other words, they are not
+ *	cached so that they will be stolen first if memory runs low.
+ */
+
+@(private="file")
+LOG2 :: intrinsics.constant_log2
+
+VM_Flag :: enum c.int {
+	Anywhere,
+	Purgable,
+	_4GB_Chunk,
+	Random_Addr,
+	No_Cache,
+	Resilient_Codesign,
+	Resilient_Media,
+	Permanent,
+
+	// NOTE(beau): log 2 of the bit we want in the bit set so we get that bit in
+	// the bit set
+
+	TPRO                = LOG2(0x1000),
+	Overwrite           = LOG2(0x4000),/* delete any existing mappings first */
+
+	Superpage_Size_Any  = LOG2(0x10000),
+	Superpage_Size_2MB  = LOG2(0x20000),
+	__Superpage3        = LOG2(0x40000),
+
+	Return_Data_Addr    = LOG2(0x100000),
+	Return_4K_Data_Addr = LOG2(0x800000),
+
+	Alias_Mask1         = 24,
+	Alias_Mask2,
+	Alias_Mask3,
+	Alias_Mask4,
+	Alias_Mask5,
+	Alias_Mask6,
+	Alias_Mask7,
+	Alias_Mask8,
+}
+
+VM_Flags :: distinct bit_set[VM_Flag; c.int]
+VM_FLAGS_FIXED :: VM_Flags{}
+
+/*
+ * VM_FLAGS_SUPERPAGE_MASK
+ *	3 bits that specify whether large pages should be used instead of
+ *	base pages (!=0), as well as the requested page size.
+ */
+VM_FLAGS_SUPERPAGE_MASK :: VM_Flags {
+	.Superpage_Size_Any,
+	.Superpage_Size_2MB,
+	.__Superpage3,
+}
+
+// 0xFF000000
+VM_FLAGS_ALIAS_MASK :: VM_Flags {
+	.Alias_Mask1,
+	.Alias_Mask2,
+	.Alias_Mask3,
+	.Alias_Mask4,
+	.Alias_Mask5,
+	.Alias_Mask6,
+	.Alias_Mask7,
+	.Alias_Mask8,
+}
+
+VM_GET_FLAGS_ALIAS :: proc(flags: VM_Flags) -> c.int {
+	return transmute(c.int)(flags & VM_FLAGS_ALIAS_MASK) >> 24
+}
+// NOTE(beau): no need for VM_SET_FLAGS_ALIAS, just mask in things from
+// VM_Flag.Alias_Mask*
+
+VM_FLAG_HW  :: VM_Flag.TPRO
+VM_FLAGS_HW :: VM_Flags{VM_FLAG_HW}
+
+/* These are the flags that we accept from user-space */
+VM_FLAGS_USER_ALLOCATE :: VM_Flags {
+	 .Anywhere,
+	 .Purgable,
+	 ._4GB_Chunk,
+	 .Random_Addr,
+	 .No_Cache,
+	 .Permanent,
+	 .Overwrite,
+} | VM_FLAGS_FIXED | VM_FLAGS_SUPERPAGE_MASK | VM_FLAGS_ALIAS_MASK | VM_FLAGS_HW
+
+VM_FLAGS_USER_MAP :: VM_Flags {
+	.Return_4K_Data_Addr,
+	.Return_Data_Addr,
+} | VM_FLAGS_USER_ALLOCATE
+
+VM_FLAGS_USER_REMAP :: VM_Flags {
+	.Anywhere,
+	.Random_Addr,
+	.Overwrite,
+	.Return_Data_Addr,
+	.Resilient_Codesign,
+	.Resilient_Media,
+} | VM_FLAGS_FIXED
+
+VM_FLAGS_SUPERPAGE_NONE :: VM_Flags{} /* no superpages, if all bits are 0 */
+
+/*
+ *	Protection values, defined as bits within the vm_prot_t type
+ */
+
+VM_Prot :: enum vm_prot_t {
+	Read,
+	Write,
+	Execute,
+}
+
+VM_Prot_Flags :: distinct bit_set[VM_Prot; vm_prot_t]
+
+VM_PROT_NONE    :: VM_Prot_Flags{}
+VM_PROT_DEFAULT :: VM_Prot_Flags{.Read, .Write}
+VM_PROT_ALL     :: VM_Prot_Flags{.Read, .Write, .Execute}
+
+/*
+ *	Enumeration of valid values for vm_inherit_t.
+ */
+
+VM_Inherit :: enum vm_inherit_t {
+	Share,
+	Copy,
+	None,
+	Donate_Copy,
+}
+
+VM_INHERIT_DEFAULT    :: VM_Inherit.Copy
+VM_INHERIT_LAST_VALID :: VM_Inherit.None
+
+Sync_Policy :: enum sync_policy_t {
+	Fifo,
+	Fixed_Priority,
+	Reversed,
+	Order_Mask,
+}
+
+SYNC_POLICY_LIFO :: Sync_Policy.Fifo | Sync_Policy.Reversed