SW 개발

[OPTEE 문서번역] OPTEE Architecture - 1 Core

. . . 2019. 8. 21. 14:24
반응형

개요

https://optee.readthedocs.io 문서를 구글 번역기 + 네이버번역기를 이용하여 번역하였습니다.

즉, 기계가 번역한 내용이므로 대략적인 내용은 확인가능합니다. 제대로 보시려면 원문을 보시길 권유드립니다.

글순서

1. Core

1.1. Interrupt handling

이 섹션에서는 optee_osSMC 예외 및 인터럽트 알림을 기반으로 월드 실행 컨텍스트의 스위치를 처리하는 방법에 대해 설명합니다. 인터럽트 알림은 IRQ / FIQ 예외이며 이는 세계 실행 컨텍스트의 전환을 의미 할 수도 있습니다. Normal World 는 Secure World 로, 또는 Secure World 는 Normal World 로의 전환.

1.1.1. Use cases of world context switch

이 섹션에서는 optee_os가 월드 컨텍스트 전환과 관련된 모든 사례를 나열합니다. Optee_os는 Secure World 에서 실행됩니다. 월드 스위치는 코어에 의해 수행되며 모니터 레벨 / 모드를 보안합니다 (모니터라고 함).

Normal World 가 Secure World 를 호출하면 Normal World 는 SMC 명령을 실행합니다. SMC 예외는 항상 모니터에 의해 동작이 잡힙니다. 관련 서비스가 신뢰할 수있는 OS를 대상으로하는 경우 모니터는 optee_os world 실행으로 전환됩니다. Secure World 가 Normal World 로 돌아 오면 optee_os는 모니터로 잡힌 SMC를 실행하여 Normal World 로 다시 전환합니다.

보안 인터럽트가 Arm GIC에 의해 신호를 받으면 optee_os 인터럽트 예외 벡터에 도달해야합니다. Secure World 가 실행 중이면 optee_os는 예외 벡터에서 인터럽트를 직접 처리합니다. 보안 인터럽트가 발생할 때 Normal World 가 실행 중이면 모니터 벡터는 예외를 처리하고 인터럽트를 처리하기 위해 optee_os를 호출해야합니다.

비보호 인터럽트가 Arm GIC에 의해 신호를 받으면 Normal World 인터럽트 예외 벡터에 도달해야한다. Normal World 가 실행 중이면 예외 벡터에서 예외를 곧바로 처리합니다. 비보안 인터럽트가 발생할 때 Secure World 가 실행 중이면, optee_os는 모니터를 통해 일시적으로 Normal World 로 돌아가 Normal World 가 인터럽트를 제공하도록합니다.

=========================
kksworks comment :
- 보안인터럽트 발생
  - Normal World 동작중: secure world 호출, 처리 후 다시 secure world로
  - secure world 동작중: 바로 처리
- 일반인터럽트 (비보호인터럽트) 발생
  - Normal World 동작중 : 바로처리
  - secure world 동작중 : Normal World 호출
  =========================

1.1.2. Core exception vectors

모니터 벡터는 AArch64에서 VBAR_EL3 이고 Armv7-A / AArch32 에서 MVBAR입니다. Normal World 또는 Secure World 가 실행되는 동안 모니터에 도달 할 수 있습니다. 실행중인 보안 상태는 SCR_NS 를 통해 모니터에 알려집니다.

SMC 예외, IRQ 또는 FIQ 예외 (소위 인터럽트) 및 비동기 중단으로부터 모니터에 도달 할 수 있습니다. Obviously monitor aborts (data, prefetch, undef) are local to the Monitor execution.

모니터는 optee_os 외부에있을 수 있습니다 (case CFG_WITH_ARM_TRUSTED_FW=y). 그렇지 않은 경우 로컬 보안 모니터 core/arch/arm/sm을 제공합니다. Armv7-A 플랫폼은 optee_os 보안 모니터를 사용해야합니다. Armv8-A 플랫폼은 Trusted Firmware A 에 의존할 가능성이 높습니다.

------------------------------------
kksworks comment:
- 아뮈래도 모니터를 외부에 둘수있다?
- optee_os 에 구현하는것이 아닌, 펌웨어 레벨에서 구현이 가능한것으로 보임 (Trust Firmware A)
------------------------------------

모니터 외부에서 실행될 때, 시스템은 Normal World (SCR_NS=1) 또는 Secure World (SCR_NS=0)에서 실행 중입니다. 각 세계는 자체 예외 벡터 테이블 (상태 벡터)을 소유합니다.

  • VBAR_EL2 or VBAR_EL1 non-secure or VBAR_EL1 secure for AArch64.
  • HVBAR or VBAR non-secure or VBAR secure for Armv7-A and AArch32.
------------------------------------
kksworks comment:
- VBAR : Vector Base Address Register 의 약자다.
  - 즉 해당 모드에서 인터럽트 발생시 인터럽트 백터인것 같다는거지.
- EL1, EL2... : Exception Level
  - http://egloos.zum.com/rousalome/v/9966116
  - EL0 : Applications
  - EL1 : OS Kernel
  - EL2 : Hypervisor
  - EL3 : Secure monitor
- SCR : System Control Resister
------------------------------------

SCR

  • Secure Control Resister
  • TrustZone 보안 모니터에서 Cotax-A5 MPCore 프로세서의 전반적인 보안 또는 비보안 상태를 제어하는 데 사용되는 필드를 포함합니다. 이러한 기능을 사용하여 banked 된 CP15 레지스터에 액세스하고 외부 비동기 이벤트가 감지될 때 CPU의 동작을 변경할 수도 있습니다.

모든 SMC 예외는 모니터 벡터에 트랩됩니다. IRQ / FIQ 예외는 모니터 벡터 또는 실행중인 상태 벡터의 상태 벡터에 트랩 될 수 있습니다.

Normal World 가 실행 중일 때 시스템은 다음과 같이 경로를 설정합니다 :

  • secure interrupts to the Monitor that will forward to optee_os
  • non-secure interrupts to the executing world exception vector.

Secure World 가 실행 중일 때 시스템은 다음 경로로 구성됩니다.

  • 보안 및 비보안 인터럽트를 실행중인 optee_os 예외 벡터에 전달합니다. optee_os는 비보안 인터럽트를 Normal World 로 전달해야한다.

Optee_os 비보안 인터럽트는 항상 실행중인 세계의 상태 벡터에서 트랩됩니다. 이것은SCR_(IRQ|FIQ)의 정적 값에 반영됩니다.

1.1.3. Native and foreign interrupts

optee_os에는 두 가지 유형의 인터럽트가 정의되어 있습니다.

  • Native interrupt - optee_os가 처리하는 인터럽트 (예 : 보안 인터럽트)
  • Foreign interrupt - optee_os가 처리하지 못하는 인터럽트 (예 : Normal World 에서 처리되는 비보안 인터럽트)

Arm GICv2 모드의 경우 기본 인터럽트는 FIQ로 전송되고 외부 인터럽트는 IRQ로 전송됩니다. Arm GICv3 모드의 경우 외부 인터럽트는 Secure World (aarch32 모니터 모드 또는 aarch64 EL3) 또는 Normal World 에서 처리 할 수있는 FIQ로 전송됩니다. 암 GICv3 모드는CFG_ARM_GICV3=y을 설정하여 활성화 할 수 있습니다. 명확성을 위해 이 문서는 주로 GICv2 규칙을 선택하고 IRQ를 optee_os 외부 인터럽트로, FIQ를 optee_os 기본 인터럽트로 참조합니다. Native interrupt 는 optee_os에 안전하게 라우팅되어야합니다. Foreign interrupt 는 Secure World 실행 중에 트랩 될때 Normal World 로 효율적으로 라우팅되어야 할 수도 있습니다.

