/* * Copyright (c) 2006-2014, Intel Corporation. All rights reserved. * Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include #include #define ALIGN_UP(x, a) ((x + (a - 1)) & ~(a - 1)) static void *_create_hob(struct efi_hob_handoff_info_table *hob_table, uint16_t hob_type, uint16_t hob_length) { size_t free_mem_size; struct efi_hob_generic_header *new_hob; struct efi_hob_generic_header *hob_end; if ((hob_table == NULL) || (hob_length == 0)) { return NULL; } hob_length = ALIGN_UP(hob_length, 8); free_mem_size = hob_table->efi_free_memory_top - hob_table->efi_free_memory_bottom; /** * hob_length already including sizeof(efi_hob_generic_header). * See the each export interface create_xxx_hob. */ if ((size_t) hob_length > free_mem_size) { return NULL; } new_hob = (struct efi_hob_generic_header *) hob_table->efi_end_of_hob_list; new_hob->hob_type = hob_type; new_hob->hob_length = hob_length; new_hob->reserved = 0x00; hob_end = (struct efi_hob_generic_header *) (hob_table->efi_end_of_hob_list + hob_length); hob_end->hob_type = EFI_HOB_TYPE_END_OF_HOB_LIST; hob_end->hob_length = sizeof(struct efi_hob_generic_header); hob_end->reserved = 0x00; hob_table->efi_end_of_hob_list = (efi_physical_address_t) hob_end; hob_table->efi_free_memory_bottom = (efi_physical_address_t) (hob_end + 1); return new_hob; } /* * Create PHIT HOB list. * * On success, return the address PHIT HOB list * On error, return NULL. * * efi_memory_begin * Base address for partition. * efi_memory_length * Size of memory for patition. * efi_free_memory_bottom * Base address PHIT HOB list can be allocated * efi_free_memory_length. * Maximum size of PHIT HOB list can have */ struct efi_hob_handoff_info_table *create_hob_list( efi_physical_address_t efi_memory_begin, size_t efi_memory_length, efi_physical_address_t efi_free_memory_bottom, size_t efi_free_memory_length) { struct efi_hob_handoff_info_table *hob_table; struct efi_hob_generic_header *hob_end; if ((efi_memory_begin == 0) || (efi_free_memory_bottom == 0) || (efi_memory_length == 0) || (efi_free_memory_length == 0)) { return NULL; } hob_table = (struct efi_hob_handoff_info_table *) efi_free_memory_bottom; hob_end = (struct efi_hob_generic_header *) (hob_table + 1); hob_table->header.hob_type = EFI_HOB_TYPE_HANDOFF; hob_table->header.hob_length = sizeof(struct efi_hob_handoff_info_table); hob_table->header.reserved = 0; hob_end->hob_type = EFI_HOB_TYPE_END_OF_HOB_LIST; hob_end->hob_length = sizeof(struct efi_hob_generic_header); hob_end->reserved = 0; hob_table->version = EFI_HOB_HANDOFF_TABLE_VERSION; hob_table->boot_mode = EFI_BOOT_WITH_FULL_CONFIGURATION; hob_table->efi_memory_top = efi_memory_begin + efi_memory_length; hob_table->efi_memory_bottom = efi_memory_begin; hob_table->efi_free_memory_top = efi_memory_begin + efi_free_memory_length; hob_table->efi_free_memory_bottom = (efi_physical_address_t) (hob_end + 1); hob_table->efi_end_of_hob_list = (efi_physical_address_t) hob_end; return hob_table; } /* * Create resource description HOB in PHIT HOB list. * * On success, return 0. * On error, return error code. * * hob_table * Address of PHIT HOB list * resource_type * Resource type see EFI_RESOURCE_* in the include/lib/hob/efi_types.h * resource_attribute * Resource attribute see EFI_RESOURCE_ATTRIBUTES_* * in the include/lib/hob/efi_types.h * phy_addr_start * Physical base address of resource * resource_length * Size of resource */ int create_resource_descriptor_hob( struct efi_hob_handoff_info_table *hob_table, efi_resource_type_t resource_type, efi_resource_attribute_type_t resource_attribute, efi_physical_address_t phy_addr_start, uint64_t resource_length) { struct efi_hob_resource_descriptor *rd_hop; rd_hop = _create_hob(hob_table, EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, sizeof(struct efi_hob_resource_descriptor)); if (rd_hop == NULL) { ERROR("No space for creating resource descriptor type hob...\n"); return -ENOMEM; } rd_hop->resource_type = resource_type; rd_hop->resource_attribute = resource_attribute; rd_hop->physical_start = phy_addr_start; rd_hop->resource_length = resource_length; memset(&rd_hop->owner, 0, sizeof(struct efi_guid)); return 0; } /* * Create GUID HOB in PHIT HOB list. * * On success, return 0. * On error, return error code. * * hob_table * Address of PHIT HOB list * guid * guid. * data length * Size of data * data * Data */ int create_guid_hob(struct efi_hob_handoff_info_table *hob_table, struct efi_guid *guid, uint16_t data_length, void **data) { struct efi_hob_guid_type *guid_hob; uint16_t hob_length; hob_length = data_length + sizeof(struct efi_hob_guid_type); if ((guid == NULL) || (data == NULL) || (hob_length < data_length)) { return -EINVAL; } guid_hob = _create_hob(hob_table, EFI_HOB_TYPE_GUID_EXTENSION, hob_length); if (guid_hob == NULL) { ERROR("No space for creating guid type hob...\n"); return -ENOMEM; } memcpy(&guid_hob->name, guid, sizeof(struct efi_guid)); *data = (void *) (guid_hob + 1); return 0; } /* * Create Firmware Volume HOB in PHIT HOB list. * * On success, return 0. * On error, return error code. * * hob_table * Address of PHIT HOB list * base_addr * Base address of firmware volume * size * Size of Firmware Volume */ int create_fv_hob(struct efi_hob_handoff_info_table *hob_table, efi_physical_address_t base_addr, uint64_t size) { struct efi_hob_firmware_volume *fv_hob; fv_hob = _create_hob(hob_table, EFI_HOB_TYPE_FV, sizeof(struct efi_hob_firmware_volume)); if (fv_hob == NULL) { ERROR("No space for creating fv type hob...\n"); return -ENOMEM; } fv_hob->base_address = base_addr; fv_hob->length = size; return 0; }