NVDIMMとACPI
DIMMに刺せる不揮発性メモリ(NVDIMM*1 )はACPIからどのように扱われるかというメモ.
TL;DR
ACPIのNFIT (NVDIMM Firmware Interaface Table)に情報が入っています.
QEMUでのエミュレーション
QEMUのNVDIMMエミュレーションで確認します.
今回は以下のようなオプションで試しました.
-machine pc,nvdimm \ -m 16G,slots=2,maxmem=32G \ -object memory-backend-file,id=mem1,share,mem-path=/home/work/vm/nvdimm-2,size=4G,align=128M \ -device nvdimm,memdev=mem1,id=nv1,label-size=2M \ ...
オプションの詳細は上記のQEMUのドキュメントを確認ください. 詳細は確認していませんが,どうもQEMU的には最初hotplug可能なメモリスロットを用意しておいて,そこにNVDIMMのデバイスを接続するという形態を取っているようです.
mem-path
で指定したパスに,指定したサイズだけのファイルが作成されます.
これでLinuxを起動すると,自動でNVDIMMが認識されます.
$ dmesg | grep pmem [ 7.284102] pmem0: detected capacity change from 0 to 4160749568 $ ls /dev/pmem0 /dev/pmem0
ACPIの情報は以下のように確認できます(iasl
はubuntuならsudo apt install acpica-tools
で入ります).
% sudo cp /sys/firmware/acpi/tables/NFIT . % sudo iasl -d NFIT % cat NFIT.dsl /* * Intel ACPI Component Architecture * AML/ASL+ Disassembler version 20180105 (64-bit version) * Copyright (c) 2000 - 2018 Intel Corporation * * Disassembly of NFIT, Tue Apr 2 06:10:17 2019 * * ACPI Data Table [NFIT] * * Format: [HexOffset DecimalOffset ByteLength] FieldName : FieldValue */ [000h 0000 4] Signature : "NFIT" [NVDIMM Firmware Interface Table] [004h 0004 4] Table Length : 000000E0 [008h 0008 1] Revision : 01 [009h 0009 1] Checksum : 40 [00Ah 0010 6] Oem ID : "BOCHS " [010h 0016 8] Oem Table ID : "BXPCNFIT" [018h 0024 4] Oem Revision : 00000001 [01Ch 0028 4] Asl Compiler ID : "BXPC" [020h 0032 4] Asl Compiler Revision : 00000001 [024h 0036 4] Reserved : 00000000 [028h 0040 2] Subtable Type : 0000 [System Physical Address Range] [02Ah 0042 2] Length : 0038 [02Ch 0044 2] Range Index : 0002 [02Eh 0046 2] Flags (decoded below) : 0003 Add/Online Operation Only : 1 Proximity Domain Valid : 1 [030h 0048 4] Reserved : 00000000 [034h 0052 4] Proximity Domain : 00000000 [038h 0056 16] Address Range GUID : 66F0D379-B4F3-4074-AC43-0D3318B78CDB [048h 0072 8] Address Range Base : 0000000440000000 [050h 0080 8] Address Range Length : 00000000F8000000 [058h 0088 8] Memory Map Attribute : 0000000000008008 [060h 0096 2] Subtable Type : 0001 [Memory Range Map] [062h 0098 2] Length : 0030 [064h 0100 4] Device Handle : 00000001 [068h 0104 2] Physical Id : 0000 [06Ah 0106 2] Region Id : 0000 [06Ch 0108 2] Range Index : 0002 [06Eh 0110 2] Control Region Index : 0003 [070h 0112 8] Region Size : 00000000F8000000 [078h 0120 8] Region Offset : 0000000000000000 [080h 0128 8] Address Region Base : 0000000000000000 [088h 0136 2] Interleave Index : 0000 [08Ah 0138 2] Interleave Ways : 0001 [08Ch 0140 2] Flags : 0000 Save to device failed : 0 Restore from device failed : 0 Platform flush failed : 0 Device not armed : 0 Health events observed : 0 Health events enabled : 0 Mapping failed : 0 [08Eh 0142 2] Reserved : 0000 [090h 0144 2] Subtable Type : 0004 [NVDIMM Control Region] [092h 0146 2] Length : 0050 [094h 0148 2] Region Index : 0003 [096h 0150 2] Vendor Id : 8086 [098h 0152 2] Device Id : 0001 [09Ah 0154 2] Revision Id : 0001 [09Ch 0156 2] Subsystem Vendor Id : 0000 [09Eh 0158 2] Subsystem Device Id : 0000 [0A0h 0160 2] Subsystem Revision Id : 0000 [0A2h 0162 1] Valid Fields : 00 [0A3h 0163 1] Manufacturing Location : 00 [0A4h 0164 2] Manufacturing Date : 0000 [0A6h 0166 2] Reserved : 0000 [0A8h 0168 4] Serial Number : 00123456 [0ACh 0172 2] Code : 0301 [0AEh 0174 2] Window Count : 0000 [0B0h 0176 8] Window Size : 0000000000000000 [0B8h 0184 8] Command Offset : 0000000000000000 [0C0h 0192 8] Command Size : 0000000000000000 [0C8h 0200 8] Status Offset : 0000000000000000 [0D0h 0208 8] Status Size : 0000000000000000 [0D8h 0216 2] Flags : 0000 Windows buffered : 0 [0DAh 0218 6] Reserved1 : 000000000000 Raw Table Data: Length 224 (0xE0) 0000: 4E 46 49 54 E0 00 00 00 01 40 42 4F 43 48 53 20 // NFIT.....@BOCHS 0010: 42 58 50 43 4E 46 49 54 01 00 00 00 42 58 50 43 // BXPCNFIT....BXPC 0020: 01 00 00 00 00 00 00 00 00 00 38 00 02 00 03 00 // ..........8..... 0030: 00 00 00 00 00 00 00 00 79 D3 F0 66 F3 B4 74 40 // ........y..f..t@ 0040: AC 43 0D 33 18 B7 8C DB 00 00 00 40 04 00 00 00 // .C.3.......@.... 0050: 00 00 00 F8 00 00 00 00 08 80 00 00 00 00 00 00 // ................ 0060: 01 00 30 00 01 00 00 00 00 00 00 00 02 00 03 00 // ..0............. 0070: 00 00 00 F8 00 00 00 00 00 00 00 00 00 00 00 00 // ................ 0080: 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 // ................ 0090: 04 00 50 00 03 00 86 80 01 00 01 00 00 00 00 00 // ..P............. 00A0: 00 00 00 00 00 00 00 00 56 34 12 00 01 03 00 00 // ........V4...... 00B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // ................ 00C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // ................ 00D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // ................
ちなみに,Proximity DomainがNUMAドメインの情報です.
(補足) SRATとの関連
ACPIのSRAT (System Resource Affinity Table)に,NUMAノードの情報や,メモリの物理アドレス,サイズなどの情報が格納されています.このテーブルはNUMAなマシンでないと存在しないかもしれません.
Linuxでは以下のようにしてSRATのMemory Affinityの情報が確認できます. 先ほどと同じQEMU上のゲストで実行すると以下のようになります.
% sudo cp /sys/firmware/acpi/SRAT . % sudo iasl -d SRAT % cat SRAT.dsl | grep -A13 "Memory Affinity" | grep -B10 -A3 "Enabled : 1" [1B0h 0432 1] Subtable Type : 01 [Memory Affinity] [1B1h 0433 1] Length : 28 [1B2h 0434 4] Proximity Domain : 00000000 [1B6h 0438 2] Reserved1 : 0000 [1B8h 0440 8] Base Address : 0000000000000000 [1C0h 0448 8] Address Length : 00000000000A0000 [1C8h 0456 4] Reserved2 : 00000000 [1CCh 0460 4] Flags (decoded below) : 00000001 Enabled : 1 Hot Pluggable : 0 Non-Volatile : 0 [1D0h 0464 8] Reserved3 : 0000000000000000 [1D8h 0472 1] Subtable Type : 01 [Memory Affinity] [1D9h 0473 1] Length : 28 [1DAh 0474 4] Proximity Domain : 00000000 [1DEh 0478 2] Reserved1 : 0000 [1E0h 0480 8] Base Address : 0000000000100000 [1E8h 0488 8] Address Length : 00000000BFF00000 [1F0h 0496 4] Reserved2 : 00000000 [1F4h 0500 4] Flags (decoded below) : 00000001 Enabled : 1 Hot Pluggable : 0 Non-Volatile : 0 [1F8h 0504 8] Reserved3 : 0000000000000000 [200h 0512 1] Subtable Type : 01 [Memory Affinity] [201h 0513 1] Length : 28 [202h 0514 4] Proximity Domain : 00000000 [206h 0518 2] Reserved1 : 0000 [208h 0520 8] Base Address : 0000000100000000 [210h 0528 8] Address Length : 0000000340000000 [218h 0536 4] Reserved2 : 00000000 [21Ch 0540 4] Flags (decoded below) : 00000001 Enabled : 1 Hot Pluggable : 0 Non-Volatile : 0 [220h 0544 8] Reserved3 : 0000000000000000 [228h 0552 1] Subtable Type : 01 [Memory Affinity] [229h 0553 1] Length : 28 [22Ah 0554 4] Proximity Domain : 00000000 [22Eh 0558 2] Reserved1 : 0000 [230h 0560 8] Base Address : 0000000440000000 [238h 0568 8] Address Length : 0000000440000000 [240h 0576 4] Reserved2 : 00000000 [244h 0580 4] Flags (decoded below) : 00000003 Enabled : 1 Hot Pluggable : 1 Non-Volatile : 0 [248h 0584 8] Reserved3 : 0000000000000000
で,ここのMemory Affinity StructureにNonVolatile
というフィールドがあります.
なのでこのフィールドからもNVDIMMかどうか判定できるのでは? という気がしますが,とりあえずQEMUでは上記のようにNonVolatileな領域はありません(一番最後のフィールドがアドレス的にNVDIMMデバイスが追加されるhotplug可能領域だと思います).
これはQEMUがhotplug可能領域にNVDIMMデバイスを指すという構成を取っているからであり,他のデバイスでは異なるのかもしれません.よく分かりません.
とりえず,NVDIMMの情報を取得するにはNFITを見るのが確実そうです.
(補足) Linuxでのエミュレーション
Linuxはブートオプションでmemmap=16G!16G
などとすると,LinuxはDRAMのアドレス16Gから始まる16GBの領域をPMEMの領域として管理するようになります(パラメータの詳細はこちら
*2).
これはACPI的には何も変化しておらず,あくまでLinuxがメモリの一部の領域をNVDIMMとして扱っていることになります.
このことは/sys/firmware/acpi/tables
以下にNFITがないことからも分かります.
参考文献
- ACPI Specification (v6.0以降), https://uefi.org/specifications
- Tiffany Kasanicky, Managing Persistent Memory, https://www.snia.org/sites/default/files/SDC/2017/presentations/Solid_State_Stor_NVM_PM_NVDIMM/Kasanicky_Tiffany_Managing_Persistent_Memory.pdf, SNIA SDC'17, 2017.
- hikalium, 自作OSでできる!NVDIMMのつかいかた, https://hikalium.hatenablog.jp/entry/2018/12/17/234735, 2018.