qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] SPARC user mode multithread
@ 2009-11-03 20:03 David Munday
  2009-11-03 20:41 ` Blue Swirl
  0 siblings, 1 reply; 9+ messages in thread
From: David Munday @ 2009-11-03 20:03 UTC (permalink / raw)
  To: qemu-devel

Hello,
I am trying to run the blackscholes program from the PARSEC2.1 benchmark suite in QEMU SPARC user mode.
In this case I am trying to run with just 2 threads. Unfortunately, when I try to run the program it hangs with the following prints:

HELPME: /mada/users/cromom/ESESC_PROJECT/esesc/emul/qemu1/target-sparc/cpu.h:516
HELPME: /mada/users/cromom/ESESC_PROJECT/esesc/emul/qemu1/target-sparc/cpu.h:516


I also turned on the print_syscall prints and have the attached the debugging output below.
This problem can be reproduced by running the following command from within the blackscholes sparc-linux directory(which I can provide) referencing the local qemu installation:

/qemu/sparc-linux-user/qemu-sparc blackscholes 2 input_file output_file

Thank you for your help,
David


TARGET SPARC
calling cpu_loop
INSIDE CPU_LOOP
23738 uname(0x4007eac2)no need to transcode

23738 brk(NULL)23738 brk(0x000e4c60)

23738 brk(0x00105c60)

23738 brk(0x00106000)

23738 getpid(1,568056,0,-2139062144,1074260345,1644167168)

23738 rt_sigaction(32,1074259708,0,132136,8,0)

23738 rt_sigaction(33,1074259708,0,132136,8,0)
23738 rt_sigaction(34,1074259708,0,132136,8,0)
23738 rt_sigprocmask(1,1074260128,0,8,8,0)
23738 rt_sigprocmask(2,1074260128,0,8,8,0)
23738 fstat64(16777216,0x4007e7b8)
23738 mmap(NULL,2097152,0x3000000,0x22000000,-1,0)
23738 write(1,0x40081000,35)
PARSEC Benchmark Suite Version 2.1

23738 open("david_input",O_RDONLY)
23738 fstat64(50331648,0x4007e5a8)
23738 mmap(NULL,2097152,0x3000000,0x22000000,-1,0)
23738 read(3,0x40083000,4096)
23738 write(1,0x40081000,81)
23738 close(3)
23738 munmap(0x40083000,2097152)
23738 write(1,0x40081000,18)
Num of Options: 1

23738 write(1,0x40081000,17)
Num of Runs: 100

23738 write(1,0x40081000,17)
Size of data: 40

23738 getrlimit(3,1074259752,17,-1033270193,10,940624)
23738 pipe(1074260160,0,1074260160,0,16,4)
23738 clone(3840,949056,24,192148,0,940624)calling do_fork 4
calling cpu_clone_regs
HELPME: /mada/users/cromom/ESESC_PROJECT/esesc/emul/qemu1/target-sparc/cpu.h:516
got out of cpu_clone_regs

got out of errno
23738 rt_sigprocmask(4,1074259528,0,8,-1,-1)
23738 read(0,0x4007e5b4,148)INSIDE CPU_LOOP
23739 clone(951200,949056,650240,1074259380,666624,940624)calling do_fork 4
calling cpu_clone_regs
HELPME: /mada/users/cromom/ESESC_PROJECT/esesc/emul/qemu1/target-sparc/cpu.h:516
got out of cpu_clone_regs

got out of errno
23739 close(0)
23739 close(0)
23739 open("david_output",O_RDONLY|O_CREAT|O_TRUNC|0x1)
23739 fstat64(0,0x4007e1b0)
23739 mmap(NULL,2097152,0x3000000,0x22000000,-1,0)
23739 write(0,0x40085000,23)
23739 close(0)
23739 munmap(0x40085000,2097152)
23739 write(0,0x4007e95c,148)
23739 rt_sigprocmask(4,0,1074260080,8,572073,952256)
23739 rt_sigsuspend(1074260080,8,1074260080,8,572073,952256)INSIDE RT SIGSUSPEND

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] SPARC user mode multithread
  2009-11-03 20:03 David Munday
@ 2009-11-03 20:41 ` Blue Swirl
  0 siblings, 0 replies; 9+ messages in thread
From: Blue Swirl @ 2009-11-03 20:41 UTC (permalink / raw)
  To: David Munday; +Cc: qemu-devel

On Tue, Nov 3, 2009 at 10:03 PM, David Munday <cromom@soe.ucsc.edu> wrote:
> Hello,
> I am trying to run the blackscholes program from the PARSEC2.1 benchmark suite in QEMU SPARC user mode.
> In this case I am trying to run with just 2 threads. Unfortunately, when I try to run the program it hangs with the following prints:
>
> HELPME: /mada/users/cromom/ESESC_PROJECT/esesc/emul/qemu1/target-sparc/cpu.h:516
> HELPME: /mada/users/cromom/ESESC_PROJECT/esesc/emul/qemu1/target-sparc/cpu.h:516

