Skip to content

Commit ee326fa

Browse files
committed
updater: Can now perform a "dangerous update" which overwrites the partition table and do raw flash writes
The updater will first attempt a standard update: If the partition table hasn't changed too much, then partitions can be updated individually. If the partition table HAS changed too much then the partition table will be overwritten and apps blindly written to flash. Still lots of work to do to make it foolproof, and more flexible.
1 parent f47ffe2 commit ee326fa

File tree

1 file changed

+74
-27
lines changed

1 file changed

+74
-27
lines changed

updater/main/main.c

Lines changed: 74 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
// CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED
1515

1616
#define MAX_PARTITIONS (24) // ESP_PARTITION_TABLE_MAX_ENTRIES
17-
#define ALIGN_BLOCK(val, alignment) ((int)(((val) + (alignment - 1)) / alignment) * alignment)
1817

1918
#define RETRO_GO_IMG_MAGIC "RG_IMG_0"
2019
typedef struct
@@ -35,7 +34,7 @@ typedef struct
3534
struct {int offset, size;} dst;
3635
} flash_task_t;
3736

38-
static size_t gp_buffer_size = 0x20000;
37+
static size_t gp_buffer_size = 0x10000;
3938
static void *gp_buffer = NULL;
4039
static rg_app_t *app;
4140

@@ -47,6 +46,8 @@ static rg_app_t *app;
4746
rg_gui_alert(_("Error"), FORMAT(error_message)); \
4847
goto fail; \
4948
}
49+
#define ALIGN_BLOCK(val, alignment) ((int)(((val) + (alignment - 1)) / alignment) * alignment)
50+
#define CHECK_OVERLAP(start1, end1, start2, end2) ((end1) > (start2) && (end2) > (start1))
5051

5152
static bool fread_at(void *output, int offset, int length, FILE *fp)
5253
{
@@ -159,11 +160,6 @@ static bool do_flash(flash_task_t *queue, size_t queue_count, FILE *fp)
159160
return false;
160161
}
161162

