【NVMe2.0b 13】NVMe 标准数据结构

4数据结构

本节介绍 NVM Express 使用的数据结构。

4.1数据布局

本节描述控制器和主机可以理解的数据布局的数据结构。

4.1.1Physical Region Page Entry and List

physical region page (PRP) entry 是指向物理内存页的指针。PRP 用作控制器和内存之间数据传输的分散/收集机制。为了在控制器和主机之间实现高效的乱序数据传输,PRP entry 的大小是固定的。

物理内存页的大小由 CC.MPS 中的主机软件配置。Figure 108 显示了由 Page Base Address 和 Offset 组成的 PRP entry 的布局。Offset 字段的大小由 CC.MPS 中配置的物理内存页大小决定。

Figure 108: PRP Entry Layout

在这里插入图片描述

Figure 109 描述了 PRP entry 的定义。

Figure 109: PRP Entry – Page Base Address and Offset
BitsDescription
63:00Page Base Address and Offset (PBAO): 该字段表示 64 位物理内存页地址。该字段的最低有效位 (n:0) 表示内存页内的偏移量(例如,如果内存页大小为 4 KiB,则bits 11:00 形成 Offset;如果内存页大小为 8 KiB,则bits 12:00 形成Offset)。如果该 entry 不是命令中的第一个 PRP entry 或命令中的 PRP List 指针,则该字段的 Offset 部分应清为 0h。Offset 应为dword对齐,由bits 1:0 清为 00b 表示。

注意:控制器不需要检查bits 1:0 是否被清除为 00b。如果bits 1:0 未清零为 00b,控制器可能会报告 PRP Offset Invalid 错误。如果控制器未报告 PRP Offset Invalid 错误,则控制器应像位 1:0 被清除为 00b 一样操作。

physical region page list(PRP List) 是单个连续内存页中的一组 PRP entries。PRP List 描述了无法在命令本身中描述的其他 PRP entries。命令中描述的任何 PRP entries 不会在 PRP List 中重复。如果要传输的数据量需要多个 PRP List 内存页,则内存页末尾之前的最后一个 PRP entry 应指向下一个 PRP List 的指针,指示 PRP List 的下一段。Figure 110 显示了 PRP List 的布局,其中每个 PRP entry 标识物理上连续的内存页。Figure 111 显示了 PRP List 的布局,其中每个 PRP entry 标识不同的内存页(即,内存页在物理上不是连续的)。

Figure 110: PRP List Layout for Physically Contiguous Memory Pages

在这里插入图片描述

Figure 111: PRP List Layout for Physically Non-Contiguous Memory Pages

在这里插入图片描述

根据命令定义,包含在命令中的第一个 PRP entry 可能在内存页内具有非0偏移量。第一个 PRP List entry(即,第一个指向包含其他 PRP entry的内存页的指针)如果存在,通常包含在命令中的 PRP Entry 2 位置中,它应该是 qword 对齐的,并且也可以在内存页中具有非0偏移量。

PRP List 中包含的 PRP entries 的内存页偏移量应为 0h。如果命令中存在第二个 PRP entry,则它的内存页偏移量应为 0h。在这两种情况下,entry 都是基于 CC.MPS 中的值对齐的内存页。如果控制器接收到这些 PRP entries 的非0偏移量,则控制器应返回 PRP Offset Invalid 错误。

包装的 entries 从entry 0 开始,PRP Lists 的大小应最小。如果需要更多 PRP List pages,则 PRP List 的最后一个 entry 包含下一个 PRP List page 的 Page Base Address。下一个 PRP List page 应与内存页对齐。命令所需的 PRP entries 总数由命令参数和内存页大小暗示。

4.1.2Scatter Gather List (SGL)

Scatter Gather List (SGL) 是内存地址空间中用于描述数据缓冲区的数据结构。控制器指示控制器在 Identify Controller data structure 中支持的 SGL 类型。数据缓冲区要么是 source buffer,要么是 destination buffer。SGL 包含一个或多个 SGL segments。SGL 中 Data Block 和 Bit Bucket 描述符的总长度应等于或超过请求传输的数据量。

