/* Level 1 Block, 1GB, entry in LPAE Descriptor format for the given physical address */ lpaed_t hvmm_mm_lpaed_l1_block( uint64_t pa, uint8_t attr_idx ) { /* lpae.c */ lpaed_t lpaed; printh( "[mm] hvmm_mm_lpaed_l1_block:\n\r" ); printh( " pa:"); uart_print_hex64(pa); printh("\n\r"); printh( " attr_idx:"); uart_print_hex32((uint32_t) attr_idx); printh("\n\r"); // Valid Block Entry lpaed.pt.valid = 1; lpaed.pt.table = 0; lpaed.bits &= ~TTBL_L1_OUTADDR_MASK; lpaed.bits |= pa & TTBL_L1_OUTADDR_MASK; lpaed.pt.sbz = 0; // Lower block attributes lpaed.pt.ai = attr_idx; lpaed.pt.ns = 1; // Allow Non-secure access lpaed.pt.user = 1; lpaed.pt.ro = 0; lpaed.pt.sh = 2; // Outher Shareable lpaed.pt.af = 1; // Access Flag set to 1? lpaed.pt.ng = 1; // Upper block attributes lpaed.pt.hint = 0; lpaed.pt.pxn = 0; lpaed.pt.xn = 0; // eXecute Never = 0 return lpaed; }
/** * @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; }
void nrm_loop(void) { int i = 0; uart_init(); uart_print(GUEST_LABEL); uart_print("=== Starting...\n\r"); gic_init(); /* We are ready to accept irqs with GIC. Enable it now */ irq_enable(); /* Test the sample virtual device * - Uncomment the following line of code only if 'vdev_sample' is registered at the monitor * - Otherwise, the monitor will hang with data abort */ #ifdef TESTS_ENABLE_VDEV_SAMPLE test_vdev_sample(); #endif #ifdef TESTS_ENABLE_PWM_TIMER hvmm_tests_pwm_timer(); #endif #ifdef TESTS_ENABLE_SP804_TIMER /* Test the SP804 timer */ hvmm_tests_sp804_timer(); #endif for( i = 0; i < NUM_ITERATIONS; i++ ) { uart_print(GUEST_LABEL); uart_print("iteration "); uart_print_hex32( i ); uart_print( "\n\r" ); nrm_delay(); #ifdef __MONITOR_CALL_HVC__ /* Hyp monitor guest run in Non-secure supervisor mode. Request test hvc ping and yield one after another */ if (i & 0x1) { uart_print(GUEST_LABEL); uart_print( "hsvc_ping()\n\r" ); hsvc_ping(); uart_print(GUEST_LABEL); uart_print( "returned from hsvc_ping() \n\r" ); } else { uart_print(GUEST_LABEL); uart_print( "hsvc_yield()\n\r" ); hsvc_yield(); uart_print(GUEST_LABEL); uart_print( "returned from hsvc_yield() \n\r" ); } #else /* Secure monitor guest run in Non-secure supervisor mode Request for switch to Secure mode (sec_loop() in the monitor) */ SWITCH_MANUAL(); #endif nrm_delay(); } uart_print(GUEST_LABEL); uart_print("done\n\r"); while(1); }
/** * @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(); }
void scheduler_test_switch_to_next_guest(void *pdata){ struct arch_regs *regs = pdata; uint64_t pct = read_cntpct(); uint32_t tval = read_cnthp_tval(); uart_print( "cntpct:"); uart_print_hex64(pct); uart_print("\n\r"); uart_print( "cnth_tval:"); uart_print_hex32(tval); uart_print("\n\r"); /* Note: As of context_switchto() and context_perform_switch() are available, no need to test if trapped from Hyp mode. context_perform_switch() takes care of it */ /* Test guest context switch */ if ( (regs->cpsr & 0x1F) != 0x1A ) { scheduler_schedule(); } }
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; }