Skip to main content

Mach Kernel Abstractions and XNU Internals

· 22 min read
Pranav Ram Joshi
Software Engineer — Systems & Networks

Man is born free, and everywhere he is in chains. - Jean-Jacques Rousseau; The Social Contract

Search for the truth is the noblest occupation of man; its publication is a duty. - Anne Louise Germaine de Staël; De l'Allemagne

Preamble: XNU and the Mach Kernel

An operating system is a set of system software that acts as a bridge between the application software and the underlying hardware. Among the various software packaged with an operating system is the kernel — a program responsible for communicating with the hardware and managing the system in its entirety. The purpose of this post is to explore the XNU kernel source and understand the core abstractions of the Mach kernel that underpin the macOS kernel architecture. We'll walk through Mach's taxonomy — tasks, threads, IPC ports, processor sets — and examine the XNU-specific implementation details, including pointer authentication and key Mach routines like task_info and mach_task_self.

The Mach Kernel

Mach is a microkernel initially released in 1985. Since then, it has been incorporated on many Operating Systems such as GNU Hurd and Apple's XNU (see [XNU_GIT]). XNU is a kernel used by Darwin Operating System which is used in macOS and iOS operating systems. One of the major difference between the Mach kernel and Linux is the fact that various kernel subsystems can be modularized. Although the definition of a monolithic and a microkernel is mostly theoretical (see [MICRO_MONO_KERN]) while most production grade kernels have started to converge the properties of both monolithic and microkernel architecture into their implementation, there are still subtle differences between Mach and monolithic kernels such as Linux.

The aim of Mach kernel was to allow Operating Systems to be built on top of Mach. As with microkernel architecture, Mach only provides a smaller subset yet fundamental functionalities such as memory management, CPU scheduling, and inter-process communication. Do note that it is the BSD layer which is responsible for providing interfaces common in Operating Systems. Figure 1 shows the OSX architecture which is an excerpt from Wikipedia: Architecture of macOS.

OS X Architecture
Figure 1: Mac OS X Architecture

Mach Kernel Abstractions in XNU

