mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	powerpc: Documentation for transactional memory on powerpc
Signed-off-by: Matt Evans <matt@ozlabs.org> Signed-off-by: Michael Neuling <mikey@neuling.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This commit is contained in:
		
							parent
							
								
									81afe7d101
								
							
						
					
					
						commit
						db8ff90702
					
				
					 1 changed files with 175 additions and 0 deletions
				
			
		
							
								
								
									
										175
									
								
								Documentation/powerpc/transactional_memory.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								Documentation/powerpc/transactional_memory.txt
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,175 @@
 | 
			
		|||
Transactional Memory support
 | 
			
		||||
============================
 | 
			
		||||
 | 
			
		||||
POWER kernel support for this feature is currently limited to supporting
 | 
			
		||||
its use by user programs.  It is not currently used by the kernel itself.
 | 
			
		||||
 | 
			
		||||
This file aims to sum up how it is supported by Linux and what behaviour you
 | 
			
		||||
can expect from your user programs.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Basic overview
 | 
			
		||||
==============
 | 
			
		||||
 | 
			
		||||
Hardware Transactional Memory is supported on POWER8 processors, and is a
 | 
			
		||||
feature that enables a different form of atomic memory access.  Several new
 | 
			
		||||
instructions are presented to delimit transactions; transactions are
 | 
			
		||||
guaranteed to either complete atomically or roll back and undo any partial
 | 
			
		||||
changes.
 | 
			
		||||
 | 
			
		||||
A simple transaction looks like this:
 | 
			
		||||
 | 
			
		||||
begin_move_money:
 | 
			
		||||
  tbegin
 | 
			
		||||
  beq   abort_handler
 | 
			
		||||
 | 
			
		||||
  ld    r4, SAVINGS_ACCT(r3)
 | 
			
		||||
  ld    r5, CURRENT_ACCT(r3)
 | 
			
		||||
  subi  r5, r5, 1
 | 
			
		||||
  addi  r4, r4, 1
 | 
			
		||||
  std   r4, SAVINGS_ACCT(r3)
 | 
			
		||||
  std   r5, CURRENT_ACCT(r3)
 | 
			
		||||
 | 
			
		||||
  tend
 | 
			
		||||
 | 
			
		||||
  b     continue
 | 
			
		||||
 | 
			
		||||
abort_handler:
 | 
			
		||||
  ... test for odd failures ...
 | 
			
		||||
 | 
			
		||||
  /* Retry the transaction if it failed because it conflicted with
 | 
			
		||||
   * someone else: */
 | 
			
		||||
  b     begin_move_money
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
The 'tbegin' instruction denotes the start point, and 'tend' the end point.
 | 
			
		||||
Between these points the processor is in 'Transactional' state; any memory
 | 
			
		||||
references will complete in one go if there are no conflicts with other
 | 
			
		||||
transactional or non-transactional accesses within the system.  In this
 | 
			
		||||
example, the transaction completes as though it were normal straight-line code
 | 
			
		||||
IF no other processor has touched SAVINGS_ACCT(r3) or CURRENT_ACCT(r3); an
 | 
			
		||||
atomic move of money from the current account to the savings account has been
 | 
			
		||||
performed.  Even though the normal ld/std instructions are used (note no
 | 
			
		||||
lwarx/stwcx), either *both* SAVINGS_ACCT(r3) and CURRENT_ACCT(r3) will be
 | 
			
		||||
updated, or neither will be updated.
 | 
			
		||||
 | 
			
		||||
If, in the meantime, there is a conflict with the locations accessed by the
 | 
			
		||||
transaction, the transaction will be aborted by the CPU.  Register and memory
 | 
			
		||||
state will roll back to that at the 'tbegin', and control will continue from
 | 
			
		||||
'tbegin+4'.  The branch to abort_handler will be taken this second time; the
 | 
			
		||||
abort handler can check the cause of the failure, and retry.
 | 
			
		||||
 | 
			
		||||
Checkpointed registers include all GPRs, FPRs, VRs/VSRs, LR, CCR/CR, CTR, FPCSR
 | 
			
		||||
and a few other status/flag regs; see the ISA for details.
 | 
			
		||||
 | 
			
		||||
Causes of transaction aborts
 | 
			
		||||
============================
 | 
			
		||||
 | 
			
		||||
- Conflicts with cache lines used by other processors
 | 
			
		||||
- Signals
 | 
			
		||||
- Context switches
 | 
			
		||||
- See the ISA for full documentation of everything that will abort transactions.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Syscalls
 | 
			
		||||
========
 | 
			
		||||
 | 
			
		||||
Performing syscalls from within transaction is not recommended, and can lead
 | 
			
		||||
to unpredictable results.
 | 
			
		||||
 | 
			
		||||
Syscalls do not by design abort transactions, but beware: The kernel code will
 | 
			
		||||
not be running in transactional state.  The effect of syscalls will always
 | 
			
		||||
remain visible, but depending on the call they may abort your transaction as a
 | 
			
		||||
side-effect, read soon-to-be-aborted transactional data that should not remain
 | 
			
		||||
invisible, etc.  If you constantly retry a transaction that constantly aborts
 | 
			
		||||
itself by calling a syscall, you'll have a livelock & make no progress.
 | 
			
		||||
 | 
			
		||||
