|
khypervisor
v1
|
#include "gic.h"#include "armv7_p15.h"#include "a15_cp15_sysregs.h"#include "smp.h"#include "context.h"#include "hvmm_trace.h"#include <gic_regs.h>#include "virqmap.h"#include "virq.h"#include "hvmm_types.h"#include <log/print.h>#include <log/uart_print.h>#include <config/cfg_platform.h>
Go to the source code of this file.
Data Structures | |
| struct | gic |
Defines | |
| #define | CBAR_PERIPHBASE_MSB_MASK 0x000000FF |
| #define | ARM_CPUID_CORTEXA15 0x412fc0f1 |
| #define | MIDR_MASK_PPN (0x0FFF <<4) |
| #define | MIDR_PPN_CORTEXA15 (0xC0F << 4) |
| #define | GIC_INT_PRIORITY_DEFAULT_WORD |
| #define | GIC_SIGNATURE_INITIALIZED 0x5108EAD7 |
Functions | |
| static void | gic_dump_registers (void) |
| static uint64_t | gic_periphbase_pa (void) |
| static hvmm_status_t | gic_init_baseaddr (uint32_t *va_base) |
| static hvmm_status_t | gic_init_dist (void) |
| static hvmm_status_t | gic_init_cpui (void) |
| hvmm_status_t | gic_enable_irq (uint32_t irq) |
| hvmm_status_t | gic_disable_irq (uint32_t irq) |
| hvmm_status_t | gic_deactivate_irq (uint32_t irq) |
| hvmm_status_t | gic_test_set_irq_handler (int irq, gic_irq_handler_t handler, void *pdata) |
| volatile uint32_t * | gic_vgic_baseaddr (void) |
| hvmm_status_t | gic_init (void) |
| hvmm_status_t | gic_test_configure_irq (uint32_t irq, gic_int_polarity_t polarity, uint8_t cpumask, uint8_t priority) |
| void | gic_interrupt (int fiq, void *pregs) |
Variables | |
| static struct gic | _gic |
| #define ARM_CPUID_CORTEXA15 0x412fc0f1 |
| #define CBAR_PERIPHBASE_MSB_MASK 0x000000FF |
| #define GIC_INT_PRIORITY_DEFAULT_WORD |
( (GIC_INT_PRIORITY_DEFAULT << 24 ) \ |(GIC_INT_PRIORITY_DEFAULT << 16 ) \ |(GIC_INT_PRIORITY_DEFAULT << 8 ) \ |(GIC_INT_PRIORITY_DEFAULT ) )
| #define GIC_SIGNATURE_INITIALIZED 0x5108EAD7 |
| #define MIDR_MASK_PPN (0x0FFF <<4) |
| #define MIDR_PPN_CORTEXA15 (0xC0F << 4) |
| hvmm_status_t gic_disable_irq | ( | uint32_t | irq | ) |
Definition at line 214 of file gic.c.
{
_gic.ba_gicd[GICD_ICENABLER + irq / 32] = (1u << (irq % 32));
return HVMM_STATUS_SUCCESS;
}
| static void gic_dump_registers | ( | void | ) | [static] |
Definition at line 46 of file gic.c.
{
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();
}
| hvmm_status_t gic_enable_irq | ( | uint32_t | irq | ) |
Definition at line 208 of file gic.c.
{
_gic.ba_gicd[GICD_ISENABLER + irq / 32] = (1u << (irq % 32));
return HVMM_STATUS_SUCCESS;
}
| hvmm_status_t gic_init | ( | void | ) |
Definition at line 247 of file gic.c.
{
hvmm_status_t result = HVMM_STATUS_UNKNOWN_ERROR;
int i;
HVMM_TRACE_ENTER();
for( i = 0; i < GIC_NUM_MAX_IRQS; i++) {
_gic.handlers[i] = 0;
}
/*
* Determining VA of GIC base adddress has not been defined yet. Let is use the PA for the time being
*/
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
*/
if ( result == HVMM_STATUS_SUCCESS ) {
result = gic_init_cpui();
}
if ( result == HVMM_STATUS_SUCCESS ) {
_gic.initialized = GIC_SIGNATURE_INITIALIZED;
}
HVMM_TRACE_EXIT();
return result;
}

