summaryrefslogtreecommitdiff
path: root/drivers/fwu-mdata/fwu-mdata-uclass.c
blob: b477e9603fb33fb7a3ecb41c691eb0de0a283946 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright (c) 2022, Linaro Limited
 */

#define LOG_CATEGORY UCLASS_FWU_MDATA

#include <common.h>
#include <dm.h>
#include <efi_loader.h>
#include <fwu.h>
#include <fwu_mdata.h>
#include <log.h>

#include <linux/errno.h>
#include <linux/types.h>
#include <u-boot/crc.h>

/**
 * fwu_get_mdata_part_num() - Get the FWU metadata partition numbers
 * @dev: FWU metadata device
 * @mdata_parts: array for storing the metadata partition numbers
 *
 * Get the partition numbers on the storage device on which the
 * FWU metadata is stored. Two partition numbers will be returned.
 *
 * Return: 0 if OK, -ve on error
 *
 */
int fwu_get_mdata_part_num(struct udevice *dev, uint *mdata_parts)
{
	const struct fwu_mdata_ops *ops = device_get_ops(dev);

	if (!ops->get_mdata_part_num) {
		log_debug("get_mdata_part_num() method not defined\n");
		return -ENOSYS;
	}

	return ops->get_mdata_part_num(dev, mdata_parts);
}

/**
 * fwu_read_mdata_partition() - Read the FWU metadata from a partition
 * @dev: FWU metadata device
 * @mdata: Copy of the FWU metadata
 * @part_num: Partition number from which FWU metadata is to be read
 *
 * Read the FWU metadata from the specified partition number
 *
 * Return: 0 if OK, -ve on error
 *
 */
int fwu_read_mdata_partition(struct udevice *dev, struct fwu_mdata *mdata,
			     uint part_num)
{
	const struct fwu_mdata_ops *ops = device_get_ops(dev);

	if (!ops->read_mdata_partition) {
		log_debug("read_mdata_partition() method not defined\n");
		return -ENOSYS;
	}

	return ops->read_mdata_partition(dev, mdata, part_num);
}

/**
 * fwu_write_mdata_partition() - Write the FWU metadata to a partition
 * @dev: FWU metadata device
 * @mdata: Copy of the FWU metadata
 * @part_num: Partition number to which FWU metadata is to be written
 *
 * Write the FWU metadata to the specified partition number
 *
 * Return: 0 if OK, -ve on error
 *
 */
int fwu_write_mdata_partition(struct udevice *dev, struct fwu_mdata *mdata,
			      uint part_num)
{
	const struct fwu_mdata_ops *ops = device_get_ops(dev);

	if (!ops->write_mdata_partition) {
		log_debug("write_mdata_partition() method not defined\n");
		return -ENOSYS;
	}

	return ops->write_mdata_partition(dev, mdata, part_num);
}

/**
 * fwu_mdata_check() - Check if the FWU metadata is valid
 * @dev: FWU metadata device
 *
 * Validate both copies of the FWU metadata. If one of the copies
 * has gone bad, restore it from the other copy.
 *
 * Return: 0 if OK, -ve on error
 *
 */
int fwu_mdata_check(struct udevice *dev)
{
	const struct fwu_mdata_ops *ops = device_get_ops(dev);

	if (!ops->check_mdata) {
		log_debug("check_mdata() method not defined\n");
		return -ENOSYS;
	}

	return ops->check_mdata(dev);
}

/**
 * fwu_get_mdata() - Get a FWU metadata copy
 * @dev: FWU metadata device
 * @mdata: Copy of the FWU metadata
 *
 * Get a valid copy of the FWU metadata.
 *
 * Note: This function is to be called first when modifying any fields
 * in the metadata. The sequence of calls to modify any field in the
 * metadata would  be 1) fwu_get_mdata 2) Modify metadata, followed by
 * 3) fwu_update_mdata
 *
 * Return: 0 if OK, -ve on error
 *
 */
int fwu_get_mdata(struct udevice *dev, struct fwu_mdata *mdata)
{
	const struct fwu_mdata_ops *ops = device_get_ops(dev);

	if (!ops->get_mdata) {
		log_debug("get_mdata() method not defined\n");
		return -ENOSYS;
	}

	return ops->get_mdata(dev, mdata);
}

/**
 * fwu_update_mdata() - Update the FWU metadata
 * @dev: FWU metadata device
 * @mdata: Copy of the FWU metadata
 *
 * Update the FWU metadata structure by writing to the
 * FWU metadata partitions.
 *
 * Note: This function is not to be called directly to update the
 * metadata fields. The sequence of function calls should be
 * 1) fwu_get_mdata() 2) Modify the medata fields 3) fwu_update_mdata()
 *
 * The sequence of updating the partitions should be, update the
 * primary metadata partition (first partition encountered), followed
 * by updating the secondary partition. With this update sequence, in
 * the rare scenario that the two metadata partitions are valid but do
 * not match, maybe due to power outage at the time of updating the
 * metadata copies, the secondary partition can be updated from the
 * primary.
 *
 * Return: 0 if OK, -ve on error
 *
 */
int fwu_update_mdata(struct udevice *dev, struct fwu_mdata *mdata)
{
	void *buf;
	const struct fwu_mdata_ops *ops = device_get_ops(dev);

	if (!ops->update_mdata) {
		log_debug("get_mdata() method not defined\n");
		return -ENOSYS;
	}

	/*
	 * Calculate the crc32 for the updated FWU metadata
	 * and put the updated value in the FWU metadata crc32
	 * field
	 */
	buf = &mdata->version;
	mdata->crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32));

	return ops->update_mdata(dev, mdata);
}

UCLASS_DRIVER(fwu_mdata) = {
	.id		= UCLASS_FWU_MDATA,
	.name		= "fwu-mdata",
};