dmi_fields_decode

Synopsis

#include <opendmi/field.h>

bool dmi_fields_decode(dmi_decoder_t *decoder);

Description

The dmi_fields_decode function reads a structure according to the layout its specification declares, instead of a decoding handler written for the type.

A specification describes its layout with the fields member of dmi_entity_spec_t, a list of dmi_field_t written with DMI_FIELDS and terminated with an empty field. Fields are read in the order they are declared, starting at the beginning of the structure body. A specification which declares fields and no decoding handler is decoded by this function, which dmi_entity_decode calls on its own, so it rarely has to be named. The bytes are read through the decoder the structure is being decoded with, see dmi_decoder_initialize.

Fields describe the bytes, while the attributes of dmi_attribute_t describe the values they are decoded into. The two are joined by the member of the decoded structure they name, and neither is a complete description of the other: a field may carry no member of its own, and a member may be computed rather than read.

Groups and truncation

The firmware of a platform writes the fields of the version of the specification it follows, and leaves out the ones of the newer versions, so a structure of a type is not as long as the decoder knows it to be.

DMI_FIELD_GROUP declares where the data is allowed to end. When the data ends at the beginning of a group, the fields of that group and of the ones after it are left unset, and the structure is marked as stopped rather than as broken; the version of the group the data has been read up to becomes the level of the structure. Ending anywhere else marks the structure as incomplete, except within the fields before the first group, which every structure of the type is required to carry.

A group may also name a bool member with present, which the function sets once every field of the group has been read, and leaves false if the data ends before the group or in the middle of it, e.g. DMI_FIELD_GROUP(.present = dmi_member(dmi_hpe_trusted_module_t, has_chip)). This is how the structures of the vendors, whose groups carry no version, tell the fields they hold from the ones they are too short for.

Integers and other values

An integer field names the type it is written with, e.g. DMI_FIELD(dmi_slot_t, ident, dmi_word_t), whose size is the width of the field. The member it is decoded into may be wider than the field, so that the value standing for "unknown" does not collide with a value a device may really have. String references, UUIDs, binary-coded decimals and bytes taken as they are have macros of their own: DMI_FIELD_STRING, DMI_FIELD_UUID, DMI_FIELD_BCD and DMI_FIELD_BINARY.

Arrays

DMI_FIELD_ARRAY declares a number of elements the data gives, which are decoded into an array of their own, allocated by the function: the member holds the pointer to the elements, and the counter the field names holds the number of the ones decoded in full. The arrays belong to the library, which frees them with the decoded structure, see dmi_fields_release, so the cleanup handler of a specification does not free them.

Values which need decoding

A field whose value means something other than the number the data carries declares a pair of handlers, decode and encode, which turn the data into the member and back. A field declared with DMI_FIELD_SPLIT gives its handlers the whole structure instead of one member, which is how the data feeding several members at once is decoded.

Parameters

decoder

Decoder of the structure, see dmi_decoder_initialize. The structure is decoded into the structure of its type.

Return value

Returns true if the structure has been decoded, which includes the structures the data ends within, and false if it cannot be.

Errors

DMI_ERROR_ARGUMENT_NULL

Decoder is nullptr.

DMI_ERROR_ARGUMENT_INVALID

A field declares a number wider than the widest one the engine reads and writes, which is eight bytes.

DMI_ERROR_STATE_INVALID

Specification declares no fields.

DMI_ERROR_INTERNAL

Fields reach another offset than the one declared.

DMI_ERROR_OUT_OF_MEMORY

Elements of an array cannot be allocated.

Examples

const dmi_entity_spec_t dmi_slot_spec =
{
    .code   = "slot",
    .type   = DMI_TYPE(system_slots),
    ...
    .fields = DMI_FIELDS({
        DMI_FIELD_STRING(dmi_slot_t, designator),
        DMI_FIELD(dmi_slot_t, type,      dmi_byte_t),
        DMI_FIELD(dmi_slot_t, bus_width, dmi_byte_t),

        DMI_FIELD_GROUP(.since = DMI_VERSION(2, 1, 0)),
        DMI_FIELD(dmi_slot_t, features_ex, dmi_byte_t),

        DMI_FIELD_GROUP(.since = DMI_VERSION(3, 2, 0)),
        DMI_FIELD_ARRAY(dmi_slot_t, peer_groups, peer_group_count,
            .count_length = sizeof(dmi_byte_t),
            .fields       = DMI_FIELDS({
                DMI_FIELD(dmi_slot_peer_group_t, bus_width, dmi_byte_t),
                {}
            })),
        {}
    })
};