------------------------------------
kksworks comment:
- Native Interrupt : 원래 해당 OS 에서 처리되는 인터럽트
- Foreign Interrupt : 각 모드가 다른 OS에서 처리되는 인터럽트
------------------------------------

1.1.4. Normal World invokes optee_os using SMC

Entering the Secure Monitor

모니터는 Secure World 의 모든 항목과 종료를 관리합니다. Normal World 에서 Secure World 에 들어가기 위해 모니터는 Normal World (범용 레지스터 및 뱅킹되지 않은 시스템 레지스터)의 상태를 저장하고 이전 보안 상태를 복원합니다. 그런 다음 예외에서 리턴이 수행되고 복원 된 보안 상태가 재개됩니다. Secure World 에서 Normal World 로 나가십시오.

일부 범용 레지스터는 진입 및 퇴출시 저장 및 복원되지 않으며, 이는 Secure World 와 Normal World 사이에서 매개 변수를 전달하는 데 사용됩니다 (자세한 내용 참조 ARM_DEN0028A_SMC_Calling_Convention ).

------------------------------------
kksworks comment :
- 기본적으로 컨텍스트 스위칭 일어날때 레지스터들을 저장하고 복원하게된다.
- 몇몇 범용레지스터는 저장안되니 주의하고..
- 몇몇 레지스터들은 아규먼트 교환용으로 사용
- 일종의 컨텍스트 스위칭의 개념과 비슷한것 같다.
------------------------------------

Entry and exit of Trusted OS

Trusted OS의 진입 및 퇴출시 각 CPU는 별도의 항목 스택을 사용하며 IRQ 및 FIQ를 차단하여 실행됩니다. SMC는 faststandard 의 두 가지 종류로 분류됩니다.

  • fast SMC의 경우 optee_os는 실행이 Normal World 로 돌아올 때까지 IRQ / FIQ가 차단 된 항목 스택에서 실행됩니다.
  • standard SMC의 경우 optee_os는 차단되지 않은 인터럽트로 요청 된 서비스를 실행합니다. 인터럽트, 주로 외부 인터럽트 전달을 처리하기 위해 optee_os는 SMC 요청에 신뢰할 수있는 스레드 (core/arch/arm/kernel/thread.c)를 할당합니다. 신뢰할 수있는 스레드는 요청 된 서비스의 실행 컨텍스트를 저장합니다. 이 컨텍스트는 요청 된 서비스가 실행되고 중단 될 때 일시 중단되고 다시 시작될 수 있습니다. 신뢰할 수있는 스레드는 서비스 실행이 완료 상태와 함께 반환되면 한 번 릴리스됩니다.

standard SMC의 경우 optee_os는 신뢰할 수있는 스레드를 할당하거나 다시 시작한 다음 IRQ / FIQ 행의 차단을 해제합니다. optee_os가 외부 인터럽트 또는 원격 서비스 호출에서 일반 영역을 호출해야하는 경우 optee_os는 IRQ / FIQ를 차단하고 신뢰할 수있는 스레드를 일시 중단합니다. 일시 중단하면 optee_os가 항목 스택으로 다시 이동합니다.

  • Both IRQ / FIQ가 차단 된 항목 스택에서 빠르고 표준 SMC 끝나고 optee_os는 SMC를 통해 모니터를 호출하여 Normal World 로 돌아갑니다.

../_images/tee_invoke.png

SMC entry to secure world

1.1.5. Deliver non-secure interrupts to Normal World

이 섹션에서는 Arm GICv1 / v2 규칙을 사용합니다. IRQ는 비보안 인터럽트 신호를 보내고 FIQ 신호는 인터럽트를 보호합니다. GICv3 구성에서는이 섹션에서 IRQ 및 FIQ를 교환해야합니다.

Forward a Foreign Interrupt from Secure World to Normal World

보안 환경에서 IRQ 예외로 IRQ를 수신한 경우... Secure World 에서는:

  1. Saves trusted thread context (entire state of all processor modes for Armv7-A)
  2. Blocks (masks) all interrupts (IRQ and FIQ)
  3. Switches to entry stack
  4. Issues an SMC with a value to indicates to Normal World that an IRQ has been delivered and last SMC call should be continued

모니터는 IRQ가 전달되기 직전임을 나타내는 리턴 코드로 정상적인 월드 컨텍스트를 복원합니다. Normal World 는 마지막 SMC를 계속해야 함을 나타내는 새로운 SMC를 발행합니다.

모니터는 보안 컨텍스트를 복원하기 전에 요청 된 IRQ에서 반환 된 것이고 이전에 저장된 컨텍스트를 찾은 Secure World 컨텍스트를 복원하고 실행이 다시 시작될 예외에서 Secure World IRQ 처리기를 반환 할 수있게합니다.

모니터 자체는 IRQ를 정상 세상으로 방금 전달했다는 것을 알지 못한다/관심하지 않는다. bookkeeping은 신뢰할 수 있는 OS의 스레드 처리에서 수행된다. Normal World 는 언제 Secure World 쓰레드가 실행을 재개해야 하는지를 결정할 책임이 있다. (for details, see Thread handling).

../_images/irq.png

IRQ received in secure world and forwarded to Normal World

SCR_NS 가 설정된 경우 Normal World 에 비보안 중단 제공

SCR 이후 IRQ는 삭제되고 IRQ는 Normal World 의 주 벡터(VBAR)를 통해 전달된다. IRQ는 다른 예외로 수신되며, 모니터와 신뢰할 수 있는 OS는 전혀 관여하지 않는다.

  • SCR
    • Secure Control Resister
    • TrustZone 보안 모니터에서 Cotax-A5 MPCore 프로세서의 전반적인 보안 또는 비보안 상태를 제어하는 데 사용되는 필드를 포함합니다. 이러한 기능을 사용하여 banked 된 CP15 레지스터에 액세스하고 외부 비동기 이벤트가 감지될 때 CPU의 동작을 변경할 수도 있습니다.
  • SCR_NR
    • Secure Control Resister 의 0번째 필드
    • 모니터 모드가 아닌 모드에서는 프로세서가 보안 상태인지 비보안 상태인지 여부를 나타냅니다. 모니터 모드에서 CP15 레지스터 액세스가 레지스터의 보안 또는 비보안 보기에 있는지 여부를 나타냅니다.
      • 0 = Secure. This is the reset value.
      • 1 = Non-secure.

1.1.6. Deliver secure interrupts to Secure World

이 섹션에서는 Arm GICv1 / v2 규칙을 사용합니다. FIQ 신호는 인터럽트를 보호하고 IRQ는 비보안 인터럽트를 신호로 보냅니다. GICv3 구성에서는 이 섹션에서 IRQ와 FIQ를 교환해야 한다. FIQ는 Normal World (SCR_NSis set) 또는 Secure World (SCR_NS is cleared)의 두 가지 다른 상태에서 수신할 수 있다. 보안 모니터가 활성화되면 (Armv8-A EL3 or Armv7-A Monitor mode) FIQ가 마스크됩니다.두 가지 다른 상태에서의 FIQ 수신은 아래에 설명되어 있습니다.

SCR_NS가 설정되었을 때 secure world를 위한 FIQ 제공

