1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright © 2022 Rafał Miłecki <rafal@milecki.pl>
6 #include <linux/kernel.h>
7 #include <linux/module.h>
8 #include <linux/mtd/mtd.h>
9 #include <linux/mtd/partitions.h>
11 #include <linux/slab.h>
13 #define TPLINK_SAFELOADER_DATA_OFFSET 4
14 #define TPLINK_SAFELOADER_MAX_PARTS 32
16 struct safeloader_cmn_header
{
21 static void *mtd_parser_tplink_safeloader_read_table(struct mtd_info
*mtd
)
23 struct safeloader_cmn_header hdr
;
24 struct device_node
*np
;
31 np
= mtd_get_of_node(mtd
);
32 if (mtd_is_partition(mtd
))
35 np
= of_get_child_by_name(np
, "partitions");
37 if (of_property_read_u32(np
, "partitions-table-offset", &offset
)) {
38 pr_err("Failed to get partitions table offset\n");
42 err
= mtd_read(mtd
, offset
, sizeof(hdr
), &bytes_read
, (uint8_t *)&hdr
);
43 if (err
&& !mtd_is_bitflip(err
)) {
44 pr_err("Failed to read from %s at 0x%x\n", mtd
->name
, offset
);
48 size
= be32_to_cpu(hdr
.size
);
50 buf
= kmalloc(size
+ 1, GFP_KERNEL
);
54 err
= mtd_read(mtd
, offset
+ sizeof(hdr
), size
, &bytes_read
, buf
);
55 if (err
&& !mtd_is_bitflip(err
)) {
56 pr_err("Failed to read from %s at 0x%zx\n", mtd
->name
, offset
+ sizeof(hdr
));
73 static int mtd_parser_tplink_safeloader_parse(struct mtd_info
*mtd
,
74 const struct mtd_partition
**pparts
,
75 struct mtd_part_parser_data
*data
)
77 struct mtd_partition
*parts
;
85 parts
= kcalloc(TPLINK_SAFELOADER_MAX_PARTS
, sizeof(*parts
), GFP_KERNEL
);
91 buf
= mtd_parser_tplink_safeloader_read_table(mtd
);
97 for (idx
= 0, offset
= TPLINK_SAFELOADER_DATA_OFFSET
;
98 idx
< TPLINK_SAFELOADER_MAX_PARTS
&&
99 sscanf(buf
+ offset
, "partition %64s base 0x%llx size 0x%llx%zn\n",
100 name
, &parts
[idx
].offset
, &parts
[idx
].size
, &bytes
) == 3;
101 idx
++, offset
+= bytes
+ 1) {
102 parts
[idx
].name
= kstrdup(name
, GFP_KERNEL
);
103 if (!parts
[idx
].name
) {
109 if (idx
== TPLINK_SAFELOADER_MAX_PARTS
)
110 pr_warn("Reached maximum number of partitions!\n");
119 for (idx
-= 1; idx
>= 0; idx
--)
120 kfree(parts
[idx
].name
);
127 static void mtd_parser_tplink_safeloader_cleanup(const struct mtd_partition
*pparts
,
132 for (i
= 0; i
< nr_parts
; i
++)
133 kfree(pparts
[i
].name
);
138 static const struct of_device_id mtd_parser_tplink_safeloader_of_match_table
[] = {
139 { .compatible
= "tplink,safeloader-partitions" },
142 MODULE_DEVICE_TABLE(of
, mtd_parser_tplink_safeloader_of_match_table
);
144 static struct mtd_part_parser mtd_parser_tplink_safeloader
= {
145 .parse_fn
= mtd_parser_tplink_safeloader_parse
,
146 .cleanup
= mtd_parser_tplink_safeloader_cleanup
,
147 .name
= "tplink-safeloader",
148 .of_match_table
= mtd_parser_tplink_safeloader_of_match_table
,
150 module_mtd_part_parser(mtd_parser_tplink_safeloader
);
152 MODULE_DESCRIPTION("TP-Link Safeloader partitions parser");
153 MODULE_LICENSE("GPL");