Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dmi #8

Merged
merged 9 commits into from
Mar 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cmd/dmidecode/testdata/Gigabyte-GA-MA74GMT-S2.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,10 @@ Base Board Information
Product Name: GA-MA74GMT-S2
Version: x.x
Serial Number:
Asset Tag:
Asset Tag: Not Specified
Features:

Location In Chassis:
Location In Chassis: Not Specified
Chassis Handle: 0x0000
Type: 0x0
Contained Object Handles: 0
Expand Down
13 changes: 13 additions & 0 deletions dmidecode/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,24 @@ package dmidecode

import (
"bytes"
"errors"
"fmt"

"github.com/u-root/smbios"
)

// Errors parsing tables.
var (
ErrUnexpectedTableType = errors.New("unexpected table type")
)

func smbiosStr(s string) string {
if s == "" {
return "Not Specified"
}
return s
}

const (
outOfSpec = "<OUT OF SPEC>"
)
Expand Down
39 changes: 39 additions & 0 deletions dmidecode/struct_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,47 @@
return off, fmt.Errorf("failed to parse %s.%s: %s", svtn, f.Name, verr)
}
}

if complete && i < sv.NumField() {
return off, fmt.Errorf("%s incomplete, got %d of %d fields", svtn, i, sv.NumField())
}

// Fill in defaults
for ; i < sv.NumField(); i++ {
f := sv.Type().Field(i)
fv := sv.Field(i)
ft := fv.Type()
tags := f.Tag.Get(fieldTagKey)
// fmt.Printf("XX %02Xh f %s t %s k %s %s\n", off, f.Name, f.Type.Name(), fv.Kind(), tags)
// Check tags first
ignore := false
var defValue uint64
for _, tag := range strings.Split(tags, ",") {
tp := strings.Split(tag, "=")
switch tp[0] {
case "-":
ignore = true
case "skip":
numBytes, _ := strconv.Atoi(tp[1])
off += numBytes
case "default":
defValue, _ = strconv.ParseUint(tp[1], 0, 64)
}
}
if ignore {
continue
}
switch fv.Kind() {
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
fv.SetUint(defValue)
off += int(ft.Size())
case reflect.Struct:
off, err := parseStruct(t, off, false /* complete */, fv)
if err != nil {
return off, err

Check warning on line 144 in dmidecode/struct_parser.go

View check run for this annotation

Codecov / codecov/patch

dmidecode/struct_parser.go#L144

Added line #L144 was not covered by tests
}
}
}

return off, nil
}
70 changes: 59 additions & 11 deletions dmidecode/struct_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"encoding/binary"
"errors"
"fmt"
"reflect"
"strings"
"testing"

Expand Down Expand Up @@ -52,20 +53,67 @@ func TestParseStructUnsupported(t *testing.T) {
}
}