When the monitor gets an FIQ exception it:

  1. Saves Normal World context and restores secure world context from last secure world exit (which will have IRQ and FIQ blocked)
  2. Clears SCR_FIQ when clearing SCR_NS
  3. Sets “FIQ” as parameter to secure world entry
  4. Does a return from exception into secure context
  5. Secure world unmasks FIQs because of the “FIQ” parameter
  6. FIQ is received as in exception using the state vector
  7. The state vector handle returns from exception in secure world
  8. Secure world issues an SMC to return to Normal World
  9. Monitor saves secure world context and restores Normal World context
  10. Does a return from exception into restored context

../_images/fiq.png

FIQ received when SCR_NS is set

../_images/irq_fiq.png

FIQ received while processing an IRQ forwarded from secure world

SCR_NS가 삭제되면 FIQ를 Secure World에 제공

Since SCR_FIQ is cleared when SCR_NS is cleared a FIQ will be delivered using the state vector (VBAR) in secure world. The FIQ is received as any other exception by Trusted OS, the monitor is not involved at all.

1.1.7. Trusted thread scheduling

Trusted thread for standard services

OP-TEE 표준 서비스는 표준 SMC를 통해 수행됩니다. 이러한 서비스의 실행은 외부 인터럽트로 인해 중단 될 수 있습니다. optee_os는 서비스 실행을 일시 중단하고 복원하기 위해 표준 SMC 항목에 신뢰할 수있는 스레드를 할당합니다.

optee_os가 서비스 완료 상태의 Normal World 로 리턴하면 신뢰 된 스레드는 종료됩니다.

신뢰할 수있는 스레드 실행은 기본 인터럽트로 중단 될 수 있습니다. 이 경우 네이티브 인터럽트는 인터럽트 예외 핸들러에 의해 처리되고 일단 제공되면 optee_os는 실행 트러스트 된 스레드로 돌아갑니다.

신뢰할 수있는 스레드 실행은 외부 인터럽트에 의해 인터럽트 될 수 있습니다. 이 경우 optee_os는 트러스트 된 스레드를 일시 중단하고 모니터 (optee_os, 소위 RPC 서비스)를 통해 Normal World 를 호출합니다. 트러스트 된 스레드는 정상적인 환경이 RPC 서비스 상태의 optee_os를 호출하면 다시 시작됩니다.

신뢰할 수있는 쓰레드 실행은 optee_os가 Normal World 에서 서비스를 호출하도록 유도 할 수있다 : 파일 접근, REE 현재 시간 획득 등 신뢰할 수있는 쓰레드는 원격 서비스 실행 중에 일시 중지 / 재개된다.

Scheduling considerations

트러스트 된 스레드가 외부 인터럽트로 인해 중단되고 optee_os가 정상적인 월드 서비스를 호출하면 정상적인 세상에서 실행중인 응용 프로그램의 일정을 변경할 수 있습니다. 신뢰할 수있는 스레드는 클라이언트 응용 프로그램이 예약 된 후에 만 ​​다시 시작됩니다. 따라서 신뢰할 수있는 스레드 실행은 일반적인 세계 호출자 컨텍스트의 스케줄링을 따릅니다.

Optee_os는 스레드 스케줄링을 구현하지 않습니다. 신뢰할 수있는 각 스레드는 Normal World 에서 호출 된 서비스를 추적해야하며 실행 상태로 반환해야합니다.

OP-TEE Linux 드라이버(as implemented in drivers/tee/optee since Linux kernel 4.12)는 OP-TEE를 호출하는 Linux 스레드가 TEE 측에서 신뢰할 수있는 스레드를 할당 받도록 설계되었습니다. 신뢰할 수있는 스레드의 실행은 Linux 커널 스케줄링 결정하에있는 호출자 Linux 스레드의 실행과 관련이 있습니다. 즉, 신뢰할 수있는 스레드는 Linux 커널에 의해 예약됩니다.

Trusted thread constraints

TEE 코어는 정적 인 수의 신뢰할 수있는 스레드를 처리합니다 ( CFG_NUM_THREADS 참조).

신뢰할 수있는 스레드는 주로 실행 스택 크기와 관련하여 메모리가 제한된 시스템에서만 비용이 많이 듭니다.

SMP 시스템에서 Normal World 가 프로세스 스케줄링을 지원하는 경우 optee_os는 여러 신뢰할 수있는 스레드를 병렬로 실행할 수 있습니다. UP 시스템에서도 optee_os에서 여러 신뢰할 수있는 스레드를 지원하면 Normal World 스케줄러를 효율적으로 사용할 수 있습니다.

1.2. Memory objects

메모리 객체 MOBJ는 메모리를 설명합니다. 제공된 인터페이스는 대부분 MOBJ를 사용하여 변환 테이블 등을 채울 때 추상적입니다. MOBJ를 설명하는 다양한 종류가 있습니다.

  • Physically contiguous memory
    • created with mobj_phys_alloc(...).
  • Virtual memory
    • one instance with the name mobj_virt available.spans the entire virtual address space.
  • Physically contiguous memory allocated from a tee_mm_pool_t *
    • created with mobj_mm_alloc(...).
  • Paged memory
    • created with mobj_paged_alloc(...).only contains the supplied size and makes mobj_is_paged(...) return true if supplied as argument.
  • Secure copy paged shared memory
    • created with mobj_seccpy_shm_alloc(...).makes mobj_is_paged(...) and mobj_is_secure(...) return true if supplied as argument.

1.3. MMU

1.3.1. Translation tables

OP-TEE는 여러 개의 L1 변환 테이블을 사용합니다. 한 개의 큰 테이블은 4 GiB이고 두 개 이상의 작은 테이블은 32 MiB에 걸쳐 있습니다. 큰 변환 테이블은 커널 모드 매핑을 처리하고 작은 변환 테이블에서 다루지 않는 모든 주소와 일치시킵니다. 작은 변환 테이블은 스레드 당 할당되며 하나의 TA 컨텍스트에 대한 가상 메모리 공간의 매핑을 포함합니다.

작은 변환 테이블과 큰 변환 테이블 간의 메모리 공간은 TTBRC에 의해 구성됩니다. TTBR1은 항상 큰 변환 표를 가리 킵니다. TTBR0은 사용자 맵핑이 활성 일 때 작은 변환 테이블을 가리키고 사용자 맵핑이 현재 활성화되지 않은 경우 큰 변환 테이블을 가리 킵니다. 레지스터 등에 대한 자세한 내용은 해당 아키텍처의 기술 참조 문서 (예 : Cortex-A53 TRM)를 참조하십시오.

변환 테이블에는 특정 정렬 제한 조건이 있으며 실제 주소의 정렬은 변환 테이블의 크기와 동일해야합니다. 변환 테이블은 정렬 제약으로 인해 메모리 조각화를 피하기 위해 정적으로 할당됩니다.

각 쓰레드는 하나의 작은 L1 변환 테이블을 가지고 있습니다. 각 TA 컨텍스트는 L1 변환 테이블의 압축 된 표현을 갖습니다. 컴팩트 표현은 TA 컨텍스트가 활성화 될 때 스레드 특정 L1 변환 테이블을 초기화하는 데 사용됩니다.

dd

1.3.2. Page table cache

TA 매핑에 사용되는 페이지 테이블은 페이지 테이블 캐시로 관리됩니다. TA 문맥이 매핑 해제되면 (자), 모든 페이지 테이블이pgt_free ()를 호출 해 해제됩니다. TA를 매핑 할 때 필요한 모든 페이지 테이블은pgt_alloc ()을 사용하여 할당됩니다.