It means that someone should figure out what Linux/Sparc does to
registers, register windows and processor flags when doing "clone".
The fix should be trivial.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] SPARC user mode multithread
       [not found] <1010833181.2491521257452944973.JavaMail.root@mail-01.cse.ucsc.edu>
@ 2009-11-05 20:29 ` David Munday
  2009-11-06 18:31   ` Blue Swirl
  0 siblings, 1 reply; 9+ messages in thread
From: David Munday @ 2009-11-05 20:29 UTC (permalink / raw)
  To: Blue Swirl; +Cc: qemu-devel

Hi,
I found the Linux/Sparc clone operations in copy_thread() from process32.c (attached)

I tried modifying cpu_clone_regs with the following code per the Sparc/linux routines, but qemu still stalls on signal suspend.

It seems like it should only need to set the stack pointer and the return addresses for the child and parent processes, but it's clearly missing something.

Is there more to this fix than these two assignments?

static inline void cpu_clone_regs(CPUState *PARENT_env, CPUState *child_env, target_ulong newsp)
{
    if (newsp)
    {
     child_env->regwptr[14] = newsp; //changed to 14 per process32.c DM
 	 //env->regwptr[22] = newsp;
     printf("setting stack pointer\n");
    }
    child_env->regwptr[0] = 0;
    child_env->regwptr[1] = 1; //added per process32.c in kernel for sparc
    parent_env->regwptr[1] = 0;  //make parent return value = 0  per process32.c in kernel for sparc}
}

Thanks,
David


----- Original Message -----
From: "Blue Swirl" <blauwirbel@gmail.com>
To: "David Munday" <cromom@soe.ucsc.edu>
Cc: qemu-devel@nongnu.org
Sent: Tuesday, November 3, 2009 12:41:04 PM GMT -08:00 US/Canada Pacific
Subject: Re: [Qemu-devel] SPARC user mode multithread

On Tue, Nov 3, 2009 at 10:03 PM, David Munday <cromom@soe.ucsc.edu> wrote:
> Hello,
> I am trying to run the blackscholes program from the PARSEC2.1 benchmark suite in QEMU SPARC user mode.
> In this case I am trying to run with just 2 threads. Unfortunately, when I try to run the program it hangs with the following prints:
>
> HELPME: /mada/users/cromom/ESESC_PROJECT/esesc/emul/qemu1/target-sparc/cpu.h:516
> HELPME: /mada/users/cromom/ESESC_PROJECT/esesc/emul/qemu1/target-sparc/cpu.h:516

It means that someone should figure out what Linux/Sparc does to
registers, register windows and processor flags when doing "clone".
The fix should be trivial.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] SPARC user mode multithread
  2009-11-05 20:29 ` David Munday
@ 2009-11-06 18:31   ` Blue Swirl
  0 siblings, 0 replies; 9+ messages in thread
From: Blue Swirl @ 2009-11-06 18:31 UTC (permalink / raw)
  To: David Munday; +Cc: qemu-devel

On Thu, Nov 5, 2009 at 10:29 PM, David Munday <cromom@soe.ucsc.edu> wrote:
> Hi,
> I found the Linux/Sparc clone operations in copy_thread() from process32.c (attached)

Forgot to attach?

> I tried modifying cpu_clone_regs with the following code per the Sparc/linux routines, but qemu still stalls on signal suspend.
>
> It seems like it should only need to set the stack pointer and the return addresses for the child and parent processes, but it's clearly missing something.
>
> Is there more to this fix than these two assignments?
>
> static inline void cpu_clone_regs(CPUState *PARENT_env, CPUState *child_env, target_ulong newsp)
> {
>    if (newsp)
>    {
>     child_env->regwptr[14] = newsp; //changed to 14 per process32.c DM
>         //env->regwptr[22] = newsp;

But 14 would be l6, not i6.

>     printf("setting stack pointer\n");
>    }
>    child_env->regwptr[0] = 0;

This should be the pid.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] SPARC user mode multithread
       [not found] <1423348936.2513841257534586216.JavaMail.root@mail-01.cse.ucsc.edu>
