Thursday, May 29, 2008

blackfin irq handler

 

/* Interrupt flows:
EVT table -->
INTERRUPT_ENTRY(N) -->
common_int_entry() -->
do_irq() -->
asm_do_IRQ() -->
generic_handle_irq() -->
irq_desc[irq]-> handler()
--> {
handle_simple_irq();
handle_level_irq();
...
} -> handle_IRQ_event() -->
action->handler() (request_irq() registers the real handler)

*/

/* ============Adam: init the EVT table ========================*/
mach-common/ints-priority.c:
-----------------------------
void __init init_exception_vectors(void)
{
SSYNC();

/* cannot program in software:
* evt0 - emulation (jtag)
* evt1 - reset
*/
bfin_write_EVT2(evt_nmi);
bfin_write_EVT3(trap);
bfin_write_EVT5(evt_ivhw);
bfin_write_EVT6(evt_timer);
bfin_write_EVT7(evt_evt7);
bfin_write_EVT8(evt_evt8);
bfin_write_EVT9(evt_evt9);
bfin_write_EVT10(evt_evt10);
bfin_write_EVT11(evt_evt11);
bfin_write_EVT12(evt_evt12);
bfin_write_EVT13(evt_evt13);
bfin_write_EVT14(evt14_softirq);
bfin_write_EVT15(evt_system_call);
CSYNC();
}

mach-common/interrupt.S
--------------------------------------------------------------------------------
/* Interrupt routine for evt2 (NMI).
* We don't actually use this, so just return.
* For inner circle type details, please see:
* http://docs.blackfin.uclinux.org/doku.php?id=linux:nmi
*/
ENTRY(_evt_nmi)
.weak _evt_nmi
rtn;
ENDPROC(_evt_nmi)

/* interrupt routine for core timer - 6 */
ENTRY(_evt_timer)
TIMER_INTERRUPT_ENTRY(EVT_IVTMR_P)

/* interrupt routine for evt7 - 7 */
ENTRY(_evt_evt7)
INTERRUPT_ENTRY(EVT_IVG7_P)
ENTRY(_evt_evt8)
INTERRUPT_ENTRY(EVT_IVG8_P)
ENTRY(_evt_evt9)
INTERRUPT_ENTRY(EVT_IVG9_P)
ENTRY(_evt_evt10)
INTERRUPT_ENTRY(EVT_IVG10_P)
ENTRY(_evt_evt11)
INTERRUPT_ENTRY(EVT_IVG11_P)
ENTRY(_evt_evt12)
INTERRUPT_ENTRY(EVT_IVG12_P)
ENTRY(_evt_evt13)
INTERRUPT_ENTRY(EVT_IVG13_P)


include/asm-blackfin/entry.h:
----------------------------------------------------------------------------
/*
* NOTE! The single-stepping code assumes that all interrupt handlers
* start by saving SYSCFG on the stack with their first instruction.
*/

/* This one is used for exceptions, emulation, and NMI. It doesn't push
RETI and doesn't do cli. */
#define SAVE_ALL_SYS save_context_no_interrupts
/* This is used for all normal interrupts. It saves a minimum of registers
to the stack, loads the IRQ number, and jumps to common code. */
#define INTERRUPT_ENTRY(N) \
[--sp] = SYSCFG; \
\
[--sp] = P0; /*orig_p0*/ \
[--sp] = R0; /*orig_r0*/ \
[--sp] = (R7:0,P5:0); \
R0 = (N); \
jump __common_int_entry;

/* For timer interrupts, we need to save IPEND, since the user_mode
macro accesses it to determine where to account time. */
#define TIMER_INTERRUPT_ENTRY(N) \
[--sp] = SYSCFG; \
\
[--sp] = P0; /*orig_p0*/ \
[--sp] = R0; /*orig_r0*/ \
[--sp] = (R7:0,P5:0); \
p0.l = lo(IPEND); \
p0.h = hi(IPEND); \
r1 = [p0]; \
R0 = (N); \
jump __common_int_entry;



mach-common/interrupt.S
--------------------------------------------------------------------------------
/* Common interrupt entry code. First we do CLI, then push
* RETI, to keep interrupts disabled, but to allow this state to be changed
* by local_bh_enable.
* R0 contains the interrupt number, while R1 may contain the value of IPEND,
* or garbage if IPEND won't be needed by the ISR. */
__common_int_entry:
[--sp] = fp;
[--sp] = usp;

[--sp] = i0;
[--sp] = i1;
[--sp] = i2;
[--sp] = i3;

[--sp] = m0;
[--sp] = m1;
[--sp] = m2;
[--sp] = m3;

[--sp] = l0;
[--sp] = l1;
[--sp] = l2;
[--sp] = l3;

[--sp] = b0;
[--sp] = b1;
[--sp] = b2;
[--sp] = b3;
[--sp] = a0.x;
[--sp] = a0.w;
[--sp] = a1.x;
[--sp] = a1.w;

[--sp] = LC0;
[--sp] = LC1;
[--sp] = LT0;
[--sp] = LT1;
[--sp] = LB0;
[--sp] = LB1;

[--sp] = ASTAT;

[--sp] = r0; /* Skip reserved */
[--sp] = RETS;
r2 = RETI;
[--sp] = r2;
[--sp] = RETX;
[--sp] = RETN;
[--sp] = RETE;
[--sp] = SEQSTAT;
[--sp] = r1; /* IPEND - R1 may or may not be set up before jumping here. */

/* Switch to other method of keeping interrupts disabled. */
#ifdef CONFIG_DEBUG_HWERR
r1 = 0x3f;
sti r1;
#else
cli r1;
#endif
[--sp] = RETI; /* orig_pc */
/* Clear all L registers. */
r1 = 0 (x);
l0 = r1;
l1 = r1;
l2 = r1;
l3 = r1;
#ifdef CONFIG_FRAME_POINTER
fp = 0;
#endif

#if ANOMALY_05000283 || ANOMALY_05000315
cc = r7 == r7;
p5.h = HI(CHIPID);
p5.l = LO(CHIPID);
if cc jump 1f;
r7.l = W[p5];
1:
#endif
r1 = sp;
SP += -12;
call _do_irq;
SP += 12;
call _return_from_int;
.Lcommon_restore_context:
RESTORE_CONTEXT
rti;

/* Adam: ====================== do_irq() =========================*/
mach-common/ints-priority.c
----------------------------------------------------------------------
#ifdef CONFIG_DO_IRQ_L1
__attribute__((l1_text))
#endif
void do_irq(int vec, struct pt_regs *fp)
{
if (vec == EVT_IVTMR_P) {
vec = IRQ_CORETMR;
} else {
struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst;
struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop;
#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561)
unsigned long sic_status[3];

sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
#ifdef CONFIG_BF54x
sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
#endif
for (;; ivg++) {
if (ivg >= ivg_stop) {
atomic_inc(&num_spurious);
return;
}
if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag)
break;
}
#else
unsigned long sic_status;

sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();

for (;; ivg++) {
if (ivg >= ivg_stop) {
atomic_inc(&num_spurious);
return;
} else if (sic_status & ivg->isrflag)
break;
}
#endif
vec = ivg->irqno;
}
asm_do_IRQ(vec, fp);

#ifdef CONFIG_KGDB
kgdb_process_breakpoint();
#endif
}

asm/kernel/irqchip.c
-----------------------------------------------------------------------------------
#ifdef CONFIG_DO_IRQ_L1
__attribute__((l1_text))
#endif
asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
{
struct pt_regs *old_regs;
struct irq_desc *desc = irq_desc + irq;
unsigned short pending, other_ints;

old_regs = set_irq_regs(regs);

/*
* Some hardware gives randomly wrong interrupts. Rather
* than crashing, do something sensible.
*/
if (irq >= NR_IRQS)
desc = &bad_irq_desc;

irq_enter();

generic_handle_irq(irq);

/* If we're the only interrupt running (ignoring IRQ15 which is for
syscalls), lower our priority to IRQ14 so that softirqs run at
that level. If there's another, lower-level interrupt, irq_exit
will defer softirqs to that. */
CSYNC();
pending = bfin_read_IPEND() & ~0x8000;
other_ints = pending & (pending - 1);
if (other_ints == 0)
lower_to_irq14();
irq_exit();

set_irq_regs(old_regs);
}

