From 405a457d2cbd515a606f1c9c5647a12829814262 Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Thu, 30 May 2024 15:21:33 -0400 Subject: [PATCH 01/18] Add supermicro.Unmarshal() to config --- config/asrockrack.go | 5 +++++ config/dell.go | 5 +++++ config/interface.go | 1 + config/supermicro.go | 5 +++++ 4 files changed, 16 insertions(+) diff --git a/config/asrockrack.go b/config/asrockrack.go index 51c995b..347b77a 100644 --- a/config/asrockrack.go +++ b/config/asrockrack.go @@ -105,6 +105,11 @@ func (cm *asrockrackVendorConfig) Marshal() (string, error) { } } +func (cm *asrockrackVendorConfig) Unmarshal(cfgData string) (err error) { + err = xml.Unmarshal([]byte(cfgData), cm.ConfigData) + return +} + // Generic config options func (cm *asrockrackVendorConfig) EnableTPM() { diff --git a/config/dell.go b/config/dell.go index 4bfc882..42d452b 100644 --- a/config/dell.go +++ b/config/dell.go @@ -129,6 +129,11 @@ func (cm *dellVendorConfig) Marshal() (string, error) { } } +func (cm *dellVendorConfig) Unmarshal(cfgData string) (err error) { + err = xml.Unmarshal([]byte(cfgData), cm.ConfigData) + return +} + // Generic config options func (cm *dellVendorConfig) EnableTPM() { diff --git a/config/interface.go b/config/interface.go index 9684cce..e860368 100644 --- a/config/interface.go +++ b/config/interface.go @@ -12,6 +12,7 @@ type VendorConfigManager interface { Raw(name, value string, menuPath []string) Marshal() (string, error) + Unmarshal(cfgData string) (err error) } func NewVendorConfigManager(configFormat, vendorName string, vendorOptions map[string]string) (VendorConfigManager, error) { diff --git a/config/supermicro.go b/config/supermicro.go index 25fd02e..4a01362 100644 --- a/config/supermicro.go +++ b/config/supermicro.go @@ -114,6 +114,11 @@ func (cm *supermicroVendorConfig) Marshal() (string, error) { } } +func (cm *supermicroVendorConfig) Unmarshal(cfgData string) (err error) { + err = xml.Unmarshal([]byte(cfgData), cm.ConfigData) + return +} + // Generic config options func (cm *supermicroVendorConfig) EnableTPM() { From 22ec8031b8741d739bafc7952a8101034838e446 Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Mon, 3 Jun 2024 12:32:43 -0400 Subject: [PATCH 02/18] config/supermicro: Add config normalization functions --- config/asrockrack.go | 4 ++ config/dell.go | 4 ++ config/errors.go | 5 +++ config/interface.go | 1 + config/supermicro.go | 103 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 117 insertions(+) diff --git a/config/asrockrack.go b/config/asrockrack.go index 347b77a..7d1e745 100644 --- a/config/asrockrack.go +++ b/config/asrockrack.go @@ -110,6 +110,10 @@ func (cm *asrockrackVendorConfig) Unmarshal(cfgData string) (err error) { return } +func (cm *asrockrackVendorConfig) StandardConfig() (biosConfig map[string]string, err error) { + return +} + // Generic config options func (cm *asrockrackVendorConfig) EnableTPM() { diff --git a/config/dell.go b/config/dell.go index 42d452b..835abf3 100644 --- a/config/dell.go +++ b/config/dell.go @@ -134,6 +134,10 @@ func (cm *dellVendorConfig) Unmarshal(cfgData string) (err error) { return } +func (cm *dellVendorConfig) StandardConfig() (biosConfig map[string]string, err error) { + return +} + // Generic config options func (cm *dellVendorConfig) EnableTPM() { diff --git a/config/errors.go b/config/errors.go index 60dd15f..e16dfde 100644 --- a/config/errors.go +++ b/config/errors.go @@ -7,11 +7,16 @@ import ( var errUnknownConfigFormat = errors.New("unknown config format") var errUnknownVendor = errors.New("unknown/unsupported vendor") +var errUnknownSettingType = errors.New("unknown setting type") func UnknownConfigFormatError(format string) error { return fmt.Errorf("unknown config format %w : %s", errUnknownConfigFormat, format) } +func UnknownSettingType(t string) error { + return fmt.Errorf("unknown setting type %w : %s", errUnknownSettingType, t) +} + func UnknownVendorError(vendorName string) error { return fmt.Errorf("unknown/unsupported vendor %w : %s", errUnknownVendor, vendorName) } diff --git a/config/interface.go b/config/interface.go index e860368..14724aa 100644 --- a/config/interface.go +++ b/config/interface.go @@ -13,6 +13,7 @@ type VendorConfigManager interface { Raw(name, value string, menuPath []string) Marshal() (string, error) Unmarshal(cfgData string) (err error) + StandardConfig() (biosConfig map[string]string, err error) } func NewVendorConfigManager(configFormat, vendorName string, vendorOptions map[string]string) (VendorConfigManager, error) { diff --git a/config/supermicro.go b/config/supermicro.go index 4a01362..15ed013 100644 --- a/config/supermicro.go +++ b/config/supermicro.go @@ -5,6 +5,12 @@ import ( "strings" ) +const ( + // enabledValue and disabledValue are utilized for bios setting value normalization + enabledValue = "Enabled" + disabledValue = "Disabled" +) + type supermicroVendorConfig struct { ConfigFormat string ConfigData *supermicroConfig @@ -32,6 +38,7 @@ type supermicroBiosCfgSetting struct { Order string `xml:"order,attr"` SelectedOption string `xml:"selectedOption,attr"` Type string `xml:"type,attr"` + CheckedStatus string `xml:"checkedStatus,attr"` } func NewSupermicroVendorConfigManager(configFormat string, vendorOptions map[string]string) (VendorConfigManager, error) { @@ -119,6 +126,102 @@ func (cm *supermicroVendorConfig) Unmarshal(cfgData string) (err error) { return } +func (cm *supermicroVendorConfig) StandardConfig() (biosConfig map[string]string, err error) { + biosConfig = make(map[string]string) + + for _, menu := range cm.ConfigData.BiosCfg.Menus { + for _, s := range menu.Settings { + switch s.Name { + // We want to drop this list of settings + case "NewSetupPassword", "NewSysPassword", "OldSetupPassword", "OldSysPassword": + // All others get normalized + default: + var k, v string + k, v, err = normalizeSetting(s) + if err != nil { + return + } + + biosConfig[k] = v + } + } + } + + return +} + +func normalizeSetting(s *supermicroBiosCfgSetting) (k, v string, err error) { + switch s.Type { + case "CheckBox": + k = normalizeName(s.Name) + v = normalizeValue(k, s.CheckedStatus) + return + case "Option": + k = normalizeName(s.Name) + v = normalizeValue(k, s.SelectedOption) + return + default: + err = UnknownSettingType(s.Type) + return + } +} + +func normalizeName(name string) string { + switch name { + case "CpuMinSevAsid": + return "amd_sev" + case "BootMode", "Boot mode select": + return "boot_mode" + case "IntelTxt": + return "intel_txt" + case "Software Guard Extensions (SGX)": + return "intel_sgx" + case "SecureBoot", "Secure Boot": + return "secure_boot" + case "Hyper-Threading", "Hyper-Threading [ALL]", "LogicalProc": + return "smt" + case "SriovGlobalEnable": + return "sr_iov" + case "TpmSecurity", "Security Device Support": + return "tpm" + default: + // When we don't normalize the value append "raw:" to the value + return "raw:" + name + } +} + +func normalizeBootMode(v string) string { + switch strings.ToLower(v) { + case "legacy": + return "BIOS" + default: + return strings.ToUpper(v) + } +} + +func normalizeValue(k, v string) string { + if k == "boot_mode" { + return normalizeBootMode(v) + } + + switch strings.ToLower(v) { + case "disable": + return disabledValue + case "disabled": + return disabledValue + case "enable": + return enabledValue + case "enabled": + return enabledValue + case "off": + return disabledValue + case "on": + return enabledValue + default: + return v + } +} + // Generic config options func (cm *supermicroVendorConfig) EnableTPM() { From d7c52783cf3aee9fd9dc9fdeacd3d85e30ce0c1c Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Mon, 3 Jun 2024 12:55:16 -0400 Subject: [PATCH 03/18] config/supermicro: Enforce ISO-8859-1/UTF-8 XML decoding --- config/supermicro.go | 35 +++++++++++++++++++++++++++-------- go.mod | 4 ++++ go.sum | 4 ++++ 3 files changed, 35 insertions(+), 8 deletions(-) create mode 100644 go.sum diff --git a/config/supermicro.go b/config/supermicro.go index 15ed013..b737446 100644 --- a/config/supermicro.go +++ b/config/supermicro.go @@ -1,8 +1,11 @@ package config import ( + "bytes" "encoding/xml" "strings" + + "golang.org/x/net/html/charset" ) const ( @@ -34,11 +37,12 @@ type supermicroBiosCfgMenu struct { type supermicroBiosCfgSetting struct { XMLName xml.Name `xml:"Setting"` - Name string `xml:"Name,attr"` + Name string `xml:"name,attr"` Order string `xml:"order,attr"` SelectedOption string `xml:"selectedOption,attr"` Type string `xml:"type,attr"` CheckedStatus string `xml:"checkedStatus,attr"` + NumericValue string `xml:"numericValue,attr"` } func NewSupermicroVendorConfigManager(configFormat string, vendorOptions map[string]string) (VendorConfigManager, error) { @@ -122,7 +126,16 @@ func (cm *supermicroVendorConfig) Marshal() (string, error) { } func (cm *supermicroVendorConfig) Unmarshal(cfgData string) (err error) { - err = xml.Unmarshal([]byte(cfgData), cm.ConfigData) + // the xml exported by sum is ISO-8859-1 encoded + decoder := xml.NewDecoder(bytes.NewReader([]byte(cfgData))) + // convert characters from non-UTF-8 to UTF-8 + decoder.CharsetReader = charset.NewReaderLabel + + err = decoder.Decode(cm.ConfigData.BiosCfg) + if err != nil { + return err + } + return } @@ -155,19 +168,25 @@ func normalizeSetting(s *supermicroBiosCfgSetting) (k, v string, err error) { case "CheckBox": k = normalizeName(s.Name) v = normalizeValue(k, s.CheckedStatus) - return case "Option": k = normalizeName(s.Name) v = normalizeValue(k, s.SelectedOption) - return + case "Password": + k = normalizeName(s.Name) + v = "" + case "Numeric": + k = normalizeName(s.Name) + v = normalizeValue(k, s.NumericValue) default: err = UnknownSettingType(s.Type) return } + + return } -func normalizeName(name string) string { - switch name { +func normalizeName(k string) string { + switch k { case "CpuMinSevAsid": return "amd_sev" case "BootMode", "Boot mode select": @@ -185,8 +204,8 @@ func normalizeName(name string) string { case "TpmSecurity", "Security Device Support": return "tpm" default: - // When we don't normalize the value append "raw:" to the value - return "raw:" + name + // When we don't normalize the key prepend "raw:" + return "raw:" + k } } diff --git a/go.mod b/go.mod index 385b3f2..a488a90 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,7 @@ module github.com/bmc-toolbox/common go 1.17 + +require golang.org/x/net v0.25.0 + +require golang.org/x/text v0.15.0 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..7cb371d --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= From 3400aa0c939305eaf787055313c52e5e1efb567c Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Wed, 5 Jun 2024 10:39:28 -0400 Subject: [PATCH 04/18] FS-1123: Enable line numbering for lint in GHA --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 78b448f..4c358a6 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -18,5 +18,5 @@ jobs: - name: Run golangci-lint uses: golangci/golangci-lint-action@v3 with: - args: -v --config .golangci.yml --timeout=5m + args: -v --config .golangci.yml --timeout=5m --out-format=colored-line-number version: latest From e4d8a1ea822da7e44d8a5dbb44f6ad97b4059186 Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Wed, 5 Jun 2024 10:49:21 -0400 Subject: [PATCH 05/18] FS-1123: Uncuddle my if --- config/supermicro.go | 1 + 1 file changed, 1 insertion(+) diff --git a/config/supermicro.go b/config/supermicro.go index b737446..d0827cc 100644 --- a/config/supermicro.go +++ b/config/supermicro.go @@ -151,6 +151,7 @@ func (cm *supermicroVendorConfig) StandardConfig() (biosConfig map[string]string default: var k, v string k, v, err = normalizeSetting(s) + if err != nil { return } From a070a211ea912544326159ff23215d6f0e0235c1 Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Wed, 5 Jun 2024 19:53:53 -0400 Subject: [PATCH 06/18] FS-1123: Flesh out generic config options for supermicro a bit --- config/errors.go | 11 ++++++ config/supermicro.go | 88 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 94 insertions(+), 5 deletions(-) diff --git a/config/errors.go b/config/errors.go index e16dfde..62285b1 100644 --- a/config/errors.go +++ b/config/errors.go @@ -9,6 +9,9 @@ var errUnknownConfigFormat = errors.New("unknown config format") var errUnknownVendor = errors.New("unknown/unsupported vendor") var errUnknownSettingType = errors.New("unknown setting type") +var errInvalidBootModeOption = errors.New("invalid BootMode option ") +var errInvalidSGXOption = errors.New("invalid SGX option ") + func UnknownConfigFormatError(format string) error { return fmt.Errorf("unknown config format %w : %s", errUnknownConfigFormat, format) } @@ -20,3 +23,11 @@ func UnknownSettingType(t string) error { func UnknownVendorError(vendorName string) error { return fmt.Errorf("unknown/unsupported vendor %w : %s", errUnknownVendor, vendorName) } + +func InvalidBootModeOption(mode string) error { + return fmt.Errorf("%w : %s", errInvalidBootModeOption, mode) +} + +func InvalidSGXOption(mode string) error { + return fmt.Errorf("%w : %s", errInvalidSGXOption, mode) +} diff --git a/config/supermicro.go b/config/supermicro.go index d0827cc..c3517c9 100644 --- a/config/supermicro.go +++ b/config/supermicro.go @@ -244,11 +244,89 @@ func normalizeValue(k, v string) string { // Generic config options -func (cm *supermicroVendorConfig) EnableTPM() { - cm.Raw(" Security Device Support", "Enable", []string{"Trusted Computing"}) - cm.Raw(" SHA-1 PCR Bank", "Enabled", []string{"Trusted Computing"}) +func (cm *supermicroVendorConfig) BootMode(mode string) error { + switch strings.ToUpper(mode) { + case "LEGACY", "UEFI", "DUAL": + cm.Raw("Boot mode select", strings.ToUpper(mode), []string{"Boot"}) + default: + return InvalidBootModeOption(strings.ToUpper(mode)) + } + + return nil +} + +func (cm *supermicroVendorConfig) BootOrder(mode string) error { + switch strings.ToUpper(mode) { + case "LEGACY": + cm.Raw("Legacy Boot Option #1", "Hard Disk", []string{"Boot"}) + cm.Raw("Legacy Boot Option #2", "Network", []string{"Boot"}) + for i := 3; i < 8; i++ { + cm.Raw("Legacy Boot Option #"+string(i), "Disabled", []string{"Boot"}) + } + case "UEFI": + cm.Raw("UEFI Boot Option #1", "UEFI Hard Disk", []string{"Boot"}) + cm.Raw("UEFI Boot Option #2", "UEFI Network", []string{"Boot"}) + for i := 3; i < 9; i++ { + cm.Raw("UEFI Boot Option #"+string(i), "Disabled", []string{"Boot"}) + } + case "DUAL": + // TODO(jwb) Is this just both sets? + default: + return InvalidBootModeOption(strings.ToUpper(mode)) + } + + return nil +} + +func (cm *supermicroVendorConfig) IntelSGX(mode string) error { + switch mode { + case "Disabled", "Enabled", "Software Controlled": + // TODO(jwb) Path needs to be determined. + cm.Raw("Software Guard Extensions (SGX)", mode, []string{"Advanced", "PCIe/PCI/PnP Configuration"}) + default: + return InvalidSGXOption(mode) + } + + return nil +} + +func (cm *supermicroVendorConfig) SecureBoot(enable bool) error { + if enable { + cm.Raw("Secure Boot", "Enabled", []string{"SMC Secure Boot Configuration"}) + // cm.Raw("Secure Boot Mode", "Setup", []string{"SMC Secure Boot Configuration"}) + } else { + cm.Raw("Secure Boot", "Disabled", []string{"SMC Secure Boot Configuration"}) + } + + return nil +} + +func (cm *supermicroVendorConfig) TPM(enable bool) error { + if enable { + // Note, this is actually 'Enable' not 'Enabled' like everything else. + cm.Raw(" Security Device Support", "Enable", []string{"Trusted Computing"}) + cm.Raw(" SHA-1 PCR Bank", "Enabled", []string{"Trusted Computing"}) + } else { + // Note, this is actually 'Disable' not 'Disabled' like everything else. + cm.Raw(" Security Device Support", "Disable", []string{"Trusted Computing"}) + cm.Raw(" SHA-1 PCR Bank", "Disabled", []string{"Trusted Computing"}) + } + + return nil } -func (cm *supermicroVendorConfig) EnableSRIOV() { - cm.Raw("SR-IOV Support", "Enabled", []string{"Advanced", "PCIe/PCI/PnP Configuration"}) +func (cm *supermicroVendorConfig) SMT(enable bool) error { + if enable { + cm.Raw("Hyper-Threading", "Enabled", []string{"Advanced", "CPU Configuration"}) + } else { + cm.Raw("Hyper-Threading", "Disabled", []string{"Advanced", "CPU Configuration"}) + } + + return nil +} + +func (cm *supermicroVendorConfig) SRIOV(enable bool) error { + // TODO(jwb) Need to figure out how we do this on platforms that support it... + + return nil } From cfd9f1a6c4ad3253e074a34bca4e2aa7f2463eab Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Wed, 5 Jun 2024 19:56:04 -0400 Subject: [PATCH 07/18] FS-1123: Add generic configuration functions to interface --- config/interface.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/config/interface.go b/config/interface.go index 14724aa..9865422 100644 --- a/config/interface.go +++ b/config/interface.go @@ -7,13 +7,18 @@ import ( ) type VendorConfigManager interface { - EnableTPM() - EnableSRIOV() - Raw(name, value string, menuPath []string) Marshal() (string, error) Unmarshal(cfgData string) (err error) StandardConfig() (biosConfig map[string]string, err error) + + BootMode(mode string) error + BootOrder(mode string) error + IntelSGX(mode string) error + SecureBoot(enable bool) error + TPM(enable bool) error + SMT(enable bool) error + SRIOV(enable bool) error } func NewVendorConfigManager(configFormat, vendorName string, vendorOptions map[string]string) (VendorConfigManager, error) { From 9b517fc514a4e10127b267bc2814ab308e058ef7 Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Thu, 18 Jul 2024 07:30:05 -0400 Subject: [PATCH 08/18] config/asrockrack.go: Explicitly return err from Unmarshal() --- config/asrockrack.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/config/asrockrack.go b/config/asrockrack.go index 7d1e745..5ec782f 100644 --- a/config/asrockrack.go +++ b/config/asrockrack.go @@ -105,9 +105,8 @@ func (cm *asrockrackVendorConfig) Marshal() (string, error) { } } -func (cm *asrockrackVendorConfig) Unmarshal(cfgData string) (err error) { - err = xml.Unmarshal([]byte(cfgData), cm.ConfigData) - return +func (cm *asrockrackVendorConfig) Unmarshal(cfgData string) error { + return xml.Unmarshal([]byte(cfgData), cm.ConfigData) } func (cm *asrockrackVendorConfig) StandardConfig() (biosConfig map[string]string, err error) { From bd1910e6cf690bced948cd47f178ba79c385cfc8 Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Thu, 18 Jul 2024 07:31:10 -0400 Subject: [PATCH 09/18] config/dell.go: Explicitly return err from Unmarshal() --- config/dell.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/config/dell.go b/config/dell.go index 835abf3..2a83b0b 100644 --- a/config/dell.go +++ b/config/dell.go @@ -129,9 +129,8 @@ func (cm *dellVendorConfig) Marshal() (string, error) { } } -func (cm *dellVendorConfig) Unmarshal(cfgData string) (err error) { - err = xml.Unmarshal([]byte(cfgData), cm.ConfigData) - return +func (cm *dellVendorConfig) Unmarshal(cfgData string) error { + return xml.Unmarshal([]byte(cfgData), cm.ConfigData) } func (cm *dellVendorConfig) StandardConfig() (biosConfig map[string]string, err error) { From dc11699d88960531be04dfa9dccfb849369873a0 Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Thu, 18 Jul 2024 07:33:28 -0400 Subject: [PATCH 10/18] config/supermicro.go: Implement Menu/Setting finder functions --- config/supermicro.go | 74 +++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 38 deletions(-) diff --git a/config/supermicro.go b/config/supermicro.go index c3517c9..4dee2f9 100644 --- a/config/supermicro.go +++ b/config/supermicro.go @@ -62,53 +62,51 @@ func NewSupermicroVendorConfigManager(configFormat string, vendorOptions map[str return supermicro, nil } -// FindMenu locates an existing SupermicroBiosCfgMenu if one exists in the ConfigData, if not -// it creates one and returns a pointer to that. -func (cm *supermicroVendorConfig) FindMenu(menuName string, menuRoot *supermicroBiosCfgMenu) (m *supermicroBiosCfgMenu) { - // root is cm.ConfigData.BiosCfg.Menus - for _, m = range menuRoot.Menus { - if m.Name == menuName { - return +// Function to find or create a setting by path +func (cm *supermicroVendorConfig) FindOrCreateSetting(path []string, value string) *supermicroBiosCfgSetting { + biosCfg := cm.ConfigData.BiosCfg + + var currentMenus *[]*supermicroBiosCfgMenu = &biosCfg.Menus + + for i, part := range path { + if i == len(path)-1 { + // Last part, create or find the setting + for j := range *currentMenus { + for k := range (*currentMenus)[j].Settings { + if (*currentMenus)[j].Settings[k].Name == part { + return (*currentMenus)[j].Settings[k] + } + } + + newSetting := &supermicroBiosCfgSetting{Name: part, SelectedOption: value} + (*currentMenus)[j].Settings = append((*currentMenus)[j].Settings, newSetting) + return (*currentMenus)[j].Settings[len((*currentMenus)[j].Settings)-1] + } + } else { + // Intermediate part, find or create the menu + currentMenu := cm.FindOrCreateMenu(currentMenus, part) + currentMenus = ¤tMenu.Menus } } - - m.Name = menuName - - menuRoot.Menus = append(menuRoot.Menus, m) - - return + return nil } -// FindMenuSetting locates an existing SupermicroBiosCfgSetting if one exists in the -// ConfigData, if not it creates one and returns a pointer to that. -func (cm *supermicroVendorConfig) FindMenuSetting(m *supermicroBiosCfgMenu, name string) (s *supermicroBiosCfgSetting) { - for _, s = range m.Settings { - if s.Name == name { - return +// Function to find or create a menu by name +func (cm *supermicroVendorConfig) FindOrCreateMenu(menus *[]*supermicroBiosCfgMenu, name string) *supermicroBiosCfgMenu { + for i := range *menus { + if (*menus)[i].Name == name { + return (*menus)[i] } } - - s.Name = name - - m.Settings = append(m.Settings, s) - - return + newMenu := &supermicroBiosCfgMenu{Name: name} + *menus = append(*menus, newMenu) + return (*menus)[len(*menus)-1] } func (cm *supermicroVendorConfig) Raw(name, value string, menuPath []string) { - menus := make([]*supermicroBiosCfgMenu, 0, len(menuPath)) + menuPath = append(menuPath, name) - for i, name := range menuPath { - var m *supermicroBiosCfgMenu - - if i == 0 { - m = cm.FindMenu(name, cm.ConfigData.BiosCfg.Menus[0]) - } else { - m = cm.FindMenu(name, menus[i-1]) - } - - menus = append(menus, m) - } + _ = cm.FindOrCreateSetting(menuPath, value) } func (cm *supermicroVendorConfig) Marshal() (string, error) { @@ -161,7 +159,7 @@ func (cm *supermicroVendorConfig) StandardConfig() (biosConfig map[string]string } } - return + return biosConfig, err } func normalizeSetting(s *supermicroBiosCfgSetting) (k, v string, err error) { From 48975f669972e992fb39754277d59ec1887e3cc3 Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Thu, 18 Jul 2024 07:33:52 -0400 Subject: [PATCH 11/18] config/asrockrack.go, config/dell.go: Use explict returns --- config/asrockrack.go | 2 +- config/dell.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/asrockrack.go b/config/asrockrack.go index 5ec782f..f44b6a7 100644 --- a/config/asrockrack.go +++ b/config/asrockrack.go @@ -110,7 +110,7 @@ func (cm *asrockrackVendorConfig) Unmarshal(cfgData string) error { } func (cm *asrockrackVendorConfig) StandardConfig() (biosConfig map[string]string, err error) { - return + return biosConfig, err } // Generic config options diff --git a/config/dell.go b/config/dell.go index 2a83b0b..fb2ed6f 100644 --- a/config/dell.go +++ b/config/dell.go @@ -134,7 +134,7 @@ func (cm *dellVendorConfig) Unmarshal(cfgData string) error { } func (cm *dellVendorConfig) StandardConfig() (biosConfig map[string]string, err error) { - return + return biosConfig, err } // Generic config options From 1eff505fb3e408b6239386a99334918aef006139 Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Thu, 18 Jul 2024 07:37:13 -0400 Subject: [PATCH 12/18] config/supermicro.go: Describe reasoning for use of for loops in BootOrder() --- config/supermicro.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/config/supermicro.go b/config/supermicro.go index 4dee2f9..0f90f10 100644 --- a/config/supermicro.go +++ b/config/supermicro.go @@ -129,12 +129,7 @@ func (cm *supermicroVendorConfig) Unmarshal(cfgData string) (err error) { // convert characters from non-UTF-8 to UTF-8 decoder.CharsetReader = charset.NewReaderLabel - err = decoder.Decode(cm.ConfigData.BiosCfg) - if err != nil { - return err - } - - return + return decoder.Decode(cm.ConfigData.BiosCfg) } func (cm *supermicroVendorConfig) StandardConfig() (biosConfig map[string]string, err error) { @@ -254,6 +249,9 @@ func (cm *supermicroVendorConfig) BootMode(mode string) error { } func (cm *supermicroVendorConfig) BootOrder(mode string) error { + // In a supermicro config there are 8 total legacy boot options and 9 UEFI boot options + // Since we primarily care about the first two boot options we explicitly define them + // and rely on the for loop to populate the remainder as Disabled. switch strings.ToUpper(mode) { case "LEGACY": cm.Raw("Legacy Boot Option #1", "Hard Disk", []string{"Boot"}) From 4150ec455ba3cb368397dab94ae433c4be654eb2 Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Thu, 18 Jul 2024 07:40:53 -0400 Subject: [PATCH 13/18] config/asrockrack.go, config/dell.go: Add dummy Unimplemented BootOrder() functions --- config/asrockrack.go | 5 +++++ config/dell.go | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/config/asrockrack.go b/config/asrockrack.go index f44b6a7..d70580a 100644 --- a/config/asrockrack.go +++ b/config/asrockrack.go @@ -115,6 +115,11 @@ func (cm *asrockrackVendorConfig) StandardConfig() (biosConfig map[string]string // Generic config options +func (cm *asrockrackVendorConfig) BootOrder(mode string) error { + // Unimplemented + return +} + func (cm *asrockrackVendorConfig) EnableTPM() { // Unimplemented } diff --git a/config/dell.go b/config/dell.go index fb2ed6f..b1a2963 100644 --- a/config/dell.go +++ b/config/dell.go @@ -139,6 +139,11 @@ func (cm *dellVendorConfig) StandardConfig() (biosConfig map[string]string, err // Generic config options +func (cm *dellVendorConfig) BootOrder(mode string) error { + // Unimplemented + return +} + func (cm *dellVendorConfig) EnableTPM() { cm.Raw("EnableTPM", "Enabled", []string{"BIOS.Setup.1-1"}) } From a8e48f64fecb73e5830d0cc9fb9cf9164a860aca Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Thu, 18 Jul 2024 07:42:59 -0400 Subject: [PATCH 14/18] config/asrockrack.go, config/dell.go: Add dummy Unimplemented BootMode() functions --- config/asrockrack.go | 5 +++++ config/dell.go | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/config/asrockrack.go b/config/asrockrack.go index d70580a..ce6af9f 100644 --- a/config/asrockrack.go +++ b/config/asrockrack.go @@ -120,6 +120,11 @@ func (cm *asrockrackVendorConfig) BootOrder(mode string) error { return } +func (cm *asrockrackVendorConfig) BootMode(mode string) error { + // Unimplemented + return +} + func (cm *asrockrackVendorConfig) EnableTPM() { // Unimplemented } diff --git a/config/dell.go b/config/dell.go index b1a2963..4ce1d61 100644 --- a/config/dell.go +++ b/config/dell.go @@ -144,6 +144,11 @@ func (cm *dellVendorConfig) BootOrder(mode string) error { return } +func (cm *dellVendorConfig) BootMode(mode string) error { + // Unimplemented + return +} + func (cm *dellVendorConfig) EnableTPM() { cm.Raw("EnableTPM", "Enabled", []string{"BIOS.Setup.1-1"}) } From f23f69e83382161740ace3e7ba54dc86e2cb813d Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Thu, 18 Jul 2024 07:47:17 -0400 Subject: [PATCH 15/18] config/asrockrack.go, config/dell.go: Add dummy Unimplemented for remaining generic funcs --- config/asrockrack.go | 25 +++++++++++++++++++++++++ config/dell.go | 26 ++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/config/asrockrack.go b/config/asrockrack.go index ce6af9f..ea9ad75 100644 --- a/config/asrockrack.go +++ b/config/asrockrack.go @@ -125,6 +125,31 @@ func (cm *asrockrackVendorConfig) BootMode(mode string) error { return } +func (cm *asrockrackVendorConfig) IntelSGX(mode string) error { + // Unimplemented + return +} + +func (cm *asrockrackVendorConfig) SecureBoot(enable bool) error { + // Unimplemented + return +} + +func (cm *asrockrackVendorConfig) TPM(enable bool) error { + // Unimplemented + return +} + +func (cm *asrockrackVendorConfig) SMT(enable bool) error { + // Unimplemented + return +} + +func (cm *asrockrackVendorConfig) SRIOV(enable bool) error { + // Unimplemented + return +} + func (cm *asrockrackVendorConfig) EnableTPM() { // Unimplemented } diff --git a/config/dell.go b/config/dell.go index 4ce1d61..8344c22 100644 --- a/config/dell.go +++ b/config/dell.go @@ -149,6 +149,32 @@ func (cm *dellVendorConfig) BootMode(mode string) error { return } +func (cm *dellVendorConfig) IntelSGX(mode string) error { + // Unimplemented + return +} + +func (cm *dellVendorConfig) SecureBoot(enable bool) error { + // Unimplemented + return +} + +func (cm *dellVendorConfig) TPM(enable bool) error { + // Unimplemented + return +} + +func (cm *dellVendorConfig) SMT(enable bool) error { + // Unimplemented + return +} + +func (cm *dellVendorConfig) SRIOV(enable bool) error { + // Unimplemented + return +} + + func (cm *dellVendorConfig) EnableTPM() { cm.Raw("EnableTPM", "Enabled", []string{"BIOS.Setup.1-1"}) } From fc87035a074777b3f8e97f6345cf2747fa70bfe0 Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Thu, 18 Jul 2024 07:49:37 -0400 Subject: [PATCH 16/18] config/asrockrack.go, config/dell.go: Properly return nil for unimplemented funcs --- config/asrockrack.go | 14 +++++++------- config/dell.go | 15 +++++++-------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/config/asrockrack.go b/config/asrockrack.go index ea9ad75..64a7ac9 100644 --- a/config/asrockrack.go +++ b/config/asrockrack.go @@ -117,37 +117,37 @@ func (cm *asrockrackVendorConfig) StandardConfig() (biosConfig map[string]string func (cm *asrockrackVendorConfig) BootOrder(mode string) error { // Unimplemented - return + return nil } func (cm *asrockrackVendorConfig) BootMode(mode string) error { // Unimplemented - return + return nil } func (cm *asrockrackVendorConfig) IntelSGX(mode string) error { // Unimplemented - return + return nil } func (cm *asrockrackVendorConfig) SecureBoot(enable bool) error { // Unimplemented - return + return nil } func (cm *asrockrackVendorConfig) TPM(enable bool) error { // Unimplemented - return + return nil } func (cm *asrockrackVendorConfig) SMT(enable bool) error { // Unimplemented - return + return nil } func (cm *asrockrackVendorConfig) SRIOV(enable bool) error { // Unimplemented - return + return nil } func (cm *asrockrackVendorConfig) EnableTPM() { diff --git a/config/dell.go b/config/dell.go index 8344c22..ec0b3e7 100644 --- a/config/dell.go +++ b/config/dell.go @@ -141,40 +141,39 @@ func (cm *dellVendorConfig) StandardConfig() (biosConfig map[string]string, err func (cm *dellVendorConfig) BootOrder(mode string) error { // Unimplemented - return + return nil } func (cm *dellVendorConfig) BootMode(mode string) error { // Unimplemented - return + return nil } func (cm *dellVendorConfig) IntelSGX(mode string) error { // Unimplemented - return + return nil } func (cm *dellVendorConfig) SecureBoot(enable bool) error { // Unimplemented - return + return nil } func (cm *dellVendorConfig) TPM(enable bool) error { // Unimplemented - return + return nil } func (cm *dellVendorConfig) SMT(enable bool) error { // Unimplemented - return + return nil } func (cm *dellVendorConfig) SRIOV(enable bool) error { // Unimplemented - return + return nil } - func (cm *dellVendorConfig) EnableTPM() { cm.Raw("EnableTPM", "Enabled", []string{"BIOS.Setup.1-1"}) } From e7cce54e3a63b8ca02c549bb98f01e26d324d47a Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Thu, 18 Jul 2024 07:58:42 -0400 Subject: [PATCH 17/18] config/supermicro.go: Correcting lint --- config/supermicro.go | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/config/supermicro.go b/config/supermicro.go index 0f90f10..668ed1e 100644 --- a/config/supermicro.go +++ b/config/supermicro.go @@ -3,6 +3,7 @@ package config import ( "bytes" "encoding/xml" + "fmt" "strings" "golang.org/x/net/html/charset" @@ -66,7 +67,7 @@ func NewSupermicroVendorConfigManager(configFormat string, vendorOptions map[str func (cm *supermicroVendorConfig) FindOrCreateSetting(path []string, value string) *supermicroBiosCfgSetting { biosCfg := cm.ConfigData.BiosCfg - var currentMenus *[]*supermicroBiosCfgMenu = &biosCfg.Menus + var currentMenus = &biosCfg.Menus for i, part := range path { if i == len(path)-1 { @@ -98,8 +99,10 @@ func (cm *supermicroVendorConfig) FindOrCreateMenu(menus *[]*supermicroBiosCfgMe return (*menus)[i] } } + newMenu := &supermicroBiosCfgMenu{Name: name} *menus = append(*menus, newMenu) + return (*menus)[len(*menus)-1] } @@ -256,14 +259,16 @@ func (cm *supermicroVendorConfig) BootOrder(mode string) error { case "LEGACY": cm.Raw("Legacy Boot Option #1", "Hard Disk", []string{"Boot"}) cm.Raw("Legacy Boot Option #2", "Network", []string{"Boot"}) + for i := 3; i < 8; i++ { - cm.Raw("Legacy Boot Option #"+string(i), "Disabled", []string{"Boot"}) + cm.Raw("Legacy Boot Option #"+fmt.Sprint(i), "Disabled", []string{"Boot"}) } case "UEFI": cm.Raw("UEFI Boot Option #1", "UEFI Hard Disk", []string{"Boot"}) cm.Raw("UEFI Boot Option #2", "UEFI Network", []string{"Boot"}) + for i := 3; i < 9; i++ { - cm.Raw("UEFI Boot Option #"+string(i), "Disabled", []string{"Boot"}) + cm.Raw("UEFI Boot Option #"+fmt.Sprint(i), "Disabled", []string{"Boot"}) } case "DUAL": // TODO(jwb) Is this just both sets? @@ -287,11 +292,10 @@ func (cm *supermicroVendorConfig) IntelSGX(mode string) error { } func (cm *supermicroVendorConfig) SecureBoot(enable bool) error { - if enable { - cm.Raw("Secure Boot", "Enabled", []string{"SMC Secure Boot Configuration"}) - // cm.Raw("Secure Boot Mode", "Setup", []string{"SMC Secure Boot Configuration"}) - } else { + if !enable { cm.Raw("Secure Boot", "Disabled", []string{"SMC Secure Boot Configuration"}) + } else { + cm.Raw("Secure Boot", "Enabled", []string{"SMC Secure Boot Configuration"}) } return nil @@ -323,6 +327,5 @@ func (cm *supermicroVendorConfig) SMT(enable bool) error { func (cm *supermicroVendorConfig) SRIOV(enable bool) error { // TODO(jwb) Need to figure out how we do this on platforms that support it... - return nil } From bac336d25909fe734ff64b3c140651e037f270e2 Mon Sep 17 00:00:00 2001 From: "James W. Brinkerhoff" Date: Thu, 18 Jul 2024 09:46:08 -0400 Subject: [PATCH 18/18] config/supermicro.go: Refactor FindOrCreateSetting to avoid premature loop exit --- config/supermicro.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/config/supermicro.go b/config/supermicro.go index 668ed1e..30e7092 100644 --- a/config/supermicro.go +++ b/config/supermicro.go @@ -78,17 +78,20 @@ func (cm *supermicroVendorConfig) FindOrCreateSetting(path []string, value strin return (*currentMenus)[j].Settings[k] } } - - newSetting := &supermicroBiosCfgSetting{Name: part, SelectedOption: value} - (*currentMenus)[j].Settings = append((*currentMenus)[j].Settings, newSetting) - return (*currentMenus)[j].Settings[len((*currentMenus)[j].Settings)-1] } + + // If no setting found in any menu, create a new setting in the first menu + newSetting := supermicroBiosCfgSetting{Name: part, SelectedOption: ""} + (*currentMenus)[0].Settings = append((*currentMenus)[0].Settings, &newSetting) + + return (*currentMenus)[0].Settings[len((*currentMenus)[0].Settings)-1] } else { // Intermediate part, find or create the menu currentMenu := cm.FindOrCreateMenu(currentMenus, part) currentMenus = ¤tMenu.Menus } } + return nil }