In my opinion, Arm TF-A (EL3) has higher privileges than Linux Kernel (EL1), and Secure World should be able to access all memory address in Normal World. To verify this feature, I added a new SMC call in Arm TF-A and wrote a kernel module to test it (on a Hikey960 Development Board). But the program does not run as expected that Arm TF-A stucked while accessing the memory address passed by Linux Kernel.
Here is my kernel module, which uses `alloc_pages` to acquire a physical address, and uses `page_address` converting it to a virtual address. And the module passes the physical address and the virtual address to Arm TF-A using `smc #0`:
```cpp static int __init smc_testing_init(void) { uintptr_t phys_addr, virt_addr;
pr_info("Mmodule loaded\n");
phys_addr = (uintptr_t) alloc_pages(GFP_KERNEL, 2); virt_addr = (uintptr_t) page_address((struct page *) phys_addr); memset((void *) virt_addr, 'A', PAGE_SIZE << 2); printk("phys_addr: 0x%llx, virt_addr: 0x%llx\n", (uint64_t) phys_addr, (uint64_t) virt_addr);
asm volatile( "ldr x0, =0xC8000003\n" "mov x1, %0\n" "mov x2, %1\n" "smc #0\n" : : "r" (phys_addr), "r" (virt_addr) : "x0", "x1", "x2" );
__free_pages((struct page *) phys_addr, 2);
return 0; }
static void __exit smc_testing_exit(void) {
pr_info("Module unloaded\n"); } ```
And here is the handler's code in Arm TF-A, which prints the addresses of physical address and virtual address, and access the first element of the memory address:
```cpp if (0xC8000003 == smc_fid) { uintptr_t virt_addr = x3;
NOTICE("phys_addr: 0x%lx, virt_addr: 0x%lx\n", phys_addr, virt_addr); NOTICE("virt_addr[0] = 0x%x\n", *((uint32_t *)virt_addr)); NOTICE("phys_addr[0] = 0x%x\n", *((uint32_t *)phys_addr));
SMC_RET0(handle); } ```
Here is the output, Arm TF-A handles the request successfully, but failed to access the memory address passed by Linux Kernel:
```bash # insmod ./smc_testing.ko [ 75.259590] smc_testing: loading out-of-tree module taints kernel. [ 75.266682] Mmodule loaded [ 75.269404] phys_addr: 0xfffffc0002dc5e00, virt_addr: 0xffff0000b7178000 NOTICE: phys_addr: 0xfffffc0002dc5e00, virt_addr: 0xffff0000b7178000 [ 96.276605] rcu: INFO: rcu_preempt detected stalls on CPUs/tasks: [ 96.282741] rcu: 4-...0: (1 ticks this GP) idle=72ec/1/0x4000000000000000 softirq=204/204 fqs=2592 [ 96.291835] (detected by 0, t=5253 jiffies, g=-643, q=16 ncpus=8) [ 96.298044] Task dump for CPU 4: [ 96.301287] task:insmod state:R running task stack:0 pid:201 ppid:185 flags:0x00000006 [ 96.311254] Call trace: [ 96.313713] __switch_to+0xe4/0x160 [ 96.317241] printk_rb_static+0x30/0x58 ```
Subject: [TF-A] Arm TF-A can not access linux kernel's virtual/physical address?
In my opinion, Arm TF-A (EL3) has higher privileges than Linux Kernel (EL1), and Secure World should be able to access all memory address in Normal World.
Make sure you have mapped the address in EL3 MMU table.
Regards, Peng.
To verify this feature, I added a new SMC call in Arm TF-
A and wrote a kernel module to test it (on a Hikey960 Development Board). But the program does not run as expected that Arm TF-A stucked while accessing the memory address passed by Linux Kernel.
Here is my kernel module, which uses `alloc_pages` to acquire a physical address, and uses `page_address` converting it to a virtual address. And the module passes the physical address and the virtual address to Arm TF-A using `smc #0`:
static int __init smc_testing_init(void) { uintptr_t phys_addr, virt_addr; pr_info("Mmodule loaded\n"); phys_addr = (uintptr_t) alloc_pages(GFP_KERNEL, 2); virt_addr = (uintptr_t) page_address((struct page *) phys_addr); memset((void *) virt_addr, 'A', PAGE_SIZE << 2); printk("phys_addr: 0x%llx, virt_addr: 0x%llx\n", (uint64_t) phys_addr, (uint64_t) virt_addr); asm volatile( "ldr x0, =0xC8000003\n" "mov x1, %0\n" "mov x2, %1\n" "smc #0\n" : : "r" (phys_addr), "r" (virt_addr) : "x0", "x1", "x2" ); __free_pages((struct page *) phys_addr, 2); return 0; } static void __exit smc_testing_exit(void) { pr_info("Module unloaded\n"); }
And here is the handler's code in Arm TF-A, which prints the addresses of physical address and virtual address, and access the first element of the memory address:
if (0xC8000003 == smc_fid) { uintptr_t virt_addr = x3; NOTICE("phys_addr: 0x%lx, virt_addr: 0x%lx\n", phys_addr, virt_addr); NOTICE("virt_addr[0] = 0x%x\n", *((uint32_t *)virt_addr)); NOTICE("phys_addr[0] = 0x%x\n", *((uint32_t *)phys_addr)); SMC_RET0(handle); }
Here is the output, Arm TF-A handles the request successfully, but failed to access the memory address passed by Linux Kernel:
# insmod ./smc_testing.ko [ 75.259590] smc_testing: loading out-of-tree module taints kernel. [ 75.266682] Mmodule loaded [ 75.269404] phys_addr: 0xfffffc0002dc5e00, virt_addr: 0xffff0000b7178000 NOTICE: phys_addr: 0xfffffc0002dc5e00, virt_addr: 0xffff0000b7178000 [ 96.276605] rcu: INFO: rcu_preempt detected stalls on CPUs/tasks: [ 96.282741] rcu: 4-...0: (1 ticks this GP) idle=72ec/1/0x4000000000000000 softirq=204/204 fqs=2592 [ 96.291835] (detected by 0, t=5253 jiffies, g=-643, q=16 ncpus=8) [ 96.298044] Task dump for CPU 4: [ 96.301287] task:insmod state:R running task stack:0 pid:201 ppid:185 flags:0x00000006 [ 96.311254] Call trace: [ 96.313713] __switch_to+0xe4/0x160 [ 96.317241] printk_rb_static+0x30/0x58 ``` -- TF-A mailing list -- tf-a@lists.trustedfirmware.org To unsubscribe send an email to tf-a-leave@lists.trustedfirmware.org
tf-a@lists.trustedfirmware.org