From 851ec2ab69b04e6a028fbb1c8cedf3e3709f6966 Mon Sep 17 00:00:00 2001 From: Yaya-Cout Date: Sat, 3 Dec 2022 18:14:43 +0100 Subject: [PATCH] [bootloader] Fix exam mode with Epsilon 19 and add support for Epsilon 20 (#302) * [bootloader] Fix exam mode on Epsilon 19 * [bootloader] Fix comment indentation * [bootloader] Restore comment indentation (even if GitHub tell that it isn't indented properly) * [bootloader] Turn tabulations into spaces * [bootloader] Mark Epsilon 19 as "safe to boot" * [bootloader] Fix Epsilon 20 boot * [bootloader] Chang version to 1.0.2 --- .gitignore | 2 + bootloader/boot.cpp | 2 +- bootloader/interface/static/messages.h | 4 +- bootloader/main.cpp | 11 +- bootloader/slots/slot.cpp | 27 ++- bootloader/slots/slot.h | 4 +- bootloader/slots/slot_exam_mode.cpp | 239 +++++++++++++------------ bootloader/slots/slot_exam_mode.h | 22 ++- bootloader/slots/userland_header.cpp | 4 +- bootloader/utility.cpp | 20 ++- 10 files changed, 195 insertions(+), 140 deletions(-) diff --git a/.gitignore b/.gitignore index 2ff966b9b60..56cb4179582 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ epsilon.map .gradle .idea/ .vs +.cache/ +compile_commands.json diff --git a/bootloader/boot.cpp b/bootloader/boot.cpp index 931b27afc39..bb9ba5aed26 100644 --- a/bootloader/boot.cpp +++ b/bootloader/boot.cpp @@ -107,7 +107,7 @@ void Boot::bootSlot(Bootloader::Slot s) { if (!s.userlandHeader()->isOmega() && !s.userlandHeader()->isUpsilon()) { // We are trying to boot epsilon, so we check the version and show an advertisement if needed const char * version = s.userlandHeader()->version(); - const char * min = "18.2.4"; + const char * min = "20.0.0"; int versionSum = Utility::versionSum(version, strlen(version)); int minimalVersionTrigger = Utility::versionSum(min, strlen(min)); if (versionSum >= minimalVersionTrigger) { diff --git a/bootloader/interface/static/messages.h b/bootloader/interface/static/messages.h index 3623915ce9d..6d97ee991cd 100644 --- a/bootloader/interface/static/messages.h +++ b/bootloader/interface/static/messages.h @@ -57,7 +57,7 @@ class Messages { constexpr static const char * epsilonWarningTitle = "Epsilon Slot"; constexpr static const char * epsilonWarningMessage1 = "!! WARNING !! "; - constexpr static const char * epsilonWarningMessage2 = "This version of epsilon"; + constexpr static const char * epsilonWarningMessage2 = "This version of Epsilon"; constexpr static const char * epsilonWarningMessage3 = "can lock the calculator."; constexpr static const char * epsilonWarningMessage4 = "Proceed the boot ?"; constexpr static const char * epsilonWarningMessage5 = "EXE - Yes"; @@ -72,7 +72,7 @@ class Messages { constexpr static const char * aboutMessage4 = "and select the OS"; constexpr static const char * aboutMessage5 = "to boot."; - constexpr static const char * bootloaderVersion = "Version 1.0.1 - FREED0M.19"; + constexpr static const char * bootloaderVersion = "Version 1.0.2 - FREED0M.20"; //USB NAMES constexpr static const char * usbUpsilonBootloader = "Upsilon Bootloader"; diff --git a/bootloader/main.cpp b/bootloader/main.cpp index c0f0995db11..9452fc15829 100644 --- a/bootloader/main.cpp +++ b/bootloader/main.cpp @@ -20,30 +20,29 @@ __attribute__ ((noreturn)) void ion_main(int argc, const char * const argv[]) { bool isSlotA = Bootloader::Slot::isFullyValid(Bootloader::Slot::A()); if (isSlotA) { - Bootloader::ExamMode::ExamMode SlotAExamMode = (Bootloader::ExamMode::ExamMode)Bootloader::ExamMode::SlotsExamMode::FetchSlotAExamMode(!Bootloader::Slot::A().userlandHeader()->isOmega()); + Bootloader::ExamMode::ExamMode SlotAExamMode = (Bootloader::ExamMode::ExamMode)Bootloader::ExamMode::SlotsExamMode::FetchSlotAExamMode(Bootloader::Slot::A().userlandHeader()->version()); if (SlotAExamMode != Bootloader::ExamMode::ExamMode::Off && SlotAExamMode != Bootloader::ExamMode::ExamMode::Unknown) { // We boot the slot in exam_mode Bootloader::Slot::A().boot(); - } + } } bool isSlotB = Bootloader::Slot::isFullyValid(Bootloader::Slot::B()); if (isSlotB) { - Bootloader::ExamMode::ExamMode SlotBExamMode = (Bootloader::ExamMode::ExamMode)Bootloader::ExamMode::SlotsExamMode::FetchSlotBExamMode(!Bootloader::Slot::B().userlandHeader()->isOmega()); + Bootloader::ExamMode::ExamMode SlotBExamMode = (Bootloader::ExamMode::ExamMode)Bootloader::ExamMode::SlotsExamMode::FetchSlotBExamMode(Bootloader::Slot::B().userlandHeader()->version()); if (SlotBExamMode != Bootloader::ExamMode::ExamMode::Off && SlotBExamMode != Bootloader::ExamMode::ExamMode::Unknown && isSlotB) { // We boot the slot in exam_mode Bootloader::Slot::B().boot(); } - } - // I have no idea if this will work, but if Pariss did a good job, it should + // I have no idea if this will work, but if Parisse did a good job, it should bool isKhiSlot = Bootloader::Slot::isFullyValid(Bootloader::Slot::Khi()); if (isKhiSlot) { - Bootloader::ExamMode::ExamMode KhiExamMode = (Bootloader::ExamMode::ExamMode)Bootloader::ExamMode::SlotsExamMode::FetchSlotKhiExamMode(); + Bootloader::ExamMode::ExamMode KhiExamMode = (Bootloader::ExamMode::ExamMode)Bootloader::ExamMode::SlotsExamMode::FetchSlotKhiExamMode(Bootloader::Slot::Khi().userlandHeader()->version()); if (KhiExamMode != Bootloader::ExamMode::ExamMode::Off && KhiExamMode != Bootloader::ExamMode::ExamMode::Unknown && isKhiSlot) { // We boot the slot in exam_mode Bootloader::Slot::Khi().boot(); diff --git a/bootloader/slots/slot.cpp b/bootloader/slots/slot.cpp index d8ce933985f..2a3cebee21f 100644 --- a/bootloader/slots/slot.cpp +++ b/bootloader/slots/slot.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include extern "C" void jump_to_firmware(const uint32_t* stackPtr, const void(*startPtr)(void)); @@ -24,7 +25,13 @@ const KernelHeader* Slot::kernelHeader() const { } const UserlandHeader* Slot::userlandHeader() const { - return m_userlandHeader; + if (m_userlandHeader->isValid()) { + return m_userlandHeader; + } else if (m_userland2Header->isValid()) { + return m_userland2Header; + } else { + return m_userlandHeader; + } } [[ noreturn ]] void Slot::boot() const { @@ -37,6 +44,24 @@ const UserlandHeader* Slot::userlandHeader() const { Ion::Device::Flash::LockSlotA(); } + // Erase the bootloader integrated in slots in Epsilon 20 + if (m_userland2Header->isValid()) { + if (m_address == 0x90000000) { + // Check if bootloader is present in slot A + if (*(uint32_t*)0x90010000 != 0xFFFFFFFF) { + // Erase bootloader in slot A + Ion::Device::ExternalFlash::EraseSector(9); + } + } + else if (m_address == 0x90400000) { + // Check if bootloader is present in slot B + if (*(uint32_t*)0x90410000 != 0xFFFFFFFF) { + // Erase bootloader in slot B + Ion::Device::ExternalFlash::EraseSector(73); + } + } + } + // Configure the MPU for the booted firmware Ion::Device::Board::bootloaderMPU(); diff --git a/bootloader/slots/slot.h b/bootloader/slots/slot.h index 8aa97b4d388..1d004660590 100644 --- a/bootloader/slots/slot.h +++ b/bootloader/slots/slot.h @@ -14,7 +14,8 @@ class Slot { Slot(uint32_t address) : m_kernelHeader(reinterpret_cast(address)), m_userlandHeader(reinterpret_cast(address + 64 * 1024)), - m_address(address) { } + m_userland2Header(reinterpret_cast(address + 128 * 1024)), + m_address(address) {} const KernelHeader* kernelHeader() const; const UserlandHeader* userlandHeader() const; @@ -32,6 +33,7 @@ class Slot { private: const KernelHeader* m_kernelHeader; const UserlandHeader* m_userlandHeader; + const UserlandHeader* m_userland2Header; const uint32_t m_address; }; diff --git a/bootloader/slots/slot_exam_mode.cpp b/bootloader/slots/slot_exam_mode.cpp index 45b3123239e..47c22995e0a 100644 --- a/bootloader/slots/slot_exam_mode.cpp +++ b/bootloader/slots/slot_exam_mode.cpp @@ -40,88 +40,70 @@ size_t numberOfBitsAfterLeadingZeroes(int i) { return maxShift; } -uint8_t * SignificantSlotAExamModeAddress(bool newVersion) { - uint32_t * persitence_start_32 = (uint32_t *)SlotsExamMode::getSlotAStartExamAddress(newVersion); - uint32_t * persitence_end_32 = (uint32_t *)SlotsExamMode::getSlotAEndExamAddress(newVersion); - if (!newVersion) { - assert((persitence_end_32 - persitence_start_32) % 4 == 0); - while (persitence_start_32 < persitence_end_32 && *persitence_start_32 == 0x0) { - // Scan by groups of 32 bits to reach first non-zero bit - persitence_start_32++; - } - uint8_t * persitence_start_8 = (uint8_t *)persitence_start_32; - uint8_t * persitence_end_8 = (uint8_t *)persitence_end_32; - while (persitence_start_8 < persitence_end_8 && *persitence_start_8 == 0x0) { - // Scan by groups of 8 bits to reach first non-zero bit - persitence_start_8++; - } - if (persitence_start_8 == persitence_end_8 - // we can't toggle from 0[3] to 2[3] when there is only one 1 bit in the whole sector - || (persitence_start_8 + 1 == persitence_end_8 && *persitence_start_8 == 1)) { - assert(Ion::Device::Flash::SectorAtAddress(SlotsExamMode::getSlotAStartExamAddress(newVersion)) >= 0); - Ion::Device::Flash::EraseSector(Ion::Device::Flash::SectorAtAddress(SlotsExamMode::getSlotAStartExamAddress(newVersion))); - return (uint8_t *)SlotsExamMode::getSlotAStartExamAddress(newVersion); - } +uint8_t SlotsExamMode::FetchSlotExamMode(const char * version, const char * Slot) { + // Get start and end from version and slot + uint32_t start = 0; + uint32_t end = 0; + if (Slot == "A") { + // If version under 16 get old addresses + if (version[0] < '1' || (version[0] == '1' && version[1] < '6')) { + start = getSlotAStartExamAddress(0); + end = getSlotAEndExamAddress(0); + } + // Else get new addresses + else { + start = getSlotAStartExamAddress(1); + end = getSlotAEndExamAddress(1); + } + } + else if (Slot == "B") { + // If version under 16 get old + if (version[0] < '1' || (version[0] == '1' && version[1] < '6')) { + start = getSlotBStartExamAddress(0); + end = getSlotBEndExamAddress(0); + } + // Else get new + else { + start = getSlotBStartExamAddress(1); + end = getSlotBEndExamAddress(1); + } + } else if (Slot == "Khi") { + // We directly get the address of the Khi exam mode without checking the + // version, because on Khi, version is KhiCAS version, not the OS version + start = getSlotKhiStartExamAddress(); + end = getSlotKhiEndExamAddress(); + } - return persitence_start_8; - } else { - persitence_end_32 = persitence_end_32 - 1; - while (persitence_end_32 - (uint32_t)(10 / 8) >= persitence_end_32 && *persitence_end_32 == 0xFFFFFFFF) { - persitence_end_32 -= 1; - } - uint8_t * start = reinterpret_cast(persitence_start_32); - uint8_t * end = reinterpret_cast(persitence_end_32 + 1) - 1; - while (end >= start + 2 && *end == 0xFF) { - end -= 1; - } - return end - 1; + if (strcmp("15.9.0", version) >= 0) { + return examFetch15(start, end); + } else if (strcmp("16.9.0", version) > 0) { + return examFetch16(start, end); + } + else if (strcmp("19.0.0", version) > 0) { + return examFetch1718(start, end); + } + else { + return examFetch19(start, end); } - } -uint8_t * SignificantSlotBExamModeAddress(bool newVersion) { - uint32_t * persitence_start_32 = (uint32_t *)SlotsExamMode::getSlotBStartExamAddress(newVersion); - uint32_t * persitence_end_32 = (uint32_t *)SlotsExamMode::getSlotBEndExamAddress(newVersion); - if (!newVersion) { - assert((persitence_end_32 - persitence_start_32) % 4 == 0); - while (persitence_start_32 < persitence_end_32 && *persitence_start_32 == 0x0) { - // Scan by groups of 32 bits to reach first non-zero bit - persitence_start_32++; - } - uint8_t * persitence_start_8 = (uint8_t *)persitence_start_32; - uint8_t * persitence_end_8 = (uint8_t *)persitence_end_32; - while (persitence_start_8 < persitence_end_8 && *persitence_start_8 == 0x0) { - // Scan by groups of 8 bits to reach first non-zero bit - persitence_start_8++; - } - if (persitence_start_8 == persitence_end_8 - // we can't toggle from 0[3] to 2[3] when there is only one 1 bit in the whole sector - || (persitence_start_8 + 1 == persitence_end_8 && *persitence_start_8 == 1)) { - assert(Ion::Device::Flash::SectorAtAddress(SlotsExamMode::getSlotBStartExamAddress(newVersion)) >= 0); - Ion::Device::Flash::EraseSector(Ion::Device::Flash::SectorAtAddress(SlotsExamMode::getSlotBStartExamAddress(newVersion))); - return (uint8_t *)SlotsExamMode::getSlotBStartExamAddress(newVersion); - } - return persitence_start_8; - } else { - persitence_end_32 = persitence_end_32 - 1; - while (persitence_end_32 - (uint32_t)(10 / 8) >= persitence_end_32 && *persitence_end_32 == 0xFFFFFFFF) { - persitence_end_32 -= 1; - } - uint8_t * start = reinterpret_cast(persitence_start_32); - uint8_t * end = reinterpret_cast(persitence_end_32 + 1) - 1; - while (end >= start + 2 && *end == 0xFF) { - end -= 1; - } - return end - 1; - } - + +uint8_t SlotsExamMode::FetchSlotAExamMode(const char* version) { + return FetchSlotExamMode(version, "A"); } -uint8_t * SignificantSlotKhiExamModeAddress() { - uint32_t * persitence_start_32 = (uint32_t *)SlotsExamMode::getSlotKhiStartExamAddress(); - uint32_t * persitence_end_32 = (uint32_t *)SlotsExamMode::getSlotKhiEndExamAddress(); - +uint8_t SlotsExamMode::FetchSlotBExamMode(const char* version) { + return FetchSlotExamMode(version, "B"); +} + +uint8_t SlotsExamMode::FetchSlotKhiExamMode(const char* version) { + return FetchSlotExamMode(version, "Khi"); +} + +uint8_t SlotsExamMode::examFetch15(uint32_t start, uint32_t end) { + uint32_t * persitence_start_32 = (uint32_t *)start; + uint32_t * persitence_end_32 = (uint32_t *)end; assert((persitence_end_32 - persitence_start_32) % 4 == 0); while (persitence_start_32 < persitence_end_32 && *persitence_start_32 == 0x0) { // Scan by groups of 32 bits to reach first non-zero bit @@ -136,65 +118,86 @@ uint8_t * SignificantSlotKhiExamModeAddress() { if (persitence_start_8 == persitence_end_8 // we can't toggle from 0[3] to 2[3] when there is only one 1 bit in the whole sector || (persitence_start_8 + 1 == persitence_end_8 && *persitence_start_8 == 1)) { - assert(Ion::Device::Flash::SectorAtAddress(SlotsExamMode::getSlotKhiStartExamAddress()) >= 0); - Ion::Device::Flash::EraseSector(Ion::Device::Flash::SectorAtAddress(SlotsExamMode::getSlotKhiStartExamAddress())); - return (uint8_t *)SlotsExamMode::getSlotKhiStartExamAddress(); - } - - return persitence_start_8; -} - -uint8_t SlotsExamMode::FetchSlotAExamMode(bool newVersion) { - uint8_t * readingAddress = SignificantSlotAExamModeAddress(newVersion); - if (!newVersion) { - // Count the number of 0[3] before reading address - uint32_t nbOfZerosBefore = ((readingAddress - (uint8_t *)getSlotAStartExamAddress(newVersion)) * numberOfBitsInByte) % 4; + assert(Ion::Device::Flash::SectorAtAddress(start) >= 0); + Ion::Device::Flash::EraseSector(start); + uint32_t nbOfZerosBefore = (((uint8_t*)start - (uint8_t*)start) * numberOfBitsInByte) % 4; // Count the number of 0[3] at reading address - size_t numberOfLeading0 = (numberOfBitsInByte - numberOfBitsAfterLeadingZeroes(*readingAddress)) % 4; + size_t numberOfLeading0 = (numberOfBitsInByte - numberOfBitsAfterLeadingZeroes(*(uint8_t*)start)) % 4; return (nbOfZerosBefore + numberOfLeading0) % 4; - } else { - return *((uint8_t *)readingAddress); } - -} - -uint8_t SlotsExamMode::FetchSlotBExamMode(bool newVersion) { - uint8_t * readingAddress = SignificantSlotBExamModeAddress(newVersion); - if (!newVersion) { - // Count the number of 0[3] before reading address - uint32_t nbOfZerosBefore = ((readingAddress - (uint8_t *)getSlotBStartExamAddress(newVersion)) * numberOfBitsInByte) % 4; + uint32_t nbOfZerosBefore = ((persitence_start_8 - (uint8_t*)start) * numberOfBitsInByte) % 4; // Count the number of 0[3] at reading address - size_t numberOfLeading0 = (numberOfBitsInByte - numberOfBitsAfterLeadingZeroes(*readingAddress)) % 4; + size_t numberOfLeading0 = (numberOfBitsInByte - numberOfBitsAfterLeadingZeroes(*persitence_start_8)) % 4; return (nbOfZerosBefore + numberOfLeading0) % 4; - } else { - return *((uint8_t *)readingAddress); +} + +uint8_t SlotsExamMode::examFetch16(uint32_t start, uint32_t end) { + uint8_t* persitence_start_8 = (uint8_t*)start; + uint8_t* persitence_end_8 = (uint8_t*)end; + while (persitence_start_8 + 1 <= persitence_end_8 && (*persitence_start_8 != 0xFF)) { + // Scan by groups of 8 bits to reach first non-zero bit + persitence_start_8++; } - + + return *(persitence_start_8 - 1); } -uint8_t SlotsExamMode::FetchSlotKhiExamMode() { - uint8_t * readingAddress = SignificantSlotKhiExamModeAddress(); - // Count the number of 0[3] before reading address - uint32_t nbOfZerosBefore = ((readingAddress - (uint8_t *)getSlotKhiStartExamAddress()) * numberOfBitsInByte) % 4; - // Count the number of 0[3] at reading address - size_t numberOfLeading0 = (numberOfBitsInByte - numberOfBitsAfterLeadingZeroes(*readingAddress)) % 4; - return (nbOfZerosBefore + numberOfLeading0) % 4; +uint8_t SlotsExamMode::examFetch1718(uint32_t start, uint32_t end) { + uint8_t* persitence_start_8 = (uint8_t*)start; + uint8_t* persitence_end_8 = (uint8_t*)end; + while (persitence_start_8 + 1 <= persitence_end_8 && (*persitence_start_8 != 0xFF)) { + // Scan by groups of 8 bits to reach first non-zero bit + persitence_start_8++; +} + + return *(persitence_start_8 - 2); +} + +uint8_t SlotsExamMode::examFetch19(uint32_t start, uint32_t end) { + uint16_t* start16 = (uint16_t*)start; + uint16_t* end16 = (uint16_t*)end; + + while (start16 + 1 <= end16 && *start16 != 0xFFFF) { + start16++; + } + + return *(start16 - 1) >> 8; } -uint32_t SlotsExamMode::getSlotAStartExamAddress(bool newVersion) { - return newVersion ? SlotAExamModeBufferStartNewVersions : SlotAExamModeBufferStartOldVersions; +uint32_t SlotsExamMode::getSlotAStartExamAddress(int ExamVersion) { + if (ExamVersion == 0) { + return SlotAExamModeBufferStartOldVersions; + } + else { + return SlotAExamModeBufferStartNewVersions; + } } -uint32_t SlotsExamMode::getSlotAEndExamAddress(bool newVersion) { - return newVersion ? SlotAExamModeBufferEndNewVersions : SlotAExamModeBufferEndOldVersions; +uint32_t SlotsExamMode::getSlotAEndExamAddress(int ExamVersion) { + if (ExamVersion == 0) { + return SlotAExamModeBufferEndOldVersions; + } + else { + return SlotAExamModeBufferEndNewVersions;; + } } -uint32_t SlotsExamMode::getSlotBStartExamAddress(bool newVersion) { - return newVersion ? SlotBExamModeBufferStartNewVersions : SlotBExamModeBufferStartOldVersions; +uint32_t SlotsExamMode::getSlotBStartExamAddress(int ExamVersion) { + if (ExamVersion == 0) { + return SlotBExamModeBufferStartOldVersions; + } + else { + return SlotBExamModeBufferStartNewVersions; + } } -uint32_t SlotsExamMode::getSlotBEndExamAddress(bool newVersion) { - return newVersion ? SlotBExamModeBufferEndNewVersions : SlotBExamModeBufferEndOldVersions; +uint32_t SlotsExamMode::getSlotBEndExamAddress(int ExamVersion) { + if (ExamVersion == 0) { + return SlotBExamModeBufferEndOldVersions; + } + else { + return SlotBExamModeBufferEndNewVersions; + } } uint32_t SlotsExamMode::getSlotKhiStartExamAddress() { diff --git a/bootloader/slots/slot_exam_mode.h b/bootloader/slots/slot_exam_mode.h index d9e380e9a31..3c19ac7a90f 100644 --- a/bootloader/slots/slot_exam_mode.h +++ b/bootloader/slots/slot_exam_mode.h @@ -25,17 +25,23 @@ static const uint32_t SlotKhiExamModeBufferEnd = 0x90183000; class SlotsExamMode{ public: - static uint8_t FetchSlotAExamMode(bool newVersion); - static uint8_t FetchSlotBExamMode(bool newVerion); - static uint8_t FetchSlotKhiExamMode(); - - static uint32_t getSlotAStartExamAddress(bool newVersion); - static uint32_t getSlotAEndExamAddress(bool newVersion); - static uint32_t getSlotBStartExamAddress(bool newVersion); - static uint32_t getSlotBEndExamAddress(bool newVersion); + static uint8_t FetchSlotExamMode(const char* version, const char* Slot); + static uint8_t FetchSlotAExamMode(const char* version); + static uint8_t FetchSlotBExamMode(const char* version); + static uint8_t FetchSlotKhiExamMode(const char* version); + + static uint32_t getSlotAStartExamAddress(int ExamVersion); + static uint32_t getSlotAEndExamAddress(int ExamVersion); + static uint32_t getSlotBStartExamAddress(int ExamVersion); + static uint32_t getSlotBEndExamAddress(int ExamVersion); static uint32_t getSlotKhiStartExamAddress(); static uint32_t getSlotKhiEndExamAddress(); + static uint8_t examFetch15(uint32_t start, uint32_t end); + static uint8_t examFetch1718(uint32_t start, uint32_t end); + static uint8_t examFetch16(uint32_t start, uint32_t end); + static uint8_t examFetch19(uint32_t start, uint32_t end); + }; enum class ExamMode : int8_t { diff --git a/bootloader/slots/userland_header.cpp b/bootloader/slots/userland_header.cpp index 3c8a9190872..a3e57afec7a 100644 --- a/bootloader/slots/userland_header.cpp +++ b/bootloader/slots/userland_header.cpp @@ -10,7 +10,9 @@ const char * UserlandHeader::version() const { } const bool UserlandHeader::isValid() const { - return m_header == Magic && m_footer == Magic; + // We only verify only the first Magic Number, to display version such as + // Epsilon 16 with older UserlandHeader layout + return m_header == Magic; } const bool UserlandHeader::isOmega() const { diff --git a/bootloader/utility.cpp b/bootloader/utility.cpp index fb6d676ac5b..786e8e0fc78 100644 --- a/bootloader/utility.cpp +++ b/bootloader/utility.cpp @@ -1,10 +1,26 @@ #include #include +// This function takes a pointer to a string (version) and the size of the +// string (versionSize) and returns an integer representing the version. +// Example: "1.2.3" will return 10203. +// "1.0.1-dev" will return 10001. int Utility::versionSum(const char * version, int length) { int sum = 0; - for (int i = 0; i < length; i++) { - sum += version[i] * (strlen(version) * 100 - i * 10); + int currentNumber = 0; + // List of numbers that are allowed in a version + const char * allowedNumbers = "0123456789"; + for (int i = 0; i < length; i++) { + if (version[i] == '.') { + sum = sum * 100 + currentNumber; + currentNumber = 0; + } else if (strchr(allowedNumbers, version[i]) != nullptr) { + currentNumber = currentNumber * 10 + (version[i] - '0'); + } else { + // We found a character that is not a number or a dot, so we stop + break; + } } + sum = sum * 100 + currentNumber; return sum; }