| /* |
| * Copyright 2016 Google Inc. |
| * |
| * See file CREDITS for list of people who contributed to this |
| * project. |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License as |
| * published by the Free Software Foundation; either version 2 of |
| * the License, or (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
| * MA 02111-1307 USA |
| */ |
| |
| #include <inttypes.h> |
| #include <stdio.h> |
| |
| #include "base/xalloc.h" |
| #include "base/fwdb.h" |
| #include "base/memory.h" |
| #include "module/uefi/fwdb.h" |
| #include "uefi/edk/Protocol/LoadedImage.h" |
| #include "uefi/edk/Protocol/SimpleFileSystem.h" |
| #include "uefi/uefi.h" |
| |
| |
| |
| extern uint8_t _binary_ro_image_start; |
| extern uint8_t _binary_ro_image_size; |
| extern uint8_t ImageBase; |
| |
| |
| |
| static EFI_GUID file_info_guid = EFI_FILE_INFO_ID; |
| static EFI_GUID loaded_image_protocol_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID; |
| static EFI_GUID simple_fs_protocol_guid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; |
| |
| |
| |
| static int insert_file_into_fwdb(EFI_FILE_PROTOCOL *root, CHAR16 *file_name, |
| const char *name) |
| { |
| EFI_FILE_PROTOCOL *file; |
| EFI_STATUS status = root->Open(root, &file, file_name, |
| EFI_FILE_MODE_READ, 0); |
| if (status != EFI_SUCCESS) { |
| printf("Failed to open file.\n"); |
| return 1; |
| } |
| |
| EFI_FILE_INFO *file_info = xmalloc(sizeof(*file_info)); |
| UINTN buf_size = sizeof(*file_info); |
| status = file->GetInfo(file, &file_info_guid, |
| &buf_size, file_info); |
| if (status == EFI_BUFFER_TOO_SMALL) { |
| free(file_info); |
| file_info = xmalloc(buf_size); |
| status = file->GetInfo(file, &file_info_guid, |
| &buf_size, file_info); |
| } |
| if (status != EFI_SUCCESS) { |
| file->Close(file); |
| free(file_info); |
| printf("Failed to get file size.\n"); |
| return 1; |
| } |
| |
| FwdbEntry entry = { .ptr = NULL, .size = file_info->FileSize }; |
| free(file_info); |
| file_info = NULL; |
| if (fwdb_access(name, NULL, &entry) || |
| fwdb_access(name, &entry, NULL)) { |
| file->Close(file); |
| return 1; |
| } |
| |
| buf_size = entry.size; |
| status = file->Read(file, &buf_size, entry.ptr); |
| if (status != EFI_SUCCESS) { |
| file->Close(file); |
| printf("Failed to read file.\n"); |
| return 1; |
| } |
| |
| file->Close(file); |
| return 0; |
| } |
| |
| int uefi_prepare_fwdb_vboot_ro(void) |
| { |
| FwdbEntry ro_image_entry = { |
| .ptr = &_binary_ro_image_start, |
| .size = &_binary_ro_image_size - &ImageBase, |
| }; |
| return fwdb_access("uefi_ro_image", NULL, &ro_image_entry); |
| } |
| |
| int uefi_prepare_fwdb_file(CHAR16 *file_name, const char *fwdb_name) |
| { |
| EFI_SYSTEM_TABLE *st = uefi_system_table_ptr(); |
| if (!st) |
| return 1; |
| EFI_BOOT_SERVICES *bs = st->BootServices; |
| |
| EFI_HANDLE handle; |
| if (uefi_image_handle(&handle)) |
| return 1; |
| |
| EFI_LOADED_IMAGE_PROTOCOL *loaded_image; |
| EFI_STATUS status = |
| bs->HandleProtocol(handle, &loaded_image_protocol_guid, |
| (void **)&loaded_image); |
| if (status != EFI_SUCCESS) { |
| printf("Failed to open loaded image protocol.\n"); |
| return 1; |
| } |
| |
| EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *simple_fs; |
| status = bs->HandleProtocol(loaded_image->DeviceHandle, |
| &simple_fs_protocol_guid, |
| (void **)&simple_fs); |
| if (status != EFI_SUCCESS) { |
| printf("Failed to open simple fs protocol.\n"); |
| return 1; |
| } |
| |
| EFI_FILE_PROTOCOL *root; |
| status = simple_fs->OpenVolume(simple_fs, &root); |
| if (status != EFI_SUCCESS) { |
| printf("Failed to open simple fs root.\n"); |
| return 1; |
| } |
| |
| int ret = insert_file_into_fwdb(root, file_name, fwdb_name); |
| |
| status = root->Close(root); |
| if (status != EFI_SUCCESS) { |
| printf("Failed to close fs root.\n"); |
| return 1; |
| } |
| |
| return ret; |
| } |
| |
| |
| int uefi_prepare_fwdb_e820_map(void) |
| { |
| if (prepare_e820_mem_ranges()) |
| return 1; |
| |
| E820MemRanges *e820 = get_e820_mem_ranges(); |
| if (!e820) |
| return 1; |
| |
| unsigned size = 0; |
| EFI_MEMORY_DESCRIPTOR *map; |
| unsigned desc_size; |
| uint32_t desc_ver; |
| |
| if (uefi_get_memory_map(&size, &map, &desc_size, &desc_ver)) |
| return 1; |
| |
| if (desc_size < sizeof(EFI_MEMORY_DESCRIPTOR)) { |
| printf("Descriptor size is too small?\n"); |
| free(map); |
| return 1; |
| } |
| |
| int num_descs = size / desc_size; |
| int num_ranges = 0; |
| for (int i = 0; i < num_descs; i++) { |
| EFI_MEMORY_DESCRIPTOR *desc = |
| (void *)((uint8_t *)map + i * desc_size); |
| |
| if (desc->NumberOfPages == 0) |
| continue; |
| |
| if (num_ranges >= ARRAY_SIZE(e820->ranges)) { |
| printf("Too many memory ranges to fit in the " |
| "FWDB map.\n"); |
| free(map); |
| return 1; |
| } |
| E820MemRange *range = &e820->ranges[num_ranges]; |
| |
| range->base = desc->PhysicalStart; |
| range->size = desc->NumberOfPages * 4 * 1024; |
| |
| num_ranges++; |
| |
| switch (desc->Type) { |
| case EfiLoaderCode: |
| case EfiLoaderData: |
| case EfiBootServicesCode: |
| case EfiBootServicesData: |
| memory_mark_used(range->base, |
| range->base + range->size); |
| case EfiConventionalMemory: |
| range->type = E820MemRange_Ram; |
| break; |
| case EfiReservedMemoryType: |
| case EfiRuntimeServicesCode: |
| case EfiRuntimeServicesData: |
| case EfiPalCode: |
| case EfiACPIMemoryNVS: |
| range->type = E820MemRange_Reserved; |
| break; |
| case EfiACPIReclaimMemory: |
| range->type = E820MemRange_Acpi; |
| break; |
| case EfiPersistentMemory: |
| range->type = E820MemRange_Nvs; |
| break; |
| case EfiUnusableMemory: |
| range->type = E820MemRange_Unusable; |
| break; |
| default: |
| printf("Warning: Memory range of type %#"PRIx32" " |
| "marked as reserved.\n", desc->Type); |
| range->type = E820MemRange_Reserved; |
| } |
| |
| range->handoff_tag = desc->Type; |
| } |
| |
| e820->num_ranges = num_ranges; |
| free(map); |
| return 0; |
| } |
| |
| int uefi_prepare_fwdb_acpi_rsdp(void) |
| { |
| uintptr_t rsdp_addr; |
| |
| if (uefi_get_acpi_rsdp_addr(&rsdp_addr)) |
| return 1; |
| |
| FwdbEntry acpi_rsdp_entry = { |
| .ptr = &rsdp_addr, |
| .size = sizeof(rsdp_addr) |
| }; |
| return fwdb_access("acpi.rsdp_addr", NULL, &acpi_rsdp_entry); |
| } |