The section Mach Kernel Abstractions of [DEV_APPLE_MACH] briefly lays out the various abstractions offered by the Mach Kernel. In XNU, the structure of the said abstractions can be located. A quick browse of XNU source tree shows that there are various files and directories. Explaining all of the source is not the scope of this blog (see [MOSX_INTERNALS] and [OS_INTERNALS]), but we will try and locate the Mach-specific components of our interest. It should be known that [osfmk/] directory contains the componenets of the Mach kernel. Also, [bsd/] contains the BSD kernel components (see [BSD_ON_MACH]). Below gives the respective structure definitions of the various abstractions introduced by Mach:

  1. Mach Tasks [osfmk/kern/task.h]. A container that contains various resources required for a "process". Essential resources include: virtual address space (vm_map_t __ptrauth(...) map;) (see [XNU_PTRAUTH_SIGNED_PTR]), list of Mach threads (queue_head_t threads;), IPC space (struct ipc_port ...;), and also BSD info (struct proc_ro *bsd_info_ro;). Do note that the mentioned attributes alone does not constitute a Mach task and there exists much more attributes.

  2. Machine Independent Mach Threads [osfmk/kern/thread.h]. A kernel thread. It contains attributes such as Mach task (struct task *t_task;), read-only thread zone (struct thread_ro *t_tro;), Asynchronous System Trap (AST) pending for the thread (ast_t volatile _Atomic ast;) (see [AST_ENUM_OPT_DECL]), current kernel stack (vm_offset_t kernel_stack;), machine-dependent thread state (struct machine_thread machine;), and other attributes.

    danger

    On Figure 7-10 of [MOSX_INTERNALS], the definition of struct thread is shown. At the end, there is one field declared as:

    struct thread {
    ...
    #ifdef MACH_BSD
    void *uthread; // per-thread user structure
    #endif
    };

    However, the structure definition has changed since then. Until commit [e6231be], the uthread field was present in struct thread. However, starting from commit [e777678], there no longer exists a distinct uthread field inside the structure.

    A Mach thread also has a 1:1 relation with the user thread (but there also could exist Mach threads with no associated user threads). This means that a user thread is associated with only one Mach thread. Upon looking at the thread_create_internal function located in [osfmk/kern/thread.c], we see a line as:

    static kern_return_t
    thread_create_internal (
    task_t parent_task,
    integer_t priority,
    thread_continue_t continuation,
    void *parameter,
    thread_create_internal_options_t options,
    thread_t *out_thread)
    {
    thread_t new_thread;
    struct thread_ro tro_tpl = { };
    ...
    /*
    * Allocate a thread and initialize static fields
    */
    new_thread = zalloc_flags(thread_zone, Z_WAITOK | Z_NOFAIL);
    ...
    #ifdef MACH_BSD
    uthread_init(parent_task, get_bsdthread_info(new_thread),
    &tro_tpl, (options & (TH_OPTION_WORKQ | TH_OPTION_AIO_WORKQ)) != 0);
    if (!task_is_a_corpse(parent_task)) {
    /*
    * uthread_init will set tro_cred (with a +1)
    * and tro_proc for live tasks.
    */
    assert(tro_tpl.tro_cred && tro_tpl.tro_proc);
    }
    #endif
    ...
    }

    and (although not exactly required) the function uthread_init (in [bsd/kern/kern_fork.c]) has the signature as:

    void uthread_init (task_t task, uthread_t uth, thread_ro_t tro_tpl, int workq_thread);

    Before I explain how the user thread structure is accessed from the Mach thread, let's see the type definition of thread_t and uthread_t. On [osfmk/mach/mach_types.h], we see the two type definitions:

    ...
    #if KERNEL
    /*
    * If we are in the kernel, then pick up the kernel definitions for
    * the basic mach types.
    */
    ...
    typedef struct thread *thread_t, *thread_act_t, *thread_inspect_t, *thread_read_t;
    ...
    #endif /* KERNEL */
    ...
    /*
    * If we are not in the kernel, then these will all be represented by
    * ports at user-space.
    */
    ...
    typedef mach_port_t thread_t;
    ...

    and since we're looking at the kernel implementation, it will indeed use the struct thread definition for thread_t.

    For uthread_t, it is type defined where struct uthread is defined: [bsd/sys/user.h].

    typedef struct uthread * uthread_t;

    We'll explore the attributes of struct uthread later. For now, let's inspect the get_bsdthread_info function which apparently takes thread_t as its argument and returns a pointer to struct uthread. It is defined in [osfmk/kern/bsd_kern.c] as:

    struct uthread *
    get_bsdthread_info(thread_t th)
    {
    return (struct uthread *)((uintptr_t)th + sizeof(struct thread));
    }

    Notice that there is an offset of sizeof(struct thread) applied to the pointer to struct thread (which is essentially what th is above). This would mean that a Mach thread structure is immediately followed by the corresponding user thread structure, in terms of addressing. Consequently, this function returns an address which lies just outside of struct thread and does an explicit cast to struct uthread *.

    The reader should also be aware that previous commit of this file shows a different variation of get_bsdthread_info function. Instead of doing pointer arithmetic to fetch the address to the uthread structure, it would simply return the uthread field that was present in struct thread itself.

  3. Machine Depenedent Mach Threads [osfmk/arm/thread.h] and [osfmk/i386/thread.h]. As seen in the comment in the source, this structure (for "historical reason") is also referred to as the Process Control Block (PCB) in the i386 structure definition. I'll discuss the ARM variant here. As seen in the machine independent structure above, it embeds the machine-dependent thread structure, containing attributes such as user context (arm_context_t *contextData;) (see [MD_THREAD_CTX]), current per-CPU data (struct cpu_data *CpuDatap;), and plenty of reserved fields.

  4. BSD process [bsd/sys/proc_internal.h]. Earlier on Mach Tasks, we saw that a reference to BSD info is embedded within the structure (bsd_info_ro). I should make the reader aware that it's the read-only data associated to a task and/or process, (see [bsd/sys/proc_ro.h]). The comment above the structure definition states that the lifetime of the read-only process structure is 1:1 with that of a proc_t (which is type definition of this structure) or a task_t (again, type definition of Mach task structure). Moreover, it also states that the proc_t and task_t structures point to the same struct proc_ro structure, except for corpses. This structure contains attributes such as parent process ID (pid_t p_ppid;), process group ID (pid_t p_pgrpid;), various UNIX identifiers including user ID, group ID, real user ID, real group ID, session ID, list of processes in process group (LIST_ENTRY(proc) p_pglist;) (see [LIST_ENTRY]), open file structures (struct filedesc p_fd;), actions for signals (struct sigacts p_sigacts;) (see [PROC_SIGACTS]), and other attributes.

  5. User Threads [bsd/sys/user.h]. It is the BSD per-thread user structure. It contains various attributes, some being related to system calls (uint64_t uu_args[8]; and int uu_rval[2]), continuation attributes for some system calls, signals pending for the thread (sigset_t uu_siglist;), signal mask for the thread (sigset_t uu_sigmask;), list of user threads in [BSD] process (TAILQ_ENTRY(uthread) uu_list;) (see [TAILQ_ENTRY]), exit reason (struct os_reason *uu_exit_reason;), and other attributes.

  6. IPC Ports [osfmk/ipc/ipc_port.h].

  7. Processor Set [osfmk/kern/processor.h]. Mach divides the available processors on a system into one or more processor sets. It is a logical grouping of processors.

    caution

    Section 7.2.2 of [MOSX_INTERNALS] describes the purpose of Processor Set as:

    The original motivation behind processor sets was to group processors to allocate them to specific system activities--a coarse-grained allocation. Moreover, in early versions of Mac OS X, processor sets had associated scheduling policies and attributes, which provided a uniform control of the scheduling aspects of the threads in the set.

    When the kernel starts up, a default processor set (pset0 on XNU) is initialized. Except for the default processor set, a processor set may contain zero processor. The default processor set must contain at least one processor. Furthermore, a processor must belong to atmost one processor set at a time.

    Under Processor Management of Chapter 9 (Volume 2) of [OS_INTERNALS], the following remark could be found regarding processor set:

    Recall, that Mach allows for multiple processor sets (and processor nodes), which allows to quickly and easily scale up to Non-Uniform Memory Access (NUMA) and other distributed processing architectures. Apple, however, has neutered this in XNU, relying only on the single pset0 - returned by the mach_host subsystem's processor_set_default() Mach Interface Generator (MIG) routine. There are, at the time of writing, hints that this may finally change - at least in iOS, wherein the A-series processor's cores are asymmetric ("P"erformance cores and "E"fficiency cores), and could thus greatly benefit from a multi-set configuration.

    A more brief introduction on asymmetric as well as heterogeneous computing (which uses the notion of P and E cores described above; terminology commonly found in intel implementation) is given below (see [CORE]). Nevertheless, we notice that there is only one processor set object on the system; pset0.

    Figure 7-2 of [MOSX_INTERNALS] has the following definition of structure processor_set:

    // osfmk/kern/processor.h

    struct processor_set {
    queue_head_t idle_queue; // queue of idle processors
    int idle_count; // how many idle processors?
    queue_head_t active_queue; // queue of active processors
    queue_head_t processors; // queue of all processors
    ...
    };

    extern struct processor_set default_set;

    On the current implementation, there does not exist explicit attribute on processor set object which references to the processor object.

  8. Processor [osfmk/kern/processor.h]. A processor object is a logical representation of a physical processor. It may be a CPU, a core, or a hyperthread (see [SMT]).