@ 2009-11-06 19:10 ` David Munday
  2009-11-06 19:19   ` Blue Swirl
  2009-11-08 19:28   ` Blue Swirl
  0 siblings, 2 replies; 9+ messages in thread
From: David Munday @ 2009-11-06 19:10 UTC (permalink / raw)
  To: Blue Swirl; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1491 bytes --]

Hi,
Sorry forgot attachment! I have attached it to this email now. I also noticed that the last line should assign the pid to the child, but I didn't see where I can find that info and pass it into the cpu_clone_regs function.

Thanks for the help,
David



----- Original Message -----
From: "Blue Swirl" <blauwirbel@gmail.com>
To: "David Munday" <cromom@soe.ucsc.edu>
Cc: qemu-devel@nongnu.org
Sent: Friday, November 6, 2009 10:31:23 AM GMT -08:00 US/Canada Pacific
Subject: Re: [Qemu-devel] SPARC user mode multithread

On Thu, Nov 5, 2009 at 10:29 PM, David Munday <cromom@soe.ucsc.edu> wrote:
> Hi,
> I found the Linux/Sparc clone operations in copy_thread() from process32.c (attached)

Forgot to attach?

> I tried modifying cpu_clone_regs with the following code per the Sparc/linux routines, but qemu still stalls on signal suspend.
>
> It seems like it should only need to set the stack pointer and the return addresses for the child and parent processes, but it's clearly missing something.
>
> Is there more to this fix than these two assignments?
>
> static inline void cpu_clone_regs(CPUState *PARENT_env, CPUState *child_env, target_ulong newsp)
> {
>    if (newsp)
>    {
>     child_env->regwptr[14] = newsp; //changed to 14 per process32.c DM
>         //env->regwptr[22] = newsp;

But 14 would be l6, not i6.

>     printf("setting stack pointer\n");
>    }
>    child_env->regwptr[0] = 0;

This should be the pid.

[-- Attachment #2: process_32.c --]
[-- Type: text/plain, Size: 19051 bytes --]

/*  linux/arch/sparc/kernel/process.c
 *
 *  Copyright (C) 1995, 2008 David S. Miller (davem@davemloft.net)
 *  Copyright (C) 1996 Eddie C. Dost   (ecd@skynet.be)
 */

/*
 * This file handles the architecture-dependent parts of process handling..
 */

#include <stdarg.h>

#include <linux/errno.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/stddef.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/user.h>
#include <linux/smp.h>
#include <linux/reboot.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/init.h>

#include <asm/auxio.h>
#include <asm/oplib.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/delay.h>
#include <asm/processor.h>
#include <asm/psr.h>
#include <asm/elf.h>
#include <asm/prom.h>
#include <asm/unistd.h>

/* 
 * Power management idle function 
 * Set in pm platform drivers (apc.c and pmc.c)
 */
void (*pm_idle)(void);
EXPORT_SYMBOL(pm_idle);

/* 
 * Power-off handler instantiation for pm.h compliance
 * This is done via auxio, but could be used as a fallback
 * handler when auxio is not present-- unused for now...
 */
void (*pm_power_off)(void) = machine_power_off;
EXPORT_SYMBOL(pm_power_off);

/*
 * sysctl - toggle power-off restriction for serial console 
 * systems in machine_power_off()
 */
int scons_pwroff = 1;

extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *);

struct task_struct *last_task_used_math = NULL;
struct thread_info *current_set[NR_CPUS];

#ifndef CONFIG_SMP

#define SUN4C_FAULT_HIGH 100

/*
 * the idle loop on a Sparc... ;)
 */
void cpu_idle(void)
{
	/* endless idle loop with no priority at all */
	for (;;) {
		if (ARCH_SUN4C) {
			static int count = HZ;
			static unsigned long last_jiffies;
			static unsigned long last_faults;
			static unsigned long fps;
			unsigned long now;
			unsigned long faults;

			extern unsigned long sun4c_kernel_faults;
			extern void sun4c_grow_kernel_ring(void);

			local_irq_disable();
			now = jiffies;
			count -= (now - last_jiffies);
			last_jiffies = now;
			if (count < 0) {
				count += HZ;
				faults = sun4c_kernel_faults;
				fps = (fps + (faults - last_faults)) >> 1;
				last_faults = faults;
#if 0
				printk("kernel faults / second = %ld\n", fps);
#endif
				if (fps >= SUN4C_FAULT_HIGH) {
					sun4c_grow_kernel_ring();
				}
			}
			local_irq_enable();
		}

		if (pm_idle) {
			while (!need_resched())
				(*pm_idle)();
		} else {
			while (!need_resched())
				cpu_relax();
		}
		preempt_enable_no_resched();
		schedule();
		preempt_disable();
		check_pgt_cache();
	}
}

#else

/* This is being executed in task 0 'user space'. */
void cpu_idle(void)
{
        set_thread_flag(TIF_POLLING_NRFLAG);
	/* endless idle loop with no priority at all */
	while(1) {
		while (!need_resched())
			cpu_relax();
		preempt_enable_no_resched();
		schedule();
		preempt_disable();
		check_pgt_cache();
	}
}

#endif

/* XXX cli/sti -> local_irq_xxx here, check this works once SMP is fixed. */
void machine_halt(void)
{
	local_irq_enable();
	mdelay(8);
	local_irq_disable();
	prom_halt();
	panic("Halt failed!");
}

void machine_restart(char * cmd)
{
	char *p;
	
	local_irq_enable();
	mdelay(8);
	local_irq_disable();

	p = strchr (reboot_command, '\n');
	if (p) *p = 0;
	if (cmd)
		prom_reboot(cmd);
	if (*reboot_command)
		prom_reboot(reboot_command);
	prom_feval ("reset");
	panic("Reboot failed!");
}

void machine_power_off(void)
{
	if (auxio_power_register &&
	    (strcmp(of_console_device->type, "serial") || scons_pwroff))
		*auxio_power_register |= AUXIO_POWER_OFF;
	machine_halt();
}

#if 0

static DEFINE_SPINLOCK(sparc_backtrace_lock);

void __show_backtrace(unsigned long fp)
{
	struct reg_window32 *rw;
	unsigned long flags;
	int cpu = smp_processor_id();

	spin_lock_irqsave(&sparc_backtrace_lock, flags);

	rw = (struct reg_window32 *)fp;
        while(rw && (((unsigned long) rw) >= PAGE_OFFSET) &&
            !(((unsigned long) rw) & 0x7)) {
		printk("CPU[%d]: ARGS[%08lx,%08lx,%08lx,%08lx,%08lx,%08lx] "
		       "FP[%08lx] CALLER[%08lx]: ", cpu,
		       rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3],
		       rw->ins[4], rw->ins[5],
		       rw->ins[6],
		       rw->ins[7]);
		printk("%pS\n", (void *) rw->ins[7]);
		rw = (struct reg_window32 *) rw->ins[6];
	}
	spin_unlock_irqrestore(&sparc_backtrace_lock, flags);
}

#define __SAVE __asm__ __volatile__("save %sp, -0x40, %sp\n\t")
#define __RESTORE __asm__ __volatile__("restore %g0, %g0, %g0\n\t")
#define __GET_FP(fp) __asm__ __volatile__("mov %%i6, %0" : "=r" (fp))

void show_backtrace(void)
{
	unsigned long fp;

	__SAVE; __SAVE; __SAVE; __SAVE;
	__SAVE; __SAVE; __SAVE; __SAVE;
	__RESTORE; __RESTORE; __RESTORE; __RESTORE;
	__RESTORE; __RESTORE; __RESTORE; __RESTORE;

	__GET_FP(fp);

	__show_backtrace(fp);
}

#ifdef CONFIG_SMP
void smp_show_backtrace_all_cpus(void)
{
	xc0((smpfunc_t) show_backtrace);
	show_backtrace();
}
#endif

void show_stackframe(struct sparc_stackf *sf)
{
	unsigned long size;
	unsigned long *stk;
	int i;

	printk("l0: %08lx l1: %08lx l2: %08lx l3: %08lx "
	       "l4: %08lx l5: %08lx l6: %08lx l7: %08lx\n",
	       sf->locals[0], sf->locals[1], sf->locals[2], sf->locals[3],
	       sf->locals[4], sf->locals[5], sf->locals[6], sf->locals[7]);
	printk("i0: %08lx i1: %08lx i2: %08lx i3: %08lx "
	       "i4: %08lx i5: %08lx fp: %08lx i7: %08lx\n",
	       sf->ins[0], sf->ins[1], sf->ins[2], sf->ins[3],
	       sf->ins[4], sf->ins[5], (unsigned long)sf->fp, sf->callers_pc);
	printk("sp: %08lx x0: %08lx x1: %08lx x2: %08lx "
	       "x3: %08lx x4: %08lx x5: %08lx xx: %08lx\n",
	       (unsigned long)sf->structptr, sf->xargs[0], sf->xargs[1],
	       sf->xargs[2], sf->xargs[3], sf->xargs[4], sf->xargs[5],
	       sf->xxargs[0]);
	size = ((unsigned long)sf->fp) - ((unsigned long)sf);
	size -= STACKFRAME_SZ;
	stk = (unsigned long *)((unsigned long)sf + STACKFRAME_SZ);
	i = 0;
	do {
		printk("s%d: %08lx\n", i++, *stk++);
	} while ((size -= sizeof(unsigned long)));
}
#endif

void show_regs(struct pt_regs *r)
{
	struct reg_window32 *rw = (struct reg_window32 *) r->u_regs[14];

        printk("PSR: %08lx PC: %08lx NPC: %08lx Y: %08lx    %s\n",
	       r->psr, r->pc, r->npc, r->y, print_tainted());
	printk("PC: <%pS>\n", (void *) r->pc);
	printk("%%G: %08lx %08lx  %08lx %08lx  %08lx %08lx  %08lx %08lx\n",
	       r->u_regs[0], r->u_regs[1], r->u_regs[2], r->u_regs[3],
	       r->u_regs[4], r->u_regs[5], r->u_regs[6], r->u_regs[7]);
	printk("%%O: %08lx %08lx  %08lx %08lx  %08lx %08lx  %08lx %08lx\n",
	       r->u_regs[8], r->u_regs[9], r->u_regs[10], r->u_regs[11],
	       r->u_regs[12], r->u_regs[13], r->u_regs[14], r->u_regs[15]);
	printk("RPC: <%pS>\n", (void *) r->u_regs[15]);

	printk("%%L: %08lx %08lx  %08lx %08lx  %08lx %08lx  %08lx %08lx\n",
	       rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3],
	       rw->locals[4], rw->locals[5], rw->locals[6], rw->locals[7]);
	printk("%%I: %08lx %08lx  %08lx %08lx  %08lx %08lx  %08lx %08lx\n",
	       rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3],
	       rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]);
}

/*
 * The show_stack is an external API which we do not use ourselves.
 * The oops is printed in die_if_kernel.
 */
void show_stack(struct task_struct *tsk, unsigned long *_ksp)
{
	unsigned long pc, fp;
	unsigned long task_base;
	struct reg_window32 *rw;
	int count = 0;

	if (tsk != NULL)
		task_base = (unsigned long) task_stack_page(tsk);
	else
		task_base = (unsigned long) current_thread_info();

	fp = (unsigned long) _ksp;
	do {
		/* Bogus frame pointer? */
		if (fp < (task_base + sizeof(struct thread_info)) ||
		    fp >= (task_base + (PAGE_SIZE << 1)))
			break;
		rw = (struct reg_window32 *) fp;
		pc = rw->ins[7];
		printk("[%08lx : ", pc);
		printk("%pS ] ", (void *) pc);
		fp = rw->ins[6];
	} while (++count < 16);
	printk("\n");
}

void dump_stack(void)
{
	unsigned long *ksp;

	__asm__ __volatile__("mov	%%fp, %0"
			     : "=r" (ksp));
	show_stack(current, ksp);
}

EXPORT_SYMBOL(dump_stack);

/*
 * Note: sparc64 has a pretty intricated thread_saved_pc, check it out.
 */
unsigned long thread_saved_pc(struct task_struct *tsk)
{
	return task_thread_info(tsk)->kpc;
}

/*
 * Free current thread data structures etc..
 */
void exit_thread(void)
{
#ifndef CONFIG_SMP
	if(last_task_used_math == current) {
#else
	if (test_thread_flag(TIF_USEDFPU)) {
#endif
		/* Keep process from leaving FPU in a bogon state. */
		put_psr(get_psr() | PSR_EF);
		fpsave(&current->thread.float_regs[0], &current->thread.fsr,
		       &current->thread.fpqueue[0], &current->thread.fpqdepth);
#ifndef CONFIG_SMP
		last_task_used_math = NULL;
#else
		clear_thread_flag(TIF_USEDFPU);
#endif
	}
}

void flush_thread(void)
{
	current_thread_info()->w_saved = 0;

#ifndef CONFIG_SMP
	if(last_task_used_math == current) {
#else
	if (test_thread_flag(TIF_USEDFPU)) {
#endif
		/* Clean the fpu. */
		put_psr(get_psr() | PSR_EF);
		fpsave(&current->thread.float_regs[0], &current->thread.fsr,
		       &current->thread.fpqueue[0], &current->thread.fpqdepth);
#ifndef CONFIG_SMP
		last_task_used_math = NULL;
#else
		clear_thread_flag(TIF_USEDFPU);
#endif
	}

	/* Now, this task is no longer a kernel thread. */
	current->thread.current_ds = USER_DS;
	if (current->thread.flags & SPARC_FLAG_KTHREAD) {
		current->thread.flags &= ~SPARC_FLAG_KTHREAD;

		/* We must fixup kregs as well. */
		/* XXX This was not fixed for ti for a while, worked. Unused? */
		current->thread.kregs = (struct pt_regs *)
		    (task_stack_page(current) + (THREAD_SIZE - TRACEREG_SZ));
	}
}

static inline struct sparc_stackf __user *
clone_stackframe(struct sparc_stackf __user *dst,
		 struct sparc_stackf __user *src)
{
	unsigned long size, fp;
	struct sparc_stackf *tmp;
	struct sparc_stackf __user *sp;

	if (get_user(tmp, &src->fp))
		return NULL;

	fp = (unsigned long) tmp;
	size = (fp - ((unsigned long) src));
	fp = (unsigned long) dst;
	sp = (struct sparc_stackf __user *)(fp - size); 

	/* do_fork() grabs the parent semaphore, we must release it
	 * temporarily so we can build the child clone stack frame
	 * without deadlocking.
	 */
	if (__copy_user(sp, src, size))
		sp = NULL;
	else if (put_user(fp, &sp->fp))
		sp = NULL;

	return sp;
}

asmlinkage int sparc_do_fork(unsigned long clone_flags,
                             unsigned long stack_start,
                             struct pt_regs *regs,
                             unsigned long stack_size)
{
	unsigned long parent_tid_ptr, child_tid_ptr;
	unsigned long orig_i1 = regs->u_regs[UREG_I1];
	long ret;

	parent_tid_ptr = regs->u_regs[UREG_I2];
	child_tid_ptr = regs->u_regs[UREG_I4];

	ret = do_fork(clone_flags, stack_start,
		      regs, stack_size,
		      (int __user *) parent_tid_ptr,
		      (int __user *) child_tid_ptr);

	/* If we get an error and potentially restart the system
	 * call, we're screwed because copy_thread() clobbered
	 * the parent's %o1.  So detect that case and restore it
	 * here.
	 */
	if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
		regs->u_regs[UREG_I1] = orig_i1;

	return ret;
}

/* Copy a Sparc thread.  The fork() return value conventions
 * under SunOS are nothing short of bletcherous:
 * Parent -->  %o0 == childs  pid, %o1 == 0
 * Child  -->  %o0 == parents pid, %o1 == 1
 *
 * NOTE: We have a separate fork kpsr/kwim because
 *       the parent could change these values between
 *       sys_fork invocation and when we reach here
 *       if the parent should sleep while trying to
 *       allocate the task_struct and kernel stack in
 *       do_fork().
 * XXX See comment above sys_vfork in sparc64. todo.
 */
extern void ret_from_fork(void);

int copy_thread(unsigned long clone_flags, unsigned long sp,
		unsigned long unused,
		struct task_struct *p, struct pt_regs *regs)
{
	struct thread_info *ti = task_thread_info(p);
	struct pt_regs *childregs;
	char *new_stack;

#ifndef CONFIG_SMP
	if(last_task_used_math == current) {
#else
	if (test_thread_flag(TIF_USEDFPU)) {
#endif
		put_psr(get_psr() | PSR_EF);
		fpsave(&p->thread.float_regs[0], &p->thread.fsr,
		       &p->thread.fpqueue[0], &p->thread.fpqdepth);
#ifdef CONFIG_SMP
		clear_thread_flag(TIF_USEDFPU);
#endif
	}

	/*
	 *  p->thread_info         new_stack   childregs
	 *  !                      !           !             {if(PSR_PS) }
	 *  V                      V (stk.fr.) V  (pt_regs)  { (stk.fr.) }
	 *  +----- - - - - - ------+===========+============={+==========}+
	 */
	new_stack = task_stack_page(p) + THREAD_SIZE;
	if (regs->psr & PSR_PS)
		new_stack -= STACKFRAME_SZ;
	new_stack -= STACKFRAME_SZ + TRACEREG_SZ;
	memcpy(new_stack, (char *)regs - STACKFRAME_SZ, STACKFRAME_SZ + TRACEREG_SZ);
	childregs = (struct pt_regs *) (new_stack + STACKFRAME_SZ);

	/*
	 * A new process must start with interrupts closed in 2.5,
	 * because this is how Mingo's scheduler works (see schedule_tail
	 * and finish_arch_switch). If we do not do it, a timer interrupt hits
	 * before we unlock, attempts to re-take the rq->lock, and then we die.
	 * Thus, kpsr|=PSR_PIL.
	 */
	ti->ksp = (unsigned long) new_stack;
	ti->kpc = (((unsigned long) ret_from_fork) - 0x8);
	ti->kpsr = current->thread.fork_kpsr | PSR_PIL;
	ti->kwim = current->thread.fork_kwim;

	if(regs->psr & PSR_PS) {
		extern struct pt_regs fake_swapper_regs;

		p->thread.kregs = &fake_swapper_regs;
		new_stack += STACKFRAME_SZ + TRACEREG_SZ;
		childregs->u_regs[UREG_FP] = (unsigned long) new_stack;
		p->thread.flags |= SPARC_FLAG_KTHREAD;
		p->thread.current_ds = KERNEL_DS;
		memcpy(new_stack, (void *)regs->u_regs[UREG_FP], STACKFRAME_SZ);
		childregs->u_regs[UREG_G6] = (unsigned long) ti;
	} else {
		p->thread.kregs = childregs;
		childregs->u_regs[UREG_FP] = sp;
		p->thread.flags &= ~SPARC_FLAG_KTHREAD;
		p->thread.current_ds = USER_DS;

		if (sp != regs->u_regs[UREG_FP]) {
			struct sparc_stackf __user *childstack;
			struct sparc_stackf __user *parentstack;

			/*
			 * This is a clone() call with supplied user stack.
			 * Set some valid stack frames to give to the child.
			 */
			childstack = (struct sparc_stackf __user *)
				(sp & ~0x7UL);
			parentstack = (struct sparc_stackf __user *)
				regs->u_regs[UREG_FP];

#if 0
			printk("clone: parent stack:\n");
			show_stackframe(parentstack);
#endif

			childstack = clone_stackframe(childstack, parentstack);
			if (!childstack)
				return -EFAULT;

#if 0
			printk("clone: child stack:\n");
			show_stackframe(childstack);
#endif

			childregs->u_regs[UREG_FP] = (unsigned long)childstack;
		}
	}

#ifdef CONFIG_SMP
	/* FPU must be disabled on SMP. */
	childregs->psr &= ~PSR_EF;
#endif

	/* Set the return value for the child. */
	childregs->u_regs[UREG_I0] = current->pid;
	childregs->u_regs[UREG_I1] = 1;

	/* Set the return value for the parent. */
	regs->u_regs[UREG_I1] = 0;

	if (clone_flags & CLONE_SETTLS)
		childregs->u_regs[UREG_G7] = regs->u_regs[UREG_I3];

	return 0;
}

/*
 * fill in the fpu structure for a core dump.
 */
int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs)
{
	if (used_math()) {
		memset(fpregs, 0, sizeof(*fpregs));
		fpregs->pr_q_entrysize = 8;
		return 1;
	}
#ifdef CONFIG_SMP
	if (test_thread_flag(TIF_USEDFPU)) {
		put_psr(get_psr() | PSR_EF);
		fpsave(&current->thread.float_regs[0], &current->thread.fsr,
		       &current->thread.fpqueue[0], &current->thread.fpqdepth);
		if (regs != NULL) {
			regs->psr &= ~(PSR_EF);
			clear_thread_flag(TIF_USEDFPU);
		}
	}
#else
	if (current == last_task_used_math) {
		put_psr(get_psr() | PSR_EF);
		fpsave(&current->thread.float_regs[0], &current->thread.fsr,
		       &current->thread.fpqueue[0], &current->thread.fpqdepth);
		if (regs != NULL) {
			regs->psr &= ~(PSR_EF);
			last_task_used_math = NULL;
		}
	}
#endif
	memcpy(&fpregs->pr_fr.pr_regs[0],
	       &current->thread.float_regs[0],
	       (sizeof(unsigned long) * 32));
	fpregs->pr_fsr = current->thread.fsr;
	fpregs->pr_qcnt = current->thread.fpqdepth;
	fpregs->pr_q_entrysize = 8;
	fpregs->pr_en = 1;
	if(fpregs->pr_qcnt != 0) {
		memcpy(&fpregs->pr_q[0],
		       &current->thread.fpqueue[0],
		       sizeof(struct fpq) * fpregs->pr_qcnt);
	}
	/* Zero out the rest. */
	memset(&fpregs->pr_q[fpregs->pr_qcnt], 0,
	       sizeof(struct fpq) * (32 - fpregs->pr_qcnt));
	return 1;
}

/*
 * sparc_execve() executes a new program after the asm stub has set
 * things up for us.  This should basically do what I want it to.
 */
asmlinkage int sparc_execve(struct pt_regs *regs)
{
	int error, base = 0;
	char *filename;

	/* Check for indirect call. */
	if(regs->u_regs[UREG_G1] == 0)
		base = 1;

	filename = getname((char __user *)regs->u_regs[base + UREG_I0]);
	error = PTR_ERR(filename);
	if(IS_ERR(filename))
		goto out;
	error = do_execve(filename,
			  (char __user * __user *)regs->u_regs[base + UREG_I1],
			  (char __user * __user *)regs->u_regs[base + UREG_I2],
			  regs);
	putname(filename);
out:
	return error;
}

/*
 * This is the mechanism for creating a new kernel thread.
 *
 * NOTE! Only a kernel-only process(ie the swapper or direct descendants
 * who haven't done an "execve()") should use this: it will work within
 * a system call from a "real" process, but the process memory space will
 * not be freed until both the parent and the child have exited.
 */
pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
{
	long retval;

	__asm__ __volatile__("mov %4, %%g2\n\t"    /* Set aside fn ptr... */
			     "mov %5, %%g3\n\t"    /* and arg. */
			     "mov %1, %%g1\n\t"
			     "mov %2, %%o0\n\t"    /* Clone flags. */
			     "mov 0, %%o1\n\t"     /* usp arg == 0 */
			     "t 0x10\n\t"          /* Linux/Sparc clone(). */
			     "cmp %%o1, 0\n\t"
			     "be 1f\n\t"           /* The parent, just return. */
			     " nop\n\t"            /* Delay slot. */
			     "jmpl %%g2, %%o7\n\t" /* Call the function. */
			     " mov %%g3, %%o0\n\t" /* Get back the arg in delay. */
			     "mov %3, %%g1\n\t"
			     "t 0x10\n\t"          /* Linux/Sparc exit(). */
			     /* Notreached by child. */
			     "1: mov %%o0, %0\n\t" :
			     "=r" (retval) :
			     "i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED),
			     "i" (__NR_exit),  "r" (fn), "r" (arg) :
			     "g1", "g2", "g3", "o0", "o1", "memory", "cc");
	return retval;
}
EXPORT_SYMBOL(kernel_thread);

unsigned long get_wchan(struct task_struct *task)
{
	unsigned long pc, fp, bias = 0;
	unsigned long task_base = (unsigned long) task;
        unsigned long ret = 0;
	struct reg_window32 *rw;
	int count = 0;

	if (!task || task == current ||
            task->state == TASK_RUNNING)
		goto out;

	fp = task_thread_info(task)->ksp + bias;
	do {
		/* Bogus frame pointer? */
		if (fp < (task_base + sizeof(struct thread_info)) ||
		    fp >= (task_base + (2 * PAGE_SIZE)))
			break;
		rw = (struct reg_window32 *) fp;
		pc = rw->ins[7];
		if (!in_sched_functions(pc)) {
			ret = pc;
			goto out;
		}
		fp = rw->ins[6] + bias;
	} while (++count < 16);

out:
	return ret;
}


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] SPARC user mode multithread
  2009-11-06 19:10 ` [Qemu-devel] SPARC user mode multithread David Munday
