aboutsummaryrefslogtreecommitdiff
path: root/core/sys/darwin
diff options
context:
space:
mode:
authorColin Davidson <colrdavidson@gmail.com>2024-11-20 15:51:08 -0800
committerColin Davidson <colrdavidson@gmail.com>2024-11-20 15:51:08 -0800
commitd60fb5a44e4d2e371562fd38947f8125b06bceb9 (patch)
tree4e924ee102c2af7b30d29017ab716ed00c51ab26 /core/sys/darwin
parentf3ab14b8ccb45d0fef8a96937635bdf0943ce7d6 (diff)
parent3229f4668dfaa5f43a374bc549f42661b002699d (diff)
update to master
Diffstat (limited to 'core/sys/darwin')
-rw-r--r--core/sys/darwin/Foundation/NSApplication.odin10
-rw-r--r--core/sys/darwin/mach_darwin.odin514
2 files changed, 510 insertions, 14 deletions
diff --git a/core/sys/darwin/Foundation/NSApplication.odin b/core/sys/darwin/Foundation/NSApplication.odin
index 7191f6d07..254da75ad 100644
--- a/core/sys/darwin/Foundation/NSApplication.odin
+++ b/core/sys/darwin/Foundation/NSApplication.odin
@@ -108,6 +108,16 @@ Application_setMainMenu :: proc "c" (self: ^Application, menu: ^Menu) {
msgSend(nil, self, "setMainMenu:", menu)
}
+@(objc_type=Application, objc_name="mainWindow")
+Application_mainWindow :: proc "c" (self: ^Application) -> ^Window {
+ return msgSend(^Window, self, "mainWindow")
+}
+
+@(objc_type=Application, objc_name="keyWindow")
+Application_keyWindow :: proc "c" (self: ^Application) -> ^Window {
+ return msgSend(^Window, self, "keyWindow")
+}
+
@(objc_type=Application, objc_name="windows")
Application_windows :: proc "c" (self: ^Application) -> ^Array {
return msgSend(^Array, self, "windows")
diff --git a/core/sys/darwin/mach_darwin.odin b/core/sys/darwin/mach_darwin.odin
index 1e728fe78..01affa6e8 100644
--- a/core/sys/darwin/mach_darwin.odin
+++ b/core/sys/darwin/mach_darwin.odin
@@ -3,17 +3,18 @@ package darwin
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.
-mach_port_t :: distinct i32
+mach_port_t :: distinct c.uint
task_t :: mach_port_t
semaphore_t :: distinct u64
-kern_return_t :: distinct u64
+kern_return_t :: distinct c.int
thread_act_t :: distinct u64
thread_state_t :: distinct ^u32
thread_list_t :: [^]thread_act_t
@@ -37,11 +38,6 @@ MACH_MSGH_BITS_COMPLEX :: 0x80000000
MACH_PORT_RIGHT_SEND :: 0
MACH_PORT_RIGHT_RECEIVE :: 1
-VM_PROT_NONE :: 0
-VM_PROT_READ :: 1
-VM_PROT_WRITE :: 2
-VM_PROT_EXECUTE :: 4
-
VM_INHERIT_SHARE :: 0
VM_INHERIT_COPY :: 1
VM_INHERIT_NONE :: 2
@@ -58,6 +54,27 @@ ARM_THREAD_STATE64 :: 6
mach_msg_option_t :: distinct i32
name_t :: distinct cstring
+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
+
+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
+
mach_msg_port_descriptor_t :: struct {
name: mach_port_t,
_: u32,
@@ -257,20 +274,489 @@ foreign mach {
task_info :: proc(task: task_t, flavor: i32, info: task_info_t, count: ^u32) -> kern_return_t ---
task_terminate :: proc(task: task_t) -> kern_return_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 ---
+
thread_get_state :: proc(thread: thread_act_t, flavor: i32, thread_state: thread_state_t, old_state_count: ^u32) -> kern_return_t ---
thread_info :: proc(thread: thread_act_t, flavor: u32, thread_info: ^thread_identifier_info, info_count: ^u32) -> kern_return_t ---
bootstrap_register2 :: proc(bp: mach_port_t, service_name: name_t, sp: mach_port_t, flags: u64) -> kern_return_t ---
bootstrap_look_up :: proc(bp: mach_port_t, service_name: name_t, sp: ^mach_port_t) -> kern_return_t ---
- 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 ---
+ 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 ---
+}
+
+
+
+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,
+
+ /* thread_depress_abort was called on a thread which
+ * was not currently depressed.
+ */
+ Not_Depressed,
+
+ /* 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,
+
+ HW = TPRO,
+}
+
+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*
+
+/* 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_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,
+
+ Default = Copy,
+ Last_Valid = None,
+}
+
+Sync_Policy :: enum sync_policy_t {
+ Fifo,
+ Fixed_Priority,
+ Reversed,
+ Order_Mask,
- 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 ---
+ Lifo = Fifo | Reversed,
}
mach_vm_trunc_page :: proc(v: u64) -> u64 {