+++ /dev/null
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * Authors: Costin Lupu <costin.lupu@cs.pub.ro>
- *
- * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation. 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.
- */
-#ifndef __UKPLAT_IRQ_H__
-#define __UKPLAT_IRQ_H__
-
-#include <uk/arch/lcpu.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct uk_alloc;
-
-/**
- * Initializes platform IRQ subsystem
- * @param a The allocator to be used for internal memory allocations
- * @return initialization status
- */
-int ukplat_irq_init(struct uk_alloc *a);
-
-typedef int (*irq_handler_func_t)(void *);
-
-/**
- * Registers an interrupt handler
- * @param irq Interrupt number
- * @param func Interrupt funciton
- * @param arg Extra argument to be handover to interrupt function
- * @return 0 on success, a negative errno value on errors
- */
-int ukplat_irq_register(unsigned long irq, irq_handler_func_t func, void *arg);
-
-/** The event payload for the #UKPLAT_EVENT_IRQ event */
-struct ukplat_event_irq_data {
- /** The registers of the interrupted code */
- struct __regs *regs;
- /** The platform specific interrupt vector number */
- unsigned long irq;
-};
-
-/**
- * This event is raised before the platform code handles an IRQ. The normal
- * IRQ handling will continue or stop according to the returned `UK_EVENT_*`
- * value.
- * Note: this event is usually raised in an interrupt context.
- */
-#define UKPLAT_EVENT_IRQ ukplat_event_irq
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __UKPLAT_IRQ_H__ */
config LIBUKINTCTLR
- bool "ukintctlr: Interrupt Controller API"
- default n
+ bool "ukintctlr: Interrupt Controller API"
+
+if LIBUKINTCTLR
+
+config LIBUKINTCTLR_MAX_HANDLERS_PER_IRQ
+ int "Maximum number of handlers per IRQ"
+ default 8
+
+config LIBUKINTCTLR_ISR_ECTX_ASSERTIONS
+ bool "Check for unmodified ECTX in interrupt handlers"
+ depends on ARCH_X86_64
+
+endif
ifeq ($(filter $(CONFIG_ARCH_ARM_64) $(CONFIG_ARCH_ARM_32),y), y)
LIBUKINTCTLR_SRCS-y += $(LIBUKINTCTLR_BASE)/arch/arm/intctlr.c
endif
+
+LIBUKINTCTLR_SRCS-y += $(LIBUKINTCTLR_BASE)/ukintctlr.c
--- /dev/null
+/* SPDX-License-Identifier: ISC */
+/*
+ * Authors: Dan Williams
+ * Martin Lucina
+ * Ricardo Koller
+ * Costin Lupu <costin.lupu@cs.pub.ro>
+ *
+ * Copyright (c) 2015-2017 IBM
+ * Copyright (c) 2016-2017 Docker, Inc.
+ * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software
+ * for any purpose with or without fee is hereby granted, provided
+ * that the above copyright notice and this permission notice appear
+ * in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/* Taken from solo5 intr.c */
+
+#include <stdlib.h>
+#include <uk/alloc.h>
+#include <uk/plat/lcpu.h>
+#include <uk/plat/time.h>
+#include <uk/plat/irq.h>
+#include <uk/plat/common/irq.h>
+#include <uk/intctlr.h>
+#include <uk/assert.h>
+#include <uk/event.h>
+#include <uk/trace.h>
+#include <uk/print.h>
+#include <errno.h>
+#include <uk/bitops.h>
+#ifdef CONFIG_UKPLAT_ISR_ECTX_ASSERTIONS
+#include <uk/arch/ctx.h>
+#endif
+
+UK_EVENT(UKPLAT_EVENT_IRQ);
+
+UK_TRACEPOINT(trace_plat_kvm_unhandled_irq, "Unhandled irq=%lu\n",
+ unsigned long);
+
+/* IRQ handlers declarations */
+struct irq_handler {
+ irq_handler_func_t func;
+ void *arg;
+};
+
+static struct irq_handler irq_handlers[__MAX_IRQ]
+ [CONFIG_KVM_MAX_IRQ_HANDLER_ENTRIES];
+
+static inline struct irq_handler *allocate_handler(unsigned long irq)
+{
+ UK_ASSERT(irq < __MAX_IRQ);
+ for (int i = 0; i < CONFIG_KVM_MAX_IRQ_HANDLER_ENTRIES; i++)
+ if (irq_handlers[irq][i].func == NULL)
+ return &irq_handlers[irq][i];
+ return NULL;
+}
+
+int ukplat_irq_register(unsigned long irq, irq_handler_func_t func, void *arg)
+{
+ struct irq_handler *h;
+ unsigned long flags;
+
+ UK_ASSERT(func);
+ if (irq >= __MAX_IRQ)
+ return -EINVAL;
+
+ flags = ukplat_lcpu_save_irqf();
+ h = allocate_handler(irq);
+ if (!h) {
+ ukplat_lcpu_restore_irqf(flags);
+ return -ENOMEM;
+ }
+
+ h->func = func;
+ h->arg = arg;
+
+ ukplat_lcpu_restore_irqf(flags);
+
+ intctrl_clear_irq(irq);
+ return 0;
+}
+
+/*
+ * TODO: This is a temporary solution used to identify non TSC clock
+ * interrupts in order to stop waiting for interrupts with deadline.
+ */
+extern unsigned long sched_have_pending_events;
+
+void _ukplat_irq_handle(struct __regs *regs, unsigned long irq)
+{
+ struct irq_handler *h;
+ int i;
+ int rc;
+ struct ukplat_event_irq_data ctx;
+#ifdef CONFIG_UKPLAT_ISR_ECTX_ASSERTIONS
+ __sz ectx_align = ukarch_ectx_align();
+ __u8 ectxbuf[ukarch_ectx_size() + ectx_align];
+ struct ukarch_ectx *ectx = (struct ukarch_ectx *)
+ ALIGN_UP((__uptr) ectxbuf, ectx_align);
+
+ ukarch_ectx_init(ectx);
+#endif
+
+ UK_ASSERT(irq < __MAX_IRQ);
+
+ ctx.regs = regs;
+ ctx.irq = irq;
+ rc = uk_raise_event(UKPLAT_EVENT_IRQ, &ctx);
+ if (unlikely(rc < 0))
+ UK_CRASH("IRQ event handler returned error: %d\n", rc);
+ if (rc == UK_EVENT_HANDLED) {
+ /* Skip all normal handlers if an event handler handled the
+ * event
+ */
+ goto exit_ack;
+ }
+
+ for (i = 0; i < CONFIG_KVM_MAX_IRQ_HANDLER_ENTRIES; i++) {
+ if (irq_handlers[irq][i].func == NULL)
+ break;
+ h = &irq_handlers[irq][i];
+ if (irq != ukplat_time_get_irq())
+ /* ukplat_time_get_irq() gives the IRQ reserved for a timer,
+ * responsible to wake up cpu from halt, so it can check if
+ * it has something to do. Effectively it is OS ticks.
+ *
+ * If interrupt comes not from the timer, the
+ * chances are some work have just
+ * arrived. Let's kick the scheduler out of
+ * the halting loop, and let it take care of
+ * that work.
+ */
+ __uk_test_and_set_bit(0, &sched_have_pending_events);
+
+ if (h->func(h->arg) == 1)
+ goto exit_ack;
+ }
+ /*
+ * Acknowledge interrupts even in the case when there was no handler for
+ * it. We do this to (1) compensate potential spurious interrupts of
+ * devices, and (2) to minimize impact on drivers that share one
+ * interrupt line that would then stay disabled.
+ */
+ trace_plat_kvm_unhandled_irq(irq);
+
+exit_ack:
+#ifdef CONFIG_UKPLAT_ISR_ECTX_ASSERTIONS
+ ukarch_ectx_assert_equal(ectx);
+#endif
+ intctrl_ack_irq(irq);
+}
+
+int ukplat_irq_init(struct uk_alloc *a __unused)
+{
+ UK_ASSERT(ukplat_lcpu_irqs_disabled());
+
+ /* Nothing for now */
+ return 0;
+}
endmenu
-config UKPLAT_ISR_ECTX_ASSERTIONS
- bool "Check for unmodified ECTX in interrupt handlers"
- default n
- depends on (ARCH_X86_64 && PLAT_KVM)
-
menuconfig PAGING
bool "Virtual memory API"
default n
#ifndef __PLAT_CMN_IRQ_H__
#define __PLAT_CMN_IRQ_H__
-#include <uk/plat/irq.h>
-
+/* Saving /restoring CPU IRQ flags and enabling / disabling IRQs on the
+ * CPU were previously part of the ukplat_irq API. These are not managed
+ * by the interrupt controller, so they need to be part of the lcpu
+ * low-level API. As some platforms may have their own implementation of
+ * these (linuxu, xen) keep them on a separate header.
+ * TODO: Remove this comment after migrating lcpu into drivers.
+ */
#if defined(__X86_64__)
#include <x86/irq.h>
#elif defined(__ARM_64__)
#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
-};
-
-/**
- * Calls the registered IRQ handlers for the given IRQ vector. This will
- * acknowledge the IRQ.
- *
- * @param regs the registers of the interrupted code
- * @param irq IRQ vector
- */
-void _ukplat_irq_handle(struct __regs *regs, unsigned long irq);
-
#endif /* __PLAT_CMN_IRQ_H__ */
endmenu
-config KVM_MAX_IRQ_HANDLER_ENTRIES
- int "Maximum number of handlers per IRQ"
- default 8
- depends on (ARCH_X86_64 || ARCH_ARM_64)
-
config RTC_PL031
bool "Arm platform RTC (PL031) driver"
default y if ARCH_ARM_64
LIBKVMPLAT_SRCS-y += $(LIBKVMPLAT_BASE)/shutdown.c
LIBKVMPLAT_SRCS-y += $(LIBKVMPLAT_BASE)/memory.c
-LIBKVMPLAT_SRCS-y += $(LIBKVMPLAT_BASE)/irq.c
LIBKVMPLAT_SRCS-y += $(LIBKVMPLAT_BASE)/io.c
LIBKVMPLAT_SRCS-y += $(UK_PLAT_COMMON_BASE)/lcpu.c|common
LIBKVMPLAT_SRCS-y += $(UK_PLAT_COMMON_BASE)/memory.c|common
+++ /dev/null
-/* SPDX-License-Identifier: ISC */
-/*
- * Authors: Dan Williams
- * Martin Lucina
- * Ricardo Koller
- * Costin Lupu <costin.lupu@cs.pub.ro>
- *
- * Copyright (c) 2015-2017 IBM
- * Copyright (c) 2016-2017 Docker, Inc.
- * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software
- * for any purpose with or without fee is hereby granted, provided
- * that the above copyright notice and this permission notice appear
- * in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
- * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
- * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
- * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-/* Taken from solo5 intr.c */
-
-#include <stdlib.h>
-#include <uk/alloc.h>
-#include <uk/plat/lcpu.h>
-#include <uk/plat/time.h>
-#include <uk/plat/irq.h>
-#include <uk/plat/common/irq.h>
-#include <uk/intctlr.h>
-#include <uk/assert.h>
-#include <uk/event.h>
-#include <uk/trace.h>
-#include <uk/print.h>
-#include <errno.h>
-#include <uk/bitops.h>
-#ifdef CONFIG_UKPLAT_ISR_ECTX_ASSERTIONS
-#include <uk/arch/ctx.h>
-#endif
-
-UK_EVENT(UKPLAT_EVENT_IRQ);
-
-UK_TRACEPOINT(trace_plat_kvm_unhandled_irq, "Unhandled irq=%lu\n",
- unsigned long);
-
-/* IRQ handlers declarations */
-struct irq_handler {
- irq_handler_func_t func;
- void *arg;
-};
-
-static struct irq_handler irq_handlers[__MAX_IRQ]
- [CONFIG_KVM_MAX_IRQ_HANDLER_ENTRIES];
-
-static inline struct irq_handler *allocate_handler(unsigned long irq)
-{
- UK_ASSERT(irq < __MAX_IRQ);
- for (int i = 0; i < CONFIG_KVM_MAX_IRQ_HANDLER_ENTRIES; i++)
- if (irq_handlers[irq][i].func == NULL)
- return &irq_handlers[irq][i];
- return NULL;
-}
-
-int ukplat_irq_register(unsigned long irq, irq_handler_func_t func, void *arg)
-{
- struct irq_handler *h;
- unsigned long flags;
-
- UK_ASSERT(func);
- if (irq >= __MAX_IRQ)
- return -EINVAL;
-
- flags = ukplat_lcpu_save_irqf();
- h = allocate_handler(irq);
- if (!h) {
- ukplat_lcpu_restore_irqf(flags);
- return -ENOMEM;
- }
-
- h->func = func;
- h->arg = arg;
-
- ukplat_lcpu_restore_irqf(flags);
-
- intctrl_clear_irq(irq);
- return 0;
-}
-
-/*
- * TODO: This is a temporary solution used to identify non TSC clock
- * interrupts in order to stop waiting for interrupts with deadline.
- */
-extern unsigned long sched_have_pending_events;
-
-void _ukplat_irq_handle(struct __regs *regs, unsigned long irq)
-{
- struct irq_handler *h;
- int i;
- int rc;
- struct ukplat_event_irq_data ctx;
-#ifdef CONFIG_UKPLAT_ISR_ECTX_ASSERTIONS
- __sz ectx_align = ukarch_ectx_align();
- __u8 ectxbuf[ukarch_ectx_size() + ectx_align];
- struct ukarch_ectx *ectx = (struct ukarch_ectx *)
- ALIGN_UP((__uptr) ectxbuf, ectx_align);
-
- ukarch_ectx_init(ectx);
-#endif
-
- UK_ASSERT(irq < __MAX_IRQ);
-
- ctx.regs = regs;
- ctx.irq = irq;
- rc = uk_raise_event(UKPLAT_EVENT_IRQ, &ctx);
- if (unlikely(rc < 0))
- UK_CRASH("IRQ event handler returned error: %d\n", rc);
- if (rc == UK_EVENT_HANDLED) {
- /* Skip all normal handlers if an event handler handled the
- * event
- */
- goto exit_ack;
- }
-
- for (i = 0; i < CONFIG_KVM_MAX_IRQ_HANDLER_ENTRIES; i++) {
- if (irq_handlers[irq][i].func == NULL)
- break;
- h = &irq_handlers[irq][i];
- if (irq != ukplat_time_get_irq())
- /* ukplat_time_get_irq() gives the IRQ reserved for a timer,
- * responsible to wake up cpu from halt, so it can check if
- * it has something to do. Effectively it is OS ticks.
- *
- * If interrupt comes not from the timer, the
- * chances are some work have just
- * arrived. Let's kick the scheduler out of
- * the halting loop, and let it take care of
- * that work.
- */
- __uk_test_and_set_bit(0, &sched_have_pending_events);
-
- if (h->func(h->arg) == 1)
- goto exit_ack;
- }
- /*
- * Acknowledge interrupts even in the case when there was no handler for
- * it. We do this to (1) compensate potential spurious interrupts of
- * devices, and (2) to minimize impact on drivers that share one
- * interrupt line that would then stay disabled.
- */
- trace_plat_kvm_unhandled_irq(irq);
-
-exit_ack:
-#ifdef CONFIG_UKPLAT_ISR_ECTX_ASSERTIONS
- ukarch_ectx_assert_equal(ectx);
-#endif
- intctrl_ack_irq(irq);
-}
-
-int ukplat_irq_init(struct uk_alloc *a __unused)
-{
- UK_ASSERT(ukplat_lcpu_irqs_disabled());
-
- /* Nothing for now */
- return 0;
-}