efi_loader: implement non-blocking file services

Implement services OpenEx(), ReadEx(), WriteEx(), FlushEx() of the
EFI_FILE_PROTOCOL.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
This commit is contained in:
Heinrich Schuchardt 2021-01-01 08:39:43 +01:00
parent ee6726be4f
commit db12f518ed
2 changed files with 281 additions and 66 deletions

View file

@ -1589,35 +1589,35 @@ struct efi_file_io_token {
struct efi_file_handle { struct efi_file_handle {
u64 rev; 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, struct efi_file_handle **new_handle,
u16 *file_name, u64 open_mode, u64 attributes); u16 *file_name, u64 open_mode, u64 attributes);
efi_status_t (EFIAPI *close)(struct efi_file_handle *file); efi_status_t (EFIAPI *close)(struct efi_file_handle *this);
efi_status_t (EFIAPI *delete)(struct efi_file_handle *file); efi_status_t (EFIAPI *delete)(struct efi_file_handle *this);
efi_status_t (EFIAPI *read)(struct efi_file_handle *file, efi_status_t (EFIAPI *read)(struct efi_file_handle *this,
efi_uintn_t *buffer_size, void *buffer); 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_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); u64 *pos);
efi_status_t (EFIAPI *setpos)(struct efi_file_handle *file, efi_status_t (EFIAPI *setpos)(struct efi_file_handle *this,
u64 pos); 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, const efi_guid_t *info_type, efi_uintn_t *buffer_size,
void *buffer); 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, const efi_guid_t *info_type, efi_uintn_t buffer_size,
void *buffer); void *buffer);
efi_status_t (EFIAPI *flush)(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 *file, efi_status_t (EFIAPI *open_ex)(struct efi_file_handle *this,
struct efi_file_handle **new_handle, struct efi_file_handle **new_handle,
u16 *file_name, u64 open_mode, u64 attributes, u16 *file_name, u64 open_mode, u64 attributes,
struct efi_file_io_token *token); 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); 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); 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); struct efi_file_io_token *token);
}; };

View file

@ -246,18 +246,16 @@ error:
return NULL; return NULL;
} }
static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *file, static efi_status_t efi_file_open_int(struct efi_file_handle *this,
struct efi_file_handle **new_handle, struct efi_file_handle **new_handle,
u16 *file_name, u64 open_mode, u64 attributes) 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_status_t ret;
EFI_ENTRY("%p, %p, \"%ls\", %llx, %llu", file, new_handle,
file_name, open_mode, attributes);
/* Check parameters */ /* Check parameters */
if (!file || !new_handle || !file_name) { if (!this || !new_handle || !file_name) {
ret = EFI_INVALID_PARAMETER; ret = EFI_INVALID_PARAMETER;
goto out; goto out;
} }
@ -291,6 +289,75 @@ static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *file,
} else { } else {
ret = EFI_NOT_FOUND; 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: out:
return EFI_EXIT(ret); return EFI_EXIT(ret);
} }
@ -441,19 +508,15 @@ static efi_status_t dir_read(struct file_handle *fh, u64 *buffer_size,
return EFI_SUCCESS; return EFI_SUCCESS;
} }
static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *file, static efi_status_t efi_file_read_int(struct efi_file_handle *this,
efi_uintn_t *buffer_size, void *buffer) 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; efi_status_t ret = EFI_SUCCESS;
u64 bs; u64 bs;
EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer); if (!this || !buffer_size || !buffer)
return EFI_INVALID_PARAMETER;
if (!buffer_size) {
ret = EFI_INVALID_PARAMETER;
goto error;
}
bs = *buffer_size; bs = *buffer_size;
if (fh->isdir) if (fh->isdir)
@ -465,34 +528,77 @@ static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *file,
else else
*buffer_size = SIZE_MAX; *buffer_size = SIZE_MAX;
error: return ret;
return EFI_EXIT(ret);
} }
/** /**
* efi_file_write() - write to file * efi_file_read() - read file
* *
* This function implements the Write() service of the EFI_FILE_PROTOCOL. * This function implements the Read() service of the EFI_FILE_PROTOCOL.
* *
* See the Unified Extensible Firmware Interface (UEFI) specification for * See the Unified Extensible Firmware Interface (UEFI) specification for
* details. * details.
* *
* @file: file handle * @this: file protocol instance
* @buffer_size: number of bytes to write * @buffer_size: number of bytes to read
* @buffer: buffer with the bytes to write * @buffer: read buffer
* Return: status code * Return: status code
*/ */
static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *file, static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *this,
efi_uintn_t *buffer_size, efi_uintn_t *buffer_size, void *buffer)
void *buffer)
{ {
struct file_handle *fh = to_fh(file); 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_read_ex() - read file asynchonously
*
* This function implements the ReadEx() 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_read_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_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; efi_status_t ret = EFI_SUCCESS;
loff_t actwrite; loff_t actwrite;
EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer); if (!this || !buffer_size || !buffer) {
if (!file || !buffer_size || !buffer) {
ret = EFI_INVALID_PARAMETER; ret = EFI_INVALID_PARAMETER;
goto out; goto out;
} }
@ -520,6 +626,67 @@ static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *file,
*buffer_size = actwrite; *buffer_size = actwrite;
fh->offset += 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: out:
return EFI_EXIT(ret); return EFI_EXIT(ret);
} }
@ -761,36 +928,84 @@ out:
return EFI_EXIT(ret); 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); struct file_handle *fh = to_fh(this);
return EFI_EXIT(EFI_SUCCESS);
if (!this)
return EFI_INVALID_PARAMETER;
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_open_ex(struct efi_file_handle *file, /**
struct efi_file_handle **new_handle, * efi_file_flush() - flush file
u16 *file_name, u64 open_mode, u64 attributes, *
struct efi_file_io_token *token) * 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_read_ex(struct efi_file_handle *file, /**
* 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) struct efi_file_io_token *token)
{ {
return EFI_UNSUPPORTED; efi_status_t ret;
}
static efi_status_t EFIAPI efi_file_write_ex(struct efi_file_handle *file, EFI_ENTRY("%p, %p", this, token);
struct efi_file_io_token *token)
{
return EFI_UNSUPPORTED;
}
static efi_status_t EFIAPI efi_file_flush_ex(struct efi_file_handle *file, if (!token) {
struct efi_file_io_token *token) ret = EFI_INVALID_PARAMETER;
{ goto out;
return EFI_UNSUPPORTED; }
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 = { static const struct efi_file_handle efi_file_handle_protocol = {