// SPDX-License-Identifier: BSD-2-Clause /* * Copyright (c) 2018, Linaro Limited */ /* * Test lockdep with hypothetical thread and lock objects */ #include #include #include "misc.h" static int self_test_lockdep1(void) { TEE_Result res = TEE_ERROR_GENERIC; struct lockdep_node_head graph; struct lockdep_lock_head thread1; int count = 1; DMSG(""); TAILQ_INIT(&thread1); TAILQ_INIT(&graph); /* Not locked, expect failure */ res = __lockdep_lock_release(&thread1, 1); if (!res) return count; count++; res = __lockdep_lock_acquire(&graph, &thread1, 1); if (res) return count; count++; res = __lockdep_lock_release(&thread1, 1); if (res) return count; count++; res = __lockdep_lock_acquire(&graph, &thread1, 1); if (res) return count; count++; res = __lockdep_lock_acquire(&graph, &thread1, 3); if (res) return count; count++; res = __lockdep_lock_acquire(&graph, &thread1, 2); if (res) return count; count++; res = __lockdep_lock_release(&thread1, 3); if (res) return count; count++; /* Already locked */ res = __lockdep_lock_acquire(&graph, &thread1, 2); if (!res) return count; lockdep_graph_delete(&graph); lockdep_queue_delete(&thread1); return 0; } static int self_test_lockdep2(void) { TEE_Result res = TEE_ERROR_GENERIC; struct lockdep_node_head graph; struct lockdep_lock_head thread1; struct lockdep_lock_head thread2; struct lockdep_lock_head thread3; int count = 1; DMSG(""); TAILQ_INIT(&thread1); TAILQ_INIT(&thread2); TAILQ_INIT(&thread3); TAILQ_INIT(&graph); res = __lockdep_lock_acquire(&graph, &thread1, 1); if (res) return count; count++; res = __lockdep_lock_acquire(&graph, &thread2, 2); if (res) return count; count++; res = __lockdep_lock_acquire(&graph, &thread1, 2); if (res) return count; count++; res = __lockdep_lock_acquire(&graph, &thread3, 3); if (res) return count; count++; res = __lockdep_lock_acquire(&graph, &thread2, 3); if (res) return count; count++; /* Deadlock 1-2-3 */ res = __lockdep_lock_acquire(&graph, &thread3, 1); if (!res) return count; lockdep_graph_delete(&graph); lockdep_queue_delete(&thread1); lockdep_queue_delete(&thread2); lockdep_queue_delete(&thread3); return 0; } static int self_test_lockdep3(void) { TEE_Result res = TEE_ERROR_GENERIC; struct lockdep_node_head graph; struct lockdep_lock_head thread1; struct lockdep_lock_head thread2; int count = 1; DMSG(""); TAILQ_INIT(&thread1); TAILQ_INIT(&thread2); TAILQ_INIT(&graph); res = __lockdep_lock_tryacquire(&graph, &thread1, 1); if (res) return count; count++; res = __lockdep_lock_release(&thread1, 1); if (res) return count; count++; res = __lockdep_lock_tryacquire(&graph, &thread1, 1); if (res) return count; count++; res = __lockdep_lock_acquire(&graph, &thread2, 2); if (res) return count; count++; res = __lockdep_lock_acquire(&graph, &thread1, 2); if (res) return count; count++; /* Deadlock 1-2 */ res = __lockdep_lock_acquire(&graph, &thread2, 1); if (!res) return count; lockdep_graph_delete(&graph); lockdep_queue_delete(&thread1); lockdep_queue_delete(&thread2); return 0; } TEE_Result core_lockdep_tests(uint32_t nParamTypes __unused, TEE_Param pParams[TEE_NUM_PARAMS] __unused) { int count = 0; count = self_test_lockdep1(); if (count) goto out; count = self_test_lockdep2(); if (count) goto out; count = self_test_lockdep3(); if (count) goto out; out: if (count) { DMSG("count=%d", count); return TEE_ERROR_GENERIC; } return TEE_SUCCESS; }