当前位置:网站首页>【Autosar 十四 启动流程详解】
【Autosar 十四 启动流程详解】
2022-07-05 18:25:00 【柯宇谦】
Autosar 十四 启动流程详解
链接文件:
1. vLinkGen_Template.lsl
这里注明了起始函数为:brsStartupEntry 函数;
"StartupEntry" = "brsStartupEntry";
"_start_tc0_asr" = "brsStartupEntry";
"_start_tc1_asr" = "brsStartupEntry";
"_start_tc2_asr" = "brsStartupEntry";
"_start_tc3_asr" = "brsStartupEntry";
"_start_tc4_asr" = "brsStartupEntry";
"_start_tc5_asr" = "brsStartupEntry";
2. BrsHwStartup.c
brsStartupEntry函数如下,接下来我们来讲讲这个函数具体干了些什么:
2.1 配置的内存区域归0
#if defined (VLINKGEN_CFG_NUM_ZERO_INIT_EARLY_GROUPS)
# if (VLINKGEN_CFG_NUM_ZERO_INIT_EARLY_GROUPS>1uL)
/* Loop over all entries of vLinkGen_ZeroInit_Early_Groups and zero the configured memory areas. */
volatile uint32 *memPtr2;
uint8 areaNum;
for(areaNum = 0; areaNum < vLinkGen_ZeroInit_Early_GroupsSet.Num; areaNum++)
{
if(vLinkGen_ZeroInit_Early_GroupsSet.Areas[areaNum].Core == CurrentCoreId &&
(vLinkGen_ZeroInit_Early_GroupsSet.Areas[areaNum].End - vLinkGen_ZeroInit_Early_GroupsSet.Areas[areaNum].Start) > 0)
{
memPtr2 = (volatile uint32 *)vLinkGen_ZeroInit_Early_GroupsSet.Areas[areaNum].Start;
while((uint32)memPtr2 < vLinkGen_ZeroInit_Early_GroupsSet.Areas[areaNum].End)
{
*memPtr2 = 0x0;
memPtr2++;
}
}
}
# endif /*VLINKGEN_CFG_NUM_ZERO_INIT_EARLY_GROUPS>1uL*/
#else
#error "Mandatory define VLINKGEN_CFG_NUM_ZERO_INIT_EARLY_GROUPS missing within vLinkGen configuration!"
#endif /*VLINKGEN_CFG_NUM_ZERO_INIT_EARLY_GROUPS*/
代码很简单,最重要的就是 vLinkGen_ZeroInit_Early_GroupsSet 这个结构体了,定义在:
vLinkGen_Lcfg.c
vLinkGen_Cfg.h
typedef struct
{
/*! Start address of the memory area. */
uint32 Start;
/*! End address of the memory area. */
uint32 End;
/*! Core ID to perform the initialization. */
uint32 Core;
/*! ECC alignment of memory area in bytes. */
uint32 Alignment;
} vLinkGen_MemArea;
typedef struct
{
/*! Number of memory areas in this set. */
uint32 Num;
/*! Table of generic memory areas. */
const vLinkGen_MemArea *Areas;
} vLinkGen_MemAreaSet;
# define VLINKGEN_CFG_NUM_ZERO_INIT_EARLY_GROUPS 2uL
const vLinkGen_MemArea vLinkGen_ZeroInit_Early_Groups[VLINKGEN_CFG_NUM_ZERO_INIT_EARLY_GROUPS] =
{
{
/* Brs_Shared_Var */
/* .Start */ (uint32)_Brs_Shared_Var_START,
/* .End */ (uint32)_lc_ge_Brs_Shared_Var,
/* .Core */ 0uL,
/* .Alignment */ 0uL
},
{
0uL,
0uL,
0uL,
0uL
}
};
const vLinkGen_MemAreaSet vLinkGen_ZeroInit_Early_GroupsSet =
{
VLINKGEN_CFG_NUM_ZERO_INIT_EARLY_GROUPS,
vLinkGen_ZeroInit_Early_Groups
};
从这里可以看出启动流程最开始,只定义Core0内存的起始和结束地址,并将这片内存区域请0:
内存的起始地址和结束地址
- /* .Start */ (uint32)_Brs_Shared_Var_START,
- /* .End */ (uint32)_lc_ge_Brs_Shared_Var,
vLinkGen_Template.lsl
group Brs_Shared_Var_PAD (align = 4)
{
reserved "Brs_Shared_Var_PAD" (size = 0);
}
"_Brs_Shared_Var_START" = "_lc_gb_Brs_Shared_Var";
"_Brs_Shared_Var_END" = ("_lc_ge_Brs_Shared_Var" == 0) ? 0 : "_lc_ge_Brs_Shared_Var" - 1;
"_Brs_Shared_Var_LIMIT" = "_lc_ge_Brs_Shared_Var";
"_Brs_Shared_Var_ALL_START" = "_Brs_Shared_Var_START";
"_Brs_Shared_Var_ALL_END" = "_Brs_Shared_Var_END";
"_Brs_Shared_Var_ALL_LIMIT" = "_Brs_Shared_Var_LIMIT";
}
xxx.mapxml
<row>0x7002f920;_lc_gb_Brs_Shared_Var_GROUP;mpe:vtc:linear</row>
<row>0x7002f920;_lc_gb_Brs_Shared_Var;mpe:vtc:linear</row>
...
<row>0x7002f922;_lc_ge_Brs_Shared_Var;mpe:vtc:linear</row>
<row>0x7002f922;_lc_ge_Brs_Shared_Var_GROUP;mpe:vtc:linear</row>
2.2 设置栈指针
uint32 CurrentCoreConfig = 0;
uint32 i;
for (i=0; i<BrsMain_CoreConfig_Size; i++)
{
if (BrsMain_CoreConfig[i].PhysicalCoreId == CurrentCoreId)
{
CurrentCoreConfig = i;
i=BrsMain_CoreConfig_Size+1;
}
}
/* Check, if no valid core config was found */
if (i==BrsMain_CoreConfig_Size)
BrsMainExceptionStartup();
BRS_SET_SP(BrsMain_CoreConfig[CurrentCoreConfig].StartupStackEndLabel);
typedef struct
{
/* Logical Id of configured core. */
uint32 LogicalCoreId;
/* Phyiscal Id of configured core. */
uint32 PhysicalCoreId;
/* End label of the startup stack. */
Brs_AddressOfConstType StartupStackEndLabel;
/* startup stack size */
uint32 StartupStackSize;
/* Reflects if core is an AUTOSAR core. */
brsCoreAsrType CoreIsAsr;
/* Start label of the exception vector table. */
Brs_AddressOfConstType ExcVecLabel;
/* Start label of the interrupt vector table. */
Brs_AddressOfConstType IntVecLabel;
}brsMain_CoreType;
const brsMain_CoreType BrsMain_CoreConfig[6u] =
{
{
/* .LogicalCoreId = */ 0u,
/* .PhysicalCoreId = */ 0u,
/* .StartupStackEndLabel = */ (Brs_AddressOfConstType)(&BRSHW_DEFINE_STARTUP_STACK(0)),
/* .StartupStackSize = */ 10240u,
/* .CoreIsAsr = */ ASR,
/* .ExcVecLabel = */ (Brs_AddressOfConstType)(&BRSHW_DEFINE_EXCVEC(0)),
/* .IntVecLabel = */ (Brs_AddressOfConstType)(&BRSHW_DEFINE_INTVEC(0))
},
...
}
在
Os_Link_Core0.lsl
也能找到各个核的内存地址分配
#if defined ( OS_LINK_EXCVEC_CODE )
if (exists(".text.OS_EXCVEC_CORE0_CODE"))
{
group OS_EXCVEC_CORE0_CODE_GROUP(align=256)
{
select "[.]text.OS_EXCVEC_CORE0_CODE";
}
"_OS_EXCVEC_CORE0_CODE_START" = "_lc_gb_OS_EXCVEC_CORE0_CODE_GROUP";
"_OS_EXCVEC_CORE0_CODE_END" = "_lc_ge_OS_EXCVEC_CORE0_CODE_GROUP" - 1;
"_OS_EXCVEC_CORE0_CODE_LIMIT" = "_lc_ge_OS_EXCVEC_CORE0_CODE_GROUP";
}
else
{
"_OS_EXCVEC_CORE0_CODE_START" = 0;
"_OS_EXCVEC_CORE0_CODE_END" = 0;
"_OS_EXCVEC_CORE0_CODE_LIMIT" = 0;
}
#endif
2.3 设置PSW
Program Status Word(PSW)
BRS_MOVE_TO_CSFR(BRS_PSW_OFFSET, 0x00000B80UL);
2.4 配置PCIX
CPUx Previous Context Information Register(PCIX)
AuxVariable = BRS_MOVE_FROM_CSFR(BRS_PCXI_OFFSET);
AuxVariable &= 0xfff00000UL;
BRS_MOVE_TO_CSFR(BRS_PCXI_OFFSET, AuxVariable);
2.5 配置CSA
The Context Save Areas (CSA)
/* =========================================================================== */
/* initialize the CSAs (inlined function) */
/* aftwerwards function calls are possible */
/* =========================================================================== */
BRS_CSA_Element* CSA;
uint32 NumberOfCSA;
uint32 pcxi_val = 0; /* the last PCXI has to point to 0 */
uint32 CSAReserve = 20; /* the LCX will be initalized to point to 20 CSAs before the very last CSA */
uint32 seg_nr, seg_idx; /* auxiliary variables to assemble the PCXI value */
BRS_CSA_Element* CSAAddress = (BRS_CSA_Element*)((uint32)BrsMain_CoreConfig[CurrentCoreConfig].StartupStackEndLabel - (uint32)BrsMain_CoreConfig[CurrentCoreConfig].StartupStackSize);
uint32 CSA_Numbers = ((uint32)BrsMain_CoreConfig[CurrentCoreConfig].StartupStackEndLabel - 1024 - (uint32)CSAAddress) / 64;
if (CSA_Numbers<512)
{
/* The configured stack size is smaller than the recommended one! * Beginning with vBaseEnv 2.17, the startup stack setup was harmonized and the stack sizes are configured automatically via the vBRS generator * (vBRS/vBRSGeneral/vBRSEnableCoreSpecificVLinkGenConfig). * The recommended default for the Aurix platforms is 33792 Byte, listed in vBaseEnv/vBaseEnvGeneral/vBaseEnvStartupStackSettings/vBaseEnvStackSize. * This means, 1024 Byte for the startup stack and 512 CSA list entries (64 Byte each). There is no separated section for the CSAs anymory, * they are placed in STACK_Cx, together with the startup stack. Be aware, that the CSAs are shared across all execution instances * (vBRS/vBRSGeneral/vBRSExecutionInstance). All instances inherit it from the first execution instance (vBRS/vBRSGeneral/vBRSFirstInstance). * Uncomment this loop, if you intentionally reduced the size of STACK_Cx and ensure it is suitable for your project. * Otherwise, please increase the size of STACK_Cx to at least 33792 (vLinkGenVarSectionGroup/vLinkGenVarSectionGroupSize). */
// while (1);
}
if(CSAAddress != 0)
{
CSA = CSAAddress;
for (NumberOfCSA=0; NumberOfCSA < CSA_Numbers; NumberOfCSA++) /* loop over all CSA elements */
{
*CSA[0] = pcxi_val; /* *CSA is equal to CSA[0] is equal to CSA.PCXI (it holds the PCXI value and has to point to the next PCXI) */
/* now translate the current CSA address to a valid PCXI value which is used within the AURIX registers */
seg_nr = (((unsigned int)CSA >> 28) & 0xf) << 16;
seg_idx = (((unsigned int)CSA >> 6) & 0xffff);
pcxi_val = seg_nr | seg_idx;
if (NumberOfCSA == CSAReserve) /* reserve CSAs for exception handling */
{
BRS_MOVE_TO_CSFR(BRS_LCX_OFFSET, pcxi_val);
}
CSA++; /* point to the next CSA */
}
BRS_MOVE_TO_CSFR(BRS_FCX_OFFSET, pcxi_val);
}
2.6 中断向量表设置
/* Program the brs default vector table base addresses to handle exceptions during startup */
BrsHw_ExceptionTable_Init((Brs_AddressOfConstType)&_Brs_ExcVect_START, BRS_DEFINE_ADDRESS_UNUSED);
3.BrsMainStartup.c
Brs_ApplicationEntry();
这个函数中最主要的作用是对内存区域进行操作(清零与赋值)
然后进入main();函数中
4.BrsMain.c
在main()函数中首先初始化每个核的中断向量表
/* Search for valid Exception- and Interrupt Table in BrsMain_CoreConfig[] (vBRS generated into vBrs_Lcfg.c) */
for (i=0; i<BrsMain_CoreConfig_Size; i++)
{
if (BrsMain_CoreConfig[i].PhysicalCoreId == coreID)
{
BrsHw_ExceptionTable_Init(BrsMain_CoreConfig[i].ExcVecLabel, BrsMain_CoreConfig[i].IntVecLabel);
i=BrsMain_CoreConfig_Size+1;
}
}
/* Check, if no valid core config was found */
if (i==BrsMain_CoreConfig_Size)
BrsMainExceptionHandler(kBrsInvalidCoreConfig, BRSERROR_MODULE_BRSMAIN, (uint16)(__LINE__));
紧接着初始化RTE
Os_InitMemory();
Os_Init();
然后EcuM模块接管系统
5.EcuM.c
5.1 设置ECU 启动模式
/* Set the current state of the EcuM to STARTUP */
EcuM_SetModuleState(ECUM_STATE_STARTUP); /* SBSW_ECUM_CSL_VAR_ACCESS */
5.2 使能中断
/* #30 Set the interrupts on ECUs with programmable interrupts (EcuM_AL_SetProgrammableInterrupts). */
EcuM_AL_SetProgrammableInterrupts();
5.3 驱动链表清零
/* #31 Initialize BSW that do not use PostBuild parameters (DriverInitListZero). */
ECUM_DRIVERINITLIST_ZERO();
5.4 清除唤醒中断源
/* Clear wakeups from all sources */
EcuM_InternalClearWakeupEvent( ECUM_WKSOURCE_ALL_SOURCES);
5.5 重置超时唤醒
/* Reset all wakeup validation timeouts */
for (loopCount = 0u; loopCount < EcuM_GetSizeOfWakeupSourceList(); loopCount++) /* PRQA S 2812 */ /* MD_EcuM_2812 */
{
EcuM_SetValidationTimeoutTable(loopCount, ECUM_NO_VALIDATION_TIMEOUT); /* SBSW_ECUM_ACCESSVALTABLE */
}
5.6 设置EcuM模式
/* Set the current state of the EcuM */
EcuM_SetModuleState(ECUM_STATE_STARTUP_ONE); /* SBSW_ECUM_CSL_VAR_ACCESS */
5.7 启动OS
/* #51 Start the AUTOSAR OS with the corresponding default appMode. */
EcuM_StartOS( EcuM_GetDefaultAppMode());
6.EcuM_Callout_Stubs.c
EcuM接管OS 启动后 会根据核ID 依次启动除了启动核之外的核。
StartCore(coreId, &status);
最后 启动OS
StartOS(appMode);
7.Os_Trap.c
StartCore(coreId, &status);
FUNC(void, OS_CODE) StartCore /* COV_OS_HALPLATFORMTESTEDASMULTICORE */
(
CoreIdType CoreID,
StatusType *Status
)
{
/* #10 If the given status pointer is valid: */
if(OS_UNLIKELY(Os_ErrCheckPointerIsNotNull(Status) != OS_CHECK_FAILED)) /* PRQA S 0315 */ /* MD_Os_Dir1.1_0315 */ /* SBSW_OS_TRAP_ERRCHECKPOINTERISNOTNULL_001 */
{
/* #20 Caller (startup code) is privileged. Call API directly. */
Os_TrapCallStartCore(CoreID, Status); /* SBSW_OS_TRAP_API_USERPOINTER_001 */
}
/* else * Do NOT write the error code to the Status pointer, as it is a NULL_PTR! */
}
OS_FUNC_ATTRIBUTE_DEFINITION(OS_LOCAL_INLINE void, OS_CODE, /* COV_OS_HALPLATFORMTESTEDASMULTICORE */
OS_ALWAYS_INLINE, Os_TrapCallStartCore,
(
CoreIdType CoreID,
StatusType *Status
)) /* COV_OS_HALPLATFORMTESTEDASMULTICORE */
{
/* #10 Inform the trace module on service function entry. */
Os_TraceOrtiApiEntry(OsOrtiApiIdStartCore);
/* #20 Call the API. */
Os_Api_StartCore(CoreID, Status); /* SBSW_OS_FC_PRECONDITION */
/* #30 Inform the trace module on service function exit. */
Os_TraceOrtiApiExit(OsOrtiApiIdStartCore);
}
FUNC(void, OS_CODE) Os_Api_StartCore /* COV_OS_HALPLATFORMMULTICOREUNSUPPORTED */
(
CoreIdType CoreID,
StatusType *Status
)
{
*Status = E_OK; /* PRQA S 2982 */ /* MD_Os_Rule2.2_2982_Config */ /* SBSW_OS_PWA_PRECONDITION */
/* #10 Perform error checks. */
if(Os_CoreIsSingleCoreOs() != 0u) /* COV_OS_TESTSUITERESTRICTIONCORECOUNT */ /* PRQA S 2991, 2992, 2995, 2996 */ /* MD_Os_Rule14.3_2991, MD_Os_Rule14.3_2992, MD_Os_Rule2.2_2995, MD_Os_Rule2.2_2996 */
{
*Status = E_OS_ID; /* SBSW_OS_PWA_PRECONDITION */
}
else if(OS_UNLIKELY(Os_CoreCheckId(CoreID) == OS_CHECK_FAILED ))
{
*Status = E_OS_ID; /* SBSW_OS_PWA_PRECONDITION */
}
else
{
P2CONST(Os_CoreConfigType, AUTOMATIC, OS_CONST) core;
P2CONST(Os_CoreConfigType, AUTOMATIC, OS_CONST) currentCore;
core = Os_CoreId2Core(CoreID);
currentCore = Os_CoreGetCurrentCore();
if(OS_UNLIKELY(Os_CoreCheckIsAsrCore(core) == OS_CHECK_FAILED)) /* SBSW_OS_CORE_CORECHECKISASRCORE_001 */
{
*Status = E_OS_ID; /* SBSW_OS_PWA_PRECONDITION */
}
else
{
if(OS_UNLIKELY(Os_CoreCheckCoreIsInactive(core) == OS_CHECK_FAILED)) /* SBSW_OS_CORE_CORECHECKCOREISINACTIVE_001 */
{
*Status = E_OS_STATE; /* SBSW_OS_PWA_PRECONDITION */
}
else
{
if(Os_CoreIsAsrCore(currentCore) != 0u) /* SBSW_OS_CORE_COREISASRCORE_002 */
{
P2CONST(Os_CoreAsrConfigType, AUTOMATIC, OS_CONST) currentCoreAsr;
currentCoreAsr = Os_Core2AsrCore(currentCore); /* SBSW_OS_CORE_CORE2ASRCORE_002 */
if(OS_UNLIKELY(Os_CoreCheckOsIsNotStarted(currentCoreAsr) == OS_CHECK_FAILED)) /* SBSW_OS_CORE_CORECHECKOSISNOTSTARTED_001 */
{
*Status = E_OS_ACCESS; /* SBSW_OS_PWA_PRECONDITION */
}
}
}
if(OS_LIKELY(*Status == E_OK))
{
P2CONST(Os_CoreAsrConfigType, AUTOMATIC, OS_CONST) coreAsr;
/* #20 Set the core activation request. */
Os_CoreGetStatus(currentCore)->CoreStartRequests[CoreID] = OS_CORESTATE_ACTIVATED_ASR; /* PRQA S 2842 */ /* MD_Os_Rule18.1_2842_Check */ /* SBSW_OS_CORE_COREGETSTATUS_003 */ /* SBSW_OS_CORE_CORESTARTREQUESTS_001 */
coreAsr = Os_Core2AsrCore(core); /* SBSW_OS_CORE_CORE2ASRCORE_001 */
/* #30 Attach to synchronization barrier. */
Os_BarrierAttach(coreAsr->Barrier); /* SBSW_OS_CORE_BARRIERATTACH_001 */
if(core->IsAutostart == TRUE) /* COV_OS_HALPLATFORMNONAUTOSTARTCORE */
{
/* #40 If the core is an auto-start core (already booted), just set the waiting signal. */
OsCfg_CoreBootBarrierRefs[CoreID]->WaitingSign = OS_CORE_BOOTBARRIER_STARTCORE; /* SBSW_OS_CORE_COREBOOTBARRIERREFS_001 */
}
else
{
/* #50 Otherwise start the core through hardware registers. */
Os_Hal_CoreStart(core->HwConfig); /* SBSW_OS_CORE_HAL_CORESTART_001 */
}
}
}
}
}
StartOS(appMode);
FUNC(void, OS_CODE) StartOS
(
AppModeType Mode
)
{
/* #10 Caller (startup code) is privileged. Call API directly. */
Os_TrapCallStartOS(Mode);
}
FUNC(void, OS_CODE) Os_Api_StartOS(AppModeType Mode)
{
/* #10 If the OS is not configured for the interrupt only use case: */
if(Os_CoreIsInterruptOnlyOs() == 0u ) /* PRQA S 2991, 2992, 2995, 2996 */ /* MD_Os_Rule14.3_2991, MD_Os_Rule14.3_2992, MD_Os_Rule2.2_2995, MD_Os_Rule2.2_2996 */
{
P2CONST(Os_CoreConfigType, AUTOMATIC, OS_CONST) core;
core = Os_CoreGetCurrentCore();
/* #10 Check that the core has been started as an AUTOSAR core. */
if(OS_UNLIKELY(Os_CoreCheckStartedAsAsr(core) == OS_CHECK_FAILED)) /* SBSW_OS_CORE_CORECHECKSTARTEDASASR_001 */ /* COV_OS_INVSTATE */
{
Os_ErrKernelPanic();
}
else
{
P2CONST(Os_CoreAsrConfigType, AUTOMATIC, OS_CONST) coreAsr;
coreAsr = Os_Core2AsrCore(core); /* SBSW_OS_CORE_CORE2ASRCORE_002 */
/* #20 Check that StartOS() was not called before. */
if(OS_UNLIKELY(Os_CoreCheckOsIsNotStarted(coreAsr) == OS_CHECK_FAILED)) /* SBSW_OS_CORE_CORECHECKOSISNOTSTARTED_001 */ /* COV_OS_INVSTATE */
{
Os_ErrKernelPanic();
}
else
{
/* #30 Enter the core's Init Hook. */
Os_HookCallOs_CoreInitHook(Os_CoreGetInitHook(coreAsr), Mode); /* SBSW_OS_CORE_COREGETINITHOOK_001 */ /* SBSW_OS_CORE_HOOKCALLOS_COREINITHOOK_001 */
}
}
}
/* #50 Else ignore the call. */
}
边栏推荐
- About Estimation with Cross-Validation
- The 11th China cloud computing standards and Applications Conference | cloud computing national standards and white paper series release, and Huayun data fully participated in the preparation
- 记录Pytorch中的eval()和no_grad()
- Logical words in Articles
- Find the first k small element select_ k
- c期末复习
- 开户注册股票炒股安全吗?有没有风险的?靠谱吗?
- Electron installation problems
- 小林coding的内存管理章节
- The 2022 China Xinchuang Ecological Market Research and model selection evaluation report released that Huayun data was selected as the mainstream manufacturer of Xinchuang IT infrastructure!
猜你喜欢
Share: ZTE Yuanhang 30 Pro root unlock BL magick ZTE 7532n 8040n 9041n brush mask original brush package root method Download
Nanjing University: Discussion on the training program of digital talents in the new era
爬虫01-爬虫基本原理讲解
Reptile 01 basic principles of reptile
Can communication of nano
Let more young people from Hong Kong and Macao know about Nansha's characteristic cultural and creative products! "Nansha kylin" officially appeared
《2022中国信创生态市场研究及选型评估报告》发布 华云数据入选信创IT基础设施主流厂商!
Use JMeter to record scripts and debug
buuctf-pwn write-ups (9)
图片数据不够?我做了一个免费的图像增强软件
随机推荐
rust统计文件中单词出现的次数
Generate classes from XML schema
Le cours d'apprentissage de la machine 2022 de l'équipe Wunda arrive.
Whether to take a duplicate subset with duplicate elements [how to take a subset? How to remove duplicates?]
Nacos distributed transactions Seata * * install JDK on Linux, mysql5.7 start Nacos configure ideal call interface coordination (nanny level detail tutorial)
jdbc读大量数据导致内存溢出
项目中遇到的问题 u-parse 组件渲染问题
How to solve the error "press any to exit" when deploying multiple easycvr on one server?
《力扣刷题计划》复制带随机指针的链表
生词生词生词生词[2]
【PaddlePaddle】 PaddleDetection 人脸识别 自定义数据集
lombok @Builder注解
Clickhouse (03) how to install and deploy Clickhouse
基于can总线的A2L文件解析(3)
Vulnhub's darkhole_ two
pytorch yolov5 训练自定义数据
vulnhub之darkhole_2
在通达信上做基金定投安全吗?
English sentence pattern reference
The main thread anr exception is caused by too many binder development threads