Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/blackfin/kernel/process.c
10817 views
1
/*
2
* Blackfin architecture-dependent process handling
3
*
4
* Copyright 2004-2009 Analog Devices Inc.
5
*
6
* Licensed under the GPL-2 or later
7
*/
8
9
#include <linux/module.h>
10
#include <linux/unistd.h>
11
#include <linux/user.h>
12
#include <linux/uaccess.h>
13
#include <linux/slab.h>
14
#include <linux/sched.h>
15
#include <linux/tick.h>
16
#include <linux/fs.h>
17
#include <linux/err.h>
18
19
#include <asm/blackfin.h>
20
#include <asm/fixed_code.h>
21
#include <asm/mem_map.h>
22
23
asmlinkage void ret_from_fork(void);
24
25
/* Points to the SDRAM backup memory for the stack that is currently in
26
* L1 scratchpad memory.
27
*/
28
void *current_l1_stack_save;
29
30
/* The number of tasks currently using a L1 stack area. The SRAM is
31
* allocated/deallocated whenever this changes from/to zero.
32
*/
33
int nr_l1stack_tasks;
34
35
/* Start and length of the area in L1 scratchpad memory which we've allocated
36
* for process stacks.
37
*/
38
void *l1_stack_base;
39
unsigned long l1_stack_len;
40
41
/*
42
* Powermanagement idle function, if any..
43
*/
44
void (*pm_idle)(void) = NULL;
45
EXPORT_SYMBOL(pm_idle);
46
47
void (*pm_power_off)(void) = NULL;
48
EXPORT_SYMBOL(pm_power_off);
49
50
/*
51
* The idle loop on BFIN
52
*/
53
#ifdef CONFIG_IDLE_L1
54
static void default_idle(void)__attribute__((l1_text));
55
void cpu_idle(void)__attribute__((l1_text));
56
#endif
57
58
/*
59
* This is our default idle handler. We need to disable
60
* interrupts here to ensure we don't miss a wakeup call.
61
*/
62
static void default_idle(void)
63
{
64
#ifdef CONFIG_IPIPE
65
ipipe_suspend_domain();
66
#endif
67
hard_local_irq_disable();
68
if (!need_resched())
69
idle_with_irq_disabled();
70
71
hard_local_irq_enable();
72
}
73
74
/*
75
* The idle thread. We try to conserve power, while trying to keep
76
* overall latency low. The architecture specific idle is passed
77
* a value to indicate the level of "idleness" of the system.
78
*/
79
void cpu_idle(void)
80
{
81
/* endless idle loop with no priority at all */
82
while (1) {
83
void (*idle)(void) = pm_idle;
84
85
#ifdef CONFIG_HOTPLUG_CPU
86
if (cpu_is_offline(smp_processor_id()))
87
cpu_die();
88
#endif
89
if (!idle)
90
idle = default_idle;
91
tick_nohz_stop_sched_tick(1);
92
while (!need_resched())
93
idle();
94
tick_nohz_restart_sched_tick();
95
preempt_enable_no_resched();
96
schedule();
97
preempt_disable();
98
}
99
}
100
101
/*
102
* This gets run with P1 containing the
103
* function to call, and R1 containing
104
* the "args". Note P0 is clobbered on the way here.
105
*/
106
void kernel_thread_helper(void);
107
__asm__(".section .text\n"
108
".align 4\n"
109
"_kernel_thread_helper:\n\t"
110
"\tsp += -12;\n\t"
111
"\tr0 = r1;\n\t" "\tcall (p1);\n\t" "\tcall _do_exit;\n" ".previous");
112
113
/*
114
* Create a kernel thread.
115
*/
116
pid_t kernel_thread(int (*fn) (void *), void *arg, unsigned long flags)
117
{
118
struct pt_regs regs;
119
120
memset(&regs, 0, sizeof(regs));
121
122
regs.r1 = (unsigned long)arg;
123
regs.p1 = (unsigned long)fn;
124
regs.pc = (unsigned long)kernel_thread_helper;
125
regs.orig_p0 = -1;
126
/* Set bit 2 to tell ret_from_fork we should be returning to kernel
127
mode. */
128
regs.ipend = 0x8002;
129
__asm__ __volatile__("%0 = syscfg;":"=da"(regs.syscfg):);
130
return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL,
131
NULL);
132
}
133
EXPORT_SYMBOL(kernel_thread);
134
135
/*
136
* Do necessary setup to start up a newly executed thread.
137
*
138
* pass the data segment into user programs if it exists,
139
* it can't hurt anything as far as I can tell
140
*/
141
void start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp)
142
{
143
set_fs(USER_DS);
144
regs->pc = new_ip;
145
if (current->mm)
146
regs->p5 = current->mm->start_data;
147
#ifndef CONFIG_SMP
148
task_thread_info(current)->l1_task_info.stack_start =
149
(void *)current->mm->context.stack_start;
150
task_thread_info(current)->l1_task_info.lowest_sp = (void *)new_sp;
151
memcpy(L1_SCRATCH_TASK_INFO, &task_thread_info(current)->l1_task_info,
152
sizeof(*L1_SCRATCH_TASK_INFO));
153
#endif
154
wrusp(new_sp);
155
}
156
EXPORT_SYMBOL_GPL(start_thread);
157
158
void flush_thread(void)
159
{
160
}
161
162
asmlinkage int bfin_vfork(struct pt_regs *regs)
163
{
164
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL,
165
NULL);
166
}
167
168
asmlinkage int bfin_clone(struct pt_regs *regs)
169
{
170
unsigned long clone_flags;
171
unsigned long newsp;
172
173
#ifdef __ARCH_SYNC_CORE_DCACHE
174
if (current->rt.nr_cpus_allowed == num_possible_cpus())
175
set_cpus_allowed_ptr(current, cpumask_of(smp_processor_id()));
176
#endif
177
178
/* syscall2 puts clone_flags in r0 and usp in r1 */
179
clone_flags = regs->r0;
180
newsp = regs->r1;
181
if (!newsp)
182
newsp = rdusp();
183
else
184
newsp -= 12;
185
return do_fork(clone_flags, newsp, regs, 0, NULL, NULL);
186
}
187
188
int
189
copy_thread(unsigned long clone_flags,
190
unsigned long usp, unsigned long topstk,
191
struct task_struct *p, struct pt_regs *regs)
192
{
193
struct pt_regs *childregs;
194
195
childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1;
196
*childregs = *regs;
197
childregs->r0 = 0;
198
199
p->thread.usp = usp;
200
p->thread.ksp = (unsigned long)childregs;
201
p->thread.pc = (unsigned long)ret_from_fork;
202
203
return 0;
204
}
205
206
/*
207
* sys_execve() executes a new program.
208
*/
209
asmlinkage int sys_execve(const char __user *name,
210
const char __user *const __user *argv,
211
const char __user *const __user *envp)
212
{
213
int error;
214
char *filename;
215
struct pt_regs *regs = (struct pt_regs *)((&name) + 6);
216
217
filename = getname(name);
218
error = PTR_ERR(filename);
219
if (IS_ERR(filename))
220
return error;
221
error = do_execve(filename, argv, envp, regs);
222
putname(filename);
223
return error;
224
}
225
226
unsigned long get_wchan(struct task_struct *p)
227
{
228
unsigned long fp, pc;
229
unsigned long stack_page;
230
int count = 0;
231
if (!p || p == current || p->state == TASK_RUNNING)
232
return 0;
233
234
stack_page = (unsigned long)p;
235
fp = p->thread.usp;
236
do {
237
if (fp < stack_page + sizeof(struct thread_info) ||
238
fp >= 8184 + stack_page)
239
return 0;
240
pc = ((unsigned long *)fp)[1];
241
if (!in_sched_functions(pc))
242
return pc;
243
fp = *(unsigned long *)fp;
244
}
245
while (count++ < 16);
246
return 0;
247
}
248
249
void finish_atomic_sections (struct pt_regs *regs)
250
{
251
int __user *up0 = (int __user *)regs->p0;
252
253
switch (regs->pc) {
254
default:
255
/* not in middle of an atomic step, so resume like normal */
256
return;
257
258
case ATOMIC_XCHG32 + 2:
259
put_user(regs->r1, up0);
260
break;
261
262
case ATOMIC_CAS32 + 2:
263
case ATOMIC_CAS32 + 4:
264
if (regs->r0 == regs->r1)
265
case ATOMIC_CAS32 + 6:
266
put_user(regs->r2, up0);
267
break;
268
269
case ATOMIC_ADD32 + 2:
270
regs->r0 = regs->r1 + regs->r0;
271
/* fall through */
272
case ATOMIC_ADD32 + 4:
273
put_user(regs->r0, up0);
274
break;
275
276
case ATOMIC_SUB32 + 2:
277
regs->r0 = regs->r1 - regs->r0;
278
/* fall through */
279
case ATOMIC_SUB32 + 4:
280
put_user(regs->r0, up0);
281
break;
282
283
case ATOMIC_IOR32 + 2:
284
regs->r0 = regs->r1 | regs->r0;
285
/* fall through */
286
case ATOMIC_IOR32 + 4:
287
put_user(regs->r0, up0);
288
break;
289
290
case ATOMIC_AND32 + 2:
291
regs->r0 = regs->r1 & regs->r0;
292
/* fall through */
293
case ATOMIC_AND32 + 4:
294
put_user(regs->r0, up0);
295
break;
296
297
case ATOMIC_XOR32 + 2:
298
regs->r0 = regs->r1 ^ regs->r0;
299
/* fall through */
300
case ATOMIC_XOR32 + 4:
301
put_user(regs->r0, up0);
302
break;
303
}
304
305
/*
306
* We've finished the atomic section, and the only thing left for
307
* userspace is to do a RTS, so we might as well handle that too
308
* since we need to update the PC anyways.
309
*/
310
regs->pc = regs->rets;
311
}
312
313
static inline
314
int in_mem(unsigned long addr, unsigned long size,
315
unsigned long start, unsigned long end)
316
{
317
return addr >= start && addr + size <= end;
318
}
319
static inline
320
int in_mem_const_off(unsigned long addr, unsigned long size, unsigned long off,
321
unsigned long const_addr, unsigned long const_size)
322
{
323
return const_size &&
324
in_mem(addr, size, const_addr + off, const_addr + const_size);
325
}
326
static inline
327
int in_mem_const(unsigned long addr, unsigned long size,
328
unsigned long const_addr, unsigned long const_size)
329
{
330
return in_mem_const_off(addr, size, 0, const_addr, const_size);
331
}
332
#define ASYNC_ENABLED(bnum, bctlnum) \
333
({ \
334
(bfin_read_EBIU_AMGCTL() & 0xe) < ((bnum + 1) << 1) ? 0 : \
335
bfin_read_EBIU_AMBCTL##bctlnum() & B##bnum##RDYEN ? 0 : \
336
1; \
337
})
338
/*
339
* We can't read EBIU banks that aren't enabled or we end up hanging
340
* on the access to the async space. Make sure we validate accesses
341
* that cross async banks too.
342
* 0 - found, but unusable
343
* 1 - found & usable
344
* 2 - not found
345
*/
346
static
347
int in_async(unsigned long addr, unsigned long size)
348
{
349
if (addr >= ASYNC_BANK0_BASE && addr < ASYNC_BANK0_BASE + ASYNC_BANK0_SIZE) {
350
if (!ASYNC_ENABLED(0, 0))
351
return 0;
352
if (addr + size <= ASYNC_BANK0_BASE + ASYNC_BANK0_SIZE)
353
return 1;
354
size -= ASYNC_BANK0_BASE + ASYNC_BANK0_SIZE - addr;
355
addr = ASYNC_BANK0_BASE + ASYNC_BANK0_SIZE;
356
}
357
if (addr >= ASYNC_BANK1_BASE && addr < ASYNC_BANK1_BASE + ASYNC_BANK1_SIZE) {
358
if (!ASYNC_ENABLED(1, 0))
359
return 0;
360
if (addr + size <= ASYNC_BANK1_BASE + ASYNC_BANK1_SIZE)
361
return 1;
362
size -= ASYNC_BANK1_BASE + ASYNC_BANK1_SIZE - addr;
363
addr = ASYNC_BANK1_BASE + ASYNC_BANK1_SIZE;
364
}
365
if (addr >= ASYNC_BANK2_BASE && addr < ASYNC_BANK2_BASE + ASYNC_BANK2_SIZE) {
366
if (!ASYNC_ENABLED(2, 1))
367
return 0;
368
if (addr + size <= ASYNC_BANK2_BASE + ASYNC_BANK2_SIZE)
369
return 1;
370
size -= ASYNC_BANK2_BASE + ASYNC_BANK2_SIZE - addr;
371
addr = ASYNC_BANK2_BASE + ASYNC_BANK2_SIZE;
372
}
373
if (addr >= ASYNC_BANK3_BASE && addr < ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE) {
374
if (ASYNC_ENABLED(3, 1))
375
return 0;
376
if (addr + size <= ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE)
377
return 1;
378
return 0;
379
}
380
381
/* not within async bounds */
382
return 2;
383
}
384
385
int bfin_mem_access_type(unsigned long addr, unsigned long size)
386
{
387
int cpu = raw_smp_processor_id();
388
389
/* Check that things do not wrap around */
390
if (addr > ULONG_MAX - size)
391
return -EFAULT;
392
393
if (in_mem(addr, size, FIXED_CODE_START, physical_mem_end))
394
return BFIN_MEM_ACCESS_CORE;
395
396
if (in_mem_const(addr, size, L1_CODE_START, L1_CODE_LENGTH))
397
return cpu == 0 ? BFIN_MEM_ACCESS_ITEST : BFIN_MEM_ACCESS_IDMA;
398
if (in_mem_const(addr, size, L1_SCRATCH_START, L1_SCRATCH_LENGTH))
399
return cpu == 0 ? BFIN_MEM_ACCESS_CORE_ONLY : -EFAULT;
400
if (in_mem_const(addr, size, L1_DATA_A_START, L1_DATA_A_LENGTH))
401
return cpu == 0 ? BFIN_MEM_ACCESS_CORE : BFIN_MEM_ACCESS_IDMA;
402
if (in_mem_const(addr, size, L1_DATA_B_START, L1_DATA_B_LENGTH))
403
return cpu == 0 ? BFIN_MEM_ACCESS_CORE : BFIN_MEM_ACCESS_IDMA;
404
#ifdef COREB_L1_CODE_START
405
if (in_mem_const(addr, size, COREB_L1_CODE_START, COREB_L1_CODE_LENGTH))
406
return cpu == 1 ? BFIN_MEM_ACCESS_ITEST : BFIN_MEM_ACCESS_IDMA;
407
if (in_mem_const(addr, size, COREB_L1_SCRATCH_START, L1_SCRATCH_LENGTH))
408
return cpu == 1 ? BFIN_MEM_ACCESS_CORE_ONLY : -EFAULT;
409
if (in_mem_const(addr, size, COREB_L1_DATA_A_START, COREB_L1_DATA_A_LENGTH))
410
return cpu == 1 ? BFIN_MEM_ACCESS_CORE : BFIN_MEM_ACCESS_IDMA;
411
if (in_mem_const(addr, size, COREB_L1_DATA_B_START, COREB_L1_DATA_B_LENGTH))
412
return cpu == 1 ? BFIN_MEM_ACCESS_CORE : BFIN_MEM_ACCESS_IDMA;
413
#endif
414
if (in_mem_const(addr, size, L2_START, L2_LENGTH))
415
return BFIN_MEM_ACCESS_CORE;
416
417
if (addr >= SYSMMR_BASE)
418
return BFIN_MEM_ACCESS_CORE_ONLY;
419
420
switch (in_async(addr, size)) {
421
case 0: return -EFAULT;
422
case 1: return BFIN_MEM_ACCESS_CORE;
423
case 2: /* fall through */;
424
}
425
426
if (in_mem_const(addr, size, BOOT_ROM_START, BOOT_ROM_LENGTH))
427
return BFIN_MEM_ACCESS_CORE;
428
if (in_mem_const(addr, size, L1_ROM_START, L1_ROM_LENGTH))
429
return BFIN_MEM_ACCESS_DMA;
430
431
return -EFAULT;
432
}
433
434
#if defined(CONFIG_ACCESS_CHECK)
435
#ifdef CONFIG_ACCESS_OK_L1
436
__attribute__((l1_text))
437
#endif
438
/* Return 1 if access to memory range is OK, 0 otherwise */
439
int _access_ok(unsigned long addr, unsigned long size)
440
{
441
int aret;
442
443
if (size == 0)
444
return 1;
445
/* Check that things do not wrap around */
446
if (addr > ULONG_MAX - size)
447
return 0;
448
if (segment_eq(get_fs(), KERNEL_DS))
449
return 1;
450
#ifdef CONFIG_MTD_UCLINUX
451
if (1)
452
#else
453
if (0)
454
#endif
455
{
456
if (in_mem(addr, size, memory_start, memory_end))
457
return 1;
458
if (in_mem(addr, size, memory_mtd_end, physical_mem_end))
459
return 1;
460
# ifndef CONFIG_ROMFS_ON_MTD
461
if (0)
462
# endif
463
/* For XIP, allow user space to use pointers within the ROMFS. */
464
if (in_mem(addr, size, memory_mtd_start, memory_mtd_end))
465
return 1;
466
} else {
467
if (in_mem(addr, size, memory_start, physical_mem_end))
468
return 1;
469
}
470
471
if (in_mem(addr, size, (unsigned long)__init_begin, (unsigned long)__init_end))
472
return 1;
473
474
if (in_mem_const(addr, size, L1_CODE_START, L1_CODE_LENGTH))
475
return 1;
476
if (in_mem_const_off(addr, size, _etext_l1 - _stext_l1, L1_CODE_START, L1_CODE_LENGTH))
477
return 1;
478
if (in_mem_const_off(addr, size, _ebss_l1 - _sdata_l1, L1_DATA_A_START, L1_DATA_A_LENGTH))
479
return 1;
480
if (in_mem_const_off(addr, size, _ebss_b_l1 - _sdata_b_l1, L1_DATA_B_START, L1_DATA_B_LENGTH))
481
return 1;
482
#ifdef COREB_L1_CODE_START
483
if (in_mem_const(addr, size, COREB_L1_CODE_START, COREB_L1_CODE_LENGTH))
484
return 1;
485
if (in_mem_const(addr, size, COREB_L1_SCRATCH_START, L1_SCRATCH_LENGTH))
486
return 1;
487
if (in_mem_const(addr, size, COREB_L1_DATA_A_START, COREB_L1_DATA_A_LENGTH))
488
return 1;
489
if (in_mem_const(addr, size, COREB_L1_DATA_B_START, COREB_L1_DATA_B_LENGTH))
490
return 1;
491
#endif
492
493
#ifndef CONFIG_EXCEPTION_L1_SCRATCH
494
if (in_mem_const(addr, size, (unsigned long)l1_stack_base, l1_stack_len))
495
return 1;
496
#endif
497
498
aret = in_async(addr, size);
499
if (aret < 2)
500
return aret;
501
502
if (in_mem_const_off(addr, size, _ebss_l2 - _stext_l2, L2_START, L2_LENGTH))
503
return 1;
504
505
if (in_mem_const(addr, size, BOOT_ROM_START, BOOT_ROM_LENGTH))
506
return 1;
507
if (in_mem_const(addr, size, L1_ROM_START, L1_ROM_LENGTH))
508
return 1;
509
510
return 0;
511
}
512
EXPORT_SYMBOL(_access_ok);
513
#endif /* CONFIG_ACCESS_CHECK */
514
515