SGL segment 是物理内存的连续区域中的 qword 对齐数据结构,描述了数据缓冲区和下一个 SGL segment(如果有)的全部、部分或没有。一个 SGL segment 由一个或多个 SGL descriptors 组成的数组。只有 SGL segment 中的最后一个 descriptor 可以是 SGL Segment descriptor 或 SGL Last Segment descriptor。

最后一个 SGL segment 是不包含 SGL Segment descriptor 或 SGL Last Segment descriptor 的 SGL segment。 控制器可以支持byte或dword对齐和Data Blocks的粒度。如果控制器仅支持 Identify Controller data structure 的 SGL Support 字段中指示的dword对齐和粒度(参见Figure 275)),则所有 Data Block descriptors 的Address 和 Length 字段中的值中两个最低有效位应清为 00b。此要求适用于指示数据和(或)元数据内存区域的 Data Block descriptors。

Identify Controller data structure 中的 SGL Descriptor Threshold (SDT) 字段(参见 Figure 275)指示命令的 SGL descriptors 的建议最大数量。如果 SDT 字段设置为非0值,并且提交的命令的总和为:

  a)具有非0 Length 字段内容的 SGL Bit Bucket descriptors 的数量; 和
  b)具有非0 Length 字段内容的 SGL Data Block descriptors 的数量,

超过 SDT 字段的值,则控制器的 performance 可能会降低。

SDT 字段的值应小于或等于 Identify Controller data structure 中的 Maximum SGL Data Block Descriptors(MSDBD) 字段的值(有关 MSDBD 字段的定义,请参阅 NVMe over Fabrics 规范)。

Keyed SGL Data Block descriptor 是一个 Data Block descriptor,它包括一个用作主机内存访问一部分的密钥。可在 Keyed SGL Data Block descriptor 中指定的最大长度为 (16 MiB – 1)。

Transport SGL Data Block descriptor 是一个 Data Block descriptor,它指定由 NVMe Transport 使用特定 NVMe Transport 的传输机制和 data buffers 传输的数据块。

SGL Identifier Descriptor Sub Type 字段可以指示关于描述符的附加信息。例如,Sub Type 可以指示 Address 字段是偏移量而不是绝对地址。Address 还可以指示 NVMe Transport。

如果出现以下情况,控制器应中止命令:

  • 一个 SGL segment 包含一个 SGL Segment descriptor 或一个 SGL Last Segment 描述符,而不是该 segment 中的最后一个 descriptor ;
  • 最后一个 SGL segment 包含一个 SGL Segment descriptor,或一个 SGL Last Segment descriptor;
  • SGL descriptor 的格式不受支持; 或
  • SGL Data Block descriptor 包含 Address 或 Length 字段,其中两个最低有效位中的任何一个设置为 1b,并且控制器仅支持 dword 对齐和粒度,如 Identify Controller data structure 的 SGL Support 字段中所示。请参阅 Figure 275。

Figure 112 定义了 SGL segment。

Figure 112: SGL Segment

在这里插入图片描述

一个 SGL segment 包含一个或多个 SGL descriptors。Figure 113 定义了 generic SGL descriptor 格式。

Figure 113: Generic SGL Descriptor Format

在这里插入图片描述

Figure 114 中定义的 SGL Descriptor Type 字段指定了 SGL 描述符类型。如果 SGL Descriptor Type 字段设置为 reserved 值或不支持的值,则 SGL descriptor 应被处理为具有 SGL Descriptor Type 错误。如果 SGL Descriptor Sub Type 字段设置为 reserved 值或不支持的值,则描述符应被处理为具有 SGL Descriptor Type 错误。

设为全0的 SGL 描述符是 Address 字段清0且 Length 字段清0的 SGL Data Block descriptor,可用作 NULL descriptor。

Figure 114: SGL Descriptor Type

在这里插入图片描述

Figure 115 定义了 SGL Descriptor Sub Type 值并指示每个 SGL Descriptor Sub Type 适用的 SGL Descriptor Types。

Figure 115: SGL Descriptor Sub Type Values

在这里插入图片描述

在这里插入图片描述

Figure 116 中定义的 SGL Data Block descriptor 描述了一个数据块。

Figure 116: SGL Data Block descriptor

在这里插入图片描述

Figure 117 中定义的 SGL Bit Bucket 描述符用于忽略部分 source data。

Figure 117: SGL Bit Bucket descriptor

在这里插入图片描述

