拓展 | Rust语言在嵌入式领域的应用

李肖遥 2021-08-06 22:23
关注、星标公众号,直达精彩内容

来源:IT创客学院



今天看到一篇关于Rust语言的文章,分享给大家,可以扩展下视野。


开卷有益,恭喜你又进步了一点点。



Rust语言是二十一世纪的语言新星。Rust被人广泛承认的一点,就是因为它能运行在多样的目标上,从桌面和服务器设备,到资源有限的嵌入式设备。

我们可以用适合来评价一门语言和技术。Rust非常适合开发嵌入式应用,它是一种和C相仿的、能应用于嵌入式设备开发的编程语言。

操作系统都是从裸机设备开始运行的,Rust语言的这一点也意味着,它能很好地用于编写操作系统。无论是应用层还是内核本身,Rust都是极富竞争力、值得投入时间的技术选项。

二十一世纪的裸机编程语言

在这个互联网全面普及、性价比设备应用更广的时代,安全和可靠性成为一门语言必须考虑的因素。Rust语言采用移动语义,拥有严格的代数类型系统以及生命周期、所有权模型;相比传统的编程语言,这些模型能在合适的时候释放所用资源,减少漏洞的出现。此外,通过语义检查,Rust能在编译期有效寻找内存和线程安全问题,降低开发和测试的负担。

Rust语言是的运行效率高、开发效率好、适用范围广。作为一门编译型语言,它直接编译输出到汇编代码,通常公认裸机的Rust语言性能在C语言级别,拥有较高的运行效率。Rust语言的开发效率很高,文档完善、编译器提示有帮助,能节省软件开发所需的时间。它能应用在多个平台和指令集中,这包括裸机平台;处理核、操作系统厂家还可以提供自己的编译目标,无需厂家自己重新开发、提供工具链。

Rust语言出彩的地方在于,它向嵌入式平台引入了大量新的编程技术。这包括了闭包、过程宏等传统上用于函数式编程的技术,和多态、虚函数表等面向对象语言的技术。新编程技术的引入,扩充了开发者的选择。即使彻底理解Rust的编程概念有一定难度,但这些易用的新技术,让开发者只需阅读实例代码,便可快速进入开发状态。这些新技术的引入,是嵌入式平台从未有过的,Rust能提高开发者的工作效率,降低平台间迁移的学习时间和成本。


裸机上的过程宏

传统用于嵌入式平台的编程,我们加快开发速度使用的宏,常常基于语法字符串的替换和修改。Rust语言扩充了宏的概念,提出了基于语法树的“过程宏”编程方法,让宏语法更容易使用、编写更方便。

“过程宏”是接收Rust代码作为输入,操作这些代码,然后产生另一些代码的过程。它和字符串的替换不同,是从语法树到语法树的替换。开发一个过程宏,可以使用简单的定义过程,或者有工作量的属性宏定义过程。简单的定义中,我们编写代码,给出宏的输入有哪些,要翻译到哪些输出代码,这样就完成了一个宏的定义。属性宏定义则允许完成语法树分析、代码生成甚至代码优化的过程,就需要编写专门的“属性宏库”,借用Rust编译器的一部分,完成宏代码的转化和输出。

过程宏是基于语法树的分析过程,借助“树”的结构我们能理解它的一些特点。因为Rust语法树的子树也是Rust代码,所以宏的定义内也可以完成语法分析,这就为代码编辑器的提示和补全提供了便利。一个语法项目不可能同时属于两颗不是亲子关系的子树,因为如果属于两颗子树,将和语法树的树根产生环,就和语法树的定义相违背,所以语法项目都是独立的,宏内代码的解析不会影响外界代码的解析。

这样的独立性也就是“卫生宏”思想的提出,Rust的过程宏可以理解为代码的“内部展开”,不影响代码的上下文。正因为Rust过程宏产生完整的语法子树,它的定义不需要额外的界符,因此只需要满足Rust语法就可以了。

在过程宏的定义之外,Rust语言提供了大量便于嵌入式开发的标签。“align”标签定义内存对齐的方式,“link_section”标签给定代码要链接到的段或区。这样,过程宏可以包装各种各样的标签,Rust语言的用户可以方便地使用,而不需要深入宏了解代码的具体要求。Rust语言定义的过程宏可以导出到包外,给其它的库使用,这有利于嵌入式Rust生态的搭建和共享。Rust语言宏灵活的特性,让宏在更多的领域有可用之处,更好地服务嵌入式平台的开发工作。


