Skip to content
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
47 changes: 47 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1236,6 +1236,53 @@ Example output from my personal workstation:
watchdog present: true
```

### TPM (Linux only)

The `ghw.TPM()` function returns a `ghw.TPMInfo` struct that contains
information about the Trusted Platform Module(s) (TPM) on the host system.

The `ghw.TPMInfo` struct contains a `Devices` field:

* `ghw.TPMInfo.Devices` is a slice of pointers to `ghw.TPMDevice` structs, one
for each TPM detected under `/sys/class/tpm`

Each `ghw.TPMDevice` struct contains multiple fields:

* `ghw.TPMDevice.ManufacturerName` is a string with the human-readable TPM
manufacturer short name (e.g. `AMD`, `IFX` for Infineon, `STM` for
STMicroelectronics)
* `ghw.TPMDevice.ManufacturerVendorID` is a string with the 16-bit TCG Vendor
ID assigned to the manufacturer, when the host exposes it (e.g. `0x1414`)
* `ghw.TPMDevice.FirmwareVersion` is a string with the TPM firmware version, if
exposed by the driver
* `ghw.TPMDevice.SpecVersion` is a string with the TCG specification version the
TPM implements (e.g. `1.2` or `2.0`)

```go
package main

import (
"fmt"

"github.com/jaypipes/ghw"
)

