From 7db91e57a0acde126a162ababfb1e0ab190130cb Mon Sep 17 00:00:00 2001 From: Palmer Dabbelt Date: Mon, 10 Jul 2017 18:04:30 -0700 Subject: RISC-V: Task implementation This patch contains the implementation of tasks on RISC-V, most of which is involved in task switching. Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/asm-offsets.h | 1 + arch/riscv/include/asm/current.h | 45 +++++++++++++++++ arch/riscv/include/asm/kprobes.h | 22 ++++++++ arch/riscv/include/asm/processor.h | 97 ++++++++++++++++++++++++++++++++++++ arch/riscv/include/asm/switch_to.h | 69 +++++++++++++++++++++++++ arch/riscv/include/asm/thread_info.h | 94 ++++++++++++++++++++++++++++++++++ 6 files changed, 328 insertions(+) create mode 100644 arch/riscv/include/asm/asm-offsets.h create mode 100644 arch/riscv/include/asm/current.h create mode 100644 arch/riscv/include/asm/kprobes.h create mode 100644 arch/riscv/include/asm/processor.h create mode 100644 arch/riscv/include/asm/switch_to.h create mode 100644 arch/riscv/include/asm/thread_info.h (limited to 'arch/riscv/include/asm') diff --git a/arch/riscv/include/asm/asm-offsets.h b/arch/riscv/include/asm/asm-offsets.h new file mode 100644 index 000000000000..d370ee36a182 --- /dev/null +++ b/arch/riscv/include/asm/asm-offsets.h @@ -0,0 +1 @@ +#include diff --git a/arch/riscv/include/asm/current.h b/arch/riscv/include/asm/current.h new file mode 100644 index 000000000000..2cf6336ef600 --- /dev/null +++ b/arch/riscv/include/asm/current.h @@ -0,0 +1,45 @@ +/* + * Based on arm/arm64/include/asm/current.h + * + * Copyright (C) 2016 ARM + * Copyright (C) 2017 SiFive + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +#ifndef __ASM_CURRENT_H +#define __ASM_CURRENT_H + +#include +#include + +#ifndef __ASSEMBLY__ + +struct task_struct; + +/* + * This only works because "struct thread_info" is at offset 0 from "struct + * task_struct". This constraint seems to be necessary on other architectures + * as well, but __switch_to enforces it. We can't check TASK_TI here because + * includes this, and I can't get the definition of "struct + * task_struct" here due to some header ordering problems. + */ +static __always_inline struct task_struct *get_current(void) +{ + register struct task_struct *tp __asm__("tp"); + return tp; +} + +#define current get_current() + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_CURRENT_H */ diff --git a/arch/riscv/include/asm/kprobes.h b/arch/riscv/include/asm/kprobes.h new file mode 100644 index 000000000000..c7eb010d1528 --- /dev/null +++ b/arch/riscv/include/asm/kprobes.h @@ -0,0 +1,22 @@ +/* + * Copied from arch/arm64/include/asm/kprobes.h + * + * Copyright (C) 2013 Linaro Limited + * Copyright (C) 2017 SiFive + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _RISCV_KPROBES_H +#define _RISCV_KPROBES_H + +#include + +#endif /* _RISCV_KPROBES_H */ diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h new file mode 100644 index 000000000000..3fe4af8147d2 --- /dev/null +++ b/arch/riscv/include/asm/processor.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2012 Regents of the University of California + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _ASM_RISCV_PROCESSOR_H +#define _ASM_RISCV_PROCESSOR_H + +#include + +#include + +/* + * This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +#define TASK_UNMAPPED_BASE PAGE_ALIGN(TASK_SIZE >> 1) + +#define STACK_TOP TASK_SIZE +#define STACK_TOP_MAX STACK_TOP +#define STACK_ALIGN 16 + +#ifndef __ASSEMBLY__ + +struct task_struct; +struct pt_regs; + +/* + * Default implementation of macro that returns current + * instruction pointer ("program counter"). + */ +#define current_text_addr() ({ __label__ _l; _l: &&_l; }) + +/* CPU-specific state of a task */ +struct thread_struct { + /* Callee-saved registers */ + unsigned long ra; + unsigned long sp; /* Kernel mode stack */ + unsigned long s[12]; /* s[0]: frame pointer */ + struct __riscv_d_ext_state fstate; +}; + +#define INIT_THREAD { \ + .sp = sizeof(init_stack) + (long)&init_stack, \ +} + +#define task_pt_regs(tsk) \ + ((struct pt_regs *)(task_stack_page(tsk) + THREAD_SIZE \ + - ALIGN(sizeof(struct pt_regs), STACK_ALIGN))) + +#define KSTK_EIP(tsk) (task_pt_regs(tsk)->sepc) +#define KSTK_ESP(tsk) (task_pt_regs(tsk)->sp) + + +/* 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. */ +static inline void release_thread(struct task_struct *dead_task) +{ +} + +extern unsigned long get_wchan(struct task_struct *p); + + +static inline void cpu_relax(void) +{ +#ifdef __riscv_muldiv + int dummy; + /* In lieu of a halt instruction, induce a long-latency stall. */ + __asm__ __volatile__ ("div %0, %0, zero" : "=r" (dummy)); +#endif + barrier(); +} + +static inline void wait_for_interrupt(void) +{ + __asm__ __volatile__ ("wfi"); +} + +struct device_node; +extern int riscv_of_processor_hart(struct device_node *node); + +extern void riscv_fill_hwcap(void); + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_RISCV_PROCESSOR_H */ diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h new file mode 100644 index 000000000000..dd6b05bff75b --- /dev/null +++ b/arch/riscv/include/asm/switch_to.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2012 Regents of the University of California + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _ASM_RISCV_SWITCH_TO_H +#define _ASM_RISCV_SWITCH_TO_H + +#include +#include +#include + +extern void __fstate_save(struct task_struct *save_to); +extern void __fstate_restore(struct task_struct *restore_from); + +static inline void __fstate_clean(struct pt_regs *regs) +{ + regs->sstatus |= (regs->sstatus & ~(SR_FS)) | SR_FS_CLEAN; +} + +static inline void fstate_save(struct task_struct *task, + struct pt_regs *regs) +{ + if ((regs->sstatus & SR_FS) == SR_FS_DIRTY) { + __fstate_save(task); + __fstate_clean(regs); + } +} + +static inline void fstate_restore(struct task_struct *task, + struct pt_regs *regs) +{ + if ((regs->sstatus & SR_FS) != SR_FS_OFF) { + __fstate_restore(task); + __fstate_clean(regs); + } +} + +static inline void __switch_to_aux(struct task_struct *prev, + struct task_struct *next) +{ + struct pt_regs *regs; + + regs = task_pt_regs(prev); + if (unlikely(regs->sstatus & SR_SD)) + fstate_save(prev, regs); + fstate_restore(next, task_pt_regs(next)); +} + +extern struct task_struct *__switch_to(struct task_struct *, + struct task_struct *); + +#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) + +#endif /* _ASM_RISCV_SWITCH_TO_H */ diff --git a/arch/riscv/include/asm/thread_info.h b/arch/riscv/include/asm/thread_info.h new file mode 100644 index 000000000000..22c3536ed281 --- /dev/null +++ b/arch/riscv/include/asm/thread_info.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2009 Chen Liqin + * Copyright (C) 2012 Regents of the University of California + * Copyright (C) 2017 SiFive + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _ASM_RISCV_THREAD_INFO_H +#define _ASM_RISCV_THREAD_INFO_H + +#include +#include + +/* thread information allocation */ +#define THREAD_SIZE_ORDER (1) +#define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) + +#ifndef __ASSEMBLY__ + +#include +#include + +typedef unsigned long mm_segment_t; + +/* + * low level task data that entry.S needs immediate access to + * - this struct should fit entirely inside of one cache line + * - if the members of this struct changes, the assembly constants + * in asm-offsets.c must be updated accordingly + * - thread_info is included in task_struct at an offset of 0. This means that + * tp points to both thread_info and task_struct. + */ +struct thread_info { + unsigned long flags; /* low level flags */ + int preempt_count; /* 0=>preemptible, <0=>BUG */ + mm_segment_t addr_limit; + /* + * These stack pointers are overwritten on every system call or + * exception. SP is also saved to the stack it can be recovered when + * overwritten. + */ + long kernel_sp; /* Kernel stack pointer */ + long user_sp; /* User stack pointer */ + int cpu; +}; + +/* + * macros/functions for gaining access to the thread information structure + * + * preempt_count needs to be 1 initially, until the scheduler is functional. + */ +#define INIT_THREAD_INFO(tsk) \ +{ \ + .flags = 0, \ + .preempt_count = INIT_PREEMPT_COUNT, \ + .addr_limit = KERNEL_DS, \ +} + +#define init_stack (init_thread_union.stack) + +#endif /* !__ASSEMBLY__ */ + +/* + * thread information flags + * - these are process state flags that various assembly files may need to + * access + * - pending work-to-be-done flags are in lowest half-word + * - other flags in upper half-word(s) + */ +#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_RESTORE_SIGMASK 4 /* restore signal mask in do_signal() */ +#define TIF_MEMDIE 5 /* is terminating due to OOM killer */ +#define TIF_SYSCALL_TRACEPOINT 6 /* syscall tracepoint instrumentation */ + +#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) +#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) +#define _TIF_SIGPENDING (1 << TIF_SIGPENDING) +#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) + +#define _TIF_WORK_MASK \ + (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | _TIF_NEED_RESCHED) + +#endif /* _ASM_RISCV_THREAD_INFO_H */ -- cgit v1.2.3