162-
static bool do_update_dangerous(const char *filename)
163-
{
164-
return false;
165-
}
166-
167163
static bool do_update(const char *filename)
168164
{
169165
esp_partition_info_t partition_table[MAX_PARTITIONS] = {0};
@@ -180,43 +176,94 @@ static bool do_update(const char *filename)
180176
if (!parse_file(partition_table, &num_partitions, fp))
181177
goto fail;
182178

183-
const char *current_partition = esp_ota_get_running_partition()->label;
184-
// At this time we only flash partitions of type app and subtype ota_X
179+
const esp_partition_t *running_partition = esp_ota_get_running_partition();
180+
const esp_partition_t *factory_partition = esp_partition_find_first(0x00, 0x00, NULL);
181+
bool dangerous = false;
182+
183+
RG_LOGW("Checking if we can perform a standard update...");
184+
size_t updatable_partitions = 0;
185185
for (size_t i = 0; i < num_partitions; ++i)
186186
{
187187
const esp_partition_info_t *src = &partition_table[i];
188188
const esp_partition_t *dst = esp_partition_find_first(src->type, ESP_PARTITION_SUBTYPE_ANY, (char *)src->label);
189189

190190
if (src->type != PART_TYPE_APP || (src->subtype & 0xF0) != PART_SUBTYPE_OTA_FLAG)
191191
RG_LOGW("Skipping partition %.16s: Unsupported type.", (char *)src->label);
192-
else if (!dst)
193-
RG_LOGW("Skipping partition %.16s: No match found.", (char *)src->label);
194-
else if ((dst->subtype & 0xF0) != PART_SUBTYPE_OTA_FLAG)
195-
RG_LOGW("Skipping partition %.16s: Not an OTA partition.", (char *)src->label);
196-
else if (strncmp(current_partition, dst->label, 16) == 0)
192+
else if (dst == running_partition)
197193
RG_LOGW("Skipping partition %.16s: Currently running.", (char *)src->label);
198-
else if (dst->size < src->pos.size)
199-
RG_LOGW("Skipping partition %.16s: New partition is bigger.", (char *)src->label);
200194
else
201195
{
202-
RG_LOGI("Partition %.16s can be updated!", (char *)src->label);
203-
flash_task_t *task = memset(&queue[queue_count++], 0, sizeof(flash_task_t));
204-
memcpy(task->name, src->label, 16);
205-
task->src.offset = src->pos.offset;
206-
task->src.size = src->pos.size;
207-
task->dst.offset = dst->address;
208-
task->dst.size = dst->size;
196+
updatable_partitions++;
197+
if (!dst)
198+
RG_LOGW("Skipping partition %.16s: No match found.", (char *)src->label);
199+
else if (dst->size < src->pos.size)
200+
RG_LOGW("Skipping partition %.16s: New partition is bigger.", (char *)src->label);
201+
else
202+
{
203+
RG_LOGI("Partition %.16s can be updated!", (char *)src->label);
204+
flash_task_t *task = memset(&queue[queue_count++], 0, sizeof(flash_task_t));
205+
memcpy(task->name, src->label, 16);
206+
task->src.offset = src->pos.offset;
207+
task->src.size = src->pos.size;
208+
task->dst.offset = dst->address;
209+
task->dst.size = dst->size;
210+
}
209211
}
210212
}
211213

212-
rg_display_clear(C_BLACK);
214+
if (updatable_partitions != queue_count)
215+
{
216+
// Some partitions can't be updated with this method, we have to attempt a dangerous update instead!
217+
RG_LOGW("Some partitions cannot be updated in this mode. updatable_partitions=%d, queue_count=%d",
218+
updatable_partitions, queue_count);
219+
#if CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED
220+
// The presence of a factory app that is NOT the current app indicates that we're controlled by
221+
// odroid-go-firmware or odroid-go-multifirmware and it isn't safe to do arbitrary flash writes
222+
if (factory_partition && factory_partition != running_partition)
223+
rg_gui_alert(_("Error"), "Probably running under odroid-go-multifirmware, cannot do full update!");
224+
else
225+
dangerous = true;
226+
#else
227+
rg_gui_alert(_("Error"), "CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is not set, cannot do full update!\n");
228+
#endif
229+
}
213230

214-
if (queue_count == 0)
231+
if (dangerous)
215232
{
216-
// Try dangerous update
217-
// goto fail;
233+
RG_LOGW("Performing a dangerous update!");
234+
queue_count = 0;
235+
for (size_t i = 0; i < num_partitions; ++i)
236+
{
237+
const esp_partition_info_t *src = &partition_table[i];
238+
if (src->type != PART_TYPE_APP || (src->subtype & 0xF0) != PART_SUBTYPE_OTA_FLAG)
239+
RG_LOGW("Skipping partition %.16s: Unsupported type.", (char *)src->label);
240+
else if (src->pos.offset < 0x10000)
241+
RG_LOGW("Skipping partition %.16s: Forbidden region.", (char *)src->label);
242+
// FIXME: Instead of skipping an overlaping partition, we should attempt to relocate it.
243+
else if (CHECK_OVERLAP(src->pos.offset, src->pos.offset + src->pos.size,
244+
running_partition->address, running_partition->address + running_partition->size))
245+
RG_LOGW("Skipping partition %.16s: Overlap with self.", (char *)src->label);
246+
else
247+
{
248+
RG_LOGI("Partition %.16s can be updated!", (char *)src->label);
249+
flash_task_t *task = memset(&queue[queue_count++], 0, sizeof(flash_task_t));
250+
memcpy(task->name, src->label, 16);
251+
task->src.offset = src->pos.offset;
252+
task->src.size = src->pos.size;
253+
task->dst.offset = src->pos.offset;
254+
task->dst.size = src->pos.size;
255+
}
256+
}
257+
258+
queue[queue_count++] = (flash_task_t){
259+
.name = "partition_table",
260+
.src = {ESP_PARTITION_TABLE_OFFSET, ESP_PARTITION_TABLE_MAX_LEN},
261+
.dst = {ESP_PARTITION_TABLE_OFFSET, ESP_PARTITION_TABLE_MAX_LEN},
262+
};
218263
}
219264

265+
rg_display_clear(C_BLACK);
266+
220267
if (!do_flash(queue, queue_count, fp))
221268
goto fail;
222269

0 commit comments

Comments
 (0)