1/* 2 * Copyright (c) 2013 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions are 16 * met: redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer; 18 * redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution; 21 * neither the name of the copyright holders nor the names of its 22 * contributors may be used to endorse or promote products derived from 23 * this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * Authors: Matt Evans 38 */ 39 40#include "dev/arm/vgic.hh" 41 42#include "base/trace.hh" 43#include "debug/Checkpoint.hh" 44#include "debug/VGIC.hh" 45#include "dev/arm/base_gic.hh" 46#include "dev/terminal.hh" 47#include "mem/packet.hh" 48#include "mem/packet_access.hh" 49 50VGic::VGic(const Params *p) 51 : PioDevice(p), platform(p->platform), gic(p->gic), vcpuAddr(p->vcpu_addr), 52 hvAddr(p->hv_addr), pioDelay(p->pio_delay), 53 maintInt(p->ppint) 54{ 55 for (int x = 0; x < VGIC_CPU_MAX; x++) {
| 1/* 2 * Copyright (c) 2013 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions are 16 * met: redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer; 18 * redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution; 21 * neither the name of the copyright holders nor the names of its 22 * contributors may be used to endorse or promote products derived from 23 * this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * Authors: Matt Evans 38 */ 39 40#include "dev/arm/vgic.hh" 41 42#include "base/trace.hh" 43#include "debug/Checkpoint.hh" 44#include "debug/VGIC.hh" 45#include "dev/arm/base_gic.hh" 46#include "dev/terminal.hh" 47#include "mem/packet.hh" 48#include "mem/packet_access.hh" 49 50VGic::VGic(const Params *p) 51 : PioDevice(p), platform(p->platform), gic(p->gic), vcpuAddr(p->vcpu_addr), 52 hvAddr(p->hv_addr), pioDelay(p->pio_delay), 53 maintInt(p->ppint) 54{ 55 for (int x = 0; x < VGIC_CPU_MAX; x++) {
|
56 postVIntEvent[x] = new PostVIntEvent(x, p->platform);
| 56 postVIntEvent[x] = new EventFunctionWrapper( 57 [this, x]{ processPostVIntEvent(x); }, 58 "Post VInterrupt to CPU");
|
57 maintIntPosted[x] = false; 58 vIntPosted[x] = false; 59 } 60 assert(sys->numRunningContexts() <= VGIC_CPU_MAX); 61} 62 63VGic::~VGic() 64{ 65 for (int x = 0; x < VGIC_CPU_MAX; x++) 66 delete postVIntEvent[x]; 67} 68 69Tick 70VGic::read(PacketPtr pkt) 71{ 72 Addr addr = pkt->getAddr(); 73 74 if (addr >= vcpuAddr && addr < vcpuAddr + GICV_SIZE) 75 return readVCpu(pkt); 76 else if (addr >= hvAddr && addr < hvAddr + GICH_REG_SIZE) 77 return readCtrl(pkt); 78 else 79 panic("Read to unknown address %#x\n", pkt->getAddr()); 80} 81 82Tick 83VGic::write(PacketPtr pkt) 84{ 85 Addr addr = pkt->getAddr(); 86 87 if (addr >= vcpuAddr && addr < vcpuAddr + GICV_SIZE) 88 return writeVCpu(pkt); 89 else if (addr >= hvAddr && addr < hvAddr + GICH_REG_SIZE) 90 return writeCtrl(pkt); 91 else 92 panic("Write to unknown address %#x\n", pkt->getAddr()); 93} 94 95Tick 96VGic::readVCpu(PacketPtr pkt) 97{ 98 Addr daddr = pkt->getAddr() - vcpuAddr; 99 100 ContextID ctx_id = pkt->req->contextId(); 101 assert(ctx_id < VGIC_CPU_MAX); 102 struct vcpuIntData *vid = &vcpuData[ctx_id]; 103 104 DPRINTF(VGIC, "VGIC VCPU read register %#x\n", daddr); 105 106 switch (daddr) { 107 case GICV_CTLR: 108 pkt->set<uint32_t>(vid->vctrl); 109 break; 110 case GICV_IAR: { 111 int i = findHighestPendingLR(vid); 112 if (i < 0 || !vid->vctrl.En) { 113 pkt->set<uint32_t>(1023); // "No int" marker 114 } else { 115 ListReg *lr = &vid->LR[i]; 116 117 pkt->set<uint32_t>(lr->VirtualID | 118 (((int)lr->CpuID) << 10)); 119 // We don't support auto-EOI of HW interrupts via real GIC! 120 // Fortunately, KVM doesn't use this. How about Xen...? Ulp! 121 if (lr->HW) 122 panic("VGIC does not support 'HW' List Register feature (LR %#x)!\n", 123 *lr); 124 lr->State = LR_ACTIVE; 125 DPRINTF(VGIC, "Consumed interrupt %d (cpu%d) from LR%d (EOI%d)\n", 126 lr->VirtualID, lr->CpuID, i, lr->EOI); 127 } 128 } break; 129 default: 130 panic("VGIC VCPU read of bad address %#x\n", daddr); 131 } 132 133 updateIntState(ctx_id); 134 135 pkt->makeAtomicResponse(); 136 return pioDelay; 137} 138 139Tick 140VGic::readCtrl(PacketPtr pkt) 141{ 142 Addr daddr = pkt->getAddr() - hvAddr; 143 144 ContextID ctx_id = pkt->req->contextId(); 145 146 DPRINTF(VGIC, "VGIC HVCtrl read register %#x\n", daddr); 147 148 /* Munge the address: 0-0xfff is the usual space banked by requester CPU. 149 * Anything > that is 0x200-sized slices of 'per CPU' regs. 150 */ 151 if (daddr & ~0x1ff) { 152 ctx_id = (daddr >> 9); 153 if (ctx_id > 8) 154 panic("VGIC: Weird unbanked hv ctrl address %#x!\n", daddr); 155 daddr &= ~0x1ff; 156 } 157 assert(ctx_id < VGIC_CPU_MAX); 158 struct vcpuIntData *vid = &vcpuData[ctx_id]; 159 160 switch (daddr) { 161 case GICH_HCR: 162 pkt->set<uint32_t>(vid->hcr); 163 break; 164 165 case GICH_VTR: 166 pkt->set<uint32_t>(0x44000000 | (NUM_LR - 1)); 167 break; 168 169 case GICH_VMCR: 170 pkt->set<uint32_t>( 171 ((uint32_t)vid->VMPriMask << 27) | 172 ((uint32_t)vid->VMBP << 21) | 173 ((uint32_t)vid->VMABP << 18) | 174 ((uint32_t)vid->VEM << 9) | 175 ((uint32_t)vid->VMCBPR << 4) | 176 ((uint32_t)vid->VMFiqEn << 3) | 177 ((uint32_t)vid->VMAckCtl << 2) | 178 ((uint32_t)vid->VMGrp1En << 1) | 179 ((uint32_t)vid->VMGrp0En << 0) 180 ); 181 break; 182 183 case GICH_MISR: 184 pkt->set<uint32_t>(getMISR(vid)); 185 break; 186 187 case GICH_EISR0: 188 pkt->set<uint32_t>(vid->eisr & 0xffffffff); 189 break; 190 191 case GICH_EISR1: 192 pkt->set<uint32_t>(vid->eisr >> 32); 193 break; 194 195 case GICH_ELSR0: { 196 uint32_t bm = 0; 197 for (int i = 0; i < ((NUM_LR < 32) ? NUM_LR : 32); i++) { 198 if (!vid->LR[i].State) 199 bm |= 1 << i; 200 } 201 pkt->set<uint32_t>(bm); 202 } break; 203 204 case GICH_ELSR1: { 205 uint32_t bm = 0; 206 for (int i = 32; i < NUM_LR; i++) { 207 if (!vid->LR[i].State) 208 bm |= 1 << (i-32); 209 } 210 pkt->set<uint32_t>(bm); 211 } break; 212 213 case GICH_APR0: 214 warn_once("VGIC GICH_APR read!\n"); 215 pkt->set<uint32_t>(0); 216 break; 217 218 case GICH_LR0: 219 case GICH_LR1: 220 case GICH_LR2: 221 case GICH_LR3: 222 pkt->set<uint32_t>(vid->LR[(daddr - GICH_LR0) >> 2]); 223 break; 224 225 default: 226 panic("VGIC HVCtrl read of bad address %#x\n", daddr); 227 } 228 229 pkt->makeAtomicResponse(); 230 return pioDelay; 231} 232 233Tick 234VGic::writeVCpu(PacketPtr pkt) 235{ 236 Addr daddr = pkt->getAddr() - vcpuAddr; 237 238 ContextID ctx_id = pkt->req->contextId(); 239 assert(ctx_id < VGIC_CPU_MAX); 240 struct vcpuIntData *vid = &vcpuData[ctx_id]; 241 242 DPRINTF(VGIC, "VGIC VCPU write register %#x <= %#x\n", daddr, pkt->get<uint32_t>()); 243 244 switch (daddr) { 245 case GICV_CTLR: 246 vid->vctrl = pkt->get<uint32_t>(); 247 break; 248 case GICV_PMR: 249 vid->VMPriMask = pkt->get<uint32_t>(); 250 break; 251 case GICV_EOIR: { 252 // We don't handle the split EOI-then-DIR mode. Linux (guest) 253 // doesn't need it though. 254 assert(!vid->vctrl.EOImode); 255 uint32_t w = pkt->get<uint32_t>(); 256 unsigned int virq = w & 0x3ff; 257 unsigned int vcpu = (w >> 10) & 7; 258 int i = findLRForVIRQ(vid, virq, vcpu); 259 if (i < 0) { 260 DPRINTF(VGIC, "EOIR: No LR for irq %d(cpu%d)\n", virq, vcpu); 261 } else { 262 DPRINTF(VGIC, "EOIR: Found LR%d for irq %d(cpu%d)\n", i, virq, vcpu); 263 ListReg *lr = &vid->LR[i]; 264 lr->State = 0; 265 // Maintenance interrupt -- via eisr -- is flagged when 266 // LRs have EOI=1 and State=INVALID! 267 } 268 } break; 269 default: 270 panic("VGIC VCPU write %#x to unk address %#x\n", pkt->get<uint32_t>(), daddr); 271 } 272 273 // This updates the EISRs and flags IRQs: 274 updateIntState(ctx_id); 275 276 pkt->makeAtomicResponse(); 277 return pioDelay; 278} 279 280Tick 281VGic::writeCtrl(PacketPtr pkt) 282{ 283 Addr daddr = pkt->getAddr() - hvAddr; 284 285 ContextID ctx_id = pkt->req->contextId(); 286 287 DPRINTF(VGIC, "VGIC HVCtrl write register %#x <= %#x\n", daddr, pkt->get<uint32_t>()); 288 289 /* Munge the address: 0-0xfff is the usual space banked by requester CPU. 290 * Anything > that is 0x200-sized slices of 'per CPU' regs. 291 */ 292 if (daddr & ~0x1ff) { 293 ctx_id = (daddr >> 9); 294 if (ctx_id > 8) 295 panic("VGIC: Weird unbanked hv ctrl address %#x!\n", daddr); 296 daddr &= ~0x1ff; 297 } 298 assert(ctx_id < VGIC_CPU_MAX); 299 struct vcpuIntData *vid = &vcpuData[ctx_id]; 300 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
| 59 maintIntPosted[x] = false; 60 vIntPosted[x] = false; 61 } 62 assert(sys->numRunningContexts() <= VGIC_CPU_MAX); 63} 64 65VGic::~VGic() 66{ 67 for (int x = 0; x < VGIC_CPU_MAX; x++) 68 delete postVIntEvent[x]; 69} 70 71Tick 72VGic::read(PacketPtr pkt) 73{ 74 Addr addr = pkt->getAddr(); 75 76 if (addr >= vcpuAddr && addr < vcpuAddr + GICV_SIZE) 77 return readVCpu(pkt); 78 else if (addr >= hvAddr && addr < hvAddr + GICH_REG_SIZE) 79 return readCtrl(pkt); 80 else 81 panic("Read to unknown address %#x\n", pkt->getAddr()); 82} 83 84Tick 85VGic::write(PacketPtr pkt) 86{ 87 Addr addr = pkt->getAddr(); 88 89 if (addr >= vcpuAddr && addr < vcpuAddr + GICV_SIZE) 90 return writeVCpu(pkt); 91 else if (addr >= hvAddr && addr < hvAddr + GICH_REG_SIZE) 92 return writeCtrl(pkt); 93 else 94 panic("Write to unknown address %#x\n", pkt->getAddr()); 95} 96 97Tick 98VGic::readVCpu(PacketPtr pkt) 99{ 100 Addr daddr = pkt->getAddr() - vcpuAddr; 101 102 ContextID ctx_id = pkt->req->contextId(); 103 assert(ctx_id < VGIC_CPU_MAX); 104 struct vcpuIntData *vid = &vcpuData[ctx_id]; 105 106 DPRINTF(VGIC, "VGIC VCPU read register %#x\n", daddr); 107 108 switch (daddr) { 109 case GICV_CTLR: 110 pkt->set<uint32_t>(vid->vctrl); 111 break; 112 case GICV_IAR: { 113 int i = findHighestPendingLR(vid); 114 if (i < 0 || !vid->vctrl.En) { 115 pkt->set<uint32_t>(1023); // "No int" marker 116 } else { 117 ListReg *lr = &vid->LR[i]; 118 119 pkt->set<uint32_t>(lr->VirtualID | 120 (((int)lr->CpuID) << 10)); 121 // We don't support auto-EOI of HW interrupts via real GIC! 122 // Fortunately, KVM doesn't use this. How about Xen...? Ulp! 123 if (lr->HW) 124 panic("VGIC does not support 'HW' List Register feature (LR %#x)!\n", 125 *lr); 126 lr->State = LR_ACTIVE; 127 DPRINTF(VGIC, "Consumed interrupt %d (cpu%d) from LR%d (EOI%d)\n", 128 lr->VirtualID, lr->CpuID, i, lr->EOI); 129 } 130 } break; 131 default: 132 panic("VGIC VCPU read of bad address %#x\n", daddr); 133 } 134 135 updateIntState(ctx_id); 136 137 pkt->makeAtomicResponse(); 138 return pioDelay; 139} 140 141Tick 142VGic::readCtrl(PacketPtr pkt) 143{ 144 Addr daddr = pkt->getAddr() - hvAddr; 145 146 ContextID ctx_id = pkt->req->contextId(); 147 148 DPRINTF(VGIC, "VGIC HVCtrl read register %#x\n", daddr); 149 150 /* Munge the address: 0-0xfff is the usual space banked by requester CPU. 151 * Anything > that is 0x200-sized slices of 'per CPU' regs. 152 */ 153 if (daddr & ~0x1ff) { 154 ctx_id = (daddr >> 9); 155 if (ctx_id > 8) 156 panic("VGIC: Weird unbanked hv ctrl address %#x!\n", daddr); 157 daddr &= ~0x1ff; 158 } 159 assert(ctx_id < VGIC_CPU_MAX); 160 struct vcpuIntData *vid = &vcpuData[ctx_id]; 161 162 switch (daddr) { 163 case GICH_HCR: 164 pkt->set<uint32_t>(vid->hcr); 165 break; 166 167 case GICH_VTR: 168 pkt->set<uint32_t>(0x44000000 | (NUM_LR - 1)); 169 break; 170 171 case GICH_VMCR: 172 pkt->set<uint32_t>( 173 ((uint32_t)vid->VMPriMask << 27) | 174 ((uint32_t)vid->VMBP << 21) | 175 ((uint32_t)vid->VMABP << 18) | 176 ((uint32_t)vid->VEM << 9) | 177 ((uint32_t)vid->VMCBPR << 4) | 178 ((uint32_t)vid->VMFiqEn << 3) | 179 ((uint32_t)vid->VMAckCtl << 2) | 180 ((uint32_t)vid->VMGrp1En << 1) | 181 ((uint32_t)vid->VMGrp0En << 0) 182 ); 183 break; 184 185 case GICH_MISR: 186 pkt->set<uint32_t>(getMISR(vid)); 187 break; 188 189 case GICH_EISR0: 190 pkt->set<uint32_t>(vid->eisr & 0xffffffff); 191 break; 192 193 case GICH_EISR1: 194 pkt->set<uint32_t>(vid->eisr >> 32); 195 break; 196 197 case GICH_ELSR0: { 198 uint32_t bm = 0; 199 for (int i = 0; i < ((NUM_LR < 32) ? NUM_LR : 32); i++) { 200 if (!vid->LR[i].State) 201 bm |= 1 << i; 202 } 203 pkt->set<uint32_t>(bm); 204 } break; 205 206 case GICH_ELSR1: { 207 uint32_t bm = 0; 208 for (int i = 32; i < NUM_LR; i++) { 209 if (!vid->LR[i].State) 210 bm |= 1 << (i-32); 211 } 212 pkt->set<uint32_t>(bm); 213 } break; 214 215 case GICH_APR0: 216 warn_once("VGIC GICH_APR read!\n"); 217 pkt->set<uint32_t>(0); 218 break; 219 220 case GICH_LR0: 221 case GICH_LR1: 222 case GICH_LR2: 223 case GICH_LR3: 224 pkt->set<uint32_t>(vid->LR[(daddr - GICH_LR0) >> 2]); 225 break; 226 227 default: 228 panic("VGIC HVCtrl read of bad address %#x\n", daddr); 229 } 230 231 pkt->makeAtomicResponse(); 232 return pioDelay; 233} 234 235Tick 236VGic::writeVCpu(PacketPtr pkt) 237{ 238 Addr daddr = pkt->getAddr() - vcpuAddr; 239 240 ContextID ctx_id = pkt->req->contextId(); 241 assert(ctx_id < VGIC_CPU_MAX); 242 struct vcpuIntData *vid = &vcpuData[ctx_id]; 243 244 DPRINTF(VGIC, "VGIC VCPU write register %#x <= %#x\n", daddr, pkt->get<uint32_t>()); 245 246 switch (daddr) { 247 case GICV_CTLR: 248 vid->vctrl = pkt->get<uint32_t>(); 249 break; 250 case GICV_PMR: 251 vid->VMPriMask = pkt->get<uint32_t>(); 252 break; 253 case GICV_EOIR: { 254 // We don't handle the split EOI-then-DIR mode. Linux (guest) 255 // doesn't need it though. 256 assert(!vid->vctrl.EOImode); 257 uint32_t w = pkt->get<uint32_t>(); 258 unsigned int virq = w & 0x3ff; 259 unsigned int vcpu = (w >> 10) & 7; 260 int i = findLRForVIRQ(vid, virq, vcpu); 261 if (i < 0) { 262 DPRINTF(VGIC, "EOIR: No LR for irq %d(cpu%d)\n", virq, vcpu); 263 } else { 264 DPRINTF(VGIC, "EOIR: Found LR%d for irq %d(cpu%d)\n", i, virq, vcpu); 265 ListReg *lr = &vid->LR[i]; 266 lr->State = 0; 267 // Maintenance interrupt -- via eisr -- is flagged when 268 // LRs have EOI=1 and State=INVALID! 269 } 270 } break; 271 default: 272 panic("VGIC VCPU write %#x to unk address %#x\n", pkt->get<uint32_t>(), daddr); 273 } 274 275 // This updates the EISRs and flags IRQs: 276 updateIntState(ctx_id); 277 278 pkt->makeAtomicResponse(); 279 return pioDelay; 280} 281 282Tick 283VGic::writeCtrl(PacketPtr pkt) 284{ 285 Addr daddr = pkt->getAddr() - hvAddr; 286 287 ContextID ctx_id = pkt->req->contextId(); 288 289 DPRINTF(VGIC, "VGIC HVCtrl write register %#x <= %#x\n", daddr, pkt->get<uint32_t>()); 290 291 /* Munge the address: 0-0xfff is the usual space banked by requester CPU. 292 * Anything > that is 0x200-sized slices of 'per CPU' regs. 293 */ 294 if (daddr & ~0x1ff) { 295 ctx_id = (daddr >> 9); 296 if (ctx_id > 8) 297 panic("VGIC: Weird unbanked hv ctrl address %#x!\n", daddr); 298 daddr &= ~0x1ff; 299 } 300 assert(ctx_id < VGIC_CPU_MAX); 301 struct vcpuIntData *vid = &vcpuData[ctx_id]; 302 303 switch (daddr) { 304 case GICH_HCR: 305 vid->hcr = pkt->get<uint32_t>(); 306 // update int state 307 break; 308 309 case GICH_VMCR: { 310 uint32_t d = pkt->get<uint32_t>(); 311 vid->VMPriMask = d >> 27; 312 vid->VMBP = (d >> 21) & 7; 313 vid->VMABP = (d >> 18) & 7; 314 vid->VEM = (d >> 9) & 1; 315 vid->VMCBPR = (d >> 4) & 1; 316 vid->VMFiqEn = (d >> 3) & 1; 317 vid->VMAckCtl = (d >> 2) & 1; 318 vid->VMGrp1En = (d >> 1) & 1; 319 vid->VMGrp0En = d & 1; 320 } break; 321 322 case GICH_APR0: 323 warn_once("VGIC GICH_APR0 written, ignored\n"); 324 break; 325 326 case GICH_LR0: 327 case GICH_LR1: 328 case GICH_LR2: 329 case GICH_LR3: 330 vid->LR[(daddr - GICH_LR0) >> 2] = pkt->get<uint32_t>(); 331 // update int state 332 break; 333 334 default: 335 panic("VGIC HVCtrl write to bad address %#x\n", daddr); 336 } 337 338 updateIntState(ctx_id); 339 340 pkt->makeAtomicResponse(); 341 return pioDelay; 342} 343 344 345uint32_t 346VGic::getMISR(struct vcpuIntData *vid) 347{ 348 return (!!vid->hcr.VGrp1DIE && !vid->VMGrp1En ? 0x80 : 0) | 349 (!!vid->hcr.VGrp1EIE && vid->VMGrp1En ? 0x40 : 0) | 350 (!!vid->hcr.VGrp0DIE && !vid->VMGrp0En ? 0x20 : 0) | 351 (!!vid->hcr.VGrp0EIE && vid->VMGrp0En ? 0x10 : 0) | 352 (!!vid->hcr.NPIE && !lrPending(vid) ? 0x08 : 0) | 353 (!!vid->hcr.LRENPIE && vid->hcr.EOICount ? 0x04 : 0) | 354 (!!vid->hcr.UIE && lrValid(vid) <= 1 ? 0x02 : 0) | 355 (vid->eisr ? 0x01 : 0); 356} 357 358void 359VGic::postVInt(uint32_t cpu, Tick when) 360{ 361 DPRINTF(VGIC, "Posting VIRQ to %d\n", cpu); 362 if (!(postVIntEvent[cpu]->scheduled())) 363 eventq->schedule(postVIntEvent[cpu], when); 364} 365 366void 367VGic::unPostVInt(uint32_t cpu) 368{ 369 DPRINTF(VGIC, "Unposting VIRQ to %d\n", cpu); 370 platform->intrctrl->clear(cpu, ArmISA::INT_VIRT_IRQ, 0); 371} 372 373void
|
| 374VGic::processPostVIntEvent(uint32_t cpu) 375{ 376 platform->intrctrl->post(cpu, ArmISA::INT_VIRT_IRQ, 0); 377} 378 379 380void
|
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}
| 381VGic::postMaintInt(uint32_t cpu) 382{ 383 DPRINTF(VGIC, "Posting maintenance PPI to GIC/cpu%d\n", cpu); 384 // Linux DT configures this as Level. 385 gic->sendPPInt(maintInt, cpu); 386} 387 388void 389VGic::unPostMaintInt(uint32_t cpu) 390{ 391 DPRINTF(VGIC, "Unposting maintenance PPI to GIC/cpu%d\n", cpu); 392 gic->clearPPInt(maintInt, cpu); 393} 394 395/* Update state (in general); something concerned with ctx_id has changed. 396 * This may raise a maintenance interrupt. 397 */ 398void 399VGic::updateIntState(ContextID ctx_id) 400{ 401 // @todo This should update APRs! 402 403 // Build EISR contents: 404 // (Cached so that regs can read them without messing about again) 405 struct vcpuIntData *tvid = &vcpuData[ctx_id]; 406 407 tvid->eisr = 0; 408 for (int i = 0; i < NUM_LR; i++) { 409 if (!tvid->LR[i].State && tvid->LR[i].EOI) { 410 tvid->eisr |= 1 << i; 411 } 412 } 413 414 assert(sys->numRunningContexts() <= VGIC_CPU_MAX); 415 for (int i = 0; i < sys->numRunningContexts(); i++) { 416 struct vcpuIntData *vid = &vcpuData[i]; 417 // Are any LRs active that weren't before? 418 if (!vIntPosted[i]) { 419 if (lrPending(vid) && vid->vctrl.En) { 420 vIntPosted[i] = true; 421 postVInt(i, curTick() + 1); 422 } 423 } else if (!lrPending(vid)) { 424 vIntPosted[i] = false; 425 unPostVInt(i); 426 } 427 428 // Any maintenance ints to send? 429 if (!maintIntPosted[i]) { 430 if (vid->hcr.En && getMISR(vid)) { 431 maintIntPosted[i] = true; 432 postMaintInt(i); 433 } 434 } else { 435 if (!vid->hcr.En || !getMISR(vid)) { 436 unPostMaintInt(i); 437 maintIntPosted[i] = false; 438 } 439 } 440 } 441} 442 443AddrRangeList 444VGic::getAddrRanges() const 445{ 446 AddrRangeList ranges; 447 ranges.push_back(RangeSize(hvAddr, GICH_REG_SIZE)); 448 ranges.push_back(RangeSize(vcpuAddr, GICV_SIZE)); 449 return ranges; 450} 451 452void 453VGic::serialize(CheckpointOut &cp) const 454{ 455 Tick interrupt_time[VGIC_CPU_MAX]; 456 for (uint32_t cpu = 0; cpu < VGIC_CPU_MAX; cpu++) { 457 interrupt_time[cpu] = 0; 458 if (postVIntEvent[cpu]->scheduled()) { 459 interrupt_time[cpu] = postVIntEvent[cpu]->when(); 460 } 461 } 462 463 DPRINTF(Checkpoint, "Serializing VGIC\n"); 464 465 SERIALIZE_ARRAY(interrupt_time, VGIC_CPU_MAX); 466 SERIALIZE_ARRAY(maintIntPosted, VGIC_CPU_MAX); 467 SERIALIZE_ARRAY(vIntPosted, VGIC_CPU_MAX); 468 SERIALIZE_SCALAR(vcpuAddr); 469 SERIALIZE_SCALAR(hvAddr); 470 SERIALIZE_SCALAR(pioDelay); 471 SERIALIZE_SCALAR(maintInt); 472 473 for (uint32_t cpu = 0; cpu < VGIC_CPU_MAX; cpu++) 474 vcpuData[cpu].serializeSection(cp, csprintf("vcpuData%d", cpu)); 475} 476 477void 478VGic::vcpuIntData::serialize(CheckpointOut &cp) const 479{ 480 uint32_t vctrl_val = vctrl; 481 SERIALIZE_SCALAR(vctrl_val); 482 uint32_t hcr_val = hcr; 483 SERIALIZE_SCALAR(hcr_val); 484 uint64_t eisr_val = eisr; 485 SERIALIZE_SCALAR(eisr_val); 486 uint8_t VMGrp0En_val = VMGrp0En; 487 SERIALIZE_SCALAR(VMGrp0En_val); 488 uint8_t VMGrp1En_val = VMGrp1En; 489 SERIALIZE_SCALAR(VMGrp1En_val); 490 uint8_t VMAckCtl_val = VMAckCtl; 491 SERIALIZE_SCALAR(VMAckCtl_val); 492 uint8_t VMFiqEn_val = VMFiqEn; 493 SERIALIZE_SCALAR(VMFiqEn_val); 494 uint8_t VMCBPR_val = VMCBPR; 495 SERIALIZE_SCALAR(VMCBPR_val); 496 uint8_t VEM_val = VEM; 497 SERIALIZE_SCALAR(VEM_val); 498 uint8_t VMABP_val = VMABP; 499 SERIALIZE_SCALAR(VMABP_val); 500 uint8_t VMBP_val = VMBP; 501 SERIALIZE_SCALAR(VMBP_val); 502 uint8_t VMPriMask_val = VMPriMask; 503 SERIALIZE_SCALAR(VMPriMask_val); 504 505 for (int i = 0; i < NUM_LR; i++) { 506 ScopedCheckpointSection sec_lr(cp, csprintf("LR%d", i)); 507 paramOut(cp, "lr", LR[i]); 508 } 509} 510 511void VGic::unserialize(CheckpointIn &cp) 512{ 513 DPRINTF(Checkpoint, "Unserializing Arm GIC\n"); 514 515 Tick interrupt_time[VGIC_CPU_MAX]; 516 UNSERIALIZE_ARRAY(interrupt_time, VGIC_CPU_MAX); 517 for (uint32_t cpu = 0; cpu < VGIC_CPU_MAX; cpu++) { 518 if (interrupt_time[cpu]) 519 schedule(postVIntEvent[cpu], interrupt_time[cpu]); 520 521 vcpuData[cpu].unserializeSection(cp, csprintf("vcpuData%d", cpu)); 522 } 523 UNSERIALIZE_ARRAY(maintIntPosted, VGIC_CPU_MAX); 524 UNSERIALIZE_ARRAY(vIntPosted, VGIC_CPU_MAX); 525 UNSERIALIZE_SCALAR(vcpuAddr); 526 UNSERIALIZE_SCALAR(hvAddr); 527 UNSERIALIZE_SCALAR(pioDelay); 528 UNSERIALIZE_SCALAR(maintInt); 529} 530 531void 532VGic::vcpuIntData::unserialize(CheckpointIn &cp) 533{ 534 paramIn(cp, "vctrl_val", vctrl); 535 paramIn(cp, "hcr_val", hcr); 536 paramIn(cp, "eisr_val", eisr); 537 paramIn(cp, "VMGrp0En_val", VMGrp0En); 538 paramIn(cp, "VMGrp1En_val", VMGrp1En); 539 paramIn(cp, "VMAckCtl_val", VMAckCtl); 540 paramIn(cp, "VMFiqEn_val", VMFiqEn); 541 paramIn(cp, "VMCBPR_val", VMCBPR); 542 paramIn(cp, "VEM_val", VEM); 543 paramIn(cp, "VMABP_val", VMABP); 544 paramIn(cp, "VMPriMask_val", VMPriMask); 545 546 for (int i = 0; i < NUM_LR; i++) { 547 ScopedCheckpointSection sec_lr(cp, csprintf("LR%d", i)); 548 paramIn(cp, "lr", LR[i]); 549 } 550} 551 552VGic * 553VGicParams::create() 554{ 555 return new VGic(this); 556}
|