Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancements and bug fixes for v0.4.0. #2

Merged
merged 4 commits into from
May 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions tools/mccibootloader_image/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ The following options are defined. Note that options can be mixed with the input
<dd>Update the input file in place.</dd>
<dt><code>-k <em>file</em></code>, <code>--keyfile <em>file</em></code></dt>
<dd>Read the signing key from <code><em>file</em></code>, which must be an OpenSSH ed25519 private key file, not password protected. The (insecure) keyfile <code>test/mcci-test.pem</code> is conventionally used for test purposes. </dd>
<dt><code>-V <em>major[.minor[.patch]][-pre]</em></code>, <code>--app-version <em>major[.minor[.patch]][-pre]</em></code></dt>
<dd>Set the application version according to the argument.</dd>
<dt><code>-s</code>, <code>--sign</code></dt>
<dd>Compute the hash (as with <code>-h</code>, and then sign. A key file must be provided.</dd>
<dt><code>-v</code>, <code>--verbose</code></dt>
Expand All @@ -93,6 +95,7 @@ Program settings:
--patch: false
--keyfile: C:/mcci/projects/lora/bootloader/tools/mccibootloader_image/test/mcci-test.pem
--comment: <<none>>
--app-version: <<none>>

input: build/arm-none-eabi/release/McciBootloader_46xx
output: build/arm-none-eabi/release/McciBootloader_46xx.elf
Expand Down
87 changes: 46 additions & 41 deletions tools/mccibootloader_image/i/mccibootloader_image.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,49 @@ static_assert(offsetof(GuidWire_t, clock_seq_low) == 9, "GUID layout mismatch");
static_assert(offsetof(GuidWire_t, node) == 10, "GUID layout mismatch");
static_assert(sizeof(GuidWire_t) == GuidWire_t_SIZE, "GUID layout mismatch");

/* versions */
namespace McciVersion {
typedef std::uint32_t Version_t;

// create a version number for comparison
constexpr std::uint32_t
makeVersion(
std::uint8_t major, std::uint8_t minor, std::uint8_t patch, std::uint8_t local = 0
)
{
return ((std::uint32_t)major << 24u) | ((std::uint32_t)minor << 16u) | ((std::uint32_t)patch << 8u) | (std::uint32_t)local;
}

// extract major number from version
constexpr std::uint8_t
getMajor(std::uint32_t v)
{
return std::uint8_t(v >> 24u);
}

// extract minor number from version
constexpr std::uint8_t
getMinor(std::uint32_t v)
{
return std::uint8_t(v >> 16u);
}

// extract patch number from version
constexpr std::uint8_t
getPatch(std::uint32_t v)
{
return std::uint8_t(v >> 8u);
}

// extract local number from version
constexpr std::uint8_t
getLocal(std::uint32_t v)
{
return std::uint8_t(v);
}
} // namespace McciVersion


// a forward reference
struct McciBootloader_AppInfo_Wire_t;

Expand All @@ -85,6 +128,8 @@ struct App_t
std::string progname;
std::string keyfilename;
std::vector<uint8_t> fileimage;
McciVersion::Version_t appVersion;
bool fAppVersion;

struct AppElf_t
{
Expand Down Expand Up @@ -118,6 +163,7 @@ struct App_t
void readImage();
void writeImage();
void elfImagePrep();
void setAppVersion(const string &versionString);

Keyfile_ed25519_t keyfile;
};
Expand All @@ -134,47 +180,6 @@ static constexpr const char *filebasename(const char *s)
return pName;
}

namespace McciVersion {
typedef std::uint32_t Version_t;

// create a version number for comparison
constexpr std::uint32_t
makeVersion(
std::uint8_t major, std::uint8_t minor, std::uint8_t patch, std::uint8_t local = 0
)
{
return ((std::uint32_t)major << 24u) | ((std::uint32_t)minor << 16u) | ((std::uint32_t)patch << 8u) | (std::uint32_t)local;
}

// extract major number from version
constexpr std::uint8_t
getMajor(std::uint32_t v)
{
return std::uint8_t(v >> 24u);
}

// extract minor number from version
constexpr std::uint8_t
getMinor(std::uint32_t v)
{
return std::uint8_t(v >> 16u);
}

// extract patch number from version
constexpr std::uint8_t
getPatch(std::uint32_t v)
{
return std::uint8_t(v >> 8u);
}

// extract local number from version
constexpr std::uint8_t
getLocal(std::uint32_t v)
{
return std::uint8_t(v);
}
} // namespace McciVersion

