1/*
2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2020-2023 Huawei Device Co., Ltd. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 *    conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 *    of conditions and the following disclaimer in the documentation and/or other materials
13 *    provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16 *    to endorse or promote products derived from this software without specific prior written
17 *    permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <stdarg.h>
33#include "securec.h"
34#include "los_context.h"
35#include "los_arch_interrupt.h"
36#include "los_debug.h"
37#include "los_hook.h"
38#include "los_task.h"
39#include "los_sched.h"
40#include "los_memory.h"
41#include "los_membox.h"
42#include "los_arch_regs.h"
43
44/* *
45 * @ingroup los_hwi
46 * Lock all interrupt.
47 */
48UINT32 ArchIntLock(VOID)
49{
50    UINT32 ret;
51
52    __asm__ volatile("rsil %0, %1" : "=r"(ret) : "i"(INT_MASK) : "memory");
53    return ret;
54}
55
56/* *
57 * @ingroup los_hwi
58 * Restore interrupt status.
59 */
60VOID ArchIntRestore(UINT32 intSave)
61{
62    __asm__ volatile("wsr.ps %0; rsync" : : "r"(intSave) : "memory");
63}
64
65/* *
66 * @ingroup los_hwi
67 * Unlock interrupt.
68 */
69UINT32 ArchIntUnLock(VOID)
70{
71    UINT32 intSave;
72
73    __asm__ volatile("rsil %0, %1" : "=r"(intSave) : "i"(0) : "memory");
74
75    return intSave;
76}
77
78/* *
79 * @ingroup los_hwi
80 * Determine if the interrupt is locked
81 */
82STATIC INLINE UINT32 ArchIntLocked(VOID)
83{
84    UINT32 intSave;
85
86    __asm__ volatile("rsr %0, ps " : "=r"(intSave) : : "memory");
87
88    return (intSave & SPREG_PS_DI_MASK);
89}
90
91/* *
92 * @ingroup los_hwi
93 * Trigger the interrupt
94 */
95STATIC UINT32 HwiPending(HWI_HANDLE_T hwiNum)
96{
97    __asm__ __volatile__("wsr   %0, intset; rsync" : : "a"(0x1U << hwiNum));
98    return LOS_OK;
99}
100
101STATIC UINT32 HwiUnmask(HWI_HANDLE_T hwiNum)
102{
103    UINT32 ier;
104
105    __asm__ __volatile__("rsr %0, intenable" : "=a"(ier) : : "memory");
106    __asm__ __volatile__("wsr %0, intenable; rsync" : : "a"(ier | ((UINT32)0x1U << hwiNum)));
107
108    return LOS_OK;
109}
110
111STATIC UINT32 HwiMask(HWI_HANDLE_T hwiNum)
112{
113    UINT32 ier;
114
115    __asm__ __volatile__("rsr %0, intenable" : "=a"(ier) : : "memory");
116    __asm__ __volatile__("wsr %0, intenable; rsync" : : "a"(ier & ~((UINT32)0x1U << hwiNum)));
117
118    return LOS_OK;
119}
120
121/* ****************************************************************************
122 Function    : HwiNumGet
123 Description : Get an interrupt number
124 Input       : None
125 Output      : None
126 Return      : Interrupt Indexes number
127 **************************************************************************** */
128STATIC UINT32 HwiNumGet(VOID)
129{
130    UINT32 ier;
131    UINT32 intenable;
132    UINT32 intSave;
133
134    __asm__ __volatile__("rsr %0, interrupt" : "=a"(ier) : : "memory");
135    __asm__ __volatile__("rsr %0, intenable" : "=a"(intenable) : : "memory");
136
137    intSave = ier & intenable;
138
139    return  __builtin_ffs(intSave) - 1;
140}
141
142/* *
143 * @ingroup los_hwi
144 * Clear the interrupt
145 */
146STATIC UINT32 HwiClear(HWI_HANDLE_T hwiNum)
147{
148    __asm__ __volatile__("wsr   %0, intclear; rsync" : : "a"(0x1U << hwiNum));
149
150    return LOS_OK;
151}
152
153STATIC UINT32 HwiCreate(HWI_HANDLE_T hwiNum, HWI_PRIOR_T hwiPrio)
154{
155    (VOID)hwiPrio;
156    HwiUnmask(hwiNum);
157    return LOS_OK;
158}
159
160STATIC HwiControllerOps g_archHwiOps = {
161    .triggerIrq     = HwiPending,
162    .enableIrq      = HwiUnmask,
163    .disableIrq     = HwiMask,
164    .getCurIrqNum   = HwiNumGet,
165    .clearIrq       = HwiClear,
166    .createIrq      = HwiCreate,
167};
168
169HwiControllerOps *ArchIntOpsGet(VOID)
170{
171    return &g_archHwiOps;
172}
173
174/* ****************************************************************************
175 Function    : HalInterrupt
176 Description : Hardware interrupt entry function
177 Input       : None
178 Output      : None
179 Return      : None
180 **************************************************************************** */
181VOID HalInterrupt(VOID)
182{
183    UINT32 hwiIndex;
184    UINT32 intSave;
185
186    intSave = LOS_IntLock();
187    g_intCount++;
188    LOS_IntRestore(intSave);
189
190    hwiIndex = HwiNumGet();
191    HwiClear(hwiIndex);
192
193    OsHookCall(LOS_HOOK_TYPE_ISR_ENTER, hwiIndex);
194
195    HalPreInterruptHandler(hwiIndex);
196
197#if (LOSCFG_PLATFORM_HWI_WITH_ARG == 1)
198    if (g_hwiHandlerForm[hwiIndex].pfnHandler != 0) {
199        g_hwiHandlerForm[hwiIndex].pfnHandler((VOID *)g_hwiHandlerForm[hwiIndex].pParm);
200    }
201#else
202    if (g_hwiHandlerForm[hwiIndex] != 0) {
203        g_hwiHandlerForm[hwiIndex]();
204    }
205#endif
206
207    HalAftInterruptHandler(hwiIndex);
208
209    OsHookCall(LOS_HOOK_TYPE_ISR_EXIT, hwiIndex);
210
211    intSave = LOS_IntLock();
212    g_intCount--;
213    LOS_IntRestore(intSave);
214    HalIrqEndCheckNeedSched();
215}
216
217ExcInfo g_excInfo = {0};
218
219#if (LOSCFG_KERNEL_PRINTF != 0)
220
221STATIC VOID OsExcTypeInfo(const ExcInfo *excInfo)
222{
223    CHAR *phaseStr[] = {"exc in init", "exc in task", "exc in hwi"};
224
225    PRINTK("Type      = %d\n", excInfo->type);
226    PRINTK("ThrdPid   = %d\n", excInfo->thrdPid);
227    PRINTK("Phase     = %s\n", phaseStr[excInfo->phase]);
228    PRINTK("FaultAddr = 0x%x\n", excInfo->faultAddr);
229}
230
231STATIC VOID OsExcCurTaskInfo(const ExcInfo *excInfo)
232{
233    PRINTK("Current task info:\n");
234    if (excInfo->phase == OS_EXC_IN_TASK) {
235        LosTaskCB *taskCB = OS_TCB_FROM_TID(LOS_CurTaskIDGet());
236        PRINTK("Task name = %s\n", taskCB->taskName);
237        PRINTK("Task ID   = %d\n", taskCB->taskID);
238        PRINTK("Task SP   = 0x%x\n", (UINTPTR)taskCB->stackPointer);
239        PRINTK("Task ST   = 0x%x\n", taskCB->topOfStack);
240        PRINTK("Task SS   = 0x%x\n", taskCB->stackSize);
241    } else if (excInfo->phase == OS_EXC_IN_HWI) {
242        PRINTK("Exception occur in interrupt phase!\n");
243    } else {
244        PRINTK("Exception occur in system init phase!\n");
245    }
246}
247
248STATIC VOID OsExcRegInfo(const ExcInfo *excInfo)
249{
250    INT32 index;
251    PRINTK("Exception reg dump:\n");
252    PRINTK("sar          = 0x%x\n", excInfo->context->sar);
253    PRINTK("excCause     = 0x%x\n", excInfo->context->excCause);
254    PRINTK("excVaddr     = 0x%x\n", excInfo->context->excVaddr);
255    PRINTK("lbeg         = 0x%x\n", excInfo->context->lbeg);
256    PRINTK("lend         = 0x%x\n", excInfo->context->lend);
257    PRINTK("lcount       = 0x%x\n", excInfo->context->lcount);
258    PRINTK("pc           = 0x%x\n", excInfo->context->pc);
259    PRINTK("ps           = 0x%x\n", excInfo->context->ps);
260    for (index = 0; index < XTENSA_LOGREG_NUM; index++) {
261        PRINTK("regA%d        = 0x%x\n", index, excInfo->context->regA[index]);
262    }
263}
264
265#if (LOSCFG_KERNEL_BACKTRACE == 1)
266STATIC VOID OsExcBackTraceInfo(const ExcInfo *excInfo)
267{
268    UINTPTR LR[LOSCFG_BACKTRACE_DEPTH] = {0};
269    UINT32 index;
270
271    OsBackTraceHookCall(LR, LOSCFG_BACKTRACE_DEPTH, 0, excInfo->context->regA[1]);
272
273    PRINTK("----- backtrace start -----\n");
274    for (index = 0; index < LOSCFG_BACKTRACE_DEPTH; index++) {
275        if (LR[index] == 0) {
276            break;
277        }
278        PRINTK("backtrace %d -- lr = 0x%x\n", index, LR[index]);
279    }
280    PRINTK("----- backtrace end -----\n");
281}
282#endif
283
284STATIC VOID OsExcMemPoolCheckInfo(VOID)
285{
286    PRINTK("\r\nmemory pools check:\n");
287#if (LOSCFG_PLATFORM_EXC == 1)
288    MemInfoCB memExcInfo[OS_SYS_MEM_NUM];
289    UINT32 errCnt;
290    UINT32 i;
291
292    (VOID)memset_s(memExcInfo, sizeof(memExcInfo), 0, sizeof(memExcInfo));
293
294    errCnt = OsMemExcInfoGet(OS_SYS_MEM_NUM, memExcInfo);
295    if (errCnt < OS_SYS_MEM_NUM) {
296        errCnt += OsMemboxExcInfoGet(OS_SYS_MEM_NUM - errCnt, memExcInfo + errCnt);
297    }
298
299    if (errCnt == 0) {
300        PRINTK("all memory pool check passed!\n");
301        return;
302    }
303
304    for (i = 0; i < errCnt; i++) {
305        PRINTK("pool num    = %d\n", i);
306        PRINTK("pool type   = %d\n", memExcInfo[i].type);
307        PRINTK("pool addr   = 0x%x\n", memExcInfo[i].startAddr);
308        PRINTK("pool size   = 0x%x\n", memExcInfo[i].size);
309        PRINTK("pool free   = 0x%x\n", memExcInfo[i].free);
310        PRINTK("pool blkNum = %d\n", memExcInfo[i].blockSize);
311        PRINTK("pool error node addr  = 0x%x\n", memExcInfo[i].errorAddr);
312        PRINTK("pool error node len   = 0x%x\n", memExcInfo[i].errorLen);
313        PRINTK("pool error node owner = %d\n", memExcInfo[i].errorOwner);
314    }
315#endif
316    UINT32 ret = LOS_MemIntegrityCheck(LOSCFG_SYS_HEAP_ADDR);
317    if (ret == LOS_OK) {
318        PRINTK("system heap memcheck over, all passed!\n");
319    }
320
321    PRINTK("memory pool check end!\n");
322}
323#endif
324
325STATIC VOID OsExcInfoDisplay(const ExcInfo *excInfo)
326{
327#if (LOSCFG_KERNEL_PRINTF != 0)
328    PRINTK("*************Exception Information**************\n");
329    OsExcTypeInfo(excInfo);
330    OsExcCurTaskInfo(excInfo);
331    OsExcRegInfo(excInfo);
332#if (LOSCFG_KERNEL_BACKTRACE == 1)
333    OsExcBackTraceInfo(excInfo);
334#endif
335    OsGetAllTskInfo();
336    OsExcMemPoolCheckInfo();
337#endif
338}
339
340VOID HalExcHandleEntry(UINTPTR faultAddr, EXC_CONTEXT_S *excBufAddr, UINT32 type)
341{
342    g_excInfo.nestCnt++;
343    g_excInfo.faultAddr = faultAddr;
344    g_excInfo.type = type;
345
346    LosTaskCB *taskCB = g_losTask.runTask;
347
348    if ((taskCB == NULL) || (taskCB == OS_TCB_FROM_TID(g_taskMaxNum))) {
349        g_excInfo.phase = OS_EXC_IN_INIT;
350        g_excInfo.thrdPid = OS_NULL_INT;
351    } else if (HwiNumGet() != OS_NULL_INT) {
352        g_excInfo.phase = OS_EXC_IN_HWI;
353        g_excInfo.thrdPid = HwiNumGet();
354    } else {
355        g_excInfo.phase = OS_EXC_IN_TASK;
356        g_excInfo.thrdPid = g_losTask.runTask->taskID;
357    }
358
359    g_excInfo.context = excBufAddr;
360
361    OsDoExcHook(EXC_INTERRUPT);
362    OsExcInfoDisplay(&g_excInfo);
363    ArchSysExit();
364}
365
366/* Stack protector */
367WEAK UINT32 __stack_chk_guard = 0xd00a0dff;
368
369WEAK VOID __stack_chk_fail(VOID)
370{
371    /* __builtin_return_address is a builtin function, building in gcc */
372    LOS_Panic("stack-protector: Kernel stack is corrupted in: 0x%x\n",
373              __builtin_return_address(0));
374}
375
376/* ****************************************************************************
377 Function    : HalHwiInit
378 Description : initialization of the hardware interrupt
379 Input       : None
380 Output      : None
381 Return      : None
382 **************************************************************************** */
383VOID HalHwiInit(VOID)
384{
385    EnableExceptionInterface();
386    HWI_PROC_FUNC *hwiForm = (HWI_PROC_FUNC *)ArchGetHwiFrom();
387    for (UINT32 i = 0; i < OS_HWI_MAX_NUM; i++) {
388        hwiForm[i + OS_SYS_VECTOR_CNT] = HalHwiDefaultHandler;
389        HwiMask(i);
390    }
391    asm volatile ("wsr %0, vecbase" : : "r"(INIT_VECTOR_START));
392    return;
393}
394