嵌入式中的模块化编程

Rust语言拥有很好的模块化编程概念。传统平台的Rust语言中,社区总结出了“模块-包-项目”的模型。这个模型也适用于嵌入式平台,增加协作开发的效率,更好地共享生态。

Rust的模块化编程分为模块、包、项目三级。模块是Rust语言可见性分划的最小单位,语言中提供了专门的关键字,来区分不同模块的代码和可见性,是由Rust语言本身确定的。在Rust语法中,“mod”是定义模块的关键字,“pub”是定义可见性的关键字。

包是Rust项目的二进制目标,这个等级是由Rust工具链给定的。每个包有版本号、作者和许可协议等元数据,要依赖和使用的库也要登记到包中,以便共同编译。库的特性有点像传统语言的条件编译,也是以包为单位规定的,每个包使用的库可以开启不同的特性,但库在同一个包中开启的特性是相同的。

“项目”这一层并非由Rust语言给定;人们开发软件时,发现一个解决方案中包含多个二进制目标是非常好的,总结之后就出现了项目的抽象模型。项目由核心和外围包组成,或者是功能相近的一组包,它通常由同一个团队组织和维护,可以在项目上添加扩展。项目在习惯上由核心包到功能包,以依赖的形式构成。实践中,“项目”可以放在同一个工作空间里,以统一管理和发布编译版本。

Rust将模块化编程引入到嵌入式开发中,也可以方便地编写测试和性能检测代码。模块化编程能提高Rust嵌入式开发者的工作效率,适应现代化嵌入式软件的需求。


搭建Rust嵌入式生态

生态是软件工业不可或缺的一部分。从编译器到软件支持,嵌入式Rust目前已经拥有良好的基础生态。此外,操作系统内核也是嵌入式编程的重要部分,嵌入式Rust和内核开发也有较好的相容度。

Rust语言的嵌入式生态

你的架构和指令集

嵌入式Rust的应用支持分为两个部分:一个是目标处理核的支持,一个是芯片外设的支持。

针对目标处理核,首先我们要编译Rust到这个指令集架构。Rust语言提供丰富的编译目标,主流的编译目标都有很好的支持;此外,如果有自主研发的指令集架构,可以为Rust添加自己的编译目标。编译完成后,还需要编写微架构支持库和微架构运行时。微架构运行时提供最小的启动代码实现,能搭建一个适合Rust代码运行的环境。微架构支持库简单包装汇编代码,允许应用代码操作寄存器、运行特殊的指令,作为编译器系统的补充。这之后,Rust对这个指令集架构的代码运行支持就完成了。

嵌入式应用定义了各有特点的中断控制器,有些是指令集架构定义的,有些是芯片设计厂家自己定义的。嵌入式Rust要支持这些中断控制器,需要在微架构运行时中添加处理和封装部分,或者作为通用架构的补充,在专用架构的支持库中添加专有架构的中断运行时。架构虽然定义了标准,但基地址、中断数量等配置可能相互不同。这些元数据配置可以放在外设访问库的中断部分,和架构支持库共同构成中断控制器的支持。

目标的处理核定义了调试接口和闪存烧写算法,我们需要在调试器软件中编写这些算法。社区通用的软件“probe-rs”是很好的调试器实现,可以替代OpenOCD,作为非常好的Rust语言调试软件。如果自己的操作系统有软件调试接口,可以添加操作系统调试器的载荷,共同完成调试软件的部分。只要处理器厂商实现了调试接口,提供相关的文档,配套的Rust软件可以尽快完成,方便各种技术的开发者调试和使用。


嵌入式生态的标准

起初嵌入式开发者会为每个芯片都编写一次代码。随着生态的发展,大家认识到,需要提供一个基本的抽象,大家都围绕着抽象去编写,就能省下为大量外设反复编码的时间。embedded-hal就是这样的标准,它是Rust语言的嵌入式外设抽象,支持大量的片内和片外外设,包括传感器等,很好地扩充了嵌入式的生态。

