[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Minios-devel] [UNIKRAFT RFC PATCH 1/2] 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 | 447 +++++++++++++++++++++++++++++++ plat/common/include/arm/gic-v2.h | 380 ++++++++++++++++++++++++++ plat/common/include/irq.h | 15 ++ plat/kvm/Makefile.uk | 2 + plat/kvm/arm/setup.c | 55 ++-- 5 files changed, 877 insertions(+), 22 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..98a7688 --- /dev/null +++ b/plat/common/arm/gic-v2.c @@ -0,0 +1,447 @@ +/* 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)) + +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, 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 interrupt 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 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) +{ + 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 enable distributor */ + write_gicd32(GICD_CTLR, read_gicd32(GICD_CTLR) & (~GICD_CTLR_ENABLE)); +} + +/* + * inspect that if an irq is in pending state, every bit + * holds the state value for the corresponding irq + */ +int gic_is_irq_pending(uint32_t irq) +{ + return !! (read_gicd32(GICD_ICPENDR(irq)) & + UK_BIT(irq % GICD_I_PER_ICPENDRn)); +} + +/* + * 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) +{ + return !! (read_gicd32(GICD_ISACTIVER(irq)) & + UK_BIT(irq % GICD_I_PER_ISACTIVERn)); +} + +/* 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)) + return; + + val = read_gicd32(GICD_ICFGR(irq)); + mask = oldmask = (val >> ((irq % GICD_I_PER_ICFGRn) * 2)) & + GICD_ICFGR_MASK; + + if (trigger == UK_IRQ_TRIGGER_LEVEL) { + mask &= ~GICD_ICFGR_TRIG_MASK; + mask |= GICD_ICFGR_TRIG_LVL; + } else if (trigger == UK_IRQ_TRIGGER_EDGE) { + mask &= ~GICD_ICFGR_TRIG_MASK; + mask |= GICD_ICFGR_TRIG_EDGE; + } + + if (polarity == UK_IRQ_POLARITY_LOW) { + mask &= ~GICD_ICFGR_POL_MASK; + mask |= GICD_ICFGR_POL_LOW; + } else if (polarity == UK_IRQ_POLARITY_HIGH) { + mask &= ~GICD_ICFGR_POL_MASK; + mask |= GICD_ICFGR_POL_HIGH; + } + + /* Check if nothing 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) + cpuif_number = GIC_MAX_CPUIF; + 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) + irq_number = GIC_MAX_IRQ; + 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 SPI priority to a default value. + */ + for (i = GIC_SPI_BASE; 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) +{ + uint32_t i; + /* set priority mask to the lowest priority to let all irq visible to cpu interface */ + gic_set_threshold_priority(GICC_PMR_PRIO_MAX); + + /* set PPI and SGI to polarity low level triggered */ + for (i = 0; i < GIC_SPI_BASE; i += GICD_I_PER_ICFGRn) + write_gicd32(GICD_ICFGR(i), GICD_ICFGR_DEF_TYPE); + + /* set PPI and SGI to a default value */ + for (i = 0; i < GIC_SPI_BASE; i += GICD_I_PER_IPRIORITYn) + write_gicd32(GICD_IPRIORITYR(i), GICD_IPRIORITY_DEF); + /* + * Deactivate and disable all PPIs. + */ + for (i = 0; i < GICD_SGI_MAX_INITID; i += GICD_I_PER_ICACTIVERn) { + write_gicd32(GICD_ICACTIVER(i), GICD_DEF_ICACTIVERn); + write_gicd32(GICD_ICENABLER(i), GICD_DEF_PPI_ICENABLERn); + } + /* Deactivate and enable all SGIs */ + for (i = 0; i < GIC_PPI_BASE; i += GICD_I_PER_ICACTIVERn) + { + write_gicd32(GICD_ICACTIVER(i), GICD_DEF_ICACTIVERn); + write_gicd32(GICD_ISENABLER(i), GICD_DEF_SGI_ISENABLERn); + } + + /* 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 find\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..dfee6a8 --- /dev/null +++ b/plat/common/include/arm/gic-v2.h @@ -0,0 +1,380 @@ +/* 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 +#define GICD_DEF_SGI_ISENABLERn 0xffff + +/* + * 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 +#define GICD_DEF_PPI_ICENABLERn 0xffff0000 + +/* + * 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 +#define GICD_PPI_START + +/* + * 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)) +#define GICD_I_PER_CPENDSGIRn 4 + +/* + * 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)) +#define GICD_I_PER_SPENDSGIRn 4 + + +/* + * 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 + +/* PPI interrupt base ID */ +#define GIC_PPI_BASE 16 + +/* 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 ccc8319..13ef986 100644 --- a/plat/kvm/Makefile.uk +++ b/plat/kvm/Makefile.uk @@ -58,7 +58,9 @@ LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/arm/cpu_native.c 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/rtc.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 09530bb..30e22bc 100644 --- a/plat/kvm/arm/setup.c +++ b/plat/kvm/arm/setup.c @@ -18,18 +18,20 @@ * 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/rtc.h> +#include <arm/gic-v2.h> void *_libkvmplat_pagetable; void *_libkvmplat_heap_start; void *_libkvmplat_stack_top; void *_libkvmplat_mem_end; -void *_libkvmplat_dtb; #define MAX_CMDLINE_SIZE 1024 static char cmdline[MAX_CMDLINE_SIZE]; @@ -47,7 +49,7 @@ static void _init_dtb(void *dtb_pointer) UK_CRASH("Invalid DTB: %s\n", fdt_strerror(ret)); _libkvmplat_dtb = dtb_pointer; - uk_pr_info("Found device tree on: %p\n", dtb_pointer); + uk_printd(DLVL_INFO, "Found device tree on: %p\n", dtb_pointer); } static void _dtb_get_psci_method(void) @@ -65,13 +67,13 @@ static void _dtb_get_psci_method(void) fdtpsci = fdt_node_offset_by_compatible(_libkvmplat_dtb, -1, "arm,psci-0.2"); if (fdtpsci < 0) { - uk_pr_info("No PSCI conduit found in DTB\n"); + uk_printd(DLVL_INFO, "No PSCI conduit found in DTB\n"); goto enomethod; } fdtmethod = fdt_getprop(_libkvmplat_dtb, fdtpsci, "method", &len); if (!fdtmethod || (len <= 0)) { - uk_pr_info("No PSCI method found\n"); + uk_printd(DLVL_INFO, "No PSCI method found\n"); goto enomethod; } @@ -80,16 +82,16 @@ static void _dtb_get_psci_method(void) else if (!strcmp(fdtmethod, "smc")) smcc_psci_call = smcc_psci_smc_call; else { - uk_pr_info("Invalid PSCI conduit method: %s\n", - fdtmethod); + uk_printd(DLVL_INFO, + "Invalid PSCI conduit method: %s\n", fdtmethod); goto enomethod; } - uk_pr_info("PSCI method: %s\n", fdtmethod); + uk_printd(DLVL_INFO, "PSCI method: %s\n", fdtmethod); return; enomethod: - uk_pr_info("Support PSCI from PSCI-0.2\n"); + uk_printd(DLVL_INFO, "Support PSCI from PSCI-0.2\n"); smcc_psci_call = NULL; } @@ -104,13 +106,13 @@ static void _init_dtb_mem(void) /* search for assigned VM memory in DTB */ if (fdt_num_mem_rsv(_libkvmplat_dtb) != 0) - uk_pr_warn("Reserved memory is not supported\n"); + uk_printd(DLVL_WARN, "Reserved memory is not supported\n"); fdt_mem = fdt_node_offset_by_prop_value(_libkvmplat_dtb, -1, "device_type", "memory", sizeof("memory")); if (fdt_mem < 0) { - uk_pr_warn("No memory found in DTB\n"); + uk_printd(DLVL_WARN, "No memory found in DTB\n"); return; } @@ -138,7 +140,8 @@ static void _init_dtb_mem(void) /* If we have more than one memory bank, give a warning messasge */ if (prop_len > prop_min_len) - uk_pr_warn("Currently, we support only one memory bank!\n"); + uk_printd(DLVL_WARN, + "Currently, we support only one memory bank!\n"); mem_base = fdt64_to_cpu(regs[0]); mem_size = fdt64_to_cpu(regs[1]); @@ -172,17 +175,25 @@ static void _dtb_get_cmdline(char *cmdline, size_t maxlen) cmdline[((unsigned int) len - 1) <= (maxlen - 1) ? ((unsigned int) len - 1) : (maxlen - 1)] = '\0'; - uk_pr_info("Command line: %s\n", cmdline); + uk_printd(DLVL_INFO, "Command line: %s\n", cmdline); return; enocmdl: - uk_pr_info("No command line found\n"); + uk_printd(DLVL_INFO, "No command line found\n"); strcpy(cmdline, CONFIG_UK_NAME); } 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); + + /* Initialize RTC */ + _dtb_init_rtc(_libkvmplat_dtb); + + ukplat_entry_argp(NULL, (char *)cmdline, strlen(cmdline)); } void _libkvmplat_start(void *dtb_pointer) @@ -190,7 +201,7 @@ void _libkvmplat_start(void *dtb_pointer) _init_dtb(dtb_pointer); _libkvmplat_init_console(); - uk_pr_info("Entering from KVM (arm64)...\n"); + uk_printd(DLVL_INFO, "Entering from KVM (arm64)...\n"); /* Get command line from DTB */ @@ -202,15 +213,15 @@ void _libkvmplat_start(void *dtb_pointer) /* Initialize memory from DTB */ _init_dtb_mem(); - uk_pr_info("pagetable start: %p\n", _libkvmplat_pagetable); - uk_pr_info(" heap start: %p\n", _libkvmplat_heap_start); - uk_pr_info(" stack top: %p\n", _libkvmplat_stack_top); + uk_printd(DLVL_INFO, "pagetable start: %p\n", _libkvmplat_pagetable); + uk_printd(DLVL_INFO, " heap start: %p\n", _libkvmplat_heap_start); + uk_printd(DLVL_INFO, " stack top: %p\n", _libkvmplat_stack_top); /* * Switch away from the bootstrap stack as early as possible. */ - uk_pr_info("Switch from bootstrap stack to stack @%p\n", - _libkvmplat_stack_top); + uk_printd(DLVL_INFO, "Switch from bootstrap stack to stack @%p\n", + _libkvmplat_stack_top); _libkvmplat_newstack((uint64_t) _libkvmplat_stack_top, _libkvmplat_entry2, NULL); -- 2.17.1 _______________________________________________ Minios-devel mailing list Minios-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/minios-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |