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