embedded-hal是统一的Rust语言标准,它是针对外设功能本身的抽象,是抽象的集合,具体实现由实现库去完成。它的扩展性很好,比如“SPI-GPIO扩展器”外设输入SPI接口抽象,输出GPIO的抽象,很多模块都是抽象到抽象的过程,就可以方便的极联、衔接和嵌套,整合更多的项目;这就非常容易为新的芯片编写支持库。

市场上海量的芯片都支持embedded-hal标准。K210、GD32V和BL602系列的芯片都提供很好的embedded-hal实现库。要编写embedded-hal标准的支持库,只需要机器生成外设库,然后编写中间层库,就能完成对此标准的原厂支持。

Rust与操作系统内核

操作系统也是嵌入式应用。常见的操作系统如按是否包含虚拟内存区分,有不含虚拟内存的实时系统,和包含虚拟内存传统操作系统。基于微架构的支持库和运行时库,操作系统内核可以很方便地编写。

社区中提供了大量成熟的操作系统运行时。如rCore系列操作系统是第一个基于RISC-V架构的完整Rust操作系统,尤其适合教学使用。RTIC框架是中断驱动的异步实时系统,完全针对应用使用Rust的宏语法生成,拥有极高的效率。Tock系统是针对微处理器的安全实时系统,已经用于手表、智能路标和加密狗等产品。

针对操作系统和应用程序开发,Rust是适合编写硬件驱动的语言。如果使用有产权的代码,可以以混合链接的形式,与Rust代码联合编译为二进制使用。系统模块、插件和动态链接库等等都能受益于Rust语言内存安全的特性,适合现在对安全敏感的开发需求。

物联网系统要求嵌入式的操作系统能够连上网络。Rust嵌入式社区也在探索射频连接的技术标准,包括蓝牙、WiFi等硬件标准。smoltcp是社区提供的非常好的TCP协议栈实现,它可以代替lwip,在嵌入式系统领域高效、安全地完成网络传输。搭配缓冲区和协议库,物联网操作系统就可以连上网了。

RustSBI:新型操作系统引导软件

我们在开发操作系统内核时,有的内核直接运行在裸机上,有的还依托于一个运行环境。在RISC-V上,“SBI”就是这样的运行环境。它除了引导启动内核,还将常驻后台,提供操作系统需要的实用功能。

RISC-V标准中,“SBI”意味着“操作系统二进制接口”,运行在其上的操作系统会通过环境调用“ecall”指令,陷入到二进制接口的实现中,由其调用具体硬件的实现功能。这种实现被称作“SBI实现”,社区常用的实现有开源的OpenSBI。RustSBI是鹏城实验室“rCore代码之夏-2020”活动提出的SBI实现,它是全新的操作系统引导软件。

实现与模块组成

RustSBI由几个功能模块组成。硬件环境接口实现了RISC-V SBI v0.2版本的接口,能运行支持此版本的操作系统。硬件运行时则是SBI实现运行在裸机环境的必要模块,它将由硬件启动,开始运行所有的RustSBI模块。SBI的初始化完成后,将进入引导启动模块,这里将发挥SBI标准“引导启动”的功能,最终启动操作系统内核。另外,兼容性模块能完成硬件到硬件间的支持,能模拟旧版硬件不存在的指令、寄存器,进一步延长操作系统的生命周期。

去年12月,RustSBI的0.1版本在深圳的Rust中国社区2020年年会上发布。使用目前最新的0.1.1版本,RustSBI已经支持大量SBI标准提出的功能,支持大量自定义的扩展功能;完全使用安全的Rust语言编写,提高开发效率。开发Rust语言的操作系统内核,可以统一编译工具链。另外,RustSBI已经被RISC-V组织收录入RISC-V SBI标准,它的实现编号为4。

RustSBI是一个库,它以库的形式设计的初衷是,便于平台开发者“积木”式地引入库的模块,为自己的硬件目标开发SBI支持。虽然RustSBI提供了QEMU、K210平台的参考实现,但应用开发者不应当将自己的目标也加入参考实现中,而是在自己的仓库里引用RustSBI的模块,可以选择参考这些实现的内容,最终完成完全可控的开发过程。这两个平台的使用范围较广,参考实现也会长期维护,以发现RustSBI本身可能的少量问题,并及时修补完善。

