深入解析非桥PCI设备的访问和配置方法

往期内容

本文章相关专栏往期内容,PCI/PCIe子系统专栏:

  1. 嵌入式系统的内存访问和总线通信机制解析、PCI/PCIe引入

Uart子系统专栏:

  1. 专栏地址:Uart子系统
  2. Linux内核早期打印机制与RS485通信技术
    – 末片,有专栏内容观看顺序

interrupt子系统专栏:

  1. 专栏地址:interrupt子系统
  2. Linux 链式与层级中断控制器讲解:原理与驱动开发
    – 末片,有专栏内容观看顺序

pinctrl和gpio子系统专栏:

  1. 专栏地址:pinctrl和gpio子系统

  2. 编写虚拟的GPIO控制器的驱动程序:和pinctrl的交互使用

    – 末片,有专栏内容观看顺序

input子系统专栏:

  1. 专栏地址:input子系统
  2. input角度:I2C触摸屏驱动分析和编写一个简单的I2C驱动程序
    – 末片,有专栏内容观看顺序

I2C子系统专栏:

  1. 专栏地址:IIC子系统
  2. 具体芯片的IIC控制器驱动程序分析:i2c-imx.c-CSDN博客
    – 末篇,有专栏内容观看顺序

总线和设备树专栏:

  1. 专栏地址:总线和设备树
  2. 设备树与 Linux 内核设备驱动模型的整合-CSDN博客
    – 末篇,有专栏内容观看顺序

img

目录

  • 往期内容
  • 1.访问PCI/PCIe设备的流程
    • 1.1 PCI/PCIe设备的配置信息
    • 1.2 主机读取设备配置信息、分配空间
    • 1.3 CPU地址空间和PCI/PCIe地址空间怎么转换?
    • 1.4 主机像读写内存一样访问设备
  • 2.PCI设备的访问方法_非桥设备(type0)
    • 2.1 硬件结构
    • 2.2 PCI本地总线信号
    • 2.3 访问PCI设备
      • 2.3.1 PCI设备的地址空间(配置空间)
      • 2.3.2 配置过程
        • 配置事务的标志:
      • 2.3.3 示例:配置PCI Agent设备

1.访问PCI/PCIe设备的流程

1.1 PCI/PCIe设备的配置信息

PCI/PCIe设备上有配置空间(配置寄存器),用来表明自己"需要多大的地址空间"。

注意,这是PCI/PCIe地址空间。

1.2 主机读取设备配置信息、分配空间

主机上的程序访问PCI/PCIe设备,读出配置信息。

分配地址空间:注意,分配的是PCI/PCIe地址空间。

把地址空间首地址写入设备。

1.3 CPU地址空间和PCI/PCIe地址空间怎么转换?

假设CPU发出的addr_cpu,是用来方位PCI设备的,转换关系为:

addr_pci  = addr_cpu + offset

在PCI/PCIe控制器中,有某个寄存器,有来保存offset值。

1.4 主机像读写内存一样访问设备

示例代码如下:

volatile unsigned int *p = addr_cpu;
unsigned int val;
*p = val;  /* 写, 硬件会把addr_cpu转换为addr_pci去写PCI/PCIe设备 */
val = *p;  /* 读, 硬件会把addr_cpu转换为addr_pci去读PCI/PCIe设备 */

img

CPU想要读取I2C设备上的某个地址的值:

  • 主芯片要发出一个 start 信号
  • 然后发出一个设备地址(用来确定是往哪一个芯片写数据),方向(读/写,0 表示写,1 表示读)
  • 从设备回应(用来确定这个设备是否存在),然后就可以传输数据
  • 从设备发送一个字节数据给主设备,并等待回应
  • 每传输一字节数据,接收方要有一个回应信号(确定数据是否接受完成),然后再传输下一个数据。
  • 数据发送完之后,主芯片就会发送一个停止信号。

像发出start信号、发出设备地址,都是CPU得去设置I2C控制器的某个寄存器才能让I2Ci控制器发出

而反观PCI/PCIe,CPU只需要发出addr_cpu,经过PCI控制器进行地址空间转换addr_pci,就可以去间接访问到地址为addr_pci的PCI设备的值。

2.PCI设备的访问方法_非桥设备(type0)

img

