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 40static 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 86static 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 127void bootctrl_init(boot_control_module_t *module __unused) 128{ 129 /* Nothing to init */ 130} 131 132unsigned 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 138int 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 192unsigned 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 206int 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 231int 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 271int 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 302int 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 320const 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 329static 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 336static struct hw_module_methods_t bootctrl_methods = { 337 .open = bootctrl_open, 338}; 339 340/* Boot Control Module implementation */ 341boot_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