include/linux/irq.h:
----------------------------------------------------------------------------------------
/*
* Architectures call this to let the generic IRQ layer
* handle an interrupt. If the descriptor is attached to an
* irqchip-style controller then we call the ->handle_irq() handler,
* and it calls __do_IRQ() if it's attached to an irqtype-style controller.
*/
static inline void generic_handle_irq(unsigned int irq)
{
struct irq_desc *desc = irq_desc + irq;

#ifdef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ
desc->handle_irq(irq, desc);
#else
if (likely(desc->handle_irq))
desc->handle_irq(irq, desc);
else
__do_IRQ(irq);
#endif
}

/* Adam: =============== Global struct irq_desc irq_desc[NR_IRQS], struct irqchip ======== */

kernel/irq/handle.c
-----------------------------------------------------------------------
/*
* Linux has a controller-independent interrupt architecture.
* Every controller has a 'controller-template', that is used
* by the main code to do the right thing. Each driver-visible
* interrupt source is transparently wired to the appropriate
* controller. Thus drivers need not be aware of the
* interrupt-controller.
*
* The code is designed to be easily extended with new/different
* interrupt controllers, without having to do assembly magic or
* having to touch the generic code.
*
* Controller mappings for all interrupt sources:
*/
struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
[0 ... NR_IRQS-1] = {
.status = IRQ_DISABLED,
.chip = &no_irq_chip,
.handle_irq = handle_bad_irq,
.depth = 1,
.lock = __SPIN_LOCK_UNLOCKED(irq_desc->lock),
#ifdef CONFIG_SMP
.affinity = CPU_MASK_ALL
#endif
}
};

/**
* struct irq_desc - interrupt descriptor
*
* @handle_irq: highlevel irq-events handler [if NULL, __do_IRQ()]
* @chip: low level interrupt hardware access
* @msi_desc: MSI descriptor
* @handler_data: per-IRQ data for the irq_chip methods
* @chip_data: platform-specific per-chip private data for the chip
* methods, to allow shared chip implementations
* @action: the irq action chain
* @status: status information
* @depth: disable-depth, for nested irq_disable() calls
* @wake_depth: enable depth, for multiple set_irq_wake() callers
* @irq_count: stats field to detect stalled irqs
* @irqs_unhandled: stats field for spurious unhandled interrupts
* @last_unhandled: aging timer for unhandled count
* @lock: locking for SMP
* @affinity: IRQ affinity on SMP
* @cpu: cpu index useful for balancing
* @pending_mask: pending rebalanced interrupts
* @dir: /proc/irq/ procfs entry
* @affinity_entry: /proc/irq/smp_affinity procfs entry on SMP
* @name: flow handler name for /proc/interrupts output
*/
struct irq_desc {
irq_flow_handler_t handle_irq;
struct irq_chip *chip;
struct msi_desc *msi_desc;
void *handler_data;
void *chip_data;
struct irqaction *action; /* IRQ action list */
unsigned int status; /* IRQ status */

unsigned int depth; /* nested irq disables */
unsigned int wake_depth; /* nested wake enables */
unsigned int irq_count; /* For detecting broken IRQs */
unsigned int irqs_unhandled;
unsigned long last_unhandled; /* Aging timer for unhandled count */
spinlock_t lock;
#ifdef CONFIG_SMP
cpumask_t affinity;
unsigned int cpu;
#endif
#if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE)
cpumask_t pending_mask;
#endif
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *dir;
#endif
const char *name;
} ____cacheline_internodealigned_in_smp;


arch/blackfin/mach-common/ints-priority.c:
------------------------------------------------------------
static struct irq_chip bfin_core_irqchip = {
.ack = bfin_ack_noop,
.mask = bfin_core_mask_irq,
.unmask = bfin_core_unmask_irq,
};

static struct irq_chip bfin_internal_irqchip = {
.ack = bfin_ack_noop,
.mask = bfin_internal_mask_irq,
.unmask = bfin_internal_unmask_irq,
.mask_ack = bfin_internal_mask_irq,
.disable = bfin_internal_mask_irq,
.enable = bfin_internal_unmask_irq,
#ifdef CONFIG_PM
.set_wake = bfin_internal_set_wake,
#endif
};

static struct irq_chip bfin_generic_error_irqchip = {
.ack = bfin_ack_noop,
.mask_ack = bfin_generic_error_mask_irq,
.mask = bfin_generic_error_mask_irq,
.unmask = bfin_generic_error_unmask_irq,
};


static struct irq_chip bfin_gpio_irqchip = {
.ack = bfin_gpio_ack_irq,
.mask = bfin_gpio_mask_irq,
.mask_ack = bfin_gpio_mask_ack_irq,
.unmask = bfin_gpio_unmask_irq,
.set_type = bfin_gpio_irq_type,
.startup = bfin_gpio_irq_startup,
.shutdown = bfin_gpio_irq_shutdown,
#ifdef CONFIG_PM
.set_wake = bfin_gpio_set_wake,
#endif
};


/* Adam: =============== How everything get initialized ======== */

blackfin/kernel/irqchip.c:
-------------------------------------------------------
void __init init_IRQ(void)
{
struct irq_desc *desc;
int irq;

spin_lock_init(&irq_controller_lock);
for (irq = 0, desc = irq_desc; irq < NR_IRQS; irq++, desc++) {
*desc = bad_irq_desc;
}

init_arch_irq();

#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
/* Now that evt_ivhw is set up, turn this on */
trace_buff_offset = 0;
bfin_write_TBUFCTL(BFIN_TRACE_ON);
printk(KERN_INFO "Hardware Trace expanded to %ik\n",
1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN);
#endif
}

blackfin/mach-common/ints-prioirty.c
-------------------------------------------------------------
/*
* This function should be called during kernel startup to initialize
* the BFin IRQ handling routines.
*/
int __init init_arch_irq(void)
{
int irq;
unsigned long ilat = 0;
/* Disable all the peripheral intrs - page 4-29 HW Ref manual */
#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561)
bfin_write_SIC_IMASK0(SIC_UNMASK_ALL);
bfin_write_SIC_IMASK1(SIC_UNMASK_ALL);
# ifdef CONFIG_BF54x
bfin_write_SIC_IMASK2(SIC_UNMASK_ALL);
# endif
#else
bfin_write_SIC_IMASK(SIC_UNMASK_ALL);
#endif

local_irq_disable();

#ifdef CONFIG_BF54x
# ifdef CONFIG_PINTx_REASSIGN
pint[0]->assign = CONFIG_PINT0_ASSIGN;
pint[1]->assign = CONFIG_PINT1_ASSIGN;
pint[2]->assign = CONFIG_PINT2_ASSIGN;
pint[3]->assign = CONFIG_PINT3_ASSIGN;
# endif
/* Whenever PINTx_ASSIGN is altered init_pint_lut() must be executed! */
init_pint_lut();
#endif

for (irq = 0; irq <= SYS_IRQS; irq++) {
if (irq <= IRQ_CORETMR)
set_irq_chip(irq, &bfin_core_irqchip);
else
set_irq_chip(irq, &bfin_internal_irqchip);

switch (irq) {
#if defined(CONFIG_BF53x)
case IRQ_PROG_INTA:
# if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
case IRQ_MAC_RX:
# endif
#elif defined(CONFIG_BF54x)
case IRQ_PINT0:
case IRQ_PINT1:
case IRQ_PINT2:
case IRQ_PINT3:
#elif defined(CONFIG_BF52x)
case IRQ_PORTF_INTA:
case IRQ_PORTG_INTA:
case IRQ_PORTH_INTA:
#elif defined(CONFIG_BF561)
case IRQ_PROG0_INTA:
case IRQ_PROG1_INTA:
case IRQ_PROG2_INTA:
#endif
set_irq_chained_handler(irq,
bfin_demux_gpio_irq);
break;
#ifdef BF537_GENERIC_ERROR_INT_DEMUX
case IRQ_GENERIC_ERROR:
set_irq_handler(irq, bfin_demux_error_irq);

break;
#endif
default:
set_irq_handler(irq, handle_simple_irq);
break;
}
}

#ifdef BF537_GENERIC_ERROR_INT_DEMUX
for (irq = IRQ_PPI_ERROR; irq <= IRQ_UART1_ERROR; irq++)
set_irq_chip_and_handler(irq, &bfin_generic_error_irqchip,
handle_level_irq);
#endif

/* if configured as edge, then will be changed to do_edge_IRQ */
for (irq = GPIO_IRQ_BASE; irq < NR_IRQS; irq++)
set_irq_chip_and_handler(irq, &bfin_gpio_irqchip,
handle_level_irq);


bfin_write_IMASK(0);
CSYNC();
ilat = bfin_read_ILAT();
CSYNC();
bfin_write_ILAT(ilat);
CSYNC();

printk(KERN_INFO "Configuring Blackfin Priority Driven Interrupts\n");
/* IMASK=xxx is equivalent to STI xx or irq_flags=xx,
* local_irq_enable()
*/
program_IAR();
/* Therefore it's better to setup IARs before interrupts enabled */
search_IAR();

/* Enable interrupts IVG7-15 */
irq_flags = irq_flags | IMASK_IVG15 |
IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |
IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW;

#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561)
bfin_write_SIC_IWR0(IWR_ENABLE_ALL);
bfin_write_SIC_IWR1(IWR_ENABLE_ALL);
# ifdef CONFIG_BF54x
bfin_write_SIC_IWR2(IWR_ENABLE_ALL);
# endif
#else
bfin_write_SIC_IWR(IWR_ENABLE_ALL);
#endif



return 0;
}

