forked from rehius/usk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
config.c
133 lines (119 loc) · 3.22 KB
/
config.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include "pico/stdlib.h"
#include "config.h"
#include "fuses.h"
#include <stdio.h>
#include <string.h>
typedef struct usk_cfg {
uint8_t cid[16];
uint8_t sign;
uint8_t version_hi;
uint8_t version_lo;
uint8_t lock;
uint16_t pcrc;
} usk_cfg;
#define VER_SIGN sizeof(usk_cfg)
uint16_t payload_crc();
#define typed_cfg ((const usk_cfg *)flash_cfg)
bool is_inited() {
return typed_cfg->sign == VER_SIGN
&& typed_cfg->version_hi == VER_HI
&& typed_cfg->version_lo == VER_LO
&& payload_crc() == typed_cfg->pcrc;
}
bool is_configured(uint8_t * cid) {
bool cid_ok = memcmp(typed_cfg->cid, cid, 16) == 0;
bool init_ok = is_inited();
return cid_ok && init_ok;
}
bool check_blank_config(int start, int size) {
for(int i = start; i < start + size; i+= 4) {
uint32_t val = *(volatile uint32_t*)(flash_cfg + i);
if (val != 0xFFFFFFFF)
return false;
}
return true;
}
void erase_config() {
for (int i = 0; i < CONFIG_SIZE; i += 0x1000) {
if (!check_blank_config(i, 0x1000)) {
flash_range_erase(CONFIG_START + i, 0x1000);
}
}
}
bool is_locked() {
return typed_cfg->lock != 0xFF;
}
void lock_config() {
if (is_locked())
return;
uint8_t buf[256];
usk_cfg * cfg = (usk_cfg *)buf;
memcpy(buf, flash_cfg, 256);
cfg->lock = 0;
flash_range_program(CONFIG_START, buf, 256);
}
extern int boot_slot;
void init_config(uint8_t * cid) {
erase_config();
uint8_t buf[256];
memset(buf, 0xFF, 256);
usk_cfg * cfg = (usk_cfg *)buf;
memcpy(cfg->cid, cid, 16);
cfg->sign = VER_SIGN;
cfg->version_hi = VER_HI;
cfg->version_lo = VER_LO;
cfg->pcrc = payload_crc();
flash_range_program(CONFIG_START, buf, 256);
}
void add_boot_record(int offset) {
if (is_locked()) {
return;
}
uint32_t buf[64];
memcpy(buf, flash_cfg + CONFIG_IDX(offset) * 256, 256);
for (int i = 0; i < 64; i++) {
if (buf[i] != 0) {
int tz = __builtin_ctz(buf[i]);
buf[i] &= ~(1 << tz);
flash_range_program(CONFIG_START + CONFIG_IDX(offset) * 256, (uint8_t*)buf, 256);
return;
}
}
lock_config();
}
int get_weigth(int offset) {
int weight = 0;
uint32_t * buf = (uint32_t*) (flash_cfg + CONFIG_IDX(offset) * 256);
for (int i = 0; i < 64; i++) {
if(buf[i] == 0)
weight += 32;
else {
weight += __builtin_ctz(buf[i]);
break;
}
}
return weight;
}
int find_best_record(int * max_weight) {
static int last_weight = -1;
static int last_offset = 0;
int best_offset = -1;
int best_weight = 0;
for (int i = OFFSET_MIN; i < OFFSET_MAX; i += OFFSET_DIV) {
int cur_weight = get_weigth(i);
if (cur_weight > best_weight) {
if (*max_weight == -1 || cur_weight < *max_weight
|| (cur_weight == *max_weight && *max_weight == last_weight &&
last_offset < i)) {
best_offset = i;
best_weight = cur_weight;
}
}
}
if (best_offset != -1) {
*max_weight = best_weight;
}
last_weight = best_weight;
last_offset = best_offset;
return best_offset;
}