blob: 790cb13065bfe3d88d7ee8283f95542e5c0bd711 [file] [edit]
// Copyright 2024 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gbl_efi_fastboot_protocol.h"
#include <zircon/assert.h>
#include <functional>
#include <span>
#include <string_view>
#include <phys/efi/main.h>
#include "utils.h"
#define GBL_EFI_FASTBOOT_PROTOCOL_GUID \
{0xc67e48a0, 0x5eb8, 0x4127, {0xbe, 0x89, 0xdf, 0x2e, 0xd9, 0x3d, 0x8a, 0x9a}}
namespace {
// It's easier to work with `char` here so we can use `string_view`, but we need to cast between
// `EfiChar8` for the protocol APIs, so double-check that they're the same size. Signedness
// shouldn't matter since in both cases they're expected to be UTF-8.
static_assert(sizeof(char) == sizeof(EfiChar8), "Char size mismatch");
// Contains information such as variable name and value.
constexpr struct Variable {
const char* var_name;
// For now we only consider constant variable.
const char* var_impl;
/// Gets the name as a string_view.
std::string_view name() const { return std::string_view(var_name); }
/// Gets the value as a string_view.
std::string_view impl() const { return std::string_view(var_impl); }
} kVariables[] = {
{"hw-revision", BOARD_NAME},
};
/// Gets the list of variables
std::span<const Variable> variables() { return std::span<const Variable>(kVariables); }
efi_status GetVar(struct GblEfiFastbootProtocol* self, size_t num_args, const EfiChar8* const* args,
size_t* buffer_size, EfiChar8* buffer) {
const std::span<const char* const> args_span{reinterpret_cast<const char* const*>(args),
num_args};
if (args_span.empty() || !buffer_size) {
return EFI_INVALID_PARAMETER;
}
std::span<uint8_t> out{buffer, *buffer_size};
for (size_t i = 0; i < variables().size(); i++) {
const Variable& var = variables()[i];
if (std::string_view(args_span[0]) != var.name()) {
continue;
}
if (out.size() < var.impl().size() + 1) {
return EFI_BUFFER_TOO_SMALL;
}
memcpy(out.data(), var.impl().data(), var.impl().size());
*buffer_size = var.impl().size();
out.data()[*buffer_size] = 0;
return EFI_SUCCESS;
}
return EFI_NOT_FOUND;
}
efi_status GetVarAll(struct GblEfiFastbootProtocol* self, void* context, GetVarAllCallback cb) {
for (size_t i = 0; i < variables().size(); i++) {
std::array args{variables()[i].name().data()};
cb(context, args.size(), reinterpret_cast<const EfiChar8**>(args.data()),
reinterpret_cast<const EfiChar8*>(variables()[i].impl().data()));
}
return EFI_SUCCESS;
}
EfiStatus CommandExec(struct GblEfiFastbootProtocol* self, size_t num_args,
const EfiChar8* const* args, size_t download_buffer_size,
size_t download_buffer_used_size, uint8_t* download_buffer,
GblEfiFastbootCommandExecResult* implementation, FastbootMessageSender sender,
void* context) {
*implementation =
GblEfiFastbootCommandExecResult::GBL_EFI_FASTBOOT_COMMAND_EXEC_RESULT_DEFAULT_IMPL;
return EFI_SUCCESS;
}
GblEfiFastbootProtocol protocol = {
.revision = GBL_EFI_FASTBOOT_PROTOCOL_REVISION,
.get_var = GetVar,
.get_var_all = GetVarAll,
.get_staged = NULL,
.command_exec = CommandExec,
.get_partition_type = NULL,
};
efi_guid guid = GBL_EFI_FASTBOOT_PROTOCOL_GUID;
} // namespace
namespace gigaboot {
efi_status InstallGblEfiFastbootProtocol() {
efi_handle out_handle = NULL;
return gEfiSystemTable->BootServices->InstallMultipleProtocolInterfaces(&out_handle, &guid,
&protocol, NULL);
}
} // namespace gigaboot