[文件下载点击此处](https://www.yuque.com/yeke5166226/uf8303/coshct9wr1b80pgr?singleDoc# 《嵌入式系统的内存访问和总线通信机制解析、PCI/PCIe引入》)

2.1 硬件结构

PCI系统框图:

img

addr_cpu地址转换为addr_pci地址后,那么多个设备,谁来响应这个addr_pci地址(这个地址是哪个设备的)?

  1. 配置

a. 对于这些设备,首先得去read设备的配置空间,去知道它是哪类设备,以及要申请地址空间的大小

b. 给设备申请的地址空间进行分配,将分配的地址范围(addr_pci类型)写入PCI设备

比如上面的1号设备,要申请4k的地址空间,假设申请成功了,PCI控制器给它起始地址为0x00000000 00000000 00000000
00000000 — 0x00000000 00000000 00000000
FFFFFFFF(假设是32位的内存),那么假设addr_pci是0x00000000 00000000 00000000
00000110,这就能知道CPU发出的地址经过转换后是想要去访问1号设备

  1. 配置后就可以通过addr来去访问设备

而对于配置,得先去理解PCI本地总线信号

2.2 PCI本地总线信号

主要分为6类:

类别信号
系统引脚CLK:给PCI设备提供时钟 RST#:用于复位PCI设备
地址/数据引脚AD[31:00]:地址、数据复用 C/BE[3:0]:命令或者字节使能 PAR:校验引脚
接口控制FRAME#:PCI主设备驱动此信号,表示一个传输开始了、进行中 IRDY#:Initiator ready, 传输发起者就绪,一般由PCI主设备驱动此信号 TRDY#:Target ready,目标设备驱动,表示它就绪了 STOP#:目标设备驱动,表示它想停止当前传输 LOCK#:锁定总线,独占总线,有PCI桥驱动此信号 IDSEL:Initialization Device Select,配置设备时,用来选中某个PCI设备 DEVSEL#:Device Select,PCI设备驱动此信号,表示说:我就是你想访问的设备
仲裁引脚REQ#:申请使用PCI总线 GNT#:授予,表示你申请的PCI总线成功了,给你使用
错误通知引脚PERR#:奇偶校验错误 SERR#:系统错误
中断引脚(可选)INTA#、INTB#、INTC#、INTD#
  1. AD是传输addr还是data?
  2. 未配置PCI设备地址空间时又该如何去选中设备进行配置访问操作?

img

2.3 访问PCI设备

在硬件结构中已经提到了访问过程

  • CPU发出地址addr_cpu
  • PCI桥把addr_cpu转换为addr_pci
  • PCI总线上所有设备都检测addr_pci地址,发现它属于某个设备的地址,该设备就负责完成此传输

步骤:

  • 访问配置空间 – addr_pci
  • 访问内存空间/IO空间 – data

2.3.1 PCI设备的地址空间(配置空间)

PCIe设备的配置空间(Configuration Space)是用于配置和管理PCIe设备的专用地址空间。每个PCIe设备都包含一个256字节(或扩展至4KB的配置空间),用于存储设备的各种信息,如设备标识、状态、控制寄存器、基址寄存器(BAR),以及与设备操作相关的其他配置信息。

  • 作用:配置空间主要用于系统识别和配置PCIe设备,操作系统可以通过访问该配置空间来获取设备的基本信息,配置设备的工作参数,并控制设备的某些功能。
  • 结构:PCIe设备的配置空间遵循PCI规范,前64字节是标准的PCI配置头,包含如设备ID、厂商ID、类代码等基本信息;其余部分包括状态寄存器、控制寄存器、基址寄存器(BAR)、扩展功能寄存器等。

围绕:怎么去配置PCI设备,使其确定自己的地址范围?

img

对于一个PCI设备,可以通过IDSEL来选中它,去读取它的配置寄存器进而去设置它的配置寄存器,对于一个PIC硬件设备的配置寄存器有256个字节,它分为64 byte的头标区(如上图中所示,固定不变)和192 byte 的设备关联区(标准扩展),标准扩展的寄存器组的第一个寄存器中的capabilities pointer字段保存的地址指向下组标准扩展寄存器的首寄存器。也就是说从0x100往后的配置空间是IP厂商自己设计,需要在每组扩展寄存器中的第一个寄存器里定义Next Capablity offset,该字段保存的地址将指向下一处扩展寄存器组的首寄存器。配置空间相关字段介绍

  • Device ID和Vendor lD(只读)

Vender ID代表PCI设备的生产厂商,Device ID代表这个厂商所生产的具体设备。Device |D和Vendor
|D是区分不同设备的关键,OS和UEFI在很多时候就是通过匹配他们来找到不同的设备驱动(Class
Code有时也起一定作用)。为了保证其唯一性,Vendor ID应当向PCI特别兴趣小组(PCI SIG)申请而得到。

  • BAR寄存器

PCle配置空间中从地址0x10开始的6个寄存器(EP),用于存储pcie设备在PCle域的基地址、基址空间大小等属性。

这些PCI总线地址空间需要在初始化时就映射为存储器域的存储器地址空间,方便处理器访问。系统软件对PCI总线进行配置时,首先获得BAR寄存器的初始化信息,之后根据处理器系统的配置,将合理的基地址写入到响应的BAR寄存器中,这个过程在BIOS运行阶段和OS启动阶段完成。系统软件还可以使用该寄存器获得PCI设备使用的BAR空间的长度,其方法是向BAR寄存器写入0XFFFFFFFF后在读取该寄存器。

每个PCI设备在BAR中描述自己需要占用多少地址空间,BI0S或者OS通过所有设备的这些信息构建一张完整的关系图,描述系统中资源的分配情况,然后在合理的将地址空间配置给每个PCI设备。BAR在bit0来表示该设备是映射到memory还是10,bar的bit0是readonlv的,也就是说,设备寄存器是映射到memory还是I0是由设备制造商决定的,其他人无法修改。

  • Revision lD和Class Code寄存器 (只读)

Revision lD记载PCI设备的版本号,可以被认为是Device ID寄存器的扩展Class
Code寄存器记载PCI设备的分类,用于系统软件识别当前PCI设备的分类。该寄存器由Base Class Code、Sub class
code和interface三个字段组成。Base Class Code将PCI设备分类为显卡、网卡、PCI杯等设备:Sub class
code对这些设备进一步细分;inteface定义为编程接囗。

  • Header Type寄存器(只读)

共8bit。系统软件使用该寄存器区分不同类型的PCI配置空间。

第7位为1表示当前PCI设备为多功能设备、为0表示单功能设备。

第6-0位表示当前配置空间的类型,为0表示该设备使用PCIAgent设备的配置空间,普通PCI设备都使用该配置头;为1表示使用PCI桥的配置空间,PCI桥使用这种配置头;为2表示使用cardbus桥片的配置空间。

  • cache line size

记录host处理器使用的cache line长度

  • Capabilities pointer

该寄存器存放capabiltes寄存器组的基地址,该寄存器组存放域PCI设备相关的扩展配置信息。该寄存器对PCI设备可选,但PCle总线规范要求其设备必须支持Capabilities结构,该寄存器组用于实现厂商自定义的PCle设备功能。

该寄存器存放Capabilities结构链表的头指针。在一个PCle设备中,可能含有多个Capability结构,这些寄存器组成一个链表。

  • interript line寄存器

记录当前PCI设备使用的中断向量号,在系统软件对该设备配置时写入。给软件使用的,PCI设备本身不使用该寄存器。软件可以写入中断相关的信息,比如在Linux系统中,可以把分配的virq(虚拟中断号)写入此寄存器。软件完全可以自己记录中断信息,没必要依赖这个寄存器。

  • Interrupt pin

这个寄存器保存PCI设备使用的中断引脚。PCI总线提供了四个中断引脚:INTA#、INTB#INTC#和INTD#。InterruptPin寄存器为1时表示使用INTA#引脚向中断控制器提交中断请求,为2表示使用INTB#,为3表示使用INTC#,为4表示使用INTD#。如果PCI设备只有一个子设备时,该设备只能使用INTA#;如果有多个子设备时,可以使用INTBD#信号。如果PCI设备不使用这些中断引脚,向处理器提交中断请求时,该寄存器的值必须为0。值得注意的是,虽然在PCIe设备中并不含有INTAD#信号,但是依然可以使用该寄存器,因为PCle设备可以使用INTx中断消息,模拟PCI设备的INTA~D#信号

Interrupt Pin取值含义
0不需要中断引脚
1通过INTA#发出中断
2通过INTB#发出中断
3通过INTC#发出中断
4通过INTD#发出中断
5~0xff保留
  • Class Code

这是只读的寄存器,它含有3个字节,用来表明设备的功能,它分为3部分

最高字节:表示"base class",用来表示它属于内存卡、显卡等待

中间字节:表示"sub-class",再细分一下类别

最低字节:用来表示寄存器级别的编程接口"Interface"

示例如下:Base Class为01h时,表示它是一个存储设备,但是还可以继续使用sub-class、Interface细分

img

2.3.2 配置过程

通过DISEL来选择某一个物理设备,这个设备可能有多种功能,比如PCI设备,最多可以有8种功能,对于每一种功能,都有不同的256字节的配置寄存器(配置空间)。那么,通过IDSEL是可以选择指定的PCI设备,但是该怎么去选择其中的某一种功能,再怎么去选择其中哪一个配置寄存器去设置配置空间?

img

1. 通过IDSEL选中某一个PCI设备

通过某个ADn去连接设备的IDSEL引脚,PCI设备被唯一选中,用于区分系统中的不同设备。

2. Function Number 和 Register Number 的选择

在PCI设备中,配置空间的访问可以使用AD[31:0]引脚来指定Function NumberRegister
Number

  • Function Number:PCI设备可能有多种功能,每种功能有独立的配置空间。在AD[31:0]地址引脚中,部分比特用于指定该设备的功能号

    • 在地址格式中,AD[10:8]这三位用于指定Function Number,也就是设备的功能选择。
  • Register Number:配置空间中的寄存器可以通过地址来选择。在地址总线的低位部分,比如AD[7:2]这六位,用来指定配置空间中的寄存器号

所以,AD引脚的组合决定了访问的是哪一个功能的哪一个寄存器。

关于配置地址和普通内存地址的区分:

在PCI协议中,区分是否是在访问配置空间或普通内存空间,主要通过**C/BE#**信号来完成,而不是直接根据地址本身来区分。具体来说,PCI总线使用了两个地址空间:

  • 内存地址空间(Memory Space)
  • 配置地址空间(Configuration Space)

通过C/BE#信号来确定当前传输的是内存访问还是配置空间访问。当要访问配置空间时,必须设置为配置事务

配置事务的标志:
  • FRAME#信号会指示这是一个PCI事务,第一拍时的**AD[31:0]**总线携带的确实是地址信息,而后面的传输则是数据。但配置事务与内存读写事务在功能上不同,通过C/BE#来表明具体的操作。

    • **C/BE#**信号:指定了是读还是写操作(例如配置读1010,配置写1011)。

因此,当发出配置事务时,在第一拍时发送配置空间的地址,后续的时钟周期中进行的是数据传输

3. 如何确定读写寄存器?

通过C/BE#引脚来确定是读寄存器还是写寄存器。在PCI配置事务中,以下是一些关键操作:

  • C/BE# 引脚用于指定操作类型:读还是写。

    • 1010表示配置读操作(configuration read)。
    • 1011表示配置写操作(configuration write)。

配置空间读操作:首先读取PCI设备的配置空间,比如Base Address Registers(BARs),这可以帮助系统知道设备所申请的I/O空间和内存空间的大小。

配置空间写操作:之后可以使用写操作来设置配置寄存器的值,如中断线、中断号、命令寄存器等。

4. 配置完成后的数据传输

配置完成后,系统可以通过内存地址I/O地址来访问该PCI设备。此时,addr_pci表示的就是设备的I/O地址或者内存空间地址。数据传输会根据PCI设备所申请的地址空间进行。

  1. 通过IDSEL引脚选中某个PCI设备。
  2. 使用AD[31:0]引脚发送地址信息,其中高位部分指定是哪个设备的哪个功能,低位部分指定配置空间中的哪个寄存器。
    • PCI协议通过**C/BE#**来区分配置空间访问和内存地址访问,而不是直接通过地址的差异来区分。此外,AD引脚不仅指定功能号,还要指定配置寄存器的编号。
  1. 使用**C/BE#**信号来指定是否进行配置空间的读写操作(配置读1010,配置写1011)。
  2. 配置完成后,系统根据设备的申请来分配I/O空间或内存空间,然后可以使用addr_pci(分配给设备的I/O或内存地址)来进行数据传输。

2.3.3 示例:配置PCI Agent设备

PCI设备可以简单地分为PCI Bridge和PCI Agent:

  • PCI Bridge:桥,用来扩展PCI设备,必定有一个Root Bridge,下面还可以有其他Bridge。
  • PCI Agent:真正的PCI设备(比如网卡),是PCI树的最末端

怎么配置PCI Agent设备?

  • 选中:通过IDSEL来选中某个设备

  • 怎么访问配置空间:发起一个type 0的配置命令

    • PCI设备最多有8个功能,每个功能都有自己的配置空间(配置寄存器)
    • 你要访问哪个功能?哪个寄存器?发起
      img
  • CPU读取配置空间的BAR,得知:这个PCI设备想申请多大空间

  • CPU分配PCI地址,写到PCI设备的BAR里

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

ArrayList常见操作源码逐句剖析

目录 前言 正文 1.需要了解的一些字段属性 1.存储 ArrayList 元素的数组缓冲区。 2.集合的大小 3.默认集合容量大小 2.ArrayList对象创建 1.无参构造 2.有参构造1 3.有参构造2 3.添加元素add(E e)以及扩容机制 ​编辑 后言 前言 源码的剖析有助于理解设计模式&…

现代密码学|Rabin密码体制及其数学基础 | 椭圆曲线密码体制及其运算 | DH密钥交换及中间人攻击

文章目录 参考Rabin密码体制及其数学基础中国剩余定理二次剩余Rabin密码体制实例 椭圆曲线密码体制及其运算原理运算规则加密解密实例 DH密钥交换及中间人攻击中间人攻击 参考 现代密码学|Rabin密码体制及其数学基础 现代密码学|椭圆曲线密码体制及其运…

硬件选型规则

光源选型: 先用型号中带H的,没有的选标准的. 光源和光源控制器的搭配需要确保接口一致。 根据型号表中的最佳工作距离和相机的尺寸。 光源控制器选型: 首先选择海康风格系列光源控制器考虑与光源的接口匹配。功率应该满足接近光源功率。检查是否退市…

sharedPreference包的使用总结

文章目录 1 概念介绍2 实现方法3 示例代码我们在上一章回中介绍了"如何自定义评分条"相关的内容,本章回中将介绍如何实现本地存储.闲话休提,让我们一起Talk Flutter吧。 1 概念介绍 Flutter是一套跨平台的UI框架,它不像原生SDK一样提供本地存储功能,因此,我们在…

TCP连接的时候遇到的异常(目标端口没开放)

import asyncioasync def check_port(ip, port, timeout1):"""检查目标 IP 和端口是否开放:param ip: 目标 IP 地址:param port: 目标端口:param timeout: 超时时间(秒)"""try:reader, writer await asyncio.open_connec…

C总结(C语言知识点,深化重难点)

C语言 1.使用C语言的7个步骤2.ASCII码3.提高程序可读性的机巧4.如何使用多种整形5.打印多种整形6.课移植类型:stdint.h和inttypes.h7.浮点数常量8.浮点值的上溢和下溢9.使用数据类型11.常量和C预处理器12.转换说明的意义12.1转换不匹配13.副作用和序列点14.数组简介…

burpsuite(6)暴力破解与验证码识别绕过

声明!!! 学习视频来自B站UP主泷羽sec,如涉及侵权马上删除文章 视频链接:泷羽sec-bilibili 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负 项目地址:https://github.com/f0ng/cap…

抗DDOS设备

0x00 定义: 抗DDOS设备顾名思义,就是防御DDoS攻击的设备,通常包含三个部分:检测中心、清洗中心和管理中心 检测中心主要负责对流量进行检测,发现流量异常后上报管理中心,由管理中心下发引流策略至清洗中心&#xff0…

systemV信号量与消息队列

目录 引言 ipc简介 ipc在kernel的管理机制(简介) 信号量 理解信号量 原子 结论 mmap 消息队列 接口 引言 在复杂的软件系统中,进程间的协调和通信是确保系统高效、稳定运行的关键。System V是一套历史悠久且功能强大的进程间通信&a…

【CKS最新模拟真题】Falco 的运行时安全性

系列文章目录 【CKS最新模拟真题】获取多个集群的上下文名称并保存到指定文件中 文章目录 系列文章目录参考地址一、TASK二、解题过程1、问题一解题2、问题二解题 参考地址 CKS考试允许打开falco的地址 https://falco.org/docs/reference/rules/supported-fields/ 一、TASK …

Altium Designer学习笔记 32 DRC检查_丝印调整

基于Altium Designer 23学习版,四层板智能小车PCB 更多AD学习笔记:Altium Designer学习笔记 1-5 工程创建_元件库创建Altium Designer学习笔记 6-10 异性元件库创建_原理图绘制Altium Designer学习笔记 11-15 原理图的封装 编译 检查 _PCB封装库的创建Al…

【原生js案例】webApp实现鼠标移入移出相册放大缩小动画

图片相册这种动画效果也很常见,在我们的网站上。鼠标滑入放大图片,滑出就恢复原来的大小。现在我们使用运动定时器来实现这种滑动效果。 感兴趣的可以关注下我的系列课程【webApp之h5端实战】,里面有大量的css3动画效果制作原生知识分析&…

MetaGPT 安装

1. 创建环境 conda create -n metagpt python3.10 && conda activate metagpt2. 可编辑方式安装 git clone --depth 1 https://github.com/geekan/MetaGPT.git cd MetaGPT pip install -e .3. 配置 metagpt --init-config运行命令,在C盘位置C:\Users\325…

流量地球(Java Python JS C++ C )

题目描述 流浪地球计划在赤道上均匀部署了N个转向发动机,按位置顺序编号为0~N-1。 初始状态下所有的发动机都是未启动状态;发动机启动的方式分为”手动启动"和”关联启动"两种方式;如果在时刻1一个发动机被启动,下一个时刻2与之相邻的两个发动机就会被”关联启动”…

Milvus向量数据库04-Pipelines搭建RAG应用

Milvus向量数据库04-Pipelines搭建RAG应用 Zilliz Cloud Pipelines 可以将文档、文本片段和图像等非结构化数据转换成可搜索的向量并存储在 Collection 中。本文将介绍 Zilliz Cloud Pipelines 的三种主要类型并提供示例代码,展示如何使用 Pipelines 搭建 RAG 应用。…

离线写博客(失败) - 用Markdown来离线写博客

因为想控制一下用网,但是又有写博客的需求,所以想研究一下离线写博客。 我看CSDN上面好像有很多介绍,Windows Live Writer 啦,Markdown啦,还有一些其他的,我看了一下,好像 Markdown还有点儿靠谱…

【洛谷】B3844 [GESP样题 二级] 画正方形(详细注释)

#include <iostream> using namespace std; int main() {//声明一个整型变量n&#xff0c;用于接收输入的数值&#xff0c;该数值将决定后续输出图案的行数和列数int n; cin >> n;//声明两个整型变量i和j&#xff0c;分别用作外层循环和内层循环的计数器int i, j;/…

Linux-音频应用编程

ALPHA I.MX6U 开发板支持音频&#xff0c;板上搭载了音频编解码芯片 WM8960&#xff0c;支持播放以及录音功能&#xff01;本章我们来学习 Linux 下的音频应用编程&#xff0c;音频应用编程相比于前面几个章节所介绍的内容、其难度有所上升&#xff0c;但是笔者仅向大家介绍 Li…

番茄社区双端视频APP源码_内附安装教程

新版视频源码|类似番茄APP视频付费软件APP源码教程 番茄社区双端视频APP源码&#xff0c;带安装教程&#xff0c;源码非组件&#xff0c;短视频、图片、交流、讨论、电影、电视剧。 没有什么问题宝塔就可以搭建&#xff0c;采集方面是火车头可以自己写规则&#xff01;

Onchain 正在蚕食 Offchain

目录 未来在链上 价值创造 技术加速 机构采用 小队&#xff1a;加速链上经济 我们正在进入一个代码就是货币、信任被编程、全球接入打破传统经济界限的时代。这种新兴模式就是我们所说的链上经济。 在此领域&#xff0c;Solana 因其在基础设施和应用程序方面的持续创新而脱颖而…