📄 arm_gic.c
字号:
} } else if (offset < 0xfe0) { goto bad_reg; } else /* offset >= 0xfe0 */ { if (offset & 3) { res = 0; } else { res = gic_id[(offset - 0xfe0) >> 2]; } } return res;bad_reg: cpu_abort (cpu_single_env, "gic_dist_readb: Bad offset %x\n", offset); return 0;}static uint32_t gic_dist_readw(void *opaque, target_phys_addr_t offset){ uint32_t val; val = gic_dist_readb(opaque, offset); val |= gic_dist_readb(opaque, offset + 1) << 8; return val;}static uint32_t gic_dist_readl(void *opaque, target_phys_addr_t offset){ uint32_t val; val = gic_dist_readw(opaque, offset); val |= gic_dist_readw(opaque, offset + 2) << 16; return val;}static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, uint32_t value){ gic_state *s = (gic_state *)opaque; int irq; int i; offset -= s->base + 0x1000; if (offset < 0x100) { if (offset == 0) { s->enabled = (value & 1); DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis"); } else if (offset < 4) { /* ignored. */ } else { goto bad_reg; } } else if (offset < 0x180) { /* Interrupt Set Enable. */ irq = (offset - 0x100) * 8; if (irq >= GIC_NIRQ) goto bad_reg; for (i = 0; i < 8; i++) { if (value & (1 << i)) { if (!GIC_TEST_ENABLED(irq + i)) DPRINTF("Enabled IRQ %d\n", irq + i); GIC_SET_ENABLED(irq + i); /* If a raised level triggered IRQ enabled then mark is as pending. */ if (GIC_TEST_LEVEL(irq + i) && !GIC_TEST_TRIGGER(irq + i)) GIC_SET_PENDING(irq + i); } } } else if (offset < 0x200) { /* Interrupt Clear Enable. */ irq = (offset - 0x180) * 8; if (irq >= GIC_NIRQ) goto bad_reg; for (i = 0; i < 8; i++) { if (value & (1 << i)) { if (GIC_TEST_ENABLED(irq + i)) DPRINTF("Disabled IRQ %d\n", irq + i); GIC_CLEAR_ENABLED(irq + i); } } } else if (offset < 0x280) { /* Interrupt Set Pending. */ irq = (offset - 0x200) * 8; if (irq >= GIC_NIRQ) goto bad_reg; for (i = 0; i < 8; i++) { if (value & (1 << i)) { GIC_SET_PENDING(irq + i); } } } else if (offset < 0x300) { /* Interrupt Clear Pending. */ irq = (offset - 0x280) * 8; if (irq >= GIC_NIRQ) goto bad_reg; for (i = 0; i < 8; i++) { if (value & (1 << i)) { GIC_CLEAR_PENDING(irq + i); } } } else if (offset < 0x400) { /* Interrupt Active. */ goto bad_reg; } else if (offset < 0x800) { /* Interrupt Priority. */ irq = offset - 0x400; if (irq >= GIC_NIRQ) goto bad_reg; s->priority[irq] = value; } else if (offset < 0xc00) { /* Interrupt CPU Target. */ irq = offset - 0x800; if (irq >= GIC_NIRQ) goto bad_reg; s->irq_target[irq] = value; } else if (offset < 0xf00) { /* Interrupt Configuration. */ irq = (offset - 0xc00) * 4; if (irq >= GIC_NIRQ) goto bad_reg; for (i = 0; i < 4; i++) { if (value & (1 << (i * 2))) { GIC_SET_MODEL(irq + i); } else { GIC_CLEAR_MODEL(irq + i); } if (value & (2 << (i * 2))) { GIC_SET_TRIGGER(irq + i); } else { GIC_CLEAR_TRIGGER(irq + i); } } } else { /* 0xf00 is only handled for word writes. */ goto bad_reg; } gic_update(s); return;bad_reg: cpu_abort (cpu_single_env, "gic_dist_writeb: Bad offset %x\n", offset);}static void gic_dist_writew(void *opaque, target_phys_addr_t offset, uint32_t value){ gic_state *s = (gic_state *)opaque; if (offset - s->base == 0xf00) { GIC_SET_PENDING(value & 0x3ff); gic_update(s); return; } gic_dist_writeb(opaque, offset, value & 0xff); gic_dist_writeb(opaque, offset + 1, value >> 8);}static void gic_dist_writel(void *opaque, target_phys_addr_t offset, uint32_t value){ gic_dist_writew(opaque, offset, value & 0xffff); gic_dist_writew(opaque, offset + 2, value >> 16);}static CPUReadMemoryFunc *gic_dist_readfn[] = { gic_dist_readb, gic_dist_readw, gic_dist_readl};static CPUWriteMemoryFunc *gic_dist_writefn[] = { gic_dist_writeb, gic_dist_writew, gic_dist_writel};static uint32_t gic_cpu_read(void *opaque, target_phys_addr_t offset){ gic_state *s = (gic_state *)opaque; offset -= s->base; switch (offset) { case 0x00: /* Control */ return s->cpu_enabled; case 0x04: /* Priority mask */ return s->priority_mask; case 0x08: /* Binary Point */ /* ??? Not implemented. */ return 0; case 0x0c: /* Acknowledge */ return gic_acknowledge_irq(s); case 0x14: /* Runing Priority */ return s->running_priority; case 0x18: /* Highest Pending Interrupt */ return s->current_pending; default: cpu_abort (cpu_single_env, "gic_cpu_writeb: Bad offset %x\n", offset); return 0; }}static void gic_cpu_write(void *opaque, target_phys_addr_t offset, uint32_t value){ gic_state *s = (gic_state *)opaque; offset -= s->base; switch (offset) { case 0x00: /* Control */ s->cpu_enabled = (value & 1); DPRINTF("CPU %sabled\n", s->cpu_enabled ? "En" : "Dis"); break; case 0x04: /* Priority mask */ s->priority_mask = (value & 0x3ff); break; case 0x08: /* Binary Point */ /* ??? Not implemented. */ break; case 0x10: /* End Of Interrupt */ return gic_complete_irq(s, value & 0x3ff); default: cpu_abort (cpu_single_env, "gic_cpu_writeb: Bad offset %x\n", offset); return; } gic_update(s);}static CPUReadMemoryFunc *gic_cpu_readfn[] = { gic_cpu_read, gic_cpu_read, gic_cpu_read};static CPUWriteMemoryFunc *gic_cpu_writefn[] = { gic_cpu_write, gic_cpu_write, gic_cpu_write};static void gic_reset(gic_state *s){ int i; memset(s->irq_state, 0, GIC_NIRQ * sizeof(gic_irq_state)); s->priority_mask = 0xf0; s->current_pending = 1023; s->running_irq = 1023; s->running_priority = 0x100; for (i = 0; i < 15; i++) { GIC_SET_ENABLED(i); GIC_SET_TRIGGER(i); } s->enabled = 0; s->cpu_enabled = 0;}void *arm_gic_init(uint32_t base, void *parent, int parent_irq){ gic_state *s; int iomemtype; s = (gic_state *)qemu_mallocz(sizeof(gic_state)); if (!s) return NULL; s->handler = gic_set_irq; s->parent = parent; s->parent_irq = parent_irq; if (base != 0xffffffff) { iomemtype = cpu_register_io_memory(0, gic_cpu_readfn, gic_cpu_writefn, s); cpu_register_physical_memory(base, 0x00000fff, iomemtype); iomemtype = cpu_register_io_memory(0, gic_dist_readfn, gic_dist_writefn, s); cpu_register_physical_memory(base + 0x1000, 0x00000fff, iomemtype); s->base = base; } else { s->base = 0; } gic_reset(s); return s;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -