详解全志R128 RTOS安全方案功能

介绍 R128 下安全方案的功能。安全完整的方案基于标准方案扩展,覆盖硬件安全、硬件加解密引擎、安全启动、安全系统、安全存储等方面。

配置文件相关

本文涉及到一些配置文件,在此进行说明。

env*.cfg配置文件路径:

board/<chip>/<board>/configs/env*.cfg

sys_config.fex路径:

board/<chip>/<board>/configs/sys_config.fex

image_header.cfg路径:

board/<chip>/<board>/configs/image_header.template.cfg

sys_partition*.fex路径:

board/<chip>/<board>/configs/sys_partition.fex

功能介绍

R128 FreeRTOS 系统上支持如下安全功能

image-20230506160432758

安全硬件

下图是 ARM 为 M33 Star 提供的一种基于 TrustZone 的 SoC 架构参考实现

image-20230506160502863

当 CPU 取指或者访问数据时,经过 SAU 与 IDAU 审查之后,携带安全属性,进入 AHB 总线。

由于 SAU/IDAU 机制只适用于 Arm M33 Star 处理器,那么 AHB 设备使用下列两种方法识别与应答这些携带安全属性的访问

  1. 第一种是外设在设计时就可以识别安全属性;
  2. 第二种需要借助其他控制器来实现,比如上图中的 PPC。开发人员设置 PPC 为不同的外设设置不同的访问规则。同理 MPC 则是用于设置存储器区域的安全属性。

R128 上有些外设可以识别安全属性,比如 CE、DMA 等。大部分外设需要借助 SPC 来配置其安全属性。其中的 PPC 对应 R128 上的 SPC,MPC 对应 R128 上的 SMC,TZMA

Arm M33 Star TrustZone 简介

Arm M33 Star TrustZone 与 Arm A 系列的 TrustZone 类似,在设计上,处理器都具有安全与非安全状态,非安全软件只能访问非安全内存。与 Arm A 处理器中的 TrustZone 技术不同, Arm M33 Star 的 Secure 和 Normal 世界是基于内存映射的,转换在异常处理中自动发生。

image-20230506160718924

安全扩展功能

除了 ARM TrustZone 安全扩展功能外,R128 在 SoC 设计上还实现了一些安全硬件来保障完整的安全特性。

  • SMC

SMC 配置 hspsram 存储区域的安全属性,只有在安全环境才可以使用该模块。

  • TZMA

TZMA 用于配置 lspsram、sram、spi flash、dsp sram、csi&vad sram 地址空间的安全属性。

模块大小
TZMA0128KB
TZMA1128KB
TZMA2256KB
TZMA3256KB
DSP_TZMA0256KB
EXPSRAM_TZMA64KB
LPSRAM_TZMA8MB
FLASH_TZMA192MB
  • SPC

SPC 配置外设的安全属性,只有在安全环境才可以使用该模块

  • CE

CE 是 AW SoC 的硬件加解密引擎,支持 AES/SHA/RSA 等算法。

  • TRNG

TRNG 是真随机数发生器,随机源是 8 路独立的唤醒振荡器,由模拟器件电源噪声产生频率抖动,用低频时钟重采样,然后进行弹性抽取和熵提取处理,最终输出 128bit 真随机数。

  • SID/efuse

efuse:一次性可编程熔丝技术,是一种 OTP(One‑Time Programmable,一次性可编程)存储器。efuse 内部数据只能从 0 变成 1,不能从 1 变成 0,只能写入一次。

Secure ID,控制 efuse 的访问。efuse 的访问只能通过 sid 模块进行。sid 本身非安全,安全非安全均可访问。但通过 sid 访问 efuse 时,安全的 efuse 只有安全世界才可以访问,非安全世界访问的结果为 0。

  • Flash Encryption

Flash Encryption 模块向 Flash 写数据时计算 AES 进行加密,从 Flash 读出数据时进行解密。支持在 SBUS 读写数据和 CBUS 读操作时进行 AES 实时加解密。仅 Nor Flash 支持。

  • Secure Timer and Watchdog

