[settings] Add the notion of a "tag magic" to numbered settings
authorMichael Brown <mcb30@etherboot.org>
Wed, 29 Oct 2008 18:17:02 +0000 (18:17 +0000)
committerMichael Brown <mcb30@etherboot.org>
Thu, 30 Oct 2008 21:47:14 +0000 (21:47 +0000)
Settings can be constructed using a dotted-decimal notation, to allow
for access to unnamed settings.  The default interpretation is as a
DHCP option number (with encapsulated options represented as
"<encapsulating option>.<encapsulated option>".

In several contexts (e.g. SMBIOS, Phantom CLP), it is useful to
interpret the dotted-decimal notation as referring to non-DHCP
options.  In this case, it becomes necessary for these contexts to
ignore standard DHCP options, otherwise we end up trying to, for
example, retrieve the boot filename from SMBIOS.

Allow settings blocks to specify a "tag magic".  When dotted-decimal
notation is used to construct a setting, the tag magic value of the
originating settings block will be ORed in to the tag number.
Store/fetch methods can then check for the magic number before
interpreting arbitrarily-numbered settings.

src/arch/i386/firmware/pcbios/smbios_settings.c
src/core/nvo.c
src/core/settings.c
src/drivers/net/phantom/phantom.c
src/include/gpxe/settings.h
src/net/netdevice.c
src/net/udp/dhcp.c

index b088e51..3238fb1 100644 (file)
 #include <gpxe/uuid.h>
 #include <smbios.h>
 
+/** SMBIOS settings tag magic number */
+#define SMBIOS_TAG_MAGIC 0x5B /* "SmBios" */
+
+/**
+ * Construct SMBIOS empty tag
+ *
+ * @ret tag            SMBIOS setting tag
+ */
+#define SMBIOS_EMPTY_TAG ( SMBIOS_TAG_MAGIC << 24 )
+
 /**
  * Construct SMBIOS raw-data tag
  *
@@ -33,7 +43,8 @@
  * @ret tag            SMBIOS setting tag
  */
 #define SMBIOS_RAW_TAG( _type, _structure, _field )            \
-       ( ( (_type) << 16 ) |                                   \
+       ( ( SMBIOS_TAG_MAGIC << 24 ) |                          \
+         ( (_type) << 16 ) |                                   \
          ( offsetof ( _structure, _field ) << 8 ) |            \
          ( sizeof ( ( ( _structure * ) 0 )->_field ) ) )
 
@@ -46,7 +57,8 @@
  * @ret tag            SMBIOS setting tag
  */
 #define SMBIOS_STRING_TAG( _type, _structure, _field )         \
-       ( ( (_type) << 16 ) |                                   \
+       ( ( SMBIOS_TAG_MAGIC << 24 ) |                          \
+         ( (_type) << 16 ) |                                   \
          ( offsetof ( _structure, _field ) << 8 ) )
 
 /**
@@ -78,16 +90,18 @@ static int smbios_fetch ( struct settings *settings __unused,
                          struct setting *setting,
                          void *data, size_t len ) {
        struct smbios_structure structure;
+       unsigned int tag_magic;
        unsigned int tag_type;
        unsigned int tag_offset;
        unsigned int tag_len;
        int rc;
 
        /* Split tag into type, offset and length */
-       tag_type = ( setting->tag >> 16 );
+       tag_magic = ( setting->tag >> 24 );
+       tag_type = ( ( setting->tag >> 16 ) & 0xff );
        tag_offset = ( ( setting->tag >> 8 ) & 0xff );
        tag_len = ( setting->tag & 0xff );
-       if ( ! tag_type )
+       if ( tag_magic != SMBIOS_TAG_MAGIC )
                return -ENOENT;
 
        /* Find SMBIOS structure */
@@ -127,6 +141,7 @@ static struct settings_operations smbios_settings_operations = {
 static struct settings smbios_settings = {
        .refcnt = NULL,
        .name = "smbios",
+       .tag_magic = SMBIOS_EMPTY_TAG,
        .siblings = LIST_HEAD_INIT ( smbios_settings.siblings ),
        .children = LIST_HEAD_INIT ( smbios_settings.children ),
        .op = &smbios_settings_operations,
index 1307802..e5c07d9 100644 (file)
@@ -203,7 +203,7 @@ void nvo_init ( struct nvo_block *nvo, struct nvs_device *nvs,
        nvo->nvs = nvs;
        nvo->fragments = fragments;
        settings_init ( &nvo->settings, &nvo_settings_operations, refcnt,
-                       "nvo" );
+                       "nvo", 0 );
 }
 
 /**
index f97842f..9ad2ced 100644 (file)
@@ -665,6 +665,7 @@ static int parse_setting_name ( const char *name, struct settings **settings,
                        }
                        tmp++;
                }
+               setting->tag |= (*settings)->tag_magic;
        }
 
        /* Identify setting type, if specified */
index 659bd2c..47bbcb9 100644 (file)
@@ -1589,6 +1589,12 @@ static struct net_device_operations phantom_operations = {
  *
  */
 
+/** Phantom CLP settings tag magic */
+#define PHN_CLP_TAG_MAGIC 0xc19c1900UL
+
+/** Phantom CLP settings tag magic mask */
+#define PHN_CLP_TAG_MAGIC_MASK 0xffffff00UL
+
 /** Phantom CLP data
  *
  */
@@ -1790,7 +1796,7 @@ struct phantom_clp_setting {
        /** gPXE setting */
        struct setting *setting;
        /** Setting number */
-       unsigned int number;
+       unsigned int clp_setting;
 };
 
 /** Phantom CLP settings */
@@ -1802,25 +1808,29 @@ static struct phantom_clp_setting clp_settings[] = {
  * Find Phantom CLP setting
  *
  * @v setting          gPXE setting
- * @v clp_setting      Equivalent Phantom CLP setting, or NULL
+ * @v clp_setting      Setting number, or 0 if not found
  */
-static struct phantom_clp_setting *
-phantom_find_clp_setting ( struct phantom_nic *phantom,
-                          struct setting *setting ) {
+static unsigned int
+phantom_clp_setting ( struct phantom_nic *phantom, struct setting *setting ) {
        struct phantom_clp_setting *clp_setting;
        unsigned int i;
 
+       /* Search the list of explicitly-defined settings */
        for ( i = 0 ; i < ( sizeof ( clp_settings ) /
                            sizeof ( clp_settings[0] ) ) ; i++ ) {
                clp_setting = &clp_settings[i];
                if ( setting_cmp ( setting, clp_setting->setting ) == 0 )
-                       return clp_setting;
+                       return clp_setting->clp_setting;
        }
 
+       /* Allow for use of numbered settings */
+       if ( ( setting->tag & PHN_CLP_TAG_MAGIC_MASK ) == PHN_CLP_TAG_MAGIC )
+               return ( setting->tag & ~PHN_CLP_TAG_MAGIC_MASK );
+
        DBGC2 ( phantom, "Phantom %p has no \"%s\" setting\n",
                phantom, setting->name );
 
-       return NULL;
+       return 0;
 }
 
 /**
@@ -1838,18 +1848,17 @@ static int phantom_store_setting ( struct settings *settings,
        struct phantom_nic_port *phantom_port =
                container_of ( settings, struct phantom_nic_port, settings );
        struct phantom_nic *phantom = phantom_port->phantom;
-       struct phantom_clp_setting *clp_setting;
+       unsigned int clp_setting;
        int rc;
 
        /* Find Phantom setting equivalent to gPXE setting */
-       clp_setting = phantom_find_clp_setting ( phantom, setting );
+       clp_setting = phantom_clp_setting ( phantom, setting );
        if ( ! clp_setting )
                return -ENOTSUP;
 
        /* Store setting */
        if ( ( rc = phantom_clp_store ( phantom, phantom_port->port,
-                                       clp_setting->number,
-                                       data, len ) ) != 0 ) {
+                                       clp_setting, data, len ) ) != 0 ) {
                DBGC ( phantom, "Phantom %p could not store setting \"%s\": "
                       "%s\n", phantom, setting->name, strerror ( rc ) );
                return rc;
@@ -1873,19 +1882,18 @@ static int phantom_fetch_setting ( struct settings *settings,
        struct phantom_nic_port *phantom_port =
                container_of ( settings, struct phantom_nic_port, settings );
        struct phantom_nic *phantom = phantom_port->phantom;
-       struct phantom_clp_setting *clp_setting;
+       unsigned int clp_setting;
        int read_len;
        int rc;
 
        /* Find Phantom setting equivalent to gPXE setting */
-       clp_setting = phantom_find_clp_setting ( phantom, setting );
+       clp_setting = phantom_clp_setting ( phantom, setting );
        if ( ! clp_setting )
                return -ENOTSUP;
 
        /* Fetch setting */
        if ( ( read_len = phantom_clp_fetch ( phantom, phantom_port->port,
-                                             clp_setting->number,
-                                             data, len ) ) < 0 ) {
+                                             clp_setting, data, len ) ) < 0 ){
                rc = read_len;
                DBGC ( phantom, "Phantom %p could not fetch setting \"%s\": "
                       "%s\n", phantom, setting->name, strerror ( rc ) );
@@ -2269,7 +2277,7 @@ static int phantom_probe ( struct pci_device *pci,
                phantom_port->port = i;
                settings_init ( &phantom_port->settings,
                                &phantom_settings_operations,
-                               &netdev->refcnt, "clp" );
+                               &netdev->refcnt, "clp", PHN_CLP_TAG_MAGIC );
        }
 
        /* BUG5945 - need to hack PCI config space on P3 B1 silicon.
index ee7dace..37c01b0 100644 (file)
@@ -72,6 +72,14 @@ struct settings {
        struct refcnt *refcnt;
        /** Name */
        const char *name;
+       /** Tag magic
+        *
+        * This value will be ORed in to any numerical tags
+        * constructed by parse_setting_name(), and can be used to
+        * avoid e.g. attempting to retrieve the subnet mask from
+        * SMBIOS, or the system UUID from DHCP.
+        */
+       unsigned int tag_magic;
        /** Parent settings block */
        struct settings *parent;
        /** Sibling settings blocks */
@@ -225,16 +233,19 @@ extern struct setting mac_setting __setting;
  * @v op               Settings block operations
  * @v refcnt           Containing object reference counter, or NULL
  * @v name             Settings block name
+ * @v tag_magic                Tag magic
  */
 static inline void settings_init ( struct settings *settings,
                                   struct settings_operations *op,
                                   struct refcnt *refcnt,
-                                  const char *name ) {
+                                  const char *name,
+                                  unsigned int tag_magic ) {
        INIT_LIST_HEAD ( &settings->siblings );
        INIT_LIST_HEAD ( &settings->children );
        settings->op = op;
        settings->refcnt = refcnt;
        settings->name = name;
+       settings->tag_magic = tag_magic;
 }
 
 /**
@@ -248,7 +259,7 @@ static inline void simple_settings_init ( struct simple_settings *simple,
                                          struct refcnt *refcnt,
                                          const char *name ) {
        settings_init ( &simple->settings, &simple_settings_operations,
-                       refcnt, name );
+                       refcnt, name, 0 );
 }
 
 /**
index 6ea90b4..81c4ae8 100644 (file)
@@ -268,7 +268,7 @@ struct net_device * alloc_netdev ( size_t priv_size ) {
                INIT_LIST_HEAD ( &netdev->rx_queue );
                settings_init ( netdev_settings ( netdev ),
                                &netdev_settings_operations, &netdev->refcnt,
-                               netdev->name );
+                               netdev->name, 0 );
                netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) );
        }
        return netdev;
index ab751cd..2134783 100644 (file)
@@ -256,7 +256,7 @@ static struct dhcp_settings * dhcpset_create ( const struct dhcphdr *dhcphdr,
                dhcppkt_init ( &dhcpset->dhcppkt, data, len );
                settings_init ( &dhcpset->settings,
                                &dhcpset_settings_operations, &dhcpset->refcnt,
-                               DHCP_SETTINGS_NAME );
+                               DHCP_SETTINGS_NAME, 0 );
        }
        return dhcpset;
 }