Commit f2156ef3 authored by Mao Minkai's avatar Mao Minkai Committed by guzitao
Browse files

sw64: add process management

Sunway inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I8Y8CY



--------------------------------

Add process management support for SW64.

Signed-off-by: default avatarMao Minkai <maominkai@wxiat.com>
Reviewed-by: default avatarHe Sheng <hesheng@wxiat.com>
Signed-off-by: default avatarGu Zitao <guzitao@wxiat.com>
parent f4d99970
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_SW64_CURRENT_H
#define _ASM_SW64_CURRENT_H

#ifndef __ASSEMBLY__

struct task_struct;
static __always_inline struct task_struct *get_current(void)
{
	register struct task_struct *tp __asm__("$8");

	return tp;
}

#define current get_current()

#endif /* __ASSEMBLY__ */

#endif /* _ASM_SW64_CURRENT_H */
+100 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * include/asm-sw64/processor.h
 *
 * Copyright (C) 1994 Linus Torvalds
 */

#ifndef _ASM_SW64_PROCESSOR_H
#define _ASM_SW64_PROCESSOR_H

#include <linux/personality.h>	/* for ADDR_LIMIT_32BIT */
#include <asm/ptrace.h>

#define task_pt_regs(task) \
	((struct pt_regs *) (task->stack + THREAD_SIZE) - 1)

/*
 * Returns current instruction pointer ("program counter").
 */
#define current_text_addr() \
	({ void *__pc; __asm__ ("br %0, .+4" : "=r"(__pc)); __pc; })

/*
 * SW64 does have an arch_pick_mmap_layout()
 */
#define HAVE_ARCH_PICK_MMAP_LAYOUT 1

/*
 * We have a 52-bit user address space: 4PB user VM...
 */
#define TASK_SIZE (0x10000000000000UL)
#define UNMAPPED_BASE (TASK_SIZE >> 6)
#define STACK_TOP \
	(current->personality & ADDR_LIMIT_32BIT ? 0x80000000 : 0x00120000000UL)

#define STACK_TOP_MAX	0x00120000000UL

/* This decides where the kernel will search for a free chunk of vm
 * space during mmap's.
 */
#define TASK_UNMAPPED_BASE \
	((current->personality & ADDR_LIMIT_32BIT) ? 0x40000000 : UNMAPPED_BASE)

struct thread_struct {
	struct user_fpsimd_state fpstate;
	/* Callee-saved registers */
	unsigned long ra;
	unsigned long sp;
	unsigned long s[7];	/* s0 ~ s6 */
};
#define INIT_THREAD  { }

struct task_struct;
struct pt_regs;

/* Do necessary setup to start up a newly executed thread.  */
extern void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp);

/* Free all resources held by a thread. */
extern void release_thread(struct task_struct *dead_task);

unsigned long __get_wchan(struct task_struct *p);

#define KSTK_EIP(tsk) (task_pt_regs(tsk)->pc)

#define KSTK_ESP(tsk) (task_pt_regs(tsk)->regs[30])

#define cpu_relax()	barrier()

#define ARCH_HAS_PREFETCH
#define ARCH_HAS_PREFETCHW
#define ARCH_HAS_SPINLOCK_PREFETCH

#ifndef CONFIG_SMP
/* Nothing to prefetch. */
#define spin_lock_prefetch(lock)	do { } while (0)
#endif

static inline void prefetch(const void *ptr)
{
	__builtin_prefetch(ptr, 0, 3);
}

static inline void prefetchw(const void *ptr)
{
	__builtin_prefetch(ptr, 1, 3);
}

#ifdef CONFIG_SMP
static inline void spin_lock_prefetch(const void *ptr)
{
	__builtin_prefetch(ptr, 1, 3);
}
#endif

static inline void wait_for_interrupt(void)
{
	__asm__ __volatile__ ("halt");
}
#endif /* _ASM_SW64_PROCESSOR_H */
+92 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_SW64_PTRACE_H
#define _ASM_SW64_PTRACE_H

#include <uapi/asm/ptrace.h>
#include <asm/hmcall.h>
#include <asm/page.h>

#define NO_SYSCALL	_AC(-1, UL)

#ifdef __KERNEL__
#ifndef __ASSEMBLY__

/*
 * This struct defines the way the registers are stored on the
 * kernel stack during a system call or other kernel entry
 */

struct pt_regs {
	union {
		struct user_pt_regs user_regs;
		struct {
			unsigned long regs[31];
			unsigned long pc;
			unsigned long ps;
		};
	};
	unsigned long orig_r0;
	unsigned long orig_r19;
	/* These are saved by HMcode: */
	unsigned long hm_ps;
	unsigned long hm_pc;
	unsigned long hm_gp;
	unsigned long hm_r16;
	unsigned long hm_r17;
	unsigned long hm_r18;
};