고정 된 최대 수의 변환 테이블을 풀에서 사용할 수 있습니다. 하나의 스레드는 전부 또는 거의 모든 테이블을 필요로하는 TA를 실행할 수 있습니다. 이것은 TA가 다른 스레드에 의해 실행되는 것을 차단할 수 있습니다. 모든 TA가 결국pgt_alloc ()을 실행하도록 허용하기 위해 테이블을 사용할 수있게되기를 기다리기 전에 할당 된 결과 테이블을 일시적으로 해제합니다.

페이지 테이블 캐시는 구성 옵션에 따라 다르게 동작합니다.

1.3.2.1. Without paging (CFG_WITH_PAGER=n)

이것은 가장 쉬운 구성입니다. 모든 페이지 테이블은.nozi.pgt_cache 섹션에 정적으로 할당됩니다. pgt_alloc ()은 프리리스트로부터 테이블을 할당하고pgt_free ()는 테이블을 프리리스트에 직접 리턴한다.

1.3.2.2. With paging enabled (CFG_WITH_PAGER=y)

페이지 테이블은tee_pager_alloc ()을 사용하여 부팅하는 동안 0으로 초기화 된 잠금 페이지로 할당됩니다. 잠긴 페이지는 페이저에서 필요할 때 물리적 페이지로 채워집니다. 물리적 페이지는tee_pager_release_phys ()로 더 이상 필요하지 않을 때 해제 될 수 있습니다.

CFG_WITH_LPAE = y를 사용하면 각 변환 테이블은 변환 테이블이 더 이상 필요하지 않을 때 물리적 페이지를 쉽게 해제 할 수있는 물리적 페이지와 크기가 같습니다. 짧은 디스크립터 표 형식 (CFG_WITH_LPAE = n)을 사용하면 각 페이지에 네 개의 변환 표가 저장되므로 더 복잡해진다. 추가 부기는 4 개의 개별 번역 테이블에서 사용되는 페이지를 릴리스 할 수있는시기를 알려주기 위해 사용됩니다.

1.3.2.3. With paging of user TA enabled (CFG_PAGED_USER_TA=y)

사용자 TA의 페이징을 사용하면 최근에 사용한 변환 테이블의 캐시가 사용됩니다. 이렇게하면 최근에 매핑되지 않은 TA의 매핑을 복원 할 때 페이지 폴트의 폭풍으로부터 우리를 구할 수 있습니다. 어떤 변환 테이블을 캐시해야하는지는 사용 된 테이블의 호출기에 의해 참조 카운팅으로 표시됩니다. 테이블을 강제적으로 해제해야하는 경우 호출기가 테이블을 더 이상 사용할 수 없다는 것을 알려주기 위해tee_pager_pgt_save_and_release_entries ()가 호출됩니다.

TA의 매핑을 제거 할 때,pgt_flush_ctx_range ()를 사용하여 캐시 된 테이블에서 제거해야합니다. 그러면 오래된 매핑이 실수로 재사용되는 것을 방지 할 수 있습니다.

1.3.3. Switching to user mode

이 섹션은 다음 구성 플래그에만 적용됩니다.

  • CFG_WITH_LPAE=n
  • CFG_CORE_UNMAP_CORE_AT_EL0=y

사용자 모드로 전환 할 때 최소한의 커널 모드 매핑 만 유지됩니다. 이것은 사용자 모드로 전환 할 때 TTBR1에서 큰 L1 변환을 제로로 선택하여 수행됩니다. 커널 모드로 돌아 가면 원래의 L1 변환 테이블이 TTBR1에 복원됩니다.

1.3.4. Switching to Normal World