Supplementary Notes

[MICRO_MONO_KERN] Despite their differences, many authors agree that the theoretical architectures often mislead the actual implementation. For example, although Linux is a monolithic kernel, subsystems like eBPF allow users to program the kernel at runtime, thereby exhibiting a property characteristic of microkernel architecture. For a deeper look at the classic BPF packet filter and its instruction set, see Berkeley Packet Filter (BPF): Packet Capture and Filtering in C. XNU--an open source kernel from Apple--can be considered as a monolithic kernel since the kernel task, a single task (with multiple threads), performs operation such as scheduling, thread reaping, callout management, paging, and UNIX exception handling. It can be considered as a monolithic kernel with different components such as Mach, BSD, and the I/O kit, all running as groups of threads in a single task in the same address space.

[BSD_ON_MACH] Although one might assume that the Mach kernel is a BSD-like kernel, this is not entirely correct. The BSD kernel found in OS X implementation is based upon FreeBSD. The Kernel Architecture Overview chapter illustrates the OS X architecture. We can observe that the BSD layer is built on top of the Mach kernel. In fact, a BSD process is one which has a corresponding Mach task assigned to it, but not all Mach task are required to have a BSD process.

[MD_THREAD_CTX] For ARM variant, the type arm_context_t is defined as typedef struct arm_context arm_context_t; and this structure inturn contains another structure member as struct arm_saved_state ss; along with another structure member for arm neon state (which we won't look into). struct arm_saved_state contains a union member as union { struct arm_saved_state32; struct arm_saved_state64; } uss;. When we look into any of the structure declared within the union, we observe that it contains information such as the array of general purpose registers, "special" registers such as the stack pointer, frame pointer, and such.

[PROC_SIGACTS] For details on the sigacts structure and how Mach exceptions are translated to UNIX signals via ux_exception.

[LIST_ENTRY] The macro used, LIST_ENTRY, is defined under [bsd/sys/queue.h] as:

#define LIST_ENTRY(type)                                                \
__MISMATCH_TAGS_PUSH \
__NULLABILITY_COMPLETENESS_PUSH \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
} \
__NULLABILITY_COMPLETENESS_POP \
__MISMATCH_TAGS_POP

