Skip to content

Commit aef6141

Browse files
authored
Merge pull request #145 from deeglaze/kdsworkaround
Extend v3 support to KDS and change proto representation
2 parents 64cd695 + 9af2767 commit aef6141

File tree

18 files changed

+784
-270
lines changed

18 files changed

+784
-270
lines changed

abi/abi.go

Lines changed: 82 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,17 @@ const (
117117
ExtraPlatformInfoV0Size = 8
118118

119119
// CpuidProductMask keeps only the SevProduct-relevant bits from the CPUID(1).EAX result.
120-
CpuidProductMask = 0x0fff0f0f
120+
CpuidProductMask = 0x0fff0fff
121121
extendedFamilyShift = 20
122122
extendedModelShift = 16
123123
familyShift = 8
124-
sevExtendedFamily = 0xA
125-
sevFamily = 0xF
126-
milanExtendedModel = 0
127-
genoaExtendedModel = 1
124+
modelShift = 4
125+
// Combined extended values
126+
zen3zen4Family = 0x19
127+
zen5Family = 0x1A
128+
milanModel = 0 | 1
129+
genoaModel = (1 << 4) | 1
130+
turinModel = 2
128131

129132
// ReportVersion2 is set by the SNP API specification
130133
// https://web.archive.org/web/20231222054111if_/http://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/specifications/56860.pdf
@@ -487,9 +490,7 @@ func ReportToProto(data []uint8) (*pb.Report, error) {
487490
mbzLo := 0x188
488491
if r.Version == ReportVersion3 {
489492
mbzLo = 0x18B
490-
r.CpuidFamId = []byte{data[0x188]}
491-
r.CpuidModId = []byte{data[0x189]}
492-
r.CpuidStep = []byte{data[0x18A]}
493+
r.Cpuid1EaxFms = FmsToCpuid1Eax(data[0x188], data[0x189], data[0x18A])
493494
}
494495

495496
if err := mbz(data, mbzLo, 0x1A0); err != nil {
@@ -635,9 +636,10 @@ func ReportToAbiBytes(r *pb.Report) ([]byte, error) {
635636

636637
// Add CPUID information if this is a version 3 report.
637638
if r.Version == ReportVersion3 {
638-
data[0x188] = r.CpuidFamId[0]
639-
data[0x189] = r.CpuidModId[0]
640-
data[0x18A] = r.CpuidStep[0]
639+
family, model, stepping := FmsFromCpuid1Eax(r.Cpuid1EaxFms)
640+
data[0x188] = family
641+
data[0x189] = model
642+
data[0x18A] = stepping
641643
}
642644

643645
copy(data[0x1A0:0x1E0], r.ChipId[:])
@@ -903,59 +905,106 @@ func (c *CertTable) Proto() *pb.CertificateChain {
903905
// See assembly implementations in cpuid_*.s
904906
var cpuid func(op uint32) (eax, ebx, ecx, edx uint32)
905907

906-
// SevProductFromCpuid1Eax returns the SevProduct that is represented by cpuid(1).eax.
907-
func SevProductFromCpuid1Eax(eax uint32) *pb.SevProduct {
908+
// FmsToCpuid1Eax returns the masked CPUID_1_EAX value that represents the given
909+
// family, model, stepping (FMS) values.
910+
func FmsToCpuid1Eax(family, model, stepping byte) uint32 {
911+
var extendedFamily byte
912+
913+
familyID := family
914+
if family >= 0xf {
915+
extendedFamily = family - 0xf
916+
familyID = 0xf
917+
}
918+
extendedModel := model >> 4
919+
modelID := model & 0xf
920+
return (uint32(extendedFamily) << extendedFamilyShift) |
921+
(uint32(extendedModel) << extendedModelShift) |
922+
(uint32(familyID) << familyShift) |
923+
(uint32(modelID) << modelShift) |
924+
(uint32(stepping & 0xf))
925+
}
926+
927+
// FmsFromCpuid1Eax returns the family, model, stepping (FMS) values extracted from a
928+
// CPUID_1_EAX value.
929+
func FmsFromCpuid1Eax(eax uint32) (byte, byte, byte) {
908930
// 31:28 reserved
909931
// 27:20 Extended Family ID
910-
extendedFamily := (eax >> extendedFamilyShift) & 0xff
932+
extendedFamily := byte((eax >> extendedFamilyShift) & 0xff)
911933
// 19:16 Extended Model ID
912-
extendedModel := (eax >> extendedModelShift) & 0xf
934+
extendedModel := byte((eax >> extendedModelShift) & 0xf)
913935
// 15:14 reserved
914936
// 11:8 Family ID
915-
family := (eax >> familyShift) & 0xf
937+
familyID := byte((eax >> familyShift) & 0xf)
938+
// 7:4 Model
939+
modelID := byte((eax >> modelShift) & 0xf)
916940
// 3:0 Stepping
917-
stepping := eax & 0xf
941+
family := extendedFamily + familyID
942+
model := (extendedModel << 4) | modelID
943+
stepping := byte(eax & 0xf)
944+
return family, model, stepping
945+
}
946+
947+
// SevProductFromCpuid1Eax returns the SevProduct that is represented by cpuid(1).eax.
948+
func SevProductFromCpuid1Eax(eax uint32) *pb.SevProduct {
949+
family, model, stepping := FmsFromCpuid1Eax(eax)
918950
// Ah, Fh, {0h,1h} values from the KDS specification,
919951
// section "Determining the Product Name".
920952
var productName pb.SevProduct_SevProductName
953+
unknown := func() {
954+
productName = pb.SevProduct_SEV_PRODUCT_UNKNOWN
955+
stepping = 0 // Reveal nothing.
956+
}
921957
// Product information specified by processor programming reference publications.
922-
if extendedFamily == sevExtendedFamily && family == sevFamily {
923-
switch extendedModel {
924-
case milanExtendedModel:
958+
switch family {
959+
case zen3zen4Family:
960+
switch model {
961+
case milanModel:
925962
productName = pb.SevProduct_SEV_PRODUCT_MILAN
926-
case genoaExtendedModel:
963+
case genoaModel:
927964
productName = pb.SevProduct_SEV_PRODUCT_GENOA
928965
default:
929-
productName = pb.SevProduct_SEV_PRODUCT_UNKNOWN
930-
stepping = 0 // Reveal nothing.
966+
unknown()
967+
}
968+
case zen5Family:
969+
switch model {
970+
case turinModel:
971+
productName = pb.SevProduct_SEV_PRODUCT_TURIN
972+
default:
973+
unknown()
931974
}
975+
default:
976+
unknown()
932977
}
933978
return &pb.SevProduct{
934979
Name: productName,
935-
MachineStepping: &wrapperspb.UInt32Value{Value: stepping},
980+
MachineStepping: &wrapperspb.UInt32Value{Value: uint32(stepping)},
936981
}
937982
}
938983

939984
// MaskedCpuid1EaxFromSevProduct returns the Cpuid1Eax value expected from the given product
940985
// when masked with CpuidProductMask.
941986
func MaskedCpuid1EaxFromSevProduct(product *pb.SevProduct) uint32 {
942-
var stepping uint32
987+
if product == nil {
988+
return 0
989+
}
990+
var family, model, stepping byte
943991
if product.MachineStepping != nil {
944-
stepping = product.MachineStepping.Value & 0xf
992+
stepping = byte(product.MachineStepping.Value & 0xf)
945993
}
946-
extendedFamily := uint32(sevExtendedFamily) << extendedFamilyShift
947-
family := uint32(sevFamily) << familyShift
948-
949-
var extendedModel uint32
950994
switch product.Name {
951995
case pb.SevProduct_SEV_PRODUCT_MILAN:
952-
extendedModel = milanExtendedModel
996+
family = zen3zen4Family
997+
model = milanModel
953998
case pb.SevProduct_SEV_PRODUCT_GENOA:
954-
extendedModel = genoaExtendedModel
999+
family = zen3zen4Family
1000+
model = genoaModel
1001+
case pb.SevProduct_SEV_PRODUCT_TURIN:
1002+
family = zen5Family
1003+
model = turinModel
9551004
default:
9561005
return 0
9571006
}
958-
return extendedFamily | family | stepping | (extendedModel << extendedModelShift)
1007+
return FmsToCpuid1Eax(family, model, stepping)
9591008
}
9601009

9611010
// SevProduct returns the SEV product enum for the CPU that runs this

abi/abi_test.go

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package abi
1717
import (
1818
"bytes"
1919
"encoding/hex"
20+
"fmt"
2021
"math/rand"
2122
"runtime"
2223
"strings"
@@ -61,9 +62,7 @@ var (
6162
author_key_digest: '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
6263
report_id: '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
6364
report_id_ma: '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
64-
cpuid_fam_id: '\x00\x00'
65-
cpuid_mod_id: '\x00\x00'
66-
cpuid_step: '\x00\x00'
65+
cpuid1eax_fms: 0
6766
chip_id: '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
6867
signature: '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
6968
`
@@ -396,17 +395,26 @@ func TestSevProduct(t *testing.T) {
396395
MachineStepping: &wrapperspb.UInt32Value{Value: 0},
397396
},
398397
},
398+
{
399+
eax: 0x00b00f21,
400+
want: &spb.SevProduct{
401+
Name: spb.SevProduct_SEV_PRODUCT_TURIN,
402+
MachineStepping: &wrapperspb.UInt32Value{Value: 1},
403+
},
404+
},
399405
}
400406
for _, tc := range tcs {
401-
cpuid = func(uint32) (uint32, uint32, uint32, uint32) { return tc.eax, 0, 0, 0 }
402-
got := SevProduct()
403-
if diff := cmp.Diff(got, tc.want, protocmp.Transform()); diff != "" {
404-
t.Errorf("SevProduct() = %+v, want %+v. Diff: %s", got, tc.want, diff)
405-
}
406-
got2 := SevProductFromCpuid1Eax(tc.eax)
407-
if diff := cmp.Diff(got2, got, protocmp.Transform()); diff != "" {
408-
t.Errorf("SevProductFromCpuid1Eax(0x%x) = %+v, want %+v. Diff: %s", tc.eax, got2, tc.want, diff)
409-
}
407+
t.Run(fmt.Sprintf("EAX_0x%x", tc.eax), func(t *testing.T) {
408+
cpuid = func(uint32) (uint32, uint32, uint32, uint32) { return tc.eax, 0, 0, 0 }
409+
got := SevProduct()
410+
if diff := cmp.Diff(got, tc.want, protocmp.Transform()); diff != "" {
411+
t.Errorf("SevProduct() = %+v, want %+v. Diff: %s", got, tc.want, diff)
412+
}
413+
got2 := SevProductFromCpuid1Eax(tc.eax)
414+
if diff := cmp.Diff(got2, got, protocmp.Transform()); diff != "" {
415+
t.Errorf("SevProductFromCpuid1Eax(0x%x) = %+v, want %+v. Diff: %s", tc.eax, got2, tc.want, diff)
416+
}
417+
})
410418
}
411419
}
412420

@@ -446,9 +454,9 @@ func TestExtendedPlatformCertTable(t *testing.T) {
446454
eax uint32
447455
stepping uint32
448456
}{
449-
{name: "Genoa-B2 cruft", pname: spb.SevProduct_SEV_PRODUCT_GENOA, eax: 0x00a10f12, stepping: 2},
450-
{name: "Milan-B1 cruft", pname: spb.SevProduct_SEV_PRODUCT_MILAN, eax: 0x00a00f11, stepping: 1},
451-
{name: "Milan-B0", pname: spb.SevProduct_SEV_PRODUCT_MILAN, eax: 0x00a00f00, stepping: 0},
457+
{name: "Genoa-B2", pname: spb.SevProduct_SEV_PRODUCT_GENOA, eax: 0x00a10f12, stepping: 2},
458+
{name: "Milan-B1", pname: spb.SevProduct_SEV_PRODUCT_MILAN, eax: 0x00a00f11, stepping: 1},
459+
{name: "Milan-B0", pname: spb.SevProduct_SEV_PRODUCT_MILAN, eax: 0x00a00f10, stepping: 0},
452460
}
453461
for _, tc := range tcs {
454462
t.Run(tc.name, func(t *testing.T) {

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module github.com/google/go-sev-guest
33
go 1.19
44

55
require (
6+
github.com/golang/protobuf v1.5.0
67
github.com/google/go-cmp v0.5.7
78
github.com/google/go-configfs-tsm v0.2.2
89
github.com/google/logger v1.1.1

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2+
github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
3+
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
4+
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
25
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
36
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
47
github.com/google/go-configfs-tsm v0.2.2 h1:YnJ9rXIOj5BYD7/0DNnzs8AOp7UcvjfTvt215EWcs98=
@@ -18,6 +21,7 @@ golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
1821
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
1922
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
2023
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
24+
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
2125
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
2226
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
2327
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

kds/kds.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,19 @@ var (
9999
"Genoa-B0": {Name: pb.SevProduct_SEV_PRODUCT_GENOA, MachineStepping: uint0},
100100
"Genoa-B1": {Name: pb.SevProduct_SEV_PRODUCT_GENOA, MachineStepping: uint1},
101101
"Genoa-B2": {Name: pb.SevProduct_SEV_PRODUCT_GENOA, MachineStepping: uint2},
102+
"Turin-B0": {Name: pb.SevProduct_SEV_PRODUCT_TURIN, MachineStepping: uint0},
103+
"Turin-B1": {Name: pb.SevProduct_SEV_PRODUCT_TURIN, MachineStepping: uint1},
102104
}
103105
milanSteppingVersions = []string{"B0", "B1"}
104106
genoaSteppingVersions = []string{"B0", "B1", "B2"}
107+
turinSteppingVersions = []string{"B0", "B1"}
108+
109+
// ProductLineCpuid associates the CPUID_1_EAX value (Stepping 0) to its AMD product name.
110+
ProductLineCpuid = map[uint32]string{
111+
0x00a00f10: "Milan",
112+
0x00a10f10: "Genoa",
113+
0x00b00f20: "Turin",
114+
}
105115
)
106116

107117
// TCBVersion is a 64-bit bitfield of different security patch levels of AMD firmware and microcode.
@@ -731,6 +741,8 @@ func ProductLine(product *pb.SevProduct) string {
731741
return "Milan"
732742
case pb.SevProduct_SEV_PRODUCT_GENOA:
733743
return "Genoa"
744+
case pb.SevProduct_SEV_PRODUCT_TURIN:
745+
return "Turin"
734746
default:
735747
return "Unknown"
736748
}
@@ -785,12 +797,22 @@ func ProductName(product *pb.SevProduct) string {
785797
if int(stepping) >= len(genoaSteppingVersions) {
786798
return "unmappedGenoaStepping"
787799
}
788-
return fmt.Sprintf("Milan-%s", genoaSteppingVersions[stepping])
800+
return fmt.Sprintf("Genoa-%s", genoaSteppingVersions[stepping])
801+
case pb.SevProduct_SEV_PRODUCT_TURIN:
802+
if int(stepping) >= len(turinSteppingVersions) {
803+
return "unmappedTurinStepping"
804+
}
805+
return fmt.Sprintf("Turin-%s", turinSteppingVersions[stepping])
789806
default:
790807
return "Unknown"
791808
}
792809
}
793810

811+
// ProductLineFromFms returns the product name used in the KDS endpoint to fetch VCEK certificates.
812+
func ProductLineFromFms(fms uint32) string {
813+
return ProductLine(abi.SevProductFromCpuid1Eax(fms))
814+
}
815+
794816
// ParseProduct returns the SevProductName for a product name without the stepping suffix.
795817
//
796818
// Deprecated: Use ParseProductLine
@@ -809,6 +831,8 @@ func ParseProductLine(productLine string) (*pb.SevProduct, error) {
809831
return &pb.SevProduct{Name: pb.SevProduct_SEV_PRODUCT_MILAN}, nil
810832
case "Genoa":
811833
return &pb.SevProduct{Name: pb.SevProduct_SEV_PRODUCT_GENOA}, nil
834+
case "Turin":
835+
return &pb.SevProduct{Name: pb.SevProduct_SEV_PRODUCT_TURIN}, nil
812836
default:
813837
return nil, fmt.Errorf("unknown AMD SEV product: %q", productLine)
814838
}

proto/fakekds.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ message Certificates {
2626
bytes chip_id = 1; // Should be 64 bytes
2727
map<uint64, bytes> tcb_certs = 2;
2828
string hostname = 3;
29+
uint32 fms = 4;
2930
}
3031
repeated ChipTCBCerts chip_certs = 1;
3132
}

proto/fakekds/fakekds.pb.go

Lines changed: 19 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)