支持一套安全 Timer 与一套安全 Watchdog

硬件加解密引擎

CE:Crypto Engine,是 AW SoC 中一个硬件加解密模块,支持多种对称、非对称、摘要生成算法。包含安全/非安全两套接口。

CE 驱动支持算法如下,但 CE 硬件加密模块支持的加密算法不仅限下列算法。

算法支持
AES‑ECB‑128/192/256
AES‑CBC‑128/192/256
AES‑CTR‑128/192/256
AES‑OFB‑128/192/256
AES‑CFB8‑128/192/256
HASH‑MD5
HASH‑SHA1
HASH‑SHA224
HASH‑SHA256
HASH‑SHA384
HASH‑SHA512
RSA‑512
RSA‑1024
RSA‑2048

CE具体接口可以在 CE | R128 Documents 找到,TRNG可以在 TRNG | R128 Documents 找到,这里不过多赘述。

安全启动

安全固件构建

安全固件与非安全固件打包过程、封装格式类似,仅在原本非安全打包方式基础上,对每个镜像加入签名信息。

source envsetup.sh
lunch_rtos R128_xxx_m33
mrtos clean
mrtos_menuconfig # 开启CONFIG_COMPONENTS_TFM。注:非安全固件需关闭
mrtos
createkeys # 创建签名密钥,无需每次执行
pack ‑s # 打包安全固件

pack ‑s 打包完成后,生成安全固件,固件位于 out 目录下,文件名为rtos_freertos_{BOARD}_uart0_secure_[8|16]Mnor_v[NUM].img。其中 v[NUM] 表示固件的版本信息,NUM 为版本号,由安全固件版本号(见4.7 节)决定。

在首次进行安全固件打包之前,必须运行一次 createkeys 创建自己的签名密钥,并将创建的秘钥妥善保存。每次执行 createkeys 后都会生成新的密钥,因此不用每次都执行,除非需要更换密钥。

安全固件配置

打包生成安全固件前,需确保 TFM 打开,在 M33 核执行 mrtos menuconfig 进入配置主界面,进行如下配置:

System components ‑‑‑>
    aw components ‑‑‑>
        TFM Support ‑‑‑>
            [*] TFM support

只有安全固件需要开始 TFM,非安全固件需要关闭,且仅有 M33 支持 TFM。

启动流程

R128 包含三个处理器,分别为 M33(ARM)、C906(RISC‑V)、HIFI5(DSP),仅 M33 支持安全隔离。

从安全性考虑,Brom 启动时,系统必须处于安全状态,因此,选择 M33 作为启动核。

R128 对于 nor 和 nand 方案采用不同的启动流程。对于 nor 方案,安全启动流程如下图所示。启动过程没有 uboot,由 boot0 直接启动安全和非安全 OS,其中 brom、boot0、S‑OS 位于安全域,M33 N‑OS、DSP OS、RISC‑V OS 位于非安全域。

image-20230506164712891

对于 nand 方案,由于 nand 需要完整的 nand 驱动才能加载位于逻辑分区的数据,而 boot0 目前只有简单驱动,只能读取物理数据,uboot 有完整的驱动,才能读取逻辑数据。因此 nand 方案启动过程是由 boot0 启动 M33 S‑OS,再由 M33 S‑OS 启动 uboot,启动流程如下图所示。

image-20230506164743973

校验流程

对于 Nor 方案来说,Brom 加载并校验 sboot,通过后,sboot 加载 M33 S‑OS、M33 N‑OS、RISC‑V OS、DSP OS,并对他们进行校验。所有校验处理都在安全域进行,保障了校验过程的安全性。

image-20230506164759713

对于 nand 方案来说,Brom 加载并校验 Sboot,再由 Sboot 加载和校验 M33 S‑OS,最后 Uboot 对 M33 N‑OS、RISC‑V OS、DSP OS 进行加载和校验

