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