func main() {
tpm, err := ghw.TPM()
if err != nil {
fmt.Printf("Error getting TPM info: %v", err)
}

fmt.Printf("%v\n", tpm)
}
```

Example output from my personal workstation:

```
tpm manufacturer_name=STM manufacturer_vendor_id= firmware_version= spec_version=2.0
```

## Advanced Usage

### Disabling warning messages
Expand Down
8 changes: 8 additions & 0 deletions alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
pciaddress "github.com/jaypipes/ghw/pkg/pci/address"
"github.com/jaypipes/ghw/pkg/product"
"github.com/jaypipes/ghw/pkg/topology"
"github.com/jaypipes/ghw/pkg/tpm"
"github.com/jaypipes/ghw/pkg/usb"
"github.com/jaypipes/ghw/pkg/watchdog"
)
Expand Down Expand Up @@ -206,3 +207,10 @@ type WatchdogInfo = watchdog.Info
var (
Watchdog = watchdog.New
)

type TPMInfo = tpm.Info
type TPMDevice = tpm.Device

var (
TPM = tpm.New
)
1 change: 1 addition & 0 deletions cmd/ghwc/commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ func showAll(cmd *cobra.Command, args []string) error {
showAccelerator,
showUSB,
showWatchdog,
showTPM,
} {
err := f(cmd, args)
if err != nil {
Expand Down
43 changes: 43 additions & 0 deletions cmd/ghwc/commands/tpm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// Use and distribution licensed under the Apache license version 2.
//
// See the COPYING file in the root project directory for full text.
//

package commands

import (
"fmt"

"github.com/jaypipes/ghw"
"github.com/spf13/cobra"
)

// tpmCmd represents the `tpm` command
var tpmCmd = &cobra.Command{
Use: "tpm",
Short: "Show TPM information for the host system",
RunE: showTPM,
}

// showTPM shows TPM information for the host system.
func showTPM(cmd *cobra.Command, args []string) error {
tpm, err := ghw.TPM(cmd.Context())
if err != nil {
return fmt.Errorf("error getting TPM info: %w", err)
}

switch outputFormat {
case outputFormatHuman:
fmt.Printf("%v\n", tpm)
case outputFormatJSON:
fmt.Printf("%s\n", tpm.JSONString(pretty))
case outputFormatYAML:
fmt.Printf("%s", tpm.YAMLString())
}
return nil
}

func init() {
rootCmd.AddCommand(tpmCmd)
}
10 changes: 9 additions & 1 deletion host.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/jaypipes/ghw/pkg/pci"
"github.com/jaypipes/ghw/pkg/product"
"github.com/jaypipes/ghw/pkg/topology"
"github.com/jaypipes/ghw/pkg/tpm"
"github.com/jaypipes/ghw/pkg/usb"
"github.com/jaypipes/ghw/pkg/watchdog"
)
Expand All @@ -44,6 +45,7 @@ type HostInfo struct {
PCI *pci.Info `json:"pci"`
USB *usb.Info `json:"usb"`
Watchdog *watchdog.Info `json:"watchdog"`
TPM *tpm.Info `json:"tpm"`
}

// Host returns a pointer to a HostInfo struct that contains fields with
Expand Down Expand Up @@ -106,6 +108,10 @@ func Host(args ...any) (*HostInfo, error) {
if err != nil {
return nil, err
}
tpmInfo, err := tpm.New(ctx)
if err != nil {
return nil, err
}

return &HostInfo{
CPU: cpuInfo,
Expand All @@ -122,14 +128,15 @@ func Host(args ...any) (*HostInfo, error) {
PCI: pciInfo,
USB: usbInfo,
Watchdog: watchdogInfo,
TPM: tpmInfo,
}, nil
}

// String returns a newline-separated output of the HostInfo's component
// structs' String-ified output
func (info *HostInfo) String() string {
return fmt.Sprintf(
"%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
"%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
info.Block.String(),
info.CPU.String(),
info.GPU.String(),
Expand All @@ -144,6 +151,7 @@ func (info *HostInfo) String() string {
info.PCI.String(),
info.USB.String(),
info.Watchdog.String(),
info.TPM.String(),
)
}

Expand Down
2 changes: 2 additions & 0 deletions pkg/linuxpath/path_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ type Paths struct {
SysClassDRM string
SysClassDMI string
SysClassNet string
SysClassTPM string
SysClassWatchdog string
SysFirmwareDeviceTree string
RunUdevData string
Expand Down Expand Up @@ -105,6 +106,7 @@ func New(ctx context.Context) *Paths {
SysClassDRM: filepath.Join(chroot, roots.Sys, "class", "drm"),
SysClassDMI: filepath.Join(chroot, roots.Sys, "class", "dmi"),
SysClassNet: filepath.Join(chroot, roots.Sys, "class", "net"),
SysClassTPM: filepath.Join(chroot, roots.Sys, "class", "tpm"),
SysClassWatchdog: filepath.Join(chroot, roots.Sys, "class", "watchdog"),
SysFirmwareDeviceTree: filepath.Join(chroot, roots.Sys, "firmware", "devicetree", "base"),
RunUdevData: filepath.Join(chroot, roots.Run, "udev", "data"),
Expand Down
3 changes: 3 additions & 0 deletions pkg/snapshot/clonetree_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ func ExpectedCloneStaticContent() []string {
"/sys/devices/system/node/node*/memory*",
"/sys/devices/system/node/node*/hugepages/hugepages-*/*",
"/sys/class/watchdog/*",
"/sys/class/tpm/tpm*/caps",
"/sys/class/tpm/tpm*/tpm_version_major",
"/sys/class/tpm/tpm*/device/vendor",
}
}

Expand Down
91 changes: 91 additions & 0 deletions pkg/tpm/tpm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
//
// Use and distribution licensed under the Apache license version 2.
//
// See the COPYING file in the root project directory for full text.
//

package tpm

import (
"fmt"

"github.com/jaypipes/ghw/internal/config"
"github.com/jaypipes/ghw/pkg/marshal"
)

// Device describes a single Trusted Platform Module (TPM) present on the host
// system.
type Device struct {
// ManufacturerName is the human-readable name of the TPM manufacturer,
// decoded from the four-character short name the TPM reports (e.g. "AMD",
// "IFX" for Infineon, "STM" for STMicroelectronics).
ManufacturerName string `json:"manufacturer_name"`
// ManufacturerVendorID is the 16-bit TCG Vendor ID assigned to the TPM
// manufacturer by the Trusted Computing Group. Note that this is a
// separate namespace from the PCI vendor ID. It may be empty when the
// host only exposes the manufacturer's short name.
// See: https://trustedcomputinggroup.org/resource/vendor-id-registry/
ManufacturerVendorID string `json:"manufacturer_vendor_id"`
// SpecVersion is the TCG TPM library (specification) version the device
// implements, i.e. the ISO/IEC 11889 version, e.g. "1.2" or "2.0".
SpecVersion string `json:"spec_version"`
// FirmwareVersion is the TPM firmware version, when the host exposes it.
FirmwareVersion string `json:"firmware_version"`
Comment thread
jaypipes marked this conversation as resolved.
}

// String returns a short string describing the TPM device.
func (d *Device) String() string {
return fmt.Sprintf(
"manufacturer_name=%s manufacturer_vendor_id=%s firmware_version=%s spec_version=%s",
d.ManufacturerName, d.ManufacturerVendorID, d.FirmwareVersion, d.SpecVersion,
)
}

// Info describes the Trusted Platform Module(s) on the host system.
type Info struct {
// Devices are the TPM devices detected under /sys/class/tpm. A host can,
// in principle, expose more than one TPM device.
Devices []*Device `json:"devices"`
}

// String returns a short string with summary information about the TPM(s) on
// the host system.
func (i *Info) String() string {
switch len(i.Devices) {
case 0:
return "tpm (no devices)"
case 1:
return "tpm " + i.Devices[0].String()
default:
return fmt.Sprintf("tpm (%d devices)", len(i.Devices))
}
}

// New returns a pointer to an Info struct that contains information about
// the TPM(s) on the host system.
func New(args ...any) (*Info, error) {
ctx := config.ContextFromArgs(args...)
info := &Info{}
if err := info.load(ctx); err != nil {
return nil, err
}
return info, nil
}

// simple private struct used to encapsulate TPM information in a top-level
// "tpm" YAML/JSON map/object key
type tpmPrinter struct {
Info *Info `json:"tpm"`
}

// YAMLString returns a string with the TPM information formatted as YAML
// under a top-level "tpm:" key
func (i *Info) YAMLString() string {
return marshal.SafeYAML(tpmPrinter{i})
}

// JSONString returns a string with the TPM information formatted as JSON
// under a top-level "tpm:" key
func (i *Info) JSONString(indent bool) string {
return marshal.SafeJSON(tpmPrinter{i}, indent)
}
Loading
Loading