Loading...
/* SPDX-License-Identifier: GPL-2.0+ */
/*
 * Logging (to memory) of calls from an EFI app
 *
 * Copyright 2024 Google LLC
 * Written by Simon Glass <sjg@chromium.org>
 */

#ifndef __EFI_LOG_H
#define __EFI_LOG_H

#include <linux/types.h>
#include <efi.h>

/**
 * enum efil_tag - Types of logging records which can be created
 */
enum efil_tag {
	EFILT_ALLOCATE_PAGES,
	EFILT_FREE_PAGES,
	EFILT_ALLOCATE_POOL,
	EFILT_FREE_POOL,

	EFILT_TESTING,

	EFILT_COUNT,
};

/**
 * struct efil_rec_hdr - Header for each logging record
 *
 * @tag: Tag which indicates the type of the record
 * @size: Size of the record in bytes
 * @ended: true if record has been completed (i.e. the function returned), false
 *	if it is still pending
 * @e_ret: Records the return function from the logged function
 */
struct efil_rec_hdr {
	enum efil_tag tag;
	int size;
	bool ended;
	efi_status_t e_ret;
};

/**
 * struct efil_hdr - Holds the header for the log
 *
 * @upto: Offset at which to store the next log record
 * @size: Total size of the log in bytes
 */
struct efil_hdr {
	int upto;
	int size;
};

enum efil_test_t {
	EFI_LOG_TEST0,
	EFI_LOG_TEST1,

	EFI_LOG_TEST_COUNT,
};

/**
 * struct efil_testing - used for testing the log
 */
struct efil_testing {
	enum efil_test_t enum_val;
	efi_uintn_t int_val;
	u64 *memory;
	void **buffer;
	u64 e_memory;
	void *e_buffer;
};

/**
 * struct efil_allocate_pages - holds info from efi_allocate_pages() call
 *
 * @e_memory: Contains the value of *@memory on return from the EFI function
 */
struct efil_allocate_pages {
	enum efi_allocate_type type;
	enum efi_memory_type memory_type;
	efi_uintn_t pages;
	u64 *memory;
	u64 e_memory;
};

/** struct efil_free_pages - holds info from efi_free_pages() call */
struct efil_free_pages {
	u64 memory;
	efi_uintn_t pages;
};

/** struct efil_allocate_pool - holds info from efi_allocate_pool() call
 *
 * @e_buffer: Contains the value of *@buffer on return from the EFI function
 */
struct efil_allocate_pool {
	enum efi_memory_type pool_type;
	efi_uintn_t size;
	void **buffer;
	void *e_buffer;
};

/** struct efil_free_pool - holds log-info from efi_free_pool() call */
struct efil_free_pool {
	void *buffer;
};

/*
 * The functions below are in pairs, with a 'start' and 'end' call for each EFI
 * function. The 'start' function (efi_logs_...) is called when the function is
 * started. It records all the arguments. The 'end' function (efi_loge_...) is
 * called when the function is ready to return. It records any output arguments
 * as well as the return value.
 *
 * The start function returns the offset of the log record. This must be passed
 * to the end function, so it can add the status code and any other useful
 * information. It is not possible for the end functions to remember the offset
 * from the associated start function, since EFI functions may be called in a
 * nested way and there is no obvious way to determine the log record to which
 * the end function refers.
 *
 * If the start function returns an error code (i.e. an offset < 0) then it is
 * safe to pass that to the end function. It will simply ignore the operation.
 * Common errors are -ENOENT if there is no log and -ENOSPC if the log is full
 */

#if CONFIG_IS_ENABLED(EFI_LOG)

/**
 * efi_logs_testing() - Record a test call to an efi function
 *
 * @enum_val:	enum value
 * @int_val:	integer value
 * @buffer:	place to write pointer address
 * @memory:	place to write memory address
 * Return:	log-offset of this new record, or -ve error code
 */
int efi_logs_testing(enum efil_test_t enum_val, efi_uintn_t int_value,
		     void *buffer, u64 *memory);

/**
 * efi_loge_testing() - Record a return from a test call
 *
 * This stores the value of the pointers also
 *
 * ofs: Offset of the record to end
 * efi_ret: status code to record
 */
int efi_loge_testing(int ofs, efi_status_t efi_ret);

/**
 * efi_logs_allocate_pages() - Record a call to efi_allocate_pages()
 *
 * @type:		type of allocation to be performed
 * @memory_type:	usage type of the allocated memory
 * @pages:		number of pages to be allocated
 * @memory:		place to write address of allocated memory
 * Return:		log-offset of this new record, or -ve error code
 */