// the layout of the image
class uint32_le_t
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Copyright and License:
#include "mccibootloader_image.h"

constexpr McciVersion::Version_t kVersion =
McciVersion::makeVersion(0, 3, 1, 0);
McciVersion::makeVersion(0, 4, 0, 0);
constexpr char kCopyright[] = "Copyright (C) 2021, MCCI Corporation";

#endif /* _mccibootloader_image_version_h_ */
44 changes: 23 additions & 21 deletions tools/mccibootloader_image/src/image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,30 @@ void App_t::readImage()
{
this->fatal("unexpected e_phoff value");
}
if (pElfIdent32->getPhnum() > 4)

// display the program header entries
if (this->fVerbose)
{
ostringstream msg;
msg << "ELF e_phnum > 4: " << pElfIdent32->getPhnum();
this->fatal(msg.str());
for (unsigned i = 0; i < pElfIdent32->getPhnum(); ++i)
{
const ElfIdent32_t::ProgramHeader_t ph { *pElfIdent32, i };

// dump the section
{
std::ostringstream msg;

msg << "ELF: section " << i << ": "
<< "vaddr(" << std::hex << ph.getVaddr() << ") "
<< "paddr(" << std::hex << ph.getPaddr() << ") "
<< "size(" << std::hex << ph.getMemsz() << ") "
<< "vend(" << std::hex << ph.getVaddr() + ph.getMemsz() << ") "
<< "offset(" << std::hex << ph.getOffset() << ") "
<< "fsize(" << std::hex << ph.getFilesz() << ") "
<< "flags(" << std::hex << ph.getFlags() << ")"
;
this->verbose(msg.str());
}
}
}

// empty the file image and set up the elf image
Expand All @@ -129,23 +148,6 @@ void App_t::readImage()
if (ph.getType() != decltype(ph.getType())::kLoad)
this->fatal("section type is not loadable");

// dump the section
if (this->fVerbose)
{
std::ostringstream msg;

msg << "ELF: section " << i << ": "
<< "vaddr(" << std::hex << ph.getVaddr() << ") "
<< "paddr(" << std::hex << ph.getPaddr() << ") "
<< "size(" << std::hex << ph.getMemsz() << ") "
<< "vend(" << std::hex << ph.getVaddr() + ph.getMemsz() << ") "
<< "offset(" << std::hex << ph.getOffset() << ") "
<< "fsize(" << std::hex << ph.getFilesz() << ") "
<< "flags(" << std::hex << ph.getFlags() << ")"
;
this->verbose(msg.str());
}

// we used to try skipping writable sections, but ...
// that requires PHDRS in the link script. Instead, use
// a heuristic to discard non-contiguous sections
Expand Down
139 changes: 123 additions & 16 deletions tools/mccibootloader_image/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ static void dumpAppInfo(
McciBootloader_AppInfo_Wire_t const &appInfo
);

static std::string versionToString(
McciVersion::Version_t version
);

