git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/sysinfo/memory.go (about) 1 // Copyright © 2016 Zlatko Čalušić 2 // 3 // Use of this source code is governed by an MIT-style license that can be found in the LICENSE file. 4 5 package sysinfo 6 7 import ( 8 "bytes" 9 "encoding/binary" 10 "io/ioutil" 11 "strconv" 12 ) 13 14 // Memory information. 15 type Memory struct { 16 Type string `json:"type,omitempty"` 17 Speed uint `json:"speed,omitempty"` // RAM data rate in MT/s 18 Size uint `json:"size,omitempty"` // RAM size in MB 19 } 20 21 func word(data []byte, index int) uint16 { 22 return binary.LittleEndian.Uint16(data[index : index+2]) 23 } 24 25 func dword(data []byte, index int) uint32 { 26 return binary.LittleEndian.Uint32(data[index : index+4]) 27 } 28 29 func qword(data []byte, index int) uint64 { 30 return binary.LittleEndian.Uint64(data[index : index+8]) 31 } 32 33 func (si *SysInfo) getMemoryInfo() { 34 dmi, err := ioutil.ReadFile("/sys/firmware/dmi/tables/DMI") 35 if err != nil { 36 // Xen hypervisor 37 if targetKB := slurpFile("/sys/devices/system/xen_memory/xen_memory0/target_kb"); targetKB != "" { 38 si.Memory.Type = "DRAM" 39 size, _ := strconv.ParseUint(targetKB, 10, 64) 40 si.Memory.Size = uint(size) / 1024 41 } 42 return 43 } 44 45 si.Memory.Size = 0 46 var memSizeAlt uint 47 loop: 48 for p := 0; p < len(dmi)-1; { 49 recType := dmi[p] 50 recLen := dmi[p+1] 51 52 switch recType { 53 case 4: 54 if si.CPU.Speed == 0 { 55 si.CPU.Speed = uint(word(dmi, p+0x16)) 56 } 57 case 17: 58 size := uint(word(dmi, p+0x0c)) 59 if size == 0 || size == 0xffff || size&0x8000 == 0x8000 { 60 break 61 } 62 if size == 0x7fff { 63 if recLen >= 0x20 { 64 size = uint(dword(dmi, p+0x1c)) 65 } else { 66 break 67 } 68 } 69 70 si.Memory.Size += size 71 72 if si.Memory.Type == "" { 73 // SMBIOS Reference Specification Version 3.0.0, page 92 74 memTypes := [...]string{ 75 "Other", "Unknown", "DRAM", "EDRAM", "VRAM", "SRAM", "RAM", "ROM", "FLASH", 76 "EEPROM", "FEPROM", "EPROM", "CDRAM", "3DRAM", "SDRAM", "SGRAM", "RDRAM", 77 "DDR", "DDR2", "DDR2 FB-DIMM", "Reserved", "Reserved", "Reserved", "DDR3", 78 "FBD2", "DDR4", "LPDDR", "LPDDR2", "LPDDR3", "LPDDR4", 79 } 80 81 if index := int(dmi[p+0x12]); index >= 1 && index <= len(memTypes) { 82 si.Memory.Type = memTypes[index-1] 83 } 84 } 85 86 if si.Memory.Speed == 0 && recLen >= 0x17 { 87 if speed := uint(word(dmi, p+0x15)); speed != 0 { 88 si.Memory.Speed = speed 89 } 90 } 91 case 19: 92 start := uint(dword(dmi, p+0x04)) 93 end := uint(dword(dmi, p+0x08)) 94 if start == 0xffffffff && end == 0xffffffff { 95 if recLen >= 0x1f { 96 start64 := qword(dmi, p+0x0f) 97 end64 := qword(dmi, p+0x17) 98 memSizeAlt += uint((end64 - start64 + 1) / 1048576) 99 } 100 } else { 101 memSizeAlt += (end - start + 1) / 1024 102 } 103 case 127: 104 break loop 105 } 106 107 for p += int(recLen); p < len(dmi)-1; { 108 if bytes.Equal(dmi[p:p+2], []byte{0, 0}) { 109 p += 2 110 break 111 } 112 p++ 113 } 114 } 115 116 // Sometimes DMI type 17 has no information, so we fall back to DMI type 19, to at least get the RAM size. 117 if si.Memory.Size == 0 && memSizeAlt > 0 { 118 si.Memory.Type = "DRAM" 119 si.Memory.Size = memSizeAlt 120 } 121 }