1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the GNU General Public License version 2. Note that NO WARRANTY is provided.
8 * See "LICENSE_GPLv2.txt" for details.
9 *
10 * @TAG(DATA61_GPL)
11 */
12
13#include <config.h>
14#include <arch/kernel/traps.h>
15#include <arch/object/vcpu.h>
16#include <arch/machine/registerset.h>
17#include <api/syscall.h>
18#include <machine/fpu.h>
19
20#include <benchmark/benchmark_track_types.h>
21#include <benchmark/benchmark_track.h>
22#include <benchmark/benchmark_utilisation.h>
23#include <arch/machine.h>
24
25void VISIBLE NORETURN
26c_handle_undefined_instruction(void)
27{
28    NODE_LOCK_SYS;
29    c_entry_hook();
30
31#ifdef TRACK_KERNEL_ENTRIES
32    ksKernelEntry.path = Entry_UserLevelFault;
33    ksKernelEntry.word = getRegister(NODE_STATE(ksCurThread), LR_svc);
34#endif
35
36#if defined(CONFIG_HAVE_FPU) && defined(CONFIG_ARCH_AARCH32)
37    /* We assume the first fault is a FP exception and enable FPU, if not already enabled */
38    if (!isFpuEnable()) {
39        handleFPUFault();
40
41        /* Restart the FP instruction that cause the fault */
42        setNextPC(NODE_STATE(ksCurThread), getRestartPC(NODE_STATE(ksCurThread)));
43    } else {
44        handleUserLevelFault(0, 0);
45    }
46
47    restore_user_context();
48    UNREACHABLE();
49#endif
50
51    /* There's only one user-level fault on ARM, and the code is (0,0) */
52    handleUserLevelFault(0, 0);
53    restore_user_context();
54    UNREACHABLE();
55}
56
57#if defined(CONFIG_HAVE_FPU) && defined(CONFIG_ARCH_AARCH64)
58void VISIBLE NORETURN
59c_handle_enfp(void)
60{
61    c_entry_hook();
62
63    handleFPUFault();
64    restore_user_context();
65    UNREACHABLE();
66}
67#endif /* CONFIG_HAVE_FPU */
68
69static inline void NORETURN
70c_handle_vm_fault(vm_fault_type_t type)
71{
72    NODE_LOCK_SYS;
73    c_entry_hook();
74
75#ifdef TRACK_KERNEL_ENTRIES
76    ksKernelEntry.path = Entry_VMFault;
77    ksKernelEntry.word = getRegister(NODE_STATE(ksCurThread), LR_svc);
78#endif
79
80    handleVMFaultEvent(type);
81    restore_user_context();
82    UNREACHABLE();
83}
84
85void VISIBLE NORETURN
86c_handle_data_fault(void)
87{
88    c_handle_vm_fault(seL4_DataFault);
89}
90
91void VISIBLE NORETURN
92c_handle_instruction_fault(void)
93{
94    c_handle_vm_fault(seL4_InstructionFault);
95}
96
97void VISIBLE NORETURN
98c_handle_interrupt(void)
99{
100    NODE_LOCK_IRQ_IF(getActiveIRQ() != irq_remote_call_ipi);
101    c_entry_hook();
102
103#ifdef TRACK_KERNEL_ENTRIES
104    ksKernelEntry.path = Entry_Interrupt;
105    ksKernelEntry.word = getActiveIRQ();
106#endif
107
108    handleInterruptEntry();
109    restore_user_context();
110}
111
112void NORETURN
113slowpath(syscall_t syscall)
114{
115#ifdef TRACK_KERNEL_ENTRIES
116    ksKernelEntry.is_fastpath = 0;
117#endif /* TRACK KERNEL ENTRIES */
118    handleSyscall(syscall);
119
120    restore_user_context();
121    UNREACHABLE();
122}
123
124void VISIBLE
125c_handle_syscall(word_t cptr, word_t msgInfo, syscall_t syscall, word_t reply)
126{
127    NODE_LOCK_SYS;
128
129    c_entry_hook();
130#ifdef TRACK_KERNEL_ENTRIES
131    benchmark_debug_syscall_start(cptr, msgInfo, syscall);
132    ksKernelEntry.is_fastpath = 1;
133#endif /* DEBUG */
134
135#ifdef CONFIG_FASTPATH
136    if (syscall == SysCall) {
137        fastpath_call(cptr, msgInfo);
138        UNREACHABLE();
139    } else if (syscall == SysReplyRecv) {
140        fastpath_reply_recv(cptr, msgInfo, reply);
141        UNREACHABLE();
142    }
143#endif /* CONFIG_FASTPATH */
144
145    if (unlikely(syscall < SYSCALL_MIN || syscall > SYSCALL_MAX)) {
146#ifdef TRACK_KERNEL_ENTRIES
147        ksKernelEntry.path = Entry_UnknownSyscall;
148        /* ksKernelEntry.word word is already set to syscall */
149#endif /* TRACK_KERNEL_ENTRIES */
150        handleUnknownSyscall(syscall);
151        restore_user_context();
152        UNREACHABLE();
153    } else {
154        slowpath(syscall);
155        UNREACHABLE();
156    }
157}
158
159#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
160VISIBLE NORETURN void
161c_handle_vcpu_fault(word_t hsr)
162{
163    c_entry_hook();
164
165#ifdef TRACK_KERNEL_ENTRIES
166    ksKernelEntry.path = Entry_VCPUFault;
167    ksKernelEntry.word = hsr;
168#endif
169    handleVCPUFault(hsr);
170    restore_user_context();
171    UNREACHABLE();
172}
173#endif /* CONFIG_ARM_HYPERVISOR_SUPPORT */
174