| static hvmm_status_t gic_init_baseaddr | ( | uint32_t * | va_base | ) | [static] |
Definition at line 86 of file gic.c.
{
// 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 hvmm_status_t gic_init_cpui | ( | void | ) | [static] |
Definition at line 181 of file gic.c.
{
hvmm_status_t result = HVMM_STATUS_UNKNOWN_ERROR;
int i;
/* Disable forwarding PPIs(ID16~31) */
_gic.ba_gicd[GICD_ICENABLER] = 0xFFFF0000;
/* Enable forwarding SGIs(ID0~15) */
_gic.ba_gicd[GICD_ISENABLER] = 0x0000FFFF;
/* Default priority for SGIs and PPIs */
for( i = 0; i < 32; i += 4 ) {
_gic.ba_gicd[GICD_IPRIORITYR | i/4] = GIC_INT_PRIORITY_DEFAULT_WORD;
}
/* No Priority Masking: the lowest value as the threshold : 255 */
_gic.ba_gicc[GICC_PMR] = 0xFF;
_gic.ba_gicc[GICC_BPR] = 0x0;
/* Enable signaling of interrupts and GICC_EOIR only drops priority */
_gic.ba_gicc[GICC_CTLR] = GICC_CTL_ENABLE | GICC_CTL_EOI;
result = HVMM_STATUS_SUCCESS;
return result;
}
| static hvmm_status_t gic_init_dist | ( | void | ) | [static] |
Definition at line 128 of file gic.c.
{
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 gic_interrupt | ( | int | fiq, |
| void * | pregs | ||
| ) |
Definition at line 337 of file gic.c.
{
/*
* 1. ACK - CPU Interface - GICC_IAR read
* 2. Completion - CPU Interface - GICC_EOIR
* 2.1 Deactivation - CPU Interface - GICC_DIR
*/
uint32_t iar;
uint32_t irq;
struct arch_regs *regs = pregs;
const struct virqmap_entry *virq_entry;
/* ACK */
iar = _gic.ba_gicc[GICC_IAR];
irq = iar & GICC_IAR_INTID_MASK;
if ( irq < _gic.lines ) {
virq_entry = virqmap_for_pirq(irq);
/* ISR */
printh( "ISR(irq):%x\n", irq);
/* IRQ INJECTION */
if(virq_entry != VIRQMAP_ENTRY_NOTFOUND) {
/* priority drop only for hanlding irq in guest */
_gic.ba_gicc[GICC_EOIR] = irq;
virq_inject(virq_entry->vmid, virq_entry->virq, irq, 1);
} else {
if ( _gic.handlers[irq] ) {
_gic.handlers[irq]( irq, regs, 0 );
}
/* Completion & Deactivation */
_gic.ba_gicc[GICC_EOIR] = irq;
_gic.ba_gicc[GICC_DIR] = irq;
}
} else {
printh( "gic:no pending irq:%x\n", irq);
}
}

| static uint64_t gic_periphbase_pa | ( | void | ) | [static] |
Definition at line 72 of file gic.c.
{
// CBAR: 4, c0, 0
// MRC p15, 4, <Rt>, c15, c0, 0; Read Configuration Base Address Register
uint64_t periphbase = (uint64_t) read_cbar();
uint64_t pbmsb = periphbase & ((uint64_t)CBAR_PERIPHBASE_MSB_MASK);
if ( pbmsb ) {
periphbase &= ~ ((uint64_t)CBAR_PERIPHBASE_MSB_MASK);
periphbase |= (pbmsb << 32);
}
return periphbase;
}
| hvmm_status_t gic_test_configure_irq | ( | uint32_t | irq, |
| gic_int_polarity_t | polarity, | ||
| uint8_t | cpumask, | ||
| uint8_t | priority | ||
| ) |
Definition at line 294 of file gic.c.
{
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 gic_test_set_irq_handler | ( | int | irq, |
| gic_irq_handler_t | handler, | ||
| void * | pdata | ||
| ) |
Definition at line 226 of file gic.c.
{
hvmm_status_t result = HVMM_STATUS_BUSY;
if ( irq < GIC_NUM_MAX_IRQS ) {
_gic.handlers[irq] = handler;
result = HVMM_STATUS_SUCCESS;
}
return result;
}
| volatile uint32_t* gic_vgic_baseaddr | ( | void | ) |
Definition at line 236 of file gic.c.
{
if ( _gic.initialized != GIC_SIGNATURE_INITIALIZED ) {
HVMM_TRACE_ENTER();
uart_print("gic: ERROR - not initialized\n\r");
HVMM_TRACE_EXIT();
}
return _gic.ba_gich;
}
1.7.6.1