vgic.cc revision 12092
12115Shsul@eecs.umich.edu/* 21881Sbinkertn@umich.edu * Copyright (c) 2013 ARM Limited 31881Sbinkertn@umich.edu * All rights reserved 41881Sbinkertn@umich.edu * 51881Sbinkertn@umich.edu * The license below extends only to copyright in the software and shall 61881Sbinkertn@umich.edu * not be construed as granting a license to any other intellectual 71881Sbinkertn@umich.edu * property including but not limited to intellectual property relating 81881Sbinkertn@umich.edu * to a hardware implementation of the functionality of the software 91881Sbinkertn@umich.edu * licensed hereunder. You may use the software subject to the license 101881Sbinkertn@umich.edu * terms below provided that you ensure that this notice is replicated 111881Sbinkertn@umich.edu * unmodified and in its entirety in all distributions of the software, 121881Sbinkertn@umich.edu * modified or unmodified, in source code or in binary form. 131881Sbinkertn@umich.edu * 141881Sbinkertn@umich.edu * Redistribution and use in source and binary forms, with or without 151881Sbinkertn@umich.edu * modification, are permitted provided that the following conditions are 161881Sbinkertn@umich.edu * met: redistributions of source code must retain the above copyright 171881Sbinkertn@umich.edu * notice, this list of conditions and the following disclaimer; 181881Sbinkertn@umich.edu * redistributions in binary form must reproduce the above copyright 191881Sbinkertn@umich.edu * notice, this list of conditions and the following disclaimer in the 201881Sbinkertn@umich.edu * documentation and/or other materials provided with the distribution; 211881Sbinkertn@umich.edu * neither the name of the copyright holders nor the names of its 221881Sbinkertn@umich.edu * contributors may be used to endorse or promote products derived from 231881Sbinkertn@umich.edu * this software without specific prior written permission. 241881Sbinkertn@umich.edu * 251881Sbinkertn@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 261881Sbinkertn@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 271881Sbinkertn@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 281881Sbinkertn@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 291881Sbinkertn@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 301881Sbinkertn@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 312006Sbinkertn@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 321881Sbinkertn@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 331881Sbinkertn@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 341881Sbinkertn@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 351881Sbinkertn@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 361881Sbinkertn@umich.edu * 372006Sbinkertn@umich.edu * Authors: Matt Evans 381881Sbinkertn@umich.edu */ 392006Sbinkertn@umich.edu 402006Sbinkertn@umich.edu#include "dev/arm/vgic.hh" 412006Sbinkertn@umich.edu 421881Sbinkertn@umich.edu#include "base/trace.hh" 431881Sbinkertn@umich.edu#include "debug/Checkpoint.hh" 441881Sbinkertn@umich.edu#include "debug/VGIC.hh" 451881Sbinkertn@umich.edu#include "dev/arm/base_gic.hh" 461881Sbinkertn@umich.edu#include "dev/terminal.hh" 471881Sbinkertn@umich.edu#include "mem/packet.hh" 481881Sbinkertn@umich.edu#include "mem/packet_access.hh" 491881Sbinkertn@umich.edu 501881Sbinkertn@umich.eduVGic::VGic(const Params *p) 511881Sbinkertn@umich.edu : PioDevice(p), platform(p->platform), gic(p->gic), vcpuAddr(p->vcpu_addr), 521881Sbinkertn@umich.edu hvAddr(p->hv_addr), pioDelay(p->pio_delay), 531881Sbinkertn@umich.edu maintInt(p->ppint) 541881Sbinkertn@umich.edu{ 551881Sbinkertn@umich.edu for (int x = 0; x < VGIC_CPU_MAX; x++) { 561881Sbinkertn@umich.edu postVIntEvent[x] = new PostVIntEvent(x, p->platform); 571881Sbinkertn@umich.edu maintIntPosted[x] = false; 581881Sbinkertn@umich.edu vIntPosted[x] = false; 591881Sbinkertn@umich.edu } 601881Sbinkertn@umich.edu assert(sys->numRunningContexts() <= VGIC_CPU_MAX); 611881Sbinkertn@umich.edu} 621881Sbinkertn@umich.edu 631881Sbinkertn@umich.eduVGic::~VGic() 641881Sbinkertn@umich.edu{ 651881Sbinkertn@umich.edu for (int x = 0; x < VGIC_CPU_MAX; x++) 661881Sbinkertn@umich.edu delete postVIntEvent[x]; 671881Sbinkertn@umich.edu} 681881Sbinkertn@umich.edu 691881Sbinkertn@umich.eduTick 701881Sbinkertn@umich.eduVGic::read(PacketPtr pkt) 711881Sbinkertn@umich.edu{ 721881Sbinkertn@umich.edu Addr addr = pkt->getAddr(); 731881Sbinkertn@umich.edu 741881Sbinkertn@umich.edu if (addr >= vcpuAddr && addr < vcpuAddr + GICV_SIZE) 751881Sbinkertn@umich.edu return readVCpu(pkt); 761881Sbinkertn@umich.edu else if (addr >= hvAddr && addr < hvAddr + GICH_REG_SIZE) 771881Sbinkertn@umich.edu return readCtrl(pkt); 781881Sbinkertn@umich.edu else 792115Shsul@eecs.umich.edu panic("Read to unknown address %#x\n", pkt->getAddr()); 801881Sbinkertn@umich.edu} 811881Sbinkertn@umich.edu 821881Sbinkertn@umich.eduTick 831881Sbinkertn@umich.eduVGic::write(PacketPtr pkt) 841881Sbinkertn@umich.edu{ 851881Sbinkertn@umich.edu Addr addr = pkt->getAddr(); 862115Shsul@eecs.umich.edu 871881Sbinkertn@umich.edu if (addr >= vcpuAddr && addr < vcpuAddr + GICV_SIZE) 881881Sbinkertn@umich.edu return writeVCpu(pkt); 891881Sbinkertn@umich.edu else if (addr >= hvAddr && addr < hvAddr + GICH_REG_SIZE) 901881Sbinkertn@umich.edu return writeCtrl(pkt); 911881Sbinkertn@umich.edu else 921881Sbinkertn@umich.edu panic("Write to unknown address %#x\n", pkt->getAddr()); 931881Sbinkertn@umich.edu} 941881Sbinkertn@umich.edu 951881Sbinkertn@umich.eduTick 961881Sbinkertn@umich.eduVGic::readVCpu(PacketPtr pkt) 971881Sbinkertn@umich.edu{ 981881Sbinkertn@umich.edu Addr daddr = pkt->getAddr() - vcpuAddr; 991881Sbinkertn@umich.edu 1001881Sbinkertn@umich.edu ContextID ctx_id = pkt->req->contextId(); 1011881Sbinkertn@umich.edu assert(ctx_id < VGIC_CPU_MAX); 1021881Sbinkertn@umich.edu struct vcpuIntData *vid = &vcpuData[ctx_id]; 1031881Sbinkertn@umich.edu 1041881Sbinkertn@umich.edu DPRINTF(VGIC, "VGIC VCPU read register %#x\n", daddr); 1051881Sbinkertn@umich.edu 1061881Sbinkertn@umich.edu switch (daddr) { 1071881Sbinkertn@umich.edu case GICV_CTLR: 1081881Sbinkertn@umich.edu pkt->set<uint32_t>(vid->vctrl); 1091881Sbinkertn@umich.edu break; 1101881Sbinkertn@umich.edu case GICV_IAR: { 1111881Sbinkertn@umich.edu int i = findHighestPendingLR(vid); 1121881Sbinkertn@umich.edu if (i < 0 || !vid->vctrl.En) { 1131881Sbinkertn@umich.edu pkt->set<uint32_t>(1023); // "No int" marker 1141881Sbinkertn@umich.edu } else { 1151881Sbinkertn@umich.edu ListReg *lr = &vid->LR[i]; 1161881Sbinkertn@umich.edu 1171881Sbinkertn@umich.edu pkt->set<uint32_t>(lr->VirtualID | 1181881Sbinkertn@umich.edu (((int)lr->CpuID) << 10)); 1191881Sbinkertn@umich.edu // We don't support auto-EOI of HW interrupts via real GIC! 1201881Sbinkertn@umich.edu // Fortunately, KVM doesn't use this. How about Xen...? Ulp! 1211881Sbinkertn@umich.edu if (lr->HW) 1221881Sbinkertn@umich.edu panic("VGIC does not support 'HW' List Register feature (LR %#x)!\n", 1231881Sbinkertn@umich.edu *lr); 1241881Sbinkertn@umich.edu lr->State = LR_ACTIVE; 1252115Shsul@eecs.umich.edu DPRINTF(VGIC, "Consumed interrupt %d (cpu%d) from LR%d (EOI%d)\n", 1261881Sbinkertn@umich.edu lr->VirtualID, lr->CpuID, i, lr->EOI); 1271881Sbinkertn@umich.edu } 1281881Sbinkertn@umich.edu } break; 1292115Shsul@eecs.umich.edu default: 1301881Sbinkertn@umich.edu panic("VGIC VCPU read of bad address %#x\n", daddr); 1311881Sbinkertn@umich.edu } 1321881Sbinkertn@umich.edu 1332115Shsul@eecs.umich.edu updateIntState(ctx_id); 1341881Sbinkertn@umich.edu 1351881Sbinkertn@umich.edu pkt->makeAtomicResponse(); 1361881Sbinkertn@umich.edu return pioDelay; 1371881Sbinkertn@umich.edu} 1381881Sbinkertn@umich.edu 1391881Sbinkertn@umich.eduTick 1401881Sbinkertn@umich.eduVGic::readCtrl(PacketPtr pkt) 1411881Sbinkertn@umich.edu{ 1421881Sbinkertn@umich.edu Addr daddr = pkt->getAddr() - hvAddr; 1431881Sbinkertn@umich.edu 1441881Sbinkertn@umich.edu ContextID ctx_id = pkt->req->contextId(); 1452115Shsul@eecs.umich.edu 1462115Shsul@eecs.umich.edu DPRINTF(VGIC, "VGIC HVCtrl read register %#x\n", daddr); 1472115Shsul@eecs.umich.edu 1482115Shsul@eecs.umich.edu /* Munge the address: 0-0xfff is the usual space banked by requester CPU. 1492115Shsul@eecs.umich.edu * Anything > that is 0x200-sized slices of 'per CPU' regs. 1502115Shsul@eecs.umich.edu */ 1512115Shsul@eecs.umich.edu if (daddr & ~0x1ff) { 1522115Shsul@eecs.umich.edu ctx_id = (daddr >> 9); 1532115Shsul@eecs.umich.edu if (ctx_id > 8) 1542115Shsul@eecs.umich.edu panic("VGIC: Weird unbanked hv ctrl address %#x!\n", daddr); 1552115Shsul@eecs.umich.edu daddr &= ~0x1ff; 1562115Shsul@eecs.umich.edu } 1572115Shsul@eecs.umich.edu assert(ctx_id < VGIC_CPU_MAX); 1582115Shsul@eecs.umich.edu struct vcpuIntData *vid = &vcpuData[ctx_id]; 1592115Shsul@eecs.umich.edu 1602115Shsul@eecs.umich.edu switch (daddr) { 1612115Shsul@eecs.umich.edu case GICH_HCR: 1622115Shsul@eecs.umich.edu pkt->set<uint32_t>(vid->hcr); 1632115Shsul@eecs.umich.edu break; 1642115Shsul@eecs.umich.edu 1652115Shsul@eecs.umich.edu case GICH_VTR: 1661881Sbinkertn@umich.edu pkt->set<uint32_t>(0x44000000 | (NUM_LR - 1)); 1671881Sbinkertn@umich.edu break; 1681881Sbinkertn@umich.edu 1691881Sbinkertn@umich.edu case GICH_VMCR: 1701881Sbinkertn@umich.edu pkt->set<uint32_t>( 1711881Sbinkertn@umich.edu ((uint32_t)vid->VMPriMask << 27) | 1721881Sbinkertn@umich.edu ((uint32_t)vid->VMBP << 21) | 1731881Sbinkertn@umich.edu ((uint32_t)vid->VMABP << 18) | 1741881Sbinkertn@umich.edu ((uint32_t)vid->VEM << 9) | 1751881Sbinkertn@umich.edu ((uint32_t)vid->VMCBPR << 4) | 1762006Sbinkertn@umich.edu ((uint32_t)vid->VMFiqEn << 3) | 1771881Sbinkertn@umich.edu ((uint32_t)vid->VMAckCtl << 2) | 1781881Sbinkertn@umich.edu ((uint32_t)vid->VMGrp1En << 1) | 1791881Sbinkertn@umich.edu ((uint32_t)vid->VMGrp0En << 0) 1801881Sbinkertn@umich.edu ); 1811881Sbinkertn@umich.edu break; 1821881Sbinkertn@umich.edu 1832115Shsul@eecs.umich.edu case GICH_MISR: 1842115Shsul@eecs.umich.edu pkt->set<uint32_t>(getMISR(vid)); 1851881Sbinkertn@umich.edu break; 1861881Sbinkertn@umich.edu 1871881Sbinkertn@umich.edu case GICH_EISR0: 1881881Sbinkertn@umich.edu pkt->set<uint32_t>(vid->eisr & 0xffffffff); 1891881Sbinkertn@umich.edu break; 1902115Shsul@eecs.umich.edu 1911881Sbinkertn@umich.edu case GICH_EISR1: 1921881Sbinkertn@umich.edu pkt->set<uint32_t>(vid->eisr >> 32); 1932115Shsul@eecs.umich.edu break; 1941881Sbinkertn@umich.edu 1951881Sbinkertn@umich.edu case GICH_ELSR0: { 1961881Sbinkertn@umich.edu uint32_t bm = 0; 1971881Sbinkertn@umich.edu for (int i = 0; i < ((NUM_LR < 32) ? NUM_LR : 32); i++) { 1981881Sbinkertn@umich.edu if (!vid->LR[i].State) 1992115Shsul@eecs.umich.edu bm |= 1 << i; 2002115Shsul@eecs.umich.edu } 2012006Sbinkertn@umich.edu pkt->set<uint32_t>(bm); 2022115Shsul@eecs.umich.edu } break; 2031881Sbinkertn@umich.edu 2041881Sbinkertn@umich.edu case GICH_ELSR1: { 2052115Shsul@eecs.umich.edu uint32_t bm = 0; 2062115Shsul@eecs.umich.edu for (int i = 32; i < NUM_LR; i++) { 2072115Shsul@eecs.umich.edu if (!vid->LR[i].State) 2082115Shsul@eecs.umich.edu bm |= 1 << (i-32); 2092115Shsul@eecs.umich.edu } 2102115Shsul@eecs.umich.edu pkt->set<uint32_t>(bm); 2111881Sbinkertn@umich.edu } break; 2121881Sbinkertn@umich.edu 2131881Sbinkertn@umich.edu case GICH_APR0: 2141881Sbinkertn@umich.edu warn_once("VGIC GICH_APR read!\n"); 2151881Sbinkertn@umich.edu pkt->set<uint32_t>(0); 2161881Sbinkertn@umich.edu break; 2171881Sbinkertn@umich.edu 2181881Sbinkertn@umich.edu case GICH_LR0: 2191881Sbinkertn@umich.edu case GICH_LR1: 2202006Sbinkertn@umich.edu case GICH_LR2: 2212006Sbinkertn@umich.edu case GICH_LR3: 2221881Sbinkertn@umich.edu pkt->set<uint32_t>(vid->LR[(daddr - GICH_LR0) >> 2]); 2231881Sbinkertn@umich.edu break; 2241881Sbinkertn@umich.edu 2251881Sbinkertn@umich.edu default: 2261881Sbinkertn@umich.edu panic("VGIC HVCtrl read of bad address %#x\n", daddr); 2271881Sbinkertn@umich.edu } 2281881Sbinkertn@umich.edu 2292006Sbinkertn@umich.edu pkt->makeAtomicResponse(); 2302006Sbinkertn@umich.edu return pioDelay; 2312006Sbinkertn@umich.edu} 2322006Sbinkertn@umich.edu 2332006Sbinkertn@umich.eduTick 2342006Sbinkertn@umich.eduVGic::writeVCpu(PacketPtr pkt) 2352006Sbinkertn@umich.edu{ 2362006Sbinkertn@umich.edu Addr daddr = pkt->getAddr() - vcpuAddr; 2372006Sbinkertn@umich.edu 2382006Sbinkertn@umich.edu ContextID ctx_id = pkt->req->contextId(); 2392006Sbinkertn@umich.edu assert(ctx_id < VGIC_CPU_MAX); 2402006Sbinkertn@umich.edu struct vcpuIntData *vid = &vcpuData[ctx_id]; 2412006Sbinkertn@umich.edu 2422006Sbinkertn@umich.edu DPRINTF(VGIC, "VGIC VCPU write register %#x <= %#x\n", daddr, pkt->get<uint32_t>()); 2432006Sbinkertn@umich.edu 2442006Sbinkertn@umich.edu switch (daddr) { 2452006Sbinkertn@umich.edu case GICV_CTLR: 2462006Sbinkertn@umich.edu vid->vctrl = pkt->get<uint32_t>(); 2472006Sbinkertn@umich.edu break; 2482006Sbinkertn@umich.edu case GICV_PMR: 2492006Sbinkertn@umich.edu vid->VMPriMask = pkt->get<uint32_t>(); 2502006Sbinkertn@umich.edu break; 2512006Sbinkertn@umich.edu case GICV_EOIR: { 2521881Sbinkertn@umich.edu // We don't handle the split EOI-then-DIR mode. Linux (guest) 2532006Sbinkertn@umich.edu // doesn't need it though. 2541881Sbinkertn@umich.edu assert(!vid->vctrl.EOImode); 2551881Sbinkertn@umich.edu uint32_t w = pkt->get<uint32_t>(); 2561881Sbinkertn@umich.edu unsigned int virq = w & 0x3ff; 2571881Sbinkertn@umich.edu unsigned int vcpu = (w >> 10) & 7; 2581881Sbinkertn@umich.edu int i = findLRForVIRQ(vid, virq, vcpu); 2591881Sbinkertn@umich.edu if (i < 0) { 2601881Sbinkertn@umich.edu DPRINTF(VGIC, "EOIR: No LR for irq %d(cpu%d)\n", virq, vcpu); 2611881Sbinkertn@umich.edu } else { 2621881Sbinkertn@umich.edu DPRINTF(VGIC, "EOIR: Found LR%d for irq %d(cpu%d)\n", i, virq, vcpu); 2631881Sbinkertn@umich.edu ListReg *lr = &vid->LR[i]; 2641881Sbinkertn@umich.edu lr->State = 0; 2651881Sbinkertn@umich.edu // Maintenance interrupt -- via eisr -- is flagged when 2661881Sbinkertn@umich.edu // LRs have EOI=1 and State=INVALID! 2671881Sbinkertn@umich.edu } 2681881Sbinkertn@umich.edu } break; 2691881Sbinkertn@umich.edu default: 2701881Sbinkertn@umich.edu panic("VGIC VCPU write %#x to unk address %#x\n", pkt->get<uint32_t>(), daddr); 2711881Sbinkertn@umich.edu } 2721881Sbinkertn@umich.edu 2731881Sbinkertn@umich.edu // This updates the EISRs and flags IRQs: 2741881Sbinkertn@umich.edu updateIntState(ctx_id); 2751881Sbinkertn@umich.edu 2761881Sbinkertn@umich.edu pkt->makeAtomicResponse(); 2771881Sbinkertn@umich.edu return pioDelay; 2781881Sbinkertn@umich.edu} 2791881Sbinkertn@umich.edu 2801881Sbinkertn@umich.eduTick 2811881Sbinkertn@umich.eduVGic::writeCtrl(PacketPtr pkt) 2821881Sbinkertn@umich.edu{ 2832115Shsul@eecs.umich.edu Addr daddr = pkt->getAddr() - hvAddr; 2842117Shsul@eecs.umich.edu 2852117Shsul@eecs.umich.edu ContextID ctx_id = pkt->req->contextId(); 2861881Sbinkertn@umich.edu 2872006Sbinkertn@umich.edu DPRINTF(VGIC, "VGIC HVCtrl write register %#x <= %#x\n", daddr, pkt->get<uint32_t>()); 2882006Sbinkertn@umich.edu 2892006Sbinkertn@umich.edu /* Munge the address: 0-0xfff is the usual space banked by requester CPU. 2902006Sbinkertn@umich.edu * Anything > that is 0x200-sized slices of 'per CPU' regs. 2911881Sbinkertn@umich.edu */ 2921881Sbinkertn@umich.edu if (daddr & ~0x1ff) { 2931881Sbinkertn@umich.edu ctx_id = (daddr >> 9); 2941881Sbinkertn@umich.edu if (ctx_id > 8) 2951881Sbinkertn@umich.edu panic("VGIC: Weird unbanked hv ctrl address %#x!\n", daddr); 2961881Sbinkertn@umich.edu daddr &= ~0x1ff; 2972006Sbinkertn@umich.edu } 2982006Sbinkertn@umich.edu assert(ctx_id < VGIC_CPU_MAX); 2991881Sbinkertn@umich.edu struct vcpuIntData *vid = &vcpuData[ctx_id]; 3002115Shsul@eecs.umich.edu 301 switch (daddr) { 302 case GICH_HCR: 303 vid->hcr = pkt->get<uint32_t>(); 304 // update int state 305 break; 306 307 case GICH_VMCR: { 308 uint32_t d = pkt->get<uint32_t>(); 309 vid->VMPriMask = d >> 27; 310 vid->VMBP = (d >> 21) & 7; 311 vid->VMABP = (d >> 18) & 7; 312 vid->VEM = (d >> 9) & 1; 313 vid->VMCBPR = (d >> 4) & 1; 314 vid->VMFiqEn = (d >> 3) & 1; 315 vid->VMAckCtl = (d >> 2) & 1; 316 vid->VMGrp1En = (d >> 1) & 1; 317 vid->VMGrp0En = d & 1; 318 } break; 319 320 case GICH_APR0: 321 warn_once("VGIC GICH_APR0 written, ignored\n"); 322 break; 323 324 case GICH_LR0: 325 case GICH_LR1: 326 case GICH_LR2: 327 case GICH_LR3: 328 vid->LR[(daddr - GICH_LR0) >> 2] = pkt->get<uint32_t>(); 329 // update int state 330 break; 331 332 default: 333 panic("VGIC HVCtrl write to bad address %#x\n", daddr); 334 } 335 336 updateIntState(ctx_id); 337 338 pkt->makeAtomicResponse(); 339 return pioDelay; 340} 341 342 343uint32_t 344VGic::getMISR(struct vcpuIntData *vid) 345{ 346 return (!!vid->hcr.VGrp1DIE && !vid->VMGrp1En ? 0x80 : 0) | 347 (!!vid->hcr.VGrp1EIE && vid->VMGrp1En ? 0x40 : 0) | 348 (!!vid->hcr.VGrp0DIE && !vid->VMGrp0En ? 0x20 : 0) | 349 (!!vid->hcr.VGrp0EIE && vid->VMGrp0En ? 0x10 : 0) | 350 (!!vid->hcr.NPIE && !lrPending(vid) ? 0x08 : 0) | 351 (!!vid->hcr.LRENPIE && vid->hcr.EOICount ? 0x04 : 0) | 352 (!!vid->hcr.UIE && lrValid(vid) <= 1 ? 0x02 : 0) | 353 (vid->eisr ? 0x01 : 0); 354} 355 356void 357VGic::postVInt(uint32_t cpu, Tick when) 358{ 359 DPRINTF(VGIC, "Posting VIRQ to %d\n", cpu); 360 if (!(postVIntEvent[cpu]->scheduled())) 361 eventq->schedule(postVIntEvent[cpu], when); 362} 363 364void 365VGic::unPostVInt(uint32_t cpu) 366{ 367 DPRINTF(VGIC, "Unposting VIRQ to %d\n", cpu); 368 platform->intrctrl->clear(cpu, ArmISA::INT_VIRT_IRQ, 0); 369} 370 371void 372VGic::postMaintInt(uint32_t cpu) 373{ 374 DPRINTF(VGIC, "Posting maintenance PPI to GIC/cpu%d\n", cpu); 375 // Linux DT configures this as Level. 376 gic->sendPPInt(maintInt, cpu); 377} 378 379void 380VGic::unPostMaintInt(uint32_t cpu) 381{ 382 DPRINTF(VGIC, "Unposting maintenance PPI to GIC/cpu%d\n", cpu); 383 gic->clearPPInt(maintInt, cpu); 384} 385 386/* Update state (in general); something concerned with ctx_id has changed. 387 * This may raise a maintenance interrupt. 388 */ 389void 390VGic::updateIntState(ContextID ctx_id) 391{ 392 // @todo This should update APRs! 393 394 // Build EISR contents: 395 // (Cached so that regs can read them without messing about again) 396 struct vcpuIntData *tvid = &vcpuData[ctx_id]; 397 398 tvid->eisr = 0; 399 for (int i = 0; i < NUM_LR; i++) { 400 if (!tvid->LR[i].State && tvid->LR[i].EOI) { 401 tvid->eisr |= 1 << i; 402 } 403 } 404 405 assert(sys->numRunningContexts() <= VGIC_CPU_MAX); 406 for (int i = 0; i < sys->numRunningContexts(); i++) { 407 struct vcpuIntData *vid = &vcpuData[i]; 408 // Are any LRs active that weren't before? 409 if (!vIntPosted[i]) { 410 if (lrPending(vid) && vid->vctrl.En) { 411 vIntPosted[i] = true; 412 postVInt(i, curTick() + 1); 413 } 414 } else if (!lrPending(vid)) { 415 vIntPosted[i] = false; 416 unPostVInt(i); 417 } 418 419 // Any maintenance ints to send? 420 if (!maintIntPosted[i]) { 421 if (vid->hcr.En && getMISR(vid)) { 422 maintIntPosted[i] = true; 423 postMaintInt(i); 424 } 425 } else { 426 if (!vid->hcr.En || !getMISR(vid)) { 427 unPostMaintInt(i); 428 maintIntPosted[i] = false; 429 } 430 } 431 } 432} 433 434AddrRangeList 435VGic::getAddrRanges() const 436{ 437 AddrRangeList ranges; 438 ranges.push_back(RangeSize(hvAddr, GICH_REG_SIZE)); 439 ranges.push_back(RangeSize(vcpuAddr, GICV_SIZE)); 440 return ranges; 441} 442 443void 444VGic::serialize(CheckpointOut &cp) const 445{ 446 Tick interrupt_time[VGIC_CPU_MAX]; 447 for (uint32_t cpu = 0; cpu < VGIC_CPU_MAX; cpu++) { 448 interrupt_time[cpu] = 0; 449 if (postVIntEvent[cpu]->scheduled()) { 450 interrupt_time[cpu] = postVIntEvent[cpu]->when(); 451 } 452 } 453 454 DPRINTF(Checkpoint, "Serializing VGIC\n"); 455 456 SERIALIZE_ARRAY(interrupt_time, VGIC_CPU_MAX); 457 SERIALIZE_ARRAY(maintIntPosted, VGIC_CPU_MAX); 458 SERIALIZE_ARRAY(vIntPosted, VGIC_CPU_MAX); 459 SERIALIZE_SCALAR(vcpuAddr); 460 SERIALIZE_SCALAR(hvAddr); 461 SERIALIZE_SCALAR(pioDelay); 462 SERIALIZE_SCALAR(maintInt); 463 464 for (uint32_t cpu = 0; cpu < VGIC_CPU_MAX; cpu++) 465 vcpuData[cpu].serializeSection(cp, csprintf("vcpuData%d", cpu)); 466} 467 468void 469VGic::vcpuIntData::serialize(CheckpointOut &cp) const 470{ 471 uint32_t vctrl_val = vctrl; 472 SERIALIZE_SCALAR(vctrl_val); 473 uint32_t hcr_val = hcr; 474 SERIALIZE_SCALAR(hcr_val); 475 uint64_t eisr_val = eisr; 476 SERIALIZE_SCALAR(eisr_val); 477 uint8_t VMGrp0En_val = VMGrp0En; 478 SERIALIZE_SCALAR(VMGrp0En_val); 479 uint8_t VMGrp1En_val = VMGrp1En; 480 SERIALIZE_SCALAR(VMGrp1En_val); 481 uint8_t VMAckCtl_val = VMAckCtl; 482 SERIALIZE_SCALAR(VMAckCtl_val); 483 uint8_t VMFiqEn_val = VMFiqEn; 484 SERIALIZE_SCALAR(VMFiqEn_val); 485 uint8_t VMCBPR_val = VMCBPR; 486 SERIALIZE_SCALAR(VMCBPR_val); 487 uint8_t VEM_val = VEM; 488 SERIALIZE_SCALAR(VEM_val); 489 uint8_t VMABP_val = VMABP; 490 SERIALIZE_SCALAR(VMABP_val); 491 uint8_t VMBP_val = VMBP; 492 SERIALIZE_SCALAR(VMBP_val); 493 uint8_t VMPriMask_val = VMPriMask; 494 SERIALIZE_SCALAR(VMPriMask_val); 495 496 for (int i = 0; i < NUM_LR; i++) { 497 ScopedCheckpointSection sec_lr(cp, csprintf("LR%d", i)); 498 paramOut(cp, "lr", LR[i]); 499 } 500} 501 502void VGic::unserialize(CheckpointIn &cp) 503{ 504 DPRINTF(Checkpoint, "Unserializing Arm GIC\n"); 505 506 Tick interrupt_time[VGIC_CPU_MAX]; 507 UNSERIALIZE_ARRAY(interrupt_time, VGIC_CPU_MAX); 508 for (uint32_t cpu = 0; cpu < VGIC_CPU_MAX; cpu++) { 509 if (interrupt_time[cpu]) 510 schedule(postVIntEvent[cpu], interrupt_time[cpu]); 511 512 vcpuData[cpu].unserializeSection(cp, csprintf("vcpuData%d", cpu)); 513 } 514 UNSERIALIZE_ARRAY(maintIntPosted, VGIC_CPU_MAX); 515 UNSERIALIZE_ARRAY(vIntPosted, VGIC_CPU_MAX); 516 UNSERIALIZE_SCALAR(vcpuAddr); 517 UNSERIALIZE_SCALAR(hvAddr); 518 UNSERIALIZE_SCALAR(pioDelay); 519 UNSERIALIZE_SCALAR(maintInt); 520} 521 522void 523VGic::vcpuIntData::unserialize(CheckpointIn &cp) 524{ 525 paramIn(cp, "vctrl_val", vctrl); 526 paramIn(cp, "hcr_val", hcr); 527 paramIn(cp, "eisr_val", eisr); 528 paramIn(cp, "VMGrp0En_val", VMGrp0En); 529 paramIn(cp, "VMGrp1En_val", VMGrp1En); 530 paramIn(cp, "VMAckCtl_val", VMAckCtl); 531 paramIn(cp, "VMFiqEn_val", VMFiqEn); 532 paramIn(cp, "VMCBPR_val", VMCBPR); 533 paramIn(cp, "VEM_val", VEM); 534 paramIn(cp, "VMABP_val", VMABP); 535 paramIn(cp, "VMPriMask_val", VMPriMask); 536 537 for (int i = 0; i < NUM_LR; i++) { 538 ScopedCheckpointSection sec_lr(cp, csprintf("LR%d", i)); 539 paramIn(cp, "lr", LR[i]); 540 } 541} 542 543VGic * 544VGicParams::create() 545{ 546 return new VGic(this); 547} 548