xref: /optee_os/core/tests/notif_test_wd.c (revision d237e616e155e6127ff2399ac5cf90655624b0e9)
11c3c4a5fSJens Wiklander // SPDX-License-Identifier: BSD-2-Clause
21c3c4a5fSJens Wiklander /*
31c3c4a5fSJens Wiklander  * Copyright (c) 2024, Linaro Limited
41c3c4a5fSJens Wiklander  */
51c3c4a5fSJens Wiklander 
61c3c4a5fSJens Wiklander #include <initcall.h>
71c3c4a5fSJens Wiklander #include <kernel/callout.h>
81c3c4a5fSJens Wiklander #include <kernel/notif.h>
91c3c4a5fSJens Wiklander #include <kernel/panic.h>
101c3c4a5fSJens Wiklander #include <kernel/tee_time.h>
111c3c4a5fSJens Wiklander #include <kernel/virtualization.h>
121c3c4a5fSJens Wiklander #include <types_ext.h>
131c3c4a5fSJens Wiklander 
141c3c4a5fSJens Wiklander #define TEST_WD_TIMER_PERIOD_MS	1000
151c3c4a5fSJens Wiklander 
161c3c4a5fSJens Wiklander struct wd_data {
171c3c4a5fSJens Wiklander 	bool pending;
181c3c4a5fSJens Wiklander 	bool enabled;
19*d237e616SJens Wiklander 	uint16_t guest_id;
201c3c4a5fSJens Wiklander 	unsigned int timeout_count;
211c3c4a5fSJens Wiklander 	unsigned int call_count;
221c3c4a5fSJens Wiklander 	struct callout callout;
231c3c4a5fSJens Wiklander };
241c3c4a5fSJens Wiklander 
251c3c4a5fSJens Wiklander static struct wd_data default_wd_data;
26*d237e616SJens Wiklander static unsigned int wd_data_id __nex_bss;
271c3c4a5fSJens Wiklander 
get_wd_data(struct guest_partition * prtn)28*d237e616SJens Wiklander static struct wd_data *get_wd_data(struct guest_partition *prtn)
291c3c4a5fSJens Wiklander {
30*d237e616SJens Wiklander 	if (IS_ENABLED(CFG_NS_VIRTUALIZATION)) {
31*d237e616SJens Wiklander 		assert(prtn);
32*d237e616SJens Wiklander 		return virt_get_guest_spec_data(prtn, wd_data_id);
33*d237e616SJens Wiklander 	}
341c3c4a5fSJens Wiklander 	return &default_wd_data;
351c3c4a5fSJens Wiklander }
361c3c4a5fSJens Wiklander 
test_wd_callback(struct callout * co)371c3c4a5fSJens Wiklander static bool test_wd_callback(struct callout *co)
381c3c4a5fSJens Wiklander {
391c3c4a5fSJens Wiklander 	struct wd_data *wd = container_of(co, struct wd_data, callout);
401c3c4a5fSJens Wiklander 
411c3c4a5fSJens Wiklander 	if (wd->pending)
421c3c4a5fSJens Wiklander 		wd->timeout_count++;
431c3c4a5fSJens Wiklander 	wd->call_count++;
44*d237e616SJens Wiklander 	if (wd->call_count < 10 || !(wd->call_count % 60) || wd->pending) {
45*d237e616SJens Wiklander 		if (IS_ENABLED(CFG_NS_VIRTUALIZATION))
46*d237e616SJens Wiklander 			DMSG("WD %"PRIu16" call_count %u, timeout_count %u",
47*d237e616SJens Wiklander 			     wd->guest_id, wd->call_count, wd->timeout_count);
48*d237e616SJens Wiklander 		else
491c3c4a5fSJens Wiklander 			DMSG("WD call_count %u, timeout_count %u",
501c3c4a5fSJens Wiklander 			     wd->call_count, wd->timeout_count);
51*d237e616SJens Wiklander 	}
521c3c4a5fSJens Wiklander 	wd->pending = true;
53*d237e616SJens Wiklander 	notif_send_async(NOTIF_VALUE_DO_BOTTOM_HALF, wd->guest_id);
541c3c4a5fSJens Wiklander 
551c3c4a5fSJens Wiklander 	return true;
561c3c4a5fSJens Wiklander }
571c3c4a5fSJens Wiklander 
wd_ndrv_atomic_cb(struct notif_driver * ndrv __unused,enum notif_event ev,uint16_t guest_id)581c3c4a5fSJens Wiklander static void wd_ndrv_atomic_cb(struct notif_driver *ndrv __unused,
59*d237e616SJens Wiklander 			      enum notif_event ev, uint16_t guest_id)
601c3c4a5fSJens Wiklander {
611c3c4a5fSJens Wiklander 	if (ev == NOTIF_EVENT_STARTED) {
62*d237e616SJens Wiklander 		struct guest_partition *prtn = virt_get_guest(guest_id);
63*d237e616SJens Wiklander 		struct wd_data *wd = get_wd_data(prtn);
641c3c4a5fSJens Wiklander 
651c3c4a5fSJens Wiklander 		if (!wd->enabled) {
66*d237e616SJens Wiklander 			wd->guest_id = guest_id;
671c3c4a5fSJens Wiklander 			callout_add(&wd->callout, test_wd_callback,
681c3c4a5fSJens Wiklander 				    TEST_WD_TIMER_PERIOD_MS);
691c3c4a5fSJens Wiklander 
701c3c4a5fSJens Wiklander 			wd->enabled = true;
711c3c4a5fSJens Wiklander 		}
72*d237e616SJens Wiklander 		virt_put_guest(prtn);
731c3c4a5fSJens Wiklander 	}
741c3c4a5fSJens Wiklander }
75fd3f2d69SJens Wiklander DECLARE_KEEP_PAGER(wd_ndrv_atomic_cb);
761c3c4a5fSJens Wiklander 
wd_ndrv_yielding_cb(struct notif_driver * ndrv __unused,enum notif_event ev)771c3c4a5fSJens Wiklander static void wd_ndrv_yielding_cb(struct notif_driver *ndrv __unused,
781c3c4a5fSJens Wiklander 				enum notif_event ev)
791c3c4a5fSJens Wiklander {
801c3c4a5fSJens Wiklander 	if (ev == NOTIF_EVENT_DO_BOTTOM_HALF) {
81*d237e616SJens Wiklander 		struct guest_partition *prtn = virt_get_current_guest();
82*d237e616SJens Wiklander 		struct wd_data *wd = get_wd_data(prtn);
831c3c4a5fSJens Wiklander 
841c3c4a5fSJens Wiklander 		if (wd->pending && wd->call_count < 10)
851c3c4a5fSJens Wiklander 			DMSG("Clearing pending");
861c3c4a5fSJens Wiklander 		wd->pending = false;
87*d237e616SJens Wiklander 		virt_put_guest(prtn);
881c3c4a5fSJens Wiklander 	}
891c3c4a5fSJens Wiklander }
901c3c4a5fSJens Wiklander 
911c3c4a5fSJens Wiklander struct notif_driver wd_ndrv __nex_data = {
921c3c4a5fSJens Wiklander 	.atomic_cb = wd_ndrv_atomic_cb,
931c3c4a5fSJens Wiklander 	.yielding_cb = wd_ndrv_yielding_cb,
941c3c4a5fSJens Wiklander };
951c3c4a5fSJens Wiklander 
wd_data_destroy(void * data)96*d237e616SJens Wiklander static void wd_data_destroy(void *data)
97*d237e616SJens Wiklander {
98*d237e616SJens Wiklander 	struct wd_data *wd = data;
99*d237e616SJens Wiklander 
100*d237e616SJens Wiklander 	callout_rem(&wd->callout);
101*d237e616SJens Wiklander }
102*d237e616SJens Wiklander 
nex_init_test_wd(void)1031c3c4a5fSJens Wiklander static TEE_Result nex_init_test_wd(void)
1041c3c4a5fSJens Wiklander {
105*d237e616SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
106*d237e616SJens Wiklander 
107*d237e616SJens Wiklander 	if (IS_ENABLED(CFG_NS_VIRTUALIZATION)) {
108*d237e616SJens Wiklander 		res = virt_add_guest_spec_data(&wd_data_id,
109*d237e616SJens Wiklander 					       sizeof(struct wd_data),
110*d237e616SJens Wiklander 					       wd_data_destroy);
111*d237e616SJens Wiklander 		if (res)
112*d237e616SJens Wiklander 			return res;
113*d237e616SJens Wiklander 	}
114*d237e616SJens Wiklander 
1151c3c4a5fSJens Wiklander 	notif_register_driver(&wd_ndrv);
1161c3c4a5fSJens Wiklander 
1171c3c4a5fSJens Wiklander 	return TEE_SUCCESS;
1181c3c4a5fSJens Wiklander }
1191c3c4a5fSJens Wiklander 
1201c3c4a5fSJens Wiklander nex_early_init(nex_init_test_wd);
1211c3c4a5fSJens Wiklander 
1221c3c4a5fSJens Wiklander struct periodic_data {
1231c3c4a5fSJens Wiklander 	unsigned int count;
1241c3c4a5fSJens Wiklander 	struct callout callout;
1251c3c4a5fSJens Wiklander };
1261c3c4a5fSJens Wiklander 
periodic_callback(struct callout * co)1271c3c4a5fSJens Wiklander static bool periodic_callback(struct callout *co)
1281c3c4a5fSJens Wiklander {
1291c3c4a5fSJens Wiklander 	struct periodic_data *d = container_of(co, struct periodic_data,
1301c3c4a5fSJens Wiklander 					       callout);
1311c3c4a5fSJens Wiklander 	TEE_Time t = { };
1321c3c4a5fSJens Wiklander 
1331c3c4a5fSJens Wiklander 	if (tee_time_get_sys_time(&t))
1341c3c4a5fSJens Wiklander 		panic();
1351c3c4a5fSJens Wiklander 	d->count++;
1361c3c4a5fSJens Wiklander 	DMSG("seconds %"PRIu32" millis %"PRIu32" count %u",
1371c3c4a5fSJens Wiklander 	     t.seconds, t.millis, d->count);
1381c3c4a5fSJens Wiklander 
1391c3c4a5fSJens Wiklander 	if (d->count > 20) {
1401c3c4a5fSJens Wiklander 		DMSG("Disabling periodic callout");
1411c3c4a5fSJens Wiklander 		return false;
1421c3c4a5fSJens Wiklander 	}
1431c3c4a5fSJens Wiklander 
1441c3c4a5fSJens Wiklander 	return true;
1451c3c4a5fSJens Wiklander }
146fd3f2d69SJens Wiklander DECLARE_KEEP_PAGER(periodic_callback);
1471c3c4a5fSJens Wiklander 
nex_init_periodic_callback(void)1481c3c4a5fSJens Wiklander static TEE_Result nex_init_periodic_callback(void)
1491c3c4a5fSJens Wiklander {
1501c3c4a5fSJens Wiklander 	struct periodic_data *d = nex_calloc(1, sizeof(*d));
1511c3c4a5fSJens Wiklander 
1521c3c4a5fSJens Wiklander 	if (!d)
1531c3c4a5fSJens Wiklander 		return TEE_ERROR_OUT_OF_MEMORY;
1541c3c4a5fSJens Wiklander 
1551c3c4a5fSJens Wiklander 	DMSG("Adding a periodic callout");
1561c3c4a5fSJens Wiklander 	callout_add(&d->callout, periodic_callback, TEST_WD_TIMER_PERIOD_MS);
1571c3c4a5fSJens Wiklander 
1581c3c4a5fSJens Wiklander 	return TEE_SUCCESS;
1591c3c4a5fSJens Wiklander }
1601c3c4a5fSJens Wiklander 
1611c3c4a5fSJens Wiklander nex_early_init(nex_init_periodic_callback);
162