1 /*
2  * Copyright 2022 The Hafnium Authors.
3  *
4  * Use of this source code is governed by a BSD-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/BSD-3-Clause.
7  */
8 
9 #include "hf/arch/irq.h"
10 #include "hf/arch/types.h"
11 #include "hf/arch/vm/interrupts_gicv3.h"
12 #include "hf/arch/vm/timer.h"
13 
14 #include "hf/ffa.h"
15 
16 #include "vmapi/hf/call.h"
17 
18 #include "ffa_endpoints.h"
19 #include "ffa_secure_partitions.h"
20 #include "gicv3.h"
21 #include "msr.h"
22 #include "partition_services.h"
23 #include "test/hftest.h"
24 #include "test/vmapi/ffa.h"
25 
26 #define TEST_SP_PREEMPTED_BY_NS_INTERRUPT_LOOP_COUNT UINT64_C(1000000)
27 
SET_UP(interrupts)28 SET_UP(interrupts)
29 {
30 	gicv3_system_setup();
31 }
32 
TEAR_DOWN(interrupts)33 TEAR_DOWN(interrupts)
34 {
35 	EXPECT_FFA_ERROR(ffa_rx_release(), FFA_DENIED);
36 }
37 
setup_physical_timer(void)38 static void setup_physical_timer(void)
39 {
40 	interrupt_enable(PHYSICAL_TIMER_IRQ, true);
41 	interrupt_set_priority(PHYSICAL_TIMER_IRQ, 0x80);
42 	interrupt_set_edge_triggered(PHYSICAL_TIMER_IRQ, true);
43 	interrupt_set_priority_mask(0xff);
44 	arch_irq_enable();
45 }
46 
start_physical_timer(uint32_t ns)47 static void start_physical_timer(uint32_t ns)
48 {
49 	/*
50 	 * Check that no (SGI or PPI) interrupts are active or pending to start
51 	 * with.
52 	 */
53 	EXPECT_EQ(io_read32_array(GICD_ISPENDR, 0), 0);
54 	EXPECT_EQ(io_read32(GICR_ISPENDR0), 0);
55 	EXPECT_EQ(io_read32_array(GICD_ISACTIVER, 0), 0);
56 	EXPECT_EQ(io_read32(GICR_ISACTIVER0), 0);
57 
58 	HFTEST_LOG("Starting timer\n");
59 	/* Set physical timer for 20 ms and enable. */
60 	write_msr(CNTP_TVAL_EL0, ns_to_ticks(ns));
61 	write_msr(CNTP_CTL_EL0, CNTx_CTL_ENABLE_MASK);
62 }
63 
check_physical_timer_interrupt_serviced(void)64 static void check_physical_timer_interrupt_serviced(void)
65 {
66 	/* Waiting for interrupt to be serviced in normal world. */
67 	while (last_interrupt_id == 0) {
68 		EXPECT_EQ(io_read32_array(GICD_ISPENDR, 0), 0);
69 		EXPECT_EQ(io_read32(GICR_ISPENDR0), 0);
70 		EXPECT_EQ(io_read32_array(GICD_ISACTIVER, 0), 0);
71 		EXPECT_EQ(io_read32(GICR_ISACTIVER0), 0);
72 	}
73 
74 	/* Check that we got the interrupt. */
75 	HFTEST_LOG("Checking for interrupt\n");
76 	EXPECT_EQ(last_interrupt_id, PHYSICAL_TIMER_IRQ);
77 
78 	/* Check timer status. */
79 	EXPECT_EQ(read_msr(CNTP_CTL_EL0),
80 		  CNTx_CTL_ISTS_MASK | CNTx_CTL_ENABLE_MASK);
81 
82 	/* There should again be no pending or active interrupts. */
83 	EXPECT_EQ(io_read32_array(GICD_ISPENDR, 0), 0);
84 	EXPECT_EQ(io_read32(GICR_ISPENDR0), 0);
85 	EXPECT_EQ(io_read32_array(GICD_ISACTIVER, 0), 0);
86 	EXPECT_EQ(io_read32(GICR_ISACTIVER0), 0);
87 }
88 
89 /**
90  * This test arms a timer in the normal world and emits a direct request to a
91  * secure partition to query for a busy loop. The timer physical PPI NS
92  * interrupt traps to Hafnium/SPMC which saves the currently running SP vCPU
93  * state and returns to the normal world. The latter traps to the irq handler
94  * and handles the timer interrupt. The SP vCPU is then resumed again through
95  * FFA_RUN which completes the busy loop and returns a sucess direct msg
96  * response.
97  */
TEST(interrupts,sp_preempted_by_ns_interrupt)98 TEST(interrupts, sp_preempted_by_ns_interrupt)
99 {
100 	struct ffa_value res;
101 	struct mailbox_buffers mb = set_up_mailbox();
102 	struct ffa_partition_info *receiver_info = service2(mb.recv);
103 	const ffa_id_t receiver_id = receiver_info->vm_id;
104 
105 	setup_physical_timer();
106 	start_physical_timer(20000000);
107 
108 	/* Send direct request to query SP to wait in a busy loop. */
109 	res = sp_busy_loop_cmd_send(
110 		hf_vm_get_id(), receiver_id,
111 		TEST_SP_PREEMPTED_BY_NS_INTERRUPT_LOOP_COUNT);
112 
113 	/* SP is pre-empted by the non-secure timer interrupt. */
114 	EXPECT_EQ(res.func, FFA_INTERRUPT_32);
115 
116 	/* VM id/vCPU index are passed through arg1. */
117 	EXPECT_EQ(res.arg1, ffa_vm_vcpu(receiver_id, 0));
118 
119 	check_physical_timer_interrupt_serviced();
120 
121 	/* Resume the SP to complete the busy loop and return with success. */
122 	res = ffa_run(ffa_vm_id(res), ffa_vcpu_index(res));
123 	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
124 	EXPECT_EQ(res.arg3, SP_SUCCESS);
125 }
126 
127 /**
128  * This test arms a timer in the normal world and emits a direct request to a
129  * secure partition to query for a busy loop. The timer physical PPI NS
130  * interrupt traps to Hafnium/SPMC at S-EL2 as FIQ. SPMC injects a managed
131  * exit vIRQ interrupt(as requested by the secure partition through the
132  * `managed-exit-virq` field in its manifest). Further, SPMC resumes the SP
133  * causing it to run its interrupt handler. SP sends a managed exit (direct
134  * message) response to the normal world. The latter traps to the irq handler
135  * and handles the timer interrupt. The SP vCPU is then resumed again through
136  * a special direct message request which completes the busy loop and returns
137  * a success direct msg response.
138  */
TEST(interrupts,sp_managed_exit)139 TEST(interrupts, sp_managed_exit)
140 {
141 	struct ffa_value res;
142 	ffa_id_t own_id = hf_vm_get_id();
143 	struct mailbox_buffers mb = set_up_mailbox();
144 	struct ffa_partition_info *receiver_info = service1(mb.recv);
145 	const ffa_id_t receiver_id = receiver_info->vm_id;
146 
147 	setup_physical_timer();
148 
149 	/* Enable SP to handle managed exit. */
150 	res = sp_virtual_interrupt_cmd_send(own_id, receiver_id,
151 					    HF_MANAGED_EXIT_INTID, true,
152 					    INTERRUPT_TYPE_IRQ);
153 
154 	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
155 	EXPECT_EQ(sp_resp(res), SP_SUCCESS);
156 
157 	start_physical_timer(20000000);
158 
159 	/* Send direct request to query SP to wait in a busy loop. */
160 	res = sp_busy_loop_cmd_send(
161 		hf_vm_get_id(), receiver_id,
162 		TEST_SP_PREEMPTED_BY_NS_INTERRUPT_LOOP_COUNT);
163 
164 	/* Expect a managed exit response from SP. */
165 	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
166 	EXPECT_EQ(sp_resp(res), HF_MANAGED_EXIT_INTID);
167 
168 	check_physical_timer_interrupt_serviced();
169 
170 	/* Resume the SP to complete the busy loop and return with success. */
171 	res = sp_resume_after_managed_exit_send(own_id, receiver_id);
172 	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
173 	EXPECT_EQ(res.arg3, SP_SUCCESS);
174 }
175