00 IOMMU neden gerekli — tehdit modeli
DMA (Direct Memory Access) yetenekli her cihaz, teorik olarak tüm fiziksel belleğe yazabilir. IOMMU bu yetkiyi sınırlandırarak sistem güvenliğinin temel katmanlarından birini oluşturur.
DMA Saldırı Yüzeyi
DMA mekanizması, cihazların CPU'yu devre dışı bırakarak belleğe doğrudan erişmesini sağlar. Bu özellik performans için zorunludur; ancak kötü niyetli veya hatalı bir cihaz, DMA üzerinden aşağıdaki saldırıları gerçekleştirebilir:
IOMMU Nasıl Korur?
IOMMU (Input-Output Memory Management Unit), CPU'nun MMU'sunun (Memory Management Unit) I/O cihazları için olan karşılığıdır. Her cihazın erişebildiği bellek aralığını tanımlayan bir sayfa tablosu tutar. Cihaz, eşlenmemiş bir adrese erişmeye çalışırsa IOMMU işlemi engeller ve bir hata (fault) üretir.
Cihaz (DMA Master)
|
| bus adresi (IOVA)
v
IOMMU / SMMU
|--- Adres eşleme tablosuna bak ---+
| |
| İzin Var | İzin Yok
v v
Fiziksel Bellek Context Fault (IRQ) -> Kernel Handler
(erişim gerçekleşir) (erişim engellendi, hata raporu)
IOVA ve Fiziksel Adres Farkı
Cihaz, fiziksel adresleri değil IOVA (I/O Virtual Address) kullanır. IOMMU bu IOVA'ları fiziksel adreslere çevirir. Böylece aynı fiziksel adresin farklı cihazlara farklı IOVA'larla görünmesi mümkündür; bu da izolasyonun temelidir.
| Senaryo | IOMMU Yok | IOMMU Var |
|---|---|---|
| Cihaz DMA adresi | Fiziksel adres | IOVA (sanal) |
| Bellek erişim sınırı | Tüm fiziksel bellek | Eşlenmiş bölgeler |
| Saldırı yüzeyi | Tüm bellek | Sadece izin verilen aralık |
| Hata tespiti | Yok (sessiz bozulma) | Context fault + IRQ |
| VM geçişi (VFIO) | Mümkün değil (güvensiz) | Mümkün (izole edilmiş) |
01 ARM SMMU mimarisi — SMMUv2 ve SMMUv3
ARM'ın SMMU (System Memory Management Unit) standardı, IOMMU işlevini ARM SoC'ları için tanımlar. SMMUv2 ve SMMUv3 arasında mimari açıdan önemli farklılıklar bulunur.
SMMUv2 Mimarisi
SMMUv2 (ARM IHI 0062), Cortex-A53/A57 nesli SoC'larda yaygın kullanılan ilk büyük SMMU revizyonudur. StreamID tabanlı cihaz kimliği kullanır ve iki aşamalı adres çevirisi destekler.
SMMUv3 Mimarisi
SMMUv3 (ARM IHI 0070), Cortex-A55/A76 nesli ile birlikte gelir. Komut kuyruğu tabanlı (command queue) bir arayüzle önceki sürümden temelden farklılaşır ve ölçeklenebilirliği büyük ölçüde artırır.
| Özellik | SMMUv2 | SMMUv3 |
|---|---|---|
| Cihaz kimliği | StreamID (16 bit) | StreamID (32 bit) + SubstreamID (20 bit) |
| Context erişimi | Doğrudan register yazma | Komut kuyruğu (CMD_QUEUE) |
| Hata raporlama | Global fault register | Olay kuyruğu (EVENT_QUEUE) |
| TLB geçersizleştirme | Senkron, global | Asenkron, granüler (TLBI_NH_ASID vb.) |
| Sayfa boyutu desteği | 4KB, 64KB | 4KB, 16KB, 64KB, 1GB süper-sayfa |
| PCIe ATS | Yok | Var (Address Translation Services) |
| PRI (Page Request Interface) | Yok | Var |
| SVA (Shared Virtual Addressing) | Yok | Var (PasID ile) |
İki Aşamalı Çeviri Akışı
Cihaz DMA talebi (IOVA)
|
v
SMMU Stage-1 (OS kontrolünde)
IOVA --[STE/CD tablosu]--> IPA
|
v
SMMU Stage-2 (Hypervisor kontrolünde)
IPA --[S2 sayfa tablosu]--> PA
|
v
Fiziksel bellek erişimi
02 Linux IOMMU çerçevesi
Linux kernel, farklı IOMMU donanımlarını (ARM SMMU, Intel VT-d, AMD-Vi) tek bir soyut arayüz altında toplar. Bu arayüz sürücü geliştiricilerine donanımdan bağımsız bir API sunar.
Temel Veri Yapıları
/* IOMMU domain — bir izolasyon alanı */
struct iommu_domain {
unsigned type; /* IOMMU_DOMAIN_DMA, IDENTITY, UNMANAGED */
const struct iommu_ops *ops; /* Donanıma özgü işlemler */
unsigned long pgsize_bitmap; /* Desteklenen sayfa boyutları */
iommu_fault_handler_t handler; /* Context fault handler */
void *handler_token;
struct iommu_domain_geometry geometry; /* IOVA aralığı */
struct iommu_dma_cookie *iova_cookie; /* IOVA havuzu */
};
/* IOMMU grubu — aynı domaine bağlı cihaz kümesi */
struct iommu_group {
struct kobject kobj;
struct kobject *devices_kobj;
struct list_head devices; /* Gruptaki cihazlar */
struct mutex mutex;
struct blocking_notifier_head notifier;
void *iommu_data;
void (*iommu_data_release)(void *iommu_data);
char *name;
int id;
struct iommu_domain *default_domain; /* Varsayılan domain */
struct iommu_domain *blocking_domain;
};
iommu_ops Arayüzü
Her IOMMU sürücüsü iommu_ops yapısını uygular. Bu yapı, sayfa tablosu yönetiminden TLB geçersizleştirmeye kadar tüm donanım işlemlerini tanımlar:
struct iommu_ops {
bool (*capable)(struct device *dev, enum iommu_cap);
struct iommu_domain *(*domain_alloc)(unsigned iommu_domain_type);
void (*domain_free)(struct iommu_domain *);
int (*attach_dev)(struct iommu_domain *, struct device *);
void (*detach_dev)(struct iommu_domain *, struct device *);
int (*map)(struct iommu_domain *, unsigned long iova,
phys_addr_t paddr, size_t size, int prot, gfp_t gfp);
size_t (*unmap)(struct iommu_domain *, unsigned long iova,
size_t size, struct iommu_iotlb_gather *);
phys_addr_t (*iova_to_phys)(struct iommu_domain *, dma_addr_t iova);
struct iommu_group *(*device_group)(struct device *);
void (*get_resv_regions)(struct device *, struct list_head *);
int (*of_xlate)(struct device *, struct of_phandle_args *);
/* ... */
};
DMA-API ile Entegrasyon
Sürücüler genellikle doğrudan IOMMU API'sini çağırmaz; bunun yerine dma_map_single, dma_alloc_coherent gibi DMA-API fonksiyonlarını kullanır. IOMMU, bu fonksiyonların altında şeffaf olarak çalışır:
/* IOMMU etkinken DMA-API akışı */
dma_map_single(dev, cpu_ptr, size, DMA_FROM_DEVICE)
|
v
iommu_map(domain, iova, phys, size, IOMMU_READ | IOMMU_WRITE)
|
v
ARM SMMU: arm_smmu_map() -> sayfa tablosuna giriş ekle
|
v
dma_addr_t (IOVA) sürücüye döner
|
v
Sürücü bu adresi donanıma yazar (DMA başlar)
03 Device Tree ile SMMU yapılandırması
ARM platformlarında SMMU, Device Tree (DT) aracılığıyla yapılandırılır. Cihaz ile SMMU arasındaki ilişki DT bağlantılarıyla tanımlanır; Linux IOMMU altyapısı bu bağlantıları önyükleme sırasında işler.
SMMU Node Tanımı
/* ARM64 DT örneği: SMMUv2 tanımı */
smmu_0: iommu@fd800000 {
compatible = "arm,mmu-500";
reg = <&smmu_reg 0 0 0 0x20000>;
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "global-faults", "perf-counters",
"context-faults";
#iommu-cells = <1>; /* 1 = StreamID sayısı */
#global-interrupts = <2>;
/* SMMU'nun bağlı olduğu bellek bölgeleri */
dma-ranges;
};
Cihaz SMMU Bağlantısı
/* Ethernet MAC — SMMU'ya StreamID 0x42 ile bağlı */
ethernet@ff000000 {
compatible = "vendor,my-eth";
reg = <0xff000000 0x10000>;
interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk_eth>;
/* SMMU bağlantısı: iommu referansı + StreamID */
iommus = <&smmu_0 0x42>;
/* IOMMU grubu ayrımı için gerekirse */
iommu-map = <0x0 &smmu_0 0x42 0x1>;
};
/* Video DMA — farklı StreamID */
video_dma@fe000000 {
compatible = "vendor,my-vdma";
reg = <0xfe000000 0x8000>;
iommus = <&smmu_0 0x55>; /* StreamID 0x55 */
};
SMMUv3 DT Tanımı
/* SMMUv3 (daha yeni platformlar) */
smmu_1: iommu@09050000 {
compatible = "arm,smmu-v3";
reg = <0x0 0x09050000 0x0 0x80000>;
interrupts = <GIC_SPI 74 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 75 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 76 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 77 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "eventq", "priq", "cmdq-sync", "gerror";
#iommu-cells = <1>;
dma-coherent; /* Donanım cache coherency desteği */
/* StreamID genişliği: 16 bit */
arm,sid-bits = <16>;
};
Önyükleme Sırasında DT İşleme
Kernel onyukleme
|
v
of_platform_populate() -- DT node'larini tara
|
v
iommu node bulundu (compatible = "arm,mmu-500")
-> arm_smmu_probe() cagrılır
-> SMMU donanimi baslatilir
|
v
Cihaz node'u islenirken "iommus" property bulundu
-> of_iommu_xlate() cagrılır
-> iommu_group olusturulur veya var olana eklenir
|
v
Cihaz surucu probe() cagrildiginda:
-> iommu_attach_device() ile domain'e baglanir
İlgili Kernel Parametreleri
04 IOMMU domain tipleri
Linux IOMMU çerçevesi birden fazla domain tipi tanımlar. Hangi tipin kullanılacağı, cihazın güvenlik gereksinimlerine ve çalışma moduna göre belirlenir.
Domain Tipleri
Domain Oluşturma ve Cihaz Bağlama
#include <linux/iommu.h>
/* Yeni bir DMA domain oluştur */
struct iommu_domain *domain = iommu_domain_alloc(&platform_bus_type);
if (!domain) {
pr_err("IOMMU domain oluşturulamadı\n");
return -ENOMEM;
}
/* Cihazı domain'e bağla */
int ret = iommu_attach_device(domain, dev);
if (ret) {
pr_err("Cihaz domain'e baglanamadi: %d\n", ret);
iommu_domain_free(domain);
return ret;
}
/* Bir bellek bölgesi eşle */
ret = iommu_map(domain,
iova, /* I/O sanal adres */
paddr, /* Fiziksel adres */
size, /* Boyut (sayfa katı) */
IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE,
GFP_KERNEL
);
/* Eşlemeyi kaldır */
size_t unmapped = iommu_unmap(domain, iova, size);
/* Cihazı ayır */
iommu_detach_device(domain, dev);
iommu_domain_free(domain);
IOMMU Grup Yönetimi
Bir IOMMU grubu, aynı izolasyon birimine dahil edilen cihazların kümesidir. Genellikle aynı PCIe Root Port veya AXI fabric segment'ini paylaşan cihazlar aynı grupta yer alır. Tüm grup aynı domain'e bağlanmak zorundadır:
/* Cihazın grubunu al */
struct iommu_group *group = iommu_group_get(dev);
if (!group) {
pr_err("Cihazın IOMMU grubu yok\n");
return -ENODEV;
}
/* Gruptaki cihaz sayısı */
int count = iommu_group_get_iommudata(group);
/* Grup ID'sini öğren */
int gid = iommu_group_id(group);
pr_info("Cihaz IOMMU grup %d'de\n", gid);
/* Referansı serbest bırak */
iommu_group_put(group);
# Kullanıcı alanından grup bilgisi:
ls /sys/bus/platform/devices/ff000000.ethernet/iommu_group/
# devices/ type reserved_regions
Domain Ayırma Kontrolü
# Bir cihazın hangi domain'e bağlı olduğunu kontrol et:
cat /sys/bus/platform/devices/ff000000.ethernet/iommu_group/type
# DMA (veya identity, unmanaged)
# Tüm IOMMU gruplarını listele:
ls /sys/kernel/iommu_groups/
# Grup 5'in üyelerini göster:
ls /sys/kernel/iommu_groups/5/devices/
05 DMA güvenli tahsis ve IOMMU eşleme
IOMMU etkin bir sistemde DMA tamponları tahsis ederken ve fiziksel adresleri eşlerken özel dikkat gerektirir. Yanlış kullanım hem güvenlik açığı hem de bellek bozulmasına neden olabilir.
dma_alloc_coherent ile Tutarlı Bellek
Tutarlı (coherent) DMA belleği, hem CPU hem cihaz tarafından tutarlı şekilde görülen, önbellek senkronizasyonu gerektirmeyen bir bölgedir. IOMMU etkinken bu belleğin IOVA alanına eşlenmesi otomatik gerçekleşir:
#include <linux/dma-mapping.h>
/* 4 KB tutarlı DMA belleği tahsis et */
dma_addr_t dma_handle;
void *cpu_addr = dma_alloc_coherent(dev, 4096,
&dma_handle, GFP_KERNEL);
if (!cpu_addr) {
dev_err(dev, "DMA bellek tahsis hatası\n");
return -ENOMEM;
}
/* cpu_addr: CPU'nun eriştiği sanal adres */
/* dma_handle: Cihaza yazılacak IOVA değeri */
/* Cihaza IOVA adresini bildir */
writel((u32)dma_handle, dev_base + DMA_ADDR_REG);
writel(4096, dev_base + DMA_LEN_REG);
writel(DMA_START, dev_base + DMA_CTRL_REG);
/* DMA tamamlandıktan sonra serbest bırak */
dma_free_coherent(dev, 4096, cpu_addr, dma_handle);
Scatter-Gather ile IOMMU Eşleme
Büyük veya parçalı tamponlar için scatter-gather listesi kullanılır. IOMMU, bu parçaları cihazdan tek parçaymış gibi görünen ardışık bir IOVA aralığına eşleyebilir (IOMMU merging):
#include <linux/scatterlist.h>
struct scatterlist sg[4];
struct page *pages[4];
int i;
/* Sayfaları tahsis et (bitişik olmak zorunda değil) */
for (i = 0; i < 4; i++) {
pages[i] = alloc_page(GFP_KERNEL);
sg_set_page(&sg[i], pages[i], PAGE_SIZE, 0);
}
sg_mark_end(&sg[3]);
/* IOMMU üzerinden eşle */
int nents = dma_map_sg(dev, sg, 4, DMA_FROM_DEVICE);
if (nents == 0) {
dev_err(dev, "SG eşleme başarısız\n");
goto free_pages;
}
/* IOMMU birleştirme sonrası nents, 4'ten az olabilir */
pr_info("SG: %d giriş, %d eşleme sonrası\n", 4, nents);
for (i = 0; i < nents; i++) {
pr_info(" sg[%d]: dma_addr=0x%llx len=%u\n",
i, (u64)sg_dma_address(&sg[i]),
sg_dma_len(&sg[i]));
}
/* İşlem sonrası eşlemeyi kaldır */
dma_unmap_sg(dev, sg, 4, DMA_FROM_DEVICE);
iommu_map ve iommu_unmap (Manuel)
VFIO veya özel güvenlik alt sistemleri gibi durumlarda eşlemeleri doğrudan IOMMU API üzerinden yönetmek gerekebilir:
/* Manuel eşleme — IOMMU_DOMAIN_UNMANAGED domain için */
ret = iommu_map(domain,
0x40000000UL, /* IOVA: cihazın göreceği adres */
phys_addr, /* PA: gerçek fiziksel adres */
SZ_2M, /* 2 MB eşle */
IOMMU_READ | IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO,
GFP_KERNEL
);
/* Eşlemeyi doğrula */
phys_addr_t check = iommu_iova_to_phys(domain, 0x40000000UL);
pr_info("IOVA 0x40000000 -> PA 0x%llx\n", (u64)check);
/* Eşlemeyi kaldır */
iommu_unmap(domain, 0x40000000UL, SZ_2M);
Streaming vs Coherent DMA Karşılaştırması
| Özellik | dma_alloc_coherent | dma_map_single (streaming) |
|---|---|---|
| Önbellek yönetimi | Otomatik (non-cacheable) | Açık sync gerektirir |
| Kullanım durumu | Sürekli erişim, kontrol yapıları | Tek seferlik veri transferi |
| Bellek verimliliği | Daha az verimli (non-cached) | Daha verimli |
| IOMMU eşleme ömrü | Kalıcı (free'ye kadar) | Transfer süresi kadar |
06 VFIO ve SMMU — cihaz geçişi
VFIO (Virtual Function I/O), kullanıcı alanı sürücülerine ve sanal makinelere gerçek donanım cihazlarını güvenli biçimde geçirmek için IOMMU altyapısını kullanır.
VFIO Mimarisi
VFIO üç temel kavram üzerine inşa edilmiştir: container, group ve device. Bu üçlü katmanlı yapı, izolasyon garantisini IOMMU ile sağlar.
Kullanici alani (VM / QEMU / uygulama)
|
| /dev/vfio/vfio (container)
v
VFIO Container
|--- IOMMU domain yönetimi
|--- IOVA adres alanı kontrol
|
+--> VFIO Group (/dev/vfio/5)
|--- Aynı IOMMU grubundaki cihazlar
|
+--> VFIO Device (bellek/irq/config erişimi)
|--- BAR eşleme (mmap)
|--- IRQ yönlendirme (eventfd)
|--- Config space erişimi
VFIO ile Cihaz Kullanımı (Kullanıcı Alanı)
#include <linux/vfio.h>
#include <sys/ioctl.h>
#include <fcntl.h>
/* 1. Container aç */
int container = open("/dev/vfio/vfio", O_RDWR);
/* 2. IOMMU tipi ayarla (TYPE1 = standart Linux IOMMU) */
ioctl(container, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU);
/* 3. Grubu aç */
int group = open("/dev/vfio/5", O_RDWR); /* Grup 5 */
/* 4. Grubu container'a bağla */
ioctl(group, VFIO_GROUP_SET_CONTAINER, &container);
/* 5. Cihazı al */
int device = ioctl(group, VFIO_GROUP_GET_DEVICE_FD,
"ff000000.ethernet");
/* 6. Cihaz bilgisini oku */
struct vfio_device_info dev_info = { .argsz = sizeof(dev_info) };
ioctl(device, VFIO_DEVICE_GET_INFO, &dev_info);
/* 7. Konuk VM belleğini IOMMU'ya eşle */
struct vfio_iommu_type1_dma_map dma_map = {
.argsz = sizeof(dma_map),
.flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE,
.vaddr = (uintptr_t)guest_mem, /* VM bellek tamponu */
.iova = 0x80000000ULL, /* IOVA adresi */
.size = guest_mem_size,
};
ioctl(container, VFIO_IOMMU_MAP_DMA, &dma_map);
VFIO-Platform (Gömülü Sistemler için)
PCIe olmayan gömülü MMIO cihazları için VFIO-Platform sürücüsü kullanılır. Platform cihazını VFIO'ya bağlamak için önce mevcut sürücüyü ayırıp vfio-platform'a bağlamak gerekir:
# Cihazın mevcut sürücüsünü ayır:
echo ff000000.ethernet > /sys/bus/platform/drivers/vendor-eth/unbind
# VFIO-platform sürücüsüne bağla:
echo ff000000.ethernet > /sys/bus/platform/drivers/vfio-platform/bind
# IOMMU grubunu kontrol et:
ls /sys/bus/platform/devices/ff000000.ethernet/iommu_group/devices/
# Yalnızca tek cihaz varsa güvenli geçiş yapılabilir
# /dev/vfio/ altında grup dosyasının oluştuğunu doğrula:
ls /dev/vfio/
QEMU ile VFIO Cihaz Geçişi
# QEMU komut satırı — ARM64 VM'e ethernet cihazı geçişi:
qemu-system-aarch64 \
-M virt \
-cpu cortex-a57 \
-m 512M \
-kernel Image \
-device vfio-platform,host=ff000000.ethernet \
-nographic
# VM içindeki sürücü cihazı doğrudan donanıma erişir
# SMMU, VM bellek eşlemesini korur
07 Hata ayıklama ve context fault analizi
IOMMU hataları, sürücü geliştirmede karşılaşılan en yaygın ve yanıltıcı sorunlardan biridir. Hata mesajlarını doğru yorumlamak ve debug altyapısını etkin kullanmak gereklidir.
CONFIG_IOMMU_DEBUG
# Derleme zamanı debug seçenekleri:
CONFIG_IOMMU_DEBUG=y
CONFIG_IOMMU_DEFAULT_DMA_STRICT=y # Senkron TLB geçersizleştirme
CONFIG_ARM_SMMU_DEBUG=y # ARM SMMU özel debug
CONFIG_IOVA_STATISTICS=y # IOVA istatistikleri
# Çalışma zamanı debug etkinleştirme (kernel parametresi):
iommu.debug=1
# DebugFS üzerinden IOMMU durumu:
mount -t debugfs none /sys/kernel/debug
ls /sys/kernel/debug/iommu/
Context Fault Handler
SMMU, yetkisiz bir bellek erişimi tespit ettiğinde bir context fault IRQ üretir. Linux bu IRQ'yu yakalar ve kernel log'una ayrıntılı bilgi yazar:
/* Kernel log'da context fault örneği */
/* arm-smmu 09050000.iommu: Unhandled context fault:
* iova=0x40100000, fsr=0x402 (TF|PF), fsynr=0x1, cb=2
* iova: Erişilmeye çalışılan IOVA adresi
* fsr: Fault Status Register
* TF: Translation Fault (eşleme yok)
* PF: Permission Fault (izin yok, eşleme var)
* cb: Context Bank numarası (hangi cihaz/domain)
*/
Özel Fault Handler Kaydı
/* Sürücü içinde özel fault handler */
static int my_iommu_fault(struct iommu_domain *domain,
struct device *dev,
unsigned long iova,
int flags, void *token)
{
dev_err(dev, "IOMMU fault: iova=0x%lx flags=0x%x\n",
iova, flags);
if (flags & IOMMU_FAULT_READ)
dev_err(dev, " Okuma hatasi\n");
if (flags & IOMMU_FAULT_WRITE)
dev_err(dev, " Yazma hatasi\n");
/* -ENOSYS: fault'u işlemedik, default handler devam eder */
/* 0: fault işlendi */
return -ENOSYS;
}
/* Domain oluşturulduktan sonra handler'ı kaydet: */
iommu_set_fault_handler(domain, my_iommu_fault, dev);
/sys/kernel/debug/iommu/ Analizi
# IOMMU durumu:
cat /sys/kernel/debug/iommu/iommu_device_list
# ARM SMMU özel debug (CONFIG_ARM_SMMU_DEBUG gerektirir):
cat /sys/kernel/debug/arm-smmu/09050000.iommu/context_bank
# IOVA tahsis istatistikleri:
cat /sys/kernel/debug/iova/ff000000.ethernet/iova_rcache
cat /sys/kernel/debug/iova/ff000000.ethernet/reserved_iova_list
Yaygın Hata Senaryoları
| Hata | Nedeni | Çözüm |
|---|---|---|
| Translation Fault (TF) | Cihaz, eşlenmemiş IOVA'ya erişiyor | dma_map_* çağrısı unutulmuş; sürücü IOVA'yı cihaza yazmadan önce eşleme yapmalı |
| Permission Fault (PF) | Eşleme var ama izin yok | iommu_map() çağrısında IOMMU_READ/WRITE/EXEC bayraklarını kontrol et |
| External Abort | SMMU kendisi bir AXI hata aldı | Donanım bağlantısı veya clock/power sorunu; DT yapılandırmasını kontrol et |
| IOVA tahsis hatası | IOVA adres alanı tükenmiş | dma_unmap_* çağrılarının yapıldığını doğrula; IOVA alanı boyutunu artır |
08 Gömülü güvenlik tasarımı
SMMU'yu gömülü bir sistemde etkin biçimde kullanmak, donanım tasarımından başlayarak yazılım mimarisine uzanan bütüncül bir yaklaşım gerektirir. Bu bölüm Cortex-A55 tabanlı bir platform üzerinden somut öneriler sunar.
SMMUv3 ATS ve PasID
SMMUv3'ün sunduğu iki gelişmiş özellik, gömülü sistemlerde yeni kullanım senaryoları açar:
Cortex-A55 Entegrasyon Örneği
/* Cortex-A55 (ARMv8.2-A) tabanlı SoC, SMMUv3 ile:
* - 4 x Cortex-A55 @ 1.8 GHz
* - SMMUv3.1 (128 context bank, 64-bit IOVA)
* - LPDDR4 512 MB
* - GbE, USB3, eMMC — hepsi SMMU'ya bağlı
*/
/* DT minimal yapılandırma: */
/*
smmu: iommu@c0000000 {
compatible = "arm,smmu-v3";
reg = <0xc0000000 0x80000>;
interrupts = <...>;
#iommu-cells = <1>;
arm,sid-bits = <16>;
dma-coherent;
};
ethernet: eth@80000000 {
iommus = <&smmu 0x100>;
};
usb: usb3@81000000 {
iommus = <&smmu 0x200>;
};
*/
/* Kernel config (güvenli gömülü imaj için): */
/*
CONFIG_IOMMU_API=y
CONFIG_ARM_SMMU_V3=y
CONFIG_IOMMU_DEFAULT_DMA_STRICT=y
CONFIG_IOMMU_DEFAULT_PASSTHROUGH=n
*/
Güvenli Sistem Mimarisi Önerileri
Kısıtlı Bellek Bölgesi Tanımı
/* Belirli bir fiziksel bölgeye erişimi yalnızca güvenilir cihazla sınırla */
/* 1. Güvenli bölgeyi reserved-memory olarak DT'de tanımla: */
/*
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
secure_region: secure@20000000 {
reg = <0x20000000 0x01000000>; /* 16 MB */
no-map;
};
};
*/
/* 2. Yalnızca crypto engine'i bu bölgeye eşle: */
static int setup_secure_dma(struct device *crypto_dev)
{
struct iommu_domain *domain;
phys_addr_t secure_phys = 0x20000000;
size_t secure_size = SZ_16M;
dma_addr_t secure_iova = 0x20000000; /* 1:1 eşleme */
domain = iommu_get_domain_for_dev(crypto_dev);
if (!domain)
return -ENODEV;
return iommu_map(domain, secure_iova, secure_phys,
secure_size,
IOMMU_READ | IOMMU_WRITE | IOMMU_NOEXEC,
GFP_KERNEL);
}
TrustZone ile SMMU Tümleşimi
ARM TrustZone etkin sistemlerde SMMU, Secure ve Non-Secure dünyaları için ayrı ayrı yapılandırılabilir. Secure monitor (EL3) SMMU'nun güvenlik bölge eşlemesini kontrol eder; Normal Dünya (EL1/EL0) yalnızca kendi bölgesi için yapılandırma yapabilir. Bu yaklaşım, bootloader'dan başlayarak güvenlik mimarisinin temelini oluşturur ve gömülü güvenlik sertifikasyonlarında (IEC 62443, Common Criteria) dikkate alınan bir bileşendir.