This document outlines the architecture and implementation details of the Secure Partition Manager (SPM) within the context of Trusted Firmware-A (TF-A) and Secure Partitions (SPs) in Arm-based systems. Here’s a summary of the key points.
Overview
Secure Partition Manager (SPM) operates at Exception Level 3 (EL3) and manages Secure Partitions at Secure Exception Level 0 (S-EL0).
Secure Partitions provide isolated execution environments for trusted applications, enabling secure services like DRM, secure payments, and authentication.
Architecture
The SPM is responsible for resource allocation, architectural setup, and service management for Secure Partitions.
A Secure Partition is a software sandbox that relies on the SPM for access to system resources and is designed to run services to completion without preemption.
Building and Configuration
The SPM is currently supported on the Arm Fixed Virtual Platform (FVP).
To enable SPM support, specific build flags must be set, and the Secure Partition image must be included in the Firmware Image Package (FIP).
Resource Management
The SPM provides a porting interface for platforms to specify resources required by Secure Partitions.
Memory management for Secure Partitions is handled through defined memory map regions and boot information.
Service Access
Services in Secure Partitions are accessed via the SMC (Secure Monitor Call) calling convention, specifically using the MM_COMMUNICATE interface.
Data exchange between the Non-secure world and Secure Partitions occurs through a shared memory region, with data structures defined in the Management Mode Interface Specification.
Runtime Model
The SPM defines interfaces for Secure Partitions to initialize and export services.
Communication between the SPM and Secure Partitions is facilitated through Supervisor Call (SVC) instructions, which allow Secure Partitions to request privileged operations.
Event Management
The Secure Partition includes an Event Management interface for service registration and completion indication, allowing the SPM to delegate service requests effectively.
Conclusion
The Secure Partition Manager and Secure Partitions provide a structured approach to implementing secure services in Arm-based systems, ensuring isolation and management of security functions while facilitating communication between secure and non-secure environments. Future revisions of the implementation are expected to enhance flexibility and feature sets.
Im trying to implementing this but need to define PLAT_SP_IMAGE_MMAP_REGIONS, and PLAT_SP_IMAGE_MAX_XLAT_TABLES with the rockchip mem map for the rk3399
To define PLAT_SP_IMAGE_MMAP_REGIONS and PLAT_SP_IMAGE_MAX_XLAT_TABLES for the Rockchip RK3399 platform, you will need to refer to the memory map specific to the RK3399 SoC.
Below is a general guideline on how to define these constants based on typical memory regions found in the RK3399 architecture. You may need to adjust the values based on your specific requirements and the memory layout of your system.
Step 1: Define Memory Regions
The RK3399 typically has several memory regions that you may want to include in your memory map. Here’s an example of how you might define these regions:
Copy Code
// Define the memory regions for the Secure Partition
define PLAT_SP_IMAGE_MMAP_REGIONS \
{ \
{ \
.base = 0x80000000, /* Base address of the Secure Partition */ \
.size = 0x1000000, /* Size of the Secure Partition memory */ \
.attr = MT_MEMORY | MT_RW | MT_SECURE, \
}, \
{ \
.base = 0x0, /* Base address for other secure memory regions */ \
.size = 0x40000000, /* Size of the other secure memory */ \
.attr = MT_MEMORY | MT_RW | MT_SECURE, \
}, \
/* Add more regions as needed */ \
}
Step 2: Define Maximum Translation Tables
The PLAT_SP_IMAGE_MAX_XLAT_TABLES constant defines the maximum number of translation tables that can be used by the Secure Partition. This value depends on the memory layout and the number of regions you have defined. A common value for many platforms is 4 or 8, but you should adjust it based on your needs.
Copy Code
define PLAT_SP_IMAGE_MAX_XLAT_TABLES 4 // Adjust based on your memory map requirements
Step 3: Integrate with the Platform Code
Make sure to integrate these definitions into the appropriate platform-specific files in your TF-A implementation. Typically, you would place these definitions in a header file specific to the RK3399 platform, such as plat/rockchip/rk3399/rk3399_def.h.
Example Integration
Here’s how you might integrate these definitions into your platform code:
Copy Code
// In rk3399_def.h or a similar header file
ifndef RK3399_DEF_H
define RK3399_DEF_H
define PLAT_SP_IMAGE_MMAP_REGIONS \
{ \
{ \
.base = 0x80000000, \
.size = 0x1000000, \
.attr = MT_MEMORY | MT_RW | MT_SECURE, \
}, \
{ \
.base = 0x0, \
.size = 0x40000000, \
.attr = MT_MEMORY | MT_RW | MT_SECURE, \
}, \
}
define PLAT_SP_IMAGE_MAX_XLAT_TABLES 4
endif // RK3399_DEF_H
Final Notes
Memory Addresses: Ensure that the base addresses and sizes you define do not overlap with other critical memory regions in your system.
Attributes: The attributes (MT_MEMORY, MT_RW, MT_SECURE) should be defined according to your security and access requirements.
Testing: After implementing these definitions, thoroughly test the Secure Partition functionality to ensure that memory access and service requests are handled correctly.
Make sure to consult the RK3399 technical reference manual and any relevant documentation for specific details about the memory map and configuration options.
Help me fill in the dots here I also need to include these structs and functions; but again adjusted for the rk3399 instead of the fvp platform:
static spm_mm_mp_info_t sp_mp_info[] = {
[0] = {0x80000000, 0},
[1] = {0x80000001, 0},
[2] = {0x80000002, 0},
[3] = {0x80000003, 0},
[4] = {0x80000100, 0},
[5] = {0x80000101, 0},
[6] = {0x80000102, 0},
[7] = {0x80000103, 0},
};
const spm_mm_boot_info_t plat_arm_secure_partition_boot_info = {
.h.type = PARAM_SP_IMAGE_BOOT_INFO,
.h.version = VERSION_1,
.h.size = sizeof(spm_mm_boot_info_t),
.h.attr = 0,
.sp_mem_base = ARM_SP_IMAGE_BASE,
.sp_mem_limit = ARM_SP_IMAGE_LIMIT,
.sp_image_base = ARM_SP_IMAGE_BASE,
.sp_stack_base = PLAT_SP_IMAGE_STACK_BASE,
.sp_heap_base = ARM_SP_IMAGE_HEAP_BASE,
.sp_ns_comm_buf_base = PLAT_SP_IMAGE_NS_BUF_BASE,
.sp_shared_buf_base = PLAT_SPM_BUF_BASE,
.sp_image_size = ARM_SP_IMAGE_SIZE,
.sp_pcpu_stack_size = PLAT_SP_IMAGE_STACK_PCPU_SIZE,
.sp_heap_size = ARM_SP_IMAGE_HEAP_SIZE,
.sp_ns_comm_buf_size = PLAT_SP_IMAGE_NS_BUF_SIZE,
.sp_shared_buf_size = PLAT_SPM_BUF_SIZE,
.num_sp_mem_regions = ARM_SP_IMAGE_NUM_MEM_REGIONS,
.num_cpus = PLATFORM_CORE_COUNT,
.mp_info = &sp_mp_info[0],
};
const struct mmap_region *plat_get_secure_partition_mmap(void *cookie)
{
return plat_arm_secure_partition_mmap;
}
const struct spm_mm_boot_info *plat_get_secure_partition_boot_info(
void *cookie)
{
return &plat_arm_secure_partition_boot_info;
}
To adapt the provided structures and functions for the RK3399 platform, you will need to define the memory regions and other parameters specific to the RK3399 architecture. Below is an example of how you might fill in the details for the spm_mm_mp_info_t array, the plat_arm_secure_partition_boot_info structure, and the associated functions.
Step 1: Define Memory Regions
You will need to define the memory regions that are relevant for the RK3399. Here’s an example of how you might set up the spm_mm_mp_info_t array:
Copy Code
static spm_mm_mp_info_t sp_mp_info[] = {
[0] = {0x80000000, 0}, // Example memory region 1
[1] = {0x80001000, 0}, // Example memory region 2
[2] = {0x80002000, 0}, // Example memory region 3
[3] = {0x80003000, 0}, // Example memory region 4
[4] = {0x80010000, 0}, // Example memory region 5
[5] = {0x80011000, 0}, // Example memory region 6
[6] = {0x80012000, 0}, // Example memory region 7
[7] = {0x80013000, 0}, // Example memory region 8
};
Step 2: Define Boot Info Structure
Next, you will define the plat_arm_secure_partition_boot_info structure. You will need to replace the placeholders with actual values based on your RK3399 memory layout:
Copy Code
const spm_mm_boot_info_t plat_arm_secure_partition_boot_info = {
.h.type = PARAM_SP_IMAGE_BOOT_INFO,
.h.version = VERSION_1,
.h.size = sizeof(spm_mm_boot_info_t),
.h.attr = 0,
.sp_mem_base = 0x80000000, // Base address for Secure Partition memory
.sp_mem_limit = 0x80010000, // Limit address for Secure Partition memory
.sp_image_base = 0x80000000, // Base address for the Secure Partition image
.sp_stack_base = 0x8000F000, // Base address for the Secure Partition stack
.sp_heap_base = 0x8000E000, // Base address for the Secure Partition heap
.sp_ns_comm_buf_base = 0x8000D000, // Base address for Non-secure communication buffer
.sp_shared_buf_base = 0x8000C000, // Base address for shared buffer
.sp_image_size = 0x00010000, // Size of the Secure Partition image
.sp_pcpu_stack_size = 0x00002000, // Per-CPU stack size
.sp_heap_size = 0x00002000, // Size of the Secure Partition heap
.sp_ns_comm_buf_size = 0x00001000, // Size of Non-secure communication buffer
.sp_shared_buf_size = 0x00001000, // Size of shared buffer
.num_sp_mem_regions = ARRAY_SIZE(sp_mp_info), // Number of memory regions defined
.num_cpus = PLATFORM_CORE_COUNT, // Number of CPU cores
.mp_info = &sp_mp_info[0], // Pointer to memory region info
};
Step 3: Implement the Functions
Finally, implement the functions to return the memory map and boot info:
Copy Code
const struct mmap_region *plat_get_secure_partition_mmap(void *cookie)
{
return plat_arm_secure_partition_mmap; // Ensure this variable is defined elsewhere
}
const struct spm_mm_boot_info *plat_get_secure_partition_boot_info(void *cookie)
{
return &plat_arm_secure_partition_boot_info;
}
Final Notes
Memory Addresses: Ensure that the base addresses and sizes you define do not overlap with other critical memory regions in your system. Adjust the addresses based on the actual memory map of the RK3399.
Attributes: The attributes for the memory regions should be defined according to your security and access requirements.
Testing: After implementing these definitions, thoroughly test the Secure Partition functionality to ensure that memory access and service requests are handled correctly.
Make sure to consult the RK3399 technical reference manual and any relevant documentation for specific details about the memory map and configuration options.
I think this portion is also necessary, help me work this in as well converting from the fvp params to expected for the rk3399 platform:
const mmap_region_t plat_arm_secure_partition_mmap[] = {
V2M_MAP_IOFPGA_EL0, /* for the UART / V2M_MAP_SECURE_SYSTEMREG_EL0, / for initializing flash */
if PSA_FWU_SUPPORT
V2M_MAP_FLASH0_RW_EL0, /* for firmware update service in standalone mm */
endif
V2M_MAP_FLASH1_RW_EL0, /* for secure variable service in standalone mm */
MAP_REGION_FLAT(DEVICE0_BASE,
DEVICE0_SIZE,
MT_DEVICE | MT_RO | MT_SECURE | MT_USER),
ARM_SP_IMAGE_MMAP,
ARM_SP_IMAGE_NS_BUF_MMAP,
ARM_SP_IMAGE_RW_MMAP,
ARM_SPM_BUF_EL0_MMAP,
{0}
};
To adapt the plat_arm_secure_partition_mmap array for the RK3399 platform, you will need to replace the existing mappings with the appropriate memory regions and attributes specific to the RK3399 architecture. Below is an example of how you might define this array, including the necessary mappings for the RK3399.
Step 1: Define Memory Regions
You will need to define the memory regions based on the RK3399’s memory map. Here’s an example of how you might set up the plat_arm_secure_partition_mmap array:
Copy Code
// Define the memory regions for the RK3399 platform
const mmap_region_t plat_arm_secure_partition_mmap[] = {
V2M_MAP_IOFPGA_EL0, /* for the UART / V2M_MAP_SECURE_SYSTEMREG_EL0, / for initializing flash */
if PSA_FWU_SUPPORT
V2M_MAP_FLASH0_RW_EL0, /* for firmware update service in standalone mm */
endif
V2M_MAP_FLASH1_RW_EL0, /* for secure variable service in standalone mm */
// Map device memory for RK3399
MAP_REGION_FLAT(DEVICE0_BASE,
DEVICE0_SIZE,
MT_DEVICE | MT_RW | MT_SECURE | MT_USER), // Adjust permissions as needed
// Add the Secure Partition image memory mapping
MAP_REGION_FLAT(0x80000000, // Base address for the Secure Partition
0x00010000, // Size of the Secure Partition image
MT_MEMORY | MT_RW | MT_SECURE), // Adjust attributes as needed
// Add Non-secure buffer mapping
MAP_REGION_FLAT(0x8000D000, // Base address for Non-secure communication buffer
0x00001000, // Size of Non-secure communication buffer
MT_MEMORY | MT_RW | MT_NON_SECURE), // Non-secure access
// Add Read-Write mapping for Secure Partition
MAP_REGION_FLAT(0x8000E000, // Base address for Secure Partition heap
0x00002000, // Size of the Secure Partition heap
MT_MEMORY | MT_RW | MT_SECURE), // Secure access
// Add SPM buffer mapping
MAP_REGION_FLAT(0x8000C000, // Base address for SPM buffer
0x00001000, // Size of SPM buffer
MT_MEMORY | MT_RW | MT_SECURE), // Secure access
{0} // End of the mapping
};
Step 2: Ensure Correct Definitions
Make sure that the following constants are defined appropriately in your platform-specific header files:
DEVICE0_BASE and DEVICE0_SIZE: These should correspond to the base address and size of the device memory region you want to map.
Adjust the base addresses and sizes according to your specific memory layout and requirements for the RK3399.
Final Notes
Memory Addresses: Ensure that the base addresses and sizes you define do not overlap with other critical memory regions in your system.
Attributes: The attributes for the memory regions should be defined according to your security and access requirements. For example, MT_DEVICE for device memory, MT_MEMORY for normal memory, and appropriate read/write permissions.
Testing: After implementing these definitions, thoroughly test the Secure Partition functionality to ensure that memory access and service requests are handled correctly.
By following these steps, you should be able to successfully adapt the memory mapping for the RK3399 platform. Make sure to consult the RK3399 technical reference manual and any relevant documentation for specific details about the memory map and configuration options.
REMOVED
define PLAT_SP_IMAGE_MMAP_REGIONS \
{ \
{ \
.base = 0x80000000, \
.size = 0x1000000, \
.attr = MT_MEMORY | MT_RW | MT_SECURE, \
}, \
{ \
.base = 0x0, \
.size = 0x40000000, \
.attr = MT_MEMORY | MT_RW | MT_SECURE, \
}, \
}