From 2f4c7fb74e849f67841746877da92c584cd09dfe Mon Sep 17 00:00:00 2001 From: "Brian J. Nemec" Date: Tue, 18 Feb 2020 13:23:56 -0800 Subject: Servo: Adds persistent storage of MAC address Adds a field to the persistent storage to store the MAC address of the device. This is enabled on ServoV4 in order to store the MAC address for the integrated ethernet port. Added a console command to set and load this value. BUG=b:149506580 TEST=Verified setting and loading the MAC address using: 'macaddr set 12:34:56:78:90:ab' and 'macaddr' or 'macaddr load' Verified that MAC addresses over 19 characters long return an error response and not update the MAC. Verified no set serial number will return the uninitialized string. Verified that the MAC address can be updated independently of serialno Verified that the persist_state fields restore during firmware updates Change-Id: I8425ce9e13322e99a4f59df444ea0dc73821aa6b Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2063330 Tested-by: Brian Nemec Reviewed-by: Wai-Hong Tam Commit-Queue: Brian Nemec --- board/servo_v4/board.h | 2 + chip/stm32/usb.c | 58 ++++++++++++++++++++++ common/flash.c | 131 ++++++++++++++++++++++++++++++++++++++++--------- common/system.c | 21 ++++++++ include/config.h | 10 ++++ include/flash.h | 19 +++++++ include/system.h | 13 +++++ 7 files changed, 230 insertions(+), 24 deletions(-) diff --git a/board/servo_v4/board.h b/board/servo_v4/board.h index ff46ae13e4..c2b08fa885 100644 --- a/board/servo_v4/board.h +++ b/board/servo_v4/board.h @@ -47,6 +47,8 @@ #define CONFIG_USB_SERIALNO #define DEFAULT_SERIALNO "Uninitialized" +#define CONFIG_MAC_ADDR +#define DEFAULT_MAC_ADDR "Uninitialized" /* USB interface indexes (use define rather than enum to expand them) */ #define USB_IFACE_CONSOLE 0 diff --git a/chip/stm32/usb.c b/chip/stm32/usb.c index 54cd90dd46..7eb2363787 100644 --- a/chip/stm32/usb.c +++ b/chip/stm32/usb.c @@ -897,4 +897,62 @@ static int command_serialno(int argc, char **argv) DECLARE_CONSOLE_COMMAND(serialno, command_serialno, "load/set [value]", "Read and write USB serial number"); + #endif /* CONFIG_USB_SERIALNO */ + +#ifdef CONFIG_MAC_ADDR + +/* Save MAC address into pstate region. */ +static int usb_save_mac_addr(const char *mac_addr) +{ + int rv; + + if (!mac_addr) { + return EC_ERROR_INVAL; + } + + /* Save this new MAC address to flash. */ + rv = board_write_mac_addr(mac_addr); + if (rv) { + return rv; + } + + /* Load this new MAC address to memory. */ + if (board_read_mac_addr() != NULL) { + return EC_SUCCESS; + } else { + return EC_ERROR_UNKNOWN; + } +} + +static int command_macaddr(int argc, char **argv) +{ + const char* buf; + int rv = EC_SUCCESS; + + if (argc != 1) { + if ((strcasecmp(argv[1], "set") == 0) && + (argc == 3)) { + ccprintf("Saving MAC address\n"); + rv = usb_save_mac_addr(argv[2]); + } else if ((strcasecmp(argv[1], "load") == 0) && + (argc == 2)) { + ccprintf("Loading MAC address\n"); + } else { + return EC_ERROR_INVAL; + } + } + + buf = board_read_mac_addr(); + if (buf == NULL) { + buf = DEFAULT_MAC_ADDR; + } + ccprintf("MAC address: %s\n", buf); + return rv; +} + +DECLARE_CONSOLE_COMMAND(macaddr, command_macaddr, + "load/set [value]", + "Read and write MAC address"); + +#endif /* CONFIG_MAC_ADDR */ diff --git a/common/flash.c b/common/flash.c index 4b3a5fae69..f2b871ee0f 100644 --- a/common/flash.c +++ b/common/flash.c @@ -45,8 +45,9 @@ /* Flags for persist_state.flags */ /* Protect persist state and RO firmware at boot */ #define PERSIST_FLAG_PROTECT_RO 0x02 -#define PSTATE_VALID_FLAGS BIT(0) -#define PSTATE_VALID_SERIALNO BIT(1) +#define PSTATE_VALID_FLAGS BIT(0) +#define PSTATE_VALID_SERIALNO BIT(1) +#define PSTATE_VALID_MAC_ADDR BIT(2) struct persist_state { uint8_t version; /* Version of this struct */ @@ -55,10 +56,15 @@ struct persist_state { uint8_t reserved; /* Reserved; set 0 */ #ifdef CONFIG_SERIALNO_LEN uint8_t serialno[CONFIG_SERIALNO_LEN]; /* Serial number. */ -#else +#endif /* CONFIG_SERIALNO_LEN */ +#ifdef CONFIG_MAC_ADDR_LEN + uint8_t mac_addr[CONFIG_MAC_ADDR_LEN]; +#endif /* CONFIG_MAC_ADDR_LEN */ +#if !defined(CONFIG_SERIALNO_LEN) && !defined(CONFIG_MAC_ADDR_LEN) uint8_t padding[4 % CONFIG_FLASH_WRITE_SIZE]; #endif }; + /* written with flash_physical_write, need to respect alignment constraints */ #ifndef CHIP_FAMILY_STM32L /* STM32L1xx is somewhat lying to us */ BUILD_ASSERT(sizeof(struct persist_state) % CONFIG_FLASH_WRITE_SIZE == 0); @@ -275,25 +281,6 @@ static uint32_t flash_read_pstate(void) } } -#ifdef CONFIG_SERIALNO_LEN -/** - * Read and return persistent serial number. - */ -const char *flash_read_pstate_serial(void) -{ - const struct persist_state *pstate = - (const struct persist_state *) - flash_physical_dataptr(CONFIG_FW_PSTATE_OFF); - - if ((pstate->version == PERSIST_STATE_VERSION) && - (pstate->valid_fields & PSTATE_VALID_SERIALNO)) { - return (const char *)(pstate->serialno); - } - - return NULL; -} -#endif - /** * Write persistent state after erasing. * @@ -374,10 +361,27 @@ static int flash_write_pstate(uint32_t flags) } #ifdef CONFIG_SERIALNO_LEN +/** + * Read and return persistent serial number. + */ +const char *flash_read_pstate_serial(void) +{ + const struct persist_state *pstate = + (const struct persist_state *) + flash_physical_dataptr(CONFIG_FW_PSTATE_OFF); + + if ((pstate->version == PERSIST_STATE_VERSION) && + (pstate->valid_fields & PSTATE_VALID_SERIALNO)) { + return (const char *)(pstate->serialno); + } + + return NULL; +} + /** * Write persistent serial number to pstate, erasing if necessary. * - * @param serialno New iascii serial number to set in pstate. + * @param serialno New ascii serial number to set in pstate. * @return EC_SUCCESS, or nonzero if error. */ int flash_write_pstate_serial(const char *serialno) @@ -408,10 +412,89 @@ int flash_write_pstate_serial(const char *serialno) return flash_write_pstate_data(&newpstate); } -#endif +#endif /* CONFIG_SERIALNO_LEN */ + +#ifdef CONFIG_MAC_ADDR_LEN + +/** + * Read and return persistent MAC address. + */ +const char *flash_read_pstate_mac_addr(void) +{ + const struct persist_state *pstate = + (const struct persist_state *) + flash_physical_dataptr(CONFIG_FW_PSTATE_OFF); + + if ((pstate->version == PERSIST_STATE_VERSION) && + (pstate->valid_fields & PSTATE_VALID_MAC_ADDR)) { + return (const char *)(pstate->mac_addr); + } + + return NULL; +} + +/** + * Write persistent MAC Addr to pstate, erasing if necessary. + * + * @param mac_addr New ascii MAC address to set in pstate. + * @return EC_SUCCESS, or nonzero if error. + */ +int flash_write_pstate_mac_addr(const char *mac_addr) +{ + int length; + struct persist_state newpstate; + const struct persist_state *pstate = + (const struct persist_state *) + flash_physical_dataptr(CONFIG_FW_PSTATE_OFF); + + /* Check that this is OK, data is valid and fits in the region. */ + if (!mac_addr) { + return EC_ERROR_INVAL; + } + + /* + * This will perform validation of the mac address before storing it. + * The MAC address format is '12:34:56:78:90:AB', a 17 character long + * string containing pairs of hex digits, each pair delimited by a ':'. + */ + length = strnlen(mac_addr, sizeof(newpstate.mac_addr)); + if (length != 17) { + return EC_ERROR_INVAL; + } + for (int i = 0; i < 17; i++) { + if (i % 3 != 2) { + /* Verify the remaining characters are hex digits. */ + if ((mac_addr[i] < '0' || '9' < mac_addr[i]) && + (mac_addr[i] < 'A' || 'F' < mac_addr[i]) && + (mac_addr[i] < 'a' || 'f' < mac_addr[i])) { + return EC_ERROR_INVAL; + } + } else { + /* Every 3rd character is a ':' */ + if (mac_addr[i] != ':') { + return EC_ERROR_INVAL; + } + } + } + /* Cache the old copy for read/modify/write. */ + memcpy(&newpstate, pstate, sizeof(newpstate)); + validate_pstate_struct(&newpstate); + + /* + * Erase any prior data and copy the string. The length was verified to + * be shorter than the buffer so a null terminator always remains. + */ + memset(newpstate.mac_addr, '\0', sizeof(newpstate.mac_addr)); + memcpy(newpstate.mac_addr, mac_addr, length); + + newpstate.valid_fields |= PSTATE_VALID_MAC_ADDR; + + return flash_write_pstate_data(&newpstate); +} +#endif /* CONFIG_MAC_ADDR_LEN */ #else /* !CONFIG_FLASH_PSTATE_BANK */ diff --git a/common/system.c b/common/system.c index 5d07bfcf90..7b50f57a1f 100644 --- a/common/system.c +++ b/common/system.c @@ -1560,6 +1560,27 @@ __overridable int board_write_serial(const char *serialno) } #endif /* CONFIG_SERIALNO_LEN */ +#ifdef CONFIG_MAC_ADDR_LEN +/* By default, read MAC address from flash, can be overridden. */ +__overridable const char *board_read_mac_addr(void) +{ + if (IS_ENABLED(CONFIG_FLASH_PSTATE) && + IS_ENABLED(CONFIG_FLASH_PSTATE_BANK)) + return flash_read_pstate_mac_addr(); + else + return ""; +} + +/* By default, write MAC address from flash, can be overridden. */ +__overridable int board_write_mac_addr(const char *mac_addr) +{ + if (IS_ENABLED(CONFIG_FLASH_PSTATE) && + IS_ENABLED(CONFIG_FLASH_PSTATE_BANK)) + return flash_write_pstate_mac_addr(mac_addr); + else + return EC_ERROR_UNIMPLEMENTED; +} +#endif /* CONFIG_MAC_ADDR_LEN */ __attribute__((weak)) void clock_enable_module(enum module_id module, int enable) diff --git a/include/config.h b/include/config.h index 87b05ed617..3dae6a4668 100644 --- a/include/config.h +++ b/include/config.h @@ -3185,6 +3185,12 @@ /* Size of the serial number if needed */ #undef CONFIG_SERIALNO_LEN +/* Support programmable Mac address field. */ +#undef CONFIG_MAC_ADDR + +/* Size of the MAC address field if needed. */ +#undef CONFIG_MAC_ADDR_LEN + /****************************************************************************/ /* Shared objects library. */ @@ -5126,6 +5132,10 @@ #define CONFIG_SERIALNO_LEN 28 #endif +#ifdef CONFIG_MAC_ADDR +#define CONFIG_MAC_ADDR_LEN 20 +#endif + #ifndef CONFIG_EC_MAX_SENSOR_FREQ_MILLIHZ #define CONFIG_EC_MAX_SENSOR_FREQ_MILLIHZ \ CONFIG_EC_MAX_SENSOR_FREQ_DEFAULT_MILLIHZ diff --git a/include/flash.h b/include/flash.h index cceac81df1..700a663a9a 100644 --- a/include/flash.h +++ b/include/flash.h @@ -343,6 +343,25 @@ const char *flash_read_pstate_serial(void); */ int flash_write_pstate_serial(const char *serialno); +/** + * Get the MAC address from flash. + * + * @return char * ascii MAC address string. + * Format: "01:23:45:67:89:AB" + * NULL if error. + */ +const char *flash_read_pstate_mac_addr(void); + +/** + * Set the MAC address in flash. + * + * @param mac_addr ascii MAC address string. + * Format: "01:23:45:67:89:AB" + * + * @return success status. + */ +int flash_write_pstate_mac_addr(const char *mac_addr); + /** * Lock or unlock HW necessary for mapped storage read. * diff --git a/include/system.h b/include/system.h index 0d785c6899..249ab58bf4 100644 --- a/include/system.h +++ b/include/system.h @@ -328,6 +328,19 @@ __override_proto const char *board_read_serial(void); */ __override_proto int board_write_serial(const char *serial); + +/** + * Optional board-level callback functions to read a unique MAC address per + * chip. Default implementation reads from flash. + */ +__override_proto const char *board_read_mac_addr(void); + +/** + * Optional board-level callback functions to write a unique MAC address per + * chip. Default implementation reads from flash. + */ +__override_proto int board_write_mac_addr(const char *mac_addr); + /* * Common bbram entries. Chips don't necessarily need to implement * all of these, error will be returned from system_get/set_bbram if -- cgit v1.2.1