13d8536b4Sopenharmony_ci/*
23d8536b4Sopenharmony_ci * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
33d8536b4Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
43d8536b4Sopenharmony_ci *
53d8536b4Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification,
63d8536b4Sopenharmony_ci * are permitted provided that the following conditions are met:
73d8536b4Sopenharmony_ci *
83d8536b4Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice, this list of
93d8536b4Sopenharmony_ci *    conditions and the following disclaimer.
103d8536b4Sopenharmony_ci *
113d8536b4Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice, this list
123d8536b4Sopenharmony_ci *    of conditions and the following disclaimer in the documentation and/or other materials
133d8536b4Sopenharmony_ci *    provided with the distribution.
143d8536b4Sopenharmony_ci *
153d8536b4Sopenharmony_ci * 3. Neither the name of the copyright holder nor the names of its contributors may be used
163d8536b4Sopenharmony_ci *    to endorse or promote products derived from this software without specific prior written
173d8536b4Sopenharmony_ci *    permission.
183d8536b4Sopenharmony_ci *
193d8536b4Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
203d8536b4Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
213d8536b4Sopenharmony_ci * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
223d8536b4Sopenharmony_ci * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
233d8536b4Sopenharmony_ci * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
243d8536b4Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
253d8536b4Sopenharmony_ci * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
263d8536b4Sopenharmony_ci * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
273d8536b4Sopenharmony_ci * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
283d8536b4Sopenharmony_ci * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
293d8536b4Sopenharmony_ci * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
303d8536b4Sopenharmony_ci */
313d8536b4Sopenharmony_ci
323d8536b4Sopenharmony_ci#include "los_exchook.h"
333d8536b4Sopenharmony_ci#include "los_context.h"
343d8536b4Sopenharmony_ci
353d8536b4Sopenharmony_ci#ifndef LOSCFG_BASE_EXC_HOOK_LIMIT
363d8536b4Sopenharmony_ci#define LOSCFG_BASE_EXC_HOOK_LIMIT  16
373d8536b4Sopenharmony_ci#endif
383d8536b4Sopenharmony_ci
393d8536b4Sopenharmony_cistruct Node {
403d8536b4Sopenharmony_ci    ExcHookFn excHookFn;
413d8536b4Sopenharmony_ci    struct Node *next;
423d8536b4Sopenharmony_ci};
433d8536b4Sopenharmony_ci
443d8536b4Sopenharmony_ciSTATIC struct Node g_excNodes[LOSCFG_BASE_EXC_HOOK_LIMIT];
453d8536b4Sopenharmony_ciSTATIC struct Node *g_excHeads[EXC_TYPE_END + 1]; /* EXC_TYPE_END is used for the free list. */
463d8536b4Sopenharmony_ci
473d8536b4Sopenharmony_ciSTATIC VOID DoExcHookInRegOrder(EXC_TYPE excType, struct Node *node)
483d8536b4Sopenharmony_ci{
493d8536b4Sopenharmony_ci    if (node != NULL) {
503d8536b4Sopenharmony_ci        DoExcHookInRegOrder(excType, node->next);
513d8536b4Sopenharmony_ci        node->excHookFn(excType);
523d8536b4Sopenharmony_ci    }
533d8536b4Sopenharmony_ci}
543d8536b4Sopenharmony_ci
553d8536b4Sopenharmony_ciSTATIC VOID DoExcHook(EXC_TYPE excType)
563d8536b4Sopenharmony_ci{
573d8536b4Sopenharmony_ci    UINT32 intSave;
583d8536b4Sopenharmony_ci    if (excType >= EXC_TYPE_END) {
593d8536b4Sopenharmony_ci        return;
603d8536b4Sopenharmony_ci    }
613d8536b4Sopenharmony_ci    intSave = LOS_IntLock();
623d8536b4Sopenharmony_ci    DoExcHookInRegOrder(excType, g_excHeads[excType]);
633d8536b4Sopenharmony_ci    LOS_IntRestore(intSave);
643d8536b4Sopenharmony_ci}
653d8536b4Sopenharmony_ci
663d8536b4Sopenharmony_ciSTATIC struct Node *GetFreeNode(VOID)
673d8536b4Sopenharmony_ci{
683d8536b4Sopenharmony_ci    struct Node *node = NULL;
693d8536b4Sopenharmony_ci    int i;
703d8536b4Sopenharmony_ci    if (g_excHeads[EXC_TYPE_END] == NULL) {
713d8536b4Sopenharmony_ci        if (g_excNodes[0].excHookFn != NULL) {
723d8536b4Sopenharmony_ci            /* no free node now */
733d8536b4Sopenharmony_ci            return NULL;
743d8536b4Sopenharmony_ci        } else {
753d8536b4Sopenharmony_ci            /* Initialize the free list */
763d8536b4Sopenharmony_ci            for (i = 0; i < LOSCFG_BASE_EXC_HOOK_LIMIT; ++i) {
773d8536b4Sopenharmony_ci                g_excNodes[i].next = g_excHeads[EXC_TYPE_END];
783d8536b4Sopenharmony_ci                g_excHeads[EXC_TYPE_END] = &g_excNodes[i];
793d8536b4Sopenharmony_ci            }
803d8536b4Sopenharmony_ci            OsExcHookRegister(DoExcHook);
813d8536b4Sopenharmony_ci        }
823d8536b4Sopenharmony_ci    }
833d8536b4Sopenharmony_ci
843d8536b4Sopenharmony_ci    node = g_excHeads[EXC_TYPE_END];
853d8536b4Sopenharmony_ci    g_excHeads[EXC_TYPE_END] = node->next;
863d8536b4Sopenharmony_ci    return node;
873d8536b4Sopenharmony_ci}
883d8536b4Sopenharmony_ci
893d8536b4Sopenharmony_ciUINT32 LOS_RegExcHook(EXC_TYPE excType, ExcHookFn excHookFn)
903d8536b4Sopenharmony_ci{
913d8536b4Sopenharmony_ci    UINT32 intSave;
923d8536b4Sopenharmony_ci    struct Node *node = NULL;
933d8536b4Sopenharmony_ci    if (excType >= EXC_TYPE_END || excHookFn == NULL) {
943d8536b4Sopenharmony_ci        return LOS_ERRNO_SYS_PTR_NULL;
953d8536b4Sopenharmony_ci    }
963d8536b4Sopenharmony_ci
973d8536b4Sopenharmony_ci    intSave = LOS_IntLock();
983d8536b4Sopenharmony_ci    node = GetFreeNode();
993d8536b4Sopenharmony_ci    if (node == NULL) {
1003d8536b4Sopenharmony_ci        LOS_IntRestore(intSave);
1013d8536b4Sopenharmony_ci        return LOS_ERRNO_SYS_HOOK_IS_FULL;
1023d8536b4Sopenharmony_ci    }
1033d8536b4Sopenharmony_ci
1043d8536b4Sopenharmony_ci    node->excHookFn = excHookFn;
1053d8536b4Sopenharmony_ci    node->next = g_excHeads[excType];
1063d8536b4Sopenharmony_ci    g_excHeads[excType] = node;
1073d8536b4Sopenharmony_ci    LOS_IntRestore(intSave);
1083d8536b4Sopenharmony_ci    return LOS_OK;
1093d8536b4Sopenharmony_ci}
1103d8536b4Sopenharmony_ci
1113d8536b4Sopenharmony_ciUINT32 LOS_UnRegExcHook(EXC_TYPE excType, ExcHookFn excHookFn)
1123d8536b4Sopenharmony_ci{
1133d8536b4Sopenharmony_ci    UINT32 intSave;
1143d8536b4Sopenharmony_ci    struct Node *node = NULL;
1153d8536b4Sopenharmony_ci    struct Node *preNode = NULL;
1163d8536b4Sopenharmony_ci    if (excType >= EXC_TYPE_END || excHookFn == NULL) {
1173d8536b4Sopenharmony_ci        return LOS_ERRNO_SYS_PTR_NULL;
1183d8536b4Sopenharmony_ci    }
1193d8536b4Sopenharmony_ci
1203d8536b4Sopenharmony_ci    intSave = LOS_IntLock();
1213d8536b4Sopenharmony_ci    for (node = g_excHeads[excType]; node != NULL; node = node->next) {
1223d8536b4Sopenharmony_ci        if (node->excHookFn == excHookFn) {
1233d8536b4Sopenharmony_ci            if (preNode) {
1243d8536b4Sopenharmony_ci                preNode->next = node->next;
1253d8536b4Sopenharmony_ci            } else {
1263d8536b4Sopenharmony_ci                g_excHeads[excType] = node->next;
1273d8536b4Sopenharmony_ci            }
1283d8536b4Sopenharmony_ci            node->excHookFn = NULL;
1293d8536b4Sopenharmony_ci            node->next = g_excHeads[EXC_TYPE_END];
1303d8536b4Sopenharmony_ci            g_excHeads[EXC_TYPE_END] = node;
1313d8536b4Sopenharmony_ci        }
1323d8536b4Sopenharmony_ci        preNode = node;
1333d8536b4Sopenharmony_ci    }
1343d8536b4Sopenharmony_ci    LOS_IntRestore(intSave);
1353d8536b4Sopenharmony_ci    return LOS_OK;
1363d8536b4Sopenharmony_ci}
137