@@ -10,12 +10,13 @@ extern crate alloc;
1010
1111use alloc:: boxed:: Box ;
1212use litebox:: platform:: RawConstPointer as _;
13+ use litebox:: utils:: TruncateExt ;
1314use litebox_common_linux:: { PtRegs , errno:: Errno } ;
1415use modular_bitfield:: prelude:: * ;
1516use modular_bitfield:: specifiers:: { B8 , B54 } ;
1617use num_enum:: TryFromPrimitive ;
1718use syscall_nr:: { LdelfSyscallNr , TeeSyscallNr } ;
18- use zerocopy:: { FromBytes , IntoBytes } ;
19+ use zerocopy:: { FromBytes , Immutable , IntoBytes } ;
1920
2021pub mod syscall_nr;
2122
@@ -394,7 +395,7 @@ impl CommandId {
394395/// `utee_params` from `optee_os/lib/libutee/include/utee_types.h`
395396/// It contains up to 4 parameters where each of them is a collection of
396397/// type (4 bits) and two 8-byte data (values or addresses).
397- #[ derive( Clone , Copy , Default , FromBytes , IntoBytes ) ]
398+ #[ derive( Clone , Copy , Default , FromBytes , Immutable , IntoBytes ) ]
398399#[ repr( C ) ]
399400pub struct UteeParams {
400401 pub types : UteeParamsTypes ,
@@ -409,9 +410,9 @@ const TEE_NUM_PARAMS: usize = 4;
409410mod workaround_identity_op_suppression {
410411 use modular_bitfield:: prelude:: * ;
411412 use modular_bitfield:: specifiers:: { B4 , B48 } ;
412- use zerocopy:: { FromBytes , IntoBytes } ;
413+ use zerocopy:: { FromBytes , Immutable , IntoBytes } ;
413414 #[ bitfield]
414- #[ derive( Clone , Copy , Default , FromBytes , IntoBytes ) ]
415+ #[ derive( Clone , Copy , Default , FromBytes , Immutable , IntoBytes ) ]
415416 #[ repr( C ) ]
416417 pub struct UteeParamsTypes {
417418 pub type_0 : B4 ,
@@ -539,7 +540,7 @@ open_enum! {
539540
540541/// `TEE_UUID` from `optee_os/lib/libutee/include/tee_api_types.h`. It uniquely identifies
541542/// TAs, cryptographic keys, and more.
542- #[ derive( Clone , Copy , PartialEq , Eq , Hash , Default , Debug , FromBytes , IntoBytes ) ]
543+ #[ derive( Clone , Copy , PartialEq , Eq , Hash , Default , Debug , FromBytes , Immutable , IntoBytes ) ]
543544#[ repr( C ) ]
544545pub struct TeeUuid {
545546 pub time_low : u32 ,
@@ -571,35 +572,101 @@ impl TeeUuid {
571572 }
572573 }
573574
574- /// Converts a UUID from OP-TEE's u32 array representation.
575+ /// Converts a UUID from OP-TEE's u64 array representation (Linux kernel format) .
575576 ///
576- /// OP-TEE passes UUIDs in SMC calls as 4 u32 values where:
577- /// - `data[0]` = `time_low` (u32)
578- /// - `data[1]` = `(time_mid << 16) | time_hi_and_version`
579- /// - `data[2..3]` = `clock_seq_and_node` (8 bytes as 2 u32s, big-endian byte order)
580- ///
581- /// For example, UUID `384fb3e0-e7f8-11e3-af63-0002a5d5c51b` is represented as:
582- /// `[0x384fb3e0, 0xe7f811e3, 0xaf630002, 0xa5d5c51b]`
583- pub fn from_u32_array ( data : [ u32 ; 4 ] ) -> Self {
577+ /// The Linux kernel packs UUIDs as two little-endian u64 values via `export_uuid()`:
578+ /// ```c
579+ /// *a = get_unaligned_le64(p); // bytes[0..8] as little-endian u64
580+ /// *b = get_unaligned_le64(p + 8); // bytes[8..16] as little-endian u64
581+ /// ```
582+ pub fn from_u64_array ( data : [ u64 ; 2 ] ) -> Self {
584583 let mut bytes = [ 0u8 ; 16 ] ;
585- bytes[ 0 ..4 ] . copy_from_slice ( & data[ 0 ] . to_be_bytes ( ) ) ;
586- bytes[ 4 ..8 ] . copy_from_slice ( & data[ 1 ] . to_be_bytes ( ) ) ;
587- bytes[ 8 ..12 ] . copy_from_slice ( & data[ 2 ] . to_be_bytes ( ) ) ;
588- bytes[ 12 ..16 ] . copy_from_slice ( & data[ 3 ] . to_be_bytes ( ) ) ;
584+ bytes[ 0 ..8 ] . copy_from_slice ( & data[ 0 ] . to_le_bytes ( ) ) ;
585+ bytes[ 8 ..16 ] . copy_from_slice ( & data[ 1 ] . to_le_bytes ( ) ) ;
589586 Self :: from_bytes ( bytes)
590587 }
588+ }
591589
592- /// Converts a UUID from OP-TEE's u64 array representation.
593- pub fn from_u64_array ( data : [ u64 ; 2 ] ) -> Self {
594- let mut bytes = [ 0u8 ; 16 ] ;
595- bytes[ 0 ..8 ] . copy_from_slice ( & data[ 0 ] . to_be_bytes ( ) ) ;
596- bytes[ 8 ..16 ] . copy_from_slice ( & data[ 1 ] . to_be_bytes ( ) ) ;
597- Self :: from_bytes ( bytes)
590+ /// TA flags from `optee_os/lib/libutee/include/user_ta_header.h`.
591+ #[ derive( Clone , Copy , PartialEq , Eq , Default , Debug , FromBytes , IntoBytes ) ]
592+ #[ repr( transparent) ]
593+ pub struct TaFlags ( u32 ) ;
594+
595+ bitflags:: bitflags! {
596+ impl TaFlags : u32 {
597+ /// TA has only one instance (deprecated flag, was USER_MODE)
598+ const USER_MODE = 0 ;
599+ /// TA executes from DDR (deprecated flag)
600+ const EXEC_DDR = 0 ;
601+ /// Only one TA instance exists at a time
602+ const SINGLE_INSTANCE = 0x0000_0004 ;
603+ /// Multiple sessions can share the instance
604+ const MULTI_SESSION = 0x0000_0008 ;
605+ /// Instance remains after last session closes
606+ const INSTANCE_KEEP_ALIVE = 0x0000_0010 ;
607+ /// TA accesses SDP memory
608+ const SECURE_DATA_PATH = 0x0000_0020 ;
609+ /// TA uses cache flush syscall
610+ const CACHE_MAINTENANCE = 0x0000_0080 ;
611+ /// TA can execute multiple sessions concurrently (pseudo-TAs only)
612+ const CONCURRENT = 0x0000_0100 ;
613+ /// Device enumeration at stage 1 (kernel driver init)
614+ const DEVICE_ENUM = 0x0000_0200 ;
615+ /// Device enumeration at stage 3 (with tee-supplicant)
616+ const DEVICE_ENUM_SUPP = 0x0000_0400 ;
617+ /// Don't close handle on corrupt object
618+ const DONT_CLOSE_HANDLE_ON_CORRUPT_OBJECT = 0x0000_0800 ;
619+ /// Device enumeration when TEE_STORAGE_PRIVATE is available
620+ const DEVICE_ENUM_TEE_STORAGE_PRIVATE = 0x0000_1000 ;
621+ /// Don't restart keep-alive TA if it crashed
622+ const INSTANCE_KEEP_CRASHED = 0x0000_2000 ;
623+ }
624+ }
625+
626+ impl TaFlags {
627+ /// Returns true if this TA should only have one instance.
628+ pub fn is_single_instance ( & self ) -> bool {
629+ self . contains ( TaFlags :: SINGLE_INSTANCE )
630+ }
631+
632+ /// Returns true if multiple sessions can share the TA instance.
633+ ///
634+ /// Note: This flag is only meaningful when `SINGLE_INSTANCE` is also set.
635+ /// For non-single-instance TAs, each session gets its own instance anyway.
636+ pub fn is_multi_session ( & self ) -> bool {
637+ self . contains ( TaFlags :: MULTI_SESSION )
638+ }
639+
640+ /// Returns true if the TA instance should persist after all sessions close.
641+ ///
642+ /// Note: This flag is only meaningful when `SINGLE_INSTANCE` is also set.
643+ /// For non-single-instance TAs, instances are always destroyed when their session closes.
644+ pub fn is_keep_alive ( & self ) -> bool {
645+ self . contains ( TaFlags :: INSTANCE_KEEP_ALIVE )
598646 }
599647}
600648
649+ /// TA header structure from `optee_os/lib/libutee/include/user_ta_header.h`.
650+ ///
651+ /// This structure is placed at the beginning of the `.ta_head` section in TA ELF binaries.
652+ #[ derive( Clone , Copy , Debug , FromBytes , IntoBytes ) ]
653+ #[ repr( C ) ]
654+ pub struct TaHead {
655+ /// TA UUID
656+ pub uuid : TeeUuid ,
657+ /// Stack size in bytes
658+ pub stack_size : u32 ,
659+ /// TA flags (see `TaFlags`)
660+ pub flags : TaFlags ,
661+ /// Deprecated entry point field
662+ pub depr_entry : u64 ,
663+ }
664+
665+ /// Name of the ELF section containing the TA header.
666+ pub const TA_HEAD_SECTION_NAME : & str = ".ta_head" ;
667+
601668/// `TEE_Identity` from `optee_os/lib/libutee/include/tee_api_types.h`.
602- #[ derive( Clone , Copy , PartialEq ) ]
669+ #[ derive( Clone , Copy , PartialEq , Immutable , IntoBytes ) ]
603670#[ repr( C ) ]
604671pub struct TeeIdentity {
605672 pub login : TeeLogin ,
@@ -683,7 +750,7 @@ const TEE_LOGIN_APPLICATION_GROUP: u32 = 0x6;
683750const TEE_LOGIN_TRUSTED_APP : u32 = 0xf000_0000 ;
684751
685752/// `TEE Login type` from `optee_os/lib/libutee/include/tee_api_defines.h`
686- #[ derive( Clone , Copy , PartialEq ) ]
753+ #[ derive( Clone , Copy , PartialEq , TryFromPrimitive , Immutable , IntoBytes ) ]
687754#[ repr( u32 ) ]
688755pub enum TeeLogin {
689756 Public = TEE_LOGIN_PUBLIC ,
@@ -727,10 +794,10 @@ impl TeeOperationMode {
727794open_enum ! {
728795 /// Origin code constants from `optee_os/lib/libutee/include/tee_api_defines.h`
729796 pub enum TeeOrigin : u32 {
730- Api = 0 ,
731- Comms = 1 ,
732- Tee = 2 ,
733- TrustedApp = 3 ,
797+ Api = 1 ,
798+ Comms = 2 ,
799+ Tee = 3 ,
800+ TrustedApp = 4 ,
734801 }
735802}
736803
@@ -897,7 +964,7 @@ const TEE_ERROR_TIME_NOT_SET: u32 = 0xffff_5000;
897964const TEE_ERROR_TIME_NEEDS_RESET : u32 = 0xffff_5001 ;
898965
899966/// `TEE_Result` (API error codes) from `optee_os/lib/libutee/include/tee_api_defines.h`
900- #[ derive( Clone , Copy , TryFromPrimitive ) ]
967+ #[ derive( Clone , Copy , TryFromPrimitive , PartialEq , Debug ) ]
901968#[ repr( u32 ) ]
902969pub enum TeeResult {
903970 Success = TEE_SUCCESS ,
@@ -931,7 +998,6 @@ pub enum TeeResult {
931998 SignatureInvalid = TEE_ERROR_SIGNATURE_INVALID ,
932999 TimeNotSet = TEE_ERROR_TIME_NOT_SET ,
9331000 TimeNeedsReset = TEE_ERROR_TIME_NEEDS_RESET ,
934- Unknown = 0xffff_ffff ,
9351001}
9361002
9371003impl From < TeeResult > for u32 {
@@ -1121,7 +1187,7 @@ bitflags::bitflags! {
11211187}
11221188
11231189/// `ldef_arg` from `optee_os/ldelf/include/ldelf.h`
1124- #[ derive( Clone , Copy , Default , FromBytes , IntoBytes ) ]
1190+ #[ derive( Clone , Copy , Default , FromBytes , Immutable , IntoBytes ) ]
11251191#[ repr( C ) ]
11261192pub struct LdelfArg {
11271193 pub uuid : TeeUuid ,
@@ -1220,7 +1286,7 @@ pub struct OpteeMsgParamFmem {
12201286 /// Lower bits of offset into shared memory reference
12211287 pub offs_low : u32 ,
12221288 /// Higher bits of offset into shared memory reference
1223- pub offs_high : u32 ,
1289+ pub offs_high : u16 ,
12241290 /// Internal offset into the first page of shared memory reference
12251291 pub internal_offs : u16 ,
12261292 /// Size of the buffer
@@ -1370,7 +1436,7 @@ pub struct OpteeMsgArgs {
13701436 pub cancel_id : u32 ,
13711437 pad : u32 ,
13721438 /// Return value from the secure world
1373- pub ret : u32 ,
1439+ pub ret : TeeResult ,
13741440 /// Origin of the return value
13751441 pub ret_origin : TeeOrigin ,
13761442 /// Number of parameters contained in `params`
@@ -1379,6 +1445,9 @@ pub struct OpteeMsgArgs {
13791445 /// a TA UUID and they are not delivered to the TA.
13801446 /// Note that, originally, the length of this array is variable. We fix it to `TEE_NUM_PARAMS + 2` to
13811447 /// simplify the implementation (our OP-TEE Shim supports up to four parameters as well).
1448+ ///
1449+ /// TODO: To support OP-TEE RPC, we should make this array length dynamic. Consider to use
1450+ /// a trailing unsized slice (DST) or other mechanisms.
13821451 pub params : [ OpteeMsgParam ; TEE_NUM_PARAMS + 2 ] ,
13831452}
13841453
@@ -1444,6 +1513,22 @@ impl OpteeMsgArgs {
14441513 Ok ( ( ) )
14451514 }
14461515 }
1516+
1517+ /// Set the size field for a memref parameter (rmem or tmem).
1518+ /// This updates `rmem.size` or `tmem.size` which share the same offset as `value.b` in the union.
1519+ pub fn set_param_memref_size (
1520+ & mut self ,
1521+ index : usize ,
1522+ size : u64 ,
1523+ ) -> Result < ( ) , OpteeSmcReturnCode > {
1524+ if index >= self . num_params as usize {
1525+ Err ( OpteeSmcReturnCode :: ENotAvail )
1526+ } else {
1527+ // rmem.size and tmem.size are at the same offset as value.b in the union
1528+ self . params [ index] . u . rmem . size = size;
1529+ Ok ( ( ) )
1530+ }
1531+ }
14471532}
14481533
14491534/// A memory page to exchange OP-TEE SMC call arguments.
@@ -1493,7 +1578,7 @@ impl OpteeSmcArgs {
14931578
14941579 /// Get the physical address of `OpteeMsgArgs`. The secure world is expected to map and copy
14951580 /// this structure.
1496- pub fn optee_msg_arg_phys_addr ( & self ) -> Result < u64 , OpteeSmcReturnCode > {
1581+ pub fn optee_msg_args_phys_addr ( & self ) -> Result < u64 , OpteeSmcReturnCode > {
14971582 // To avoid potential sign extension and overflow issues, OP-TEE stores the low and
14981583 // high 32 bits of a 64-bit address in `args[2]` and `args[1]`, respectively.
14991584 if self . args [ 1 ] & 0xffff_ffff_0000_0000 == 0 && self . args [ 2 ] & 0xffff_ffff_0000_0000 == 0 {
@@ -1503,6 +1588,11 @@ impl OpteeSmcArgs {
15031588 Err ( OpteeSmcReturnCode :: EBadAddr )
15041589 }
15051590 }
1591+
1592+ /// Set the return code of an OP-TEE SMC call
1593+ pub fn set_return_code ( & mut self , code : OpteeSmcReturnCode ) {
1594+ self . args [ 0 ] = code as usize ;
1595+ }
15061596}
15071597
15081598/// `OPTEE_SMC_FUNCID_*` from `core/arch/arm/include/sm/optee_smc.h`
@@ -1568,7 +1658,7 @@ pub enum OpteeSmcResult<'a> {
15681658 shm_lower32 : usize ,
15691659 } ,
15701660 CallWithArg {
1571- msg_arg : Box < OpteeMsgArgs > ,
1661+ msg_args : Box < OpteeMsgArgs > ,
15721662 } ,
15731663}
15741664
@@ -1701,19 +1791,51 @@ impl From<OpteeSmcReturnCode> for litebox_common_linux::errno::Errno {
17011791 }
17021792}
17031793
1794+ /// Parse the `.ta_head` section from a raw ELF binary.
1795+ ///
1796+ /// This function searches for the `.ta_head` section in the ELF and parses the `TaHead`
1797+ /// structure from it. Returns `None` if the section is not found or cannot be parsed.
1798+ ///
1799+ /// # Arguments
1800+ /// * `elf_data` - Raw bytes of the ELF binary
1801+ pub fn parse_ta_head ( elf_data : & [ u8 ] ) -> Option < TaHead > {
1802+ use core:: mem:: size_of;
1803+ use elf:: { ElfBytes , endian:: AnyEndian } ;
1804+
1805+ let elf = ElfBytes :: < AnyEndian > :: minimal_parse ( elf_data) . ok ( ) ?;
1806+ let ( shdrs, strtab) = elf. section_headers_with_strtab ( ) . ok ( ) ?;
1807+ let shdrs = shdrs?;
1808+ let strtab = strtab?;
1809+
1810+ for shdr in shdrs {
1811+ let name = strtab. get ( shdr. sh_name as usize ) . ok ( ) ?;
1812+ if name == TA_HEAD_SECTION_NAME {
1813+ let offset: usize = shdr. sh_offset . truncate ( ) ;
1814+ let size: usize = shdr. sh_size . truncate ( ) ;
1815+
1816+ if size < size_of :: < TaHead > ( ) {
1817+ return None ;
1818+ }
1819+
1820+ return TaHead :: read_from_bytes ( & elf_data[ offset..offset + size_of :: < TaHead > ( ) ] ) . ok ( ) ;
1821+ }
1822+ }
1823+ None
1824+ }
1825+
17041826#[ cfg( test) ]
17051827mod tests {
17061828 use super :: * ;
17071829
17081830 #[ test]
1709- fn test_tee_uuid_from_u32_array ( ) {
1831+ fn test_tee_uuid_from_u64_array ( ) {
17101832 // Test with OP-TEE's well-known UUID: 384fb3e0-e7f8-11e3-af63-0002a5d5c51b
1711- // As documented in optee_msg.h :
1712- // OPTEE_MSG_UID_0 = 0x384fb3e0
1713- // OPTEE_MSG_UID_1 = 0xe7f811e3
1714- // OPTEE_MSG_UID_2 = 0xaf630002
1715- // OPTEE_MSG_UID_3 = 0xa5d5c51b
1716- let uuid = TeeUuid :: from_u32_array ( [ 0x384fb3e0 , 0xe7f811e3 , 0xaf630002 , 0xa5d5c51b ] ) ;
1833+ // UUID bytes (big-endian for time fields) :
1834+ // [0x38, 0x4f, 0xb3, 0xe0, 0xe7, 0xf8, 0x11, 0xe3, 0xaf, 0x63, 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b]
1835+ // When read as two little-endian u64 values:
1836+ // data[0] = bytes[0..8] as LE u64 = 0xe311f8e7_e0b34f38
1837+ // data[1] = bytes[8..16] as LE u64 = 0x1bc5d5a5_020063af
1838+ let uuid = TeeUuid :: from_u64_array ( [ 0xe311f8e7_e0b34f38 , 0x1bc5d5a5_020063af ] ) ;
17171839
17181840 assert_eq ! ( uuid. time_low, 0x384fb3e0 ) ;
17191841 assert_eq ! ( uuid. time_mid, 0xe7f8 ) ;
0 commit comments