uti: futex call function in mcctrl
Previously, futex code of McKerenl was called by mccontrol, but there ware some problems with this method. (Mainly, location of McKernel image on memory) Call futex code in mcctrl instead of the one in McKernel image, giving the following benefits: 1. Not relying on shared kernel virtual address space with Linux any more 2. The cpu id store / retrieve is not needed and resulting in the code Change-Id: Ic40929b64a655b270c435859fa287fedb713ee5c refe: #1428
This commit is contained in:
committed by
Masamichi Takagi
parent
35296c8210
commit
a9973e913d
@ -5,7 +5,7 @@ struct syscall_struct {
|
||||
int number;
|
||||
unsigned long args[6];
|
||||
unsigned long ret;
|
||||
unsigned long uti_clv; /* copy of a clv in McKernel */
|
||||
unsigned long uti_info; /* reference to data in McKernel */
|
||||
};
|
||||
|
||||
#define UTI_SZ_SYSCALL_STACK 16
|
||||
@ -17,7 +17,7 @@ struct uti_desc {
|
||||
int mck_tid; /* TODO: Move this out for multiple migrated-to-Linux threads */
|
||||
unsigned long key; /* struct task_struct* of mcexec thread, used to search struct host_thread */
|
||||
int pid, tid; /* Used as the id of tracee when issuing MCEXEC_UP_TERMINATE_THREAD */
|
||||
unsigned long uti_clv; /* copy of McKernel clv */
|
||||
unsigned long uti_info; /* reference to data in McKernel */
|
||||
|
||||
int fd; /* /dev/mcosX */
|
||||
struct syscall_struct syscall_stack[UTI_SZ_SYSCALL_STACK]; /* stack of system call arguments and return values */
|
||||
@ -26,6 +26,36 @@ struct uti_desc {
|
||||
int start_syscall_intercept; /* Used to sync between mcexec.c and syscall_intercept.c */
|
||||
};
|
||||
|
||||
/* Reference to McKernel variables accessed by mcctrl */
|
||||
struct uti_info {
|
||||
/* clv info */
|
||||
unsigned long thread_va;
|
||||
void *uti_futex_resp;
|
||||
void *ikc2linux;
|
||||
unsigned long uti_futex_resp_pa;
|
||||
unsigned long ikc2linux_pa;
|
||||
|
||||
/* thread info */
|
||||
int tid;
|
||||
int cpu;
|
||||
void *status;
|
||||
void *spin_sleep_lock;
|
||||
void *spin_sleep;
|
||||
void *vm;
|
||||
void *futex_q;
|
||||
unsigned long status_pa;
|
||||
unsigned long spin_sleep_lock_pa;
|
||||
unsigned long spin_sleep_pa;
|
||||
unsigned long vm_pa;
|
||||
unsigned long futex_q_pa;
|
||||
|
||||
/* global info */
|
||||
int mc_idle_halt;
|
||||
void *futex_queue;
|
||||
void *os; // set by mcctrl
|
||||
unsigned long futex_queue_pa;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -16,13 +16,15 @@ kmod(mcctrl
|
||||
-I${IHK_FULL_SOURCE_DIR}/include/arch/${ARCH}
|
||||
-I${PROJECT_SOURCE_DIR}/executer/include
|
||||
-I${CMAKE_CURRENT_SOURCE_DIR}/arch/${ARCH}/include
|
||||
-I${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
-I${PROJECT_BINARY_DIR}
|
||||
-I${PROJECT_SOURCE_DIR}/kernel/include
|
||||
-I${PROJECT_SOURCE_DIR}/arch/${ARCH}/kernel/include
|
||||
-DMCEXEC_PATH=\\"${MCEXEC_PATH}\\"
|
||||
${ARCH_C_FLAGS}
|
||||
SOURCES
|
||||
driver.c control.c ikc.c syscall.c procfs.c binfmt_mcexec.c
|
||||
sysfs.c sysfs_files.c arch/${ARCH}/archdeps.c
|
||||
sysfs.c sysfs_files.c mc_plist.c futex.c arch/${ARCH}/archdeps.c arch/${ARCH}/cpu.c
|
||||
EXTRA_SYMBOLS
|
||||
${PROJECT_BINARY_DIR}/ihk/linux/core/Module.symvers
|
||||
DEPENDS
|
||||
|
||||
96
executer/kernel/mcctrl/arch/arm64/cpu.c
Normal file
96
executer/kernel/mcctrl/arch/arm64/cpu.c
Normal file
@ -0,0 +1,96 @@
|
||||
/* cpu.c COPYRIGHT FUJITSU LIMITED 2015-2019 */
|
||||
|
||||
#include <cpu.h>
|
||||
|
||||
/* we not have "pause" instruction, instead "yield" instruction */
|
||||
void cpu_pause(void)
|
||||
{
|
||||
asm volatile("yield" ::: "memory");
|
||||
}
|
||||
|
||||
#if defined(CONFIG_HAS_NMI)
|
||||
#include <arm-gic-v3.h>
|
||||
|
||||
/* restore interrupt (ICC_PMR_EL1 <= flags) */
|
||||
void cpu_restore_interrupt(unsigned long flags)
|
||||
{
|
||||
asm volatile(
|
||||
"msr_s " __stringify(ICC_PMR_EL1) ",%0"
|
||||
:
|
||||
: "r" (flags)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
/* save ICC_PMR_EL1 & disable interrupt (ICC_PMR_EL1 <= ICC_PMR_EL1_MASKED) */
|
||||
unsigned long cpu_disable_interrupt_save(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned long masked = ICC_PMR_EL1_MASKED;
|
||||
|
||||
asm volatile(
|
||||
"mrs_s %0, " __stringify(ICC_PMR_EL1) "\n"
|
||||
"msr_s " __stringify(ICC_PMR_EL1) ",%1"
|
||||
: "=&r" (flags)
|
||||
: "r" (masked)
|
||||
: "memory");
|
||||
return flags;
|
||||
}
|
||||
|
||||
/* save ICC_PMR_EL1 & enable interrupt (ICC_PMR_EL1 <= ICC_PMR_EL1_UNMASKED) */
|
||||
unsigned long cpu_enable_interrupt_save(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned long masked = ICC_PMR_EL1_UNMASKED;
|
||||
|
||||
asm volatile(
|
||||
"mrs_s %0, " __stringify(ICC_PMR_EL1) "\n"
|
||||
"msr_s " __stringify(ICC_PMR_EL1) ",%1"
|
||||
: "=&r" (flags)
|
||||
: "r" (masked)
|
||||
: "memory");
|
||||
return flags;
|
||||
}
|
||||
|
||||
#else /* defined(CONFIG_HAS_NMI) */
|
||||
|
||||
/* @ref.impl arch/arm64/include/asm/spinlock.h::arch_local_irq_restore */
|
||||
/* restore interrupt (PSTATE.DAIF = flags restore) */
|
||||
void cpu_restore_interrupt(unsigned long flags)
|
||||
{
|
||||
asm volatile(
|
||||
"msr daif, %0 // arch_local_irq_restore"
|
||||
:
|
||||
: "r" (flags)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
/* @ref.impl arch/arm64/include/asm/irqflags.h::arch_local_irq_save */
|
||||
/* save PSTATE.DAIF & disable interrupt (PSTATE.DAIF I bit set) */
|
||||
unsigned long cpu_disable_interrupt_save(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
asm volatile(
|
||||
"mrs %0, daif // arch_local_irq_save\n"
|
||||
"msr daifset, #2"
|
||||
: "=r" (flags)
|
||||
:
|
||||
: "memory");
|
||||
return flags;
|
||||
}
|
||||
|
||||
/* save PSTATE.DAIF & enable interrupt (PSTATE.DAIF I bit set) */
|
||||
unsigned long cpu_enable_interrupt_save(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
asm volatile(
|
||||
"mrs %0, daif // arch_local_irq_save\n"
|
||||
"msr daifclr, #2"
|
||||
: "=r" (flags)
|
||||
:
|
||||
: "memory");
|
||||
return flags;
|
||||
}
|
||||
#endif /* defined(CONFIG_HAS_NMI) */
|
||||
|
||||
142
executer/kernel/mcctrl/arch/arm64/include/arch-lock.h
Normal file
142
executer/kernel/mcctrl/arch/arm64/include/arch-lock.h
Normal file
@ -0,0 +1,142 @@
|
||||
/* This is copy of the necessary part from McKernel, for uti-futex */
|
||||
|
||||
/* arch-lock.h COPYRIGHT FUJITSU LIMITED 2015-2018 */
|
||||
#ifndef __HEADER_ARM64_COMMON_ARCH_LOCK_H
|
||||
#define __HEADER_ARM64_COMMON_ARCH_LOCK_H
|
||||
|
||||
#include <linux/preempt.h>
|
||||
#include <cpu.h>
|
||||
|
||||
#define ihk_mc_spinlock_lock __ihk_mc_spinlock_lock
|
||||
#define ihk_mc_spinlock_unlock __ihk_mc_spinlock_unlock
|
||||
|
||||
#define ihk_mc_spinlock_lock_noirq __ihk_mc_spinlock_lock_noirq
|
||||
#define ihk_mc_spinlock_unlock_noirq __ihk_mc_spinlock_unlock_noirq
|
||||
|
||||
/* @ref.impl arch/arm64/include/asm/spinlock_types.h::TICKET_SHIFT */
|
||||
#define TICKET_SHIFT 16
|
||||
|
||||
/* @ref.impl ./arch/arm64/include/asm/lse.h::ARM64_LSE_ATOMIC_INSN */
|
||||
/* else defined(CONFIG_AS_LSE) && defined(CONFIG_ARM64_LSE_ATOMICS) */
|
||||
#define _ARM64_LSE_ATOMIC_INSN(llsc, lse) llsc
|
||||
|
||||
/* @ref.impl arch/arm64/include/asm/spinlock_types.h::arch_spinlock_t */
|
||||
typedef struct {
|
||||
#ifdef __AARCH64EB__
|
||||
uint16_t next;
|
||||
uint16_t owner;
|
||||
#else /* __AARCH64EB__ */
|
||||
uint16_t owner;
|
||||
uint16_t next;
|
||||
#endif /* __AARCH64EB__ */
|
||||
} __attribute__((aligned(4))) _ihk_spinlock_t;
|
||||
|
||||
/* @ref.impl arch/arm64/include/asm/spinlock.h::arch_spin_lock */
|
||||
/* spinlock lock */
|
||||
static inline void
|
||||
__ihk_mc_spinlock_lock_noirq(_ihk_spinlock_t *lock)
|
||||
{
|
||||
unsigned int tmp;
|
||||
_ihk_spinlock_t lockval, newval;
|
||||
|
||||
preempt_disable();
|
||||
|
||||
asm volatile(
|
||||
/* Atomically increment the next ticket. */
|
||||
_ARM64_LSE_ATOMIC_INSN(
|
||||
/* LL/SC */
|
||||
" prfm pstl1strm, %3\n"
|
||||
"1: ldaxr %w0, %3\n"
|
||||
" add %w1, %w0, %w5\n"
|
||||
" stxr %w2, %w1, %3\n"
|
||||
" cbnz %w2, 1b\n",
|
||||
/* LSE atomics */
|
||||
" mov %w2, %w5\n"
|
||||
" ldadda %w2, %w0, %3\n"
|
||||
__nops(3)
|
||||
)
|
||||
|
||||
/* Did we get the lock? */
|
||||
" eor %w1, %w0, %w0, ror #16\n"
|
||||
" cbz %w1, 3f\n"
|
||||
/*
|
||||
* No: spin on the owner. Send a local event to avoid missing an
|
||||
* unlock before the exclusive load.
|
||||
*/
|
||||
" sevl\n"
|
||||
"2: wfe\n"
|
||||
" ldaxrh %w2, %4\n"
|
||||
" eor %w1, %w2, %w0, lsr #16\n"
|
||||
" cbnz %w1, 2b\n"
|
||||
/* We got the lock. Critical section starts here. */
|
||||
"3:"
|
||||
: "=&r" (lockval), "=&r" (newval), "=&r" (tmp), "+Q" (*lock)
|
||||
: "Q" (lock->owner), "I" (1 << TICKET_SHIFT)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
/* spinlock lock & interrupt disable & PSTATE.DAIF save */
|
||||
static inline unsigned long
|
||||
__ihk_mc_spinlock_lock(_ihk_spinlock_t *lock)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
flags = cpu_disable_interrupt_save();
|
||||
|
||||
__ihk_mc_spinlock_lock_noirq(lock);
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
/* @ref.impl arch/arm64/include/asm/spinlock.h::arch_spin_unlock */
|
||||
/* spinlock unlock */
|
||||
static inline void
|
||||
__ihk_mc_spinlock_unlock_noirq(_ihk_spinlock_t *lock)
|
||||
{
|
||||
unsigned long tmp;
|
||||
|
||||
asm volatile(_ARM64_LSE_ATOMIC_INSN(
|
||||
/* LL/SC */
|
||||
" ldrh %w1, %0\n"
|
||||
" add %w1, %w1, #1\n"
|
||||
" stlrh %w1, %0",
|
||||
/* LSE atomics */
|
||||
" mov %w1, #1\n"
|
||||
" staddlh %w1, %0\n"
|
||||
__nops(1))
|
||||
: "=Q" (lock->owner), "=&r" (tmp)
|
||||
:
|
||||
: "memory");
|
||||
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
static inline void
|
||||
__ihk_mc_spinlock_unlock(_ihk_spinlock_t *lock, unsigned long flags)
|
||||
{
|
||||
__ihk_mc_spinlock_unlock_noirq(lock);
|
||||
|
||||
cpu_restore_interrupt(flags);
|
||||
}
|
||||
|
||||
typedef struct mcs_rwlock_lock {
|
||||
_ihk_spinlock_t slock;
|
||||
#ifndef ENABLE_UBSAN
|
||||
} __aligned(64) mcs_rwlock_lock_t;
|
||||
#else
|
||||
} mcs_rwlock_lock_t;
|
||||
#endif
|
||||
|
||||
static inline void
|
||||
mcs_rwlock_writer_lock_noirq(struct mcs_rwlock_lock *lock)
|
||||
{
|
||||
ihk_mc_spinlock_lock_noirq(&lock->slock);
|
||||
}
|
||||
|
||||
static inline void
|
||||
mcs_rwlock_writer_unlock_noirq(struct mcs_rwlock_lock *lock)
|
||||
{
|
||||
ihk_mc_spinlock_unlock_noirq(&lock->slock);
|
||||
}
|
||||
|
||||
#endif /* !__HEADER_ARM64_COMMON_ARCH_LOCK_H */
|
||||
@ -38,4 +38,26 @@ static const unsigned long arch_rus_vm_flags = VM_RESERVED | VM_MIXEDMAP | VM_EX
|
||||
#else
|
||||
static const unsigned long arch_rus_vm_flags = VM_DONTDUMP | VM_MIXEDMAP | VM_EXEC;
|
||||
#endif
|
||||
|
||||
#define _xchg(ptr, x) \
|
||||
({ \
|
||||
__typeof__(*(ptr)) __ret; \
|
||||
__ret = (__typeof__(*(ptr))) \
|
||||
__xchg((unsigned long)(x), (ptr), sizeof(*(ptr))); \
|
||||
__ret; \
|
||||
})
|
||||
|
||||
#define xchg4(ptr, x) _xchg(ptr, x)
|
||||
#define xchg8(ptr, x) _xchg(ptr, x)
|
||||
|
||||
enum arm64_pf_error_code {
|
||||
PF_PROT = 1 << 0,
|
||||
PF_WRITE = 1 << 1,
|
||||
PF_USER = 1 << 2,
|
||||
PF_RSVD = 1 << 3,
|
||||
PF_INSTR = 1 << 4,
|
||||
|
||||
PF_PATCH = 1 << 29,
|
||||
PF_POPULATE = 1 << 30,
|
||||
};
|
||||
#endif /* __HEADER_MCCTRL_ARM64_ARCHDEPS_H */
|
||||
|
||||
51
executer/kernel/mcctrl/arch/x86_64/cpu.c
Normal file
51
executer/kernel/mcctrl/arch/x86_64/cpu.c
Normal file
@ -0,0 +1,51 @@
|
||||
/* This is copy of the necessary part from McKernel, for uti-futex */
|
||||
|
||||
#include <cpu.h>
|
||||
|
||||
/*@
|
||||
@ assigns \nothing;
|
||||
@ behavior to_enabled:
|
||||
@ assumes flags & RFLAGS_IF;
|
||||
@ ensures \interrupt_disabled == 0;
|
||||
@ behavior to_disabled:
|
||||
@ assumes !(flags & RFLAGS_IF);
|
||||
@ ensures \interrupt_disabled > 0;
|
||||
@*/
|
||||
void cpu_restore_interrupt(unsigned long flags)
|
||||
{
|
||||
asm volatile("push %0; popf" : : "g"(flags) : "memory", "cc");
|
||||
}
|
||||
|
||||
void cpu_pause(void)
|
||||
{
|
||||
asm volatile("pause" ::: "memory");
|
||||
}
|
||||
|
||||
/*@
|
||||
@ assigns \nothing;
|
||||
@ ensures \interrupt_disabled > 0;
|
||||
@ behavior from_enabled:
|
||||
@ assumes \interrupt_disabled == 0;
|
||||
@ ensures \result & RFLAGS_IF;
|
||||
@ behavior from_disabled:
|
||||
@ assumes \interrupt_disabled > 0;
|
||||
@ ensures !(\result & RFLAGS_IF);
|
||||
@*/
|
||||
unsigned long cpu_disable_interrupt_save(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
asm volatile("pushf; pop %0; cli" : "=r"(flags) : : "memory", "cc");
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
unsigned long cpu_enable_interrupt_save(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
asm volatile("pushf; pop %0; sti" : "=r"(flags) : : "memory", "cc");
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
106
executer/kernel/mcctrl/arch/x86_64/include/arch-lock.h
Normal file
106
executer/kernel/mcctrl/arch/x86_64/include/arch-lock.h
Normal file
@ -0,0 +1,106 @@
|
||||
/* This is copy of the necessary part from McKernel, for uti-futex */
|
||||
|
||||
#ifndef __HEADER_X86_COMMON_ARCH_LOCK
|
||||
#define __HEADER_X86_COMMON_ARCH_LOCK
|
||||
|
||||
#include <linux/preempt.h>
|
||||
#include <cpu.h>
|
||||
|
||||
#define ihk_mc_spinlock_lock __ihk_mc_spinlock_lock
|
||||
#define ihk_mc_spinlock_unlock __ihk_mc_spinlock_unlock
|
||||
|
||||
#define ihk_mc_spinlock_lock_noirq __ihk_mc_spinlock_lock_noirq
|
||||
#define ihk_mc_spinlock_unlock_noirq __ihk_mc_spinlock_unlock_noirq
|
||||
|
||||
typedef unsigned short __ticket_t;
|
||||
typedef unsigned int __ticketpair_t;
|
||||
|
||||
/* arch/x86/include/asm/spinlock_types.h defines struct __raw_tickets */
|
||||
typedef struct ihk_spinlock {
|
||||
union {
|
||||
__ticketpair_t head_tail;
|
||||
struct ihk__raw_tickets {
|
||||
__ticket_t head, tail;
|
||||
} tickets;
|
||||
};
|
||||
} _ihk_spinlock_t;
|
||||
|
||||
static inline void ihk_mc_spinlock_init(_ihk_spinlock_t *lock)
|
||||
{
|
||||
lock->head_tail = 0;
|
||||
}
|
||||
|
||||
static inline void __ihk_mc_spinlock_lock_noirq(_ihk_spinlock_t *lock)
|
||||
{
|
||||
register struct ihk__raw_tickets inc = { .tail = 0x0002 };
|
||||
|
||||
preempt_disable();
|
||||
|
||||
asm volatile ("lock xaddl %0, %1\n"
|
||||
: "+r" (inc), "+m" (*(lock)) : : "memory", "cc");
|
||||
|
||||
if (inc.head == inc.tail)
|
||||
goto out;
|
||||
|
||||
for (;;) {
|
||||
if (*((volatile __ticket_t *)&lock->tickets.head) == inc.tail)
|
||||
goto out;
|
||||
cpu_pause();
|
||||
}
|
||||
|
||||
out:
|
||||
barrier(); /* make sure nothing creeps before the lock is taken */
|
||||
}
|
||||
|
||||
static inline void __ihk_mc_spinlock_unlock_noirq(_ihk_spinlock_t *lock)
|
||||
{
|
||||
__ticket_t inc = 0x0002;
|
||||
|
||||
asm volatile ("lock addw %1, %0\n"
|
||||
: "+m" (lock->tickets.head)
|
||||
: "ri" (inc) : "memory", "cc");
|
||||
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
static inline unsigned long __ihk_mc_spinlock_lock(_ihk_spinlock_t *lock)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
flags = cpu_disable_interrupt_save();
|
||||
|
||||
__ihk_mc_spinlock_lock_noirq(lock);
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static inline void __ihk_mc_spinlock_unlock(_ihk_spinlock_t *lock,
|
||||
unsigned long flags)
|
||||
{
|
||||
__ihk_mc_spinlock_unlock_noirq(lock);
|
||||
|
||||
cpu_restore_interrupt(flags);
|
||||
}
|
||||
|
||||
typedef struct mcs_rwlock_lock {
|
||||
_ihk_spinlock_t slock;
|
||||
|
||||
#ifndef ENABLE_UBSAN
|
||||
} __aligned(64) mcs_rwlock_lock_t;
|
||||
#else
|
||||
} mcs_rwlock_lock_t;
|
||||
#endif
|
||||
|
||||
static inline void
|
||||
mcs_rwlock_writer_lock_noirq(struct mcs_rwlock_lock *lock)
|
||||
{
|
||||
ihk_mc_spinlock_lock_noirq(&lock->slock);
|
||||
}
|
||||
|
||||
static inline void
|
||||
mcs_rwlock_writer_unlock_noirq(struct mcs_rwlock_lock *lock)
|
||||
{
|
||||
ihk_mc_spinlock_unlock_noirq(&lock->slock);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -23,4 +23,26 @@ static const unsigned long arch_rus_vm_flags = VM_RESERVED | VM_MIXEDMAP;
|
||||
#else
|
||||
static const unsigned long arch_rus_vm_flags = VM_DONTDUMP | VM_MIXEDMAP;
|
||||
#endif
|
||||
|
||||
#define xchg4(ptr, x) \
|
||||
({ \
|
||||
int __x = (x); \
|
||||
asm volatile("xchgl %k0,%1" \
|
||||
: "=r" (__x) \
|
||||
: "m" (*ptr), "0" (__x) \
|
||||
: "memory"); \
|
||||
__x; \
|
||||
})
|
||||
|
||||
enum x86_pf_error_code {
|
||||
PF_PROT = 1 << 0,
|
||||
PF_WRITE = 1 << 1,
|
||||
PF_USER = 1 << 2,
|
||||
PF_RSVD = 1 << 3,
|
||||
PF_INSTR = 1 << 4,
|
||||
|
||||
PF_PATCH = 1 << 29,
|
||||
PF_POPULATE = 1 << 30,
|
||||
};
|
||||
|
||||
#endif /* __HEADER_MCCTRL_X86_64_ARCHDEPS_H */
|
||||
|
||||
@ -50,6 +50,8 @@
|
||||
#include <uapi/linux/sched/types.h>
|
||||
#endif
|
||||
#include <archdeps.h>
|
||||
#include <uti.h>
|
||||
#include <futex.h>
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
@ -2891,57 +2893,28 @@ static long mcexec_release_user_space(struct release_user_space_desc *__user arg
|
||||
#endif
|
||||
}
|
||||
|
||||
static long (*mckernel_do_futex)(int n, unsigned long arg0, unsigned long arg1,
|
||||
unsigned long arg2, unsigned long arg3,
|
||||
unsigned long arg4, unsigned long arg5,
|
||||
unsigned long _uti_clv,
|
||||
void *uti_futex_resp,
|
||||
void *_linux_wait_event,
|
||||
void *_linux_printk,
|
||||
void *_linux_clock_gettime);
|
||||
/* Convert phys_addr to virt_addr on Linux */
|
||||
static void
|
||||
uti_info_p2v(struct uti_info *info)
|
||||
{
|
||||
info->uti_futex_resp =
|
||||
(void *)phys_to_virt(info->uti_futex_resp_pa);
|
||||
info->ikc2linux =
|
||||
(void *)phys_to_virt(info->ikc2linux_pa);
|
||||
|
||||
long uti_wait_event(void *_resp, unsigned long nsec_timeout) {
|
||||
struct uti_futex_resp *resp = _resp;
|
||||
if (nsec_timeout) {
|
||||
return wait_event_interruptible_timeout(resp->wq, resp->done, nsecs_to_jiffies(nsec_timeout));
|
||||
} else {
|
||||
return wait_event_interruptible(resp->wq, resp->done);
|
||||
}
|
||||
}
|
||||
info->status =
|
||||
(void *)phys_to_virt(info->status_pa);
|
||||
info->spin_sleep_lock =
|
||||
(void *)phys_to_virt(info->spin_sleep_lock_pa);
|
||||
info->spin_sleep =
|
||||
(void *)phys_to_virt(info->spin_sleep_pa);
|
||||
info->vm =
|
||||
(void *)phys_to_virt(info->vm_pa);
|
||||
info->futex_q =
|
||||
(void *)phys_to_virt(info->futex_q_pa);
|
||||
|
||||
int uti_printk(const char *fmt, ...) {
|
||||
int sum = 0, nwritten;
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
nwritten = vprintk(fmt, args);
|
||||
sum += nwritten;
|
||||
va_end(args);
|
||||
return sum;
|
||||
}
|
||||
|
||||
int uti_clock_gettime(clockid_t clk_id, struct timespec *tp) {
|
||||
int ret = 0;
|
||||
struct timespec64 ts64;
|
||||
dprintk("%s: clk_id=%x,REALTIME=%x,MONOTONIC=%x\n", __FUNCTION__, clk_id, CLOCK_REALTIME, CLOCK_MONOTONIC);
|
||||
switch(clk_id) {
|
||||
case CLOCK_REALTIME:
|
||||
getnstimeofday64(&ts64);
|
||||
tp->tv_sec = ts64.tv_sec;
|
||||
tp->tv_nsec = ts64.tv_nsec;
|
||||
dprintk("%s: CLOCK_REALTIME,%ld.%09ld\n", __FUNCTION__, tp->tv_sec, tp->tv_nsec);
|
||||
break;
|
||||
case CLOCK_MONOTONIC: {
|
||||
/* Do not use getrawmonotonic() because it returns different value than clock_gettime() */
|
||||
ktime_get_ts64(&ts64);
|
||||
tp->tv_sec = ts64.tv_sec;
|
||||
tp->tv_nsec = ts64.tv_nsec;
|
||||
dprintk("%s: CLOCK_MONOTONIC,%ld.%09ld\n", __FUNCTION__, tp->tv_sec, tp->tv_nsec);
|
||||
break; }
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
info->futex_queue =
|
||||
(void *)phys_to_virt(info->futex_queue_pa);
|
||||
}
|
||||
|
||||
long mcexec_syscall_thread(ihk_os_t os, unsigned long arg, struct file *file)
|
||||
@ -2950,36 +2923,38 @@ long mcexec_syscall_thread(ihk_os_t os, unsigned long arg, struct file *file)
|
||||
int number;
|
||||
unsigned long args[6];
|
||||
unsigned long ret;
|
||||
unsigned long uti_clv; /* copy of a clv in McKernel */
|
||||
unsigned long uti_info; /* reference to data in McKernel */
|
||||
};
|
||||
struct syscall_struct param;
|
||||
struct syscall_struct __user *uparam =
|
||||
(struct syscall_struct __user *)arg;
|
||||
long rc;
|
||||
|
||||
|
||||
if (copy_from_user(¶m, uparam, sizeof param)) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
|
||||
if (param.number == __NR_futex) {
|
||||
struct uti_futex_resp resp = {
|
||||
.done = 0
|
||||
};
|
||||
init_waitqueue_head(&resp.wq);
|
||||
|
||||
if (!mckernel_do_futex) {
|
||||
if (ihk_os_get_special_address(os, IHK_SPADDR_MCKERNEL_DO_FUTEX,
|
||||
(unsigned long *)&mckernel_do_futex,
|
||||
NULL)) {
|
||||
kprintf("%s: ihk_os_get_special_address failed\n", __FUNCTION__);
|
||||
return -EINVAL;
|
||||
}
|
||||
dprintk("%s: mckernel_do_futex=%p\n", __FUNCTION__, mckernel_do_futex);
|
||||
}
|
||||
struct uti_info *_uti_info = NULL;
|
||||
|
||||
init_waitqueue_head(&resp.wq);
|
||||
_uti_info = (struct uti_info *)param.uti_info;
|
||||
|
||||
/* Convert phys_addr to virt_addr on Linux */
|
||||
uti_info_p2v(_uti_info);
|
||||
|
||||
_uti_info->os = (void *)os;
|
||||
|
||||
rc = do_futex(param.number, param.args[0],
|
||||
param.args[1], param.args[2],
|
||||
param.args[3], param.args[4], param.args[5],
|
||||
(struct uti_info *)param.uti_info,
|
||||
(void *)&resp);
|
||||
|
||||
rc = (*mckernel_do_futex)(param.number, param.args[0], param.args[1], param.args[2],
|
||||
param.args[3], param.args[4], param.args[5], param.uti_clv, (void *)&resp, (void *)uti_wait_event, (void *)uti_printk, (void *)uti_clock_gettime);
|
||||
param.ret = rc;
|
||||
} else {
|
||||
struct mcctrl_usrdata *usrdata = ihk_host_os_get_usrdata(os);
|
||||
|
||||
1115
executer/kernel/mcctrl/futex.c
Normal file
1115
executer/kernel/mcctrl/futex.c
Normal file
File diff suppressed because it is too large
Load Diff
10
executer/kernel/mcctrl/include/cpu.h
Normal file
10
executer/kernel/mcctrl/include/cpu.h
Normal file
@ -0,0 +1,10 @@
|
||||
/* This is copy of the necessary part from McKernel, for uti-futex */
|
||||
#ifndef MC_CPU_H
|
||||
#define MC_CPU_H
|
||||
|
||||
void cpu_restore_interrupt(unsigned long flags);
|
||||
void cpu_pause(void);
|
||||
unsigned long cpu_disable_interrupt_save(void);
|
||||
unsigned long cpu_enable_interrupt_save(void);
|
||||
|
||||
#endif
|
||||
169
executer/kernel/mcctrl/include/futex.h
Normal file
169
executer/kernel/mcctrl/include/futex.h
Normal file
@ -0,0 +1,169 @@
|
||||
/* This is copy of the necessary part from McKernel, for uti-futex */
|
||||
|
||||
#ifndef _FUTEX_H
|
||||
#define _FUTEX_H
|
||||
|
||||
#include <mc_plist.h>
|
||||
#include <arch-lock.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
/** \name Futex Commands
|
||||
* @{
|
||||
*/
|
||||
#define FUTEX_WAIT 0
|
||||
#define FUTEX_WAKE 1
|
||||
#define FUTEX_FD 2
|
||||
#define FUTEX_REQUEUE 3
|
||||
#define FUTEX_CMP_REQUEUE 4
|
||||
#define FUTEX_WAKE_OP 5
|
||||
#define FUTEX_LOCK_PI 6
|
||||
#define FUTEX_UNLOCK_PI 7
|
||||
#define FUTEX_TRYLOCK_PI 8
|
||||
#define FUTEX_WAIT_BITSET 9
|
||||
#define FUTEX_WAKE_BITSET 10
|
||||
#define FUTEX_WAIT_REQUEUE_PI 11
|
||||
#define FUTEX_CMP_REQUEUE_PI 12
|
||||
// @}
|
||||
|
||||
#define FUTEX_PRIVATE_FLAG 128
|
||||
#define FUTEX_CLOCK_REALTIME 256
|
||||
#define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME)
|
||||
|
||||
#define FUTEX_WAIT_PRIVATE (FUTEX_WAIT | FUTEX_PRIVATE_FLAG)
|
||||
#define FUTEX_WAKE_PRIVATE (FUTEX_WAKE | FUTEX_PRIVATE_FLAG)
|
||||
#define FUTEX_REQUEUE_PRIVATE (FUTEX_REQUEUE | FUTEX_PRIVATE_FLAG)
|
||||
#define FUTEX_CMP_REQUEUE_PRIVATE (FUTEX_CMP_REQUEUE | FUTEX_PRIVATE_FLAG)
|
||||
#define FUTEX_WAKE_OP_PRIVATE (FUTEX_WAKE_OP | FUTEX_PRIVATE_FLAG)
|
||||
#define FUTEX_LOCK_PI_PRIVATE (FUTEX_LOCK_PI | FUTEX_PRIVATE_FLAG)
|
||||
#define FUTEX_UNLOCK_PI_PRIVATE (FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG)
|
||||
#define FUTEX_TRYLOCK_PI_PRIVATE (FUTEX_TRYLOCK_PI | FUTEX_PRIVATE_FLAG)
|
||||
#define FUTEX_WAIT_BITSET_PRIVATE (FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG)
|
||||
#define FUTEX_WAKE_BITSET_PRIVATE (FUTEX_WAKE_BITSET | FUTEX_PRIVATE_FLAG)
|
||||
#define FUTEX_WAIT_REQUEUE_PI_PRIVATE (FUTEX_WAIT_REQUEUE_PI | \
|
||||
FUTEX_PRIVATE_FLAG)
|
||||
#define FUTEX_CMP_REQUEUE_PI_PRIVATE (FUTEX_CMP_REQUEUE_PI | \
|
||||
FUTEX_PRIVATE_FLAG)
|
||||
|
||||
|
||||
/** \name Futex Operations, used for FUTEX_WAKE_OP
|
||||
* @{
|
||||
*/
|
||||
#define FUTEX_OP_SET 0 /* *(int *)UADDR2 = OPARG; */
|
||||
#define FUTEX_OP_ADD 1 /* *(int *)UADDR2 += OPARG; */
|
||||
#define FUTEX_OP_OR 2 /* *(int *)UADDR2 |= OPARG; */
|
||||
#define FUTEX_OP_ANDN 3 /* *(int *)UADDR2 &= ~OPARG; */
|
||||
#define FUTEX_OP_XOR 4 /* *(int *)UADDR2 ^= OPARG; */
|
||||
|
||||
#define FUTEX_OP_OPARG_SHIFT 8U /* Use (1 << OPARG) instead of OPARG. */
|
||||
|
||||
#define FUTEX_OP_CMP_EQ 0 /* if (oldval == CMPARG) wake */
|
||||
#define FUTEX_OP_CMP_NE 1 /* if (oldval != CMPARG) wake */
|
||||
#define FUTEX_OP_CMP_LT 2 /* if (oldval < CMPARG) wake */
|
||||
#define FUTEX_OP_CMP_LE 3 /* if (oldval <= CMPARG) wake */
|
||||
#define FUTEX_OP_CMP_GT 4 /* if (oldval > CMPARG) wake */
|
||||
#define FUTEX_OP_CMP_GE 5 /* if (oldval >= CMPARG) wake */
|
||||
// @}
|
||||
|
||||
#define FUT_OFF_INODE 1 /* We set bit 0 if key has a reference on inode */
|
||||
#define FUT_OFF_MMSHARED 2 /* We set bit 1 if key has a reference on mm */
|
||||
|
||||
#define FUTEX_HASHBITS 8 /* 256 entries in each futex hash tbl */
|
||||
|
||||
#define PS_RUNNING 0x1
|
||||
#define PS_INTERRUPTIBLE 0x2
|
||||
#define PS_UNINTERRUPTIBLE 0x4
|
||||
#define PS_ZOMBIE 0x8
|
||||
#define PS_EXITED 0x10
|
||||
#define PS_STOPPED 0x20
|
||||
|
||||
static inline int get_futex_value_locked(uint32_t *dest, uint32_t *from)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pagefault_disable();
|
||||
ret = __get_user(*dest, from);
|
||||
pagefault_enable();
|
||||
|
||||
return ret ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
union futex_key {
|
||||
struct {
|
||||
unsigned long pgoff;
|
||||
void *phys;
|
||||
int offset;
|
||||
} shared;
|
||||
struct {
|
||||
unsigned long address;
|
||||
void *mm; // Acctually, process_vm
|
||||
int offset;
|
||||
} private;
|
||||
struct {
|
||||
unsigned long word;
|
||||
void *ptr;
|
||||
int offset;
|
||||
} both;
|
||||
};
|
||||
|
||||
#define FUTEX_KEY_INIT ((union futex_key) { .both = { .ptr = NULL } })
|
||||
|
||||
#define FUTEX_BITSET_MATCH_ANY 0xffffffff
|
||||
|
||||
/**
|
||||
* struct futex_q - The hashed futex queue entry, one per waiting task
|
||||
* @task: the task waiting on the futex
|
||||
* @lock_ptr: the hash bucket lock
|
||||
* @key: the key the futex is hashed on
|
||||
* @requeue_pi_key: the requeue_pi target futex key
|
||||
* @bitset: bitset for the optional bitmasked wakeup
|
||||
*
|
||||
* We use this hashed waitqueue, instead of a normal wait_queue_t, so
|
||||
* we can wake only the relevant ones (hashed queues may be shared).
|
||||
*
|
||||
* A futex_q has a woken state, just like tasks have TASK_RUNNING.
|
||||
* It is considered woken when plist_node_empty(&q->list) || q->lock_ptr == 0.
|
||||
* The order of wakup is always to make the first condition true, then
|
||||
* the second.
|
||||
*
|
||||
* PI futexes are typically woken before they are removed from the hash list via
|
||||
* the rt_mutex code. See unqueue_me_pi().
|
||||
*/
|
||||
struct futex_q {
|
||||
struct mc_plist_node list;
|
||||
|
||||
void *task; // Actually, struct thread
|
||||
_ihk_spinlock_t *lock_ptr;
|
||||
union futex_key key;
|
||||
union futex_key *requeue_pi_key;
|
||||
uint32_t bitset;
|
||||
|
||||
/* Used to wake-up a thread running on a Linux CPU */
|
||||
void *uti_futex_resp;
|
||||
|
||||
/* Used to wake-up a thread running on a McKernel from Linux */
|
||||
void *th_spin_sleep;
|
||||
void *th_status;
|
||||
void *th_spin_sleep_lock;
|
||||
void *proc_status;
|
||||
void *proc_update_lock;
|
||||
void *runq_lock;
|
||||
void *clv_flags;
|
||||
int intr_id;
|
||||
int intr_vector;
|
||||
|
||||
unsigned long th_spin_sleep_pa;
|
||||
unsigned long th_status_pa;
|
||||
unsigned long th_spin_sleep_lock_pa;
|
||||
unsigned long proc_status_pa;
|
||||
unsigned long proc_update_lock_pa;
|
||||
unsigned long runq_lock_pa;
|
||||
unsigned long clv_flags_pa;
|
||||
};
|
||||
|
||||
long do_futex(int n, unsigned long arg0, unsigned long arg1,
|
||||
unsigned long arg2, unsigned long arg3,
|
||||
unsigned long arg4, unsigned long arg5,
|
||||
struct uti_info *uti_info,
|
||||
void *uti_futex_resp);
|
||||
|
||||
#endif
|
||||
277
executer/kernel/mcctrl/include/mc_plist.h
Normal file
277
executer/kernel/mcctrl/include/mc_plist.h
Normal file
@ -0,0 +1,277 @@
|
||||
/* This is copy of the necessary part from McKernel, for uti-futex */
|
||||
|
||||
/*
|
||||
* Descending-priority-sorted double-linked list
|
||||
*
|
||||
* (C) 2002-2003 Intel Corp
|
||||
* Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>.
|
||||
*
|
||||
* 2001-2005 (c) MontaVista Software, Inc.
|
||||
* Daniel Walker <dwalker@mvista.com>
|
||||
*
|
||||
* (C) 2005 Thomas Gleixner <tglx@linutronix.de>
|
||||
*
|
||||
* Simplifications of the original code by
|
||||
* Oleg Nesterov <oleg@tv-sign.ru>
|
||||
*
|
||||
* Licensed under the FSF's GNU Public License v2 or later.
|
||||
*
|
||||
* Based on simple lists (include/linux/list.h).
|
||||
*
|
||||
* This is a priority-sorted list of nodes; each node has a
|
||||
* priority from INT_MIN (highest) to INT_MAX (lowest).
|
||||
*
|
||||
* Addition is O(K), removal is O(1), change of priority of a node is
|
||||
* O(K) and K is the number of RT priority levels used in the system.
|
||||
* (1 <= K <= 99)
|
||||
*
|
||||
* This list is really a list of lists:
|
||||
*
|
||||
* - The tier 1 list is the prio_list, different priority nodes.
|
||||
*
|
||||
* - The tier 2 list is the node_list, serialized nodes.
|
||||
*
|
||||
* Simple ASCII art explanation:
|
||||
*
|
||||
* |HEAD |
|
||||
* | |
|
||||
* |prio_list.prev|<------------------------------------|
|
||||
* |prio_list.next|<->|pl|<->|pl|<--------------->|pl|<-|
|
||||
* |10 | |10| |21| |21| |21| |40| (prio)
|
||||
* | | | | | | | | | | | |
|
||||
* | | | | | | | | | | | |
|
||||
* |node_list.next|<->|nl|<->|nl|<->|nl|<->|nl|<->|nl|<-|
|
||||
* |node_list.prev|<------------------------------------|
|
||||
*
|
||||
* The nodes on the prio_list list are sorted by priority to simplify
|
||||
* the insertion of new nodes. There are no nodes with duplicate
|
||||
* priorites on the list.
|
||||
*
|
||||
* The nodes on the node_list are ordered by priority and can contain
|
||||
* entries which have the same priority. Those entries are ordered
|
||||
* FIFO
|
||||
*
|
||||
* Addition means: look for the prio_list node in the prio_list
|
||||
* for the priority of the node and insert it before the node_list
|
||||
* entry of the next prio_list node. If it is the first node of
|
||||
* that priority, add it to the prio_list in the right position and
|
||||
* insert it into the serialized node_list list
|
||||
*
|
||||
* Removal means remove it from the node_list and remove it from
|
||||
* the prio_list if the node_list list_head is non empty. In case
|
||||
* of removal from the prio_list it must be checked whether other
|
||||
* entries of the same priority are on the list or not. If there
|
||||
* is another entry of the same priority then this entry has to
|
||||
* replace the removed entry on the prio_list. If the entry which
|
||||
* is removed is the only entry of this priority then a simple
|
||||
* remove from both list is sufficient.
|
||||
*
|
||||
* INT_MIN is the highest priority, 0 is the medium highest, INT_MAX
|
||||
* is lowest priority.
|
||||
*
|
||||
* No locking is done, up to the caller.
|
||||
*
|
||||
*/
|
||||
#ifndef _MC_PLIST_H_
|
||||
#define _MC_PLIST_H_
|
||||
|
||||
#include <arch-lock.h>
|
||||
|
||||
struct mc_plist_head {
|
||||
struct list_head prio_list;
|
||||
struct list_head node_list;
|
||||
#ifdef CONFIG_DEBUG_PI_LIST
|
||||
raw_spinlock_t *rawlock;
|
||||
spinlock_t *spinlock;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct mc_plist_node {
|
||||
int prio;
|
||||
struct mc_plist_head plist;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_PI_LIST
|
||||
# define PLIST_HEAD_LOCK_INIT(_lock) .spinlock = _lock
|
||||
# define PLIST_HEAD_LOCK_INIT_RAW(_lock) .rawlock = _lock
|
||||
#else
|
||||
# define PLIST_HEAD_LOCK_INIT(_lock)
|
||||
# define PLIST_HEAD_LOCK_INIT_RAW(_lock)
|
||||
#endif
|
||||
|
||||
#define _MCK_PLIST_HEAD_INIT(head) \
|
||||
.prio_list = LIST_HEAD_INIT((head).prio_list), \
|
||||
.node_list = LIST_HEAD_INIT((head).node_list)
|
||||
|
||||
/**
|
||||
* PLIST_HEAD_INIT - static struct plist_head initializer
|
||||
* @head: struct plist_head variable name
|
||||
* @_lock: lock to initialize for this list
|
||||
*/
|
||||
#define MCK_PLIST_HEAD_INIT(head, _lock) \
|
||||
{ \
|
||||
_MCK_PLIST_HEAD_INIT(head), \
|
||||
MCK_PLIST_HEAD_LOCK_INIT(&(_lock)) \
|
||||
}
|
||||
|
||||
/**
|
||||
* PLIST_HEAD_INIT_RAW - static struct plist_head initializer
|
||||
* @head: struct plist_head variable name
|
||||
* @_lock: lock to initialize for this list
|
||||
*/
|
||||
#define MCK_PLIST_HEAD_INIT_RAW(head, _lock) \
|
||||
{ \
|
||||
_MCK_PLIST_HEAD_INIT(head), \
|
||||
MCK_PLIST_HEAD_LOCK_INIT_RAW(&(_lock)) \
|
||||
}
|
||||
|
||||
/**
|
||||
* PLIST_NODE_INIT - static struct plist_node initializer
|
||||
* @node: struct plist_node variable name
|
||||
* @__prio: initial node priority
|
||||
*/
|
||||
#define MCK_PLIST_NODE_INIT(node, __prio) \
|
||||
{ \
|
||||
.prio = (__prio), \
|
||||
.plist = { _MCK_PLIST_HEAD_INIT((node).plist) }, \
|
||||
}
|
||||
|
||||
/**
|
||||
* plist_head_init - dynamic struct plist_head initializer
|
||||
* @head: &struct plist_head pointer
|
||||
* @lock: spinlock protecting the list (debugging)
|
||||
*/
|
||||
static inline void
|
||||
mc_plist_head_init(struct mc_plist_head *head, _ihk_spinlock_t *lock)
|
||||
{
|
||||
INIT_LIST_HEAD(&head->prio_list);
|
||||
INIT_LIST_HEAD(&head->node_list);
|
||||
#ifdef CONFIG_DEBUG_PI_LIST
|
||||
head->spinlock = lock;
|
||||
head->rawlock = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* plist_head_init_raw - dynamic struct plist_head initializer
|
||||
* @head: &struct plist_head pointer
|
||||
* @lock: raw_spinlock protecting the list (debugging)
|
||||
*/
|
||||
static inline void
|
||||
mc_plist_head_init_raw(struct mc_plist_head *head, _ihk_spinlock_t *lock)
|
||||
{
|
||||
INIT_LIST_HEAD(&head->prio_list);
|
||||
INIT_LIST_HEAD(&head->node_list);
|
||||
#ifdef CONFIG_DEBUG_PI_LIST
|
||||
head->rawlock = lock;
|
||||
head->spinlock = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* plist_node_init - Dynamic struct plist_node initializer
|
||||
* @node: &struct plist_node pointer
|
||||
* @prio: initial node priority
|
||||
*/
|
||||
static inline void mc_plist_node_init(struct mc_plist_node *node, int prio)
|
||||
{
|
||||
node->prio = prio;
|
||||
mc_plist_head_init(&node->plist, NULL);
|
||||
}
|
||||
|
||||
extern void mc_plist_add(struct mc_plist_node *node,
|
||||
struct mc_plist_head *head);
|
||||
extern void mc_plist_del(struct mc_plist_node *node,
|
||||
struct mc_plist_head *head);
|
||||
|
||||
/**
|
||||
* plist_for_each - iterate over the plist
|
||||
* @pos: the type * to use as a loop counter
|
||||
* @head: the head for your list
|
||||
*/
|
||||
#define mc_plist_for_each(pos, head) \
|
||||
list_for_each_entry(pos, &(head)->node_list, plist.node_list)
|
||||
|
||||
/**
|
||||
* plist_for_each_safe - iterate safely over a plist of given type
|
||||
* @pos: the type * to use as a loop counter
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list
|
||||
*
|
||||
* Iterate over a plist of given type, safe against removal of list entry.
|
||||
*/
|
||||
#define mc_plist_for_each_safe(pos, n, head) \
|
||||
list_for_each_entry_safe(pos, n, &(head)->node_list, plist.node_list)
|
||||
|
||||
/**
|
||||
* plist_for_each_entry - iterate over list of given type
|
||||
* @pos: the type * to use as a loop counter
|
||||
* @head: the head for your list
|
||||
* @mem: the name of the list_struct within the struct
|
||||
*/
|
||||
#define mc_plist_for_each_entry(pos, head, mem) \
|
||||
list_for_each_entry(pos, &(head)->node_list, mem.plist.node_list)
|
||||
|
||||
/**
|
||||
* plist_for_each_entry_safe - iterate safely over list of given type
|
||||
* @pos: the type * to use as a loop counter
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list
|
||||
* @m: the name of the list_struct within the struct
|
||||
*
|
||||
* Iterate over list of given type, safe against removal of list entry.
|
||||
*/
|
||||
#define mc_plist_for_each_entry_safe(pos, n, head, m) \
|
||||
list_for_each_entry_safe(pos, n, &(head)->node_list, m.plist.node_list)
|
||||
|
||||
/**
|
||||
* plist_head_empty - return !0 if a plist_head is empty
|
||||
* @head: &struct plist_head pointer
|
||||
*/
|
||||
static inline int mc_plist_head_empty(const struct mc_plist_head *head)
|
||||
{
|
||||
return list_empty(&head->node_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* plist_node_empty - return !0 if plist_node is not on a list
|
||||
* @node: &struct plist_node pointer
|
||||
*/
|
||||
static inline int mc_plist_node_empty(const struct mc_plist_node *node)
|
||||
{
|
||||
return mc_plist_head_empty(&node->plist);
|
||||
}
|
||||
|
||||
/* All functions below assume the plist_head is not empty. */
|
||||
|
||||
/**
|
||||
* plist_first_entry - get the struct for the first entry
|
||||
* @head: the &struct plist_head pointer
|
||||
* @type: the type of the struct this is embedded in
|
||||
* @member: the name of the list_struct within the struct
|
||||
*/
|
||||
#ifdef CONFIG_DEBUG_PI_LIST
|
||||
# define mc_plist_first_entry(head, type, member) \
|
||||
({ \
|
||||
WARN_ON(mc_plist_head_empty(head)); \
|
||||
container_of(mc_plist_first(head), type, member); \
|
||||
})
|
||||
#else
|
||||
# define mc_plist_first_entry(head, type, member) \
|
||||
container_of(mc_plist_first(head), type, member)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* plist_first - return the first node (and thus, highest priority)
|
||||
* @head: the &struct plist_head pointer
|
||||
*
|
||||
* Assumes the plist is _not_ empty.
|
||||
*/
|
||||
static inline struct mc_plist_node *mc_plist_first(
|
||||
const struct mc_plist_head *head)
|
||||
{
|
||||
return list_entry(head->node_list.next,
|
||||
struct mc_plist_node, plist.node_list);
|
||||
}
|
||||
|
||||
#endif
|
||||
100
executer/kernel/mcctrl/mc_plist.c
Normal file
100
executer/kernel/mcctrl/mc_plist.c
Normal file
@ -0,0 +1,100 @@
|
||||
/* This is copy of the necessary part from McKernel, for uti-futex */
|
||||
|
||||
#include <mc_plist.h>
|
||||
#include <arch-lock.h>
|
||||
|
||||
#ifdef CONFIG_DEBUG_PI_LIST
|
||||
|
||||
static void mc_plist_check_prev_next(struct list_head *t, struct list_head *p,
|
||||
struct list_head *n)
|
||||
{
|
||||
WARN(n->prev != p || p->next != n,
|
||||
"top: %p, n: %p, p: %p\n"
|
||||
"prev: %p, n: %p, p: %p\n"
|
||||
"next: %p, n: %p, p: %p\n",
|
||||
t, t->next, t->prev,
|
||||
p, p->next, p->prev,
|
||||
n, n->next, n->prev);
|
||||
}
|
||||
|
||||
static void mc_plist_check_list(struct list_head *top)
|
||||
{
|
||||
struct list_head *prev = top, *next = top->next;
|
||||
|
||||
mc_plist_check_prev_next(top, prev, next);
|
||||
while (next != top) {
|
||||
prev = next;
|
||||
next = prev->next;
|
||||
mc_plist_check_prev_next(top, prev, next);
|
||||
}
|
||||
}
|
||||
|
||||
static void mc_plist_check_head(struct mc_plist_head *head)
|
||||
{
|
||||
WARN_ON(!head->rawlock && !head->spinlock);
|
||||
if (head->rawlock)
|
||||
WARN_ON_SMP(!raw_spin_is_locked(head->rawlock));
|
||||
if (head->spinlock)
|
||||
WARN_ON_SMP(!spin_is_locked(head->spinlock));
|
||||
mc_plist_check_list(&head->prio_list);
|
||||
mc_plist_check_list(&head->node_list);
|
||||
}
|
||||
|
||||
#else
|
||||
# define mc_plist_check_head(h) do { } while (0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* plist_add - add @node to @head
|
||||
*
|
||||
* @node: &struct plist_node pointer
|
||||
* @head: &struct plist_head pointer
|
||||
*/
|
||||
void mc_plist_add(struct mc_plist_node *node, struct mc_plist_head *head)
|
||||
{
|
||||
struct mc_plist_node *iter;
|
||||
|
||||
mc_plist_check_head(head);
|
||||
#if 0
|
||||
WARN_ON(!plist_node_empty(node));
|
||||
#endif
|
||||
|
||||
list_for_each_entry(iter, &head->prio_list, plist.prio_list) {
|
||||
if (node->prio < iter->prio)
|
||||
goto lt_prio;
|
||||
else if (node->prio == iter->prio) {
|
||||
iter = list_entry(iter->plist.prio_list.next,
|
||||
struct mc_plist_node, plist.prio_list);
|
||||
goto eq_prio;
|
||||
}
|
||||
}
|
||||
|
||||
lt_prio:
|
||||
list_add_tail(&node->plist.prio_list, &iter->plist.prio_list);
|
||||
eq_prio:
|
||||
list_add_tail(&node->plist.node_list, &iter->plist.node_list);
|
||||
|
||||
mc_plist_check_head(head);
|
||||
}
|
||||
|
||||
/**
|
||||
* plist_del - Remove a @node from plist.
|
||||
*
|
||||
* @node: &struct plist_node pointer - entry to be removed
|
||||
* @head: &struct plist_head pointer - list head
|
||||
*/
|
||||
void mc_plist_del(struct mc_plist_node *node, struct mc_plist_head *head)
|
||||
{
|
||||
mc_plist_check_head(head);
|
||||
|
||||
if (!list_empty(&node->plist.prio_list)) {
|
||||
struct mc_plist_node *next = mc_plist_first(&node->plist);
|
||||
|
||||
list_move_tail(&next->plist.prio_list, &node->plist.prio_list);
|
||||
list_del_init(&node->plist.prio_list);
|
||||
}
|
||||
|
||||
list_del_init(&node->plist.node_list);
|
||||
|
||||
mc_plist_check_head(head);
|
||||
}
|
||||
@ -2962,7 +2962,9 @@ static void kill_thread(unsigned long tid, int sig,
|
||||
}
|
||||
}
|
||||
|
||||
static long util_thread(struct thread_data_s *my_thread, unsigned long rp_rctx, int remote_tid, unsigned long pattr, unsigned long uti_clv, unsigned long _uti_desc)
|
||||
static long util_thread(struct thread_data_s *my_thread,
|
||||
unsigned long rp_rctx, int remote_tid, unsigned long pattr,
|
||||
unsigned long uti_info, unsigned long _uti_desc)
|
||||
{
|
||||
struct uti_get_ctx_desc get_ctx_desc;
|
||||
struct uti_switch_ctx_desc switch_ctx_desc;
|
||||
@ -3014,7 +3016,7 @@ static long util_thread(struct thread_data_s *my_thread, unsigned long rp_rctx,
|
||||
uti_desc->key = get_ctx_desc.key;
|
||||
uti_desc->pid = getpid();
|
||||
uti_desc->tid = gettid();
|
||||
uti_desc->uti_clv = uti_clv;
|
||||
uti_desc->uti_info = uti_info;
|
||||
|
||||
/* Initialize list of syscall arguments for syscall_intercept */
|
||||
if (sizeof(struct syscall_struct) * 11 > page_size) {
|
||||
@ -4823,7 +4825,8 @@ return_execve2:
|
||||
case __NR_sched_setaffinity:
|
||||
if (w.sr.args[0] == 0) {
|
||||
ret = util_thread(my_thread, w.sr.args[1], w.sr.rtid,
|
||||
w.sr.args[2], w.sr.args[3], w.sr.args[4]);
|
||||
w.sr.args[2], w.sr.args[3],
|
||||
w.sr.args[4]);
|
||||
}
|
||||
else {
|
||||
__eprintf("__NR_sched_setaffinity: invalid argument (%lx)\n", w.sr.args[0]);
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include <syscall.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/types.h> /* for pid_t in uprotocol.h */
|
||||
#include "../include/uprotocol.h"
|
||||
#include "../include/uti.h"
|
||||
#include "./archdep_uti.h"
|
||||
@ -76,7 +77,7 @@ hook(long syscall_number,
|
||||
uti_desc.syscall_stack[stack_top].args[3] = arg3;
|
||||
uti_desc.syscall_stack[stack_top].args[4] = arg4;
|
||||
uti_desc.syscall_stack[stack_top].args[5] = arg5;
|
||||
uti_desc.syscall_stack[stack_top].uti_clv = uti_desc.uti_clv;
|
||||
uti_desc.syscall_stack[stack_top].uti_info = uti_desc.uti_info;
|
||||
uti_desc.syscall_stack[stack_top].ret = -EINVAL;
|
||||
|
||||
ret = uti_syscall3(__NR_ioctl, uti_desc.fd,
|
||||
|
||||
Reference in New Issue
Block a user