xref: /xnu-12377.61.12/osfmk/kern/exclaves_sensor.c (revision 4d495c6e23c53686cf65f45067f79024cf5dcee8) !
1 /*
2  * Copyright (c) 2023 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 #include <stdint.h>
30 #include <mach/exclaves.h>
31 #include <mach/kern_return.h>
32 #include <libkern/coreanalytics/coreanalytics.h>
33 
34 #include "exclaves_boot.h"
35 #include "exclaves_debug.h"
36 #include "exclaves_resource.h"
37 #include "exclaves_sensor.h"
38 
39 #if CONFIG_EXCLAVES
40 
41 #include <kern/locks.h>
42 #include <kern/thread.h>
43 #include <kern/thread_call.h>
44 
45 #include "kern/exclaves.tightbeam.h"
46 
47 
48 /* -------------------------------------------------------------------------- */
49 #pragma mark EIC
50 
51 #define EXCLAVES_EIC "com.apple.service.ExclaveIndicatorController"
52 #define EXCLAVES_EIC_COPYREQUEST "com.apple.service.ExclaveIndicatorController.SensorCopyRequest"
53 
54 /* The minimum time a sensor is on. */
55 #define EXCLAVES_EIC_MIN_SENSOR_TIME (3100 * NSEC_PER_MSEC) /* 3.1 seconds */
56 
57 /* Default to 30Hz */
58 static uint64_t exclaves_display_healthcheck_rate_hz = 30;
59 
60 static exclaveindicatorcontroller_sensorrequest_s eic_client;
61 static exclaveindicatorcontroller_sensorcopyrequest_s eic_copy_client;
62 
63 CA_EVENT(exclave_indicator_controller_metrics_v1,
64     CA_INT, metrics_duration_ms,
65     CA_INT, num_sessions_mic,
66     CA_INT, num_sessions_dropped_mic,
67     CA_INT, num_sessions_denied_healthcheck_mic,
68     CA_INT, num_sessions_denied_sensor_control_mic,
69     CA_INT, duration_allowed_ms_mic,
70     CA_INT, duration_pending_ms_mic,
71     CA_INT, duration_control_ms_mic,
72     CA_INT, duration_denied_ms_mic,
73     CA_INT, bips_allowed_mic,
74     CA_INT, bips_pending_mic,
75     CA_INT, bips_control_mic,
76     CA_INT, bips_denied_mic,
77 
78     CA_INT, num_sessions_cam,
79     CA_INT, num_sessions_dropped_cam,
80     CA_INT, num_sessions_denied_healthcheck_cam,
81     CA_INT, num_sessions_denied_sensor_control_cam,
82     CA_INT, duration_allowed_ms_cam,
83     CA_INT, duration_pending_ms_cam,
84     CA_INT, duration_control_ms_cam,
85     CA_INT, duration_denied_ms_cam,
86     CA_INT, bips_allowed_cam,
87     CA_INT, bips_pending_cam,
88     CA_INT, bips_control_cam,
89     CA_INT, bips_denied_cam);
90 
91 static inline __unused exclaveindicatorcontroller_sensortype_s
sensor_type_to_eic_sensortype(exclaves_sensor_type_t type)92 sensor_type_to_eic_sensortype(exclaves_sensor_type_t type)
93 {
94 	assert3u(type, >, 0);
95 	assert3u(type, <=, EXCLAVES_SENSOR_MAX);
96 
97 	switch (type) {
98 	case EXCLAVES_SENSOR_CAM:
99 		return EXCLAVEINDICATORCONTROLLER_SENSORTYPE_SENSOR_CAM;
100 	case EXCLAVES_SENSOR_MIC:
101 		return EXCLAVEINDICATORCONTROLLER_SENSORTYPE_SENSOR_MIC;
102 	case EXCLAVES_SENSOR_CAM_ALT_FACEID:
103 		return EXCLAVEINDICATORCONTROLLER_SENSORTYPE_SENSOR_CAM_ALT_FACEID;
104 	case EXCLAVES_SENSOR_CAM_ALT_FACEID_DELAYED:
105 		return EXCLAVEINDICATORCONTROLLER_SENSORTYPE_SENSOR_CAM_ALT_FACEID_DELAYED;
106 	case EXCLAVES_SENSOR_TEST:
107 		return EXCLAVEINDICATORCONTROLLER_SENSORTYPE_SENSOR_TEST;
108 	case EXCLAVES_SENSOR_TEST_MIL:
109 		return EXCLAVEINDICATORCONTROLLER_SENSORTYPE_SENSOR_TEST_MIL;
110 	case EXCLAVES_SENSOR_TEST_CIL:
111 		return EXCLAVEINDICATORCONTROLLER_SENSORTYPE_SENSOR_TEST_CIL;
112 	default:
113 		panic("unknown sensor type");
114 	}
115 }
116 
117 static inline exclaves_sensor_status_t
eic_sensorstatus_to_sensor_status(exclaveindicatorcontroller_sensorstatusresponse_s status)118 eic_sensorstatus_to_sensor_status(exclaveindicatorcontroller_sensorstatusresponse_s status)
119 {
120 	assert3u(status, >, 0);
121 	assert3u(status, <=, EXCLAVEINDICATORCONTROLLER_SENSORSTATUSRESPONSE_SENSOR_PENDING);
122 
123 	switch (status) {
124 	case EXCLAVEINDICATORCONTROLLER_SENSORSTATUSRESPONSE_SENSOR_ALLOWED:
125 		return EXCLAVES_SENSOR_STATUS_ALLOWED;
126 	case EXCLAVEINDICATORCONTROLLER_SENSORSTATUSRESPONSE_SENSOR_DENIED:
127 		return EXCLAVES_SENSOR_STATUS_DENIED;
128 	case EXCLAVEINDICATORCONTROLLER_SENSORSTATUSRESPONSE_SENSOR_CONTROL:
129 		return EXCLAVES_SENSOR_STATUS_CONTROL;
130 	case EXCLAVEINDICATORCONTROLLER_SENSORSTATUSRESPONSE_SENSOR_PENDING:
131 		return EXCLAVES_SENSOR_STATUS_PENDING;
132 	default:
133 		panic("unknown sensor status");
134 	}
135 }
136 
137 static kern_return_t
exclaves_eic_init(void)138 exclaves_eic_init(void)
139 {
140 	exclaves_id_t sensorrequest_id, sensorcopyrequest_id;
141 	tb_endpoint_t sensorrequest_endpoint, sensorcopyrequest_endpoint;
142 	tb_error_t ret;
143 
144 	sensorrequest_id = exclaves_service_lookup(EXCLAVES_DOMAIN_KERNEL, EXCLAVES_EIC);
145 	if (sensorrequest_id == EXCLAVES_INVALID_ID) {
146 		exclaves_requirement_assert(EXCLAVES_R_EIC,
147 		    "exclaves indicator controller not found");
148 		return KERN_SUCCESS;
149 	}
150 
151 	sensorcopyrequest_id = exclaves_service_lookup(EXCLAVES_DOMAIN_KERNEL, EXCLAVES_EIC_COPYREQUEST);
152 	if (sensorcopyrequest_id == EXCLAVES_INVALID_ID) {
153 		exclaves_requirement_assert(EXCLAVES_R_EIC,
154 		    "ExclaveIndicatorController SensorCopyRequest service not found");
155 		return KERN_SUCCESS;
156 	}
157 
158 	sensorrequest_endpoint = tb_endpoint_create_with_value(TB_TRANSPORT_TYPE_XNU, sensorrequest_id, TB_ENDPOINT_OPTIONS_NONE);
159 	sensorcopyrequest_endpoint = tb_endpoint_create_with_value(TB_TRANSPORT_TYPE_XNU, sensorcopyrequest_id, TB_ENDPOINT_OPTIONS_NONE);
160 
161 	ret = exclaveindicatorcontroller_sensorrequest__init(&eic_client, sensorrequest_endpoint);
162 	if (ret != TB_ERROR_SUCCESS) {
163 		exclaves_requirement_assert(EXCLAVES_R_EIC, "failed to initialize eic sensor request client");
164 		return KERN_FAILURE;
165 	}
166 
167 	ret = exclaveindicatorcontroller_sensorcopyrequest__init(&eic_copy_client, sensorcopyrequest_endpoint);
168 	if (ret != TB_ERROR_SUCCESS) {
169 		exclaves_requirement_assert(EXCLAVES_R_EIC, "failed to initialize eic sensor copy request client");
170 		/* Clean up first client (sensorrequest) if second client (sensorcopyrequest) init fails */
171 		exclaveindicatorcontroller_sensorrequest__destruct(&eic_client);
172 		return KERN_FAILURE;
173 	}
174 
175 	return KERN_SUCCESS;
176 }
177 
178 static kern_return_t
exclaves_eic_tick_rate(uint64_t rate_hz)179 exclaves_eic_tick_rate(uint64_t rate_hz)
180 {
181 	exclaveindicatorcontroller_indicatorrefreshrate_s rate;
182 
183 	/* Round up to nearest supported value. */
184 	switch (rate_hz) {
185 	case 0 ... 30:
186 		exclaves_display_healthcheck_rate_hz = 30;
187 		rate.tag = EXCLAVEINDICATORCONTROLLER_INDICATORREFRESHRATE__HZ_30;
188 		break;
189 	case 31 ... 60:
190 		exclaves_display_healthcheck_rate_hz = 60;
191 		rate.tag = EXCLAVEINDICATORCONTROLLER_INDICATORREFRESHRATE__HZ_60;
192 		break;
193 	default:
194 		exclaves_display_healthcheck_rate_hz = 120;
195 		rate.tag = EXCLAVEINDICATORCONTROLLER_INDICATORREFRESHRATE__HZ_120;
196 		break;
197 	}
198 
199 	tb_error_t ret = exclaveindicatorcontroller_sensorrequest_setindicatorrefreshrate(
200 		&eic_client, &rate, ^(__unused exclaveindicatorcontroller_requesterror_s result) {});
201 
202 	return ret == TB_ERROR_SUCCESS ? KERN_SUCCESS : KERN_FAILURE;
203 }
204 
205 static kern_return_t
exclaves_eic_sensor_start(exclaves_sensor_type_t __unused sensor_type,__assert_only uint64_t flags,exclaves_sensor_status_t * status)206 exclaves_eic_sensor_start(exclaves_sensor_type_t __unused sensor_type,
207     __assert_only uint64_t flags, exclaves_sensor_status_t *status)
208 {
209 	assert3p(status, !=, NULL);
210 	assert3u(flags, ==, 0);
211 
212 	const exclaveindicatorcontroller_sensortype_s sensor =
213 	    sensor_type_to_eic_sensortype(sensor_type);
214 
215 	tb_error_t ret = exclaveindicatorcontroller_sensorrequest_start(
216 		&eic_client, sensor, ^(exclaveindicatorcontroller_sensorstatusresponse_s result) {
217 		*status = eic_sensorstatus_to_sensor_status(result);
218 	});
219 
220 	return ret == TB_ERROR_SUCCESS ? KERN_SUCCESS : KERN_FAILURE;
221 }
222 
223 static kern_return_t
exclaves_eic_sensor_stop(exclaves_sensor_type_t __unused sensor_type)224 exclaves_eic_sensor_stop(exclaves_sensor_type_t __unused sensor_type)
225 {
226 	const exclaveindicatorcontroller_sensortype_s sensor =
227 	    sensor_type_to_eic_sensortype(sensor_type);
228 
229 	tb_error_t ret = exclaveindicatorcontroller_sensorrequest_stop(&eic_client,
230 	    sensor);
231 	return ret == TB_ERROR_SUCCESS ? KERN_SUCCESS : KERN_FAILURE;
232 }
233 
234 static kern_return_t
exclaves_eic_sensor_status(exclaves_sensor_type_t __unused sensor_type,__assert_only uint64_t flags,exclaves_sensor_status_t * status)235 exclaves_eic_sensor_status(exclaves_sensor_type_t __unused sensor_type,
236     __assert_only uint64_t flags, exclaves_sensor_status_t *status)
237 {
238 	assert3p(status, !=, NULL);
239 	assert3u(flags, ==, 0);
240 
241 	const exclaveindicatorcontroller_sensortype_s sensor =
242 	    sensor_type_to_eic_sensortype(sensor_type);
243 
244 	tb_error_t ret = exclaveindicatorcontroller_sensorrequest_status(
245 		&eic_client, sensor, ^(exclaveindicatorcontroller_sensorstatusresponse_s result) {
246 		*status = eic_sensorstatus_to_sensor_status(result);
247 	});
248 
249 	return ret == TB_ERROR_SUCCESS ? KERN_SUCCESS : KERN_FAILURE;
250 }
251 
252 /*
253  * It is intentional to keep "buffer" untyped here as it avoids xnu having to
254  * understand what those IDs are at all. They are simply passed through from the
255  * resource table as-is.
256  */
257 static kern_return_t
exclaves_eic_sensor_copy(uint32_t buffer,uint64_t size1,uint64_t offset1,uint64_t size2,uint64_t offset2,exclaves_sensor_status_t * status)258 exclaves_eic_sensor_copy(uint32_t buffer, uint64_t size1, uint64_t offset1,
259     uint64_t size2, uint64_t offset2, exclaves_sensor_status_t *status)
260 {
261 	assert3u(size1, >, 0);
262 	assert3p(status, !=, NULL);
263 
264 	tb_error_t ret = exclaveindicatorcontroller_sensorcopyrequest_copy(
265 		&eic_copy_client, buffer, offset1, size1, offset2, size2,
266 		^(exclaveindicatorcontroller_sensorstatusresponse_s result) {
267 		*status = eic_sensorstatus_to_sensor_status(result);
268 	});
269 
270 	return ret == TB_ERROR_SUCCESS ? KERN_SUCCESS : KERN_FAILURE;
271 }
272 
273 static bool
exclaves_sensor_tick(void)274 exclaves_sensor_tick(void)
275 {
276 	__block bool again = true;
277 	__unused tb_error_t ret = exclaveindicatorcontroller_sensorrequest_tick(
278 		&eic_client, ^(bool result) {
279 		again = result;
280 	});
281 	assert3u(ret, ==, TB_ERROR_SUCCESS);
282 
283 	return again;
284 }
285 
286 /* -------------------------------------------------------------------------- */
287 #pragma mark sensor
288 
289 static LCK_GRP_DECLARE(sensor_lck_grp, "exclaves_sensor");
290 
291 typedef struct {
292 	/*
293 	 * Count of how many times sensor_start has been called on this sensor
294 	 * without a corresponding sensor_stop.
295 	 */
296 	uint64_t s_startcount;
297 
298 	/* Last start time. */
299 	uint64_t s_start_abs;
300 
301 	/* Last stop time. */
302 	uint64_t s_stop_abs;
303 
304 	/* mutex to protect updates to the above */
305 	lck_mtx_t s_mutex;
306 
307 	/* Keep track of whether this sensor was initialised or not. */
308 	bool s_initialised;
309 } exclaves_sensor_t;
310 
311 /**
312  * A reverse lookup table for the sensor resources,
313  * as the kpi uses sensor ids directly to access the same resources */
314 static exclaves_sensor_t sensors[EXCLAVES_SENSOR_MAX];
315 
316 /*
317  * A thread call used to periodically call "status" on any open sensors.
318  */
319 static thread_call_t sensor_healthcheck_tcall = NULL;
320 
321 static inline bool
valid_sensor(exclaves_sensor_type_t sensor_type)322 valid_sensor(exclaves_sensor_type_t sensor_type)
323 {
324 	switch (sensor_type) {
325 	case EXCLAVES_SENSOR_CAM:
326 	case EXCLAVES_SENSOR_MIC:
327 	case EXCLAVES_SENSOR_CAM_ALT_FACEID:
328 	case EXCLAVES_SENSOR_CAM_ALT_FACEID_DELAYED:
329 	case EXCLAVES_SENSOR_TEST:
330 	case EXCLAVES_SENSOR_TEST_MIL:
331 	case EXCLAVES_SENSOR_TEST_CIL:
332 		return true;
333 	default:
334 		return false;
335 	}
336 }
337 
338 static inline exclaves_sensor_t *
sensor_type_to_sensor(exclaves_sensor_type_t sensor_type)339 sensor_type_to_sensor(exclaves_sensor_type_t sensor_type)
340 {
341 	assert(valid_sensor(sensor_type));
342 	return &sensors[sensor_type - 1];
343 }
344 
345 /* Calculate the next healthcheck time. */
346 static void
healthcheck_deadline(uint64_t * deadline,uint64_t * leeway)347 healthcheck_deadline(uint64_t *deadline, uint64_t *leeway)
348 {
349 	const uint32_t interval =
350 	    NSEC_PER_SEC / exclaves_display_healthcheck_rate_hz;
351 	clock_interval_to_deadline(interval, 1, deadline);
352 	nanoseconds_to_absolutetime(interval / 2, leeway);
353 }
354 
355 
356 /*
357  * Called from the threadcall to call into exclaves with a status command for
358  * every started sensor. Re-arms itself so it runs at a frequency set by the
359  * display healthcheck rate. Exits when there are no longer any started sensors.
360  * A sensor has a minimum on-time. For stopped sensors, call back into exclaves
361  * until this minimum time has been reached.
362  */
363 static void
exclaves_sensor_healthcheck(__unused void * param0,__unused void * param1)364 exclaves_sensor_healthcheck(__unused void *param0, __unused void *param1)
365 {
366 	uint64_t hc_leeway, hc_deadline;
367 
368 	/*
369 	 * Calculate the next deadline up-front so the overhead of calling into
370 	 * exclaves doesn't add to the period.
371 	 */
372 	healthcheck_deadline(&hc_deadline, &hc_leeway);
373 
374 	if (exclaves_sensor_tick()) {
375 		thread_call_enter_delayed_with_leeway(sensor_healthcheck_tcall,
376 		    NULL, hc_deadline, hc_leeway, THREAD_CALL_DELAY_LEEWAY);
377 	}
378 }
379 
380 static kern_return_t
exclaves_sensor_init(void)381 exclaves_sensor_init(void)
382 {
383 	kern_return_t kr = exclaves_eic_init();
384 	if (kr != KERN_SUCCESS) {
385 		return kr;
386 	}
387 
388 	for (uint32_t i = 1; i <= EXCLAVES_SENSOR_MAX; i++) {
389 		exclaves_sensor_t *sensor = sensor_type_to_sensor(i);
390 
391 		lck_mtx_init(&sensor->s_mutex, &sensor_lck_grp, NULL);
392 
393 		sensor->s_startcount = 0;
394 		sensor->s_initialised = true;
395 	}
396 
397 	sensor_healthcheck_tcall =
398 	    thread_call_allocate_with_priority(exclaves_sensor_healthcheck,
399 	    NULL, THREAD_CALL_PRIORITY_KERNEL);
400 
401 	return KERN_SUCCESS;
402 }
403 EXCLAVES_BOOT_TASK(exclaves_sensor_init, EXCLAVES_BOOT_RANK_ANY);
404 
405 kern_return_t
exclaves_sensor_start(exclaves_sensor_type_t sensor_type,uint64_t flags,exclaves_sensor_status_t * status)406 exclaves_sensor_start(exclaves_sensor_type_t sensor_type, uint64_t flags,
407     exclaves_sensor_status_t *status)
408 {
409 	if (!valid_sensor(sensor_type)) {
410 		return KERN_INVALID_ARGUMENT;
411 	}
412 
413 	exclaves_sensor_t *sensor = sensor_type_to_sensor(sensor_type);
414 	if (!sensor->s_initialised) {
415 		return KERN_FAILURE;
416 	}
417 
418 	lck_mtx_lock(&sensor->s_mutex);
419 	kern_return_t kr;
420 
421 	if (sensor->s_startcount == UINT64_MAX) {
422 		lck_mtx_unlock(&sensor->s_mutex);
423 		return KERN_INVALID_ARGUMENT;
424 	}
425 
426 	if (sensor->s_startcount > 0) {
427 		kr = exclaves_eic_sensor_status(sensor_type, flags, status);
428 		if (kr == KERN_SUCCESS) {
429 			sensor->s_startcount += 1;
430 		}
431 		lck_mtx_unlock(&sensor->s_mutex);
432 		return kr;
433 	}
434 
435 	// call start iff startcount is 0
436 	kr = exclaves_eic_sensor_start(sensor_type, flags, status);
437 	if (kr != KERN_SUCCESS) {
438 		lck_mtx_unlock(&sensor->s_mutex);
439 		return kr;
440 	}
441 
442 	sensor->s_start_abs = mach_absolute_time();
443 	sensor->s_startcount += 1;
444 
445 	lck_mtx_unlock(&sensor->s_mutex);
446 
447 	/* Kick off the periodic status check. */
448 	(void)thread_call_enter(sensor_healthcheck_tcall);
449 
450 	return KERN_SUCCESS;
451 }
452 
453 kern_return_t
exclaves_sensor_stop(exclaves_sensor_type_t sensor_type,uint64_t flags,exclaves_sensor_status_t * status)454 exclaves_sensor_stop(exclaves_sensor_type_t sensor_type, uint64_t flags,
455     exclaves_sensor_status_t *status)
456 {
457 	if (!valid_sensor(sensor_type)) {
458 		return KERN_INVALID_ARGUMENT;
459 	}
460 
461 	exclaves_sensor_t *sensor = sensor_type_to_sensor(sensor_type);
462 	if (!sensor->s_initialised) {
463 		return KERN_FAILURE;
464 	}
465 
466 	kern_return_t kr;
467 
468 	lck_mtx_lock(&sensor->s_mutex);
469 
470 	if (sensor->s_startcount == 0) {
471 		lck_mtx_unlock(&sensor->s_mutex);
472 		return KERN_INVALID_ARGUMENT;
473 	}
474 
475 	if (sensor->s_startcount > 1) {
476 		kr = exclaves_eic_sensor_status(sensor_type, flags, status);
477 		if (kr == KERN_SUCCESS) {
478 			sensor->s_startcount -= 1;
479 		}
480 		lck_mtx_unlock(&sensor->s_mutex);
481 		return kr;
482 	}
483 
484 	// call stop iff startcount is going to go to 0
485 	kr = exclaves_eic_sensor_stop(sensor_type);
486 	if (kr != KERN_SUCCESS) {
487 		lck_mtx_unlock(&sensor->s_mutex);
488 		return kr;
489 	}
490 
491 	sensor->s_stop_abs = mach_absolute_time();
492 	sensor->s_startcount = 0;
493 
494 	kr = exclaves_eic_sensor_status(sensor_type, flags, status);
495 
496 	lck_mtx_unlock(&sensor->s_mutex);
497 
498 	return kr;
499 }
500 
501 kern_return_t
exclaves_sensor_status(exclaves_sensor_type_t sensor_type,uint64_t flags,exclaves_sensor_status_t * status)502 exclaves_sensor_status(exclaves_sensor_type_t sensor_type, uint64_t flags,
503     exclaves_sensor_status_t *status)
504 {
505 	if (!valid_sensor(sensor_type)) {
506 		return KERN_INVALID_ARGUMENT;
507 	}
508 
509 	exclaves_sensor_t *sensor = sensor_type_to_sensor(sensor_type);
510 	if (!sensor->s_initialised) {
511 		return KERN_FAILURE;
512 	}
513 
514 	return exclaves_eic_sensor_status(sensor_type, flags, status);
515 }
516 
517 kern_return_t
exclaves_sensor_tick_rate(uint64_t rate_hz)518 exclaves_sensor_tick_rate(uint64_t rate_hz)
519 {
520 	/*
521 	 * Make sure that the initialisation has taken place before calling into
522 	 * the EIC. Any sensor is sufficient.
523 	 */
524 	exclaves_sensor_t *sensor = sensor_type_to_sensor(EXCLAVES_SENSOR_CAM);
525 	if (!sensor->s_initialised) {
526 		return KERN_FAILURE;
527 	}
528 
529 	return exclaves_eic_tick_rate(rate_hz);
530 }
531 
532 kern_return_t
exclaves_display_healthcheck_rate(uint64_t __unused ns)533 exclaves_display_healthcheck_rate(uint64_t __unused ns)
534 {
535 	/* Deprecated, no longer does anything */
536 	return KERN_SUCCESS;
537 }
538 
539 kern_return_t
exclaves_sensor_copy(uint32_t buffer,uint64_t size1,uint64_t offset1,uint64_t size2,uint64_t offset2,exclaves_sensor_status_t * status)540 exclaves_sensor_copy(uint32_t buffer, uint64_t size1, uint64_t offset1,
541     uint64_t size2, uint64_t offset2, exclaves_sensor_status_t *status)
542 {
543 	/*
544 	 * Make sure that the initialisation has taken place before calling into
545 	 * the EIC. Any sensor is sufficient.
546 	 */
547 	exclaves_sensor_t *sensor = sensor_type_to_sensor(EXCLAVES_SENSOR_CAM);
548 	if (!sensor->s_initialised) {
549 		return KERN_FAILURE;
550 	}
551 
552 
553 	return exclaves_eic_sensor_copy(buffer, size1, offset1, size2, offset2,
554 	           status);
555 }
556 
557 kern_return_t
exclaves_indicator_min_on_time_deadlines(struct exclaves_indicator_deadlines * deadlines)558 exclaves_indicator_min_on_time_deadlines(struct exclaves_indicator_deadlines *deadlines)
559 {
560 	assert(deadlines);
561 
562 	//For now, only one version is supported. Return an error if libsyscall sends us any other versions
563 	if (deadlines->version != 1) {
564 		return KERN_INVALID_ARGUMENT;
565 	}
566 
567 	// Make sure that the initialisation has taken place before calling into
568 	// the EIC. Any sensor is sufficient.
569 	exclaves_sensor_t *sensor = sensor_type_to_sensor(EXCLAVES_SENSOR_CAM);
570 	if (!sensor->s_initialised) {
571 		return KERN_FAILURE;
572 	}
573 
574 	tb_error_t ret = exclaveindicatorcontroller_sensorrequest_getmotstate(
575 		&eic_client, ^(exclaveindicatorcontroller_motstate_s result) {
576 		deadlines->camera_indicator = result.deadlinecil;
577 		deadlines->mic_indicator = result.deadlinemil;
578 		deadlines->faceid_indicator = result.deadlinefid;
579 	});
580 
581 	return ret == TB_ERROR_SUCCESS ? KERN_SUCCESS : KERN_FAILURE;
582 }
583 
584 static kern_return_t
exclaves_sensor_get_and_clear_metrics(ca_event_t event)585 exclaves_sensor_get_and_clear_metrics(ca_event_t event)
586 {
587 	if (!event) {
588 		return KERN_INVALID_ARGUMENT;
589 	}
590 
591 	/*
592 	 * Make sure that the initialisation has taken place before calling into
593 	 * the EIC. Any sensor is sufficient.
594 	 */
595 	exclaves_sensor_t *sensor = sensor_type_to_sensor(EXCLAVES_SENSOR_CAM);
596 	if (!sensor->s_initialised) {
597 		return KERN_FAILURE;
598 	}
599 
600 	CA_EVENT_TYPE(exclave_indicator_controller_metrics_v1) * e = event->data;
601 
602 	tb_error_t ret = exclaveindicatorcontroller_sensorrequest_getandclearmetrics(
603 		&eic_client, ^(exclaveindicatorcontroller_sensorrequestmetrics_s result) {
604 		e->metrics_duration_ms = result.metricsdurationms;
605 
606 		/* Microphone metrics */
607 		e->num_sessions_mic = result.numsessionsmic;
608 		e->num_sessions_dropped_mic = result.numsessionsdroppedmic;
609 		e->num_sessions_denied_healthcheck_mic = result.numsessionsdeniedhealthcheckmic;
610 		e->num_sessions_denied_sensor_control_mic = result.numsessionsdeniedsensorcontrolmic;
611 		e->duration_allowed_ms_mic = result.durationallowedmsmic;
612 		e->duration_pending_ms_mic = result.durationpendingmsmic;
613 		e->duration_control_ms_mic = result.durationcontrolmsmic;
614 		e->duration_denied_ms_mic = result.durationdeniedmsmic;
615 		e->bips_allowed_mic = result.bipsallowedmic;
616 		e->bips_pending_mic = result.bipspendingmic;
617 		e->bips_control_mic = result.bipscontrolmic;
618 		e->bips_denied_mic = result.bipsdeniedmic;
619 
620 		/* Camera metrics */
621 		e->num_sessions_cam = result.numsessionscam;
622 		e->num_sessions_dropped_cam = result.numsessionsdroppedcam;
623 		e->num_sessions_denied_healthcheck_cam = result.numsessionsdeniedhealthcheckcam;
624 		e->num_sessions_denied_sensor_control_cam = result.numsessionsdeniedsensorcontrolcam;
625 		e->duration_allowed_ms_cam = result.durationallowedmscam;
626 		e->duration_pending_ms_cam = result.durationpendingmscam;
627 		e->duration_control_ms_cam = result.durationcontrolmscam;
628 		e->duration_denied_ms_cam = result.durationdeniedmscam;
629 		e->bips_allowed_cam = result.bipsallowedcam;
630 		e->bips_pending_cam = result.bipspendingcam;
631 		e->bips_control_cam = result.bipscontrolcam;
632 		e->bips_denied_cam = result.bipsdeniedcam;
633 	});
634 
635 	return ret == TB_ERROR_SUCCESS ? KERN_SUCCESS : KERN_FAILURE;
636 }
637 
638 void
exclaves_indicator_metrics_report(void)639 exclaves_indicator_metrics_report(void)
640 {
641 	ca_event_t event = CA_EVENT_ALLOCATE(exclave_indicator_controller_metrics_v1);
642 	kern_return_t kr = exclaves_sensor_get_and_clear_metrics(event);
643 
644 	if (kr != KERN_SUCCESS) {
645 		CA_EVENT_DEALLOCATE(event);
646 		return;
647 	}
648 
649 	CA_EVENT_SEND(event);
650 }
651 
652 #else /* CONFIG_EXCLAVES */
653 
654 kern_return_t
exclaves_display_healthcheck_rate(__unused uint64_t ns)655 exclaves_display_healthcheck_rate(__unused uint64_t ns)
656 {
657 	return KERN_NOT_SUPPORTED;
658 }
659 
660 kern_return_t
exclaves_sensor_tick_rate(uint64_t __unused rate_hz)661 exclaves_sensor_tick_rate(uint64_t __unused rate_hz)
662 {
663 	return KERN_NOT_SUPPORTED;
664 }
665 
666 #endif /* CONFIG_EXCLAVES */
667