[uboot] create uboot from github:
repo: https://github.com/u-boot/u-boot commit: d80bb749fab53da72c4a0e09b8c2d2aaa3103c91 Change-Id: Ie6434426e1ec15bc08bb1832798e371f3fd5fb29
This commit is contained in:
236
u-boot-2021.10/lib/efi_loader/efi_load_initrd.c
Normal file
236
u-boot-2021.10/lib/efi_loader/efi_load_initrd.c
Normal file
@ -0,0 +1,236 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2020, Linaro Limited
|
||||
*/
|
||||
|
||||
#define LOG_CATEGORY LOGC_EFI
|
||||
#include <common.h>
|
||||
#include <efi_loader.h>
|
||||
#include <efi_load_initrd.h>
|
||||
#include <efi_variable.h>
|
||||
#include <fs.h>
|
||||
#include <malloc.h>
|
||||
#include <mapmem.h>
|
||||
|
||||
static efi_status_t EFIAPI
|
||||
efi_load_file2_initrd(struct efi_load_file_protocol *this,
|
||||
struct efi_device_path *file_path, bool boot_policy,
|
||||
efi_uintn_t *buffer_size, void *buffer);
|
||||
|
||||
static const struct efi_load_file_protocol efi_lf2_protocol = {
|
||||
.load_file = efi_load_file2_initrd,
|
||||
};
|
||||
|
||||
/*
|
||||
* Device path defined by Linux to identify the handle providing the
|
||||
* EFI_LOAD_FILE2_PROTOCOL used for loading the initial ramdisk.
|
||||
*/
|
||||
static const struct efi_initrd_dp dp_lf2_handle = {
|
||||
.vendor = {
|
||||
{
|
||||
DEVICE_PATH_TYPE_MEDIA_DEVICE,
|
||||
DEVICE_PATH_SUB_TYPE_VENDOR_PATH,
|
||||
sizeof(dp_lf2_handle.vendor),
|
||||
},
|
||||
EFI_INITRD_MEDIA_GUID,
|
||||
},
|
||||
.end = {
|
||||
DEVICE_PATH_TYPE_END,
|
||||
DEVICE_PATH_SUB_TYPE_END,
|
||||
sizeof(dp_lf2_handle.end),
|
||||
}
|
||||
};
|
||||
|
||||
static efi_handle_t efi_initrd_handle;
|
||||
|
||||
/**
|
||||
* get_initrd_fp() - Get initrd device path from a FilePathList device path
|
||||
*
|
||||
* @initrd_fp: the final initrd filepath
|
||||
*
|
||||
* Return: status code. Caller must free initrd_fp
|
||||
*/
|
||||
static efi_status_t get_initrd_fp(struct efi_device_path **initrd_fp)
|
||||
{
|
||||
const efi_guid_t lf2_initrd_guid = EFI_INITRD_MEDIA_GUID;
|
||||
struct efi_device_path *dp = NULL;
|
||||
|
||||
/*
|
||||
* if bootmgr is setup with and initrd, the device path will be
|
||||
* in the FilePathList[] of our load options in Boot####.
|
||||
* The first device path of the multi instance device path will
|
||||
* start with a VenMedia and the initrds will follow.
|
||||
*
|
||||
* If the device path is not found return EFI_INVALID_PARAMETER.
|
||||
* We can then use this specific return value and not install the
|
||||
* protocol, while allowing the boot to continue
|
||||
*/
|
||||
dp = efi_get_dp_from_boot(lf2_initrd_guid);
|
||||
if (!dp)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
|
||||
*initrd_fp = dp;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_load_file2_initrd() - load initial RAM disk
|
||||
*
|
||||
* This function implements the LoadFile service of the EFI_LOAD_FILE2_PROTOCOL
|
||||
* in order to load an initial RAM disk requested by the Linux kernel stub.
|
||||
*
|
||||
* See the UEFI spec for details.
|
||||
*
|
||||
* @this: EFI_LOAD_FILE2_PROTOCOL instance
|
||||
* @file_path: media device path of the file, "" in this case
|
||||
* @boot_policy: must be false
|
||||
* @buffer_size: size of allocated buffer
|
||||
* @buffer: buffer to load the file
|
||||
*
|
||||
* Return: status code
|
||||
*/
|
||||
static efi_status_t EFIAPI
|
||||
efi_load_file2_initrd(struct efi_load_file_protocol *this,
|
||||
struct efi_device_path *file_path, bool boot_policy,
|
||||
efi_uintn_t *buffer_size, void *buffer)
|
||||
{
|
||||
struct efi_device_path *initrd_fp = NULL;
|
||||
efi_status_t ret = EFI_NOT_FOUND;
|
||||
struct efi_file_handle *f = NULL;
|
||||
efi_uintn_t bs;
|
||||
|
||||
EFI_ENTRY("%p, %p, %d, %p, %p", this, file_path, boot_policy,
|
||||
buffer_size, buffer);
|
||||
|
||||
if (!this || this != &efi_lf2_protocol ||
|
||||
!buffer_size) {
|
||||
ret = EFI_INVALID_PARAMETER;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (file_path->type != dp_lf2_handle.end.type ||
|
||||
file_path->sub_type != dp_lf2_handle.end.sub_type) {
|
||||
ret = EFI_INVALID_PARAMETER;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (boot_policy) {
|
||||
ret = EFI_UNSUPPORTED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = get_initrd_fp(&initrd_fp);
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto out;
|
||||
|
||||
/* Open file */
|
||||
f = efi_file_from_path(initrd_fp);
|
||||
if (!f) {
|
||||
log_err("Can't find initrd specified in Boot####\n");
|
||||
ret = EFI_NOT_FOUND;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Get file size */
|
||||
ret = efi_file_size(f, &bs);
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto out;
|
||||
|
||||
if (!buffer || *buffer_size < bs) {
|
||||
ret = EFI_BUFFER_TOO_SMALL;
|
||||
*buffer_size = bs;
|
||||
} else {
|
||||
ret = EFI_CALL(f->read(f, &bs, (void *)(uintptr_t)buffer));
|
||||
*buffer_size = bs;
|
||||
}
|
||||
|
||||
out:
|
||||
efi_free_pool(initrd_fp);
|
||||
if (f)
|
||||
EFI_CALL(f->close(f));
|
||||
return EFI_EXIT(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* check_initrd() - Determine if the file defined as an initrd in Boot####
|
||||
* load_options device path is present
|
||||
*
|
||||
* Return: status code
|
||||
*/
|
||||
static efi_status_t check_initrd(void)
|
||||
{
|
||||
struct efi_device_path *initrd_fp = NULL;
|
||||
struct efi_file_handle *f;
|
||||
efi_status_t ret;
|
||||
|
||||
ret = get_initrd_fp(&initrd_fp);
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* If the file is not found, but the file path is set, return an error
|
||||
* and trigger the bootmgr fallback
|
||||
*/
|
||||
f = efi_file_from_path(initrd_fp);
|
||||
if (!f) {
|
||||
log_err("Can't find initrd specified in Boot####\n");
|
||||
ret = EFI_NOT_FOUND;
|
||||
goto out;
|
||||
}
|
||||
|
||||
EFI_CALL(f->close(f));
|
||||
|
||||
out:
|
||||
efi_free_pool(initrd_fp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_initrd_register() - create handle for loading initial RAM disk
|
||||
*
|
||||
* This function creates a new handle and installs a Linux specific vendor
|
||||
* device path and an EFI_LOAD_FILE2_PROTOCOL. Linux uses the device path
|
||||
* to identify the handle and then calls the LoadFile service of the
|
||||
* EFI_LOAD_FILE2_PROTOCOL to read the initial RAM disk.
|
||||
*
|
||||
* Return: status code
|
||||
*/
|
||||
efi_status_t efi_initrd_register(void)
|
||||
{
|
||||
efi_status_t ret;
|
||||
|
||||
/*
|
||||
* Allow the user to continue if Boot#### file path is not set for
|
||||
* an initrd
|
||||
*/
|
||||
ret = check_initrd();
|
||||
if (ret == EFI_INVALID_PARAMETER)
|
||||
return EFI_SUCCESS;
|
||||
if (ret != EFI_SUCCESS)
|
||||
return ret;
|
||||
|
||||
ret = EFI_CALL(efi_install_multiple_protocol_interfaces
|
||||
(&efi_initrd_handle,
|
||||
/* initramfs */
|
||||
&efi_guid_device_path, &dp_lf2_handle,
|
||||
/* LOAD_FILE2 */
|
||||
&efi_guid_load_file2_protocol,
|
||||
(void *)&efi_lf2_protocol,
|
||||
NULL));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_initrd_deregister() - delete the handle for loading initial RAM disk
|
||||
*
|
||||
* This will delete the handle containing the Linux specific vendor device
|
||||
* path and EFI_LOAD_FILE2_PROTOCOL for loading an initrd
|
||||
*
|
||||
* Return: status code
|
||||
*/
|
||||
void efi_initrd_deregister(void)
|
||||
{
|
||||
efi_delete_handle(efi_initrd_handle);
|
||||
efi_initrd_handle = NULL;
|
||||
}
|
||||
Reference in New Issue
Block a user