image-20230506164851210

签名校验

R128 支持两种签名校验,一种是软件 ECC‑256 算法,一种是硬件 SHA256‑RSA2048 算法,默认使用 SHA256‑RSA2048 算法。具体的签名校验方法配置在board/R128s2/pro/configs/image_header.template.cfg配置文件中,如下所示选择具体的签名校验算法:

"magic" : "AWIH",
"hversion" : "0.5",
"pversion" : "0",
"key_type" : "rsa", #rsa/ecc
"image" : {"max_size": "16384K"},

配置完签名算法 key_type 后,在创建密钥执行 createkeys 时会自动根据配置文件生成对应的密钥,并在执行打包命令的时候会采用对应的签名校验算法进行固件打包签名。

信任链

R128 整个安全启动过程中,以 efuse 中的根公钥 hash 为起点,通过层层校验,保障每一层固件在没有篡改的情况下正常运行。

在实现过程中,每一层可使用不同的签名密钥,充分保障了安全性。

烧写 rotpk.bin 与 secure enable bit

烧写 rotpk.bin 与 secure enable bit,主要包括以下几种方式:

  1. 使用 PhoenixSuit 烧写安全固件,安全固件烧写完毕时自动烧写 efuse 中的 secure enable bit 位。
  2. 通过 efuse 或 TFM 控制台命令将 rotpk.bin 烧写到设备的 efuse 中,具体操作方式见 5.5 节 TFM 使用示例。
  3. 在 烧 写 安 全 固 件 完 毕 时, 解 析 安 全 固 件 获 取 rotpk.bin 并 写 入 efuse, 然 后 再将 efuse 中 的 secure enable bit 置 1。(该 方 式 需 要 在 uboot 中 开 启 宏:CONFIG_SUNXI_BURN_ROTPK_ON_SPRITE=y)

  4. 对于 Nand 方案支持 Dragon SN 工具烧写 rotpk.bin 到设备的 efuse 中。

efuse 的硬件特性决定了 efuse 中每个 bit 仅能烧写一次。此外,efuse 中会划分出很多区域,大部分区域也只能烧写一次。详细请参考芯片 SID 规范。

烧写 secure enable bit 后,会让设备变成安全设备,此操作是不可逆的。后续将只能启动安全固件,启动不了非安全固件。

如果既烧写了 secure enable bit,又烧写了 rotpk.bin,设备就只能启动与 rotpk.bin 对应密钥签名的安全固件;如果只烧写 secure enable bit,没有烧写 rotpk.bin,此设备上烧写的任何安全固件都可以启动。调试时可只烧写 secure enable bit,但是设备出厂前必须要烧写 rotpk.bin。

防回退

R128 支持防止固件版本回退,打包过程中会根据配置文件image_header.template.cfg中的pversion 对应的版本信息加入到镜像的 Image Header 中。

在启动过程中,brom 在 sboot 校验之前,会读取 sboot 镜像 Image Header 中的版本信息,将该版本信息与 efuse 中 NV 区域保存的版本信息进行对比:

  • 如果 efuse 中的版本信息高,不启动 sboot0,brom 转入 fel 烧写。

  • 如果 efuse 的版本小于等于 Image Header 中的版本,继续加载 sboot 并校验。

sboot 启动过程中,如果发现 efuse 的版本小于 Image Header 中的版本,则将此版本信息写入到efuse 中的 NV 区域

安全固件最多支持更新 32 个版本。

安全量产方法

支持三种量产方式:

  1. 使用 LiveSuit/PhoenixSuit 烧写安全固件,在固件烧写完成时自动烧写 secure bit。启动之后,提供控制台命令方式烧写 rotpk。
  2. 离线安全固件量产方式,flash 上同时保存安全与非安全 boot0,第一次启动时,走非安全boot0,在非安全 boot0 中烧写 secure bit,重启;第二次启动时,走安全 boot0,进行正常的安全启动。rotpk 可以在非安全 boot0 中烧写,也可以在控制台中烧写。
  3. 对于 Nand 方案支持 Dragon SN 工具烧写 efuse,因此可以在使用 LiveSuit/PhoenixSuit 烧写安全固件时自动烧写 secure bit,启动后再通过 Dragon SN 工具烧写 rotpk

