1cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson/*
2cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson * Copyright 2014 The Chromium OS Authors. All rights reserved.
3cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson * Use of this source code is governed by a BSD-style license that can be
4cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson * found in the LICENSE file.
5cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson */
6cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson
7cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson#include <stdint.h>
8cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson#include <stdio.h>
9cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson
102559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson#include "file_type.h"
11cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson#include "fmap.h"
12cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson#include "futility.h"
13cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson#include "traversal.h"
14cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson
15cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson/* What functions do we invoke for a particular operation and component? */
16cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson
17cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson/* FUTIL_OP_SHOW */
186f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardsonstatic int (* const cb_show_funcs[])(struct futil_traverse_state_s *state) = {
19cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	futil_cb_show_begin,		/* CB_BEGIN_TRAVERSAL */
20cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	NULL,				/* CB_END_TRAVERSAL */
21cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	futil_cb_show_gbb,		/* CB_FMAP_GBB */
22cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	futil_cb_show_fw_preamble,	/* CB_FMAP_VBLOCK_A */
23cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	futil_cb_show_fw_preamble,	/* CB_FMAP_VBLOCK_B */
246f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	futil_cb_show_fw_main,		/* CB_FMAP_FW_MAIN_A */
256f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	futil_cb_show_fw_main,		/* CB_FMAP_FW_MAIN_B */
264805f1841de9d670aaed9bdaea21147ee1d59242Bill Richardson	futil_cb_show_pubkey,		/* CB_PUBKEY */
276f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	futil_cb_show_keyblock,		/* CB_KEYBLOCK */
28cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	futil_cb_show_gbb,		/* CB_GBB */
29cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	futil_cb_show_fw_preamble,	/* CB_FW_PREAMBLE */
305f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	futil_cb_show_kernel_preamble,	/* CB_KERN_PREAMBLE */
316f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	NULL,				/* CB_RAW_FIRMWARE */
326f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	NULL,				/* CB_RAW_KERNEL */
334805f1841de9d670aaed9bdaea21147ee1d59242Bill Richardson	futil_cb_show_privkey,		/* CB_PRIVKEY */
34cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson};
35cf6e78dbd54684ebba0c3bfc2524426f61193416Bill RichardsonBUILD_ASSERT(ARRAY_SIZE(cb_show_funcs) == NUM_CB_COMPONENTS);
36cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson
3715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson/* FUTIL_OP_SIGN */
386f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardsonstatic int (* const cb_sign_funcs[])(struct futil_traverse_state_s *state) = {
3915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	futil_cb_sign_begin,		/* CB_BEGIN_TRAVERSAL */
4015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	futil_cb_sign_end,		/* CB_END_TRAVERSAL */
4115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	NULL,				/* CB_FMAP_GBB */
425f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	futil_cb_sign_fw_vblock,	/* CB_FMAP_VBLOCK_A */
435f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	futil_cb_sign_fw_vblock,	/* CB_FMAP_VBLOCK_B */
445f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	futil_cb_sign_fw_main,		/* CB_FMAP_FW_MAIN_A */
455f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	futil_cb_sign_fw_main,		/* CB_FMAP_FW_MAIN_B */
465f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	futil_cb_sign_pubkey,		/* CB_PUBKEY */
475f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	NULL,				/* CB_KEYBLOCK */
485f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	NULL,				/* CB_GBB */
495f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	NULL,				/* CB_FW_PREAMBLE */
505f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	futil_cb_resign_kernel_part,	/* CB_KERN_PREAMBLE */
515f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	futil_cb_sign_raw_firmware,	/* CB_RAW_FIRMWARE */
525f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	futil_cb_create_kernel_part,	/* CB_RAW_KERNEL */
534805f1841de9d670aaed9bdaea21147ee1d59242Bill Richardson	NULL,				/* CB_PRIVKEY */
5415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson};
5515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill RichardsonBUILD_ASSERT(ARRAY_SIZE(cb_sign_funcs) == NUM_CB_COMPONENTS);
5615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
576f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardsonstatic int (* const * const cb_func[])(struct futil_traverse_state_s *state) = {
58cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	cb_show_funcs,
5915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	cb_sign_funcs,
60cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson};
61cf6e78dbd54684ebba0c3bfc2524426f61193416Bill RichardsonBUILD_ASSERT(ARRAY_SIZE(cb_func) == NUM_FUTIL_OPS);
62cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson
63cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson/*
64cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson * File types that don't need iterating can use a lookup table to determine the
65cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson * callback component and name. The index is the file type.
66cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson */
67cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardsonstatic const struct {
68cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	enum futil_cb_component component;
69cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	const char * const name;
70cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson} direct_callback[] = {
71cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	{0,                NULL},		/* FILE_TYPE_UNKNOWN */
72cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	{CB_PUBKEY,        "VbPublicKey"},	/* FILE_TYPE_PUBKEY */
73cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	{CB_KEYBLOCK,      "VbKeyBlock"},	/* FILE_TYPE_KEYBLOCK */
746f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	{CB_FW_PREAMBLE,   "FW Preamble"},	/* FILE_TYPE_FW_PREAMBLE */
75cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	{CB_GBB,           "GBB"},		/* FILE_TYPE_GBB */
76cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	{0,                NULL},		/* FILE_TYPE_BIOS_IMAGE */
77cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	{0,                NULL},		/* FILE_TYPE_OLD_BIOS_IMAGE */
786f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	{CB_KERN_PREAMBLE, "Kernel Preamble"},	/* FILE_TYPE_KERN_PREAMBLE */
796f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	{CB_RAW_FIRMWARE,  "raw firmware"},	/* FILE_TYPE_RAW_FIRMWARE */
806f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	{CB_RAW_KERNEL,    "raw kernel"},	/* FILE_TYPE_RAW_KERNEL */
812559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson	{0,                "chromiumos disk"},	/* FILE_TYPE_CHROMIUMOS_DISK */
824805f1841de9d670aaed9bdaea21147ee1d59242Bill Richardson	{CB_PRIVKEY,       "VbPrivateKey"},	/* FILE_TYPE_PRIVKEY */
83cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson};
84cf6e78dbd54684ebba0c3bfc2524426f61193416Bill RichardsonBUILD_ASSERT(ARRAY_SIZE(direct_callback) == NUM_FILE_TYPES);
85cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson
86cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson/*
87cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson * The Chrome OS BIOS must contain specific FMAP areas, and we generally want
88cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson * to look at each one in a certain order.
89cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson */
90cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardsonstruct bios_area_s {
91cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	const char * const name;
92cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	enum futil_cb_component component;
93cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson};
94cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson
95cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson/* This are the expected areas, in order of traversal. */
96cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardsonstatic const struct bios_area_s bios_area[] = {
97cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	{"GBB",       CB_FMAP_GBB},
98cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	{"FW_MAIN_A", CB_FMAP_FW_MAIN_A},
99cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	{"FW_MAIN_B", CB_FMAP_FW_MAIN_B},
100cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	{"VBLOCK_A",  CB_FMAP_VBLOCK_A},
101cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	{"VBLOCK_B",  CB_FMAP_VBLOCK_B},
102cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	{0, 0}
103cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson};
104cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson
105cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson/* Really old BIOS images had different names, but worked the same. */
106cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardsonstatic const struct bios_area_s old_bios_area[] = {
107cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	{"GBB Area",        CB_FMAP_GBB},
108cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	{"Firmware A Data", CB_FMAP_FW_MAIN_A},
109cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	{"Firmware B Data", CB_FMAP_FW_MAIN_B},
110cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	{"Firmware A Key",  CB_FMAP_VBLOCK_A},
111cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	{"Firmware B Key",  CB_FMAP_VBLOCK_B},
112cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	{0, 0}
113cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson};
114cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson
115cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardsonstatic int has_all_areas(uint8_t *buf, uint32_t len, FmapHeader *fmap,
116cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson			 const struct bios_area_s *area)
117cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson{
1186f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	/* We must have all the expected areas */
1196f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	for (; area->name; area++)
120cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson		if (!fmap_find_by_name(buf, len, fmap, area->name, 0))
121cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson			return 0;
122cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson
123cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	/* Found 'em all */
124cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	return 1;
125cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson}
126cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson
1272559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardsonenum futil_file_type recognize_bios_image(uint8_t *buf, uint32_t len)
1282559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson{
1292559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson	FmapHeader *fmap = fmap_find(buf, len);
1302559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson	if (fmap) {
1312559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson		if (has_all_areas(buf, len, fmap, bios_area))
1322559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson			return FILE_TYPE_BIOS_IMAGE;
1332559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson		if (has_all_areas(buf, len, fmap, old_bios_area))
1342559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson			return FILE_TYPE_OLD_BIOS_IMAGE;
1352559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson	}
1362559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson	return FILE_TYPE_UNKNOWN;
1372559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson}
1386f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson
1397ccd9ce48e761b7614d29ff95ef97d0a7dc1d599Bill Richardsonstatic const char * const futil_cb_component_str[] = {
1406f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	"CB_BEGIN_TRAVERSAL",
1416f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	"CB_END_TRAVERSAL",
1426f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	"CB_FMAP_GBB",
1436f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	"CB_FMAP_VBLOCK_A",
1446f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	"CB_FMAP_VBLOCK_B",
1456f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	"CB_FMAP_FW_MAIN_A",
1466f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	"CB_FMAP_FW_MAIN_B",
1476f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	"CB_PUBKEY",
1486f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	"CB_KEYBLOCK",
1496f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	"CB_GBB",
1506f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	"CB_FW_PREAMBLE",
1516f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	"CB_KERN_PREAMBLE",
1526f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	"CB_RAW_FIRMWARE",
1536f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	"CB_RAW_KERNEL",
1544805f1841de9d670aaed9bdaea21147ee1d59242Bill Richardson	"CB_PRIVKEY",
1556f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson};
1566f72ffa8037acb69de4fc4346783ea10298a7e57Bill RichardsonBUILD_ASSERT(ARRAY_SIZE(futil_cb_component_str) == NUM_CB_COMPONENTS);
1576f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson
1586f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardsonstatic int invoke_callback(struct futil_traverse_state_s *state,
1596f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson			   enum futil_cb_component c, const char *name,
1606f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson			   uint32_t offset, uint8_t *buf, uint32_t len)
1616f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson{
1626f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	Debug("%s: name \"%s\" op %d component %s"
1636f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	      " offset=0x%08x len=0x%08x, buf=%p\n",
1646f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	      __func__, name, state->op, futil_cb_component_str[c],
1656f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	      offset, len, buf);
1666f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson
16705987b159acb9737707b9ef92b818ac434ef8c3dDavid Riley	if ((int) c < 0 || c >= NUM_CB_COMPONENTS) {
1686f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson		fprintf(stderr, "Invalid component %d\n", c);
1696f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson		return 1;
1706f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	}
1716f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson
1726f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	state->component = c;
1736f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	state->name = name;
1746f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	state->cb_area[c].offset = offset;
1756f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	state->cb_area[c].buf = buf;
1766f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	state->cb_area[c].len = len;
1776f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	state->my_area = &state->cb_area[c];
1786f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson
1796f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	if (cb_func[state->op][c])
1806f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson		return cb_func[state->op][c](state);
1816f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson
1826f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson	return 0;
1836f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson}
1846f72ffa8037acb69de4fc4346783ea10298a7e57Bill Richardson
1857ccd9ce48e761b7614d29ff95ef97d0a7dc1d599Bill Richardsonstatic void fmap_limit_area(FmapAreaHeader *ah, uint32_t len)
1867ccd9ce48e761b7614d29ff95ef97d0a7dc1d599Bill Richardson{
1877ccd9ce48e761b7614d29ff95ef97d0a7dc1d599Bill Richardson	uint32_t sum = ah->area_offset + ah->area_size;
1887ccd9ce48e761b7614d29ff95ef97d0a7dc1d599Bill Richardson	if (sum < ah->area_size || sum > len) {
1897ccd9ce48e761b7614d29ff95ef97d0a7dc1d599Bill Richardson		Debug("%s(%s) 0x%x + 0x%x > 0x%x\n",
1907ccd9ce48e761b7614d29ff95ef97d0a7dc1d599Bill Richardson		      __func__, ah->area_name,
1917ccd9ce48e761b7614d29ff95ef97d0a7dc1d599Bill Richardson		      ah->area_offset, ah->area_size, len);
1927ccd9ce48e761b7614d29ff95ef97d0a7dc1d599Bill Richardson		ah->area_offset = 0;
1937ccd9ce48e761b7614d29ff95ef97d0a7dc1d599Bill Richardson		ah->area_size = 0;
1947ccd9ce48e761b7614d29ff95ef97d0a7dc1d599Bill Richardson	}
1957ccd9ce48e761b7614d29ff95ef97d0a7dc1d599Bill Richardson}
1967ccd9ce48e761b7614d29ff95ef97d0a7dc1d599Bill Richardson
197b0f1cc5e22e87a3ef1655643116991673dd1b531Bill Richardsonint futil_traverse(uint8_t *buf, uint32_t len,
198b0f1cc5e22e87a3ef1655643116991673dd1b531Bill Richardson		   struct futil_traverse_state_s *state,
199b0f1cc5e22e87a3ef1655643116991673dd1b531Bill Richardson		   enum futil_file_type type)
200cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson{
201cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	FmapHeader *fmap;
202cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	FmapAreaHeader *ah = 0;
203cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	const struct bios_area_s *area;
204cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	int retval = 0;
205cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson
20605987b159acb9737707b9ef92b818ac434ef8c3dDavid Riley	if ((int) state->op < 0 || state->op >= NUM_FUTIL_OPS) {
207b0f1cc5e22e87a3ef1655643116991673dd1b531Bill Richardson		fprintf(stderr, "Invalid op %d\n", state->op);
208b0f1cc5e22e87a3ef1655643116991673dd1b531Bill Richardson		return 1;
209b0f1cc5e22e87a3ef1655643116991673dd1b531Bill Richardson	}
210b0f1cc5e22e87a3ef1655643116991673dd1b531Bill Richardson
211b0f1cc5e22e87a3ef1655643116991673dd1b531Bill Richardson	if (type == FILE_TYPE_UNKNOWN)
2122559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson		type = futil_file_type_buf(buf, len);
213cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	state->in_type = type;
214cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson
215cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	state->errors = retval;
216cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	retval |= invoke_callback(state, CB_BEGIN_TRAVERSAL, "<begin>",
217cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson				  0, buf, len);
218cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	state->errors = retval;
219cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson
220cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	switch (type) {
221cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	case FILE_TYPE_BIOS_IMAGE:
222cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson		/* We've already checked, so we know this will work. */
223cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson		fmap = fmap_find(buf, len);
224cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson		for (area = bios_area; area->name; area++) {
225cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson			/* We know this will work, too */
226cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson			fmap_find_by_name(buf, len, fmap, area->name, &ah);
2277ccd9ce48e761b7614d29ff95ef97d0a7dc1d599Bill Richardson			/* But the file might be truncated */
2287ccd9ce48e761b7614d29ff95ef97d0a7dc1d599Bill Richardson			fmap_limit_area(ah, len);
229cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson			retval |= invoke_callback(state,
230cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson						  area->component,
231cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson						  area->name,
232cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson						  ah->area_offset,
233cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson						  buf + ah->area_offset,
234cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson						  ah->area_size);
235cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson			state->errors = retval;
236cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson		}
237cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson		break;
238cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson
239cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	case FILE_TYPE_OLD_BIOS_IMAGE:
240cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson		/* We've already checked, so we know this will work. */
241cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson		fmap = fmap_find(buf, len);
242cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson		for (area = old_bios_area; area->name; area++) {
243cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson			/* We know this will work, too */
244cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson			fmap_find_by_name(buf, len, fmap, area->name, &ah);
2457ccd9ce48e761b7614d29ff95ef97d0a7dc1d599Bill Richardson			/* But the file might be truncated */
2467ccd9ce48e761b7614d29ff95ef97d0a7dc1d599Bill Richardson			fmap_limit_area(ah, len);
247cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson			retval |= invoke_callback(state,
248cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson						  area->component,
249cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson						  area->name,
250cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson						  ah->area_offset,
251cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson						  buf + ah->area_offset,
252cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson						  ah->area_size);
253cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson			state->errors = retval;
254cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson		}
255cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson		break;
256cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson
2577ccd9ce48e761b7614d29ff95ef97d0a7dc1d599Bill Richardson	case FILE_TYPE_UNKNOWN:
2587ccd9ce48e761b7614d29ff95ef97d0a7dc1d599Bill Richardson	case FILE_TYPE_CHROMIUMOS_DISK:
2597ccd9ce48e761b7614d29ff95ef97d0a7dc1d599Bill Richardson		/* Nothing to do for these file types (yet) */
2607ccd9ce48e761b7614d29ff95ef97d0a7dc1d599Bill Richardson		break;
2617ccd9ce48e761b7614d29ff95ef97d0a7dc1d599Bill Richardson
262cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	default:
2637ccd9ce48e761b7614d29ff95ef97d0a7dc1d599Bill Richardson		/* All other file types have their own callbacks */
2642559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson		retval |= invoke_callback(state,
2652559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson					  direct_callback[type].component,
2662559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson					  direct_callback[type].name,
2672559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson					  0, buf, len);
2682559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson		state->errors = retval;
2692559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson		break;
270cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	}
271cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson
272cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	retval |= invoke_callback(state, CB_END_TRAVERSAL, "<end>",
273cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson				  0, buf, len);
274cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson	return retval;
275cf6e78dbd54684ebba0c3bfc2524426f61193416Bill Richardson}
276