khypervisor
v1
|
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