+ while (c) {
+ LOG_DEBUG("%c%c 0x%08"PRIx32"-0x%08"PRIx32" (%"PRIu32" bytes)",
+ c->backup ? 'b' : ' ', c->free ? ' ' : '*',
+ c->address, c->address + c->size - 1, c->size);
+ c = c->next;
+ }
+}
+
+/* Reduce area to size bytes, create a new free area from the remaining bytes, if any. */
+static void target_split_working_area(struct working_area *area, uint32_t size)
+{
+ assert(area->free); /* Shouldn't split an allocated area */
+ assert(size <= area->size); /* Caller should guarantee this */
+
+ /* Split only if not already the right size */
+ if (size < area->size) {
+ struct working_area *new_wa = malloc(sizeof(*new_wa));
+
+ if (new_wa == NULL)
+ return;
+
+ new_wa->next = area->next;
+ new_wa->size = area->size - size;
+ new_wa->address = area->address + size;
+ new_wa->backup = NULL;
+ new_wa->user = NULL;
+ new_wa->free = true;
+
+ area->next = new_wa;
+ area->size = size;
+
+ /* If backup memory was allocated to this area, it has the wrong size
+ * now so free it and it will be reallocated if/when needed */
+ if (area->backup) {
+ free(area->backup);
+ area->backup = NULL;
+ }
+ }
+}
+
+/* Merge all adjacent free areas into one */
+static void target_merge_working_areas(struct target *target)
+{
+ struct working_area *c = target->working_areas;
+
+ while (c && c->next) {
+ assert(c->next->address == c->address + c->size); /* This is an invariant */
+
+ /* Find two adjacent free areas */
+ if (c->free && c->next->free) {
+ /* Merge the last into the first */
+ c->size += c->next->size;
+
+ /* Remove the last */
+ struct working_area *to_be_freed = c->next;
+ c->next = c->next->next;
+ if (to_be_freed->backup)
+ free(to_be_freed->backup);
+ free(to_be_freed);
+
+ /* If backup memory was allocated to the remaining area, it's has
+ * the wrong size now */
+ if (c->backup) {
+ free(c->backup);
+ c->backup = NULL;
+ }
+ } else {
+ c = c->next;
+ }
+ }
+}
+
+int target_alloc_working_area_try(struct target *target, uint32_t size, struct working_area **area)
+{