Although not needed, __MISMATCH_TAGS_PUSH and __MISMATCH_TAGS_POP expands to pragma operators for C++ (and when using clang(1) compiler), else to nothing. These macros too are defined in [bsd/sys/queue.h] with definition as:

#if defined(__clang__) && defined(__cplusplus)
#define __MISMATCH_TAGS_PUSH \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wmismatched-tags\"")
#define __MISMATCH_TAGS_POP \
_Pragma("clang diagnostic pop")
#else
#define __MISMATCH_TAGS_PUSH
#define __MISMATCH_TAGS_POP
#endif

Likewise, __NULLABILITY_COMPLETENESS_PUSH and __NULLABILITY_COMPLETENESS_POP only expand to pragma when compiling with clang. It is also defined in [bsd/sys/queue.h]. The definition is as follows:

#if defined(__clang__)
#define __NULLABILITY_COMPLETENESS_PUSH \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wnullability-completeness\"")
#define __NULLABILITY_COMPLETENESS_POP \
_Pragma("clang diagnostic pop")
#else
#define __NULLABILITY_COMPLETENESS_PUSH
#define __NULLABILITY_COMPLETENESS_POP
#endif

[TAILQ_ENTRY] The macro TAILQ_ENTRY is defined in [bsd/sys/queue.h] as:

#define TRACEBUF        struct qm_trace trace;

#define TAILQ_ENTRY(type) \
__MISMATCH_TAGS_PUSH \
__NULLABILITY_COMPLETENESS_PUSH \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
TRACEBUF \
} \
__NULLABILITY_COMPLETENESS_POP \
__MISMATCH_TAGS_POP

Except for the presence of another macro: TRACEBUF, it is similar to one described in [LIST_ENTRY].

XNU Implementation Details

The implementation patterns below make extensive use of C preprocessor techniques such as conditional compilation with __has_attribute and token pasting. For a focused walkthrough of how these techniques work in Apple's API_AVAILABLE macro, see How the API_AVAILABLE Macro Works on macOS.

