Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 02ce496f authored by Al Viro's avatar Al Viro
Browse files

frv: split ret_from_fork, simplify kernel_thread() a lot

parent d878d6da
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -7,7 +7,7 @@ heads-$(CONFIG_MMU) := head-mmu-fr451.o

extra-y:= head.o vmlinux.lds

obj-y := $(heads-y) entry.o entry-table.o break.o switch_to.o kernel_thread.o \
obj-y := $(heads-y) entry.o entry-table.o break.o switch_to.o \
	 kernel_execve.o process.o traps.o ptrace.o signal.o dma.o \
	 sys_frv.o time.o setup.o frv_ksyms.o \
	 debug-stub.o irq.o sleep.o uaccess.o
+8 −0
Original line number Diff line number Diff line
@@ -863,6 +863,14 @@ ret_from_fork:
	setlos.p	#0,gr8
	bra		__syscall_exit

	.globl		ret_from_kernel_thread
ret_from_kernel_thread:
	lddi.p		@(gr28,#REG_GR(8)),gr20
	call		schedule_tail
	or.p		gr20,gr20,gr8
	calll		@(gr21,gr0)
	bra		sys_exit

###################################################################################################
#
# Return to user mode is not as complex as all this looks,
+0 −1
Original line number Diff line number Diff line
@@ -30,7 +30,6 @@ EXPORT_SYMBOL(ip_fast_csum);
EXPORT_SYMBOL(local_irq_count);
EXPORT_SYMBOL(local_bh_count);
#endif
EXPORT_SYMBOL(kernel_thread);

EXPORT_SYMBOL(__res_bus_clock_speed_HZ);
EXPORT_SYMBOL(__page_offset);

arch/frv/kernel/kernel_thread.S

deleted100644 → 0
+0 −77
Original line number Diff line number Diff line
/* kernel_thread.S: kernel thread creation
 *
 * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
 * Written by David Howells (dhowells@redhat.com)
 *
 * 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; either version
 * 2 of the License, or (at your option) any later version.
 */

#include <linux/linkage.h>
#include <linux/kern_levels.h>
#include <asm/unistd.h>

#define CLONE_VM	0x00000100	/* set if VM shared between processes */

	.section .rodata
kernel_thread_emsg:
	.asciz	KERN_ERR "failed to create kernel thread: error=%d\n"

	.text
	.balign		4

###############################################################################
#
# Create a kernel thread
#
# int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
#
###############################################################################
	.globl		kernel_thread
	.type		kernel_thread,@function
kernel_thread:
	or.p		gr8,gr0,gr4
	or		gr9,gr0,gr5

	# start by forking the current process, but with shared VM
	setlos.p	#__NR_clone,gr7		; syscall number
	ori		gr10,#CLONE_VM,gr8	; first syscall arg	[clone_flags]
	sethi.p		#0xe4e4,gr9		; second syscall arg	[newsp]
	setlo		#0xe4e4,gr9
	setlos.p	#0,gr10			; third syscall arg	[parent_tidptr]
	setlos		#0,gr11			; fourth syscall arg	[child_tidptr]
	tira		gr0,#0
	setlos.p	#4095,gr7
	andcc		gr8,gr8,gr0,icc0
	addcc.p		gr8,gr7,gr0,icc1
	bnelr		icc0,#2
	bc		icc1,#0,kernel_thread_error

	# now invoke the work function
	or		gr5,gr0,gr8
	calll		@(gr4,gr0)

	# and finally exit the thread
	setlos		#__NR_exit,gr7		; syscall number
	tira		gr0,#0

kernel_thread_error:
	subi		sp,#8,sp
	movsg		lr,gr4
	sti		gr8,@(sp,#0)
	sti.p		gr4,@(sp,#4)

	or		gr8,gr0,gr9
	sethi.p		%hi(kernel_thread_emsg),gr8
	setlo		%lo(kernel_thread_emsg),gr8

	call		printk

	ldi		@(sp,#4),gr4
	ldi		@(sp,#0),gr8
	subi		sp,#8,sp
	jmpl		@(gr4,gr0)

	.size		kernel_thread,.-kernel_thread
+23 −21
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@
#include "local.h"

asmlinkage void ret_from_fork(void);
asmlinkage void ret_from_kernel_thread(void);

#include <asm/pgalloc.h>

@@ -172,29 +173,21 @@ int copy_thread(unsigned long clone_flags,
		unsigned long usp, unsigned long topstk,
		struct task_struct *p, struct pt_regs *regs)
{
	struct pt_regs *childregs0, *childregs, *regs0;
	struct pt_regs *childregs;

	regs0 = __kernel_frame0_ptr;
	childregs0 = (struct pt_regs *)
	childregs = (struct pt_regs *)
		(task_stack_page(p) + THREAD_SIZE - FRV_FRAME0_SIZE);
	childregs = childregs0;

	/* set up the userspace frame (the only place that the USP is stored) */
	*childregs0 = *regs0;
	*childregs = *regs;

	childregs0->gr8		= 0;
	childregs0->sp		= usp;
	childregs0->next_frame	= NULL;
	childregs->sp		= usp;
	childregs->next_frame	= NULL;

	/* set up the return kernel frame if called from kernel_thread() */
	if (regs != regs0) {
		childregs--;
		*childregs = *regs;
		childregs->sp = (unsigned long) childregs0;
		childregs->next_frame = childregs0;
		childregs->gr15 = (unsigned long) task_thread_info(p);
		childregs->gr29 = (unsigned long) p;
	}
	if (unlikely(!user_mode(regs)))
		p->thread.pc = (unsigned long) ret_from_kernel_thread;
	else
		p->thread.pc = (unsigned long) ret_from_fork;

	p->set_child_tid = p->clear_child_tid = NULL;

@@ -203,8 +196,7 @@ int copy_thread(unsigned long clone_flags,
	p->thread.sp	 = (unsigned long) childregs;
	p->thread.fp	 = 0;
	p->thread.lr	 = 0;
	p->thread.pc	 = (unsigned long) ret_from_fork;
	p->thread.frame0 = childregs0;
	p->thread.frame0 = childregs;

	/* the new TLS pointer is passed in as arg #5 to sys_clone() */
	if (clone_flags & CLONE_SETTLS)
@@ -347,3 +339,13 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
	       sizeof(current->thread.user->f));
	return 1;
}

int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
{
	struct pt_regs regs = {
		.gr8 = (unsigned long)arg;
		.gr9 = (unsigned long)fn;
		.psr = PSR_S;
	};
	return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
}