u-boot/lib/efi_loader/efi_capsule.c
AKASHI Takahiro 2bc27ca8a0 efi_loader: define UpdateCapsule api
In this commit, skeleton functions for capsule-related API's are
added under CONFIG_EFI_UPDATE_CAPSULE configuration.
Detailed implementation for a specific capsule type will be added
in the succeeding patches.

Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
2020-12-03 21:22:49 +01:00

165 lines
4.3 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* EFI Capsule
*
* Copyright (c) 2018 Linaro Limited
* Author: AKASHI Takahiro
*/
#include <common.h>
#include <efi_loader.h>
#include <efi_variable.h>
#include <fs.h>
#include <malloc.h>
#include <sort.h>
const efi_guid_t efi_guid_capsule_report = EFI_CAPSULE_REPORT_GUID;
/**
* get_last_capsule - get the last capsule index
*
* Retrieve the index of the capsule invoked last time from "CapsuleLast"
* variable.
*
* Return:
* * > 0 - the last capsule index invoked
* * 0xffff - on error, or no capsule invoked yet
*/
static __maybe_unused unsigned int get_last_capsule(void)
{
u16 value16[11]; /* "CapsuleXXXX": non-null-terminated */
char value[11], *p;
efi_uintn_t size;
unsigned long index = 0xffff;
efi_status_t ret;
size = sizeof(value16);
ret = efi_get_variable_int(L"CapsuleLast", &efi_guid_capsule_report,
NULL, &size, value16, NULL);
if (ret != EFI_SUCCESS || u16_strncmp(value16, L"Capsule", 7))
goto err;
p = value;
utf16_utf8_strcpy(&p, value16);
strict_strtoul(&value[7], 16, &index);
err:
return index;
}
/**
* set_capsule_result - set a result variable
* @capsule: Capsule
* @return_status: Return status
*
* Create and set a result variable, "CapsuleXXXX", for the capsule,
* @capsule.
*/
static __maybe_unused
void set_capsule_result(int index, struct efi_capsule_header *capsule,
efi_status_t return_status)
{
u16 variable_name16[12];
struct efi_capsule_result_variable_header result;
struct efi_time time;
efi_status_t ret;
efi_create_indexed_name(variable_name16, "Capsule", index);
result.variable_total_size = sizeof(result);
result.capsule_guid = capsule->capsule_guid;
ret = EFI_CALL((*efi_runtime_services.get_time)(&time, NULL));
if (ret == EFI_SUCCESS)
memcpy(&result.capsule_processed, &time, sizeof(time));
else
memset(&result.capsule_processed, 0, sizeof(time));
result.capsule_status = return_status;
ret = efi_set_variable(variable_name16, &efi_guid_capsule_report,
EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS,
sizeof(result), &result);
if (ret)
printf("EFI: creating %ls failed\n", variable_name16);
}
/**
* efi_update_capsule() - process information from operating system
* @capsule_header_array: Array of virtual address pointers
* @capsule_count: Number of pointers in capsule_header_array
* @scatter_gather_list: Array of physical address pointers
*
* This function implements the UpdateCapsule() runtime service.
*
* See the Unified Extensible Firmware Interface (UEFI) specification for
* details.
*
* Return: status code
*/
efi_status_t EFIAPI efi_update_capsule(
struct efi_capsule_header **capsule_header_array,
efi_uintn_t capsule_count,
u64 scatter_gather_list)
{
struct efi_capsule_header *capsule;
unsigned int i;
efi_status_t ret;
EFI_ENTRY("%p, %lu, %llu\n", capsule_header_array, capsule_count,
scatter_gather_list);
if (!capsule_count) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
ret = EFI_UNSUPPORTED;
for (i = 0, capsule = *capsule_header_array; i < capsule_count;
i++, capsule = *(++capsule_header_array)) {
}
out:
return EFI_EXIT(ret);
}
/**
* efi_query_capsule_caps() - check if capsule is supported
* @capsule_header_array: Array of virtual pointers
* @capsule_count: Number of pointers in capsule_header_array
* @maximum_capsule_size: Maximum capsule size
* @reset_type: Type of reset needed for capsule update
*
* This function implements the QueryCapsuleCapabilities() runtime service.
*
* See the Unified Extensible Firmware Interface (UEFI) specification for
* details.
*
* Return: status code
*/
efi_status_t EFIAPI efi_query_capsule_caps(
struct efi_capsule_header **capsule_header_array,
efi_uintn_t capsule_count,
u64 *maximum_capsule_size,
u32 *reset_type)
{
struct efi_capsule_header *capsule __attribute__((unused));
unsigned int i;
efi_status_t ret;
EFI_ENTRY("%p, %lu, %p, %p\n", capsule_header_array, capsule_count,
maximum_capsule_size, reset_type);
if (!maximum_capsule_size) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
*maximum_capsule_size = U64_MAX;
*reset_type = EFI_RESET_COLD;
ret = EFI_SUCCESS;
for (i = 0, capsule = *capsule_header_array; i < capsule_count;
i++, capsule = *(++capsule_header_array)) {
/* TODO */
}
out:
return EFI_EXIT(ret);
}