Xeon-SP boards: Factor out OCP VPD `get_cxl_mode()` impl
[coreboot2.git] / util / cbfstool / cse_fpt.c
blob51fa9d0fbcebf2bcc96d628031f761fc85220395
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /* CSE FPT tool */
4 #include <commonlib/endian.h>
5 #include <getopt.h>
6 #include <errno.h>
7 #include <stdlib.h>
8 #include <sys/stat.h>
9 #include <sys/types.h>
10 #include <unistd.h>
12 #include "common.h"
13 #include "cse_fpt.h"
15 static struct params {
16 const char *output_dir;
17 const char *partition_name;
19 struct fpt_hdr_ops *hdr_ops;
20 } params;
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
34 struct fpt_entry {
35 uint8_t name[4]; /* ASCII short name */
36 uint8_t rsvd1[4];
37 uint32_t offset; /* Offset in bytes from start of FPT binary */
38 uint32_t length; /* Size in bytes */
39 uint8_t rsvd2[12];
40 uint32_t flags;
41 } __packed;
43 static struct fpt {
44 struct buffer input_buff;
46 const struct fpt_hdr_ops *hdr_ops;
48 fpt_hdr_ptr hdr;
49 struct fpt_entry *entries;
50 } fpt;
52 static void usage(const char *name)
54 printf("%s: Utility for CSE FPT\n\n"
55 "USAGE:\n"
56 " %s FILE COMMAND\n\n"
57 "COMMANDs:\n"
58 " print\n"
59 " dump [-o OUTPUT_DIR] [-n NAME]\n"
60 "\nOPTIONS:\n"
61 " -o OUTPUT_DIR : Directory to dump the partition files in\n"
62 " -n NAME : Name of partition to dump\n"
63 "\n",
64 name, name);
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 };
74 size_t i;
76 for (i = 0; i < ARRAY_SIZE(fpt_offsets); i++) {
77 if (buffer_size(input_buff) < (strlen(FPT_MARKER) + fpt_offsets[i]))
78 continue;
80 const uint8_t *data = buffer_get(input_buff);
82 if (!memcmp(data + fpt_offsets[i], FPT_MARKER, strlen(FPT_MARKER)))
83 break;
86 if (i == ARRAY_SIZE(fpt_offsets)) {
87 ERROR("Could not locate FPT at known offsets.\n");
88 return -1;
91 buffer_clone(fpt_buff, input_buff);
92 buffer_seek(fpt_buff, fpt_offsets[i]);
94 return 0;
97 static int read_fpt_entries(struct buffer *buff)
99 size_t i;
100 struct fpt_entry *e;
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);
107 return -1;
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);
121 return 0;
124 static const struct fpt_hdr_ops *get_fpt_hdr_ops(struct buffer *buff)
126 static const struct fpt_hdr_ops *hdr_ops[] = {
127 &fpt_hdr_20_ops,
128 &fpt_hdr_21_ops,
131 for (size_t i = 0; i < ARRAY_SIZE(hdr_ops); i++) {
132 if (hdr_ops[i]->match_version(buff))
133 return hdr_ops[i];
136 return NULL;
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);
146 return -1;
149 if (get_fpt_buff(input_buff, &fpt_buff))
150 return -1;
152 fpt.hdr_ops = get_fpt_hdr_ops(&fpt_buff);
153 if (fpt.hdr_ops == NULL) {
154 ERROR("FPT header format not supported!\n");
155 return -1;
158 fpt.hdr = fpt.hdr_ops->read(&fpt_buff);
159 if (!fpt.hdr) {
160 ERROR("Unable to read FPT header!\n");
161 return -1;
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',
184 e->flags);
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)
206 if (!name)
207 return false;
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];
219 return NULL;
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));
227 } else {
228 const struct fpt_entry *e = get_partition_entry(params.partition_name);
229 if (e)
230 print_fpt_entry(e);
231 else {
232 ERROR("Partition %s not found!\n", params.partition_name);
233 return -1;
236 return 0;
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");
244 exit(-1);
246 return false;
249 /* Dump all partitions if no name provided. */
250 if (params.partition_name == NULL)
251 return true;
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;
259 char *filepath;
261 /* output_dir name followed by '/' */
262 if (params.output_dir)
263 filename_len += strlen(params.output_dir) + 1;
265 filepath = malloc(filename_len);
266 if (!filepath)
267 return NULL;
269 snprintf(filepath, filename_len, "%s%s%s",
270 params.output_dir ? : "",
271 params.output_dir ? "/" : "",
272 e->name);
274 return filepath;
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;
281 char *filepath;
283 if (end_offset > buffer_size(&fpt.input_buff)) {
284 ERROR("Offset out of bounds for the partition!\n");
285 return -1;
288 filepath = get_file_path(e);
289 if (!filepath) {
290 ERROR("Failed to allocate space for filepath!\n");
291 return -1;
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);
299 free(filepath);
301 return 0;
304 static int cmd_dump(void)
306 size_t i;
307 bool found = false;
308 struct stat sb;
310 if (params.output_dir && (stat(params.output_dir, &sb) == -1)) {
311 ERROR("Failed to stat %s: %s\n", params.output_dir, strerror(errno));
312 return -1;
315 for (i = 0; i < fpt.hdr_ops->get_entry_count(fpt.hdr); i++) {
316 if (!should_dump_partition(&fpt.entries[i]))
317 continue;
318 found = true;
319 if (write_partition_to_file(&fpt.entries[i]))
320 return -1;
323 if (found == false) {
324 if (params.partition_name)
325 ERROR("%s not found!\n", params.partition_name);
326 ERROR("No partitions dumped!\n");
327 return -1;
330 return 0;
333 static struct command {
334 const char *name;
335 const char *optstring;
336 int (*function)(void);
337 } commands[] = {
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'},
346 {NULL, 0, 0, 0 }
349 int main(int argc, char **argv)
351 if (argc < 3) {
352 ERROR("Incorrect number of args(%d)!\n", argc);
353 usage(argv[0]);
354 return 1;
357 const char *prog_name = argv[0];
358 const char *image_name = argv[1];
359 const char *cmd = argv[2];
360 size_t i;
362 for (i = 0; i < ARRAY_SIZE(commands); i++) {
363 if (strcmp(cmd, commands[i].name))
364 continue;
366 int c;
367 int option_index;
369 while (1) {
370 c = getopt_long(argc, argv, commands[i].optstring,
371 long_options, &option_index);
373 if (c == -1)
374 break;
376 if (strchr(commands[i].optstring, c) == NULL) {
377 ERROR("Invalid option '%c'\n", c);
378 usage(prog_name);
379 return 1;
382 switch (c) {
383 case 'o':
384 params.output_dir = optarg;
385 break;
386 case 'n':
387 params.partition_name = optarg;
388 break;
389 case 'h':
390 case '?':
391 default:
392 usage(prog_name);
393 return 1;
397 break;
400 if (i == ARRAY_SIZE(commands)) {
401 ERROR("No command match %s\n", cmd);
402 usage(prog_name);
403 return 1;
406 if (fpt_parse(image_name))
407 return 1;
409 return commands[i].function();