Sunday, August 27, 2006

System call in Blackfin - resend


================================================
arch/blackfin/mach-common/ints-priority-sc.c:

int init_arch_irq()
{

#ifndef CONFIG_KGDB
*pEVT0 = evt_emulation;
#==endif
*pEVT2 = evt_evt2;
*pEVT3 = trap;
*pEVT5 = evt_ivhw;
*pEVT6 = evt_timer;
*pEVT7 = evt_evt7;
*pEVT8 = evt_evt8;
*pEVT9 = evt_evt9;
*pEVT10 = evt_evt10;
*pEVT11 = evt_evt11;
*pEVT12 = evt_evt12;
*pEVT13 = evt_evt13;
*pEVT14 = evt14_softirq;
*pEVT15 = evt_system_call;
__builtin_bfin_csync();
}
=======================================================
arch/blackfin/mach-common/entry.S:

ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor
mode)*/
/* Since the kernel stack can be anywhere, it's not guaranteed to be
* covered by a CPLB. Switch to an exception stack; use RETN as a
* scratch register (for want of a better option).
*/
/----------------------------------
#define ENTRY(name) .globl name; ALIGN; name:
-----------------------------------/

retn = sp;
/-------------------------------
Use RETN just as a tmp register?
--------------------------------/

sp.l = exception_stack_top;
sp.h = exception_stack_top;
/------------------------------------
In entry.S
/* Put this in the kernel data section - that should always be covered
by
* a CPLB.
*/
exception_stack:
.rept 1024
.long 0;
.endr
exception_stack_top:
----------------------------------------/

/* Try to deal with syscalls quickly. */
[--sp] = ASTAT;
[--sp] = (R7:6, P5:4);
r7 = SEQSTAT; /* reason code is in bit 5:0 */
r6.l = lo(SEQSTAT_EXCAUSE);
r6.h = hi(SEQSTAT_EXCAUSE);
r7 = r7 & r6;
p5.h = extable;
p5.l = extable;
p4 = r7;
p5 = p5 + (p4 << 2);
p4 = [p5];
jump (p4);

/---------------------------------------------
What is the relationship between the extable and the exception handler
entry?? When is extable get initialized?
-----------------------------------------------/

badsys:
r7 = -ENOSYS; /* signextending enough */
[sp + PT_R0] = r7; /* return value from system call */
jump syscall_really_exit;

ENTRY(ex_syscall)
(R7:6,P5:4) = [sp++];
ASTAT = [sp++];
raise 15; /* invoked by TRAP #0, for sys call */
sp = retn;
rtx

==============================================
mach-comm/interrupt.S

/* interrupt routine for system_call - 15 */
ENTRY(_evt_system_call)
SAVE_CONTEXT_SYSCALL
#ifdef CONFIG_FRAME_POINTER
fp = 0;
#==endif
call system_call;
jump common_restore_context;
/------------------------------------
Note: It does not go through common_int_entry:
-------------------------------------/

==============================================
entry.S:

ENTRY(system_call)
/* Store IPEND */
p2.l = lo(IPEND);
p2.h = hi(IPEND);
csync;
r0 = [p2];
[sp + PT_IPEND] = r0;

/* Store RETS for now */
r0 = rets;
/--------------------------------
call system_call;
jump common_restore_context;
--------------------------------/

[sp + PT_RESERVED] = r0;
/* Set the stack for the current process */
r7 = sp;
r6.l = lo(ALIGN_PAGE_MASK);
r6.h = hi(ALIGN_PAGE_MASK);
r7 = r7 & r6; /*thread_info*/
p2 = r7;
p2 = [p2];

[p2+(TASK_THREAD+THREAD_KSP)] = sp;
#ifdef CONFIG_IPIPE
r0 = sp;
SP += -12;
call ___ipipe_syscall_root;
SP += 12;
cc = r0 == 1;
/--------------------------------
Should not pass to Linux, no tail work
------------------------------------/
if cc jump syscall_really_exit;
cc = r0 == -1;
/-------------------------------------
Should not pass to Linux, tail work (handling signal)
-------------------------------------/
if cc jump resume_userspace;
/-----------------------------------------
Should pass to Linux
------------------------------------------/
r3 = [sp + PT_R3];
r4 = [sp + PT_R4];
p0 = [sp + PT_ORIG_P0];
#==endif /* CONFIG_IPIPE */

/* Check the System Call */
r7 = __NR_syscall;
/*System call number is passed in P0 */
r5 = p0;
cc = r5 < r7;
if ! cc jump badsys;

/* Execute the appropriate system call */

p4 = r5;
p5.l = sys_call_table;
p5.h = sys_call_table;
p5 = p5 + (p4 << 2);
r0 = [sp + PT_R0];
r1 = [sp + PT_R1];
r2 = [sp + PT_R2];
p5 = [p5];

/* are we tracing syscalls?*/
r7 = sp;
r6.l = lo(ALIGN_PAGE_MASK);
r6.h = hi(ALIGN_PAGE_MASK);
r7 = r7 & r6;
p2 = r7;
r7 = [p2+TI_FLAGS];
CC = BITTST(r7,TIF_SYSCALL_TRACE);
if CC JUMP sys_trace;

[--sp] = r4;
[--sp] = r3;
SP += -12;
call (p5);
SP += 20;
[sp + PT_R0] = r0;

resume_userspace:
r7 = sp;
r4.l = lo(ALIGN_PAGE_MASK);
r4.h = hi(ALIGN_PAGE_MASK);
r7 = r7 & r4; /*thread_info->flags*/
p5 = r7;
resume_userspace_1:
/* Disable interrupts. */
[--sp] = reti;
reti = [sp++];