安全系统

软件系统架构

R128 系统中只有一份安全 OS,即运行在 M33 上的 S‑OS,其他 RISC‑V/DSP 如需访问安全资源,跨核调用到 M33 N‑OS,M33 N‑OS 再调用 S‑OS 的资源。

image-20230506165919382

TFM

M33 Star 安全 OS 我们采用的 Arm 官方推出的 TF‑M(Trusted Firmware‑M),TF‑M 实现了ARMv8‑M 架构的 SPE(Secure Porcessing Environment),它是一种对标 PSA 认证的平台安全架构参考实现,方便 Chip、RTOS 与 Device 通过 PSA 认证。其软件框架如下图所示。

../_images/readme_tfm_v8.png

TF‑M 包含:

  • 安全启动。用来来认证 NSPE/SPE 镜像的完整性。
  • TF‑M Core。负责控制 SPE 与 NSPE 隔离、通信。
  • 安全服务。包括 ITS(Internal Trusted Storage),PS(Protected Storage)等。
源码结构

供非安全环境调用的 TFM API 接口放置在 M33 rtos 下的components/aw/tfm目录下,安全 M33 RTOS 编译前配置上 CONFIG_COMPONENTS_TFM,即可将 NSC 相关 API编入到 M33 RTOS 镜像中。

TFM 接口

非安全端调用传入的非安全端 API 接口指针 pxCallback

函数原型

uint32_t tfm_sunxi_nsc_func(Callback_t pxCallback);

参数:

  • pxCallback:非安全端 API 接口指针

返回值

  • 该函数被调用的次数

调用说明: 该函数用于安全非安全交互测试,在非安全端调用该函数之后,会切换到安全端,该函数在安全端会调用传入的非安全端 API 接口指针。

按照给定的 key_name 将长度为 key_bit_len 的 key_data 烧写到对应的安全 efuse 区域

函数原型

int tfm_sunxi_efuse_write(char key_name, unsigned char key_data, unsigned int key_bit_len);

参数:

  • key_name:efuse 对应的区域名
  • key_data:待烧写到 efuse 中的数据
  • key_bit_len:待烧写到 efuse 中数据的长度

返回值

  • 0:成功
  • 负数:失败
在安全端进行加解密操作

函数原型

int tfm_sunxi_aes_with_hardware(crypto_aes_req_ctx_t *aes_ctx);

参数:

  • aes_ctx:crypto_aes_req_ctx_t 结构体指针

返回值

  • 仅返回 0:无意义

调用说明: 调用之前,请注意对待加解密所需的数据密钥进行对应的 cache 操作

在安全端设置 flashenc 所需的 nonce 值

函数原型

void tfm_sunxi_flashenc_set_nonce(uint8_t *nonce);

参数:

  • nonce:nonce 值,共 6 Bytes。

返回值

开启/关闭特定通道的 flashenc

函数原型

void tfm_sunxi_flashenc_enable(uint8_t id)/tfm_sunxi_flashenc_disable(uint8_t id);

参数:

  • id:通道 index

返回值

设置 flashenc

函数原型

void tfm_sunxi_flashenc_config(uint8_t id, uint32_t saddr, uint32_t eaddr, uint32_t *key);

参数:

  • id:通道 index
  • saddr:设置的起始地址
  • eaddr:设置的结束地址
  • key:加密密钥

返回值

设置 flashenc 加密密钥

函数原型

void tfm_sunxi_flashenc_set_key(uint8_t id,uint32_t *key);

参数:

  • id:通道 index
  • 加密密钥

返回值

设置 flashenc 加密地址范围

函数原型

