1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Verified Boot for Embedded (VBE) loading firmware phases
4  *
5  * Copyright 2022 Google LLC
6  * Written by Simon Glass <sjg@chromium.org>
7  */
8 
9 #define LOG_CATEGORY LOGC_BOOT
10 
11 #include <common.h>
12 #include <dm.h>
13 #include <bootflow.h>
14 #include <vbe.h>
15 #include <version_string.h>
16 #include <dm/device-internal.h>
17 #include "vbe_simple.h"
18 
vbe_simple_fixup_node(ofnode node,struct simple_state * state)19 int vbe_simple_fixup_node(ofnode node, struct simple_state *state)
20 {
21 	const char *version, *str;
22 	int ret;
23 
24 	version = strdup(state->fw_version);
25 	if (!version)
26 		return log_msg_ret("dup", -ENOMEM);
27 
28 	ret = ofnode_write_string(node, "cur-version", version);
29 	if (ret)
30 		return log_msg_ret("ver", ret);
31 	ret = ofnode_write_u32(node, "cur-vernum", state->fw_vernum);
32 	if (ret)
33 		return log_msg_ret("num", ret);
34 
35 	/* Drop the 'U-Boot ' at the start */
36 	str = version_string;
37 	if (!strncmp("U-Boot ", str, 7))
38 		str += 7;
39 	ret = ofnode_write_string(node, "bootloader-version", str);
40 	if (ret)
41 		return log_msg_ret("bl", ret);
42 
43 	return 0;
44 }
45 
46 /**
47  * bootmeth_vbe_simple_ft_fixup() - Write out all VBE simple data to the DT
48  *
49  * @ctx: Context for event
50  * @event: Event to process
51  * @return 0 if OK, -ve on error
52  */
bootmeth_vbe_simple_ft_fixup(void * ctx,struct event * event)53 static int bootmeth_vbe_simple_ft_fixup(void *ctx, struct event *event)
54 {
55 	oftree tree = event->data.ft_fixup.tree;
56 	struct udevice *dev;
57 
58 	/*
59 	 * Ideally we would have driver model support for fixups, but that does
60 	 * not exist yet. It is a step too far to try to do this before VBE is
61 	 * in place.
62 	 */
63 	for (vbe_find_first_device(&dev); dev; vbe_find_next_device(&dev)) {
64 		struct simple_state state;
65 		ofnode node, subnode, chosen;
66 		int ret;
67 
68 		if (strcmp("vbe_simple", dev->driver->name))
69 			continue;
70 
71 		/* Check if there is a node to fix up, adding if not */
72 		chosen = oftree_path(tree, "/chosen");
73 		if (!ofnode_valid(chosen))
74 			continue;
75 
76 		ret = device_probe(dev);
77 		if (ret) {
78 			/*
79 			 * This should become an error when VBE is updated to
80 			 * only bind this device when a node exists
81 			 */
82 			log_debug("VBE device '%s' failed to probe (err=%d)",
83 				  dev->name, ret);
84 			return 0;
85 		}
86 
87 		ret = ofnode_add_subnode(chosen, "fwupd", &node);
88 		if (ret && ret != -EEXIST)
89 			return log_msg_ret("fwu", ret);
90 
91 		ret = ofnode_add_subnode(node, dev->name, &subnode);
92 		if (ret && ret != -EEXIST)
93 			return log_msg_ret("dev", ret);
94 
95 		/* Copy over the vbe properties for fwupd */
96 		log_debug("Fixing up: %s\n", dev->name);
97 		ret = ofnode_copy_props(dev_ofnode(dev), subnode);
98 		if (ret)
99 			return log_msg_ret("cp", ret);
100 
101 		ret = vbe_simple_read_state(dev, &state);
102 		if (ret)
103 			return log_msg_ret("read", ret);
104 
105 		ret = vbe_simple_fixup_node(subnode, &state);
106 		if (ret)
107 			return log_msg_ret("fix", ret);
108 	}
109 
110 	return 0;
111 }
112 EVENT_SPY(EVT_FT_FIXUP, bootmeth_vbe_simple_ft_fixup);
113