@ 2009-11-06 19:19   ` Blue Swirl
  2009-11-08 19:28   ` Blue Swirl
  1 sibling, 0 replies; 9+ messages in thread
From: Blue Swirl @ 2009-11-06 19:19 UTC (permalink / raw)
  To: David Munday; +Cc: qemu-devel

On Fri, Nov 6, 2009 at 9:10 PM, David Munday <cromom@soe.ucsc.edu> wrote:
> Hi,
> Sorry forgot attachment! I have attached it to this email now. I also noticed that the last line should assign the pid to the child, but I didn't see where I can find that info and pass it into the cpu_clone_regs function.

Maybe just call getpid()?

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] SPARC user mode multithread
  2009-11-06 19:10 ` [Qemu-devel] SPARC user mode multithread David Munday
  2009-11-06 19:19   ` Blue Swirl
@ 2009-11-08 19:28   ` Blue Swirl
  2009-11-10  0:34     ` David Munday
  2010-04-20  1:48     ` Gabriel Southern
  1 sibling, 2 replies; 9+ messages in thread
From: Blue Swirl @ 2009-11-08 19:28 UTC (permalink / raw)
  To: David Munday; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 342 bytes --]

On Fri, Nov 6, 2009 at 9:10 PM, David Munday <cromom@soe.ucsc.edu> wrote:
> Hi,
> Sorry forgot attachment! I have attached it to this email now. I also noticed that the last line should assign the pid to the child, but I didn't see where I can find that info and pass it into the cpu_clone_regs function.

Could you test if this patch helps?

[-- Attachment #2: 0001-sparc-linux-user-fix-fork.patch --]
[-- Type: application/x-patch, Size: 1779 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] SPARC user mode multithread
  2009-11-08 19:28   ` Blue Swirl
