1 /*
2 * Copyright (C) 2015 Intel Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /*
18 * Implementation of boot_control HAL as specified by google in
19 * Brillo Development Platform Specification. Please refer to the
20 * said document for more details.
21 */
22
23
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <hardware/hardware.h>
31 #include <hardware/boot_control.h>
32
33 #include "bootctrl.h"
34
35 #define BOOTCTRL_METADATA_FILE "/dev/block/by-name/misc"
36 #define SLOT_SUFFIX_STR "androidboot.slot_suffix="
37
38 #define COMMAND_LINE_SIZE 2048
39
bootctrl_read_metadata(boot_ctrl_t * bctrl)40 static int bootctrl_read_metadata(boot_ctrl_t *bctrl)
41 {
42 int fd, err;
43 ssize_t sz, size;
44 char *buf = (char *)bctrl;
45
46 fd = open(BOOTCTRL_METADATA_FILE, O_RDONLY);
47 if (fd < 0) {
48 err = errno;
49 fprintf(stderr, "Error opening metadata file: %s\n", strerror(errno));
50 return -err;
51 }
52 if (lseek(fd, OFFSETOF_SLOT_SUFFIX, SEEK_SET) < 0) {
53 err = errno;
54 fprintf(stderr, "Error seeking to metadata offset: %s\n", strerror(errno));
55 close(fd);
56 return -err;
57 }
58 size = sizeof(boot_ctrl_t);
59 do {
60 sz = read(fd, buf, size);
61 if (sz == 0) {
62 break;
63 } else if (sz < 0) {
64 if (errno == EINTR) {
65 continue;
66 }
67 err = -errno;
68 fprintf(stderr, "Error reading metadata file\n");
69 close(fd);
70 return err;
71 }
72 size -= sz;
73 buf += sz;
74 } while(size > 0);
75
76 close(fd);
77
78 /* Check if the data is correct */
79 if (bctrl->magic != BOOTCTRL_MAGIC) {
80 fprintf(stderr, "metadata is not initialised or corrupted.\n");
81 return -EIO;
82 }
83 return 0;
84 }
85
bootctrl_write_metadata(boot_ctrl_t * bctrl)86 static int bootctrl_write_metadata(boot_ctrl_t *bctrl)
87 {
88 int fd, err;
89 ssize_t sz, size;
90 char *buf = (char *)bctrl;
91
92 fd = open(BOOTCTRL_METADATA_FILE, O_RDWR);
93 if (fd < 0) {
94 err = errno;
95 fprintf(stderr, "Error opening metadata file: %s\n", strerror(errno));
96 return -err;
97 }
98
99 if (lseek(fd, OFFSETOF_SLOT_SUFFIX, SEEK_SET) < 0) {
100 err = errno;
101 fprintf(stderr, "Error seeking to metadata offset: %s\n", strerror(errno));
102 close(fd);
103 return -err;
104 }
105 size = sizeof(boot_ctrl_t);
106 do {
107 sz = write(fd, buf, size);
108 if (sz == 0) {
109 break;
110 } else if (sz < 0) {
111 if (errno == EINTR) {
112 continue;
113 }
114 err = -errno;
115 fprintf(stderr, "Error Writing metadata file\n");
116 close(fd);
117 return err;
118 }
119 size -= sz;
120 buf += sz;
121 } while(size > 0);
122
123 close(fd);
124 return 0;
125 }
126
bootctrl_init(boot_control_module_t * module __unused)127 void bootctrl_init(boot_control_module_t *module __unused)
128 {
129 /* Nothing to init */
130 }
131
bootctrl_get_number_slots(boot_control_module_t * module __unused)132 unsigned bootctrl_get_number_slots(boot_control_module_t *module __unused)
133 {
134 /* This is A/B system, so it will be always 2. */
135 return 2;
136 }
137
bootctrl_get_active_slot()138 int bootctrl_get_active_slot()
139 {
140 int fd, err, slot;
141 ssize_t size = COMMAND_LINE_SIZE, sz;
142 off_t off;
143 char *buf, *ptr;
144 char *str;
145
146 fd = open("/proc/cmdline", O_RDONLY);
147 if (fd < 0) {
148 err = -errno;
149 fprintf(stderr, "error reading commandline\n");
150 return err;
151 }
152 ptr = buf = malloc(size);
153 if (!buf) {
154 err = -errno;
155 fprintf(stderr, "Error allocating memory\n");
156 close(fd);
157 return err;
158 }
159 do {
160 sz = read(fd, buf, size);
161 if (sz == 0) {
162 break;
163 } else if (sz < 0) {
164 if (errno == EINTR) {
165 continue;
166 }
167 err = -errno;
168 fprintf(stderr, "Error reading file\n");
169 free(ptr);
170 close(fd);
171 return err;
172 }
173 size -= sz;
174 buf += sz;
175 } while(size > 0);
176 str = strstr((char *)ptr, SLOT_SUFFIX_STR);
177 if (!str) {
178 err = -EIO;
179 fprintf(stderr, "cannot find %s in kernel commandline.\n", SLOT_SUFFIX_STR);
180 free(ptr);
181 close(fd);
182 return err;
183 }
184 str += sizeof(SLOT_SUFFIX_STR);
185 slot = (*str == 'a') ? 0 : 1;
186 free(ptr);
187 close(fd);
188
189 return slot;
190 }
191
bootctrl_get_current_slot(boot_control_module_t * module __unused)192 unsigned bootctrl_get_current_slot(boot_control_module_t *module __unused)
193 {
194 int ret;
195 boot_ctrl_t metadata;
196
197 ret = bootctrl_read_metadata(&metadata);
198 if (ret < 0) {
199 /* anything larger than 2 will be considered as error. */
200 return (unsigned)ret;
201 }
202
203 return bootctrl_get_active_slot();
204 }
205
bootctrl_mark_boot_successful(boot_control_module_t * module __unused)206 int bootctrl_mark_boot_successful(boot_control_module_t *module __unused)
207 {
208 int ret, slot;
209 boot_ctrl_t metadata;
210 slot_metadata_t *slotp;
211
212 ret = bootctrl_read_metadata(&metadata);
213 if (ret < 0) {
214 return ret;
215 }
216
217 /* In markBootSuccessful(), set Successful Boot to 1 and
218 * Tries Remaining to 0.
219 */
220 slot = bootctrl_get_active_slot();
221 if (slot < 0) {
222 return slot;
223 }
224 slotp = &metadata.slot_info[slot];
225 slotp->successful_boot = 1;
226 slotp->tries_remaining = 0;
227
228 return bootctrl_write_metadata(&metadata);
229 }
230
bootctrl_set_active_boot_slot(boot_control_module_t * module __unused,unsigned slot)231 int bootctrl_set_active_boot_slot(boot_control_module_t *module __unused,
232 unsigned slot)
233 {
234 int ret, slot2;
235 boot_ctrl_t metadata;
236 slot_metadata_t *slotp;
237
238 if (slot >= 2) {
239 fprintf(stderr, "Wrong Slot value %u\n", slot);
240 return -EINVAL;
241 }
242 ret = bootctrl_read_metadata(&metadata);
243 if (ret < 0) {
244 return ret;
245 }
246
247 /* In setActiveBootSlot(), set Priority to 15, Tries Remaining to 7 and
248 * Successful Boot to 0. Before doing this, lower priorities of other slots
249 * so they are all less than 15 in a way that preserves existing priority
250 * ordering. Calling setActiveBootSlot() on a slot that already has
251 * Successful Boot set to 1 MUST not fail.
252 */
253 slotp = &metadata.slot_info[slot];
254 slotp->successful_boot = 0;
255 slotp->priority = 15;
256 slotp->tries_remaining = 7;
257
258 slot2 = (slot == 0) ? 1 : 0;
259 slotp = &metadata.slot_info[slot2];
260 if (slotp->priority >= 15) {
261 slotp->priority = 14;
262 }
263 ret = bootctrl_write_metadata(&metadata);
264 if (ret < 0) {
265 return ret;
266 }
267
268 return 0;
269 }
270
bootctrl_set_slot_as_unbootable(boot_control_module_t * module __unused,unsigned slot)271 int bootctrl_set_slot_as_unbootable(boot_control_module_t *module __unused,
272 unsigned slot)
273 {
274 int ret;
275 boot_ctrl_t metadata;
276 slot_metadata_t *slotp;
277
278 if (slot >= 2) {
279 fprintf(stderr, "Wrong Slot value %u\n", slot);
280 return -EINVAL;
281 }
282 ret = bootctrl_read_metadata(&metadata);
283 if (ret < 0) {
284 return ret;
285 }
286
287 /* In setSlotAsUnbootable(), set Priority, Tries Remaining and
288 * Successful Boot to 0.
289 */
290 slotp = &metadata.slot_info[slot];
291 slotp->successful_boot = 0;
292 slotp->priority = 0;
293 slotp->tries_remaining = 0;
294 ret = bootctrl_write_metadata(&metadata);
295 if (ret < 0) {
296 return ret;
297 }
298
299 return 0;
300 }
301
bootctrl_is_slot_bootable(boot_control_module_t * module __unused,unsigned slot)302 int bootctrl_is_slot_bootable(boot_control_module_t *module __unused,
303 unsigned slot)
304 {
305 int ret;
306 boot_ctrl_t metadata;
307
308 if (slot >= 2) {
309 fprintf(stderr, "Wrong Slot value %u\n", slot);
310 return -EINVAL;
311 }
312 ret = bootctrl_read_metadata(&metadata);
313 if (ret < 0) {
314 return ret;
315 }
316
317 return (metadata.slot_info[slot].priority != 0);
318 }
319
bootctrl_get_suffix(boot_control_module_t * module __unused,unsigned slot)320 const char *bootctrl_get_suffix(boot_control_module_t *module __unused,
321 unsigned slot)
322 {
323 static const char* suffix[2] = {BOOTCTRL_SUFFIX_A, BOOTCTRL_SUFFIX_B};
324 if (slot >= 2)
325 return NULL;
326 return suffix[slot];
327 }
328
bootctrl_open(const hw_module_t * module,const char * id __unused,hw_device_t ** device __unused)329 static int bootctrl_open(const hw_module_t *module, const char *id __unused,
330 hw_device_t **device __unused)
331 {
332 /* Nothing to do currently */
333 return 0;
334 }
335
336 static struct hw_module_methods_t bootctrl_methods = {
337 .open = bootctrl_open,
338 };
339
340 /* Boot Control Module implementation */
341 boot_control_module_t HAL_MODULE_INFO_SYM = {
342 .common = {
343 .tag = HARDWARE_MODULE_TAG,
344 .module_api_version = BOOT_CONTROL_MODULE_API_VERSION_0_1,
345 .hal_api_version = HARDWARE_HAL_API_VERSION,
346 .id = BOOT_CONTROL_HARDWARE_MODULE_ID,
347 .name = "boot_control HAL",
348 .author = "Intel Corporation",
349 .methods = &bootctrl_methods,
350 },
351 .init = bootctrl_init,
352 .getNumberSlots = bootctrl_get_number_slots,
353 .getCurrentSlot = bootctrl_get_current_slot,
354 .markBootSuccessful = bootctrl_mark_boot_successful,
355 .setActiveBootSlot = bootctrl_set_active_boot_slot,
356 .setSlotAsUnbootable = bootctrl_set_slot_as_unbootable,
357 .isSlotBootable = bootctrl_is_slot_bootable,
358 .getSuffix = bootctrl_get_suffix,
359 };
360
361