blob: 5e014be0962ee4ba2cddb329d94dc8b18d73c5e7 [file] [log] [blame]
merothh54856102021-11-04 12:07:41 +05301/*
2 * Copyright (c) 2013,2016,2020 The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#define _LARGEFILE64_SOURCE /* enable lseek64() */
31
32/******************************************************************************
33 * INCLUDE SECTION
34 ******************************************************************************/
35#include <fcntl.h>
36#include <string.h>
37#include <errno.h>
38#include <sys/stat.h>
39#include <sys/ioctl.h>
40#include <unistd.h>
41#include <linux/fs.h>
42#include <limits.h>
43#include <dirent.h>
44#include <linux/kernel.h>
45#include <map>
46#include <vector>
47#include <string>
48#ifndef __STDC_FORMAT_MACROS
49#define __STDC_FORMAT_MACROS
50#endif
51#include <inttypes.h>
52
53
54#define LOG_TAG "gpt-utils"
55#include <cutils/log.h>
56#include <cutils/properties.h>
57#include "gpt-utils.h"
58#include <zlib.h>
59#include <endian.h>
60
61
62/******************************************************************************
63 * DEFINE SECTION
64 ******************************************************************************/
65#define BLK_DEV_FILE "/dev/block/mmcblk0"
66/* list the names of the backed-up partitions to be swapped */
67/* extension used for the backup partitions - tzbak, abootbak, etc. */
68#define BAK_PTN_NAME_EXT "bak"
69#define XBL_PRIMARY "/dev/block/bootdevice/by-name/xbl"
70#define XBL_BACKUP "/dev/block/bootdevice/by-name/xblbak"
71#define XBL_AB_PRIMARY "/dev/block/bootdevice/by-name/xbl_a"
72#define XBL_AB_SECONDARY "/dev/block/bootdevice/by-name/xbl_b"
73/* GPT defines */
74#define MAX_LUNS 26
75//This will allow us to get the root lun path from the path to the partition.
76//i.e: from /dev/block/sdaXXX get /dev/block/sda. The assumption here is that
77//the boot critical luns lie between sda to sdz which is acceptable because
78//only user added external disks,etc would lie beyond that limit which do not
79//contain partitions that interest us here.
80#define PATH_TRUNCATE_LOC (sizeof("/dev/block/sda") - 1)
81
82//From /dev/block/sda get just sda
83#define LUN_NAME_START_LOC (sizeof("/dev/block/") - 1)
84#define BOOT_LUN_A_ID 1
85#define BOOT_LUN_B_ID 2
86/******************************************************************************
87 * MACROS
88 ******************************************************************************/
89
90
91#define GET_4_BYTES(ptr) ((uint32_t) *((uint8_t *)(ptr)) | \
92 ((uint32_t) *((uint8_t *)(ptr) + 1) << 8) | \
93 ((uint32_t) *((uint8_t *)(ptr) + 2) << 16) | \
94 ((uint32_t) *((uint8_t *)(ptr) + 3) << 24))
95
96#define GET_8_BYTES(ptr) ((uint64_t) *((uint8_t *)(ptr)) | \
97 ((uint64_t) *((uint8_t *)(ptr) + 1) << 8) | \
98 ((uint64_t) *((uint8_t *)(ptr) + 2) << 16) | \
99 ((uint64_t) *((uint8_t *)(ptr) + 3) << 24) | \
100 ((uint64_t) *((uint8_t *)(ptr) + 4) << 32) | \
101 ((uint64_t) *((uint8_t *)(ptr) + 5) << 40) | \
102 ((uint64_t) *((uint8_t *)(ptr) + 6) << 48) | \
103 ((uint64_t) *((uint8_t *)(ptr) + 7) << 56))
104
105#define PUT_4_BYTES(ptr, y) *((uint8_t *)(ptr)) = (y) & 0xff; \
106 *((uint8_t *)(ptr) + 1) = ((y) >> 8) & 0xff; \
107 *((uint8_t *)(ptr) + 2) = ((y) >> 16) & 0xff; \
108 *((uint8_t *)(ptr) + 3) = ((y) >> 24) & 0xff;
109
110/******************************************************************************
111 * TYPES
112 ******************************************************************************/
113using namespace std;
114enum gpt_state {
115 GPT_OK = 0,
116 GPT_BAD_SIGNATURE,
117 GPT_BAD_CRC
118};
119//List of LUN's containing boot critical images.
120//Required in the case of UFS devices
121struct update_data {
122 char lun_list[MAX_LUNS][PATH_MAX];
123 uint32_t num_valid_entries;
124};
125
126int32_t set_boot_lun(char *sg_dev,uint8_t boot_lun_id);
127/******************************************************************************
128 * FUNCTIONS
129 ******************************************************************************/
130/**
131 * ==========================================================================
132 *
133 * \brief Read/Write len bytes from/to block dev
134 *
135 * \param [in] fd block dev file descriptor (returned from open)
136 * \param [in] rw RW flag: 0 - read, != 0 - write
137 * \param [in] offset block dev offset [bytes] - RW start position
138 * \param [in] buf Pointer to the buffer containing the data
139 * \param [in] len RW size in bytes. Buf must be at least that big
140 *
141 * \return 0 on success
142 *
143 * ==========================================================================
144 */
145static int blk_rw(int fd, int rw, int64_t offset, uint8_t *buf, unsigned len)
146{
147 int r;
148
149 if (lseek64(fd, offset, SEEK_SET) < 0) {
150 fprintf(stderr, "block dev lseek64 %" PRIi64 " failed: %s\n", offset,
151 strerror(errno));
152 return -1;
153 }
154
155 if (rw)
156 r = write(fd, buf, len);
157 else
158 r = read(fd, buf, len);
159
160 if (r < 0)
161 fprintf(stderr, "block dev %s failed: %s\n", rw ? "write" : "read",
162 strerror(errno));
163 else
164 r = 0;
165
166 return r;
167}
168
169
170
171/**
172 * ==========================================================================
173 *
174 * \brief Search within GPT for partition entry with the given name
175 * or it's backup twin (name-bak).
176 *
177 * \param [in] ptn_name Partition name to seek
178 * \param [in] pentries_start Partition entries array start pointer
179 * \param [in] pentries_end Partition entries array end pointer
180 * \param [in] pentry_size Single partition entry size [bytes]
181 *
182 * \return First partition entry pointer that matches the name or NULL
183 *
184 * ==========================================================================
185 */
186static uint8_t *gpt_pentry_seek(const char *ptn_name,
187 const uint8_t *pentries_start,
188 const uint8_t *pentries_end,
189 uint32_t pentry_size)
190{
191 char *pentry_name;
192 unsigned len = strlen(ptn_name);
193 unsigned i;
194 char name8[MAX_GPT_NAME_SIZE] = {0}; // initialize with null
195
196 for (pentry_name = (char *) (pentries_start + PARTITION_NAME_OFFSET);
197 pentry_name < (char *) pentries_end;
198 pentry_name += pentry_size) {
199
200 /* Partition names in GPT are UTF-16 - ignoring UTF-16 2nd byte */
201 for (i = 0; i < sizeof(name8) / 2; i++)
202 name8[i] = pentry_name[i * 2];
203 name8[i] = '\0';
204
205 if (!strncmp(ptn_name, name8, len)) {
206 if (name8[len] == 0 || !strcmp(&name8[len], BAK_PTN_NAME_EXT))
207 return (uint8_t *) (pentry_name - PARTITION_NAME_OFFSET);
208 }
209 }
210
211 return NULL;
212}
213
214
215
216/**
217 * ==========================================================================
218 *
219 * \brief Swaps boot chain in GPT partition entries array
220 *
221 * \param [in] pentries_start Partition entries array start
222 * \param [in] pentries_end Partition entries array end
223 * \param [in] pentry_size Single partition entry size
224 *
225 * \return 0 on success, 1 if no backup partitions found
226 *
227 * ==========================================================================
228 */
229static int gpt_boot_chain_swap(const uint8_t *pentries_start,
230 const uint8_t *pentries_end,
231 uint32_t pentry_size)
232{
233 const char ptn_swap_list[][MAX_GPT_NAME_SIZE] = { PTN_SWAP_LIST };
234
235 int backup_not_found = 1;
236 unsigned i;
237
238 for (i = 0; i < ARRAY_SIZE(ptn_swap_list); i++) {
239 uint8_t *ptn_entry;
240 uint8_t *ptn_bak_entry;
241 uint8_t ptn_swap[PTN_ENTRY_SIZE];
Siddeswar Aluganti77993932021-04-14 12:04:04 -0700242 //Skip the xbl, multiimgoem, multiimgqti partitions on UFS devices. That is handled
merothh54856102021-11-04 12:07:41 +0530243 //seperately.
Luofan Chencc9c5112023-05-24 23:56:36 +0800244 if (gpt_utils_is_ufs_device() && (!strncmp(ptn_swap_list[i],PTN_XBL,strlen(PTN_XBL))
Siddeswar Aluganti77993932021-04-14 12:04:04 -0700245 || !strncmp(ptn_swap_list[i],PTN_MULTIIMGOEM,strlen(PTN_MULTIIMGOEM))
Luofan Chencc9c5112023-05-24 23:56:36 +0800246 || !strncmp(ptn_swap_list[i],PTN_MULTIIMGQTI,strlen(PTN_MULTIIMGQTI))))
merothh54856102021-11-04 12:07:41 +0530247 continue;
248
249 ptn_entry = gpt_pentry_seek(ptn_swap_list[i], pentries_start,
250 pentries_end, pentry_size);
251 if (ptn_entry == NULL)
252 continue;
253
254 ptn_bak_entry = gpt_pentry_seek(ptn_swap_list[i],
255 ptn_entry + pentry_size, pentries_end, pentry_size);
256 if (ptn_bak_entry == NULL) {
257 fprintf(stderr, "'%s' partition not backup - skip safe update\n",
258 ptn_swap_list[i]);
259 continue;
260 }
261
262 /* swap primary <-> backup partition entries */
263 memcpy(ptn_swap, ptn_entry, PTN_ENTRY_SIZE);
264 memcpy(ptn_entry, ptn_bak_entry, PTN_ENTRY_SIZE);
265 memcpy(ptn_bak_entry, ptn_swap, PTN_ENTRY_SIZE);
266 backup_not_found = 0;
267 }
268
269 return backup_not_found;
270}
271
272
273
274/**
275 * ==========================================================================
276 *
277 * \brief Sets secondary GPT boot chain
278 *
279 * \param [in] fd block dev file descriptor
280 * \param [in] boot Boot chain to switch to
281 *
282 * \return 0 on success
283 *
284 * ==========================================================================
285 */
286static int gpt2_set_boot_chain(int fd, enum boot_chain boot)
287{
288 int64_t gpt2_header_offset;
289 uint64_t pentries_start_offset;
290 uint32_t gpt_header_size;
291 uint32_t pentry_size;
292 uint32_t pentries_array_size;
293
294 uint8_t *gpt_header = NULL;
295 uint8_t *pentries = NULL;
296 uint32_t crc;
297 uint32_t crc_zero;
298 uint32_t blk_size = 0;
299 int r;
300
301
302 crc_zero = crc32(0L, Z_NULL, 0);
303 if (ioctl(fd, BLKSSZGET, &blk_size) != 0) {
304 fprintf(stderr, "Failed to get GPT device block size: %s\n",
305 strerror(errno));
306 r = -1;
307 goto EXIT;
308 }
309 gpt_header = (uint8_t*)malloc(blk_size);
310 if (!gpt_header) {
311 fprintf(stderr, "Failed to allocate memory to hold GPT block\n");
312 r = -1;
313 goto EXIT;
314 }
315 gpt2_header_offset = lseek64(fd, 0, SEEK_END) - blk_size;
316 if (gpt2_header_offset < 0) {
317 fprintf(stderr, "Getting secondary GPT header offset failed: %s\n",
318 strerror(errno));
319 r = -1;
320 goto EXIT;
321 }
322
323 /* Read primary GPT header from block dev */
324 r = blk_rw(fd, 0, blk_size, gpt_header, blk_size);
325
326 if (r) {
327 fprintf(stderr, "Failed to read primary GPT header from blk dev\n");
328 goto EXIT;
329 }
330 pentries_start_offset =
331 GET_8_BYTES(gpt_header + PENTRIES_OFFSET) * blk_size;
332 pentry_size = GET_4_BYTES(gpt_header + PENTRY_SIZE_OFFSET);
333 pentries_array_size =
334 GET_4_BYTES(gpt_header + PARTITION_COUNT_OFFSET) * pentry_size;
335
336 pentries = (uint8_t *) calloc(1, pentries_array_size);
337 if (pentries == NULL) {
338 fprintf(stderr,
339 "Failed to alloc memory for GPT partition entries array\n");
340 r = -1;
341 goto EXIT;
342 }
343 /* Read primary GPT partititon entries array from block dev */
344 r = blk_rw(fd, 0, pentries_start_offset, pentries, pentries_array_size);
345 if (r)
346 goto EXIT;
347
348 crc = crc32(crc_zero, pentries, pentries_array_size);
349 if (GET_4_BYTES(gpt_header + PARTITION_CRC_OFFSET) != crc) {
350 fprintf(stderr, "Primary GPT partition entries array CRC invalid\n");
351 r = -1;
352 goto EXIT;
353 }
354
355 /* Read secondary GPT header from block dev */
356 r = blk_rw(fd, 0, gpt2_header_offset, gpt_header, blk_size);
357 if (r)
358 goto EXIT;
359
360 gpt_header_size = GET_4_BYTES(gpt_header + HEADER_SIZE_OFFSET);
361 pentries_start_offset =
362 GET_8_BYTES(gpt_header + PENTRIES_OFFSET) * blk_size;
363
364 if (boot == BACKUP_BOOT) {
365 r = gpt_boot_chain_swap(pentries, pentries + pentries_array_size,
366 pentry_size);
367 if (r)
368 goto EXIT;
369 }
370
371 crc = crc32(crc_zero, pentries, pentries_array_size);
372 PUT_4_BYTES(gpt_header + PARTITION_CRC_OFFSET, crc);
373
374 /* header CRC is calculated with this field cleared */
375 PUT_4_BYTES(gpt_header + HEADER_CRC_OFFSET, 0);
376 crc = crc32(crc_zero, gpt_header, gpt_header_size);
377 PUT_4_BYTES(gpt_header + HEADER_CRC_OFFSET, crc);
378
379 /* Write the modified GPT header back to block dev */
380 r = blk_rw(fd, 1, gpt2_header_offset, gpt_header, blk_size);
381 if (!r)
382 /* Write the modified GPT partititon entries array back to block dev */
383 r = blk_rw(fd, 1, pentries_start_offset, pentries,
384 pentries_array_size);
385
386EXIT:
387 if(gpt_header)
388 free(gpt_header);
389 if (pentries)
390 free(pentries);
391 return r;
392}
393
394/**
395 * ==========================================================================
396 *
397 * \brief Checks GPT state (header signature and CRC)
398 *
399 * \param [in] fd block dev file descriptor
400 * \param [in] gpt GPT header to be checked
401 * \param [out] state GPT header state
402 *
403 * \return 0 on success
404 *
405 * ==========================================================================
406 */
407static int gpt_get_state(int fd, enum gpt_instance gpt, enum gpt_state *state)
408{
409 int64_t gpt_header_offset;
410 uint32_t gpt_header_size;
411 uint8_t *gpt_header = NULL;
412 uint32_t crc;
413 uint32_t crc_zero;
414 uint32_t blk_size = 0;
415
416 *state = GPT_OK;
417
418 crc_zero = crc32(0L, Z_NULL, 0);
419 if (ioctl(fd, BLKSSZGET, &blk_size) != 0) {
420 fprintf(stderr, "Failed to get GPT device block size: %s\n",
421 strerror(errno));
422 goto error;
423 }
424 gpt_header = (uint8_t*)malloc(blk_size);
425 if (!gpt_header) {
426 fprintf(stderr, "gpt_get_state:Failed to alloc memory for header\n");
427 goto error;
428 }
429 if (gpt == PRIMARY_GPT)
430 gpt_header_offset = blk_size;
431 else {
432 gpt_header_offset = lseek64(fd, 0, SEEK_END) - blk_size;
433 if (gpt_header_offset < 0) {
434 fprintf(stderr, "gpt_get_state:Seek to end of GPT part fail\n");
435 goto error;
436 }
437 }
438
439 if (blk_rw(fd, 0, gpt_header_offset, gpt_header, blk_size)) {
440 fprintf(stderr, "gpt_get_state: blk_rw failed\n");
441 goto error;
442 }
443 if (memcmp(gpt_header, GPT_SIGNATURE, sizeof(GPT_SIGNATURE)))
444 *state = GPT_BAD_SIGNATURE;
445 gpt_header_size = GET_4_BYTES(gpt_header + HEADER_SIZE_OFFSET);
446
447 crc = GET_4_BYTES(gpt_header + HEADER_CRC_OFFSET);
448 /* header CRC is calculated with this field cleared */
449 PUT_4_BYTES(gpt_header + HEADER_CRC_OFFSET, 0);
450 if (crc32(crc_zero, gpt_header, gpt_header_size) != crc)
451 *state = GPT_BAD_CRC;
452 free(gpt_header);
453 return 0;
454error:
455 if (gpt_header)
456 free(gpt_header);
457 return -1;
458}
459
460
461
462/**
463 * ==========================================================================
464 *
465 * \brief Sets GPT header state (used to corrupt and fix GPT signature)
466 *
467 * \param [in] fd block dev file descriptor
468 * \param [in] gpt GPT header to be checked
469 * \param [in] state GPT header state to set (GPT_OK or GPT_BAD_SIGNATURE)
470 *
471 * \return 0 on success
472 *
473 * ==========================================================================
474 */
475static int gpt_set_state(int fd, enum gpt_instance gpt, enum gpt_state state)
476{
477 int64_t gpt_header_offset;
478 uint32_t gpt_header_size;
479 uint8_t *gpt_header = NULL;
480 uint32_t crc;
481 uint32_t crc_zero;
482 uint32_t blk_size = 0;
483
484 crc_zero = crc32(0L, Z_NULL, 0);
485 if (ioctl(fd, BLKSSZGET, &blk_size) != 0) {
486 fprintf(stderr, "Failed to get GPT device block size: %s\n",
487 strerror(errno));
488 goto error;
489 }
490 gpt_header = (uint8_t*)malloc(blk_size);
491 if (!gpt_header) {
492 fprintf(stderr, "Failed to alloc memory for gpt header\n");
493 goto error;
494 }
495 if (gpt == PRIMARY_GPT)
496 gpt_header_offset = blk_size;
497 else {
498 gpt_header_offset = lseek64(fd, 0, SEEK_END) - blk_size;
499 if (gpt_header_offset < 0) {
500 fprintf(stderr, "Failed to seek to end of GPT device\n");
501 goto error;
502 }
503 }
504 if (blk_rw(fd, 0, gpt_header_offset, gpt_header, blk_size)) {
505 fprintf(stderr, "Failed to r/w gpt header\n");
506 goto error;
507 }
508 if (state == GPT_OK)
509 memcpy(gpt_header, GPT_SIGNATURE, sizeof(GPT_SIGNATURE));
510 else if (state == GPT_BAD_SIGNATURE)
511 *gpt_header = 0;
512 else {
513 fprintf(stderr, "gpt_set_state: Invalid state\n");
514 goto error;
515 }
516
517 gpt_header_size = GET_4_BYTES(gpt_header + HEADER_SIZE_OFFSET);
518
519 /* header CRC is calculated with this field cleared */
520 PUT_4_BYTES(gpt_header + HEADER_CRC_OFFSET, 0);
521 crc = crc32(crc_zero, gpt_header, gpt_header_size);
522 PUT_4_BYTES(gpt_header + HEADER_CRC_OFFSET, crc);
523
524 if (blk_rw(fd, 1, gpt_header_offset, gpt_header, blk_size)) {
525 fprintf(stderr, "gpt_set_state: blk write failed\n");
526 goto error;
527 }
528 return 0;
529error:
530 if(gpt_header)
531 free(gpt_header);
532 return -1;
533}
534
535int get_scsi_node_from_bootdevice(const char *bootdev_path,
536 char *sg_node_path,
537 size_t buf_size)
538{
539 char sg_dir_path[PATH_MAX] = {0};
540 char real_path[PATH_MAX] = {0};
541 DIR *scsi_dir = NULL;
542 struct dirent *de;
543 int node_found = 0;
544 if (!bootdev_path || !sg_node_path) {
545 fprintf(stderr, "%s : invalid argument\n",
546 __func__);
547 goto error;
548 }
549 if (readlink(bootdev_path, real_path, sizeof(real_path) - 1) < 0) {
550 fprintf(stderr, "failed to resolve link for %s(%s)\n",
551 bootdev_path,
552 strerror(errno));
553 goto error;
554 }
555 if(strlen(real_path) < PATH_TRUNCATE_LOC + 1){
556 fprintf(stderr, "Unrecognized path :%s:\n",
557 real_path);
558 goto error;
559 }
560 //For the safe side in case there are additional partitions on
561 //the XBL lun we truncate the name.
562 real_path[PATH_TRUNCATE_LOC] = '\0';
563 if(strlen(real_path) < LUN_NAME_START_LOC + 1){
564 fprintf(stderr, "Unrecognized truncated path :%s:\n",
565 real_path);
566 goto error;
567 }
568 //This will give us /dev/block/sdb/device/scsi_generic
569 //which contains a file sgY whose name gives us the path
570 //to /dev/sgY which we return
571 snprintf(sg_dir_path, sizeof(sg_dir_path) - 1,
572 "/sys/block/%s/device/scsi_generic",
573 &real_path[LUN_NAME_START_LOC]);
574 scsi_dir = opendir(sg_dir_path);
575 if (!scsi_dir) {
576 fprintf(stderr, "%s : Failed to open %s(%s)\n",
577 __func__,
578 sg_dir_path,
579 strerror(errno));
580 goto error;
581 }
582 while((de = readdir(scsi_dir))) {
583 if (de->d_name[0] == '.')
584 continue;
585 else if (!strncmp(de->d_name, "sg", 2)) {
586 snprintf(sg_node_path,
587 buf_size -1,
588 "/dev/%s",
589 de->d_name);
590 fprintf(stderr, "%s:scsi generic node is :%s:\n",
591 __func__,
592 sg_node_path);
593 node_found = 1;
594 break;
595 }
596 }
597 if(!node_found) {
598 fprintf(stderr,"%s: Unable to locate scsi generic node\n",
599 __func__);
600 goto error;
601 }
602 closedir(scsi_dir);
603 return 0;
604error:
605 if (scsi_dir)
606 closedir(scsi_dir);
607 return -1;
608}
609
610
611
612//Swtich betwieen using either the primary or the backup
613//boot LUN for boot. This is required since UFS boot partitions
614//cannot have a backup GPT which is what we use for failsafe
615//updates of the other 'critical' partitions. This function will
616//not be invoked for emmc targets and on UFS targets is only required
617//to be invoked for XBL.
618//
619//The algorithm to do this is as follows:
620//- Find the real block device(eg: /dev/block/sdb) that corresponds
621// to the /dev/block/bootdevice/by-name/xbl(bak) symlink
622//
623//- Once we have the block device 'node' name(sdb in the above example)
624// use this node to to locate the scsi generic device that represents
625// it by checking the file /sys/block/sdb/device/scsi_generic/sgY
626//
627//- Once we locate sgY we call the query ioctl on /dev/sgy to switch
628//the boot lun to either LUNA or LUNB
629int gpt_utils_set_xbl_boot_partition(enum boot_chain chain)
630{
631 struct stat st;
632 ///sys/block/sdX/device/scsi_generic/
633 char sg_dev_node[PATH_MAX] = {0};
634 uint8_t boot_lun_id = 0;
635 const char *boot_dev = NULL;
636
637 if (chain == BACKUP_BOOT) {
638 boot_lun_id = BOOT_LUN_B_ID;
639 if (!stat(XBL_BACKUP, &st))
640 boot_dev = XBL_BACKUP;
641 else if (!stat(XBL_AB_SECONDARY, &st))
642 boot_dev = XBL_AB_SECONDARY;
643 else {
644 fprintf(stderr, "%s: Failed to locate secondary xbl\n",
645 __func__);
646 goto error;
647 }
648 } else if (chain == NORMAL_BOOT) {
649 boot_lun_id = BOOT_LUN_A_ID;
650 if (!stat(XBL_PRIMARY, &st))
651 boot_dev = XBL_PRIMARY;
652 else if (!stat(XBL_AB_PRIMARY, &st))
653 boot_dev = XBL_AB_PRIMARY;
654 else {
655 fprintf(stderr, "%s: Failed to locate primary xbl\n",
656 __func__);
657 goto error;
658 }
659 } else {
660 fprintf(stderr, "%s: Invalid boot chain id\n", __func__);
661 goto error;
662 }
663 //We need either both xbl and xblbak or both xbl_a and xbl_b to exist at
664 //the same time. If not the current configuration is invalid.
665 if((stat(XBL_PRIMARY, &st) ||
666 stat(XBL_BACKUP, &st)) &&
667 (stat(XBL_AB_PRIMARY, &st) ||
668 stat(XBL_AB_SECONDARY, &st))) {
669 fprintf(stderr, "%s:primary/secondary XBL prt not found(%s)\n",
670 __func__,
671 strerror(errno));
672 goto error;
673 }
674 fprintf(stderr, "%s: setting %s lun as boot lun\n",
675 __func__,
676 boot_dev);
677 if (get_scsi_node_from_bootdevice(boot_dev,
678 sg_dev_node,
679 sizeof(sg_dev_node))) {
680 fprintf(stderr, "%s: Failed to get scsi node path for xblbak\n",
681 __func__);
682 goto error;
683 }
684 /* set boot lun using /dev/sg or /dev/ufs-bsg* */
685 if (set_boot_lun(sg_dev_node, boot_lun_id)) {
686 fprintf(stderr, "%s: Failed to set xblbak as boot partition\n",
687 __func__);
688 goto error;
689 }
690 return 0;
691error:
692 return -1;
693}
694
695int gpt_utils_is_ufs_device()
696{
697 char bootdevice[PROPERTY_VALUE_MAX] = {0};
698 property_get("ro.boot.bootdevice", bootdevice, "N/A");
699 if (strlen(bootdevice) < strlen(".ufshc") + 1)
700 return 0;
701 return (!strncmp(&bootdevice[strlen(bootdevice) - strlen(".ufshc")],
702 ".ufshc",
703 sizeof(".ufshc")));
704}
705//dev_path is the path to the block device that contains the GPT image that
706//needs to be updated. This would be the device which holds one or more critical
707//boot partitions and their backups. In the case of EMMC this function would
708//be invoked only once on /dev/block/mmcblk1 since it holds the GPT image
709//containing all the partitions For UFS devices it could potentially be
710//invoked multiple times, once for each LUN containing critical image(s) and
711//their backups
712int prepare_partitions(enum boot_update_stage stage, const char *dev_path)
713{
714 int r = 0;
715 int fd = -1;
716 int is_ufs = gpt_utils_is_ufs_device();
717 enum gpt_state gpt_prim, gpt_second;
718 enum boot_update_stage internal_stage;
719 struct stat xbl_partition_stat;
720
721 if (!dev_path) {
722 fprintf(stderr, "%s: Invalid dev_path\n",
723 __func__);
724 r = -1;
725 goto EXIT;
726 }
727 fd = open(dev_path, O_RDWR);
728 if (fd < 0) {
729 fprintf(stderr, "%s: Opening '%s' failed: %s\n",
730 __func__,
731 BLK_DEV_FILE,
732 strerror(errno));
733 r = -1;
734 goto EXIT;
735 }
736 r = gpt_get_state(fd, PRIMARY_GPT, &gpt_prim) ||
737 gpt_get_state(fd, SECONDARY_GPT, &gpt_second);
738 if (r) {
739 fprintf(stderr, "%s: Getting GPT headers state failed\n",
740 __func__);
741 goto EXIT;
742 }
743
744 /* These 2 combinations are unexpected and unacceptable */
745 if (gpt_prim == GPT_BAD_CRC || gpt_second == GPT_BAD_CRC) {
746 fprintf(stderr, "%s: GPT headers CRC corruption detected, aborting\n",
747 __func__);
748 r = -1;
749 goto EXIT;
750 }
751 if (gpt_prim == GPT_BAD_SIGNATURE && gpt_second == GPT_BAD_SIGNATURE) {
752 fprintf(stderr, "%s: Both GPT headers corrupted, aborting\n",
753 __func__);
754 r = -1;
755 goto EXIT;
756 }
757
758 /* Check internal update stage according GPT headers' state */
759 if (gpt_prim == GPT_OK && gpt_second == GPT_OK)
760 internal_stage = UPDATE_MAIN;
761 else if (gpt_prim == GPT_BAD_SIGNATURE)
762 internal_stage = UPDATE_BACKUP;
763 else if (gpt_second == GPT_BAD_SIGNATURE)
764 internal_stage = UPDATE_FINALIZE;
765 else {
766 fprintf(stderr, "%s: Abnormal GPTs state: primary (%d), secondary (%d), "
767 "aborting\n", __func__, gpt_prim, gpt_second);
768 r = -1;
769 goto EXIT;
770 }
771
772 /* Stage already set - ready for update, exitting */
773 if ((int) stage == (int) internal_stage - 1)
774 goto EXIT;
775 /* Unexpected stage given */
776 if (stage != internal_stage) {
777 r = -1;
778 goto EXIT;
779 }
780
781 switch (stage) {
782 case UPDATE_MAIN:
783 if (is_ufs) {
784 if(stat(XBL_PRIMARY, &xbl_partition_stat)||
785 stat(XBL_BACKUP, &xbl_partition_stat)){
786 //Non fatal error. Just means this target does not
787 //use XBL but relies on sbl whose update is handled
788 //by the normal methods.
789 fprintf(stderr, "%s: xbl part not found(%s).Assuming sbl in use\n",
790 __func__,
791 strerror(errno));
792 } else {
793 //Switch the boot lun so that backup boot LUN is used
794 r = gpt_utils_set_xbl_boot_partition(BACKUP_BOOT);
795 if(r){
796 fprintf(stderr, "%s: Failed to set xbl backup partition as boot\n",
797 __func__);
798 goto EXIT;
799 }
800 }
801 }
802 //Fix up the backup GPT table so that it actually points to
803 //the backup copy of the boot critical images
804 fprintf(stderr, "%s: Preparing for primary partition update\n",
805 __func__);
806 r = gpt2_set_boot_chain(fd, BACKUP_BOOT);
807 if (r) {
808 if (r < 0)
809 fprintf(stderr,
810 "%s: Setting secondary GPT to backup boot failed\n",
811 __func__);
812 /* No backup partitions - do not corrupt GPT, do not flag error */
813 else
814 r = 0;
815 goto EXIT;
816 }
817 //corrupt the primary GPT so that the backup(which now points to
818 //the backup boot partitions is used)
819 r = gpt_set_state(fd, PRIMARY_GPT, GPT_BAD_SIGNATURE);
820 if (r) {
821 fprintf(stderr, "%s: Corrupting primary GPT header failed\n",
822 __func__);
823 goto EXIT;
824 }
825 break;
826 case UPDATE_BACKUP:
827 if (is_ufs) {
828 if(stat(XBL_PRIMARY, &xbl_partition_stat)||
829 stat(XBL_BACKUP, &xbl_partition_stat)){
830 //Non fatal error. Just means this target does not
831 //use XBL but relies on sbl whose update is handled
832 //by the normal methods.
833 fprintf(stderr, "%s: xbl part not found(%s).Assuming sbl in use\n",
834 __func__,
835 strerror(errno));
836 } else {
837 //Switch the boot lun so that backup boot LUN is used
838 r = gpt_utils_set_xbl_boot_partition(NORMAL_BOOT);
839 if(r) {
840 fprintf(stderr, "%s: Failed to set xbl backup partition as boot\n",
841 __func__);
842 goto EXIT;
843 }
844 }
845 }
846 //Fix the primary GPT header so that is used
847 fprintf(stderr, "%s: Preparing for backup partition update\n",
848 __func__);
849 r = gpt_set_state(fd, PRIMARY_GPT, GPT_OK);
850 if (r) {
851 fprintf(stderr, "%s: Fixing primary GPT header failed\n",
852 __func__);
853 goto EXIT;
854 }
855 //Corrupt the scondary GPT header
856 r = gpt_set_state(fd, SECONDARY_GPT, GPT_BAD_SIGNATURE);
857 if (r) {
858 fprintf(stderr, "%s: Corrupting secondary GPT header failed\n",
859 __func__);
860 goto EXIT;
861 }
862 break;
863 case UPDATE_FINALIZE:
864 //Undo the changes we had made in the UPDATE_MAIN stage so that the
865 //primary/backup GPT headers once again point to the same set of
866 //partitions
867 fprintf(stderr, "%s: Finalizing partitions\n",
868 __func__);
869 r = gpt2_set_boot_chain(fd, NORMAL_BOOT);
870 if (r < 0) {
871 fprintf(stderr, "%s: Setting secondary GPT to normal boot failed\n",
872 __func__);
873 goto EXIT;
874 }
875
876 r = gpt_set_state(fd, SECONDARY_GPT, GPT_OK);
877 if (r) {
878 fprintf(stderr, "%s: Fixing secondary GPT header failed\n",
879 __func__);
880 goto EXIT;
881 }
882 break;
883 default:;
884 }
885
886EXIT:
887 if (fd >= 0) {
888 fsync(fd);
889 close(fd);
890 }
891 return r;
892}
893
894int add_lun_to_update_list(char *lun_path, struct update_data *dat)
895{
896 uint32_t i = 0;
897 struct stat st;
898 if (!lun_path || !dat){
899 fprintf(stderr, "%s: Invalid data",
900 __func__);
901 return -1;
902 }
903 if (stat(lun_path, &st)) {
904 fprintf(stderr, "%s: Unable to access %s. Skipping adding to list",
905 __func__,
906 lun_path);
907 return -1;
908 }
909 if (dat->num_valid_entries == 0) {
910 fprintf(stderr, "%s: Copying %s into lun_list[%d]\n",
911 __func__,
912 lun_path,
913 i);
914 strlcpy(dat->lun_list[0], lun_path,
915 PATH_MAX * sizeof(char));
916 dat->num_valid_entries = 1;
917 } else {
918 for (i = 0; (i < dat->num_valid_entries) &&
919 (dat->num_valid_entries < MAX_LUNS - 1); i++) {
920 //Check if the current LUN is not already part
921 //of the lun list
922 if (!strncmp(lun_path,dat->lun_list[i],
923 strlen(dat->lun_list[i]))) {
924 //LUN already in list..Return
925 return 0;
926 }
927 }
928 fprintf(stderr, "%s: Copying %s into lun_list[%d]\n",
929 __func__,
930 lun_path,
931 dat->num_valid_entries);
932 //Add LUN path lun list
933 strlcpy(dat->lun_list[dat->num_valid_entries], lun_path,
934 PATH_MAX * sizeof(char));
935 dat->num_valid_entries++;
936 }
937 return 0;
938}
939
940int prepare_boot_update(enum boot_update_stage stage)
941{
942 int is_ufs = gpt_utils_is_ufs_device();
943 struct stat ufs_dir_stat;
944 struct update_data data;
945 int rcode = 0;
946 uint32_t i = 0;
947 int is_error = 0;
948 const char ptn_swap_list[][MAX_GPT_NAME_SIZE] = { PTN_SWAP_LIST };
949 //Holds /dev/block/bootdevice/by-name/*bak entry
950 char buf[PATH_MAX] = {0};
951 //Holds the resolved path of the symlink stored in buf
952 char real_path[PATH_MAX] = {0};
953
954 if (!is_ufs) {
955 //emmc device. Just pass in path to mmcblk0
956 return prepare_partitions(stage, BLK_DEV_FILE);
957 } else {
958 //Now we need to find the list of LUNs over
959 //which the boot critical images are spread
960 //and set them up for failsafe updates.To do
961 //this we find out where the symlinks for the
962 //each of the paths under
963 ///dev/block/bootdevice/by-name/PTN_SWAP_LIST
964 //actually point to.
965 fprintf(stderr, "%s: Running on a UFS device\n",
966 __func__);
967 memset(&data, '\0', sizeof(struct update_data));
968 for (i=0; i < ARRAY_SIZE(ptn_swap_list); i++) {
969 //XBL on UFS does not follow the convention
970 //of being loaded based on well known GUID'S.
971 //We take care of switching the UFS boot LUN
972 //explicitly later on.
Siddeswar Aluganti77993932021-04-14 12:04:04 -0700973 if (!strncmp(ptn_swap_list[i],PTN_XBL,strlen(PTN_XBL))
974 || !strncmp(ptn_swap_list[i],PTN_MULTIIMGOEM,strlen(PTN_MULTIIMGOEM))
975 || !strncmp(ptn_swap_list[i],PTN_MULTIIMGQTI,strlen(PTN_MULTIIMGQTI)))
merothh54856102021-11-04 12:07:41 +0530976 continue;
977 snprintf(buf, sizeof(buf),
978 "%s/%sbak",
979 BOOT_DEV_DIR,
980 ptn_swap_list[i]);
981 if (stat(buf, &ufs_dir_stat)) {
982 continue;
983 }
984 if (readlink(buf, real_path, sizeof(real_path) - 1) < 0)
985 {
986 fprintf(stderr, "%s: readlink error. Skipping %s",
987 __func__,
988 strerror(errno));
989 } else {
990 if(strlen(real_path) < PATH_TRUNCATE_LOC + 1){
991 fprintf(stderr, "Unknown path.Skipping :%s:\n",
992 real_path);
993 } else {
994 real_path[PATH_TRUNCATE_LOC] = '\0';
995 add_lun_to_update_list(real_path, &data);
996 }
997 }
998 memset(buf, '\0', sizeof(buf));
999 memset(real_path, '\0', sizeof(real_path));
1000 }
1001 for (i=0; i < data.num_valid_entries; i++) {
1002 fprintf(stderr, "%s: Preparing %s for update stage %d\n",
1003 __func__,
1004 data.lun_list[i],
1005 stage);
1006 rcode = prepare_partitions(stage, data.lun_list[i]);
1007 if (rcode != 0)
1008 {
1009 fprintf(stderr, "%s: Failed to prepare %s.Continuing..\n",
1010 __func__,
1011 data.lun_list[i]);
1012 is_error = 1;
1013 }
1014 }
1015 }
1016 if (is_error)
1017 return -1;
1018 return 0;
1019}
1020
1021//Given a parttion name(eg: rpm) get the path to the block device that
1022//represents the GPT disk the partition resides on. In the case of emmc it
1023//would be the default emmc dev(/dev/block/mmcblk0). In the case of UFS we look
1024//through the /dev/block/bootdevice/by-name/ tree for partname, and resolve
1025//the path to the LUN from there.
1026static int get_dev_path_from_partition_name(const char *partname,
1027 char *buf,
1028 size_t buflen)
1029{
1030 struct stat st;
1031 char path[PATH_MAX] = {0};
1032 if (!partname || !buf || buflen < ((PATH_TRUNCATE_LOC) + 1)) {
1033 ALOGE("%s: Invalid argument", __func__);
1034 goto error;
1035 }
1036 if (gpt_utils_is_ufs_device()) {
1037 //Need to find the lun that holds partition partname
1038 snprintf(path, sizeof(path),
1039 "%s/%s",
1040 BOOT_DEV_DIR,
1041 partname);
1042 if (stat(path, &st)) {
1043 goto error;
1044 }
1045 if (readlink(path, buf, buflen) < 0)
1046 {
1047 goto error;
1048 } else {
1049 buf[PATH_TRUNCATE_LOC] = '\0';
1050 }
1051 } else {
1052 snprintf(buf, buflen, BLK_DEV_FILE);
1053 }
1054 return 0;
1055
1056error:
1057 return -1;
1058}
1059
1060int gpt_utils_get_partition_map(vector<string>& ptn_list,
1061 map<string, vector<string>>& partition_map) {
1062 char devpath[PATH_MAX] = {'\0'};
1063 map<string, vector<string>>::iterator it;
1064 if (ptn_list.size() < 1) {
1065 fprintf(stderr, "%s: Invalid ptn list\n", __func__);
1066 goto error;
1067 }
1068 //Go through the passed in list
1069 for (uint32_t i = 0; i < ptn_list.size(); i++)
1070 {
1071 //Key in the map is the path to the device that holds the
1072 //partition
1073 if (get_dev_path_from_partition_name(ptn_list[i].c_str(),
1074 devpath,
1075 sizeof(devpath))) {
1076 //Not necessarily an error. The partition may just
1077 //not be present.
1078 continue;
1079 }
1080 string path = devpath;
1081 it = partition_map.find(path);
1082 if (it != partition_map.end()) {
1083 it->second.push_back(ptn_list[i]);
1084 } else {
1085 vector<string> str_vec;
1086 str_vec.push_back( ptn_list[i]);
1087 partition_map.insert(pair<string, vector<string>>
1088 (path, str_vec));
1089 }
1090 memset(devpath, '\0', sizeof(devpath));
1091 }
1092 return 0;
1093error:
1094 return -1;
1095}
1096
1097//Get the block size of the disk represented by decsriptor fd
1098static uint32_t gpt_get_block_size(int fd)
1099{
1100 uint32_t block_size = 0;
1101 if (fd < 0) {
1102 ALOGE("%s: invalid descriptor",
1103 __func__);
1104 goto error;
1105 }
1106 if (ioctl(fd, BLKSSZGET, &block_size) != 0) {
1107 ALOGE("%s: Failed to get GPT dev block size : %s",
1108 __func__,
1109 strerror(errno));
1110 goto error;
1111 }
1112 return block_size;
1113error:
1114 return 0;
1115}
1116
1117//Write the GPT header present in the passed in buffer back to the
1118//disk represented by fd
1119static int gpt_set_header(uint8_t *gpt_header, int fd,
1120 enum gpt_instance instance)
1121{
1122 uint32_t block_size = 0;
1123 off64_t gpt_header_offset = 0;
1124 if (!gpt_header || fd < 0) {
1125 ALOGE("%s: Invalid arguments",
1126 __func__);
1127 goto error;
1128 }
1129 block_size = gpt_get_block_size(fd);
1130 if (block_size == 0) {
1131 ALOGE("%s: Failed to get block size", __func__);
1132 goto error;
1133 }
1134 if (instance == PRIMARY_GPT)
1135 gpt_header_offset = block_size;
1136 else
1137 gpt_header_offset = lseek64(fd, 0, SEEK_END) - block_size;
1138 if (gpt_header_offset <= 0) {
1139 ALOGE("%s: Failed to get gpt header offset",__func__);
1140 goto error;
1141 }
1142 if (blk_rw(fd, 1, gpt_header_offset, gpt_header, block_size)) {
1143 ALOGE("%s: Failed to write back GPT header", __func__);
1144 goto error;
1145 }
1146 return 0;
1147error:
1148 return -1;
1149}
1150
1151//Read out the GPT header for the disk that contains the partition partname
1152static uint8_t* gpt_get_header(const char *partname, enum gpt_instance instance)
1153{
1154 uint8_t* hdr = NULL;
1155 char devpath[PATH_MAX] = {0};
1156 int64_t hdr_offset = 0;
1157 uint32_t block_size = 0;
1158 int fd = -1;
1159 if (!partname) {
1160 ALOGE("%s: Invalid partition name", __func__);
1161 goto error;
1162 }
1163 if (get_dev_path_from_partition_name(partname, devpath, sizeof(devpath))
1164 != 0) {
1165 ALOGE("%s: Failed to resolve path for %s",
1166 __func__,
1167 partname);
1168 goto error;
1169 }
1170 fd = open(devpath, O_RDWR);
1171 if (fd < 0) {
1172 ALOGE("%s: Failed to open %s : %s",
1173 __func__,
1174 devpath,
1175 strerror(errno));
1176 goto error;
1177 }
1178 block_size = gpt_get_block_size(fd);
1179 if (block_size == 0)
1180 {
1181 ALOGE("%s: Failed to get gpt block size for %s",
1182 __func__,
1183 partname);
1184 goto error;
1185 }
1186
1187 hdr = (uint8_t*)malloc(block_size);
1188 if (!hdr) {
1189 ALOGE("%s: Failed to allocate memory for gpt header",
1190 __func__);
1191 }
1192 if (instance == PRIMARY_GPT)
1193 hdr_offset = block_size;
1194 else {
1195 hdr_offset = lseek64(fd, 0, SEEK_END) - block_size;
1196 }
1197 if (hdr_offset < 0) {
1198 ALOGE("%s: Failed to get gpt header offset",
1199 __func__);
1200 goto error;
1201 }
1202 if (blk_rw(fd, 0, hdr_offset, hdr, block_size)) {
1203 ALOGE("%s: Failed to read GPT header from device",
1204 __func__);
1205 goto error;
1206 }
1207 close(fd);
1208 return hdr;
1209error:
1210 if (fd >= 0)
1211 close(fd);
1212 if (hdr)
1213 free(hdr);
1214 return NULL;
1215}
1216
1217//Returns the partition entry array based on the
1218//passed in buffer which contains the gpt header.
1219//The fd here is the descriptor for the 'disk' which
1220//holds the partition
1221static uint8_t* gpt_get_pentry_arr(uint8_t *hdr, int fd)
1222{
1223 uint64_t pentries_start = 0;
1224 uint32_t pentry_size = 0;
1225 uint32_t block_size = 0;
1226 uint32_t pentries_arr_size = 0;
1227 uint8_t *pentry_arr = NULL;
1228 int rc = 0;
1229 if (!hdr) {
1230 ALOGE("%s: Invalid header", __func__);
1231 goto error;
1232 }
1233 if (fd < 0) {
1234 ALOGE("%s: Invalid fd", __func__);
1235 goto error;
1236 }
1237 block_size = gpt_get_block_size(fd);
1238 if (!block_size) {
1239 ALOGE("%s: Failed to get gpt block size for",
1240 __func__);
1241 goto error;
1242 }
1243 pentries_start = GET_8_BYTES(hdr + PENTRIES_OFFSET) * block_size;
1244 pentry_size = GET_4_BYTES(hdr + PENTRY_SIZE_OFFSET);
1245 pentries_arr_size =
1246 GET_4_BYTES(hdr + PARTITION_COUNT_OFFSET) * pentry_size;
1247 pentry_arr = (uint8_t*)calloc(1, pentries_arr_size);
1248 if (!pentry_arr) {
1249 ALOGE("%s: Failed to allocate memory for partition array",
1250 __func__);
1251 goto error;
1252 }
1253 rc = blk_rw(fd, 0,
1254 pentries_start,
1255 pentry_arr,
1256 pentries_arr_size);
1257 if (rc) {
1258 ALOGE("%s: Failed to read partition entry array",
1259 __func__);
1260 goto error;
1261 }
1262 return pentry_arr;
1263error:
1264 if (pentry_arr)
1265 free(pentry_arr);
1266 return NULL;
1267}
1268
1269static int gpt_set_pentry_arr(uint8_t *hdr, int fd, uint8_t* arr)
1270{
1271 uint32_t block_size = 0;
1272 uint64_t pentries_start = 0;
1273 uint32_t pentry_size = 0;
1274 uint32_t pentries_arr_size = 0;
1275 int rc = 0;
1276 if (!hdr || fd < 0 || !arr) {
1277 ALOGE("%s: Invalid argument", __func__);
1278 goto error;
1279 }
1280 block_size = gpt_get_block_size(fd);
1281 if (!block_size) {
1282 ALOGE("%s: Failed to get gpt block size for",
1283 __func__);
1284 goto error;
1285 }
1286 pentries_start = GET_8_BYTES(hdr + PENTRIES_OFFSET) * block_size;
1287 pentry_size = GET_4_BYTES(hdr + PENTRY_SIZE_OFFSET);
1288 pentries_arr_size =
1289 GET_4_BYTES(hdr + PARTITION_COUNT_OFFSET) * pentry_size;
1290 rc = blk_rw(fd, 1,
1291 pentries_start,
1292 arr,
1293 pentries_arr_size);
1294 if (rc) {
1295 ALOGE("%s: Failed to read partition entry array",
1296 __func__);
1297 goto error;
1298 }
1299 return 0;
1300error:
1301 return -1;
1302}
1303
1304
1305
1306//Allocate a handle used by calls to the "gpt_disk" api's
1307struct gpt_disk * gpt_disk_alloc()
1308{
1309 struct gpt_disk *disk;
1310 disk = (struct gpt_disk *)malloc(sizeof(struct gpt_disk));
1311 if (!disk) {
1312 ALOGE("%s: Failed to allocate memory", __func__);
1313 goto end;
1314 }
1315 memset(disk, 0, sizeof(struct gpt_disk));
1316end:
1317 return disk;
1318}
1319
1320//Free previously allocated/initialized handle
1321void gpt_disk_free(struct gpt_disk *disk)
1322{
1323 if (!disk)
1324 return;
1325 if (disk->hdr)
1326 free(disk->hdr);
1327 if (disk->hdr_bak)
1328 free(disk->hdr_bak);
1329 if (disk->pentry_arr)
1330 free(disk->pentry_arr);
1331 if (disk->pentry_arr_bak)
1332 free(disk->pentry_arr_bak);
1333 free(disk);
1334 return;
1335}
1336
1337//fills up the passed in gpt_disk struct with information about the
1338//disk represented by path dev. Returns 0 on success and -1 on error.
1339int gpt_disk_get_disk_info(const char *dev, struct gpt_disk *dsk)
1340{
1341
1342 struct gpt_disk *disk = NULL;
1343 int fd = -1;
1344 uint32_t gpt_header_size = 0;
1345 uint32_t crc_zero;
1346
1347 crc_zero = crc32(0L, Z_NULL, 0);
1348 if (!dsk || !dev) {
1349 ALOGE("%s: Invalid arguments", __func__);
1350 goto error;
1351 }
1352 disk = dsk;
1353 disk->hdr = gpt_get_header(dev, PRIMARY_GPT);
1354 if (!disk->hdr) {
1355 ALOGE("%s: Failed to get primary header", __func__);
1356 goto error;
1357 }
1358 gpt_header_size = GET_4_BYTES(disk->hdr + HEADER_SIZE_OFFSET);
1359 disk->hdr_crc = crc32(crc_zero, disk->hdr, gpt_header_size);
1360 disk->hdr_bak = gpt_get_header(dev, SECONDARY_GPT);
1361 if (!disk->hdr_bak) {
1362 ALOGE("%s: Failed to get backup header", __func__);
1363 goto error;
1364 }
1365 disk->hdr_bak_crc = crc32(crc_zero, disk->hdr_bak, gpt_header_size);
1366
1367 //Descriptor for the block device. We will use this for further
1368 //modifications to the partition table
1369 if (get_dev_path_from_partition_name(dev,
1370 disk->devpath,
1371 sizeof(disk->devpath)) != 0) {
1372 ALOGE("%s: Failed to resolve path for %s",
1373 __func__,
1374 dev);
1375 goto error;
1376 }
1377 fd = open(disk->devpath, O_RDWR);
1378 if (fd < 0) {
1379 ALOGE("%s: Failed to open %s: %s",
1380 __func__,
1381 disk->devpath,
1382 strerror(errno));
1383 goto error;
1384 }
1385 disk->pentry_arr = gpt_get_pentry_arr(disk->hdr, fd);
1386 if (!disk->pentry_arr) {
1387 ALOGE("%s: Failed to obtain partition entry array",
1388 __func__);
1389 goto error;
1390 }
1391 disk->pentry_arr_bak = gpt_get_pentry_arr(disk->hdr_bak, fd);
1392 if (!disk->pentry_arr_bak) {
1393 ALOGE("%s: Failed to obtain backup partition entry array",
1394 __func__);
1395 goto error;
1396 }
1397 disk->pentry_size = GET_4_BYTES(disk->hdr + PENTRY_SIZE_OFFSET);
1398 disk->pentry_arr_size =
1399 GET_4_BYTES(disk->hdr + PARTITION_COUNT_OFFSET) *
1400 disk->pentry_size;
1401 disk->pentry_arr_crc = GET_4_BYTES(disk->hdr + PARTITION_CRC_OFFSET);
1402 disk->pentry_arr_bak_crc = GET_4_BYTES(disk->hdr_bak +
1403 PARTITION_CRC_OFFSET);
1404 disk->block_size = gpt_get_block_size(fd);
1405 close(fd);
1406 disk->is_initialized = GPT_DISK_INIT_MAGIC;
1407 return 0;
1408error:
1409 if (fd >= 0)
1410 close(fd);
1411 return -1;
1412}
1413
1414//Get pointer to partition entry from a allocated gpt_disk structure
1415uint8_t* gpt_disk_get_pentry(struct gpt_disk *disk,
1416 const char *partname,
1417 enum gpt_instance instance)
1418{
1419 uint8_t *ptn_arr = NULL;
1420 if (!disk || !partname || disk->is_initialized != GPT_DISK_INIT_MAGIC) {
1421 ALOGE("%s: Invalid argument",__func__);
1422 goto error;
1423 }
1424 ptn_arr = (instance == PRIMARY_GPT) ?
1425 disk->pentry_arr : disk->pentry_arr_bak;
1426 return (gpt_pentry_seek(partname, ptn_arr,
1427 ptn_arr + disk->pentry_arr_size ,
1428 disk->pentry_size));
1429error:
1430 return NULL;
1431}
1432
1433//Update CRC values for the various components of the gpt_disk
1434//structure. This function should be called after any of the fields
1435//have been updated before the structure contents are written back to
1436//disk.
1437int gpt_disk_update_crc(struct gpt_disk *disk)
1438{
1439 uint32_t gpt_header_size = 0;
1440 uint32_t crc_zero;
1441 crc_zero = crc32(0L, Z_NULL, 0);
1442 if (!disk || (disk->is_initialized != GPT_DISK_INIT_MAGIC)) {
1443 ALOGE("%s: invalid argument", __func__);
1444 goto error;
1445 }
1446 //Recalculate the CRC of the primary partiton array
1447 disk->pentry_arr_crc = crc32(crc_zero,
1448 disk->pentry_arr,
1449 disk->pentry_arr_size);
1450 //Recalculate the CRC of the backup partition array
1451 disk->pentry_arr_bak_crc = crc32(crc_zero,
1452 disk->pentry_arr_bak,
1453 disk->pentry_arr_size);
1454 //Update the partition CRC value in the primary GPT header
1455 PUT_4_BYTES(disk->hdr + PARTITION_CRC_OFFSET, disk->pentry_arr_crc);
1456 //Update the partition CRC value in the backup GPT header
1457 PUT_4_BYTES(disk->hdr_bak + PARTITION_CRC_OFFSET,
1458 disk->pentry_arr_bak_crc);
1459 //Update the CRC value of the primary header
1460 gpt_header_size = GET_4_BYTES(disk->hdr + HEADER_SIZE_OFFSET);
1461 //Header CRC is calculated with its own CRC field set to 0
1462 PUT_4_BYTES(disk->hdr + HEADER_CRC_OFFSET, 0);
1463 PUT_4_BYTES(disk->hdr_bak + HEADER_CRC_OFFSET, 0);
1464 disk->hdr_crc = crc32(crc_zero, disk->hdr, gpt_header_size);
1465 disk->hdr_bak_crc = crc32(crc_zero, disk->hdr_bak, gpt_header_size);
1466 PUT_4_BYTES(disk->hdr + HEADER_CRC_OFFSET, disk->hdr_crc);
1467 PUT_4_BYTES(disk->hdr_bak + HEADER_CRC_OFFSET, disk->hdr_bak_crc);
1468 return 0;
1469error:
1470 return -1;
1471}
1472
1473//Write the contents of struct gpt_disk back to the actual disk
1474int gpt_disk_commit(struct gpt_disk *disk)
1475{
1476 int fd = -1;
1477 if (!disk || (disk->is_initialized != GPT_DISK_INIT_MAGIC)){
1478 ALOGE("%s: Invalid args", __func__);
1479 goto error;
1480 }
Benergy Meenan Ravuric378f222021-07-12 23:27:12 +05301481 fd = open(disk->devpath, O_RDWR | O_DSYNC);
merothh54856102021-11-04 12:07:41 +05301482 if (fd < 0) {
1483 ALOGE("%s: Failed to open %s: %s",
1484 __func__,
1485 disk->devpath,
1486 strerror(errno));
1487 goto error;
1488 }
1489 //Write the primary header
1490 if(gpt_set_header(disk->hdr, fd, PRIMARY_GPT) != 0) {
1491 ALOGE("%s: Failed to update primary GPT header",
1492 __func__);
1493 goto error;
1494 }
1495 //Write back the primary partition array
1496 if (gpt_set_pentry_arr(disk->hdr, fd, disk->pentry_arr)) {
1497 ALOGE("%s: Failed to write primary GPT partition arr",
1498 __func__);
1499 goto error;
1500 }
1501 //Write back the secondary header
1502 if(gpt_set_header(disk->hdr_bak, fd, SECONDARY_GPT) != 0) {
1503 ALOGE("%s: Failed to update secondary GPT header",
1504 __func__);
1505 goto error;
1506 }
1507 //Write back the secondary partition array
1508 if (gpt_set_pentry_arr(disk->hdr_bak, fd, disk->pentry_arr_bak)) {
1509 ALOGE("%s: Failed to write secondary GPT partition arr",
1510 __func__);
1511 goto error;
1512 }
Benergy Meenan Ravuric378f222021-07-12 23:27:12 +05301513 fsync(fd);
merothh54856102021-11-04 12:07:41 +05301514 close(fd);
1515 return 0;
1516error:
1517 if (fd >= 0)
1518 close(fd);
1519 return -1;
1520}