kernel/irq/chip.c:
------------------------------------------------------
/**
* handle_simple_irq - Simple and software-decoded IRQs.
* @irq: the interrupt number
* @desc: the interrupt description structure for this irq
*
* Simple interrupts are either sent from a demultiplexing interrupt
* handler or come from hardware, where no interrupt hardware control
* is necessary.
*
* Note: The caller is expected to handle the ack, clear, mask and
* unmask issues if necessary.
*/
void fastcall
handle_simple_irq(unsigned int irq, struct irq_desc *desc)
{
struct irqaction *action;
irqreturn_t action_ret;
const unsigned int cpu = smp_processor_id();

spin_lock(&desc->lock);

if (unlikely(desc->status & IRQ_INPROGRESS))
goto out_unlock;
desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
kstat_cpu(cpu).irqs[irq]++;

action = desc->action;
if (unlikely(!action || (desc->status & IRQ_DISABLED)))
goto out_unlock;

desc->status |= IRQ_INPROGRESS;
spin_unlock(&desc->lock);

action_ret = handle_IRQ_event(irq, action);
if (!noirqdebug)
note_interrupt(irq, desc, action_ret);

spin_lock(&desc->lock);
desc->status &= ~IRQ_INPROGRESS;
out_unlock:
spin_unlock(&desc->lock);
}

/**
* handle_level_irq - Level type irq handler
* @irq: the interrupt number
* @desc: the interrupt description structure for this irq
*
* Level type interrupts are active as long as the hardware line has
* the active level. This may require to mask the interrupt and unmask
* it after the associated handler has acknowledged the device, so the
* interrupt line is back to inactive.
*/
void fastcall
handle_level_irq(unsigned int irq, struct irq_desc *desc)
{
unsigned int cpu = smp_processor_id();
struct irqaction *action;
irqreturn_t action_ret;

spin_lock(&desc->lock);
mask_ack_irq(desc, irq);

if (unlikely(desc->status & IRQ_INPROGRESS))
goto out_unlock;
desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
kstat_cpu(cpu).irqs[irq]++;

/*
* If its disabled or no action available
* keep it masked and get out of here
*/
action = desc->action;
if (unlikely(!action || (desc->status & IRQ_DISABLED)))
goto out_unlock;

desc->status |= IRQ_INPROGRESS;
spin_unlock(&desc->lock);

action_ret = handle_IRQ_event(irq, action);
if (!noirqdebug)
note_interrupt(irq, desc, action_ret);

spin_lock(&desc->lock);
desc->status &= ~IRQ_INPROGRESS;
if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
desc->chip->unmask(irq);
out_unlock:
spin_unlock(&desc->lock);
}

kernel/irq/handle.c:
------------------------------------------------------
/**
* handle_IRQ_event - irq action chain handler
* @irq: the interrupt number
* @action: the interrupt action chain for this irq
*
* Handles the action chain of an irq event
*/
irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
{
irqreturn_t ret, retval = IRQ_NONE;
unsigned int status = 0;

handle_dynamic_tick(action);

if (!(action->flags & IRQF_DISABLED))
local_irq_enable_in_hardirq();

do {
ret = action->handler(irq, action->dev_id);
if (ret == IRQ_HANDLED)
status |= action->flags;
retval |= ret;
action = action->next;
} while (action);

if (status & IRQF_SAMPLE_RANDOM)
add_interrupt_randomness(irq);
local_irq_disable();

return retval;
}

 

/* Interrupt flows:
EVT table -->
INTERRUPT_ENTRY(N) -->
common_int_entry() -->
do_irq() -->
asm_do_IRQ() -->
generic_handle_irq() -->
irq_desc[irq]-> handler()
--> {
handle_simple_irq();
handle_level_irq();
...
} -> handle_IRQ_event() -->
action->handler() (request_irq() registers the real handler)

*/

/* ============Adam: init the EVT table ========================*/
mach-common/ints-priority.c:
-----------------------------
void __init init_exception_vectors(void)
{
SSYNC();

/* cannot program in software:
* evt0 - emulation (jtag)
* evt1 - reset
*/
bfin_write_EVT2(evt_nmi);
bfin_write_EVT3(trap);
bfin_write_EVT5(evt_ivhw);
bfin_write_EVT6(evt_timer);
bfin_write_EVT7(evt_evt7);
bfin_write_EVT8(evt_evt8);
bfin_write_EVT9(evt_evt9);
bfin_write_EVT10(evt_evt10);
bfin_write_EVT11(evt_evt11);
bfin_write_EVT12(evt_evt12);
bfin_write_EVT13(evt_evt13);
bfin_write_EVT14(evt14_softirq);
bfin_write_EVT15(evt_system_call);
CSYNC();
}

mach-common/interrupt.S
--------------------------------------------------------------------------------
/* Interrupt routine for evt2 (NMI).
* We don't actually use this, so just return.
* For inner circle type details, please see:
* http://docs.blackfin.uclinux.org/doku.php?id=linux:nmi
*/
ENTRY(_evt_nmi)
.weak _evt_nmi
rtn;
ENDPROC(_evt_nmi)

/* interrupt routine for core timer - 6 */
ENTRY(_evt_timer)
TIMER_INTERRUPT_ENTRY(EVT_IVTMR_P)

/* interrupt routine for evt7 - 7 */
ENTRY(_evt_evt7)
INTERRUPT_ENTRY(EVT_IVG7_P)
ENTRY(_evt_evt8)
INTERRUPT_ENTRY(EVT_IVG8_P)
ENTRY(_evt_evt9)
INTERRUPT_ENTRY(EVT_IVG9_P)
ENTRY(_evt_evt10)
INTERRUPT_ENTRY(EVT_IVG10_P)
ENTRY(_evt_evt11)
INTERRUPT_ENTRY(EVT_IVG11_P)
ENTRY(_evt_evt12)
INTERRUPT_ENTRY(EVT_IVG12_P)
ENTRY(_evt_evt13)
INTERRUPT_ENTRY(EVT_IVG13_P)


include/asm-blackfin/entry.h:
----------------------------------------------------------------------------
/*
* NOTE! The single-stepping code assumes that all interrupt handlers
* start by saving SYSCFG on the stack with their first instruction.
*/

/* This one is used for exceptions, emulation, and NMI. It doesn't push
RETI and doesn't do cli. */
#define SAVE_ALL_SYS save_context_no_interrupts
/* This is used for all normal interrupts. It saves a minimum of registers
to the stack, loads the IRQ number, and jumps to common code. */
#define INTERRUPT_ENTRY(N) \
[--sp] = SYSCFG; \
\
[--sp] = P0; /*orig_p0*/ \
[--sp] = R0; /*orig_r0*/ \
[--sp] = (R7:0,P5:0); \
R0 = (N); \
jump __common_int_entry;

/* For timer interrupts, we need to save IPEND, since the user_mode
macro accesses it to determine where to account time. */
#define TIMER_INTERRUPT_ENTRY(N) \
[--sp] = SYSCFG; \
\
[--sp] = P0; /*orig_p0*/ \
[--sp] = R0; /*orig_r0*/ \
[--sp] = (R7:0,P5:0); \
p0.l = lo(IPEND); \
p0.h = hi(IPEND); \
r1 = [p0]; \
R0 = (N); \
jump __common_int_entry;



mach-common/interrupt.S
--------------------------------------------------------------------------------
/* Common interrupt entry code. First we do CLI, then push
* RETI, to keep interrupts disabled, but to allow this state to be changed
* by local_bh_enable.
* R0 contains the interrupt number, while R1 may contain the value of IPEND,
* or garbage if IPEND won't be needed by the ISR. */
__common_int_entry:
[--sp] = fp;
[--sp] = usp;

[--sp] = i0;
[--sp] = i1;
[--sp] = i2;
[--sp] = i3;

[--sp] = m0;
[--sp] = m1;
[--sp] = m2;
[--sp] = m3;

[--sp] = l0;
[--sp] = l1;
[--sp] = l2;
[--sp] = l3;

[--sp] = b0;
[--sp] = b1;
[--sp] = b2;
[--sp] = b3;
[--sp] = a0.x;
[--sp] = a0.w;
[--sp] = a1.x;
[--sp] = a1.w;

[--sp] = LC0;
[--sp] = LC1;
[--sp] = LT0;
[--sp] = LT1;
[--sp] = LB0;
[--sp] = LB1;

[--sp] = ASTAT;

[--sp] = r0; /* Skip reserved */
[--sp] = RETS;
r2 = RETI;
[--sp] = r2;
[--sp] = RETX;
[--sp] = RETN;
[--sp] = RETE;
[--sp] = SEQSTAT;
[--sp] = r1; /* IPEND - R1 may or may not be set up before jumping here. */

/* Switch to other method of keeping interrupts disabled. */
#ifdef CONFIG_DEBUG_HWERR
r1 = 0x3f;
sti r1;
#else
cli r1;
#endif
[--sp] = RETI; /* orig_pc */
/* Clear all L registers. */
r1 = 0 (x);
l0 = r1;
l1 = r1;
l2 = r1;
l3 = r1;
#ifdef CONFIG_FRAME_POINTER
fp = 0;
#endif

#if ANOMALY_05000283 || ANOMALY_05000315
cc = r7 == r7;
p5.h = HI(CHIPID);
p5.l = LO(CHIPID);
if cc jump 1f;
r7.l = W[p5];
1:
#endif
r1 = sp;
SP += -12;
call _do_irq;
SP += 12;
call _return_from_int;
.Lcommon_restore_context:
RESTORE_CONTEXT
rti;

/* Adam: ====================== do_irq() =========================*/
mach-common/ints-priority.c
----------------------------------------------------------------------
#ifdef CONFIG_DO_IRQ_L1
__attribute__((l1_text))
#endif
void do_irq(int vec, struct pt_regs *fp)
{
if (vec == EVT_IVTMR_P) {
vec = IRQ_CORETMR;
} else {
struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst;
struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop;
#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561)
unsigned long sic_status[3];

sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
#ifdef CONFIG_BF54x
sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
#endif
for (;; ivg++) {
if (ivg >= ivg_stop) {
atomic_inc(&num_spurious);
return;
}
if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag)
break;
}
#else
unsigned long sic_status;

sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();

for (;; ivg++) {
if (ivg >= ivg_stop) {
atomic_inc(&num_spurious);
return;
} else if (sic_status & ivg->isrflag)
break;
}
#endif
vec = ivg->irqno;
}
asm_do_IRQ(vec, fp);

#ifdef CONFIG_KGDB
kgdb_process_breakpoint();
#endif
}

asm/kernel/irqchip.c
-----------------------------------------------------------------------------------
#ifdef CONFIG_DO_IRQ_L1
__attribute__((l1_text))
#endif
asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
{
struct pt_regs *old_regs;
struct irq_desc *desc = irq_desc + irq;
unsigned short pending, other_ints;

old_regs = set_irq_regs(regs);

/*
* Some hardware gives randomly wrong interrupts. Rather
* than crashing, do something sensible.
*/
if (irq >= NR_IRQS)
desc = &bad_irq_desc;

irq_enter();

generic_handle_irq(irq);

/* If we're the only interrupt running (ignoring IRQ15 which is for
syscalls), lower our priority to IRQ14 so that softirqs run at
that level. If there's another, lower-level interrupt, irq_exit
will defer softirqs to that. */
CSYNC();
pending = bfin_read_IPEND() & ~0x8000;
other_ints = pending & (pending - 1);
if (other_ints == 0)
lower_to_irq14();
irq_exit();

set_irq_regs(old_regs);
}

include/linux/irq.h:
----------------------------------------------------------------------------------------
/*
* Architectures call this to let the generic IRQ layer
* handle an interrupt. If the descriptor is attached to an
* irqchip-style controller then we call the ->handle_irq() handler,
* and it calls __do_IRQ() if it's attached to an irqtype-style controller.
*/
static inline void generic_handle_irq(unsigned int irq)
{
struct irq_desc *desc = irq_desc + irq;

#ifdef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ
desc->handle_irq(irq, desc);
#else
if (likely(desc->handle_irq))
desc->handle_irq(irq, desc);
else
__do_IRQ(irq);
#endif
}

/* Adam: =============== Global struct irq_desc irq_desc[NR_IRQS], struct irqchip ======== */

kernel/irq/handle.c
-----------------------------------------------------------------------
/*
* Linux has a controller-independent interrupt architecture.
* Every controller has a 'controller-template', that is used
* by the main code to do the right thing. Each driver-visible
* interrupt source is transparently wired to the appropriate
* controller. Thus drivers need not be aware of the
* interrupt-controller.
*
* The code is designed to be easily extended with new/different
* interrupt controllers, without having to do assembly magic or
* having to touch the generic code.
*
* Controller mappings for all interrupt sources:
*/
struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
[0 ... NR_IRQS-1] = {
.status = IRQ_DISABLED,
.chip = &no_irq_chip,
.handle_irq = handle_bad_irq,
.depth = 1,
.lock = __SPIN_LOCK_UNLOCKED(irq_desc->lock),
#ifdef CONFIG_SMP
.affinity = CPU_MASK_ALL
#endif
}
};

/**
* struct irq_desc - interrupt descriptor
*
* @handle_irq: highlevel irq-events handler [if NULL, __do_IRQ()]
* @chip: low level interrupt hardware access
* @msi_desc: MSI descriptor
* @handler_data: per-IRQ data for the irq_chip methods
* @chip_data: platform-specific per-chip private data for the chip
* methods, to allow shared chip implementations
* @action: the irq action chain
* @status: status information
* @depth: disable-depth, for nested irq_disable() calls
* @wake_depth: enable depth, for multiple set_irq_wake() callers
* @irq_count: stats field to detect stalled irqs
* @irqs_unhandled: stats field for spurious unhandled interrupts
* @last_unhandled: aging timer for unhandled count
* @lock: locking for SMP
* @affinity: IRQ affinity on SMP
* @cpu: cpu index useful for balancing
* @pending_mask: pending rebalanced interrupts
* @dir: /proc/irq/ procfs entry
* @affinity_entry: /proc/irq/smp_affinity procfs entry on SMP
* @name: flow handler name for /proc/interrupts output
*/
struct irq_desc {
irq_flow_handler_t handle_irq;
struct irq_chip *chip;
struct msi_desc *msi_desc;
void *handler_data;
void *chip_data;
struct irqaction *action; /* IRQ action list */
unsigned int status; /* IRQ status */

unsigned int depth; /* nested irq disables */
unsigned int wake_depth; /* nested wake enables */
unsigned int irq_count; /* For detecting broken IRQs */
unsigned int irqs_unhandled;
unsigned long last_unhandled; /* Aging timer for unhandled count */
spinlock_t lock;
#ifdef CONFIG_SMP
cpumask_t affinity;
unsigned int cpu;
#endif
#if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE)
cpumask_t pending_mask;
#endif
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *dir;
#endif
const char *name;
} ____cacheline_internodealigned_in_smp;


arch/blackfin/mach-common/ints-priority.c:
------------------------------------------------------------
static struct irq_chip bfin_core_irqchip = {
.ack = bfin_ack_noop,
.mask = bfin_core_mask_irq,
.unmask = bfin_core_unmask_irq,
};

static struct irq_chip bfin_internal_irqchip = {
.ack = bfin_ack_noop,
.mask = bfin_internal_mask_irq,
.unmask = bfin_internal_unmask_irq,
.mask_ack = bfin_internal_mask_irq,
.disable = bfin_internal_mask_irq,
.enable = bfin_internal_unmask_irq,
#ifdef CONFIG_PM
.set_wake = bfin_internal_set_wake,
#endif
};

static struct irq_chip bfin_generic_error_irqchip = {
.ack = bfin_ack_noop,
.mask_ack = bfin_generic_error_mask_irq,
.mask = bfin_generic_error_mask_irq,
.unmask = bfin_generic_error_unmask_irq,
};


static struct irq_chip bfin_gpio_irqchip = {
.ack = bfin_gpio_ack_irq,
.mask = bfin_gpio_mask_irq,
.mask_ack = bfin_gpio_mask_ack_irq,
.unmask = bfin_gpio_unmask_irq,
.set_type = bfin_gpio_irq_type,
.startup = bfin_gpio_irq_startup,
.shutdown = bfin_gpio_irq_shutdown,
#ifdef CONFIG_PM
.set_wake = bfin_gpio_set_wake,
#endif
};


/* Adam: =============== How everything get initialized ======== */

blackfin/kernel/irqchip.c:
-------------------------------------------------------
void __init init_IRQ(void)
{
struct irq_desc *desc;
int irq;

spin_lock_init(&irq_controller_lock);
for (irq = 0, desc = irq_desc; irq < NR_IRQS; irq++, desc++) {
*desc = bad_irq_desc;
}

init_arch_irq();

#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
/* Now that evt_ivhw is set up, turn this on */
trace_buff_offset = 0;
bfin_write_TBUFCTL(BFIN_TRACE_ON);
printk(KERN_INFO "Hardware Trace expanded to %ik\n",
1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN);
#endif
}

blackfin/mach-common/ints-prioirty.c
-------------------------------------------------------------
/*
* This function should be called during kernel startup to initialize
* the BFin IRQ handling routines.
*/
int __init init_arch_irq(void)
{
int irq;
unsigned long ilat = 0;
/* Disable all the peripheral intrs - page 4-29 HW Ref manual */
#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561)
bfin_write_SIC_IMASK0(SIC_UNMASK_ALL);
bfin_write_SIC_IMASK1(SIC_UNMASK_ALL);
# ifdef CONFIG_BF54x
bfin_write_SIC_IMASK2(SIC_UNMASK_ALL);
# endif
#else
bfin_write_SIC_IMASK(SIC_UNMASK_ALL);
#endif

local_irq_disable();

#ifdef CONFIG_BF54x
# ifdef CONFIG_PINTx_REASSIGN
pint[0]->assign = CONFIG_PINT0_ASSIGN;
pint[1]->assign = CONFIG_PINT1_ASSIGN;
pint[2]->assign = CONFIG_PINT2_ASSIGN;
pint[3]->assign = CONFIG_PINT3_ASSIGN;
# endif
/* Whenever PINTx_ASSIGN is altered init_pint_lut() must be executed! */
init_pint_lut();
#endif

for (irq = 0; irq <= SYS_IRQS; irq++) {
if (irq <= IRQ_CORETMR)
set_irq_chip(irq, &bfin_core_irqchip);
else
set_irq_chip(irq, &bfin_internal_irqchip);

switch (irq) {
#if defined(CONFIG_BF53x)
case IRQ_PROG_INTA:
# if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
case IRQ_MAC_RX:
# endif
#elif defined(CONFIG_BF54x)
case IRQ_PINT0:
case IRQ_PINT1:
case IRQ_PINT2:
case IRQ_PINT3:
#elif defined(CONFIG_BF52x)
case IRQ_PORTF_INTA:
case IRQ_PORTG_INTA:
case IRQ_PORTH_INTA:
#elif defined(CONFIG_BF561)
case IRQ_PROG0_INTA:
case IRQ_PROG1_INTA:
case IRQ_PROG2_INTA:
#endif
set_irq_chained_handler(irq,
bfin_demux_gpio_irq);
break;
#ifdef BF537_GENERIC_ERROR_INT_DEMUX
case IRQ_GENERIC_ERROR:
set_irq_handler(irq, bfin_demux_error_irq);

break;
#endif
default:
set_irq_handler(irq, handle_simple_irq);
break;
}
}

#ifdef BF537_GENERIC_ERROR_INT_DEMUX
for (irq = IRQ_PPI_ERROR; irq <= IRQ_UART1_ERROR; irq++)
set_irq_chip_and_handler(irq, &bfin_generic_error_irqchip,
handle_level_irq);
#endif

/* if configured as edge, then will be changed to do_edge_IRQ */
for (irq = GPIO_IRQ_BASE; irq < NR_IRQS; irq++)
set_irq_chip_and_handler(irq, &bfin_gpio_irqchip,
handle_level_irq);


bfin_write_IMASK(0);
CSYNC();
ilat = bfin_read_ILAT();
CSYNC();
bfin_write_ILAT(ilat);
CSYNC();

printk(KERN_INFO "Configuring Blackfin Priority Driven Interrupts\n");
/* IMASK=xxx is equivalent to STI xx or irq_flags=xx,
* local_irq_enable()
*/
program_IAR();
/* Therefore it's better to setup IARs before interrupts enabled */
search_IAR();

/* Enable interrupts IVG7-15 */
irq_flags = irq_flags | IMASK_IVG15 |
IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |
IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW;

#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561)
bfin_write_SIC_IWR0(IWR_ENABLE_ALL);
bfin_write_SIC_IWR1(IWR_ENABLE_ALL);
# ifdef CONFIG_BF54x
bfin_write_SIC_IWR2(IWR_ENABLE_ALL);
# endif
#else
bfin_write_SIC_IWR(IWR_ENABLE_ALL);
#endif

return 0;
}

kernel/irq/chip.c:
------------------------------------------------------
/**
* handle_simple_irq - Simple and software-decoded IRQs.
* @irq: the interrupt number
* @desc: the interrupt description structure for this irq
*
* Simple interrupts are either sent from a demultiplexing interrupt
* handler or come from hardware, where no interrupt hardware control
* is necessary.
*
* Note: The caller is expected to handle the ack, clear, mask and
* unmask issues if necessary.
*/
void fastcall
handle_simple_irq(unsigned int irq, struct irq_desc *desc)
{
struct irqaction *action;
irqreturn_t action_ret;
const unsigned int cpu = smp_processor_id();

spin_lock(&desc->lock);

if (unlikely(desc->status & IRQ_INPROGRESS))
goto out_unlock;
desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
kstat_cpu(cpu).irqs[irq]++;

action = desc->action;
if (unlikely(!action || (desc->status & IRQ_DISABLED)))
goto out_unlock;

desc->status |= IRQ_INPROGRESS;
spin_unlock(&desc->lock);

action_ret = handle_IRQ_event(irq, action);
if (!noirqdebug)
note_interrupt(irq, desc, action_ret);

spin_lock(&desc->lock);
desc->status &= ~IRQ_INPROGRESS;
out_unlock:
spin_unlock(&desc->lock);
}

/**
* handle_level_irq - Level type irq handler
* @irq: the interrupt number
* @desc: the interrupt description structure for this irq
*
* Level type interrupts are active as long as the hardware line has
* the active level. This may require to mask the interrupt and unmask
* it after the associated handler has acknowledged the device, so the
* interrupt line is back to inactive.
*/
void fastcall
handle_level_irq(unsigned int irq, struct irq_desc *desc)
{
unsigned int cpu = smp_processor_id();
struct irqaction *action;
irqreturn_t action_ret;

spin_lock(&desc->lock);
mask_ack_irq(desc, irq);

if (unlikely(desc->status & IRQ_INPROGRESS))
goto out_unlock;
desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
kstat_cpu(cpu).irqs[irq]++;

/*
* If its disabled or no action available
* keep it masked and get out of here
*/
action = desc->action;
if (unlikely(!action || (desc->status & IRQ_DISABLED)))
goto out_unlock;

desc->status |= IRQ_INPROGRESS;
spin_unlock(&desc->lock);

action_ret = handle_IRQ_event(irq, action);
if (!noirqdebug)
note_interrupt(irq, desc, action_ret);

spin_lock(&desc->lock);
desc->status &= ~IRQ_INPROGRESS;
if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
desc->chip->unmask(irq);
out_unlock:
spin_unlock(&desc->lock);
}

kernel/irq/handle.c:
------------------------------------------------------
/**
* handle_IRQ_event - irq action chain handler
* @irq: the interrupt number
* @action: the interrupt action chain for this irq
*
* Handles the action chain of an irq event
*/
irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
{
irqreturn_t ret, retval = IRQ_NONE;
unsigned int status = 0;

handle_dynamic_tick(action);

if (!(action->flags & IRQF_DISABLED))
local_irq_enable_in_hardirq();

do {
ret = action->handler(irq, action->dev_id);
if (ret == IRQ_HANDLED)
status |= action->flags;
retval |= ret;
action = action->next;
} while (action);

if (status & IRQF_SAMPLE_RANDOM)
add_interrupt_randomness(irq);
local_irq_disable();

return retval;
}

Thursday, May 08, 2008

Using expr

http://www.faqs.org/docs/abs/HTML/moreadv.html

Example 12-6. Using expr

   1 #!/bin/bash
2
3 # Demonstrating some of the uses of 'expr'
4 # =======================================
5
6 echo
7
8 # Arithmetic Operators
9 # ---------- ---------
10
11 echo "Arithmetic Operators"
12 echo
13 a=`expr 5 + 3`
14 echo "5 + 3 = $a"
15
16 a=`expr $a + 1`
17 echo
18 echo "a + 1 = $a"
19 echo "(incrementing a variable)"
20
21 a=`expr 5 % 3`
22 # modulo
23 echo
24 echo "5 mod 3 = $a"
25
26 echo
27 echo
28
29 # Logical Operators
30 # ------- ---------
31
32 # Returns 1 if true, 0 if false,
33 #+ opposite of normal Bash convention.
34
35 echo "Logical Operators"
36 echo
37
38 x=24
39 y=25
40 b=`expr $x = $y` # Test equality.
41 echo "b = $b" # 0 ( $x -ne $y )
42 echo
43
44 a=3
45 b=`expr $a \> 10`
46 echo 'b=`expr $a \> 10`, therefore...'
47 echo "If a > 10, b = 0 (false)"
48 echo "b = $b" # 0 ( 3 ! -gt 10 )
49 echo
50
51 b=`expr $a \< 10`
52 echo "If a < 10, b = 1 (true)"
53 echo "b = $b" # 1 ( 3 -lt 10 )
54 echo
55 # Note escaping of operators.
56
57 b=`expr $a \<= 3`
58 echo "If a <= 3, b = 1 (true)"
59 echo "b = $b" # 1 ( 3 -le 3 )
60 # There is also a "\>=" operator (greater than or equal to).
61
62
63 echo
64 echo
65
66 # Comparison Operators
67 # ---------- ---------
68
69 echo "Comparison Operators"
70 echo
71 a=zipper
72 echo "a is $a"
73 if [ `expr $a = snap` ]
74 # Force re-evaluation of variable 'a'
75 then
76 echo "a is not zipper"
77 fi
78
79 echo
80 echo
81
82
83
84 # String Operators
85 # ------ ---------
86
87 echo "String Operators"
88 echo
89
90 a=1234zipper43231
91 echo "The string being operated upon is \"$a\"."
92
93 # length: length of string
94 b=`expr length $a`
95 echo "Length of \"$a\" is $b."
96
97 # index: position of first character in substring
98 # that matches a character in string
99 b=`expr index $a 23`
100 echo "Numerical position of first \"2\" in \"$a\" is \"$b\"."
101
102 # substr: extract substring, starting position & length specified
103 b=`expr substr $a 2 6`
104 echo "Substring of \"$a\", starting at position 2,\
105 and 6 chars long is \"$b\"."
106
107
108 # The default behavior of the 'match' operations is to
109 #+ search for the specified match at the ***beginning*** of the string.
110 #
111 # uses Regular Expressions
112 b=`expr match "$a" '[0-9]*'` # Numerical count.
113 echo Number of digits at the beginning of \"$a\" is $b.
114 b=`expr match "$a" '\([0-9]*\)'` # Note that escaped parentheses
115 # == == + trigger substring match.
116 echo "The digits at the beginning of \"$a\" are \"$b\"."
117
118 echo
119
120 exit 0

Important

The : operator can substitute for match. For example, b=`expr $a : [0-9]*` is the exact equivalent of b=`expr match $a [0-9]*` in the above listing.

   1 #!/bin/bash
2
3 echo
4 echo "String operations using \"expr \$string : \" construct"
5 echo "==================================================="
6 echo
7
8 a=1234zipper5FLIPPER43231
9
10 echo "The string being operated upon is \"`expr "$a" : '\(.*\)'`\"."
11 # Escaped parentheses grouping operator. == ==
12
13 # ***************************
14 #+ Escaped parentheses
15 #+ match a substring
16 # ***************************
17
18
19 # If no escaped parentheses...
20 #+ then 'expr' converts the string operand to an integer.
21
22 echo "Length of \"$a\" is `expr "$a" : '.*'`." # Length of string
23
24 echo "Number of digits at the beginning of \"$a\" is `expr "$a" : '[0-9]*'`."
25
26 # ------------------------------------------------------------------------- #
27
28 echo
29
30 echo "The digits at the beginning of \"$a\" are `expr "$a" : '\([0-9]*\)'`."
31 # == ==
32 echo "The first 7 characters of \"$a\" are `expr "$a" : '\(.......\)'`."
33 # ===== == ==
34 # Again, escaped parentheses force a substring match.
35 #
36 echo "The last 7 characters of \"$a\" are `expr "$a" : '.*\(.......\)'`."
37 # ==== end of string operator ^^
38 # (actually means skip over one or more of any characters until specified
39 #+ substring)
40
41 echo
42
43 exit 0

regular expression

An expression is a string of characters. Those characters that have an interpretation above and beyond their literal meaning are called metacharacters. A quote symbol, for example, may denote speech by a person, ditto, or a meta-meaning for the symbols that follow. Regular Expressions are sets of characters and/or metacharacters that UNIX endows with special features. [1]

The main uses for Regular Expressions (REs) are text searches and string manipulation. An RE matches a single character or a set of characters (a substring or an entire string).

  • The asterisk -- * -- matches any number of repeats of the character string or RE preceding it, including zero.

    "1133*" matches 11 + one or more 3's + possibly other characters: 113, 1133, 111312, and so forth.

  • The dot -- . -- matches any one character, except a newline. [2]

    "13." matches 13 + at least one of any character (including a space): 1133, 11333, but not 13 (additional character missing).

  • The caret -- ^ -- matches the beginning of a line, but sometimes, depending on context, negates the meaning of a set of characters in an RE.

  • The dollar sign -- $ -- at the end of an RE matches the end of a line.

    "^$" matches blank lines.

    Note

    The ^ and $ are known as anchors, since they indicate or anchor a position within an RE.

  • Brackets -- [...] -- enclose a set of characters to match in a single RE.

    "[xyz]" matches the characters x, y, or z.

    "[c-n]" matches any of the characters in the range c to n.

    "[B-Pk-y]" matches any of the characters in the ranges B to P and k to y.

    "[a-z0-9]" matches any lowercase letter or any digit.

    "[^b-d]" matches all characters except those in the range b to d. This is an instance of ^ negating or inverting the meaning of the following RE (taking on a role similar to ! in a different context).

    Combined sequences of bracketed characters match common word patterns. "[Yy][Ee][Ss]" matches yes, Yes, YES, yEs, and so forth. "[0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9][0-9][0-9]" matches any Social Security number.

  • The backslash -- \ -- escapes a special character, which means that character gets interpreted literally.

    A "\$" reverts back to its literal meaning of "$", rather than its RE meaning of end-of-line. Likewise a "\\" has the literal meaning of "\".

  • Escaped "angle brackets" -- \<...\> -- mark word boundaries.

    The angle brackets must be escaped, since otherwise they have only their literal character meaning.

    "\" matches the word "the", but not the words "them", "there", "other", etc.

     bash$ cat textfile
    This is line 1, of which there is only one instance.
    This is the only instance of line 2.
    This is line 3, another line.
    This is line 4.



    bash$ grep 'the' textfile
    This is line 1, of which there is only one instance.
    This is the only instance of line 2.
    This is line 3, another line.



    bash$ grep '\' textfile
    This is the only instance of line 2.

  • Extended REs. Used in egrep, awk, and Perl

  • The question mark -- ? -- matches zero or one of the previous RE. It is generally used for matching single characters.

  • The plus -- + -- matches one or more of the previous RE. It serves a role similar to the *, but does not match zero occurrences.

       1 # GNU versions of sed and awk can use "+",
    2 # but it needs to be escaped.
    3
    4 echo a111b | sed -ne '/a1\+b/p'
    5 echo a111b | grep 'a1\+b'
    6 echo a111b | gawk '/a1+b/'
    7 # All of above are equivalent.
    8
    9 # Thanks, S.C.

  • Escaped "curly brackets" -- \{ \} -- indicate the number of occurrences of a preceding RE to match.

    It is necessary to escape the curly brackets since they have only their literal character meaning otherwise. This usage is technically not part of the basic RE set.

    "[0-9]\{5\}" matches exactly five digits (characters in the range of 0 to 9).

    Note

    Curly brackets are not available as an RE in the "classic" (non-POSIX compliant) version of awk. However, gawk has the --re-interval option that permits them (without being escaped).

     bash$ echo 2222 | gawk --re-interval '/2{3}/'
    2222

    Perl and some egrep versions do not require escaping the curly brackets.

  • Parentheses -- ( ) -- enclose groups of REs. They are useful with the following "|" operator and in substring extraction using expr.

  • The -- | -- "or" RE operator matches any of a set of alternate characters.

     bash$ egrep 're(a|e)d' misc.txt
    People who read seem to be better informed than those who do not.
    The clarinet produces sound by the vibration of its reed.

