diff --git a/drivers/partition/gpt.c b/drivers/partition/gpt.c new file mode 100644 index 0000000..9240d5a --- /dev/null +++ b/drivers/partition/gpt.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +static int unicode_to_ascii(unsigned short *str_in, unsigned char *str_out) +{ + uint8_t *name = (uint8_t *)str_in; + int i; + + assert((str_in != NULL) && (str_out != NULL) && (name[0] != '\0')); + + /* check whether the unicode string is valid */ + for (i = 1; i < (EFI_NAMELEN << 1); i += 2) { + if (name[i] != '\0') + return -EINVAL; + } + /* convert the unicode string to ascii string */ + for (i = 0; i < (EFI_NAMELEN << 1); i += 2) { + str_out[i >> 1] = name[i]; + if (name[i] == '\0') + break; + } + return 0; +} + +int parse_gpt_entry(gpt_entry_t *gpt_entry, partition_entry_t *entry) +{ + int result; + + assert((gpt_entry != 0) && (entry != 0)); + + if ((gpt_entry->first_lba == 0) && (gpt_entry->last_lba == 0)) { + return -EINVAL; + } + + memset(entry, 0, sizeof(partition_entry_t)); + result = unicode_to_ascii(gpt_entry->name, (uint8_t *)entry->name); + if (result != 0) { + return result; + } + entry->start = (uint64_t)gpt_entry->first_lba * PARTITION_BLOCK_SIZE; + entry->length = (uint64_t)(gpt_entry->last_lba - + gpt_entry->first_lba + 1) * + PARTITION_BLOCK_SIZE; + return 0; +} diff --git a/drivers/partition/partition.c b/drivers/partition/partition.c new file mode 100644 index 0000000..8bf6848 --- /dev/null +++ b/drivers/partition/partition.c @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static uint8_t mbr_sector[PARTITION_BLOCK_SIZE]; +partition_entry_list_t list; + +#if LOG_LEVEL >= LOG_LEVEL_VERBOSE +static void dump_entries(int num) +{ + char name[EFI_NAMELEN]; + int i, j, len; + + VERBOSE("Partition table with %d entries:\n", num); + for (i = 0; i < num; i++) { + len = snprintf(name, EFI_NAMELEN, "%s", list.list[i].name); + for (j = 0; j < EFI_NAMELEN - len - 1; j++) { + name[len + j] = ' '; + } + name[EFI_NAMELEN - 1] = '\0'; + VERBOSE("%d: %s %lx-%lx\n", i + 1, name, list.list[i].start, + list.list[i].start + list.list[i].length - 4); + } +} +#else +#define dump_entries(num) ((void)num) +#endif + +/* + * Load the first sector that carries MBR header. + * The MBR boot signature should be always valid whether it's MBR or GPT. + */ +static int load_mbr_header(uintptr_t image_handle, mbr_entry_t *mbr_entry) +{ + size_t bytes_read; + uintptr_t offset; + int result; + + assert(mbr_entry != NULL); + /* MBR partition table is in LBA0. */ + result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET); + if (result != 0) { + WARN("Failed to seek (%i)\n", result); + return result; + } + result = io_read(image_handle, (uintptr_t)&mbr_sector, + PARTITION_BLOCK_SIZE, &bytes_read); + if (result != 0) { + WARN("Failed to read data (%i)\n", result); + return result; + } + + /* Check MBR boot signature. */ + if ((mbr_sector[PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) || + (mbr_sector[PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) { + return -ENOENT; + } + offset = (uintptr_t)&mbr_sector + MBR_PRIMARY_ENTRY_OFFSET; + memcpy(mbr_entry, (void *)offset, sizeof(mbr_entry_t)); + return 0; +} + +/* + * Load GPT header and check the GPT signature. + * If partiton numbers could be found, check & update it. + */ +static int load_gpt_header(uintptr_t image_handle) +{ + gpt_header_t header; + size_t bytes_read; + int result; + + result = io_seek(image_handle, IO_SEEK_SET, GPT_HEADER_OFFSET); + if (result != 0) { + return result; + } + result = io_read(image_handle, (uintptr_t)&header, + sizeof(gpt_header_t), &bytes_read); + if ((result != 0) || (sizeof(gpt_header_t) != bytes_read)) { + return result; + } + if (memcmp(header.signature, GPT_SIGNATURE, + sizeof(header.signature)) != 0) { + return -EINVAL; + } + + /* partition numbers can't exceed PLAT_PARTITION_MAX_ENTRIES */ + list.entry_count = header.list_num; + if (list.entry_count > PLAT_PARTITION_MAX_ENTRIES) { + list.entry_count = PLAT_PARTITION_MAX_ENTRIES; + } + return 0; +} + +static int load_gpt_entry(uintptr_t image_handle, gpt_entry_t *entry) +{ + size_t bytes_read; + int result; + + assert(entry != NULL); + result = io_read(image_handle, (uintptr_t)entry, sizeof(gpt_entry_t), + &bytes_read); + if (sizeof(gpt_entry_t) != bytes_read) + return -EINVAL; + return result; +} + +static int verify_partition_gpt(uintptr_t image_handle) +{ + gpt_entry_t entry; + int result, i; + + for (i = 0; i < list.entry_count; i++) { + result = load_gpt_entry(image_handle, &entry); + assert(result == 0); + result = parse_gpt_entry(&entry, &list.list[i]); + if (result != 0) { + break; + } + } + if (i == 0) { + return -EINVAL; + } + /* + * Only records the valid partition number that is loaded from + * partition table. + */ + list.entry_count = i; + dump_entries(list.entry_count); + + return 0; +} + +int load_partition_table(unsigned int image_id) +{ + uintptr_t dev_handle, image_handle, image_spec = 0; + mbr_entry_t mbr_entry; + int result; + + result = plat_get_image_source(image_id, &dev_handle, &image_spec); + if (result != 0) { + WARN("Failed to obtain reference to image id=%u (%i)\n", + image_id, result); + return result; + } + + result = io_open(dev_handle, image_spec, &image_handle); + if (result != 0) { + WARN("Failed to access image id=%u (%i)\n", image_id, result); + return result; + } + + result = load_mbr_header(image_handle, &mbr_entry); + if (result != 0) { + WARN("Failed to access image id=%u (%i)\n", image_id, result); + return result; + } + if (mbr_entry.type == PARTITION_TYPE_GPT) { + result = load_gpt_header(image_handle); + assert(result == 0); + result = io_seek(image_handle, IO_SEEK_SET, GPT_ENTRY_OFFSET); + assert(result == 0); + result = verify_partition_gpt(image_handle); + } else { + /* MBR type isn't supported yet. */ + result = -EINVAL; + goto exit; + } +exit: + io_close(image_handle); + return result; +} + +const partition_entry_t *get_partition_entry(const char *name) +{ + int i; + + for (i = 0; i < list.entry_count; i++) { + if (strcmp(name, list.list[i].name) == 0) { + return &list.list[i]; + } + } + return NULL; +} + +const partition_entry_list_t *get_partition_entry_list(void) +{ + return &list; +} + +void partition_init(unsigned int image_id) +{ + load_partition_table(image_id); +} diff --git a/include/drivers/partition/gpt.h b/include/drivers/partition/gpt.h new file mode 100644 index 0000000..bd0a7f0 --- /dev/null +++ b/include/drivers/partition/gpt.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __GPT_H__ +#define __GPT_H__ + +#include + +#define PARTITION_TYPE_GPT 0xee +#define GPT_HEADER_OFFSET PARTITION_BLOCK_SIZE +#define GPT_ENTRY_OFFSET (GPT_HEADER_OFFSET + \ + PARTITION_BLOCK_SIZE) +#define GUID_LEN 16 + +#define GPT_SIGNATURE "EFI PART" + +typedef struct gpt_entry { + unsigned char type_uuid[GUID_LEN]; + unsigned char unique_uuid[GUID_LEN]; + unsigned long long first_lba; + unsigned long long last_lba; + unsigned long long attr; + unsigned short name[EFI_NAMELEN]; +} gpt_entry_t; + +typedef struct gpt_header { + unsigned char signature[8]; + unsigned int revision; + unsigned int size; + unsigned int header_crc; + unsigned int reserved; + unsigned long long current_lba; + unsigned long long backup_lba; + unsigned long long first_lba; + unsigned long long last_lba; + unsigned char disk_uuid[16]; + /* starting LBA of array of partition entries */ + unsigned long long part_lba; + /* number of partition entries in array */ + unsigned int list_num; + /* size of a single partition entry (usually 128) */ + unsigned int part_size; + unsigned int part_crc; +} gpt_header_t; + +int parse_gpt_entry(gpt_entry_t *gpt_entry, partition_entry_t *entry); + +#endif /* __GPT_H__ */ diff --git a/include/drivers/partition/mbr.h b/include/drivers/partition/mbr.h new file mode 100644 index 0000000..5287e28 --- /dev/null +++ b/include/drivers/partition/mbr.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MBR_H__ +#define __MBR_H__ + +#define MBR_OFFSET 0 + +#define MBR_PRIMARY_ENTRY_OFFSET 0x1be +#define MBR_PRIMARY_ENTRY_SIZE 0x10 +#define MBR_PRIMARY_ENTRY_NUMBER 4 +#define MBR_CHS_ADDRESS_LEN 3 + +#define MBR_SIGNATURE_FIRST 0x55 +#define MBR_SIGNATURE_SECOND 0xAA + +typedef struct mbr_entry { + unsigned char status; + unsigned char first_sector[MBR_CHS_ADDRESS_LEN]; + unsigned char type; + unsigned char last_sector[MBR_CHS_ADDRESS_LEN]; + unsigned int first_lba; + unsigned int sector_nums; +} mbr_entry_t; + +#endif /* __MBR_H__ */ diff --git a/include/drivers/partition/partition.h b/include/drivers/partition/partition.h new file mode 100644 index 0000000..9d7221d --- /dev/null +++ b/include/drivers/partition/partition.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __PARTITION_H__ +#define __PARTITION_H__ + +#include +#include + +#if !PLAT_PARTITION_MAX_ENTRIES +# define PLAT_PARTITION_MAX_ENTRIES 128 +#endif /* PLAT_PARTITION_MAX_ENTRIES */ + +CASSERT(PLAT_PARTITION_MAX_ENTRIES <= 128, assert_plat_partition_max_entries); + +#define PARTITION_BLOCK_SIZE 512 + +#define EFI_NAMELEN 36 + +typedef struct partition_entry { + uint64_t start; + uint64_t length; + char name[EFI_NAMELEN]; +} partition_entry_t; + +typedef struct partition_entry_list { + partition_entry_t list[PLAT_PARTITION_MAX_ENTRIES]; + int entry_count; +} partition_entry_list_t; + +int load_partition_table(unsigned int image_id); +const partition_entry_t *get_partition_entry(const char *name); +const partition_entry_list_t *get_partition_entry_list(void); +void partition_init(unsigned int image_id); + +#endif /* __PARTITION_H__ */