github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/bootloader/lkenv/lkenv_v2.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2020 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package lkenv 21 22 import ( 23 "fmt" 24 ) 25 26 /** 27 * Following structure has to be kept in sync with c structure defined by 28 * include/lk/snappy-boot_v2.h 29 * c headerfile is used by bootloader, this ensures sync of the environment 30 * between snapd and bootloader 31 32 * when this structure needs to be updated, 33 * new version should be introduced instead together with c header file, 34 * which is to be adopted by bootloader 35 * 36 * !!! Support for old version has to be maintained, as it is not guaranteed 37 * all existing bootloader would adopt new version! 38 */ 39 40 type SnapBootSelect_v2_recovery struct { 41 /* Contains value BOOTSELECT_SIGNATURE defined above */ 42 Signature uint32 43 /* snappy boot select version */ 44 Version uint32 45 46 /** snapd_recovery_mode is what mode the system will be booted in, one of 47 * "install", "recover" or "run" 48 */ 49 Snapd_recovery_mode [SNAP_FILE_NAME_MAX_LEN]byte 50 51 /** snapd_recovery_system defines the recovery system label to be used when 52 * booting the system, it must be defined to one of the values in the 53 * bootimg matrix below 54 */ 55 Snapd_recovery_system [SNAP_FILE_NAME_MAX_LEN]byte 56 57 /** 58 * Matrix for mapping of recovery system boot img partition to kernel snap 59 * revisions for those recovery systems 60 * 61 * First column represents boot image partition label (e.g. recov_a, recov_a) 62 * value are static and should be populated at gadget build time 63 * or latest at image build time. Values are not further altered at run 64 * time. 65 * Second column represents the name of the currently installed recovery 66 * system label there - note that every recovery system has only one 67 * kernel for it, so this is in effect a proxy for the kernel revision 68 * 69 * The initial value representing initial single recovery system is 70 * populated at image build time by snapd 71 * 72 * There are SNAP_RECOVERY_BOOTIMG_PART_NUM rows in the matrix, representing 73 * all possible recovery systems on the image. 74 * The following describes how this matrix should be modified at different 75 * stages: 76 * - at image build time: 77 * - default recovery system label should be filled into free slot 78 * (first row, second column) 79 * - snapd: 80 * - when new recovery system is being created, snapd cycles 81 * through matrix to find unused 'boot slot' to be used for new 82 * recovery system from free slot, first column represents partition 83 * label to which kernel snap boot image should be extracted. Second 84 * column is then populated recovery system label. 85 * - snapd_recovery_mode and snapd_recovery_system are written/used 86 * normally when transitioning to/from recover/install/run modes 87 * - bootloader: 88 * - bootloader reads snapd_recovery_system to determine what label 89 * should be searched for in the matrix, then finds the corresponding 90 * partition label for the kernel snap from that recovery system. Then 91 * snapd_recovery_mode is read and both variables are put onto the 92 * kernel commandline when booting the linux kernel 93 * - bootloader NEVER alters this matrix values 94 * 95 * [ <bootimg 1 part label> ] [ <kernel snap revision installed in this boot partition> ] 96 * [ <bootimg 2 part label> ] [ <kernel snap revision installed in this boot partition> ] 97 */ 98 Bootimg_matrix [SNAP_RECOVERY_BOOTIMG_PART_NUM][2][SNAP_FILE_NAME_MAX_LEN]byte 99 100 /* name of the boot image from kernel snap to be used for extraction 101 when not defined or empty, default boot.img will be used */ 102 Bootimg_file_name [SNAP_FILE_NAME_MAX_LEN]byte 103 104 /** try_recovery_system contains the label of a recovery system to be 105 * tried. This entry is completely transparent to the bootloader and is 106 * only modified by snapd or snap-bootstrap. 107 */ 108 Try_recovery_system [SNAP_FILE_NAME_MAX_LEN]byte 109 110 /** recovery_system_status contains the status of a tried recovery 111 * systems, which is one of "", "try", "tried". This entry is completely 112 * transparent to the bootloader and is only modified by snapd or 113 * snap-bootstrap 114 */ 115 Recovery_system_status [SNAP_FILE_NAME_MAX_LEN]byte 116 117 /* unused placeholders for additional parameters in the future */ 118 Unused_key_01 [SNAP_FILE_NAME_MAX_LEN]byte 119 Unused_key_02 [SNAP_FILE_NAME_MAX_LEN]byte 120 Unused_key_03 [SNAP_FILE_NAME_MAX_LEN]byte 121 Unused_key_04 [SNAP_FILE_NAME_MAX_LEN]byte 122 Unused_key_05 [SNAP_FILE_NAME_MAX_LEN]byte 123 Unused_key_06 [SNAP_FILE_NAME_MAX_LEN]byte 124 Unused_key_07 [SNAP_FILE_NAME_MAX_LEN]byte 125 Unused_key_08 [SNAP_FILE_NAME_MAX_LEN]byte 126 Unused_key_09 [SNAP_FILE_NAME_MAX_LEN]byte 127 Unused_key_10 [SNAP_FILE_NAME_MAX_LEN]byte 128 Unused_key_11 [SNAP_FILE_NAME_MAX_LEN]byte 129 Unused_key_12 [SNAP_FILE_NAME_MAX_LEN]byte 130 Unused_key_13 [SNAP_FILE_NAME_MAX_LEN]byte 131 Unused_key_14 [SNAP_FILE_NAME_MAX_LEN]byte 132 Unused_key_15 [SNAP_FILE_NAME_MAX_LEN]byte 133 Unused_key_16 [SNAP_FILE_NAME_MAX_LEN]byte 134 Unused_key_17 [SNAP_FILE_NAME_MAX_LEN]byte 135 Unused_key_18 [SNAP_FILE_NAME_MAX_LEN]byte 136 137 /* unused array of 10 key value pairs */ 138 Key_value_pairs [10][2][SNAP_FILE_NAME_MAX_LEN]byte 139 140 /* crc32 value for structure */ 141 Crc32 uint32 142 } 143 144 func newV2Recovery() *SnapBootSelect_v2_recovery { 145 return &SnapBootSelect_v2_recovery{ 146 Version: SNAP_BOOTSELECT_VERSION_V2, 147 Signature: SNAP_BOOTSELECT_RECOVERY_SIGNATURE, 148 } 149 } 150 151 func (v2recovery *SnapBootSelect_v2_recovery) currentVersion() uint32 { return v2recovery.Version } 152 func (v2recovery *SnapBootSelect_v2_recovery) currentSignature() uint32 { return v2recovery.Signature } 153 func (v2recovery *SnapBootSelect_v2_recovery) currentCrc32() uint32 { return v2recovery.Crc32 } 154 155 func (v2recovery *SnapBootSelect_v2_recovery) get(key string) string { 156 switch key { 157 case "snapd_recovery_mode": 158 return cToGoString(v2recovery.Snapd_recovery_mode[:]) 159 case "snapd_recovery_system": 160 return cToGoString(v2recovery.Snapd_recovery_system[:]) 161 case "bootimg_file_name": 162 return cToGoString(v2recovery.Bootimg_file_name[:]) 163 case "try_recovery_system": 164 return cToGoString(v2recovery.Try_recovery_system[:]) 165 case "recovery_system_status": 166 return cToGoString(v2recovery.Recovery_system_status[:]) 167 } 168 return "" 169 } 170 171 func (v2recovery *SnapBootSelect_v2_recovery) set(key, value string) { 172 switch key { 173 case "snapd_recovery_mode": 174 copyString(v2recovery.Snapd_recovery_mode[:], value) 175 case "snapd_recovery_system": 176 copyString(v2recovery.Snapd_recovery_system[:], value) 177 case "bootimg_file_name": 178 copyString(v2recovery.Bootimg_file_name[:], value) 179 case "try_recovery_system": 180 copyString(v2recovery.Try_recovery_system[:], value) 181 case "recovery_system_status": 182 copyString(v2recovery.Recovery_system_status[:], value) 183 } 184 } 185 186 func (v2recovery *SnapBootSelect_v2_recovery) bootImgRecoverySystemMatrix() (bootimgMatrixGeneric, error) { 187 return (bootimgMatrixGeneric)((&v2recovery.Bootimg_matrix)[:]), nil 188 } 189 190 func (v2recovery *SnapBootSelect_v2_recovery) bootImgKernelMatrix() (bootimgMatrixGeneric, error) { 191 return nil, fmt.Errorf("internal error: v2 recovery lkenv has no boot image partition kernel matrix") 192 } 193 194 type SnapBootSelect_v2_run struct { 195 /* Contains value BOOTSELECT_SIGNATURE defined above */ 196 Signature uint32 197 /* snappy boot select version */ 198 Version uint32 199 200 /* kernel_status, one of: 'empty', "try", "trying" */ 201 Kernel_status [SNAP_FILE_NAME_MAX_LEN]byte 202 /* current kernel snap revision */ 203 Snap_kernel [SNAP_FILE_NAME_MAX_LEN]byte 204 /* current try kernel snap revision */ 205 Snap_try_kernel [SNAP_FILE_NAME_MAX_LEN]byte 206 207 /* gadget_mode, one of: 'empty', "try", "trying" */ 208 Gadget_mode [SNAP_FILE_NAME_MAX_LEN]byte 209 /* GADGET assets: current gadget assets revision */ 210 Snap_gadget [SNAP_FILE_NAME_MAX_LEN]byte 211 /* GADGET assets: try gadget assets revision */ 212 Snap_try_gadget [SNAP_FILE_NAME_MAX_LEN]byte 213 214 /** 215 * Matrix for mapping of run mode boot img partition to installed kernel 216 * snap revision 217 * 218 * First column represents boot image partition label (e.g. boot_a,boot_b ) 219 * value are static and should be populated at gadget built time 220 * or latest at image build time. Values are not further altered at run 221 * time. 222 * Second column represents name currently installed kernel snap 223 * e.g. pi2-kernel_123.snap 224 * initial value representing initial kernel snap revision 225 * is populated at image build time by snapd 226 * 227 * There are two rows in the matrix, representing current and previous 228 * kernel revision 229 * The following describes how this matrix should be modified at different 230 * stages: 231 * - snapd in install mode: 232 * - extracted kernel snap revision name should be filled 233 * into free slot (first row, second row) 234 * - snapd in run mode: 235 * - when new kernel snap revision is being installed, snapd cycles 236 * through matrix to find unused 'boot slot' to be used for new kernel 237 * snap revision from free slot, first column represents partition 238 * label to which kernel snap boot image should be extracted. Second 239 * column is then populated with kernel snap revision name. 240 * - kernel_status, snap_try_kernel, snap_try_core behaves same way as 241 * with u-boot 242 * - bootloader: 243 * - bootloader reads kernel_status to determine if snap_kernel or 244 * snap_try_kernel is used to get kernel snap revision name. 245 * kernel snap revision is then used to search matrix to determine 246 * partition label to be used for current boot 247 * - bootloader NEVER alters this matrix values 248 * 249 * [ <bootimg 1 part label> ] [ <kernel snap revision installed in this boot partition> ] 250 * [ <bootimg 2 part label> ] [ <kernel snap revision installed in this boot partition> ] 251 */ 252 Bootimg_matrix [SNAP_RUN_BOOTIMG_PART_NUM][2][SNAP_FILE_NAME_MAX_LEN]byte 253 254 /* name of the boot image from kernel snap to be used for extraction 255 when not defined or empty, default boot.img will be used */ 256 Bootimg_file_name [SNAP_FILE_NAME_MAX_LEN]byte 257 258 /** 259 * gadget assets: Matrix for mapping of gadget asset partitions 260 * Optional boot asset tracking, based on bootloader support 261 * Some boot chains support A/B boot assets for increased robustness 262 * example being A/B TrustExecutionEnvironment 263 * This matrix can be used to track current and try boot assets for 264 * robust updates 265 * Use of Gadget_asset_matrix matches use of Bootimg_matrix 266 * 267 * [ <boot assets 1 part label> ] [ <currently installed assets revision in this partition> ] 268 * [ <boot assets 2 part label> ] [ <currently installed assets revision in this partition> ] 269 */ 270 Gadget_asset_matrix [SNAP_RUN_BOOTIMG_PART_NUM][2][SNAP_FILE_NAME_MAX_LEN]byte 271 272 /* unused placeholders for additional parameters in the future */ 273 Unused_key_01 [SNAP_FILE_NAME_MAX_LEN]byte 274 Unused_key_02 [SNAP_FILE_NAME_MAX_LEN]byte 275 Unused_key_03 [SNAP_FILE_NAME_MAX_LEN]byte 276 Unused_key_04 [SNAP_FILE_NAME_MAX_LEN]byte 277 Unused_key_05 [SNAP_FILE_NAME_MAX_LEN]byte 278 Unused_key_06 [SNAP_FILE_NAME_MAX_LEN]byte 279 Unused_key_07 [SNAP_FILE_NAME_MAX_LEN]byte 280 Unused_key_08 [SNAP_FILE_NAME_MAX_LEN]byte 281 Unused_key_09 [SNAP_FILE_NAME_MAX_LEN]byte 282 Unused_key_10 [SNAP_FILE_NAME_MAX_LEN]byte 283 Unused_key_11 [SNAP_FILE_NAME_MAX_LEN]byte 284 Unused_key_12 [SNAP_FILE_NAME_MAX_LEN]byte 285 Unused_key_13 [SNAP_FILE_NAME_MAX_LEN]byte 286 Unused_key_14 [SNAP_FILE_NAME_MAX_LEN]byte 287 Unused_key_15 [SNAP_FILE_NAME_MAX_LEN]byte 288 Unused_key_16 [SNAP_FILE_NAME_MAX_LEN]byte 289 Unused_key_17 [SNAP_FILE_NAME_MAX_LEN]byte 290 Unused_key_18 [SNAP_FILE_NAME_MAX_LEN]byte 291 Unused_key_19 [SNAP_FILE_NAME_MAX_LEN]byte 292 Unused_key_20 [SNAP_FILE_NAME_MAX_LEN]byte 293 294 /* unused array of 10 key value pairs */ 295 Key_value_pairs [10][2][SNAP_FILE_NAME_MAX_LEN]byte 296 297 /* crc32 value for structure */ 298 Crc32 uint32 299 } 300 301 func newV2Run() *SnapBootSelect_v2_run { 302 return &SnapBootSelect_v2_run{ 303 Version: SNAP_BOOTSELECT_VERSION_V2, 304 Signature: SNAP_BOOTSELECT_SIGNATURE, 305 } 306 } 307 308 func (v2run *SnapBootSelect_v2_run) currentCrc32() uint32 { return v2run.Crc32 } 309 func (v2run *SnapBootSelect_v2_run) currentVersion() uint32 { return v2run.Version } 310 func (v2run *SnapBootSelect_v2_run) currentSignature() uint32 { return v2run.Signature } 311 312 func (v2run *SnapBootSelect_v2_run) get(key string) string { 313 switch key { 314 case "kernel_status": 315 return cToGoString(v2run.Kernel_status[:]) 316 case "snap_kernel": 317 return cToGoString(v2run.Snap_kernel[:]) 318 case "snap_try_kernel": 319 return cToGoString(v2run.Snap_try_kernel[:]) 320 case "snap_gadget": 321 return cToGoString(v2run.Snap_gadget[:]) 322 case "snap_try_gadget": 323 return cToGoString(v2run.Snap_try_gadget[:]) 324 case "bootimg_file_name": 325 return cToGoString(v2run.Bootimg_file_name[:]) 326 } 327 return "" 328 } 329 330 func (v2run *SnapBootSelect_v2_run) set(key, value string) { 331 switch key { 332 case "kernel_status": 333 copyString(v2run.Kernel_status[:], value) 334 case "snap_kernel": 335 copyString(v2run.Snap_kernel[:], value) 336 case "snap_try_kernel": 337 copyString(v2run.Snap_try_kernel[:], value) 338 case "snap_gadget": 339 copyString(v2run.Snap_gadget[:], value) 340 case "snap_try_gadget": 341 copyString(v2run.Snap_try_gadget[:], value) 342 case "bootimg_file_name": 343 copyString(v2run.Bootimg_file_name[:], value) 344 } 345 } 346 347 func (v2run *SnapBootSelect_v2_run) bootImgKernelMatrix() (bootimgMatrixGeneric, error) { 348 return (bootimgMatrixGeneric)((&v2run.Bootimg_matrix)[:]), nil 349 } 350 351 func (v2run *SnapBootSelect_v2_run) bootImgRecoverySystemMatrix() (bootimgMatrixGeneric, error) { 352 return nil, fmt.Errorf("internal error: v2 run lkenv has no boot image partition recovery system matrix") 353 }