1 /* SPDX-License-Identifier: GPL-2.0-only */
4 #include <commonlib/endian.h>
15 static struct params
{
16 const char *output_dir
;
17 const char *partition_name
;
19 struct fpt_hdr_ops
*hdr_ops
;
22 #define FPT_ENTRY_TYPE_MASK 0x7f
23 #define FPT_ENTRY_TYPE_SHIFT 0
24 #define GET_FPT_ENTRY_TYPE(x) (((x) >> FPT_ENTRY_TYPE_SHIFT) & FPT_ENTRY_TYPE_MASK)
25 #define FPT_ENTRY_TYPE_CODE 0x0
26 #define FPT_ENTRY_TYPE_DATA 0x1
28 #define FPT_ENTRY_VALID_MASK 0xff
29 #define FPT_ENTRY_VALID_SHIFT 24
30 #define GET_FPT_ENTRY_VALID(x) (((x) >> FPT_ENTRY_VALID_SHIFT) & FPT_ENTRY_VALID_MASK)
31 #define FPT_ENTRY_INVALID 0xff
32 #define FPT_ENTRY_VALID 0x0
35 uint8_t name
[4]; /* ASCII short name */
37 uint32_t offset
; /* Offset in bytes from start of FPT binary */
38 uint32_t length
; /* Size in bytes */
44 struct buffer input_buff
;
46 const struct fpt_hdr_ops
*hdr_ops
;
49 struct fpt_entry
*entries
;
52 static void usage(const char *name
)
54 printf("%s: Utility for CSE FPT\n\n"
56 " %s FILE COMMAND\n\n"
59 " dump [-o OUTPUT_DIR] [-n NAME]\n"
61 " -o OUTPUT_DIR : Directory to dump the partition files in\n"
62 " -n NAME : Name of partition to dump\n"
67 static int get_fpt_buff(struct buffer
*input_buff
, struct buffer
*fpt_buff
)
70 * FPT marker is typically at offset 0x10 in the released CSE binary. Check at offset
71 * 0x10 first and if that fails fall back to checking offset 0.
73 const size_t fpt_offsets
[] = { 0x10, 0 };
76 for (i
= 0; i
< ARRAY_SIZE(fpt_offsets
); i
++) {
77 if (buffer_size(input_buff
) < (strlen(FPT_MARKER
) + fpt_offsets
[i
]))
80 const uint8_t *data
= buffer_get(input_buff
);
82 if (!memcmp(data
+ fpt_offsets
[i
], FPT_MARKER
, strlen(FPT_MARKER
)))
86 if (i
== ARRAY_SIZE(fpt_offsets
)) {
87 ERROR("Could not locate FPT at known offsets.\n");
91 buffer_clone(fpt_buff
, input_buff
);
92 buffer_seek(fpt_buff
, fpt_offsets
[i
]);
97 static int read_fpt_entries(struct buffer
*buff
)
101 const size_t entries
= fpt
.hdr_ops
->get_entry_count(fpt
.hdr
);
102 const size_t fpt_entries_size
= sizeof(struct fpt_entry
) * entries
;
104 if (buffer_size(buff
) < fpt_entries_size
) {
105 ERROR("Not enough bytes(actual=0x%zx, expected=0x%zx) for FPT entries!\n",
106 buffer_size(buff
), fpt_entries_size
);
110 e
= fpt
.entries
= malloc(fpt_entries_size
);
112 for (i
= 0; i
< entries
; i
++, e
++) {
113 READ_MEMBER(buff
, e
->name
);
114 READ_MEMBER(buff
, e
->rsvd1
);
115 READ_MEMBER(buff
, e
->offset
);
116 READ_MEMBER(buff
, e
->length
);
117 READ_MEMBER(buff
, e
->rsvd2
);
118 READ_MEMBER(buff
, e
->flags
);
124 static const struct fpt_hdr_ops
*get_fpt_hdr_ops(struct buffer
*buff
)
126 static const struct fpt_hdr_ops
*hdr_ops
[] = {
131 for (size_t i
= 0; i
< ARRAY_SIZE(hdr_ops
); i
++) {
132 if (hdr_ops
[i
]->match_version(buff
))
139 static int fpt_parse(const char *image_name
)
141 struct buffer
*input_buff
= &fpt
.input_buff
;
142 struct buffer fpt_buff
;
144 if (buffer_from_file(input_buff
, image_name
)) {
145 ERROR("Failed to read input file %s\n", image_name
);
149 if (get_fpt_buff(input_buff
, &fpt_buff
))
152 fpt
.hdr_ops
= get_fpt_hdr_ops(&fpt_buff
);
153 if (fpt
.hdr_ops
== NULL
) {
154 ERROR("FPT header format not supported!\n");
158 fpt
.hdr
= fpt
.hdr_ops
->read(&fpt_buff
);
160 ERROR("Unable to read FPT header!\n");
164 return read_fpt_entries(&fpt_buff
);
167 static bool is_partition_valid(const struct fpt_entry
*e
)
169 return e
->offset
!= 0 && e
->length
!= 0 &&
170 GET_FPT_ENTRY_VALID(e
->flags
) != FPT_ENTRY_INVALID
;
173 static bool is_partition_code(const struct fpt_entry
*e
)
175 return GET_FPT_ENTRY_TYPE(e
->flags
) == FPT_ENTRY_TYPE_CODE
;
178 static void print_fpt_entry(const struct fpt_entry
*e
)
180 printf("%-25s0x%-23x0x%-23x%c,%c (0x%.8x)\n",
181 e
->name
, e
->offset
, e
->length
,
182 is_partition_code(e
) ? 'C' : 'D',
183 is_partition_valid(e
) ? 'V' : 'I',
187 static void print_fpt_entries(const struct fpt_entry
*e
, size_t count
)
189 printf("\n * FPT entries\n");
191 printf("%-25s%-25s%-25s%-25s\n", "Name", "Offset", "Size", "Flags");
193 printf("=============================================================="
194 "===============================\n");
196 for (size_t i
= 0; i
< count
; i
++)
197 print_fpt_entry(&e
[i
]);
199 printf("=============================================================="
200 "================================\n");
201 printf("Flags: I=invalid, V=valid, C=code, D=data\n");
204 static bool partition_name_match(const struct fpt_entry
*e
, const char *name
)
209 return !memcmp(e
->name
, name
, sizeof(e
->name
));
212 static const struct fpt_entry
*get_partition_entry(const char *name
)
214 for (size_t i
= 0; i
< fpt
.hdr_ops
->get_entry_count(fpt
.hdr
); i
++) {
215 if (partition_name_match(&fpt
.entries
[i
], name
))
216 return &fpt
.entries
[i
];
222 static int cmd_print(void)
224 if (params
.partition_name
== NULL
) {
225 fpt
.hdr_ops
->print(fpt
.hdr
);
226 print_fpt_entries(fpt
.entries
, fpt
.hdr_ops
->get_entry_count(fpt
.hdr
));
228 const struct fpt_entry
*e
= get_partition_entry(params
.partition_name
);
232 ERROR("Partition %s not found!\n", params
.partition_name
);
239 static bool should_dump_partition(const struct fpt_entry
*e
)
241 if (!is_partition_valid(e
)) {
242 if (partition_name_match(e
, params
.partition_name
)) {
243 ERROR("Invalid partition requested to be dumped!\n");
249 /* Dump all partitions if no name provided. */
250 if (params
.partition_name
== NULL
)
253 return partition_name_match(e
, params
.partition_name
);
256 static char *get_file_path(const struct fpt_entry
*e
)
258 size_t filename_len
= sizeof(e
->name
) + 1;
261 /* output_dir name followed by '/' */
262 if (params
.output_dir
)
263 filename_len
+= strlen(params
.output_dir
) + 1;
265 filepath
= malloc(filename_len
);
269 snprintf(filepath
, filename_len
, "%s%s%s",
270 params
.output_dir
? : "",
271 params
.output_dir
? "/" : "",
277 static int write_partition_to_file(const struct fpt_entry
*e
)
279 size_t end_offset
= e
->offset
+ e
->length
- 1;
280 struct buffer part_buffer
;
283 if (end_offset
> buffer_size(&fpt
.input_buff
)) {
284 ERROR("Offset out of bounds for the partition!\n");
288 filepath
= get_file_path(e
);
290 ERROR("Failed to allocate space for filepath!\n");
294 printf("Dumping %.4s in %s\n", e
->name
, filepath
);
296 buffer_splice(&part_buffer
, &fpt
.input_buff
, e
->offset
, e
->length
);
297 buffer_write_file(&part_buffer
, filepath
);
304 static int cmd_dump(void)
310 if (params
.output_dir
&& (stat(params
.output_dir
, &sb
) == -1)) {
311 ERROR("Failed to stat %s: %s\n", params
.output_dir
, strerror(errno
));
315 for (i
= 0; i
< fpt
.hdr_ops
->get_entry_count(fpt
.hdr
); i
++) {
316 if (!should_dump_partition(&fpt
.entries
[i
]))
319 if (write_partition_to_file(&fpt
.entries
[i
]))
323 if (found
== false) {
324 if (params
.partition_name
)
325 ERROR("%s not found!\n", params
.partition_name
);
326 ERROR("No partitions dumped!\n");
333 static struct command
{
335 const char *optstring
;
336 int (*function
)(void);
338 { "print", "n:?", cmd_print
},
339 { "dump", "n:o:?", cmd_dump
},
342 static struct option long_options
[] = {
343 {"help", required_argument
, 0, 'h'},
344 {"partition_name", required_argument
, 0, 'n'},
345 {"output_dir", required_argument
, 0, 'o'},
349 int main(int argc
, char **argv
)
352 ERROR("Incorrect number of args(%d)!\n", argc
);
357 const char *prog_name
= argv
[0];
358 const char *image_name
= argv
[1];
359 const char *cmd
= argv
[2];
362 for (i
= 0; i
< ARRAY_SIZE(commands
); i
++) {
363 if (strcmp(cmd
, commands
[i
].name
))
370 c
= getopt_long(argc
, argv
, commands
[i
].optstring
,
371 long_options
, &option_index
);
376 if (strchr(commands
[i
].optstring
, c
) == NULL
) {
377 ERROR("Invalid option '%c'\n", c
);
384 params
.output_dir
= optarg
;
387 params
.partition_name
= optarg
;
400 if (i
== ARRAY_SIZE(commands
)) {
401 ERROR("No command match %s\n", cmd
);
406 if (fpt_parse(image_name
))
409 return commands
[i
].function();