/* SPDX-License-Identifier: Apache-2.0 OR MIT */ /* * Copyright (c) 2024 Rockchip Electronics Co., Ltd. */ #include "kmpp_obj_macro.h" #ifdef __OBJECT_HERLPER_H__ #error “MUST NOT include obj_helper.h within obj_helper.h“ #endif /* define object helper for loop include detection */ #define __OBJECT_HERLPER_H__ #if !defined(KMPP_OBJ_NAME) || \ !defined(KMPP_OBJ_INTF_TYPE) || \ !defined(KMPP_OBJ_IMPL_TYPE) #warning "When using kmpp_obj_helper.h The following macro must be defined:" #warning "KMPP_OBJ_NAME - object name" #warning "KMPP_OBJ_INTF_TYPE - object interface type" #warning "KMPP_OBJ_IMPL_TYPE - object implement type" #warning "option macro:" #warning "KMPP_OBJ_EXTRA_SIZE - object extra size in bytes" #warning "KMPP_OBJ_ENTRY_TABLE - object element value / pointer entry table" #warning "KMPP_OBJ_FUNC_IOCTL - object element ioctl cmd and function table" #warning "KMPP_OBJ_FUNC_INIT - add object init function" #warning "KMPP_OBJ_FUNC_DEINIT - add object deinit function" #warning "KMPP_OBJ_FUNC_DUMP - add object dump function" #warning "KMPP_OBJ_FUNC_EXPORT_DISABLE - disable function exprot by EXPORT_SYMBOL" #warning "KMPP_OBJ_ACCESS_DISABLE - disable access function creation" #warning "KMPP_OBJ_SHARE_DISABLE - disable object sharing by /dev/kmpp_objs to userspace" #warning "KMPP_OBJ_HIERARCHY_ENABLE - enable hierarchy name creation" #ifndef KMPP_OBJ_NAME #error "KMPP_OBJ_NAME not defined" #endif #ifndef KMPP_OBJ_INTF_TYPE #error "KMPP_OBJ_INTF_TYPE not defined" #endif #ifndef KMPP_OBJ_IMPL_TYPE #error "KMPP_OBJ_IMPL_TYPE not defined" #endif #else /* all input macro defined */ #include #ifndef KMPP_OBJ_EXTRA_SIZE #define KMPP_OBJ_EXTRA_SIZE 0 #endif #ifndef KMPP_OBJ_ENTRY_TABLE #define KMPP_OBJ_ENTRY_TABLE(prefix, ENTRY, STRCT, EHOOK, SHOOK, ALIAS) #endif #define ENTRY_TO_TRIE(prefix, ftype, type, name, flag, ...) \ do { \ KmppEntry tbl = { \ .tbl.elem_offset = ((size_t)&(((KMPP_OBJ_IMPL_TYPE *)0)->CONCAT_DOT(__VA_ARGS__))), \ .tbl.elem_size = sizeof(((KMPP_OBJ_IMPL_TYPE *)0)->CONCAT_DOT(__VA_ARGS__)), \ .tbl.elem_type = ELEM_TYPE_##ftype, \ .tbl.flag_offset = FLAG_TYPE_TO_OFFSET(name, flag, #flag), \ }; \ kmpp_objdef_add_entry(KMPP_OBJ_DEF(prefix), ENTRY_TO_NAME_START(name), &tbl); \ ENTRY_TO_NAME_END(name); \ } while (0); #if !defined(KMPP_OBJ_ACCESS_DISABLE) #define VAL_ENTRY_TBL(prefix, ftype, type, name, flag, ...) \ static KmppEntry *CONCAT_US(tbl, prefix, __VA_ARGS__) = NULL; #define VAL_HOOK_IDX(prefix, ftype, type, name, flag, ...) \ static rk_s32 CONCAT_US(hook, prefix, get, __VA_ARGS__) = -1; \ static rk_s32 CONCAT_US(hook, prefix, set, __VA_ARGS__) = -1; #define ENTRY_QUERY(prefix, ftype, type, name, flag, ...) \ do { \ kmpp_objdef_get_entry(KMPP_OBJ_DEF(prefix), ENTRY_TO_NAME_START(name), &CONCAT_US(tbl, prefix, __VA_ARGS__)); \ } while (0); #define HOOK_QUERY(prefix, ftype, type, name, flag, ...) \ do { \ CONCAT_US(hook, prefix, set, __VA_ARGS__) = \ kmpp_objdef_get_hook(KMPP_OBJ_DEF(prefix), CONCAT_STR(set, __VA_ARGS__)); \ CONCAT_US(hook, prefix, get, __VA_ARGS__) = \ kmpp_objdef_get_hook(KMPP_OBJ_DEF(prefix), CONCAT_STR(get, __VA_ARGS__)); \ } while (0); #define ENTRY_TO_FUNC(prefix, ftype, type, name, flag, ...) \ rk_s32 CONCAT_US(prefix, get, __VA_ARGS__)(KMPP_OBJ_INTF_TYPE s, type *v) \ { \ rk_s32 ret = kmpp_obj_check(s, __FUNCTION__); \ if (ret) return ret; \ if (CONCAT_US(tbl, prefix, __VA_ARGS__)) \ ret = kmpp_obj_tbl_get_##ftype(s, CONCAT_US(tbl, prefix, __VA_ARGS__), v); \ else \ *v = ((KMPP_OBJ_IMPL_TYPE*)kmpp_obj_to_entry(s))->CONCAT_DOT(__VA_ARGS__); \ return ret; \ } \ rk_s32 CONCAT_US(prefix, set, __VA_ARGS__)(KMPP_OBJ_INTF_TYPE s, type v) \ { \ rk_s32 ret = kmpp_obj_check(s, __FUNCTION__); \ if (ret) return ret; \ if (CONCAT_US(tbl, prefix, __VA_ARGS__)) \ ret = kmpp_obj_tbl_set_##ftype(s, CONCAT_US(tbl, prefix, __VA_ARGS__), v); \ else \ ((KMPP_OBJ_IMPL_TYPE*)kmpp_obj_to_entry(s))->CONCAT_DOT(__VA_ARGS__) = v; \ return ret; \ } \ rk_s32 CONCAT_US(prefix, test, __VA_ARGS__)(KMPP_OBJ_INTF_TYPE s) \ { \ if (kmpp_obj_check(s, __FUNCTION__)) return 0; \ return kmpp_obj_tbl_test(s, CONCAT_US(tbl, prefix, __VA_ARGS__)); \ } #define STRUCT_TO_FUNC(prefix, ftype, type, name, flag, ...) \ rk_s32 CONCAT_US(prefix, get, __VA_ARGS__)(KMPP_OBJ_INTF_TYPE s, type *v) \ { \ rk_s32 ret = kmpp_obj_check(s, __FUNCTION__); \ if (ret) return ret; \ if (CONCAT_US(tbl, prefix, __VA_ARGS__)) \ ret = kmpp_obj_tbl_get_##ftype(s, CONCAT_US(tbl, prefix, __VA_ARGS__), v); \ else \ memcpy(v, &((KMPP_OBJ_IMPL_TYPE*)kmpp_obj_to_entry(s))->CONCAT_DOT(__VA_ARGS__), \ sizeof(((KMPP_OBJ_IMPL_TYPE*)0)->CONCAT_DOT(__VA_ARGS__))); \ return ret; \ } \ rk_s32 CONCAT_US(prefix, set, __VA_ARGS__)(KMPP_OBJ_INTF_TYPE s, type *v) \ { \ rk_s32 ret = kmpp_obj_check(s, __FUNCTION__); \ if (ret) return ret; \ if (CONCAT_US(tbl, prefix, __VA_ARGS__)) \ ret = kmpp_obj_tbl_set_##ftype(s, CONCAT_US(tbl, prefix, __VA_ARGS__), v); \ else \ memcpy(&((KMPP_OBJ_IMPL_TYPE*)kmpp_obj_to_entry(s))->CONCAT_DOT(__VA_ARGS__), v, \ sizeof(((KMPP_OBJ_IMPL_TYPE*)0)->CONCAT_DOT(__VA_ARGS__))); \ return ret; \ } \ rk_s32 CONCAT_US(prefix, test, __VA_ARGS__)(KMPP_OBJ_INTF_TYPE s) \ { \ if (kmpp_obj_check(s, __FUNCTION__)) return 0; \ return kmpp_obj_tbl_test(s, CONCAT_US(tbl, prefix, __VA_ARGS__)); \ } #define EHOOK_TO_FUNC(prefix, ftype, type, name, flag, ...) \ rk_s32 CONCAT_US(prefix, get, __VA_ARGS__)(KMPP_OBJ_INTF_TYPE s, type *v) \ { \ rk_s32 ret = kmpp_obj_check(s, __FUNCTION__); \ if (ret) return ret; \ if (CONCAT_US(hook, prefix, get, __VA_ARGS__) >= 0) \ ret = kmpp_obj_idx_run(s, CONCAT_US(hook, prefix, get, __VA_ARGS__), (void *)v, __FUNCTION__); \ return ret; \ } \ rk_s32 CONCAT_US(prefix, set, __VA_ARGS__)(KMPP_OBJ_INTF_TYPE s, type v) \ { \ rk_s32 ret = kmpp_obj_check(s, __FUNCTION__); \ if (ret) return ret; \ if (CONCAT_US(hook, prefix, set, __VA_ARGS__) >= 0) \ ret = kmpp_obj_idx_run(s, CONCAT_US(hook, prefix, set, __VA_ARGS__), (void *)&v, __FUNCTION__); \ return ret; \ } #define SHOOK_TO_FUNC(prefix, ftype, type, name, flag, ...) \ \ rk_s32 CONCAT_US(prefix, get, __VA_ARGS__)(KMPP_OBJ_INTF_TYPE s, type *v) \ { \ rk_s32 ret = kmpp_obj_check(s, __FUNCTION__); \ if (ret) return ret; \ if (CONCAT_US(hook, prefix, get, __VA_ARGS__) >= 0) \ ret = kmpp_obj_idx_run(s, CONCAT_US(hook, prefix, get, __VA_ARGS__), (void *)v, __FUNCTION__); \ return ret; \ } \ rk_s32 CONCAT_US(prefix, set, __VA_ARGS__)(KMPP_OBJ_INTF_TYPE s, type *v) \ { \ rk_s32 ret = kmpp_obj_check(s, __FUNCTION__); \ if (ret) return ret; \ if (CONCAT_US(hook, prefix, set, __VA_ARGS__) >= 0) \ ret = kmpp_obj_idx_run(s, CONCAT_US(prefix, set, __VA_ARGS__), (void *)v, __FUNCTION__); \ return ret; \ } #else #define VAL_ENTRY_TBL ENTRY_NOTHING #define VAL_HOOK_IDX ENTRY_NOTHING #define ENTRY_QUERY ENTRY_NOTHING #define HOOK_QUERY ENTRY_NOTHING #define ENTRY_TO_FUNC ENTRY_NOTHING #define STRUCT_TO_FUNC ENTRY_NOTHING #define EHOOK_TO_FUNC ENTRY_NOTHING #define SHOOK_TO_FUNC ENTRY_NOTHING #endif /* disable structure layout macro for global variable definition */ #undef CFG_DEF_START #undef CFG_DEF_END #undef STRUCT_START #undef STRUCT_END #undef ENTRY_TO_NAME_START #undef ENTRY_TO_NAME_END #define CFG_DEF_START(...) #define CFG_DEF_END(...) #define STRUCT_START(...) #define STRUCT_END(...) #define ENTRY_TO_NAME_START(name, ...) TO_STR(name) #define ENTRY_TO_NAME_END(...) /* object definition common functions */ static KmppObjDef KMPP_OBJ_DEF(KMPP_OBJ_NAME) = NULL; static rk_u32 KMPP_OBJ_DEF_DEUBG(KMPP_OBJ_NAME) = 0; /* globla variable definitions */ KMPP_OBJ_ENTRY_TABLE(KMPP_OBJ_NAME, VAL_ENTRY_TBL, VAL_ENTRY_TBL, VAL_HOOK_IDX, VAL_HOOK_IDX, ENTRY_NOTHING) /* enable structure layout macro for objdef registration */ #ifdef KMPP_OBJ_HIERARCHY_ENABLE #undef CFG_DEF_START #undef CFG_DEF_END #undef STRUCT_START #undef STRUCT_END #undef ENTRY_TO_NAME_START #undef ENTRY_TO_NAME_END #define CFG_DEF_START(...) \ { \ char str_buf[256] = {0}; \ rk_s32 str_pos = 0; \ rk_s32 str_size = sizeof(str_buf) - 1; #define CFG_DEF_END(...) \ } #define STRUCT_START(...) \ { \ rk_s32 CONCAT_US(pos, __VA_ARGS__, root) = str_pos; \ str_pos += snprintf(str_buf + str_pos, str_size - str_pos, str_pos ? ":%s" : "%s", CONCAT_STR(__VA_ARGS__)); #define STRUCT_END(...) \ str_pos = CONCAT_US(pos, __VA_ARGS__, root); \ str_buf[str_pos] = '\0'; \ } #define ENTRY_TO_NAME_START(name, ...) \ ({ \ snprintf(str_buf + str_pos, str_size - str_pos, str_pos ? ":%s" : "%s", TO_STR(name)); \ str_buf; \ }) #define ENTRY_TO_NAME_END(...) \ str_buf[str_pos] = '\0'; #endif void CONCAT_US(KMPP_OBJ_NAME, register)(void) { rk_s32 impl_size = (sizeof(KMPP_OBJ_IMPL_TYPE) + KMPP_OBJ_EXTRA_SIZE + 3) & ~3; rk_s32 __flag_base = impl_size << 3; rk_s32 __flag_step = 0; rk_s32 __flag_prev = 0; rk_s32 __flag_record[ELEM_FLAG_RECORD_MAX]; (void) __flag_base; (void) __flag_step; (void) __flag_prev; (void) __flag_record; mpp_env_get_u32(TO_STR(CONCAT_US(KMPP_OBJ_NAME, debug)), &KMPP_OBJ_DEF_DEUBG(KMPP_OBJ_NAME), 0); kmpp_objdef_get(&KMPP_OBJ_DEF(KMPP_OBJ_NAME), TO_STR(KMPP_OBJ_INTF_TYPE)); if (KMPP_OBJ_DEF(KMPP_OBJ_NAME)) { KMPP_OBJ_DBG_LOG(TO_STR(KMPP_OBJ_NAME) " found at kernel\n"); return; } KMPP_OBJ_DBG_LOG("register enter\n"); kmpp_objdef_register(&KMPP_OBJ_DEF(KMPP_OBJ_NAME), impl_size, TO_STR(KMPP_OBJ_INTF_TYPE)); if (!KMPP_OBJ_DEF(KMPP_OBJ_NAME)) { mpp_loge_f(TO_STR(KMPP_OBJ_NAME) " init failed\n"); return; } KMPP_OBJ_ENTRY_TABLE(KMPP_OBJ_NAME, ENTRY_TO_TRIE, ENTRY_TO_TRIE, ENTRY_TO_TRIE, ENTRY_TO_TRIE, ENTRY_TO_TRIE) kmpp_objdef_add_entry(KMPP_OBJ_DEF(KMPP_OBJ_NAME), NULL, NULL); KMPP_OBJ_ENTRY_TABLE(KMPP_OBJ_NAME, ENTRY_QUERY, ENTRY_QUERY, HOOK_QUERY, HOOK_QUERY, ENTRY_NOTHING); #if defined(KMPP_OBJ_FUNC_INIT) kmpp_objdef_add_init(KMPP_OBJ_DEF(KMPP_OBJ_NAME), KMPP_OBJ_FUNC_INIT); #endif #if defined(KMPP_OBJ_FUNC_DEINIT) kmpp_objdef_add_deinit(KMPP_OBJ_DEF(KMPP_OBJ_NAME), KMPP_OBJ_FUNC_DEINIT); #endif #if defined(KMPP_OBJ_FUNC_IOCTL) kmpp_objdef_add_ioctl(KMPP_OBJ_DEF(KMPP_OBJ_NAME), &KMPP_OBJ_FUNC_IOCTL); #endif #if defined(KMPP_OBJ_FUNC_DUMP) kmpp_objdef_add_dump(KMPP_OBJ_DEF(KMPP_OBJ_NAME), KMPP_OBJ_FUNC_DUMP); #endif #if !defined(KMPP_OBJ_SHARE_DISABLE) && defined(__KERNEL__) kmpp_objdef_share(KMPP_OBJ_DEF(KMPP_OBJ_NAME)); #endif KMPP_OBJ_DBG_LOG("register leave\n"); } void CONCAT_US(KMPP_OBJ_NAME, unregister)(void) { KmppObjDef def = __sync_fetch_and_and(&KMPP_OBJ_DEF(KMPP_OBJ_NAME), NULL); KMPP_OBJ_DBG_LOG("unregister enter\n"); kmpp_objdef_put(def); KMPP_OBJ_DBG_LOG("unregister leave\n"); } MPP_SINGLETON(KMPP_OBJ_SGLN_ID, TO_STR(KMPP_OBJ_NAME), CONCAT_US(KMPP_OBJ_NAME, register), CONCAT_US(KMPP_OBJ_NAME, unregister)); rk_s32 CONCAT_US(KMPP_OBJ_NAME, size)(void) { return kmpp_objdef_get_entry_size(KMPP_OBJ_DEF(KMPP_OBJ_NAME)); } rk_s32 CONCAT_US(KMPP_OBJ_NAME, get)(KMPP_OBJ_INTF_TYPE *obj) { return kmpp_obj_get_f((KmppObj *)obj, KMPP_OBJ_DEF(KMPP_OBJ_NAME)); } rk_s32 CONCAT_US(KMPP_OBJ_NAME, put)(KMPP_OBJ_INTF_TYPE obj) { return kmpp_obj_put_f(obj); } rk_s32 CONCAT_US(KMPP_OBJ_NAME, dump)(KMPP_OBJ_INTF_TYPE obj, const char *caller) { return kmpp_obj_kdump_f(obj, caller); } #if !defined(KMPP_OBJ_FUNC_EXPORT_DISABLE) && defined(__KERNEL__) #include EXPORT_SYMBOL(CONCAT_US(KMPP_OBJ_NAME, size)); EXPORT_SYMBOL(CONCAT_US(KMPP_OBJ_NAME, get)); EXPORT_SYMBOL(CONCAT_US(KMPP_OBJ_NAME, put)); EXPORT_SYMBOL(CONCAT_US(KMPP_OBJ_NAME, dump)); #endif /* disable structure layout macro for access function definition */ #undef CFG_DEF_START #undef CFG_DEF_END #undef STRUCT_START #undef STRUCT_END #undef ENTRY_TO_NAME_START #undef ENTRY_TO_NAME_END #define CFG_DEF_START(...) #define CFG_DEF_END(...) #define STRUCT_START(...) #define STRUCT_END(...) #if !defined(KMPP_OBJ_ACCESS_DISABLE) /* object element access functions */ KMPP_OBJ_ENTRY_TABLE(KMPP_OBJ_NAME, ENTRY_TO_FUNC, STRUCT_TO_FUNC, EHOOK_TO_FUNC, SHOOK_TO_FUNC, ENTRY_NOTHING) #if !defined(KMPP_OBJ_FUNC_EXPORT_DISABLE) && defined(__KERNEL__) #define KMPP_OBJ_EXPORT(prefix, ftype, type, name, flag, ...) \ EXPORT_SYMBOL(CONCAT_US(prefix, get, __VA_ARGS__)); \ EXPORT_SYMBOL(CONCAT_US(prefix, set, __VA_ARGS__)); #define KMPP_OBJ_EXPORT_NONE(prefix, ftype, type, name, flag, ...) KMPP_OBJ_ENTRY_TABLE(KMPP_OBJ_NAME, KMPP_OBJ_EXPORT, KMPP_OBJ_EXPORT, KMPP_OBJ_EXPORT, KMPP_OBJ_EXPORT, KMPP_OBJ_EXPORT_NONE) #undef KMPP_OBJ_EXPORT #endif #endif /* restore layout definition */ #undef CFG_DEF_START #undef CFG_DEF_END #undef STRUCT_START #undef STRUCT_END #undef KMPP_OBJ_NAME #undef KMPP_OBJ_INTF_TYPE #undef KMPP_OBJ_IMPL_TYPE #undef KMPP_OBJ_EXTRA_SIZE #undef KMPP_OBJ_ENTRY_TABLE #undef KMPP_OBJ_FUNC_INIT #undef KMPP_OBJ_FUNC_DEINIT #undef KMPP_OBJ_FUNC_IOCTL #undef KMPP_OBJ_FUNC_DUMP #undef KMPP_OBJ_FUNC_EXPORT_DISABLE #undef KMPP_OBJ_ACCESS_DISABLE #undef KMPP_OBJ_SHARE_DISABLE #undef KMPP_OBJ_HIERARCHY_ENABLE /* undef tmp macro */ #undef ENTRY_TO_TRIE #undef ENTRY_TO_FUNC #undef STRUCT_TO_FUNC #undef EHOOK_TO_FUNC #undef SHOOK_TO_FUNC #undef VAL_ENTRY_TBL #undef VAL_HOOK_IDX #undef ENTRY_QUERY #undef HOOK_QUERY #undef __OBJECT_HERLPER_H__ #endif