110 lines
2.5 KiB
C
Raw Normal View History

2026-01-21 18:59:54 +08:00
// SPDX-License-Identifier: GPL-2.0
/*
* This file handles the architecture-dependent parts of process handling.
*/
#include <linux/sched/debug.h>
#include <linux/ptrace.h>
#include <linux/elfcore.h>
#include <linux/slab.h>
#include <linux/random.h>
#include <asm/fpu.h>
2026-01-29 22:25:33 +08:00
#include <asm/switch_to.h>
#include <asm/syscall.h>
2026-01-21 18:59:54 +08:00
#include "proto.h"
/*
* Re-start a thread when doing execve()
*/
void
start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp)
{
regs->pc = pc;
regs->ps = 8;
2026-01-29 22:25:33 +08:00
regs->regs[30] = sp;
2026-01-21 18:59:54 +08:00
}
EXPORT_SYMBOL(start_thread);
void
flush_thread(void)
{
/* Arrange for each exec'ed process to start off with a clean slate
* with respect to the FPU. This is all exceptions disabled.
*/
current_thread_info()->ieee_state = 0;
2026-01-29 22:25:33 +08:00
wrfpcr(FPCR_INIT | ieee_swcr_to_fpcr(0));
2026-01-21 18:59:54 +08:00
/* Clean slate for TLS. */
2026-01-29 22:25:33 +08:00
current_thread_info()->pcb.tp = 0;
2026-01-21 18:59:54 +08:00
}
void
release_thread(struct task_struct *dead_task)
{
}
2026-01-29 22:25:33 +08:00
int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
{
/*
* aux_save() has to read the current TLS pointer from CSR:TID as it
* may be out-of-sync with the saved value.
*/
aux_save(src);
*dst = *src;
return 0;
}
2026-01-21 18:59:54 +08:00
/*
* Copy architecture-specific thread state
*/
2026-01-29 22:25:33 +08:00
int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
2026-01-21 18:59:54 +08:00
{
2026-01-29 22:25:33 +08:00
unsigned long clone_flags = args->flags;
unsigned long usp = args->stack;
unsigned long tls = args->tls;
2026-01-21 18:59:54 +08:00
struct thread_info *childti = task_thread_info(p);
struct pt_regs *childregs = task_pt_regs(p);
struct pt_regs *regs = current_pt_regs();
2026-01-29 22:25:33 +08:00
extern void ret_from_fork(void);
extern void ret_from_kernel_thread(void);
p->thread.sp = (unsigned long) childregs;
2026-01-21 18:59:54 +08:00
2026-01-29 22:25:33 +08:00
if (unlikely(args->fn)) {
2026-01-21 18:59:54 +08:00
/* kernel thread */
2026-01-29 22:25:33 +08:00
memset(childregs, 0, sizeof(struct pt_regs));
p->thread.ra = (unsigned long) ret_from_kernel_thread;
p->thread.s[0] = (unsigned long) args->fn; /* function */
p->thread.s[1] = (unsigned long) args->fn_arg;
2026-01-21 18:59:54 +08:00
return 0;
}
2026-01-29 22:25:33 +08:00
2026-01-21 18:59:54 +08:00
/*
* Note: if CLONE_SETTLS is not set, then we must inherit the
* value from the parent, which will have been set by the block
* copy in dup_task_struct. This is non-intuitive, but is
* required for proper operation in the case of a threaded
* application calling fork.
*/
if (clone_flags & CLONE_SETTLS)
2026-01-29 22:25:33 +08:00
childti->pcb.tp = tls;
2026-01-21 18:59:54 +08:00
else
2026-01-29 22:25:33 +08:00
regs->regs[20] = 0;
2026-01-21 18:59:54 +08:00
*childregs = *regs;
2026-01-29 22:25:33 +08:00
if (usp)
childregs->regs[30] = usp;
syscall_set_return_value(NULL, childregs, 0, 0);
p->thread.ra = (unsigned long) ret_from_fork;
2026-01-21 18:59:54 +08:00
return 0;
}
unsigned long arch_randomize_brk(struct mm_struct *mm)
{
return randomize_page(mm->brk, 0x02000000);
}