aboutsummaryrefslogtreecommitdiff
path: root/src/core/acpimac.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/acpimac.c')
-rw-r--r--src/core/acpimac.c153
1 files changed, 125 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;