void tfm_sunxi_flashenc_set_region(uint8_t id, uint32_t saddr, uint32_t eaddr);

参数:

  • id:通道 index
  • saddr:设置的起始地址
  • eaddr:设置的结束地址

返回值

设置 efuse 中的 ssk 作为 flashenc 的加密密钥

函数原型

void tfm_sunxi_flashenc_set_ssk_key(uint8_t id);

参数:

  • id:通道 index

返回值

跳转到 tfm 安全空间利用 ssk 作为密钥进行 aes 加密

函数原型

void tfm_sunxi_aes_encrypt_with_hardware_ssk(uint8_t dst_addr, uint8_t src_addr, int len);

参数:

  • dst_addr: 加密后数据存放地址
  • src_addr: 加密数据存放地址
  • len:加密数据长度

返回值

dump 出对应地址的值

函数原型

void tfm_sunxi_hexdump(const uint32_t *addr, uint32_t num);

参数:

  • addr:起始地址
  • num:dump 的 word 个数

返回值

打印出当前 sau 配置信息

函数原型

 void tfm_sunxi_sau_info_printf(void);

参数:

返回值

读寄存器值

函数原型

 uint32_t tfm_sunxi_readl(uint32_t reg);

参数:

  • reg:寄存器地址

返回值

  • 寄存器值
写寄存器值

函数原型

void tfm_sunxi_writel(uint32_t reg, uint32_t value);

参数:

  • reg:待写的寄存器
  • value:待写入的值

返回值

读取 efuse 内容

读取 efuse 内容函数原型

int tfm_sunxi_efuse_read(char key_name, unsigned char key_data, size_t key_bit_len);

参数:

  • key_name:efuse 对应的区域名
  • key_data:存放读取 efuse 的数据
  • key_bit_len:读取数据的长度

返回值

  • 负数:函数运行错误
  • 正数:实际读取的 bit 数

TFM 开启配置

在 RTOS 环境下,M33 核执行 mrtos menuconfig 进入配置主界面,进行如下配置:

System components ‑‑‑>
    aw components ‑‑‑>
        TFM Support ‑‑‑>
            [*] TFM support #TFM驱动
            [*] TFM test demo #TFM测试代码

R128 中提供了四个TFM 的 测 试 demo, 包 括 tfm_demo、tfm_crypto_demo、tfm_efuse_write 和 tfm_efuse_read,分别用于测试安全非安全交互、非安全调用安全加密接口和对 efuse 内容进行读写(对 efuse 进行读写需要开启 efuse 驱动 DRIVERS_EFUSE)。

c906>rpccli arm tfm_demo
secure call 1 time, non‑secure call 1 time.
secure call 2 time, non‑secure call 2 time.
secure call 3 time, non‑secure call 3 time.
secure call 4 time, non‑secure call 4 time.
secure call 5 time, non‑secure call 5 time.
secure call 6 time, non‑secure call 6 time.
secure call 7 time, non‑secure call 7 time.
secure call 8 time, non‑secure call 8 time.
secure call 9 time, non‑secure call 9 time.
secure call 10 time, non‑secure call 10 time.

c906>rpccli arm tfm_crypto_demo
tfm aes ecb test success!

c906>rpccli arm tfm_efuse_write rotpk E2990EC8B001F2732EE5517739F52F6177E80AAEE220B5DBDA928BC5940FD025
#efuse中写入rotpk
key_hex_string: E2990EC8B001F2732EE5517739F52F6177E80AAEE220B5DBDA928BC5940FD025, buf_len: 64

c906>rpccli arm tfm_efuse_read rotpk #efuse中读取rotpk
efuse [rotpk] data:
0x08133AA0: E2 99 0E C8 B0 01 F2 73 2E E5 51 77 39 F5 2F 61 |.......s..Qw9./a|
0x08133AB0: 77 E8 0A AE E2 20 B5 DB DA 92 8B C5 94 0F D0 25 |w.... .........%|