Simple syscalls (e.g. sigprocmask()) "could" be OK.  Even things like write()
 | 
			
		||||
from, say, printf() should be OK as long as the kernel does not access any
 | 
			
		||||
memory that was accessed transactionally.
 | 
			
		||||
 | 
			
		||||
Consider any syscalls that happen to work as debug-only -- not recommended for
 | 
			
		||||
production use.  Best to queue them up till after the transaction is over.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Signals
 | 
			
		||||
=======
 | 
			
		||||
 | 
			
		||||
Delivery of signals (both sync and async) during transactions provides a second
 | 
			
		||||
thread state (ucontext/mcontext) to represent the second transactional register
 | 
			
		||||
state.  Signal delivery 'treclaim's to capture both register states, so signals
 | 
			
		||||
abort transactions.  The usual ucontext_t passed to the signal handler
 | 
			
		||||
represents the checkpointed/original register state; the signal appears to have
 | 
			
		||||
arisen at 'tbegin+4'.
 | 
			
		||||
 | 
			
		||||
If the sighandler ucontext has uc_link set, a second ucontext has been
 | 
			
		||||
delivered.  For future compatibility the MSR.TS field should be checked to
 | 
			
		||||
determine the transactional state -- if so, the second ucontext in uc->uc_link
 | 
			
		||||
represents the active transactional registers at the point of the signal.
 | 
			
		||||
 | 
			
		||||
For 64-bit processes, uc->uc_mcontext.regs->msr is a full 64-bit MSR and its TS
 | 
			
		||||
field shows the transactional mode.
 | 
			
		||||
 | 
			
		||||
For 32-bit processes, the mcontext's MSR register is only 32 bits; the top 32
 | 
			
		||||
bits are stored in the MSR of the second ucontext, i.e. in
 | 
			
		||||
uc->uc_link->uc_mcontext.regs->msr.  The top word contains the transactional
 | 
			
		||||
state TS.
 | 
			
		||||
 | 
			
		||||
However, basic signal handlers don't need to be aware of transactions
 | 
			
		||||
and simply returning from the handler will deal with things correctly:
 | 
			
		||||
 | 
			
		||||
Transaction-aware signal handlers can read the transactional register state
 | 
			
		||||
from the second ucontext.  This will be necessary for crash handlers to
 | 
			
		||||
determine, for example, the address of the instruction causing the SIGSEGV.
 | 
			
		||||
 | 
			
		||||
Example signal handler:
 | 
			
		||||
 | 
			
		||||
    void crash_handler(int sig, siginfo_t *si, void *uc)
 | 
			
		||||
    {
 | 
			
		||||
      ucontext_t *ucp = uc;
 | 
			
		||||
      ucontext_t *transactional_ucp = ucp->uc_link;
 | 
			
		||||
 | 
			
		||||
      if (ucp_link) {
 | 
			
		||||
        u64 msr = ucp->uc_mcontext.regs->msr;
 | 
			
		||||
        /* May have transactional ucontext! */
 | 
			
		||||
#ifndef __powerpc64__
 | 
			
		||||
        msr |= ((u64)transactional_ucp->uc_mcontext.regs->msr) << 32;
 | 
			
		||||
#endif
 | 
			
		||||
        if (MSR_TM_ACTIVE(msr)) {
 | 
			
		||||
           /* Yes, we crashed during a transaction.  Oops. */
 | 
			
		||||
   fprintf(stderr, "Transaction to be restarted at 0x%llx, but "
 | 
			
		||||
                           "crashy instruction was at 0x%llx\n",
 | 
			
		||||
                           ucp->uc_mcontext.regs->nip,
 | 
			
		||||
                           transactional_ucp->uc_mcontext.regs->nip);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      fix_the_problem(ucp->dar);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Failure cause codes used by kernel
 | 
			
		||||
==================================
 | 
			
		||||
 | 
			
		||||
These are defined in <asm/reg.h>, and distinguish different reasons why the
 | 
			
		||||
kernel aborted a transaction:
 | 
			
		||||
 | 
			
		||||
 TM_CAUSE_RESCHED       Thread was rescheduled.
 | 
			
		||||
 TM_CAUSE_FAC_UNAV      FP/VEC/VSX unavailable trap.
 | 
			
		||||
 TM_CAUSE_SYSCALL       Currently unused; future syscalls that must abort
 | 
			
		||||
                        transactions for consistency will use this.
 | 
			
		||||
 TM_CAUSE_SIGNAL        Signal delivered.
 | 
			
		||||
 TM_CAUSE_MISC          Currently unused.
 | 
			
		||||
 | 
			
		||||
These can be checked by the user program's abort handler as TEXASR[0:7].
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
GDB
 | 
			
		||||
===
 | 
			
		||||
 | 
			
		||||
GDB and ptrace are not currently TM-aware.  If one stops during a transaction,
 | 
			
		||||
it looks like the transaction has just started (the checkpointed state is
 | 
			
		||||
presented).  The transaction cannot then be continued and will take the failure
 | 
			
		||||
handler route.  Furthermore, the transactional 2nd register state will be
 | 
			
		||||
inaccessible.  GDB can currently be used on programs using TM, but not sensibly
 | 
			
		||||
in parts within transactions.
 | 
			
		||||
		Loading…
	
		Reference in a new issue