Arm EL0 Address Translation - linux

I want to translate a virtual user level address (EL0) to a physical address.
Arm provides an instruction AT to translate a virtual address to a physical address. This instruction should be called by privileged level (EL1), so I write a linux kernel module to execute this instruction. I pass a user level address (EL0) virt_addr through ioctl() to kernel module, and execute instruction AT.
According to the instruction manual, I execute the instruction by this way:
// S1E0R: S1 means stage 1, E0 means EL0 and R means read.
asm volatile("AT S1E0R, %[_addr_]" :: [_addr_]"r"(virt_addr));
// Register PAR_EL1 stores the translation result.
asm volatile("MRS %0, PAR_EL1": "=r"(phys_addr));
However, the value of register PAR_EL1, i.e. stored in phys_addr, is 0x80b (or 0b100000001011), which is not a correct result.
Then I found a manual about register PAR_EL1.
According to the manual, bit[0] is 1 means a fault occurs on the execution of an Address translation instruction.
bits[6:1] is Fault Status Code (FST). My FST is 0b000101. The manual tell me that the error information is: Translation fault, level 1.
I don't know the fault reason.
My cpu is Cortex-A53, and operating system is Linux-4.14.59.

Related

What does swi SYS_ERROR0 do in arm linux kernel?

Below is the code for reset vector as defined arm linux (arch/arm/kernel/entry-armv.S)
vector_rst:
ARM( swi SYS_ERROR0 )
THUMB( svc #0 )
THUMB( nop )
b vector_und
What does the instruction swi SYS_ERROR0 do ? When I checked, I found SYS_ERROR0 in arch/arm/kernel/asm-offsets.c
DEFINE(SYS_ERROR0, 0x9f0000);
I was unable to find anything related to it on internet. Can someone explain what does this instruction do ? What is SYS_ERROR0 ?
I was unable to find anything related to it on internet. Can someone explain what does this instruction do ? What is SYS_ERROR0 ?
DEFINE(SYS_ERROR0, 0x9f0000);
The swi instruction is typically a call from user mode to system mode. Ie, User space to the Linux kernel. Lower numbers are standard Linux system call such as open(), sbrk(), etc.
If you look at uapi/asm/unistd.h in arch/arm you can see some defines like __ARM_NR_BASE which is __NR_SYSCALL_BASE+0x0f0000. This can be 0x9f0000 for OABI systems. Basically, these are secret system calls that are ARM specific kernel calls. For instance, __ARM_NR_get_tls is only used for libc thread management on the ARM. Other CPUs may have different non-syscall mechanisms to do the same thing and/or the syscall interface may be different than on the ARM CPU.
So SYS_ERROR0 is a special ARM system call. By the way, asm-offset.c is never used directly. It is compiled and the object is scanned by a script to get assembler offsets to structures, etc. So if a compiler packs structures differently, then in theory, the assembler will be in-sync with the compiler version. We start here,
.L__vectors_start:
W(b) vector_rst
W(b) vector_und
W(ldr) pc, .L__vectors_start + 0x1000
W(b) vector_pabt
W(b) vector_dabt
W(b) vector_addrexcptn
W(b) vector_irq
W(b) vector_fiq
The swi is a vector handled by W(ldr) pc, .L__vectors_start + 0x1000, so the code is 4k after the vector table. This is vector_swi and you can see the code in entry-common.S. There are two methods of making a syscall. The older one (OABI) encodes the call in the SWI instruction. This is bad as the ICACHE must be examined as data (DCACHE). The newer systems pass the syscall in r7. There are two jump tables; sys_call_table and sys_oabi_call_table to handle OABI and the newer mechanism. In both case, higher __NR_SYSCALL_BASE are special cased and use arm_syscall in traps.c. So SYS_ERROR0 is the case 0: /* branch through 0 */ code in traps.c. The message branch through zero is printed (because user space jump to the reset vector which can be at address 0) and the user space gets a signal.

how to read kernel image in arm linux?

I am trying to read kernel image and calculate a checksum value of this image. Firstly, I used a smc instruction to trigger a exception, and in the exception handler, I tried to read the first bytes of the image. I don't really know what the address is, but from some documents, I know the kernel image is decompressed in address like 0x20008000, 0x30008000 or 0xC0008000(they call this ZRELADDR, i don't really know whether this is the right address...). So I tried to read the memory like this:
uint32_t test;
test = * (uint32_t *)0x30008000;
DMSG("test : %x\n",test);
But the system crashed with a data abort exception,
core data-abort at address 0x30008000
fsr 0x00000005 ttbr0 0x7df7006a ttbr1 0x7df7006a cidr 0x0
cpu #0 cpsr 0x200001b3
r0 0x00000090 r4 0x7df4bf51 r8 0x00000000 r12 0x00000000
r1 0x09010000 r5 0x806665e0 r9 0x00000000 sp 0x7df77f50
r2 0x0000000d r6 0x7f002000 r10 0x00000000 lr 0x7df273ff
r3 0x30008000 r7 0x7df77f60 r11 0x00000000 pc 0x7df052f0
ERR TEE-CORE:tee_pager_handle_fault:602: Unexpected page fault! Trap CPU
PANIC: tee_pager_handle_fault core/arch/arm/mm/tee_pager.c:603
I guess I am on the wrong way. Does anyone know how to read the kernel image in runtime environment?
Thanks for your help!
EDIT:Thanks for your reply. I am talking about secure kernel. I am trying to check the integrity of the kernel under TrustZone, and to insure the kernel haven't be compromised. So I guess a checksum like hash value may help me. Also, I am a novice who is trying to be familiar with the memory system of arm, so I tried to start with simple read some certain memory address. I have tried to read 0xc0000000 as Artless Noise said, but the same error occurs again. Again I tried to find "_test" and "stext" address in System.map, which is 0x80008000, and error occurs again.
The beginning of the RAM is usually mapped at 0xC0000000. This depends on CONFIG_PAGE_OFFSET:
- VMSPLIT_3G: 0xC0000000
- VMSPLIT_2G: 0x80000000
- VMSPLIT_1G: 0x40000000
Note that this is a virtual address if you have an MMU (usual case), the physical address will depend on your actual architecture (it may or may not be 0x00000000). The kernel is loaded a few pages after that, at an offset of 0x8000.
So, you can probably find the (uncompressed) kernel at 0xC0008000 but it may as well be located somewhere else.
You can also try to ioremap() offset 0x8000 of your RAM.
Can you give us a bit more information on the particular SoC you are working on?
If you are in secure mode and you believe that in secure mode it access physical address then from below these macro you can deduce the physical address.
The physical address at which kernel loads is PHYS_OFFSET + TEXT_OFFSET (text offset is 0x8000),
PHYS_OFFSET definition will be depend on the CONFIG_ARM_PATCH_PHYS_VIRT patch.
if CONFIG_ARM_PATCH_PHYS_VIRT is defined, then PHYS_OFFSET will be equal to __pv_phys_offset otherwise PHYS_OFFSET will be defined as CONFIG_PHYS_OFFSET in your kernel config file.