/****************************************************************************\
|
| Read-only data.
Expand Down Expand Up @@ -196,6 +200,13 @@ void App_t::scanArgs(int argc, char **argv)
this->usage("missing comment value");
this->pComment = *argv++;
}
else if (arg == "-V" || arg == "--app-version")
{
if (*argv == nullptr)
this->usage("missing app-version value");

this->setAppVersion(string(*argv));
}
else if (arg == "--version")
{
std::cout << "mccibootloader_image v"
Expand Down Expand Up @@ -257,6 +268,7 @@ void App_t::scanArgs(int argc, char **argv)
<< " --patch: " << this->fPatch << "\n"
<< " --keyfile: " << this->keyfilename << "\n"
<< " --comment: " << (pComment == NULL ? "<<none>>": pComment) << "\n"
<< " --app-version: " << (!this->fAppVersion ? "<<none>>": versionToString(this->appVersion)) << "\n"
<< "\n"
<< "input: " << this->infilename << "\n"
<< "output: "
Expand All @@ -271,17 +283,119 @@ void App_t::scanArgs(int argc, char **argv)
void App_t::usage(const string &message)
{
string usage = message;
if (usage != "")
if (usage != "" && usage[usage.length() - 1] != '\n')
{
usage.append(": ");
}
usage.append("usage: ");
usage.append(this->progname);
usage.append(" -[vsh k{keyfile} c{comment}] --[version sign hash comment {comment} dry-run add-time force-binary] infile [outfile]\n");
usage.append(" -[vsh k{keyfile} c{comment} -V{app-version}] --[version sign hash app-version {version} comment {comment} dry-run add-time force-binary] infile [outfile]\n");
fprintf(stderr, "%s\n", usage.c_str());
exit(EXIT_FAILURE);
}

static std::string versionToString(McciVersion::Version_t version)
{
ostringstream sVersion;
sVersion << unsigned(McciVersion::getMajor(version))
<< "."
<< unsigned(McciVersion::getMinor(version))
<< "."
<< unsigned(McciVersion::getPatch(version))
;
if (McciVersion::getLocal(version) != 0)
{
sVersion << "-"
<< unsigned(McciVersion::getLocal(version));
}

return sVersion.str();
}

void App_t::setAppVersion(
const string &versionString
)
{
unsigned i = 0;

auto const failstring = [&versionString, &i](const string &message) -> string
{
string result;
result = message + ": ";
result += versionString.substr(0, i);
result += "[";
result += versionString.substr(i);
result += "]\n";
return result;
};

auto const getn = [this, &versionString, &i, &failstring]() -> std::uint8_t
{
std::uint32_t result;
auto const n = versionString.length();
bool err;
bool gotDigit;

err = false;
gotDigit = false;
result = 0;

while (i < n && !err)
{
auto c = versionString[i];
if (! ('0' <= c && c <= '9'))
break;

gotDigit = true;
result = result * 10 + (c - '0');
if (result >= 256)
err = true;
else
++i;
}

if (! gotDigit)
err = true;

if (err)
this->usage(failstring("illegal app-version syntax"));

return result;
};
auto const checkpunct = [&versionString, &i](char c) -> bool
{
auto const n = versionString.length();

if (i < n && versionString[i] == c)
{
++i;
return true;
}
return false;
};

auto const major = getn();
std::uint8_t minor, patch, prerelease;
minor = patch = prerelease = 0;

if (checkpunct('.'))
{
minor = getn();
if (checkpunct('.'))
patch = getn();
}
if (checkpunct('-'))
{
prerelease = getn();
}

if (i < versionString.length())
this->usage(failstring("illegal value for app-version"));

this->appVersion = McciVersion::makeVersion(major, minor, patch, prerelease);
this->fAppVersion = true;
}

void dumpAppInfo(
std::string const &s,
McciBootloader_AppInfo_Wire_t const &appInfo
Expand All @@ -296,21 +410,8 @@ void dumpAppInfo(
<< " posixTimestamp: " << std::setw(16) << std::setfill(' ') << appInfo.posixTimestamp.get() << "\n"
<< " comment: " << appInfo.comment.get() << "\n";
;
auto version = appInfo.version.get();
ostringstream sVersion;
sVersion << unsigned(McciVersion::getMajor(version))
<< "."
<< unsigned(McciVersion::getMinor(version))
<< "."
<< unsigned(McciVersion::getPatch(version))
;
if (McciVersion::getLocal(version) != 0)
{
sVersion << "-"
<< unsigned(McciVersion::getLocal(version));
}

std::cout << " version: " << std::setw(16) << std::setfill(' ') << sVersion.str();
std::cout << " version: " << std::setw(16) << std::setfill(' ') << versionToString(appInfo.version.get());
std::cout << "\n";
std::cout << "\n";
}
Expand Down Expand Up @@ -384,6 +485,12 @@ void App_t::addHeader()
this->authSize
);

// set the version if one was provided
if (this->fAppVersion)
appInfo.version.put(
this->appVersion
);

// add posix time
if (this->fAddTime)
{
Expand Down