Hey,
in Fiasco.OC we have a function inside src/kernel/foc/l4/pkg/l4sys/include/thread.h
L4_INLINE l4_msgtag_t l4_thread_ex_regs_ret(l4_cap_idx_t thread, l4_addr_t *ip, l4_addr_t *sp, l4_umword_t *flags) L4_NOTHROW;
which allows us for a given thread (capability ID) to read its general purpose registers, SP and IP. Is there a similar function (if not, how could I achieve it) to access the ARM A9 System control registers or, to be more precise, the Data Fault Address Register (DFAR) [1] of a thread? I tried creating a function similar to the above mentioned, but modified the body to do this:
unsigned int v; asm volatile ("mrc p15, 0, %[v], c6, c0, 0" : [v]"=r"(v) :: );
and then write v back to the caller. But this just made the whole system hang. Any ideas? Thanks in advance!
Best regards, Josef
[1] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.100511_0401_10_e...
Hi,
On Thu Jan 25, 2018 at 16:32:25 +0000, Stark, Josef wrote:
Hey,
in Fiasco.OC we have a function inside src/kernel/foc/l4/pkg/l4sys/include/thread.h
L4_INLINE l4_msgtag_t l4_thread_ex_regs_ret(l4_cap_idx_t thread, l4_addr_t *ip, l4_addr_t *sp, l4_umword_t *flags) L4_NOTHROW;
which allows us for a given thread (capability ID) to read its general purpose registers, SP and IP. Is there a similar function (if not, how could I achieve it) to access the ARM A9 System control registers or, to be more precise, the Data Fault Address Register (DFAR) [1] of a thread? I tried creating a function similar to the above mentioned, but modified the body to do this:
unsigned int v; asm volatile ("mrc p15, 0, %[v], c6, c0, 0" : [v]"=r"(v) :: );
and then write v back to the caller. But this just made the whole system hang. Any ideas? Thanks in advance!
This MRC is a privileged instruction and cannot be called in user-level. If for whatever reason you need to know DFAR (why?), you need to do the mrc in the kernel and have an interface to retrieve it from there. Taking any security considerations aside, add another function to L4::Thread (Thread_object in the kernel) to get the value, it's an easy option.
Adam
Hey,
This MRC is a privileged instruction and cannot be called in user-level. If for whatever reason you need to know DFAR (why?), you need to do the mrc in the kernel and have an interface to retrieve it from there. Taking any security considerations aside, add another function to L4::Thread (Thread_object in the kernel) to get the value, it's an easy option.
I did this now, we already had a custom function that reads all the general purpose registers, and IP and SP (by calling Thread::user_ip() and Thread::user_sp()) so there I inserted my assembler call. Now the call doesn't freeze the system anymore and it returns a value. But the strange thing is that when I have 3 threads in a process and only 1 is faulting and I call this function for all of them, they all return the same value from their DFAR (0xe07c). When I instead read the DFSR (c5 instead of c6), they all return 0x7. But I'm thinking that when only one of the threads is faulting, their DFSRs or DFARs should return different values. What am I missing? The IP and SP registers appear to be read correctly and with different values.
(why?)
I have a userspace application that has registered itself as fault handler for its child. Now, when a page fault arrives, I want to identify the faulting thread by comparing the page fault address from the pf-report with the DFAR registers of each of the threads. I'm using Genode on top of Fiasco.OC, and Genode's pagefault report doesn't include a direct way to identify/access the faulting thread.
Thanks for your help!
Best regards, Josef
Hi,
On Friday, 26. January 2018, 14:34:29 Stark, Josef wrote:
Hey,
I did this now, we already had a custom function that reads all the general purpose registers, and IP and SP (by calling Thread::user_ip() and Thread::user_sp()) so there I inserted my assembler call. Now the call doesn't freeze the system anymore and it returns a value. But the strange thing is that when I have 3 threads in a process and only 1 is faulting and I call this function for all of them, they all return the same value from their DFAR (0xe07c). When I instead read the DFSR (c5 instead of c6), they all return 0x7. But I'm thinking that when only one of the threads is faulting, their DFSRs or DFARs should return different values. What am I missing? The IP and SP registers appear to be read correctly and with different values.
The DFAR/DFSR registers are CPU registers. They are not specific to a thread. When a thread faults, DFAR/DFSR get set in hardware on the CPU. Now when the OS switches contexts on the CPU these registers are unaffected. Your solution only ever sees the last fault address on the CPU. And that might not even need to be a userland address either.
I have a userspace application that has registered itself as fault handler for its child. Now, when a page fault arrives, I want to identify the faulting thread by comparing the page fault address from the pf-report with the DFAR registers of each of the threads. I'm using Genode on top of Fiasco.OC, and Genode's pagefault report doesn't include a direct way to identify/access the faulting thread.
Maybe a way forward is to register different page fault handlers for your threads in question? So each handler knows which thread(s) it serves already.
Hope that helps a bit.
- Christian
l4-hackers@os.inf.tu-dresden.de