blob: 7d16c9047c4c39842d1537d5780faee780c93ee1 [file] [log] [blame]
/*
* 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/physmem.h"
#include "module/uefi/fwdb.h"
#include "uefi/edk/Protocol/LoadedImage.h"
#include "uefi/edk/Protocol/SimpleFileSystem.h"
#include "uefi/uefi.h"
#include "vboot/util/memory.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;
UINTN buf_size = sizeof(file_info);
status = file->GetInfo(file, &file_info_guid,
&buf_size, &file_info);
if (status != EFI_SUCCESS) {
file->Close(file);
printf("Failed to get file size.\n");
return 1;
}
FwdbEntry entry = { .ptr = NULL, .size = file_info.FileSize };
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);
}