start implementing SimpleTextOutputProtocol

This commit is contained in:
wmpod2xwie 2024-06-19 15:47:08 +10:00
parent f1827e6b23
commit 845559a9f5
12 changed files with 241 additions and 264 deletions

View File

@ -8,8 +8,8 @@ edition = "2021"
[dependencies] [dependencies]
[[bin]] [[bin]]
name = "uefi_os_loader" name = "os_loader"
path = "src/uefi_os_loader.rs" path = "src/os_loader.rs"
[features] [features]
default = [] default = []

View File

@ -29,7 +29,7 @@ disk_image="$HOME/tmpfs/disk.img"
block_size="1M" block_size="1M"
count="100" count="100"
disk_size="100MiB" disk_size="100MiB"
bootloader="${script_directory}/../target/x86_64-unknown-uefi/release/uefi_os_loader.efi" bootloader="${script_directory}/../target/x86_64-unknown-uefi/release/os_loader.efi"
# Get the size of the bootloader in bytes # Get the size of the bootloader in bytes
bootloader_size=$(stat -c%s "$bootloader") bootloader_size=$(stat -c%s "$bootloader")

14
src/boot_services.rs Normal file
View File

@ -0,0 +1,14 @@
use crate::structs::*;
use crate::types::Handle;
/**
UEFI uses the EFI Boot Services Table, which contains a table header and pointers to all of the boot
services. The definition for this table is shown in the following code fragments. Except for the table
header, all elements in the EFI Boot Services Tables are prototypes of function pointers to functions as
defined in Section 7. The function pointers in this table are not valid after the operating system has taken
control of the platform with a call to EFI_BOOT_SERVICES.ExitBootServices().
**/
#[repr(C)]
pub struct BootServicesTable {
efi_table_header: TableHeader,
load_image: extern "efiapi" fn(boot_policy: bool, parent_image_hanle: Handle),
}

View File

@ -1,4 +1,4 @@
use crate::uefi_structs::{MemoryDescriptor, Status, TPL}; use crate::structs::{MemoryDescriptor, Status, TPL};
// Task Priority Services // Task Priority Services
pub type raise_tpl = fn(efi_tpl: TPL) -> Status; pub type raise_tpl = fn(efi_tpl: TPL) -> Status;
@ -16,4 +16,4 @@ pub type get_memory_map = extern "efiapi" fn(
map_key: *mut usize, map_key: *mut usize,
descriptor_size: *mut usize, descriptor_size: *mut usize,
descriptor_version: *mut u32, descriptor_version: *mut u32,
) -> Status; ) -> Status;

View File

@ -1,42 +0,0 @@
//
// type efi_main = fn(i32) -> i32;
/*
Step 2: Obtain the Function Pointer
Assuming you're given a pointer to a table that contains function pointers, you'll first need to safely access this table and the specific function pointer. This is often done by casting the provided pointer to a Rust struct that mirrors the layout of the UEFI table. Here's a simplified example:
rust
#[repr(C)]
struct UefiTable {
example_function: *const ExampleFunction,
}
*/
/*
// Assume this is the function signature provided by UEFI.
type GetTime = unsafe extern "efiapi" fn(/* parameters */) -> /* return type */;
#[repr(C)]
struct RuntimeServices {
// Other fields omitted
get_time: *const GetTime,
// Other fields omitted
}
fn main() {
let runtime_services: *const RuntimeServices = /* provided by UEFI */;
unsafe {
if let Some(services) = runtime_services.as_ref() {
if let Some(get_time) = services.get_time.as_ref() {
get_time(/* arguments */);
}
}
}
}
*/

View File

