Sandy
Sandy

Reputation: 155

updating SCTLR_EL1 register not working in bare-matel ARMv8 program on QEMU

I am learning armv8 assembly program for my project. I wrote a simple program which tries to modify value of SCTLR_EL1 register. Unfortunately this code is not working. I am enabling I-cache, but the only thing I see is 0x0 in SCTLR_EL1.

.section .text
.global _start

_start:
    mov x0, xzr                 // Initialize x0 to zero
    // Set SCTLR_EL1 and confirm the modification
    mrs x0, SCTLR_EL1            // Read SCTLR_EL1 into x0
    orr x0, x0, #(1 << 12)       // Enable I-Cache
    msr SCTLR_EL1, x0            // Write back to SCTLR_EL1

    mrs x0, SCTLR_EL1            // Read the modified SCTLR_EL1 into x0
    // Store the value in a known memory location for debugging
    ldr x1, =sctlr_el1_val
    str x0, [x1]

    b loop

loop:
    b loop

.data
.align 8
sctlr_el1_val: .quad 0x0100        // Memory location to store the SCTLR_EL1 value

memmap

MEMORY
{
    rom  : ORIGIN = 0x00010000, LENGTH = 32K
}

SECTIONS
{
   .text : { *(.text*) } > rom
}

QEMU command used is as follows:

qemu-system-aarch64 -M virt -cpu cortex-a57 -m 512M -nographic -machine secure=on \
-S -s -kernel path_to_your_binary.elf -d in_asm,cpu

Output I see in console is:

PSTATE=000003cd ---- EL3h
 PC=0000000000000200 X00=0000000000000000 X01=0000000000000000
X02=0000000000000000 X03=0000000000000000 X04=0000000000000000
X05=0000000000000000 X06=0000000000000000 X07=0000000000000000
X08=0000000000000000 X09=0000000000000000 X10=0000000000000000
X11=0000000000000000 X12=0000000000000000 X13=0000000000000000
X14=0000000000000000 X15=0000000000000000 X16=0000000000000000
X17=0000000000000000 X18=0000000000000000 X19=0000000000000000
X20=0000000000000000 X21=0000000000000000 X22=0000000000000000
X23=0000000000000000 X24=0000000000000000 X25=0000000000000000
X26=0000000000000000 X27=0000000000000000 X28=0000000000000000
X29=0000000000000000 X30=0000000000000000  SP=0000000000000000
PSTATE=000003cd ---- EL3h

GDB did not show anything:

(gdb) x/x 0x0100
0x100:  0x00000000
(gdb) x/x $SCTLR_EL1
Value can't be converted to integer.
(gdb) p/x $SCTLR_EL1
$1 = void
(gdb) display  $SCTLR_EL1
1: $SCTLR_EL1 = void
(gdb)  p/x $CurrentEL
$2 = void

How can i modify CurrentEL and SCTLR_EL1? and how can I see those register value using GDB? Can someone please help? Thank you.

Upvotes: 1

Views: 116

Answers (1)

Johannes Krottmayer
Johannes Krottmayer

Reputation: 66

The QEMU output what you see is caused from an exception. As @Jester mentioned this is because you are enabling -machine secure=on. This option enables the ARM TrustZone extension. Use a higher program entry point address. An entry point at 0x40000000 should work.

You also have forgotten the isb instruction after writing to SCTLR_EL1. When you read directly SCTLR_EL1 after the write-back without isb instruction, the content from SCTLR_EL1 is the old one (content before msr SCTLR_EL1, x0).

.section .text
.func _start,_start
.type _start,%function
.global _start

_start:
    mov x0, xzr                 /* Initialize x0 to zero */
    mrs x0, SCTLR_EL1           /* Read SCTLR_EL1 into x0 */
    orr x0, x0, #(1 << 12)      /* Enable I-Cache */
    msr SCTLR_EL1, x0           /* Write back to SCTLR_EL1 */
    isb                         /* Instruction Synchronization barrier */

loop:
    b loop

.size _start, . - _start
.endfunc

To display the registers values with GDB you can use the command info registers or info all-registers. These should also include the SCTLR register.

CurrentEL can be extracted from the current program status register (cpsr) in the output from GDB.

For changing/switching to a lower exception levels there you can find enough samples here on SO on other sites.

Upvotes: 2

Related Questions