blob: 3f1d2695af18655d04b016b9774f5dd12d6c4e79 [file] [log] [blame]
// Copyright 2016 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Library to provide access to the Chrome OS master configuration
#ifndef CHROMEOS_CONFIG_LIBCROS_CONFIG_CROS_CONFIG_H_
#define CHROMEOS_CONFIG_LIBCROS_CONFIG_CROS_CONFIG_H_
#include "chromeos-config/libcros_config/cros_config_interface.h"
#include <memory>
#include <string>
#include <vector>
#include <base/files/file.h>
#include <base/files/file_path.h>
#include <base/macros.h>
#include <base/values.h>
#include <brillo/brillo_export.h>
namespace base {
class CommandLine;
class FilePath;
} // namespace base
namespace brillo {
struct SmbiosTable;
class BRILLO_EXPORT CrosConfig : public CrosConfigInterface {
public:
CrosConfig();
~CrosConfig() override;
// Prepare the configuration system for for access to the configuration for
// the model this is running on. This reads the configuration file into
// memory.
// @return true if OK, false on error.
bool InitModel();
// Alias for the above, since this is used by several clients.
bool Init();
// Prepare the configuration system for testing.
// This reads in the given configuration file and selects the supplied
// model name.
// @filepath: Path to configuration .dtb file.
// @name: Platform name as returned by 'mosys platform id'.
// @sku_id: SKU ID as returned by 'mosys platform sku'.
// @customization_id: VPD customization ID from 'mosys platform customization'
// @return true if OK, false on error.
bool InitForTest(const base::FilePath& filepath, const std::string& name,
int sku_id, const std::string& customization_id);
// Internal function to obtain a property value and return a list of log
// messages on failure. Public for tests.
// @path: Path to locate. Must start with "/".
// @prop: Property name to look up
// @val_out: returns the string value found, if any
// @log_msgs_out: returns a list of error messages if this function fails
// @return true if found, false if not found
bool GetString(const std::string& path, const std::string& prop,
std::string* val_out, std::vector<std::string>* log_msgs_out);
// CrosConfigInterface:
bool GetString(const std::string& path,
const std::string& prop,
std::string* val_out) override;
// CrosConfigInterface:
bool GetAbsPath(const std::string& path, const std::string& prop,
std::string* val_out) override;
private:
// Init for a particular config file
// This calls InitCommon() with the given file after reading the identity
// information for this device.
// @filepath: Path to configuration file to use
bool InitForConfig(const base::FilePath& filepath);
// Common init function for both production and test code.
// @filepath: path to configuration .dtb file.
// @smbios_file: File containing memory to scan (typically this is /dev/mem)
// @vpd_file: File containing the customization_id from VPD. Typically this
// is '/sys/firmware/vpd/ro/customization_id'.
bool InitCommon(const base::FilePath& filepath,
const base::FilePath& smbios_file,
const base::FilePath& vpd_file);
// Runs a quick init check and prints an error to stderr if it fails.
// @return true if OK, false on error.
bool InitCheck() const;
// Obtain the full path for the node at a given offset.
// @offset: offset of the node to check.
// @return path to node, or "unknown" if it 256 characters or more (due to
// limited buffer space). This is much longer than any expected length so
// should not happen.
std::string GetFullPath(int offset);
// Obtain offset of a given path, relative to the base node.
// @base_offset: offset of base node.
// @path: Path to locate (relative to @base). Must start with "/".
// @return node offset of the node found, or negative value on error.
int GetPathOffset(int base_offset, const std::string& path);
// Internal function to obtain a property value based on a node offset
// This looks up a property for a path, relative to a given base node offset.
// @base_offset: offset of base node for the search.
// @path: Path to locate (relative to @base). Must start with "/".
// @prop: Property name to look up
// @val_out: returns the string value found, if any
// @log_msgs_out: returns a list of error messages if this function fails
// @return true if found, false if not found
bool GetString(int base_offset, const std::string& path,
const std::string& prop, std::string* val_out,
std::vector<std::string>* log_msgs_out);
// Look up a phandle in a node.
// Looks up a phandle with the given property name in the given node.
// @node_offset: Offset of node to look in.
// @prop_name: Name of property to look up.
// @offset_out: Returns the offset of the node the phandle points to, if
// found.
// @return true if found, false if not.
bool LookupPhandle(int node_offset, const std::string& prop_name,
int *offset_out);
// Select the model / submodel to use
// Looks up the given name and sku_id in the mapping table and sets the
// model and submodel that will be used for the duration of execution.
// @find_name: Platform name to search for
// @find_sku_id: SKU ID to search for
// @find_customization_id: Customization ID to search for
// @return true on success, false on failure
bool SelectModelConfigByIDs(const std::string& find_name, int find_sku_id,
const std::string& find_customization_id);
// Check a single sku-map node for a match
// This searches the given sku-map node to see if it is a match for the given
// SKU ID.
// @node: 'sku-map' node to examine
// @find_sku_id: SKU ID to search for. This is not required (can be -1) for
// single-sku matching
// @find_name: Platform name to search for. Can be empty if the name does
// not need to be checked (no smbios-name-match property). This only works
// on x86 devices at present although it should be easily extensible to ARM.
// @platform_name_out: Returns platform name for this SKU, if found
// @return the phandle to a model or submodel node that was found (> 0), or 0
// if not found, or negative on error
int FindIDsInMap(int node, const std::string& find_name, int find_sku_id,
std::string* platform_name_out);
// Check all sku-map nodes for a match
// This searches all the sku-map subnodes to see if one is a match for the
// given SKU ID.
// @mapping_node: 'mapping' node to examine
// @find_name: platform name to search for
// @find_sku_id: SKU ID to search for
// @platform_name_out: Returns platform name for this SKU, if found
// @return the phandle to a model or submodel node that was found (> 0), or 0
// if not found, or negative on error
int FindIDsInAllMaps(int mapping_node, const std::string& find_name,
int find_sku_id, std::string* platform_name_out);
// Find the model node pointed to by a phandle
// Note that a SKU map can point to either a model node or a submodel node.
// In the latter case, this function still returns the model node, but the
// submodel node is available in @target_out.
// @phandle: Phandle to look up
// @target_out: Returns the target node of the phandle, which may be a model
// node or a submodel node
// @return model node for this phandle, or negative on error
int FollowPhandle(int phandle, int* target_out);
// Read the device identity information
// On x86 platforms the identify generally comes from two bits of information
// in the SMBIOS system table. These are set up by AP firmware, so in effect
// AP firmware sets the device identity. We also support using the VPD
// (customization_id) to dynamically determine device identity. This has
// been used to support Whitelabels/Zergs in the past, but can be used to
// support any applicable use case.
//
// For ARM systems we could instead look at the device-tree compatible string,
// which should be enough to identify the device. Again this is set up by AP
// firmware, but in fact is built as part of the kernel. The note above about
// VPD applies to ARM as well.
//
// For now we just implement x86 identity, requiring access to memory (to
// read the SMBIOS table) and the VPD device (to read the customization ID).
//
// @smbios_file: File containing memory to scan (typically this is /dev/mem)
// @vpd_file: File containing the customization_id from VPD. Typically this
// is '/sys/firmware/vpd/ro/customization_id'.
// @name_out: Platform name read from SMBIOS system table
// @sku_id_out: SKU ID read from SMBIOS system table
// @customization_id_out: Whitelabel name read from system table
bool ReadIdentity(const base::FilePath& smbios_file,
const base::FilePath& vpd_file, std::string* name_out,
int* sku_id_out, std::string* customization_id_out);
// Read a string from an SMBIOS string table
// See the System Management BIOS (SMBIOS) Reference Specification for full
// details.
// @table: Table to read from
// @string_id: ID of string to read. The value 1 means to pick the first
// string from the the table, i.e. strings are numbered from 1, not 0.
// @return string found, or "" if not found
std::string GetSmbiosString(const SmbiosTable& table, unsigned int string_id);
// Read the system table from memory
// @smbios_file: File containing SMBIOS tables to scan (typically this is
// /sys/firmware/dmi/tables/DMI)
// @table_out: Returns a copy of the table found
// @return true if found, false if not
bool GetSystemTable(const base::FilePath& smbios_file,
SmbiosTable* table_out);
// SMBIOS Table Types
// We only use the system table, but for testing purposes we include BIOS.
enum SmbiosTypes {
SMBIOS_TYPE_BIOS = 0,
SMBIOS_TYPE_SYSTEM,
};
// Search through some tables looking for particular table type.
// All data is copied into the output table, so that the caller does not need
// to reference the memory region to obtain table information.
// @type: Type to search for
// @base_ptr: Start of memory region to search
// @size: Size of region in bytes
// @table_out: Returns a copy of the table found
// @return true if found, false if not
bool FindAndCopyTable(SmbiosTypes type, const char* base_ptr,
unsigned int size, SmbiosTable* table_out);
// Calculates the length of an SMBIOS string table
// The strings are stored one after another, each with a trailing nul, and
// with a final additional nul after the last string. An empty table consists
// of two nul bytes.
// @ptr: Pointer to start of table (and therefore first string)
// @return length of table in bytes
unsigned int StringTableLength(const char* ptr);
// Write out files containing fake identity information, used for testing.
// The two files returned mirror the contents of the files that ReadIdentity()
// uses to ready identity information.
// @name: Platform name to write (e.g. 'Reef')
// @sku_id: SKU ID number to write (e.g. 8)
// @customization_id: Whitelabel name to write
// @smbios_file_out: Returns the 'dev/mem'-style file write that was written
// @vpd_file_out: Returns the '/sys/firmware/vpd/ro/customization_id'-style
// file that was written
// @return true if OK, false on error
bool FakeIdentity(const std::string& name, int sku_id,
const std::string& customization_id,
base::FilePath* smbios_file_out,
base::FilePath* vpd_file_out);
// Write SMBIOS tables to a file, for testing
// Tables are read from /dev/mem. This function writes the tables in the same
// format as they are found in memory.
// This is suitable for parsing as a normal SMBIOS structure in memory.
// We only write a few things, in a very simplistic way, to avoid pulling in
// an entire SMBIOS library.
// @smbios_file: File to write to
// @name: Platform name to write (e.g. 'Reef')
// @sku_id: SKU ID number to write (e.g. 8)
// @return true if OK, false on error
bool WriteFakeTables(base::File* smbios_file, const std::string& name,
int sku_id);
// Decode the device identifiers to resolve the model / submodel
// The decodes the output from 'mosys platform id' into the two fields
// @output: Output string from mosys
// @name_out: Returns the platform name (which may be an empty string)
// @sku_id_out: Returns the SKU ID (which may be -1 if there is none)
// @customization_id_out: Returns the customization id (may be empty string)
// @return true on success, false on failure
bool DecodeIdentifiers(const std::string &output, std::string* name_out,
int* sku_id_out, std::string* customization_id_out);
std::string blob_; // Device tree binary blob
std::string model_; // Model name for this device
int model_offset_ = -1; // Device tree offset of the model's node
int submodel_offset_ = -1; // Device tree offset of the submodel's node
std::string model_name_; // Name of current model
std::string submodel_name_; // Name of current submodel
std::string platform_name_; // Platform name associated with the SKU map
int whitelabel_offset_ = -1; // Device tree offset of the whitelabel model
// We support a special-case 'whitelabel' node which is inside a model. This
// holds the device tree offset of that node. We check this first on any
// property reads, since it overrides the model itself.
int whitelabel_tag_offset_ = -1;
int target_dirs_offset_ = -1; // Device tree offset of the target-dirs node
std::vector<int> default_offsets_; // Device tree offset of default modes
bool inited_ = false; // true if the class is ready for use (Init*ed)
// JSON configuration
std::unique_ptr<const base::Value> json_config_ = nullptr;
const base::DictionaryValue* model_dict_ = nullptr; // Model root
DISALLOW_COPY_AND_ASSIGN(CrosConfig);
};
} // namespace brillo
#endif // CHROMEOS_CONFIG_LIBCROS_CONFIG_CROS_CONFIG_H_