ARM Mimari (aarch64) Notları

2021-09-16 | Tags: #tubitak #arm #hypervisor

https://developer.arm.com/documentation/102404/0200

ARM mimarisi en popüler mimarilerden birisi, her yıl 7 milyar ARM mimarili cihaz pazara sürülüyor. Arm mimarisinin 3 temel profili bulunmaktadır. Bunlar:

  • A: Applications ==> v8 de geliyor
  • R: Real-time
  • M: Microcontroller

Mimari & Mikro-Mimari

Mimari ve mikro-mimari terimleri birbirlerinden farklıdır. Mimari terimi kullanıldığı zaman işlemcinin fonksiyonel işlevselliğinden bahsedilir. Mimari bir işlemcinin hangi instruction'larda ne yapacağını ve hangi instruction'ları alacağını söyler. Dokümanda mimarinin donanım ve yazılım arasında bir köprü olduğundan bahsedilmektedir.

Mimarinin temel taşları:

  1. Instruction Set: Her bir instruction ne yapacak
  2. Register Set: Register'ların işlevleri
  3. Exception Model: x86 privilege modele benzer
  4. Memory Model
  5. Debug

Mimaride görüldüğü üzere işlemcinin nasıl yapıldığı anlatılmaz. Mikro-mimaride ise işlemcilerin nasıl tasarlandığı (pipeline,cache, vb) gibi özellikler anlatılır.

ARM mimarisi beraberinde başka küçük mimarileri getirmektedir. Bunlar:

  • GIC: Generic Interrupt Controller
  • SMMU: System Memory Management Unit
  • Generic Timer
  • AMBA: Bus architecture

