+/*
+ * The default percentage of memory that can be mlocked is scaled based on the total
+ * amount of memory in the system. These percentages are caclulated
+ * offline and stored in this table. We index this table by
+ * log2(max_mem) - VM_USER_WIREABLE_MIN_CONFIG. We clamp this index in the range
+ * [0, sizeof(wire_limit_percents) / sizeof(vm_map_size_t))
+ *
+ * Note that these values were picked for mac.
+ * If we ever have very large memory config arm devices, we may want to revisit
+ * since the kernel overhead is smaller there due to the larger page size.
+ */
+
+/* Start scaling iff we're managing > 2^32 = 4GB of RAM. */
+#define VM_USER_WIREABLE_MIN_CONFIG 32
+static vm_map_size_t wire_limit_percents[] =
+{ 70, 73, 76, 79, 82, 85, 88, 91, 94, 97};
+
+/*
+ * Sets the default global user wire limit which limits the amount of
+ * memory that can be locked via mlock() based on the above algorithm..
+ * This can be overridden via a sysctl.
+ */
+static void
+kmem_set_user_wire_limits(void)
+{
+ uint64_t available_mem_log;
+ uint64_t max_wire_percent;
+ size_t wire_limit_percents_length = sizeof(wire_limit_percents) /
+ sizeof(vm_map_size_t);
+ vm_map_size_t limit;
+ uint64_t config_memsize = max_mem;
+#if defined(XNU_TARGET_OS_OSX)
+ config_memsize = max_mem_actual;
+#endif /* defined(XNU_TARGET_OS_OSX) */
+
+ available_mem_log = bit_floor(config_memsize);
+
+ if (available_mem_log < VM_USER_WIREABLE_MIN_CONFIG) {
+ available_mem_log = 0;
+ } else {
+ available_mem_log -= VM_USER_WIREABLE_MIN_CONFIG;
+ }
+ if (available_mem_log >= wire_limit_percents_length) {
+ available_mem_log = wire_limit_percents_length - 1;
+ }
+ max_wire_percent = wire_limit_percents[available_mem_log];
+
+ limit = config_memsize * max_wire_percent / 100;
+ /* Cap the number of non lockable bytes at VM_NOT_USER_WIREABLE_MAX */
+ if (config_memsize - limit > VM_NOT_USER_WIREABLE_MAX) {
+ limit = config_memsize - VM_NOT_USER_WIREABLE_MAX;
+ }
+
+ vm_global_user_wire_limit = limit;
+ /* the default per task limit is the same as the global limit */
+ vm_per_task_user_wire_limit = limit;
+ vm_add_wire_count_over_global_limit = 0;
+ vm_add_wire_count_over_user_limit = 0;
+}
+