SOC-ATF 安全启动BL31流程分析(3)
一、BL31启动流程
与bl1和bl2不同,bl31包含两部分功能,在启动时作为启动流程的一部分,执行软硬件初始化以及启动bl32和bl33镜像。在系统启动完成后,将继续驻留于系统中,并处理来自其它异常等级的smc异常,以及其它需要路由到EL3处理的中断等。因此bl31启动流程主要包含以下工作:
(1)cpu初始化
(2)c运行时环境初始化
(3)基本硬件初始化,如gic,串口,timer等
(4)页表创建和cache使能
(5)启动后级镜像的准备以及新镜像的跳转
(6)若bl31支持el3中断,则需要初始化中断处理框架
(7)运行时不同secure状态的smc处理,以及异常等级切换上下文的初始化
(8)用于处理smc命令的运行时服务注册
网友的图:
二、bl31 基础初始化
2.1 参数保存
mov x20, x0
mov x21, x1
mov x22, x2
mov x23, x3
与bl2相同,将bl2传入的参数从caller寄存器保存到callee寄存器中
2.2 el3_entrypoint_common函数
该函数在bl1中已经详细介绍过了,但bl31对其的调用方式还是与bl1有所不同的。让我们看下bl31中的调用:
#if !RESET_TO_BL31el3_entrypoint_common \_init_sctlr=0 \_warm_boot_mailbox=0 \_secondary_cold_boot=0 \_init_memory=0 \_init_c_runtime=1 \_exception_vectors=runtime_exceptions \_pie_fixup_size=BL31_LIMIT - BL31_BASE
#elseel3_entrypoint_common \_init_sctlr=1 \_warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS \_secondary_cold_boot=!COLD_BOOT_SINGLE_CPU \_init_memory=1 \_init_c_runtime=1 \_exception_vectors=runtime_exceptions \_pie_fixup_size=BL31_LIMIT - BL31_BASEmov x20, 0mov x21, 0mov x22, 0mov x23, 0
#endif
由上面的代码可知,根据是否设置了RESET_TO_BL31,该函数有两套不同的调用参数。这是因为atf支持两种启动方式:
(1)启动从bl1开始执行,这是atf默认的启动方式。此时由于bl1已经执行过el3_entrypoint_common函数,系统基本配置都已经设置完成。因此像设置sctlr寄存器、热启动跳转处理、secondary cpu处理,以及内存初始化流程在bl1中都已经完成,bl31中就可以跳过它们了
(2)支持从bl31开始启动的基础是armv8支持动态设置cpu的重启地址,armv8架构提供了RVBAR(reset vector base address register)寄存器用于设置reset时cpu的启动位置。该寄存器一共有三个:RVBAR_EL1、RVBAR_EL2和RVBAR_EL3,根据系统实现的最高异常等级确定使用哪一个。我们知道armv8重启总是从最高异常等级开始执行,因此我们只需要设置最高异常等级的RVBAR寄存器即可。由于bl31运行在el3下,故若我们需要支持启动从bl31开始,就可通过将地址设置到RVBAR_EL3寄存器实现。
若启动从bl31开始,则由于它是第一级启动镜像,因此el3_entrypoint_common需要从头设置系统状态,因此该函数中的sctlr寄存器、启动跳转处理、secondary cpu处理,以及内存初始化流程等都需要执行。
虽然el3_entrypoint_common需要做的工作有点多,但这种方式直接跳过了bl1和bl2两级启动流程,相比于第一种方式其启动速度要更快,这也是它的最大优势。
最后这种方式将参数保存寄存器x20 – x23的值清零也非常好理解,因为此时bl31是启动的第一级镜像,自然就没有前级镜像传递的参数,此时将这些值清零可避免后面参数解析时出现问题
三、bl31 参数设置
3.1 bl31_early_platform_setup
该函数先初始化qemu控制台,然后解析bl2传入的镜像描述链表参数,并将解析到的bl32和bl33镜像ep_info保存到全局变量中。其主要流程如下:
qemu_console_init(); (1)bl_params_t *params_from_bl2 = (bl_params_t *)arg0; (2)…bl_params_node_t *bl_params = params_from_bl2->head; (3)while (bl_params) { (4)if (bl_params->image_id == BL32_IMAGE_ID) {bl32_image_ep_info = *bl_params->ep_info; (5)}if (bl_params->image_id == BL33_IMAGE_ID){bl33_image_ep_info = *bl_params->ep_info; (6)}bl_params = bl_params->next_params_info;}if (!bl33_image_ep_info.pc) (7)panic();
(1)控制台初始化
(2)获取arg0传入的镜像描述参数指针
(3)获取镜像链表头节点
(4)遍历镜像链表
(5)若该链表中含有bl32镜像描述符,则将其ep_info保存到全局变量
(6)多该链表中含有bl33镜像描述符,同样将其ep_info保存到全局变量
(7)校验bl33镜像的入口地址
3.2 bl31_plat_arch_setup
该函数用于为bl31相关内存创建页表,并使能MMU和dcache,其代码如下:
void bl31_plat_arch_setup(void){qemu_configure_mmu_el3(BL31_BASE, (BL31_END - BL31_BASE),BL_CODE_BASE, BL_CODE_END,BL_RO_DATA_BASE, BL_RO_DATA_END,BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END);}
四、bl31 主处理函数
4.1 bl31_platform_setup
该函数是平台相关的,qemu平台的实现如下:
void bl31_platform_setup(void)
{plat_qemu_gic_init(); (1)qemu_gpio_init(); (2)
}
(1)初始化gic,包括gic的distributor,redistributor,cpu interface等的初始化。关于bl31 gic和中断处理的详细流程,可以百度;
(2)初始化qemu平台的gpio,即为其设置gpio基地址和操作相关的回调函数
4.2 ehf初始化
ehf用于初始化el3中断处理相关的功能。在gicv3中中断被分为三个group:group0、secure group1和non secure group 1,它们根据scr_el3的irq和fiq位配置不同可分别路由到不同的异常等级处理。Ehf用于处理group0中断,这种中断总是以fiq形式触发,通过设置scr_el3将其路由到el3处理就可以在bl31中处理这种类型中断了。关于中断路由原理,后面补
ehf初始化流程主要就是设置group 0的路由方式,并为其设置一个总的中断处理函数。其主要流程如下:
void __init ehf_init(void)
{unsigned int flags = 0;int ret __unused;…set_interrupt_rm_flag(flags, NON_SECURE);set_interrupt_rm_flag(flags, SECURE); (1)ret = register_interrupt_type_handler(INTR_TYPE_EL3,ehf_el3_interrupt_handler, flags); (2)assert(ret == 0);
}
(1)计算中断路由相关的flag
(2)设置EL3类型(group 0)中断的中断路由方式和bl31总的中断处理函数
bl31中断处理函数ehf_el3_interrupt_handler会由异常向量表处理流程调用,它会继续根据中断优先级调用实际每个优先级对应的处理函数。中断优先级对应处理函数的注册流程分为以下共有两步,以下是中断注册流程的示例: 源码路径--plat/common/aarch64/plat_ehf.c
ehf_pri_desc_t plat_exceptions[] = {
#if RAS_EXTENSIONEHF_PRI_DESC(PLAT_PRI_BITS, PLAT_RAS_PRI),
#endif
#if SDEI_SUPPORTEHF_PRI_DESC(PLAT_PRI_BITS, PLAT_SDEI_CRITICAL_PRI),EHF_PRI_DESC(PLAT_PRI_BITS, PLAT_SDEI_NORMAL_PRI),
#endif
#if SPM_MMEHF_PRI_DESC(PLAT_PRI_BITS, PLAT_SP_PRI),
#endif
#ifdef PLAT_EHF_DESCPLAT_EHF_DESC,
#endif
};EHF_REGISTER_PRIORITIES(plat_exceptions, ARRAY_SIZE(plat_exceptions), PLAT_PRI_BITS);
上面的例子中注册了RAS、SDEI等中断,并为它们分配了不同的优先级,但是此时只是为中断处理函数占了一个位,而并未实际定义。它们实际上要在驱动中通过ehf_register_priority_handler注册。如对于sdei,其注册流程如下:
void sdei_init(void)
{…ehf_register_priority_handler(PLAT_SDEI_CRITICAL_PRI,sdei_intr_handler);ehf_register_priority_handler(PLAT_SDEI_NORMAL_PRI,sdei_intr_handler);
}
上面的源码路径:services/std_svc/sdei/sdei_main.c ;在 services 目录下的源码基本都是runtime service的函数。
当ehf_register_priority_handler注册完成后,理论上bl31就可以接收和处理el3中断了。但是实际上bl31正在执行时,PSTATE的irq和fiq中断掩码都是被mask掉的,即el3中断只有在cpu运行于低于EL3异常等级的时候才能真正被触发和处理 。
4.3 运行时服务初始化
前面我们提到bl31在系统初始化完成后还需要驻留系统,并处理来自低异常等级的smc异常,其异常处理流程被称为运行时服务。Arm为它们的使用场景定义了一系列的规范,分别用于处理类型不同的任务,如cpu电源管理规范PSCI、代理non secure world处理中断的软件事件代理规范SDEI,以及用于trust os相关调用的SPD等。显然这些服务被使用之前,其服务处理函数需要先注册到bl31中,运行时服务初始化流程即是用于该目的。
在分析运行时服务初始化流程之前,我们先看下其注册方式。以下是其注册接口DECLARE_RT_SVC的定义:
#define DECLARE_RT_SVC(_name, _start, _end, _type, _setup, _smch) \static const rt_svc_desc_t __svc_desc_ ## _name \ (1)__section("rt_svc_descs") __used = { \ (2).start_oen = (_start), \.end_oen = (_end), \.call_type = (_type), \.name = #_name, \.init = (_setup), \.handle = (_smch) \}
该接口定义了一个结构体__svc_desc_ ## _name,并将其放到了一个特殊的段rt_svc_descs中。这段的定义位于链接脚本头文件include/common/bl_common.ld.h中,其定义如下:
#define RT_SVC_DESCS \. = ALIGN(STRUCT_ALIGN); \__RT_SVC_DESCS_START__ = .; \KEEP(*(rt_svc_descs)) \__RT_SVC_DESCS_END__ = .;
即这些被注册的运行时服务结构体都被保存到以__RT_SVC_DESCS_START__开头,__RT_SVC_DESCS_END__结尾的rt_svc_descs段中,其数据可表示为如下结构:
因此若需要获取这些结构体指针,只需遍历这段地址就可以了。运行时服务初始化函数runtime_svc_init 即是如此,其定义如下:
void __init runtime_svc_init(void)
{…rt_svc_descs = (rt_svc_desc_t *) RT_SVC_DESCS_START; (1)for (index = 0U; index < RT_SVC_DECS_NUM; index++) { (2)rt_svc_desc_t *service = &rt_svc_descs[index];rc = validate_rt_svc_desc(service); (3)if (rc != 0) {ERROR("Invalid runtime service descriptor %p\n",(void *) service);panic();}if (service->init != NULL) { rc = service->init(); (4)if (rc != 0) {ERROR("Error initializing runtime service %s\n",service->name);continue;}}…}
}
(1)获取rt_svc_descs段的起始地址RT_SVC_DESCS_START
(2)遍历该段中所有已注册rt_svc_desc_t结构体相应的运行时服务
(3)校验运行时服务有效性
(4)调用该服务对应的初始化回调,该回调函数是在DECLARE_RT_SVC注册宏中通过参数_setup传入的
4.4 启动bl32
Bl32主要用于运行trust os,它主要用来保护用户的敏感数据(如密码、指纹、人脸等),以及与其相关的功能模块,如加解密算法,ta的加载与执行,secure storage等。各个厂家的trust os实现都有所不同,但基本思路是类似的,下面分析中涉及到具体的trust os时,我们将选取开源框架optee为例。
启动流程中bl32运行流程如下:
if (bl32_init != NULL) {INFO("BL31: Initializing BL32\n");int32_t rc = (*bl32_init)();if (rc == 0)WARN("BL31: BL32 initialization failed\n");}
它首先判断bl32_init是否已注册,若已注册则通过调用该函数执行实际的bl32运行流程。我们先看下optee架构下bl32_init注册流程(services/spd/opteed):
DECLARE_RT_SVC(opteed_fast,OEN_TOS_START,OEN_TOS_END,SMC_TYPE_FAST,opteed_setup, (1)opteed_smc_handler
);static int32_t opteed_setup(void)
{…bl31_register_bl32_init(&opteed_init) (2)return 0;
}void bl31_register_bl32_init(int32_t (*func)(void))
{bl32_init = func; (3)
}
(1)通过DECLARE_RT_SVC设置optee的初始化回调opteed_setup
(2)将opteed_init函数注册为bl32的启动函数
(3)实际的回调注册
因此optee的bl32启动函数为opteed_init,它的流程与我们先前bl1启动bl2的跳转方式类似,其流程图如下:
它先获取先前保存的secure镜像ep信息(即bl32的ep信息),然后用其初始化异常等级切换的上下文,设置secure el1的系统寄存器,spsr_el3和elr_el3等。然后调用opteed_enter_sp函数跳转到bl32。这里有个问题,bl31除了启动bl32后,还需要继续启动bl33,因此bl32启动完成后还需要跳转回bl31并继续执行bl33启动流程。由于bl32在secure EL1执行,其同步进入bl31只能使用smc方式,因此需要在smc处理流程中跳转到原先的断点处。Armv8中c语言的lr寄存器为x30,因此若我们在跳转之前保存x30及运行上下文,然后再smc处理流程中恢复这些上下文即可以实现恢复断点处执行了。以下为opteed_enter_sp函数的上下文保存流程:
func opteed_enter_spmov x3, spstr x3, [x0, #0]sub sp, sp, #OPTEED_C_RT_CTX_SIZEstp x19, x20, [sp, #OPTEED_C_RT_CTX_X19]stp x21, x22, [sp, #OPTEED_C_RT_CTX_X21]stp x23, x24, [sp, #OPTEED_C_RT_CTX_X23]stp x25, x26, [sp, #OPTEED_C_RT_CTX_X25]stp x27, x28, [sp, #OPTEED_C_RT_CTX_X27]stp x29, x30, [sp, #OPTEED_C_RT_CTX_X29]b el3_exit
endfunc opteed_enter_sp
在该函数中上下文会被保存到全局变量opteed_sp_context中,optee初始化完成后返回smc处理的流程如下(services/spd/opteed/opteed_main.c):
uintptr_t opteed_smc_handler(…)
{
optee_context_t *optee_ctx = &opteed_sp_context[linear_id];…switch (smc_fid) {case TEESMC_OPTEED_RETURN_ENTRY_DONE: (1)assert(optee_vector_table == NULL);optee_vector_table = (optee_vectors_t *) x1;…opteed_synchronous_sp_exit(optee_ctx, x1); (2)break;…}
}
(1)表明本次smc调用是bl32启动完成后返回
(2)调用该函数恢复进入bl32之前保存的上下文,返回断点处继续执行。该函数的定义如下:
func opteed_exit_spmov sp, x0 (1)ldp x19, x20, [x0, #(OPTEED_C_RT_CTX_X19 - OPTEED_C_RT_CTX_SIZE)]ldp x21, x22, [x0, #(OPTEED_C_RT_CTX_X21 - OPTEED_C_RT_CTX_SIZE)]ldp x23, x24, [x0, #(OPTEED_C_RT_CTX_X23 - OPTEED_C_RT_CTX_SIZE)]ldp x25, x26, [x0, #(OPTEED_C_RT_CTX_X25 - OPTEED_C_RT_CTX_SIZE)]ldp x27, x28, [x0, #(OPTEED_C_RT_CTX_X27 - OPTEED_C_RT_CTX_SIZE)]ldp x29, x30, [x0, #(OPTEED_C_RT_CTX_X29 - OPTEED_C_RT_CTX_SIZE)] (2)mov x0, x1ret (3)
endfunc opteed_exit_sp
(1)恢复进入bl32之前保存在context中的栈
(2)恢复进入bl32之前保存的callee寄存器
(3)返回断点处继续执行,兜兜转转一圈,我们好不容易又返回到bl31_main函数了
最后,用一张图来描述以上整个流程:
4.5 启动bl33
bl33启动流程与前面各级镜像启动流程,类似,也是根据ep_info设置bl33的上下文、入口地址和参数,然后跳转到入口执行。大家有兴趣可以自行根据代码分析一下,这里不再赘述。好了,atf启动流程总算走完了,接下来我们将跳转到bl33(uboot)的世界,一切的准备都是为了uboot启动kernel那一刻的美好
相关文章:
SOC-ATF 安全启动BL31流程分析(3)
一、BL31启动流程 与bl1和bl2不同,bl31包含两部分功能,在启动时作为启动流程的一部分,执行软硬件初始化以及启动bl32和bl33镜像。在系统启动完成后,将继续驻留于系统中,并处理来自其它异常等级的smc异常,以…...
计算机三级网络技术备考
#subtotal 1Mbps1024kb128KB12.8M/s #1024B1KB 1024KB1MB 1024MB1GB #路由器的5G信号和平常的波长不同(5G的穿墙性能差) #局域网LAN(一公里内——构成集线机、交换机、同轴电缆) #城域网MAN(几公里到几十公里——光…...
Linux红帽:RHCSA认证知识讲解(四)修改远程配置文件,取消root禁用,便于使用root身份远程
Linux红帽:RHCSA认证知识讲解(四)修改远程配置文件,取消root禁用,便于使用root身份远程 前言一、远程连接的用途和原因二、通过 ssh 远程登陆系统三、默认限制及解决方案(一)非常规方法一&#…...
【笔记ing】每天50个英语词汇
ex- e-out exclude 排外,排除 expect 期待,期望 单词构成: 前缀(prefix):情感(emotion)方向(orientation) 词根(root)…...
Linux 基本开发工具的使用(yum、vim、gcc、g++、gdb、make/makefile)
文章目录 Linux 软件包管理器 - yum理解什么是软件包和yum如何查看/查找软件包如何安装软件如何实现本地机器和云服务器之间的文件互传如何卸载软件 Linux 编辑器 - vim 的使用vim 的基本概念vim 的基本操作vim 命令模式各命令汇总vim 底行模式各命令汇总vim 的简单配置 Linux …...
idea创建第一个springboot程序
说明: 我计划用idea,创建第一个springboot程序,但是作为新手完全不会弄,今天我就亲自尝试一边,并且出一期详细,完美的教程,亲测可以运行 step1. 点击file , 选new, 选…...
python 使用 venv 创建虚拟环境 (VSCode)
Python 自带了一个名为 venv 的模块,可以用来创建虚拟环境。这是 Python 官方推荐的方式,不需要额外安装 Anaconda 或其他工具。 假设项目名为myproject,进入到项目目录 cd myproject 创建虚拟环境 python3 -m venv 虚拟环境名(…...
组态软件在物联网中的应用
随着物联网的快速发展,组态软件在物联网中的应用也越来越广泛。组态软件是一种用于创建和管理物联网系统的可视化工具,它能够将传感器、设备和网络连接起来,实现数据的采集、分析和可视化。本文将探讨组态软件在物联网中的应用,并…...
字节火山引擎-大模型声音复刻,流式语音合成接口
字节火山引擎-大模型声音复刻,流式语音合成接口 参考文档:火山引擎-大模型声音复刻文档 官网给出的示例代码有bug,这里已经修改了 创建应用 声音复刻大模型页面查看应用,获取接口调用需要的参数 注意调用tts接口时候需要三个参数…...
QT:Graphics View的坐标系介绍
在 Qt 的 Graphics View 框架中,存在三种不同的坐标系,分别是 物品坐标系(Item Coordinates)、场景坐标系(Scene Coordinates) 和 视图坐标系(View Coordinates)。这三种坐标系在图形…...
轻松搭建:使用Anaconda创建虚拟环境并在PyCharm中配置
一、使用Anaconda创建虚拟环境 1. 安装Anaconda 2..conda常用的命令 3. 创建虚拟环境-以搭建MachineVision为例 4. 激活虚拟环境 5. 安装依赖包 二、PyCharm配置环境 在进行Python项目开发时,合理的环境管理是必不可少的,特别是当你在多个项目中…...
Unity TMPro显示中文字体
TMP默认的字体只能显示英语,那么怎么显示中文呢 1、找到支持中文的字体文件 在c盘搜索Fonts文件夹有很多支持中文的字体文件 我这里选择雅黑 PS.双击打开发现里面有粗体细体普通三个版本,也可以只导入一个版本进去 2、将其拖入到unity Assets里面 3…...
【嵌入式原理设计】实验五:远程控制翻盖设计
目录 一、实验目的 二、实验环境 三、实验内容 四、实验记录及处理 五、实验小结 六、成果文件提取链接 一、实验目的 熟悉和掌握舵机及串口控制方式 二、实验环境 Win10ESP32实验开发板 三、实验内容 1、熟悉舵机的控制方式; 2、用串口发…...
矩阵乘积态简介
定义 矩阵乘积态(Matrix Product State, MPS)是一种用于表示量子多体系统的强大工具,特别是在一维系统中。MPS 是一种张量网络状态,它通过将全局量子态分解为一系列局部张量的乘积来有效地表示量子态。 注释: 量子态表…...
国自然面上项目|基于肺癌精准靶向治疗的基因影像组学研究|基金申请·25-02-26
小罗碎碎念 今天和大家分享一个国自然面上项目,执行年限为2019.01~2022.12,直接费用为57万元。 项目旨在解决肺癌靶向治疗耐药问题,通过整合多组学和影像组学技术构建预测模型。 研究期间,对非小细胞肺癌 CT 影像组学…...
OA办公系统自动渗透测试过程
目录 一、下载环境源码 二、部署环境 三、测试 XSS漏洞 SQL注入 文件上传漏洞 一、下载环境源码 OA源码打包地址: https://download.csdn.net/download/weixin_43650289/90434502?spm=1001.2014.3001.5503 二、部署环境...
Fisher信息矩阵(Fisher Information Matrix,简称FIM)
Fisher信息矩阵简介 Fisher信息矩阵(Fisher Information Matrix,简称FIM)是统计学和信息理论中的一个重要概念,广泛应用于参数估计、统计推断和机器学习领域。它以统计学家罗纳德费希尔(Ronald Fisher)的名…...
nginx反向代理以及负载均衡(常见案例)
一、nginx反向代理 1、什么是代理服务器? 代理服务器,客户机在发送请求时,不会直接发送给目的主机,而是先发送给代理服务器,代理服务接受客户机请求之后,再向主机发出,并接收目的主机返回的数据…...
LabVIEW形状误差测量系统
在机械制造领域,形状与位置公差(GD&T)直接影响装配精度与产品寿命。国内中小型机加工企业因形状误差导致的返工率高达12%-18%。传统测量方式存在以下三大痛点: 设备局限:机械式千分表需人工读数,精度…...
将VsCode变得顺手好用(1
目录 设置中文 配置调试功能 提效和增强相关插件 主题和图标相关插件 创建js文件 设置中文 打开【拓展】 输入【Chinese】 下载完成后重启Vs即可变为中文 配置调试功能 在随便一个位置新建一个文件夹,用于放置调试文件以及你未来写的代码,随便命名但…...
排序模板——C++
0.排序模板题目 题目描述 将读入的 N 个数从小到大排序后输出。 输入格式 第一行为一个正整数 N。 第二行包含 N 个空格隔开的正整数 ai,为你需要进行排序的数。 输出格式 将给定的 N 个数从小到大输出,数之间空格隔开,行末换行且无空格。 …...
HTTP/HTTPS 服务端口监测的简易实现
一 HTTP/HTTPS 服务端口监测的简易实现方法 在当今快节奏的工作环境中,工作忙碌成为了许多职场人的常态。就拿我们团队最近经历的事情来说,工作任务一个接一个,大家都在各自的岗位上争分夺秒地忙碌着。然而,就在这样高强度的工作…...
快速入门——状态管理VueX
Vuex介绍 状态管理 每一个Vuex应用的核心都是一个store,与普通的全局对象不同的是,基于Vue数据与视图绑定的特点,当store中的状态发生变化时,与之绑定的视图也会被重新渲染。 store中的状态不允许被直接修改,改变sto…...
C# 根据Ollama+DeepSeekR1开发本地AI辅助办公助手
在上一篇《访问DeepSeekR1本地部署API服务搭建自己的AI办公助手》中,我们通过通过Ollama提供的本地API接口用Python实现了一个简易的AI办公助手,但是需要运行Py脚本,还比较麻烦,下面我们用C#依据Ollama提供的API接口开发一个本地A…...
Flutter - 基础Widget
Flutter 中万物皆 Widget,基础Widget 同步对应 Android View. 普通文本 Text /*** 控制文本样式统一使用 style:TextStyle, 例:fontSize(字体大小),color(颜色),shadows(阴影)等等* 控制文本布局需单独设置:* textAlign(文不对齐方式)* te…...
Tips :仿真竞争条件 指的是什么?
文章目录 **为什么会出现仿真竞争条件?****典型场景举例****System Verilog 如何解决竞争条件?****1. 使用 `program` 块隔离测试平台****2. 使用 `clocking` 块明确时序关系****3. 非阻塞赋值(`<=`)的合理使用****竞争条件的根本原因****总结****代码结构****1. 设计模…...
【Elasticsearch】script_fields 和 runtime_fields的区别
script_fields和runtime_fields都是 Elasticsearch 中用于动态计算字段值的功能,但它们在实现方式、应用场景和性能表现上存在显著区别。以下是两者的详细对比: 1.定义和应用场景 • script_fields: • 定义:通过 Painless 脚本…...
达梦DTS数据迁移工具生产篇(MySQL->DM8)
本文章使用的DTS工具为 2024年9月18日的版本,使用的目的端DM8数据库版本为2023年12月的版本,注意数据库版本和DTS版本之间跨度不要太大,以免出现各种兼容性的报错。若发现版本差距过大时,请联系达梦技术服务工程师处理。 1. 迁移…...
【安卓逆向】逆向APP界面UI修改再安装
1.背景 有一客户找到我,说能不能把APP首页的底部多余界面去掉。 逆向实战 想要去除安卓应用软件中的内容,需要对APP逆向进行修改再打包。 通过工具 MIT管理器工具 提取APK包,点击apk文件,点击查看反编译apk。 搜索关键字。这里关键…...
企业级大模型应用的Java-Python异构融合架构实践
一、后端语言相关技术生态 Python语言 Python在AI计算领域拥有全面的生态支持: 底层工具库: Pandas、NumPy、SciPy、Matplotlib深度学习框架: PyTorch、TensorFlow领域专用框架: HuggingFace Transformers(社区生态为主) 常见Python框架 …...
深度剖析数据中台架构图,铸造数字文明的基石
🔥🔥 AllData大数据产品是可定义数据中台,以数据平台为底座,以数据中台为桥梁,以机器学习平台为中层框架,以大模型应用为上游产品,提供全链路数字化解决方案。 ✨奥零数据科技官网:http://www.aolingdata.com ✨AllData开源项目:https://github.com/alldatacenter/a…...
python实现基于文心一言大模型的sql小工具
一、准备工作 注册与登录: 登录百度智能云千帆控制台,注册并登录您的账号。 创建千帆应用: 根据实际需求创建千帆应用。创建成功后,获取AppID、API Key、Secret Key等信息。如果已有千帆应用,可以直接查看已有应用的AP…...
飞腾腾锐D2000 + OpenHarmony 4.1release部署deepseek大模型
简介 1.1 飞腾腾锐D2000 飞腾腾锐D2000是一款面向桌面应用的高性能通用处理,集成8个飞腾自主研发的高能效处理器核FTC663,兼 容64位ARMv8指令集并支持ARM64和ARM32两种执行模式,支持单精度、双精度浮点运算指令和ASIMD处理 指令,主…...
进程概念、PCB及进程查看
文章目录 一.进程的概念进程控制块(PCB) 二.进程查看通过指令查看进程通过proc目录查看进程的cwd和exe获取进程pid和ppid通过fork()创建子进程 一.进程的概念 进程是一个运行起来的程序,而程序是存放在磁盘的,cpu要想执行程序的指…...
Oracle 数据库基础入门(一):搭建数据管理基石
在当今数字化时代,数据库作为数据管理的核心工具,对于各类应用系统的开发至关重要。尤其是在 Java 全栈开发领域,掌握一款强大的数据库技术是必备技能。Oracle 数据库以其卓越的性能、高度的可靠性和丰富的功能,在企业级应用中广泛…...
selenium如何实现,开启浏览器的开发者工具模式,并且开启 toggle移动设备模拟模式
核心实现代码 pythonCopy Code from selenium import webdriver from selenium.webdriver.chrome.options import Options def enable_devtools_with_toggle(): options Options() # 强制开启开发者工具 options.add_argument("--auto-open-devtools-for-tabs&quo…...
分布式锁实现(数据库+Redis+Zookeeper)
1. 数据库分布式锁 实现原理 基于唯一索引: 创建一张锁表,通过唯一索引(如锁名称)保证互斥性。 加锁:插入一条记录,成功则获取锁,失败则重试。 解锁:删除对应记录。 乐观锁&…...
七、Spring Boot:初识与项目搭建
深入解析 Spring Boot:初识与项目搭建 Spring Boot 是基于 Spring Framework 的开源 Java 基础框架,旨在简化 Spring 应用的开发过程。它通过“约定优于配置”的理念,极大地减少了开发中的配置工作,同时提供了“开箱即用”的功能…...
记录一下用docker克隆某授权制定ip的环境恢复
#首先还是要看日志根据问题去进行调整 java web的老项目配置文件一般是 bin启动里边的脚本 还有conf中的 xml配置文件 再或者就是classes中的配置文件,再或者就是lib中的jar包中的配置文件 1.安装docker 2.创建docker网络 docker network create --driver bridge --subnet…...
【含文档+PPT+源码】基于微信小程序的健康饮食食谱推荐平台的设计与实现
项目介绍 本课程演示的是一款基于微信小程序的健康饮食食谱推荐平台的设计与实现,主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 1.包含:项目源码、项目文档、数据库脚本、软件工具等所有资料 2.带你从零开始部署运行本…...
主流虚拟化技术讲解
目录 VMware vSphere Microsoft Hyper-V KVM(Kernel-based Virtual Machine) OpenStack VMware vSphere 架构与组件:VMware vSphere 是基于裸金属虚拟化技术的平台,核心组件包括 ESXi 主机和 vCenter Server。ESXi 是虚拟化层…...
java开发——为什么要使用动态代理?
举个例子:假如有一个杀手专杀男的,不杀女的。代码如下: public interface Killer {void kill(String name, String sex);void watch(String name); }public class ManKiller implements Killer {Overridepublic void kill(String name, Stri…...
kotlin 知识点一 变量和函数
在Kotlin中定义变量的方式和Java 区别很大,在Java 中如果想要定义一个变 量,需要在变量前面声明这个变量的类型,比如说int a表示a是一个整型变量,String b表 示b是一个字符串变量。而Kotlin中定义一个变量,只允许在变量…...
将CUBE或3DL LUT转换为PNG图像
概述 在大部分情况下,LUT 文件通常为 CUBE 或 3DL 格式。但是我们在 OpenGL Shader 中使用的LUT,通常是图像格式的 LUT 文件。下面,我将教大家如何将这些文件转换为 PNG 图像格式。 条形LUT在线转换(不是8x8网络)&am…...
侯捷 C++ 课程学习笔记:类的声明与构造函数
目录 一、类的声明 二、内联函数 三、访问级别 四、构造函数 五、构造函数重载 六、实际应用案例 七、学习心得 一、类的声明 类的声明是定义类的基本结构,包括类的成员变量和成员函数。类的声明分为类头和类体两部分。 类头(class head…...
BGP状态和机制
BGP邻居优化 为了增加稳定性,通常建议实验回环口来建立邻居。更新源:建立邻居和邻居所学习到的路由的下一跳。多跳:EBGP邻居建立默认选哟直连,因为TTL=1,如果非直连,必须修改TTL。命令备注peer 2.2.2.2 connect-interface lo1配置更新源peer 2.2.2.2 ebgp-max-hop 2配置T…...
MongoDB 数据库简介
MongoDB 数据库简介 引言 随着互联网技术的飞速发展,数据已经成为企业的重要资产。为了高效地管理和处理这些数据,数据库技术应运而生。MongoDB作为一种流行的NoSQL数据库,因其灵活的数据模型和高效的数据处理能力,受到了广泛的关注。本文将为您详细介绍MongoDB的基本概念…...
浏览器下载vue.js.devtools,谷歌浏览器和edg浏览器
1、谷歌浏览器下载: 情况一:如果谷歌应用商店可以打开,那么就直接到谷歌应用商店下载,直接搜索vue.js.devtools添加扩展即可。 情况二:谷歌浏览器的谷歌应用商城打不开,那么就百度搜索极简插件找到vue.js.…...
Android AOSP系统裁记录
Android 系统裁剪是指根据需求移除不必要的组件和功能,以优化系统性能、减少存储占用或满足特定设备需求。以下是 Android 系统裁剪的基本步骤: 1. 准备环境 操作系统:推荐使用 Ubuntu 或 macOS。 工具: Android SDK Android N…...
Could not download npm for node v14.21.3(nvm无法下载节点v14.21.3的npm)
场景描述:之前的项目用的是node以前的版本,使用nvm没下载下来,npm命令执行不了 错误如下图,15版本的node同理,下载的都是.exe可执行文件的扩展名,使用npm命令终端无法识别 解决思路:去node官网…...