Skip to content

Commit

Permalink
feat: add amd-suite
Browse files Browse the repository at this point in the history
amd-suite runs AMD specific tests for:
* AMD PSB
* AMD SME
* AMD SEV
* AMD SEV-SNP

Signed-off-by: Christian Walter <[email protected]>
  • Loading branch information
walterchris committed Jan 26, 2025
1 parent 1ab9344 commit 1da4441
Show file tree
Hide file tree
Showing 5 changed files with 878 additions and 7 deletions.
4 changes: 2 additions & 2 deletions cmd/core/amd-suite/TESTPLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ Id | Group | Test | Implemented | Reference | Notes
13 | PSB | Platform Model ID is not zero | :x: | - | Should be non-zero
14 | PSB | Read BIOS Key Revision is not zero | :x: | - | Should be non zero
15 | PSB | AMD Key is disabled | :x: | - | If the AMD key is not disabled, the system will still boot AMD signed firmware
16 | PSB | Secure Debug is disabled | :x: | - | -
16 | PSB | Secure Debug is disabled | :x: | - | Should be disabled
17 | PSB | Keys are fused | :x: | - | Test checks if the customer keys have been fused by reading `Customer Key Lock` from the `PSB_STATUS` register.
18 | PSB | PSB Policy Hash | :x: | - | Check the PSB Policy Hash
18 | PSB | PSB Policy Hash | :x: | - | Check the PSB Policy Hash and print it.
19 | PSB | Revocation Status | :x: | - | Check the Revokation Status
20 | SME | SME Support | :x: | - | Test checks `0x8000001f`
21 | SME | SME Enabled | :x: | - | Test checks `MSR_AMD64_SYSCFG`
Expand Down
129 changes: 129 additions & 0 deletions cmd/core/amd-suite/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package main

import (
"fmt"
"sort"

"github.com/9elements/converged-security-suite/v2/pkg/test"
"github.com/9elements/converged-security-suite/v2/pkg/tools"
"github.com/9elements/go-linux-lowlevel-hw/pkg/hwapi"
log "github.com/sirupsen/logrus"

a "github.com/logrusorgru/aurora"
)

type context struct {
logpath string
}

var cli struct {
ExecTests execTestsCmd `cmd:"" help:"Executes tests given by test set" short:"e"`

Version versionCmd `cmd:"" help:"Prints the version of the program"`
Debug bool `help:"Enable debug mode."`
}

type versionCmd struct{}

type execTestsCmd struct {
Set string `required:"" short:"s" default:"all" help:"Select a subset, or all test that should be run"`
}

func (v *versionCmd) Run(ctx *context) error {
tools.ShowVersion(programName, gittag, gitcommit)
return nil
}

func (e *execTestsCmd) Run(ctx *context) error {
preset := &test.PreSet{}
switch e.Set {
case "general":
run("AMD General", getTests("general"), preset)
case "psb":
run("AMD PSB", getTests("psb"), preset)
case "sme":
run("AMD SME", getTests("sme"), preset)
case "sev":
run("AMD SEV", getTests("sev"), preset)
case "sevsnp":
run("AMD SEV-SNP", getTests("sevsnp"), preset)
case "all":
fmt.Println("Running all tests")
run("AMD", getTests("all"), preset)
default:
return fmt.Errorf("Unknown test set: %s", e.Set)
}

return nil
}

func getTests(group string) []*test.Test {
switch group {
case "psb":
return test.TestsAMDPSP
case "sme":
return test.TestsAMDSME
case "sev":
return test.TestsAMDSEV
case "sevsnp":
return test.TestsAMDSEVSNP
case "all":
return test.TestsAMD
default:
// For "general" or unknown groups, return just the family/model test
return []*test.Test{}
}
}

func run(testGroup string, tests []*test.Test, preset *test.PreSet) bool {
result := false

hwAPI := hwapi.GetAPI()

log.Infof("%s tests (%d tests)", a.Bold(a.Gray(20-1, testGroup).BgGray(4-1)), len(tests))
log.Info("--------------------------------------------------")
for idx := range tests {
if len(testnos) > 0 {
// SearchInt returns an index where to "insert" idx
i := sort.SearchInts(testnos, idx)
if i >= len(testnos) {
continue
}
// still here? i must be within testnos.
if testnos[i] != idx {
continue
}
}

_ = tests[idx].Run(hwAPI, preset)
}

for index := range tests {
var s string

if tests[index].Status == test.NotImplemented {
continue
}
if tests[index].Result == test.ResultNotRun {
continue
}
s += fmt.Sprintf("%02d - ", index)
s += fmt.Sprintf("%-40s: ", a.Bold(tests[index].Name))

if tests[index].Result == test.ResultPass {
s += fmt.Sprintf("%-20s", a.Bold(a.Green(tests[index].Result)))
} else {
s += fmt.Sprintf("%-20s", a.Bold(a.Red(tests[index].Result)))
result = false
}
if tests[index].ErrorText != "" {
s += fmt.Sprintf(" (%s)", tests[index].ErrorText)
} else if len(tests[index].ErrorText) == 0 && tests[index].Result == test.ResultFail {
s += " (No error text given)"
}
log.Infof("%s", s)

}

return result
}
33 changes: 33 additions & 0 deletions cmd/core/amd-suite/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package main

