[PATCH 1/1] efi_loader: implement non-blocking file services
Michal Simek
monstr at monstr.eu
Fri Apr 30 12:09:37 CEST 2021
Hi Heinrich,
pá 1. 1. 2021 v 19:29 odesílatel Heinrich Schuchardt
<xypron.glpk at gmx.de> napsal:
>
> Implement services OpenEx(), ReadEx(), WriteEx(), FlushEx() of the
> EFI_FILE_PROTOCOL.
>
> Signed-off-by: Heinrich Schuchardt <xypron.glpk at gmx.de>
> ---
> include/efi_api.h | 28 ++--
> lib/efi_loader/efi_file.c | 317 ++++++++++++++++++++++++++++++++------
> 2 files changed, 280 insertions(+), 65 deletions(-)
>
> diff --git a/include/efi_api.h b/include/efi_api.h
> index ecb43a0607..2b54ee02a2 100644
> --- a/include/efi_api.h
> +++ b/include/efi_api.h
> @@ -1589,35 +1589,35 @@ struct efi_file_io_token {
>
> struct efi_file_handle {
> u64 rev;
> - efi_status_t (EFIAPI *open)(struct efi_file_handle *file,
> + efi_status_t (EFIAPI *open)(struct efi_file_handle *this,
> struct efi_file_handle **new_handle,
> u16 *file_name, u64 open_mode, u64 attributes);
> - efi_status_t (EFIAPI *close)(struct efi_file_handle *file);
> - efi_status_t (EFIAPI *delete)(struct efi_file_handle *file);
> - efi_status_t (EFIAPI *read)(struct efi_file_handle *file,
> + efi_status_t (EFIAPI *close)(struct efi_file_handle *this);
> + efi_status_t (EFIAPI *delete)(struct efi_file_handle *this);
> + efi_status_t (EFIAPI *read)(struct efi_file_handle *this,
> efi_uintn_t *buffer_size, void *buffer);
> - efi_status_t (EFIAPI *write)(struct efi_file_handle *file,
> + efi_status_t (EFIAPI *write)(struct efi_file_handle *this,
> efi_uintn_t *buffer_size, void *buffer);
> - efi_status_t (EFIAPI *getpos)(struct efi_file_handle *file,
> + efi_status_t (EFIAPI *getpos)(struct efi_file_handle *this,
> u64 *pos);
> - efi_status_t (EFIAPI *setpos)(struct efi_file_handle *file,
> + efi_status_t (EFIAPI *setpos)(struct efi_file_handle *this,
> u64 pos);
> - efi_status_t (EFIAPI *getinfo)(struct efi_file_handle *file,
> + efi_status_t (EFIAPI *getinfo)(struct efi_file_handle *this,
> const efi_guid_t *info_type, efi_uintn_t *buffer_size,
> void *buffer);
> - efi_status_t (EFIAPI *setinfo)(struct efi_file_handle *file,
> + efi_status_t (EFIAPI *setinfo)(struct efi_file_handle *this,
> const efi_guid_t *info_type, efi_uintn_t buffer_size,
> void *buffer);
> - efi_status_t (EFIAPI *flush)(struct efi_file_handle *file);
> - efi_status_t (EFIAPI *open_ex)(struct efi_file_handle *file,
> + efi_status_t (EFIAPI *flush)(struct efi_file_handle *this);
> + efi_status_t (EFIAPI *open_ex)(struct efi_file_handle *this,
> struct efi_file_handle **new_handle,
> u16 *file_name, u64 open_mode, u64 attributes,
> struct efi_file_io_token *token);
> - efi_status_t (EFIAPI *read_ex)(struct efi_file_handle *file,
> + efi_status_t (EFIAPI *read_ex)(struct efi_file_handle *this,
> struct efi_file_io_token *token);
> - efi_status_t (EFIAPI *write_ex)(struct efi_file_handle *file,
> + efi_status_t (EFIAPI *write_ex)(struct efi_file_handle *this,
> struct efi_file_io_token *token);
> - efi_status_t (EFIAPI *flush_ex)(struct efi_file_handle *file,
> + efi_status_t (EFIAPI *flush_ex)(struct efi_file_handle *this,
> struct efi_file_io_token *token);
> };
>
> diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c
> index 72b7ec1e63..8ece8e71ee 100644
> --- a/lib/efi_loader/efi_file.c
> +++ b/lib/efi_loader/efi_file.c
> @@ -246,18 +246,16 @@ error:
> return NULL;
> }
>
> -static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *file,
> - struct efi_file_handle **new_handle,
> - u16 *file_name, u64 open_mode, u64 attributes)
> +static efi_status_t efi_file_open_int(struct efi_file_handle *this,
> + struct efi_file_handle **new_handle,
> + u16 *file_name, u64 open_mode,
> + u64 attributes)
> {
> - struct file_handle *fh = to_fh(file);
> + struct file_handle *fh = to_fh(this);
> efi_status_t ret;
>
> - EFI_ENTRY("%p, %p, \"%ls\", %llx, %llu", file, new_handle,
> - file_name, open_mode, attributes);
> -
> /* Check parameters */
> - if (!file || !new_handle || !file_name) {
> + if (!this || !new_handle || !file_name) {
> ret = EFI_INVALID_PARAMETER;
> goto out;
> }
> @@ -291,6 +289,75 @@ static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *file,
> } else {
> ret = EFI_NOT_FOUND;
> }
> +out:
> + return ret;
> +}
> +
> +/**
> + * efi_file_open_()
> + *
> + * This function implements the Open service of the File Protocol.
> + * See the UEFI spec for details.
> + *
> + * @this: EFI_FILE_PROTOCOL instance
> + * @new_handle: on return pointer to file handle
> + * @file_name: file name
> + * @open_mode: mode to open the file (read, read/write, create/read/write)
> + * @attributes: attributes for newly created file
> + */
> +static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *this,
> + struct efi_file_handle **new_handle,
> + u16 *file_name, u64 open_mode,
> + u64 attributes)
> +{
> + efi_status_t ret;
> +
> + EFI_ENTRY("%p, %p, \"%ls\", %llx, %llu", this, new_handle,
> + file_name, open_mode, attributes);
> +
> + ret = efi_file_open_int(this, new_handle, file_name, open_mode,
> + attributes);
> +
> + return EFI_EXIT(ret);
> +}
> +
> +/**
> + * efi_file_open_ex() - open file asynchronously
> + *
> + * This function implements the OpenEx service of the File Protocol.
> + * See the UEFI spec for details.
> + *
> + * @this: EFI_FILE_PROTOCOL instance
> + * @new_handle: on return pointer to file handle
> + * @file_name: file name
> + * @open_mode: mode to open the file (read, read/write, create/read/write)
> + * @attributes: attributes for newly created file
> + * @token: transaction token
> + */
> +static efi_status_t EFIAPI efi_file_open_ex(struct efi_file_handle *this,
> + struct efi_file_handle **new_handle,
> + u16 *file_name, u64 open_mode,
> + u64 attributes,
> + struct efi_file_io_token *token)
> +{
> + efi_status_t ret;
> +
> + EFI_ENTRY("%p, %p, \"%ls\", %llx, %llu, %p", this, new_handle,
> + file_name, open_mode, attributes, token);
> +
> + if (!token) {
> + ret = EFI_INVALID_PARAMETER;
> + goto out;
> + }
> +
> + ret = efi_file_open_int(this, new_handle, file_name, open_mode,
> + attributes);
> +
> + if (ret == EFI_SUCCESS && token->event) {
> + token->status = EFI_SUCCESS;
> + efi_signal_event(token->event);
> + }
> +
> out:
> return EFI_EXIT(ret);
> }
> @@ -441,19 +508,15 @@ static efi_status_t dir_read(struct file_handle *fh, u64 *buffer_size,
> return EFI_SUCCESS;
> }
>
> -static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *file,
> - efi_uintn_t *buffer_size, void *buffer)
> +static efi_status_t efi_file_read_int(struct efi_file_handle *this,
> + efi_uintn_t *buffer_size, void *buffer)
> {
> - struct file_handle *fh = to_fh(file);
> + struct file_handle *fh = to_fh(this);
> efi_status_t ret = EFI_SUCCESS;
> u64 bs;
>
> - EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer);
> -
> - if (!buffer_size) {
> - ret = EFI_INVALID_PARAMETER;
> - goto error;
> - }
> + if (!this || !buffer_size || !buffer)
> + return EFI_INVALID_PARAMETER;
>
> bs = *buffer_size;
> if (fh->isdir)
> @@ -465,34 +528,77 @@ static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *file,
> else
> *buffer_size = SIZE_MAX;
>
> -error:
> + return ret;
> +}
> +
> +/**
> + * efi_file_read() - read file
> + *
> + * This function implements the Read() service of the EFI_FILE_PROTOCOL.
> + *
> + * See the Unified Extensible Firmware Interface (UEFI) specification for
> + * details.
> + *
> + * @this: file protocol instance
> + * @buffer_size: number of bytes to read
> + * @buffer: read buffer
> + * Return: status code
> + */
> +static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *this,
> + efi_uintn_t *buffer_size, void *buffer)
> +{
> + efi_status_t ret;
> +
> + EFI_ENTRY("%p, %p, %p", this, buffer_size, buffer);
> +
> + ret = efi_file_read_int(this, buffer_size, buffer);
> +
> return EFI_EXIT(ret);
> }
>
> /**
> - * efi_file_write() - write to file
> + * efi_file_read_ex() - read file asynchonously
> *
> - * This function implements the Write() service of the EFI_FILE_PROTOCOL.
> + * This function implements the ReadEx() service of the EFI_FILE_PROTOCOL.
> *
> * See the Unified Extensible Firmware Interface (UEFI) specification for
> * details.
> *
> - * @file: file handle
> - * @buffer_size: number of bytes to write
> - * @buffer: buffer with the bytes to write
> + * @this: file protocol instance
> + * @token: transaction token
> * Return: status code
> */
> -static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *file,
> - efi_uintn_t *buffer_size,
> - void *buffer)
> +static efi_status_t EFIAPI efi_file_read_ex(struct efi_file_handle *this,
> + struct efi_file_io_token *token)
> {
> - struct file_handle *fh = to_fh(file);
> + efi_status_t ret;
> +
> + EFI_ENTRY("%p, %p", this, token);
> +
> + if (!token) {
> + ret = EFI_INVALID_PARAMETER;
> + goto out;
> + }
> +
> + ret = efi_file_read_int(this, &token->buffer_size, token->buffer);
> +
> + if (ret == EFI_SUCCESS && token->event) {
> + token->status = EFI_SUCCESS;
> + efi_signal_event(token->event);
> + }
> +
> +out:
> + return EFI_EXIT(ret);
> +}
> +
> +static efi_status_t efi_file_write_int(struct efi_file_handle *this,
> + efi_uintn_t *buffer_size, void *buffer)
> +{
> + struct file_handle *fh = to_fh(this);
> efi_status_t ret = EFI_SUCCESS;
> loff_t actwrite;
>
> - EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer);
> -
> - if (!file || !buffer_size || !buffer) {
> + if (!this || !buffer_size || !buffer) {
> ret = EFI_INVALID_PARAMETER;
> goto out;
> }
> @@ -520,6 +626,67 @@ static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *file,
> *buffer_size = actwrite;
> fh->offset += actwrite;
>
> +out:
> + return ret;
> +}
> +
> +/**
> + * efi_file_write() - write to file
> + *
> + * This function implements the Write() service of the EFI_FILE_PROTOCOL.
> + *
> + * See the Unified Extensible Firmware Interface (UEFI) specification for
> + * details.
> + *
> + * @this: file protocol instance
> + * @buffer_size: number of bytes to write
> + * @buffer: buffer with the bytes to write
> + * Return: status code
> + */
> +static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *this,
> + efi_uintn_t *buffer_size,
> + void *buffer)
> +{
> + efi_status_t ret;
> +
> + EFI_ENTRY("%p, %p, %p", this, buffer_size, buffer);
> +
> + ret = efi_file_write_int(this, buffer_size, buffer);
> +
> + return EFI_EXIT(ret);
> +}
> +
> +/**
> + * efi_file_write_ex() - write to file
> + *
> + * This function implements the WriteEx() service of the EFI_FILE_PROTOCOL.
> + *
> + * See the Unified Extensible Firmware Interface (UEFI) specification for
> + * details.
> + *
> + * @this: file protocol instance
> + * @token: transaction token
> + * Return: status code
> + */
> +static efi_status_t EFIAPI efi_file_write_ex(struct efi_file_handle *this,
> + struct efi_file_io_token *token)
> +{
> + efi_status_t ret;
> +
> + EFI_ENTRY("%p, %p", this, token);
> +
> + if (!token) {
> + ret = EFI_INVALID_PARAMETER;
> + goto out;
> + }
> +
> + ret = efi_file_write_int(this, &token->buffer_size, token->buffer);
> +
> + if (ret == EFI_SUCCESS && token->event) {
> + token->status = EFI_SUCCESS;
> + efi_signal_event(token->event);
> + }
> +
> out:
> return EFI_EXIT(ret);
> }
> @@ -761,36 +928,84 @@ out:
> return EFI_EXIT(ret);
> }
>
> -static efi_status_t EFIAPI efi_file_flush(struct efi_file_handle *file)
> +/**
> + * efi_file_flush_int() - flush file
> + *
> + * This is the internal implementation of the Flush() and FlushEx() services of
> + * the EFI_FILE_PROTOCOL.
> + *
> + * @this: file protocol instance
> + * Return: status code
> + */
> +static efi_status_t efi_file_flush_int(struct efi_file_handle *this)
> {
> - EFI_ENTRY("%p", file);
> - return EFI_EXIT(EFI_SUCCESS);
> -}
> + struct file_handle *fh = to_fh(this);
>
> -static efi_status_t EFIAPI efi_file_open_ex(struct efi_file_handle *file,
> - struct efi_file_handle **new_handle,
> - u16 *file_name, u64 open_mode, u64 attributes,
> - struct efi_file_io_token *token)
> -{
> - return EFI_UNSUPPORTED;
> -}
> + if (!this)
> + return EFI_INVALID_PARAMETER;
>
> -static efi_status_t EFIAPI efi_file_read_ex(struct efi_file_handle *file,
> - struct efi_file_io_token *token)
> -{
> - return EFI_UNSUPPORTED;
> + if (!(fh->open_mode & EFI_FILE_MODE_WRITE))
> + return EFI_ACCESS_DENIED;
> +
> + /* TODO: flush for file position after end of file */
> + return EFI_SUCCESS;
> }
>
> -static efi_status_t EFIAPI efi_file_write_ex(struct efi_file_handle *file,
> - struct efi_file_io_token *token)
> +/**
> + * efi_file_flush() - flush file
> + *
> + * This function implements the Flush() service of the EFI_FILE_PROTOCOL.
> + *
> + * See the Unified Extensible Firmware Interface (UEFI) specification for
> + * details.
> + *
> + * @this: file protocol instance
> + * Return: status code
> + */
> +static efi_status_t EFIAPI efi_file_flush(struct efi_file_handle *this)
> {
> - return EFI_UNSUPPORTED;
> + efi_status_t ret;
> +
> + EFI_ENTRY("%p", this);
> +
> + ret = efi_file_flush_int(this);
> +
> + return EFI_EXIT(ret);
> }
>
> -static efi_status_t EFIAPI efi_file_flush_ex(struct efi_file_handle *file,
> - struct efi_file_io_token *token)
> +/**
> + * efi_file_flush_ex() - flush file
> + *
> + * This function implements the FlushEx() service of the EFI_FILE_PROTOCOL.
> + *
> + * See the Unified Extensible Firmware Interface (UEFI) specification for
> + * details.
> + *
> + * @this: file protocol instance
> + * @token: transaction token
> + * Return: status code
> + */
> +static efi_status_t EFIAPI efi_file_flush_ex(struct efi_file_handle *this,
> + struct efi_file_io_token *token)
> {
> - return EFI_UNSUPPORTED;
> + efi_status_t ret;
> +
> + EFI_ENTRY("%p, %p", this, token);
> +
> + if (!token) {
> + ret = EFI_INVALID_PARAMETER;
> + goto out;
> + }
> +
> + ret = efi_file_flush_int(this);
> +
> + if (ret == EFI_SUCCESS && token->event) {
> + token->status = EFI_SUCCESS;
> + efi_signal_event(token->event);
> + }
> +
> +out:
> + return EFI_EXIT(ret);
> }
>
> static const struct efi_file_handle efi_file_handle_protocol = {
> --
> 2.29.2
>
I have been trying to boot Fedora 35 Rawhide which booted fine with
2021.01 version but not with 2021.04 version.
I have bisect it and this patch is causing that grub doesn't start
automatically for this image.
(I haven't checked others yet).
U-Boot 2021.01-00398-gdb12f518edb0 (Apr 30 2021 - 12:00:13 +0200)
Model: ZynqMP ZCU104 RevC
Board: Xilinx ZynqMP
DRAM: 2 GiB
PMUFW: v1.1
EL Level: EL2
Chip ID: zu7e
WDT: Started with servicing (60s timeout)
NAND: 0 MiB
MMC: mmc at ff170000: 0
Loading Environment from FAT... *** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
Bootmode: LVL_SHFT_SD_MODE1
Reset reason: EXTERNAL
Net:
ZYNQ GEM: ff0e0000, mdio bus ff0e0000, phyaddr 12, interface rgmii-id
eth0: ethernet at ff0e0000
Hit any key to stop autoboot: 0
switch to partitions #0, OK
mmc0 is current device
Scanning mmc 0:1...
libfdt fdt_check_header(): FDT_ERR_BADMAGIC
Scanning disk mmc at ff170000.blk...
Found 4 disks
Loading Boot0000 'Fedora' failed
EFI boot manager: Cannot load any image
Found EFI removable media binary efi/boot/bootaa64.efi
858216 bytes read in 79 ms (10.4 MiB/s)
libfdt fdt_check_header(): FDT_ERR_BADMAGIC
Booting /efi\boot\bootaa64.efi
System BootOrder not found. Initializing defaults.
Could not read \EFI\: Invalid Parameter
Error: could not find boot options: Invalid Parameter
start_image() returned Invalid Parameter
## Application failed, r = 2
EFI LOAD FAILED: continuing...
JTAG: Trying to boot script at 0x20000000
## Executing script at 20000000
Wrong image format for "source" command
JTAG: SCRIPT FAILED: continuing...
switch to partitions #0, OK
mmc0 is current device
Scanning mmc 0:1...
libfdt fdt_check_header(): FDT_ERR_BADMAGIC
Loading Boot0000 'Fedora' failed
EFI boot manager: Cannot load any image
Found EFI removable media binary efi/boot/bootaa64.efi
858216 bytes read in 78 ms (10.5 MiB/s)
libfdt fdt_check_header(): FDT_ERR_BADMAGIC
Booting /efi\boot\bootaa64.efi
System BootOrder not found. Initializing defaults.
Could not read \EFI\: Invalid Parameter
Error: could not find boot options: Invalid Parameter
start_image() returned Invalid Parameter
## Application failed, r = 2
EFI LOAD FAILED: continuing...
when this patch is reverted I am getting
eth0: ethernet at ff0e0000
Hit any key to stop autoboot: 0
switch to partitions #0, OK
mmc0 is current device
Scanning mmc 0:1...
libfdt fdt_check_header(): FDT_ERR_BADMAGIC
Scanning disk mmc at ff170000.blk...
Found 4 disks
Loading Boot0000 'Fedora' failed
EFI boot manager: Cannot load any image
Found EFI removable media binary efi/boot/bootaa64.efi
858216 bytes read in 80 ms (10.2 MiB/s)
libfdt fdt_check_header(): FDT_ERR_BADMAGIC
Booting /efi\boot\bootaa64.efi
System BootOrder not found. Initializing defaults.
ethernet at ff0e0000 Waiting for PHY auto negotiation to complete. done
Fedora (5.12.0-0.rc6.20210407git2d743660786e.185.fc35.aarch64)
35 (Rawhide Prerelease)
UEFI Firmware Settings
...
Do you know what's the problem here?
Peter: Have you ever seen this behavior?
Thanks,
Michal
--
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Xilinx Microblaze
Maintainer of Linux kernel - Xilinx Zynq ARM and ZynqMP ARM64 SoCs
U-Boot custodian - Xilinx Microblaze/Zynq/ZynqMP/Versal SoCs
More information about the U-Boot
mailing list