[acpi] Support the "_RTXMAC_" format for ACPI-based MAC addresses

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).

Reported-by: Andreas Hammarskjöld <junior@2PintSoftware.com>
Tested-by: Andreas Hammarskjöld <junior@2PintSoftware.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown
2022-03-23 15:02:17 +00:00
parent 614c3f43a1
commit f58b5109f4
2 changed files with 144 additions and 28 deletions

View File

@@ -46,11 +46,79 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** MACA signature */ /** MACA signature */
#define MACA_SIGNATURE ACPI_SIGNATURE ( 'M', 'A', 'C', 'A' ) #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. * 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 * Extract MAC address from DSDT/SSDT
@@ -59,6 +127,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* @v len Length of DSDT/SSDT * @v len Length of DSDT/SSDT
* @v offset Offset of signature within DSDT/SSDT * @v offset Offset of signature within DSDT/SSDT
* @v data Data buffer * @v data Data buffer
* @v extractor ACPI MAC address extractor
* @ret rc Return status code * @ret rc Return status code
* *
* Some vendors provide a "system MAC address" within the DSDT/SSDT, * 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. * string that appears shortly after an "AMAC" or "MACA" signature.
* This should work for most implementations encountered in practice. * This should work for most implementations encountered in practice.
*/ */
static int acpi_extract_mac ( userptr_t zsdt, size_t len, size_t offset, static int acpimac_extract ( userptr_t zsdt, size_t len, size_t offset,
void *data ) { void *data, struct acpimac_extractor *extractor ){
static const char prefix[9] = "_AUXMAC_#"; size_t prefix_len = strlen ( extractor->prefix );
uint8_t *hw_addr = data; uint8_t *hw_addr = data;
size_t skip = 0; size_t skip = 0;
char auxmac[ sizeof ( prefix ) /* "_AUXMAC_#" */ + char buf[ prefix_len + extractor->len + 1 /* "#" */ + 1 /* NUL */ ];
( ETH_ALEN * 2 ) /* MAC */ + 1 /* "#" */ + 1 /* NUL */ ]; char *mac = &buf[prefix_len];
char *mac = &auxmac[ sizeof ( prefix ) ];
int decoded_len;
int rc; int rc;
/* Skip signature and at least one tag byte */ /* Skip signature and at least one tag byte */
offset += ( 4 /* signature */ + 1 /* tag byte */ ); offset += ( 4 /* signature */ + 1 /* tag byte */ );
/* Scan for "_AUXMAC_#.....#" close to signature */ /* Scan for suitable string close to signature */
for ( skip = 0 ; for ( skip = 0 ;
( ( skip < AUXMAC_MAX_SKIP ) && ( ( skip < ACPIMAC_MAX_SKIP ) &&
( offset + skip + sizeof ( auxmac ) ) < len ) ; ( offset + skip + sizeof ( buf ) ) <= len ) ;
skip++ ) { skip++ ) {
/* Read value */ /* Read value */
copy_from_user ( auxmac, zsdt, ( offset + skip ), copy_from_user ( buf, zsdt, ( offset + skip ),
sizeof ( auxmac ) ); sizeof ( buf ) );
/* Check for expected format */ /* Check for expected format */
if ( memcmp ( auxmac, prefix, sizeof ( prefix ) ) != 0 ) if ( memcmp ( buf, extractor->prefix, prefix_len ) != 0 )
continue; continue;
if ( auxmac[ sizeof ( auxmac ) - 2 ] != '#' ) if ( buf[ sizeof ( buf ) - 2 ] != '#' )
continue; continue;
if ( auxmac[ sizeof ( auxmac ) - 1 ] != '\0' ) if ( buf[ sizeof ( buf ) - 1 ] != '\0' )
continue; 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 */ /* Terminate MAC address string */
mac = &auxmac[ sizeof ( prefix ) ]; mac[extractor->len] = '\0';
mac[ ETH_ALEN * 2 ] = '\0';
/* Decode MAC address */ /* Decode MAC address */
decoded_len = base16_decode ( mac, hw_addr, ETH_ALEN ); if ( ( rc = extractor->decode ( mac, hw_addr ) ) != 0 )
if ( decoded_len < 0 ) {
rc = decoded_len;
DBGC ( colour, "ACPI could not decode MAC \"%s\": %s\n",
mac, strerror ( rc ) );
return rc; return rc;
}
/* Check MAC address validity */ /* Check MAC address validity */
if ( ! is_valid_ether_addr ( hw_addr ) ) { if ( ! is_valid_ether_addr ( hw_addr ) ) {
@@ -131,6 +193,36 @@ static int acpi_extract_mac ( userptr_t zsdt, size_t len, size_t offset,
return -ENOENT; return -ENOENT;
} }
/**
* 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 * Extract MAC address from DSDT/SSDT
* *
@@ -142,12 +234,17 @@ int acpi_mac ( uint8_t *hw_addr ) {
/* Look for an "AMAC" address */ /* Look for an "AMAC" address */
if ( ( rc = acpi_extract ( AMAC_SIGNATURE, hw_addr, if ( ( rc = acpi_extract ( AMAC_SIGNATURE, hw_addr,
acpi_extract_mac ) ) == 0 ) acpimac_extract_auxmac ) ) == 0 )
return 0; return 0;
/* Look for a "MACA" address */ /* Look for a "MACA" address */
if ( ( rc = acpi_extract ( MACA_SIGNATURE, hw_addr, 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 0;
return -ENOENT; return -ENOENT;

View File

@@ -159,6 +159,24 @@ ACPI_TABLES ( maca_tables, &maca_ssdt1, &maca_ssdt2 );
ACPI_MAC ( maca, &maca_tables, ACPI_MAC ( maca, &maca_tables,
DATA ( 0x52, 0x54, 0x00, 0x11, 0x22, 0x33 ) ); 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 */ /** Current ACPI test table set */
static struct acpi_test_tables *acpi_test_tables; static struct acpi_test_tables *acpi_test_tables;
@@ -229,6 +247,7 @@ static void acpi_test_exec ( void ) {
/* MAC extraction tests */ /* MAC extraction tests */
acpi_mac_ok ( &amac ); acpi_mac_ok ( &amac );
acpi_mac_ok ( &maca ); acpi_mac_ok ( &maca );
acpi_mac_ok ( &rtma );
} }
/** ACPI self-test */ /** ACPI self-test */