Mimarinin dokümanlarında bazı terimlerin önemli olduğundan bahsedilmektedir, bunlar:

  • PE ==> Processing Element (Kendisine ait program counter'ı olan her şey)
  • IMP DEF ==> Implementation Defined, Burada işlemcinin bazı özelliklerinin statik bir şekilde ayarlanması gerektiğinden bashediliyor.
  • RES0/RES1 Reserved ==> Herhangi bir etkisi olmayan

ISA => Instruction Set Architecture, bir yazlımın işlemciyi nasıl kontrol edeceğini tanımlar.

aarch64 registers

aarch64 registerlar açıklama
X0,X1..X30 General Purpose 64bit
W0,W1..W30 General Purpose 32bit
XZR, WZR Zero Register
SP Stack Pointer
X30 Link Register
PC Program Counter

Exception level:

Exception Level Stack Pointer Exception Link Register Saved Process Status Register
EL0 SP_EL0 - -
EL1 SP_EL1 ELR_EL1 SPSR_EL_1
EL2 SP_EL2 ELR_EL2 SPSR_EL_2
EL3 SP_EL3 ELR_EL3 SPSR_EL_3

ARM mimarisinim 31 tane general purpose register'ı bulunuyor. Register isimlendirmesi: X0, X1, ... X30

  • X register'ları 64 bit işlemler için tercih ediliyor. W register'ları 32 bit işlemler için
  • 32 adet vector ve floating point için bulunan register'lar var. Bunlar da:
  • BX = 8 bit
  • HX = 16bit
  • QX = 128bit
  • Zero registers : ZXR, WZR
  • Stack pointer : SP
  • Burada x86 mimarisinden farklı olarak her bir exception level için bir SP tutuluyor. SP'nin anlamı ise şu an ki bulunan exception level'deki sp.
  • Link register : X30
  • Program Counter : PC

aritmetik instructionlar

Arm Assembly C
ADD x, y, z x = y + z
SUB x, y, z x = y - z
SDIV x, y, z x = y / z
AND x, y, z x = y & z
ORR x, y, z x = y | z
ERR x, y, z x = y ^ z
ASR x, y, z x = y >> z

system registers

System register'ları işlemciyi ayarlamak, MMU ayarlaması, exception handling gibi işlemleri yapmak için kullanırız. System register'larına direk olarak erişmek mümkün değildir bunun için özel instructionlar bulunamkatadır.

instruction kullanım açıklama
MRS MRS Xd, system register'ı Xd içerisine koy
MSR MSR , Xn Xn'yi system register'a yaz

Önemli: System register'larının isimleri _ELx ile biter. Burada x minimum yetki seviyesini belirtir. Daha düşük seviyeden bu registerlara erişmek bir exception oluşturur.

load & store

arm mimarisinde registerlar üzerinde direk işlem yapılmadığını önceden bahsetmiştik. bundan ötürü load & store instructionları önemli.

instruction kullanımı açıklama
LDR ldr dest, [src] bellekten register'a yükler
STR str src, [dest] register'dan belleke yükler
ADR adr x0, variable bir label'ın adresini register'a koyuyor.

örnek:

  .section data
var: .word 1
  .section text
  .global main
main:
adr x0, data
ldr w1, [x0]

addressing

load & store instructionları için birden çok adresleme metodu mevcuttur.

  • base register LDR WO, [X1]
  • offset addressing LDR WO, [X1, #10]
  • pre-index addressing LDR WO, [X1, #10]!
  • post-index addressing LDR WO, [X1], #12


branch

instructionlar bellekte nasıl yer alırsalar aynı sırada çalışmaları gerekir. bunu değiştirebilecek tek şey branch instructionlarıdır.

instruction kullanım
B (unconditional) B <label> diyerek istediğimiz adrese zıplayabiliyoruz.
BR BR <XN> diyerek XN içerisinde bulunan adrese zıplayabiliyoruz
BLE branch less than or equal
BGE branch greater than

Örnek C Kodu:

if (a == 5)
  b = 5;

Compiler tarafından oluşturulmuş kod:

CMP W0, #5
BNE skip
MOV W8, #5
skip:

!! Önemli : CMP insturction'ı çağrıldığı zaman bunun sonucu PSTATE register'ında saklanıyor ve branch işlemleri de bu register'a bakılarak yapılıyor.

instruction kullanım açıklama
CBZ CBZ Xn, label Eğer Xn sıfırsa label'a git
CBNZ CBNZ Xn, label Eğer Xn sıfır değilse label'a git

alu flags

flag mean
N negative
C carry
V overflow
Z zero

function calls

fonksiyonlar çağırıldığı zaman tekrar geri dönebilmek için link işlemini yapmamız gerekir. arm isa'sında da B veya BR instructionlarına L ekleyerek bunu yapmak mümkündür.

BL foo

foo:
  RET
  • LR register'ına dönüş adresi yazılır.
  • Ret instruction'ı geldiği zaman bu adrese geri dönülütr

bir fonksiyon çağrısını doğru bir şekilde gerçekleştirebilmek için bazı sorulara cevap vermemiz gerekir. 1. Fonksiyon çağrısının oluşturulması (call) 2. Fonkisiyondan geri dönülmesi (ret) 3. Argüman gönderme 4. Lokal değişkenleri saklama 5. Fonksiyonun değer döndürmesi

örnek bir c fonksiyonu:

long foo(long a, long a)
{
    long k;
    k = foo2();
    return (k + a);
}

1 ve 2. sıkıntıların çözümü için auto register 'lar kullanılabilir.

instruction kullanım
BL branch and link ==> dönüş adresini X30'da sakla
RET X30'daki adrese git

ancak bu instructionlarda bize çözüm olarak yeterli değil. eğer iç içe fonksiyonlar tanımlanırsa:

foo:
    bl foo2

foo2:
    bl foo3
    ret

foo3:
    ret

burada foo2'nin nereye gideceğini kaybettik . bunu kaybetmememk için stack 'i doğru bir şekilde kullanmamız gerekiyor.

stack işlemleri

  • SP(stack pointer) stack'in en üst noktasını belirtir.
  • SP aarch64'de 16'nın katı olmalıdır
sub sp, sp, 16
+------------+ 0
|            |
|            |
|            |
|            |
|            |
+------------+ New SP
|            |
+------------+ Old SP
|            |
+------------+
|            |
+------------+
instruction kullanımı açıklama
LDR ldr dest, [src] bellekten register'a yükler
STR str src, [dest] register'dan belleke yükler

Dönülecek adresi ayarlayabilmeiz için şu işlemleri yapmamız gerekiyor.

str x30, [sp]
..
ldr x30, [sp]

Özellikle call işlemleri yaparken register kullanımına önem vermiliyiz. ARM mimarisinde bu kullanım kuralları Procedure Call Standard (PCS) olarak adlandırılmaktadır.

registers isim açıklama
X0..X7 parametre ve sonuç parametre ve sonuçlar bu registerlarda tutulur, alınır
X8..X18 caller saved geçiçi değişkenler bunları kullanıcı stack'te saklamalıdır
X19.. X29 calle saved kalıcı değişkenler call'lar arası kullanılabilir

okunabilir assembly yazımı

# Sabit tanımlama
.equ SIZE, 48

# Register isimlendirme
counter .req x20

foo:
    sub sp, sp, SIZE
    add counter, #1
    add sp, sp, SIZE

Quick notes about MMU: * MMU (Memory Management Unit) * Translates virtual address to physical address * Multiple programs or even vm's can run their own virtual address space. * TLB (Translation Lookahead Buffer): some type of cache to decrease overhead of memory access with referancing actual memory locations. * Cache : L1 cache * Address translation done by hardware

V8 ===> Cache ===> MMU ===> Memory

Qemu Specific

  • . - 0x40000000 memory mapped peripherals

~ ARM V8

  • Page sizes: 4KB, 16KB, 64KB
  • ( TTBR0_EL1 , TTBR1_EL1 ) Translation Table Base Registers
  • ( TCR_EL1 ) Translation Control Register
  • MAIR : Memory Attribute Indirection Register : Specify memory type
  • EL2 and EL3 have a TTBR0, but no TTBR1.

Memory Attributes

Flag Description
AF Access Flag
SH Shareable attribute
AP Access Permission
NS Security Bit

TCR Register

Memory Types

  • Gathering: gather and merge into single transaction
  • Reordering: reorder transaction
  • Early-acknowledge: early acknownledge of transaction
.equ TT_S1_NORMAL_NO_CACHE, 0x00000000000000401    // Index = 0, AF=1
.equ TT_S1_NORMAL_WBWA,     0x00000000000000405    // Index = 1, AF=1
.equ TT_S1_DEVICE_nGnRnE,   0x00600000000000409    // Index = 2, AF=1, PXN=1, UXN=1

Address Translation

  • When MMU is enabled hardware automatically translates virtual addresses to physical addresses.
  • For example one level look-up table will look like this

A virtual address structure :

63-42 41-29 28-0
TTBR selector index in page table low bits of virtual address

  • (41-29) will give us how many entries will be page table 2^13 = 8192
  • So the first value initialized into TTBR0_EL1 or TTBR1_EL1 register is very important to create correct translation.

How to Create EL1 Page Table

Full source code can be found here: https://developer.arm.com/documentation/102416/latest
  • 1. Clear all registers
mov      x0, #0
mov      x1, #0
mov      x2, #0
mov      x3, #0
mov      x4, #0
mov      x5, #0
mov      x6, #0
mov      x7, #0
mov      x8, #0
mov      x9, #0
mov      x10, #0
mov      x11, #0
mov      x12, #0
mov      x13, #0
mov      x14, #0
mov      x15, #0
mov      x16, #0
mov      x17, #0
mov      x18, #0
mov      x19, #0
mov      x20, #0
mov      x21, #0
mov      x22, #0
mov      x23, #0
mov      x24, #0
mov      x25, #0
mov      x26, #0
mov      x27, #0
mov      x28, #0
mov      x29, #0
mov      x30, #0
  • 2. Set VMID : We need to disable 2 stage address translation
MSR     VTTBR_EL2, xzr
  • 3. Set base register
LDR      x0, =tt_l1_base
MSR      TTBR0_EL1, x0

Instructions

instruction kullanımı açıklama
MOV mov x1, x2 ; mov x1, #5
MRS MRS Xd, system register'ı Xd içerisine koy
MSR MSR , Xn Xn'yi system register'a yaz

Memory Instructions

instruction kullanımı açıklama
LDR ldr dest, [src] loads a 32-bit constant value or an address
STR str src, [dest] stores to memory address
ADR adr x0, variable bir label'ın adresini register'a koyuyor.

Examples:

var1 = 13; address of var1 = 0x10

ldr x0, addr            @ ==> loads address (0x10)
ldr x0, =var1           @ ==> loads address of variable (0x10)
ldr x0, [addr]          @ ==> load value inside address (13)
ldr x0, [addr, #12]     @ ==> load value inside (address + 12) must be 4 byte aligned

LDR ARM pseudo-instruction

[R1,#0x14]          ===> (base+0x14)
LDR  r2,=place      ===> loads address of place
LDR  r1,=0xfff      ===> loads 0xfff into r1

Exception levels

Exception Level Stack Pointer Exception Link Register Saved Process Status Register
EL0 SP_EL0 - -
EL1 SP_EL1 ELR_EL1 SPSR_EL_1
EL2 SP_EL2 ELR_EL2 SPSR_EL_2
EL3 SP_EL3 ELR_EL3 SPSR_EL_3
  • elr : Exception Link Register holds the exception return address
  • spsr : The processor state is stored in spsr

Core registers

Register Desc.
SCTLR system control register (level control of the system, including memory)
TTBR0_EL1, TTBR1_EL1 Translation Table Base Registers
TCR_EL1 Translation Control Register
SCR_ELx Secure configuration register, Secure or Non-secure, what mode the processor branches to if an IRQ, FIQ or external abort occurs

Snippets

Inline assembly:

uint64_t read_register_64(){
    uint64_t foo;
    asm volatile ("mov %0, x14" : "=r"(foo) ::);
    return foo;
}

kaynaklar


This was the end of the blog post. You can reach me via email umusasadik at gmail com