ARM Linux Kernel Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

192239
1625
172589


ARM64(Aarch64) - Special Register 설정(Trace32) 이제는 ARM의 시대

AArch64 64비트 아키텍쳐에서 설정해야 할 Special Register에 대해서 잠깐 살펴볼께요.
우선 커널이 구동될 때의 Exception Level이 1이니까 EL1 모드만 점검하죠.


TTBR1_EL1
약자는 Translation Table Base Register인데, 가상주소와 물리주소를 변환할 때 쓰이죠.

Trace32로 이 레지스터를 설정하고 싶으면 아래 커맨드를 써야 하지오.
Data.Set SPR:0x30201 %Quad 0x82ba1000  // TTBR1_EL1

TCR_EL1
Translation Control Register의 약자인데 Stage 1 가상 주소 Translation 시 필요한 Translation 베이스 레지스터 정보를
포함하고 있어요.
Trace32로 이 레지스터를 설정하고 싶으면 아래 커맨드를 쓰면 되죠.
Data.Set SPR:0x30202 %Quad 0x00000032B5193519 // TCR_EL1

MAIR_EL1
Memory Attribute Indirection Register이거든요. Trace32로 아래 명령어로 설정 가능해요.
Data.Set SPR:0x30A20 %Quad 0x000000FF440C0400 // MAIR_EL1

SCTLR_EL1
가장 중요한 레지스터인데요.

ARM53 문서께서 System Control Register라고 하시네요.
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0488d/CIHDIEBD.html

Trace32 설정 커맨드는 아래와 같아요.
Data.Set SPR:0x30100 %Quad 0x0000000004C5D93D // SCTLR_EL1

그럼 커널 패닉이 일어났을 때 이 레지스터 정보를 찍고 싶으면 어떻게 해야 할까요?
아래 패치를 적용하면 커널 로그로 확인이 가능하죠. panic reboot notifier call을 하나 설정하고 콜백함수에 해당 루틴을 추가하면 되죠.
diff --git a/drivers/soc/pompeii/crash_handle_panic.c b/drivers/soc/pompeii/crash_handle_panic.c
index 27b9b60..431fd85 100644
--- a/drivers/soc/pompeii/crash_handle_panic.c
+++ b/drivers/soc/pompeii/crash_handle_panic.c
@@ -70,6 +70,41 @@ static int gen_key_panic = 0;
 static int key_crash_cnt = 0;
 static unsigned long key_crash_last_time = 0;
 
+static DEFINE_SPINLOCK(panic_lock);
+
+static u64 ttbr1_el1_reg = 0;
+static u64 tcr_el1_reg = 0;
+static u64 mair_el1_reg = 0;
+static u64 amair_el1_reg = 0;
+static u64 sctlr_el1_reg = 0;
+
+void get_mmu_sys_ctrl_register(void)
+{
+       ttbr1_el1_reg = read_sysreg(ttbr1_el1);
+       tcr_el1_reg = read_sysreg(tcr_el1);
+       mair_el1_reg = read_sysreg(mair_el1);
+       amair_el1_reg = read_sysreg(amair_el1);
+       sctlr_el1_reg = read_sysreg(sctlr_el1);
+
+       printk("ttbr1: %llx  tcr: %llx sctlr: %llx mair: %llx amair: %llx \n",
+                                       ttbr1_el1_reg, sctlr_el1_reg, sctlr_el1_reg, mair_el1_reg, amair_el1_reg);
+}
+
+static int crash_handler_panic(struct notifier_block *this,
+                 unsigned long event,
+                 void *ptr)
+{
+    unsigned long flags;
+    spin_lock_irqsave(&panic_lock, flags);
+
+    printk(KERN_CRIT "%s called\n", __func__);
+    get_mmu_sys_ctrl_register();
+
+    spin_unlock_irqrestore(&panic_lock, flags);
+    return NOTIFY_DONE;
+}
+
+
+static struct notifier_block panic_blk = {
+    .notifier_call  = crash_handler_panic,
+    .priority    = 1004,
+};
+
 static int __init crash_panic_handler_early_init(void)
 {
        struct device_node *np;
@@ -477,6 +517,8 @@ static int __init lge_panic_handler_early_init(void)
                return -ENODEV;
        }
 
+       atomic_notifier_chain_register(&panic_notifier_list, &panic_blk);
+
        of_property_read_u32(np, "mem-addr", (u32*)&panic_handler->fb_addr);
        of_property_read_u32(np, "mem-size", (u32*)&panic_handler->fb_size);

번외로 한 가지 주의할 점은 u64로 설정한 변수는 %llx, %lld 로 printk 아규먼트를 줘야 해요.
 

핑백

덧글

댓글 입력 영역