Added maximumMemoryAccessSizePerRequest limit in EdbgAvr8Interface class to allow debug tools to apply a hard limit on memory access sizes per request

This commit is contained in:
Nav
2021-11-22 23:07:18 +00:00
parent ade9550ea2
commit f202502005
2 changed files with 60 additions and 5 deletions

View File

@@ -1220,13 +1220,18 @@ TargetMemoryBuffer EdbgAvr8Interface::readMemory(
}
if (type == Avr8MemoryType::FLASH_PAGE) {
if (this->targetParameters.flashPageSize.value_or(0) < 1) {
// Flash reads must be done in pages
auto pageSize = this->targetParameters.flashPageSize.value_or(0);
if (pageSize < 1
|| (
this->maximumMemoryAccessSizePerRequest.has_value()
&& pageSize > this->maximumMemoryAccessSizePerRequest
)
) {
throw Exception("Missing/invalid flash page size parameter");
}
// Flash reads must be done in pages
auto pageSize = this->targetParameters.flashPageSize.value();
if ((bytes % pageSize) != 0 || (startAddress % pageSize) != 0) {
/*
* The number of bytes to read and/or the start address are not aligned.
@@ -1316,7 +1321,35 @@ TargetMemoryBuffer EdbgAvr8Interface::readMemory(
return memoryBuffer;
}
} else {
}
/*
* Enforce a maximum memory access request size.
*
* See the comment for EdbgAvr8Interface::setMaximumMemoryAccessSizePerRequest() for more on this.
*/
if (this->maximumMemoryAccessSizePerRequest.has_value() && bytes > this->maximumMemoryAccessSizePerRequest) {
auto maximumRequestSize = this->maximumMemoryAccessSizePerRequest.value();
auto totalReadsRequired = std::ceil(static_cast<float>(bytes) / static_cast<float>(maximumRequestSize));
auto output = std::vector<unsigned char>();
output.reserve(bytes);
for (float i = 1; i <= totalReadsRequired; i++) {
auto bytesToRead = static_cast<std::uint32_t>((bytes - output.size()) > maximumRequestSize ?
maximumRequestSize : bytes - output.size());
auto data = this->readMemory(
type,
static_cast<std::uint32_t>(startAddress + output.size()),
bytesToRead,
excludedAddresses
);
output.insert(output.end(), data.begin(), data.end());
}
return output;
}
if (type != Avr8MemoryType::FLASH_PAGE) {
/*
* EDBG AVR8 debug tools behave in a really weird way when responding with more than two packets
* for a single read (non-flash) memory command. The data they return in this case appears to be of little use.

View File

@@ -38,6 +38,26 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
this->avoidMaskedMemoryRead = avoidMaskedMemoryRead;
}
/**
* Some EDBG AVR8 debug tools behave in a really weird way when servicing read memory requests that exceed a
* certain size. For example, the ATMEGA4809-XPRO Xplained Pro debug tool returns incorrect data for any read
* memory command that exceeds 256 bytes in the size of the read request, despite the fact that the HID report
* size is 512 bytes. The debug tool doesn't report any error, it just returns incorrect data.
*
* To address this, debug tool drivers can set a hard limit on the number of bytes this EdbgAvr8Interface instance
* will attempt to access in a single request, using the EdbgAvr8Interface::setMaximumMemoryAccessSizePerRequest()
* function.
*
* This limit will be enforced in all forms of memory access on the AVR8 target, including register access.
*
* @TODO: Enforce the limit on memory writes.
*
* @param maximumSize
*/
void setMaximumMemoryAccessSizePerRequest(std::uint32_t maximumSize) {
this->maximumMemoryAccessSizePerRequest = maximumSize;
}
/*
* The public methods below implement the interface defined by the Avr8Interface class.
* See the comments in that class for more info on the expected behaviour of each method.
@@ -275,6 +295,8 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
*/
bool avoidMaskedMemoryRead = false;
std::optional<std::uint32_t> maximumMemoryAccessSizePerRequest;
/**
* We keep record of the current target state for caching purposes. We'll only refresh the target state if the
* target is running. If it has already stopped, then we assume it cannot transition to a running state without