From 8ca901ef508e9c684d9fb9c67ae707e4a962e6de Mon Sep 17 00:00:00 2001 From: wmpod2xwie Date: Fri, 21 Jun 2024 13:27:46 +1000 Subject: [PATCH] Fix System Table memory layout, achieve function calls using UEFI function pointers --- docs/OVMF_VARS.fd | Bin 131072 -> 131072 bytes scripts/run_emulator.sh | 8 +- src/boot_services.rs | 101 +++++++++++++++++++++- src/functions.rs | 19 ----- src/os_loader.rs | 55 +++++++++--- src/simple_text_output.rs | 34 +++++--- src/structs.rs | 173 +++++++++++++++++++++++++++++--------- src/system_table.rs | 34 ++++---- 8 files changed, 320 insertions(+), 104 deletions(-) delete mode 100644 src/functions.rs diff --git a/docs/OVMF_VARS.fd b/docs/OVMF_VARS.fd index 96121fd6101efaa989de4c2b4e531b8f1b01cf71..b39c0c8be2eedd65fc0c41c70999f30e434f9a5d 100644 GIT binary patch literal 131072 zcmeI*e{5Z48Nl)P^j_An;l^ggtp1>c1VeVw6*ou_x7EVdvXyS79c*LjaD~m3vQ!v? zgVg{!*faq|1}=1q(O`iUf02?5{t#kLUZ3Zld)wRF^W!X1G@zZw}{xkdi9eY;)#lv}&PRriJGWuP|Jz{KGFMx8 zW5~br<@Kd9Z$AFkp5HwBhk1h^awqns7ViCmyG?#>cZ>2r&YkT!mvLQgn`?60<;S^n zZJm4VrQw|?-&@>1_|DR|hPux?n4VGRE*Q+LsN0dc`o7+WUikOT7dGz7rk!P7bhC7; zOV_1SKJ!-BE$efKtdUOHtYvxi^3IgZrOR96dfaAN(#^8OK3Vc=dDiQ0k#~0Y%A!rn zo+a;22Q0gIS+^uuPr-F>@A`TA(5cxiFTH;G8+*U_;NUu0uReFR%ze2vU6EUFT~FIO zs^^@5bzCKucNLYayk+^?KRrI++&L9pcB3p!ru?!$Di8hj)-s8jwA|`sKH7WL#@T-z zZ2xxsWu5Q-@XP&6+@)@bTbx_-MtS^MdA!73ChxprjVG02Xh=&$C3UiWmd3w29en!5 zfoneVz4^2%EIOQE%Gl;_eGdgr(!O(|t{o;SnQoS&Mn zPqJC(v}CV+cIG$d4Xkf_V9uNM9hvn%8|=C=w!K#ottIo8Z$DX6cWmBw?{o)V+t&BF zHYwd^dA(C+%W||``J~LH2FjlpQDi|ZT#HX zVv^0KJa3nmp1|hL&#y)<*8D0VZG8M^Ya667Tl(3By4x!)R)y+P^vnadyo%ga^T)SM5?@@4v!m-}a?=cQ)Vxj!EG$aC-R`TaEqzINmj zf4}#V-3d&!Jnxn{c%3Ixo|WAQt9xs}HuybtXzb_1FuAOCot_U^r|QQ-WO-;9B?>Cb zwrfni61weE8dDX;uvloD@JN8g>4?orZk%P?w47@sg3iFUqhb`YATM3#ez0M~w>Ay0 zUU`34_tBT{U-jl_oe_fk6y6Y9EHzI4A#<>0Xd5=xe@AYyuHxt_$MhYM3rf;nRD#a5 zU!ZnJ1MJS|I#vN4Yh29@t)tU1uJZ5)FTB0$nXmLLfBD{re|vc5tJmjtgj4>Ga4zQ% zzu%~F_v?VTt4tqX#j0i?vBugxWqOp;*cvv&+@1vG;F6T9ZbwvzSv{+DO!s1FxmA3B zt%`x2OShQHT=!+RSK6SQV9w=eO=hg{|))&m%!8lg1`_9&64&GFFxI|1w!&?K{ZxOzvET)-m!tT0JIC zYD1o{!j5SJ3u`JP&yu34^$SZjr&6H0fn+6Ug(B=c(1; zjF_|yBhOQOJZ?W1t9Imhf`dzK$nzA(mEj=Vc)nF_$@7fGoqCYxAcpeRP#`7e*hBq=+mDAdGL@p>v(943#KA~vsJIM1CACHsg(SVmJ z^nyTZT#@G~j;nl)j=HFZJkNwn*{rcfo`*aSc^+xC3xm4KNKskp9M^5-`pBYRq1~nA z`{J)@BF|H}H{A5g^Q@OBveY?^5%N5dhge!4t;cHSyn?zjo`>-~8eG-7`G^LmwM}3= z594_l&vW|5H*5RPcph#2CQfQYo`*b7AuYr~T&!hdoe3?6B4!iHqbiF^%1~IYrbL4r*^GLYl#{Y32=JD58`u8!c_O^c^J>5!NquZ;o&%<~g#`8!;U_1}wc>)_-`}r&G!#sYRK;hfIg73q;EcUz9 z;=Wh?Mya;eeva`xveUr#Z84rl>P+zYFvj!jOD)`M{q9L&G$%$QYaV%?DI70s`|cjb z^Dv%g^dyK@e18hvTeR+zaNSmMTp5xY#xVez*WfV%nOYYB;r<&U9w&G)YGT*B%T{aT}2q1s}0tg_000Iag zfB*srAb)6<%w}KNvn minimum_size ? total_size : minimum_size )) @@ -66,6 +66,10 @@ mount_directory=$(mktemp --tmpdir="$script_directory" -d) sudo mount -v "${loop_device}p1" "$mount_directory" sudo mkdir -pv "${mount_directory}/EFI/BOOT/" sudo cp -vf "$bootloader" "${mount_directory}/EFI/BOOT/BOOTX64.EFI" + +# Create the startup.nsh script +echo -e "FS0:\ncd EFI\\BOOT\nBOOTX64.EFI" | sudo tee "${mount_directory}/startup.nsh" + sudo umount -v "${mount_directory}" echo "Partition and formatting ✓" diff --git a/src/boot_services.rs b/src/boot_services.rs index 641082c..e5abc15 100644 --- a/src/boot_services.rs +++ b/src/boot_services.rs @@ -9,6 +9,103 @@ use crate::types::Handle; **/ #[repr(C)] pub struct BootServicesTable { - efi_table_header: TableHeader, - load_image: extern "efiapi" fn(boot_policy: bool, parent_image_hanle: Handle), + pub efi_table_header: TableHeader, + pub raise_tpl: RaiseTpl, + pub restore_tpl: RestoreTpl, + pub allocate_pages: AllocatePages, + pub free_pages: FreePages, + pub get_memory_map: GetMemoryMap, + pub allocate_pool: AllocatePool, + pub free_pool: FreePool, + pub create_event: CreateEvent, + pub set_timer: SetTimer, + pub wait_for_event: WaitForEvent, + pub signal_event: SignalEvent, + pub close_event: CloseEvent, + pub check_event: CheckEvent, + pub install_protocol_interface: InstallProtocolInterface, + pub reinstall_protocol_interface: ReinstallProtocolInterface, + pub uninstall_protocol_interface: UninstallProtocolInterface, + pub handle_protocol: HandleProtocol, + pub reserved: Reserved, + pub register_protocol_notify: RegisterProtocolNotify, + pub locate_handle: LocateHandle, + pub locate_device_path: LocateDevicePath, + pub install_configuration_table: InstallConfigurationTable, + pub load_image: LoadImage, + pub start_image: StartImage, + pub exit: Exit, + pub unload_image: UnloadImage, + pub exit_boot_services: ExitBootServices, + pub get_next_monotonic_count: GetNextMonotonicCount, + pub stall: Stall, + pub set_watchdog_timer: SetWatchdogTimer, + pub connect_controller: ConnectController, + pub disconnect_contoller: DisconnectController, + pub open_protocol: OpenProtocol, + pub close_protocol: CloseProtocol, + pub open_protocol_information: OpenProtocolInformation, + pub protocol_per_handle: ProtocolPerHandle, + pub locate_handle_buffer: LocateHandleBuffer, + pub locate_protocol: LocateProtocol, + pub install_multiple_protocol_interfaces: InstallMultipleProtocolInterfaces, + pub uninstall_multiple_protocol_interfaces: UninstallMultipleProtocolInterfaces, + pub calculate_crc_32: CalculateCrc32, + pub copy_mem: CopyMem, + pub set_mem: SetMem, + pub create_event_ex: CreateEventEx, +} + +pub type RaiseTpl = extern "efiapi" fn() -> Status; +pub type RestoreTpl = extern "efiapi" fn() -> Status; +pub type AllocatePages = extern "efiapi" fn() -> Status; +pub type FreePages = extern "efiapi" fn() -> Status; +pub type GetMemoryMap = extern "efiapi" fn() -> Status; +pub type AllocatePool = extern "efiapi" fn() -> Status; +pub type FreePool = extern "efiapi" fn() -> Status; +pub type CreateEvent = extern "efiapi" fn() -> Status; +pub type SetTimer = extern "efiapi" fn() -> Status; +pub type WaitForEvent = extern "efiapi" fn() -> Status; +pub type SignalEvent = extern "efiapi" fn() -> Status; +pub type CloseEvent = extern "efiapi" fn() -> Status; +pub type CheckEvent = extern "efiapi" fn() -> Status; +pub type InstallProtocolInterface = extern "efiapi" fn() -> Status; +pub type ReinstallProtocolInterface = extern "efiapi" fn() -> Status; +pub type UninstallProtocolInterface = extern "efiapi" fn() -> Status; +pub type HandleProtocol = extern "efiapi" fn() -> Status; +pub type Reserved = extern "efiapi" fn() -> Status; +pub type RegisterProtocolNotify = extern "efiapi" fn() -> Status; +pub type LocateHandle = extern "efiapi" fn() -> Status; +pub type LocateDevicePath = extern "efiapi" fn() -> Status; +pub type InstallConfigurationTable = extern "efiapi" fn() -> Status; +pub type LoadImage = extern "efiapi" fn() -> Status; +pub type StartImage = extern "efiapi" fn() -> Status; +pub type Exit = extern "efiapi" fn( + image_handle: Handle, + exit_status: Status, + exit_data_size: usize, + *const u16 +) -> Status; +pub type UnloadImage = extern "efiapi" fn() -> Status; +pub type ExitBootServices = extern "efiapi" fn() -> Status; +pub type GetNextMonotonicCount = extern "efiapi" fn() -> Status; +pub type Stall = extern "efiapi" fn() -> Status; +pub type SetWatchdogTimer = extern "efiapi" fn() -> Status; +pub type ConnectController = extern "efiapi" fn() -> Status; +pub type DisconnectController = extern "efiapi" fn() -> Status; +pub type OpenProtocol = extern "efiapi" fn() -> Status; +pub type CloseProtocol = extern "efiapi" fn() -> Status; +pub type OpenProtocolInformation = extern "efiapi" fn() -> Status; +pub type ProtocolPerHandle = extern "efiapi" fn() -> Status; +pub type LocateHandleBuffer = extern "efiapi" fn() -> Status; +pub type LocateProtocol = extern "efiapi" fn() -> Status; +pub type InstallMultipleProtocolInterfaces = extern "efiapi" fn() -> Status; +pub type UninstallMultipleProtocolInterfaces = extern "efiapi" fn() -> Status; +pub type CalculateCrc32 = extern "efiapi" fn() -> Status; +pub type CopyMem = extern "efiapi" fn() -> Status; +pub type SetMem = extern "efiapi" fn() -> Status; +pub type CreateEventEx = extern "efiapi" fn() -> Status; + +impl BootServicesTable { + pub const BOOT_SERVICES_SIGNATURE: u64 = 0x56524553544f4f42; } diff --git a/src/functions.rs b/src/functions.rs deleted file mode 100644 index 0d7e4e9..0000000 --- a/src/functions.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::structs::{MemoryDescriptor, Status, TPL}; - -// Task Priority Services -pub type raise_tpl = fn(efi_tpl: TPL) -> Status; -pub type restore_tpl = fn() -> (); - -// Memory Services -pub type allocate_pages = fn() -> (); -pub type free_pages = fn() -> (); -pub type allocate_pool = fn() -> (); -pub type free_pool = fn() -> (); - -pub type get_memory_map = extern "efiapi" fn( - memory_map_size: *mut usize, - memory_map: *mut MemoryDescriptor, - map_key: *mut usize, - descriptor_size: *mut usize, - descriptor_version: *mut u32, -) -> Status; diff --git a/src/os_loader.rs b/src/os_loader.rs index 8756075..a6ef0a3 100644 --- a/src/os_loader.rs +++ b/src/os_loader.rs @@ -1,32 +1,63 @@ #![no_std] #![no_main] -pub mod functions; +pub mod boot_services; +pub mod simple_text_output; pub mod structs; pub mod system_table; pub mod types; -pub mod boot_services; -pub mod simple_text_output; -use core::panic::PanicInfo; +use core::{panic::PanicInfo, ptr::null}; +use boot_services::BootServicesTable; +use simple_text_output::SimpleTextOutputProtocol; +use structs::Status; use system_table::SystemTable; use types::Handle; -use simple_text_output::SimpleTextOutputProtocol; #[no_mangle] #[export_name = "efi_main"] -extern "efiapi" fn efi_main(image_handle: Handle, system_table: *mut SystemTable) -> usize { - unsafe { - let system_table_ref: &SystemTable = &*system_table; - let console_out: *mut SimpleTextOutputProtocol = system_table_ref.console_out; +extern "efiapi" fn efi_main(image_handle: Handle, system_table_ptr: *mut SystemTable) -> usize { + if system_table_ptr.is_null() { + return usize::from(Status::OutOfResources); } - loop {}; - 0 // EFI_SUCCESS + + let system_table: &SystemTable = initialize_system_table(system_table_ptr); + let console_out: Option<&SimpleTextOutputProtocol> = initialize_console_out(system_table); + let boot_services_table: Option<&BootServicesTable> = initialize_boot_services(system_table); + + if let Some(console_out) = console_out { + (console_out.clear_screen)(console_out); + } + + if let Some(boot_services_table) = boot_services_table { + (boot_services_table.exit)(image_handle, Status::Success, 0, null()); + } + + usize::from(Status::Success) // EFI_SUCCESS } +fn initialize_system_table(system_table_ptr: *mut SystemTable) -> &'static SystemTable { + unsafe { &*system_table_ptr } +} +fn initialize_console_out(system_table: &SystemTable) -> Option<&SimpleTextOutputProtocol> { + let console_out = system_table.console_out; + if !console_out.is_null() { + unsafe { Some(&*console_out) } + } else { + None + } +} + +fn initialize_boot_services(system_table: &SystemTable) -> Option<&BootServicesTable> { + if !system_table.boot_services_table_pointer.is_null() { + unsafe { Some(&*system_table.boot_services_table_pointer)} + } else { + None + } +} #[panic_handler] fn panic(_info: &PanicInfo) -> ! { loop {} -} \ No newline at end of file +} diff --git a/src/simple_text_output.rs b/src/simple_text_output.rs index 1b96419..9919973 100644 --- a/src/simple_text_output.rs +++ b/src/simple_text_output.rs @@ -1,18 +1,28 @@ -use crate::structs::Status; +use crate::structs::{Status, GUID}; use crate::types::Char16; #[repr(C)] pub struct SimpleTextOutputProtocol { - reset: text_reset, - output_string: text_string, - test_string: text_test_string, - query_mode: text_query_mode, - set_mode: text_set_mode, - set_attribute: text_set_attribute, - clear_screen: text_clear_screen, - set_cursor_position: text_set_cursor_position, - enable_cursor: text_enable_cursor, - mode: *mut SimpleTextOutputMode, + pub reset: text_reset, + pub output_string: text_string, + pub test_string: text_test_string, + pub query_mode: text_query_mode, + pub set_mode: text_set_mode, + pub set_attribute: text_set_attribute, + pub clear_screen: text_clear_screen, + pub set_cursor_position: text_set_cursor_position, + pub enable_cursor: text_enable_cursor, + pub mode: *mut SimpleTextOutputMode, +} + +impl SimpleTextOutputProtocol { + pub const SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID: GUID = GUID { + data1: 0x387477c2, + data2: 0x69c7, + data3: 0x11d2, + data4: [0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b], + }; + } pub type text_reset = @@ -31,7 +41,7 @@ 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; -pub type text_clear_screen = extern "efiapi" fn(this: SimpleTextOutputProtocol) -> Status; +pub type text_clear_screen = extern "efiapi" fn(this: &SimpleTextOutputProtocol) -> Status; pub type text_set_cursor_position = extern "efiapi" fn(this: &SimpleTextOutputProtocol, column: usize, row: usize) -> Status; pub type text_enable_cursor = diff --git a/src/structs.rs b/src/structs.rs index 3b2c742..8f932a7 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -35,53 +35,146 @@ pub struct TableHeader { reserved: u32, } -#[repr(C)] +#[repr(u64)] 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, + Success = 0, + LoadError = 1, + InvalidParameter = 2, + Unsupported = 3, + BadBufferSize = 4, + BufferTooSmall = 5, + NotReady = 6, + DeviceError = 7, + WriteProtected = 8, + OutOfResources = 9, + VolumeCorrupted = 10, + VolumeFull = 11, + NoMedia = 12, + MediaChanged = 13, + NotFound = 14, + AccessDenied = 15, + NoResponse = 16, + NoMapping = 17, + Timeout = 18, + NotStarted = 19, + AlreadyStarted = 20, + Aborted = 21, + IcmpError = 22, + TftpError = 23, + ProtocolError = 24, + IncompatibleVersion = 25, + SecurityViolation = 26, + CrcError = 27, + EndOfMedia = 28, + EndOfFile = 31, + InvalidLanguage = 32, + CompromisedData = 33, + IpAddressConflict = 34, + HttpError = 35, } +impl From for Status { + fn from(value: u64) -> Self { + match value { + 0 => Status::Success, + 1 => Status::LoadError, + 2 => Status::InvalidParameter, + 3 => Status::Unsupported, + 4 => Status::BadBufferSize, + 5 => Status::BufferTooSmall, + 6 => Status::NotReady, + 7 => Status::DeviceError, + 8 => Status::WriteProtected, + 9 => Status::OutOfResources, + 10 => Status::VolumeCorrupted, + 11 => Status::VolumeFull, + 12 => Status::NoMedia, + 13 => Status::MediaChanged, + 14 => Status::NotFound, + 15 => Status::AccessDenied, + 16 => Status::NoResponse, + 17 => Status::NoMapping, + 18 => Status::Timeout, + 19 => Status::NotStarted, + 20 => Status::AlreadyStarted, + 21 => Status::Aborted, + 22 => Status::IcmpError, + 23 => Status::TftpError, + 24 => Status::ProtocolError, + 25 => Status::IncompatibleVersion, + 26 => Status::SecurityViolation, + 27 => Status::CrcError, + 28 => Status::EndOfMedia, + 31 => Status::EndOfFile, + 32 => Status::InvalidLanguage, + 33 => Status::CompromisedData, + 34 => Status::IpAddressConflict, + 35 => Status::HttpError, + _ => Status::Unsupported, // Default case + } + } +} + +impl From for u64 { + fn from(status: Status) -> Self { + status as u64 + } +} + +impl From for usize { + fn from(status: Status) -> Self { + status as usize + } +} + + +// #[repr(u64)] +// 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], +pub struct GUID { + pub data1: u32, + pub data2: u16, + pub data3: u16, + pub data4: [u8; 8], } #[repr(C)] diff --git a/src/system_table.rs b/src/system_table.rs index bd07897..359d87c 100644 --- a/src/system_table.rs +++ b/src/system_table.rs @@ -42,21 +42,21 @@ pub struct ImageEntryPoint { 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)); -} +#[repr(u32)] +pub enum SystemTableRevisions { + EFI_2_100_SYSTEM_TABLE_REVISION = (2 << 16) | 100, + EFI_1_90_SYSTEM_TABLE_REVISION = ((2 << 16) | (90)), + EFI_1_80_SYSTEM_TABLE_REVISION = ((2 << 16) | (80)), + EFI_1_70_SYSTEM_TABLE_REVISION = ((2 << 16) | (70)), + EFI_1_60_SYSTEM_TABLE_REVISION = ((2 << 16) | (60)), + EFI_1_50_SYSTEM_TABLE_REVISION = ((2 << 16) | (50)), + EFI_1_40_SYSTEM_TABLE_REVISION = ((2 << 16) | (40)), + EFI_1_31_SYSTEM_TABLE_REVISION = ((2 << 16) | (31)), + EFI_1_30_SYSTEM_TABLE_REVISION = ((2 << 16) | (30)), + EFI_1_20_SYSTEM_TABLE_REVISION = ((2 << 16) | (20)), + EFI_1_10_SYSTEM_TABLE_REVISION = ((2 << 16) | (10)), + EFI_1_00_SYSTEM_TABLE_REVISION = ((2 << 16) | (00)), + EFI_0_10_SYSTEM_TABLE_REVISION = ((1 << 16) | (10)), + EFI_0_02_SYSTEM_TABLE_REVISION = ((1 << 16) | (02)), +} \ No newline at end of file