diff options
Diffstat (limited to 'arch/score/kernel/process.c')
-rw-r--r-- | arch/score/kernel/process.c | 55 |
1 files changed, 14 insertions, 41 deletions
diff --git a/arch/score/kernel/process.c b/arch/score/kernel/process.c index 637970cfd3f4..6f311cf64b99 100644 --- a/arch/score/kernel/process.c +++ b/arch/score/kernel/process.c | |||
@@ -60,6 +60,7 @@ void __noreturn cpu_idle(void) | |||
60 | } | 60 | } |
61 | 61 | ||
62 | void ret_from_fork(void); | 62 | void ret_from_fork(void); |
63 | void ret_from_kernel_thread(void); | ||
63 | 64 | ||
64 | void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) | 65 | void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) |
65 | { | 66 | { |
@@ -86,29 +87,27 @@ void flush_thread(void) {} | |||
86 | * set up the kernel stack and exception frames for a new process | 87 | * set up the kernel stack and exception frames for a new process |
87 | */ | 88 | */ |
88 | int copy_thread(unsigned long clone_flags, unsigned long usp, | 89 | int copy_thread(unsigned long clone_flags, unsigned long usp, |
89 | unsigned long unused, | 90 | unsigned long arg, |
90 | struct task_struct *p, struct pt_regs *regs) | 91 | struct task_struct *p, struct pt_regs *regs) |
91 | { | 92 | { |
92 | struct thread_info *ti = task_thread_info(p); | 93 | struct thread_info *ti = task_thread_info(p); |
93 | struct pt_regs *childregs = task_pt_regs(p); | 94 | struct pt_regs *childregs = task_pt_regs(p); |
94 | 95 | ||
95 | p->set_child_tid = NULL; | 96 | p->thread.reg0 = (unsigned long) childregs; |
96 | p->clear_child_tid = NULL; | 97 | if (unlikely(!regs)) { |
97 | 98 | memset(childregs, 0, sizeof(struct pt_regs)); | |
98 | *childregs = *regs; | 99 | p->thread->reg12 = usp; |
99 | childregs->regs[7] = 0; /* Clear error flag */ | 100 | p->thread->reg13 = arg; |
100 | childregs->regs[4] = 0; /* Child gets zero as return value */ | 101 | p->thread.reg3 = (unsigned long) ret_from_kernel_thread; |
101 | regs->regs[4] = p->pid; | ||
102 | |||
103 | if (childregs->cp0_psr & 0x8) { /* test kernel fork or user fork */ | ||
104 | childregs->regs[0] = usp; /* user fork */ | ||
105 | } else { | 102 | } else { |
106 | childregs->regs[28] = (unsigned long) ti; /* kernel fork */ | 103 | *childregs = *regs; |
107 | childregs->regs[0] = (unsigned long) childregs; | 104 | childregs->regs[7] = 0; /* Clear error flag */ |
105 | childregs->regs[4] = 0; /* Child gets zero as return value */ | ||
106 | childregs->regs[0] = usp; /* user fork */ | ||
107 | regs->regs[4] = p->pid; /* WTF? */ | ||
108 | p->thread.reg3 = (unsigned long) ret_from_fork; | ||
108 | } | 109 | } |
109 | 110 | ||
110 | p->thread.reg0 = (unsigned long) childregs; | ||
111 | p->thread.reg3 = (unsigned long) ret_from_fork; | ||
112 | p->thread.cp0_psr = 0; | 111 | p->thread.cp0_psr = 0; |
113 | 112 | ||
114 | return 0; | 113 | return 0; |
@@ -120,32 +119,6 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r) | |||
120 | return 1; | 119 | return 1; |
121 | } | 120 | } |
122 | 121 | ||
123 | static void __noreturn | ||
124 | kernel_thread_helper(void *unused0, int (*fn)(void *), | ||
125 | void *arg, void *unused1) | ||
126 | { | ||
127 | do_exit(fn(arg)); | ||
128 | } | ||
129 | |||
130 | /* | ||
131 | * Create a kernel thread. | ||
132 | */ | ||
133 | long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | ||
134 | { | ||
135 | struct pt_regs regs; | ||
136 | |||
137 | memset(®s, 0, sizeof(regs)); | ||
138 | |||
139 | regs.regs[6] = (unsigned long) arg; | ||
140 | regs.regs[5] = (unsigned long) fn; | ||
141 | regs.cp0_epc = (unsigned long) kernel_thread_helper; | ||
142 | regs.cp0_psr = (regs.cp0_psr & ~(0x1|0x4|0x8)) | \ | ||
143 | ((regs.cp0_psr & 0x3) << 2); | ||
144 | |||
145 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, \ | ||
146 | 0, ®s, 0, NULL, NULL); | ||
147 | } | ||
148 | |||
149 | unsigned long thread_saved_pc(struct task_struct *tsk) | 122 | unsigned long thread_saved_pc(struct task_struct *tsk) |
150 | { | 123 | { |
151 | return task_pt_regs(tsk)->cp0_epc; | 124 | return task_pt_regs(tsk)->cp0_epc; |