Wednesday, May 07, 2008

find & xargs

http://www.kalamazoolinux.org/tech/find.html

find & xargs

Part of the reason why the Linux command line is so POWERFUL!

Finding files can be a daunting task, given the vast number of files on your average Linux filesystem. The number of system files in an average Linux install is well into the tens of thousands, or even hundreds of thousands of files. That's not counting user files!

The command `find` is, as it's name implies, used to aid you in finding files you are looking for, anywhere in your filesystems. Plus much more (see below).

find can use a large number of other criteria to find a file.

  • The first argument to "find" is the directory (or directories) to perform the search.
    • Example: find (and display) every file in your home directory:
      • find $HOME

  • "-name" the name of a file, or a partial name (basic regex).
    • Example: find the file named "bookmarks.html" in your home directory:
      • find $HOME -name bookmarks.html
    • Example: find all files starting with the name "bookmarks" in your home directory:
      • find $HOME -name bookmarks\*
        • Characters that mean something special to the shell, like the asterisk must
          be escaped with a backslash or put in single quotes, to avoid problems.

  • "-atime/-ctime/-mtime" the last time a files's "access time", "file status" and "modification time",
    measured in days or minutes. The time can be compared to another file with "-newer/-anewer/-cnewer".
    • Example: find everything in your home directory modified in the last 24 hours:
      • find $HOME -mtime 0
    • Example: find everything in your home directory modified in the last 7 days:
      • find $HOME -mtime -7
    • Example: find everything in your home directory that have NOT been modified in the last year:
      • find $HOME -mtime +365
    • Example: find everything in your home that has been modified more recently than "abc.txt":
      • find $HOME -newer klug/find.html

  • "-type x" files of a certain type (file, directory, symlink, socket, pipe, block, character) (fdlspbc)
    • Example: find all directories under /tmp
      • find /tmp -type d

  • "-user" files owned by a certain user.
    • Example: find all files owned by user "bruce" under /var
      • find /var -user bruce

  • "-group" files which are a member of a certain group.
    • Example: find all files in group "users" under /var
      • find /var -group users

  • "-size" files of a certain size.
    • Size can be specified in blocks, bytes, works, Kilobytes, Megabytes or Gigabytes (bcwkMG).
    • Example: find all files in your home directory exactly 100 bytes long:
      • find $HOME -size 100c
    • Example: find all files in your home directory smaller than 100 bytes:
      • find $HOME -size -100c
    • Example: find all files in your home directory larger than 100MB:
      • find $HOME -size +100M

  • "-perm" files that has certain permissions, or has individual bits set or not set.
    • Example: find all files in your root directory that are SUID.
      • find / -xdev -type f -perm +4000
    • Example: find all files in your root directory that are SUID-root.
      • find / -xdev -type f -user root -perm +4000

  • "-links" files that has a certain number of hard links.
    • Example: find all files in your home directory with a hard link count of two:
      • find $HOME -type f -links 2
    • Example: find all files in your home directory with more than one hard link:
      • find $HOME -type f -links +1

  • "-inum" a file with a certain `inum`, useful in filesystem debugging and locating identical hard linked files.
    • Example: find file with inum=114300 in the /home partition:
      • find /home -inum 114300

find can perform a number of actions on the file(s) it finds.

  • "-print" prints the names of the files it finds. This is the default if no other actions are specified.
    These two commands are identical on recent Linux systems:
    • find $HOME -name bookmarks.html
      find $HOME -name bookmarks.html -print
    • Variations include:
      • "-ls" to display detailed output instead of just filename ("ls -dils" format).
      • "-fprint" to send the output to a file instead of stdout.
      • "-printf" to format the output in a specific way.
      • "-fprintf" a combination of the above two.

  • "-print0" Same as -print, except it separates files by a null character (ascii 0) instead of a newline.
    Although the usefulness of this may not be immediately obvious, it is extremely useful!
    See examples below. (the argument ends in the number ZERO, not the letter O)
    • Variations include:
      • "-fprint0" to send output to a file instead of stdout.

  • "-delete" will delete all files it finds. Use with care! :-)
    • Example: delete all files named "core" in the /tmp directory:
      • find /tmp -type f -name core -delete

  • "-exec" will execute any command on the files found.
    • Use "{}" to specify the filename found in the command.
    • End the command with a ";" (escape it!) to execute the command every time a file is found.
    • End the command with a "+" to pass multiple files to the command (like xargs).
    • Variations include:
      • "-execdir" to execute the command in it's directory (instead of the current directory)
      • "-ok" to ask the user for each file found if the command should be executed.
      • "-okdir" ask the user and execute in the file's directory.

Other useful find parameters:

  • "-xdev" Don't descend directories on other filesystems.
    • Useful for searching a single hard drive partition and omitting other HDD partitions, /proc,
      CDROM's, network mounts, etc. (network drives and CD's can be really slow to search)

  • "-maxdepth n" Descend at most n directory levels. (cannot be negative)

  • "-mindepth n" Do not apply tests or actions at levels less than n (non-negative).

  • "-daystart" perform time tests from beginning of today, instead of current date/time.

  • "-L" follow symbolic links (does not follow symlinks by default).

  • "-fstype x" only find files a filesystems of type x.
    • Useful for searching hard drive partitions and omitting CDROM's, network mounts, etc.

  • "-regex pattern" use full regular expressions.
    • Variations include:
      • "-iregex" case insensitive regex.

  • "-depth" Process each directory's contents before the directory itself
    • Useful for removing, since the directory has to be empty before it can be removed

  • "-noleaf" Do not optimize by assuming that directories contain 2 fewer subdirectories than their hard link count.
    • The default optimization improves speed significantly on Unix filesystems.
      However it doesn't work so well on other filesystems (DOS, CDROM, etc.), hence this option.

OPERATORS

  • "! expr" True if expr is false. (logical NOT)

  • "( expr )" Force precedence.

  • "expr1 -a expr2" Logical AND (default operation, not necessary)

  • "expr1 -o expr2" Logical OR.

  • "expr1 , expr2" For different searches while traversing the filesystem hierarchy only once.
    Must be used with parenthesis and -fprint to save separate outputs.

Examples:

  • Display all jpg files in the top two levels of your home directory:
    • find $HOME -maxdepth 2 -name \*jpg -print -exec xv {} \;
    • find $HOME -maxdepth 2 -name '*jpg' -print -exec xv {} +
    • find $HOME -maxdepth 2 -name '*jpg' -print0 | xargs -0 xv

  • cron job to make all files & directories world readable/writable in common area:
    • find /somedir/common -type f -exec chmod a+wr {} \;
      find /somedir/common -type d -exec chmod 777 {} \;

  • cron job to force correct owner/group/permissions on certain files:
    • find $BSE/lib/user \( -name '[p,u]*' -a -type f -a ! -perm 664 \) -exec chmod 664 {} \;
      find $BSE/lib/user \( -name 'd*' -a -type f -a ! -perm 666 \) -exec chmod 666 {} \;
      find $BSE/lib/user \( -type f -a ! -user bsp \) -exec chown bsp {} \;
      find $BSE/lib/user \( -type f -a ! -group programs \) -exec chgrp programs {} \;

  • cron job to delete some old log files and keep record of files removed:
    • find /var/opt/hparray/log -mtime +30 -print -exec rm -f {} \; >> $logf 2> /dev/null

  • cron job to delete some old temp files and keep record of files removed:
    • find / -name core -type f -fstype xfs -print -exec rm -f {} \; >> $logf 2> /dev/null
      find /var/tmp -mtime +1 -name '*aaa*' -print -exec rm -f {} \; >> $logf 2> /dev/null
      find /var/tmp -mtime +1 -name 'srt*' -print -exec rm -f {} \; >> $logf 2> /dev/null
      find /var/tmp -mtime +7 -print -exec rm -f {} \; >> $logf 2> /dev/null

  • Traverse /var only once, listing setuid files and directories into /root/suid.txt
    and large files into /root/big/txt. (example taken from the find man page):
    • find /var \( -perm +4000 -fprintf /root/suid.txt '%#m %u %p\n' \) , \
      \( -size +100M -fprintf /root/big.txt '%-10s %p\n' \)

