[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Minios-devel] [UNIKRAFT RFC PATCH 1/2] Implement gic-v2 library for Arm
Hi, Any comments on gicv2? It's the key point and emergency. Bests Jianyong wu > -----Original Message----- > From: Jianyong Wu <Jianyong.Wu@xxxxxxx> > Sent: Friday, November 9, 2018 5:03 PM > To: minios-devel@xxxxxxxxxxxxxxxxxxxx; simon.kuenzer@xxxxxxxxx > Cc: Kaly Xin (Arm Technology China) <Kaly.Xin@xxxxxxx>; Wei Chen (Arm > Technology China) <Wei.Chen@xxxxxxx>; Jianyong Wu (Arm Technology > China) <Jianyong.Wu@xxxxxxx>; nd <nd@xxxxxxx> > Subject: [Minios-devel] [UNIKRAFT RFC PATCH 1/2] Implement gic-v2 library > for Arm > > 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 | 394 > +++++++++++++++++++++++++++++++++++++++ > plat/common/include/arm/gic-v2.h | 380 > +++++++++++++++++++++++++++++++++++++ > plat/common/include/irq.h | 15 ++ > plat/kvm/Makefile.uk | 1 + > plat/kvm/arm/setup.c | 61 +++--- > 5 files changed, 824 insertions(+), 27 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..d212cfa > --- /dev/null > +++ b/plat/common/arm/gic-v2.c > @@ -0,0 +1,394 @@ > +/* 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 */ > + UK_ASSERT(threshold_prio <= GICC_PMR_PRIO_MAX); > + 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 */ > + UK_ASSERT(sgintid <= GICD_SGI_MAX_INITID); > + > + /* 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. > + * TODO: this will not work untill SMP is supported */ 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. > + * TODO: this will not work untill SMP is supported */ 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)); > +} > + > +/* 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; > + uint32_t naddr, nsize; > + const uint64_t *regs; > + > + uk_printd(DLVL_INFO, "Probing GICv2...\n"); > + /* Currently, we only support 1 GIC per system */ > + fdt_gic = uk_dtb_find_device(dtb, gic_device_list, > +sizeof(gic_device_list)); > + > + /* Get region size at regs region in dtb */ > + naddr = uk_dtb_read_region(dtb, fdt_gic, &nsize, ®s); > + > + /* Get device address and size at regs region */ > + gic_dist_addr = (void *)uk_dtb_read_term(regs, 0, naddr, nsize, > &gic_dist_size); > + gic_cpuif_addr = (void *)uk_dtb_read_term(regs, 1, naddr, nsize, > +&gic_cpuif_size); > + > + 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 > 197175a..572f4c3 100644 > --- a/plat/kvm/Makefile.uk > +++ b/plat/kvm/Makefile.uk > @@ -61,6 +61,7 @@ LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += > $(UK_PLAT_COMMON_BASE)/arm/time.c|commo > 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/fdt.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/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..14e64ad 100644 > --- a/plat/kvm/arm/setup.c > +++ b/plat/kvm/arm/setup.c > @@ -18,18 +18,16 @@ > * 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> > - > -void *_libkvmplat_pagetable; > -void *_libkvmplat_heap_start; > -void *_libkvmplat_stack_top; > -void *_libkvmplat_mem_end; > -void *_libkvmplat_dtb; > +#include <arm/rtc.h> > +#include <arm/gic-v2.h> > +#include <arm/fdt.h> > > #define MAX_CMDLINE_SIZE 1024 > static char cmdline[MAX_CMDLINE_SIZE]; > @@ -47,7 +45,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 +63,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 +78,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 +102,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 +136,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 +171,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 +197,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 +209,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.7.4 _______________________________________________ Minios-devel mailing list Minios-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/minios-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |