blob: 0002779ebc2b5b5101f1382d1c7d7c1c7421dacc [file] [log] [blame]
Julian Hall51a3fb32022-11-07 16:25:56 +00001/*
2 * Copyright (c) 2022, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
Gyorgy Szing3c446242023-03-31 01:53:15 +02008#include "raw_installer.h"
9
Julian Hall51a3fb32022-11-07 16:25:56 +000010#include <assert.h>
11#include <stddef.h>
12#include <string.h>
Julian Hall51a3fb32022-11-07 16:25:56 +000013
Gyorgy Szing3c446242023-03-31 01:53:15 +020014#include "media/volume/index/volume_index.h"
15#include "protocols/service/fwu/packed-c/status.h"
16#include "service/fwu/agent/fw_directory.h"
Julian Hall51a3fb32022-11-07 16:25:56 +000017
Gyorgy Szing3c446242023-03-31 01:53:15 +020018static int raw_installer_begin(void *context, unsigned int current_volume_id,
19 unsigned int update_volume_id)
Julian Hall51a3fb32022-11-07 16:25:56 +000020{
21 struct raw_installer *subject = (struct raw_installer *)context;
22
23 (void)current_volume_id;
24
Gyorgy Szing3c446242023-03-31 01:53:15 +020025 int status = volume_index_find(update_volume_id, &subject->target_volume);
Julian Hall51a3fb32022-11-07 16:25:56 +000026
27 if (status == 0) {
Julian Hall51a3fb32022-11-07 16:25:56 +000028 assert(subject->target_volume);
29
30 subject->commit_count = 0;
31 subject->is_open = false;
32 }
33
34 return status;
35}
36
37static int raw_installer_finalize(void *context)
38{
39 struct raw_installer *subject = (struct raw_installer *)context;
40
41 /* Close volume if left open */
42 if (subject->is_open) {
Julian Hall51a3fb32022-11-07 16:25:56 +000043 assert(subject->target_volume);
44
45 volume_close(subject->target_volume);
46 subject->is_open = false;
47 }
48
49 return FWU_STATUS_SUCCESS;
50}
51
52static void raw_installer_abort(void *context)
53{
54 raw_installer_finalize(context);
55}
56
Gyorgy Szing3c446242023-03-31 01:53:15 +020057static int raw_installer_open(void *context, const struct image_info *image_info)
Julian Hall51a3fb32022-11-07 16:25:56 +000058{
59 struct raw_installer *subject = (struct raw_installer *)context;
60 int status = FWU_STATUS_DENIED;
61
62 /* Because the raw_installer uses a single image to update the
63 * target volume, it only makes sense to commit a single image
64 * during an update transaction. Defend against the case where
65 * an input update package contains more than one raw image to
66 * install into a particular location.
67 */
68 if (!subject->is_open && subject->commit_count < 1) {
Julian Hall51a3fb32022-11-07 16:25:56 +000069 assert(subject->target_volume);
70
71 status = volume_open(subject->target_volume);
72
73 if (!status) {
Julian Hall51a3fb32022-11-07 16:25:56 +000074 /* Prior to writing to the volume to install the image, ensure
75 * that the volume is erased.
76 */
77 status = volume_erase(subject->target_volume);
78
79 if (!status) {
Julian Hall51a3fb32022-11-07 16:25:56 +000080 subject->is_open = true;
81 subject->bytes_written = 0;
82 } else {
83 /* Failed to erase */
84 volume_close(subject->target_volume);
85 }
86 }
87 }
88
89 return status;
90}
91
92static int raw_installer_commit(void *context)
93{
94 struct raw_installer *subject = (struct raw_installer *)context;
95 int status = FWU_STATUS_DENIED;
96
97 if (subject->is_open) {
Julian Hall51a3fb32022-11-07 16:25:56 +000098 assert(subject->target_volume);
99
100 status = volume_close(subject->target_volume);
101
102 ++subject->commit_count;
103 subject->is_open = false;
104
105 if (!status && !subject->bytes_written) {
Julian Hall51a3fb32022-11-07 16:25:56 +0000106 /* Installing a zero length image can imply an image delete
107 * operation. For certain types of installer, this is a legitimate
108 * operation. For a raw_installer, there really is no way to
109 * delete an image so return an error if an attempt was made.
110 */
111 status = FWU_STATUS_NOT_AVAILABLE;
112 }
113 }
114
115 return status;
116}
117
Gyorgy Szing3c446242023-03-31 01:53:15 +0200118static int raw_installer_write(void *context, const uint8_t *data, size_t data_len)
Julian Hall51a3fb32022-11-07 16:25:56 +0000119{
120 struct raw_installer *subject = (struct raw_installer *)context;
121 int status = FWU_STATUS_DENIED;
122
123 if (subject->is_open) {
Julian Hall51a3fb32022-11-07 16:25:56 +0000124 assert(subject->target_volume);
125
126 size_t len_written = 0;
127
Gyorgy Szing3c446242023-03-31 01:53:15 +0200128 status = volume_write(subject->target_volume, (const uintptr_t)data, data_len,
129 &len_written);
Julian Hall51a3fb32022-11-07 16:25:56 +0000130
131 subject->bytes_written += len_written;
132
133 /* Check for the volume full condition where not all the requested
134 * data was written.
135 */
136 if (!status && (len_written != data_len))
137 status = FWU_STATUS_OUT_OF_BOUNDS;
138 }
139
140 return status;
141}
142
Gyorgy Szing3c446242023-03-31 01:53:15 +0200143static int raw_installer_enumerate(void *context, uint32_t volume_id,
144 struct fw_directory *fw_directory)
Julian Hall51a3fb32022-11-07 16:25:56 +0000145{
146 struct raw_installer *subject = (struct raw_installer *)context;
147 struct volume *volume = NULL;
148
149 int status = volume_index_find(volume_id, &volume);
150
151 if (status != 0)
152 return status;
153
154 assert(volume);
155
156 /* Found the active volume so query it for information in order to
157 * prepare an entry in the fw_directory to represent the whole volume
158 * as an advertised updatable image.
159 */
Gyorgy Szing3c446242023-03-31 01:53:15 +0200160 struct image_info image_info = { 0 };
Julian Hall51a3fb32022-11-07 16:25:56 +0000161
162 /* Limit the advertised max size to the volume size. The volume needs
163 * to be open to query its size.
164 */
165 if (!subject->is_open) {
166 /* Open if necessary */
167 status = volume_open(volume);
168 if (status != 0)
169 return status;
170 }
171
172 status = volume_size(volume, &image_info.max_size);
173 if (status != 0)
174 return status;
175
176 if (!subject->is_open) {
177 /* Leave volume in the same open state */
178 status = volume_close(volume);
179 if (status)
180 return status;
181 }
182
183 /* These attributes will have been assigned during platform configuration */
184 image_info.img_type_uuid = subject->base_installer.location_uuid;
185 image_info.location_id = subject->base_installer.location_id;
186 image_info.install_type = subject->base_installer.install_type;
187
188 status = fw_directory_add_image_info(fw_directory, &image_info);
189
190 return status;
191}
192
Gyorgy Szing3c446242023-03-31 01:53:15 +0200193void raw_installer_init(struct raw_installer *subject, const struct uuid_octets *location_uuid,
194 uint32_t location_id)
Julian Hall51a3fb32022-11-07 16:25:56 +0000195{
196 /* Define concrete installer interface */
197 static const struct installer_interface interface = {
Gyorgy Szing3c446242023-03-31 01:53:15 +0200198 raw_installer_begin, raw_installer_finalize, raw_installer_abort,
199 raw_installer_open, raw_installer_commit, raw_installer_write,
Julian Hall51a3fb32022-11-07 16:25:56 +0000200 raw_installer_enumerate
201 };
202
203 /* Initialize base installer - a raw_installer is a type of
204 * installer that always updates a whole volume.
205 */
Gyorgy Szing3c446242023-03-31 01:53:15 +0200206 installer_init(&subject->base_installer, INSTALL_TYPE_WHOLE_VOLUME, location_id,
207 location_uuid, subject, &interface);
Julian Hall51a3fb32022-11-07 16:25:56 +0000208
209 /* Initialize raw_installer specifics */
210 subject->target_volume = NULL;
211 subject->commit_count = 0;
212 subject->bytes_written = 0;
213 subject->is_open = false;
214}
215
216void raw_installer_deinit(struct raw_installer *subject)
217{
218 (void)subject;
219}