khypervisor  v1
Data Structures | Defines | Functions | Variables
gic/gic.c File Reference
#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>
Include dependency graph for gic.c:

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_tgic_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 Documentation

#define ARM_CPUID_CORTEXA15   0x412fc0f1

Definition at line 18 of file gic.c.

#define CBAR_PERIPHBASE_MSB_MASK   0x000000FF

Definition at line 16 of file gic.c.

Value:

Definition at line 24 of file gic.c.

#define GIC_SIGNATURE_INITIALIZED   0x5108EAD7

Definition at line 29 of file gic.c.

#define MIDR_MASK_PPN   (0x0FFF <<4)

Definition at line 20 of file gic.c.

#define MIDR_PPN_CORTEXA15   (0xC0F << 4)

Definition at line 21 of file gic.c.


Function Documentation

Definition at line 220 of file gic.c.

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();
}

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;
}

Here is the call graph for this function:

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;
}

Here is the call graph for this function:

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;
}

Here is the call graph for this function:

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);
    }
}

Here is the call graph for this function:

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;
}

Here is the call graph for this function:

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;
}

Variable Documentation

struct gic _gic [static]

Definition at line 44 of file gic.c.

 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines