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

📄 arm_gic.c

📁 xen虚拟机源代码安装包
💻 C
📖 第 1 页 / 共 2 页
字号:
/*  * ARM AMBA Generic/Distributed Interrupt Controller * * Copyright (c) 2006 CodeSourcery. * Written by Paul Brook * * This code is licenced under the GPL. *//* TODO: Some variants of this controller can handle multiple CPUs.   Currently only single CPU operation is implemented.  */#include "vl.h"#include "arm_pic.h"//#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/* Distributed interrupt controller.  */static const uint8_t gic_id[] ={ 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };#define GIC_NIRQ 96typedef struct gic_irq_state{    unsigned enabled:1;    unsigned pending:1;    unsigned active:1;    unsigned level:1;    unsigned model:1; /* 0 = 1:N, 1 = N:N */    unsigned trigger:1; /* nonzero = edge triggered.  */} gic_irq_state;#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) s->irq_state[irq].pending = 1#define GIC_CLEAR_PENDING(irq) s->irq_state[irq].pending = 0#define GIC_TEST_PENDING(irq) s->irq_state[irq].pending#define GIC_SET_ACTIVE(irq) s->irq_state[irq].active = 1#define GIC_CLEAR_ACTIVE(irq) s->irq_state[irq].active = 0#define GIC_TEST_ACTIVE(irq) s->irq_state[irq].active#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) s->irq_state[irq].level = 1#define GIC_CLEAR_LEVEL(irq) s->irq_state[irq].level = 0#define GIC_TEST_LEVEL(irq) s->irq_state[irq].level#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].triggertypedef struct gic_state{    arm_pic_handler handler;    uint32_t base;    void *parent;    int parent_irq;    int enabled;    int cpu_enabled;    gic_irq_state irq_state[GIC_NIRQ];    int irq_target[GIC_NIRQ];    int priority[GIC_NIRQ];    int last_active[GIC_NIRQ];    int priority_mask;    int running_irq;    int running_priority;    int current_pending;} 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;    s->current_pending = 1023;    if (!s->enabled || !s->cpu_enabled) {        pic_set_irq_new(s->parent, s->parent_irq, 0);        return;    }    best_prio = 0x100;    best_irq = 1023;    for (irq = 0; irq < 96; irq++) {        if (GIC_TEST_ENABLED(irq) && GIC_TEST_PENDING(irq)) {            if (s->priority[irq] < best_prio) {                best_prio = s->priority[irq];                best_irq = irq;            }        }    }    if (best_prio > s->priority_mask) {        pic_set_irq_new(s->parent, s->parent_irq, 0);    } else {        s->current_pending = best_irq;        if (best_prio < s->running_priority) {            DPRINTF("Raised pending IRQ %d\n", best_irq);            pic_set_irq_new(s->parent, s->parent_irq, 1);        }    }}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))         return;    if (level) {        GIC_SET_LEVEL(irq);        if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq)) {            DPRINTF("Set %d pending\n", irq);            GIC_SET_PENDING(irq);        }    } else {        GIC_CLEAR_LEVEL(irq);    }    gic_update(s);}static void gic_set_running_irq(gic_state *s, int irq){    s->running_irq = irq;    if (irq == 1023)        s->running_priority = 0x100;    else        s->running_priority = s->priority[irq];    gic_update(s);}static uint32_t gic_acknowledge_irq(gic_state *s){    int new_irq;    new_irq = s->current_pending;    if (new_irq == 1023 || s->priority[new_irq] >= s->running_priority) {        DPRINTF("ACK no pending IRQ\n");        return 1023;    }    pic_set_irq_new(s->parent, s->parent_irq, 0);    s->last_active[new_irq] = s->running_irq;    /* For level triggered interrupts we clear the pending bit while       the interrupt is active.  */    GIC_CLEAR_PENDING(new_irq);    gic_set_running_irq(s, new_irq);    DPRINTF("ACK %d\n", new_irq);    return new_irq;}static void gic_complete_irq(gic_state * s, int irq){    int update = 0;    DPRINTF("EOI %d\n", irq);    if (s->running_irq == 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)) {            GIC_SET_PENDING(irq);            update = 1;        }    }    if (irq != s->running_irq) {        /* Complete an IRQ that is not currently running.  */        int tmp = s->running_irq;        while (s->last_active[tmp] != 1023) {            if (s->last_active[tmp] == irq) {                s->last_active[tmp] = s->last_active[irq];                break;            }            tmp = s->last_active[tmp];        }        if (update) {            gic_update(s);        }    } else {        /* Complete the current running IRQ.  */        gic_set_running_irq(s, s->last_active[s->running_irq]);    }}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;    offset -= s->base + 0x1000;    if (offset < 0x100) {        if (offset == 0)            return s->enabled;        if (offset == 4)            return (GIC_NIRQ / 32) - 1;        if (offset < 0x08)            return 0;        goto bad_reg;    } else if (offset < 0x200) {        /* Interrupt Set/Clear Enable.  */        if (offset < 0x180)            irq = (offset - 0x100) * 8;        else            irq = (offset - 0x180) * 8;        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;        if (irq >= GIC_NIRQ)            goto bad_reg;        res = 0;        for (i = 0; i < 8; i++) {            if (GIC_TEST_PENDING(irq + i)) {                res |= (1 << i);            }        }    } else if (offset < 0x400) {        /* Interrupt Active.  */        irq = (offset - 0x300) * 8;        if (irq >= GIC_NIRQ)            goto bad_reg;        res = 0;        for (i = 0; i < 8; i++) {            if (GIC_TEST_ACTIVE(irq + i)) {                res |= (1 << i);            }        }    } else if (offset < 0x800) {        /* Interrupt Priority.  */        irq = offset - 0x400;        if (irq >= GIC_NIRQ)            goto bad_reg;        res = s->priority[irq];    } else if (offset < 0xc00) {        /* Interrupt CPU Target.  */        irq = offset - 0x800;        if (irq >= GIC_NIRQ)            goto bad_reg;        res = s->irq_target[irq];    } else if (offset < 0xf00) {        /* Interrupt Configuration.  */        irq = (offset - 0xc00) * 2;        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 + -