func TestParseStructSupported(t *testing.T) {
buffer := []byte{
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
func TestParseStruct(t *testing.T) {
type foobar struct {
Foo uint8 `smbios:"default=0xe"`
}
table := smbios.Table{
Data: buffer,
}
unknownType := &UnknownTypes{
Table: table,
type someStruct struct {
Off0 uint64
Off8 uint8
Off9 string
_ uint8 `smbios:"-"`
Off10 uint16
Off14 uint8 `smbios:"skip=2"`
_ uint8 `smbios:"-"`
Off15 uint8 `smbios:"skip=2,default=0x1"`
Off17 uint8 `smbios:"default=0xf"`
Off18 foobar
}

off, err := parseStruct(&table, 0, false, unknownType)
if err != nil {
t.Errorf("TestParseStructUnsupported : parseStruct() = %d, '%v' want: 'nil'", off, err)
for _, tt := range []struct {
table *smbios.Table
value any
err error
want any
}{
{
table: &smbios.Table{
Data: []byte{
0x1, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
0xff, // Off8
0x1, // Off9
0x2, 0x1, // Off10
0xff, 0xff, // skipped
0x5, // Off14
},
Strings: []string{
"foobar",
},
},
value: &someStruct{},
want: &someStruct{
Off0: 0x01,
Off8: 0xff,
Off9: "foobar",
Off10: 0x102,
Off14: 0x05,
Off15: 0x1,
Off17: 0x0f,
Off18: foobar{
Foo: 0xe,
},
},
},
} {
t.Run("", func(t *testing.T) {
if _, err := parseStruct(tt.table, 0, false, tt.value); !errors.Is(err, tt.err) {
t.Errorf("parseStruct = %v, want %v", err, tt.err)
}
if !reflect.DeepEqual(tt.value, tt.want) {
t.Errorf("parseStruct = %v, want %v", tt.value, tt.want)
}
})
}
}

Expand Down
79 changes: 36 additions & 43 deletions dmidecode/type0_bios_information.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,64 +5,57 @@
package dmidecode

import (
"errors"
"fmt"
"io"
"strings"

"github.com/u-root/smbios"
)

// Much of this is auto-generated. If adding a new type, see README for instructions.

// BIOSInfo is Defined in DSP0134 7.1.
// BIOSInfo is defined in DSP0134 7.1.
type BIOSInfo struct {
smbios.Table
Vendor string // 04h
Version string // 05h
StartingAddressSegment uint16 // 06h
ReleaseDate string // 08h
ROMSize uint8 // 09h
Characteristics BIOSChars // 0Ah
CharacteristicsExt1 BIOSCharsExt1 // 12h
CharacteristicsExt2 BIOSCharsExt2 // 13h
SystemBIOSMajorRelease uint8 // 14h
SystemBIOSMinorRelease uint8 // 15h
EmbeddedControllerFirmwareMajorRelease uint8 // 16h
EmbeddedControllerFirmwareMinorRelease uint8 // 17h
ExtendedROMSize uint16 // 18h
smbios.Header `smbios:"-"`
Vendor string // 04h
Version string // 05h
StartingAddressSegment uint16 // 06h
ReleaseDate string // 08h
ROMSize uint8 // 09h
Characteristics BIOSChars // 0Ah
CharacteristicsExt1 BIOSCharsExt1 // 12h
CharacteristicsExt2 BIOSCharsExt2 // 13h
BIOSMajor uint8 `smbios:"default=0xff"` // 14h
BIOSMinor uint8 `smbios:"default=0xff"` // 15h
ECMajor uint8 `smbios:"default=0xff"` // 16h
ECMinor uint8 `smbios:"default=0xff"` // 17h
ExtendedROMSize uint16 // 18h
}

// ParseBIOSInfo parses a generic Table into BIOSInfo.
func ParseBIOSInfo(t *smbios.Table) (*BIOSInfo, error) {
return parseBIOSInfo(parseStruct, t)
}

func parseBIOSInfo(parsingFunction parseStructure, t *smbios.Table) (*BIOSInfo, error) {
if t.Type != smbios.TableTypeBIOSInfo {
return nil, fmt.Errorf("invalid table type %d", t.Type)
return nil, fmt.Errorf("%w: %d", ErrUnexpectedTableType, t.Type)
}
if t.Len() < 0x12 {
return nil, errors.New("required fields missing")
return nil, fmt.Errorf("%w: BIOS info table must be at least %d bytes", io.ErrUnexpectedEOF, 0x12)
}
bi := &BIOSInfo{
Header: t.Header,
}
bi := &BIOSInfo{Table: *t}
if _, err := parsingFunction(t, 0 /* off */, false /* complete */, bi); err != nil {
if _, err := parseStruct(t, 0 /* off */, false /* complete */, bi); err != nil {
return nil, err
}
return bi, nil
}

// GetROMSizeBytes returns ROM size in bytes.
func (bi *BIOSInfo) GetROMSizeBytes() uint64 {
if bi.ROMSize != 0xff {
// ROMSizeBytes returns ROM size in bytes.
func (bi *BIOSInfo) ROMSizeBytes() uint64 {
if bi.ROMSize != 0xff || bi.ExtendedROMSize == 0 {
return 65536 * (uint64(bi.ROMSize) + 1)
}
var extSize uint64
if bi.Len() >= 0x1a {
extSize = uint64(bi.ExtendedROMSize)
} else {
extSize = 0x10 // 16 MB
}

extSize := uint64(bi.ExtendedROMSize)
unit := (extSize >> 14)

multiplier := uint64(1)
switch unit {
case 0:
Expand All @@ -76,9 +69,9 @@ func (bi *BIOSInfo) GetROMSizeBytes() uint64 {
func (bi *BIOSInfo) String() string {
lines := []string{
bi.Header.String(),
fmt.Sprintf("\tVendor: %s", bi.Vendor),
fmt.Sprintf("\tVersion: %s", bi.Version),
fmt.Sprintf("\tRelease Date: %s", bi.ReleaseDate),
fmt.Sprintf("\tVendor: %s", smbiosStr(bi.Vendor)),
fmt.Sprintf("\tVersion: %s", smbiosStr(bi.Version)),
fmt.Sprintf("\tRelease Date: %s", smbiosStr(bi.ReleaseDate)),
}
if bi.StartingAddressSegment != 0 {
lines = append(lines,
Expand All @@ -87,16 +80,16 @@ func (bi *BIOSInfo) String() string {
)
}
lines = append(lines,
fmt.Sprintf("\tROM Size: %s", kmgt(bi.GetROMSizeBytes())),
fmt.Sprintf("\tROM Size: %s", kmgt(bi.ROMSizeBytes())),
fmt.Sprintf("\tCharacteristics:\n%s", bi.Characteristics),
bi.CharacteristicsExt1.String(),
bi.CharacteristicsExt2.String(),
)
if bi.Len() >= 0x16 && bi.SystemBIOSMajorRelease != 0xff { // 2.4+
lines = append(lines, fmt.Sprintf("\tBIOS Revision: %d.%d", bi.SystemBIOSMajorRelease, bi.SystemBIOSMinorRelease))
if bi.BIOSMajor != 0xff { // 2.4+
lines = append(lines, fmt.Sprintf("\tBIOS Revision: %d.%d", bi.BIOSMajor, bi.BIOSMinor))
}
if bi.Len() >= 0x18 && bi.EmbeddedControllerFirmwareMajorRelease != 0xff {
lines = append(lines, fmt.Sprintf("\tFirmware Revision: %d.%d", bi.EmbeddedControllerFirmwareMajorRelease, bi.EmbeddedControllerFirmwareMinorRelease))
if bi.ECMajor != 0xff {
lines = append(lines, fmt.Sprintf("\tFirmware Revision: %d.%d", bi.ECMajor, bi.ECMinor))
}
return strings.Join(lines, "\n")
}
Expand Down
Loading
Loading