Figure 118 中定义的 SGL Segment descriptor 描述了下一个 SGL segment,前提是它不是最后一个 SGL segment。

Figure 118: SGL Segment descriptor

在这里插入图片描述

Figure 119 中定义的 The SGL Last Segment descriptor 描述了下一个和最后一个 SGL segment。包含 SGL Segment descriptor 或 SGL Last Segment descriptor 的最后一个 SGL segment 将作为错误处理。

Figure 119: SGL Last Segment descriptor

在这里插入图片描述

Figure 120 中定义的 Keyed SGL Data Block descriptor 描述了一个加密的数据块。

Figure 120: Keyed SGL Data Block descriptor

在这里插入图片描述

Figure 121: Transport SGL Data Block descriptor

在这里插入图片描述

4.1.2.1SGL示例

Figure 122 显示了使用 SGL 的数据读取请求示例。在此示例中,逻辑块大小为 512B。访问的逻辑块总长度为 13 KiB,其中只有 11 KiB 传输到主机。命令中的 Number of Logical Blocks (NLB) 字段应指定 26,表示在控制器上访问的逻辑块的总长度为 13 KiB。有三个 SGL segments 描述了逻辑块数据在内存中传输的位置。

三个 SGL segments 总共包含三个 Data Block descriptors,长度分别为 3 KiB、4 KiB 和 4 KiB。destination SGL 的第 1 段包含长度为 2 KiB 的 Bit Bucket descriptor,指定不从 NVM 传输(即忽略)2 KiB 逻辑块数据。destination SGL 的第 1 段还包含一个 Last Segment descriptor,指定描述符指向的 segment 是最后一个 SGL segment。

Figure 122: SGL Read Example

在这里插入图片描述

4.1.3Metadata Region (MR)

元数据区域的定义是特定于 command set 的。有关适用性和其他详细信息(如果有),请参阅每个 I/O Command Set 规范。

4.2Feature值

Get Features 命令(参见第 5.15 节)和 Set Features 命令(参见第 5.27 节)可用于读取和修改控制器的操作参数。操作参数由 Feature Identifiers 分组和标识。每个 Feature Identifier 都包含一个或多个可能影响 Feature 行为的属性。

如果在 Figure 275 中 Identify Controller data structure 的 Optional NVM Command Support(ONCS) 字段中的第 4 位设置为“1”,那么对于每个 Feature,都有三个设置:default、saved和current。如果在Identify Controller data structure 的 Optional NVM Command Support 字段中将第 4 位清除为“0”,则控制器仅支持每个 Feature 的current 值和 default 值。在这种情况下,当前值可以在power cycle和基于Figure 316 中指定的信息的 resets 期间保持不变。

如果 ONCS 字段中的第 4 位设置为“1”,则每个 Feature 都具有支持的capabilities(请参阅Figure 195),这些 capabilities 是使用 Get Features 中的 Select 字段中的 Supported Capabilities 值发现的(请参阅Figure 192)。

除非另有说明,否则每个 Feature 的默认值是供应商特定的并由制造商设置。default 值不可更改。

Feature 可能是可保存的。保存的值是 Controller Level Reset 后 Feature 具有的值。如果 Feature 不可保存,则:

  a) 在 Controller Level Reset 后使用 default 值; 和

  b) 读取 saved 值的 Get Features 命令会返回 default 值。

Feature 的 current 值是控制器为该 Feature 主动使用的值。

Set Features 命令使用命令指定的值来设置:

  a) 该 Feature 的 current 值; 或
  b) 如果该 Feature 是可保存的, 则可以Set 该 Feature 的 current 值和该 Feature 的 saved 值。

Feature 设置可能适用于:   a) the controller (i.e., the feature is not namespace specific); or   b) a namespace (i.e., the feature is namespace specific).

对于用于控制器的 feature 值:

  a)如果 NSID 字段被清为 0h 或设为 FFFFFFFFh,则:

  • Set Features 命令应为控制器设置指定的 feature 值;
  • Get Features 命令应返回控制器请求的 feature 值的当前设置;

b)如果 NSID 字段设置为 valid namespace identifier(请参阅第 3.2.1.2 节),则:

  • Set Features 命令应以 Feature Not Namespace Specific 状态码中止;
  • Get Features 命令应返回控制器请求的 feature 值的当前设置。