r7 = [p5 + TI_FLAGS];
r4.l = lo(_TIF_WORK_MASK);
r4.h = hi(_TIF_WORK_MASK);
r7 = r7 & r4;

syscall_resched:
cc = BITTST(r7, TIF_NEED_RESCHED);
if !cc jump syscall_sigpending;

/* Reenable interrupts. */
[--sp] = reti;
r0 = [sp++];

SP += -12;
call _schedule;
SP += 12;

jump resume_userspace_1;

syscall_sigpending:
cc = BITTST(r7, TIF_RESTORE_SIGMASK);
if cc jump syscall_do_signals;
cc = BITTST(r7, TIF_SIGPENDING);
if !cc jump syscall_really_exit;
syscall_do_signals:
/* Reenable interrupts. */
[--sp] = reti;
r0 = [sp++];

r0 = sp;
SP += -12;
call _do_signal;
SP += 12;

syscall_really_exit:
#ifdef CONFIG_IPIPE
[--sp] = reti;
r5 = [sp++];
#==endif /* CONFIG_IPIPE */
r5 = [sp + PT_RESERVED];
rets = r5;
rts;

sys_trace:
[--sp] = r3;
[--sp] = r2;
[--sp] = r1;
[--sp] = r0;
[--sp] = p5;
[--sp] = p2;
[--sp] = p1;
[--sp] = p0;
r1 = 0;
call _syscall_trace;
p0 = [sp++];
p1 = [sp++];
p2 = [sp++];
p5 = [sp++];
r0 = [sp++];
r1 = [sp++];
r2 = [sp++];
r3 = [sp++];

[--sp] = r4;
[--sp] = r3;
SP += -12;
call (p5);
SP += 20;
[sp + PT_R0] = r0;

[--sp] = r3;
[--sp] = r2;
[--sp] = r1;
[--sp] = r0;
[--sp] = p5;
[--sp] = p2;
[--sp] = p1;
[--sp] = p0;
r1 = 1;
call _syscall_trace;
p0 = [sp++];
p1 = [sp++];
p2 = [sp++];
p5 = [sp++];
r0 = [sp++];
r1 = [sp++];
r2 = [sp++];
r3 = [sp++];

jump resume_userspace;

ipipe-root.c
====================================================
asmlinkage int __ipipe_syscall_root(struct pt_regs *regs)
{
/---------------------------------------
r0 = sp; -- kernel stack
----------------------------------------/

ipipe_declare_cpuid;
unsigned long flags;

/*
* This routine either returns:
* 0 -- if the syscall is to be passed to Linux;
* 1 -- if the syscall should not be passed to Linux, and no
* tail work should be performed;
* -1 -- if the syscall should not be passed to Linux but the
* tail work has to be performed (for handling signals etc).
*/

if (__ipipe_event_pipelined_p(IPIPE_EVENT_SYSCALL) &&
__ipipe_dispatch_event(IPIPE_EVENT_SYSCALL,regs) > 0) {
/*
* We might enter here over a non-root domain and exit
* over the root one as a result of the syscall
* (i.e. by recycling the register set of the current
* context across the migration), so we need to fixup
* the interrupt flag upon return too, so that
* __ipipe_unstall_iret_root() resets the correct
* stall bit on exit.
*/
if (ipipe_current_domain == ipipe_root_domain && !in_atomic()) {
/*
* Sync pending VIRQs before _TIF_NEED_RESCHED
* is tested.
*/
ipipe_lock_cpu(flags);
if ((ipipe_root_domain->cpudata[cpuid].irq_pending_hi &
IPIPE_IRQMASK_VIRT) != 0)
__ipipe_sync_stage(IPIPE_IRQMASK_VIRT);
ipipe_unlock_cpu(flags);
return -1;
}
return 1;
}

return 0;
}

kernel/ipipe/core.c
==================================================================
/* __ipipe_dispatch_event() -- Low-level event dispatcher. */

int fastcall __ipipe_dispatch_event (unsigned event, void *data)
{
struct ipipe_domain *start_domain, *this_domain, *next_domain;
struct list_head *pos, *npos;
unsigned long flags;
ipipe_declare_cpuid;
int propagate = 1;

ipipe_lock_cpu(flags);

start_domain = this_domain = ipipe_percpu_domain[cpuid];

list_for_each_safe(pos,npos,&__ipipe_pipeline) {

next_domain = list_entry(pos,struct ipipe_domain,p_link);

/*
* Note: Domain migration may occur while running
* event or interrupt handlers, in which case the
* current register set is going to be recycled for a
* different domain than the initiating one. We do
* care for that, always tracking the current domain
* descriptor upon return from those handlers.
*/
if (next_domain->evhand[event] != NULL) {
ipipe_percpu_domain[cpuid] = next_domain;
ipipe_unlock_cpu(flags);
propagate = !next_domain->evhand[event](event,start_domain,data);
ipipe_lock_cpu(flags);
if (ipipe_percpu_domain[cpuid] != next_domain)
this_domain = ipipe_percpu_domain[cpuid];
}

if (next_domain != ipipe_root_domain && /* NEVER sync the root stage
here. */
next_domain->cpudata[cpuid].irq_pending_hi != 0 &&
!test_bit(IPIPE_STALL_FLAG,&next_domain->cpudata[cpuid].status)) {
ipipe_percpu_domain[cpuid] = next_domain;
__ipipe_sync_stage(IPIPE_IRQMASK_ANY);
ipipe_load_cpuid();
if (ipipe_percpu_domain[cpuid] != next_domain)
this_domain = ipipe_percpu_domain[cpuid];
}

ipipe_percpu_domain[cpuid] = this_domain;

if (next_domain == this_domain || !propagate)
break;
}

ipipe_unlock_cpu(flags);

return !propagate;
}

No comments:

Blog Archive