1201b66b7SHaojian Zhuang /* 2201b66b7SHaojian Zhuang * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. 3201b66b7SHaojian Zhuang * 4*82cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause 5201b66b7SHaojian Zhuang */ 6201b66b7SHaojian Zhuang 7201b66b7SHaojian Zhuang #include <assert.h> 8201b66b7SHaojian Zhuang #include <debug.h> 9201b66b7SHaojian Zhuang #include <io_storage.h> 10201b66b7SHaojian Zhuang #include <gpt.h> 11201b66b7SHaojian Zhuang #include <mbr.h> 12201b66b7SHaojian Zhuang #include <partition.h> 13201b66b7SHaojian Zhuang #include <platform.h> 14201b66b7SHaojian Zhuang #include <string.h> 15201b66b7SHaojian Zhuang 16201b66b7SHaojian Zhuang static uint8_t mbr_sector[PARTITION_BLOCK_SIZE]; 17201b66b7SHaojian Zhuang partition_entry_list_t list; 18201b66b7SHaojian Zhuang 19201b66b7SHaojian Zhuang #if LOG_LEVEL >= LOG_LEVEL_VERBOSE 20201b66b7SHaojian Zhuang static void dump_entries(int num) 21201b66b7SHaojian Zhuang { 22201b66b7SHaojian Zhuang char name[EFI_NAMELEN]; 23201b66b7SHaojian Zhuang int i, j, len; 24201b66b7SHaojian Zhuang 25201b66b7SHaojian Zhuang VERBOSE("Partition table with %d entries:\n", num); 26201b66b7SHaojian Zhuang for (i = 0; i < num; i++) { 27201b66b7SHaojian Zhuang len = snprintf(name, EFI_NAMELEN, "%s", list.list[i].name); 28201b66b7SHaojian Zhuang for (j = 0; j < EFI_NAMELEN - len - 1; j++) { 29201b66b7SHaojian Zhuang name[len + j] = ' '; 30201b66b7SHaojian Zhuang } 31201b66b7SHaojian Zhuang name[EFI_NAMELEN - 1] = '\0'; 32201b66b7SHaojian Zhuang VERBOSE("%d: %s %lx-%lx\n", i + 1, name, list.list[i].start, 33201b66b7SHaojian Zhuang list.list[i].start + list.list[i].length - 4); 34201b66b7SHaojian Zhuang } 35201b66b7SHaojian Zhuang } 36201b66b7SHaojian Zhuang #else 37201b66b7SHaojian Zhuang #define dump_entries(num) ((void)num) 38201b66b7SHaojian Zhuang #endif 39201b66b7SHaojian Zhuang 40201b66b7SHaojian Zhuang /* 41201b66b7SHaojian Zhuang * Load the first sector that carries MBR header. 42201b66b7SHaojian Zhuang * The MBR boot signature should be always valid whether it's MBR or GPT. 43201b66b7SHaojian Zhuang */ 44201b66b7SHaojian Zhuang static int load_mbr_header(uintptr_t image_handle, mbr_entry_t *mbr_entry) 45201b66b7SHaojian Zhuang { 46201b66b7SHaojian Zhuang size_t bytes_read; 47201b66b7SHaojian Zhuang uintptr_t offset; 48201b66b7SHaojian Zhuang int result; 49201b66b7SHaojian Zhuang 50201b66b7SHaojian Zhuang assert(mbr_entry != NULL); 51201b66b7SHaojian Zhuang /* MBR partition table is in LBA0. */ 52201b66b7SHaojian Zhuang result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET); 53201b66b7SHaojian Zhuang if (result != 0) { 54201b66b7SHaojian Zhuang WARN("Failed to seek (%i)\n", result); 55201b66b7SHaojian Zhuang return result; 56201b66b7SHaojian Zhuang } 57201b66b7SHaojian Zhuang result = io_read(image_handle, (uintptr_t)&mbr_sector, 58201b66b7SHaojian Zhuang PARTITION_BLOCK_SIZE, &bytes_read); 59201b66b7SHaojian Zhuang if (result != 0) { 60201b66b7SHaojian Zhuang WARN("Failed to read data (%i)\n", result); 61201b66b7SHaojian Zhuang return result; 62201b66b7SHaojian Zhuang } 63201b66b7SHaojian Zhuang 64201b66b7SHaojian Zhuang /* Check MBR boot signature. */ 65201b66b7SHaojian Zhuang if ((mbr_sector[PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) || 66201b66b7SHaojian Zhuang (mbr_sector[PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) { 67201b66b7SHaojian Zhuang return -ENOENT; 68201b66b7SHaojian Zhuang } 69201b66b7SHaojian Zhuang offset = (uintptr_t)&mbr_sector + MBR_PRIMARY_ENTRY_OFFSET; 70201b66b7SHaojian Zhuang memcpy(mbr_entry, (void *)offset, sizeof(mbr_entry_t)); 71201b66b7SHaojian Zhuang return 0; 72201b66b7SHaojian Zhuang } 73201b66b7SHaojian Zhuang 74201b66b7SHaojian Zhuang /* 75201b66b7SHaojian Zhuang * Load GPT header and check the GPT signature. 76201b66b7SHaojian Zhuang * If partiton numbers could be found, check & update it. 77201b66b7SHaojian Zhuang */ 78201b66b7SHaojian Zhuang static int load_gpt_header(uintptr_t image_handle) 79201b66b7SHaojian Zhuang { 80201b66b7SHaojian Zhuang gpt_header_t header; 81201b66b7SHaojian Zhuang size_t bytes_read; 82201b66b7SHaojian Zhuang int result; 83201b66b7SHaojian Zhuang 84201b66b7SHaojian Zhuang result = io_seek(image_handle, IO_SEEK_SET, GPT_HEADER_OFFSET); 85201b66b7SHaojian Zhuang if (result != 0) { 86201b66b7SHaojian Zhuang return result; 87201b66b7SHaojian Zhuang } 88201b66b7SHaojian Zhuang result = io_read(image_handle, (uintptr_t)&header, 89201b66b7SHaojian Zhuang sizeof(gpt_header_t), &bytes_read); 90201b66b7SHaojian Zhuang if ((result != 0) || (sizeof(gpt_header_t) != bytes_read)) { 91201b66b7SHaojian Zhuang return result; 92201b66b7SHaojian Zhuang } 93201b66b7SHaojian Zhuang if (memcmp(header.signature, GPT_SIGNATURE, 94201b66b7SHaojian Zhuang sizeof(header.signature)) != 0) { 95201b66b7SHaojian Zhuang return -EINVAL; 96201b66b7SHaojian Zhuang } 97201b66b7SHaojian Zhuang 98201b66b7SHaojian Zhuang /* partition numbers can't exceed PLAT_PARTITION_MAX_ENTRIES */ 99201b66b7SHaojian Zhuang list.entry_count = header.list_num; 100201b66b7SHaojian Zhuang if (list.entry_count > PLAT_PARTITION_MAX_ENTRIES) { 101201b66b7SHaojian Zhuang list.entry_count = PLAT_PARTITION_MAX_ENTRIES; 102201b66b7SHaojian Zhuang } 103201b66b7SHaojian Zhuang return 0; 104201b66b7SHaojian Zhuang } 105201b66b7SHaojian Zhuang 106201b66b7SHaojian Zhuang static int load_gpt_entry(uintptr_t image_handle, gpt_entry_t *entry) 107201b66b7SHaojian Zhuang { 108201b66b7SHaojian Zhuang size_t bytes_read; 109201b66b7SHaojian Zhuang int result; 110201b66b7SHaojian Zhuang 111201b66b7SHaojian Zhuang assert(entry != NULL); 112201b66b7SHaojian Zhuang result = io_read(image_handle, (uintptr_t)entry, sizeof(gpt_entry_t), 113201b66b7SHaojian Zhuang &bytes_read); 114201b66b7SHaojian Zhuang if (sizeof(gpt_entry_t) != bytes_read) 115201b66b7SHaojian Zhuang return -EINVAL; 116201b66b7SHaojian Zhuang return result; 117201b66b7SHaojian Zhuang } 118201b66b7SHaojian Zhuang 119201b66b7SHaojian Zhuang static int verify_partition_gpt(uintptr_t image_handle) 120201b66b7SHaojian Zhuang { 121201b66b7SHaojian Zhuang gpt_entry_t entry; 122201b66b7SHaojian Zhuang int result, i; 123201b66b7SHaojian Zhuang 124201b66b7SHaojian Zhuang for (i = 0; i < list.entry_count; i++) { 125201b66b7SHaojian Zhuang result = load_gpt_entry(image_handle, &entry); 126201b66b7SHaojian Zhuang assert(result == 0); 127201b66b7SHaojian Zhuang result = parse_gpt_entry(&entry, &list.list[i]); 128201b66b7SHaojian Zhuang if (result != 0) { 129201b66b7SHaojian Zhuang break; 130201b66b7SHaojian Zhuang } 131201b66b7SHaojian Zhuang } 132201b66b7SHaojian Zhuang if (i == 0) { 133201b66b7SHaojian Zhuang return -EINVAL; 134201b66b7SHaojian Zhuang } 135201b66b7SHaojian Zhuang /* 136201b66b7SHaojian Zhuang * Only records the valid partition number that is loaded from 137201b66b7SHaojian Zhuang * partition table. 138201b66b7SHaojian Zhuang */ 139201b66b7SHaojian Zhuang list.entry_count = i; 140201b66b7SHaojian Zhuang dump_entries(list.entry_count); 141201b66b7SHaojian Zhuang 142201b66b7SHaojian Zhuang return 0; 143201b66b7SHaojian Zhuang } 144201b66b7SHaojian Zhuang 145201b66b7SHaojian Zhuang int load_partition_table(unsigned int image_id) 146201b66b7SHaojian Zhuang { 147201b66b7SHaojian Zhuang uintptr_t dev_handle, image_handle, image_spec = 0; 148201b66b7SHaojian Zhuang mbr_entry_t mbr_entry; 149201b66b7SHaojian Zhuang int result; 150201b66b7SHaojian Zhuang 151201b66b7SHaojian Zhuang result = plat_get_image_source(image_id, &dev_handle, &image_spec); 152201b66b7SHaojian Zhuang if (result != 0) { 153201b66b7SHaojian Zhuang WARN("Failed to obtain reference to image id=%u (%i)\n", 154201b66b7SHaojian Zhuang image_id, result); 155201b66b7SHaojian Zhuang return result; 156201b66b7SHaojian Zhuang } 157201b66b7SHaojian Zhuang 158201b66b7SHaojian Zhuang result = io_open(dev_handle, image_spec, &image_handle); 159201b66b7SHaojian Zhuang if (result != 0) { 160201b66b7SHaojian Zhuang WARN("Failed to access image id=%u (%i)\n", image_id, result); 161201b66b7SHaojian Zhuang return result; 162201b66b7SHaojian Zhuang } 163201b66b7SHaojian Zhuang 164201b66b7SHaojian Zhuang result = load_mbr_header(image_handle, &mbr_entry); 165201b66b7SHaojian Zhuang if (result != 0) { 166201b66b7SHaojian Zhuang WARN("Failed to access image id=%u (%i)\n", image_id, result); 167201b66b7SHaojian Zhuang return result; 168201b66b7SHaojian Zhuang } 169201b66b7SHaojian Zhuang if (mbr_entry.type == PARTITION_TYPE_GPT) { 170201b66b7SHaojian Zhuang result = load_gpt_header(image_handle); 171201b66b7SHaojian Zhuang assert(result == 0); 172201b66b7SHaojian Zhuang result = io_seek(image_handle, IO_SEEK_SET, GPT_ENTRY_OFFSET); 173201b66b7SHaojian Zhuang assert(result == 0); 174201b66b7SHaojian Zhuang result = verify_partition_gpt(image_handle); 175201b66b7SHaojian Zhuang } else { 176201b66b7SHaojian Zhuang /* MBR type isn't supported yet. */ 177201b66b7SHaojian Zhuang result = -EINVAL; 178201b66b7SHaojian Zhuang goto exit; 179201b66b7SHaojian Zhuang } 180201b66b7SHaojian Zhuang exit: 181201b66b7SHaojian Zhuang io_close(image_handle); 182201b66b7SHaojian Zhuang return result; 183201b66b7SHaojian Zhuang } 184201b66b7SHaojian Zhuang 185201b66b7SHaojian Zhuang const partition_entry_t *get_partition_entry(const char *name) 186201b66b7SHaojian Zhuang { 187201b66b7SHaojian Zhuang int i; 188201b66b7SHaojian Zhuang 189201b66b7SHaojian Zhuang for (i = 0; i < list.entry_count; i++) { 190201b66b7SHaojian Zhuang if (strcmp(name, list.list[i].name) == 0) { 191201b66b7SHaojian Zhuang return &list.list[i]; 192201b66b7SHaojian Zhuang } 193201b66b7SHaojian Zhuang } 194201b66b7SHaojian Zhuang return NULL; 195201b66b7SHaojian Zhuang } 196201b66b7SHaojian Zhuang 197201b66b7SHaojian Zhuang const partition_entry_list_t *get_partition_entry_list(void) 198201b66b7SHaojian Zhuang { 199201b66b7SHaojian Zhuang return &list; 200201b66b7SHaojian Zhuang } 201201b66b7SHaojian Zhuang 202201b66b7SHaojian Zhuang void partition_init(unsigned int image_id) 203201b66b7SHaojian Zhuang { 204201b66b7SHaojian Zhuang load_partition_table(image_id); 205201b66b7SHaojian Zhuang } 206