1 // © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
2 //
3 // SPDX-License-Identifier: BSD-3-Clause
4
5 #include <assert.h>
6 #include <hyptypes.h>
7
8 #include <hypcontainers.h>
9
10 #include <atomic.h>
11 #include <compiler.h>
12 #include <panic.h>
13 #include <scheduler.h>
14 #include <trace.h>
15 #include <virq.h>
16
17 #include "arm_vm_timer.h"
18 #include "event_handlers.h"
19
20 static void
arm_vm_timer_inject_timer_virq(thread_t * thread,arm_vm_timer_type_t tt)21 arm_vm_timer_inject_timer_virq(thread_t *thread, arm_vm_timer_type_t tt)
22 {
23 if (tt == ARM_VM_TIMER_TYPE_VIRTUAL) {
24 (void)virq_assert(&thread->virtual_timer_virq_src, false);
25 } else if (tt == ARM_VM_TIMER_TYPE_PHYSICAL) {
26 (void)virq_assert(&thread->physical_timer_virq_src, false);
27 } else {
28 panic("Invalid timer");
29 }
30 }
31
32 // Handle the timer queue expiry coming from the hyp arch timer
33 static void
arm_vm_timer_type_timer_action(thread_t * thread,arm_vm_timer_type_t tt)34 arm_vm_timer_type_timer_action(thread_t *thread, arm_vm_timer_type_t tt)
35 {
36 bool is_current = thread_get_self() == thread;
37
38 if (is_current && arm_vm_timer_is_irq_pending(tt)) {
39 arm_vm_timer_inject_timer_virq(thread, tt);
40 } else if (!is_current &&
41 arm_vm_timer_is_irq_enabled_thread(thread, tt)) {
42 arm_vm_timer_inject_timer_virq(thread, tt);
43 } else {
44 TRACE(DEBUG, INFO, "Redundant VM hyp timeout");
45 }
46 }
47
48 bool
arm_vm_timer_handle_timer_action(timer_action_t action_type,timer_t * timer)49 arm_vm_timer_handle_timer_action(timer_action_t action_type, timer_t *timer)
50 {
51 if (action_type == TIMER_ACTION_VIRTUAL_TIMER) {
52 arm_vm_timer_type_timer_action(
53 thread_container_of_virtual_timer(timer),
54 ARM_VM_TIMER_TYPE_VIRTUAL);
55 } else if (action_type == TIMER_ACTION_PHYSICAL_TIMER) {
56 arm_vm_timer_type_timer_action(
57 thread_container_of_physical_timer(timer),
58 ARM_VM_TIMER_TYPE_PHYSICAL);
59 } else {
60 TRACE(DEBUG, INFO, "Spurious VM hyp timeout");
61 }
62
63 return true;
64 }
65
66 // Handle the VM arch timer expiry
67 static bool
arm_vm_timer_type_irq_received(thread_t * thread,arm_vm_timer_type_t tt)68 arm_vm_timer_type_irq_received(thread_t *thread, arm_vm_timer_type_t tt)
69 REQUIRE_PREEMPT_DISABLED
70 {
71 bool injected = false;
72
73 if (arm_vm_timer_is_irq_pending(tt)) {
74 arm_vm_timer_inject_timer_virq(thread, tt);
75 arm_vm_timer_arch_timer_hw_irq_activated(tt);
76 injected = true;
77 } else {
78 TRACE(DEBUG, INFO, "Spurious VM timer IRQ");
79 }
80
81 return injected;
82 }
83
84 bool
arm_vm_timer_handle_irq_received(irq_t irq)85 arm_vm_timer_handle_irq_received(irq_t irq)
86 {
87 bool injected = false;
88 thread_t *thread = thread_get_self();
89
90 if (irq == PLATFORM_VM_ARCH_VIRTUAL_TIMER_IRQ) {
91 injected = arm_vm_timer_type_irq_received(
92 thread, ARM_VM_TIMER_TYPE_VIRTUAL);
93 } else if (irq == PLATFORM_VM_ARCH_PHYSICAL_TIMER_IRQ) {
94 injected = arm_vm_timer_type_irq_received(
95 thread, ARM_VM_TIMER_TYPE_PHYSICAL);
96 } else {
97 panic("Invalid VM timer IRQ");
98 }
99
100 return !injected;
101 }
102
103 static bool
arm_vm_timer_virq_check_pending(thread_t * thread,arm_vm_timer_type_t tt)104 arm_vm_timer_virq_check_pending(thread_t *thread, arm_vm_timer_type_t tt)
105 REQUIRE_PREEMPT_DISABLED
106 {
107 bool ret = true;
108
109 if (thread == thread_get_self()) {
110 ret = arm_vm_timer_is_irq_pending(tt);
111
112 if (!ret) {
113 arm_vm_timer_arch_timer_hw_irq_deactivate(tt);
114 }
115 }
116
117 return ret;
118 }
119
120 bool
arm_vm_timer_handle_virq_check_pending(virq_trigger_t trigger,virq_source_t * source)121 arm_vm_timer_handle_virq_check_pending(virq_trigger_t trigger,
122 virq_source_t *source)
123 {
124 bool ret = true;
125
126 if (trigger == VIRQ_TRIGGER_VIRTUAL_TIMER) {
127 ret = arm_vm_timer_virq_check_pending(
128 thread_container_of_virtual_timer_virq_src(source),
129 ARM_VM_TIMER_TYPE_VIRTUAL);
130
131 } else if (trigger == VIRQ_TRIGGER_PHYSICAL_TIMER) {
132 ret = arm_vm_timer_virq_check_pending(
133 thread_container_of_physical_timer_virq_src(source),
134 ARM_VM_TIMER_TYPE_PHYSICAL);
135 } else {
136 /* Do Nothing */
137 }
138
139 return ret;
140 }
141