对于用于一个命名空间的 feature 值:

a) 如果 NSID 字段设置为 active namespace identifier(请参阅第 3.2.1.4 节),则:

  • Set Features 命令应设置指定命名空间的指定 feature 值;
  • Get Features 命令应返回指定命名空间的请求 feature 值的当前设置;

b) 如果 NSID 字段设置为 FFFFFFFFh,则:

  • 对于 Set Features 命令,控制器应:
      o如果在 Identify Controller data structure 中将 MDS 位设为“1”,则使用 Invalid Field in Command 中止命令; 或者
      o如果 Identify Controller data structure 中的MDS位被清为’0’,除非另有说明,否则为所有连接到处理命令的控制器的命名空间设置指定的 Feature 值;
  • 对于 Get Features 命令,除非第 5.27.1 节另有规定,否则控制器应以 Invalid Namespace or Format 状态码中止命令;

  c) 如果 NSID 字段设置为任何其他值,则 Set Features 命令和 Get Features 命令应中止,如 Figure 87 中 namespace identifier 使用规则中所述。

如果控制器支持 Set Features 命令中的 Save 字段和 Get Features 命令中的 Select 字段,那么任何命名空间特定的 Feature Identifier 都可以在每个命名空间的基础上保存。

在 Figure 316 中定义了强制和可选的 Feature Identifiers。如果处理了指定不支持的 Feature Identifier的 Get Features 命令或 Set Features 命令,则控制器应中止命令,状态码为 Invalid Field in Command。

4.3Identifier的格式与布局

本节为正确实施 Identify Controller、Identify Namespace 和 Namespace Identification Descriptor data structures 中定义的各种identifiers提供指导。

4.3.1PCI Vendor ID (VID) 和 PCI Subsystem Vendor ID (SSVID)

PCI Vendor ID(VID,bytes 01:00)和 PCI Subsystem Vendor ID(SSVID,bytes 03:02)在 Identify Controller data structure 中定义。这些值由 PCI SIG 分配。每个 identifier 都是小端格式的 16 位数字。

例子: - VID = ABCDh; and - SSVID = 1234h.

Figure 123: PCI Vendor ID (VID) and PCI Subsystem Vendor ID (SSVID)

在这里插入图片描述

4.3.2Serial Number (SN) 和 Model Number (MN)

Serial Number(SN,bytes 23:04)和 Model Number(MN,bytes 63:24)在 Identify Controller data structure 中定义。这些值是供应商分配的 ASCII 字符串。每个 identifier 都是大端格式。

示例(显示为 ASCII 字符的值): - SN = “SN1”; and - MN = “M2”.

Figure 124: Serial Number (SN) and Model Number (MN)

在这里插入图片描述

4.3.3IEEE OUI Identifier (IEEE)

IEEE OUI Identifier(OUI,bytes 75:73)在 Identify Controller data structure 中定义。该值由 IEEE Registration Authority 分配。identifier采用小端格式。

例子:

  • OUI = ABCDEFh.
Figure 125: IEEE OUI Identifier (IEEE)

在这里插入图片描述

4.3.4IEEE Extended Unique Identifier (EUI64)

IEEE Extended Unique Identifier(EUI64,bytes 127:120)在 Identify Namespace data structure 中定义。教程可在 https://standards.ieee.org/develop/regauth/tut/index.html 获得。IEEE 定义了可用于该字段的三种格式:MA-L、MA-M 和 MA-S。本节中的示例使用 MA-L 格式。

MA-L 格式定义为一个由八个八位字节组成的字符串:

Figure 126: IEEE Extended Unique Identifier (EUI64), MA-L Format

在这里插入图片描述

EUI64 以大端格式定义。OUI 字段不同于 4.3.3 节中描述的小端格式的 OUI Identifier。

例子:

  • OUI Identifier = ABCDEFh; and
  • Extension Identifier = 0123456789h.
Figure 127: IEEE Extended Unique Identifier (EUI64), OUI Identifier

在这里插入图片描述

Figure 128: IEEE Extended Unique Identifier (EUI64), Ext. ID (cont)

在这里插入图片描述

MA-L 格式类似于定义为 IEEE Registered 指示符 (NAA = 5) 的 World Wide Name (WWN) 格式,如下所示。

