?? arm_gic.c
字號:
#endif } 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", (int)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;#ifdef NVIC gic_state *s = (gic_state *)opaque; uint32_t addr; addr = offset - s->base; if (addr < 0x100 || addr > 0xd00) return nvic_readl(s->nvic, addr);#endif 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; int cpu; cpu = gic_get_current_cpu(); offset -= s->base + GIC_DIST_OFFSET; if (offset < 0x100) {#ifdef NVIC goto bad_reg;#else if (offset == 0) { s->enabled = (value & 1); DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis"); } else if (offset < 4) { /* ignored. */ } else { goto bad_reg; }#endif } else if (offset < 0x180) { /* Interrupt Set Enable. */ irq = (offset - 0x100) * 8 + GIC_BASE_IRQ; if (irq >= GIC_NIRQ) goto bad_reg; if (irq < 16) value = 0xff; for (i = 0; i < 8; i++) { if (value & (1 << i)) { int mask = (irq < 32) ? (1 << cpu) : GIC_TARGET(irq); 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, mask) && !GIC_TEST_TRIGGER(irq + i)) { DPRINTF("Set %d pending mask %x\n", irq + i, mask); GIC_SET_PENDING(irq + i, mask); } } } } else if (offset < 0x200) { /* Interrupt Clear Enable. */ irq = (offset - 0x180) * 8 + GIC_BASE_IRQ; if (irq >= GIC_NIRQ) goto bad_reg; if (irq < 16) value = 0; 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 + GIC_BASE_IRQ; if (irq >= GIC_NIRQ) goto bad_reg; if (irq < 16) irq = 0; for (i = 0; i < 8; i++) { if (value & (1 << i)) { GIC_SET_PENDING(irq + i, GIC_TARGET(irq)); } } } else if (offset < 0x300) { /* Interrupt Clear Pending. */ irq = (offset - 0x280) * 8 + GIC_BASE_IRQ; if (irq >= GIC_NIRQ) goto bad_reg; for (i = 0; i < 8; i++) { /* ??? This currently clears the pending bit for all CPUs, even for per-CPU interrupts. It's unclear whether this is the corect behavior. */ if (value & (1 << i)) { GIC_CLEAR_PENDING(irq + i, ALL_CPU_MASK); } } } else if (offset < 0x400) { /* Interrupt Active. */ goto bad_reg; } else if (offset < 0x800) { /* Interrupt Priority. */ irq = (offset - 0x400) + GIC_BASE_IRQ; if (irq >= GIC_NIRQ) goto bad_reg; if (irq < 32) { s->priority1[irq][cpu] = value; } else { s->priority2[irq - 32] = value; }#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) value = 0; else if (irq < 32) value = ALL_CPU_MASK; s->irq_target[irq] = value & ALL_CPU_MASK; } else if (offset < 0xf00) { /* Interrupt Configuration. */ irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; if (irq >= GIC_NIRQ) goto bad_reg; if (irq < 32) value |= 0xaa; 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); } }#endif } else { /* 0xf00 is only handled for 32-bit writes. */ goto bad_reg; } gic_update(s); return;bad_reg: cpu_abort(cpu_single_env, "gic_dist_writeb: Bad offset %x\n", (int)offset);}static void gic_dist_writew(void *opaque, target_phys_addr_t offset, uint32_t value){ 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_state *s = (gic_state *)opaque;#ifdef NVIC uint32_t addr; addr = offset - s->base; if (addr < 0x100 || (addr > 0xd00 && addr != 0xf00)) { nvic_writel(s->nvic, addr, value); return; }#endif if (offset - s->base == GIC_DIST_OFFSET + 0xf00) { int cpu; int irq; int mask; cpu = gic_get_current_cpu(); irq = value & 0x3ff; switch ((value >> 24) & 3) { case 0: mask = (value >> 16) & ALL_CPU_MASK; break; case 1: mask = 1 << cpu; break; case 2: mask = ALL_CPU_MASK ^ (1 << cpu); break; default: DPRINTF("Bad Soft Int target filter\n"); mask = ALL_CPU_MASK; break; } GIC_SET_PENDING(irq, mask); gic_update(s); return; } 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};#ifndef NVICstatic uint32_t gic_cpu_read(gic_state *s, int cpu, int offset){ switch (offset) { case 0x00: /* Control */ return s->cpu_enabled[cpu]; case 0x04: /* Priority mask */ return s->priority_mask[cpu]; case 0x08: /* Binary Point */ /* ??? Not implemented. */ return 0; case 0x0c: /* Acknowledge */ return gic_acknowledge_irq(s, cpu); case 0x14: /* Runing Priority */ return s->running_priority[cpu]; case 0x18: /* Highest Pending Interrupt */ return s->current_pending[cpu]; default: cpu_abort(cpu_single_env, "gic_cpu_read: Bad offset %x\n", (int)offset); return 0; }}static void gic_cpu_write(gic_state *s, int cpu, int offset, uint32_t value){ switch (offset) { case 0x00: /* Control */ s->cpu_enabled[cpu] = (value & 1); DPRINTF("CPU %sabled\n", s->cpu_enabled ? "En" : "Dis"); break; case 0x04: /* Priority mask */ s->priority_mask[cpu] = (value & 0xff); break; case 0x08: /* Binary Point */ /* ??? Not implemented. */ break; case 0x10: /* End Of Interrupt */ return gic_complete_irq(s, cpu, value & 0x3ff); default: cpu_abort(cpu_single_env, "gic_cpu_write: Bad offset %x\n", (int)offset); return; } gic_update(s);}#endifstatic void gic_reset(gic_state *s){ int i; memset(s->irq_state, 0, GIC_NIRQ * sizeof(gic_irq_state)); for (i = 0 ; i < NCPU; i++) { s->priority_mask[i] = 0xf0; s->current_pending[i] = 1023; s->running_irq[i] = 1023; s->running_priority[i] = 0x100;#ifdef NVIC /* The NVIC doesn't have per-cpu interfaces, so enable by default. */ s->cpu_enabled[i] = 1;#else s->cpu_enabled[i] = 0;#endif } for (i = 0; i < 16; i++) { GIC_SET_ENABLED(i); GIC_SET_TRIGGER(i); }#ifdef NVIC /* The NVIC is always enabled. */ s->enabled = 1;#else s->enabled = 0;#endif}static gic_state *gic_init(uint32_t base, qemu_irq *parent_irq){ gic_state *s; int iomemtype; int i; s = (gic_state *)qemu_mallocz(sizeof(gic_state)); if (!s) return NULL; s->in = qemu_allocate_irqs(gic_set_irq, s, GIC_NIRQ); for (i = 0; i < NCPU; i++) { s->parent_irq[i] = parent_irq[i]; } iomemtype = cpu_register_io_memory(0, gic_dist_readfn, gic_dist_writefn, s); cpu_register_physical_memory(base + GIC_DIST_OFFSET, 0x00001000, iomemtype); s->base = base; gic_reset(s); return s;}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -