s390: add support for transactional memory
Allow user-space processes to use transactional execution (TX). If the TX facility is available user space programs can use transactions for fine-grained serialization based on the data objects that are referenced during a transaction. This is useful for lockless data structures and speculative compiler optimizations. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
@@ -42,6 +42,7 @@ enum s390_regset {
|
||||
REGSET_GENERAL,
|
||||
REGSET_FP,
|
||||
REGSET_LAST_BREAK,
|
||||
REGSET_TDB,
|
||||
REGSET_SYSTEM_CALL,
|
||||
REGSET_GENERAL_EXTENDED,
|
||||
};
|
||||
@@ -52,6 +53,21 @@ void update_per_regs(struct task_struct *task)
|
||||
struct thread_struct *thread = &task->thread;
|
||||
struct per_regs old, new;
|
||||
|
||||
/* Take care of the enable/disable of transactional execution. */
|
||||
if (MACHINE_HAS_TE) {
|
||||
unsigned long cr0, cr0_new;
|
||||
|
||||
__ctl_store(cr0, 0, 0);
|
||||
/* set or clear transaction execution bits 8 and 9. */
|
||||
if (task->thread.per_flags & PER_FLAG_NO_TE)
|
||||
cr0_new = cr0 & ~(3UL << 54);
|
||||
else
|
||||
cr0_new = cr0 | (3UL << 54);
|
||||
/* Only load control register 0 if necessary. */
|
||||
if (cr0 != cr0_new)
|
||||
__ctl_load(cr0_new, 0, 0);
|
||||
}
|
||||
|
||||
/* Copy user specified PER registers */
|
||||
new.control = thread->per_user.control;
|
||||
new.start = thread->per_user.start;
|
||||
@@ -60,6 +76,10 @@ void update_per_regs(struct task_struct *task)
|
||||
/* merge TIF_SINGLE_STEP into user specified PER registers. */
|
||||
if (test_tsk_thread_flag(task, TIF_SINGLE_STEP)) {
|
||||
new.control |= PER_EVENT_IFETCH;
|
||||
#ifdef CONFIG_64BIT
|
||||
new.control |= PER_CONTROL_SUSPENSION;
|
||||
new.control |= PER_EVENT_TRANSACTION_END;
|
||||
#endif
|
||||
new.start = 0;
|
||||
new.end = PSW_ADDR_INSN;
|
||||
}
|
||||
@@ -100,6 +120,7 @@ void ptrace_disable(struct task_struct *task)
|
||||
memset(&task->thread.per_event, 0, sizeof(task->thread.per_event));
|
||||
clear_tsk_thread_flag(task, TIF_SINGLE_STEP);
|
||||
clear_tsk_thread_flag(task, TIF_PER_TRAP);
|
||||
task->thread.per_flags = 0;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_64BIT
|
||||
@@ -416,6 +437,16 @@ long arch_ptrace(struct task_struct *child, long request,
|
||||
put_user(task_thread_info(child)->last_break,
|
||||
(unsigned long __user *) data);
|
||||
return 0;
|
||||
case PTRACE_ENABLE_TE:
|
||||
if (!MACHINE_HAS_TE)
|
||||
return -EIO;
|
||||
child->thread.per_flags &= ~PER_FLAG_NO_TE;
|
||||
return 0;
|
||||
case PTRACE_DISABLE_TE:
|
||||
if (!MACHINE_HAS_TE)
|
||||
return -EIO;
|
||||
child->thread.per_flags |= PER_FLAG_NO_TE;
|
||||
return 0;
|
||||
default:
|
||||
/* Removing high order bit from addr (only for 31 bit). */
|
||||
addr &= PSW_ADDR_INSN;
|
||||
@@ -903,6 +934,28 @@ static int s390_last_break_set(struct task_struct *target,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s390_tdb_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
{
|
||||
struct pt_regs *regs = task_pt_regs(target);
|
||||
unsigned char *data;
|
||||
|
||||
if (!(regs->int_code & 0x200))
|
||||
return -ENODATA;
|
||||
data = target->thread.trap_tdb;
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, data, 0, 256);
|
||||
}
|
||||
|
||||
static int s390_tdb_set(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int s390_system_call_get(struct task_struct *target,
|
||||
@@ -951,6 +1004,14 @@ static const struct user_regset s390_regsets[] = {
|
||||
.get = s390_last_break_get,
|
||||
.set = s390_last_break_set,
|
||||
},
|
||||
[REGSET_TDB] = {
|
||||
.core_note_type = NT_S390_TDB,
|
||||
.n = 1,
|
||||
.size = 256,
|
||||
.align = 1,
|
||||
.get = s390_tdb_get,
|
||||
.set = s390_tdb_set,
|
||||
},
|
||||
#endif
|
||||
[REGSET_SYSTEM_CALL] = {
|
||||
.core_note_type = NT_S390_SYSTEM_CALL,
|
||||
@@ -1148,6 +1209,14 @@ static const struct user_regset s390_compat_regsets[] = {
|
||||
.get = s390_compat_last_break_get,
|
||||
.set = s390_compat_last_break_set,
|
||||
},
|
||||
[REGSET_TDB] = {
|
||||
.core_note_type = NT_S390_TDB,
|
||||
.n = 1,
|
||||
.size = 256,
|
||||
.align = 1,
|
||||
.get = s390_tdb_get,
|
||||
.set = s390_tdb_set,
|
||||
},
|
||||
[REGSET_SYSTEM_CALL] = {
|
||||
.core_note_type = NT_S390_SYSTEM_CALL,
|
||||
.n = 1,
|
||||
|
Reference in New Issue
Block a user