summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Kelly <mike@weatherwax.co.uk>2025-08-31 23:21:54 +0200
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2025-08-31 23:21:54 +0200
commitfdfca0e86009c5a7b188fa39e939de800a73391d (patch)
treed590b5ebe43d1ed21fd5dbae75240031e99b34a8
parenteec7037c885f6e54bf8f22d421d6abc55a2cd667 (diff)
Add mach_port_set_ktype RPC to set ktype of a user port
For now, we only allow a newly-introduced MACH_PORT_KTYPE_USER_DEVICE type that makes ipc_kmsg_copyin_body use page lists, which keep them in a busy state that prevents them from being paged out.
-rw-r--r--include/mach/mach_port.defs18
-rw-r--r--include/mach/port.h6
-rw-r--r--ipc/ipc_object.c1
-rw-r--r--ipc/mach_port.c39
-rw-r--r--kern/ipc_kobject.h9
5 files changed, 70 insertions, 3 deletions
diff --git a/include/mach/mach_port.defs b/include/mach/mach_port.defs
index 3823bb14..3f2aed14 100644
--- a/include/mach/mach_port.defs
+++ b/include/mach/mach_port.defs
@@ -358,3 +358,21 @@ routine mach_port_set_protected_payload(
routine mach_port_clear_protected_payload(
task : ipc_space_t;
name : mach_port_name_t);
+
+/*
+ * Set the kernel port type for specific kernel behaviour.
+ * ktype must be one of:
+ * MACH_PORT_KTYPE_NONE
+ * MACH_PORT_KTYPE_USER_DEVICE
+ * The named port must not be currently associated with any
+ * other kernel port type.
+ */
+
+type mach_port_ktype_t = unsigned;
+
+routine mach_port_set_ktype(
+ host : host_priv_t;
+ task : ipc_space_t;
+ name : mach_port_name_t;
+ right : mach_port_right_t;
+ ktype : mach_port_ktype_t);
diff --git a/include/mach/port.h b/include/mach/port.h
index c9bbcf17..488d2c9e 100644
--- a/include/mach/port.h
+++ b/include/mach/port.h
@@ -156,4 +156,10 @@ typedef struct mach_port_status {
#define MACH_PORT_QLIMIT_DEFAULT ((mach_port_msgcount_t) 5)
#define MACH_PORT_QLIMIT_MAX ((mach_port_msgcount_t) 16)
+typedef unsigned int mach_port_ktype_t;
+
+/* Constants for calls to mach_port_set_ktype() */
+#define MACH_PORT_KTYPE_NONE 0
+#define MACH_PORT_KTYPE_USER_DEVICE 28
+
#endif /* _MACH_PORT_H_ */
diff --git a/ipc/ipc_object.c b/ipc/ipc_object.c
index 1074fb2c..d6c332e6 100644
--- a/ipc/ipc_object.c
+++ b/ipc/ipc_object.c
@@ -944,6 +944,7 @@ char *ikot_print_array[IKOT_MAX_TYPE] = {
"(CLOCK) ",
"(CLOCK_CTRL) ",
"(PAGER_PROXY) ", /* 27 */
+ "(USER_DEVICE) ", /* 28 */
/* << new entries here */
"(UNKNOWN) " /* magic catchall */
}; /* Please keep in sync with kern/ipc_kobject.h */
diff --git a/ipc/mach_port.c b/ipc/mach_port.c
index d8696e23..eed3e725 100644
--- a/ipc/mach_port.c
+++ b/ipc/mach_port.c
@@ -1567,6 +1567,45 @@ mach_port_clear_protected_payload(
return KERN_SUCCESS;
}
+kern_return_t
+mach_port_set_ktype(
+ host_t host_priv,
+ ipc_space_t space,
+ mach_port_name_t name,
+ mach_port_right_t right,
+ mach_port_ktype_t ktype)
+{
+ ipc_port_t port;
+ kern_return_t kr;
+
+ if (host_priv == HOST_NULL)
+ return KERN_INVALID_HOST;
+
+ if (space == IS_NULL)
+ return KERN_INVALID_TASK;
+
+ if (ktype != MACH_PORT_KTYPE_NONE
+ && ktype != MACH_PORT_KTYPE_USER_DEVICE)
+ return KERN_INVALID_ARGUMENT;
+
+ kr = ipc_object_translate(space, name, right, (ipc_object_t *)&port);
+ if (kr != KERN_SUCCESS)
+ return kr;
+
+ /* port is locked and active */
+ if (ip_kotype(port) == IKOT_NONE || ip_kotype(port) == IKOT_USER_DEVICE)
+ ipc_kobject_set(port, IKO_NULL,
+ ktype == MACH_PORT_KTYPE_NONE
+ ? IKOT_NONE
+ : IKOT_USER_DEVICE);
+ else
+ kr = KERN_INVALID_ARGUMENT;
+
+ ip_unlock(port);
+
+ return kr;
+}
+
#if MACH_KDB
void
diff --git a/kern/ipc_kobject.h b/kern/ipc_kobject.h
index 606a66a9..63ad87c5 100644
--- a/kern/ipc_kobject.h
+++ b/kern/ipc_kobject.h
@@ -77,9 +77,10 @@ typedef unsigned int ipc_kobject_type_t;
#define IKOT_CLOCK 25
#define IKOT_CLOCK_CTRL 26
#define IKOT_PAGER_PROXY 27
+#define IKOT_USER_DEVICE 28
/* << new entries here */
-#define IKOT_UNKNOWN 28 /* magic catchall */
-#define IKOT_MAX_TYPE 29 /* # of IKOT_ types */
+#define IKOT_UNKNOWN 29 /* magic catchall */
+#define IKOT_MAX_TYPE 30 /* # of IKOT_ types */
/* Please keep ipc/ipc_object.c:ikot_print_array up to date */
#define is_ipc_kobject(ikot) (ikot != IKOT_NONE)
@@ -90,7 +91,9 @@ typedef unsigned int ipc_kobject_type_t;
*/
#define ipc_kobject_vm_page_list(ikot) \
- ((ikot == IKOT_PAGING_REQUEST) || (ikot == IKOT_DEVICE))
+ ((ikot == IKOT_PAGING_REQUEST) || \
+ (ikot == IKOT_DEVICE) || \
+ (ikot == IKOT_USER_DEVICE))
#define ipc_kobject_vm_page_steal(ikot) (ikot == IKOT_PAGING_REQUEST)