외부 인터럽트 (see Native and foreign interrupts 나 RPC를 통해 Normal World 로 전환 할 때 Secure World 가 다른 CPU에서 실행을 재개 할 가능성이 있습니다. 즉, 새 CPU는 현재 활성화 된 TA의 컨텍스트로 구성되어야합니다. 이것은 실행을 다시 시작할 때 항상 CPU에 TA 컨텍스트를 설정하여 해결됩니다.

1.4. Pager

OP-TEE는 현재 OP-TEE 커널 메모리를 위해> 256 KiB RAM이 필요합니다. OP-TEE가 TrustZone 보호 DDR을 사용하는 경우 문제가되지 않지만 보안상의 이유로 OP-TEE는 TrustZone 보호 SRAM을 대신 사용해야 할 수도 있습니다. 사용 가능한 SRAM의 양은 플랫폼에 따라 몇 KiB에서 최대 512 KiB까지 다양합니다. 단지 몇 KiB의 SRAM이있는 플랫폼은 SRAM에서 완벽한 TEE 솔루션을 실행할 수 있다고 기대할 수 없습니다. 그러나 128 ~ 256 KiB의 SRAM을 가진 사람들은 SRAM에서 가능한 TEE 솔루션을 가질 것으로 기대할 수 있습니다. 호출기는 가상 메모리를 사용하는 OP-TEE의 요구 페이징 부분을 통해이 문제에 대한 솔루션을 제공합니다.

1.4.1. Secure memory

TrustZone 보호 SRAM은 일반적으로 TrustZone 보호 DRAM보다 보안 성이 높습니다. 일반적으로 DRAM에 더 많은 공격 경로가 있기 때문입니다. 공격 벡터는 하드웨어에 따라 다르며 플랫폼마다 다를 수 있습니다.

1.4.2. Backing store

TrustZone 보호 DRAM 또는 일부 경우 비보안 DRAM이 백업 저장소로 사용됩니다. 백업 저장소의 데이터는 페이지 당 한 개의 해시 (SHA-256) (4KB)로 무결성 보호됩니다. 읽기 전용 페이지는 OP-TEE 바이너리 자체가 암호화되지 않았기 때문에 암호화되지 않습니다.

1.4.3. Partitioning of memory

수요 페이징을 처리하는 코드는 교착 상태를 유발할 수 있으므로 항상 사용 가능해야합니다. 가상 메모리는 다음과 같이 분할됩니다.

Type Sections
unpaged text rodata data bss heap1 nozi heap2
init / paged text_init rodata_init
paged text_pageable rodata_pageable
demand alloc ...

nozi가 "zero zero initialized"를 나타낼 때,이 섹션은 엔트리 스택 (TEE 호출기가 활성화되지 않은 경우 스레드 스택)과 변환 테이블 (호출기가 활성화되고 LPAE MMU가 사용되는 경우 TEE 호출기 캐시 변환 테이블)을 포함합니다.

init 영역은 OP-TEE가 초기화 될 때 사용할 수 있으며 호출기를 초기화하는 데 필요한 모든 것을 포함합니다. 페이저가 초기화 된 후에이 영역은 페이징 된 요구에 사용됩니다.

demand alloc 영역은 요청에 따라 페이지가 할당되고 호출기에서 제거되는 특별한 영역입니다. 이러한 페이지는 OP-TEE에서 더 이상 필요하지 않을 때 반환됩니다. 스레드 스택은 현재이 영역에 속합니다. 즉, 스택을 사용하지 않을 경우 더 나은 성능을 위해 페이저에서 실제 페이지를 사용할 수 있습니다.

다른 영역에서 코드를 수집하는 기술은 모든 기능과 데이터를 별도의 섹션으로 컴파일하는 데 기반합니다. 그리고 나서, 모든 오브젝트 파일을--gc-sections과 연결하여 unpaged 함수에 대한 엔트리 함수의 의존성 그래프 밖에있는 섹션을 제거함으로써, 비공개 텍스트와 막대 그래프를 수집합니다. 스크립트는이 ELF 파일을 분석하여 최종 링크 스크립트의 비트를 생성합니다. 이 과정은 init 텍스트와 rodata에 대해 반복됩니다. "unpaged"또는 "init"이 아닌 것은 "페이징"됩니다.

1.4.4. Partitioning of the binary

Note 이 절에서 제공되는 구조체 정의는 다음 이중 라이센스에 의해 명시 적으로 다루어집니다. SPDX-License-Identifier: (BSD-2-Clause OR GPL-2.0)

바이너리는 다음과 같이 네 부분으로 나뉩니다.

Binary
Header
Init
Hashes
Pageable

헤더는 다음과 같이 정의됩니다.

#define OPTEE_MAGIC             0x4554504f
#define OPTEE_VERSION           1
#define OPTEE_ARCH_ARM32        0
#define OPTEE_ARCH_ARM64        1

struct optee_header {
        uint32_t magic;
        uint8_t version;
        uint8_t arch;
        uint16_t flags;
        uint32_t init_size;
        uint32_t init_load_addr_hi;
        uint32_t init_load_addr_lo;
        uint32_t init_mem_usage;
        uint32_t paged_size;
};

헤더는 OP-TEE 자체가 아닌 OP-TEE의 로더에서만 사용됩니다. OP-TEE를 초기화하기 위해 로더는 전체 바이너리를 메모리에로드하고 헤더 다음에 나오는init_size 바이트를(init_load_addr_hi << 32 | init_load_addr_lo)에 복사합니다. init_mem_usage는 로더에 의해 OP-TEE가 초기화 할 수있는 충분한 물리적 메모리가 있는지를 검사하는데 사용됩니다. 로더는r0 / x0에 복사되지 않은 것을 따르는 첫 번째 바이트의 주소를 제공하고 OP-TEE를 시작하기 위해로드 주소로 점프합니다.

위와 같이 내부에 파티션이있는 전체 바이너리 외에도 별도의 바이너리로드를 지원하는 로더의 빌드 프로세스 중에 세 개의 추가 바이너리가 동시에 생성됩니다.

v2 binary
Header
v2 binary
Init
Hashes
v2 binary
Pageable

이 경우 로더는 헤더 바이너리를 먼저로드하여 이미지 목록과 각 이미지의 정보를 가져옵니다. 구조체에 지정된 특정로드 주소에로드하십시오. 이러한 바이너리는 기존 바이너리와 구별하기 위해 v2 접미사로 이름이 지정됩니다. 헤더 형식은 바이너리를 효율적으로로드하는 로더를 돕기 위해 업데이트되었습니다.

#define OPTEE_IMAGE_ID_PAGER    0
#define OPTEE_IMAGE_ID_PAGED    1

struct optee_image {
        uint32_t load_addr_hi;
        uint32_t load_addr_lo;
        uint32_t image_id;
        uint32_t size;
};

struct optee_header_v2 {
        uint32_t magic;
        uint8_t version;
        uint8_t arch;
        uint16_t flags;
        uint32_t nb_images;
        struct optee_image optee_image[];
};

매직 번호와 아키텍처는 원래대로 동일합니다. 버전이 2로 증가했습니다. load_addr_hiload_addr_lo는 페이징 가능한 부분이 로더에 의해 동적으로 사용 가능한 위치에로드 될 수 있기 때문에 페이지 가능 바이너리의 경우 0xFFFFFFFF가 될 수 있습니다. image_id는 로더가 현재 바이너리를 처리하는 방법을 나타냅니다. 별도의로드를 지원하지 않는 로더는 모든 v2 바이너리를 무시합니다.

1.4.5. Initializing the pager

호출기는 "init"영역을 최소화하기 위해 부팅 중에 가능한 한 초기에 초기화됩니다. 전역 변수tee_mm_vcoretee_pager_init (...)에 제공된 레벨 2 변환 테이블에 의해 커버되는 가상 메모리 범위를 설명합니다.

1.4.5.1. Assign pageable areas

호출기가 처리 할 가상 메모리 범위는 tee_pager_add_core_area ()를 호출하여 등록됩니다.

bool tee_pager_add_area(tee_mm_entry_t *mm,
                        uint32_t flags,
                        const void *store,
                        const void *hashes);

범위를 알려주는`tee_mm_entry_t '를 가리키는 포인터, 메모리가 어떻게 매핑되어야 하는지를 알려주는 플래그 (readonly, execute 등), 그리고 페이지의 백업 스토어와 해쉬에 대한 포인터를 취한다.

1.4.5.2. Assign physical pages

물리적 SRAM 페이지는tee_pager_add_pages (...)를 호출하여 제공됩니다.

void tee_pager_add_pages(tee_vaddr_t vaddr,
                         size_t npages,
                         bool unmap);

tee_pager_add_pages (...)는 그 뒤에 가상 주소vaddrnpages 엔트리를 매핑하는 엔트리에 저장된 물리적 주소를 취해 필요에 따라 새로운 페이지를 매핑합니다. unmap 매개 변수는 초기화 된 데이터가 없거나 페이지를 재활용해야 할 때까지 계속 매핑되므로 페이지가 즉시 매핑 해제되어야하는지 여부를 알려줍니다. "init"영역의 페이지는 유효한 내용을 가지고 있고 사용 중이기 때문에 unmap == false와 함께 제공됩니다.

1.4.6. Invocation

호출기는 중단 처리기의 일부로 호출됩니다. 물리적 페이지 풀은 서로 다른 가상 주소를 매핑하는 데 사용됩니다. 새로운 가상 주소가 매핑 될 필요가있을 때, 빈 물리 페이지가 새로운 주소에 매핑되고, 빈 물리 페이지가 발견되지 않으면, 가장 오래된 물리 페이지가 대신 선택된다. 페이지가 매핑되면 새 데이터가 백업 저장소에서 복사되고 페이지 해시가 확인됩니다. 확인되면 호출기는 예외를 반환하여 실행을 다시 시작합니다.

1.4.7. Data structures

../_images/tee_pager_area.png

주요 호출기 데이터 구조가 서로 관련되는 방식

1.4.7.1. struct tee_pager_area

이것은 페이지 된 메모리 범위를 처리 할 때 중심적인 데이터 구조입니다. 그것은 다음과 같이 정의됩니다.

struct tee_pager_area {
    struct fobj *fobj;
    size_t fobj_pgoffs;
    enum tee_pager_area_type type;
    uint32_t flags;
    vaddr_t base;
    size_t size;
    struct pgt *pgt;
    TAILQ_ENTRY(tee_pager_area) link;
    TAILQ_ENTRY(tee_pager_area) fobj_link;
};

여기서basesize는 메모리 범위를 말하고fobjfobj_pgoffs는 내용을 저장합니다. struct tee_pager_areastruct fobj와 하나의struct pgt (번역 테이블)만을 사용할 수 있습니다. 그래서 여러 개의 fobj 또는 pgts에 걸친 메모리 범위가 여러 영역으로 나뉩니다.

1.4.7.2. struct fobj

이것은 초기화 된 방법에 따라 다른 implmentation을 사용하는 polymorph 객체입니다. 그것은 다음과 같이 정의됩니다 :

struct fobj_ops {
    void (*free)(struct fobj *fobj);
    TEE_Result (*load_page)(struct fobj *fobj, unsigned int page_idx,
                            void *va);
    TEE_Result (*save_page)(struct fobj *fobj, unsigned int page_idx,
                            const void *va);
};

struct fobj {
    const struct fobj_ops *ops;
    unsigned int num_pages;
    struct refcount refc;
    struct tee_pager_area_head areas;
};
num_pages: fobj가 얼마나 많은 페이지를 다루고 있는지 알려줍니다.
refc: 참조 카운터는 'fobj'를 참조하는 모든 사람이 필요에 따라 이것을 늘리거나 줄여야합니다.
areas: fobj를 사용하는 영역의 목록으로 가상 페이지를 사용할 수 없을 때 통과합니다.

1.4.7.3. struct tee_pager_pmem

이 구조체는 물리적 페이지를 나타냅니다. 그것은 다음과 같이 정의됩니다.

struct tee_pager_pmem {
    unsigned int flags;
    unsigned int fobj_pgidx;
    struct fobj *fobj;
    void *va_alias;
    TAILQ_ENTRY(tee_pager_pmem) link;
};

PMEM_FLAG_DIRTY: Bit is set in flags when the page is mapped read/write at at least one location. PMEM_FLAG_HIDDEN: Bit is set in flags when the page is hidden, that is, not accessible anywhere. fobj_pgidx: The page at this index in the fobj is used in this physical page. fobj: The fobj backing this page. va_alias: Virtual address where this physical page is updated when loading it from backing store or when writing it back.

모든struct tee_pager_pmem는 전역 목록tee_pager_pmem_head 또는tee_pager_lock_pmem_head에 저장됩니다. 후자는 필요에 따라 메모리에 매핑되고 잠긴 페이지에서 사용됩니다. 페이지는tee_pager_release_phys ()를 호출하여 명시 적으로 해제 될 때tee_pager_pmem_head로 되돌려집니다.

물리적 페이지는 둘 이상의`tee_pager_area '가 동시에 사용할 수 있습니다. 이는 공유 보안 메모리로도 알려져 있으며 읽기 전용 및 읽기 - 쓰기 매핑 모두에 해당됩니다.

페이지가 숨겨지면 모든 변환 테이블에서 매핑이 해제되고PMEM_FLAG_HIDDEN 비트가 설정되지만 메모리에 유지됩니다. 물리적 페이지가 릴리즈되면 모든 변환 테이블에서 매핑이 해제되고 그 내용이 스토리지에 다시 쓰여지고fobj 필드는 물리적 페이지가 사용되지 않았 음을 알리기 위해NULL으로 설정됩니다.

struct tee_pager_pmemfobj를 참조 할 때fobj를 참조해야하는struct tee_pager_area 때문에 사용 가능하다는 것이 이미 보장되어 있으므로 참조 카운터를 업데이트하지 않습니다.

1.4.8. Paging of user TA

사용자 TA의 페이징은CFG_PAGED_USER_TA = y를 사용하여 선택적으로 활성화 할 수 있습니다. 사용자 TA의 페이징은 OP-TEE 커널 파트의 페이징과 유사하지만 약간의 차이점이 있습니다.

  • Read/write pages are paged in addition to read-only pages
  • Page tables are managed dynamically

tee_pager_add_uta_area (...)는 TA를 채울 때 필요한 초기 읽기 / 쓰기 매핑을 설정하는 데 사용됩니다. TA가 완전히 채워지고 재배치되면tee_pager_set_uta_area_attr (...)는 TA가 실행될 때 사용되는 엄격한 권한으로 영역 매핑을 변경합니다.

1.4.8.1. Paging shared secure memory

공유 보안 메모리는 'tee_pager_area'를 동일한 백킹 'fobj'를 사용하여 여러 개 만들면 얻을 수 있습니다. tee_pager_area가 할당되고fobj가 할당되면이fobj를 사용하여tee_pager_areas에 대한 목록에 추가됩니다. 이것은 물리적 페이지가 공개 될 때 도움이됩니다.

오류가 먼저 발생하면 일치하는tee_pager_area '가 위치합니다. 그런 다음tee_pager_pmem_head를 검색하여 물리적 페이지가 이미 필요한 'fobj'페이지를 보유하고 있는지 확인합니다. 그렇다면pgt '가 업데이트되어 물리적 페이지를 적절한 위치에 매핑합니다. 물리적 페이지가 페이지를 보유하고 있지 않으면 새로운 물리적 페이지가 할당되고, 초기화되고, 마지막으로 매핑됩니다.

가능한 적은 변경 사항을 매핑으로 업데이트하기 위해 액세스 제한 -> 읽기 전용 또는 읽기 - 쓰기 - 읽기 전용 -은 페이지 폴트 발생시 사용 된 가상 주소에 대해서만 수행됩니다. 물리적 페이지를 매핑하는 데 사용되는 모든 변환 테이블에서 다른 방향의 변경 사항을 수행해야합니다.

1.5. Stacks

다른 단계 동안 다른 스택이 사용됩니다. 스택은 다음과 같습니다.

  • Secure monitor stack (128 bytes), CPU에 묶여있습니다. OP-TEE가 보안 모니터로 컴파일 된 경우에만 사용할 수 있습니다. 타겟이 Armv7-A이지만 Armv8-A에는 절대 해당하지 않습니다.
  • Temp stack (small ~1KB), CPU에 묶여있다. 한 상태에서 다른 상태로 전환 할 때 사용됩니다. 이 스택을 사용할 때 인터럽트는 항상 비활성화되며 임시 스택을 사용할 때 중단이 치명적입니다.
  • Abort stack (medium ~2KB), CPU에 묶여있다. 데이터 트래핑 또는 프리 페치 중단을 할 때 사용됩니다. TA가 죽을 때만 사용자 공간에서의 공격이 결코 치명적이지 않습니다. 커널 모드에서의 중단은 호출기에서 요구 페이징을 수행하는 데 사용되며, 호출기가 비활성화되어 있으면 모든 커널 모드 중단이 치명적입니다.
  • Thread stack (large ~8KB), 대신 현재 스레드 / 작업에 의해 사용되는 CPU에 바인딩되지 않습니다. 인터럽트는 일반적으로이 스택을 사용할 때 활성화됩니다.
  • Notes for Armv7-A/AArch32

    StackCommentTemp는 항상 SP_IRQ와 SP_FIQ에 할당 된 입출력 중에SP_SVC에 할당됩니다. 항상 스레드가 활성화되어있을 때SP_ABTThreadAssigned가SP_SVC에 할당됩니다.

  • Notes for AArch64

    AArch64에서 OP-TEE에 사용할 수있는 스택 포인터는 'SP_EL1'과 'SP_EL0'두 개뿐입니다. 예외가 수신되면 스택 포인터는 항상SP_EL1이며, 이는SP_EL0에 적절한 스택 포인터를 할당하는 동안 일시적으로 사용됩니다. SP_EL1에는 항상 thread_core_local [cpu_id]의 값이 할당됩니다. 이 구조체는 레지스터의 임시 저장을위한 여유 공간을 가지며 관련 스택 포인터도 유지합니다. 일반적으로 스택 포인터를 아래의 CPU에 할당하는 것에 대해 이야기 할 때 우리는 SP_EL0을 의미합니다.

1.5.1. Boot

이른 시동 동안에 CPU는 처음으로 Normal World 로 OP-TEE가 끝날 때까지 사용되는 임시 스택으로 구성됩니다.

  • Notes for AArch64

    SPSEL은 진입 / 퇴출시 항상 '0'이되어 스택 포인터로 작용하는SP_EL0을 갖습니다.

1.5.2. Normal entry

OP-TEE가 Normal World 에서 입력 될 때마다 임시 스택이 초기 스택으로 사용됩니다. 빠른 호출의 경우이 스택 만 사용됩니다. 일반 호출의 경우 빈 스레드 슬롯이 선택되고 CPU는 해당 스택으로 전환합니다.

1.5.3. Normal exit

스레드가 작업을 완료하고 스레드가 해제되면 정상 종료가 발생합니다. 메인 쓰레드 함수tee_entry_std (...)가 반환 할 때 인터럽트는 비활성화되고 CPU는 임시 스택으로 전환된다. 스레드가 해제되고 OP-TEE이 Normal World 로 종료됩니다.

1.5.4. RPC exit

OP-TEE가 Normal World 에서 서비스를 필요로 할 때 RPC 이탈이 발생합니다. 현재 RPC는 스레드가 실행 중 상태 인 경우에만 수행 할 수 있습니다. RPC는`thread_rpc (...) '를 호출함으로써 시작된다.이 상태는 쓰레드가 복구 될 때이 함수가 마치 정상적으로 리턴 한 것처럼 다음 명령에서 계속 될 수있는 방식으로 상태를 저장한다. CPU는 Normal World 로 돌아 가기 전에 임시 스택을 사용하도록 전환합니다.

1.5.5. Foreign interrupt exit

외부 인터럽트 종료는 OP-TEE가 외부 인터럽트를 수신 할 때 발생합니다. Arm GICv2 모드의 경우 외부 인터럽트는 IRQ로 보내지며 이는 Normal World 에서 항상 처리됩니다. 외부 인터럽트 종료는 RPC exit와 유사하지만 스레드 상태를 대신 저장하는 것은 thread_irq_handler (...)elx_irq (...) 입니다 (각각 Armv7-A / Aarch32 및 Aarch64 용). 스레드는 같은 방법으로 다시 시작됩니다. Arm GICv3 모드의 경우 보안 인터럽트 (AArch64의 EL3) 또는 Normal World 에서 처리 할 수있는 외부 인터럽트가 FIQ로 전송됩니다. 이 모드는 아직 지원되지 않습니다.

  • Notes for Armv7-A/AArch32

    SP_IRQ는 별도의 스택 대신 임시 스택으로 초기화됩니다. Normal World 로 나가기 전에 CPU 상태가 SVC로 변경되고 임시 스택이 선택됩니다.

  • Notes for AArch64

    SP_EL0에는 임시 스택이 할당되고 IRQ 처리 중에 선택됩니다. 원래의SP_EL0은 스레드 컨텍스트에 저장되어 다시 시작할 때 복원됩니다.

1.5.6. Resume entry

OP-TEE is entered using the temp stack in the same way as for normal entry. The thread to resume is looked up and the state is restored to resume execution. The procedure to resume from an RPC exit or an foreign interrupt exit is exactly the same.

1.5.7. Syscall

Syscall’s are executed using the thread stack.

  • Notes for Armv7-A/AArch32

    특별한SP_SVC는 이미 쓰레드 스택으로 설정되어 있지 않습니다.

  • Notes for syscall AArch64

    예외 처리의 초기 단계에서 TA가 AArch64에서 실행될 경우 원본SP_EL0struct thread_svc_regs에 저장됩니다. 현재 쓰레드 스택은SP_EL0에 할당되고 그 다음에 선택됩니다. 리턴 할 때SP_EL0struct thread_svc_regs에있는 것을 할당받습니다. 이렇게하면 syscall 예외 처리기가thread_unwind_user_mode (...)로 직접 리턴되는tee_svc_sys_return_helper (...)를 허용합니다.

1.6. Shared Memory

공유 메모리는 비보안 및 Secure World 간에 공유되는 메모리 블록입니다. 두 세계간에 데이터를 전송하는 데 사용됩니다.

공유 메모리는 Non Secure World , 즉 Linux OP-TEE 드라이버에 의해 할당되고 관리됩니다. Secure World 에서는 풀이 아닌 개별 공유 버퍼 만 고려합니다. 각 공유 메모리는 연관된 속성으로 참조됩니다.

  • Buffer start address and byte size,
  • Cache attributes of the shared memory buffer,
  • List of chunks if mapped from noncontiguous pages.

조작 된 공유 메모리 버퍼 참조는 OP-TEE 코어에서 알려진 공유 메모리 영역 중 하나에 맞아야합니다. OP-TEE는 두 종류의 공유 ​​메모리 영역을 지원합니다 : 인접한 버퍼를위한 필수 영역과 인접하지 않은 버퍼를위한 선택적 여분의 메모리 영역.

1.6.1. Contiguous shared buffers

설정 지시자CFG_SHMEM_STARTCFG_SHMEM_SIZE는 공유 메모리 버퍼가 연속적인 공유 메모리 영역을 정의합니다. 일반 메모리 레이아웃은 그것을MEM_AREA_NSEC_SHM 메모리 영역으로 등록합니다.

비Secure World 는OPTEE_SMC_GET_SHM_CONFIG을 발행하여 인접한 공유 메모리 영역 구성을 검색합니다 :

  • Physical address of the start of the pool
  • Size of the pool
  • Whether or not the memory is cached

Contiguous shared memory (also known as static or reserved shared memory) is enabled with the configuration flag CFG_CORE_RESERVED_SHM=y.

1.6.2. Noncontiguous shared buffers

연속되지 않은 공유 메모리 버퍼의 이점을 얻으려면 Secure World 레지스터 동적 공유 메모리 영역과 비보안 월드가 OP-TEE API를 사용하여 참조하기 전에 비 연속 버퍼를 등록해야합니다.

OP-TEE 코어 일반 부팅 시퀀스는 장치 트리 및 / 또는 플랫폼에서 명시 적으로 등록한 영역에서 동적 공유 영역을 검색합니다.

비보안 측은 OPTEE_MSG_CMD_REGISTER_SHM API를 사용하여 OP-TEE 호출 API를 사용하여 버퍼를 4kByte 청크 목록으로 OP-TEE 코어에 등록해야합니다.

불연속 공유 메모리 (동적 공유 메모리라고도 함)는 구성 플래그CFG_CORE_DYN_SHM = y로 활성화됩니다.

1.6.3. Shared Memory Chunk Allocation

공유 메모리 청크 할당을 담당하는 OP-TEE 용 Linux 커널 드라이버입니다. OP-TEE 리눅스 커널 드라이버는 리눅스 커널의 일반적인 할당 지원 (CONFIG_GENERIC_ALLOCATION)을 공유 메모리 물리 덩어리 할당 / 해제에 의존합니다. OP-TEE 리눅스 커널 드라이버는 공유 메모리 버퍼 참조를 추적하기 위해 리눅스 커널 dma-buf 지원 (CONFIG_DMA_SHARED_BUFFER)에 의존합니다.

1.6.4. Using shared memory

  • From the Client Application
  • 클라이언트 응용 프로그램은 GlobalPlatform 클라이언트 API 함수 인 TEEC_AllocateSharedMemory (...)를 사용하여 공유 메모리 할당을 요청할 수 있습니다. 클라이언트 응용 프로그램은 GlobalPlatform 클라이언트 API 함수TEEC_RegisterSharedMemory (...) 를 통해 메모리를 등록 할 수도 있습니다. 그런 다음 공유 메모리 참조를 신뢰할 수있는 응용 프로그램을 호출 할 때 매개 변수로 사용할 수 있습니다.
  • From the Linux Driver
  • 때때로 리눅스 커널 드라이버는 Secure World 와의 통신을 위해 공유 메모리를 할당해야한다. 예를 들어 TEEC_TempMemoryReference 타입의 버퍼를 사용할 때.
  • From OP-TEE core
  • OP-TEE 코어가 TEE 요청자 (dynamic TA loading, REE time request,…)로부터 정보를 필요로하는 경우 공유 메모리가 할당되어야합니다. 할당은 유스 케이스에 달려있다. OP-TEE 코어는 다음과 같은 공유 메모리 할당을 요구합니다 :optee_msg_arg 구조체. Non Secure World 에 인수를 전달하는데 사용되며, 할당은OPTEE_SMC_RPC_FUNC_ALLOC 메시지를 보냄으로써 이루어집니다. 어떤 경우 페이로드는 신뢰할 수있는 응용 프로그램을로드 할 때와 같이 TEE 요청자의 결과를 저장하는 데 필요합니다. 이런 유형의 할당은OPTEE_MSG_RPC_CMD_SHM_ALLOC (OPTEE_MSG_RPC_SHM_TYPE_APPL, ...)메시지를 보내서 수행됩니다. 공유 메모리의 물리적 주소는 나중에 메모리를 사용할 때 나중에 사용됩니다.
  • From TEE Supplicant
  • TEE 요청자는 또한 Normal World 와 Secure World 간에 데이터를 교환하는 데 사용되는 공유 메모리로 작업하고 있습니다. TEE 요청자는 데이터를 저장하는 데 사용되는 OP-TEE 코어에서 메모리 주소를받습니다. 예를 들어, 신뢰할 수있는 응용 프로그램이로드 된 경우입니다. 이 경우 TEE 요청자가 Linux 응용 프로그램과 마찬가지로 Linux 드라이버와 관련하여 제공된 공유 메모리를 등록해야합니다.

1.7. SMC

1.7.1. SMC Interface

OP-TEE의 SMC 인터페이스는 optee_smc.hoptee_msg.h를 사용하여 두 단계로 정의됩니다. 이전 파일은 SMC 식별자를 정의하고 각 SMC의 레지스터에서 전달되는 내용을 정의합니다. 후자의 파일은 OP-TEE 메시지 프로토콜을 정의합니다. OP-TEE 메시지 프로토콜은 현재 유일하게 사용할 수있는 옵션 인 경우에도 SMC 에만 국한되지 않습니다.

1.7.2. SMC communication

SMC 통신에 사용되는 주요 구조체는struct optee_msg_arg(in optee_msg.h)에 정의되어 있습니다.

소스 코드를 살펴보면, 주로 optee_msg_argthread_smc_args (in thread.h)를 사용하여 통신이 이루어지는 것을 볼 수 있습니다. 여기서 optee_msg_arg는 주요 구조로 볼 수 있습니다. Linux kernel TEE framework driver는 optee_client 또는 Linux 커널의 내부 서비스에서 직접 매개 변수를 가져옵니다.

구조체에 매개 변수와 몇 가지 부가적인 부기 정보를 채 웁니다. SMC에 대한 매개 변수는 레지스터 1에서 7로 전달되고 레지스터 0에는 SMC ID가 저장됩니다.이 ID는 표준 또는 고속 호출인지 여부를 알려줍니다.

1.8. Thread handling

OP-TEE 코어는 두 개의 스레드를 사용하여 병렬로 실행중인 작업을 지원할 수 있습니다 (완전히 활성화되지 않았습니다!). 다른 목적을위한 핸들러가 있습니다. thread.c에서 thread_init_primary (...)라는 함수를 찾을 수 있습니다. 이 함수는 OP-TEE 코어가 표준 또는 고속 호출, FIQ 및 PSCI 호출을받을 때 호출되어야하는 init_handler() (function) 를 할당합니다. 이러한 서비스에 대한 기본 핸들러가 있지만 플랫폼은 대신 자신의 플랫폼 특정 핸들러를 구현할지 여부를 결정할 수 있습니다.

1.8.1. Synchronization primitives

OP-TEE에는 쓰레드와 CPU의 동기화를위한 3 가지 기본 요소가 있습니다 : spin-lock, mutex, condvar.

  • Spin-lock
  • 스핀 락은unsigned int로 표현됩니다. 이것은 가장 원시적 인 잠금입니다. 인터럽트는 스핀 잠금을 시도하기 전에 비활성화해야하며 잠금이 해제 될 때까지 비활성화 된 상태로 유지해야합니다.
  • Mutex
  • mutex는struct mutex로 표현됩니다. 뮤텍스는 활성화 또는 비활성화 된 인터럽트로 잠금 및 잠금 해제 될 수 있지만 일반 스레드에서만 가능합니다. 뮤텍스는 인터럽트 처리기, 중단 처리기 또는 CPU에 대한 스레드가 선택되기 전에 사용할 수 없습니다. 뮤텍스는MUTEX_INITIALIZER 또는mutex_init (...)로 시작합니다. 뮤텍스 functionsFunctionPurposemutex_lock (...)뮤텍스를 잠급니다. 뮤텍스가 잠기지 않은 경우 이것은 빠른 동작입니다. 그렇지 않으면 함수는 정상적인 세상에서 기다릴 RPC를 발행합니다.mutex_unlock (...)뮤텍스를 잠금 해제합니다.
    • 웨이터가 없다면 이것은 빠른 연산입니다. 그렇지 않으면 함수는 정상적인 세상에서 웨이터를 깨우기 위해 RPC를 발행합니다.mutex_trylock (...)잠금이 해제되면 뮤텍스를 잠그고true를 반환합니다. 그렇지 않으면 뮤텍스가 변경되지 않고 함수는false를 반환합니다.mutex_destroy (...)뮤텍스가 잠금 해제되어 있고 웨이터가 없다고 주장하면 뮤텍스에서 사용 된 메모리를 해제 할 수 있습니다. 뮤텍스가 잠겨지면mutex_lock (...)또는`mutex_trylock (...) '을 호출하는 스레드가 소유하며, 뮤텍스는 뮤텍스를 소유 한 스레드에 의해서만 잠금 해제 될 수 있습니다. 뮤텍스를 가지고있을 때 스레드는 TA 사용자 공간으로 나가면 안됩니다.
  • Condvar
  • condvar는struct condvar에 의해 표현됩니다. condvar는 pthreads 표준의pthread_condvar_t와 비슷하지만 덜 고급입니다. 조건 변수는 일부 조건이 충족되기를 기다리는 데 사용되며 항상 뮤텍스와 함께 사용됩니다. 조건 변수가 특정 뮤텍스와 함께 사용되면, 파기 될 때까지 해당 뮤텍스와 함께 사용해야합니다. condvar는CONDVAR_INITIALIZER 또는condvar_init (...)로 초기화됩니다. Condvar functionsFunctionPurposecondvar_wait (...)mutex가 Atomically 으로 잠금을 해제하고 RPC를 통해 Normal World 에서 대기하여 조건 변수가 신호를 받으면 함수가 mutex를 다시 잠급니다. condvar_signal (...)조건 변수의 웨이터 중 한 명을 깨운다(waiting incondvar_wait(...)). condvar_broadcast (...)조건 변수의 모든 웨이터를 기동시킵니다. condvar_signal (...) 또는 condvar_broadcast (...)호출자는 웨이터가 신호를 놓치지 않도록 조건 변수와 연관된 뮤텍스를 유지해야합니다.
반응형