Figure 129: MA-L similarity to WWN

在这里插入图片描述

4.3.5Namespace Globally Unique Identifier (NGUID)

命名空间全局唯一标识符(Namespace Globally Unique Identifier,NGUID,bytes 119:104)在 Identify Namespace data structure 中定义。NGUID 由 IEEE OUI、扩展标识符和供应商特定扩展标识符组成。扩展标识符和厂商特定扩展标识符都由厂商分配并且可以被视为单个字段。NGUID 以大端格式定义。OUI 字段不同于 4.3.3 节中描述的小端格式的 OUI Identifier。

例子:

  • OUI Identifier = ABCDEFh;
  • Extension Identifier = 0123456789h; and
  • Vendor Specific Extension Identifier = FEDCBA9876543210h.
Figure 130: Namespace Globally Unique Identifier (NGUID)

在这里插入图片描述

Figure 131: Namespace Globally Unique Identifier (NGUID), OUI

在这里插入图片描述

Figure 132: Namespace Globally Unique Identifier (NGUID), Extension Identifier (continued)

在这里插入图片描述

NGUID 格式类似于作为 IEEE Registered Extended 指示符 (NAA = 6) 的 World Wide Name (WWN) 格式,如下所示。

Figure 133: Namespace Globally Unique Identifier (NGUID), NGUID similarity to WWN

在这里插入图片描述

4.3.6Universally Unique Identifier (UUID)

Universally Unique Identifier 在 RFC 4122 中定义并包含在 Namespace Identification Descriptor (参见Figure 277)。RFC 4122 中描述了 UUID 的字节顺序要求。

4.4List Data Structures

本节描述了本规范中使用的列表数据结构。

4.4.1Controller List

Figure 134 中定义的 Controller List 是控制器ID 升序的有序列表。controller identifier 在 Figure 134 中Identify data structure 的 bytes 79:78 中定义。未使用的条目用0填充。

Figure 134: Controller List Format

在这里插入图片描述

Figure 135 中定义的 Namespace List 是 namespace ID 的有序列表。未使用的条目是0填充的。

Figure 135: Namespace List Format

在这里插入图片描述

4.5NVMe Qualified Names

NVMe Qualified Names (NQN) 用于唯一描述主机或 NVM 子系统,以用于识别和身份验证。NVM 子系统的 NVMe Qualified Name 在 Identify Controller data structure 中指定。NQN 在主机或 NVM 子系统的生命周期内是永久的。

NVMe Qualified Name 被编码为具有以下属性的 Unicode 字符串:

  • 编码为 UTF-8(请参阅 RFC 3629);
  • 以下字符用于格式化:
        o破折号 (‘-‘=U+002d);
        o点 (‘.’=U+002e);
        o冒号 (‘:’=U+003a);
  • 名字的最大长度为 223 个字节;
  • 字符串以空值结尾。

有两种受支持的 NQN 格式。任何拥有域名的组织都可以使用第一种格式。这种命名格式可用于创建人类可解释的字符串来描述主机或 NVM 子系统。这种格式包括:

  • 字符串“nqn”;
  • 字符串“.” (即 ASCII 句点字符);
  • 日期代码,格式为“yyyy-mm”。该日期应在命名机构拥有以这种格式使用的域名的时间间隔内。日期代码使用公历。应包括所有数字和破折号;
  • 字符串“.” (即 ASCII 句点字符);
  • 创建NQN 的命名机构的反向域名;
  • domain名所有者分配的不超过最大长度带冒号(😃 前缀的字符串。命名机构负责确保 NQN 是全球唯一的。

使用该格式的 NQN 中的反向域名不得为“org.nvmexpress”。

以下是“Example NVMe, Inc.”可能生成的 NVMe Qualified Name 示例:

  • The string “nqn.2014-08.com.example:nvme:nvm-subsystem-sn-d78432”; and
  • The string “nqn.2014-08.com.example:nvme.host.sys.xyz”.

当没有命名机构或不需要人类可解释的字符串时,第二种格式可用于创建唯一标识符。这种格式包括:

  • 字符串“nqn”;
  • 字符串“.” (即 ASCII 句点字符);
  • 字符串“2014-08.org.nvmexpress:uuid:”;
  • 基于 RFC 4122 中定义的 128 位 UUID,表示为格式为“11111111-2222-3333-4444-555555555555”的字符串。

以下是使用基于 UUID 格式的 NVMe Qualified Name 的示例:

  • “nqn.2014-08.org.nvmexpress:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6”.

NVMe 主机、控制器和 NVM 子系统比较(例如,是否相等),NVMe 将 NVMe Qualified Names用作二进制字符串,无需任何文本处理或特定 Unicode 字符集或区域设置的文本比较逻辑(例如,大小写折叠或转换为小写情况下,Unicode 规范化)。任何此类文本处理:

  ;a)可能作为 NVMe Qualified Names 进入 NVMe 主机和 NVM 子系统的一部分发生;
 &nbspb)不应作为通过 NVMe connection 接收 NVMe Qualified Names 的一部分发生,如 Figure 136 所示。

