• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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