@ -1,18 +1,23 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
mod uefi_functions; pub mod functions;
mod uefi_structs; pub mod structs;
use core::panic::PanicInfo; pub mod system_table;
pub mod types;
pub mod boot_services;
pub mod simple_text_output;
use uefi_structs::{Handle, SystemTable}; use core::panic::PanicInfo;
use system_table::SystemTable;
use types::Handle;
#[no_mangle] #[no_mangle]
#[export_name = "efi_main"] #[export_name = "efi_main"]
extern "efiapi" fn efi_main(image_handle: Handle, system_table: *mut SystemTable) -> usize { extern "efiapi" fn efi_main(image_handle: Handle, system_table: *mut SystemTable) -> usize {
unsafe { unsafe {
let system_table_ref: &SystemTable = &*system_table; let system_table_ref: &SystemTable = &*system_table;
let console_out: *mut uefi_structs::SimpleTextOutputProtocol = system_table_ref.console_out; let console_out: *mut structs::SimpleTextOutputProtocol = system_table_ref.console_out;
} }
loop {}; loop {};
0 // EFI_SUCCESS 0 // EFI_SUCCESS
@ -23,5 +28,4 @@ extern "efiapi" fn efi_main(image_handle: Handle, system_table: *mut SystemTable
#[panic_handler] #[panic_handler]
fn panic(_info: &PanicInfo) -> ! { fn panic(_info: &PanicInfo) -> ! {
loop {} loop {}
} }

52
src/simple_text_output.rs Normal file
View File

@ -0,0 +1,52 @@
use crate::structs::Status;
use crate::types::Char16;
#[repr(C)]
pub struct SimpleTextOutputProtocol {}
pub type text_reset =
extern "efiapi" fn(this: &SimpleTextOutputProtocol, extended_verification: bool) -> Status;
pub type text_string =
extern "efiapi" fn(this: &SimpleTextOutputProtocol, string: *const Char16) -> Status;
pub type text_test_string =
extern "efiapi" fn(this: &SimpleTextOutputProtocol, string: *const Char16) -> Status;
pub type text_query_mode = extern "efiapi" fn(
this: &SimpleTextOutputProtocol,
mode_number: usize,
column: &mut usize,
rows: &mut usize,
) -> Status;
pub type text_set_mode =
extern "efiapi" fn(this: &SimpleTextOutputProtocol, mode_number: usize) -> Status;
pub type text_set_attribute =
extern "efiapi" fn(this: &SimpleTextOutputProtocol, Attribute: usize) -> Status;
#[repr(C)]
pub enum Attribute {
Black = 0x00 ,
Blue = 0x01 ,
Green = 0x02 ,
Cyan = 0x03 ,
Red = 0x04 ,
Magenta = 0x05 ,
Brown = 0x06 ,
LightGray = 0x07 ,
Bright = 0x08 ,
// DarkGray = 0x08 ,
LightBlue = 0x09 ,
LightGreen = 0x0a ,
LightCyan = 0x0b ,
LightRed = 0x0c ,
LightMagenta = 0x0d ,
Yellow = 0x0e ,
White = 0x0f ,
// BackgroundBlack = 0x00 ,
BackgroundBlue = 0x10 ,
BackgroundGreen = 0x20 ,
BackgroundCyan = 0x30 ,
BackgroundRed = 0x40 ,
BackgroundMagenta = 0x50 ,
BackgroundBrown = 0x60 ,
BackgroundLightGray = 0x70 ,
}

94
src/structs.rs Normal file
View File

@ -0,0 +1,94 @@
#[repr(C)]
pub struct TableSignatures;
impl TableSignatures {
pub const SYSTEM_TABLE_SIGNATURE: u64 = 0x5453595320494249;
pub const BOOT_TABLE_SIGNATURE: u64 = 0x56524553544f4f42;
}
#[repr(C)]
pub struct RuntimeServicesTable {
efi_table_header: TableHeader,
}
#[repr(C)]
pub struct ACPIConfigurationTable {}
#[repr(C)]
pub struct SMBIOSConfigurationTable {}
#[repr(C)]
pub struct SALSystemTable {}
#[repr(C)]
pub struct ConfigurationTable {}
#[repr(C)]
pub struct SimpleTextInputProtocol {}
#[repr(C)]
pub struct TableHeader {
signature: u64,
revision: u32,
header_size: u32,
crc32: u32,
reserved: u32,
}
#[repr(C)]
pub enum Status {
Success,
LoadError,
InvalidParameter,
Unsupported,
BadBufferSize,
BufferTooSmall,
NotReady,
DeviceError,
WriteProtected,
OutOfResources,
VolumeCorrupted,
VolumeFull,
NoMedia,
MediaChanged,
NotFound,
AccessDenied,
NoResponce,
NoMapping,
Timeout,
NotStarted,
AlreadyStarted,
Aborted,
IcmpError,
TftpError,
ProtocolError,
IncompatibleVersion,
SecurityViolation,
CrcError,
EndOfMedia,
EndOfFile,
InvalidLanguage,
CompromisedData,
IpAddressConflict,
HttpError,
}
#[repr(C)]
pub struct TPL {}
#[repr(C)]
pub struct EFIGUID {
data1: u32,
data2: u16,
data3: u16,
data4: [u8; 8],
}
#[repr(C)]
pub struct MemoryDescriptor {
pub type_: u32,
pub physical_start: u64,
pub virtual_start: u64,
pub number_of_pages: u64,
pub attribute: u64,
}

61
src/system_table.rs Normal file
View File

@ -0,0 +1,61 @@
use crate::boot_services::BootServicesTable;
use crate::structs::*;
use crate::types::Handle;
#[repr(C)]
pub struct SystemTable {
/// The table header for the EFI System Table. This header contains the EFI_SYSTEM_TABLE_SIGNATURE and EFI_SYSTEM_TABLE_REVISION values along with the size of the EFI_SYSTEM_TABLE structure and a 32-bit CRC to verify that the contents of the EFI System Table are valid.
pub efi_table_header: TableHeader,
/// A pointer to a null terminated string that identifies the vendor that produces the system firmware for the platform.
pub firmware_vendor: *mut u16,
/// A firmware vendor specific value that identifies the revision of the system firmware for the platform.
pub firmware_revision: SystemTableRevisions,
/// The handle for the active console input device. This handle must support EFI_SIMPLE_TEXT_INPUT_PROTOCOL and EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL. If there is no active console, these protocols must still be present.
pub console_in_handle: Handle,
/// A pointer to the EFI_SIMPLE_TEXT_INPUT_PROTOCOL interface that is associated with ConsoleInHandle.
pub console_in: *mut SimpleTextInputProtocol,
/// The handle for the active console output device. This handle must support the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL. If there is no active console, this protocol must still be present.
pub console_out_handle: Handle,
/// A pointer to the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL interface that is associated with ConsoleOutHandle.
pub console_out: *mut SimpleTextOutputProtocol,
/// The handle for the active standard error console device. This handle must support the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL. If there is no active console, this protocol must still be present.
pub standard_error_handle: Handle,
/// A pointer to the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL interface that is associated with StandardErrorHandle.
pub standard_error: *mut SimpleTextOutputProtocol,
/// A pointer to the EFI Runtime Services Table.
pub runtime_services_table_pointer: *mut RuntimeServicesTable,
/// A pointer to the EFI Boot Services Table.
pub boot_services_table_pointer: *mut BootServicesTable,
/// The number of system configuration tables in the buffer ConfigurationTable.
pub number_of_table_entries: usize,
/// A pointer to the system configuration tables. The number of entries in the table is NumberOfTableEntries.
pub configuration_table: ConfigurationTable,
// ACPIConfigurationTablePointer: *mut ACPIConfigurationTable,
// SMBIOSConfigurationTable: *mut SMBIOSConfigurationTable,
// SALSystemTable: *mut SALSystemTable
}
#[repr(C)]
pub struct ImageEntryPoint {
image_handle: *const i32, // The firmware allocated handle for the UEFI image.
system_table_pointer: *const i32, // A pointer to the EFI System Table.
}
#[repr(C)]
pub struct SystemTableRevisions;
impl SystemTableRevisions {
pub const EFI_1_90_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (90));
pub const EFI_1_80_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (80));
pub const EFI_1_70_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (70));
pub const EFI_1_60_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (60));
pub const EFI_1_50_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (50));
pub const EFI_1_40_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (40));
pub const EFI_1_31_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (31));
pub const EFI_1_30_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (30));
pub const EFI_1_20_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (20));
pub const EFI_1_10_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (10));
pub const EFI_1_00_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (00));
pub const EFI_0_10_SYSTEM_TABLE_REVISION: u32 = ((1 << 16) | (10));
pub const EFI_0_02_SYSTEM_TABLE_REVISION: u32 = ((1 << 16) | (02));
}

