Re: Phi pour N0110: déverrouillage + multiboot Omega 2.0
Posted: 29 Mar 2022, 08:37
Le code que je propose pour exam_mode.cpp, sous forme de diff et ci-dessous en entier.
Apres, je n'ai pas encore compris comment le changement de slot du bootloader interfere avec le mode examen. D'ailleurs en lisant boot.cpp du bootloader j'ai l'impression que MAXDELTA devrait valoir 4 plutot que 5.
et au complet
Apres, je n'ai pas encore compris comment le changement de slot du bootloader interfere avec le mode examen. D'ailleurs en lisant boot.cpp du bootloader j'ai l'impression que MAXDELTA devrait valoir 4 plutot que 5.
- Code: Select all
6,7d5
< #define MAXDELTA 5 // must be <= 8
<
26,30c24,28
< * - 0[MAXDELTA]: the exam mode is off;
< * - 1[MAXDELTA]: the standard exam mode is activated;
< * - 2[MAXDELTA]: the NoSym exam mode is activated;
< * - 3[MAXDELTA]: the Dutch exam mode is activated;
< * - 4[MAXDELTA]: the NoSymNoText exam mode is activated. */
---
> * - 0[3]: the exam mode is off;
> * - 1[3]: the standard exam mode is activated;
> * - 2[3]: the NoSym exam mode is activated;
> * - 3[3]: the Dutch exam mode is activated;
> * - 4[3]: the NoSymNoText exam mode is activated. */
33,34c31,32
< * flash sector that does not point to 0. If this flash sector does not have
< * enough 1, it is erased (to 1) and significantExamModeAddress
---
> * flash sector that does not point to 0. If this flash sector has only 0s or
> * if it has only one 1, it is erased (to 1) and significantExamModeAddress
39c37
< // if i = 0b00011101, firstOneBitInByte(i) returns 5
---
> // if i = 0b000011101, firstOneBitInByte(i) returns 5
70c68,69
< || (persitence_start_8 + 1 == 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)) {
82c81
< uint32_t nbOfZerosBefore = ((readingAddress - (uint8_t *)&_exam_mode_buffer_start) * numberOfBitsInByte) % MAXDELTA;
---
> uint32_t nbOfZerosBefore = ((readingAddress - (uint8_t *)&_exam_mode_buffer_start) * numberOfBitsInByte) % 4;
84,85c83,84
< size_t numberOfLeading0 = (numberOfBitsInByte - numberOfBitsAfterLeadingZeroes(*readingAddress)) % MAXDELTA;
< return (nbOfZerosBefore + numberOfLeading0) % MAXDELTA;
---
> size_t numberOfLeading0 = (numberOfBitsInByte - numberOfBitsAfterLeadingZeroes(*readingAddress)) % 4;
> return (nbOfZerosBefore + numberOfLeading0) % 4;
89c88
< assert(delta >= 1 && delta < MAXDELTA);
---
> assert(delta == 1 || delta == 2 || delta == 3);
95c94
< /* We write in 2 bytes instead of 1, in case there were not enough bits
---
> /* We write in 2 bytes instead of 1, in case there was only one bit
113c112,115
< size_t writtenFlash = *writingAddress <= (1<<(MAXDELTA-1))-1 ? sizeof(uint16_t) : sizeof(uint8_t);
---
> /* As the number of changed bits is capped by 2, if *writingAddress has more
> * than one remaining 1 bit, we know we toggle bits only in the first byte of
> * newValue. We can settle for writing one byte instead of two. */
> size_t writtenFlash = *writingAddress == 1 ? sizeof(uint16_t) : sizeof(uint8_t);
115c117
< assert(writingAddress < (uint8_t *)&_exam_mode_buffer_end - 1 );
---
> assert(writingAddress < (uint8_t *)&_exam_mode_buffer_end - 1 || (writingAddress == (uint8_t *)&_exam_mode_buffer_end - 1 && writtenFlash == 1));
et au complet
- Code: Select all
#include <ion/exam_mode.h>
#include <drivers/config/exam_mode.h>
#include "flash.h"
#include <assert.h>
#define MAXDELTA 5 // must be <= 8
extern "C" {
extern char _exam_mode_buffer_start;
extern char _exam_mode_buffer_end;
}
namespace Ion {
namespace ExamMode {
char ones[Config::ExamModeBufferSize]
__attribute__((section(".exam_mode_buffer")))
__attribute__((used))
= {EXAM_BUFFER_CONTENT};
/* The exam mode is written in flash so that it is resilient to resets.
* We erase the dedicated flash sector (all bits written to 1) and, upon
* deactivating or activating standard, nosym or Dutch exam mode we write one, two or tree
* bits to 0. To determine in which exam mode we are, we count the number of
* leading 0 bits. If it is equal to:
* - 0[MAXDELTA]: the exam mode is off;
* - 1[MAXDELTA]: the standard exam mode is activated;
* - 2[MAXDELTA]: the NoSym exam mode is activated;
* - 3[MAXDELTA]: the Dutch exam mode is activated;
* - 4[MAXDELTA]: the NoSymNoText exam mode is activated. */
/* significantExamModeAddress returns the first uint32_t * in the exam mode
* flash sector that does not point to 0. If this flash sector does not have
* enough 1, it is erased (to 1) and significantExamModeAddress
* returns the start of the sector. */
constexpr static size_t numberOfBitsInByte = 8;
// if i = 0b00011101, firstOneBitInByte(i) returns 5
size_t numberOfBitsAfterLeadingZeroes(int i) {
int minShift = 0;
int maxShift = numberOfBitsInByte;
while (maxShift > minShift+1) {
int shift = (minShift + maxShift)/2;
int shifted = i >> shift;
if (shifted == 0) {
maxShift = shift;
} else {
minShift = shift;
}
}
return maxShift;
}
uint8_t * SignificantExamModeAddress() {
uint32_t * persitence_start_32 = (uint32_t *)&_exam_mode_buffer_start;
uint32_t * persitence_end_32 = (uint32_t *)&_exam_mode_buffer_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
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
|| (persitence_start_8 + 1 == persitence_end_8 )) {
assert(Ion::Device::Flash::SectorAtAddress((uint32_t)&_exam_mode_buffer_start) >= 0);
Ion::Device::Flash::EraseSector(Ion::Device::Flash::SectorAtAddress((uint32_t)&_exam_mode_buffer_start));
return (uint8_t *)&_exam_mode_buffer_start;
}
return persitence_start_8;
}
uint8_t FetchExamMode() {
uint8_t * readingAddress = SignificantExamModeAddress();
// Count the number of 0[3] before reading address
uint32_t nbOfZerosBefore = ((readingAddress - (uint8_t *)&_exam_mode_buffer_start) * numberOfBitsInByte) % MAXDELTA;
// Count the number of 0[3] at reading address
size_t numberOfLeading0 = (numberOfBitsInByte - numberOfBitsAfterLeadingZeroes(*readingAddress)) % MAXDELTA;
return (nbOfZerosBefore + numberOfLeading0) % MAXDELTA;
}
void IncrementExamMode(uint8_t delta) {
assert(delta >= 1 && delta < MAXDELTA);
uint8_t * writingAddress = SignificantExamModeAddress();
assert(*writingAddress != 0);
size_t nbOfTargetedOnes = numberOfBitsAfterLeadingZeroes(*writingAddress);
// Compute the new value with delta bits switched to 0.
/* We write in 2 bytes instead of 1, in case there were not enough bits
* left to 1 in writingAddress. */
nbOfTargetedOnes += numberOfBitsInByte;
nbOfTargetedOnes -= delta;
constexpr size_t newValueSize = sizeof(uint16_t)/sizeof(uint8_t);
uint8_t newValue[newValueSize];
if (nbOfTargetedOnes > numberOfBitsInByte) {
size_t nbOfTargetedOnesInFirstByte = nbOfTargetedOnes - numberOfBitsInByte;
assert(nbOfTargetedOnesInFirstByte <= numberOfBitsInByte);
newValue[0] = ((uint16_t)1 << nbOfTargetedOnesInFirstByte) - 1;
newValue[1] = 0xFF;
} else {
assert(nbOfTargetedOnes <= numberOfBitsInByte);
newValue[0] = 0;
newValue[1] = ((uint16_t)1 << nbOfTargetedOnes) - 1;
}
// Write the value in flash
size_t writtenFlash = *writingAddress <= (1<<(MAXDELTA-1))-1 ? sizeof(uint16_t) : sizeof(uint8_t);
/* Avoid writing out of sector */
assert(writingAddress < (uint8_t *)&_exam_mode_buffer_end - 1 );
Ion::Device::Flash::WriteMemory(writingAddress, newValue, writtenFlash);
}
}
}