How Control Registers are accessed in Linux

i have been reading Linux source code ported on to a propriety platform based on ARM Cortex -A7 MPCore - NEON Architecture
The code below shows how a control register of a module is modified up on calling an API
drivers\module\module-specific_file.c
static inline void API(....)
{
if (set)
__raw_writel(msk, (void *)((u32) (reg) + 0x1000));
else
{
__raw_writel(msk, (void *)((u32) (reg) + 0x2000));
}
}
in the above code reg is actually a virtual address and msk is a mask lets say x7FF and set is a parameter passed which conveys request of set/clear
but actually my doubt is how does modifying the control register address is modifying the value to be written to register ... ?? further if i look at the api which is been called it looks like below
arch\arm\include\asm\Io.h
static inline void __raw_writel(u32 val, volatile void __iomem *addr)
{
asm volatile("str %1, %0"
: "+Qo" (*(volatile u32 __force *)addr)
: "r" (val));
}
if any one have come across this kind of accessing control registers please let me know how actually content of registers are modified by modifying the virtual address.
As I know, registers are mapped in virtual address space. Have a look at /proc/iomem for example, you'll see mapped registers addresses and what hardware they are belong. The addresses of registers are strictly determined by hardware developers.
Typically, to map register address one should call ioremap function. It returns the address. Often this address is the base address, where the register addresses begin. To write something in register you just need to write the data in this address plus the resister offset.
E.g.: On ARM PXA320, there is a set of LCD registers. Somewhere ion driver code one may see - ioremap(BASE_ADDR, SIZE_OF_ADDR_SET);
In order to write __raw_write(value, base_addr + offset) function is used.

mpc85xx(P2040) startup using Nor Flash, where is Nor Flash mapped to?