4
src/types.rs Normal file
View File

@ -0,0 +1,4 @@
use core;
pub type Handle = *mut core::ffi::c_void;
pub type PhysicalAddress = u64;
pub type Char16 = u16;

View File

@ -1,207 +0,0 @@
use crate::uefi_functions::raise_tpl;
#[repr(C)]
pub struct ImageEntryPoint {
image_handle: *const i32, // The firmware allocated handle for the UEFI image.
system_table_pointer: *const i32, // A pointer to the EFI System Table.
}
#[repr(C)]
pub struct TableSignatures;
impl TableSignatures {
pub const SYSTEM_TABLE_SIGNATURE: u64 = 0x5453595320494249;
pub const BOOT_TABLE_SIGNATURE: u64 = 0x56524553544f4f42;
}
#[repr(C)]
pub struct SystemTableRevisions;
impl SystemTableRevisions {
pub const EFI_2_90_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (90));
pub const EFI_2_80_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (80));
pub const EFI_2_70_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (70));
pub const EFI_2_60_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (60));
pub const EFI_2_50_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (50));
pub const EFI_2_40_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (40));
pub const EFI_2_31_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (31));
pub const EFI_2_30_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (30));
pub const EFI_2_20_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (20));
pub const EFI_2_10_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (10));
pub const EFI_2_00_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (00));
pub const EFI_1_10_SYSTEM_TABLE_REVISION: u32 = ((1 << 16) | (10));
pub const EFI_1_02_SYSTEM_TABLE_REVISION: u32 = ((1 << 16) | (02));
}
/**
UEFI uses the EFI System Table, which contains pointers to the runtime and boot services tables. The
definition for this table is shown in the following code fragments. Except for the table header, all
elements in the service tables are pointers to functions as defined in Section 7 and Section 8. Prior to a
call to EFI_BOOT_SERVICES.ExitBootServices(), all of the fields of the EFI System Table are valid.
After an operating system has taken control of the platform with a call to ExitBootServices(), only
the Hdr, FirmwareVendor, FirmwareRevision, RuntimeServices, NumberOfTableEntries,
and ConfigurationTable fields are valid
**/
#[repr(C)]
pub struct SystemTable {
/// The table header for the EFI System Table. This header contains the EFI_SYSTEM_TABLE_SIGNATURE and EFI_SYSTEM_TABLE_REVISION values along with the size of the EFI_SYSTEM_TABLE structure and a 32-bit CRC to verify that the contents of the EFI System Table are valid.
pub efi_table_header: TableHeader,
/// A pointer to a null terminated string that identifies the vendor that produces the system firmware for the platform.
pub firmware_vendor: *mut u16,
/// A firmware vendor specific value that identifies the revision of the system firmware for the platform.
pub firmware_revision: SystemTableRevisions,
/// The handle for the active console input device. This handle must support EFI_SIMPLE_TEXT_INPUT_PROTOCOL and EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL. If there is no active console, these protocols must still be present.
pub console_in_handle: Handle,
/// A pointer to the EFI_SIMPLE_TEXT_INPUT_PROTOCOL interface that is associated with ConsoleInHandle.
pub console_in: *mut SimpleTextInputProtocol,
/// The handle for the active console output device. This handle must support the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL. If there is no active console, this protocol must still be present.
pub console_out_handle: Handle,
/// A pointer to the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL interface that is associated with ConsoleOutHandle.
pub console_out: *mut SimpleTextOutputProtocol,
/// The handle for the active standard error console device. This handle must support the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL. If there is no active console, this protocol must still be present.
pub standard_error_handle: Handle,
/// A pointer to the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL interface that is associated with StandardErrorHandle.
pub standard_error: *mut SimpleTextOutputProtocol,
/// A pointer to the EFI Runtime Services Table.
pub runtime_services_table_pointer: *mut RuntimeServicesTable,
/// A pointer to the EFI Boot Services Table.
pub boot_services_table_pointer: *mut BootServicesTable,
/// The number of system configuration tables in the buffer ConfigurationTable.
pub number_of_table_entries: usize,
/// A pointer to the system configuration tables. The number of entries in the table is NumberOfTableEntries.
pub configuration_table: ConfigurationTable,
// ACPIConfigurationTablePointer: *mut ACPIConfigurationTable,
// SMBIOSConfigurationTable: *mut SMBIOSConfigurationTable,
// SALSystemTable: *mut SALSystemTable
}
/**
UEFI uses the EFI Boot Services Table, which contains a table header and pointers to all of the boot
services. The definition for this table is shown in the following code fragments. Except for the table
header, all elements in the EFI Boot Services Tables are prototypes of function pointers to functions as
defined in Section 7. The function pointers in this table are not valid after the operating system has taken
control of the platform with a call to EFI_BOOT_SERVICES.ExitBootServices().
**/
#[repr(C)]
pub struct BootServicesTable {
efi_table_header: TableHeader,
load_image: extern "efiapi" fn(boot_policy: bool, parent_image_hanle: Handle),
}
#[repr(C)]
pub struct RuntimeServicesTable {
efi_table_header: TableHeader,
}
#[repr(C)]
pub struct ACPIConfigurationTable {}
#[repr(C)]
pub struct SMBIOSConfigurationTable {}
#[repr(C)]
pub struct SALSystemTable {}
#[repr(C)]
pub struct ConfigurationTable {}
#[repr(C)]
pub struct Handle {}
#[repr(C)]
pub struct SimpleTextInputProtocol {}
#[repr(C)]
pub struct SimpleTextOutputProtocol {}
// TODO:
/*
Signature A 64-bit signature that identifies the type of table that follows.
Unique signatures have been generated for the EFI System Table, the
EFI Boot Services Table, and the EFI Runtime Services Table.
Revision The revision of the EFI Specification to which this table conforms.
The upper 16 bits of this field contain the major revision value, and
the lower 16 bits contain the minor revision value. The minor
revision values are binary coded decimals and are limited to the
range of 00..99.
When printed or displayed UEFI spec revision is referred as (Major
revision).(Minor revision upper decimal).(Minor revision lower
decimal) or (Major revision).(Minor revision upper decimal) in case
Minor revision lower decimal is set to 0. For example:
A specification with the revision value ((2<<16) | (30)) would be
referred as 2.3;
A specification with the revision value ((2<<16) | (31)) would be
referred as 2.3.1
HeaderSize The size, in bytes, of the entire table including the
EFI_TABLE_HEADER.
CRC32 The 32-bit CRC for the entire table. This value is computed by setting
this field to 0, and computing the 32-bit CRC for HeaderSize bytes.
Reserved Reserved field that must be set to 0.
*/
#[repr(C)]
pub struct TableHeader {
signature: u64,
revision: u32,
header_size: u32,
crc32: u32,
reserved: u32,
}
#[repr(C)]
pub enum Status {
Success,
LoadError,
InvalidParameter,
Unsupported,
BadBufferSize,
BufferTooSmall,
NotReady,
DeviceError,
WriteProtected,
OutOfResources,
VolumeCorrupted,
VolumeFull,
NoMedia,
MediaChanged,
NotFound,
AccessDenied,
NoResponce,
NoMapping,
Timeout,
NotStarted,
AlreadyStarted,
Aborted,
IcmpError,
TftpError,
ProtocolError,
IncompatibleVersion,
SecurityViolation,
CrcError,
EndOfMedia,
EndOfFile,
InvalidLanguage,
CompromisedData,
IpAddressConflict,
HttpError,
}
#[repr(C)]
pub struct TPL {}
#[repr(C)]
pub struct EFIGUID {
data1: u32,
data2: u16,
data3: u16,
data4: [u8; 8],
}
#[repr(C)]
pub struct MemoryDescriptor {
pub type_: u32,
pub physical_start: u64,
pub virtual_start: u64,
pub number_of_pages: u64,
pub attribute: u64,
}

View File

@ -1,3 +0,0 @@
use core;
pub type Handle = *mut core::ffi::c_void;
pub type PhysicalAddress = u64;