1
0
forked from 0ad/0ad

final smbios improvements.

add comments
add support for bit flags
use wrapper classes and SFINAE instead of flags to detect enums / sizes
/ handles
avoid potential truncation of byte sizes
avoid displaying numeric_limits::min values ("unknown")

This was SVN commit r9168.
This commit is contained in:
janwas 2011-04-05 17:14:18 +00:00
parent d3ba9a24d3
commit 1c2e410b7d
2 changed files with 384 additions and 228 deletions

View File

@ -20,6 +20,10 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* provide access to System Management BIOS information
*/
#include "precompiled.h"
#include "smbios.h"
@ -35,6 +39,7 @@
namespace SMBIOS {
//-----------------------------------------------------------------------------
// GetTable
#if OS_WIN
@ -72,6 +77,7 @@ static LibError GetTable(wfirmware::Table& table)
//-----------------------------------------------------------------------------
// strings
// pointers to the strings (if any) at the end of an SMBIOS structure
typedef std::vector<const char*> Strings;
@ -102,14 +108,16 @@ static Strings ExtractStrings(const Header* header, const char* end, const Heade
}
// storage for all structures' strings
// storage for all structures' strings (must be copied from the original
// wfirmware table since its std::vector container cannot be stored in a
// static variable because we may be called before _cinit)
static char* stringStorage;
static char* stringStoragePos;
// pointers to dynamically allocated structures
static Structures structures;
static void Cleanup()
static void Cleanup() // called via atexit
{
SAFE_FREE(stringStorage);
stringStoragePos = 0;
@ -121,6 +129,9 @@ static void Cleanup()
}
//-----------------------------------------------------------------------------
// FieldInitializer
// define function templates that invoke a Visitor for each of a structure's fields
#define FIELD(flags, type, name, units) visitor(flags, p.name, #name, units);
#define STRUCTURE(name, id) template<class Visitor> void VisitFields(name& p, Visitor& visitor) { name##_FIELDS }
@ -141,25 +152,42 @@ public:
{
}
template<typename T>
void operator()(size_t flags, T& t, const char* UNUSED(name), const char* UNUSED(units))
template<typename Field>
void operator()(size_t flags, Field& field, const char* UNUSED(name), const char* UNUSED(units))
{
if((flags & F_DERIVED) || data >= end)
{
t = T();
field = Field();
return;
}
if(flags & F_ENUM)
t = T(*data++);
else
{
memcpy(&t, data, sizeof(t));
data += sizeof(t);
}
Read(field); // SFINAE
}
private:
template<typename T>
T ReadValue()
{
T value;
memcpy(&value, data, sizeof(value));
data += sizeof(value);
return value;
}
// construct from SMBIOS representations that don't match the
// actual type (e.g. enum)
template<typename Field>
void Read(Field& field, typename Field::T* = 0)
{
field = Field(ReadValue<typename Field::T>());
}
template<typename Field>
void Read(Field& field, ...)
{
field = ReadValue<Field>();
}
const u8* data;
const u8* end;
const Strings& strings;
@ -169,11 +197,11 @@ private:
// C++03 14.7.3(2): "An explicit specialization shall be declared [..] in the
// namespace of which the enclosing class [..] is a member.
// avoid "forcing value to bool true or false" warning
// (this specialization avoids a "forcing value to bool true or false" warning)
template<>
void FieldInitializer::operator()<bool>(size_t flags, bool& UNUSED(t), const char* UNUSED(name), const char* UNUSED(units))
{
// SMBIOS doesn't specify any single booleans, so we're only called for
// SMBIOS doesn't specify any individual booleans, so we're only called for
// derived fields and don't need to do anything.
debug_assert(flags & F_DERIVED);
}
@ -181,24 +209,16 @@ void FieldInitializer::operator()<bool>(size_t flags, bool& UNUSED(t), const cha
template<>
void FieldInitializer::operator()<const char*>(size_t flags, const char*& t, const char* UNUSED(name), const char* UNUSED(units))
{
t = 0; // (allow immediate `return' when the string is found to be invalid)
u8 number;
operator()(flags, number, 0, 0);
if(number == 0) // no string given
{
t = 0;
return;
}
if(number > strings.size())
{
debug_printf(L"SMBIOS: invalid string number %d (count=%d)\n", number, strings.size());
t = 0;
return;
}
if(strings[number-1] == 0)
{
t = 0;
return;
}
@ -221,14 +241,14 @@ void Fixup(Structure& UNUSED(structure))
template<>
void Fixup<Bios>(Bios& p)
{
p.size = u64(p.encodedSize+1) * 64*KiB;
p.size = size_t(p.encodedSize+1) * 64*KiB;
}
template<>
void Fixup<Processor>(Processor& p)
{
p.populated = (p.status.value & 0x40) != 0;
p.status = (ProcessorStatus)bits((size_t)p.status.value, 0, 2);
p.populated = (p.status & 0x40) != 0;
p.status = (ProcessorStatus)bits(p.status, 0, 2);
if(p.voltage & 0x80)
p.voltage &= ~0x80;
@ -249,10 +269,10 @@ void Fixup<Cache>(Cache& p)
{
struct DecodeSize
{
size_t operator()(u16 size) const
u64 operator()(u16 size) const
{
const size_t granularity = IsBitSet(size, 15)? 64*KiB : 1*KiB;
return size_t(bits(size, 0, 14)) * granularity;
return u64(bits(size, 0, 14)) * granularity;
}
};
p.maxSize = DecodeSize()(p.maxSize16);
@ -260,7 +280,7 @@ void Fixup<Cache>(Cache& p)
p.level = bits(p.configuration, 0, 2)+1;
p.location = (CacheLocation)bits(p.configuration, 5, 6);
p.mode = (CacheMode)bits(p.configuration, 8, 9);
p.configuration &= ~0x367;
p.configuration = (CacheConfigurationFlags)(p.configuration & ~0x367);
}
template<>
@ -274,7 +294,7 @@ template<>
void Fixup<OnBoardDevices>(OnBoardDevices& p)
{
p.enabled = (p.type.value & 0x80) != 0;
p.type = (OnBoardDeviceType)(p.type.value & ~0x80);
p.type = (OnBoardDeviceType)(p.type & ~0x80);
}
template<>
@ -291,6 +311,7 @@ void Fixup<MemoryDevice>(MemoryDevice& p)
p.size = u64(bits(p.size16, 0, 14)) * (IsBitSet(p.size16, 15)? 1*KiB : 1*MiB);
else
p.size = u64(bits(p.size32, 0, 30)) * MiB;
p.rank = bits(p.attributes, 0, 3);
}
template<>
@ -334,6 +355,7 @@ void Fixup<TemperatureProbe>(TemperatureProbe& p)
//-----------------------------------------------------------------------------
// InitStructures
template<class Structure>
void AddStructure(const Header* header, const Strings& strings, Structure*& listHead)
@ -413,41 +435,53 @@ static LibError InitStructures()
}
const Structures* GetStructures()
{
static ModuleInitState initState;
LibError ret = ModuleInit(&initState, InitStructures);
if(ret != INFO::OK)
return 0;
return &structures;
}
//-----------------------------------------------------------------------------
// StringFromEnum
template<class Enum>
static inline const char* EnumeratorFromValue(Enum UNUSED(value))
std::string StringFromEnum(Enum UNUSED(field))
{
return 0;
return "(unknown enumeration)";
}
// define specializations of EnumeratorFromValue
#define ENUM(enumerator, value) case value: return #enumerator;
#define ENUMERATION(name)\
template<>\
inline const char* EnumeratorFromValue<name>(name value)\
#define ENUM(enumerator, VALUE)\
if(field.value == VALUE) /* single bit flag or matching enumerator */\
return #enumerator;\
if(!is_pow2(VALUE)) /* these aren't bit flags */\
{\
switch(value.value)\
allowFlags = false;\
string.clear();\
}\
if(allowFlags && (field.value & (VALUE)))\
{\
if(!string.empty())\
string += "|";\
string += #enumerator;\
}
#define ENUMERATION(name, type)\
template<>\
std::string StringFromEnum<name>(name field)\
{\
std::string string;\
bool allowFlags = true;\
name##_ENUMERATORS\
/* (don't warn about the value 0, e.g. optional fields) */\
if(string.empty() && field != 0)\
{\
name##_ENUMERATORS \
default: return 0;\
std::stringstream ss;\
ss << "(unknown " << #name << " " << field.value << ")";\
return ss.str();\
}\
return string;\
}
ENUMERATIONS
#undef ENUMERATION
#undef ENUM
//-----------------------------------------------------------------------------
// FieldStringizer
class FieldStringizer
{
NONCOPYABLE(FieldStringizer); // reference member
@ -457,92 +491,177 @@ public:
{
}
template<typename T>
void operator()(size_t flags, T& value, const char* name, const char* units)
template<typename Field>
void operator()(size_t flags, Field& field, const char* name, const char* units)
{
if(flags & F_INTERNAL)
return;
static u64 zero;
cassert_dependent(sizeof(value) <= sizeof(zero));
if((flags & F_ENUM) == 0 && memcmp(&value, &zero, sizeof(value)) == 0)
Write(flags, field, name, units); // SFINAE
}
// special case for sizes [bytes]
template<typename T>
void operator()(size_t flags, Size<T>& size, const char* name, const char* units)
{
if(flags & F_INTERNAL)
return;
ss << " "; // indent
ss << name << ": ";
if(flags & (F_HEX|F_FLAGS))
ss << std::hex << std::uppercase;
else
ss << std::dec;
const u64 value = (u64)size.value;
if(value == 0)
return;
if(flags & F_ENUM)
u64 divisor;
if(value > GiB)
{
const char* name = EnumeratorFromValue(value);
if(name)
ss << name;
else
ss << value;
divisor = GiB;
units = " GiB";
}
else if(flags & F_SIZE)
else if(value > MiB)
{
u64 value64 = (u64)value;
if(value64 > GiB)
ss << value64/GiB << " GiB";
else if(value64 > MiB)
ss << value64/MiB << " MiB";
else if(value64 > KiB)
ss << value64/KiB << " KiB";
else
ss << value << " bytes";
divisor = MiB;
units = " MiB";
}
else if(value > KiB)
{
divisor = KiB;
units = " KiB";
}
else if(sizeof(value) == 1) // avoid printing as a character
ss << (unsigned)value;
else
ss << value;
{
divisor = 1;
units = " bytes";
}
ss << units << "\n";
WriteName(name);
// (avoid floating-point output unless division would truncate the value)
if(value % divisor == 0)
ss << (value/divisor);
else
ss << (double(value)/divisor);
WriteUnits(units);
}
private:
void WriteName(const char* name)
{
ss << " "; // indent
ss << name << ": ";
}
void WriteUnits(const char* units)
{
ss << units;
ss << "\n";
}
// enumerations and bit flags
template<typename Field>
void Write(size_t UNUSED(flags), Field& field, const char* name, const char* units, typename Field::Enum* = 0)
{
// 0 usually means "not included in structure", but some packed
// enumerations actually use that value. therefore, only skip this
// field if it is zero AND no matching enumerator is found.
const std::string string = StringFromEnum(field);
if(string.empty())
return;
WriteName(name);
ss << StringFromEnum(field);
WriteUnits(units);
}
// all other field types
template<typename Field>
void Write(size_t flags, Field& field, const char* name, const char* units, ...)
{
// SMBIOS uses the smallest representable signed/unsigned value to
// indicate `unknown' (except enumerators - but those are handled in
// the other function overload), so skip those.
if(field == std::numeric_limits<Field>::min())
return;
WriteName(name);
if(flags & F_HEX)
ss << std::hex << std::uppercase;
if(sizeof(field) == 1) // avoid printing as a character
ss << unsigned(field);
else
ss << field;
if(flags & F_HEX)
ss << std::dec; // (revert to decimal, e.g. for displaying sizes)
WriteUnits(units);
}
std::stringstream& ss;
};
template<>
void FieldStringizer::operator()<bool>(size_t flags, bool& value, const char* name, const char* units)
{
debug_assert(units[0] == '\0'); // why would this be specified?
if(flags & F_INTERNAL)
return;
ss << " "; // indent
ss << name << ": \"" << (value? "true" : "false") << "\"\n";
WriteName(name);
ss << (value? "true" : "false");
WriteUnits(units);
}
template<>
void FieldStringizer::operator()<Handle>(size_t flags, Handle& handle, const char* name, const char* units)
{
debug_assert(units[0] == '\0'); // why would this be specified?
if(flags & F_INTERNAL || handle.value == 0xFFFE || handle.value == 0xFFFF)
if(flags & F_INTERNAL)
return;
ss << " "; // indent
ss << name << ": " << handle.value << "\n";
// don't display useless handles
if(handle.value == 0 || handle.value == 0xFFFE || handle.value == 0xFFFF)
return;
WriteName(name);
ss << handle.value;
WriteUnits(units);
}
template<>
void FieldStringizer::operator()<const char*>(size_t flags, const char*& value, const char* name, const char* units)
{
debug_assert(units[0] == '\0'); // why would this be specified for strings?
if((flags & F_INTERNAL) || value == 0)
if(flags & F_INTERNAL)
return;
// don't display useless strings
const ssize_t length = (ssize_t)strlen(value);
if(std::count(value, value+length, ' ') == length) // all spaces
if(value == 0)
return;
if(strcmp(value, "To Be Filled By O.E.M.") == 0)
std::string string(value);
const size_t lastChar = string.find_last_not_of(' ');
if(lastChar == std::string::npos) // nothing but spaces
return;
string.resize(lastChar+1); // strip trailing spaces
if(string == "To Be Filled By O.E.M.")
return;
ss << " "; // indent
ss << name << ": \"" << value << "\"\n";
WriteName(name);
ss << "\"" << string << "\"";
WriteUnits(units);
}
//-----------------------------------------------------------------------------
// public interface
const Structures* GetStructures()
{
static ModuleInitState initState;
LibError ret = ModuleInit(&initState, InitStructures);
if(ret != INFO::OK)
return 0;
return &structures;
}
@ -557,7 +676,6 @@ void StringizeStructure(const char* name, Structure* p, std::stringstream& ss)
}
}
std::string StringizeStructures(const Structures* structures)
{
if(!structures)

View File

@ -20,52 +20,56 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* provide access to System Management BIOS information
*/
#ifndef INCLUDED_SMBIOS
#define INCLUDED_SMBIOS
namespace SMBIOS {
// to introduce another enumeration:
// 1) add its name here
// 1) add its name and underlying type here
// 2) define a <name>_ENUMERATORS macro specifying its enumerators
// (prefer lower case to avoid conflicts with macros)
#define ENUMERATIONS\
ENUMERATION(Status)\
ENUMERATION(ECC)\
ENUMERATION(SystemWakeUpType)\
ENUMERATION(BaseboardFlags)\
ENUMERATION(BaseboardType)\
ENUMERATION(ChassisType)\
ENUMERATION(ChassisSecurityStatus)\
ENUMERATION(ProcessorType)\
ENUMERATION(ProcessorStatus)\
ENUMERATION(ProcessorUpgrade)\
ENUMERATION(ProcessorFlags)\
ENUMERATION(CacheMode)\
ENUMERATION(CacheLocation)\
ENUMERATION(CacheConfigurationFlags)\
ENUMERATION(CacheFlags)\
ENUMERATION(CacheType)\
ENUMERATION(CacheAssociativity)\
ENUMERATION(PortConnectorType)\
ENUMERATION(PortType)\
ENUMERATION(SystemSlotType)\
ENUMERATION(SystemSlotBusWidth)\
ENUMERATION(SystemSlotUsage)\
ENUMERATION(SystemSlotLength)\
ENUMERATION(SystemSlotFlags1)\
ENUMERATION(SystemSlotFlags2)\
ENUMERATION(OnBoardDeviceType)\
ENUMERATION(MemoryArrayLocation)\
ENUMERATION(MemoryArrayUse)\
ENUMERATION(MemoryDeviceFormFactor)\
ENUMERATION(MemoryDeviceType)\
ENUMERATION(MemoryDeviceTypeFlags)\
ENUMERATION(PortableBatteryChemistry)\
ENUMERATION(VoltageProbeLocation)\
ENUMERATION(CoolingDeviceType)\
ENUMERATION(TemperatureProbeLocation)\
ENUMERATION(SystemBootStatus)
ENUMERATION(Status, u8)\
ENUMERATION(ECC, u8)\
ENUMERATION(SystemWakeUpType, u8)\
ENUMERATION(BaseboardFlags, u8)\
ENUMERATION(BaseboardType, u8)\
ENUMERATION(ChassisType, u8)\
ENUMERATION(ChassisSecurityStatus, u8)\
ENUMERATION(ProcessorType, u8)\
ENUMERATION(ProcessorStatus, u8)\
ENUMERATION(ProcessorUpgrade, u8)\
ENUMERATION(ProcessorFlags, u16)\
ENUMERATION(CacheMode, u8)\
ENUMERATION(CacheLocation, u8)\
ENUMERATION(CacheConfigurationFlags, u16)\
ENUMERATION(CacheFlags, u16)\
ENUMERATION(CacheType, u8)\
ENUMERATION(CacheAssociativity, u8)\
ENUMERATION(PortConnectorType, u8)\
ENUMERATION(PortType, u8)\
ENUMERATION(SystemSlotType, u8)\
ENUMERATION(SystemSlotBusWidth, u8)\
ENUMERATION(SystemSlotUsage, u8)\
ENUMERATION(SystemSlotLength, u8)\
ENUMERATION(SystemSlotFlags1, u8)\
ENUMERATION(SystemSlotFlags2, u8)\
ENUMERATION(OnBoardDeviceType, u8)\
ENUMERATION(MemoryArrayLocation, u8)\
ENUMERATION(MemoryArrayUse, u8)\
ENUMERATION(MemoryDeviceFormFactor, u8)\
ENUMERATION(MemoryDeviceType, u8)\
ENUMERATION(MemoryDeviceTypeFlags, u16)\
ENUMERATION(PortableBatteryChemistry, u8)\
ENUMERATION(VoltageProbeLocation, u8)\
ENUMERATION(CoolingDeviceType, u8)\
ENUMERATION(TemperatureProbeLocation, u8)\
ENUMERATION(SystemBootStatus, u8)
// to introduce another structure:
@ -102,35 +106,45 @@ namespace SMBIOS {
/* ManagementControllerHostInterface (42) is optional */
//-----------------------------------------------------------------------------
// declarations required for the fields
// indicates a field (:= member of a structure) is:
enum FieldFlags
{
// computed via other fields (i.e. should not be copied from the SMBIOS data).
F_DERIVED = 0x01,
F_DERIVED = 1,
// not intended for use by applications (usually because it is
// superseded by another - possibly derived - field).
F_INTERNAL = 0x02,
// an enum type; we'll read an SMBIOS byte and cast it to this type.
// (could also be detected via is_enum, but that requires TR1/C++0x)
// (using enum member variables instead of the raw u8 means the debugger
// will display the enumerators)
F_ENUM = 0x04,
// a collection of bit flags.
F_FLAGS = 0x08,
// not intended for display / use by applications (usually because
// it is superseded by another - possibly derived - field).
F_INTERNAL = 2,
// a number that should be displayed in hexadecimal form.
F_HEX = 0x20,
F_SIZE = 0x40
F_HEX = 4
};
#pragma pack(push, 1)
// (wrapper classes allow special handling of certain fields via
// template specialization and function overloads)
// size [bytes] - displayed with auto-range
template<typename T>
struct Size
{
Size(): value(0) {}
Size(T value): value(value) {}
T value;
};
// SMBIOS structure handle - only displayed if meaningful
struct Handle
{
Handle(): value(0) {}
Handle(u16 value): value(value) {}
u16 value;
};
// shared by several structures
#define Status_ENUMERATORS\
ENUM(other, 1)\
ENUM(unknown, 2)\
@ -149,6 +163,9 @@ enum FieldFlags
ENUM(crc, 7)
#pragma pack(push, 1)
//-----------------------------------------------------------------------------
// Bios
@ -160,7 +177,7 @@ enum FieldFlags
FIELD(F_INTERNAL, u8, encodedSize, "")\
FIELD(F_HEX, u64, characteristics, "")\
/* omit subsequent fields because we can't handle the variable-length characteristics extension */\
FIELD(F_DERIVED|F_SIZE, u64, size, "")
FIELD(F_DERIVED, Size<size_t>, size, "")
//-----------------------------------------------------------------------------
@ -183,7 +200,7 @@ enum FieldFlags
FIELD(0, const char*, serialNumber, "")\
FIELD(F_HEX, u64, uuid0, "")\
FIELD(F_HEX, u64, uuid1, "")\
FIELD(F_ENUM, SystemWakeUpType, wakeUpType, "")\
FIELD(0, SystemWakeUpType, wakeUpType, "")\
FIELD(0, const char*, skuNumber, "")\
FIELD(0, const char*, family, "")
@ -219,10 +236,10 @@ enum FieldFlags
FIELD(0, const char*, version, "")\
FIELD(0, const char*, serialNumber, "")\
FIELD(0, const char*, assetTag, "")\
FIELD(F_FLAGS, u8, flags, "")\
FIELD(0, BaseboardFlags, flags, "")\
FIELD(0, const char*, location, "")\
FIELD(0, Handle, hChassis, "")\
FIELD(F_ENUM, BaseboardType, type, "")\
FIELD(0, BaseboardType, type, "")\
/* omit subsequent fields because we can't handle the variable-length contained objects */
@ -269,14 +286,14 @@ enum FieldFlags
#define Chassis_FIELDS\
FIELD(0, const char*, manufacturer, "")\
FIELD(F_ENUM, ChassisType, type, "")\
FIELD(0, ChassisType, type, "")\
FIELD(0, const char*, version, "")\
FIELD(0, const char*, serialNumber, "")\
FIELD(0, const char*, assetTag, "")\
FIELD(F_ENUM, Status, state, "")\
FIELD(F_ENUM, Status, powerState, "")\
FIELD(F_ENUM, Status, thermalState, "")\
FIELD(F_ENUM, ChassisSecurityStatus, securityStatus, "")\
FIELD(0, Status, state, "")\
FIELD(0, Status, powerState, "")\
FIELD(0, Status, thermalState, "")\
FIELD(0, ChassisSecurityStatus, securityStatus, "")\
FIELD(0, u32, oemDefined, "")\
FIELD(0, u8, height, "U")\
FIELD(0, u8, numPowerCords, "")\
@ -300,7 +317,7 @@ enum FieldFlags
ENUM(enabled, 1)\
ENUM(user_disabled, 2)\
ENUM(post_disabled, 3)\
ENUM(cpu_idle, 4)
ENUM(idle, 4)
#define ProcessorUpgrade_ENUMERATORS\
ENUM(other, 1)\
@ -357,7 +374,7 @@ enum FieldFlags
#define Processor_FIELDS\
FIELD(0, const char*, socket, "")\
FIELD(F_ENUM, ProcessorType, type, "")\
FIELD(0, ProcessorType, type, "")\
FIELD(0, u8, family, "") /* we don't bother providing enumerators for > 200 families */\
FIELD(0, const char*, manufacturer, "")\
FIELD(F_HEX, u64, id, "")\
@ -366,8 +383,8 @@ enum FieldFlags
FIELD(0, u16, externalClockFrequency, " MHz")\
FIELD(0, u16, maxFrequency, " MHz")\
FIELD(0, u16, bootFrequency, " MHz")\
FIELD(F_ENUM, ProcessorStatus, status, "")\
FIELD(F_ENUM, ProcessorUpgrade, upgrade, "")\
FIELD(0, ProcessorStatus, status, "")\
FIELD(0, ProcessorUpgrade, upgrade, "")\
FIELD(0, Handle, hL1, "")\
FIELD(0, Handle, hL2, "")\
FIELD(0, Handle, hL3, "")\
@ -377,7 +394,7 @@ enum FieldFlags
FIELD(0, u8, coresPerPackage, "")\
FIELD(0, u8, enabledCores, "")\
FIELD(0, u8, logicalPerPackage, "")\
FIELD(F_FLAGS, u16, characteristics, "")\
FIELD(0, ProcessorFlags, flags, "")\
FIELD(0, u16, family2, "")\
FIELD(F_DERIVED, bool, populated, "")
@ -435,20 +452,20 @@ enum FieldFlags
#define Cache_FIELDS\
FIELD(0, const char*, designation, "")\
FIELD(F_FLAGS, u16, configuration, "")\
FIELD(0, CacheConfigurationFlags, configuration, "")\
FIELD(F_INTERNAL, u16, maxSize16, "")\
FIELD(F_INTERNAL, u16, installedSize16, "")\
FIELD(F_FLAGS, u16, supportedFlags, "")\
FIELD(F_FLAGS, u16, currentFlags, "")\
FIELD(0, CacheFlags, supportedFlags, "")\
FIELD(0, CacheFlags, currentFlags, "")\
FIELD(0, u8, speed, " ns")\
FIELD(F_ENUM, ECC, ecc, "")\
FIELD(F_ENUM, CacheType, type, "")\
FIELD(F_ENUM, CacheAssociativity, associativity, "")\
FIELD(0, ECC, ecc, "")\
FIELD(0, CacheType, type, "")\
FIELD(0, CacheAssociativity, associativity, "")\
FIELD(F_DERIVED, size_t, level, "") /* 1..8 */\
FIELD(F_DERIVED|F_ENUM, CacheLocation, location, "")\
FIELD(F_DERIVED|F_ENUM, CacheMode, mode, "")\
FIELD(F_DERIVED|F_SIZE, size_t, maxSize, "")\
FIELD(F_DERIVED|F_SIZE, size_t, installedSize, "")
FIELD(F_DERIVED, CacheLocation, location, "")\
FIELD(F_DERIVED, CacheMode, mode, "")\
FIELD(F_DERIVED, Size<u64>, maxSize, "")\
FIELD(F_DERIVED, Size<u64>, installedSize, "")
//-----------------------------------------------------------------------------
@ -538,10 +555,10 @@ enum FieldFlags
#define PortConnector_FIELDS\
FIELD(0, const char*, internalDesignator, "")\
FIELD(F_ENUM, PortConnectorType, internalConnectorType, "")\
FIELD(0, PortConnectorType, internalConnectorType, "")\
FIELD(0, const char*, externalDesignator, "")\
FIELD(F_ENUM, PortConnectorType, externalConnectorType, "")\
FIELD(F_ENUM, PortType, portType, "")
FIELD(0, PortConnectorType, externalConnectorType, "")\
FIELD(0, PortType, portType, "")
//-----------------------------------------------------------------------------
@ -616,8 +633,8 @@ enum FieldFlags
#define SystemSlotLength_ENUMERATORS\
ENUM(other, 1)\
ENUM(unknown, 2)\
ENUM(short_length, 3)\
ENUM(long_length, 4)
ENUM(_short, 3)\
ENUM(_long, 4)
#define SystemSlotFlags1_ENUMERATORS\
ENUM(unknown, 0x1)\
@ -636,13 +653,13 @@ enum FieldFlags
#define SystemSlot_FIELDS\
FIELD(0, const char*, designation, "")\
FIELD(F_ENUM, SystemSlotType, type, "")\
FIELD(F_ENUM, SystemSlotBusWidth, busWidth, "")\
FIELD(F_ENUM, SystemSlotUsage, usage, "")\
FIELD(F_ENUM, SystemSlotLength, length, "")\
FIELD(0, SystemSlotType, type, "")\
FIELD(0, SystemSlotBusWidth, busWidth, "")\
FIELD(0, SystemSlotUsage, usage, "")\
FIELD(0, SystemSlotLength, length, "")\
FIELD(0, u16, id, "")\
FIELD(F_FLAGS, u8, characteristics, "")\
FIELD(F_FLAGS, u8, characteristics2, "")\
FIELD(0, SystemSlotFlags1, flags1, "")\
FIELD(0, SystemSlotFlags2, flags2, "")\
FIELD(0, u8, busNumber, "")\
FIELD(F_INTERNAL, u8, functionAndDeviceNumber, "")\
FIELD(F_DERIVED, u8, deviceNumber, "")\
@ -665,7 +682,7 @@ enum FieldFlags
ENUM(sas_controller, 10)
#define OnBoardDevices_FIELDS\
FIELD(F_ENUM, OnBoardDeviceType, type, "")\
FIELD(0, OnBoardDeviceType, type, "")\
FIELD(0, const char*, description, "")\
FIELD(F_DERIVED, bool, enabled, "")\
/* NB: this structure could contain any number of type/description pairs, but Dell BIOS only provides 1 */
@ -700,13 +717,13 @@ enum FieldFlags
ENUM(cache, 7)
#define MemoryArray_FIELDS\
FIELD(F_ENUM, MemoryArrayLocation, location, "")\
FIELD(F_ENUM, MemoryArrayUse, use, "")\
FIELD(F_ENUM, ECC, ecc, "")\
FIELD(0, MemoryArrayLocation, location, "")\
FIELD(0, MemoryArrayUse, use, "")\
FIELD(0, ECC, ecc, "")\
FIELD(F_INTERNAL, u32, maxCapacity32, "")\
FIELD(0, Handle, hError, "")\
FIELD(0, u16, numDevices, "")\
FIELD(F_SIZE, u64, maxCapacity, "")
FIELD(0, Size<u64>, maxCapacity, "")
//-----------------------------------------------------------------------------
@ -775,29 +792,30 @@ enum FieldFlags
FIELD(0, u16, totalWidth, " bits")\
FIELD(0, u16, dataWidth, " bits")\
FIELD(F_INTERNAL, u16, size16, "")\
FIELD(F_ENUM, MemoryDeviceFormFactor, formFactor, "")\
FIELD(0, MemoryDeviceFormFactor, formFactor, "")\
FIELD(0, u8, deviceSet, "")\
FIELD(0, const char*, locator, "")\
FIELD(0, const char*, bank, "")\
FIELD(F_ENUM, MemoryDeviceType, type, "")\
FIELD(F_FLAGS, u16, typeFlags, "")\
FIELD(0, MemoryDeviceType, type, "")\
FIELD(0, MemoryDeviceTypeFlags, typeFlags, "")\
FIELD(0, u16, speed, " MHz")\
FIELD(0, const char*, manufacturer, "")\
FIELD(0, const char*, serialNumber, "")\
FIELD(0, const char*, assetTag, "")\
FIELD(0, const char*, partNumber, "")\
FIELD(F_FLAGS, u8, attributes, "")\
FIELD(F_INTERNAL, u8, attributes, "")\
FIELD(F_INTERNAL, u32, size32, "")\
FIELD(0, u16, configuredSpeed, " MHz")\
FIELD(F_DERIVED|F_SIZE, u64, size, "")
FIELD(F_DERIVED, Size<u64>, size, "")\
FIELD(F_DERIVED, u8, rank, "")\
//-----------------------------------------------------------------------------
// MemoryArrayMappedAddress
#define MemoryArrayMappedAddress_FIELDS\
FIELD(F_INTERNAL, u32, startAddress32, " bits")\
FIELD(F_INTERNAL, u32, endAddress32, " bits")\
FIELD(F_INTERNAL, u32, startAddress32, "")\
FIELD(F_INTERNAL, u32, endAddress32, "")\
FIELD(0, Handle, hMemoryArray, "")\
FIELD(0, u8, partitionWidth, "")\
FIELD(F_HEX, u64, startAddress, "")\
@ -808,8 +826,8 @@ enum FieldFlags
// MemoryDeviceMappedAddress
#define MemoryDeviceMappedAddress_FIELDS\
FIELD(F_INTERNAL, u32, startAddress32, " bits")\
FIELD(F_INTERNAL, u32, endAddress32, " bits")\
FIELD(F_INTERNAL, u32, startAddress32, "")\
FIELD(F_INTERNAL, u32, endAddress32, "")\
FIELD(0, Handle, hMemoryDevice, "")\
FIELD(0, Handle, hMemoryArrayMappedAddress, "")\
FIELD(0, u8, partitionRowPosition, "")\
@ -838,11 +856,11 @@ enum FieldFlags
FIELD(0, const char*, date, "")\
FIELD(0, const char*, serialNumber, "")\
FIELD(0, const char*, deviceName, "")\
FIELD(F_ENUM, PortableBatteryChemistry, chemistry, "")\
FIELD(0, PortableBatteryChemistry, chemistry, "")\
FIELD(0, u16, capacity, " mWh")\
FIELD(0, u16, voltage, " mV")\
FIELD(0, const char*, sbdsVersion, "")\
FIELD(0, u8, maxError, "%")\
FIELD(0, i8, maxError, "%")\
FIELD(0, u16, sbdsSerialNumber, "")\
FIELD(0, u16, sbdsDate, "")\
FIELD(0, const char*, sbdsChemistry, "")\
@ -869,13 +887,13 @@ enum FieldFlags
#define VoltageProbe_FIELDS\
FIELD(0, const char*, description, "")\
FIELD(F_INTERNAL, u8, locationAndStatus, "")\
FIELD(0, u16, maxValue, " mV")\
FIELD(0, u16, minValue, " mV")\
FIELD(0, u16, resolution, " x 0.1 mV")\
FIELD(0, u16, tolerance, " mV")\
FIELD(0, u16, accuracy, " x 0.01%")\
FIELD(0, i16, maxValue, " mV")\
FIELD(0, i16, minValue, " mV")\
FIELD(0, i16, resolution, " x 0.1 mV")\
FIELD(0, i16, tolerance, " mV")\
FIELD(0, i16, accuracy, " x 0.01%")\
FIELD(0, u32, oemDefined, "")\
FIELD(0, u16, nominalValue, " mv")\
FIELD(0, i16, nominalValue, " mv")\
FIELD(F_DERIVED, VoltageProbeLocation, location, "")\
FIELD(F_DERIVED, Status, status, "")
@ -932,9 +950,9 @@ enum FieldFlags
FIELD(F_INTERNAL, u8, locationAndStatus, "")\
FIELD(0, i16, maxValue, " dDegC")\
FIELD(0, i16, minValue, " dDegC")\
FIELD(0, u16, resolution, " mDegC")\
FIELD(0, u16, tolerance, " dDegC")\
FIELD(0, u16, accuracy, " x 0.01%")\
FIELD(0, i16, resolution, " mDegC")\
FIELD(0, i16, tolerance, " dDegC")\
FIELD(0, i16, accuracy, " x 0.01%")\
FIELD(0, u32, oemDefined, "")\
FIELD(0, i16, nominalValue, " dDegC")\
FIELD(F_DERIVED, TemperatureProbeLocation, location, "")\
@ -958,20 +976,11 @@ enum FieldFlags
#define SystemBoot_FIELDS\
FIELD(F_INTERNAL, u32, reserved32, "")\
FIELD(F_INTERNAL, u16, reserved16, "")\
FIELD(F_ENUM, SystemBootStatus, status, "")\
FIELD(0, SystemBootStatus, status, "")\
//-----------------------------------------------------------------------------
// (can't be a typedef due to template specialization)
struct Handle
{
Handle(): value(0) {}
Handle(u16 value): value(value) {}
u16 value;
};
struct Header
{
u8 id;
@ -979,15 +988,20 @@ struct Header
Handle handle;
};
// define each enumeration
// define each enumeration:
#define ENUM(enumerator, value) enumerator = value,
#define ENUMERATION(name)\
// (a struct wrapper allows reusing common enumerator names such as `other'.)
#define ENUMERATION(name, type)\
struct name\
{\
/* (determines how much data to read from SMBIOS) */\
typedef type T;\
name(): value((Enum)0) {}\
name(u8 value8): value((Enum)value8) {}\
name(size_t num): value((Enum)num) {}\
/* (the existence of this member type indicates the field is an enum) */\
enum Enum { name##_ENUMERATORS } value;\
operator int() const { return value; }\
/* (allows generic Field comparison against numeric_limits) */\
operator size_t() const { return value; }\
};
ENUMERATIONS
#undef ENUMERATION
@ -995,12 +1009,20 @@ ENUMERATIONS
// declare each structure
#define FIELD(flags, type, name, units) type name;
#define STRUCTURE(name, id) struct name { Header header; name* next; name##_FIELDS };
#define STRUCTURE(name, id)\
struct name\
{\
/* (allows searching for a structure with a given handle) */\
Header header;\
/* (defines a linked list of instances of this structure type) */\
name* next;\
name##_FIELDS\
};
STRUCTURES
#undef STRUCTURE
#undef FIELD
// declare a UDT holding pointers (freed at exit) to each structure
// declare a struct holding pointers (freed at exit) to each structure
struct Structures
{
#define STRUCTURE(name, id) name* name##_;
@ -1010,7 +1032,23 @@ struct Structures
#pragma pack(pop)
//-----------------------------------------------------------------------------
/**
* @return 0 on failure or a pointer to a static Structures (i.e. always
* valid), with its member pointers non-zero iff the SMBIOS includes the
* corresponding structure.
*
* thread-safe; return value should be cached (if possible) to avoid an
* atomic comparison.
**/
LIB_API const Structures* GetStructures();
/**
* @return a string describing all structures (omitting fields with
* meaningless or dummy values).
**/
LIB_API std::string StringizeStructures(const Structures*);
} // namespace SMBIOS