int efi_logs_allocate_pages(enum efi_allocate_type type,
			    enum efi_memory_type memory_type, efi_uintn_t pages,
			    u64 *memory);

/**
 * efi_loge_allocate_pages() - Record a return from efi_allocate_pages()
 *
 * This stores the value of the memory pointer also
 *
 * ofs: Offset of the record to end
 * efi_ret: status code to record
 */
int efi_loge_allocate_pages(int ofs, efi_status_t efi_ret);

/**
 * efi_logs_free_pages() - Record a call to efi_free_pages()
 *
 * @memory:	start of the memory area to be freed
 * @pages:	number of pages to be freed
 * Return:	log-offset of this new record, or -ve error code
 */
int efi_logs_free_pages(u64 memory, efi_uintn_t pages);

/**
 * efi_loge_free_pages() - Record a return from efi_free_pages()
 *
 * ofs: Offset of the record to end
 * efi_ret: status code to record
 */
int efi_loge_free_pages(int ofs, efi_status_t efi_ret);

/**
 * efi_logs_allocate_pool() - Record a call to efi_allocate_pool()
 *
 * @pool_type:	type of the pool from which memory is to be allocated
 * @size:	number of bytes to be allocated
 * @buffer:	place to hold pointer to allocated memory
 * Return:	log-offset of this new record, or -ve error code
 */
int efi_logs_allocate_pool(enum efi_memory_type pool_type, efi_uintn_t size,
			   void **buffer);

/**
 * efi_loge_allocate_pool() - Record a return from efi_allocate_pool()
 *
 * This stores the value of the buffer pointer also
 *
 * ofs: Offset of the record to end
 * efi_ret: status code to record
 */
int efi_loge_allocate_pool(int ofs, efi_status_t efi_ret);

/**
 * efi_logs_free_pool() - Record a call to efi_free_pool()
 *
 * @buffer:	start of memory to be freed
 * Return:	log-offset of this new record, or -ve error code
 */
int efi_logs_free_pool(void *buffer);

/**
 * efi_loge_free_pool() - Record a return from efi_free_pool()
 *
 * ofs: Offset of the record to end
 * efi_ret: status code to record
 */
int efi_loge_free_pool(int ofs, efi_status_t efi_ret);

#else /* !EFI_LOG */

static inline int efi_logs_allocate_pages(enum efi_allocate_type type,
					  enum efi_memory_type memory_type,
					  efi_uintn_t pages, u64 *memory)
{
	return -ENOSYS;
}

static inline int efi_loge_allocate_pages(int ofs, efi_status_t efi_ret)
{
	return -ENOSYS;
}

static inline int efi_logs_free_pages(u64 memory, efi_uintn_t pages)
{
	return -ENOSYS;
}

static inline int efi_loge_free_pages(int ofs, efi_status_t efi_ret)
{
	return -ENOSYS;
}

static inline int efi_logs_allocate_pool(enum efi_memory_type pool_type,
					 efi_uintn_t size, void **buffer)
{
	return -ENOSYS;
}

static inline int efi_loge_allocate_pool(int ofs, efi_status_t efi_ret)
{
	return -ENOSYS;
}

static inline int efi_logs_free_pool(void *buffer)
{
	return -ENOSYS;
}

static inline int efi_loge_free_pool(int ofs, efi_status_t efi_ret)
{
	return -ENOSYS;
}

static inline int efi_logs_testing(enum efil_test_t enum_val,
				   efi_uintn_t int_value, void *buffer,
				   u64 *memory)
{
	return -ENOSYS;
}

static inline int efi_loge_testing(int ofs, efi_status_t efi_ret)
{
	return -ENOSYS;
}

#endif /* EFI_LOG */

/* below are some general functions */

/**
 * efi_log_show() - Show the EFI log
 *
 * Displays the log of EFI boot-services calls which are so-far enabled for
 * logging
 *
 * Return: 0 on success, or -ve error code
 */
int efi_log_show(void);

/**
 * efi_log_reset() - Reset the log, erasing all records
 *
 * Return 0 if OK, -ENOENT if the log could not be found

 */
int efi_log_reset(void);

/**
 * efi_log_init() - Create a log in the bloblist, then reset it
 *
 * Return 0 if OK, -ENOMEM if the bloblist is not large enough
 */
int efi_log_init(void);

#endif /* __EFI_LOG_H */