727 lines
22 KiB
C
727 lines
22 KiB
C
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
|
|
/*
|
|
* common/cmd_dynamic.c
|
|
*
|
|
* Copyright (C) 2020 Amlogic, Inc. All rights reserved.
|
|
*
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <command.h>
|
|
#include <environment.h>
|
|
#include <malloc.h>
|
|
#include <asm/byteorder.h>
|
|
#include <config.h>
|
|
#include <asm/arch/io.h>
|
|
#include <emmc_partitions.h>
|
|
#include <partition_table.h>
|
|
#include <version.h>
|
|
|
|
#ifdef CONFIG_BOOTLOADER_CONTROL_BLOCK
|
|
extern int store_read_ops(
|
|
unsigned char *partition_name,
|
|
unsigned char *buf, uint64_t off, uint64_t size);
|
|
extern int store_write_ops(
|
|
unsigned char *partition_name,
|
|
unsigned char *buf, uint64_t off, uint64_t size);
|
|
|
|
/* Magic signature for LpMetadataGeometry. */
|
|
#define LP_METADATA_GEOMETRY_MAGIC 0x616c4467
|
|
|
|
/* Space reserved for geometry information. */
|
|
#define LP_METADATA_GEOMETRY_SIZE 4096
|
|
|
|
#define LP_METADATA_HEADER_SIZE 124
|
|
|
|
#define SUPERBUF_SIZE 16384
|
|
|
|
/* Magic signature for LpMetadataHeader. */
|
|
#define LP_METADATA_HEADER_MAGIC 0x414C5030
|
|
|
|
/* Current metadata version. */
|
|
#define LP_METADATA_MAJOR_VERSION 10
|
|
#define LP_METADATA_MINOR_VERSION_MIN 0
|
|
#define LP_METADATA_MINOR_VERSION_MAX 2
|
|
|
|
/* Metadata version needed to use the UPDATED partition attribute. */
|
|
#define LP_METADATA_VERSION_FOR_UPDATED_ATTR 1
|
|
|
|
/* Metadata version needed for the new expanded header struct. */
|
|
#define LP_METADATA_VERSION_FOR_EXPANDED_HEADER 2
|
|
|
|
/* Attributes for the LpMetadataPartition::attributes field.
|
|
*
|
|
* READONLY - The partition should not be considered writable. When used with
|
|
* device mapper, the block device will be created as read-only.
|
|
*/
|
|
#define LP_PARTITION_ATTR_NONE 0x0
|
|
#define LP_PARTITION_ATTR_READONLY (1 << 0)
|
|
|
|
/* This flag is only intended to be used with super_empty.img and super.img on
|
|
* retrofit devices. On these devices there are A and B super partitions, and
|
|
* we don't know ahead of time which slot the image will be applied to.
|
|
*
|
|
* If set, the partition name needs a slot suffix applied. The slot suffix is
|
|
* determined by the metadata slot number (0 = _a, 1 = _b).
|
|
*/
|
|
#define LP_PARTITION_ATTR_SLOT_SUFFIXED (1 << 1)
|
|
|
|
/* This flag is applied automatically when using MetadataBuilder::NewForUpdate.
|
|
* It signals that the partition was created (or modified) for a snapshot-based
|
|
* update. If this flag is not present, the partition was likely flashed via
|
|
* fastboot.
|
|
*/
|
|
#define LP_PARTITION_ATTR_UPDATED (1 << 2)
|
|
|
|
/* This flag marks a partition as disabled. It should not be used or mapped. */
|
|
#define LP_PARTITION_ATTR_DISABLED (1 << 3)
|
|
|
|
/* Mask that defines all valid attributes. When changing this, make sure to
|
|
* update ParseMetadata().
|
|
*/
|
|
#define LP_PARTITION_ATTRIBUTE_MASK_V0 \
|
|
(LP_PARTITION_ATTR_READONLY | LP_PARTITION_ATTR_SLOT_SUFFIXED)
|
|
#define LP_PARTITION_ATTRIBUTE_MASK_V1 (LP_PARTITION_ATTR_UPDATED | LP_PARTITION_ATTR_DISABLED)
|
|
#define LP_PARTITION_ATTRIBUTE_MASK \
|
|
(LP_PARTITION_ATTRIBUTE_MASK_V0 | LP_PARTITION_ATTRIBUTE_MASK_V1)
|
|
|
|
/* Default name of the physical partition that holds logical partition entries.
|
|
* The layout of this partition will look like:
|
|
*
|
|
* +--------------------+
|
|
* | Disk Geometry |
|
|
* +--------------------+
|
|
* | Geometry Backup |
|
|
* +--------------------+
|
|
* | Metadata |
|
|
* +--------------------+
|
|
* | Backup Metadata |
|
|
* +--------------------+
|
|
* | Logical Partitions |
|
|
* +--------------------+
|
|
*/
|
|
#define LP_METADATA_DEFAULT_PARTITION_NAME "super"
|
|
|
|
/* Size of a sector is always 512 bytes for compatibility with the Linux kernel. */
|
|
#define LP_SECTOR_SIZE 512
|
|
|
|
/* Amount of space reserved at the start of every super partition to avoid
|
|
* creating an accidental boot sector.
|
|
*/
|
|
#define LP_PARTITION_RESERVED_BYTES 4096
|
|
|
|
/* This structure is stored at block 0 in the first 4096 bytes of the
|
|
* partition, and again in the following block. It is never modified and
|
|
* describes how logical partition information can be located.
|
|
*/
|
|
typedef struct LpMetadataGeometry {
|
|
/* 0: Magic signature (LP_METADATA_GEOMETRY_MAGIC). */
|
|
u32 magic;
|
|
|
|
/* 4: Size of the LpMetadataGeometry struct. */
|
|
u32 struct_size;
|
|
|
|
/* 8: SHA256 checksum of this struct, with this field set to 0. */
|
|
u8 checksum[32];
|
|
|
|
/* 40: Maximum amount of space a single copy of the metadata can use. This
|
|
* must be a multiple of LP_SECTOR_SIZE.
|
|
*/
|
|
u32 metadata_max_size;
|
|
|
|
/* 44: Number of copies of the metadata to keep. For A/B devices, this
|
|
* will be 2. For an A/B/C device, it would be 3, et cetera. For Non-A/B
|
|
* it will be 1. A backup copy of each slot is kept, so if this is "2",
|
|
* there will be four copies total.
|
|
*/
|
|
u32 metadata_slot_count;
|
|
|
|
/* 48: Logical block size. This is the minimal alignment for partition and
|
|
* extent sizes, and it must be a multiple of LP_SECTOR_SIZE. Note that
|
|
* this must be equal across all LUNs that comprise the super partition,
|
|
* and thus this field is stored in the geometry, not per-device.
|
|
*/
|
|
u32 logical_block_size;
|
|
} __attribute__((packed)) LpMetadataGeometry;
|
|
|
|
/* The logical partition metadata has a number of tables; they are described
|
|
* in the header via the following structure.
|
|
*
|
|
* The size of the table can be computed by multiplying entry_size by
|
|
* num_entries, and the result must not overflow a 32-bit signed integer.
|
|
*/
|
|
typedef struct LpMetadataTableDescriptor {
|
|
/* 0: Location of the table, relative to end of the metadata header. */
|
|
u32 offset;
|
|
/* 4: Number of entries in the table. */
|
|
u32 num_entries;
|
|
/* 8: Size of each entry in the table, in bytes. */
|
|
u32 entry_size;
|
|
} __attribute__((packed)) LpMetadataTableDescriptor;
|
|
|
|
/* Binary format for the header of the logical partition metadata format.
|
|
*
|
|
* The format has three sections. The header must occur first, and the
|
|
* proceeding tables may be placed in any order after.
|
|
*
|
|
* +-----------------------------------------+
|
|
* | Header data - fixed size |
|
|
* +-----------------------------------------+
|
|
* | Partition table - variable size |
|
|
* +-----------------------------------------+
|
|
* | Partition table extents - variable size |
|
|
* +-----------------------------------------+
|
|
*
|
|
* The "Header" portion is described by LpMetadataHeader. It will always
|
|
* precede the other three blocks.
|
|
*
|
|
* All fields are stored in little-endian byte order when serialized.
|
|
*
|
|
* This struct is versioned; see the |major_version| and |minor_version|
|
|
* fields.
|
|
*/
|
|
typedef struct LpMetadataHeader {
|
|
/* 0: Four bytes equal to LP_METADATA_HEADER_MAGIC. */
|
|
u32 magic;
|
|
|
|
/* 4: Version number required to read this metadata. If the version is not
|
|
* equal to the library version, the metadata should be considered
|
|
* incompatible.
|
|
*/
|
|
u16 major_version;
|
|
|
|
/* 6: Minor version. A library supporting newer features should be able to
|
|
* read metadata with an older minor version. However, an older library
|
|
* should not support reading metadata if its minor version is higher.
|
|
*/
|
|
u16 minor_version;
|
|
|
|
/* 8: The size of this header struct. */
|
|
u32 header_size;
|
|
|
|
/* 12: SHA256 checksum of the header, up to |header_size| bytes, computed as
|
|
* if this field were set to 0.
|
|
*/
|
|
u8 header_checksum[32];
|
|
|
|
/* 44: The total size of all tables. This size is contiguous; tables may not
|
|
* have gaps in between, and they immediately follow the header.
|
|
*/
|
|
u32 tables_size;
|
|
|
|
/* 48: SHA256 checksum of all table contents. */
|
|
u8 tables_checksum[32];
|
|
|
|
/* 80: Partition table descriptor. */
|
|
LpMetadataTableDescriptor partitions;
|
|
/* 92: Extent table descriptor. */
|
|
LpMetadataTableDescriptor extents;
|
|
/* 104: Updateable group descriptor. */
|
|
LpMetadataTableDescriptor groups;
|
|
/* 116: Block device table. */
|
|
LpMetadataTableDescriptor block_devices;
|
|
|
|
/* Everything past here is header version 1.2+, and is only included if
|
|
* needed. When liblp supporting >= 1.2 reads a < 1.2 header, it must
|
|
* zero these additional fields.
|
|
*/
|
|
|
|
/* 128: See LP_HEADER_FLAG_ constants for possible values. Header flags are
|
|
* independent of the version number and intended to be informational only.
|
|
* New flags can be added without bumping the version.
|
|
*/
|
|
u32 flags;
|
|
|
|
/* 132: Reserved (zero), pad to 256 bytes. */
|
|
u8 reserved[124];
|
|
} __attribute__((packed)) LpMetadataHeader;
|
|
|
|
/* This device uses Virtual A/B. Note that on retrofit devices, the expanded
|
|
* header may not be present.
|
|
*/
|
|
#define LP_HEADER_FLAG_VIRTUAL_AB_DEVICE 0x1
|
|
|
|
/* This struct defines a logical partition entry, similar to what would be
|
|
* present in a GUID Partition Table.
|
|
*/
|
|
typedef struct LpMetadataPartition {
|
|
/* 0: Name of this partition in ASCII characters. Any unused characters in
|
|
* the buffer must be set to 0. Characters may only be alphanumeric or _.
|
|
* The name must include at least one ASCII character, and it must be unique
|
|
* across all partition names. The length (36) is the same as the maximum
|
|
* length of a GPT partition name.
|
|
*/
|
|
char name[36];
|
|
|
|
/* 36: Attributes for the partition (see LP_PARTITION_ATTR_* flags above). */
|
|
u32 attributes;
|
|
|
|
/* 40: Index of the first extent owned by this partition. The extent will
|
|
* start at logical sector 0. Gaps between extents are not allowed.
|
|
*/
|
|
u32 first_extent_index;
|
|
|
|
/* 44: Number of extents in the partition. Every partition must have at
|
|
* least one extent.
|
|
*/
|
|
u32 num_extents;
|
|
|
|
/* 48: Group this partition belongs to. */
|
|
u32 group_index;
|
|
} __attribute__((packed)) LpMetadataPartition;
|
|
|
|
/* This extent is a dm-linear target, and the index is an index into the
|
|
* LinearExtent table.
|
|
*/
|
|
#define LP_TARGET_TYPE_LINEAR 0
|
|
|
|
/* This extent is a dm-zero target. The index is ignored and must be 0. */
|
|
#define LP_TARGET_TYPE_ZERO 1
|
|
|
|
/* This struct defines an extent entry in the extent table block. */
|
|
typedef struct LpMetadataExtent {
|
|
/* 0: Length of this extent, in 512-byte sectors. */
|
|
u64 num_sectors;
|
|
|
|
/* 8: Target type for device-mapper (see LP_TARGET_TYPE_* values). */
|
|
u32 target_type;
|
|
|
|
/* 12: Contents depends on target_type.
|
|
*
|
|
* LINEAR: The sector on the physical partition that this extent maps onto.
|
|
* ZERO: This field must be 0.
|
|
*/
|
|
u64 target_data;
|
|
|
|
/* 20: Contents depends on target_type.
|
|
*
|
|
* LINEAR: Must be an index into the block devices table.
|
|
* ZERO: This field must be 0.
|
|
*/
|
|
u32 target_source;
|
|
} __attribute__((packed)) LpMetadataExtent;
|
|
|
|
/* This struct defines an entry in the groups table. Each group has a maximum
|
|
* size, and partitions in a group must not exceed that size. There is always
|
|
* a "default" group of unlimited size, which is used when not using update
|
|
* groups or when using overlayfs or fastbootd.
|
|
*/
|
|
typedef struct LpMetadataPartitionGroup {
|
|
/* 0: Name of this group. Any unused characters must be 0. */
|
|
char name[36];
|
|
|
|
/* 36: Flags (see LP_GROUP_*). */
|
|
u32 flags;
|
|
|
|
/* 40: Maximum size in bytes. If 0, the group has no maximum size. */
|
|
u64 maximum_size;
|
|
} __attribute__((packed)) LpMetadataPartitionGroup;
|
|
|
|
/* This flag is only intended to be used with super_empty.img and super.img on
|
|
* retrofit devices. If set, the group needs a slot suffix to be interpreted
|
|
* correctly. The suffix is automatically applied by ReadMetadata().
|
|
*/
|
|
#define LP_GROUP_SLOT_SUFFIXED (1 << 0)
|
|
|
|
/* This struct defines an entry in the block_devices table. There must be at
|
|
* least one device, and the first device must represent the partition holding
|
|
* the super metadata.
|
|
*/
|
|
typedef struct LpMetadataBlockDevice {
|
|
/* 0: First usable sector for allocating logical partitions. this will be
|
|
* the first sector after the initial geometry blocks, followed by the
|
|
* space consumed by metadata_max_size*metadata_slot_count*2.
|
|
*/
|
|
u64 first_logical_sector;
|
|
|
|
/* 8: Alignment for defining partitions or partition extents. For example,
|
|
* an alignment of 1MiB will require that all partitions have a size evenly
|
|
* divisible by 1MiB, and that the smallest unit the partition can grow by
|
|
* is 1MiB.
|
|
*
|
|
* Alignment is normally determined at runtime when growing or adding
|
|
* partitions. If for some reason the alignment cannot be determined, then
|
|
* this predefined alignment in the geometry is used instead. By default
|
|
* it is set to 1MiB.
|
|
*/
|
|
u32 alignment;
|
|
|
|
/* 12: Alignment offset for "stacked" devices. For example, if the "super"
|
|
* partition itself is not aligned within the parent block device's
|
|
* partition table, then we adjust for this in deciding where to place
|
|
* |first_logical_sector|.
|
|
*
|
|
* Similar to |alignment|, this will be derived from the operating system.
|
|
* If it cannot be determined, it is assumed to be 0.
|
|
*/
|
|
u32 alignment_offset;
|
|
|
|
/* 16: Block device size, as specified when the metadata was created. This
|
|
* can be used to verify the geometry against a target device.
|
|
*/
|
|
u64 size;
|
|
|
|
/* 24: Partition name in the GPT. Any unused characters must be 0. */
|
|
char partition_name[36];
|
|
|
|
/* 60: Flags (see LP_BLOCK_DEVICE_* flags below). */
|
|
u32 flags;
|
|
} __attribute__((packed)) LpMetadataBlockDevice;
|
|
|
|
/* This flag is only intended to be used with super_empty.img and super.img on
|
|
* retrofit devices. On these devices there are A and B super partitions, and
|
|
* we don't know ahead of time which slot the image will be applied to.
|
|
*
|
|
* If set, the block device needs a slot suffix applied before being used with
|
|
* IPartitionOpener. The slot suffix is determined by the metadata slot number
|
|
* (0 = _a, 1 = _b).
|
|
*/
|
|
#define LP_BLOCK_DEVICE_SLOT_SUFFIXED (1 << 0)
|
|
|
|
/* For ease of writing compatibility checks, the original metadata header is
|
|
* preserved below, and typedefs are provided for the current version.
|
|
*/
|
|
typedef struct LpMetadataHeaderV1_0 {
|
|
u32 magic;
|
|
u16 major_version;
|
|
u16 minor_version;
|
|
u32 header_size;
|
|
u8 header_checksum[32];
|
|
u32 tables_size;
|
|
u8 tables_checksum[32];
|
|
LpMetadataTableDescriptor partitions;
|
|
LpMetadataTableDescriptor extents;
|
|
LpMetadataTableDescriptor groups;
|
|
LpMetadataTableDescriptor block_devices;
|
|
} __attribute__((packed)) LpMetadataHeaderV1_0;
|
|
|
|
typedef LpMetadataHeader LpMetadataHeaderV1_2;
|
|
|
|
typedef struct PartitionList
|
|
{
|
|
char name[128];
|
|
struct PartitionList *next;
|
|
}__attribute__((packed)) PartitionList;
|
|
|
|
PartitionList* part_list = NULL;
|
|
|
|
void printlist(void)
|
|
{
|
|
PartitionList *node = part_list;
|
|
|
|
while (node) {
|
|
printf("name: %s\n", node->name);
|
|
node = node->next;
|
|
}
|
|
}
|
|
|
|
int GetPrimaryGeometryOffset(void) {
|
|
int offset = LP_PARTITION_RESERVED_BYTES;
|
|
return offset;
|
|
}
|
|
|
|
int GetBackupGeometryOffset(void) {
|
|
int offset = GetPrimaryGeometryOffset() + LP_METADATA_GEOMETRY_SIZE;
|
|
return offset;
|
|
}
|
|
|
|
int GetPrimaryMetadataOffset(LpMetadataGeometry* geometry, int slot_number) {
|
|
int offset = LP_PARTITION_RESERVED_BYTES + (LP_METADATA_GEOMETRY_SIZE * 2) +
|
|
geometry->metadata_max_size * slot_number;
|
|
//printf("GetPrimaryMetadataOffset : %d\n", offset);
|
|
return offset;
|
|
}
|
|
|
|
int GetBackupMetadataOffset(LpMetadataGeometry* geometry, int slot_number) {
|
|
int start = LP_PARTITION_RESERVED_BYTES + (LP_METADATA_GEOMETRY_SIZE * 2) +
|
|
geometry->metadata_max_size * geometry->metadata_slot_count;
|
|
|
|
return start + geometry->metadata_max_size * slot_number;
|
|
}
|
|
|
|
int GetTotalMetadataSize(int metadata_max_size, int max_slots) {
|
|
return LP_PARTITION_RESERVED_BYTES +
|
|
(LP_METADATA_GEOMETRY_SIZE + metadata_max_size * max_slots) * 2;
|
|
}
|
|
|
|
int ParseGeometry(const void* buffer, LpMetadataGeometry* geometry) {
|
|
memcpy(geometry, buffer, sizeof(LpMetadataGeometry));
|
|
|
|
// Check the magic signature.
|
|
if (geometry->magic != LP_METADATA_GEOMETRY_MAGIC) {
|
|
printf("Logical partition metadata has invalid geometry magic signature\n");
|
|
return -1;
|
|
}
|
|
// Reject if the struct size is larger than what we compiled. This is so we
|
|
// can compute a checksum with the |struct_size| field rather than using
|
|
// sizeof.
|
|
if (geometry->struct_size > sizeof(LpMetadataGeometry)) {
|
|
printf("Logical partition metadata has unrecognized fields.\n");
|
|
return -1;
|
|
}
|
|
|
|
// Check that the struct size is equal (this will have to change if we ever
|
|
// change the struct size in a release).
|
|
if (geometry->struct_size != sizeof(LpMetadataGeometry)) {
|
|
printf("Logical partition metadata has invalid struct size.\n");
|
|
return -1;
|
|
}
|
|
if (geometry->metadata_slot_count == 0) {
|
|
printf("Logical partition metadata has invalid slot count.\n");
|
|
return -1;
|
|
}
|
|
if (geometry->metadata_max_size % LP_SECTOR_SIZE != 0) {
|
|
printf("Metadata max size is not sector-aligned.\n");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int ReadPrimaryGeometry(char *superbuf, LpMetadataGeometry* geometry) {
|
|
char buffer[LP_METADATA_GEOMETRY_SIZE];
|
|
|
|
memcpy(buffer, superbuf + LP_PARTITION_RESERVED_BYTES, LP_METADATA_GEOMETRY_SIZE);
|
|
return ParseGeometry(buffer, geometry);
|
|
}
|
|
|
|
int ReadBackupGeometry(char *superbuf, LpMetadataGeometry* geometry) {
|
|
char buffer[LP_METADATA_GEOMETRY_SIZE];
|
|
|
|
memcpy(buffer,
|
|
superbuf + LP_PARTITION_RESERVED_BYTES + LP_METADATA_GEOMETRY_SIZE,
|
|
LP_METADATA_GEOMETRY_SIZE);
|
|
return ParseGeometry(buffer, geometry);
|
|
}
|
|
|
|
// Read and validate geometry information from a block device that holds
|
|
// logical partitions. If the information is corrupted, this will attempt
|
|
// to read it from a secondary backup location.
|
|
int ReadLogicalPartitionGeometry(char *superbuf, LpMetadataGeometry* geometry) {
|
|
if (ReadPrimaryGeometry(superbuf, geometry) == 0)
|
|
return 0;
|
|
|
|
return ReadBackupGeometry(superbuf, geometry);
|
|
}
|
|
|
|
static int ValidateMetadataHeader(LpMetadataHeader* header) {
|
|
// Do basic validation of key metadata bits.
|
|
if (header->magic != LP_METADATA_HEADER_MAGIC) {
|
|
printf("Logical partition metadata has invalid magic value.\n");
|
|
return -1;
|
|
}
|
|
// Check that the version is compatible.
|
|
if (header->major_version != LP_METADATA_MAJOR_VERSION ||
|
|
header->minor_version > LP_METADATA_MINOR_VERSION_MAX) {
|
|
printf("Logical partition metadata has incompatible version.\n");
|
|
return -1;
|
|
}
|
|
|
|
// Check that table entry sizes can match their respective structs. If
|
|
// table sizes change, these checks will have to be adjusted.
|
|
if (header->partitions.entry_size != sizeof(LpMetadataPartition)) {
|
|
printf("Logical partition metadata has invalid partition table entry size.\n");
|
|
return -1;
|
|
}
|
|
if (header->extents.entry_size != sizeof(LpMetadataExtent)) {
|
|
printf("Logical partition metadata has invalid extent table entry size.\n");
|
|
return -1;
|
|
}
|
|
if (header->groups.entry_size != sizeof(LpMetadataPartitionGroup)) {
|
|
printf("Logical partition metadata has invalid group table entry size.\n");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int ReadMetadataHeader(char *superbuf, LpMetadataHeader *header,
|
|
LpMetadataGeometry *geometry, int slot_number)
|
|
{
|
|
char *buffer = NULL;
|
|
int cursor = 0;
|
|
PartitionList *tail = NULL;
|
|
PartitionList *node = NULL;
|
|
int ishead = 0;
|
|
int i;
|
|
int index = 0;
|
|
|
|
//printf("metaoffset: %d\n", GetPrimaryMetadataOffset(geometry, slot_number));
|
|
|
|
memcpy(header, superbuf + GetPrimaryMetadataOffset(geometry, slot_number),
|
|
sizeof(LpMetadataHeader));
|
|
if (ValidateMetadataHeader(header) != 0)
|
|
return -1;
|
|
|
|
//printf("header table size = %d\n", header->tables_size);
|
|
buffer = (char *)malloc(header->tables_size);
|
|
if (!buffer) {
|
|
printf("Out of memory reading logical partition tables.\n");
|
|
return -1;
|
|
}
|
|
|
|
if (header->minor_version == 0)
|
|
index = GetPrimaryMetadataOffset(geometry, slot_number)
|
|
+ sizeof(LpMetadataHeaderV1_0);
|
|
else
|
|
index = GetPrimaryMetadataOffset(geometry, slot_number)
|
|
+ sizeof(LpMetadataHeader);
|
|
|
|
memcpy(buffer, superbuf + index, header->tables_size);
|
|
cursor = index + header->partitions.offset;
|
|
|
|
//printf("index: %d\n", index);
|
|
//printf("cursor: %d\n", cursor);
|
|
|
|
u32 valid_attributes = LP_PARTITION_ATTRIBUTE_MASK_V0;
|
|
|
|
if (header->minor_version >= LP_METADATA_VERSION_FOR_UPDATED_ATTR)
|
|
valid_attributes |= LP_PARTITION_ATTRIBUTE_MASK_V1;
|
|
|
|
// ValidateTableSize ensured that |cursor| is valid for the number of
|
|
// entries in the table.
|
|
for (i = 0; i < header->partitions.num_entries; i++) {
|
|
LpMetadataPartition partition;
|
|
|
|
memcpy(&partition, superbuf + cursor, sizeof(partition));
|
|
cursor += header->partitions.entry_size;
|
|
|
|
printf("partition name : %s\n", partition.name);
|
|
|
|
if (partition.attributes & ~valid_attributes) {
|
|
printf("Logical partition has invalid attribute set.\n");
|
|
if (buffer)
|
|
free(buffer);
|
|
return -1;
|
|
}
|
|
if (partition.first_extent_index + partition.num_extents <
|
|
partition.first_extent_index) {
|
|
printf("Logical partition first_extent_index + num_extents overflowed.\n");
|
|
if (buffer)
|
|
free(buffer);
|
|
return -1;
|
|
}
|
|
if (partition.first_extent_index + partition.num_extents >
|
|
header->extents.num_entries) {
|
|
printf("Logical partition has invalid extent list.\n");
|
|
if (buffer)
|
|
free(buffer);
|
|
return -1;
|
|
}
|
|
if (partition.group_index >= header->groups.num_entries) {
|
|
printf("Logical partition has invalid group index.\n");
|
|
if (buffer)
|
|
free(buffer);
|
|
return -1;
|
|
}
|
|
|
|
node = malloc(sizeof(PartitionList));
|
|
strlcpy(node->name, partition.name,
|
|
min(sizeof(PartitionList), sizeof(partition.name)));
|
|
if (ishead == 0) {
|
|
part_list = node;
|
|
part_list->next = NULL;
|
|
tail = node;
|
|
ishead = -1;
|
|
} else {
|
|
tail->next = node;
|
|
tail = node;
|
|
}
|
|
//metadata->partitions.push_back(partition);
|
|
}
|
|
|
|
if (tail)
|
|
tail->next = NULL;
|
|
|
|
if (buffer)
|
|
free(buffer);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int do_ReadMetadata(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|
{
|
|
char *partition = "super";
|
|
char *superbuf;
|
|
LpMetadataGeometry geometry;
|
|
LpMetadataHeader metadata_header;
|
|
char *slot;
|
|
int slot_number = 0;
|
|
|
|
superbuf = (char *)malloc(SUPERBUF_SIZE);
|
|
if (!superbuf) {
|
|
printf("Out of memory reading logical partition tables.\n");
|
|
goto ERR;
|
|
}
|
|
|
|
if (dynamic_partition) {
|
|
if (store_read_ops((unsigned char *)partition,
|
|
(unsigned char *)superbuf, 0, SUPERBUF_SIZE) < 0) {
|
|
printf("failed to store read %s.\n", partition);
|
|
goto ERR;
|
|
}
|
|
|
|
//dump_mem(superbuf, SUPERBUF_SIZE);
|
|
|
|
if (ReadLogicalPartitionGeometry(superbuf, &geometry) != 0)
|
|
goto ERR;
|
|
|
|
if (has_boot_slot == 1) {
|
|
slot = getenv("slot-suffixes");
|
|
//printf("slot-suffixes: %s\n", slot);
|
|
if (strcmp(slot, "0") == 0)
|
|
slot_number = 0;
|
|
else if (strcmp(slot, "1") == 0)
|
|
slot_number = 1;
|
|
}
|
|
|
|
ReadMetadataHeader(superbuf, &metadata_header, &geometry, slot_number);
|
|
|
|
//printlist();
|
|
}
|
|
|
|
if (superbuf)
|
|
free(superbuf);
|
|
|
|
return 0;
|
|
|
|
ERR:
|
|
if (superbuf)
|
|
free(superbuf);
|
|
return -1;
|
|
|
|
}
|
|
|
|
int is_partition_logical(char *partition_name)
|
|
{
|
|
run_command("readMetadata", 0);
|
|
PartitionList *node = part_list;
|
|
|
|
while (node) {
|
|
//printf("name: %s\n",node->name);
|
|
if (strcmp(node->name, partition_name) == 0)
|
|
return 0;
|
|
node = node->next;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
#else
|
|
static int do_ReadMetadata(
|
|
cmd_tbl_t *cmdtp,
|
|
int flag,
|
|
int argc,
|
|
char *const argv[]) {
|
|
// Do-Nothing!
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_BOOTLOADER_CONTROL_BLOCK */
|
|
|
|
U_BOOT_CMD(
|
|
readMetadata, 1, 0, do_ReadMetadata,
|
|
"readMetadata",
|
|
"\nThis command will read metadata in super\n"
|
|
"So you can execute command: readMetadata"
|
|
);
|
|
|