mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
USB Protection correction (#90)
This commit is contained in:
@@ -13,7 +13,7 @@ using namespace Shared;
|
||||
|
||||
namespace Settings {
|
||||
|
||||
UsbInfoController::UsbInfoController(Responder *parentResponder):
|
||||
UsbInfoController::UsbInfoController(Responder *parentResponder):
|
||||
GenericSubController(parentResponder),
|
||||
m_usbProtectionLevelController(this),
|
||||
m_contentView(&m_selectableTableView)
|
||||
@@ -23,7 +23,7 @@ UsbInfoController::UsbInfoController(Responder *parentResponder):
|
||||
}
|
||||
|
||||
bool UsbInfoController::handleEvent(Ion::Events::Event event) {
|
||||
if ((Ion::Events::OK == event || Ion::Events::EXE == event) && selectedRow() == 0) {
|
||||
if ((Ion::Events::OK == event || Ion::Events::EXE == event || Ion::Events::Right == event) && selectedRow() == 0) {
|
||||
if (!GlobalPreferences::sharedGlobalPreferences()->dfuUnlocked()) {
|
||||
if (!GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) {
|
||||
Ion::LED::setColor(KDColorPurple);
|
||||
@@ -39,15 +39,8 @@ bool UsbInfoController::handleEvent(Ion::Events::Event event) {
|
||||
m_selectableTableView.reloadCellAtLocation(0, 0);
|
||||
return true;
|
||||
}
|
||||
// We cannot use things like willExitResponderChain because this view can disappear due to an USB connection,
|
||||
// and in this case we must keep the DFU status.
|
||||
if ((Ion::Events::Left == event || Ion::Events::Home == event || Ion::Events::Back == event) && GlobalPreferences::sharedGlobalPreferences()->dfuUnlocked()) {
|
||||
GlobalPreferences::sharedGlobalPreferences()->setDfuUnlocked(false);
|
||||
m_selectableTableView.reloadCellAtLocation(0, 0);
|
||||
Container::activeApp()->displayWarning(I18n::Message::USBProtectionReactivated);
|
||||
return true;
|
||||
}
|
||||
if ((Ion::Events::OK == event || Ion::Events::EXE == event) && selectedRow() == 1) {
|
||||
|
||||
if ((Ion::Events::OK == event || Ion::Events::EXE == event || Ion::Events::Right == event) && selectedRow() == 1) {
|
||||
GenericSubController *subController = &m_usbProtectionLevelController;
|
||||
subController->setMessageTreeModel(m_messageTreeModel->childAtIndex(1));
|
||||
StackViewController *stack = stackController();
|
||||
@@ -55,6 +48,20 @@ bool UsbInfoController::handleEvent(Ion::Events::Event event) {
|
||||
stack->push(subController);
|
||||
return true;
|
||||
}
|
||||
|
||||
// We cannot use things like willExitResponderChain because this view can disappear due to an USB connection,
|
||||
// and in this case we must keep the DFU status.
|
||||
if ((event != Ion::Events::USBPlug && event != Ion::Events::USBEnumeration) &&
|
||||
GlobalPreferences::sharedGlobalPreferences()->dfuUnlocked()) {
|
||||
GlobalPreferences::sharedGlobalPreferences()->setDfuUnlocked(false);
|
||||
m_selectableTableView.reloadCellAtLocation(0, 0);
|
||||
Container::activeApp()->displayWarning(I18n::Message::USBProtectionReactivated);
|
||||
if (!GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) {
|
||||
Ion::LED::setColor(KDColorBlack);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return GenericSubController::handleEvent(event);
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ __DFU_GETSTATUS = 3
|
||||
__DFU_CLRSTATUS = 4
|
||||
__DFU_GETSTATE = 5
|
||||
__DFU_ABORT = 6
|
||||
__DFU_UNLOCK = 11
|
||||
|
||||
# DFU status
|
||||
__DFU_STATE_APP_IDLE = 0x00
|
||||
@@ -145,6 +146,10 @@ def abort_request():
|
||||
__dev.ctrl_transfer(0x21, __DFU_ABORT, 0, __DFU_INTERFACE, None, __TIMEOUT)
|
||||
|
||||
|
||||
def unlock_request():
|
||||
"""Deactivate the protection"""
|
||||
__dev.ctrl_transfer(0x21, __DFU_UNLOCK, 0, __DFU_INTERFACE, None, __TIMEOUT)
|
||||
|
||||
def clr_status():
|
||||
"""Clears any error status (perhaps left over from a previous session)."""
|
||||
__dev.ctrl_transfer(0x21, __DFU_CLRSTATUS, 0, __DFU_INTERFACE,
|
||||
@@ -587,6 +592,7 @@ def main():
|
||||
elements = read_dfu_file(args.path)
|
||||
if not elements:
|
||||
return
|
||||
unlock_request()
|
||||
print("Writing memory...")
|
||||
write_elements(elements, args.mass_erase, progress=cli_progress)
|
||||
|
||||
|
||||
@@ -176,8 +176,8 @@ SECTIONS {
|
||||
*(.text._ZN20KDPostProcessContext15setClippingRectE6KDRect)
|
||||
*(.text._ZNK6KDFont17indexForCodePointE9CodePoint)
|
||||
*(.text._ZNK6KDFont26fetchGrayscaleGlyphAtIndexEhPh)
|
||||
*(.text.LZ4_decompress_safe)
|
||||
*(.text.LZ4_wildCopy)
|
||||
*(.text.LZ4_decompress_safe*)
|
||||
*(.text.LZ4_wildCopy*)
|
||||
*(.text.*DFU*)
|
||||
*(.text.*isEnumerated*)
|
||||
*(.text._ZN3Ion3USB6enableEv)
|
||||
@@ -214,6 +214,7 @@ SECTIONS {
|
||||
*(.text._ZNK10Statistics5Store33sortedElementAtCumulatedFrequencyEidb)
|
||||
*(.text.round)
|
||||
*(.text._ZNK10Statistics5Store8minIndexEPdi*)
|
||||
*(.text.LZ4_decompress_safe*)
|
||||
|
||||
/* 'standby' dependencies '*/
|
||||
*(.text._ZN3Ion6Device5Power20internalFlashStandbyEv)
|
||||
@@ -277,6 +278,12 @@ SECTIONS {
|
||||
*(.rodata._ZN8Sequence23TypeParameterController25willDisplayCellAtLocationEP13HighlightCellii*)
|
||||
*(.rodata._ZN6KDFont16privateSmallFontE)
|
||||
*(.rodata._ZN4I18nL23CountryPreferencesArrayE)
|
||||
*(.rodata._ZN3Ion6Device3LED6ConfigL7RGBPinsE*)
|
||||
*(.rodata._ZN4I18nL23CountryPreferencesArrayE*)
|
||||
*(.rodata._ZN3Ion6Device3USB6ConfigL7VbusPinE*)
|
||||
*(.rodata.bp*)
|
||||
*(.rodata.dp_l*)
|
||||
*(.rodata.dp_h*)
|
||||
*(.rodata.abort_sleeping.str1.1)
|
||||
*(.rodata.abort_core.str1.1)
|
||||
*(.rodata.dfu_bootloader)
|
||||
|
||||
@@ -15,8 +15,6 @@ namespace Ion {
|
||||
namespace Device {
|
||||
namespace USB {
|
||||
|
||||
constexpr static uint8_t k_externalMagik[9] = {0x64, 0x6c, 0x31, 0x31, 0x23, 0x39, 0x38, 0x33, 0x35};
|
||||
|
||||
static inline uint32_t minUint32T(uint32_t x, uint32_t y) { return x < y ? x : y; }
|
||||
|
||||
void DFUInterface::StatusData::push(Channel *c) const {
|
||||
@@ -111,6 +109,9 @@ bool DFUInterface::processSetupInRequest(SetupPacket *request, uint8_t *transfer
|
||||
return getState(transferBuffer, transferBufferLength, transferBufferMaxLength);
|
||||
case (uint8_t)DFURequest::Abort:
|
||||
return dfuAbort(transferBufferLength);
|
||||
case (uint8_t)DFURequest::Unlock:
|
||||
m_dfuUnlocked = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -140,17 +141,17 @@ bool DFUInterface::processUploadRequest(SetupPacket *request, uint8_t *transferB
|
||||
}
|
||||
if (request->wValue() == 0) {
|
||||
/* The host requests to read the commands supported by the bootloader. After
|
||||
* receiving this command, the device should returns N bytes representing
|
||||
* the command codes for :
|
||||
* Get command / Set Address Pointer / Erase / Read Unprotect
|
||||
* We no not need it for now. */
|
||||
* receiving this command, the device should returns N bytes representing
|
||||
* the command codes for :
|
||||
* Get command / Set Address Pointer / Erase / Read Unprotect
|
||||
* We no not need it for now. */
|
||||
return false;
|
||||
} else if (request->wValue() == 1) {
|
||||
m_ep0->stallTransaction();
|
||||
return false;
|
||||
} else {
|
||||
/* We decided to never protect Read operation. Else we would have to check
|
||||
* here it is not protected before reading. */
|
||||
* here it is not protected before reading. */
|
||||
|
||||
// Compute the reading address
|
||||
uint32_t readAddress = (request->wValue() - 2) * Endpoint0::MaxTransferSize + m_addressPointer;
|
||||
@@ -199,7 +200,7 @@ void DFUInterface::eraseCommand(uint8_t *transferBuffer, uint16_t transferBuffer
|
||||
// Sector erase
|
||||
assert(transferBufferLength == 5);
|
||||
|
||||
uint32_t m_eraseAddress = transferBuffer[1]
|
||||
m_eraseAddress = transferBuffer[1]
|
||||
+ (transferBuffer[2] << 8)
|
||||
+ (transferBuffer[3] << 16)
|
||||
+ (transferBuffer[4] << 24);
|
||||
@@ -214,24 +215,21 @@ void DFUInterface::eraseCommand(uint8_t *transferBuffer, uint16_t transferBuffer
|
||||
|
||||
void DFUInterface::eraseMemoryIfNeeded() {
|
||||
if (m_erasePage < 0) {
|
||||
// There was no erase waiting.
|
||||
return;
|
||||
}
|
||||
|
||||
willErase();
|
||||
|
||||
#if 0 // We don't erase now the flash memory to avoid crash if writing is refused
|
||||
#if 0 // We don't erase now the flash memory to avoid crash if writing is refused
|
||||
if (m_erasePage == Flash::TotalNumberOfSectors()) {
|
||||
Flash::MassErase();
|
||||
Flash::MassErase();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if ((m_eraseAddress >= k_externalAppsBorderAddress && m_eraseAddress < ExternalFlash::Config::EndAddress) || m_dfuUnlocked) {
|
||||
Flash::EraseSector(m_erasePage);
|
||||
if ((m_eraseAddress >= k_ExternalBorderAddress && m_eraseAddress < ExternalFlash::Config::EndAddress) || m_dfuUnlocked) {
|
||||
int32_t order = Flash::SectorAtAddress(m_eraseAddress);
|
||||
Flash::EraseSector(order);
|
||||
}
|
||||
/* Put an out of range value in m_erasePage to indicate that no erase is
|
||||
* waiting. */
|
||||
m_erasePage = -1;
|
||||
m_state = State::dfuDNLOADIDLE;
|
||||
m_status = Status::OK;
|
||||
m_erasePage = -1;
|
||||
@@ -242,67 +240,89 @@ void DFUInterface::writeOnMemory() {
|
||||
// Write on SRAM
|
||||
// FIXME We should check that we are not overriding the current instructions.
|
||||
memcpy((void *)m_writeAddress, m_largeBuffer, m_largeBufferLength);
|
||||
resetProtectionVariables(); // We can reset the protection variables because update process is finsihed.
|
||||
resetFlashParameters(); // We are writing in SRAM, so we can reset flash parameters
|
||||
} else if (Flash::SectorAtAddress(m_writeAddress) >= 0) {
|
||||
if (m_dfuLevel == 2) { // If no-update mode, we throw an error
|
||||
if (m_dfuLevel == 2) { // We don't accept update
|
||||
m_largeBufferLength = 0;
|
||||
m_state = State::dfuERROR;
|
||||
m_status = Status::errWRITE;
|
||||
leaveDFUAndReset(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(m_isTemporaryUnlocked || m_dfuUnlocked)) {
|
||||
if (m_writeAddress >= InternalFlash::Config::StartAddress && m_writeAddress <= InternalFlash::Config::EndAddress) {
|
||||
// We check if the user is autorized to write on the internal flash
|
||||
if (m_haveAlreadyFlashedExternal) {
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
if (k_internalMagik[i] != m_largeBuffer[k_internalMagikPointer + i]) {
|
||||
m_largeBufferLength = 0;
|
||||
m_state = State::dfuERROR;
|
||||
m_status = Status::errWRITE;
|
||||
// We don't leave DFU to avoid having only external flashed
|
||||
return;
|
||||
}
|
||||
m_largeBuffer[k_internalMagikPointer + i] = 0; // We reset the buffer to its initial value
|
||||
|
||||
int currentMemoryType; // Detection of the current memory type (Internal or External)
|
||||
|
||||
if (m_writeAddress >= InternalFlash::Config::StartAddress && m_writeAddress <= InternalFlash::Config::EndAddress) {
|
||||
// We are writing in Internal where live the internal recovery (it's the most sensitive memory type)
|
||||
if (m_isInternalLocked && !m_dfuUnlocked) {
|
||||
// We have to check if external was written in order to
|
||||
// prevent recovery mode loop or the necessity to activate STM bootloader (which is like a superuser mode)
|
||||
// Nevertheless, unlike NumWorks, we don't forbid its access.
|
||||
m_largeBufferLength = 0;
|
||||
m_state = State::dfuERROR;
|
||||
m_status = Status::errTARGET;
|
||||
leaveDFUAndReset(false);
|
||||
return;
|
||||
}
|
||||
|
||||
currentMemoryType = 0;
|
||||
|
||||
// If the protection is activated,
|
||||
// we check the internal magic code in order to prevent the NumWorks' Bootloader flash
|
||||
|
||||
if (m_isFirstInternalPacket && !m_dfuUnlocked) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (k_omegaMagic[i] != m_largeBuffer[k_internalMagicAddress + i]) {
|
||||
m_largeBufferLength = 0;
|
||||
m_state = State::dfuERROR;
|
||||
m_status = Status::errVERIFY;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else { // All people trying to write on the internal flash before external are considered as not authorized
|
||||
m_largeBufferLength = 0;
|
||||
m_state = State::dfuERROR;
|
||||
m_status = Status::errTARGET;
|
||||
leaveDFUAndReset(false);
|
||||
return;
|
||||
}
|
||||
// We only check the first packet because there is some predictable data in there
|
||||
m_isFirstInternalPacket = false;
|
||||
}
|
||||
else if (m_writeAddress < k_externalAppsBorderAddress) { // If we are not installing external apps
|
||||
if (m_dfuLevel == 0) {
|
||||
for (size_t i = 0; i < 9; i++) {
|
||||
if (k_externalMagik[i] != m_largeBuffer[k_externalMagikPointer + i]) {
|
||||
m_largeBufferLength = 0;
|
||||
m_state = State::dfuERROR;
|
||||
m_status = Status::errWRITE;
|
||||
leaveDFUAndReset(false);
|
||||
return;
|
||||
}
|
||||
m_largeBuffer[k_externalMagikPointer + i] = 0; // We reset the buffer to its initial value
|
||||
} else {
|
||||
|
||||
currentMemoryType = 1;
|
||||
// We are writing in the external part where live the users apps. It's not a sensitive memory,
|
||||
// but we check it in Upsilon Mode to ensure compatibility between the internal and the external.
|
||||
if (m_writeAddress < k_ExternalBorderAddress && m_isFirstExternalPacket && m_dfuLevel == 0 &&
|
||||
!m_dfuUnlocked) {
|
||||
// We skip any data verification if the user is writing in the Optionals Applications part in the
|
||||
// external (Externals Apps)
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (k_externalUpsilonMagic[i] != m_largeBuffer[k_externalMagicAddress + i]) {
|
||||
m_largeBufferLength = 0;
|
||||
leaveDFUAndReset(false);
|
||||
return;
|
||||
}
|
||||
m_isTemporaryUnlocked = true; // We can unlock the flash because signature is good
|
||||
}
|
||||
else {
|
||||
m_haveAlreadyFlashedExternal = true;
|
||||
}
|
||||
}
|
||||
// We only check the first packet because there is some predictable data in there,
|
||||
// and we unlock the internal memory
|
||||
m_isFirstExternalPacket = false;
|
||||
m_isInternalLocked = false;
|
||||
}
|
||||
|
||||
int pageToErase = Flash::SectorAtAddress(m_writeAddress);
|
||||
|
||||
//On vérifie qu'on a pas déjà effacé le secteur et si ce n'est pas un secteur external déjà effacé
|
||||
if ((m_lastErasedPage == -1 || pageToErase != m_lastErasedPage) && m_writeAddress < k_externalAppsBorderAddress && !m_dfuUnlocked) {
|
||||
Flash::EraseSector(pageToErase);
|
||||
m_lastErasedPage = pageToErase;
|
||||
// We check if we changed the memory type where we are writing from last time.
|
||||
if (m_lastMemoryType >= 0 && currentMemoryType != m_lastMemoryType) {
|
||||
m_lastMemoryType = -1;
|
||||
}
|
||||
|
||||
m_erasePage = Flash::SectorAtAddress(m_writeAddress);
|
||||
|
||||
// We check if the Sector where we are writing was not already erased and if not, we erase it.
|
||||
if ((m_lastMemoryType < 0 || m_erasePage != m_lastPageErased) &&
|
||||
m_writeAddress < k_ExternalBorderAddress && !m_dfuUnlocked) {
|
||||
Flash::EraseSector(m_erasePage);
|
||||
m_lastMemoryType = currentMemoryType;
|
||||
}
|
||||
|
||||
m_lastPageErased = m_erasePage;
|
||||
m_erasePage = -1;
|
||||
|
||||
// We wait a little before writing in order to prevent some memory error.
|
||||
Ion::Timing::msleep(1);
|
||||
Flash::WriteMemory(reinterpret_cast<uint8_t *>(m_writeAddress), m_largeBuffer, m_largeBufferLength);
|
||||
} else {
|
||||
// Invalid write address
|
||||
@@ -311,7 +331,6 @@ void DFUInterface::writeOnMemory() {
|
||||
m_status = Status::errTARGET;
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset the buffer length
|
||||
m_largeBufferLength = 0;
|
||||
// Change the interface state and status
|
||||
@@ -350,11 +369,14 @@ bool DFUInterface::dfuAbort(uint16_t *transferBufferLength) {
|
||||
}
|
||||
|
||||
void DFUInterface::leaveDFUAndReset(bool do_reset) {
|
||||
resetProtectionVariables();
|
||||
resetFlashParameters();
|
||||
m_isInternalLocked = true;
|
||||
m_isFirstInternalPacket = true;
|
||||
m_isFirstExternalPacket = true;
|
||||
m_device->setResetOnDisconnect(do_reset);
|
||||
m_device->detach();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace USB
|
||||
class DFUInterface : public Interface {
|
||||
|
||||
public:
|
||||
DFUInterface(Device *device, Endpoint0 *ep0, uint8_t bInterfaceAlternateSetting):
|
||||
DFUInterface(Device *device, Endpoint0 *ep0, uint8_t bInterfaceAlternateSetting) :
|
||||
Interface(ep0),
|
||||
m_device(device),
|
||||
m_status(Status::OK),
|
||||
@@ -34,16 +34,18 @@ public:
|
||||
m_writeAddress(0),
|
||||
m_eraseAddress(0),
|
||||
m_bInterfaceAlternateSetting(bInterfaceAlternateSetting),
|
||||
m_lastErasedPage(-1),
|
||||
m_isErasingAndWriting(false),
|
||||
m_isTemporaryUnlocked(false),
|
||||
m_haveAlreadyFlashedExternal(false),
|
||||
m_isFirstInternalPacket(true),
|
||||
m_isInternalLocked(true),
|
||||
m_isFirstExternalPacket(true),
|
||||
m_lastMemoryType(-1),
|
||||
m_lastPageErased(-1),
|
||||
m_dfuUnlocked(false),
|
||||
m_dfuLevel(0)
|
||||
{
|
||||
|
||||
m_dfuLevel(0) {
|
||||
}
|
||||
|
||||
uint32_t addressPointer() const { return m_addressPointer; }
|
||||
|
||||
void wholeDataReceivedCallback(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength) override;
|
||||
void wholeDataSentCallback(SetupPacket *request, uint8_t *transferBuffer, uint16_t *transferBufferLength) override;
|
||||
bool isErasingAndWriting() const { return m_isErasingAndWriting; }
|
||||
@@ -68,7 +70,8 @@ private:
|
||||
GetStatus = 3,
|
||||
ClearStatus = 4,
|
||||
GetState = 5,
|
||||
Abort = 6
|
||||
Abort = 6,
|
||||
Unlock = 11
|
||||
};
|
||||
|
||||
// DFU Download Commmand Codes
|
||||
@@ -99,32 +102,33 @@ private:
|
||||
};
|
||||
|
||||
enum class State : uint8_t {
|
||||
appIDLE = 0,
|
||||
appDETACH = 1,
|
||||
dfuIDLE = 2,
|
||||
dfuDNLOADSYNC = 3,
|
||||
dfuDNBUSY = 4,
|
||||
dfuDNLOADIDLE = 5,
|
||||
dfuMANIFESTSYNC = 6,
|
||||
dfuMANIFEST = 7,
|
||||
appIDLE = 0,
|
||||
appDETACH = 1,
|
||||
dfuIDLE = 2,
|
||||
dfuDNLOADSYNC = 3,
|
||||
dfuDNBUSY = 4,
|
||||
dfuDNLOADIDLE = 5,
|
||||
dfuMANIFESTSYNC = 6,
|
||||
dfuMANIFEST = 7,
|
||||
dfuMANIFESTWAITRESET = 8,
|
||||
dfuUPLOADIDLE = 9,
|
||||
dfuERROR = 10
|
||||
dfuUPLOADIDLE = 9,
|
||||
dfuERROR = 10
|
||||
};
|
||||
|
||||
class StatusData : public Streamable {
|
||||
public:
|
||||
StatusData(Status status, State state, uint32_t pollTimeout = 10):
|
||||
StatusData(Status status, State state, uint32_t pollTimeout = 10) :
|
||||
/* We put a default pollTimeout value of 1ms: if the device is busy, the
|
||||
* host has to wait 1ms before sending a getStatus Request. */
|
||||
m_bStatus((uint8_t)status),
|
||||
m_bwPollTimeout{uint8_t((pollTimeout >> 16) & 0xFF), uint8_t((pollTimeout >> 8) & 0xFF), uint8_t(pollTimeout & 0xFF)},
|
||||
m_bState((uint8_t)state),
|
||||
* host has to wait 1ms before sending a getStatus Request. */
|
||||
m_bStatus((uint8_t) status),
|
||||
m_bwPollTimeout{uint8_t((pollTimeout >> 16) & 0xFF), uint8_t((pollTimeout >> 8) & 0xFF),uint8_t(pollTimeout & 0xFF)},
|
||||
m_bState((uint8_t) state),
|
||||
m_iString(0)
|
||||
{
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
void push(Channel * c) const override;
|
||||
void push(Channel *c) const override;
|
||||
private:
|
||||
uint8_t m_bStatus; // Status resulting from the execution of the most recent request
|
||||
uint8_t m_bwPollTimeout[3]; // m_bwPollTimeout is 24 bits
|
||||
@@ -135,7 +139,7 @@ private:
|
||||
class StateData : public Streamable
|
||||
{
|
||||
public:
|
||||
StateData(State state) : m_bState((uint8_t)state) {}
|
||||
StateData(State state) : m_bState((uint8_t) state) {}
|
||||
protected:
|
||||
void push(Channel *c) const override;
|
||||
private:
|
||||
@@ -143,15 +147,16 @@ private:
|
||||
};
|
||||
|
||||
/* The Flash and SRAM addresses are in flash.ld. However, dfu_interface is
|
||||
* linked with dfu.ld, so we cannot access the values. */
|
||||
constexpr static uint32_t k_sramStartAddress = 0x20000000;
|
||||
constexpr static uint32_t k_sramEndAddress = 0x20040000;
|
||||
constexpr static uint32_t k_externalAppsBorderAddress = 0x90200000;
|
||||
* linked with dfu.ld, so we cannot access the values. */
|
||||
constexpr static uint32_t k_sramStartAddress = 0x20000000;
|
||||
constexpr static uint32_t k_sramEndAddress = 0x20040000;
|
||||
constexpr static uint32_t k_ExternalBorderAddress = 0x90200000;
|
||||
|
||||
constexpr static int k_internalMagikPointer = 0x1C4;
|
||||
constexpr static int k_externalMagikPointer = 0x44F;
|
||||
constexpr static uint8_t k_internalMagik[4] = {0xF0, 0x0D, 0xC0, 0xDE};
|
||||
constexpr static uint8_t k_externalMagik[4] = {0x32, 0x30, 0x30, 0x36};
|
||||
const static int k_internalMagicAddress = 0x1C4;
|
||||
constexpr static int k_externalMagicAddress = 0x44f;
|
||||
constexpr static uint8_t k_omegaMagic[4] = {0xF0, 0x0D, 0xC0, 0xDE};
|
||||
// TODO maybe do: add seperated upsilon magic (k_upsilonMagic)
|
||||
constexpr static uint8_t k_externalUpsilonMagic[4] = {0x32, 0x30, 0x30, 0x36};
|
||||
|
||||
// Download and upload
|
||||
bool processDownloadRequest(uint16_t wLength, uint16_t *transferBufferLength);
|
||||
@@ -174,14 +179,18 @@ private:
|
||||
// Abort
|
||||
bool dfuAbort(uint16_t *transferBufferLength);
|
||||
// Leave DFU
|
||||
void leaveDFUAndReset(bool do_reset=true);
|
||||
void leaveDFUAndReset(bool do_reset = true);
|
||||
|
||||
/* Erase and Write state. After starting the erase of flash memory, the user
|
||||
* can no longer leave DFU mode by pressing the Back key of the keyboard. This
|
||||
* way, we prevent the user from interrupting a software download. After every
|
||||
* software download, the calculator resets, which unlocks the "exit on
|
||||
* pressing back". */
|
||||
void willErase() { m_isErasingAndWriting = true; }
|
||||
void resetProtectionVariables() { m_lastErasedPage = -1; m_isTemporaryUnlocked = false; m_haveAlreadyFlashedExternal = false; }
|
||||
void resetFlashParameters() {
|
||||
m_lastMemoryType = -1;
|
||||
m_lastPageErased = -1;
|
||||
}
|
||||
|
||||
Device *m_device;
|
||||
Status m_status;
|
||||
@@ -194,10 +203,12 @@ private:
|
||||
uint32_t m_writeAddress;
|
||||
uint32_t m_eraseAddress;
|
||||
uint8_t m_bInterfaceAlternateSetting;
|
||||
uint8_t m_lastErasedPage;
|
||||
bool m_isErasingAndWriting;
|
||||
bool m_isTemporaryUnlocked;
|
||||
bool m_haveAlreadyFlashedExternal;
|
||||
bool m_isFirstInternalPacket;
|
||||
bool m_isInternalLocked;
|
||||
bool m_isFirstExternalPacket;
|
||||
uint8_t m_lastMemoryType; // -1: None; 0: internal; 1: external
|
||||
uint8_t m_lastPageErased; // -1 default value
|
||||
bool m_dfuUnlocked;
|
||||
uint8_t m_dfuLevel; // 0: Upsilon only, 1: Omega-forked only, 2: No update
|
||||
};
|
||||
|
||||
@@ -38,6 +38,7 @@ public:
|
||||
#else
|
||||
m_username{"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"},
|
||||
#endif
|
||||
m_osType(UpsilonMagic),
|
||||
m_ohm_footer(OmegaMagic) { }
|
||||
const char * version() const {
|
||||
assert(m_storageAddress != nullptr);
|
||||
@@ -78,6 +79,7 @@ public:
|
||||
private:
|
||||
constexpr static uint32_t Magic = 0xDEC00DF0;
|
||||
constexpr static uint32_t OmegaMagic = 0xEFBEADDE;
|
||||
constexpr static uint32_t UpsilonMagic = 0x55707369;
|
||||
uint32_t m_header;
|
||||
const char m_version[8];
|
||||
const char m_patchLevel[8];
|
||||
@@ -87,6 +89,7 @@ private:
|
||||
uint32_t m_ohm_header;
|
||||
const char m_UpsilonVersion[16];
|
||||
const volatile char m_username[16];
|
||||
uint32_t m_osType;
|
||||
uint32_t m_ohm_footer;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user