import (
"github.com/9elements/converged-security-suite/v2/pkg/log"
"github.com/alecthomas/kong"
fianoLog "github.com/linuxboot/fiano/pkg/log"
)

const (
programName = "amd-suite"
programDesc = "AMD PSB, SME, SEV and SEV-SNP Test Suite"
)

var (
gitcommit string
gittag string
testnos []int
)

func main() {
ctx := kong.Parse(&cli,
kong.Name(programName),
kong.Description(programDesc),
kong.UsageOnError(),
kong.ConfigureHelp(kong.HelpOptions{
Compact: true,
Summary: true,
}))

fianoLog.DefaultLogger = log.FianoLogger{}
err := ctx.Run(&context{})
ctx.FatalIfErrorf(err)
}
35 changes: 30 additions & 5 deletions pkg/hwapi/mock_pc.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ import (

type pcmock struct {
ReadMemoryFunc func(uint64) byte
cpuidResponse map[uint32]struct {
eax uint32
ebx uint32
ecx uint32
edx uint32
}
}

func (n pcmock) CPUBlacklistTXTSupport() bool {
Expand Down Expand Up @@ -41,19 +47,30 @@ func (n pcmock) HasMTRR() bool {
func (n pcmock) ProcessorBrandName() string {
return ""
}

func (n pcmock) CPUSignature() uint32 {
return 0
}

func (n pcmock) CPUSignatureFull() (uint32, uint32, uint32, uint32) {
return 0, 0, 0, 0
}

func (n pcmock) CPULogCount() uint32 {
return 0
}

func (n pcmock) CPUID(leaf uint32, subleaf uint32) (uint32, uint32, uint32, uint32) {
if response, ok := n.cpuidResponse[leaf]; ok {
return response.eax, response.ebx, response.ecx, response.edx
}
return 0, 0, 0, 0
}

func (n pcmock) IsReservedInE820(start uint64, end uint64) (bool, error) {
return false, fmt.Errorf("not implemented")
}

func (n pcmock) UsableMemoryAbove4G() (size uint64, err error) {
return 0, fmt.Errorf("not implemented")
}
Expand Down Expand Up @@ -101,6 +118,7 @@ func (n pcmock) AllowsVMXInSMX() (bool, error) {
func (n pcmock) TXTLeavesAreEnabled() (bool, error) {
return false, fmt.Errorf("not implemented")
}

func (n pcmock) IA32DebugInterfaceEnabledOrLocked() (*hwapi.IA32Debug, error) {
return nil, fmt.Errorf("not implemented")
}
Expand Down Expand Up @@ -153,10 +171,10 @@ func (n pcmock) ReadHostBridgeDPR() (hwapi.DMAProtectedRange, error) {
return hwapi.DMAProtectedRange{}, fmt.Errorf("not implemented")
}

//MockPCReadMemory emulates a x86_64 platform memory map
// MockPCReadMemory emulates a x86_64 platform memory map
func MockPCReadMemory(addr uint64) byte {
mem := map[uint64][]byte{
0xFED30000: []byte{
0xFED30000: {
0x01, 0xa7, 0x86, 0x80, 0x6b, 0xc8, 0x7b, 0x02, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Expand Down Expand Up @@ -253,7 +271,6 @@ func MockPCReadMemory(addr uint64) byte {
}

return 0xff

}

func (n pcmock) ReadPhys(addr int64, data hwapi.UintN) error {
Expand Down Expand Up @@ -299,9 +316,11 @@ func (n pcmock) NVLocked(tpmCon *hwapi.TPM) (bool, error) {
func (n pcmock) ReadNVPublic(tpmCon *hwapi.TPM, index uint32) ([]byte, error) {
return []byte{}, fmt.Errorf("not implemented")
}

func (n pcmock) NVReadValue(tpmCon *hwapi.TPM, index uint32, password string, size, offhandle uint32) ([]byte, error) {
return []byte{}, fmt.Errorf("not implemented")
}

func (n pcmock) ReadPCR(tpmCon *hwapi.TPM, pcr uint32) ([]byte, error) {
return []byte{}, fmt.Errorf("not implemented")
}
Expand Down Expand Up @@ -342,9 +361,15 @@ func (n pcmock) PCIWriteConfigSpace(d hwapi.PCIDevice, off int, val interface{})
return fmt.Errorf("not implemented")
}

//GetPcMock returns APIInterfaces for mocking the hwapi used in unittests
// GetPcMock returns APIInterfaces for mocking the hwapi used in unittests
func GetPcMock(ReadMemoryFunc func(uint64) byte) hwapi.LowLevelHardwareInterfaces {
return pcmock{
ReadMemoryFunc,
ReadMemoryFunc: ReadMemoryFunc,
cpuidResponse: make(map[uint32]struct {
eax uint32
ebx uint32
ecx uint32
edx uint32
}),
}
}
Loading

0 comments on commit 1da4441

Please sign in to comment.