#define arch_has_single_step()		(1)
#define user_mode(regs) (((regs)->ps & 8) != 0)
#define instruction_pointer(regs) ((regs)->pc)
#define profile_pc(regs) instruction_pointer(regs)
#define user_stack_pointer(pt_regs) ((pt_regs)->regs[30])
#define kernel_stack_pointer(regs) ((unsigned long)((regs) + 1))
#define instruction_pointer_set(regs, val) ((regs)->pc = val)

#define force_successful_syscall_return() (current_pt_regs()->orig_r0 = NO_SYSCALL)

#define MAX_REG_OFFSET (offsetof(struct pt_regs, orig_r0))

extern short regoffsets[];

extern unsigned long syscall_trace_enter(void);
extern void syscall_trace_leave(void);

/**
 * regs_get_register() - get register value from its offset
 * @regs:       pt_regs from which register value is gotten
 * @offset:     offset of the register.
 *
 * regs_get_register returns the value of a register whose offset from @regs.
 * The @offset is the offset of the register in struct pt_regs.
 * If @offset is bigger than MAX_REG_OFFSET, this returns 0.
 */
static inline u64 regs_get_register(struct pt_regs *regs, unsigned int offset)
{
	if (unlikely(offset > MAX_REG_OFFSET))
		return 0;

	return *(unsigned long *)((unsigned long)regs + offset);
}
extern int regs_query_register_offset(const char *name);
extern unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
					       unsigned int n);

static inline int is_syscall_success(struct pt_regs *regs)
{
	return !regs->regs[19];
}

static inline long regs_return_value(struct pt_regs *regs)
{
	if ((regs->orig_r0 == NO_SYSCALL) || is_syscall_success(regs))
		return regs->regs[0];
	else
		return -regs->regs[0];
}

#endif /* !__ASSEMBLY__ */
#endif /* __KERNEL__ */

#endif /* _ASM_SW64_PTRACE_H */
+60 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_SW64_SWITCH_TO_H
#define _ASM_SW64_SWITCH_TO_H

#include <linux/sched.h>

extern void __fpstate_save(struct task_struct *save_to);
extern void __fpstate_restore(struct task_struct *restore_from);
extern struct task_struct *__switch_to(struct task_struct *prev,
				       struct task_struct *next);
extern void restore_da_match_after_sched(void);

static inline void aux_save(struct task_struct *task)
{
	struct pcb_struct *pcb;

	if (likely(!(task->flags & PF_KTHREAD))) {
		pcb = &task_thread_info(task)->pcb;
		pcb->tp = rtid();
		__fpstate_save(task);
	}
}

static inline void aux_restore(struct task_struct *task)
{
	struct pcb_struct *pcb;

	if (likely(!(task->flags & PF_KTHREAD))) {
		pcb = &task_thread_info(task)->pcb;
		wrtp(pcb->tp);
		__fpstate_restore(task);
	}
}

static inline void __switch_to_aux(struct task_struct *prev,
				   struct task_struct *next)
{
	aux_save(prev);
	aux_restore(next);
}


#define switch_to(prev, next, last)					\
do {									\
	struct task_struct *__prev = (prev);				\
	struct task_struct *__next = (next);				\
	__switch_to_aux(__prev, __next);				\
	(last) = __switch_to(__prev, __next);				\
} while (0)


/* TODO: finish_arch_switch has been removed from arch-independent code. */

/*
 * finish_arch_switch will be called after switch_to
 */
#define finish_arch_post_lock_switch		restore_da_match_after_sched


#endif /* _ASM_SW64_SWITCH_TO_H */
+148 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_SW64_THREAD_INFO_H
#define _ASM_SW64_THREAD_INFO_H

#ifdef __KERNEL__

#ifndef __ASSEMBLY__
#include <asm/types.h>
#include <asm/sysinfo.h>

typedef struct {
	unsigned long seg;
} mm_segment_t;


struct pcb_struct {
	unsigned long tp;
	unsigned long da_match, da_mask;
	unsigned long dv_match, dv_mask;
	union {
		unsigned long dc_ctl;
		unsigned long match_ctl;
	};
	unsigned long ia_match, ia_mask;
	unsigned long iv_match;
	unsigned long ida_match, ida_mask;
};

struct thread_info {
	struct pcb_struct	pcb;		/* hmcode state */

	unsigned int		flags;		/* low level flags */
	unsigned int		ieee_state;	/* see fpu.h */

	mm_segment_t		addr_limit;	/* thread address space */
	unsigned int		cpu;		/* current CPU */
	int			preempt_count;	/* 0 => preemptible, <0 => BUG */
	unsigned int		status;		/* thread-synchronous flags */

