/ duct-tape / src / host.c
host.c
  1  #include <darlingserver/duct-tape/stubs.h>
  2  
  3  #include <kern/host.h>
  4  #include <mach_debug/mach_debug.h>
  5  
  6  #include <libsimple/lock.h>
  7  
  8  // Linux sysinfo (from the sysinfo man page)
  9  struct sysinfo {
 10  	long uptime;
 11  	unsigned long loads[3];
 12  	unsigned long totalram;
 13  	unsigned long freeram;
 14  	unsigned long sharedram;
 15  	unsigned long bufferram;
 16  	unsigned long totalswap;
 17  	unsigned long freeswap;
 18  	unsigned short procs;
 19  	unsigned long totalhigh;
 20  	unsigned long freehigh;
 21  	unsigned int mem_unit;
 22  	char _f[20 - 2 * sizeof(long) - sizeof(int)];
 23  };
 24  int sysinfo(struct sysinfo *info);
 25  
 26  // Linux sysconf
 27  long sysconf(int name);
 28  #define _SC_NPROCESSORS_CONF 83
 29  #define _SC_NPROCESSORS_ONLN 84
 30  
 31  static void cache_sysinfo(void* context) {
 32  	struct sysinfo* cached_sysinfo = context;
 33  
 34  	if (sysinfo(cached_sysinfo) < 0) {
 35  		panic("Failed to retrieve sysinfo");
 36  	}
 37  };
 38  
 39  kern_return_t host_info(host_t host, host_flavor_t flavor, host_info_t info, mach_msg_type_number_t* count) {
 40  	static libsimple_once_t once_token = LIBSIMPLE_ONCE_INITIALIZER;
 41  	static struct sysinfo cached_sysinfo;
 42  
 43  	if (host == HOST_NULL) {
 44  		return KERN_INVALID_ARGUMENT;
 45  	}
 46  
 47  	switch (flavor) {
 48  		case HOST_BASIC_INFO: {
 49  			host_basic_info_t basic_info = (host_basic_info_t)info;
 50  
 51  			// need at least enough space for the legacy structure
 52  			if (*count < HOST_BASIC_INFO_OLD_COUNT) {
 53  				return KERN_FAILURE;
 54  			}
 55  
 56  			libsimple_once(&once_token, cache_sysinfo, &cached_sysinfo);
 57  
 58  			uint64_t memsize = cached_sysinfo.totalram * cached_sysinfo.mem_unit;
 59  
 60  			basic_info->memory_size = memsize;
 61  #if __x86_64__ || __i386__
 62  			basic_info->cpu_type = CPU_TYPE_X86;
 63  #if __x86_64__
 64  			basic_info->cpu_subtype = CPU_SUBTYPE_X86_64_ALL;
 65  #else
 66  			basic_info->cpu_subtype = CPU_SUBTYPE_I386_ALL;
 67  #endif
 68  #else
 69  			#error Unknown CPU type
 70  #endif
 71  			basic_info->max_cpus = sysconf(_SC_NPROCESSORS_CONF);
 72  			basic_info->avail_cpus = sysconf(_SC_NPROCESSORS_ONLN);
 73  
 74  			// if there's room for the modern structure, fill in some additional info
 75  			if (*count >= HOST_BASIC_INFO_COUNT) {
 76  				// TODO: properly differentiate physical vs. logical cores
 77  				dtape_stub_safe("modern HOST_BASIC_INFO");
 78  				basic_info->cpu_threadtype = CPU_THREADTYPE_NONE;
 79  				basic_info->physical_cpu = basic_info->avail_cpus;
 80  				basic_info->physical_cpu_max = basic_info->max_cpus;
 81  				basic_info->logical_cpu = basic_info->avail_cpus;
 82  				basic_info->logical_cpu_max = basic_info->max_cpus;
 83  
 84  				basic_info->max_mem = memsize;
 85  
 86  				*count = HOST_BASIC_INFO_COUNT;
 87  			} else {
 88  				*count = HOST_BASIC_INFO_OLD_COUNT;
 89  			}
 90  
 91  			return KERN_SUCCESS;
 92  		}
 93  
 94  		case HOST_PRIORITY_INFO: {
 95  			// <copied from="xnu://7195.141.2/osfmk/kern/host.c">
 96  			host_priority_info_t priority_info;
 97  
 98  			if (*count < HOST_PRIORITY_INFO_COUNT) {
 99  				return KERN_FAILURE;
100  			}
101  
102  			priority_info = (host_priority_info_t)info;
103  
104  			priority_info->kernel_priority = MINPRI_KERNEL;
105  			priority_info->system_priority = MINPRI_KERNEL;
106  			priority_info->server_priority = MINPRI_RESERVED;
107  			priority_info->user_priority = BASEPRI_DEFAULT;
108  			priority_info->depress_priority = DEPRESSPRI;
109  			priority_info->idle_priority = IDLEPRI;
110  			priority_info->minimum_priority = MINPRI_USER;
111  			priority_info->maximum_priority = MAXPRI_RESERVED;
112  
113  			*count = HOST_PRIORITY_INFO_COUNT;
114  
115  			return KERN_SUCCESS;
116  			// </copied>
117  		}
118  
119  		case HOST_DEBUG_INFO_INTERNAL:
120  			return KERN_NOT_SUPPORTED;
121  
122  		case HOST_PREFERRED_USER_ARCH: {
123  			host_preferred_user_arch_t user_arch_info;
124  
125  			if (*count < HOST_PREFERRED_USER_ARCH_COUNT) {
126  				return KERN_FAILURE;
127  			}
128  
129  			*count = HOST_PREFERRED_USER_ARCH_COUNT;
130  
131  			user_arch_info = (void*)info;
132  
133  #if __x86_64__ || __i386__
134  			user_arch_info->cpu_type = CPU_TYPE_X86;
135  #if __x86_64__
136  			user_arch_info->cpu_subtype = CPU_SUBTYPE_X86_64_ALL;
137  #else
138  			user_arch_info->cpu_subtype = CPU_SUBTYPE_I386_ALL;
139  #endif
140  #elif __aarch64__
141  			// TODO: check whether this is actually what ARM64 macOS returns
142  			user_arch_info->cpu_type = CPU_TYPE_ARM64;
143  			user_arch_info->cpu_subtype = CPU_SUBTYPE_ARM64_ALL;
144  #else
145  			#error HOST_PREFERRED_USER_ARCH not implemented for this architecture
146  #endif
147  
148  			return KERN_SUCCESS;
149  		};
150  
151  		case HOST_SCHED_INFO:
152  			dtape_stub_unsafe("HOST_SCHED_INFO");
153  		case HOST_RESOURCE_SIZES:
154  			dtape_stub_unsafe("HOST_RESOURCE_SIZES");
155  		case HOST_CAN_HAS_DEBUGGER:
156  			dtape_stub_unsafe("HOST_CAN_HAS_DEBUGGER");
157  		case HOST_VM_PURGABLE:
158  			dtape_stub_unsafe("HOST_VM_PURGABLE");
159  
160  		case HOST_MACH_MSG_TRAP:
161  		case HOST_SEMAPHORE_TRAPS:
162  			*count = 0;
163  			return KERN_SUCCESS;
164  
165  		default:
166  			return KERN_INVALID_ARGUMENT;
167  	}
168  };
169  
170  kern_return_t host_default_memory_manager(host_priv_t host_priv, memory_object_default_t* default_manager, memory_object_cluster_size_t cluster_size) {
171  	dtape_stub_unsafe();
172  };
173  
174  kern_return_t host_get_boot_info(host_priv_t host_priv, kernel_boot_info_t boot_info) {
175  	dtape_stub_unsafe();
176  };
177  
178  kern_return_t host_get_UNDServer(host_priv_t host_priv, UNDServerRef* serverp) {
179  	dtape_stub_unsafe();
180  };
181  
182  kern_return_t host_set_UNDServer(host_priv_t host_priv, UNDServerRef server) {
183  	dtape_stub_unsafe();
184  };
185  
186  kern_return_t host_lockgroup_info(host_t host, lockgroup_info_array_t* lockgroup_infop, mach_msg_type_number_t* lockgroup_infoCntp) {
187  	dtape_stub_unsafe();
188  };
189  
190  kern_return_t host_reboot(host_priv_t host_priv, int options) {
191  	dtape_stub_unsafe();
192  };
193  
194  kern_return_t host_security_create_task_token(host_security_t host_security, task_t parent_task, security_token_t sec_token, audit_token_t audit_token, host_priv_t host_priv, ledger_port_array_t ledger_ports, mach_msg_type_number_t num_ledger_ports, boolean_t inherit_memory, task_t* child_task) {
195  	dtape_stub_safe();
196  	return KERN_NOT_SUPPORTED;
197  };
198  
199  kern_return_t host_security_set_task_token(host_security_t host_security, task_t task, security_token_t sec_token, audit_token_t audit_token, host_priv_t host_priv) {
200  	dtape_stub_unsafe();
201  };
202  
203  kern_return_t host_virtual_physical_table_info(host_t host, hash_info_bucket_array_t* infop, mach_msg_type_number_t* countp) {
204  	dtape_stub_unsafe();
205  };
206  
207  kern_return_t host_statistics(host_t host, host_flavor_t flavor, host_info_t info, mach_msg_type_number_t* count) {
208  	switch (flavor) {
209  		// we can get away with not implementing it
210  		case HOST_VM_INFO: {
211  			vm_statistics_t stat32 = (vm_statistics_t)info;
212  
213  			if (*count < HOST_VM_INFO_REV0_COUNT) {
214  				return KERN_FAILURE;
215  			}
216  
217  			dtape_stub_safe("HOST_VM_INFO");
218  			memset(stat32, 0, (*count) * sizeof(integer_t));
219  
220  			return KERN_SUCCESS;
221  		}
222  
223  		case HOST_CPU_LOAD_INFO:
224  			dtape_stub_safe("HOST_CPU_LOAD_INFO");
225  			return KERN_INVALID_ARGUMENT;
226  
227  		default:
228  			dtape_stub_unsafe();
229  	}
230  };
231  
232  kern_return_t vm_stats(void* info, unsigned int* count) {
233  	vm_statistics64_t stat = (vm_statistics64_t)info;
234  
235  	if (*count < HOST_VM_INFO64_COUNT)
236  		return (KERN_FAILURE);
237  
238  	memset(stat, 0, sizeof(*stat));
239  
240  	dtape_stub("TODO: actually fill in the values with something useful");
241  
242  	*count = HOST_VM_INFO64_COUNT;
243  
244  	return KERN_SUCCESS;
245  };