aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2022-03-23 15:02:17 +0000
committerMichael Brown <mcb30@ipxe.org>2022-03-24 12:58:52 +0000
commit739206bf2b8c6d7d0276260a82a23cc5bb1cba43 (patch)
tree0421c3bf5b6fe7d201d6ebc0770108cec0f2b3f7
parent614c3f43a12cd6be6d79d7a8a63cfa603ff9d49f (diff)
downloadipxe-acpimac.zip
ipxe-acpimac.tar.gz
ipxe-acpimac.tar.bz2
[acpi] Support the "_RTXMAC_" format for ACPI-based MAC addressesacpimac
Some newer HP products expose the host-based MAC (HBMAC) address using an ACPI method named "RTMA" returning a part-binary string of the form "_RTXMAC_#<mac>#", where "<mac>" comprises the raw MAC address bytes. Extend the existing support to handle this format alongside the older "_AUXMAC_" format (which uses a base16-encoded MAC address). Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r--src/core/acpimac.c153
-rw-r--r--src/tests/acpi_test.c19
2 files changed, 144 insertions, 28 deletions
diff --git a/src/core/acpimac.c b/src/core/acpimac.c
index 1cc8220..5920480 100644
--- a/src/core/acpimac.c
+++ b/src/core/acpimac.c
@@ -46,11 +46,79 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** MACA signature */
#define MACA_SIGNATURE ACPI_SIGNATURE ( 'M', 'A', 'C', 'A' )
-/** Maximum number of bytes to skip after AMAC/MACA signature
+/** RTMA signature */
+#define RTMA_SIGNATURE ACPI_SIGNATURE ( 'R', 'T', 'M', 'A' )
+
+/** Maximum number of bytes to skip after ACPI signature
*
* This is entirely empirical.
*/
-#define AUXMAC_MAX_SKIP 8
+#define ACPIMAC_MAX_SKIP 8
+
+/** An ACPI MAC extraction mechanism */
+struct acpimac_extractor {
+ /** Prefix string */
+ const char *prefix;
+ /** Encoded MAC length */
+ size_t len;
+ /** Decode MAC
+ *
+ * @v mac Encoded MAC
+ * @v hw_addr MAC address to fill in
+ * @ret rc Return status code
+ */
+ int ( * decode ) ( const char *mac, uint8_t *hw_addr );
+};
+
+/**
+ * Decode Base16-encoded MAC address
+ *
+ * @v mac Encoded MAC
+ * @v hw_addr MAC address to fill in
+ * @ret rc Return status code
+ */
+static int acpimac_decode_base16 ( const char *mac, uint8_t *hw_addr ) {
+ int len;
+ int rc;
+
+ /* Attempt to base16-decode MAC address */
+ len = base16_decode ( mac, hw_addr, ETH_ALEN );
+ if ( len < 0 ) {
+ rc = len;
+ DBGC ( colour, "ACPI could not decode base16 MAC \"%s\": %s\n",
+ mac, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Decode raw MAC address
+ *
+ * @v mac Encoded MAC
+ * @v hw_addr MAC address to fill in
+ * @ret rc Return status code
+ */
+static int acpimac_decode_raw ( const char *mac, uint8_t *hw_addr ) {
+
+ memcpy ( hw_addr, mac, ETH_ALEN );
+ return 0;
+}
+
+/** "_AUXMAC_" extraction mechanism */
+static struct acpimac_extractor acpimac_auxmac = {
+ .prefix = "_AUXMAC_#",
+ .len = ( ETH_ALEN * 2 ),
+ .decode = acpimac_decode_base16,
+};
+
+/** "_RTXMAC_" extraction mechanism */
+static struct acpimac_extractor acpimac_rtxmac = {
+ .prefix = "_RTXMAC_#",
+ .len = ETH_ALEN,
+ .decode = acpimac_decode_raw,
+};
/**
* Extract MAC address from DSDT/SSDT
@@ -59,6 +127,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* @v len Length of DSDT/SSDT
* @v offset Offset of signature within DSDT/SSDT
* @v data Data buffer
+ * @v extractor ACPI MAC address extractor
* @ret rc Return status code
*
* Some vendors provide a "system MAC address" within the DSDT/SSDT,
@@ -72,51 +141,44 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* string that appears shortly after an "AMAC" or "MACA" signature.
* This should work for most implementations encountered in practice.
*/
-static int acpi_extract_mac ( userptr_t zsdt, size_t len, size_t offset,
- void *data ) {
- static const char prefix[9] = "_AUXMAC_#";
+static int acpimac_extract ( userptr_t zsdt, size_t len, size_t offset,
+ void *data, struct acpimac_extractor *extractor ){
+ size_t prefix_len = strlen ( extractor->prefix );
uint8_t *hw_addr = data;
size_t skip = 0;
- char auxmac[ sizeof ( prefix ) /* "_AUXMAC_#" */ +
- ( ETH_ALEN * 2 ) /* MAC */ + 1 /* "#" */ + 1 /* NUL */ ];
- char *mac = &auxmac[ sizeof ( prefix ) ];
- int decoded_len;
+ char buf[ prefix_len + extractor->len + 1 /* "#" */ + 1 /* NUL */ ];
+ char *mac = &buf[prefix_len];
int rc;
/* Skip signature and at least one tag byte */
offset += ( 4 /* signature */ + 1 /* tag byte */ );
- /* Scan for "_AUXMAC_#.....#" close to signature */
+ /* Scan for suitable string close to signature */
for ( skip = 0 ;
- ( ( skip < AUXMAC_MAX_SKIP ) &&
- ( offset + skip + sizeof ( auxmac ) ) < len ) ;
+ ( ( skip < ACPIMAC_MAX_SKIP ) &&
+ ( offset + skip + sizeof ( buf ) ) <= len ) ;
skip++ ) {
/* Read value */
- copy_from_user ( auxmac, zsdt, ( offset + skip ),
- sizeof ( auxmac ) );
+ copy_from_user ( buf, zsdt, ( offset + skip ),
+ sizeof ( buf ) );
/* Check for expected format */
- if ( memcmp ( auxmac, prefix, sizeof ( prefix ) ) != 0 )
+ if ( memcmp ( buf, extractor->prefix, prefix_len ) != 0 )
continue;
- if ( auxmac[ sizeof ( auxmac ) - 2 ] != '#' )
+ if ( buf[ sizeof ( buf ) - 2 ] != '#' )
continue;
- if ( auxmac[ sizeof ( auxmac ) - 1 ] != '\0' )
+ if ( buf[ sizeof ( buf ) - 1 ] != '\0' )
continue;
- DBGC ( colour, "ACPI found MAC string \"%s\"\n", auxmac );
+ DBGC ( colour, "ACPI found MAC:\n" );
+ DBGC_HDA ( colour, ( offset + skip ), buf, sizeof ( buf ) );
/* Terminate MAC address string */
- mac = &auxmac[ sizeof ( prefix ) ];
- mac[ ETH_ALEN * 2 ] = '\0';
+ mac[extractor->len] = '\0';
/* Decode MAC address */
- decoded_len = base16_decode ( mac, hw_addr, ETH_ALEN );
- if ( decoded_len < 0 ) {
- rc = decoded_len;
- DBGC ( colour, "ACPI could not decode MAC \"%s\": %s\n",
- mac, strerror ( rc ) );
+ if ( ( rc = extractor->decode ( mac, hw_addr ) ) != 0 )
return rc;
- }
/* Check MAC address validity */
if ( ! is_valid_ether_addr ( hw_addr ) ) {
@@ -132,6 +194,36 @@ static int acpi_extract_mac ( userptr_t zsdt, size_t len, size_t offset,
}
/**
+ * Extract "_AUXMAC_" MAC address from DSDT/SSDT
+ *
+ * @v zsdt DSDT or SSDT
+ * @v len Length of DSDT/SSDT
+ * @v offset Offset of signature within DSDT/SSDT
+ * @v data Data buffer
+ * @ret rc Return status code
+ */
+static int acpimac_extract_auxmac ( userptr_t zsdt, size_t len, size_t offset,
+ void *data ) {
+
+ return acpimac_extract ( zsdt, len, offset, data, &acpimac_auxmac );
+}
+
+/**
+ * Extract "_RTXMAC_" MAC address from DSDT/SSDT
+ *
+ * @v zsdt DSDT or SSDT
+ * @v len Length of DSDT/SSDT
+ * @v offset Offset of signature within DSDT/SSDT
+ * @v data Data buffer
+ * @ret rc Return status code
+ */
+static int acpimac_extract_rtxmac ( userptr_t zsdt, size_t len, size_t offset,
+ void *data ) {
+
+ return acpimac_extract ( zsdt, len, offset, data, &acpimac_rtxmac );
+}
+
+/**
* Extract MAC address from DSDT/SSDT
*
* @v hw_addr MAC address to fill in
@@ -142,12 +234,17 @@ int acpi_mac ( uint8_t *hw_addr ) {
/* Look for an "AMAC" address */
if ( ( rc = acpi_extract ( AMAC_SIGNATURE, hw_addr,
- acpi_extract_mac ) ) == 0 )
+ acpimac_extract_auxmac ) ) == 0 )
return 0;
/* Look for a "MACA" address */
if ( ( rc = acpi_extract ( MACA_SIGNATURE, hw_addr,
- acpi_extract_mac ) ) == 0 )
+ acpimac_extract_auxmac ) ) == 0 )
+ return 0;
+
+ /* Look for a "RTMA" address */
+ if ( ( rc = acpi_extract ( RTMA_SIGNATURE, hw_addr,
+ acpimac_extract_rtxmac ) ) == 0 )
return 0;
return -ENOENT;
diff --git a/src/tests/acpi_test.c b/src/tests/acpi_test.c
index 972067e..1ca5bef 100644
--- a/src/tests/acpi_test.c
+++ b/src/tests/acpi_test.c
@@ -159,6 +159,24 @@ ACPI_TABLES ( maca_tables, &maca_ssdt1, &maca_ssdt2 );
ACPI_MAC ( maca, &maca_tables,
DATA ( 0x52, 0x54, 0x00, 0x11, 0x22, 0x33 ) );
+/** "RTMA" SSDT */
+ACPI_TABLE ( rtma_ssdt, "SSDT",
+ DATA ( 0x53, 0x53, 0x44, 0x54, 0x44, 0x00, 0x00, 0x00, 0x02,
+ 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x49, 0x4e, 0x54, 0x4c, 0x04, 0x06, 0x21, 0x20,
+ 0x10, 0x1f, 0x5c, 0x5f, 0x53, 0x42, 0x5f, 0x14, 0x18,
+ 0x52, 0x54, 0x4d, 0x41, 0x08, 0x0d, 0x5f, 0x52, 0x54,
+ 0x58, 0x4d, 0x41, 0x43, 0x5f, 0x23, 0x52, 0x54, 0x30,
+ 0x30, 0x30, 0x31, 0x23, 0x00 ) );
+
+/** "RTMA" test tables */
+ACPI_TABLES ( rtma_tables, &rtma_ssdt );
+
+/** "RTMA" test */
+ACPI_MAC ( rtma, &rtma_tables,
+ DATA ( 0x52, 0x54, 0x30, 0x30, 0x30, 0x31 ) );
+
/** Current ACPI test table set */
static struct acpi_test_tables *acpi_test_tables;
@@ -229,6 +247,7 @@ static void acpi_test_exec ( void ) {
/* MAC extraction tests */
acpi_mac_ok ( &amac );
acpi_mac_ok ( &maca );
+ acpi_mac_ok ( &rtma );
}
/** ACPI self-test */