xref: /aosp_15_r20/system/extras/boot_control_copy/bootinfo.cpp (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*288bf522SAndroid Build Coastguard Worker  *
4*288bf522SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*288bf522SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*288bf522SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*288bf522SAndroid Build Coastguard Worker  *
8*288bf522SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*288bf522SAndroid Build Coastguard Worker  *
10*288bf522SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*288bf522SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*288bf522SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*288bf522SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*288bf522SAndroid Build Coastguard Worker  * limitations under the License.
15*288bf522SAndroid Build Coastguard Worker  */
16*288bf522SAndroid Build Coastguard Worker 
17*288bf522SAndroid Build Coastguard Worker #include <errno.h>
18*288bf522SAndroid Build Coastguard Worker #include <fcntl.h>
19*288bf522SAndroid Build Coastguard Worker #include <linux/fs.h>
20*288bf522SAndroid Build Coastguard Worker #include <sys/ioctl.h>
21*288bf522SAndroid Build Coastguard Worker #include <sys/stat.h>
22*288bf522SAndroid Build Coastguard Worker #include <sys/types.h>
23*288bf522SAndroid Build Coastguard Worker #include <unistd.h>
24*288bf522SAndroid Build Coastguard Worker 
25*288bf522SAndroid Build Coastguard Worker #include <arpa/inet.h>
26*288bf522SAndroid Build Coastguard Worker #include <stdio.h>
27*288bf522SAndroid Build Coastguard Worker #include <stdlib.h>
28*288bf522SAndroid Build Coastguard Worker #include <string.h>
29*288bf522SAndroid Build Coastguard Worker 
30*288bf522SAndroid Build Coastguard Worker #include <cutils/properties.h>
31*288bf522SAndroid Build Coastguard Worker #include <fs_mgr.h>
32*288bf522SAndroid Build Coastguard Worker 
33*288bf522SAndroid Build Coastguard Worker #include "bootinfo.h"
34*288bf522SAndroid Build Coastguard Worker 
35*288bf522SAndroid Build Coastguard Worker using android::fs_mgr::Fstab;
36*288bf522SAndroid Build Coastguard Worker using android::fs_mgr::GetEntryForMountPoint;
37*288bf522SAndroid Build Coastguard Worker using android::fs_mgr::ReadDefaultFstab;
38*288bf522SAndroid Build Coastguard Worker using android::fs_mgr::ReadFstabFromFile;
39*288bf522SAndroid Build Coastguard Worker 
40*288bf522SAndroid Build Coastguard Worker // Open the appropriate fstab file and fallback to /fstab.device if
41*288bf522SAndroid Build Coastguard Worker // that's what's being used.
open_fstab(Fstab * fstab)42*288bf522SAndroid Build Coastguard Worker static bool open_fstab(Fstab* fstab) {
43*288bf522SAndroid Build Coastguard Worker   return ReadDefaultFstab(fstab) || ReadFstabFromFile("/fstab.device", fstab);
44*288bf522SAndroid Build Coastguard Worker }
45*288bf522SAndroid Build Coastguard Worker 
boot_info_open_partition(const char * name,uint64_t * out_size,int flags)46*288bf522SAndroid Build Coastguard Worker int boot_info_open_partition(const char* name, uint64_t* out_size, int flags) {
47*288bf522SAndroid Build Coastguard Worker   char* path;
48*288bf522SAndroid Build Coastguard Worker   int fd;
49*288bf522SAndroid Build Coastguard Worker 
50*288bf522SAndroid Build Coastguard Worker   // We can't use fs_mgr to look up |name| because fstab doesn't list
51*288bf522SAndroid Build Coastguard Worker   // every slot partition (it uses the slotselect option to mask the
52*288bf522SAndroid Build Coastguard Worker   // suffix) and |slot| is expected to be of that form, e.g. boot_a.
53*288bf522SAndroid Build Coastguard Worker   //
54*288bf522SAndroid Build Coastguard Worker   // We can however assume that there's an entry for the /misc mount
55*288bf522SAndroid Build Coastguard Worker   // point and use that to get the device file for the misc
56*288bf522SAndroid Build Coastguard Worker   // partition. From there we'll assume that a by-name scheme is used
57*288bf522SAndroid Build Coastguard Worker   // so we can just replace the trailing "misc" by the given |name|,
58*288bf522SAndroid Build Coastguard Worker   // e.g.
59*288bf522SAndroid Build Coastguard Worker   //
60*288bf522SAndroid Build Coastguard Worker   //   /dev/block/platform/soc.0/7824900.sdhci/by-name/misc ->
61*288bf522SAndroid Build Coastguard Worker   //   /dev/block/platform/soc.0/7824900.sdhci/by-name/boot_a
62*288bf522SAndroid Build Coastguard Worker   //
63*288bf522SAndroid Build Coastguard Worker   // If needed, it's possible to relax this assumption in the future
64*288bf522SAndroid Build Coastguard Worker   // by trawling /sys/block looking for the appropriate sibling of
65*288bf522SAndroid Build Coastguard Worker   // misc and then finding an entry in /dev matching the sysfs entry.
66*288bf522SAndroid Build Coastguard Worker 
67*288bf522SAndroid Build Coastguard Worker   Fstab fstab;
68*288bf522SAndroid Build Coastguard Worker   if (!open_fstab(&fstab)) {
69*288bf522SAndroid Build Coastguard Worker     return -1;
70*288bf522SAndroid Build Coastguard Worker   }
71*288bf522SAndroid Build Coastguard Worker   auto record = GetEntryForMountPoint(&fstab, "/misc");
72*288bf522SAndroid Build Coastguard Worker   if (record == nullptr) {
73*288bf522SAndroid Build Coastguard Worker     return -1;
74*288bf522SAndroid Build Coastguard Worker   }
75*288bf522SAndroid Build Coastguard Worker   if (strcmp(name, "misc") == 0) {
76*288bf522SAndroid Build Coastguard Worker     path = strdup(record->blk_device.c_str());
77*288bf522SAndroid Build Coastguard Worker   } else {
78*288bf522SAndroid Build Coastguard Worker     size_t trimmed_len, name_len;
79*288bf522SAndroid Build Coastguard Worker     const char* end_slash = strrchr(record->blk_device.c_str(), '/');
80*288bf522SAndroid Build Coastguard Worker     if (end_slash == NULL) {
81*288bf522SAndroid Build Coastguard Worker       return -1;
82*288bf522SAndroid Build Coastguard Worker     }
83*288bf522SAndroid Build Coastguard Worker     trimmed_len = end_slash - record->blk_device.c_str() + 1;
84*288bf522SAndroid Build Coastguard Worker     name_len = strlen(name);
85*288bf522SAndroid Build Coastguard Worker     path = static_cast<char*>(calloc(trimmed_len + name_len + 1, 1));
86*288bf522SAndroid Build Coastguard Worker     strncpy(path, record->blk_device.c_str(), trimmed_len);
87*288bf522SAndroid Build Coastguard Worker     strncpy(path + trimmed_len, name, name_len);
88*288bf522SAndroid Build Coastguard Worker   }
89*288bf522SAndroid Build Coastguard Worker 
90*288bf522SAndroid Build Coastguard Worker   fd = open(path, flags);
91*288bf522SAndroid Build Coastguard Worker   free(path);
92*288bf522SAndroid Build Coastguard Worker 
93*288bf522SAndroid Build Coastguard Worker   // If we successfully opened the device, get size if requested.
94*288bf522SAndroid Build Coastguard Worker   if (fd != -1 && out_size != NULL) {
95*288bf522SAndroid Build Coastguard Worker     if (ioctl(fd, BLKGETSIZE64, out_size) != 0) {
96*288bf522SAndroid Build Coastguard Worker       close(fd);
97*288bf522SAndroid Build Coastguard Worker       return -1;
98*288bf522SAndroid Build Coastguard Worker     }
99*288bf522SAndroid Build Coastguard Worker   }
100*288bf522SAndroid Build Coastguard Worker 
101*288bf522SAndroid Build Coastguard Worker   return fd;
102*288bf522SAndroid Build Coastguard Worker }
103*288bf522SAndroid Build Coastguard Worker 
104*288bf522SAndroid Build Coastguard Worker // As per struct bootloader_message_ab which is defined in
105*288bf522SAndroid Build Coastguard Worker // boot/1.1/default.
106*288bf522SAndroid Build Coastguard Worker // struct bootloader_message_ab {
107*288bf522SAndroid Build Coastguard Worker //     struct bootloader_message message;
108*288bf522SAndroid Build Coastguard Worker //     char slot_suffix[32];
109*288bf522SAndroid Build Coastguard Worker //     char update_channel[128];
110*288bf522SAndroid Build Coastguard Worker //
111*288bf522SAndroid Build Coastguard Worker //     // Round up the entire struct to 4096-byte.
112*288bf522SAndroid Build Coastguard Worker //     char reserved[1888];
113*288bf522SAndroid Build Coastguard Worker // };
114*288bf522SAndroid Build Coastguard Worker //
115*288bf522SAndroid Build Coastguard Worker // We can use the 32 bytes in the bootctrl_suffix field provided that they
116*288bf522SAndroid Build Coastguard Worker // start with the active slot suffix terminated by NUL. It just so happens
117*288bf522SAndroid Build Coastguard Worker // that BrilloBootInfo is laid out this way.
118*288bf522SAndroid Build Coastguard Worker #define BOOTINFO_OFFSET 2048
119*288bf522SAndroid Build Coastguard Worker 
boot_info_load(BrilloBootInfo * out_info)120*288bf522SAndroid Build Coastguard Worker bool boot_info_load(BrilloBootInfo* out_info) {
121*288bf522SAndroid Build Coastguard Worker   int fd;
122*288bf522SAndroid Build Coastguard Worker 
123*288bf522SAndroid Build Coastguard Worker   memset(out_info, '\0', sizeof(BrilloBootInfo));
124*288bf522SAndroid Build Coastguard Worker 
125*288bf522SAndroid Build Coastguard Worker   fd = boot_info_open_partition("misc", NULL, O_RDONLY);
126*288bf522SAndroid Build Coastguard Worker   if (fd == -1) return false;
127*288bf522SAndroid Build Coastguard Worker   if (lseek(fd, BOOTINFO_OFFSET, SEEK_SET) != BOOTINFO_OFFSET) {
128*288bf522SAndroid Build Coastguard Worker     close(fd);
129*288bf522SAndroid Build Coastguard Worker     return false;
130*288bf522SAndroid Build Coastguard Worker   }
131*288bf522SAndroid Build Coastguard Worker   ssize_t num_read;
132*288bf522SAndroid Build Coastguard Worker   do {
133*288bf522SAndroid Build Coastguard Worker     num_read = read(fd, (void*)out_info, sizeof(BrilloBootInfo));
134*288bf522SAndroid Build Coastguard Worker   } while (num_read == -1 && errno == EINTR);
135*288bf522SAndroid Build Coastguard Worker   close(fd);
136*288bf522SAndroid Build Coastguard Worker   if (num_read != sizeof(BrilloBootInfo)) return false;
137*288bf522SAndroid Build Coastguard Worker   return true;
138*288bf522SAndroid Build Coastguard Worker }
139*288bf522SAndroid Build Coastguard Worker 
boot_info_save(BrilloBootInfo * info)140*288bf522SAndroid Build Coastguard Worker bool boot_info_save(BrilloBootInfo* info) {
141*288bf522SAndroid Build Coastguard Worker   int fd;
142*288bf522SAndroid Build Coastguard Worker 
143*288bf522SAndroid Build Coastguard Worker   fd = boot_info_open_partition("misc", NULL, O_RDWR);
144*288bf522SAndroid Build Coastguard Worker   if (fd == -1) return false;
145*288bf522SAndroid Build Coastguard Worker   if (lseek(fd, BOOTINFO_OFFSET, SEEK_SET) != BOOTINFO_OFFSET) {
146*288bf522SAndroid Build Coastguard Worker     close(fd);
147*288bf522SAndroid Build Coastguard Worker     return false;
148*288bf522SAndroid Build Coastguard Worker   }
149*288bf522SAndroid Build Coastguard Worker   ssize_t num_written;
150*288bf522SAndroid Build Coastguard Worker   do {
151*288bf522SAndroid Build Coastguard Worker     num_written = write(fd, (void*)info, sizeof(BrilloBootInfo));
152*288bf522SAndroid Build Coastguard Worker   } while (num_written == -1 && errno == EINTR);
153*288bf522SAndroid Build Coastguard Worker   close(fd);
154*288bf522SAndroid Build Coastguard Worker   if (num_written != sizeof(BrilloBootInfo)) return false;
155*288bf522SAndroid Build Coastguard Worker   return true;
156*288bf522SAndroid Build Coastguard Worker }
157*288bf522SAndroid Build Coastguard Worker 
boot_info_validate(BrilloBootInfo * info)158*288bf522SAndroid Build Coastguard Worker bool boot_info_validate(BrilloBootInfo* info) {
159*288bf522SAndroid Build Coastguard Worker   if (info->magic[0] != 'B' || info->magic[1] != 'C' || info->magic[2] != 'c') return false;
160*288bf522SAndroid Build Coastguard Worker   if (info->active_slot >= 2) return false;
161*288bf522SAndroid Build Coastguard Worker   return true;
162*288bf522SAndroid Build Coastguard Worker }
163*288bf522SAndroid Build Coastguard Worker 
boot_info_reset(BrilloBootInfo * info)164*288bf522SAndroid Build Coastguard Worker void boot_info_reset(BrilloBootInfo* info) {
165*288bf522SAndroid Build Coastguard Worker   memset(info, '\0', sizeof(BrilloBootInfo));
166*288bf522SAndroid Build Coastguard Worker   info->magic[0] = 'B';
167*288bf522SAndroid Build Coastguard Worker   info->magic[1] = 'C';
168*288bf522SAndroid Build Coastguard Worker   info->magic[2] = 'c';
169*288bf522SAndroid Build Coastguard Worker }
170