为什么用Rust开发RustSBI呢?我们认为,相比使用C语言,嵌入式Rust的生态圈在协调发展阶段,它容易支持新硬件,Rust语言较强的编译约束也提高了硬件代码的安全性。

硬件到硬件的兼容性

RISC-V是快速更迭的指令集规范。我们为新版RISC-V硬件编写软件,会遇到与旧版硬件不兼容的情况。硬件和硬件之间的兼容性,也能通过软件完成——这是RustSBI提供的功能与亮点之一。

RustSBI实现的硬件兼容性,是靠捕获指令异常完成的。例如,K210平台实现的是1.9.1版本的RISC-V特权级标准,它规定了旧版的页表刷新指令;而目前最新的1.11版标准,规定的是新版的刷新指令。为新标准编写的操作系统内核,使用新版刷新指令,会因为K210硬件无法找到新版指令,抛出非法指令异常。这个非法指令异常被RustSBI捕获,它解析后,发现是新版的页表刷新指令,便直接在硬件上运行旧版的指令,完成指令的页表刷新功能。

这种硬件兼容性,目前能支持新增的指令和寄存器。一切情况下,指令、寄存器在仍然存在,但新版中修改了它们的功能和意义。只靠RustSBI软件本身,就不足以提供兼容性支持了。如果RISC-V芯片实现提供特定的兼容性外设,比如这个外设能拦截特定CSR寄存器的访问指令,就可以在功能修改的寄存器访问时,产生一个可供软件捕获的中断。这样的外设设计之后,使用RustSBI软件,将能支持功能修改的指令和寄存器,将进一步提升操作系统内核的硬件兼容性。

兼容旧硬件,也是兼容未来新硬件的过程。未来的RISC-V标准快速发展,将与目前的硬件标准产生一定的差异;在硬件不变的前提下,未来软件能对当前的硬件兼容,就能延长软件的生命周期。或许,我们未来升级RISC-V上的操作系统,只需要更换硬件中的RustSBI固件,就能完美兼容最新标准的操作系统了。升级原有系统的硬件也非常容易,替换RustSBI固件就能达到升级效果。

另外,硬件兼容性也意味着实现硬件上缺少的指令集。当这些指令集运行时,就会陷入到软件中,由RustSBI软件模拟这些指令,最终返回,这个过程应用软件不会有感知。当然,这种软件模拟过程可以满足正确性,效率不如新版的硬件,但临时运行一个新版的软件、体验新版的指令集还是足够的。当模拟指令的过程多到影响性能时,也就是硬件该升级的时候了。


RustSBI与嵌入式Rust生态

在RustSBI的实现中,多次使用“embedded-hal”的实现完成编写过程。“embedded-hal”是Rust嵌入式的外设规范,它对大量厂家的外设提供了软件支持。只要厂家的硬件支持“embedded-hal”,只需要编写部分抽象接口代码,RustSBI支持就可以快速地开发完成。

硬件处理核和SoC系统的开发也受益于设计好的RustSBI软件架构。“RustSBI很快速地实现了仿真环境的双核测试,”华中科技大学的社区贡献者车春池说,“这能为处理核提供丰富的测试环境,在开发高性能RISC-V处理核中非常重要。”

无论硬件和软件,我们都乐于看到各个应用领域积极互动,嵌入式Rust生态的发展过程得到加快。“embedded-hal”本是裸机外设的标准,RustSBI将这个标准运用在引导软件上,能加速裸机外设的开发和建设,也能更快适配SBI标准到平台上。

借这个项目,我们很高兴能参与嵌入式领域Rust语言的建设,希望这些微小的技术更新和迭代,最终能回馈到未来物联网行业更轻便、更安全的开发体验中去。

免责声明:本文素材来源网络,版权归原作者所有。如涉及作品版权问题,请与我联系删除。
‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧  END  ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧

关注我的微信公众号,回复“加群”按规则加入技术交流群。

欢迎关注我的视频号:


点击“阅读原文”查看更多分享,欢迎点分享、收藏、点赞、在看。

