void extra_timer_callback(void *pdata) { HVMM_TRACE_ENTER(); HVMM_TRACE_EXIT(); }
hvmm_status_t vdev_reg_device(vdev_info_t *new_vdev) { hvmm_status_t result = HVMM_STATUS_BUSY; int i = 0; HVMM_TRACE_ENTER(); for (i = 0; i < MAX_VDEV; i++) { if (vdev_list[i].handler == 0x0 ) { vdev_list[i].name = new_vdev->name; vdev_list[i].base = new_vdev->base; vdev_list[i].size = new_vdev->size; vdev_list[i].handler = new_vdev->handler; printh("vdev:Registered vdev '%s' at index %d\n", vdev_list[i].name, i); result = HVMM_STATUS_SUCCESS; break; } } if ( result != HVMM_STATUS_SUCCESS ) { printh("vdev:Failed registering vdev '%s', max %d full \n", new_vdev->name, MAX_VDEV); } HVMM_TRACE_EXIT(); return result; }
void interrupt_nsptimer(int irq, void *pregs, void *pdata ) { uint32_t ctl; struct arch_regs *regs = pregs; uart_print( "=======================================\n\r" ); HVMM_TRACE_ENTER(); /* Disable NS Physical Timer Interrupt */ ctl = read_cntp_ctl(); ctl &= ~(0x1); write_cntp_ctl(ctl); /* Trigger another interrupt */ test_start_timer(); /* Test guest context switch */ if ( (regs->cpsr & 0x1F) != 0x1A ) { /* Not from Hyp, switch the guest context */ context_dump_regs( regs ); context_switchto(sched_policy_determ_next()); } HVMM_TRACE_EXIT(); uart_print( "=======================================\n\r" ); }
void interrupt_pwmtimer(void *pdata) { pwm_timer_disable_int(); uart_print("=======================================\n\r"); HVMM_TRACE_ENTER(); HVMM_TRACE_EXIT(); uart_print("=======================================\n\r"); pwm_timer_enable_int(); }
volatile uint32_t *gic_vgic_baseaddr(void) { if (_gic.initialized != GIC_SIGNATURE_INITIALIZED) { HVMM_TRACE_ENTER(); uart_print("gic: ERROR - not initialized\n\r"); HVMM_TRACE_EXIT(); } return _gic.ba_gich; }
void callback_test_timer(void *pdata) { vmid_t vmid; HVMM_TRACE_ENTER(); vmid = guest_current_vmid(); printf("Injecting IRQ 30 to Guest:%d\n", vmid); /* SW VIRQ, No PIRQ */ interrupt_guest_inject(vmid, 30, 0, INJECT_SW); HVMM_TRACE_EXIT(); }
hvmm_status_t hvmm_tests_gic_pwm_timer(void) { /* Testing pwm timer event (timer1, Interrupt ID : 69), Cortex-A15 exynos5250 * - Periodically triggers timer interrupt * - Just print uart_print */ HVMM_TRACE_ENTER(); pwm_timer_init(); pwm_timer_set_callback(&interrupt_pwmtimer); pwm_timer_enable_int(); HVMM_TRACE_EXIT(); return HVMM_STATUS_SUCCESS; }
void callback_timer(void *pdata) { vmid_t vmid; HVMM_TRACE_ENTER(); vmid = context_current_vmid(); printh( "Injecting IRQ 30 to Guest:%d\n", vmid); //vgic_inject_virq_sw( 30, VIRQ_STATE_PENDING, GIC_INT_PRIORITY_DEFAULT, smp_processor_id(), 1); /* SW VIRQ, No PIRQ */ if ( _timer_status[vmid] == 0 ) virq_inject(vmid, 30, 0, 0); HVMM_TRACE_EXIT(); }
/* * Configure sp804 timer irq for test */ hvmm_status_t hvmm_tests_sp804_timer(void) { HVMM_TRACE_ENTER(); /* * Until the guest enables IRQ34, for SP804, through VGICD, we manually enable here for * test purpose so the hypervisor can receive and forward to a designated guest */ gic_test_configure_irq(34, GIC_INT_POLARITY_LEVEL, gic_cpumask_current(), GIC_INT_PRIORITY_DEFAULT ); HVMM_TRACE_EXIT(); return HVMM_STATUS_SUCCESS; }
hvmm_status_t hvmm_tests_gic_timer(void) { /* Testing Non-secure Physical Timer Event * (PPI2, Interrupt ID:30), Cortex-A15 * - Periodically triggers timer interrupt * - switches guest context at every timer interrupt */ HVMM_TRACE_ENTER(); /* handler */ interrupt_request(30, &interrupt_nsptimer); /* configure and enable interrupt */ interrupt_host_configure(30); /* start timer */ test_start_timer(); HVMM_TRACE_EXIT(); return HVMM_STATUS_SUCCESS; }
/** * @brief Initializes and enables GIC Distributor * <pre> * Initialization sequence * 1. Set Default SPI's polarity. * 2. Set Default priority. * 3. Diable all interrupts. * 4. Route all IRQs to all target processors. * 5. Enable Distributor. * </pre> * @return Always return success. */ static hvmm_status_t gic_init_dist(void) { uint32_t type; int i; uint32_t cpumask; HVMM_TRACE_ENTER(); /* Disable Distributor */ _gic.ba_gicd[GICD_CTLR] = 0; type = _gic.ba_gicd[GICD_TYPER]; _gic.lines = 32 * ((type & GICD_TYPE_LINES_MASK) + 1); _gic.cpus = 1 + ((type & GICD_TYPE_CPUS_MASK) >> GICD_TYPE_CPUS_SHIFT); uart_print("GIC: lines:"); uart_print_hex32(_gic.lines); uart_print(" cpus:"); uart_print_hex32(_gic.cpus); uart_print(" IID:"); uart_print_hex32(_gic.ba_gicd[GICD_IIDR]); uart_print("\n\r"); /* Interrupt polarity for SPIs (Global Interrupts) active-low */ for (i = 32; i < _gic.lines; i += 16) _gic.ba_gicd[GICD_ICFGR + i / 16] = 0x0; /* Default Priority for all Interrupts * Private/Banked interrupts will be configured separately */ for (i = 32; i < _gic.lines; i += 4) _gic.ba_gicd[GICD_IPRIORITYR + i / 4] = GIC_INT_PRIORITY_DEFAULT_WORD; /* Disable all global interrupts. * Private/Banked interrupts will be configured separately */ for (i = 32; i < _gic.lines; i += 32) _gic.ba_gicd[GICD_ICENABLER + i / 32] = 0xFFFFFFFF; /* Route all global IRQs to this CPU */ cpumask = 1 << smp_processor_id(); cpumask |= cpumask << 8; cpumask |= cpumask << 16; for (i = 32; i < _gic.lines; i += 4) _gic.ba_gicd[GICD_ITARGETSR + i / 4] = cpumask; /* Enable Distributor */ _gic.ba_gicd[GICD_CTLR] = GICD_CTLR_ENABLE; HVMM_TRACE_EXIT(); return HVMM_STATUS_SUCCESS; }
/** * @brief Return address of GIC memory map to _gic.baseaddr. * @param va_base Base address(Physical) of GIC. * @return If target architecture is Cortex-A15 then return success, * otherwise return failed. */ static hvmm_status_t gic_init_baseaddr(uint32_t *va_base) { /* MIDR[15:4], CRn:c0, Op1:0, CRm:c0, Op2:0 == 0xC0F (Cortex-A15) */ /* Cortex-A15 C15 System Control, C15 Registers */ /* Name: Op1, CRm, Op2 */ uint32_t midr; hvmm_status_t result = HVMM_STATUS_UNKNOWN_ERROR; HVMM_TRACE_ENTER(); midr = read_midr(); uart_print("midr:"); uart_print_hex32(midr); uart_print("\n\r"); /* * Note: * We currently support GICv2 with Cortex-A15 only. * Other architectures with GICv2 support will be further * listed and added for support later */ if ((midr & MIDR_MASK_PPN) == MIDR_PPN_CORTEXA15) { /* fall-back to periphbase addr from cbar */ if (va_base == 0) { va_base = (uint32_t *)(uint32_t)(gic_periphbase_pa() & \ 0x00000000FFFFFFFFULL); } _gic.baseaddr = (uint32_t) va_base; uart_print("cbar:"); uart_print_hex32(_gic.baseaddr); uart_print("\n\r"); _gic.ba_gicd = (uint32_t *)(_gic.baseaddr + GIC_OFFSET_GICD); _gic.ba_gicc = (uint32_t *)(_gic.baseaddr + GIC_OFFSET_GICC); _gic.ba_gich = (uint32_t *)(_gic.baseaddr + GIC_OFFSET_GICH); _gic.ba_gicv = (uint32_t *)(_gic.baseaddr + GIC_OFFSET_GICV); _gic.ba_gicvi = (uint32_t *)(_gic.baseaddr + GIC_OFFSET_GICVI); result = HVMM_STATUS_SUCCESS; } else { uart_print("GICv2 Unsupported\n\r"); uart_print("midr.ppn:"); uart_print_hex32(midr & MIDR_MASK_PPN); uart_print("\n\r"); result = HVMM_STATUS_UNSUPPORTED_FEATURE; } HVMM_TRACE_EXIT(); return result; }
static void gic_dump_registers(void) { uint32_t midr; HVMM_TRACE_ENTER(); midr = read_midr(); uart_print("midr:"); uart_print_hex32(midr); uart_print("\n\r"); if ((midr & MIDR_MASK_PPN) == MIDR_PPN_CORTEXA15) { uint32_t value; uart_print("cbar:"); uart_print_hex32(_gic.baseaddr); uart_print("\n\r"); uart_print("ba_gicd:"); uart_print_hex32((uint32_t)_gic.ba_gicd); uart_print("\n\r"); uart_print("ba_gicc:"); uart_print_hex32((uint32_t)_gic.ba_gicc); uart_print("\n\r"); uart_print("ba_gich:"); uart_print_hex32((uint32_t)_gic.ba_gich); uart_print("\n\r"); uart_print("ba_gicv:"); uart_print_hex32((uint32_t)_gic.ba_gicv); uart_print("\n\r"); uart_print("ba_gicvi:"); uart_print_hex32((uint32_t)_gic.ba_gicvi); uart_print("\n\r"); value = _gic.ba_gicd[GICD_CTLR]; uart_print("GICD_CTLR:"); uart_print_hex32(value); uart_print("\n\r"); value = _gic.ba_gicd[GICD_TYPER]; uart_print("GICD_TYPER:"); uart_print_hex32(value); uart_print("\n\r"); value = _gic.ba_gicd[GICD_IIDR]; uart_print("GICD_IIDR:"); uart_print_hex32(value); uart_print("\n\r"); } HVMM_TRACE_EXIT(); }
/* * Creates a mapping table between PIRQ and VIRQ.vmid/pirq/coreid. * Mapping of between pirq and virq is hard-coded. */ hvmm_status_t virqmap_init(void) { // TODO(wonseok): read file and initialize the mapping. HVMM_TRACE_ENTER(); int i; for (i = 0; i < GIC_NUM_MAX_IRQS; i++) { _virqmap[i].vmid = VMID_INVALID; _virqmap[i].virq = 0; } // NOTE(wonseok): referenced by https://github.com/kesl/khypervisor/wiki/Hardware-Resources-of-Guest-Linux-on-FastModels-RTSM_VE-Cortex-A15x1 CFG_GUEST0_VIRQMAP(_virqmap); CFG_GUEST1_VIRQMAP(_virqmap); vgicd_set_callback_changed_istatus(&virqmap_vgicd_changed_istatus_callback_handler); HVMM_TRACE_EXIT(); return HVMM_STATUS_SUCCESS; }
static void test_start_timer(void) { uint32_t ctl; uint32_t tval; uint64_t pct; HVMM_TRACE_ENTER(); /* every second */ tval = read_cntfrq(); write_cntp_tval(tval); pct = read_cntpct(); uart_print("cntpct:"); uart_print_hex64(pct); uart_print("\n\r"); uart_print("cntp_tval:"); uart_print_hex32(tval); uart_print("\n\r"); /* enable timer */ ctl = read_cntp_ctl(); ctl |= 0x1; write_cntp_ctl(ctl); HVMM_TRACE_EXIT(); }
hvmm_status_t gic_configure_irq(uint32_t irq, enum gic_int_polarity polarity, uint8_t cpumask, uint8_t priority) { hvmm_status_t result = HVMM_STATUS_UNKNOWN_ERROR; HVMM_TRACE_ENTER(); if (irq < _gic.lines) { uint32_t icfg; volatile uint8_t *reg8; /* disable forwarding */ result = gic_disable_irq(irq); if (result == HVMM_STATUS_SUCCESS) { /* polarity: level or edge */ icfg = _gic.ba_gicd[GICD_ICFGR + irq / 16]; if (polarity == GIC_INT_POLARITY_LEVEL) icfg &= ~(2u << (2 * (irq % 16))); else icfg |= (2u << (2 * (irq % 16))); _gic.ba_gicd[GICD_ICFGR + irq / 16] = icfg; /* routing */ reg8 = (uint8_t *) &(_gic.ba_gicd[GICD_ITARGETSR]); reg8[irq] = cpumask; /* priority */ reg8 = (uint8_t *) &(_gic.ba_gicd[GICD_IPRIORITYR]); reg8[irq] = priority; /* enable forwarding */ result = gic_enable_irq(irq); } } else { uart_print("invalid irq:"); uart_print_hex32(irq); uart_print("\n\r"); result = HVMM_STATUS_UNSUPPORTED_FEATURE; } HVMM_TRACE_EXIT(); return result; }
hvmm_status_t hvmm_tests_gic_timer(void) { /* Testing Non-secure Physical Timer Event (PPI2, Interrupt ID:30), Cortex-A15 * - Periodically triggers timer interrupt * - switches guest context at every timer interrupt */ HVMM_TRACE_ENTER(); /* handler */ gic_test_set_irq_handler( 30, &interrupt_nsptimer, 0 ); /* configure and enable interrupt */ gic_test_configure_irq(30, GIC_INT_POLARITY_LEVEL, gic_cpumask_current(), GIC_INT_PRIORITY_DEFAULT ); /* start timer */ test_start_timer(); HVMM_TRACE_EXIT(); return HVMM_STATUS_SUCCESS; }
hvmm_status_t gic_init(void) { uint32_t cpu = smp_processor_id(); hvmm_status_t result = HVMM_STATUS_UNKNOWN_ERROR; HVMM_TRACE_ENTER(); /* * Determining VA of GIC base adddress has not been defined yet. * Let is use the PA for the time being */ if (!cpu) { result = gic_init_baseaddr((void *)CFG_GIC_BASE_PA); if (result == HVMM_STATUS_SUCCESS) gic_dump_registers(); /* * Initialize and Enable GIC Distributor */ if (result == HVMM_STATUS_SUCCESS) result = gic_init_dist(); } /* * Initialize and Enable GIC CPU Interface for this CPU * For test it */ if (cpu) result = HVMM_STATUS_SUCCESS; if (result == HVMM_STATUS_SUCCESS) result = gic_init_cpui(); if (result == HVMM_STATUS_SUCCESS) _gic.initialized = GIC_SIGNATURE_INITIALIZED; HVMM_TRACE_EXIT(); return result; }
hvmm_status_t vdev_emulate(uint32_t fipa, uint32_t wnr, vdev_access_size_t access_size, uint32_t srt, struct arch_regs *regs) { hvmm_status_t result = HVMM_STATUS_NOT_FOUND; int i = 0; uint32_t offset; uint8_t isize = 4; HVMM_TRACE_ENTER(); if ( regs->cpsr & 0x20 ) { /* Thumb */ isize = 2; } for (i = 0; i < MAX_VDEV; i++){ if ( vdev_list[i].base == 0 ) break; offset = fipa - vdev_list[i].base; if ( fipa >= vdev_list[i].base && offset < vdev_list[i].size && vdev_list[i].handler != 0) { /* fipa is in the rage: base ~ base + size */ printh("vdev: found %s for fipa %x srt:%x gpr[srt]:%x write:%d vmid:%d\n", vdev_list[i].name, fipa, srt, regs->gpr[srt], wnr, context_current_vmid() ); result = vdev_list[i].handler(wnr, offset, &(regs->gpr[srt]), access_size); if ( wnr == 0 ) { printh("vdev: result:%x\n", regs->gpr[srt] ); } /* Update PC regardless handling result */ regs->pc += isize; break; } else { printh("vdev: fipa %x base %x not matched\n", fipa, vdev_list[i].base ); } } HVMM_TRACE_EXIT(); return result; }
void callback_timer(void *pdata) { HVMM_TRACE_ENTER(); vgic_inject_virq_sw( 30, VIRQ_STATE_PENDING, GIC_INT_PRIORITY_DEFAULT, smp_processor_id(), 1); HVMM_TRACE_EXIT(); }