This section documents some of the implementation found in the XNU source tree.

1. [XNU_PTRAUTH_SIGNED_PTR] In the source, we see the field declared as:

struct task {
...
vm_map_t XNU_PTRAUTH_SIGNED_PTR("task.map") map;
...
}

The arm64e specification introduced the notion of Pointer Authentication Code. Various articles are available on the web which explains this topic. If you want to explore it, Pointer Authentication documentation from clang explains this topic in an apparent manner. Getting back, XNU_PTRAUTH_SIGNED_PTR is a macro which is defined (in [libkern/os/base.h]) as:

#if KERNEL
#if __has_feature(ptrauth_calls)
#define XNU_PTRAUTH_SIGNED_FUNCTION_PTR(type) \
__ptrauth(ptrauth_key_function_pointer, 1, ptrauth_string_discriminator(type))
#else
#define XNU_PTRAUTH_SIGNED_FUNCTION_PTR(type)
#endif
#define XNU_PTRAUTH_SIGNED_PTR OS_PTRAUTH_SIGNED_PTR
#define XNU_PTRAUTH_SIGNED_PTR_AUTH_NULL OS_PTRAUTH_SIGNED_PTR_AUTH_NULL
#endif // KERNEL

The macro OS_PTRAUTH_SIGNED_PTR is also defined under the same file, [libkern/os/base.h], as:

#if KERNEL
#if __has_feature(ptrauth_calls)
#include <ptrauth.h>
#define OS_PTRAUTH_SIGNED_PTR(type) __ptrauth(ptrauth_key_process_independent_data, 1, ptrauth_string_discriminator(type))
#define OS_PTRAUTH_SIGNED_PTR_AUTH_NULL(type) __ptrauth(ptrauth_key_process_independent_data, 1, ptrauth_string_discriminator(type), "authenticates-null-values")
#define OS_PTRAUTH_DISCRIMINATOR(str) ptrauth_string_discriminator(str)
#define __ptrauth_only
#else // __has_feature(ptrauth_calls)
#define OS_PTRAUTH_SIGNED_PTR(type)
#define OS_PTRAUTH_SIGNED_PTR_AUTH_NULL(type)
#define OS_PTRAUTH_DISCRIMINATOR(str) 0
#define __ptrauth_only __unused
#endif // __has_feature(ptrauth_calls)
#endif // KERNEL

2. [AST_ENUM_OPT_DECL] In the source, we see the field declared as: os_atomic(ast_t) ast;. os_atomic is a parameterized macro that expands conditionally. In [libkern/os/atomic.h], there are two (conditional) macro definitions for os_atomic. From what I can tell, if C++ is used, it is defined as: #define os_atomic(type) std::atomic<type> volatile, and otherwise defined as: #define os_atomic(type) type volatile _Atomic.

Besides that, ast_t is an enumerable type, defined (in [osfmk/kern/ast.h]) as:

__options_decl(ast_t, uint32_t, {
AST_PREEMPT = 0x01,
AST_QUANTUM = 0x02,
AST_URGENT = 0x04,
AST_HANDOFF = 0x08,
AST_YIELD = 0x10,
AST_APC = 0x20, /* migration APC hook */
AST_LEDGER = 0x40,
AST_BSD = 0x80,
AST_KPERF = 0x100, /* kernel profiling */
AST_MACF = 0x200, /* MACF user ret pending */
AST_RESET_PCS = 0x400, /* restartable ranges */
AST_ARCADE = 0x800, /* arcade subsciption support */
AST_MACH_EXCEPTION = 0x1000,
AST_TELEMETRY_USER = 0x2000, /* telemetry sample requested on interrupt from userspace */
AST_TELEMETRY_KERNEL = 0x4000, /* telemetry sample requested on interrupt from kernel */
AST_TELEMETRY_PMI = 0x8000, /* telemetry sample requested on PMI */
AST_SFI = 0x10000, /* Evaluate if SFI wait is needed before return to userspace */
AST_DTRACE = 0x20000,
AST_TELEMETRY_IO = 0x40000, /* telemetry sample requested for I/O */
AST_KEVENT = 0x80000,
AST_REBALANCE = 0x100000, /* thread context switched due to rebalancing */
// was AST_UNQUIESCE 0x200000
AST_PROC_RESOURCE = 0x400000, /* port space and/or file descriptor table has reached its limits */
AST_DEBUG_ASSERT = 0x800000, /* check debug assertion */
AST_TELEMETRY_MACF = 0x1000000, /* telemetry sample requested by MAC framework */
AST_SYNTHESIZE_MACH = 0x2000000,
});

