00 ARM Exception Level mimarisi
ARMv8-A, çalışma ortamını dört ayrıcalık katmanına (EL0–EL3) ve iki güvenlik durumuna (Secure/Non-Secure) böler; bu yapı TF-A'nın temelini oluşturur.
Exception Level hiyerarşisi
ARMv8-A mimarisinde işlemci her zaman belirli bir Exception Level (EL) ve güvenlik durumunda çalışır. EL seviyesi yükseldikçe ayrıcalıklar artar; EL3 en yüksek ayrıcalıklı seviyedir ve her zaman Secure durumundadır.
┌─────────────────────────────────────────────────────────┐
│ NON-SECURE WORLD │
│ EL0 : User uygulamalar (glibc programları) │
│ EL1 : Linux kernel, sürücüler, istisna işleyiciler │
│ EL2 : Hypervisor (KVM, Xen) — opsiyonel │
└────────────────────┬────────────────────────────────────┘
│ SMC (Secure Monitor Call)
┌────────────────────▼────────────────────────────────────┐
│ SECURE WORLD │
│ EL3 : Secure Monitor (TF-A BL31) — daima Secure │
│ S-EL1 : Trusted OS (OP-TEE, Hafnium) │
│ S-EL0 : Trusted Applications │
└─────────────────────────────────────────────────────────┘
EL geçişleri
Normal World'den Secure World'e geçmek için SMC (Secure Monitor Call) komutu kullanılır. EL3'teki Secure Monitor bu çağrıyı alır, bağlamı kaydeder ve uygun dünyaya yönlendirir.
| Seviye | Dünya | Tipik yazılım | Geçiş komutu |
|---|---|---|---|
| EL0 | Non-Secure | Kullanıcı uygulamaları | SVC → EL1 |
| EL1 | Non-Secure | Linux kernel | HVC → EL2, SMC → EL3 |
| EL2 | Non-Secure | KVM/Xen hypervisor | SMC → EL3 |
| EL3 | Secure | TF-A BL31 runtime | ERET → herhangi EL |
| S-EL1 | Secure | OP-TEE OS | SMC → EL3 |
| S-EL0 | Secure | Trusted Application | SVC → S-EL1 |
SCR_EL3 — Secure Configuration Register
EL3'teki SCR_EL3 kaydı, Secure/Non-Secure geçişlerini ve SMC yakalama davranışını kontrol eder. TF-A bu kaydı boot aşamasında yapılandırır.
01 TF-A boot zinciri genel bakış
Trusted Firmware-A, ARM platformlarında ROM'dan başlayıp U-Boot veya UEFI'ye devreden beş aşamalı bir boot zinciri tanımlar.
Boot loader aşamaları
ROM (SoC içi, immutable)
│
▼
BL1 — Boot Loader Stage 1
│ Genellikle SoC ROM'una gömülü ya da küçük SRAM'de çalışır
│ FIP imajını yükler, BL2'ye geçer
▼
BL2 — Boot Loader Stage 2
│ Tüm kalan boot imajlarını (BL31, BL32, BL33) yükler
│ Platform init: DDR, clock, güvenlik periferikleri
▼
BL31 — EL3 Runtime Firmware
│ DRAM'de kalıcı olarak çalışır (EL3 resident)
│ SMC handler, PSCI, RAS, GIC routing
▼
BL32 — Secure-EL1 Payload (opsiyonel)
│ Genellikle OP-TEE OS — Trusted OS
▼
BL33 — Non-Secure Firmware
U-Boot, UEFI (EDK2), ya da doğrudan Linux
FIP — Firmware Image Package
TF-A tüm boot imajlarını tek bir FIP (Firmware Image Package) dosyasında paketler. FIP, UUID tabanlı bir dizin ve binary payload'lardan oluşur; flash'a tek blok olarak yazılır.
| FIP içeriği | UUID | Açıklama |
|---|---|---|
| BL2 | 5f04 … | İkinci aşama boot loader |
| BL31 | 47d4 … | EL3 runtime (Secure Monitor) |
| BL32 | 05d0 … | Secure-EL1 payload (OP-TEE) |
| BL33 | d6d0 … | Non-secure firmware (U-Boot) |
| HW_CONFIG | 08b8 … | Platform Device Tree |
| TB_FW_CONFIG | 6c07 … | TF-A firmware config DTB |
| NT_FW_CONFIG | 28da … | Non-trusted firmware config DTB |
Kaynak dizin yapısı
trusted-firmware-a/
├── bl1/ # BL1 kaynak kodu
├── bl2/ # BL2 kaynak kodu
├── bl31/ # BL31 (EL3 runtime) kaynak kodu
├── bl32/ # SP_MIN (32-bit TEE stub)
├── common/ # Ortak kütüphaneler: crypto, fip_parser, uuid
├── drivers/ # ARM Trusted Board Boot, GIC, TZC, UART vb.
├── include/ # Platform-bağımsız başlık dosyaları
├── lib/ # xlat_tables, el3_runtime, libc alt seti
├── make_helpers/ # Makefile yardımcıları
├── plat/ # Platform portları
│ ├── arm/ # ARM referans platformları (FVP, Juno)
│ ├── st/ # STM32MP1/MP2
│ ├── xilinx/ # Zynq UltraScale+
│ ├── mediatek/ # MT8xxx serisi
│ └── myplatform/ # Kendi platform portunuz
└── tools/
├── fiptool/ # FIP paketle/aç aracı
└── cert_create/ # Güven zinciri sertifika üretici
02 BL1 — ROM stage ve FIP yükleme
BL1, çoğu zaman SoC ROM'una ya da küçük bir SRAM'e yerleştirilen ilk güvenilir kodun bulunduğu aşamadır; FIP'i bulur ve BL2'yi belleğe yükler.
BL1 sorumlulukları
BL1 entry point akışı (basitleştirilmiş)
/* bl1/aarch64/bl1_entrypoint.S — özet */
el3_entrypoint_common: /* EL3'e özgü ilk setup */
msr SPSel, #1 /* SP_EL3 seç */
bl bl1_setup /* Platform early init */
bl bl1_main /* Ana BL1 fonksiyonu */
/* bl1/bl1_main.c */
void bl1_main(void)
{
/* 1. EL3 güvenlik ayarları */
bl1_arch_setup();
/* 2. Platform ilklendirme */
bl1_platform_setup();
/* 3. FIP'ten BL2 imajını yükle */
image_desc_t *bl2_desc = bl1_plat_get_image_desc(BL2_IMAGE_ID);
bl1_load_bl2();
/* 4. BL2'ye authenticate et (CoT etkinse) */
auth_mod_verify_img(BL2_IMAGE_ID, ...);
/* 5. BL2'ye geç */
bl1_prepare_next_image(BL2_IMAGE_ID);
}
Trusted Board Boot (TBBR)
TF-A, Trusted Board Boot Requirements (TBBR) standardını destekler. Her boot imajının bir X.509 sertifikasıyla imzalanmasını zorunlu kılar. TRUSTED_BOARD_BOOT=1 ile derleme yapıldığında BL1, BL2'nin ROTPK (Root of Trust Public Key) ile imzalandığını doğrular; doğrulama başarısız olursa boot durur.
# TBBR etkin derleme — BL1 imzalı BL2 bekler
make PLAT=myplatform TRUSTED_BOARD_BOOT=1 \
GENERATE_COT=1 \
ROT_KEY=keys/rot_key.pem \
all fip
03 BL2 — image loader ve bellek düzeni
BL2, FIP içindeki tüm imajları (BL31, BL32, BL33) DRAM'e yükler ve platform periferlerini başlatır; ardından kontrolü BL31'e devreder.
BL2'nin yüklediği imajlar
/* bl2/bl2_main.c — yükleme sırası */
int bl2_main(void)
{
bl2_arch_setup();
bl2_plat_preload_setup(); /* Platform erken init: DDR eğitimi vb. */
/* SCP_BL2 (opsiyonel — System Control Processor firmware) */
load_image_flush(SCP_BL2_IMAGE_ID);
/* BL31 — EL3 runtime, DRAM'in güvenli bölgesine */
load_image_flush(BL31_IMAGE_ID);
/* BL32 — OP-TEE, Secure-EL1 bölgesine (opsiyonel) */
load_image_flush(BL32_IMAGE_ID);
/* BL33 — U-Boot ya da UEFI, Non-Secure DRAM'e */
load_image_flush(BL33_IMAGE_ID);
/* BL31'e geç */
bl2_run_next_image(&bl31_ep_info);
}
Bellek düzeni (örnek — Cortex-A55 platformu)
Adres Aralığı Kullanım ───────────────────────────────────────────────── 0x0000_0000 – 0x0003_FFFF Trusted SRAM (256 KB) ├── BL1 kodu (ROM'da ya da SRAM başında) └── BL2 kodu + stack 0x4000_0000 – 0x43FF_FFFF Secure DRAM (64 MB — TZC korumalı) ├── BL31 runtime kodu + data └── BL32 (OP-TEE) kodu + data + heap 0x4400_0000 – 0xFFFF_FFFF Non-Secure DRAM └── BL33 (U-Boot) yükleme adresi + Linux image
Platform bellek tanımları
/* plat/myplatform/include/platform_def.h */
/* Trusted SRAM */
#define BL1_RO_BASE ULL(0x00000000)
#define BL1_RO_LIMIT ULL(0x00010000) /* 64 KB */
#define BL_RAM_BASE ULL(0x00010000)
#define BL_RAM_SIZE ULL(0x00030000) /* 192 KB */
/* BL2 SRAM bölgesi */
#define BL2_BASE ULL(0x00010000)
#define BL2_LIMIT ULL(0x00040000)
/* BL31 Secure DRAM */
#define BL31_BASE ULL(0x40000000)
#define BL31_LIMIT ULL(0x40040000) /* 256 KB */
/* BL32 (OP-TEE) */
#define BL32_BASE ULL(0x40400000)
#define BL32_LIMIT ULL(0x43C00000) /* 60 MB */
#define BL32_MEM_SIZE (BL32_LIMIT - BL32_BASE)
/* BL33 (U-Boot) */
#define BL33_BASE ULL(0x44000000)
#define PLAT_PHY_ADDR_SPACE_SIZE ULL(0x100000000)
DDR eğitimi ve BL2 platform init
Birçok SoC'de DDR kontrolörü BL2 sırasında başlatılır. bl2_plat_handle_pre_image_load() hook'u bu iş için kullanılır. DDR hazır olmadan BL31/BL32 DRAM adreslerine yüklenemez.
/* plat/myplatform/bl2_plat_setup.c */
void bl2_plat_preload_setup(void)
{
/* 1. PLL ve clock ağacını başlat */
myplat_clock_init();
/* 2. DDR PHY eğitimi ve kontrolör başlatma */
myplat_ddr_init();
/* 3. GIC, güvenlik periferikleri */
myplat_security_setup();
INFO("BL2: DDR hazir, %u MB\n", DRAM_SIZE_MB);
}
04 BL31 — EL3 runtime firmware ve SMC işleyici
BL31, sistem çalışır hâldeyken DRAM'de daima aktif kalan EL3 firmware'idir; SMC çağrılarını işler, PSCI servislerini sunar ve dünyalar arası geçişleri yönetir.
BL31 başlangıç akışı
/* bl31/bl31_main.c */
void bl31_main(void)
{
/* 1. EL3 runtime servisleri kaydettir */
runtime_svc_init(); /* PSCI, SDEI, SPM, vendor SMC vb. */
/* 2. GIC CPU interface init (her CPU için) */
gicv3_cpuif_enable(plat_my_core_pos());
/* 3. BL32 (OP-TEE) başlat — varsa */
if (bl32_init != NULL)
(*bl32_init)();
/* 4. BL33 (U-Boot) giriş bilgilerini hazırla */
bl31_prepare_next_image_entry();
/* 5. Konsol bırak, BL33'e ERET */
console_flush();
}
SMC çağrı mekanizması
Normal World'deki kod smc #0 komutuyla EL3'e geçer. ARM SMC Calling Convention (SMCCC) standart kayıt düzenini tanımlar.
Runtime servis kaydı
/* PSCI servis tanımı — services/std_svc/std_svc_setup.c */
DECLARE_RT_SVC(
std_svc,
OEN_STD_START,
OEN_STD_END,
SMC_TYPE_FAST,
std_svc_setup,
std_svc_smc_handler /* SMC geldiğinde çağrılan fonksiyon */
);
uintptr_t std_svc_smc_handler(uint32_t smc_fid,
u_register_t x1, u_register_t x2,
u_register_t x3, u_register_t x4,
void *cookie, void *handle,
u_register_t flags)
{
/* PSCI çağrısı mı? */
if (is_psci_fid(smc_fid))
return psci_smc_handler(smc_fid, x1, x2, x3, x4,
cookie, handle, flags);
/* SDEI (Software Delegated Exception Interface) */
if (is_sdei_fid(smc_fid))
return sdei_smc_handler(smc_fid, x1, x2, x3, x4,
cookie, handle, flags);
SMC_RET1(handle, SMC_UNK);
}
Vendor SiP servis ekleme
/* plat/myplatform/sip_svc.c — özel SiP SMC servisi */
#define MYPLAT_SIP_SVC_OEM_FUSE 0xC2000001UL
#define MYPLAT_SIP_SVC_THERMAL_READ 0xC2000002UL
static uintptr_t myplat_sip_handler(uint32_t smc_fid, ...)
{
switch (smc_fid) {
case MYPLAT_SIP_SVC_OEM_FUSE:
myplat_blow_fuse((uint32_t)x1, (uint32_t)x2);
SMC_RET1(handle, 0);
case MYPLAT_SIP_SVC_THERMAL_READ:
SMC_RET1(handle, myplat_read_temperature());
default:
SMC_RET1(handle, SMC_UNK);
}
}
DECLARE_RT_SVC(myplat_sip,
OEN_SIP_START, OEN_SIP_END,
SMC_TYPE_FAST, NULL, myplat_sip_handler);
05 PSCI — güç yönetimi servisleri
Power State Coordination Interface (PSCI), işlemci çekirdeklerinin açılıp kapanmasını, uyku durumlarını ve sistem sıfırlamasını standart SMC çağrılarıyla Linux'a sunan ARM standardıdır.
Temel PSCI fonksiyonları
| SMC ID (64-bit) | Fonksiyon | Kullanım |
|---|---|---|
| 0xC4000001 | CPU_SUSPEND | Çekirdeği derin uyku moduna al |
| 0xC4000002 | CPU_OFF | Çekirdeği tamamen kapat (hotplug) |
| 0xC4000003 | CPU_ON | Başka bir çekirdeği başlat |
| 0xC4000004 | AFFINITY_INFO | Çekirdek güç durumunu sorgula |
| 0xC4000008 | SYSTEM_OFF | Sistemi kapat |
| 0xC4000009 | SYSTEM_RESET | Sistemi yeniden başlat |
| 0xC400000A | SYSTEM_RESET2 | Sıfırlama sebebi iletme |
| 0x84000010 | PSCI_VERSION | PSCI versiyon sorgula |
Platform PSCI handler implementasyonu
/* plat/myplatform/myplat_pm.c */
static void myplat_cpu_standby(plat_local_state_t cpu_state)
{
uint64_t scr = read_scr_el3();
/* IRQ gelene dek WFI */
write_scr_el3(scr | SCR_IRQ_BIT);
isb();
dsb();
wfi();
write_scr_el3(scr);
}
static int myplat_pwr_domain_on(u_register_t mpidr)
{
unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr);
/* CPU başlangıç adresini platform register'a yaz */
mmio_write_64(MYPLAT_CPU_RELEASE_ADDR(cpu_id),
(uint64_t)&bl31_warm_entrypoint);
/* Cache flush — diğer çekirdek okuyabilmeli */
flush_dcache_range(MYPLAT_CPU_RELEASE_ADDR(cpu_id), 8);
/* CPU'yu GIC üzerinden uyandır (SGI ya da platform reset) */
myplat_send_sgi(cpu_id, 0);
return PSCI_E_SUCCESS;
}
static void myplat_pwr_domain_off(const psci_power_state_t *target)
{
/* GIC CPU interface devre dışı */
gicv3_cpuif_disable(plat_my_core_pos());
/* Platform-specific power gate */
myplat_cpu_power_down(plat_my_core_pos());
}
static void myplat_system_reset(void)
{
/* Watchdog üzerinden sıfırlama */
mmio_write_32(MYPLAT_WDT_BASE + WDT_CTL, WDT_RESET_NOW);
wfi(); /* Asla dönmemeli */
}
const plat_psci_ops_t myplat_psci_ops = {
.cpu_standby = myplat_cpu_standby,
.pwr_domain_on = myplat_pwr_domain_on,
.pwr_domain_off = myplat_pwr_domain_off,
.pwr_domain_suspend = myplat_pwr_domain_suspend,
.pwr_domain_on_finish = myplat_pwr_domain_on_finish,
.system_off = myplat_system_off,
.system_reset = myplat_system_reset,
.validate_power_state = myplat_validate_power_state,
};
Linux device tree PSCI düğümü
/* board.dts */
/ {
psci {
compatible = "arm,psci-1.0";
method = "smc";
cpu_on = <0xC4000003>;
cpu_off = <0xC4000002>;
cpu_suspend = <0xC4000001>;
sys_poweroff = <0xC4000008>;
sys_reset = <0xC4000009>;
};
cpus {
cpu@0 { enable-method = "psci"; };
cpu@1 { enable-method = "psci"; };
cpu@2 { enable-method = "psci"; };
cpu@3 { enable-method = "psci"; };
};
};
06 Güvenli/güvensiz bellek bölümleme
TrustZone bellek koruması, TZC-400 (TrustZone Address Space Controller) ve TZASC gibi donanım bileşenleriyle DRAM bölgelerini Secure/Non-Secure olarak erişime kilitler.
TZC-400 mimarisi
TZC-400, DRAM kontrolörü ile işlemci arasına yerleştirilen bir adres uzayı denetleyicisidir. Her DRAM işlemi için kaynak (Secure/Non-Secure, CPU/DMA) ve hedef adres aralığını denetler; ihlalde AXI DECERR döndürür.
CPU / DMA master → AXI bus → TZC-400 → DRAM kontrolör → DRAM TZC-400 dahili yapısı: ┌─────────────────────────────────────────┐ │ Region 0: Background region (tümü) │ │ Region 1: 0x40000000–0x43FFFFFF │ │ → Secure only (BL31 + OP-TEE) │ │ Region 2: 0x44000000–0xFFFFFFFF │ │ → Non-Secure R/W │ └─────────────────────────────────────────┘
TZC-400 TF-A konfigürasyonu
/* plat/myplatform/myplat_security.c */
#include <drivers/arm/tzc400.h>
void myplat_security_setup(void)
{
/* TZC-400 başlat */
tzc400_init(MYPLAT_TZC_BASE);
tzc400_disable_filters();
/* Region 0: tüm DRAM — sadece Secure erişim (varsayılan kısıtlayıcı) */
tzc400_configure_region0(TZC_REGION_S_RDWR, 0);
/* Region 1: Secure DRAM — BL31 + OP-TEE */
tzc400_configure_region(
MYPLAT_TZC_FILTER,
1, /* region numarası */
BL32_BASE, /* başlangıç: 0x40000000 */
BL32_LIMIT - 1, /* bitiş: 0x43FFFFFF */
TZC_REGION_S_RDWR, /* sadece Secure okuma/yazma */
PLAT_ARM_TZC_NS_DEV_ACCESS /* Non-Secure erişim yok */
);
/* Region 2: Non-Secure DRAM — U-Boot, Linux */
tzc400_configure_region(
MYPLAT_TZC_FILTER,
2,
BL33_BASE, /* 0x44000000 */
PLAT_ARM_DRAM1_BASE + PLAT_ARM_DRAM1_SIZE - 1,
TZC_REGION_S_RDWR,
TZC_REGION_ACCESS_RDWR /* NS okuma/yazma */
);
tzc400_enable_filters();
tzc400_set_action(TZC_ACTION_ERR); /* ihlalde AXI error */
}
TZMP1 — TrustZone Media Protection
Video/kamera pipeline'larında media buffer'ların korunması için TZC'ye ek olarak SMMU (System MMU) güvenlik konfigürasyonu gerekir. Secure World DMA master NSAID'i Secure olarak işaretlenmelidir.
| Bileşen | Görev | TF-A sürücüsü |
|---|---|---|
| TZC-400 | DRAM bölge erişim kontrolü | drivers/arm/tzc/tzc400.c |
| GIC-600 | Güvenli/güvensiz kesme yönlendirme | drivers/arm/gic/v3/gicv3_main.c |
| TZASC | TZC-400 benzeri, bazı Xilinx/ST SoC'ler | drivers/arm/tzc/tzc_dmc620.c |
| SMMU-v3 | DMA master güvenlik izolasyonu | drivers/arm/smmu/smmu_v3.c |
| NIC-400 | AXI interconnect güvenlik ayarları | Platform özel |
07 Platform port yazımı
Yeni bir SoC için TF-A portu, plat/myplatform/ dizininde platform makroları, console, clock, güç yönetimi ve bellek düzeni fonksiyonlarının implement edilmesiyle oluşturulur.
Minimum platform dizin yapısı
plat/myplatform/
├── platform.mk # Derleme sistemi: kaynak listesi, tanımlar
├── include/
│ └── platform_def.h # Adres, boyut, limit makroları
├── myplat_bl1_setup.c # bl1_plat_arch_setup, bl1_platform_setup
├── myplat_bl2_setup.c # bl2_plat_preload_setup, image listesi
├── myplat_bl31_setup.c # bl31_platform_setup, bl31_plat_runtime_setup
├── myplat_pm.c # plat_psci_ops implementasyonu
├── myplat_security.c # TZC, NIC konfigürasyonu
├── myplat_topology.c # plat_core_pos_by_mpidr, cluster topolojisi
├── myplat_io.c # FIP'i okuyan IO backend (NOR/eMMC/SPI)
└── aarch64/
└── myplat_helpers.S # Erken asm init, CPU release address
platform.mk — zorunlu değişkenler
# plat/myplatform/platform.mk
# İşlemci kütüphanesi (Cortex-A55 çekirdek)
ARM_CORTEX_A55 := yes
HW_ASSISTED_COHERENCY := 1
USE_COHERENT_MEM := 0
# Desteklenen boot loader'lar
MYPLAT_SOURCES := \
plat/myplatform/myplat_bl1_setup.c \
plat/myplatform/myplat_bl2_setup.c \
plat/myplatform/myplat_bl31_setup.c \
plat/myplatform/myplat_pm.c \
plat/myplatform/myplat_security.c \
plat/myplatform/myplat_topology.c \
plat/myplatform/myplat_io.c \
plat/myplatform/aarch64/myplat_helpers.S
BL1_SOURCES += $(MYPLAT_SOURCES)
BL2_SOURCES += $(MYPLAT_SOURCES)
BL31_SOURCES += $(MYPLAT_SOURCES)
# GICv3 sürücüsü ekle
include drivers/arm/gic/v3/gicv3.mk
GIC_SOURCES := $(GICV3_SOURCES)
BL31_SOURCES += $(GIC_SOURCES)
# TZC-400
BL2_SOURCES += drivers/arm/tzc/tzc400.c
Topoloji tanımlama
/* plat/myplatform/myplat_topology.c */
/* 4 çekirdek, tek cluster, tek socket */
const mpidr_afflvl_limit_t mpidr_afflvl_limits[MPIDR_AFFLVL_MAX + 1] = {
{ .min = 0, .max = 3 }, /* Afflvl0: CPU 0-3 */
{ .min = 0, .max = 0 }, /* Afflvl1: Cluster 0 */
{ .min = 0, .max = 0 }, /* Afflvl2: System 0 */
};
int plat_core_pos_by_mpidr(u_register_t mpidr)
{
unsigned int cluster = MPIDR_AFFLVL1_VAL(mpidr);
unsigned int cpu = MPIDR_AFFLVL0_VAL(mpidr);
if (cluster != 0 || cpu >= PLATFORM_CORE_COUNT)
return -1;
return (int)cpu;
}
unsigned int plat_get_syscnt_freq2(void) {
return MYPLAT_SYSCNT_FREQ; /* 24 MHz */
}
IO backend — eMMC'den FIP okuma
/* plat/myplatform/myplat_io.c (özet) */
static const io_dev_connector_t *emmc_dev_con;
static uintptr_t emmc_dev_handle;
static const io_block_spec_t fip_block_spec = {
.offset = FIP_EMMC_SECTOR * MMC_BLOCK_SIZE,
.length = PLAT_ARM_FIP_MAX_SIZE,
};
void myplat_io_setup(void)
{
register_io_dev_block(&emmc_dev_con);
io_dev_open(emmc_dev_con, (uintptr_t)&emmc_dev_spec,
&emmc_dev_handle);
plat_io_register_img_io(FIP_IMAGE_ID, emmc_dev_handle,
&fip_block_spec);
}
08 Build, flash ve JTAG debug
TF-A'yı derleyip FIP oluşturmak, target'a yazmak ve JTAG üzerinden BL1'den itibaren adım adım debug etmek için gereken komutlar ve yöntemler.
Derleme — temel komutlar
# Bağımlılıklar (Ubuntu/Debian)
sudo apt install build-essential gcc-aarch64-linux-gnu \
binutils-aarch64-linux-gnu libssl-dev python3 \
device-tree-compiler
# Sade BL31 derle (sadece TF-A, BL32/BL33 harici)
make PLAT=myplatform CROSS_COMPILE=aarch64-linux-gnu- \
DEBUG=1 LOG_LEVEL=50 \
bl31
# Tam FIP oluştur: BL2 + BL31 + OP-TEE + U-Boot
make PLAT=myplatform CROSS_COMPILE=aarch64-linux-gnu- \
DEBUG=1 LOG_LEVEL=50 \
BL32=/path/to/tee.bin \
BL33=/path/to/u-boot.bin \
all fip
# TBBR ile imzalı FIP
make PLAT=myplatform CROSS_COMPILE=aarch64-linux-gnu- \
TRUSTED_BOARD_BOOT=1 GENERATE_COT=1 \
ROT_KEY=keys/rot_key.pem \
BL32=/path/to/tee.bin BL33=/path/to/u-boot.bin \
all fip certificates
# Çıktı dosyaları
# build/myplatform/debug/
# bl1.bin bl2.bin bl31.bin fip.bin
# certificates/ (CoT sertifikaları)
FIP aracı — içeriği incele / değiştir
# FIP içeriğini listele
tools/fiptool/fiptool info build/myplatform/debug/fip.bin
# FIP'ten BL31 çıkar
tools/fiptool/fiptool unpack --bl31 /tmp/bl31.bin fip.bin
# FIP'e yeni BL33 ekle (U-Boot güncellendiğinde)
tools/fiptool/fiptool update --bl33 /path/to/new-u-boot.bin fip.bin
# FIP boyutu ve UUID listesi
tools/fiptool/fiptool info --verbose fip.bin
Flash yazma — eMMC üzerinden
# U-Boot komut satırından (tftp + mmc write):
# 1. FIP'i TFTP ile DRAM'e çek
tftp 0x44000000 fip.bin
# 2. eMMC boot0 bölümüne yaz (sektör 64'ten başlayarak)
mmc dev 0 1 # boot0 hw partition seç
mmc write 0x44000000 0x40 0x800 # 0x40 = sektör 64, 0x800 = 1 MB
# OpenOCD + flash_write ile doğrudan programlama:
openocd -f interface/jlink.cfg \
-f target/myplatform.cfg \
-c "init; halt; \
flash write_image erase fip.bin 0x08000000; \
reset run; exit"
JTAG debug — BL1'den adım adım
# OpenOCD + GDB ile BL1 debug (semboller dahil)
# Terminal 1: OpenOCD başlat
openocd -f interface/jlink.cfg \
-f target/myplatform.cfg
# Terminal 2: GDB bağlan
aarch64-linux-gnu-gdb build/myplatform/debug/bl1/bl1.elf
(gdb) target remote :3333
(gdb) monitor reset halt
(gdb) load # ELF sembollerini yükle
(gdb) break bl1_main # BL1 main'e breakpoint
(gdb) continue
# BL31 debug için (DRAM'e yüklendikten sonra)
(gdb) add-symbol-file build/myplatform/debug/bl31/bl31.elf \
-s .text 0x40000000 # BL31 yükleme adresi
# Belirli SMC çağrısında durma
(gdb) break psci_smc_handler
(gdb) commands
> printf "SMC fid: 0x%x, x1=0x%lx\n", $x0, $x1
> continue
> end
TF-A log seviyeleri
# Tipik BL31 verbose çıktısı (LOG_LEVEL=50):
# NOTICE: BL31: v2.9(debug):ceb12bb
# NOTICE: BL31: Built: Apr 15 2026 09:00:00
# INFO: BL31: Initializing runtime services
# INFO: BL31: cortex_a55: CPU workaround for erratum 768277 was applied
# INFO: BL31: PSCI v1.1 initialized
# INFO: GICv3 with legacy support detected
# INFO: BL31: Preparing for EL3 exit to normal world
# VERBOSE: Entry point address = 0x44000000
# VERBOSE: SPSR = 0x3c9