在MQN条目进入时(在Figure 136 中的1,在 RFC4122 中描述为“input”),NVMe 主机软件可以处理 NVMe Qualified Name(基于 Unicode 本地设置转换为小写)。在MQN条目进入时(在Figure 136 中的 3,在 RFC4122 中描述为“input”),控制器可以处理 NVMe Qualified Name(例如,基于 Unicode 区域设置转换为小写)。在主机(例如,在Figure 136 中的2)从控制器接收到 NVMe Qualified Name 时,不应发生文本处理(例如,不折叠大小写)。当控制器(在Figure 136 中的4)从主机接收到 NVMe Qualified Name,不应进行文本处理(例如,不进行大小写折叠)。

Figure 136: NQN Processing

在这里插入图片描述

4.5.1Unique Identifier

在 Identify Controller data structure(参见Figure 275)中指定的 NVM Subsystem NVMe Qualified Name应(例如,由主机软件)用作 NVM 子系统的唯一标识符。如果控制器符合不包含 NVM Subsystem NQN 的旧版 NVM Express 规范,则 Identify Controller data structure 中的 PCI Vendor ID、Serial Number 和 Model Number 字段以及 NQN Starting String “nqn.2014.08 .org.nvmexpress:” 可以由主机组合形成一个全局唯一值,用于标识 NVM 子系统(对于使用 NQN 的主机软件)。主机应使用Figure 137 中所示的方法为未在 Identify Controller data structure 中提供 NQN 的旧 NVM 子系统构建 NVM Subsystem NQN。供应商用来分配SN和MN以确保唯一性的机制超出了本规范的范围。

Figure 137: NQN Construction for Older NVM Subsystems

在这里插入图片描述

在这里插入图片描述

一个 NVM 子系统可能包含多个控制器。NVM 子系统中包含的所有控制器共享相同的 NVM subsystem unique identifier。在 Identify Controller data structure中返回的 Controller ID (CNTLID) 值可用于唯一标识 NVM 子系统内的控制器。Controller ID 值与 NVM subsystem identifier 结合形成一个全局唯一值,用于标识控制器。供应商用于分配 Controller ID 值的机制超出了本规范的范围。

Identify Namespace data structure(请参阅适用的I/O Command Set规范)包含 IEEE Extended Unique Identifier (EUI64) 和 Namespace Globally Unique Identifier (NGUID) 字段。Namespace Identification Descriptor data structure(参见Figure 277)包含 Namespace UUID。EUI64是8字节的EUI-64标识符(参考4.3.4 节),NGUID是基于EUI-64的16字节标识符(参考4.3.5 节),Namespace UUID是在 RFC 4122 中描述的16字节标识符(请参阅第 4.3.6 节)。

创建命名空间时,控制器应在以下一项或多项中指示全局唯一值:

  a)the EUI64 field;
  b)the NGUID field; or
  c)Namespace Identifier Type 字段设置为 3h 的Namespace Identification Descriptor。

如果 EUI64 字段被清为 0h 并且 NGUID 字段被清为 0h,则命名空间应支持 Namespace Identification Descriptor data structure 中的有效的Namespace UUID。

如果 NSFEAT 字段中的 UIDREUSE 位被清为“0”,则在删除使用该值的原始命名空间后,控制器可以为新命名空间重用非零 NGUID/EUI64 值。如果 UIDREUSE 位设置为“1”,则在删除使用该值的原始名称空间后,控制器不得为新命名空间重用非零 NGUID/EUI64。

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值