2025-06-11 22:53:28 +02:00
|
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
2017-07-24 23:46:13 -07:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2016-2017, Linaro Ltd.
|
|
|
|
|
* All rights reserved.
|
|
|
|
|
*/
|
2016-07-08 11:26:26 -07:00
|
|
|
#include <errno.h>
|
|
|
|
|
#include <string.h>
|
2024-03-25 17:12:40 -05:00
|
|
|
#include <stdlib.h>
|
2016-07-08 11:26:26 -07:00
|
|
|
#include <libxml/parser.h>
|
|
|
|
|
#include <libxml/tree.h>
|
2024-12-17 14:01:22 -06:00
|
|
|
#include <unistd.h>
|
2016-07-08 11:26:26 -07:00
|
|
|
|
|
|
|
|
#include "patch.h"
|
2018-10-05 12:55:56 +08:00
|
|
|
#include "qdl.h"
|
2025-06-18 09:39:54 +02:00
|
|
|
|
2025-08-28 11:26:11 -05:00
|
|
|
static struct list_head patches = LIST_INIT(patches);
|
2025-09-16 20:32:27 -05:00
|
|
|
static bool patches_loaded;
|
2016-07-08 11:26:26 -07:00
|
|
|
|
|
|
|
|
int patch_load(const char *patch_file)
|
|
|
|
|
{
|
|
|
|
|
struct patch *patch;
|
|
|
|
|
xmlNode *node;
|
|
|
|
|
xmlNode *root;
|
|
|
|
|
xmlDoc *doc;
|
|
|
|
|
int errors;
|
|
|
|
|
|
|
|
|
|
doc = xmlReadFile(patch_file, NULL, 0);
|
|
|
|
|
if (!doc) {
|
2024-12-17 13:24:30 -06:00
|
|
|
ux_err("failed to parse patch-type file \"%s\"\n", patch_file);
|
2016-07-08 11:26:26 -07:00
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
root = xmlDocGetRootElement(doc);
|
|
|
|
|
for (node = root->children; node ; node = node->next) {
|
|
|
|
|
if (node->type != XML_ELEMENT_NODE)
|
|
|
|
|
continue;
|
|
|
|
|
|
2025-06-18 09:39:54 +02:00
|
|
|
if (xmlStrcmp(node->name, (xmlChar *)"patch")) {
|
2024-12-17 13:24:30 -06:00
|
|
|
ux_err("unrecognized tag \"%s\" in patch-type file, ignoring\n", node->name);
|
2016-07-08 11:26:26 -07:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
errors = 0;
|
|
|
|
|
|
|
|
|
|
patch = calloc(1, sizeof(struct patch));
|
|
|
|
|
|
|
|
|
|
patch->sector_size = attr_as_unsigned(node, "SECTOR_SIZE_IN_BYTES", &errors);
|
|
|
|
|
patch->byte_offset = attr_as_unsigned(node, "byte_offset", &errors);
|
|
|
|
|
patch->filename = attr_as_string(node, "filename", &errors);
|
|
|
|
|
patch->partition = attr_as_unsigned(node, "physical_partition_number", &errors);
|
|
|
|
|
patch->size_in_bytes = attr_as_unsigned(node, "size_in_bytes", &errors);
|
2021-04-29 10:25:55 -05:00
|
|
|
patch->start_sector = attr_as_string(node, "start_sector", &errors);
|
2016-07-08 11:26:26 -07:00
|
|
|
patch->value = attr_as_string(node, "value", &errors);
|
|
|
|
|
patch->what = attr_as_string(node, "what", &errors);
|
|
|
|
|
|
|
|
|
|
if (errors) {
|
2024-12-17 13:24:30 -06:00
|
|
|
ux_err("errors while parsing patch-type file \"%s\"\n", patch_file);
|
2016-07-08 11:26:26 -07:00
|
|
|
free(patch);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-28 11:26:11 -05:00
|
|
|
list_add(&patches, &patch->node);
|
2016-07-08 11:26:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
xmlFreeDoc(doc);
|
|
|
|
|
|
2025-09-16 20:32:27 -05:00
|
|
|
patches_loaded = true;
|
|
|
|
|
|
2016-07-08 11:26:26 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
2025-06-18 09:39:54 +02:00
|
|
|
|
2018-11-09 17:33:51 -08:00
|
|
|
int patch_execute(struct qdl_device *qdl, int (*apply)(struct qdl_device *qdl, struct patch *patch))
|
2016-07-08 11:26:26 -07:00
|
|
|
{
|
|
|
|
|
struct patch *patch;
|
2024-12-17 14:01:22 -06:00
|
|
|
unsigned int count = 0;
|
|
|
|
|
unsigned int idx = 0;
|
2016-09-21 11:52:27 -07:00
|
|
|
int ret;
|
2016-07-08 11:26:26 -07:00
|
|
|
|
2025-09-16 20:32:27 -05:00
|
|
|
if (!patches_loaded)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2025-08-28 11:26:11 -05:00
|
|
|
list_for_each_entry(patch, &patches, node) {
|
2025-11-17 15:03:07 -08:00
|
|
|
if (!patch->filename)
|
|
|
|
|
continue;
|
|
|
|
|
|
2024-12-17 14:01:22 -06:00
|
|
|
if (!strcmp(patch->filename, "DISK"))
|
|
|
|
|
count++;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-28 11:26:11 -05:00
|
|
|
list_for_each_entry(patch, &patches, node) {
|
2025-11-17 15:03:07 -08:00
|
|
|
if (!patch->filename)
|
|
|
|
|
continue;
|
|
|
|
|
|
2016-07-08 11:26:26 -07:00
|
|
|
if (strcmp(patch->filename, "DISK"))
|
|
|
|
|
continue;
|
|
|
|
|
|
2018-11-09 17:33:51 -08:00
|
|
|
ret = apply(qdl, patch);
|
2016-09-21 11:52:27 -07:00
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
2024-12-17 14:01:22 -06:00
|
|
|
|
|
|
|
|
ux_progress("Applying patches", idx++, count);
|
2016-07-08 11:26:26 -07:00
|
|
|
}
|
|
|
|
|
|
2024-12-17 14:01:22 -06:00
|
|
|
ux_info("%d patches applied\n", idx);
|
|
|
|
|
|
2016-07-08 11:26:26 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
2024-12-13 13:05:57 -06:00
|
|
|
|
|
|
|
|
void free_patches(void)
|
|
|
|
|
{
|
2025-08-28 11:26:11 -05:00
|
|
|
struct patch *patch;
|
2024-12-13 13:05:57 -06:00
|
|
|
struct patch *next;
|
|
|
|
|
|
2025-08-28 11:26:11 -05:00
|
|
|
list_for_each_entry_safe(patch, next, &patches, node) {
|
2024-12-13 13:05:57 -06:00
|
|
|
free((void *)patch->filename);
|
|
|
|
|
free((void *)patch->start_sector);
|
|
|
|
|
free((void *)patch->value);
|
|
|
|
|
free((void *)patch->what);
|
|
|
|
|
free(patch);
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-28 11:26:11 -05:00
|
|
|
list_init(&patches);
|
2024-12-13 13:05:57 -06:00
|
|
|
}
|