1 /* 2 * Copyright (c) 2014-2015, Linaro Ltd and Contributors. All rights reserved. 3 * Copyright (c) 2014-2015, Hisilicon Ltd and Contributors. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * Neither the name of ARM nor the names of its contributors may be used 16 * to endorse or promote products derived from this software without specific 17 * prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <debug.h> 33 #include <dw_mmc.h> 34 #include <errno.h> 35 #include <io_storage.h> 36 #include <mmio.h> 37 #include <partitions.h> 38 #include <platform_def.h> 39 #include <string.h> 40 #include "hikey_private.h" 41 42 #define EFI_ENTRIES 128 43 #define EFI_ENTRY_SIZE (sizeof(struct efi_entry)) 44 #define EFI_MBR_SIZE 512 45 #define EFI_HEADER_SIZE 512 46 #define EFI_TOTAL_SIZE (EFI_MBR_SIZE + EFI_HEADER_SIZE + \ 47 EFI_ENTRY_SIZE * EFI_ENTRIES) 48 49 struct efi_header { 50 char signature[8]; 51 uint32_t revision; 52 uint32_t size; 53 uint32_t header_crc; 54 uint32_t reserved; 55 uint64_t current_lba; 56 uint64_t backup_lba; 57 uint64_t first_lba; 58 uint64_t last_lba; 59 uint8_t disk_uuid[16]; 60 /* starting LBA of array of partition entries */ 61 uint64_t part_lba; 62 /* number of partition entries in array */ 63 uint32_t part_num; 64 /* size of a single partition entry (usually 128) */ 65 uint32_t part_size; 66 uint32_t part_crc; 67 }; 68 69 struct efi_entry { 70 uint8_t type_uuid[16]; 71 uint8_t uniq_uuid[16]; 72 uint64_t first_lba; 73 uint64_t last_lba; 74 uint64_t attr; 75 uint16_t name[EFI_NAMELEN]; 76 }; 77 78 /* the first entry is dummy for ptable (covers both primary & secondary) */ 79 static struct ptentry ptable[EFI_ENTRIES + 1]; 80 static int entries; /* partition entry entries */ 81 82 static void dump_entries(void) 83 { 84 int i; 85 86 VERBOSE("Partition table with %d entries:\n", entries); 87 for (i = 0; i < entries; i++) { 88 VERBOSE("%s %llx-%llx\n", ptable[i].name, 89 ptable[i].start, 90 ptable[i].start + ptable[i].length - 4); 91 } 92 } 93 94 static int convert_ascii_string(uint16_t *str_in, uint8_t *str_out) 95 { 96 uint8_t *name = (uint8_t *)str_in; 97 int i; 98 99 if (name[0] == '\0' || !str_in || !str_out) 100 return -EINVAL; 101 for (i = 1; i < (EFI_NAMELEN << 1); i += 2) { 102 if (name[i] != '\0') 103 return -EINVAL; 104 } 105 for (i = 0; i < (EFI_NAMELEN << 1); i += 2) { 106 str_out[i >> 1] = name[i]; 107 if (name[i] == '\0') 108 break; 109 } 110 return 0; 111 } 112 113 static int parse_entry(uintptr_t buf) 114 { 115 struct efi_entry *entry = (struct efi_entry *)buf; 116 int ret; 117 118 /* exhaused partition entry */ 119 if ((entry->first_lba == 0) && (entry->last_lba == 0)) 120 return 1; 121 ret = convert_ascii_string(entry->name, (uint8_t *)ptable[entries].name); 122 if (ret < 0) 123 return ret; 124 ptable[entries].start = (uint64_t)entry->first_lba * 512; 125 ptable[entries].length = (uint64_t)(entry->last_lba - entry->first_lba + 1) * 512; 126 entries++; 127 return 0; 128 } 129 130 /* create dummy entry for ptable */ 131 static void create_dummy_entry(void) 132 { 133 int bytes; 134 ptable[entries].start = 0; 135 ptable[entries].length = 0; 136 bytes = sprintf(ptable[entries].name, "ptable"); 137 ptable[entries].name[bytes] = '\0'; 138 entries++; 139 } 140 141 struct ptentry *find_ptn(const char *str) 142 { 143 struct ptentry *ptn = NULL; 144 int i; 145 146 for (i = 0; i < entries; i++) { 147 if (!strcmp(ptable[i].name, str)) { 148 ptn = &ptable[i]; 149 break; 150 } 151 } 152 return ptn; 153 } 154 155 int get_partition(void) 156 { 157 int result = IO_FAIL; 158 int i, ret, num_entries; 159 size_t bytes_read; 160 uintptr_t emmc_dev_handle, spec, img_handle; 161 unsigned int buf[MMC_BLOCK_SIZE >> 2]; 162 struct efi_header *hd = NULL; 163 164 create_dummy_entry(); 165 result = plat_get_image_source(NORMAL_EMMC_NAME, &emmc_dev_handle, 166 &spec); 167 if (result) { 168 WARN("failed to open eMMC normal partition\n"); 169 return result; 170 } 171 result = io_open(emmc_dev_handle, spec, &img_handle); 172 if (result != IO_SUCCESS) { 173 WARN("Failed to open eMMC device\n"); 174 return result; 175 } 176 result = io_seek(img_handle, IO_SEEK_SET, 0); 177 if (result) 178 goto exit; 179 result = io_read(img_handle, (uintptr_t)buf, EFI_MBR_SIZE, 180 &bytes_read); 181 if ((result != IO_SUCCESS) || (bytes_read < EFI_MBR_SIZE)) { 182 WARN("Failed to read eMMC (%i)\n", result); 183 goto exit; 184 } 185 /* check the magic number in last word */ 186 if (buf[(MMC_BLOCK_SIZE >> 2) - 1] != 0xaa550000) { 187 WARN("Can't find MBR protection information\n"); 188 goto exit; 189 } 190 191 result = io_read(img_handle, (uintptr_t)buf, EFI_HEADER_SIZE, 192 &bytes_read); 193 if ((result != IO_SUCCESS) || (bytes_read < EFI_HEADER_SIZE)) { 194 WARN("Failed to read eMMC (%i)\n", result); 195 goto exit; 196 } 197 hd = (struct efi_header *)((uintptr_t)buf); 198 if (strncmp(hd->signature, "EFI PART", 8)) { 199 WARN("Failed to find partition table\n"); 200 goto exit; 201 } 202 num_entries = hd->part_num; 203 for (i = 0; i < num_entries; i++) { 204 result = io_read(img_handle, (uintptr_t)buf, EFI_HEADER_SIZE, 205 &bytes_read); 206 if ((result != IO_SUCCESS) || (bytes_read < EFI_HEADER_SIZE)) { 207 WARN("Failed to read eMMC (%i)\n", result); 208 goto exit; 209 } 210 /* each header contains four partition entries */ 211 ret = parse_entry((uintptr_t)buf); 212 if (ret) 213 break; 214 ret = parse_entry((uintptr_t)buf + EFI_ENTRY_SIZE); 215 if (ret) 216 break; 217 ret = parse_entry((uintptr_t)buf + EFI_ENTRY_SIZE * 2); 218 if (ret) 219 break; 220 ret = parse_entry((uintptr_t)buf + EFI_ENTRY_SIZE * 3); 221 if (ret) 222 break; 223 } 224 exit: 225 io_close(img_handle); 226 update_fip_spec(); 227 dump_entries(); 228 return result; 229 } 230