xargs

  • Why do we need this "xargs" thing? It's in the presentation title! :-)
    Answer: Speed and efficiency.
    • The second line runs much faster than the first for a large number of files:
      • find / -name core -exec rm -f {} \;
      • rm -f $(find / -name core -print)
      In other words, running "rm" once, with all the filenames on the command line
      is much faster than running "rm" multiple times, once for each file.
    • However, the second line could fail if the number of files is very large and
      exceeds the maximum number of characters allowed in a single command.
    • "xargs" will combine the single line output of find and run commands with multiple
      arguments, multiple times if necessary to avoid the max chars per line limit.
      • find / -name core -print | xargs rm -f
    • The simplest way to see what xargs does, is to run some simple commands:
      • find $HOME -maxdepth 2 -name \*.jpg -exec echo {} \;
      • find $HOME -maxdepth 2 -name \*.jpg | xargs echo

  • Enter the power of ZERO!
    • The 2nd command will fail if any of the files contain a space or other special character:
      • find $HOME -maxdepth 2 -name \*.jpg -exec ls {} \;
      • find $HOME -maxdepth 2 -name \*.jpg | xargs ls
    • Delimiting the file names with NULL fixes the problem:
      • find $HOME -maxdepth 2 -name \*.jpg -print0 | xargs -0 ls

  • Real world example of a very useful set of commands: (This happens to me all the time)
    • Our "webmaster" comes to me and asks if I can "find" all the web pages
      that contain the graphic file "ArmstrongISS.jpg" so they can edit those pages.
      • find /home/httpd \( -name \*.html -o -name \*.php -o -name \*.php3 \) -print0 \
        | xargs -0 grep -l "ArmstrongISS.jpg"
      Note: add a "-i" parameter to "grep" for a case insensitive search on the string.
    • The above example alone is worth more than double the price of admission! :-)
      Not only does it find files by name, it only displays file names containing a certain string!
      When combining "find" with other Linux commands (like grep) and it's potential use in shell
      scripts, the power is only limited by your imagination! (and your command line skills). :-)
    • Similar examples to demo on my local system:
      • find $HOME \( -name \*txt -o -name \*html \) -print0 | xargs -0 grep -li vpn
      • find $HOME \( -name \*txt -o -name \*html \) -exec grep -li vpn {} +

Miscellaneous

  • Always read the man page for "find" & "xargs" on the system where you plan on using it.
    "find" has been around for a long time, but is still evolving at a rapid rate.
    • Some arguments are fairly new, and may not exist on some older systems,
      and some commercial Unix systems.
      • Some parameters, like "-delete" and -exec followed by a plus sign ("+"),
        are REALLY NEW. (Neither existed in the SuSE 9.2 "find"!)
      • Other parameters may be named something completely different on
        commerical Unix systems (i.e. "-fstype" == "-fsonly" on HPUX)
      • Older versions of "find" did NOT have "-print" as the default action.
        In fact there was no default, so running find without any action did
        nothing noticeable (except use CPU time and grind the hard drive)!

  • Always test your commands using "-exec echo" before invoking real commands,
    especially destructive commands like removing files! :-)

  • Honorable mention: "locate".
    • The "locate" package comes with most distributions.
      • Installs by default on Redhat/Fedora systems.
      • Comes with SuSE, but does not install by default.
    • "Locate" consists of a cron job that runs nightly (by default),
      and stores all filenames on your system in a searchable database.
    • Simply type "locate filename" to find the location (directory) of a file.
    • Is MUCH faster than using "find" on your entire directory structure, but only
      tells you where files live. It has none of the extra functionality of "find".
    • Using the right tool for the job, "locate" is faster than "find" when you are
      only looking for the locations of files (or where they lived as of yesterday).

  • Any [more] questions?
    • Note to self: if this went too quickly, read the "find" man page out-loud very slowly! :-)

  • Fin.

Monday, May 05, 2008

blackfin system call

 /* Adam:

uclibc: syscall()
---> excpt 0;

HW: EVT3 --> trap()
jump _ex_table()->_ex_syscall;
--> raise 15;

HW: EVT15 --> evt_system_call()
call (real system call)
*/

uClibc/libc/sysdeps/linux/bfin/syscall.c:
------------------------------------------
long syscall(long sysnum, long a, long b, long c, long d, long e, long f)
{
int _r0 = 0;

__asm__ __volatile__ (
"R5 = %7;"
"R4 = %6;"
"R3 = %5;"
"R2 = %4;"
"R1 = %3;"
"R0 = %2;"
"P0 = %1;"
"excpt 0;"
"%0 = R0;"
: "=r" (_r0)
: "rm" (sysnum),
"rm" (a),
"rm" (b),
"rm" (c),
"rm" (d),
"rm" (e),
"rm" (f)
: "memory","CC","R0","R1","R2","R3","R4","R5","P0");

if (_r0 >= (unsigned long) -4095) {
(*__errno_location()) = (-_r0);
_r0 = (unsigned long) -1;
}

return (long)_r0;
}

/* Adam:
excpt 0;

The Force Exception instruction forces an exception with code uimm4.
When the EXCPT instruction is issued, the sequencer vectors to the excep-
tion handler that the user provides.

start_kernel()
---> trap_init()

setup_arch()
--> init_exception_vectors()
*/


mach-common/ints-priority.c:
-----------------------------
void __init init_exception_vectors(void)
{
SSYNC();

/* cannot program in software:
* evt0 - emulation (jtag)
* evt1 - reset
*/
bfin_write_EVT2(evt_nmi);
bfin_write_EVT3(trap);
bfin_write_EVT5(evt_ivhw);
bfin_write_EVT6(evt_timer);
bfin_write_EVT7(evt_evt7);
bfin_write_EVT8(evt_evt8);
bfin_write_EVT9(evt_evt9);
bfin_write_EVT10(evt_evt10);
bfin_write_EVT11(evt_evt11);
bfin_write_EVT12(evt_evt12);
bfin_write_EVT13(evt_evt13);
bfin_write_EVT14(evt14_softirq);
bfin_write_EVT15(evt_system_call);
CSYNC();
}

arch/blackfin/kernel/traps.c:
-----------------------------

/* Initiate the event table handler */
void __init trap_init(void)
{
CSYNC();
bfin_write_EVT3(trap);
CSYNC();
}

/* Adam:
EVT3: The 4th entry of event table is for exception.

"excpt 0;" will finally jump here:
*/
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).
*/
EX_SCRATCH_REG = sp;
sp.l = _exception_stack_top;
sp.h = _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 = _ex_table;
p5.l = _ex_table;
p4 = r7;
p5 = p5 + (p4 << p4 =" [p5];" r7 =" -ENOSYS;" astat =" [sp++];" sp =" EX_SCRATCH_REG;" fp =" 0;" l =" lo(IPEND);" h =" hi(IPEND);" r0 =" [p2];" r0 =" rets;" r7 =" sp;" l =" lo(ALIGN_PAGE_MASK);" h =" hi(ALIGN_PAGE_MASK);" r7 =" r7" p2 =" r7;" p2 =" [p2];" r7 =" __NR_syscall;" r6 =" p0;" cc =" r6" r7 =" sp;" l =" lo(ALIGN_PAGE_MASK);" h =" hi(ALIGN_PAGE_MASK);" r7 =" r7" p2 =" r7;" r7 =" [p2+TI_FLAGS];" cc =" BITTST(r7,TIF_SYSCALL_TRACE);" p4 =" p0;" l =" _sys_call_table;" h =" _sys_call_table;" p5 =" p5" r0 =" [sp" r1 =" [sp" r2 =" [sp" p5 =" [p5];" r7 =" sp;" l =" lo(ALIGN_PAGE_MASK);" h =" hi(ALIGN_PAGE_MASK);" r7 =" r7">flags */
p5 = r7;
.Lresume_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;

.Lsyscall_resched:
cc = BITTST(r7, TIF_NEED_RESCHED);
if !cc jump .Lsyscall_sigpending;

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

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

jump .Lresume_userspace_1;

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

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

.Lsyscall_really_exit:
r5 = [sp + PT_RESERVED];
rets = r5;
rts;
ENDPROC(_system_call)

Blog Archive