中提供的 TFM 接口和测试 demo 位于 lichee/rtos/components/aw/tfm 目录下。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/283732.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【AI】人类视觉感知特性与深度学习模型(2/2)

目录 二、人类视觉感知特性对深度学习模型的启发 2.1 视觉关注和掩盖与调节注意力模型的关系 1.视觉关注和掩盖 2. 注意力机制模型 2.2 对比敏感度与U形网络的联系 2.3 非局部约束与点积注意力的联系 续上节 【AI】人类视觉感知特性与深度学习模型&#xff08;1/2&#…

Radishes:分分钟复制一个网易云音乐

Radishes是一个免费开源的跨平台音乐平台&#xff0c;它提供大量的无版权音乐供用户免费浏览、搜索、观看歌单和下载&#xff0c;并根据个人喜好推荐音乐&#xff0c;支持多端使用。还有一个叫xpet的&#xff0c;功能也差不多&#xff0c;需要魔法&#xff0c;有条件有兴趣的朋…

苦心分享两款免费AI 绘图软件,效果真的不错

这里写自定义目录标题 图一是 AI 绘画软件一键抠图做的&#xff0c;软件还免费 网址:https://www.yijiankoutu.com/ 一个非常强大的AI绘画网站&#xff0c;能够免费生成各种好看的二次元、3D、国风、漫画、卡通等风格的图片&#xff0c;生成图片跟文字匹配度非常高&#xff0c;…

深入解析 可空值类型

前言&#xff1a; 问&#xff1a;为什么会有可空值类型的诞生&#xff1f; 答&#xff1a;应对在某些特定场景中获取的信息可能是不完整的。 C# 1中的可空值类型 在C#1中没有对应的表示Null值的方法。当时普遍都是采用其他方式。第一种在数据缺失的情况下给其一个默认值。第…

【远程开发】穿越跳板机和CLion远程开发——全面配置流程

文章目录 穿越跳板机配置 ProxyJump 方案Cygwin上的配置 建立 SSH Tunneling 方案 代码映射目录映射方案配置Rsync加速 远程服务器方案(todo) 远程Debug tips&#xff1a;本文讲了两种穿越跳板机的方案(推荐ProxyJump方案)&#xff0c;和两种代码映射的方案。实际任选一对搭配即…

动态规划10-多重背包

题目描述 有N种物品和一个容量为V 的背包。第i种物品最多有Mi件可用&#xff0c;每件耗费的空间是Ci &#xff0c;价值是Wi 。求解将哪些物品装入背包可使这些物品的耗费的空间 总和不超过背包容量&#xff0c;且价值总和最大。 思路分析 区别于完全背包和简单的01背包问题&…

WPF+Halcon 培训项目实战(10):HS组件绘制图案

文章目录 前言相关链接项目专栏运行环境匹配图片模板匹配加载模板文件运行结果 绘制十字标 WPF HS组件绘制图像绘制和生成的区别 前言 为了更好地去学习WPFHalcon&#xff0c;我决定去报个班学一下。原因无非是想换个工作。相关的教学视频来源于下方的Up主的提供的教程。这里只…

海康visionmaster-渲染结果:控件颜色:控件颜色修改的方法

描述 环境&#xff1a;VM4.0.0 VS2015 及以上 现象&#xff1a;简易修改 VM 控件的颜色&#xff1f; 解答 对二次开发中嵌入控件的颜色进行修改&#xff0c;具体代码如下&#xff1a; C# string colorinfo “ColorStyle3”; AppColorService.CurColorDefine colorinfo; “Co…

全志R128 DSP开发工具安装教程

资料准备 要编译和仿真DSP&#xff0c;需要以下资料&#xff1a; DSP 核 SDK&#xff0c;SDK 需要包含DSP 编译源码。Cadence Xtensa 的 Windows IDE 工具 (Xplorer‑8.0.13 版本)&#xff0c; Windows 版本 DSP 的 package 包。Cadence Xtensa 的 License&#xff0c;用于服…

