| /* |
| * Copyright (C) 2015 Hardkernel Co,. Ltd |
| * Dongjin Kim <tobetter@gmail.com> |
| * |
| * SPDX-License-Identifier: GPL-2.0+ |
| */ |
| |
| #include <common.h> |
| #include <linux/sizes.h> |
| #include <linux/string.h> |
| #include <usb/fastboot.h> |
| |
| /* FIXME: Is block size always 512? */ |
| #define bytes_to_lba(x) ((x) / 512) |
| #define gbytes_to_lba(x) ((x) * 1024 * 1024 * 2) |
| |
| #define SZ_RESERVED (48 * SZ_1K + 512) /* BL1 + MBR */ |
| #define SZ_BOOTLOADER (720 * SZ_1K) |
| #define SZ_BOOTMESSAGE (4 * SZ_1K) |
| |
| static struct fbt_partition { |
| const char *name; |
| lbaint_t lba; |
| } partitions[] = { |
| { |
| .name = "-reserved", |
| .lba = bytes_to_lba(SZ_RESERVED) |
| }, { |
| .name = "bootloader", |
| .lba = bytes_to_lba(SZ_BOOTLOADER |
| - (SZ_RESERVED + SZ_BOOTMESSAGE)) |
| }, { |
| .name = "bcb", /* Bootloader control block */ |
| .lba = bytes_to_lba(SZ_BOOTMESSAGE) |
| }, { |
| .name = "env", /* "environment" */ |
| .lba = bytes_to_lba(CONFIG_ENV_SIZE) |
| }, { |
| .name = "dtb", /* Device Tree */ |
| .lba = bytes_to_lba(SZ_64K) |
| }, { |
| .name = "boot", /* Boot image */ |
| .lba = bytes_to_lba(16 * SZ_1M) |
| }, { |
| .name = "recovery", /* Recovery Image */ |
| .lba = bytes_to_lba(12 * SZ_1M) |
| }, { |
| .name = "logo", /* Logo */ |
| .lba = bytes_to_lba(2 * SZ_1M) |
| } |
| }; |
| |
| static struct dos_partition { |
| const char *name; |
| int part; |
| u8 type; |
| lbaint_t lba; |
| } dos_partitions[] = { |
| { |
| .name = "cache", |
| .part = 2, |
| .type = 0x83, |
| .lba = bytes_to_lba(512 * SZ_1M), |
| }, { |
| .name = "system", |
| .part = 3, |
| .type = 0x83, |
| .lba = gbytes_to_lba(1), |
| }, { |
| .name = "userdata", |
| .part = 4, |
| .type = 0x83, |
| .lba = gbytes_to_lba(3), |
| }, { |
| .name = "vfat", |
| .part = 1, |
| .type = 0x0c, |
| .lba = -1, |
| }, |
| }; |
| |
| static int n = 0; |
| |
| static int valid_partition_number(int part) |
| { |
| return (1 <= part) && (part <= ARRAY_SIZE(dos_partitions)); |
| } |
| |
| /* |
| * Initiate dos partition index and return the first sector (lba) |
| */ |
| lbaint_t board_dos_partition_start(void) |
| { |
| int n; |
| lbaint_t next = 0; |
| |
| for (n = 0 ; n < ARRAY_SIZE(partitions); n++) |
| next += partitions[n].lba; |
| |
| return next; |
| } |
| |
| /* |
| * Get the partition detail, partition number and its type, as well as |
| * return the number of sectors to allocate for the partition. |
| */ |
| lbaint_t board_dos_partition_next(int *part, u8 *type) |
| { |
| if (!valid_partition_number(n + 1)) |
| return 0; |
| |
| struct dos_partition *p = &dos_partitions[n++]; |
| |
| *part = p->part; /* partition number */ |
| *type = p->type; /* partition type */ |
| |
| /* Use remained sectors for this partition */ |
| if (p->lba == -1) |
| return -1; |
| |
| return p->lba; |
| } |
| |
| /* |
| * Return the partition name of given partiton number. Since DOS partition |
| * does not support name on its parition table, the partition names are |
| * predefined upon each partition number. |
| */ |
| char *board_dos_partition_name(int part, char* name) |
| { |
| int i; |
| |
| if (!valid_partition_number(part)) |
| return NULL; |
| |
| for (i = 0; i < ARRAY_SIZE(dos_partitions); i++) { |
| /* Partition number is same with given to seek */ |
| if (dos_partitions[i].part == part) { |
| strcpy(name, dos_partitions[i].name); |
| return name; |
| } |
| } |
| |
| return NULL; |
| } |
| |
| /* |
| * Initiate the fastboot partition entries with internal system partitions and |
| * DOS partition table. |
| */ |
| int board_partition_init(void) |
| { |
| struct mmc *mmc; |
| fastboot_ptentry ptn; |
| lbaint_t next = 0; |
| lbaint_t len; |
| int n = 0; |
| |
| fastboot_flash_reset_ptn(); |
| |
| mmc = find_mmc_device(CONFIG_FASTBOOT_FLASH_MMC_DEV); |
| |
| for (n = 0 ; mmc && n < ARRAY_SIZE(partitions); n++) { |
| len = partitions[n].lba; |
| |
| /* Skip to add the partition if start with '-', but move forward |
| * to next position as much as its size |
| */ |
| if (partitions[n].name[0] == '-') { |
| next += len; |
| continue; |
| } |
| |
| /* 'env' partition contains U-boot's environment fields, it |
| * could be damaged by fastboot if its offset is invalid with |
| * defined by CONFIG_ENV_OFFSET. |
| */ |
| if (!strcmp(partitions[n].name, "env") && |
| (bytes_to_lba(CONFIG_ENV_OFFSET) != next)) { |
| printf("WARNING!!: Invalid offset of 'env' partition," |
| " it must be " LBAFU " but " LBAFU "\n", |
| next, (lbaint_t)bytes_to_lba(CONFIG_ENV_OFFSET)); |
| } |
| |
| if (len == 0) |
| len = mmc->block_dev.lba - next; |
| |
| strncpy((char*)&ptn.name, partitions[n].name, sizeof(ptn.name)); |
| |
| ptn.start = next; |
| ptn.length = len; |
| |
| /* Add the partition to fastboot partition entry table */ |
| fastboot_flash_add_ptn(&ptn); |
| |
| next += len; |
| } |
| |
| fastboot_load_dos_partition(); |
| |
| return 0; |
| } |
| |
| int board_fastboot_pre_flash(block_dev_desc_t *dev_desc, lbaint_t start, |
| void *buffer) |
| { |
| if (start == 0) { |
| /* MUST be trying to modify MBR, hence at least DOS partition |
| * table have to be kept. So buffer to flashing will be |
| * overwritten with exist partition table. |
| */ |
| u8 mbr[512]; |
| |
| if (dev_desc->block_read(dev_desc->dev, start, 1, mbr) != 1) { |
| printf("fastboot: can't read MBR from device %d\n", |
| dev_desc->dev); |
| return -EIO; |
| } |
| |
| memcpy(buffer + 0x1be, &mbr[0x1be], 512 - 0x1be); |
| } |
| |
| return 0; |
| } |