khypervisor  v1
gic/vgic.c
Go to the documentation of this file.
00001 #include <vgic.h>
00002 #include <hvmm_trace.h>
00003 #include <armv7_p15.h>
00004 #include <gic.h>
00005 #include <gic_regs.h>
00006 #include <slotpirq.h>
00007 #include <context.h>
00008 #include <k-hypervisor-config.h>
00009 #include <asm-arm_inline.h>
00010 
00011 #include <log/print.h>
00012 
00013 /* for test, surpress traces */
00014 #define __VGIC_DISABLE_TRACE__
00015 #define VGIC_SIMULATE_HWVIRQ
00016 
00017 #ifdef __VGIC_DISABLE_TRACE__
00018 #ifdef HVMM_TRACE_ENTER
00019 #undef HVMM_TRACE_ENTER
00020 #undef HVMM_TRACE_EXIT
00021 #undef HVMM_TRACE_HEX32
00022 #define HVMM_TRACE_ENTER()
00023 #define HVMM_TRACE_EXIT()
00024 #define HVMM_TRACE_HEX32(a,b)
00025 #endif
00026 #endif
00027 
00028 /* Cortex-A15: 25 (PPI6) */
00029 #define VGIC_MAINTENANCE_INTERRUPT_IRQ  25
00030 
00031 #define VGIC_MAX_LISTREGISTERS          VGIC_NUM_MAX_SLOTS
00032 #define VGIC_SIGNATURE_INITIALIZED      0x45108EAD
00033 #define VGIC_READY()                    (_vgic.initialized == VGIC_SIGNATURE_INITIALIZED) 
00034 
00035 /*
00036  * Operations:
00037  * - INIT - [V] Number of List Registers
00038  * - INIT - [V] route/enable maintenance IRQ
00039  * - INIT - [V] enable VGIC
00040  * - INIT - [V] Enable/Disable Virtual IRQ HCR.VI[7]
00041  *       - vgic_inject_enable()
00042  * - [V] Inject virq, slot(lr), hw?, state=pending,priority,
00043  *      - hw:1 - physicalID
00044  *      - hw:0 - cpuid, EOI(->maintenance int)
00045  *      GICH_ELSR[VIRQ/32][VIRQ%32] == 1, Free
00046  *      Otherwise, Used
00047  *
00048  *      - vgic_inject_virq( virq, slot, state, priority, hw, physrc, maintenance )
00049  *      - vgic_inject_virq_hw( virq, state, priority, pirq)
00050  *      - vgic_inject_virq_sw( virq, state, priority, cpuid, maintenance )
00051  *
00052  *  - [*] ISR: Maintenance IRQ
00053  *      Check VICH_MISR
00054  *          [V] EOI - At least one VIRQ EOI
00055  *          [ ] U - Underflow - Non or one valid interrupt in LRs
00056  *          [ ] LRENP - LI Entry Not Present (no valid interrupt for an EOI request)
00057  *          [ ] NP - No Pending Interrupt
00058  *          [ ] VGrp[0/1][E/D] 
00059  *  - [V] Context Switch:
00060  *  Saved/Restored Registers:
00061  *      - GICH_LR
00062  *      - GICH_APR
00063  *      - GICH_HCR
00064  *      - GICH_VMCR
00065  *  Saved/Restored Data:
00066  *      - Free Interrupts
00067  *
00068  */
00069 
00070 struct vgic {
00071     volatile uint32_t *base;    /* Base address of VGIC (Virtual Interface Control Registers) */
00072     uint32_t num_lr;            /* Number of List Registers */
00073     uint32_t initialized;       /* vgic module initialized if == VGIC_SIGNATURE_INITIALIZED */
00074     uint64_t valid_lr_mask;
00075 };
00076 
00077 hvmm_status_t vgic_injection_enable(uint8_t enable);
00078 
00079 static struct vgic _vgic;
00080 static void (*_cb_virq_flush)(vmid_t vmid) = 0;
00081 
00082 static uint32_t vgic_find_free_slot(void)
00083 {
00084     uint32_t slot;
00085     uint32_t shift = 0;
00086 
00087     slot = _vgic.base[GICH_ELSR0];
00088     if ( slot == 0 && _vgic.num_lr > 32 ) {
00089         /* first 32 slots are occupied, try the later */
00090         slot = _vgic.base[GICH_ELSR1];
00091         shift = 32;
00092     }
00093 
00094 
00095     if ( slot ) {
00096         slot &= -(slot);
00097         slot = (31 - asm_clz(slot));
00098         slot += shift;
00099     } else {
00100         /* 64 slots are fully occupied */
00101         slot = VGIC_SLOT_NOTFOUND;
00102     }
00103     return slot;
00104 }
00105 
00106 /*
00107  * Test if the List Registers 'slot' is free
00108  * Return
00109  *  Free - 'slot' is returned
00110  *  Occupied but another free slot found - new free slot
00111  *  Fully occupied - VGIC_SLOT_NOTFOUND
00112  */
00113 
00114 static uint32_t vgic_is_free_slot(uint32_t slot)
00115 {
00116     uint32_t free_slot = VGIC_SLOT_NOTFOUND;
00117     
00118     if ( slot < 32 ) {
00119         if ( _vgic.base[GICH_ELSR0] & (1 << slot) )
00120             free_slot = slot;
00121     } else {
00122         if ( _vgic.base[GICH_ELSR1] & (1 << (slot - 32)) )
00123             free_slot = slot;
00124     }
00125 
00126     if ( free_slot != slot ) {
00127         free_slot = vgic_find_free_slot();
00128     }
00129 
00130     return free_slot;
00131 }
00132 
00133 static void _vgic_dump_status(void)
00134 {
00135     /*
00136      * === VGIC Status Summary ===
00137      * Initialized: Yes
00138      * Num ListRegs: n
00139      * Hypervisor Control
00140      *  - Enabled: Yes
00141      *  - EOICount: 
00142      *  - Underflow:
00143      *  - LRENPIE:
00144      *  - NPIE:
00145      *  - VGrp0EIE:
00146      *  - VGrp0DIE:
00147      *  - VGrp1EIE:
00148      *  - VGrp1DIE:
00149      * VGIC Type
00150      *  - ListRegs:
00151      *  - PREbits:
00152      *  - PRIbits:
00153      * Virtual Machine Control
00154      *  - 
00155      */
00156     uart_print("=== VGIC Status ===\n\r");
00157     uart_print(" Initialized:"); uart_print( ( VGIC_READY() ? "Yes" : "No" ) ); uart_print("\n\r");
00158     uart_print(" Num ListRegs:"); uart_print_hex32( _vgic.num_lr ); uart_print("\n\r");
00159     uart_print(" LR_MASK:"); uart_print_hex64( _vgic.valid_lr_mask ); uart_print("\n\r");
00160 }
00161 
00162 static void _vgic_dump_regs(void)
00163 {
00164 #ifndef __VGIC_DISABLE_TRACE__
00165     /*
00166      * HCR * VTR * VMCR * MISR * EISR0 * EISR1 * ELSR0 * ELSR1 * APR * LR0~n
00167      */
00168     int i;
00169     HVMM_TRACE_ENTER();
00170 
00171     uart_print("  hcr:"); uart_print_hex32( _vgic.base[GICH_HCR] ); uart_print("\n\r");
00172     uart_print("  vtr:"); uart_print_hex32( _vgic.base[GICH_VTR] ); uart_print("\n\r");
00173     uart_print(" vmcr:"); uart_print_hex32( _vgic.base[GICH_VMCR] ); uart_print("\n\r");
00174     uart_print(" misr:"); uart_print_hex32( _vgic.base[GICH_MISR] ); uart_print("\n\r");
00175     uart_print("eisr0:"); uart_print_hex32( _vgic.base[GICH_EISR0] ); uart_print("\n\r");
00176     uart_print("eisr1:"); uart_print_hex32( _vgic.base[GICH_EISR1] ); uart_print("\n\r");
00177     uart_print("elsr0:"); uart_print_hex32( _vgic.base[GICH_ELSR0] ); uart_print("\n\r");
00178     uart_print("elsr1:"); uart_print_hex32( _vgic.base[GICH_ELSR1] ); uart_print("\n\r");
00179     uart_print("  apr:"); uart_print_hex32( _vgic.base[GICH_APR] ); uart_print("\n\r");
00180 
00181     uart_print("   LR:\n\r"); 
00182     for( i = 0; i < _vgic.num_lr; i++ ) {
00183         if ( vgic_is_free_slot(i) != i ) {
00184             uart_print_hex32( _vgic.base[GICH_LR + i] ); uart_print(" - "); uart_print_hex32(i); uart_print("\n\r");
00185         }
00186     }
00187 
00188     HVMM_TRACE_EXIT();
00189 #endif
00190 }
00191 
00192 static void _vgic_isr_maintenance_irq(int irq, void *pregs, void *pdata)
00193 {
00194     HVMM_TRACE_ENTER();
00195 
00196     if ( _vgic.base[GICH_MISR] & GICH_MISR_EOI ) {
00197         /* clean up invalid entries from List Registers */
00198         uint32_t eisr = _vgic.base[GICH_EISR0];
00199         uint32_t slot;
00200         uint32_t pirq;
00201         vmid_t vmid;
00202 
00203         vmid = context_current_vmid();
00204         while(eisr) {
00205             slot = (31 - asm_clz(eisr));
00206             eisr &= ~(1 << slot);
00207             _vgic.base[GICH_LR + slot] = 0;
00208 
00209             /* deactivate associated pirq at the slot */
00210             pirq = slotpirq_get(vmid, slot);
00211             if ( pirq != PIRQ_INVALID ) {
00212                 gic_deactivate_irq(pirq);
00213                 slotpirq_clear(vmid, slot);
00214                 printh( "vgic: deactivated pirq %d at slot %d\n", pirq, slot );
00215             } else {
00216                 printh( "vgic: deactivated virq at slot %d\n", slot );
00217             }
00218             slotvirq_clear(vmid, slot);
00219         }
00220 
00221         eisr = _vgic.base[GICH_EISR1];
00222         while(eisr) {
00223             slot = (31 - asm_clz(eisr));
00224             eisr &= ~(1 << slot);
00225             _vgic.base[GICH_LR + slot + 32] = 0;
00226 
00227             /* deactivate associated pirq at the slot */
00228             pirq = slotpirq_get(vmid, slot + 32);
00229             if ( pirq != PIRQ_INVALID ) {
00230                 gic_deactivate_irq(pirq);
00231                 slotpirq_clear(vmid, slot + 32);
00232                 printh( "vgic: deactivated pirq %d at slot %d\n", pirq, slot );
00233             } else {
00234                 printh( "vgic: deactivated virq at slot %d\n", slot );
00235             }
00236             slotvirq_clear(vmid, slot);
00237         }
00238     }
00239 
00240     if ( _vgic.base[GICH_MISR] & GICH_MISR_NP ) {
00241         /* No pending virqs, no need to keep vgic enabled */
00242         _vgic.base[GICH_HCR] &= ~(GICH_HCR_NPIE);
00243         printh( "vgic: no pending virqs, disabling no pending interrupt\n" );
00244         {
00245             int i;
00246             printh( "vgic: active virqs...\n" );
00247             for (i = 0; i < _vgic.num_lr; i++ ) {
00248                 if ( _vgic.base[GICH_LR + i] & 0x20000000 ) {
00249                     printh( "- lr[%d]: %x\n", i, _vgic.base[GICH_LR + i] );
00250                 }
00251             }
00252         }
00253     }
00254     
00255     {
00256       uint64_t elsr;
00257       elsr = _vgic.base[GICH_ELSR1];
00258       elsr <<= 32;
00259       elsr |= _vgic.base[GICH_ELSR0];
00260 
00261       if ( ((~elsr) & _vgic.valid_lr_mask) == 0 ) {
00262         /* No valid interrupt */
00263           vgic_enable(0);
00264           vgic_injection_enable(0);
00265           printh( "vgic: no valid virqs, disabling vgic\n" );
00266      } else {
00267           printh( "vgic:MISR:%x ELSR0:%x ELSR1:%x\n",
00268                _vgic.base[GICH_MISR], 
00269                _vgic.base[GICH_ELSR0],
00270                _vgic.base[GICH_ELSR1]);
00271         }
00272     }
00273 
00274     HVMM_TRACE_EXIT();
00275 }
00276 
00277 hvmm_status_t vgic_enable(uint8_t enable)
00278 {
00279     hvmm_status_t result = HVMM_STATUS_BAD_ACCESS;
00280 
00281     if ( VGIC_READY() ) {
00282 
00283         if ( enable ) {
00284             uint32_t hcr = _vgic.base[GICH_HCR];
00285 
00286             hcr |= GICH_HCR_EN | GICH_HCR_NPIE;
00287 
00288             _vgic.base[GICH_HCR] = hcr;
00289         } else {
00290             _vgic.base[GICH_HCR] &= ~(GICH_HCR_EN | GICH_HCR_NPIE);
00291         }
00292 
00293         result = HVMM_STATUS_SUCCESS;
00294     } 
00295     return result;
00296 }
00297 
00298 hvmm_status_t vgic_injection_enable(uint8_t enable)
00299 {
00300     uint32_t hcr;
00301 
00302     hcr = read_hcr();
00303     if ( enable ) {
00304         if ( (hcr & HCR_VI) == 0 ) {
00305             hcr |= HCR_VI;
00306             write_hcr(hcr);
00307         }
00308     } else {
00309         if ( hcr & HCR_VI ) {
00310             hcr &= ~(HCR_VI);
00311             write_hcr(hcr);
00312         }
00313     }
00314 
00315     hcr = read_hcr();
00316     printh( " updated hcr: %x\n", hcr);
00317     return HVMM_STATUS_SUCCESS;
00318 }
00319 
00320 /*
00321  * Params
00322  * @virq            virtual id (seen to the guest as an IRQ)
00323  * @slot            index to GICH_LR, slot < _vgic.num_lr
00324  * @state           INACTIVE, PENDING, ACTIVE, or PENDING_ACTIVE
00325  * @priority        5bit priority
00326  * @hw              1 - physical interrupt, 0 - otherwise
00327  * @physrc          hw:1 - Physical ID, hw:0 - CPUID
00328  * @maintenance     hw:0, requires EOI asserts Virtual Maintenance Interrupt
00329  *
00330  * @return          slot index, or VGIC_SLOT_NOTFOUND
00331  */
00332 uint32_t vgic_inject_virq( 
00333         uint32_t virq, uint32_t slot, virq_state_t state, uint32_t priority, 
00334         uint8_t hw, uint32_t physrc, uint8_t maintenance )
00335 {
00336     uint32_t physicalid;
00337     uint32_t lr_desc;
00338 
00339     HVMM_TRACE_ENTER();
00340 
00341     physicalid = (hw ? physrc : (maintenance << 9) | (physrc & 0x7)) << GICH_LR_PHYSICALID_SHIFT;
00342     physicalid &= GICH_LR_PHYSICALID_MASK;
00343 
00344 
00345     lr_desc = (GICH_LR_HW_MASK & (hw << GICH_LR_HW_SHIFT) ) |
00346         /* (GICH_LR_GRP1_MASK & (1 << GICH_LR_GRP1_SHIFT) )| */
00347         (GICH_LR_STATE_MASK & (state << GICH_LR_STATE_SHIFT) ) |
00348         (GICH_LR_PRIORITY_MASK & ( (priority >> 3)  << GICH_LR_PRIORITY_SHIFT) ) |
00349         physicalid |
00350         (GICH_LR_VIRTUALID_MASK & virq );
00351 
00352     slot = vgic_is_free_slot( slot );
00353 
00354     HVMM_TRACE_HEX32("lr_desc:", lr_desc);
00355     HVMM_TRACE_HEX32("free slot:", slot);
00356 
00357     if ( slot != VGIC_SLOT_NOTFOUND ) {
00358         _vgic.base[GICH_LR + slot] = lr_desc;
00359         vgic_injection_enable(1);
00360         vgic_enable(1);
00361     }
00362     _vgic_dump_regs();
00363 
00364     HVMM_TRACE_EXIT();
00365     return slot;
00366 }
00367 
00368 /*
00369  * Return: slot index if successful, VGIC_SLOT_NOTFOUND otherwise 
00370  */
00371 uint32_t vgic_inject_virq_hw( uint32_t virq, virq_state_t state, uint32_t priority, uint32_t pirq)
00372 {
00373     uint32_t slot = VGIC_SLOT_NOTFOUND;
00374     HVMM_TRACE_ENTER();
00375 
00376     slot = vgic_find_free_slot();
00377     HVMM_TRACE_HEX32("slot:", slot);
00378     if ( slot != VGIC_SLOT_NOTFOUND ) {
00379 #ifdef VGIC_SIMULATE_HWVIRQ
00380         slot = vgic_inject_virq( virq, slot, state, priority, 0, 0, 1 );
00381 #else
00382         slot = vgic_inject_virq( virq, slot, state, priority, 1, pirq, 0 );
00383 #endif
00384     }
00385 
00386     HVMM_TRACE_EXIT();
00387     return slot;
00388 }
00389 
00390 uint32_t vgic_inject_virq_sw( uint32_t virq, virq_state_t state, uint32_t priority, uint32_t cpuid, uint8_t maintenance)
00391 {
00392     uint32_t slot = VGIC_SLOT_NOTFOUND;
00393     HVMM_TRACE_ENTER();
00394 
00395     slot = vgic_find_free_slot();
00396     HVMM_TRACE_HEX32("slot:", slot);
00397     if ( slot != VGIC_SLOT_NOTFOUND ) {
00398         slot = vgic_inject_virq( virq, slot, state, priority, 0, cpuid, maintenance );
00399     }
00400 
00401     HVMM_TRACE_EXIT();
00402     return slot;
00403 }
00404 
00405 
00406 hvmm_status_t vgic_maintenance_irq_enable(uint8_t enable)
00407 {
00408     uint32_t irq = VGIC_MAINTENANCE_INTERRUPT_IRQ;
00409 
00410     HVMM_TRACE_ENTER();
00411     if ( enable ) {
00412         gic_test_set_irq_handler( irq, &_vgic_isr_maintenance_irq, 0 );
00413         gic_test_configure_irq( irq,
00414                 GIC_INT_POLARITY_LEVEL,
00415                 gic_cpumask_current(),
00416                 GIC_INT_PRIORITY_DEFAULT );
00417     } else {
00418         gic_test_set_irq_handler( irq, 0, 0 );
00419         gic_disable_irq( irq );
00420     }
00421     HVMM_TRACE_EXIT();
00422     return HVMM_STATUS_SUCCESS;
00423 }
00424 
00425 static uint64_t _vgic_valid_lr_mask( uint32_t num_lr )
00426 {
00427     uint64_t mask_valid_lr = 0xFFFFFFFFFFFFFFFFULL;
00428     if ( num_lr < VGIC_MAX_LISTREGISTERS ) {
00429         mask_valid_lr >>= num_lr;
00430         mask_valid_lr <<= num_lr;
00431         mask_valid_lr = ~mask_valid_lr;
00432     }
00433 
00434     return mask_valid_lr;
00435 }
00436 
00437 /* 
00438  * Registers the callback for flushing out queued virqs for the specified guest (vmid)
00439  */
00440 hvmm_status_t vgic_setcallback_virq_flush(void (*callback)(vmid_t vmid))
00441 {
00442     _cb_virq_flush = callback;
00443     if ( _cb_virq_flush == 0 ) {
00444         printh( "vgic: virq_flush() cleared\n" );
00445     } else {
00446         printh( "vgic: virq_flush() set to function at %x\n", (uint32_t) _cb_virq_flush );
00447     }
00448     return HVMM_STATUS_SUCCESS;
00449 }
00450 
00451 hvmm_status_t vgic_init(void)
00452 {
00453     hvmm_status_t result = HVMM_STATUS_UNKNOWN_ERROR;
00454 
00455     HVMM_TRACE_ENTER();
00456 
00457     _vgic.base = gic_vgic_baseaddr();
00458     _vgic.num_lr = (_vgic.base[GICH_VTR] & GICH_VTR_LISTREGS_MASK) + 1;
00459     _vgic.valid_lr_mask = _vgic_valid_lr_mask( _vgic.num_lr );
00460     _vgic.initialized = VGIC_SIGNATURE_INITIALIZED;
00461 
00462     vgic_maintenance_irq_enable(1);
00463 
00464     slotpirq_init();
00465 
00466     result = HVMM_STATUS_SUCCESS;
00467 
00468     _vgic_dump_status();
00469     _vgic_dump_regs();
00470 
00471     HVMM_TRACE_EXIT();
00472     return result;
00473 }
00474 
00475 hvmm_status_t vgic_init_status( struct vgic_status *status, vmid_t vmid)
00476 {
00477     hvmm_status_t result = HVMM_STATUS_SUCCESS;
00478     int i;
00479 
00480     status->hcr = 0;
00481     status->apr = 0;
00482     status->vmcr = 0;
00483     status->saved_once = 0;
00484     for( i = 0; i < _vgic.num_lr; i++) {
00485         status->lr[i] = 0;
00486     }
00487 
00488     return result;
00489 }
00490 
00491 hvmm_status_t vgic_save_status( struct vgic_status *status, vmid_t vmid )
00492 {
00493     hvmm_status_t result = HVMM_STATUS_SUCCESS;
00494     int i;
00495 
00496 
00497     for( i = 0; i < _vgic.num_lr; i++ ) {
00498         status->lr[i] = _vgic.base[GICH_LR + i];
00499     }
00500     status->hcr = _vgic.base[GICH_HCR];
00501     status->apr = _vgic.base[GICH_APR];
00502     status->vmcr = _vgic.base[GICH_VMCR];
00503     status->saved_once = VGIC_SIGNATURE_INITIALIZED;
00504 
00505     vgic_enable(0);
00506     return result;
00507 }
00508 
00509 hvmm_status_t vgic_restore_status( struct vgic_status *status, vmid_t vmid )
00510 {
00511     hvmm_status_t result = HVMM_STATUS_BAD_ACCESS;
00512     int i;
00513 
00514     for( i = 0; i < _vgic.num_lr; i++) {
00515         _vgic.base[GICH_LR + i] = status->lr[i];
00516     }
00517     _vgic.base[GICH_APR] = status->apr;
00518     _vgic.base[GICH_VMCR] = status->vmcr;
00519     _vgic.base[GICH_HCR] = status->hcr;
00520 
00521     /* Inject queued virqs to the next guest */
00522     vgic_flush_virqs(vmid);
00523 
00524     _vgic_dump_regs();
00525     result = HVMM_STATUS_SUCCESS;
00526 
00527     return result;
00528 }
00529 
00530 hvmm_status_t vgic_flush_virqs(vmid_t vmid)
00531 {
00532     hvmm_status_t result = HVMM_STATUS_IGNORED;
00533     if ( _cb_virq_flush != 0 ) {
00534         _cb_virq_flush(vmid);
00535         result = HVMM_STATUS_SUCCESS;
00536     }
00537 
00538     return result;
00539 }
00540 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines