[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Minios-devel] [UNIKRAFT RFC PATCH] plat/arm: Implement gic-v2 library for Arm
From: Jianyong Wu <Jianyong.Wu@xxxxxxx> This library has implemented basic GICv2 functions. We don't support GICv2M and security extension in this library. Signed-off-by: Wei Chen <wei.chen@xxxxxxx> Signed-off-by: Jianyong Wu <Jianyong.Wu@xxxxxxx> --- plat/common/arm/gic-v2.c | 459 +++++++++++++++++++++++++++++++++++++++ plat/common/include/arm/gic-v2.h | 374 +++++++++++++++++++++++++++++++ plat/common/include/irq.h | 15 ++ plat/kvm/Makefile.uk | 2 + plat/kvm/arm/setup.c | 13 +- 5 files changed, 860 insertions(+), 3 deletions(-) create mode 100644 plat/common/arm/gic-v2.c create mode 100644 plat/common/include/arm/gic-v2.h diff --git a/plat/common/arm/gic-v2.c b/plat/common/arm/gic-v2.c new file mode 100644 index 0000000..01581e1 --- /dev/null +++ b/plat/common/arm/gic-v2.c @@ -0,0 +1,459 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Authors: Wei Chen <Wei.Chen@xxxxxxx> + * Jianyong Wu <Jianyong.Wu@xxxxxxx> + * + * Copyright (c) 2018, Arm Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. + */ +#include <string.h> +#include <libfdt.h> +#include <uk/essentials.h> +#include <uk/print.h> +#include <uk/assert.h> +#include <uk/bitops.h> +#include <uk/asm.h> +#include <irq.h> +#include <arm/cpu.h> +#include <arm/gic-v2.h> +static void *gic_dist_addr, *gic_cpuif_addr; +static uint64_t gic_dist_size, gic_cpuif_size; + +#define GIC_DIST_REG(r) (gic_dist_addr + (r)) +#define GIC_CPU_REG(r) (gic_cpuif_addr + (r)) + +extern void *_libkvmplat_dtb; +static char *gic_device_list[] = { + "arm,cortex-a15-gic", + "arm,cortex-a7-gic", + "arm,cortex-a9-gic", + "arm,gic-400", + "arm,eb11mp-gic", + "arm,pl390", + "arm,arm1176jzf-devchip-gic", + "arm,arm11mp-gic", + "arm,tc11mp-gic", + "brcm,brahma-b15-gic", + "nvidia,tegra210-agic", + "qcom,msm-8660-qgic", + "qcom,msm-qgic2", +}; + +/* inline functions to access GICC & GICD registers */ +static inline void write_gicd8(uint64_t offset, uint8_t val) +{ + ioreg_write8(GIC_DIST_REG(offset), val); +} + +static inline void write_gicd32(uint64_t offset, uint32_t val) +{ + ioreg_write32(GIC_DIST_REG(offset), val); +} + +static inline uint32_t read_gicd32(uint64_t offset) +{ + return ioreg_read32(GIC_DIST_REG(offset)); +} + +static inline void write_gicc32(uint64_t offset, uint32_t val) +{ + ioreg_write32(GIC_CPU_REG(offset), val); +} + +static inline uint32_t read_gicc32(uint64_t offset) +{ + return ioreg_read32(GIC_CPU_REG(offset)); +} + +/* + * Functions of GIC CPU interface + */ + +/* Enable GIC cpu interface */ +static void gic_enable_cpuif(void) +{ + /* just set bit 0 to 1 to enable cpu interface */ + write_gicc32(GICC_CTLR, read_gicc32(GICC_CTLR) | GICC_CTLR_ENABLE); +} + +/* Disable GIC cpu interface */ +static void gic_disable_cpuif(void) +{ + /* only clear bit 0 to 0 to disable cpu interface */ + write_gicc32(GICC_CTLR, read_gicc32(GICC_CTLR) & (~GICC_CTLR_ENABLE)); +} + +/* Set priority threshold for processor */ +static void gic_set_threshold_priority(uint32_t threshold_prio) +{ + /* GICC_PMR allocate 1 byte for each irq */ + if (threshold_prio > GICC_PMR_PRIO_MAX) + UK_CRASH("Possible priority from 0 to 255, input: %d\n", + threshold_prio); + write_gicc32(GICC_PMR, threshold_prio); +} + +/* + * Acknowledging irq equals reading GICC_IAR also + * get the intrrupt ID as the side effect. + */ +uint32_t gic_ack_irq(void) +{ + return read_gicc32(GICC_IAR); +} + +/* + * write to GICC_EOIR to inform cpu interface completation + * of interrupt processing. If GICC_CTLR.EOImode sets to 1 + * this func just gets priority drop. + */ +void gic_eoi_irq(uint32_t irq) +{ + write_gicc32(GICC_EOIR, irq); +} + +/* Functions of GIC Distributor */ + +/* + * @sgintid denotes the sgi ID; + * @targetfilter : this term is TargetListFilter + * 0 denotes forwarding interrupt to cpu specified in the + * target list; 1 denotes forwarding interrupt to cpu execpt the + * processor that request the intrrupt; 2 denotes forwarding the + * interrupt only to the cpu that requtest the interrupt. + * @targetlist is bitmask, which bit 1 denotes forwarding to and only low 8 + * bit is in use. + */ +static void gic_sgi_gen(uint32_t sgintid, uint8_t targetfilter, + uint8_t targetlist) +{ + uint32_t val; + + /* Only INTID 0-15 allocated to sgi */ + if (sgintid > GICD_SGI_MAX_INITID) + UK_CRASH("Only INTID 0-15 allocated to sgi\n"); + + /* Set SGI tagetfileter field */ + val = (targetfilter & GICD_SGI_FILTER_MASK) << GICD_SGI_FILTER_SHIFT; + + /* Set SGI targetlist field */ + val |= (targetlist & GICD_SGI_TARGET_MASK) << GICD_SGI_TARGET_SHIFT; + + /* Set SGI INITID field */ + val |= sgintid; + + /* Generate SGI */ + write_gicd32(GICD_SGIR, val); +} + +/* + * Forward the SGI to the CPU interfaces specified in the + * targetlist. Targetlist is a 8-bit bitmap for 0~7 CPU. + */ +void gic_sgi_gen_to_list(uint32_t sgintid, uint8_t targetlist) +{ + gic_sgi_gen(sgintid, GICD_SGI_FILTER_TO_LIST, targetlist); +} + +/* + * Forward the SGI to all CPU interfaces except that of the + * processor that requested the interrupt. + */ +void gic_sgi_gen_to_others(uint32_t sgintid) +{ + gic_sgi_gen(sgintid, GICD_SGI_FILTER_TO_OTHERS, 0); +} + +/* + * Forward the SGI only to the CPU interface of the processor + * that requested the interrupt. + */ +void gic_sgi_gen_to_self(uint32_t sgintid) +{ + gic_sgi_gen(sgintid, GICD_SGI_FILTER_TO_SELF, 0); +} + +/* + * set target cpu for irq in distributor, + * @target: bitmask value, bit 1 indicates target to + * corresponding cpu interface + */ +void gic_set_irq_target(uint32_t irq, uint8_t target) +{ + write_gicd8(GICD_ITARGETSR(irq), target); +} + +/* set priority for irq in distributor */ +void gic_set_irq_prio(uint32_t irq, uint8_t priority) +{ + write_gicd8(GICD_IPRIORITYR(irq), priority); +} + +/* + * Enable an irq in distributor, each irq occupies one bit + * to configure in corresponding registor + */ +void gic_enable_irq(uint32_t irq) +{ + write_gicd32(GICD_ISENABLER(irq), + UK_BIT(irq % GICD_I_PER_ISENABLERn)); +} + +/* + * Disable an irq in distributor, one bit reserved for an irq + * to configure in corresponding register + */ +void gic_disable_irq(uint32_t irq) +{ + write_gicd32(GICD_ICENABLER(irq), + UK_BIT(irq % GICD_I_PER_ICENABLERn)); +} + +/* Enable distributor */ +static void gic_enable_dist(void) +{ + /* just set bit 0 to 1 to enable distributor */ + write_gicd32(GICD_CTLR, read_gicd32(GICD_CTLR) | GICD_CTLR_ENABLE); +} + +/* disable distributor */ +static void gic_disable_dist(void) +{ + /* just clear bit 0 to 0 to disable distributor */ + write_gicd32(GICD_CTLR, read_gicd32(GICD_CTLR) & (~GICD_CTLR_ENABLE)); +} + +/* + * set pending state for an irq in distributor, one bit + * reserved for an irq to configure in corresponding register + */ +void gic_set_irq_pending(uint32_t irq) +{ + write_gicd32(GICD_ISPENDR(irq), + UK_BIT(irq % GICD_I_PER_ISPENDRn)); +} + +/* + * clear pending state for an irq in distributor, one bit + * reserved for an irq to configure in corresponding register + */ +void gic_clear_irq_pending(uint32_t irq) +{ + write_gicd32(GICD_ICPENDR(irq), + UK_BIT(irq % GICD_I_PER_ICPENDRn)); +} + +/* + * inspect that if an irq is in pending state, every bit + * holds the value for the corresponding irq + */ +int gic_is_irq_pending(uint32_t irq) +{ + if (read_gicd32(GICD_ISPENDR(irq)) & + UK_BIT(irq % GICD_I_PER_ISPENDRn)) + return 1; + return 0; +} + +/* set active state for an irq in distributor */ +void gic_set_irq_active(uint32_t irq) +{ + write_gicd32(GICD_ISACTIVER(irq), + UK_BIT(irq % GICD_I_PER_ISACTIVERn)); +} + +/* clear active state for an irq in distributor */ +void gic_clear_irq_active(uint32_t irq) +{ + write_gicd32(GICD_ICACTIVER(irq), + UK_BIT(irq % GICD_I_PER_ICACTIVERn)); +} + +/* + * inspect that if an irq is in active state, + * every bit holds the value for an irq + */ +int gic_is_irq_active(uint32_t irq) +{ + if (read_gicd32(GICD_ISACTIVER(irq)) & + UK_BIT(irq % GICD_I_PER_ISACTIVERn)) + return 1; + return 0; +} + +/* Config intrrupt trigger type and polarity */ +void gic_set_irq_type(uint32_t irq, int trigger, int polarity) +{ + uint32_t val, mask, oldmask; + + if ((trigger >= UK_IRQ_TRIGGER_MAX) || + (polarity >= UK_IRQ_POLARITY_MAX)) + UK_CRASH("too big trigger value\n"); + + val = read_gicd32(GICD_ICFGR(irq)); + mask = oldmask = (val >> ((irq % GICD_I_PER_ICFGRn) * 2)) & + GICD_ICFGR_MASK; + + mask &= ~GICD_ICFGR_TRIG_MASK; + mask |= (trigger == UK_IRQ_TRIGGER_LEVEL) ? GICD_ICFGR_TRIG_LVL : GICD_ICFGR_TRIG_EDGE; + mask &= ~GICD_ICFGR_POL_MASK; + mask |= (polarity == UK_IRQ_POLARITY_LOW) ? GICD_ICFGR_POL_LOW : GICD_ICFGR_POL_HIGH; + + /* Check if anything changed */ + if (mask == oldmask) + return; + + /* Update new interrupt type */ + val &= (~(GICD_ICFGR_MASK << (irq % GICD_I_PER_ICFGRn) * 2)); + val |= (mask << (irq % GICD_I_PER_ICFGRn) * 2); + write_gicd32(GICD_ICFGR(irq), val); +} + +static void gic_init_dist(void) +{ + uint32_t val, cpuif_number, irq_number; + uint32_t i; + + /* Turn down distributor */ + gic_disable_dist(); + + /* Get GIC CPU interface */ + val = read_gicd32(GICD_TYPER); + cpuif_number = GICD_TYPER_CPUI_NUM(val); + if (cpuif_number > GIC_MAX_CPUIF) + UK_CRASH("too big cpuif_number\n"); + uk_printd(DLVL_INFO, "GICv2 Max CPU interface:%d\n", cpuif_number); + + /* Get the maximum number of interrupts that the GIC supports */ + irq_number = GICD_TYPER_LINE_NUM(val); + if (irq_number > GIC_MAX_IRQ) + UK_CRASH("too big irq_number\n"); + uk_printd(DLVL_INFO, "GICv2 Max interrupt lines:%d\n", irq_number); + /* + * Set all SPI interrupts targets to all CPU. + */ + for (i = GIC_SPI_BASE; i < irq_number; i += GICD_I_PER_ITARGETSRn) + write_gicd32(GICD_ITARGETSR(i), GICD_ITARGETSR_DEF); + + /* + * Set all SPI interrupts type to be polarity low level triggered + */ + for (i = GIC_SPI_BASE; i < irq_number; i += GICD_I_PER_ICFGRn) + write_gicd32(GICD_ICFGR(i), GICD_ICFGR_DEF_TYPE); + + /* + * Set all interrupts priority to a default value. + */ + for (i = 0; i < irq_number; i += GICD_I_PER_IPRIORITYn) + write_gicd32(GICD_IPRIORITYR(i), GICD_IPRIORITY_DEF); + + /* + * Deactivate and disable all SPIs. + */ + for (i = GIC_SPI_BASE; i < irq_number; i += GICD_I_PER_ICACTIVERn) { + write_gicd32(GICD_ICACTIVER(i), GICD_DEF_ICACTIVERn); + write_gicd32(GICD_ICENABLER(i), GICD_DEF_ICENABLERn); + } + + /* turn on distributor */ + gic_enable_dist(); +} + +static void gic_init_cpuif(void) +{ + /* set priority mask to the lowest priority to let all irq visible to cpu interface */ + gic_set_threshold_priority(GICC_PMR_PRIO_MAX); + + /* enable cpu interface */ + gic_enable_cpuif(); +} + +int _dtb_init_gic(void *dtb) +{ + uint32_t idx; + int fdt_gic, naddr, nsize, prop_len, prop_min_len; + const uint64_t *regs; + + uk_printd(DLVL_INFO, "Probing GICv2...\n"); + /* Currently, we only support 1 GIC per system */ + for (idx = 0; + idx < sizeof(gic_device_list) / sizeof(gic_device_list[0]); + idx++) { + fdt_gic = fdt_node_offset_by_compatible(dtb, -1, + gic_device_list[idx]); + if (fdt_gic >= 0) + break; + } + + if (fdt_gic < 0) + UK_CRASH("No valid GIC device found\n"); + + naddr = fdt_address_cells(dtb, fdt_gic); + if (naddr < 0 || naddr >= FDT_MAX_NCELLS) + UK_CRASH("Could not find proper address cells!\n"); + + nsize = fdt_size_cells(dtb, fdt_gic); + if (nsize < 0 || nsize >= FDT_MAX_NCELLS) + UK_CRASH("Could not find proper size cells!\n"); + + regs = fdt_getprop(dtb, fdt_gic, "reg", &prop_len); + + /* + * The property must contain at least the start address and size + * of distributor and cpu interface + */ + prop_min_len = (int)sizeof(fdt32_t) * (naddr + nsize) * 2; + if (regs == NULL || prop_len < prop_min_len) + UK_CRASH("Bad 'reg' property: %p %d\n", regs, prop_len); + + /* + * From: + * https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt + * We know that the first region is the GIC distributor register + * base and size. The 2nd region is the GIC cpu interface register + * base and size. + */ + gic_dist_addr = (void *)fdt64_to_cpu(regs[0]); + gic_dist_size = fdt64_to_cpu(regs[1]); + gic_cpuif_addr = (void *)fdt64_to_cpu(regs[2]); + gic_cpuif_size = fdt64_to_cpu(regs[3]); + + uk_printd(DLVL_INFO, "Found GICv2 on:\n"); + uk_printd(DLVL_INFO, "\tCPU interface address: %p\n", gic_cpuif_addr); + uk_printd(DLVL_INFO, "\tDistributor address: %p\n", gic_dist_addr); + + + /* Initialize GICv2 distributor */ + gic_init_dist(); + + /* Initialize GICv2 CPU interface */ + gic_init_cpuif(); + + return 0; +} diff --git a/plat/common/include/arm/gic-v2.h b/plat/common/include/arm/gic-v2.h new file mode 100644 index 0000000..6d7d267 --- /dev/null +++ b/plat/common/include/arm/gic-v2.h @@ -0,0 +1,374 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Authors: Wei Chen <Wei.Chen@xxxxxxx> + * Jianyong Wu <Jianyong.Wu@xxxxxxx> + * + * Copyright (c) 2018, Arm Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. + */ +#ifndef __PLAT_CMN_ARM_GIC_H__ +#define __PLAT_CMN_ARM_GIC_H__ + +/* + * Distributor registers. Unikraft only support run on non-secure + * so we just describe non-secure registers. + */ + +/* + * Distributor Control Register, GICD_CTLR. + * Enables the forwarding of pending interrupts from the + * Distributor to the CPU interfaces + */ +#define GICD_CTLR 0x0000 +#define GICD_CTLR_ENABLE 0x1 + +/* + * Interrupt Controller Type Register, GICD_TYPER. + * Provides information about the configuration of the GIC. + */ +#define GICD_TYPER 0x0004 +#define GICD_TYPER_LINE_NUM(r) ((((r) & 0x1f) + 1) << 5) +#define GICD_TYPER_CPUI_NUM(r) ((((r) >> 5) & 0x3) + 1) + +/* + * Distributor Implementer Identification Register, GICD_IIDR. + * Provides information about the implementer and revision of the Distributor. + */ +#define GICD_IIDR 0x0008 +#define GICD_IIDR_PROD(r) (((r) >> 24) & 0xff) +#define GICD_IIDR_VAR(r) (((r) >> 16) & 0xf) +#define GICD_IIDR_REV(r) (((r) >> 12) & 0xf) +#define GICD_IIDR_IMPL(r) ((r) & 0xfff) + +/* + * Interrupt Group Registers, GICD_IGROUPRn + * These registers provide a status bit for each interrupt supported by + * the GIC. Each bit controls whether the corresponding interrupt is in + * Group 0 or Group 1 + */ +#define GICD_IGROUPR(n) (0x0080 + 4 * ((n) >> 5)) +#define GICD_I_PER_IGROUPRn 32 + +/* + * Interrupt Set-Enable Registers, GICD_ISENABLERn. + * These registers provide a Set-enable bit for each interrupt supported + * by the GIC. Writing 1 to a Set-enable bit enables forwarding of the + * corresponding interrupt from the Distributor to the CPU interfaces. + * Reading a bit identifies whether the interrupt is enabled. + */ +#define GICD_ISENABLER(n) (0x0100 + 4 * ((n) >> 5)) +#define GICD_I_PER_ISENABLERn 32 + +/* + * Interrupt Clear-Enable Registers, GICD_ICENABLERn. + * Provide a Clear-enable bit for each interrupt supported by the GIC. + * Writing 1 to a Clear-enable bit disables forwarding of the + * corresponding interrupt from the Distributor to the CPU interfaces. + * Reading a bit identifies whether the interrupt is enabled. + */ +#define GICD_ICENABLER(n) (0x0180 + 4 * ((n) >> 5)) +#define GICD_I_PER_ICENABLERn 32 +#define GICD_DEF_ICENABLERn 0xffffffff + +/* + * Interrupt Set-Pending Registers, GICD_ISPENDRn. + * Provide a Set-pending bit for each interrupt supported by the GIC. + * Writing 1 to a Set-pending bit sets the status of the corresponding + * peripheral interrupt to pending. Reading a bit identifies whether + * the interrupt is pending. + */ +#define GICD_ISPENDR(n) (0x0200 + 4 * ((n) >> 5)) +#define GICD_I_PER_ISPENDRn 32 + +/* + * Interrupt Clear-Pending Registers, GICD_ICPENDRn + * Provide a Clear-pending bit for each interrupt supported by the GIC. + * Writing 1 to a Clear-pending bit clears the pending state of the + * corresponding peripheral interrupt. Reading a bit identifies whether + * the interrupt is pending. + */ +#define GICD_ICPENDR(n) (0x0280 + 4 * ((n) >> 5)) +#define GICD_I_PER_ICPENDRn 32 + +/* + * Interrupt Set-Active Registers, GICD_ISACTIVERn + * Provide a Set-active bit for each interrupt that the GIC supports. + * Writing to a Set-active bit Activates the corresponding interrupt. + * These registers are used when preserving and restoring GIC state. + */ +#define GICD_ISACTIVER(n) (0x0300 + 4 * ((n) >> 5)) +#define GICD_I_PER_ISACTIVERn 32 + +/* + * Interrupt Clear-Active Registers, GICD_ICACTIVERn + * Provide a Clear-active bit for each interrupt that the GIC supports. + * Writing to a Clear-active bit Deactivates the corresponding interrupt. + * These registers are used when preserving and restoring GIC state. + */ +#define GICD_ICACTIVER(n) (0x0380 + 4 * ((n) >> 5)) +#define GICD_I_PER_ICACTIVERn 32 +#define GICD_DEF_ICACTIVERn 0xffffffff + +/* + * Interrupt ID mask for GICD_ISENABLER, GICD_ICENABLER, GICD_ISPENDR, + * GICD_ICPENDR, GICD_ISACTIVER and GICD_ICACTIVER + */ +#define GICD_I_MASK(n) (1ul << ((n) & 0x1f)) + +/* + * Interrupt Priority Registers, GICD_IPRIORITYRn + * Provide an 8-bit priority field for each interrupt supported by the + * GIC. + * + * These registers are byte-accessible, so we define this macro + * for byte-access. + */ +#define GICD_IPRIORITYR(n) (0x0400 + (n)) +#define GICD_I_PER_IPRIORITYn 4 +#define GICD_IPRIORITY_DEF 0xa0a0a0a0 + +/* + * Interrupt Processor Targets Registers, GICD_ITARGETSRn + * Provide an 8-bit CPU targets field for each interrupt supported by + * the GIC. + * + * These registers are byte-accessible, so we define this macro + * for byte-access. + */ +#define GICD_ITARGETSR(n) (0x0800 + (n)) +#define GICD_I_PER_ITARGETSRn 4 +#define GICD_ITARGETSR_DEF 0xffffffff + +/* + * Interrupt Configuration Registers, GICD_ICFGRn + * The GICD_ICFGRs provide a 2-bit Int_config field for each interrupt + * supported by the GIC. This field identifies whether the corresponding + * interrupt is edge-triggered or level-sensitive. + */ +#define GICD_ICFGR(n) (0x0C00 + 4 * ((n) >> 4)) +#define GICD_I_PER_ICFGRn 16 +#define GICD_ICFGR_DEF_TYPE 0 +#define GICD_ICFGR_MASK 0x3 +/* First bit is a polarity bit (0 - low, 1 - high) */ +#define GICD_ICFGR_POL_LOW (0 << 0) +#define GICD_ICFGR_POL_HIGH (1 << 0) +#define GICD_ICFGR_POL_MASK 0x1 +/* Second bit is a trigger bit (0 - level, 1 - edge) */ +#define GICD_ICFGR_TRIG_LVL (0 << 1) +#define GICD_ICFGR_TRIG_EDGE (1 << 1) +#define GICD_ICFGR_TRIG_MASK 0x2 + +/* + * Software Generated Interrupt Register, GICD_SGIR + */ +#define GICD_SGIR 0x0F00 +#define GICD_SGI_TARGET_SHIFT 16 +#define GICD_SGI_TARGET_MASK 0xff +#define GICD_SGI_FILTER_SHIFT 24 +#define GICD_SGI_FILTER_MASK 0x3 +#define GICD_SGI_MAX_INITID 15 + +/* + * Forward the interrupt to the CPU interfaces specified in the + * CPUTargetList field + */ +#define GICD_SGI_FILTER_TO_LIST 0x0 +/* + * Forward the interrupt to all CPU interfaces except that of the + * processor that requested the interrupt. + */ +#define GICD_SGI_FILTER_TO_OTHERS 0x1 +/* + * Forward the interrupt only to the CPU interface of the processor + * that requested the interrupt. + */ +#define GICD_SGI_FILTER_TO_SELF 0x2 + +/* + * SGI Clear-Pending Registers, GICD_CPENDSGIRn + * Provide a clear-pending bit for each supported SGI and source + * processor combination. When a processor writes a 1 to a clear-pending + * bit, the pending state of the corresponding SGI for the corresponding + * source processor is removed, and no longer targets the processor + * performing the write. Writing a 0 has no effect. Reading a bit identifies + * whether the SGI is pending, from the corresponding source processor, on + * the reading processor. + */ +#define GICD_CPENDSGIRn (0x0F10 + 4 *((n) >> 2)) + +/* + * SGI Set-Pending Registers, GICD_SPENDSGIRn + * Provide a set-pending bit for each supported SGI and source processor + * combination. When a processor writes a 1 to a set-pending bit, the pending + * state is applied to the corresponding SGI for the corresponding source + * processor. Writing a 0 has no effect. Reading a bit identifies whether + * the SGI is pending, from the corresponding source processor, on the + * reading processor. + */ +#define GICD_SPENDSGIRn (0x0F20 + 4 *((n) >> 2)) + + +/* + * CPU interface registers. Unikraft only support run on non-secure + * so we just describe non-secure registers. + */ + +/* CPU Interface Control Register */ +#define GICC_CTLR 0x0000 +#define GICC_CTLR_ENABLE 0x1 + +/* Interrupt Priority Mask Register */ +#define GICC_PMR 0x0004 +#define GICC_PMR_PRIO_MAX 255 + +/* Binary Point Register */ +#define GICC_BPR 0x0008 + +/* Interrupt Acknowledge Register */ +#define GICC_IAR 0x000C +#define GICC_IAR_INTID_MASK 0x3FF +#define GICC_IAR_INTID_SPURIOUS 1023 + +/* End of Interrupt Register */ +#define GICC_EOIR 0x0010 + +/* Running Priority Register */ +#define GICC_RPR 0x0014 + +/* Highest Priority Pending Interrupt Register */ +#define GICC_HPPIR 0x0018 + +/* Aliased Binary Point Register */ +#define GICC_ABPR 0x001C + +/* CPU Interface Identification Register */ +#define GICC_IIDR 0x00FC + +/* Deactivate Interrupt Register */ +#define GICC_DIR 0x1000 + +/* + * Acknowledging irq equals reading GICC_IAR also + * get the intrrupt ID as the side effect. + */ +uint32_t gic_ack_irq(void); + +/* + * write to GICC_EOIR to inform cpu interface completation + * of interrupt processing. If GICC_CTLR.EOImode sets to 1 + * this func just gets priority drop. + */ +void gic_eoi_irq(uint32_t irq); + +/* + * Forward the SIG to the CPU interfaces specified in the + * targetlist. Targetlist is a 8-bit bitmap for 0~7 CPU. + */ +void gic_sgi_gen_to_list(uint32_t sgintid, uint8_t targetlist); + +/* + * Forward the SGI to all CPU interfaces except that of the + * processor that requested the interrupt. + */ +void gic_sgi_gen_to_others(uint32_t sgintid); + +/* + * Forward the SGI only to the CPU interface of the processor + * that requested the interrupt. + */ +void gic_sgi_gen_to_self(uint32_t sgintid); + +/* + * set target cpu for irq in distributor, + * @target: bitmask value, bit 1 indicates target to + * corresponding cpu interface + */ +void gic_set_irq_target(uint32_t irq, uint8_t target); + +/* set priority for irq in distributor */ +void gic_set_irq_prio(uint32_t irq, uint8_t priority); + +/* + * Enable an irq in distributor, each irq occupies one bit + * to configure in corresponding registor + */ +void gic_enable_irq(uint32_t irq); + +/* + * Disable an irq in distributor, one bit reserved for an irq + * to configure in corresponding register + */ +void gic_disable_irq(uint32_t irq); + +/* + * set pending state for an irq in distributor, one bit + * reserved for an irq to configure in corresponding register + */ +void gic_set_irq_pending(uint32_t irq); + +/* + * clear pending state for an irq in distributor, one bit + * reserved for an irq to configure in corresponding register + */ +void gic_clear_irq_pending(uint32_t irq); + +/* + * inspect that if an irq is in pending state, every bit + * holds the value for the corresponding irq + */ +int gic_is_irq_pending(uint32_t irq); + +/* set active state for an irq in distributor */ +void gic_set_irq_active(uint32_t irq); + +/* clear active state for an irq in distributor */ +void gic_clear_irq_active(uint32_t irq); + +/* + * inspect that if an irq is in active state, + * every bit holds the value for an irq + */ +int gic_is_irq_active(uint32_t irq); + +/* Config intrrupt trigger type and polarity */ +void gic_set_irq_type(uint32_t irq, int trigger, int polarity); + +/* Initialize GICv2 from device tree */ +int _dtb_init_gic(void *dtb); + +/* Max CPU interface for GICv2 */ +#define GIC_MAX_CPUIF 8 + +/* SPI interrupt base ID */ +#define GIC_SPI_BASE 32 + +/* Max support interrupt number for GICv2 */ +#define GIC_MAX_IRQ 1020 + +#endif //__PLAT_CMN_ARM_GICV2_H__ diff --git a/plat/common/include/irq.h b/plat/common/include/irq.h index edaccfe..c36d004 100644 --- a/plat/common/include/irq.h +++ b/plat/common/include/irq.h @@ -43,5 +43,20 @@ #error "Add irq.h for current architecture." #endif +/* define IRQ trigger types */ +enum uk_irq_trigger { + UK_IRQ_TRIGGER_NONE = 0, + UK_IRQ_TRIGGER_EDGE = 1, + UK_IRQ_TRIGGER_LEVEL = 2, + UK_IRQ_TRIGGER_MAX +}; + +/* define IRQ trigger polarities */ +enum uk_irq_polarity { + UK_IRQ_POLARITY_NONE = 0, + UK_IRQ_POLARITY_HIGH = 1, + UK_IRQ_POLARITY_LOW = 2, + UK_IRQ_POLARITY_MAX +}; #endif /* __PLAT_CMN_IRQ_H__ */ diff --git a/plat/kvm/Makefile.uk b/plat/kvm/Makefile.uk index b493bba..9a9fab4 100644 --- a/plat/kvm/Makefile.uk +++ b/plat/kvm/Makefile.uk @@ -54,11 +54,13 @@ ifeq ($(CONFIG_ARCH_ARM_64),y) ifeq ($(findstring y,$(CONFIG_KVM_KERNEL_SERIAL_CONSOLE) $(CONFIG_KVM_DEBUG_SERIAL_CONSOLE)),y) LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/pl011.c|common endif +LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/bitops.c|common LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/cpu_native.c|common LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/cache64.S|common LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/psci_arm64.S|common LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/time.c|common LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/traps.c|common +LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/gic-v2.c|common LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(LIBKVMPLAT_BASE)/arm/entry64.S LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(LIBKVMPLAT_BASE)/arm/exceptions.S LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(LIBKVMPLAT_BASE)/arm/pagetable.S diff --git a/plat/kvm/arm/setup.c b/plat/kvm/arm/setup.c index 7423e8b..9f03498 100644 --- a/plat/kvm/arm/setup.c +++ b/plat/kvm/arm/setup.c @@ -18,12 +18,14 @@ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <limits.h> #include <libfdt.h> -#include <kvm/console.h> +#include <uk/essentials.h> #include <uk/assert.h> +#include <kvm/console.h> #include <kvm-arm/mm.h> #include <arm/cpu.h> -#include <uk/arch/limits.h> +#include <arm/gic-v2.h> void *_libkvmplat_pagetable; void *_libkvmplat_heap_start; @@ -183,7 +185,12 @@ enocmdl: static void _libkvmplat_entry2(void *arg __attribute__((unused))) { - ukplat_entry_argp(NULL, (char *)cmdline, strlen(cmdline)); + /* After switch to new stack, we start initializing other devices */ + + /* Initialize GIC interrupt controller */ + _dtb_init_gic(_libkvmplat_dtb); + + ukplat_entry_argp(NULL, (char *)cmdline, strlen(cmdline)); } void _libkvmplat_start(void *dtb_pointer) -- 2.7.4 IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you. _______________________________________________ Minios-devel mailing list Minios-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/minios-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |