diff options
author | Chris Dearman <chris.dearman@imgtec.com> | 2016-03-17 15:01:57 -0700 |
---|---|---|
committer | Chris Dearman <chris.dearman@imgtec.com> | 2016-03-17 15:20:45 -0700 |
commit | 4234d175b750d5c27a40007ad8ce21172bc9a9c3 (patch) | |
tree | 23d87acba94720b0cb3e31d4f1172ca6785bf323 | |
parent | 5d63509477036224df9481867871e446a59acfe4 (diff) | |
download | creatorci41-4234d175b750d5c27a40007ad8ce21172bc9a9c3.tar.gz |
Add proddata utility
Gives access to the OTP board information: serial number, MAC
addresses.
Imported from systems/proddata commit e4d57941645a42b7a711cbb52c104ff559e1bc9f
Change-Id: I79f4ee1ea4a524c1a3f52d7433a34738bb695751
-rw-r--r-- | BoardConfig.mk | 3 | ||||
-rw-r--r-- | proddata/Android.mk | 39 | ||||
-rw-r--r-- | proddata/device_data.cpp | 286 | ||||
-rw-r--r-- | proddata/device_data.h | 157 | ||||
-rw-r--r-- | proddata/flash_access.cpp | 88 | ||||
-rw-r--r-- | proddata/flash_access.h | 69 | ||||
-rw-r--r-- | proddata/main.cpp | 131 | ||||
-rw-r--r-- | proddata/mtd_access.cpp | 143 | ||||
-rw-r--r-- | proddata/mtd_access.h | 55 | ||||
-rw-r--r-- | proddata/proddata.cpp | 87 | ||||
-rw-r--r-- | proddata/proddata.h | 74 | ||||
-rw-r--r-- | proddata/userotp_access.cpp | 105 | ||||
-rw-r--r-- | proddata/userotp_access.h | 54 |
13 files changed, 1291 insertions, 0 deletions
diff --git a/BoardConfig.mk b/BoardConfig.mk index 6155059..d9acbbd 100644 --- a/BoardConfig.mk +++ b/BoardConfig.mk @@ -38,6 +38,9 @@ PRODUCT_COPY_FILES += \ device/imagination/creatorci41/fstab.device:root/fstab.${soc_name} \ device/imagination/creatorci41/provision-device:provision-device +DEVICE_PACKAGES += \ + proddata + BOARD_SEPOLICY_DIRS += \ device/imagination/creatorci41/sepolicy diff --git a/proddata/Android.mk b/proddata/Android.mk new file mode 100644 index 0000000..0c4e4c8 --- /dev/null +++ b/proddata/Android.mk @@ -0,0 +1,39 @@ +# +# Copyright (C) 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_PATH := $(call my-dir) + +# proddata +# ============================================================================== +include $(CLEAR_VARS) +LOCAL_SRC_FILES := \ + device_data.cpp \ + flash_access.cpp \ + main.cpp \ + mtd_access.cpp \ + proddata.cpp \ + userotp_access.cpp + +LOCAL_MODULE := proddata +LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS += -Wall -Werror +LOCAL_SHARED_LIBRARIES := \ + libbase \ + liblog \ + libutils +LOCAL_C_INCLUDES := \ + $(TOP)/system/core/base/include +include $(BUILD_EXECUTABLE) diff --git a/proddata/device_data.cpp b/proddata/device_data.cpp new file mode 100644 index 0000000..82b05ad --- /dev/null +++ b/proddata/device_data.cpp @@ -0,0 +1,286 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * DeviceData class + * + * @author Imagination Technologies + * + * @copyright <b>Copyright 2016 by Imagination Technologies Limited and/or its affiliated group companies.</b> + */ + +#include "device_data.h" +#ifdef __ANDROID__ +#include <android-base/logging.h> +#define DLOG(x) LOG(x) +#else +#include <glog/logging.h> +#endif + + +static const int kCRCSize = 2; + +/* CRC-16 lookup table */ +static const uint16_t crctab16[] = { + 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, + 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440, + 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, + 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841, + 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, + 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, + 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641, + 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040, + 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240, + 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, + 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, + 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, + 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, + 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40, + 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, + 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041, + 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240, + 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441, + 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, + 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, + 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, + 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, + 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640, + 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041, + 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241, + 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440, + 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, + 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841, + 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, + 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41, + 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, + 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040 +}; + +uint16_t update_crc16(uint16_t crc, uint8_t c) { + + crc = (crc >> 8) ^ crctab16[(crc ^ c) & 0xff]; + + return crc; +} + +static std::vector<uint8_t> CalculateDataCRC(const std::vector<uint8_t> &data) { + uint16_t crc16 = 0; + const uint8_t *ptr = data.data(); + int size = data.size(); + while (size) { + crc16 = update_crc16(crc16, *ptr); + ptr++; + size--; + } + /* convert uint16_t crc to crc vector */ + uint8_t crc_0 = (crc16 >> 8) & 0xff; + uint8_t crc_1 = crc16 & 0xff; + + std::vector<uint8_t> crc; + + crc.push_back(crc_0); + crc.push_back(crc_1); + + return crc; +} + +static void AddDataCRC(std::vector<uint8_t> *data) { + std::vector<uint8_t> crc = CalculateDataCRC(*data); + data->insert(data->begin(), crc.begin(), crc.end()); +} + +static void CheckDataCRC(const std::vector<uint8_t> &data) { + /* ignore first 2 bytes which stores crc */ + std::vector<uint8_t> data_without_crc(data.begin() + kCRCSize, data.end()); + std::vector<uint8_t> crc = CalculateDataCRC(data_without_crc); + + if ((crc[0] != data[0]) || (crc[1] != data[1])) { + LOG(ERROR) << "Data corrupted:CRC failed"; +#ifdef __ANDROID__ + exit(-1); +#else + throw std::runtime_error("Data corrupted:CRC failed"); +#endif + } +} + +/* TODO: Scenario of version check will be different when more than one version is actually + supported, need to select register map according to version read and proceed for reading + content. */ + +static void CheckDataLayoutVersion(std::vector<uint8_t> &data) { + uint8_t version = data[2]; + + /* TODO: Change hardcoded version, when support for more than one version is added */ + if (version != 0x01) { +#ifdef __ANDROID__ + LOG(ERROR) << "Invalid data layout version"; + exit(-1); +#else + throw std::runtime_error("Invalid data layout version"); +#endif + } +} + +DeviceData::DeviceData(std::unique_ptr<FlashAccess> flash_access) : + flash_access_(std::move(flash_access)) { + DLOG(INFO) << "Initialising DeviceData"; +} + +DeviceData::~DeviceData() { + DLOG(INFO) << "Deinitialising DeviceData"; +} + +int DeviceData::GetRegisterSize(RegisterName register_name) { + std::map<std::string, struct DataField> register_data_fields; + + if (register_name == register0) { + register_data_fields = register0_data_fields_; + } else if (register_name == register1) { + register_data_fields = register1_data_fields_; + } + + int size = 0; + for (const auto &field : register_data_fields) { + size = size + field.second.size; + } + + return size; +} + +int DeviceData::GetCRCOffset(RegisterName register_name) { + const DataField field = GetDataField(register_name, "CRC"); + + return field.offset; +} + +const DeviceData::DataField DeviceData::GetDataField(RegisterName register_name, + const std::string &name) { + std::map<std::string, struct DataField> register_data_fields; + + if (register_name == register0) { + register_data_fields = register0_data_fields_; + } else if (register_name == register1) { + register_data_fields = register1_data_fields_; + } + + for (const auto &field : register_data_fields) { + if (field.first == name) { + return field.second; + } + } + + std::string error = "Invalid data field: " + name; +#ifdef __ANDROID__ + LOG(ERROR) << error; + exit(-1); +#else + throw std::runtime_error(error); +#endif +} + +void DeviceData::ParseData(const std::vector<uint8_t> &data, std::vector<uint8_t> *mac_data, + std::vector<uint8_t> *wifi_data) { + int mac_data_size = GetRegisterSize(register0) - kCRCSize; + int wifi_data_size = GetRegisterSize(register1) - kCRCSize; + int size = data.size(); + if (size != (mac_data_size + wifi_data_size)) { + LOG(ERROR) << "Data size error"; +#ifdef __ANDROID__ + exit(-1); +#else + throw std::runtime_error("Data size error"); +#endif + } + + mac_data->assign(data.begin(), data.begin() + mac_data_size); + wifi_data->assign(data.begin() + mac_data_size, data.end()); + + /* Add CRC */ + AddDataCRC(mac_data); + AddDataCRC(wifi_data); +} + +void DeviceData::Write(const std::vector<uint8_t> &data) { + std::vector<uint8_t> mac_data; + std::vector<uint8_t> wifi_data; + + ParseData(data, &mac_data, &wifi_data); + + flash_access_->Write(mac_data, GetCRCOffset(register0)); + flash_access_->Write(wifi_data, GetCRCOffset(register1)); +} + +std::vector<uint8_t> DeviceData::Read() { + std::vector<uint8_t> data[2]; + + /* read data from 2 registers */ + for (int i = 0; i < 2; i++) { + DeviceData::RegisterName register_name = static_cast<DeviceData::RegisterName>(i); + data[i] = flash_access_->Read(GetRegisterSize(register_name), GetCRCOffset(register_name)); + + /* check crc */ + CheckDataCRC(data[i]); + + /* Check version */ + CheckDataLayoutVersion(data[i]); + + /* remove crc from data */ + data[i].erase(data[i].begin(), data[i].begin() + kCRCSize); + } + + std::vector<uint8_t> buf = data[0]; + buf.insert(buf.end(), data[1].begin(), data[1].end()); + + return buf; +} + +std::vector<uint8_t> DeviceData::ReadValue(const std::string &name) { + DeviceData::RegisterName register_name; + DataField field; + if (register0_data_fields_.end() != register0_data_fields_.find(name)) { + field = GetDataField(register0, name); + register_name = register0; + } else if (register1_data_fields_.end() != register1_data_fields_.find(name)) { + field = GetDataField(register1, name); + register_name = register1; + } else if (key_serial == name) { + return flash_access_->ReadSerial(); + } else { + LOG(ERROR) << "Invalid data field: " << name; +#ifdef __ANDROID__ + exit(-1); +#else + throw std::runtime_error("Invalid data field: " + name); +#endif + } + + std::vector<uint8_t> buf; + + /* read complete register into buf to check for crc and version */ + buf = flash_access_->Read(GetRegisterSize(register_name), GetCRCOffset(register_name)); + CheckDataCRC(buf); + CheckDataLayoutVersion(buf); + + int data_field_position = field.offset - GetCRCOffset(register_name); + + /* Get data field from buf */ + std::vector<uint8_t> data(buf.begin() + data_field_position, + buf.begin() + data_field_position + field.size); + + return data; +} diff --git a/proddata/device_data.h b/proddata/device_data.h new file mode 100644 index 0000000..791e525 --- /dev/null +++ b/proddata/device_data.h @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * DeviceData class + * + * @author Imagination Technologies + * + * @copyright <b>Copyright 2016 by Imagination Technologies Limited and/or its affiliated group companies.</b> + */ + + +#ifndef DEVICEDATA_H_ +#define DEVICEDATA_H_ + +#include <map> +#include <memory> +#include <string> +#include <vector> +#include "flash_access.h" + +/** + * @brief class for maintaining device data layout and performing read/write operations + */ +class DeviceData { + public: + /** + * @brief Constructor + * + * Creates an instance of DeviceData + * @param[in] flash_access unique pointer to FlashAccess implementation + * + */ + explicit DeviceData(std::unique_ptr<FlashAccess> flash_access); + ~DeviceData(); + + /** + * @brief Parse the data into wifi calibration data and MAC and write appropriately + * + * @param[in] data chunk of data to be written + */ + void Write(const std::vector<uint8_t> &data); + + /** + * @brief Read device data from memory + * + * returns vector containing raw data + */ + std::vector<uint8_t> Read(); + + /** + * @brief Read device data value e.g MAC_0 + * + * @param[in] name name of data field + * returns vector containing raw data + */ + std::vector<uint8_t> ReadValue(const std::string &name); + + /** + * @brief struct for storing size and offset for each field + */ + struct DataField { + int size; + int offset; + }; + + private: + const std::string key_serial{"SERIAL"}; + const std::map<std::string, struct DataField> register0_data_fields_ { + {"CRC", {2, 0}}, + {"VERSION", {1, 2}}, + {"MAC_0", {6, 3}}, + {"MAC_1", {6, 9}}, + {"MAC_2", {6, 15}}, + {"MAC_3", {6, 21}}, + {"MAC_4", {6, 27}}, + {"MAC_5", {6, 33}}, + }; + const std::map<std::string, struct DataField> register1_data_fields_ { + {"CRC", {2, 256}}, + {"VERSION", {1, 258}}, + {"DCXO", {1, 259}}, + {"DSSS_TX_POWER_2.4", {1, 260}}, + {"OFDM_TX_POWER_2.4_MCS7", {1, 261}}, + {"OFDM_TX_POWER_5B1_MCS5", {1, 262}}, + {"OFDM_TX_POWER_5B2_MCS5", {1, 263}}, + {"OFDM_TX_POWER_5B3_MCS5", {1, 264}}, + {"OFDM_TX_POWER_5B4_MCS5", {1, 265}}, + {"OFDM_TX_POWER_5B1_MCS7", {1, 266}}, + {"OFDM_TX_POWER_5B2_MCS7", {1, 267}}, + {"OFDM_TX_POWER_5B3_MCS7", {1, 268}}, + {"OFDM_TX_POWER_5B4_MCS7", {1, 269}}, + {"OFDM_TX_POWER_5B1_MCS8", {1, 270}}, + {"OFDM_TX_POWER_5B2_MCS8", {1, 271}}, + {"OFDM_TX_POWER_5B3_MCS8", {1, 272}}, + {"OFDM_TX_POWER_5B4_MCS8", {1, 273}}, + {"OFDM_TX_POWER_5B1_MCS9", {1, 274}}, + {"OFDM_TX_POWER_5B2_MCS9", {1, 275}}, + {"OFDM_TX_POWER_5B3_MCS9", {1, 276}}, + {"OFDM_TX_POWER_5B4_MCS9", {1, 277}}, + }; + + enum RegisterName { + register0, + register1, + }; + + std::unique_ptr<FlashAccess> flash_access_; + + /** + * @brief Parse data vector to mac data and wifi data and validate CRC + * + * @param[in] data vector containing raw data + * @param[out] mac_str pointer to vector storing mac data + * @param[out] wifi_str pointer to vector storing wifi data + */ + void ParseData(const std::vector<uint8_t> &data, std::vector<uint8_t> *mac_data, + std::vector<uint8_t> *wifi_data); + + /** + * @brief Get Sum of size of all data fields in map + * + * @param[in] register_name enum specifying which register map to use + */ + int GetRegisterSize(RegisterName register_name); + + /** + * @brief Get offset of CRC field from register map + * + * @param[in] register_name enum specifying which register map to use + */ + int GetCRCOffset(RegisterName register_name); + + /** + * @brief Get DataField structure(size, offset) from corresponding name(key) + * + * @param[in] register_name enum specifying which register map to use + * @param[in] name name of data field + */ + const DeviceData::DataField GetDataField(RegisterName register_name, const std::string &name); +}; + +#endif // DEVICEDATA_H_ diff --git a/proddata/flash_access.cpp b/proddata/flash_access.cpp new file mode 100644 index 0000000..c549c85 --- /dev/null +++ b/proddata/flash_access.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Abstract class for flash access + * + * @author Imagination Technologies + * + * @copyright <b>Copyright 2016 by Imagination Technologies Limited and/or its affiliated group companies.</b> + */ + +#include "flash_access.h" +#ifdef __ANDROID__ +#include <android-base/logging.h> +#define DLOG(x) LOG(x) +#else +#include <glog/logging.h> +#endif +#include <mtd/mtd-user.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <stdexcept> + +FlashAccess::FlashAccess(const std::string &device_name) { + fd_ = open(device_name.c_str(), O_RDWR); + if (fd_ < 0) { + DLOG(ERROR) << "Can't open device: " << strerror(errno); +#ifdef __ANDROID__ + exit(-1); +#else + throw std::runtime_error("FlashAccess Initialization failed"); +#endif + } +} + +FlashAccess::~FlashAccess() { + close(fd_); +} + +std::vector<uint8_t> FlashAccess::ReadSerial() { + DLOG(INFO) << "Reading serial number"; + const int size = 8; + std::vector<uint8_t> buf(size); + int val = MTD_OTP_FACTORY; + if (ioctl(fd_, OTPSELECT, &val) < 0) { + DLOG(ERROR) << "ioctl failed and returned error: " << strerror(errno); +#ifdef __ANDROID__ + exit(-1); +#else + throw std::runtime_error("Factory OTP access failed"); +#endif + } + + if (lseek(fd_, 0, SEEK_SET) < 0) { + DLOG(ERROR) << "read serial: lseek failed: " << strerror(errno); +#ifdef __ANDROID__ + exit(-1); +#else + throw std::runtime_error("read serial: lseek failed"); +#endif + } + + int ret = read(fd_, buf.data(), buf.size()); + if (ret < 0) { + DLOG(ERROR) << "read serial num failed:" << strerror(errno); +#ifdef __ANDROID__ + exit(-1); +#else + throw std::runtime_error("read serial num failed"); +#endif + } + return buf; +} + diff --git a/proddata/flash_access.h b/proddata/flash_access.h new file mode 100644 index 0000000..7f2ea4d --- /dev/null +++ b/proddata/flash_access.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Abstract class for flash access + * + * @author Imagination Technologies + * + * @copyright <b>Copyright 2016 by Imagination Technologies Limited and/or its affiliated group companies.</b> + */ + +#ifndef FLASHACCESS_H_ +#define FLASHACCESS_H_ + +#include <string> +#include <vector> + +/** + * @brief Abstract class for flash access + */ +class FlashAccess { + public: + explicit FlashAccess(const std::string &device_name); + virtual ~FlashAccess(); + + /** + * @brief Write data to flash + * + * @param[in] buf chunk of data to be written + * @param[in] offset device offset + */ + virtual void Write(const std::vector<uint8_t> &buf, const int offset) = 0; + + /** + * @brief Read data from flash storage + + * @param[in] size size of data to be read + * @param[in] offset device offset + * @returns vector containing read data + * + */ + virtual std::vector<uint8_t> Read(const int size, const int offset) = 0; + + /** + * @brief Read serial number + * + * returns vector containing serial number + */ + virtual std::vector<uint8_t> ReadSerial(); + + protected: + int fd_; +}; + +#endif // FLASHACCESS_H_ diff --git a/proddata/main.cpp b/proddata/main.cpp new file mode 100644 index 0000000..d764083 --- /dev/null +++ b/proddata/main.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Proddata tool main entry point + * + * @author Imagination Technologies + * + * @copyright <b>Copyright 2016 by Imagination Technologies Limited and/or its affiliated group companies.</b> + */ + +#ifdef __ANDROID__ +#include <android-base/logging.h> +#define DLOG(x) LOG(x) +#else +#include <glog/logging.h> +#endif +#include <iomanip> +#include <iostream> +#include <string> +#include "proddata.h" +#include "flash_access.h" +#include "userotp_access.h" + +static void PrintData(std::vector<uint8_t> &data) { + int size = data.size(); + for (int i = 0; i < size; i++) { + std::cout << std::setw(2) << std::setfill('0') << std::hex << static_cast<int>(data[i]); + } + std::cout << std::endl; +} + +static void usage() { + std::string mesg = "Usage: proddata write <data> Write calibration data \n" + " proddata read Read calibration data \n" + " proddata read <name e.g DCXO> Read data field \n"; + std::cerr << mesg; +} + +#ifdef __ANDROID__ +int main(int argc, char* argv[]) { + + if (argc < 2) { + usage(); + return -1; + } + + // TODO(Sagar): Make FlashAccess implemetation and hardcoded device name configurable + std::unique_ptr<FlashAccess> flash_access(new UserOTPAccess("/dev/mtd/mtd0")); + Proddata proddata(std::move(flash_access)); + + if (!strcmp(argv[1], "write")) { + if (argv[2] == NULL) { + std::cerr << "Specify data to be written to OTP" << std::endl; + return -1; + } else { + proddata.Write(argv[2]); + } + } else if (!strcmp(argv[1], "read")) { + std::vector<uint8_t> data; + if (argv[2] == NULL) { + data = proddata.Read(); + } else { + data = proddata.ReadValue(argv[2]); + } + PrintData(data); + } else { + std::cerr << "Invalid command" << std::endl; + usage(); + return -1; + } + + return 0; +} +#else +int main(int argc, char* argv[]) { + google::InitGoogleLogging(argv[0]); + + if (argc < 2) { + usage(); + return -1; + } + + try { + // TODO(Sagar): Make FlashAccess implemetation and harcoded device name configurable + std::unique_ptr<FlashAccess> flash_access(new UserOTPAccess("/dev/mtd1")); + Proddata proddata(std::move(flash_access)); + + if (!strcmp(argv[1], "write")) { + if (argv[2] == NULL) { + std::cerr << "Specify data to be written to OTP" << std::endl; + return -1; + } else { + proddata.Write(argv[2]); + } + } else if (!strcmp(argv[1], "read")) { + std::vector<uint8_t> data; + if (argv[2] == NULL) { + data = proddata.Read(); + } else { + data = proddata.ReadValue(argv[2]); + } + PrintData(data); + } else { + std::cerr << "Invalid command" << std::endl; + usage(); + return -1; + } + } catch (std::runtime_error &e) { + google::ShutdownGoogleLogging(); + return -1; + } + + google::ShutdownGoogleLogging(); + return 0; +} +#endif diff --git a/proddata/mtd_access.cpp b/proddata/mtd_access.cpp new file mode 100644 index 0000000..bc15719 --- /dev/null +++ b/proddata/mtd_access.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * MTDAccess class + * + * @author Imagination Technologies + * + * @copyright <b>Copyright 2016 by Imagination Technologies Limited and/or its affiliated group companies.</b> + */ + +#include "mtd_access.h" +#ifdef __ANDROID__ +#include <android-base/logging.h> +#define DLOG(x) LOG(x) +#else +#include <glog/logging.h> +#endif +#include <fcntl.h> +#include <sys/ioctl.h> +#include <stdexcept> + +MTDAccess::MTDAccess(const std::string &device_name) : FlashAccess(device_name) { + DLOG(INFO) << "Initialising MTDAccess"; + if (ioctl(fd_, MEMGETINFO, &mtd_info_) < 0) { + DLOG(ERROR) << "ioctl failed and returned error: " << strerror(errno); + close(fd_); +#ifdef __ANDROID__ + exit(-1); +#else + throw std::runtime_error("MTDAccess Initialization failed"); +#endif + } +} + +MTDAccess::~MTDAccess() { + DLOG(INFO) << "Deinitialising MTDAccess"; +} + +/** + * Replace vector content with replacement vector from specified position + * + * @param[out] data vector whose content is to be replaced + * @param[in] replacement_vector replacement vector + * @param[in] position position in the vector from where content is to be replaced + */ + +static void replace(std::vector<uint8_t> *data, const std::vector<uint8_t> &replacement_vector, + int position) { + auto erase_end = data->begin() + position + replacement_vector.size(); + + if (erase_end > data->end()) { /* data should fit in 1st sector of mtd device */ +#ifdef __ANDROID__ + LOG(ERROR) << "Cannot replace content of vector with replacement vector"; + exit(-1); +#else + throw std::runtime_error("Cannot replace content of vector with replacement vector"); +#endif + } + + data->erase(data->begin() + position, erase_end); + data->insert(data->begin() + position, replacement_vector.begin(), replacement_vector.end()); +} + +void MTDAccess::Write(const std::vector<uint8_t> &buf, const int offset) { + int sector_size = mtd_info_.erasesize; + + /* read sector (note : it is assumed that all the device data will be on 1st sector) */ + std::vector<uint8_t> read_buf = this->Read(sector_size, 0); + + /* erase sector */ + erase_info_t ei; + ei.length = mtd_info_.erasesize; + ei.start = 0; + if (ioctl(fd_, MEMERASE, &ei) < 0) { + DLOG(ERROR) << "ioctl failed and returned error: " << strerror(errno); +#ifdef __ANDROID__ + exit(-1); +#else + throw std::runtime_error("mtd write: ioctl failed"); +#endif + } + /* modify sector */ + replace(&read_buf, buf, offset); + + /* write sector */ + if (lseek(fd_, 0, SEEK_SET) < 0) { + DLOG(ERROR) << "mtd write: lseek failed:" << strerror(errno); +#ifdef __ANDROID__ + exit(-1); +#else + throw std::runtime_error("mtd write: lseek failed"); +#endif + } + + int ret = write(fd_, read_buf.data(), sector_size); + if (ret < 0) { + DLOG(ERROR) << "mtd write failed:" << strerror(errno); +#ifdef __ANDROID__ + exit(-1); +#else + throw std::runtime_error("mtd write failed"); +#endif + } +} + +std::vector<uint8_t> MTDAccess::Read(const int size, const int offset) { + std::vector<uint8_t> buf(size); + if (lseek(fd_, offset, SEEK_SET) < 0) { + DLOG(ERROR) << "mtd read: lseek failed:" << strerror(errno); +#ifdef __ANDROID__ + exit(-1); +#else + throw std::runtime_error("mtd read: lseek failed"); +#endif + } + + int ret = read(fd_, buf.data(), buf.size()); + if (ret < 0) { + DLOG(ERROR) << "mtd read failed:" << strerror(errno); +#ifdef __ANDROID__ + exit(-1); +#else + throw std::runtime_error("mtd read failed"); +#endif + } + return buf; +} + diff --git a/proddata/mtd_access.h b/proddata/mtd_access.h new file mode 100644 index 0000000..2fab793 --- /dev/null +++ b/proddata/mtd_access.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * MTDAccess class + * + * @author Imagination Technologies + * + * @copyright <b>Copyright 2016 by Imagination Technologies Limited and/or its affiliated group companies.</b> + */ + +#ifndef MTDACCESS__H_ +#define MTDACCESS__H_ + +#include <mtd/mtd-user.h> +#include <string> +#include <vector> +#include "flash_access.h" + +/** + * @brief MTDAccess class to perfrom read/write on mtd device + */ +class MTDAccess final: public FlashAccess { + public: + /** + * @brief Constructor + * + * Creates an instance of MTDAccess + * + */ + explicit MTDAccess(const std::string &device_name); + ~MTDAccess(); + + void Write(const std::vector<uint8_t> &buf, const int offset); + std::vector<uint8_t> Read(const int size, const int offset); + + private: + mtd_info_t mtd_info_; +}; + +#endif // MTDACCESS_H_ diff --git a/proddata/proddata.cpp b/proddata/proddata.cpp new file mode 100644 index 0000000..e5ee18c --- /dev/null +++ b/proddata/proddata.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Proddata class + * + * @author Imagination Technologies + * + * @copyright <b>Copyright 2016 by Imagination Technologies Limited and/or its affiliated group companies.</b> + */ + +#include "proddata.h" +#ifdef __ANDROID__ +#include <android-base/logging.h> +#define DLOG(x) LOG(x) +#else +#include <glog/logging.h> +#endif +#include "device_data.h" +#include "flash_access.h" + +/** + * Format string containing hexadecimal symbols + * @note string should only have symbols 0-9 A-F + * @return vector containing raw data + * + */ + +std::vector<uint8_t> FormatString(const std::string &data) { + int size = data.size(); + std::vector<uint8_t> buf(size/2); + const char *src = data.c_str(); + int j = 0; + for (int i = 0; i < size; i += 2) { + sscanf(src + i, "%02hhx", &buf[j++]); + } + + return buf; +} + +Proddata::Proddata(std::unique_ptr<FlashAccess> flash_access) { + DLOG(INFO) << "Initialising Proddata"; + device_data_ = std::unique_ptr<DeviceData>(new DeviceData(std::move(flash_access))); +} + +Proddata::~Proddata() { + LOG(INFO) << "Deinitialising Proddata"; +} + +void Proddata::Write(const std::string &data) { + LOG(INFO) << "Writing wifi calibration and MAC data"; + if (data.size() % 2 != 0) { + LOG(ERROR) << "Invalid data given"; +#ifdef __ANDROID__ + exit(-1); +#else + throw std::runtime_error("Invalid data given"); +#endif + } + + std::vector<uint8_t> buf = FormatString(data); + device_data_->Write(buf); +} + +std::vector<uint8_t> Proddata::Read() { + DLOG(INFO) << "Reading wifi calibration and MAC data"; + return device_data_->Read(); +} + +std::vector<uint8_t> Proddata::ReadValue(const std::string &name) { + DLOG(INFO) << "Reading data"; + return device_data_->ReadValue(name); +} diff --git a/proddata/proddata.h b/proddata/proddata.h new file mode 100644 index 0000000..2b0089e --- /dev/null +++ b/proddata/proddata.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * Proddata class + * + * @author Imagination Technologies + * + * @copyright <b>Copyright 2016 by Imagination Technologies Limited and/or its affiliated group companies.</b> + */ + +#ifndef PRODDATA_H_ +#define PRODDATA_H_ + +#include <string> +#include <vector> +#include "device_data.h" + +/** + * @brief Class to perform read/write of production data. + */ +class Proddata { + public: + /** + * @brief Constructor + * + * Creates an instance of Proddata + * + * @param[in] flash_access unique pointer to FlashAccess implementation + */ + explicit Proddata(std::unique_ptr<FlashAccess> flash_access); + ~Proddata(); + + /** + * @brief Write production data + * + * @param[in] data chunk of data to be written + */ + void Write(const std::string &data); + + /** + * @brief Read production data + * + * returns vector containing raw data + */ + std::vector<uint8_t> Read(); + + /** + * @brief Read production data value e.g mac + * + * @param[in] value to be read + * returns vector containing raw data + */ + std::vector<uint8_t> ReadValue(const std::string& name); + + private: + std::unique_ptr<DeviceData> device_data_; +}; + +#endif // PRODDATA_H_ diff --git a/proddata/userotp_access.cpp b/proddata/userotp_access.cpp new file mode 100644 index 0000000..6397465 --- /dev/null +++ b/proddata/userotp_access.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * UserOTPAccess class + * + * @author Imagination Technologies + * + * @copyright <b>Copyright 2016 by Imagination Technologies Limited and/or its affiliated group companies.</b> + */ + +#include "userotp_access.h" +#ifdef __ANDROID__ +#include <android-base/logging.h> +#define DLOG(x) LOG(x) +#else +#include <glog/logging.h> +#endif +#include <mtd/mtd-user.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <stdexcept> + +UserOTPAccess::UserOTPAccess(const std::string &device_name) : FlashAccess(device_name) { + DLOG(INFO) << "Initialising UserOTPAccess"; +} + +UserOTPAccess::~UserOTPAccess() { + DLOG(INFO) << "Deinitialising UserOTPAccess"; +} + +void UserOTPAccess::Write(const std::vector<uint8_t> &buf, const int offset) { + SelectUserOTP(); + + if (lseek(fd_, offset, SEEK_SET) < 0) { + DLOG(ERROR) << "user otp write: lseek failed: " << strerror(errno); +#ifdef __ANDROID__ + exit(-1); +#else + throw std::runtime_error("user otp write: lseek failed"); +#endif + } + + int ret = write(fd_, buf.data(), buf.size()); + if (ret < 0) { + DLOG(ERROR) << "user otp write failed: " << strerror(errno); +#ifdef __ANDROID__ + exit(-1); +#else + throw std::runtime_error("user otp write failed"); +#endif + } +} + +std::vector<uint8_t> UserOTPAccess::Read(const int size, const int offset) { + std::vector<uint8_t> buf(size); + SelectUserOTP(); + + if (lseek(fd_, offset, SEEK_SET) < 0) { + DLOG(ERROR) << "user otp read: lseek failed: " << strerror(errno); +#ifdef __ANDROID__ + exit(-1); +#else + throw std::runtime_error("user otp read: lseek failed"); +#endif + } + + int ret = read(fd_, buf.data(), buf.size()); + if (ret < 0) { + DLOG(ERROR) << "user otp read failed:" << strerror(errno); +#ifdef __ANDROID__ + exit(-1); +#else + throw std::runtime_error("user otp read failed"); +#endif + } + return buf; +} + +void UserOTPAccess::SelectUserOTP() { + int val = MTD_OTP_USER; + if (ioctl(fd_, OTPSELECT, &val) < 0) { + DLOG(ERROR) << "ioctl failed and returned error: " << strerror(errno); +#ifdef __ANDROID__ + exit(-1); +#else + throw std::runtime_error("UserOTPAccess: ioctl failed"); +#endif + } +} + diff --git a/proddata/userotp_access.h b/proddata/userotp_access.h new file mode 100644 index 0000000..54f5a37 --- /dev/null +++ b/proddata/userotp_access.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * UserOTPAccess class + * + * @author Imagination Technologies + * + * @copyright <b>Copyright 2016 by Imagination Technologies Limited and/or its affiliated group companies.</b> + */ + +#ifndef USEROTPACCESS__H_ +#define USEROTPACCESS__H_ + +#include <string> +#include <vector> +#include "flash_access.h" + +/** + * @brief UserOTPAccess class to perform read/write on user OTP memory + */ +class UserOTPAccess final: public FlashAccess { + public: + /** + * @brief Constructor + * + * Creates an instance of UserOTPAccess + * + */ + explicit UserOTPAccess(const std::string &device_name); + ~UserOTPAccess(); + + void Write(const std::vector<uint8_t> &buf, const int offset); + std::vector<uint8_t> Read(const int size, const int offset); + + private: + void SelectUserOTP(); +}; + +#endif // USEROTPACCESS_H_ |