提交 ac919f08 编写于 作者: J James Hogan

metag: Traps

Add trap code for metag. At the lowest level Meta traps (and return from
interrupt instruction - RTI) simply swap the PC and PCX registers and
optionally toggle the interrupt status bit (ISTAT). Low level TBX code
in tbipcx.S handles the core context save, determine the TBX signal
number based on the core trigger that fired (using the TXSTATI status
register), and call TBX signal handlers (mostly in traps.c) via a vector
table.
Signed-off-by: NJames Hogan <james.hogan@imgtec.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
上级 a2c5d4ed
/*
* Copyright (C) 2012 Imagination Technologies Ltd.
*
* 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.
*/
#ifndef _ASM_METAG_SWITCH_H
#define _ASM_METAG_SWITCH_H
/* metag SWITCH codes */
#define __METAG_SW_PERM_BREAK 0x400002 /* compiled in breakpoint */
#define __METAG_SW_SYS_LEGACY 0x440000 /* legacy system calls */
#define __METAG_SW_SYS 0x440001 /* system calls */
/* metag SWITCH instruction encoding */
#define __METAG_SW_ENCODING(TYPE) (0xaf000000 | (__METAG_SW_##TYPE))
#endif /* _ASM_METAG_SWITCH_H */
/*
* Copyright (C) 2005,2008 Imagination Technologies
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
*/
#ifndef _METAG_TBIVECTORS_H
#define _METAG_TBIVECTORS_H
#ifndef __ASSEMBLY__
#include <asm/tbx.h>
typedef TBIRES (*kick_irq_func_t)(TBIRES, int, int, int, PTBI, int *);
extern TBIRES kick_handler(TBIRES, int, int, int, PTBI);
struct kick_irq_handler {
struct list_head list;
kick_irq_func_t func;
};
extern void kick_register_func(struct kick_irq_handler *);
extern void kick_unregister_func(struct kick_irq_handler *);
extern void head_end(TBIRES, unsigned long);
extern void restart_critical_section(TBIRES State);
extern TBIRES tail_end_sys(TBIRES, int, int *);
static inline TBIRES tail_end(TBIRES state)
{
return tail_end_sys(state, -1, NULL);
}
DECLARE_PER_CPU(PTBI, pTBI);
extern PTBI pTBI_get(unsigned int);
extern int ret_from_fork(TBIRES arg);
extern int do_page_fault(struct pt_regs *regs, unsigned long address,
unsigned int write_access, unsigned int trapno);
extern TBIRES __TBIUnExpXXX(TBIRES State, int SigNum, int Triggers, int Inst,
PTBI pTBI);
#endif
#endif /* _METAG_TBIVECTORS_H */
/*
* Copyright (C) 2009 Imagination Technologies
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
*
* The Meta KICK interrupt mechanism is generally a useful feature, so
* we provide an interface for registering multiple interrupt
* handlers. All the registered interrupt handlers are "chained". When
* a KICK interrupt is received the first function in the list is
* called. If that interrupt handler cannot handle the KICK the next
* one is called, then the next until someone handles it (or we run
* out of functions). As soon as one function handles the interrupt no
* other handlers are called.
*
* The only downside of chaining interrupt handlers is that each
* handler must be able to detect whether the KICK was intended for it
* or not. For example, when the IPI handler runs and it sees that
* there are no IPI messages it must not signal that the KICK was
* handled, thereby giving the other handlers a chance to run.
*
* The reason that we provide our own interface for calling KICK
* handlers instead of using the generic kernel infrastructure is that
* the KICK handlers require access to a CPU's pTBI structure. So we
* pass it as an argument.
*/
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/types.h>
#include <asm/traps.h>
/*
* All accesses/manipulations of kick_handlers_list should be
* performed while holding kick_handlers_lock.
*/
static DEFINE_SPINLOCK(kick_handlers_lock);
static LIST_HEAD(kick_handlers_list);
void kick_register_func(struct kick_irq_handler *kh)
{
unsigned long flags;
spin_lock_irqsave(&kick_handlers_lock, flags);
list_add_tail(&kh->list, &kick_handlers_list);
spin_unlock_irqrestore(&kick_handlers_lock, flags);
}
void kick_unregister_func(struct kick_irq_handler *kh)
{
unsigned long flags;
spin_lock_irqsave(&kick_handlers_lock, flags);
list_del(&kh->list);
spin_unlock_irqrestore(&kick_handlers_lock, flags);
}
TBIRES
kick_handler(TBIRES State, int SigNum, int Triggers, int Inst, PTBI pTBI)
{
struct kick_irq_handler *kh;
struct list_head *lh;
int handled = 0;
TBIRES ret;
head_end(State, ~INTS_OFF_MASK);
/* If we interrupted user code handle any critical sections. */
if (State.Sig.SaveMask & TBICTX_PRIV_BIT)
restart_critical_section(State);
trace_hardirqs_off();
/*
* There is no need to disable interrupts here because we
* can't nest KICK interrupts in a KICK interrupt handler.
*/
spin_lock(&kick_handlers_lock);
list_for_each(lh, &kick_handlers_list) {
kh = list_entry(lh, struct kick_irq_handler, list);
ret = kh->func(State, SigNum, Triggers, Inst, pTBI, &handled);
if (handled)
break;
}
spin_unlock(&kick_handlers_lock);
WARN_ON(!handled);
return tail_end(ret);
}
/* Pass a breakpoint through to Codescape */
#include <asm/tbx.h>
.text
.global ___TBIUnExpXXX
.type ___TBIUnExpXXX,function
___TBIUnExpXXX:
TSTT D0Ar2,#TBICTX_CRIT_BIT ! Result of nestable int call?
BZ $LTBINormCase ! UnExpXXX at background level
MOV D0Re0,TXMASKI ! Read TXMASKI
XOR TXMASKI,D1Re0,D1Re0 ! Turn off BGNDHALT handling!
OR D0Ar2,D0Ar2,D0Re0 ! Preserve bits cleared
$LTBINormCase:
MSETL [A0StP],D0Ar6,D0Ar4,D0Ar2 ! Save args on stack
SETL [A0StP++],D0Ar2,D1Ar1 ! Init area for returned values
SWITCH #0xC20208 ! Total stack frame size 8 Dwords
! write back size 2 Dwords
GETL D0Re0,D1Re0,[--A0StP] ! Get result
SUB A0StP,A0StP,#(8*3) ! Recover stack frame
MOV PC,D1RtP
.size ___TBIUnExpXXX,.-___TBIUnExpXXX
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册