	int bpt_nsaved;
	unsigned long bpt_addr[2];		/* breakpoint handling  */
	unsigned int bpt_insn[2];
#ifdef CONFIG_DYNAMIC_FTRACE
	unsigned long		dyn_ftrace_addr;
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
	unsigned long		dyn_ftrace_regs_addr;
#endif
#endif
};

static __always_inline u64 rtid(void)
{
	u64 val;

	asm volatile("rtid %0" : "=r" (val) : :);
	return val;
}

/*
 * Macros/functions for gaining access to the thread information structure.
 */
#define INIT_THREAD_INFO(tsk)				\
{							\
	.addr_limit	= KERNEL_DS,			\
	.preempt_count	= INIT_PREEMPT_COUNT,		\
}


#endif /* __ASSEMBLY__ */

/* Thread information allocation.  */
#define THREAD_SIZE_ORDER	1
#define THREAD_SIZE		(2 * PAGE_SIZE)

/*
 * Thread information flags:
 * - these are process state flags and used from assembly
 * - pending work-to-be-done flags come first and must be assigned to be
 *   within bits 0 to 7 to fit in and immediate operand.
 *
 * TIF_SYSCALL_TRACE is known to be 0 via blbs.
 */
#define TIF_SYSCALL_TRACE	0	/* syscall trace active */
#define TIF_NOTIFY_RESUME	1	/* callback before returning to user */
#define TIF_SIGPENDING		2	/* signal pending */
#define TIF_NEED_RESCHED	3	/* rescheduling necessary */
#define TIF_SYSCALL_AUDIT	4       /* syscall audit active */
#define TIF_UPROBE		5       /* uprobe breakpoint or singlestep */
#define TIF_PATCH_PENDING       6       /* pending live patching update */
#define TIF_NOTIFY_SIGNAL	7	/* signal notifications exist */
#define TIF_DIE_IF_KERNEL	9	/* dik recursion lock */
#define TIF_SYSCALL_TRACEPOINT	10
#define TIF_SECCOMP		11	/* secure computing */
#define TIF_MEMDIE		13	/* is terminating due to OOM killer */
#define TIF_POLLING_NRFLAG	14      /* idle is polling for TIF_NEED_RESCHED */

#define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
#define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
#define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
#define _TIF_PATCH_PENDING      (1 << TIF_PATCH_PENDING)
#define _TIF_SYSCALL_AUDIT	(1 << TIF_SYSCALL_AUDIT)
#define _TIF_POLLING_NRFLAG	(1 << TIF_POLLING_NRFLAG)
#define _TIF_SECCOMP		(1 << TIF_SECCOMP)
#define _TIF_SYSCALL_TRACEPOINT	(1 << TIF_SYSCALL_TRACEPOINT)
#define _TIF_UPROBE		(1 << TIF_UPROBE)
#define _TIF_NOTIFY_SIGNAL	(1 << TIF_NOTIFY_SIGNAL)

/* Work to do on interrupt/exception return.  */
#define _TIF_WORK_MASK		(_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
				 _TIF_NOTIFY_RESUME | _TIF_UPROBE | \
				 _TIF_PATCH_PENDING | _TIF_NOTIFY_SIGNAL)

#define _TIF_SYSCALL_WORK	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
				 _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP)

/* Work to do on any return to userspace.  */
#define _TIF_ALLWORK_MASK	(_TIF_WORK_MASK	| _TIF_SYSCALL_TRACE)

#define TS_UAC_NOPRINT		0x0001	/* ! Preserve the following three */
#define TS_UAC_NOFIX		0x0002	/* ! flags as they match          */
#define TS_UAC_SIGBUS		0x0004	/* ! userspace part of 'prctl' */

#define SET_UNALIGN_CTL(task, value)	({				\
	__u32 status = task_thread_info(task)->status & ~UAC_BITMASK;	\
	if (value & PR_UNALIGN_NOPRINT)					\
		status |= TS_UAC_NOPRINT;				\
	if (value & PR_UNALIGN_SIGBUS)					\
		status |= TS_UAC_SIGBUS;				\
	if (value & PR_NOFIX)	/* sw-specific */			\
		status |= TS_UAC_NOFIX;					\
	task_thread_info(task)->status = status;			\
	0; })

#define GET_UNALIGN_CTL(task, value)	({				\
	__u32 status = task_thread_info(task)->status & ~UAC_BITMASK;	\
	__u32 res = 0;							\
	if (status & TS_UAC_NOPRINT)					\
		res |= PR_UNALIGN_NOPRINT;				\
	if (status & TS_UAC_SIGBUS)					\
		res |= PR_UNALIGN_SIGBUS;				\
	if (status & TS_UAC_NOFIX)					\
		res |= PR_NOFIX;					\
	put_user(res, (int __user *)(value));				\
	})

#endif /* __KERNEL__ */
#endif /* _ASM_SW64_THREAD_INFO_H */
Loading