@ 2009-11-10  0:34     ` David Munday
  2010-04-20  1:48     ` Gabriel Southern
  1 sibling, 0 replies; 9+ messages in thread
From: David Munday @ 2009-11-10  0:34 UTC (permalink / raw)
  To: Blue Swirl; +Cc: qemu-devel

I just patched and ran with two of the programs with from the parsec suite and they both run with the small input sets. I will run the full suite later tonight and let you know the results.

Thanks for the help,
David

----- Original Message -----
From: "Blue Swirl" <blauwirbel@gmail.com>
To: "David Munday" <cromom@soe.ucsc.edu>
Cc: qemu-devel@nongnu.org
Sent: Sunday, November 8, 2009 11:28:21 AM GMT -08:00 US/Canada Pacific
Subject: Re: [Qemu-devel] SPARC user mode multithread

On Fri, Nov 6, 2009 at 9:10 PM, David Munday <cromom@soe.ucsc.edu> wrote:
> Hi,
> Sorry forgot attachment! I have attached it to this email now. I also noticed that the last line should assign the pid to the child, but I didn't see where I can find that info and pass it into the cpu_clone_regs function.

Could you test if this patch helps?

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] SPARC user mode multithread
  2009-11-08 19:28   ` Blue Swirl
  2009-11-10  0:34     ` David Munday
