⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 arm_gic.c.svn-base

📁 我们自己开发的一个OSEK操作系统!不知道可不可以?
💻 SVN-BASE
📖 第 1 页 / 共 2 页
字号:
/* * ARM Generic/Distributed Interrupt Controller * * Copyright (c) 2006-2007 CodeSourcery. * Written by Paul Brook * * This code is licenced under the GPL. *//* This file contains implementation code for the RealView EB interrupt   controller, MPCore distributed interrupt controller and ARMv7-M   Nested Vectored Interrupt Controller.  *///#define DEBUG_GIC#ifdef DEBUG_GIC#define DPRINTF(fmt, args...) \do { printf("arm_gic: " fmt , ##args); } while (0)#else#define DPRINTF(fmt, args...) do {} while(0)#endif#ifdef NVICstatic const uint8_t gic_id[] ={ 0x00, 0xb0, 0x1b, 0x00, 0x0d, 0xe0, 0x05, 0xb1 };#define GIC_DIST_OFFSET 0/* The NVIC has 16 internal vectors.  However these are not exposed   through the normal GIC interface.  */#define GIC_BASE_IRQ    32#elsestatic const uint8_t gic_id[] ={ 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };#define GIC_DIST_OFFSET 0x1000#define GIC_BASE_IRQ    0#endiftypedef struct gic_irq_state{    /* ??? The documentation seems to imply the enable bits are global, even       for per-cpu interrupts.  This seems strange.  */    unsigned enabled:1;    unsigned pending:NCPU;    unsigned active:NCPU;    unsigned level:1;    unsigned model:1; /* 0 = N:N, 1 = 1:N */    unsigned trigger:1; /* nonzero = edge triggered.  */} gic_irq_state;#define ALL_CPU_MASK ((1 << NCPU) - 1)#define GIC_SET_ENABLED(irq) s->irq_state[irq].enabled = 1#define GIC_CLEAR_ENABLED(irq) s->irq_state[irq].enabled = 0#define GIC_TEST_ENABLED(irq) s->irq_state[irq].enabled#define GIC_SET_PENDING(irq, cm) s->irq_state[irq].pending |= (cm)#define GIC_CLEAR_PENDING(irq, cm) s->irq_state[irq].pending &= ~(cm)#define GIC_TEST_PENDING(irq, cm) ((s->irq_state[irq].pending & (cm)) != 0)#define GIC_SET_ACTIVE(irq, cm) s->irq_state[irq].active |= (cm)#define GIC_CLEAR_ACTIVE(irq, cm) s->irq_state[irq].active &= ~(cm)#define GIC_TEST_ACTIVE(irq, cm) ((s->irq_state[irq].active & (cm)) != 0)#define GIC_SET_MODEL(irq) s->irq_state[irq].model = 1#define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = 0#define GIC_TEST_MODEL(irq) s->irq_state[irq].model#define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level = (cm)#define GIC_CLEAR_LEVEL(irq, cm) s->irq_state[irq].level &= ~(cm)#define GIC_TEST_LEVEL(irq, cm) (s->irq_state[irq].level & (cm)) != 0#define GIC_SET_TRIGGER(irq) s->irq_state[irq].trigger = 1#define GIC_CLEAR_TRIGGER(irq) s->irq_state[irq].trigger = 0#define GIC_TEST_TRIGGER(irq) s->irq_state[irq].trigger#define GIC_GET_PRIORITY(irq, cpu) \  (((irq) < 32) ? s->priority1[irq][cpu] : s->priority2[(irq) - 32])#ifdef NVIC#define GIC_TARGET(irq) 1#else#define GIC_TARGET(irq) s->irq_target[irq]#endiftypedef struct gic_state{    uint32_t base;    qemu_irq parent_irq[NCPU];    int enabled;    int cpu_enabled[NCPU];    gic_irq_state irq_state[GIC_NIRQ];#ifndef NVIC    int irq_target[GIC_NIRQ];#endif    int priority1[32][NCPU];    int priority2[GIC_NIRQ - 32];    int last_active[GIC_NIRQ][NCPU];    int priority_mask[NCPU];    int running_irq[NCPU];    int running_priority[NCPU];    int current_pending[NCPU];    qemu_irq *in;#ifdef NVIC    void *nvic;#endif} gic_state;/* TODO: Many places that call this routine could be optimized.  *//* Update interrupt status after enabled or pending bits have been changed.  */static void gic_update(gic_state *s){    int best_irq;    int best_prio;    int irq;    int level;    int cpu;    int cm;    for (cpu = 0; cpu < NCPU; cpu++) {        cm = 1 << cpu;        s->current_pending[cpu] = 1023;        if (!s->enabled || !s->cpu_enabled[cpu]) {	    qemu_irq_lower(s->parent_irq[cpu]);            return;        }        best_prio = 0x100;        best_irq = 1023;        for (irq = 0; irq < GIC_NIRQ; irq++) {            if (GIC_TEST_ENABLED(irq) && GIC_TEST_PENDING(irq, cm)) {                if (GIC_GET_PRIORITY(irq, cpu) < best_prio) {                    best_prio = GIC_GET_PRIORITY(irq, cpu);                    best_irq = irq;                }            }        }        level = 0;        if (best_prio <= s->priority_mask[cpu]) {            s->current_pending[cpu] = best_irq;            if (best_prio < s->running_priority[cpu]) {                DPRINTF("Raised pending IRQ %d\n", best_irq);                level = 1;            }        }        qemu_set_irq(s->parent_irq[cpu], level);    }}static void __attribute__((unused))gic_set_pending_private(gic_state *s, int cpu, int irq){    int cm = 1 << cpu;    if (GIC_TEST_PENDING(irq, cm))        return;    DPRINTF("Set %d pending cpu %d\n", irq, cpu);    GIC_SET_PENDING(irq, cm);    gic_update(s);}/* Process a change in an external IRQ input.  */static void gic_set_irq(void *opaque, int irq, int level){    gic_state *s = (gic_state *)opaque;    /* The first external input line is internal interrupt 32.  */    irq += 32;    if (level == GIC_TEST_LEVEL(irq, ALL_CPU_MASK))        return;    if (level) {        GIC_SET_LEVEL(irq, ALL_CPU_MASK);        if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq)) {            DPRINTF("Set %d pending mask %x\n", irq, GIC_TARGET(irq));            GIC_SET_PENDING(irq, GIC_TARGET(irq));        }    } else {        GIC_CLEAR_LEVEL(irq, ALL_CPU_MASK);    }    gic_update(s);}static void gic_set_running_irq(gic_state *s, int cpu, int irq){    s->running_irq[cpu] = irq;    if (irq == 1023) {        s->running_priority[cpu] = 0x100;    } else {        s->running_priority[cpu] = GIC_GET_PRIORITY(irq, cpu);    }    gic_update(s);}static uint32_t gic_acknowledge_irq(gic_state *s, int cpu){    int new_irq;    int cm = 1 << cpu;    new_irq = s->current_pending[cpu];    if (new_irq == 1023            || GIC_GET_PRIORITY(new_irq, cpu) >= s->running_priority[cpu]) {        DPRINTF("ACK no pending IRQ\n");        return 1023;    }    s->last_active[new_irq][cpu] = s->running_irq[cpu];    /* Clear pending flags for both level and edge triggered interrupts.       Level triggered IRQs will be reasserted once they become inactive.  */    GIC_CLEAR_PENDING(new_irq, GIC_TEST_MODEL(new_irq) ? ALL_CPU_MASK : cm);    gic_set_running_irq(s, cpu, new_irq);    DPRINTF("ACK %d\n", new_irq);    return new_irq;}static void gic_complete_irq(gic_state * s, int cpu, int irq){    int update = 0;    int cm = 1 << cpu;    DPRINTF("EOI %d\n", irq);    if (s->running_irq[cpu] == 1023)        return; /* No active IRQ.  */    if (irq != 1023) {        /* Mark level triggered interrupts as pending if they are still           raised.  */        if (!GIC_TEST_TRIGGER(irq) && GIC_TEST_ENABLED(irq)                && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) {            DPRINTF("Set %d pending mask %x\n", irq, cm);            GIC_SET_PENDING(irq, cm);            update = 1;        }    }    if (irq != s->running_irq[cpu]) {        /* Complete an IRQ that is not currently running.  */        int tmp = s->running_irq[cpu];        while (s->last_active[tmp][cpu] != 1023) {            if (s->last_active[tmp][cpu] == irq) {                s->last_active[tmp][cpu] = s->last_active[irq][cpu];                break;            }            tmp = s->last_active[tmp][cpu];        }        if (update) {            gic_update(s);        }    } else {        /* Complete the current running IRQ.  */        gic_set_running_irq(s, cpu, s->last_active[s->running_irq[cpu]][cpu]);    }}static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset){    gic_state *s = (gic_state *)opaque;    uint32_t res;    int irq;    int i;    int cpu;    int cm;    int mask;    cpu = gic_get_current_cpu();    cm = 1 << cpu;    offset -= s->base + GIC_DIST_OFFSET;    if (offset < 0x100) {#ifndef NVIC        if (offset == 0)            return s->enabled;        if (offset == 4)            return ((GIC_NIRQ / 32) - 1) | ((NCPU - 1) << 5);        if (offset < 0x08)            return 0;#endif        goto bad_reg;    } else if (offset < 0x200) {        /* Interrupt Set/Clear Enable.  */        if (offset < 0x180)            irq = (offset - 0x100) * 8;        else            irq = (offset - 0x180) * 8;        irq += GIC_BASE_IRQ;        if (irq >= GIC_NIRQ)            goto bad_reg;        res = 0;        for (i = 0; i < 8; i++) {            if (GIC_TEST_ENABLED(irq + i)) {                res |= (1 << i);            }        }    } else if (offset < 0x300) {        /* Interrupt Set/Clear Pending.  */        if (offset < 0x280)            irq = (offset - 0x200) * 8;        else            irq = (offset - 0x280) * 8;        irq += GIC_BASE_IRQ;        if (irq >= GIC_NIRQ)            goto bad_reg;        res = 0;        mask = (irq < 32) ?  cm : ALL_CPU_MASK;        for (i = 0; i < 8; i++) {            if (GIC_TEST_PENDING(irq + i, mask)) {                res |= (1 << i);            }        }    } else if (offset < 0x400) {        /* Interrupt Active.  */        irq = (offset - 0x300) * 8 + GIC_BASE_IRQ;        if (irq >= GIC_NIRQ)            goto bad_reg;        res = 0;        mask = (irq < 32) ?  cm : ALL_CPU_MASK;        for (i = 0; i < 8; i++) {            if (GIC_TEST_ACTIVE(irq + i, mask)) {                res |= (1 << i);            }        }    } else if (offset < 0x800) {        /* Interrupt Priority.  */        irq = (offset - 0x400) + GIC_BASE_IRQ;        if (irq >= GIC_NIRQ)            goto bad_reg;        res = GIC_GET_PRIORITY(irq, cpu);#ifndef NVIC    } else if (offset < 0xc00) {        /* Interrupt CPU Target.  */        irq = (offset - 0x800) + GIC_BASE_IRQ;        if (irq >= GIC_NIRQ)            goto bad_reg;        if (irq >= 29 && irq <= 31) {            res = cm;        } else {            res = GIC_TARGET(irq);        }    } else if (offset < 0xf00) {        /* Interrupt Configuration.  */        irq = (offset - 0xc00) * 2 + GIC_BASE_IRQ;        if (irq >= GIC_NIRQ)            goto bad_reg;        res = 0;        for (i = 0; i < 4; i++) {            if (GIC_TEST_MODEL(irq + i))                res |= (1 << (i * 2));            if (GIC_TEST_TRIGGER(irq + i))                res |= (2 << (i * 2));        }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -