1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Verified Boot for Embedded (VBE) 'simple' method
4  *
5  * Copyright 2024 Google LLC
6  * Written by Simon Glass <sjg@chromium.org>
7  */
8 
9 #define LOG_CATEGORY LOGC_BOOT
10 
11 #include <dm.h>
12 #include <memalign.h>
13 #include <mmc.h>
14 #include <dm/ofnode.h>
15 #include "vbe_abrec.h"
16 
abrec_read_priv(ofnode node,struct abrec_priv * priv)17 int abrec_read_priv(ofnode node, struct abrec_priv *priv)
18 {
19 	memset(priv, '\0', sizeof(*priv));
20 	if (ofnode_read_u32(node, "area-start", &priv->area_start) ||
21 	    ofnode_read_u32(node, "area-size", &priv->area_size) ||
22 	    ofnode_read_u32(node, "version-offset", &priv->version_offset) ||
23 	    ofnode_read_u32(node, "version-size", &priv->version_size) ||
24 	    ofnode_read_u32(node, "state-offset", &priv->state_offset) ||
25 	    ofnode_read_u32(node, "state-size", &priv->state_size))
26 		return log_msg_ret("read", -EINVAL);
27 	ofnode_read_u32(node, "skip-offset", &priv->skip_offset);
28 	priv->storage = strdup(ofnode_read_string(node, "storage"));
29 	if (!priv->storage)
30 		return log_msg_ret("str", -EINVAL);
31 
32 	return 0;
33 }
34 
abrec_read_nvdata(struct abrec_priv * priv,struct udevice * blk,struct abrec_state * state)35 int abrec_read_nvdata(struct abrec_priv *priv, struct udevice *blk,
36 		      struct abrec_state *state)
37 {
38 	ALLOC_CACHE_ALIGN_BUFFER(u8, buf, MMC_MAX_BLOCK_LEN);
39 	const struct vbe_nvdata *nvd = (struct vbe_nvdata *)buf;
40 	uint flags;
41 	int ret;
42 
43 	ret = vbe_read_nvdata(blk, priv->area_start + priv->state_offset,
44 			      priv->state_size, buf);
45 	if (ret == -EPERM) {
46 		memset(buf, '\0', MMC_MAX_BLOCK_LEN);
47 		log_warning("Starting with empty state\n");
48 	} else if (ret) {
49 		return log_msg_ret("nv", ret);
50 	}
51 
52 	state->fw_vernum = nvd->fw_vernum;
53 	flags = nvd->flags;
54 	state->try_count = flags & VBEF_TRY_COUNT_MASK;
55 	state->try_b = flags & VBEF_TRY_B;
56 	state->recovery = flags & VBEF_RECOVERY;
57 	state->pick = (flags & VBEF_PICK_MASK) >> VBEF_PICK_SHIFT;
58 
59 	return 0;
60 }
61 
abrec_read_state(struct udevice * dev,struct abrec_state * state)62 int abrec_read_state(struct udevice *dev, struct abrec_state *state)
63 {
64 	struct abrec_priv *priv = dev_get_priv(dev);
65 	struct udevice *blk;
66 	int ret;
67 
68 	ret = vbe_get_blk(priv->storage, &blk);
69 	if (ret)
70 		return log_msg_ret("blk", ret);
71 
72 	ret = vbe_read_version(blk, priv->area_start + priv->version_offset,
73 			       state->fw_version, MAX_VERSION_LEN);
74 	if (ret)
75 		return log_msg_ret("ver", ret);
76 	log_debug("version=%s\n", state->fw_version);
77 
78 	ret = abrec_read_nvdata(priv, blk, state);
79 	if (ret)
80 		return log_msg_ret("nvd", ret);
81 
82 	return 0;
83 }
84