@ 2010-04-20  1:48     ` Gabriel Southern
  1 sibling, 0 replies; 9+ messages in thread
From: Gabriel Southern @ 2010-04-20  1:48 UTC (permalink / raw)
  To: Blue Swirl; +Cc: qemu-devel

Hi,

I noticed that this patch never got applied, but I'm not sure if it
works.  It seems like it works for forks, but not for pthreads.  I
tried applying it to the current git head and it seems to change the
behavior from dumping the registers to dying silently for code with
pthreads, but does work with forks (at least for a very simple test
program without shared memory).

-Gabriel

On Sun, Nov 8, 2009 at 12:28 PM, Blue Swirl <blauwirbel@gmail.com> wrote:
> On Fri, Nov 6, 2009 at 9:10 PM, David Munday <cromom@soe.ucsc.edu> wrote:
>> Hi,
>> Sorry forgot attachment! I have attached it to this email now. I also noticed that the last line should assign the pid to the child, but I didn't see where I can find that info and pass it into the cpu_clone_regs function.
>
> Could you test if this patch helps?
>

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2010-04-20  1:48 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <1423348936.2513841257534586216.JavaMail.root@mail-01.cse.ucsc.edu>
2009-11-06 19:10 ` [Qemu-devel] SPARC user mode multithread David Munday
2009-11-06 19:19   ` Blue Swirl
2009-11-08 19:28   ` Blue Swirl
2009-11-10  0:34     ` David Munday
2010-04-20  1:48     ` Gabriel Southern
     [not found] <1010833181.2491521257452944973.JavaMail.root@mail-01.cse.ucsc.edu>
2009-11-05 20:29 ` David Munday
2009-11-06 18:31   ` Blue Swirl
2009-11-03 20:03 David Munday
2009-11-03 20:41 ` Blue Swirl

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).