I see from the Trust zone that the chip that supports Trustzone will run in two worlds.
The general world, the security world, the corresponding Qualcomm side is hlos,qsee.
Such as:
The following is the software architecture diagram for Hlos and Qsee
Hlos These two are divided into kernel layer, user layer. The user layer Trustzone the app over there via the API that qseecom provides.
Qseecom driver, in addition to providing the API, also calls the SCM function to do world switching.
SCM driver after receiving qseecom's call, the Hlos related data (including instruction parameters) is placed in the reference buffer, and then the SCM call is executed.
Qsapp accepts requests from Hlos through the API provided by Qsee and returns the execution results to Hlos.
In addition to providing APIs, Qsee also transmits data from Hlos to Qsapp from Monitor, and then returns the Qsapp data to Hlos.
Monitor doesn't have to say, switching the world, and also dealing with the contents of shared buffer.
is the approximate architecture diagram, the details are more complex, no Kaiyuan.
The following is a simple qseecom_security_test code to illustrate the entire invocation process.
Such as:
Qseecom_security_test.c
int main (int argc, char *argv[]) {.... /* Initialize the Global/statics to zero * /memset (g_qseecommhandles, 0, sizeof (g_qseecommhandles)); memset (g_xors, 0, sizeof (g_xors));
Initialize the global variable first g_qseecommhandles
for (j = 0; J < Num_clients; J + +) {/ * Initialize the barriers to ensure that commands aren ' t sent before the list Eners * have been started. Otherwise, errors'll be generated. * /ret = Sem_init (&barrier[j], 0, 0);//Initialize a semaphore if (ret) { logd ("Barrier Init failed%i,%i", ret, err NO); G_err =-1; break; } ret = Pthread_create (&threads[j], NULL, &test_thread, (void*) j);//Create Test_thread thread }
Initializes a barrier signal variable for synchronization at thread creation time
Then call the Pthread_create () function to create the test_thread thread, which will start the Qsapp.
void *test_thread (void* threadid) { ... Do {... LOGD ("t% #X: Starting Qsapp ...", (uint32_t) threadid); ret = Qseecom_start_app (&g_qseecommhandles[tid][0], "/firmware/image",//Qsapp "Starting with the name Securitytest " Securitytest ", sizeof (qseecom_req_res_t) * *); LOGD ("t% #X: Started qsapp ...", (uint32_t) threadid); Check_return (ret, __line__);
Then came the Test_thread thread
Call the Qseecom_start_app () function to start the Qsapp.
This function is implemented in kernel as follows:
Qseecom.c
static int Qseecom_load_app (struct qseecom_dev_handle *data, void __user *argp) {.../* Get the handle of the shared FD */ih Andle = Ion_import_dma_buf (QSEECOM.ION_CLNT,LOAD_IMG_REQ.IFD_DATA_FD) .../* Scm_call to load the app and get The app_id back */ret = Scm_call (Scm_svc_tzscheduler, 1, &load_req,sizeof (struct qseecom_load_app_ireq),& Resp, sizeof (RESP));
Get shared buf FD for communication with the secure world
Call Scm_call () to get into the safe world.
Scm_call () is implemented as follows:
Arch/arm/mach-msm/scm.c
int Scm_call (u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len,void *resp_buf, size_t resp_len) {... ret = scm_cal L_common (svc_id, cmd_id, Cmd_buf, Cmd_len, Resp_buf,resp_len, CMD, Len); Kfree (cmd); return ret;}
The implementation of Scm_call_common is as follows:
static int Scm_call_common (U32 svc_id, u32 cmd_id, const void *cmd_buf,size_t cmd_len, void *resp_buf, size_t resp_len,str UCT Scm_command *scm_buf,size_t scm_buf_length) {.... mutex_lock (&scm_lock); ret = __scm_call (SCM_BUF);//Call Mutex_ Unlock (&scm_lock); if (ret) return RET;RSP = Scm_command_to_response (scm_buf); start = (unsigned long) rsp;do {SCM_INV _range (start, start + sizeof (*RSP));} while (!rsp->is_complete), end = (unsigned long) scm_get_response_buffer (RSP) + resp_len;scm_inv_range (start, end); if (resp_buf) memcpy (Resp_buf, Scm_get_response_buffer (RSP), Resp_len); return ret;}
Call __scm_call () into a secure world and call Scm_get_response_buffer () to get the information returned by the safe world for the Qsapp client
The __scm_call is implemented as follows:
static int __scm_call (const struct Scm_command *cmd) {... ret = SMC (CMD_ADDR); .... return ret;}
The SMC is implemented as follows:
Static U32 SMC (U32 cmd_addr) {int context_id;register u32 r0 asm ("r0") = 1;register u32 R1 asm ("r1") = (u32) &context_id Register u32 R2 ASM ("r2") = cmd_addr;do {asm volatile (__asmeq ("%0", "R0") __asmeq ("%1", "R0") __asmeq ("%2", "R1") __asmeq ( "%3", "R2") #ifdef requires_sec ". Arch_extension sec\n" #endif "smc#0@ switch to secure world\n": "=r" (R0): "R" (R0), "R" (R1 ), "R" (R2): "R3");} while (R0 = = scm_interrupted); return r0;}
It's a assembler, okay, the qsapp of the safe world is already running, and when Qsapp completes the service, it returns the data. This function will return.
Starting Qsapp has been completed, the following registration listener, the listener used to monitor the Qsapp over there request. Because sometimes Qsapp also need to hlos this side to do some things.
The implementation is as follows:
void *listener_thread (void* threadid) {.... Do {... /* Register as a listener with the Qsapp * /LOGD ("l% #X: Registering as listener with Qsapp ...", (uint32_t) threadid); ret = Qseecom_register_listener (&g_qseecommhandles[parent_tid][tid], get_lstnr_svc_id (Parent_tid, Tid), sizeof (qseecom_req_res_t), 0); for (;;) { /* Wait for request from the Qsapp * /ret = Qseecom_receive_req (G_qseecommhandles[parent_tid][tid], req_res, si Zeof (qseecom_req_res_t)); if (ret) break; .... /* Send The response to the Qsapp */ ret = QSEECOM_SEND_RESP (G_qseecommhandles[parent_tid][tid], req_res, sizeof (QSE ecom_req_res_t)); Check_return (ret, __line__); } } while (0); ...}
This function is long, simplified, and step to point
First call the Qseecom_register_listener () function to register the listener and tell Qsapp that I can receive your application.
See again for the For loop no, this is waiting for the qsapp side of the message, one but the news qseecom_reveive_req return, this way after processing.
Then call QSEECOM_SEND_RESP () to send response to Qsapp.
Either the start Qsapp, or the registration listener are executed in the thread, and once all the threads have exited, the Qseecom_shutdown_app () function is called to stop the Qsapp.
The entire process is completed. As follows:
void *test_thread (void* threadid) {... if (g_qseecommhandles[tid][0]! = NULL) { Qseecom_shutdown_app (&g_qseeco Mmhandles[tid][0]); } } while (0); Pthread_exit (NULL); return NULL;}
Note: The functions beginning with qseecom _xx are implemented in the qseecom.c of kernel, and SCM system calls are implemented in SCM.C.
Hlos user layer grasp QSEEComAPI.h file
Hlos kernel layer qseecom.c and scm.c two files
Thank you
Brief talk on the realization of Qualcomm Trustzone