cr50: signer: sync up with upstream

This change just copies files shared between two repositories which
have changed since the last sync up. This time it is as of @CL85098.

BRANCH=none
BUG=none
TEST=the signed image  boots fine on the b1 board.

Change-Id: I7a1d1b344119e6f6729a38bbea04da75f2d3371c
Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/329407
Reviewed-by: Marius Schilder <mschilder@chromium.org>
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
This commit is contained in:
Vadim Bendebury
2016-02-26 16:42:16 -08:00
committed by chrome-bot
parent b47c1fed20
commit d1bf3aecfa
4 changed files with 264 additions and 302 deletions

View File

@@ -7,8 +7,8 @@
#include <getopt.h>
#include <inttypes.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -19,12 +19,12 @@
#include <rapidjson/document.h>
#endif
#include <string>
#include <map>
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <iostream>
#include <sstream>
#include <libxml/parser.h>
@@ -32,17 +32,24 @@
using namespace std;
#define VERBOSE(...) do{if(FLAGS_verbose)fprintf(stderr, __VA_ARGS__);}while(0)
#define FATAL(...) do{fprintf(stderr, __VA_ARGS__);abort();}while(0)
#define VERBOSE(...) \
do { \
if (FLAGS_verbose) fprintf(stderr, __VA_ARGS__); \
} while (0)
#define FATAL(...) \
do { \
fprintf(stderr, __VA_ARGS__); \
abort(); \
} while (0)
bool FLAGS_verbose = false;
bool FLAGS_cros = false;
int last_logical_offset = -1;
int fuse_index = 0;
// Brute xml parsing.
// Find HashItem w/ key == name, return val field, recursively.
static
xmlChar* get_val(xmlNodePtr node, const char* key) {
static xmlChar* get_val(xmlNodePtr node, const char* key) {
xmlNode* cur_node = NULL;
xmlChar* val = NULL;
@@ -75,9 +82,8 @@ xmlChar* get_val(xmlNodePtr node, const char* key) {
return val;
}
static
bool get_fuse(xmlNodePtr a_node,
map<string, uint32_t>* ids, map<string, uint32_t>* bits) {
static bool get_fuse(xmlNodePtr a_node, map<string, uint32_t>* ids,
map<string, uint32_t>* bits) {
bool result = false;
// Interested in <HashType>
@@ -110,9 +116,8 @@ bool get_fuse(xmlNodePtr a_node,
return result;
}
static
bool find_fuses(xmlNodePtr a_node,
map<string, uint32_t>* ids, map<string, uint32_t>* bits) {
static bool find_fuses(xmlNodePtr a_node, map<string, uint32_t>* ids,
map<string, uint32_t>* bits) {
xmlNode* cur_node = NULL;
bool done = false;
@@ -137,9 +142,8 @@ bool find_fuses(xmlNodePtr a_node,
return done;
}
static
bool find_default_reg_value(xmlNodePtr a_node,
const string& regname, string* result) {
static bool find_default_reg_value(xmlNodePtr a_node, const string& regname,
string* result) {
xmlNode* cur_node = NULL;
bool done = false;
@@ -168,12 +172,9 @@ bool find_default_reg_value(xmlNodePtr a_node,
return done;
}
// Read XML, populate two maps, name -> val
bool readXML(const string& filename,
map<string, uint32_t>* ids,
map<string, uint32_t>* bits,
uint32_t* p4cl) {
bool readXML(const string& filename, map<string, uint32_t>* ids,
map<string, uint32_t>* bits, uint32_t* p4cl) {
bool result = false;
LIBXML_TEST_VERSION
@@ -182,7 +183,8 @@ bool readXML(const string& filename,
if (doc) {
result = find_fuses(xmlDocGetRootElement(doc), ids, bits);
string p4clStr;
result &= find_default_reg_value(xmlDocGetRootElement(doc), "SWDP_P4_LAST_SYNC", &p4clStr);
result &= find_default_reg_value(xmlDocGetRootElement(doc),
"SWDP_P4_LAST_SYNC", &p4clStr);
if (result) {
*p4cl = atoi(p4clStr.c_str());
}
@@ -195,84 +197,14 @@ bool readXML(const string& filename,
return result;
}
// Write minified XML
bool writeXML(const string& filename,
map<string, uint32_t>& ids,
map<string, uint32_t>& bits,
uint32_t p4cl) {
bool result = false;
// Get the names in order.
vector<string> names;
names.resize(ids.size());
for (map<string, uint32_t>::const_iterator it = ids.begin(); it != ids.end(); ++it) {
const string& name = it->first;
uint32_t offset = it->second;
names[offset] = name;
}
// Write out as nodes.
ofstream ofs(filename.c_str(), ofstream::out);
if (ofs) {
ofs << "<ArrayType>" << endl;
for (size_t i = 0; i < names.size(); ++i) {
const string& name = names[i];
ofs << "<ArrayItem>" << endl;
ofs << " <HashType>" << endl;
ofs << " <HashItem>" << endl;
ofs << " <Key>RegName</Key>" << endl;
ofs << " <Value>" << name << "</Value>" << endl;
ofs << " </HashItem>" << endl;
ofs << " <HashItem>" << endl;
ofs << " <Key>FuseLogicalOffset</Key>" << endl;
ofs << " <Value>" << i << "</Value>" << endl;
ofs << " </HashItem>" << endl;
ofs << " <HashItem>" << endl;
ofs << " <Key>Width</Key>" << endl;
ofs << " <Value>" << bits[name] << "</Value>" << endl;
ofs << " </HashItem>" << endl;
ofs << " </HashType>" << endl;
ofs << "</ArrayItem>" << endl;
}
// Write p4cl
ofs << "<ArrayItem>" << endl;
ofs << "<HashType>" << endl;
ofs << " <HashItem>" << endl;
ofs << " <Key>RegName</Key>" << endl;
ofs << " <Value>SWDP_P4_LAST_SYNC</Value>" << endl;
ofs << " </HashItem>" << endl;
ofs << " <HashItem>" << endl;
ofs << " <Key>Default</Key>" << endl;
ofs << " <Value>" << p4cl << "</Value>" << endl;
ofs << " </HashItem>" << endl;
// Write fake offset to make parser happy
ofs << " <HashItem>" << endl;
ofs << " <Key>FuseLogicalOffset</Key>" << endl;
ofs << " <Value>0</Value>" << endl;
ofs << " </HashItem>" << endl;
ofs << "</HashType>" << endl;
ofs << "</ArrayItem>" << endl;
ofs << "</ArrayType>" << endl;
result = true;
}
return result;
}
// Read JSON, populate map, name -> val
bool readJSON(const string& filename,
string* tag,
map<string, uint32_t>* values,
map<string, uint32_t>* fusemap,
bool readJSON(const string& filename, string* tag,
map<string, uint32_t>* values, map<string, uint32_t>* fusemap,
map<string, uint32_t>* infomap) {
bool result = false;
#ifdef HAVE_JSON
ifstream ifs(filename.c_str());
if (ifs) {
// Touch up a bit to allow for comments.
// Beware: we drop everything past and including '//' from any line.
// Thus '//' cannot be substring of any value..
@@ -290,27 +222,35 @@ bool readJSON(const string& filename,
// Try parse.
rapidjson::Document d;
if (d.Parse(s.c_str()).HasParseError()) {
FATAL("JSON %s[%lu]: parse error\n", filename.c_str(), d.GetErrorOffset());
FATAL("JSON %s[%lu]: parse error\n", filename.c_str(),
d.GetErrorOffset());
} else {
#define CHECKVALUE(x) do { \
if (!d.HasMember(x)){FATAL("manifest is lacking field '%s'\n", x);}; \
#define CHECKVALUE(x) \
do { \
if (!d.HasMember(x)) { \
FATAL("manifest is lacking field '%s'\n", x); \
}; \
} while (0)
#define GETVALUE(x) do { \
if (!d.HasMember(x)){FATAL("manifest is lacking field '%s'\n", x);}; \
(*values)[x] = d[x].GetInt(); \
#define GETVALUE(x) \
do { \
if (!d.HasMember(x)) { \
FATAL("manifest is lacking field '%s'\n", x); \
}; \
(*values)[x] = d[x].GetInt(); \
} while (0)
CHECKVALUE("fuses");
const rapidjson::Document::ValueType& fuses = d["fuses"];
for (rapidjson::Value::ConstMemberIterator it = fuses.MemberBegin(); it != fuses.MemberEnd(); ++it) {
for (rapidjson::Value::ConstMemberIterator it = fuses.MemberBegin();
it != fuses.MemberEnd(); ++it) {
(*fusemap)[it->name.GetString()] = it->value.GetInt();
}
CHECKVALUE("info");
const rapidjson::Document::ValueType& infos = d["info"];
for (rapidjson::Value::ConstMemberIterator it = infos.MemberBegin(); it != infos.MemberEnd(); ++it) {
for (rapidjson::Value::ConstMemberIterator it = infos.MemberBegin();
it != infos.MemberEnd(); ++it) {
(*infomap)[it->name.GetString()] = it->value.GetInt();
}
@@ -333,7 +273,6 @@ bool readJSON(const string& filename,
#undef GETVALUE
#undef CHECKVALUE
}
}
#endif // HAVE_JSON
@@ -351,53 +290,57 @@ string hashesFilename;
bool fillPattern = false;
uint32_t pattern = -1;
bool fillRandom = false;
string xmlOutputFilename;
void usage(int argc, char* argv[]) {
fprintf(stderr, "Usage: %s options\n"
fprintf(stderr,
"Usage: %s options\n"
"--input=$elf-filename\n"
"--output=output-filename\n"
"--key=$pem-filename\n"
"[--cros] to sign for the ChromeOS realm w/o manifest\n"
"[--xml=$xml-filename] typically 'havenTop.xml'\n"
"[--json=$json-filename] the signing manifest\n"
"[--format=bin|hex] output file format, hex is default\n"
"[--signature=$sig-filename] replace signature with file content\n"
"[--hashes=$hashes-filename] destination file for intermediary hashes to be signed\n"
"[--hashes=$hashes-filename] destination file for intermediary "
"hashes to be signed\n"
"[--randomfill] to pad image to 512K with random bits\n"
"[--patternfill=N] to pad image to 512K with pattern N\n"
"[--writefuses=$xml-filename] to write out shortened xml\n"
"[--verbose]\n",
argv[0]);
}
int getOptions(int argc, char* argv[]) {
static struct option long_options[] = {
// name, has_arg
{"format", required_argument, NULL, 'f'},
{"help", no_argument, NULL, 'h'},
{"input", required_argument, NULL, 'i'},
{"json", required_argument, NULL, 'j'},
{"key", required_argument, NULL, 'k'},
{"output", required_argument, NULL, 'o'},
{"verbose", no_argument, NULL, 'v'},
{"xml", required_argument, NULL, 'x'},
{"signature", required_argument, NULL, 's'},
{"hashes", required_argument, NULL, 'H'},
{"randomfill", no_argument, NULL, 'r'},
{"patternfill", required_argument, NULL, 'p'},
{"writefuses", required_argument, NULL, 'w'},
{0, 0, 0, 0}
};
// name, has_arg
{"cros", no_argument, NULL, 'c'},
{"format", required_argument, NULL, 'f'},
{"help", no_argument, NULL, 'h'},
{"input", required_argument, NULL, 'i'},
{"json", required_argument, NULL, 'j'},
{"key", required_argument, NULL, 'k'},
{"output", required_argument, NULL, 'o'},
{"verbose", no_argument, NULL, 'v'},
{"xml", required_argument, NULL, 'x'},
{"signature", required_argument, NULL, 's'},
{"hashes", required_argument, NULL, 'H'},
{"randomfill", no_argument, NULL, 'r'},
{"patternfill", required_argument, NULL, 'p'},
{"writefuses", required_argument, NULL, 'w'},
{0, 0, 0, 0}};
int c, option_index = 0;
outputFormat.assign("hex");
while ((c = getopt_long(argc, argv, "i:o:p:k:x:j:f:s:H:w:hvr",
long_options, &option_index)) != -1) {
while ((c = getopt_long(argc, argv, "i:o:p:k:x:j:f:s:H:chvr", long_options,
&option_index)) != -1) {
switch (c) {
case 0:
fprintf(stderr, "option %s", long_options[option_index].name);
if (optarg) fprintf(stderr, " with arg %s", optarg);
fprintf(stderr, "\n");
break;
case 'c':
FLAGS_cros = true;
break;
case 'i':
inputFilename.assign(optarg);
break;
@@ -410,9 +353,6 @@ int getOptions(int argc, char* argv[]) {
case 'x':
xmlFilename.assign(optarg);
break;
case 'w':
xmlOutputFilename.assign(optarg);
break;
case 's':
signatureFilename.assign(optarg);
break;
@@ -444,9 +384,7 @@ int getOptions(int argc, char* argv[]) {
return 1;
}
}
if (inputFilename.empty() ||
outputFilename.empty() ||
keyFilename.empty() ||
if (inputFilename.empty() || outputFilename.empty() || keyFilename.empty() ||
((outputFormat != "bin") && (outputFormat != "hex"))) {
usage(argc, argv);
return 1;
@@ -476,8 +414,10 @@ int main(int argc, char* argv[]) {
hdr.ro_base = image.ro_base();
hdr.ro_max = image.ro_max();
hdr.rx_base = image.rx_base();
hdr.rx_max = image.rx_max() + 12; // TODO: m3 I prefetch sets off GLOBALSEC when too tight
// make sure these are nops or such?
hdr.rx_max =
image.rx_max() +
12; // TODO: m3 instruction prefetch sets off GLOBALSEC when too tight
// make sure these are nops or such?
hdr.timestamp_ = time(NULL);
// Parse signing manifest.
@@ -501,7 +441,8 @@ int main(int argc, char* argv[]) {
}
// Fill in more of hdr, per manifest values
for (map<string, uint32_t>::const_iterator it = values.begin(); it != values.end(); ++it) {
for (map<string, uint32_t>::const_iterator it = values.begin();
it != values.end(); ++it) {
VERBOSE("%s : %u\n", it->first.c_str(), it->second);
}
@@ -522,13 +463,21 @@ int main(int argc, char* argv[]) {
FATAL("mismatched keyid JSON %d vs. key %d\n", values["keyid"], hdr.keyid);
}
if (FLAGS_cros) {
if (!tag.empty()) {
FATAL("--cros whilst also specifying tag per manifest is a no go");
}
tag = "\x01\x00\x00\x00"; // cros realm identifier in rwr[0]
}
// Fill in tag.
VERBOSE("tag: \"%s\"\n", tag.c_str());
strncpy((char*)(&hdr.tag), tag.c_str(), sizeof(hdr.tag));
// List the specific fuses and values.
VERBOSE("care about %lu fuses:\n", fuses.size());
for (map<string, uint32_t>::const_iterator it = fuses.begin(); it != fuses.end(); ++it) {
for (map<string, uint32_t>::const_iterator it = fuses.begin();
it != fuses.end(); ++it) {
VERBOSE("fuse '%s' should have value %u\n", it->first.c_str(), it->second);
}
@@ -543,8 +492,7 @@ int main(int argc, char* argv[]) {
}
if (values["p4cl"] != xml_p4cl) {
FATAL("mismatching p4cl: xml %u vs. json %u\n",
xml_p4cl, values["p4cl"]);
FATAL("mismatching p4cl: xml %u vs. json %u\n", xml_p4cl, values["p4cl"]);
}
VERBOSE("found %lu fuse definitions\n", fuse_ids.size());
@@ -560,24 +508,18 @@ int main(int argc, char* argv[]) {
fuse_ids["FW_DEFINED_DATA_EXTRA_BLK6"] = 125;
fuse_bits["FW_DEFINED_DATA_EXTRA_BLK6"] = 5;
for (map<string, uint32_t>::const_iterator it = fuse_ids.begin(); it != fuse_ids.end(); ++it) {
VERBOSE("fuse '%s' at %u, width %u\n",
it->first.c_str(), it->second, fuse_bits[it->first]);
}
// Write condensed XML if asked to.
if (!xmlOutputFilename.empty()) {
writeXML(xmlOutputFilename,
fuse_ids,
fuse_bits,
xml_p4cl);
for (map<string, uint32_t>::const_iterator it = fuse_ids.begin();
it != fuse_ids.end(); ++it) {
VERBOSE("fuse '%s' at %u, width %u\n", it->first.c_str(), it->second,
fuse_bits[it->first]);
}
// Compute fuse_values array, according to manifest and xml.
uint32_t fuse_values[FUSE_MAX];
for (size_t i = 0; i < FUSE_MAX; ++i) fuse_values[i] = FUSE_IGNORE;
for (map<string, uint32_t>::const_iterator x = fuses.begin(); x != fuses.end(); ++x) {
for (map<string, uint32_t>::const_iterator x = fuses.begin();
x != fuses.end(); ++x) {
map<string, uint32_t>::const_iterator it = fuse_ids.find(x->first);
if (it == fuse_ids.end()) {
FATAL("cannot find definition for fuse '%s'\n", x->first.c_str());
@@ -596,20 +538,18 @@ int main(int argc, char* argv[]) {
}
// Print out fuse hash input.
VERBOSE("expected fuse state:");
VERBOSE("expected fuse state:\n");
for (size_t i = 0; i < FUSE_MAX; ++i) {
if (! (i % 8))
VERBOSE("\n");
VERBOSE("%08x ", fuse_values[i]);
}
VERBOSE("\n");
// Compute info_values array, according to manifest.
uint32_t info_values[INFO_MAX];
for (size_t i = 0; i < INFO_MAX; ++i) info_values[i] = INFO_IGNORE;
for (map<string, uint32_t>::const_iterator x = infos.begin(); x != infos.end(); ++x) {
for (map<string, uint32_t>::const_iterator x = infos.begin();
x != infos.end(); ++x) {
uint32_t index = atoi(x->first.c_str());
assert(index < INFO_MAX);
@@ -621,10 +561,8 @@ int main(int argc, char* argv[]) {
// TODO: read values from JSON or implement version logic here.
// Print out info hash input.
VERBOSE("expected info state:");
VERBOSE("expected info state:\n");
for (size_t i = 0; i < INFO_MAX; ++i) {
if (! (i % 8))
VERBOSE("\n");
VERBOSE("%08x ", info_values[i]);
}
VERBOSE("\n");
@@ -635,7 +573,8 @@ int main(int argc, char* argv[]) {
int n = ::read(fd, hdr.signature, sizeof(hdr.signature));
::close(fd);
if (n != sizeof(hdr.signature)) FATAL("cannot read from '%s'\n", signatureFilename.c_str());
if (n != sizeof(hdr.signature))
FATAL("cannot read from '%s'\n", signatureFilename.c_str());
VERBOSE("provided signature\n");
} else {

View File

@@ -5,6 +5,10 @@
#ifndef __EC_UTIL_SIGNER_COMMON_SIGNED_HEADER_H
#define __EC_UTIL_SIGNER_COMMON_SIGNED_HEADER_H
#include <assert.h>
#include <string.h>
#include <inttypes.h>
#define FUSE_PADDING 0x55555555 // baked in hw!
#define FUSE_IGNORE 0xa3badaac // baked in rom!
#define FUSE_MAX 128 // baked in rom!
@@ -33,6 +37,9 @@ typedef struct SignedHeader {
assert(n < INFO_MAX);
infomap[n / 32] |= 1 << (n & 31);
}
void print() const {
}
#endif // __cplusplus
uint32_t magic; // -1 (thanks, boot_sys!)

View File

@@ -294,8 +294,7 @@ void getPIN(uint8_t* out) {
static
std::string tokenFilename(const uint8_t* fp) {
const char* home = getenv("HOME");
if (home == NULL)
home = getpwuid(getuid())->pw_dir;
if (home == NULL) getpwuid(getuid())->pw_dir;
std::string s(home);
s.append("/.tmp/");
for (int i = 0; i < 32; ++i) {
@@ -568,10 +567,6 @@ int Gnubby::write_bn(uint8_t p1, BIGNUM* n, size_t length) {
UCHAR resp[1024];
DWORD resp_len = 0;
if (!handle_) {
open();
}
memcpy(req, "\x00\x66\x00\x00\x00\x00\x00", 7);
req[2] = p1;
req[5] = length >> 8;
@@ -600,6 +595,11 @@ int Gnubby::write(RSA* rsa) {
UCHAR resp[2048];
DWORD resp_len = 0;
if (!handle_) {
result = (open() != 1);
if (result) goto __fail;
}
// lock(100)
result = gnubby_lock(handle_, (UCHAR)100);
if (result != 0) goto __fail;
@@ -627,7 +627,7 @@ int Gnubby::write(RSA* rsa) {
__fail:
// (always try to) unlock
gnubby_lock(handle_, 0);
if (handle_) gnubby_lock(handle_, 0);
return result;
}

View File

@@ -2,20 +2,9 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <common/image.h>
// global C++ includes
#include <string>
// global C includes
#include <assert.h>
#include <fcntl.h>
#include <gelf.h>
#include <libelf.h>
#include <openssl/bn.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
@@ -24,27 +13,51 @@
#include <sys/types.h>
#include <unistd.h>
// local includes
#include <gelf.h>
#include <libelf.h>
#include <common/publickey.h>
#include <common/image.h>
#include <openssl/bn.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <common/signed_header.h>
#include <string>
using namespace std;
extern bool FLAGS_verbose;
#define VERBOSE(...) do{if(FLAGS_verbose)fprintf(stderr, __VA_ARGS__);}while(0)
#define WARN(...) do{fprintf(stderr, __VA_ARGS__);}while(0)
#define FATAL(...) do{fprintf(stderr, __VA_ARGS__);abort();}while(0)
#define VERBOSE(...) \
do { \
if (FLAGS_verbose) fprintf(stderr, __VA_ARGS__); \
} while (0)
#define WARN(...) \
do { \
fprintf(stderr, __VA_ARGS__); \
} while (0)
#define FATAL(...) \
do { \
fprintf(stderr, __VA_ARGS__); \
abort(); \
} while (0)
static const int FLASH_START = 0x40000;
static const int FLASH_START = 0x4000;
static const int FLASH_END = FLASH_START + 512 * 1024;
Image::Image()
: success_(true), low_(FLASH_END - FLASH_START), high_(0),
base_(0), ro_base_(FLASH_END), rx_base_(FLASH_END),
ro_max_(0), rx_max_(0) {
: success_(true),
low_(FLASH_END - FLASH_START),
high_(0),
base_(0),
ro_base_(FLASH_END * 16),
rx_base_(FLASH_END * 16),
ro_max_(0),
rx_max_(0) {
memset(mem_, 0xff, sizeof(mem_)); // default memory content
}
@@ -78,9 +91,9 @@ bool Image::fromElf(const string& filename) {
goto fail;
}
// printf("Elf filesize: %lu\n", elf_stats.st_size);
// printf("Elf filesize: %lu\n", elf_stats.st_size);
if ((base_ptr = (char*) malloc(elf_stats.st_size)) == NULL) {
if ((base_ptr = (char*)malloc(elf_stats.st_size)) == NULL) {
WARN("cannot malloc %lu\n", elf_stats.st_size);
goto fail;
}
@@ -91,8 +104,8 @@ bool Image::fromElf(const string& filename) {
}
// Sniff content for sanity
if (*(uint32_t*) base_ptr != 0x464c457f) {
// WARN("'%s' is not elf file\n", filename);
if (*(uint32_t*)base_ptr != 0x464c457f) {
// WARN("'%s' is not elf file\n", filename);
goto fail;
}
@@ -107,53 +120,49 @@ bool Image::fromElf(const string& filename) {
gelf_getshdr(scn, &shdr);
VERBOSE("type %08x; flags %08lx ", shdr.sh_type, shdr.sh_flags);
VERBOSE("%08lx(@%08lx)[%08lx] align %lu ",
shdr.sh_addr, shdr.sh_offset, shdr.sh_size, shdr.sh_addralign);
VERBOSE("%08lx(@%08lx)[%08lx] align %lu\n", shdr.sh_addr, shdr.sh_offset,
shdr.sh_size, shdr.sh_addralign);
// Ignore sections that are not alloc
if (!(shdr.sh_flags & SHF_ALLOC)) {
VERBOSE("non aloc, ignored\n");
continue;
}
// Ignore sections that are not exec
if (!(shdr.sh_flags & SHF_EXECINSTR)) {
VERBOSE("non exec, ignored\n");
continue;
}
// Ignore sections outside our flash range
if (shdr.sh_addr < FLASH_START ||
shdr.sh_addr + shdr.sh_size >= FLASH_END) {
VERBOSE("out of bounds, ignored\n");
if (shdr.sh_addr < FLASH_START * 16 ||
shdr.sh_addr + shdr.sh_size >= FLASH_END * 16) {
continue;
}
VERBOSE("\n");
// Track rx boundaries
if (shdr.sh_addr < rx_base_) {
rx_base_ = shdr.sh_addr;
}
if (shdr.sh_addr + shdr.sh_size> rx_max_) {
if (shdr.sh_addr + shdr.sh_size > rx_max_) {
rx_max_ = shdr.sh_addr + shdr.sh_size;
}
}
// Load image per program headers and track total ro segment
for (int index = 0; gelf_getphdr(elf, index, &phdr); ++index) {
VERBOSE("phdr %08lx(@%08lx) [%08lx/%08lx]",
phdr.p_vaddr, phdr.p_paddr, phdr.p_filesz, phdr.p_memsz);
VERBOSE("phdr %08lx(@%08lx) [%08lx/%08lx]", phdr.p_vaddr, phdr.p_paddr,
phdr.p_filesz, phdr.p_memsz);
if (phdr.p_filesz != phdr.p_memsz) {
VERBOSE(" (size mismatch, not loading)\n");
// Ignore sections outside our flash range
if (phdr.p_paddr < FLASH_START * 16 ||
phdr.p_paddr + phdr.p_filesz >= FLASH_END * 16) {
VERBOSE(" (outside flash, skipped)\n");
continue;
}
// Ignore sections outside our flash range
if (phdr.p_paddr < FLASH_START ||
phdr.p_paddr + phdr.p_memsz >= FLASH_END) {
VERBOSE(" (out of bounds, not loading)\n");
// Ignore p_offset 0, which ELF hdr; cannot be legit.
if (phdr.p_offset == 0) {
VERBOSE(" (offset 0, ignoring)\n");
continue;
}
@@ -169,8 +178,7 @@ bool Image::fromElf(const string& filename) {
// Copy data into image
for (size_t n = 0; n < phdr.p_filesz; ++n) {
store(phdr.p_paddr + n - FLASH_START,
base_ptr[phdr.p_offset + n]);
store(phdr.p_paddr + n - FLASH_START * 16, base_ptr[phdr.p_offset + n]);
}
}
@@ -178,7 +186,7 @@ bool Image::fromElf(const string& filename) {
base_ = low_;
// Set ro_base to start, so app can read its own header.
ro_base_ = base_ + FLASH_START;
ro_base_ = base_ + FLASH_START * 16;
// Set rx_base to just past header, where interrupt vectors are,
// since fetching a vector gets done on the I bus.
rx_base_ = ro_base_ + sizeof(SignedHeader);
@@ -216,54 +224,53 @@ bool Image::fromIntelHex(const string& filename, bool withSignature) {
continue;
}
if (line[7] != '0') {
WARN("unknown record type %s", line);
success_ = false;
} else switch (line[8]) {
case '1': { // 01 eof
} break;
case '2': { // 02 segment
if (!strncmp(line, ":02000002", 9)) {
char* p = line + 9;
int s = parseWord(&p);
if (s != 0x1000) {
if (s >= FLASH_START/16 && s <= FLASH_END/16) {
seg = s - FLASH_START/16;
//WARN("at segment %04x\n", seg);
WARN("unknown record type %s", line);
success_ = false;
} else
switch (line[8]) {
case '1': { // 01 eof
} break;
case '2': { // 02 segment
if (!strncmp(line, ":02000002", 9)) {
char* p = line + 9;
int s = parseWord(&p);
if (s != 0x1000) {
if (s >= FLASH_START && s <= FLASH_END) {
seg = s - FLASH_START;
// WARN("at segment %04x\n", seg);
} else {
WARN("data should in range %x-%x: %s\n", FLASH_START,
FLASH_END, line);
success_ = false;
}
}
}
isRam = !strcmp(line, ":020000021000EC");
} break;
case '0': { // 00 data
char* p = line + 1;
int len = parseByte(&p);
int adr = parseWord(&p);
parseByte(&p);
while (len--) {
if (isRam) {
int v = parseByte(&p);
if (v != 0) {
WARN("WARNING: non-zero RAM byte %02x at %04x\n", v, adr);
}
++adr;
} else {
WARN("data should fit in range %x-%x: %s\n",
FLASH_START, FLASH_END, line);
success_ = false;
store((seg * 16) + adr++, parseByte(&p));
}
}
}
isRam = !strcmp(line, ":020000021000EC");
} break;
case '0': { // 00 data
char* p = line + 1;
int len = parseByte(&p);
int adr = parseWord(&p);
parseByte(&p);
while (len--) {
if (isRam) {
int v = parseByte(&p);
if (v != 0) {
WARN("WARNING: non-zero RAM byte %02x at %04x\n",
v, adr);
}
++adr;
} else {
store((seg * 16) + adr++, parseByte(&p));
}
}
} break;
case '3': { // 03 entry point
} break;
default: {
WARN("unknown record type %s", line);
success_ = false;
} break;
}
} break;
case '3': { // 03 entry point
} break;
default: {
WARN("unknown record type %s", line);
success_ = false;
} break;
}
}
fclose(fp);
} else {
@@ -290,14 +297,14 @@ bool Image::fromIntelHex(const string& filename, bool withSignature) {
}
if (success_) {
VERBOSE("low %08x, high %08x\n",
FLASH_START + low_, FLASH_START + high_);
VERBOSE("low %08x, high %08x\n", FLASH_START * 16 + low_,
FLASH_START * 16 + high_);
// Round image to multiple of 2K.
high_ = ((high_ + 2047) / 2048) * 2048;
ro_base_ = FLASH_START + base_;
rx_base_ = FLASH_START + base_;
ro_max_ = FLASH_START + base_ + size();
rx_max_ = FLASH_START + base_ + size();
ro_base_ = FLASH_START * 16 + base_;
rx_base_ = FLASH_START * 16 + base_;
ro_max_ = FLASH_START * 16 + base_ + size();
rx_max_ = FLASH_START * 16 + base_ + size();
VERBOSE("base %08lx, size %08lx\n", ro_base_, size());
}
@@ -306,20 +313,20 @@ bool Image::fromIntelHex(const string& filename, bool withSignature) {
Image::~Image() {}
void Image::toIntelHex(FILE *fout) const {
void Image::toIntelHex(FILE* fout) const {
for (int i = base_; i < high_; i += 16) {
// spit out segment record at start of segment.
if (!((i - base_)&0xffff)) {
int s = FLASH_START/16 + (base_>>4) + ((i - base_)>>4);
if (!((i - base_) & 0xffff)) {
int s = FLASH_START + (base_ >> 4) + ((i - base_) >> 4);
fprintf(fout, ":02000002%04X%02X\n", s,
(~((2 + 2 + (s>>8)) & 255) + 1) & 255);
(~((2 + 2 + (s >> 8)) & 255) + 1) & 255);
}
// spit out data records, 16 bytes each.
fprintf(fout, ":10%04X00", (i - base_)&0xffff);
int crc = 16 + (((i - base_)>>8)&255) + ((i - base_)&255);
fprintf(fout, ":10%04X00", (i - base_) & 0xffff);
int crc = 16 + (((i - base_) >> 8) & 255) + ((i - base_) & 255);
for (int n = 0; n < 16; ++n) {
fprintf(fout, "%02X", mem_[i+n]);
crc += mem_[i+n];
fprintf(fout, "%02X", mem_[i + n]);
crc += mem_[i + n];
}
fprintf(fout, "%02X", (~(crc & 255) + 1) & 255);
fprintf(fout, "\n");
@@ -327,7 +334,7 @@ void Image::toIntelHex(FILE *fout) const {
}
void Image::fillPattern(uint32_t pattern) {
for (int i = high_ - base_; i < 512*1024 - 2048; i += 4) {
for (int i = high_ - base_; i < 512 * 1024 - 2048; i += 4) {
*(uint32_t*)(mem_ + i) = pattern;
}
high_ = 512 * 1024 - 2048;
@@ -335,7 +342,7 @@ void Image::fillPattern(uint32_t pattern) {
void Image::fillRandom() {
srand(time(NULL));
for (int i = high_ - base_; i < 512*1024 - 2048; i += 4) {
for (int i = high_ - base_; i < 512 * 1024 - 2048; i += 4) {
*(uint32_t*)(mem_ + i) = rand();
}
high_ = 512 * 1024 - 2048;
@@ -352,18 +359,37 @@ void Image::generate(const std::string& filename, bool hex_output) const {
fclose(fout);
}
int Image::nibble(char n) {
switch (n) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return n - '0';
case 'a': case 'A': return 10;
case 'b': case 'B': return 11;
case 'c': case 'C': return 12;
case 'd': case 'D': return 13;
case 'e': case 'E': return 14;
case 'f': case 'F': return 15;
case 'a':
case 'A':
return 10;
case 'b':
case 'B':
return 11;
case 'c':
case 'C':
return 12;
case 'd':
case 'D':
return 13;
case 'e':
case 'E':
return 14;
case 'f':
case 'F':
return 15;
default:
WARN("bad hex digit '%c'\n", n);
success_ = false;
@@ -393,15 +419,14 @@ void Image::store(int adr, int v) {
success_ = false;
return;
}
// VERBOSE("mem_[0x%08x]=0x%02x\n", adr, v&255);
mem_[adr] = v;
if (adr > high_) high_ = adr;
if (adr < low_) low_ = adr;
}
bool Image::sign(PublicKey& key,
const SignedHeader* input_hdr,
const uint32_t fuses[FUSE_MAX],
const uint32_t info[INFO_MAX],
bool Image::sign(PublicKey& key, const SignedHeader* input_hdr,
const uint32_t fuses[FUSE_MAX], const uint32_t info[INFO_MAX],
const string& hashesFilename) {
BIGNUM* sig = NULL;
SignedHeader* hdr = (SignedHeader*)(&mem_[base_]);
@@ -428,22 +453,16 @@ bool Image::sign(PublicKey& key,
SHA256_Update(&sha256, fuses, FUSE_MAX * sizeof(uint32_t));
SHA256_Final(hashes.fuses_hash, &sha256);
hdr->fuses_chk_ =
(hashes.fuses_hash[0] << 0)
| (hashes.fuses_hash[1] << 8)
| (hashes.fuses_hash[2] << 16)
| (hashes.fuses_hash[3] << 24);
hdr->fuses_chk_ = (hashes.fuses_hash[0] << 0) | (hashes.fuses_hash[1] << 8) |
(hashes.fuses_hash[2] << 16) | (hashes.fuses_hash[3] << 24);
// Hash info
SHA256_Init(&sha256);
SHA256_Update(&sha256, info, INFO_MAX * sizeof(uint32_t));
SHA256_Final(hashes.info_hash, &sha256);
hdr->info_chk_ =
(hashes.info_hash[0] << 0)
| (hashes.info_hash[1] << 8)
| (hashes.info_hash[2] << 16)
| (hashes.info_hash[3] << 24);
hdr->info_chk_ = (hashes.info_hash[0] << 0) | (hashes.info_hash[1] << 8) |
(hashes.info_hash[2] << 16) | (hashes.info_hash[3] << 24);
// Hash img
int size = this->size() - offsetof(SignedHeader, tag);
@@ -451,11 +470,8 @@ bool Image::sign(PublicKey& key,
SHA256_Update(&sha256, &hdr->tag, size);
SHA256_Final(hashes.img_hash, &sha256);
hdr->img_chk_ =
(hashes.img_hash[0] << 0)
| (hashes.img_hash[1] << 8)
| (hashes.img_hash[2] << 16)
| (hashes.img_hash[3] << 24);
hdr->img_chk_ = (hashes.img_hash[0] << 0) | (hashes.img_hash[1] << 8) |
(hashes.img_hash[2] << 16) | (hashes.img_hash[3] << 24);
// Dump out values for comparing against boot_rom
VERBOSE("Himg =");
@@ -478,7 +494,7 @@ bool Image::sign(PublicKey& key,
if (!hashesFilename.empty()) {
// Write hashes to file for subsequent extraneous (re)signing.
int fd = open(hashesFilename.c_str(), O_CREAT|O_TRUNC|O_RDWR, 0600);
int fd = open(hashesFilename.c_str(), O_CREAT | O_TRUNC | O_RDWR, 0600);
if (fd >= 0) {
write(fd, &hashes, sizeof(hashes));
close(fd);