where __options_decl is a parameterized macro (defined in [bsd/sys/cdefs.h]) which expands as:

#if __has_attribute(enum_extensibility)
#define __enum_open __attribute__((__enum_extensibility__(open)))
#define __enum_closed __attribute__((__enum_extensibility__(closed)))
#else
#define __enum_open
#define __enum_closed
#endif // __has_attribute(enum_extensibility)

#if __has_attribute(flag_enum)
#define __enum_options __attribute__((__flag_enum__))
#else
#define __enum_options
#endif

#define __options_decl(_name, _type, ...) \
typedef enum : _type __VA_ARGS__ __enum_open __enum_options _name
tip

The internal type used for an enumeration type is an integer. It is implementation defined whether the integer is signed or unsigned. Moreover, the width of the integer is usually that of int data type.

If we want to override the default implementation of the enumeration type (like shown above), the syntax would be:

enum : unsigned int {
FOO,
BAR,
BAZ
};

This is not defined in the C standard, but most compilers for the C language supports this extension for an enumeration type.

3. See LIST_ENTRY
4. See TAILQ_ENTRY

Mach Kernel Routines

The description of most of these routines can be found in MIT: Mach IPC Interface

  • mach_task_self: Return a send right to the caller's task_self port.

    #include <mach/mach_traps.h>

    /*
    * param: none
    *
    * return: send right to the task's kernel port.
    */
    mach_port_t
    mach_task_self (void);
    caution

    Under mach/mach_init.h file, we see the declaration of mach_task_self as:

    extern mach_port_t      mach_task_self_;
    #define mach_task_self() mach_task_self_
    #define current_task() mach_task_self()
  • task_info: Return per-task information according to specified flavor.

    #include <mach/task.h>

    /*
    * params:
    * task - The port of the task for which the information is to be returned.
    * flavor - The type of information to be returned. See below.
    * task_info - Information about the specified task.
    * task_info_count - On input, the maximum size of the buffer; on output, the size returned (in natural-sized units).
    */
    kern_return_t
    task_info ( task_t task,
    task_flavor_t flavor,
    task_info_t task_info,
    mach_msg_type_number_t task_info_count);

    The table below describes the various arguments to flavor, task_info, and task_info_count which is currently implemented in XNU (specifically [osfmk/kern/task.c]).

    flavortask_info (address of)task_info_countRemark
    TASK_BASIC_INFO_32struct task_basic_info_32 (task_basic_info_32_data_t)TASK_BASIC_INFO_32_COUNTNot preferred; use MACH_TASK_BASIC_INFO
    TASK_BASIC2_INFO_32struct task_basic_info_32 (task_basic_info_32_data_t)TASK_BASIC_INFO_32_COUNTNot preferred; BASIC2 was used to get the maximum resident size instead of current resident size
    TASK_BASIC_INFO_64struct task_basic_info_32 (task_basic_info_32_data_t)TASK_BASIC_INFO_32_COUNTNot preferred; only available on arm64 (non-arm64 described below)
    TASK_BASIC_INFO_64struct task_basic_info_64 (task_basic_info_64_data_t)TASK_BASIC_INFO_64_COUNTNot preferred; used on non-arm64 variant
    TASK_BASIC_INFO_64_2struct task_basic_info_64_2 (task_basic_info_64_2_data_t)TASK_BASIC_INFO_64_2_COUNTNot preferred; only available on arm64
    MACH_TASK_BASIC_INFOstruct mach_task_basic_info (mach_task_basic_info_data_t)MACH_TASK_BASIC_INFO_COUNT-
    TASK_THREAD_TIMES_INFOstruct task_thread_times_info (task_thread_times_info_data_t)TASK_THREAD_TIMES_INFO_COUNT-
    TASK_ABSOLUTETIME_INFOstruct task_absolutetime_info (task_absolutetime_info_data_t)TASK_ABSOLUTETIME_INFO_COUNT-
    TASK_DYLD_INFOstruct task_dyld_info (task_dyld_info_data_t)TASK_DYLD_INFO_COUNTAfter the addition of all_image_info_format field, task_info_count could be either TASK_DYLD_INFO_COUNT or the backward compatible TASK_LEGACY_DYLD_INFO_COUNT
    TASK_EXTMOD_INFOstruct task_extmod_info (task_extmod_info_data_t)TASK_EXTMOD_INFO_COUNT-
    TASK_KERNELMEMORY_INFOstruct task_kernelmemory_info (task_kernelmemory_info_data_t)TASK_KERNELMEMORY_INFO_COUNT-
    TASK_SCHED_FIFO_INFOstruct policy_fifo_base (policy_fifo_base_data_t)POLICY_FIFO_BASE_COUNTObsolete; see below
    TASK_SCHED_RR_INFOstruct policy_rr_base (policy_rr_base_data_t)POLICY_RR_BASE_COUNTObsolete; see below
    TASK_SCHED_TIMESHARE_INFOstruct policy_timeshare_base (policy_timeshare_base_data_t)POLICY_TIMESHARE_BASE_COUNTObsolete; see below
    TASK_SECURITY_TOKENsecurity_token_t (defined in mach/message.h)TASK_SECURITY_TOKEN_COUNT-
    TASK_AUDIT_TOKENaudit_token_t (defined in mach/message.h)TASK_AUDIT_TOKEN_COUNT-
    TASK_SCHED_INFO--Obsolete
    TASK_EVENTS_INFOstruct task_events_info (task_events_info_data_t)TASK_EVENTS_INFO_COUNT-
    TASK_AFFINITY_TAG_INFOstruct task_affinity_tag_info (task_affinity_tag_info_data_t)TASK_AFFINITY_TAG_INFO_COUNTOn task_info implementation of XNU, it appears to internally call task_affinity_info which is defined in [osfmk/kern/affinity.c]
    TASK_POWER_INFOstruct task_power_info (task_power_info_data_t)TASK_POWER_INFO_COUNTOn task_info implementation of XNU, it appears to internally call task_power_info_locked which is defined in [osfmk/kern/task.c]
    TASK_POWER_INFO_V2struct task_power_info_v2 (task_power_info_v2_data_t)TASK_POWER_INFO_V2_COUNT (or TASK_POWER_INFO_V2_COUNT_OLD)On task_info implementation of XNU, it only checks for TASK_POWER_INFO_V2_COUNT_OLD, and also calls task_power_info_locked
    TASK_VM_INFOstruct task_vm_info (task_vm_info_data_t)TASK_VM_INFO_COUNTThe value of task_info_count could also be TASK_VM_INFO_REV[0-7]_COUNT, where TASK_INFO_REV7_COUNT is identical to TASK_VM_INFO_COUNT. The structure definition provides additional attributes for each new revision. Some additional checks is performed on arm64 architecture on Iphones (some apps pass task_info_count as count of bytes instead of count of natural_t) ...
    TASK_VM_INFO_PURGEABLEstruct task_vm_info (task_vm_info_data_t)TASK_VM_INFO_COUNT... and if the task is a kernel task, the internal field of task_vm_info_data_t is adjusted by considering the "memory held in VM compressor". Furthermore, when TASK_VM_INFO_PURGEABLE is used, purgeable_volatile_[pmap|resident|virtual] attributes are appropriately returned. A series of checks for revision is performed and appropriate attributes are filled
    TASK_WAIT_STATE_INFOstruct task_wait_state_info (task_wait_state_info_data_t)TASK_WAIT_STATE_INFO_COUNTMarked as deprecated with further note as, "Currently allowing some results until all users stop calling it. The results may not be accurate."
    TASK_VM_INFO_PURGEABLE_ACCOUNTstruct pvm_account_info (pvm_account_info_data_t)PVM_ACCOUNT_INFO_COUNTOnly visible in developement builds (DEVELOPMENT or DEBUG symbol must be present while compiling the kernel). Returns KERN_NOT_SUPPORTED when used on production builds
    TASK_FLAGS_INFOstruct task_flags_info (task_flags_info_data_t)TASK_FLAGS_INFO_COUNT-
    TASK_DEBUG_INFO_INTERNALstruct task_debug_info_internal (task_debug_info_internal_data_t)TASK_DEBUG_INFO_INTERNAL_COUNTOnly visible in developement builds (DEVELOPMENT or DEBUG symbol must be present while compiling the kernel). Returns KERN_NOT_SUPPORTED when used on production builds
    TASK_SUSPEND_STATS_INFOstruct task_suspend_stats_s (task_suspend_stats_data_t)TASK_SUSPEND_STATS_INFO_COUNTRequires CONFIG_TASK_SUSPEND_STATS symbol to be present along with either of debug symbol (DEVELOPMENT or DEBUG) when compiling the kernel to support this flavor. Returns KERN_NOT_SUPPORTED when used on production builds
    TASK_SUSPEND_SOURCES_INFOstruct task_suspend_source_s (task_suspend_source_data_t)TASK_SUSPEND_SOURCES_INFO_COUNTRequires CONFIG_TASK_SUSPEND_STATS symbol to be present along with either of debug symbol (DEVELOPMENT or DEBUG) when compiling the kernel to support this flavor. Returns KERN_NOT_SUPPORTED when used on production builds
    TASK_SECURITY_CONFIG_INFOstruct task_security_config_infoTASK_SECURITY_CONFIG_INFO_COUNT-
    TASK_IPC_SPACE_POLICY_INFOstruct task_ipc_space_policy_infoTASK_IPC_SPACE_POLICY_INFO_COUNT-
    danger

    Regarding TASK_SCHED_FIFO_INFO, TASK_SCHED_RR_INFO, and TASK_SCHED_TIMESHARE_INFO, until commit [c1dac77], XNU provided appropriate task_info handling capability. However, starting commit [8149afc], support for TASK_SCHED_FIFO_INFO was removed. Although capability for TASK_SCHED_RR_INFO and TASK_SCHED_TIMESHARE_INFO still exist, commit [14e3d83] marked them as obsolete.

References

[DEV_APPLE_MACH] https://developer.apple.com/library/archive/documentation/Darwin/Conceptual/KernelProgramming/Mach/Mach.html

[APUE] Stevens, W.R., & Rago. S.A. (2013). Advanced Programming in Unix Environment.

[MOS] Tanenbaum, A.S., & Bos H. (2014). Modern Operating Systems.

[MOSX_INTERNALS] Singh, A (2007). Mac OS X Internals: A Systems Approach.

[OS_INTERNALS] Levin, J (2016, 2017, 2019) MacOS and iOS Internals Trilogy. https://www.newosxbook.com/index.php

[INTEL_HVHCE] https://www.intel.com/content/www/us/en/docs/sycl/introduction/latest/01-homogeneous-vs-heterogeneous.html

[XNU_GIT] https://github.com/apple-oss-distributions/xnu

[Draves 91] http://staff.ustc.edu.cn/~bjhua/courses/ats/2014/ref/draves91continuations.pdf

[COMMIT] f6217f891ac0bb64f3d375211650a4c1ff8ca1ea