blob: afea594917bb0ce2ffa22d30d013d012bbb86b28 [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include "phys/efi/file.h"
#include <zircon/assert.h>
#include <efi/protocol/file.h>
#include <efi/protocol/simple-file-system.h>
#include <fbl/alloc_checker.h>
#include <ktl/string_view.h>
#include <ktl/unique_ptr.h>
#include <phys/efi/main.h>
#include <phys/efi/protocol.h>
#include <phys/symbolize.h>
#include "src/lib/utf_conversion/utf_conversion.h"
#include <ktl/enforce.h>
template <>
constexpr const efi_guid& kEfiProtocolGuid<efi_simple_file_system_protocol> =
SimpleFileSystemProtocol;
namespace {
ktl::unique_ptr<char16_t[]> ConvertUtf8ToUtf16CString(ktl::string_view utf8) {
fbl::AllocChecker ac;
ktl::unique_ptr<char16_t[]> utf16(new (&ac) char16_t[utf8.size() + 1]);
if (!ac.check()) {
return nullptr;
}
size_t len = utf8.size();
zx_status_t status = utf8_to_utf16(reinterpret_cast<const uint8_t*>(utf8.data()), utf8.size(),
reinterpret_cast<uint16_t*>(utf16.get()), &len);
if (status != ZX_OK) {
printf("%s: Error %d converting UTF8 file name \"%.*s\" to UTF16!\n", ProgramName(), status,
static_cast<int>(utf8.size()), utf8.data());
return nullptr;
}
ZX_ASSERT_MSG(len <= utf8.size(), "%zu UTF8 became %zu UTF16??", utf8.size(), len);
utf16[len] = L'\0';
return utf16;
}
} // namespace
EfiFilePtr EfiRootDir() {
if (!gEfiLoadedImage) {
printf("%s: Cannot get EFI root filesystem without LOADED_IMAGE_PROTOCOL\n", ProgramName());
return {};
}
auto fs = EfiOpenProtocol<efi_simple_file_system_protocol>(gEfiLoadedImage->DeviceHandle);
if (fs.is_error()) {
printf("%s: EFI error %#zx getting SIMPLE_FILE_SYSTEM_PROTOCOL\n", ProgramName(),
fs.error_value());
}
efi_file_protocol* root = nullptr;
efi_status status = fs->OpenVolume(fs.value().get(), &root);
if (status != EFI_SUCCESS) {
printf("%s: EFI error %#zx from OpenVolume", ProgramName(), status);
return {};
}
return EfiFilePtr(root);
}
fitx::result<efi_status, uint64_t> EfiFileSize(efi_file_protocol* file) {
union {
efi_file_info info;
char space[sizeof(efi_file_info) + sizeof(char16_t[255])];
} buffer;
size_t info_size = sizeof(buffer);
efi_status status = file->GetInfo(file, &FileInfoGuid, &info_size, &buffer);
if (status != EFI_SUCCESS) {
return fitx::error{status};
}
ZX_ASSERT(info_size >= sizeof(buffer.info));
return fitx::ok(buffer.info.FileSize);
}
fitx::result<efi_status, EfiFilePtr> EfiOpenFile(const char16_t* filename, efi_file_protocol* dir) {
efi_file_protocol* file = nullptr;
efi_status status = dir->Open(dir, &file, filename, EFI_FILE_MODE_READ, 0);
if (status != EFI_SUCCESS) {
return fitx::error{status};
}
return fitx::ok(EfiFilePtr(file));
}
fitx::result<efi_status, EfiFilePtr> EfiOpenFile(ktl::string_view filename,
efi_file_protocol* dir) {
ktl::unique_ptr<char16_t[]> utf16 = ConvertUtf8ToUtf16CString(filename);
if (!utf16) {
return fitx::error{EFI_OUT_OF_RESOURCES};
}
return EfiOpenFile(utf16.get(), dir);
}