Using UEFI Runtime Services in your Kernel: Difference between revisions

From OSDev.wiki
Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content deleted Content added
m Bot: Replace deprecated source tag with syntaxhighlight
 
(One intermediate revision by one other user not shown)
Line 20: Line 20:


You will need to simply add a member to the structure.
You will need to simply add a member to the structure.
<source lang="c">
<syntaxhighlight lang="c">
typedef struct s_boot_info
typedef struct s_boot_info
{
{
Line 27: Line 27:
EFI_RUNTIME_SERVICES *RT;
EFI_RUNTIME_SERVICES *RT;
} boot_info;
} boot_info;
</syntaxhighlight>
</source>
In order to pass the pointer to the kernel, you need to define the EFI_RUNTIME_SERVICES structure yourself.
In order to pass the pointer to the kernel, you need to define the EFI_RUNTIME_SERVICES structure yourself.


You need to define the Runtime Services header and structure.
You need to define the Runtime Services header and structure.
<source lang="c">
<syntaxhighlight lang="c">
typedef struct s_efi_table_header {
typedef struct s_efi_table_header {
uint64_t signature;
uint64_t signature;
Line 39: Line 39:
uint32_t reserved;
uint32_t reserved;
} Efi_Table_Header;
} Efi_Table_Header;
</syntaxhighlight>
</source>
<source lang="c">
<syntaxhighlight lang="c">
// A structure replicating that of the EFI_RUNTIME_SERVICES structure in UEFI
// A structure replicating that of the EFI_RUNTIME_SERVICES structure in UEFI
typedef struct s_efi_runtime_service_handle {
typedef struct s_efi_runtime_service_handle {
Line 59: Line 59:
Efi_Query_Variable_Info QueryVariableInfo;
Efi_Query_Variable_Info QueryVariableInfo;
} Efi_Runtime_Services;
} Efi_Runtime_Services;
</syntaxhighlight>
</source>
You will also need to declare the methods as well as dependent structures and enums yourself.
You will also need to declare the methods as well as dependent structures and enums yourself.
<source lang="c">
<syntaxhighlight lang="c">
typedef enum {
typedef enum {
EfiResetCold,
EfiResetCold,
Line 76: Line 76:
uint16_t *ResetData
uint16_t *ResetData
);
);
</syntaxhighlight>
</source>


To find the correct declarations/structures, refer to the UEFI headers, specifically GNU-EFI's ''efiapi.h''.
To find the correct declarations/structures, refer to the UEFI headers, specifically GNU-EFI's ''efiapi.h''.
Line 83: Line 83:


This definition is not a type, it is a macro that specifies that a function must use the UEFI calling convention.
This definition is not a type, it is a macro that specifies that a function must use the UEFI calling convention.
<source lang="c">
<syntaxhighlight lang="c">
#define EfiApi __attribute__(ms_abi)
#define EfiApi __attribute__(ms_abi)
</syntaxhighlight>
</source>


== Using the Runtime Services ==
== Using the Runtime Services ==
Now that you have a pointer, you can now start calling UEFI functions.
Now that you have a pointer, you can now start calling UEFI functions.
<source lang="c">
<syntaxhighlight lang="c">
void kmain(boot_info *info)
void kmain(boot_info *info)
{
{
Line 95: Line 95:
info->RT->ResetSystem(EfiResetShutdown, 0, 0, nullptr);
info->RT->ResetSystem(EfiResetShutdown, 0, 0, nullptr);
}
}
</syntaxhighlight>
</lang>


[[Category:UEFI|{{PAGENAME}}]]

Latest revision as of 04:55, 9 June 2024

UEFI Runtime Services are functions provided by the firmware that can be used in any CPU mode, and at any time, even after you exit UEFI Boot Services. Runtime Services can contain useful functions for an operating system, such as resetting/shutting down the system, getting the current time, setting the current time, etc. One may wish to use these functions outside of the boot process. The process is relatively trivial.


Obtaining the Runtime Services Pointer

Bootloader

In order to obtain the Runtime Services pointer it is highly recommended to use a modified, minimal, UEFI-exclusive bootloader. Some bootloaders that will not work:

  • GRUB
  • coreboot
  • NexBoot
  • Any BIOS-based bootloader


Obtaining

In order to obtain the Runtime Services pointer you will need an info structure that you pass to your kernel. If you do not have one it is imperative that you create one.

You will need to simply add a member to the structure.

typedef struct s_boot_info 
{
    // A pointer to the EFI runtime services structure
    // that contains numerous useful function pointers
    EFI_RUNTIME_SERVICES *RT;
} boot_info;

In order to pass the pointer to the kernel, you need to define the EFI_RUNTIME_SERVICES structure yourself.

You need to define the Runtime Services header and structure.

typedef struct s_efi_table_header {
	uint64_t                     signature;
	uint32_t                     rev;
	uint32_t                     size;
	uint32_t                     crc;
	uint32_t                     reserved;
} Efi_Table_Header;
// A structure replicating that of the EFI_RUNTIME_SERVICES structure in UEFI
typedef struct s_efi_runtime_service_handle {
	Efi_Table_Header header;
	Efi_Get_Time                    GetTime;
	Efi_Set_Time                    SetTime;
	Efi_Get_Wakeup_Time             GetWakeupTime;
	Efi_Set_Wakeup_Time             SetWakeupTime;
	Efi_Set_Virtual_Address_Map     SetVirtualAddressMap;
	Efi_Convert_Pointer             ConvertPointer;
	Efi_Get_Variable                GetVariable;
	Efi_Get_Next_Variable_Name      GetNextVariableName;
	Efi_Set_Variable                SetVariable;
	Efi_Get_Next_High_Mono_Count    GetNextHighMonotonicCount;
	Efi_Reset_System                ResetSystem;
	Efi_Update_Capsule              UpdateCapsule;
	Efi_Query_Capsule_Capabilities  QueryCapsuleCapabilities;
	Efi_Query_Variable_Info         QueryVariableInfo;
} Efi_Runtime_Services;

You will also need to declare the methods as well as dependent structures and enums yourself.

typedef enum {
	EfiResetCold,
	EfiResetWarm,
	EfiResetShutdown
} Efi_Reset_Type;

typedef
uint64_t (EfiApi *Efi_Reset_System) 
(
    Efi_Reset_Type  	        	ResetType,
    uint64_t		              	ResetStatus,
    uint64_t				DataSize,
    uint16_t                   		*ResetData
);

To find the correct declarations/structures, refer to the UEFI headers, specifically GNU-EFI's efiapi.h.

EFIAPI

This definition is not a type, it is a macro that specifies that a function must use the UEFI calling convention.

#define EfiApi __attribute__(ms_abi)

Using the Runtime Services

Now that you have a pointer, you can now start calling UEFI functions.

void kmain(boot_info *info)
{
    // Shuts down the system
    info->RT->ResetSystem(EfiResetShutdown, 0, 0, nullptr);
}