linux安装java8

1、下载java 根据自己系统的位数下载 查看系统位数命令&#xff1a;getconf LONG_BIT 下载地址 https://www.oracle.com/java/technologies/javase/javase8u211-later-archive-downloads.html 2、解压、移动 将下载的文件上传到linux系统中并解压 tar -zxvf jdk-8u333-linux…

人是需要被肯定和认可的,赞美也是一种动力

前几天转发了一些网上的文章&#xff0c;突然有了10个关注我的人&#xff0c;赞美数和收藏量也上去了一些。 这是一种很意外的惊喜。 看了一下主题是&#xff1a; 1,如何将.NET8创建的控制台程序部署成WINDOWS服务。 2,.NET进阶篇06-async异步、thread多线程 3,易语言启动线程传…

最优轨迹生成(四)—— 带约束轨迹优化

本系列文章是学习深蓝学院-移动机器人运动规划课程第五章最优轨迹生成 过程中所记录的笔记&#xff0c;本系列文章共包含四篇文章&#xff0c;依次介绍了微分平坦特性、无约束BVP轨迹优化、无约束BIVP轨迹优、 带约束轨迹优化等内容 本系列文章链接如下&#xff1a; 最优轨迹生…

【ChatGPT 默认强化学习策略】PPO 近端策略优化算法

PPO 近端策略优化算法 PPO 概率比率裁剪 演员-评论家算法演员-评论家算法&#xff1a;多智能体强化学习核心框架概率比率裁剪&#xff1a;逐步进行变化的方法PPO 目标函数的设计重要性采样KL散度 PPO 概率比率裁剪 演员-评论家算法 论文链接&#xff1a;https://arxiv.org…

12. 整数转罗马数字

罗马数字包含以下七种字符&#xff1a; I&#xff0c; V&#xff0c; X&#xff0c; L&#xff0c;C&#xff0c;D 和 M。 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000 …

Filezilla使用

服务端 点击安装包 点击我接受 点击下一步 点击下一步 点击下一步 点击安装即可 配置用户组&#xff0c;点击编辑&#xff0c;出现组点击 点击添加&#xff0c;点击确定即可 配置用户&#xff0c;点击编辑点击用户 点击添加&#xff0c;设置用户名&#xff…

打印9*9乘法口诀

一. main函数实现 1.参数n表示乘法口诀表总共有多少行 2.设定两个循环 外层循环控制总共有多少行 内层循环控制每行有多少个表达式以及表达式中的内容 #include<stdio.h> int main() {int n 0;scanf("%d", &n);for (int i 1; i < n; …

丢失VCRUNTIME140_1.dll怎么办,多种dll问题解决方法分享

丢失VCRUNTIME140_1.dll是许多计算机用户经常遇到的问题之一。VCRUNTIME140_1.dll是一个动态链接库文件&#xff0c;它是Visual C Redistributable Package的一部分。Visual C Redistributable Package是微软为了支持运行使用Visual C编写的软件而提供的一个可再发行组件包。当…

Django 学习教程- Hello world入门案例

系列 Django学习教程-介绍与安装 欢迎来到第Djagno学习教程第二章Hello World 入门案例。 在本教程中&#xff0c;我将引导您完成django的Hello World入门案例。 让我们开始吧&#xff01; 版本 Django 5.0Python 3.10 创建项目 安装 Django 之后&#xff0c;您现在应该…

RK3568平台开发系列讲解(Linux系统篇)PWM系统编程

🚀返回专栏总目录 文章目录 一、什么是PWM二、PWM相关节点三、PWM应用编程沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将介绍 PWM 的系统编程。 一、什么是PWM PWM,即脉冲宽度调制(Pulse Width Modulation)

CSS 纵向底部往上动画

<template><div class"container" mouseenter"startAnimation" mouseleave"stopAnimation"><!-- 旋方块 --><div class"box" :class"{ scale-up-ver-bottom: isAnimating }"><!-- 元素内容 --&g…