diff options
author | Yabin Cui | 2016-06-30 16:36:59 -0500 |
---|---|---|
committer | Yabin Cui | 2016-06-30 17:13:12 -0500 |
commit | 9b15ba8269f7a2cb63ac31185fcbb17c86236f99 (patch) | |
tree | 48a5ceff01d266f82a3594d703a79806a6ce099e /bootloader_message | |
parent | 937ca850ecda287872e36c8a75b8c035d407d44d (diff) | |
parent | 2f272c0551f984e83bc5abaf240e0dddb38a3326 (diff) | |
download | platform-bootable-recovery-9b15ba8269f7a2cb63ac31185fcbb17c86236f99.tar.gz platform-bootable-recovery-9b15ba8269f7a2cb63ac31185fcbb17c86236f99.tar.xz platform-bootable-recovery-9b15ba8269f7a2cb63ac31185fcbb17c86236f99.zip |
resolve merge conflicts of 2f272c0 to nyc-mr1-dev-plus-aosp
Change-Id: I889d94a723415ad2e660b8c99e66935142918bc4
Diffstat (limited to 'bootloader_message')
-rw-r--r-- | bootloader_message/Android.mk | 24 | ||||
-rw-r--r-- | bootloader_message/bootloader_message.cpp | 181 | ||||
-rw-r--r-- | bootloader_message/include/bootloader_message/bootloader_message.h | 199 |
3 files changed, 404 insertions, 0 deletions
diff --git a/bootloader_message/Android.mk b/bootloader_message/Android.mk new file mode 100644 index 00000000..815ac67d --- /dev/null +++ b/bootloader_message/Android.mk | |||
@@ -0,0 +1,24 @@ | |||
1 | # Copyright (C) 2016 The Android Open Source Project | ||
2 | # | ||
3 | # Licensed under the Apache License, Version 2.0 (the "License"); | ||
4 | # you may not use this file except in compliance with the License. | ||
5 | # You may obtain a copy of the License at | ||
6 | # | ||
7 | # http://www.apache.org/licenses/LICENSE-2.0 | ||
8 | # | ||
9 | # Unless required by applicable law or agreed to in writing, software | ||
10 | # distributed under the License is distributed on an "AS IS" BASIS, | ||
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
12 | # See the License for the specific language governing permissions and | ||
13 | # limitations under the License. | ||
14 | |||
15 | LOCAL_PATH := $(call my-dir) | ||
16 | |||
17 | include $(CLEAR_VARS) | ||
18 | LOCAL_CLANG := true | ||
19 | LOCAL_SRC_FILES := bootloader_message.cpp | ||
20 | LOCAL_MODULE := libbootloader_message | ||
21 | LOCAL_STATIC_LIBRARIES := libbase libfs_mgr | ||
22 | LOCAL_C_INCLUDES := $(LOCAL_PATH)/include | ||
23 | LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include | ||
24 | include $(BUILD_STATIC_LIBRARY) | ||
diff --git a/bootloader_message/bootloader_message.cpp b/bootloader_message/bootloader_message.cpp new file mode 100644 index 00000000..e7195ae9 --- /dev/null +++ b/bootloader_message/bootloader_message.cpp | |||
@@ -0,0 +1,181 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2016 The Android Open Source Project | ||
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 | #include <bootloader_message/bootloader_message.h> | ||
18 | |||
19 | #include <errno.h> | ||
20 | #include <fcntl.h> | ||
21 | #include <string.h> | ||
22 | #include <sys/system_properties.h> | ||
23 | |||
24 | #include <string> | ||
25 | #include <vector> | ||
26 | |||
27 | #include <android-base/file.h> | ||
28 | #include <android-base/stringprintf.h> | ||
29 | #include <android-base/unique_fd.h> | ||
30 | #include <fs_mgr.h> | ||
31 | |||
32 | static struct fstab* read_fstab(std::string* err) { | ||
33 | // The fstab path is always "/fstab.${ro.hardware}". | ||
34 | std::string fstab_path = "/fstab."; | ||
35 | char value[PROP_VALUE_MAX]; | ||
36 | if (__system_property_get("ro.hardware", value) == 0) { | ||
37 | *err = "failed to get ro.hardware"; | ||
38 | return nullptr; | ||
39 | } | ||
40 | fstab_path += value; | ||
41 | struct fstab* fstab = fs_mgr_read_fstab(fstab_path.c_str()); | ||
42 | if (fstab == nullptr) { | ||
43 | *err = "failed to read " + fstab_path; | ||
44 | } | ||
45 | return fstab; | ||
46 | } | ||
47 | |||
48 | static std::string get_misc_blk_device(std::string* err) { | ||
49 | struct fstab* fstab = read_fstab(err); | ||
50 | if (fstab == nullptr) { | ||
51 | return ""; | ||
52 | } | ||
53 | fstab_rec* record = fs_mgr_get_entry_for_mount_point(fstab, "/misc"); | ||
54 | if (record == nullptr) { | ||
55 | *err = "failed to find /misc partition"; | ||
56 | return ""; | ||
57 | } | ||
58 | return record->blk_device; | ||
59 | } | ||
60 | |||
61 | // In recovery mode, recovery can get started and try to access the misc | ||
62 | // device before the kernel has actually created it. | ||
63 | static bool wait_for_device(const std::string& blk_device, std::string* err) { | ||
64 | int tries = 0; | ||
65 | int ret; | ||
66 | err->clear(); | ||
67 | do { | ||
68 | ++tries; | ||
69 | struct stat buf; | ||
70 | ret = stat(blk_device.c_str(), &buf); | ||
71 | if (ret == -1) { | ||
72 | *err += android::base::StringPrintf("failed to stat %s try %d: %s\n", | ||
73 | blk_device.c_str(), tries, strerror(errno)); | ||
74 | sleep(1); | ||
75 | } | ||
76 | } while (ret && tries < 10); | ||
77 | |||
78 | if (ret) { | ||
79 | *err += android::base::StringPrintf("failed to stat %s\n", blk_device.c_str()); | ||
80 | } | ||
81 | return ret == 0; | ||
82 | } | ||
83 | |||
84 | static bool read_misc_partition(void* p, size_t size, size_t offset, std::string* err) { | ||
85 | std::string misc_blk_device = get_misc_blk_device(err); | ||
86 | if (misc_blk_device.empty()) { | ||
87 | return false; | ||
88 | } | ||
89 | if (!wait_for_device(misc_blk_device, err)) { | ||
90 | return false; | ||
91 | } | ||
92 | android::base::unique_fd fd(open(misc_blk_device.c_str(), O_WRONLY | O_SYNC)); | ||
93 | if (fd.get() == -1) { | ||
94 | *err = android::base::StringPrintf("failed to open %s: %s", misc_blk_device.c_str(), | ||
95 | strerror(errno)); | ||
96 | return false; | ||
97 | } | ||
98 | if (lseek(fd.get(), static_cast<off_t>(offset), SEEK_SET) != static_cast<off_t>(offset)) { | ||
99 | *err = android::base::StringPrintf("failed to lseek %s: %s", misc_blk_device.c_str(), | ||
100 | strerror(errno)); | ||
101 | return false; | ||
102 | } | ||
103 | if (!android::base::ReadFully(fd.get(), p, size)) { | ||
104 | *err = android::base::StringPrintf("failed to read %s: %s", misc_blk_device.c_str(), | ||
105 | strerror(errno)); | ||
106 | return false; | ||
107 | } | ||
108 | return true; | ||
109 | } | ||
110 | |||
111 | static bool write_misc_partition(const void* p, size_t size, size_t offset, std::string* err) { | ||
112 | std::string misc_blk_device = get_misc_blk_device(err); | ||
113 | if (misc_blk_device.empty()) { | ||
114 | return false; | ||
115 | } | ||
116 | android::base::unique_fd fd(open(misc_blk_device.c_str(), O_WRONLY | O_SYNC)); | ||
117 | if (fd.get() == -1) { | ||
118 | *err = android::base::StringPrintf("failed to open %s: %s", misc_blk_device.c_str(), | ||
119 | strerror(errno)); | ||
120 | return false; | ||
121 | } | ||
122 | if (lseek(fd.get(), static_cast<off_t>(offset), SEEK_SET) != static_cast<off_t>(offset)) { | ||
123 | *err = android::base::StringPrintf("failed to lseek %s: %s", misc_blk_device.c_str(), | ||
124 | strerror(errno)); | ||
125 | return false; | ||
126 | } | ||
127 | if (!android::base::WriteFully(fd.get(), p, size)) { | ||
128 | *err = android::base::StringPrintf("failed to write %s: %s", misc_blk_device.c_str(), | ||
129 | strerror(errno)); | ||
130 | return false; | ||
131 | } | ||
132 | |||
133 | // TODO: O_SYNC and fsync duplicates each other? | ||
134 | if (fsync(fd.get()) == -1) { | ||
135 | *err = android::base::StringPrintf("failed to fsync %s: %s", misc_blk_device.c_str(), | ||
136 | strerror(errno)); | ||
137 | return false; | ||
138 | } | ||
139 | return true; | ||
140 | } | ||
141 | |||
142 | bool read_bootloader_message(bootloader_message* boot, std::string* err) { | ||
143 | return read_misc_partition(boot, sizeof(*boot), BOOTLOADER_MESSAGE_OFFSET_IN_MISC, err); | ||
144 | } | ||
145 | |||
146 | bool write_bootloader_message(const bootloader_message& boot, std::string* err) { | ||
147 | return write_misc_partition(&boot, sizeof(boot), BOOTLOADER_MESSAGE_OFFSET_IN_MISC, err); | ||
148 | } | ||
149 | |||
150 | bool clear_bootloader_message(std::string* err) { | ||
151 | bootloader_message boot = {}; | ||
152 | return write_bootloader_message(boot, err); | ||
153 | } | ||
154 | |||
155 | bool write_bootloader_message(const std::vector<std::string>& options, std::string* err) { | ||
156 | bootloader_message boot = {}; | ||
157 | strlcpy(boot.command, "boot-recovery", sizeof(boot.command)); | ||
158 | strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery)); | ||
159 | for (const auto& s : options) { | ||
160 | strlcat(boot.recovery, s.c_str(), sizeof(boot.recovery)); | ||
161 | if (s.back() != '\n') { | ||
162 | strlcat(boot.recovery, "\n", sizeof(boot.recovery)); | ||
163 | } | ||
164 | } | ||
165 | return write_bootloader_message(boot, err); | ||
166 | } | ||
167 | |||
168 | bool read_wipe_package(std::string* package_data, size_t size, std::string* err) { | ||
169 | package_data->resize(size); | ||
170 | return read_misc_partition(&(*package_data)[0], size, WIPE_PACKAGE_OFFSET_IN_MISC, err); | ||
171 | } | ||
172 | |||
173 | bool write_wipe_package(const std::string& package_data, std::string* err) { | ||
174 | return write_misc_partition(package_data.data(), package_data.size(), | ||
175 | WIPE_PACKAGE_OFFSET_IN_MISC, err); | ||
176 | } | ||
177 | |||
178 | extern "C" bool write_bootloader_message(const char* options) { | ||
179 | std::string err; | ||
180 | return write_bootloader_message({options}, &err); | ||
181 | } | ||
diff --git a/bootloader_message/include/bootloader_message/bootloader_message.h b/bootloader_message/include/bootloader_message/bootloader_message.h new file mode 100644 index 00000000..f343c64a --- /dev/null +++ b/bootloader_message/include/bootloader_message/bootloader_message.h | |||
@@ -0,0 +1,199 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008 The Android Open Source Project | ||
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 | #ifndef _BOOTLOADER_MESSAGE_H | ||
18 | #define _BOOTLOADER_MESSAGE_H | ||
19 | |||
20 | #include <assert.h> | ||
21 | #include <stddef.h> | ||
22 | #include <stdint.h> | ||
23 | |||
24 | // Spaces used by misc partition are as below: | ||
25 | // 0 - 2K For bootloader_message | ||
26 | // 2K - 16K Used by Vendor's bootloader (the 2K - 4K range may be optionally used | ||
27 | // as bootloader_message_ab struct) | ||
28 | // 16K - 64K Used by uncrypt and recovery to store wipe_package for A/B devices | ||
29 | // Note that these offsets are admitted by bootloader,recovery and uncrypt, so they | ||
30 | // are not configurable without changing all of them. | ||
31 | static const size_t BOOTLOADER_MESSAGE_OFFSET_IN_MISC = 0; | ||
32 | static const size_t WIPE_PACKAGE_OFFSET_IN_MISC = 16 * 1024; | ||
33 | |||
34 | /* Bootloader Message (2-KiB) | ||
35 | * | ||
36 | * This structure describes the content of a block in flash | ||
37 | * that is used for recovery and the bootloader to talk to | ||
38 | * each other. | ||
39 | * | ||
40 | * The command field is updated by linux when it wants to | ||
41 | * reboot into recovery or to update radio or bootloader firmware. | ||
42 | * It is also updated by the bootloader when firmware update | ||
43 | * is complete (to boot into recovery for any final cleanup) | ||
44 | * | ||
45 | * The status field is written by the bootloader after the | ||
46 | * completion of an "update-radio" or "update-hboot" command. | ||
47 | * | ||
48 | * The recovery field is only written by linux and used | ||
49 | * for the system to send a message to recovery or the | ||
50 | * other way around. | ||
51 | * | ||
52 | * The stage field is written by packages which restart themselves | ||
53 | * multiple times, so that the UI can reflect which invocation of the | ||
54 | * package it is. If the value is of the format "#/#" (eg, "1/3"), | ||
55 | * the UI will add a simple indicator of that status. | ||
56 | * | ||
57 | * We used to have slot_suffix field for A/B boot control metadata in | ||
58 | * this struct, which gets unintentionally cleared by recovery or | ||
59 | * uncrypt. Move it into struct bootloader_message_ab to avoid the | ||
60 | * issue. | ||
61 | */ | ||
62 | struct bootloader_message { | ||
63 | char command[32]; | ||
64 | char status[32]; | ||
65 | char recovery[768]; | ||
66 | |||
67 | // The 'recovery' field used to be 1024 bytes. It has only ever | ||
68 | // been used to store the recovery command line, so 768 bytes | ||
69 | // should be plenty. We carve off the last 256 bytes to store the | ||
70 | // stage string (for multistage packages) and possible future | ||
71 | // expansion. | ||
72 | char stage[32]; | ||
73 | |||
74 | // The 'reserved' field used to be 224 bytes when it was initially | ||
75 | // carved off from the 1024-byte recovery field. Bump it up to | ||
76 | // 1184-byte so that the entire bootloader_message struct rounds up | ||
77 | // to 2048-byte. | ||
78 | char reserved[1184]; | ||
79 | }; | ||
80 | |||
81 | /** | ||
82 | * We must be cautious when changing the bootloader_message struct size, | ||
83 | * because A/B-specific fields may end up with different offsets. | ||
84 | */ | ||
85 | #if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus) | ||
86 | static_assert(sizeof(struct bootloader_message) == 2048, | ||
87 | "struct bootloader_message size changes, which may break A/B devices"); | ||
88 | #endif | ||
89 | |||
90 | /** | ||
91 | * The A/B-specific bootloader message structure (4-KiB). | ||
92 | * | ||
93 | * We separate A/B boot control metadata from the regular bootloader | ||
94 | * message struct and keep it here. Everything that's A/B-specific | ||
95 | * stays after struct bootloader_message, which should be managed by | ||
96 | * the A/B-bootloader or boot control HAL. | ||
97 | * | ||
98 | * The slot_suffix field is used for A/B implementations where the | ||
99 | * bootloader does not set the androidboot.ro.boot.slot_suffix kernel | ||
100 | * commandline parameter. This is used by fs_mgr to mount /system and | ||
101 | * other partitions with the slotselect flag set in fstab. A/B | ||
102 | * implementations are free to use all 32 bytes and may store private | ||
103 | * data past the first NUL-byte in this field. It is encouraged, but | ||
104 | * not mandatory, to use 'struct bootloader_control' described below. | ||
105 | */ | ||
106 | struct bootloader_message_ab { | ||
107 | struct bootloader_message message; | ||
108 | char slot_suffix[32]; | ||
109 | |||
110 | // Round up the entire struct to 4096-byte. | ||
111 | char reserved[2016]; | ||
112 | }; | ||
113 | |||
114 | /** | ||
115 | * Be cautious about the struct size change, in case we put anything post | ||
116 | * bootloader_message_ab struct (b/29159185). | ||
117 | */ | ||
118 | #if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus) | ||
119 | static_assert(sizeof(struct bootloader_message_ab) == 4096, | ||
120 | "struct bootloader_message_ab size changes"); | ||
121 | #endif | ||
122 | |||
123 | #define BOOT_CTRL_MAGIC 0x42414342 /* Bootloader Control AB */ | ||
124 | #define BOOT_CTRL_VERSION 1 | ||
125 | |||
126 | struct slot_metadata { | ||
127 | // Slot priority with 15 meaning highest priority, 1 lowest | ||
128 | // priority and 0 the slot is unbootable. | ||
129 | uint8_t priority : 4; | ||
130 | // Number of times left attempting to boot this slot. | ||
131 | uint8_t tries_remaining : 3; | ||
132 | // 1 if this slot has booted successfully, 0 otherwise. | ||
133 | uint8_t successful_boot : 1; | ||
134 | // 1 if this slot is corrupted from a dm-verity corruption, 0 | ||
135 | // otherwise. | ||
136 | uint8_t verity_corrupted : 1; | ||
137 | // Reserved for further use. | ||
138 | uint8_t reserved : 7; | ||
139 | } __attribute__((packed)); | ||
140 | |||
141 | /* Bootloader Control AB | ||
142 | * | ||
143 | * This struct can be used to manage A/B metadata. It is designed to | ||
144 | * be put in the 'slot_suffix' field of the 'bootloader_message' | ||
145 | * structure described above. It is encouraged to use the | ||
146 | * 'bootloader_control' structure to store the A/B metadata, but not | ||
147 | * mandatory. | ||
148 | */ | ||
149 | struct bootloader_control { | ||
150 | // NUL terminated active slot suffix. | ||
151 | char slot_suffix[4]; | ||
152 | // Bootloader Control AB magic number (see BOOT_CTRL_MAGIC). | ||
153 | uint32_t magic; | ||
154 | // Version of struct being used (see BOOT_CTRL_VERSION). | ||
155 | uint8_t version; | ||
156 | // Number of slots being managed. | ||
157 | uint8_t nb_slot : 3; | ||
158 | // Number of times left attempting to boot recovery. | ||
159 | uint8_t recovery_tries_remaining : 3; | ||
160 | // Ensure 4-bytes alignment for slot_info field. | ||
161 | uint8_t reserved0[2]; | ||
162 | // Per-slot information. Up to 4 slots. | ||
163 | struct slot_metadata slot_info[4]; | ||
164 | // Reserved for further use. | ||
165 | uint8_t reserved1[8]; | ||
166 | // CRC32 of all 28 bytes preceding this field (little endian | ||
167 | // format). | ||
168 | uint32_t crc32_le; | ||
169 | } __attribute__((packed)); | ||
170 | |||
171 | #if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus) | ||
172 | static_assert(sizeof(struct bootloader_control) == | ||
173 | sizeof(((struct bootloader_message_ab *)0)->slot_suffix), | ||
174 | "struct bootloader_control has wrong size"); | ||
175 | #endif | ||
176 | |||
177 | #ifdef __cplusplus | ||
178 | |||
179 | #include <string> | ||
180 | #include <vector> | ||
181 | |||
182 | bool read_bootloader_message(bootloader_message* boot, std::string* err); | ||
183 | bool write_bootloader_message(const bootloader_message& boot, std::string* err); | ||
184 | bool write_bootloader_message(const std::vector<std::string>& options, std::string* err); | ||
185 | bool clear_bootloader_message(std::string* err); | ||
186 | |||
187 | bool read_wipe_package(std::string* package_data, size_t size, std::string* err); | ||
188 | bool write_wipe_package(const std::string& package_data, std::string* err); | ||
189 | |||
190 | #else | ||
191 | |||
192 | #include <stdbool.h> | ||
193 | |||
194 | // C Interface. | ||
195 | bool write_bootloader_message(const char* options); | ||
196 | |||
197 | #endif // ifdef __cplusplus | ||
198 | |||
199 | #endif // _BOOTLOADER_MESSAGE_H | ||