Home | History | Annotate | Download | only in partition
      1 /*
      2  * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
      3  *
      4  * SPDX-License-Identifier: BSD-3-Clause
      5  */
      6 
      7 #include <assert.h>
      8 #include <debug.h>
      9 #include <gpt.h>
     10 #include <io_storage.h>
     11 #include <mbr.h>
     12 #include <partition.h>
     13 #include <platform.h>
     14 #include <string.h>
     15 
     16 static uint8_t mbr_sector[PARTITION_BLOCK_SIZE];
     17 partition_entry_list_t list;
     18 
     19 #if LOG_LEVEL >= LOG_LEVEL_VERBOSE
     20 static void dump_entries(int num)
     21 {
     22 	char name[EFI_NAMELEN];
     23 	int i, j, len;
     24 
     25 	VERBOSE("Partition table with %d entries:\n", num);
     26 	for (i = 0; i < num; i++) {
     27 		len = snprintf(name, EFI_NAMELEN, "%s", list.list[i].name);
     28 		for (j = 0; j < EFI_NAMELEN - len - 1; j++) {
     29 			name[len + j] = ' ';
     30 		}
     31 		name[EFI_NAMELEN - 1] = '\0';
     32 		VERBOSE("%d: %s %lx-%lx\n", i + 1, name, list.list[i].start,
     33 			list.list[i].start + list.list[i].length - 4);
     34 	}
     35 }
     36 #else
     37 #define dump_entries(num)	((void)num)
     38 #endif
     39 
     40 /*
     41  * Load the first sector that carries MBR header.
     42  * The MBR boot signature should be always valid whether it's MBR or GPT.
     43  */
     44 static int load_mbr_header(uintptr_t image_handle, mbr_entry_t *mbr_entry)
     45 {
     46 	size_t bytes_read;
     47 	uintptr_t offset;
     48 	int result;
     49 
     50 	assert(mbr_entry != NULL);
     51 	/* MBR partition table is in LBA0. */
     52 	result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET);
     53 	if (result != 0) {
     54 		WARN("Failed to seek (%i)\n", result);
     55 		return result;
     56 	}
     57 	result = io_read(image_handle, (uintptr_t)&mbr_sector,
     58 			 PARTITION_BLOCK_SIZE, &bytes_read);
     59 	if (result != 0) {
     60 		WARN("Failed to read data (%i)\n", result);
     61 		return result;
     62 	}
     63 
     64 	/* Check MBR boot signature. */
     65 	if ((mbr_sector[PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) ||
     66 	    (mbr_sector[PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) {
     67 		return -ENOENT;
     68 	}
     69 	offset = (uintptr_t)&mbr_sector + MBR_PRIMARY_ENTRY_OFFSET;
     70 	memcpy(mbr_entry, (void *)offset, sizeof(mbr_entry_t));
     71 	return 0;
     72 }
     73 
     74 /*
     75  * Load GPT header and check the GPT signature.
     76  * If partiton numbers could be found, check & update it.
     77  */
     78 static int load_gpt_header(uintptr_t image_handle)
     79 {
     80 	gpt_header_t header;
     81 	size_t bytes_read;
     82 	int result;
     83 
     84 	result = io_seek(image_handle, IO_SEEK_SET, GPT_HEADER_OFFSET);
     85 	if (result != 0) {
     86 		return result;
     87 	}
     88 	result = io_read(image_handle, (uintptr_t)&header,
     89 			 sizeof(gpt_header_t), &bytes_read);
     90 	if ((result != 0) || (sizeof(gpt_header_t) != bytes_read)) {
     91 		return result;
     92 	}
     93 	if (memcmp(header.signature, GPT_SIGNATURE,
     94 		   sizeof(header.signature)) != 0) {
     95 		return -EINVAL;
     96 	}
     97 
     98 	/* partition numbers can't exceed PLAT_PARTITION_MAX_ENTRIES */
     99 	list.entry_count = header.list_num;
    100 	if (list.entry_count > PLAT_PARTITION_MAX_ENTRIES) {
    101 		list.entry_count = PLAT_PARTITION_MAX_ENTRIES;
    102 	}
    103 	return 0;
    104 }
    105 
    106 static int load_gpt_entry(uintptr_t image_handle, gpt_entry_t *entry)
    107 {
    108 	size_t bytes_read;
    109 	int result;
    110 
    111 	assert(entry != NULL);
    112 	result = io_read(image_handle, (uintptr_t)entry, sizeof(gpt_entry_t),
    113 			 &bytes_read);
    114 	if (sizeof(gpt_entry_t) != bytes_read)
    115 		return -EINVAL;
    116 	return result;
    117 }
    118 
    119 static int verify_partition_gpt(uintptr_t image_handle)
    120 {
    121 	gpt_entry_t entry;
    122 	int result, i;
    123 
    124 	for (i = 0; i < list.entry_count; i++) {
    125 		result = load_gpt_entry(image_handle, &entry);
    126 		assert(result == 0);
    127 		result = parse_gpt_entry(&entry, &list.list[i]);
    128 		if (result != 0) {
    129 			break;
    130 		}
    131 	}
    132 	if (i == 0) {
    133 		return -EINVAL;
    134 	}
    135 	/*
    136 	 * Only records the valid partition number that is loaded from
    137 	 * partition table.
    138 	 */
    139 	list.entry_count = i;
    140 	dump_entries(list.entry_count);
    141 
    142 	return 0;
    143 }
    144 
    145 int load_partition_table(unsigned int image_id)
    146 {
    147 	uintptr_t dev_handle, image_handle, image_spec = 0;
    148 	mbr_entry_t mbr_entry;
    149 	int result;
    150 
    151 	result = plat_get_image_source(image_id, &dev_handle, &image_spec);
    152 	if (result != 0) {
    153 		WARN("Failed to obtain reference to image id=%u (%i)\n",
    154 			image_id, result);
    155 		return result;
    156 	}
    157 
    158 	result = io_open(dev_handle, image_spec, &image_handle);
    159 	if (result != 0) {
    160 		WARN("Failed to access image id=%u (%i)\n", image_id, result);
    161 		return result;
    162 	}
    163 
    164 	result = load_mbr_header(image_handle, &mbr_entry);
    165 	if (result != 0) {
    166 		WARN("Failed to access image id=%u (%i)\n", image_id, result);
    167 		return result;
    168 	}
    169 	if (mbr_entry.type == PARTITION_TYPE_GPT) {
    170 		result = load_gpt_header(image_handle);
    171 		assert(result == 0);
    172 		result = io_seek(image_handle, IO_SEEK_SET, GPT_ENTRY_OFFSET);
    173 		assert(result == 0);
    174 		result = verify_partition_gpt(image_handle);
    175 	} else {
    176 		/* MBR type isn't supported yet. */
    177 		result = -EINVAL;
    178 		goto exit;
    179 	}
    180 exit:
    181 	io_close(image_handle);
    182 	return result;
    183 }
    184 
    185 const partition_entry_t *get_partition_entry(const char *name)
    186 {
    187 	int i;
    188 
    189 	for (i = 0; i < list.entry_count; i++) {
    190 		if (strcmp(name, list.list[i].name) == 0) {
    191 			return &list.list[i];
    192 		}
    193 	}
    194 	return NULL;
    195 }
    196 
    197 const partition_entry_list_t *get_partition_entry_list(void)
    198 {
    199 	return &list;
    200 }
    201 
    202 void partition_init(unsigned int image_id)
    203 {
    204 	load_partition_table(image_id);
    205 }
    206