李肖遥 公众号“技术让梦想更伟大”,作者:李肖遥,专注嵌入式,只推荐适合你的博文,干货,技术心得,与君共勉。
评论
  • Ubuntu20.04默认情况下为root账号自动登录,本文介绍如何取消root账号自动登录,改为通过输入账号密码登录,使用触觉智能EVB3568鸿蒙开发板演示,搭载瑞芯微RK3568,四核A55处理器,主频2.0Ghz,1T算力NPU;支持OpenHarmony5.0及Linux、Android等操作系统,接口丰富,开发评估快人一步!添加新账号1、使用adduser命令来添加新用户,用户名以industio为例,系统会提示设置密码以及其他信息,您可以根据需要填写或跳过,命令如下:root@id
    Industio_触觉智能 2025-01-17 14:14 155浏览
  • 书接上回:【2022年终总结】阳光总在风雨后,启航2023-面包板社区  https://mbb.eet-china.com/blog/468701-438244.html 总结2019,松山湖有个欧洲小镇-面包板社区  https://mbb.eet-china.com/blog/468701-413397.html        2025年该是总结下2024年的喜怒哀乐,有个好的开始,才能更好的面对2025年即将
    liweicheng 2025-01-24 23:18 40浏览
  • 本文介绍瑞芯微开发板/主板Android配置APK默认开启性能模式方法,开启性能模式后,APK的CPU使用优先级会有所提高。触觉智能RK3562开发板演示,搭载4核A53处理器,主频高达2.0GHz;内置独立1Tops算力NPU,可应用于物联网网关、平板电脑、智能家居、教育电子、工业显示与控制等行业。源码修改修改源码根目录下文件device/rockchip/rk3562/package_performance.xml并添加以下内容,注意"+"号为添加内容,"com.tencent.mm"为AP
    Industio_触觉智能 2025-01-17 14:09 218浏览
  • 现在为止,我们已经完成了Purple Pi OH主板的串口调试和部分配件的连接,接下来,让我们趁热打铁,完成剩余配件的连接!注:配件连接前请断开主板所有供电,避免敏感电路损坏!1.1 耳机接口主板有一路OTMP 标准四节耳机座J6,具备进行音频输出及录音功能,接入耳机后声音将优先从耳机输出,如下图所示:1.21.2 相机接口MIPI CSI 接口如上图所示,支持OV5648 和OV8858 摄像头模组。接入摄像头模组后,使用系统相机软件打开相机拍照和录像,如下图所示:1.3 以太网接口主板有一路
    Industio_触觉智能 2025-01-20 11:04 200浏览
  • 故障现象 一辆2007款日产天籁车,搭载VQ23发动机(气缸编号如图1所示,点火顺序为1-2-3-4-5-6),累计行驶里程约为21万km。车主反映,该车起步加速时偶尔抖动,且行驶中加速无力。 图1 VQ23发动机的气缸编号 故障诊断接车后试车,发动机怠速运转平稳,但只要换挡起步,稍微踩下一点加速踏板,就能感觉到车身明显抖动。用故障检测仪检测,发动机控制模块(ECM)无故障代码存储,且无失火数据流。用虹科Pico汽车示波器测量气缸1点火信号(COP点火信号)和曲轴位置传感器信
    虹科Pico汽车示波器 2025-01-23 10:46 97浏览
  • 2024年是很平淡的一年,能保住饭碗就是万幸了,公司业绩不好,跳槽又不敢跳,还有一个原因就是老板对我们这些员工还是很好的,碍于人情也不能在公司困难时去雪上加霜。在工作其间遇到的大问题没有,小问题还是有不少,这里就举一两个来说一下。第一个就是,先看下下面的这个封装,你能猜出它的引脚间距是多少吗?这种排线座比较常规的是0.6mm间距(即排线是0.3mm间距)的,而这个规格也是我们用得最多的,所以我们按惯性思维来看的话,就会认为这个座子就是0.6mm间距的,这样往往就不会去细看规格书了,所以这次的运气
    wuliangu 2025-01-21 00:15 386浏览
  • 高速先生成员--黄刚这不马上就要过年了嘛,高速先生就不打算给大家上难度了,整一篇简单但很实用的文章给大伙瞧瞧好了。相信这个标题一出来,尤其对于PCB设计工程师来说,心就立马凉了半截。他们辛辛苦苦进行PCB的过孔设计,高速先生居然说设计多大的过孔他们不关心!另外估计这时候就跳出很多“挑刺”的粉丝了哈,因为翻看很多以往的文章,高速先生都表达了过孔孔径对高速性能的影响是很大的哦!咋滴,今天居然说孔径不关心了?别,别急哈,听高速先生在这篇文章中娓娓道来。首先还是要对各位设计工程师的设计表示肯定,毕竟像我
    一博科技 2025-01-21 16:17 169浏览
  • 数字隔离芯片是一种实现电气隔离功能的集成电路,在工业自动化、汽车电子、光伏储能与电力通信等领域的电气系统中发挥着至关重要的作用。其不仅可令高、低压系统之间相互独立,提高低压系统的抗干扰能力,同时还可确保高、低压系统之间的安全交互,使系统稳定工作,并避免操作者遭受来自高压系统的电击伤害。典型数字隔离芯片的简化原理图值得一提的是,数字隔离芯片历经多年发展,其应用范围已十分广泛,凡涉及到在高、低压系统之间进行信号传输的场景中基本都需要应用到此种芯片。那么,电气工程师在进行电路设计时到底该如何评估选择一
    华普微HOPERF 2025-01-20 16:50 134浏览
  • 飞凌嵌入式基于瑞芯微RK3562系列处理器打造的FET3562J-C全国产核心板,是一款专为工业自动化及消费类电子设备设计的产品,凭借其强大的功能和灵活性,自上市以来得到了各行业客户的广泛关注。本文将详细介绍如何启动并测试RK3562J处理器的MCU,通过实际操作步骤,帮助各位工程师朋友更好地了解这款芯片。1、RK3562J处理器概述RK3562J处理器采用了4*Cortex-A53@1.8GHz+Cortex-M0@200MHz架构。其中,4个Cortex-A53核心作为主要核心,负责处理复杂
    飞凌嵌入式 2025-01-24 11:21 94浏览
  •     IPC-2581是基于ODB++标准、结合PCB行业特点而指定的PCB加工文件规范。    IPC-2581旨在替代CAM350格式,成为PCB加工行业的新的工业规范。    有一些免费软件,可以查看(不可修改)IPC-2581数据文件。这些软件典型用途是工艺校核。    1. Vu2581        出品:Downstream     
    电子知识打边炉 2025-01-22 11:12 155浏览
  •  万万没想到!科幻电影中的人形机器人,正在一步步走进我们人类的日常生活中来了。1月17日,乐聚将第100台全尺寸人形机器人交付北汽越野车,再次吹响了人形机器人疯狂进厂打工的号角。无独有尔,银河通用机器人作为一家成立不到两年时间的创业公司,在短短一年多时间内推出革命性的第一代产品Galbot G1,这是一款轮式、双臂、身体可折叠的人形机器人,得到了美团战投、经纬创投、IDG资本等众多投资方的认可。作为一家成立仅仅只有两年多时间的企业,智元机器人也把机器人从梦想带进了现实。2024年8月1
    刘旷 2025-01-21 11:15 733浏览
  • 临近春节,各方社交及应酬也变得多起来了,甚至一月份就排满了各式约见。有的是关系好的专业朋友的周末“恳谈会”,基本是关于2025年经济预判的话题,以及如何稳定工作等话题;但更多的预约是来自几个客户老板及副总裁们的见面,他们为今年的经济预判与企业发展焦虑而来。在聊天过程中,我发现今年的聊天有个很有意思的“点”,挺多人尤其关心我到底是怎么成长成现在的多领域风格的,还能掌握一些经济趋势的分析能力,到底学过哪些专业、在企业管过哪些具体事情?单单就这个一个月内,我就重复了数次“为什么”,再辅以我上次写的:《
    牛言喵语 2025-01-22 17:10 206浏览
  • 嘿,咱来聊聊RISC-V MCU技术哈。 这RISC-V MCU技术呢,简单来说就是基于一个叫RISC-V的指令集架构做出的微控制器技术。RISC-V这个啊,2010年的时候,是加州大学伯克利分校的研究团队弄出来的,目的就是想搞个新的、开放的指令集架构,能跟上现代计算的需要。到了2015年,专门成立了个RISC-V基金会,让这个架构更标准,也更好地推广开了。这几年啊,这个RISC-V的生态系统发展得可快了,好多公司和机构都加入了RISC-V International,还推出了不少RISC-V
    丙丁先生 2025-01-21 12:10 783浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