I'm porting u-boot to P2040 based board these days.
As u-boot/arch/powerpc/mpc85xx/start.s commented:
The processor starts at 0xffff_fffc and the code is first executed in the last 4K page in flash/rom.
In u-boot/arch/powerpc/mpc85xx/resetvec.S:
.section .resetvec,"ax"
b _start_e500
And in u-boot.lds linker script:
.resetvec RESET_VECTOR_ADDRESS :
{
KEEP(*(.resetvec))
} :text = 0xffff
The reset vector is at 0xffff_fffc, which contains a jump instruction to _start_e500.
The E500MCRM Chapter 6.6 mentioned:
This default TLB entry translates the first instruction fetch out of reset(at effective address 0xffff_fffc).
This instruction should be a branch to the beginning of this page.
So, if I configure the HCW to let powerpc boot from Nor Flash, why should I suppose that the Nor Flash's
last 4K is mapped to 0xffff_f000~0xffff_ffff? Since there're no LAW setup yet and the default BR0/OR0 of Local Bus
does not match that range. I’m confused about how Nor Flash be access at the very beginning of core startup.
Another question is:
Does P2040 always have MMU enabled so as to translate effective address to real address even at u-boot stage?
If so, beside accessing to CCSRBAR, all other memory access should have TLB entry setup first.
Best Regards,
Hook Guo

Kernel Oops page fault error codes for ARM

What does error code after Oops give information about the panic in arm ex.
Oops: 17 [#1] PREEMPT SMP
what 17 give information in this case.
In x86 it represents -
bit 0 == 0: no page found 1: protection fault
bit 1 == 0: read access 1: write access
bit 2 == 0: kernel-mode access 1: user-mode access
bit 3 == 1: use of reserved bit detected
bit 4 == 1: fault was an instruction fetch
But i am not able to find any information in arm.
Thanks
Shunty
What you printed above as description of bits is page fault descriptions, not Oops faults.
See Linux's oops-tracing for more information on looking for Linux crash analysis.
Below is how your Oops: 17 [#1] PREEMPT SMP arch/arm/kernel/traps.c:
#define S_PREEMPT " PREEMPT"
...
#define S_SMP " SMP"
...
printk(KERN_EMERG "Internal error: %s: %x [#%d]" S_PREEMPT S_SMP S_ISA "\n", str, err, ++die_counter);
Page faults doesn't need to crash the kernel, as well as not all kernel crashes are page faults. So there is a high chance Oops: 17 is not related to page faults at all. (and as a bonus my wild guess is it is about scheduling / just sounds familiar to me.)
Looks like you're asking about the ARM Fault Status Register (FSR) bits. I looked up the kernel code (arch/arm/mm/fault.c) and found that this is what is actually passed as a parameter to the Oops code:
static void
__do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
struct pt_regs *regs)
{
[...]
pr_alert("Unable to handle kernel %s at virtual address %08lx\n",
(addr < PAGE_SIZE) ? "NULL pointer dereference" :
"paging request", addr);
show_pte(mm, addr);
die("Oops", regs, **fsr**);
[...]
}
So, anyway, this I traced to the FSR register on the ARM(v4 and above?) MMU:
Source: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0438d/BABFFDFD.html
...
[3:0] FS[3:0]
Fault Status bits. This field indicates the type of exception generated. Any encoding not listed is reserved:
b00001
Alignment fault.
b00100
Instruction cache maintenance fault[a].
b01100
Synchronous external abort on translation table walk, 1st level.
b01110
Synchronous external abort on translation table walk, 2nd level.
b11100
Synchronous parity error on translation table walk, 1st level.
b11110
Synchronous parity error on translation table walk, 2nd level.
b00101
Translation fault, 1st level.
b00111
Translation fault, 2nd level.
b00011
Access flag fault, 1st level.
b00110
Access flag fault, 2nd level.
b01001
Domain fault, 1st level.
b01011
Domain fault, 2nd level.
b01101
Permission fault, 1st level.
b01111
Permission fault, 2nd level.
b00010
Debug event.
b01000
Synchronous external abort, non-translation.
b11001
Synchronous parity error on memory access.
b10110
Asynchronous external abort.
b11000
Asynchronous parity error on memory access.
...
Disclaimer: I don't know whether this info is still relevant; the doc states it's for the ARM Cortex A15 and the page is marked as Superseded.
Could see this page also:
ARM926EJ-S Fault address and fault status registers

Resources