[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Minios-devel] [UNIKRAFT PATCH 2/7] plat/linuxu: Add linuxu (x86_64) interrupts support
We use signals to emulate the behavior of interrupts on plat/linuxu. Signed-off-by: Costin Lupu <costin.lupu@xxxxxxxxx> --- plat/linuxu/Makefile.uk | 2 + plat/linuxu/include/linuxu/irq.h | 50 ++++++++ plat/linuxu/include/linuxu/signal.h | 151 ++++++++++++++++++++++++ plat/linuxu/include/linuxu/syscall-x86_64.h | 4 + plat/linuxu/include/linuxu/syscall.h | 24 +++- plat/linuxu/irq.c | 176 ++++++++++++++++++++++++++++ plat/linuxu/lcpu.c | 63 +++++++--- 7 files changed, 454 insertions(+), 16 deletions(-) create mode 100644 plat/linuxu/include/linuxu/irq.h create mode 100644 plat/linuxu/include/linuxu/signal.h create mode 100644 plat/linuxu/irq.c diff --git a/plat/linuxu/Makefile.uk b/plat/linuxu/Makefile.uk index 38f92ac..8f07cb3 100644 --- a/plat/linuxu/Makefile.uk +++ b/plat/linuxu/Makefile.uk @@ -12,6 +12,7 @@ $(eval $(call addplatlib,linuxu,liblinuxuplat)) ## Platform library definitions ## LIBLINUXUPLAT_CINCLUDES-y += -I$(LIBLINUXUPLAT_BASE)/include +LIBLINUXUPLAT_CINCLUDES-y += -I$(UK_PLAT_COMMON_BASE)/include LIBLINUXUPLAT_SRCS-$(ARCH_X86_32) += $(LIBLINUXUPLAT_BASE)/x86/entry32.S LIBLINUXUPLAT_SRCS-$(ARCH_X86_64) += $(LIBLINUXUPLAT_BASE)/x86/entry64.S @@ -22,4 +23,5 @@ LIBLINUXUPLAT_SRCS-y += $(LIBLINUXUPLAT_BASE)/console.c LIBLINUXUPLAT_SRCS-y += $(LIBLINUXUPLAT_BASE)/shutdown.c LIBLINUXUPLAT_SRCS-y += $(LIBLINUXUPLAT_BASE)/memory.c LIBLINUXUPLAT_SRCS-y += $(LIBLINUXUPLAT_BASE)/lcpu.c +LIBLINUXUPLAT_SRCS-y += $(LIBLINUXUPLAT_BASE)/irq.c LIBLINUXUPLAT_SRCS-y += $(LIBLINUXUPLAT_BASE)/time.c diff --git a/plat/linuxu/include/linuxu/irq.h b/plat/linuxu/include/linuxu/irq.h new file mode 100644 index 0000000..d1b1c5e --- /dev/null +++ b/plat/linuxu/include/linuxu/irq.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Authors: Costin Lupu <costin.lupu@xxxxxxxxx> + * + * 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. + * + * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. + */ + +#ifndef __IRQ_H__ +#define __IRQ_H__ + +void irq_enable(void); +void irq_disable(void); +int irq_disabled(void); + +unsigned long irq_save(void); +void irq_restore(unsigned long flags); + +typedef int (*irq_handler_func_t)(void *arg); + +void irq_register(int irq, irq_handler_func_t func, void *arg); +void irq_handle(int irq); + +#endif /* __IRQ_H__ */ diff --git a/plat/linuxu/include/linuxu/signal.h b/plat/linuxu/include/linuxu/signal.h new file mode 100644 index 0000000..f46ce4e --- /dev/null +++ b/plat/linuxu/include/linuxu/signal.h @@ -0,0 +1,151 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Authors: Costin Lupu <costin.lupu@xxxxxxxxx> + * + * 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. + * + * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. + */ +#ifndef __SIGNAL_H__ +#define __SIGNAL_H__ + +/* Signal numbers */ +#define SIGALRM 14 + + +/* sigaction */ + +typedef void (*uk_sighandler_t)(int); +typedef void (*uk_sigrestore_t)(void); + +struct uk_sigaction { + uk_sighandler_t sa_handler; + int sa_flags; + uk_sigrestore_t sa_restorer; + sigset_t sa_mask; +}; + +/* sigaction flags */ +#define SA_SIGINFO 0x00000004 +#define SA_RESTORER 0x04000000 + + +/* Signal enabling/disabling definitions (sigprocmask) */ +#ifndef SIG_BLOCK +#define SIG_BLOCK 0 +#endif +#ifndef SIG_UNBLOCK +#define SIG_UNBLOCK 1 +#endif +#ifndef SIG_SETMASK +#define SIG_SETMASK 2 +#endif + +/* sigset utils */ +#define SIGSET_WORDS_NUM (sizeof(sigset_t) / sizeof(unsigned long int)) + +#define sigemptyset(set) \ + ({ \ + unsigned int __count = 0; \ + unsigned long int *__set = (set); \ + while (__count++ < SIGSET_WORDS_NUM) \ + *__set++ = 0; \ + 0; \ + }) + +#define sigfillset(set) \ + ({ \ + unsigned int __count = 0; \ + unsigned long int *__set = (set); \ + while (__count++ < SIGSET_WORDS_NUM) \ + *__set++ = ~0UL; \ + 0; \ + }) + +#define sigisemptyset(set) \ + ({ \ + unsigned int __count = 0; \ + const unsigned long int *__set = (set); \ + int __ret = __set[__count++]; \ + while (!__ret && __count < SIGSET_WORDS_NUM) \ + __ret = __set[__count++]; \ + __ret == 0; \ + }) + + +#define sig_word_idx(sig) \ + (((sig) - 1) / (8 * sizeof (unsigned long int))) + +#define sig_word_mask(sig) \ + (((unsigned long int) 1) << (((sig) - 1) % (8 * sizeof (unsigned long int)))) + + +#define sigaddset(set, sig) \ + ({ \ + unsigned long int __word = sig_word_idx(sig); \ + unsigned long int __mask = sig_word_mask(sig); \ + unsigned long int *__set = (set); \ + __set[__word] |= __mask; \ + 0; \ + }) + +#define sigdelset(set, sig) \ + ({ \ + unsigned long int __word = sig_word_idx(sig); \ + unsigned long int __mask = sig_word_mask(sig); \ + unsigned long int *__set = (set); \ + __set[__word] &= ~__mask; \ + 0; \ + }) + +#define sigismember(set, sig) \ + ({ \ + unsigned long int __word = sig_word_idx(sig); \ + unsigned long int __mask = sig_word_mask(sig); \ + unsigned long int *__set = (set); \ + __set[__word] & __mask ? 1 : 0; \ + }) + + +/* Signal event definitions */ +typedef union uk_sigval { + int sival_int; + void *sival_ptr; +} uk_sigval_t; + +typedef struct uk_sigevent { + uk_sigval_t sigev_value; + int sigev_signo; + int sigev_notify; + + /* We aren't interested now in what follows here */ + int pad[64]; + +} uk_sigevent_t; + +#endif /* __SIGNAL_H__ */ diff --git a/plat/linuxu/include/linuxu/syscall-x86_64.h b/plat/linuxu/include/linuxu/syscall-x86_64.h index c3c4550..5622921 100644 --- a/plat/linuxu/include/linuxu/syscall-x86_64.h +++ b/plat/linuxu/include/linuxu/syscall-x86_64.h @@ -46,6 +46,10 @@ #define __SC_MUNMAP 11 #define __SC_IOCTL 16 #define __SC_EXIT 60 + +#define __SC_RT_SIGACTION 13 +#define __SC_RT_SIGPROCMASK 14 + #define __SC_PSELECT6 270 /* NOTE: from linux-4.6.3 (arch/x86/entry/entry_64.S): diff --git a/plat/linuxu/include/linuxu/syscall.h b/plat/linuxu/include/linuxu/syscall.h index 1b0a3bc..2f4125b 100644 --- a/plat/linuxu/include/linuxu/syscall.h +++ b/plat/linuxu/include/linuxu/syscall.h @@ -37,8 +37,7 @@ #define __SYSCALL_H__ #include <sys/types.h> -#include <sys/select.h> -#include <sys/time.h> +#include <linuxu/signal.h> #if defined __X86_64__ #include <linuxu/syscall-x86_64.h> @@ -95,6 +94,27 @@ static inline void *sys_mmap(void *addr, size_t len, int prot, int flags, sys_mmap((addr), (len), (PROT_READ | PROT_WRITE), \ (MAP_SHARED | MAP_ANONYMOUS), -1, 0) + +static inline int sys_sigaction(int signum, + const struct uk_sigaction *action, struct uk_sigaction *oldaction) +{ + return (int) syscall4(__SC_RT_SIGACTION, + (long) signum, + (long) action, + (long) oldaction, + sizeof(sigset_t)); +} + +static inline int sys_sigprocmask(int how, + const sigset_t *set, sigset_t *oldset) +{ + return (int) syscall4(__SC_RT_SIGPROCMASK, + (long) how, + (long) set, + (long) oldset, + sizeof(sigset_t)); +} + static inline int sys_pselect6(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const void *sigmask) diff --git a/plat/linuxu/irq.c b/plat/linuxu/irq.c new file mode 100644 index 0000000..4dbdd20 --- /dev/null +++ b/plat/linuxu/irq.c @@ -0,0 +1,176 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Authors: Costin Lupu <costin.lupu@xxxxxxxxx> + * + * 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. + * + * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. + */ +#include <stdlib.h> +#include <uk/alloc.h> +#include <uk/list.h> +#include <uk/plat/lcpu.h> +#include <linuxu/irq.h> +#include <linuxu/syscall.h> +#include <linuxu/signal.h> +#include <linuxu/assert.h> + +#define IRQS_NUM 16 + +/* IRQ handlers declarations */ +struct irq_handler { + irq_handler_func_t func; + void *arg; + + struct uk_sigaction oldaction; + + UK_SLIST_ENTRY(struct irq_handler) entries; +}; + +UK_SLIST_HEAD(irq_handler_head, struct irq_handler); +static struct irq_handler_head irq_handlers[IRQS_NUM]; + +static struct uk_alloc *allocator; +static sigset_t handled_signals_set; +static unsigned long irq_enabled = 0; + + +void irq_enable(void) +{ + int rc; + + rc = sys_sigprocmask(SIG_UNBLOCK, &handled_signals_set, NULL); + LINUXU_ASSERT(rc, 0); + + irq_enabled = 1; +} + +void irq_disable(void) +{ + int rc; + + rc = sys_sigprocmask(SIG_BLOCK, &handled_signals_set, NULL); + LINUXU_ASSERT(rc, 0); + + irq_enabled = 0; +} + +int irq_disabled(void) +{ + return (irq_enabled == 0); +} + +unsigned long irq_save(void) +{ + unsigned long flags = irq_enabled; + + if (irq_enabled) + irq_disable(); + + return flags; +} + +void irq_restore(unsigned long flags) +{ + if (flags) { + if (!irq_enabled) + irq_enable(); + + } else if (irq_enabled) + irq_disable(); +} + +void __restorer(); +asm("__restorer:mov $15,%rax\nsyscall"); + +void irq_register(int irq, irq_handler_func_t func, void *arg) +{ + struct irq_handler *h; + struct uk_sigaction action; + sigset_t set; + unsigned long flags; + int rc; + + UK_ASSERT(irq < IRQS_NUM); + + /* New handler */ + h = uk_malloc(allocator, sizeof(struct irq_handler)); + UK_ASSERT(h != NULL); + h->func = func; + h->arg = arg; + + /* Register signal action */ + memset(&action, 0, sizeof(action)); + action.sa_handler = irq_handle; + action.sa_flags = SA_RESTORER; + action.sa_restorer = __restorer; + + rc = sys_sigaction(irq, &action, &h->oldaction); + LINUXU_ASSERT(rc, 0); + + flags = ukplat_lcpu_save_irqf(); + UK_SLIST_INSERT_HEAD(&irq_handlers[irq], h, entries); + ukplat_lcpu_restore_irqf(flags); + + /* Unblock the signal */ + sigemptyset(&set); + sigaddset(&set, irq); + + rc = sys_sigprocmask(SIG_UNBLOCK, &set, NULL); + LINUXU_ASSERT(rc, 0); + + /* Add to our handled signals set */ + sigaddset(&handled_signals_set, irq); +} + +void irq_handle(int irq) +{ + struct irq_handler *h; + int handled = 0; + + UK_SLIST_FOREACH(h, &irq_handlers[irq], entries) { + if (h->func(h->arg) == 1) { + handled = 1; + break; + } + } + + if (!handled) + UK_CRASH("Unhandled irq=%d\n", irq); +} + +int ukplat_irq_init(struct uk_alloc *a) +{ + UK_ASSERT(irq_enabled == 0); + UK_ASSERT(allocator == NULL); + + allocator = a; + sigemptyset(&handled_signals_set); + + return 0; +} diff --git a/plat/linuxu/lcpu.c b/plat/linuxu/lcpu.c index 42f5690..52ce23d 100644 --- a/plat/linuxu/lcpu.c +++ b/plat/linuxu/lcpu.c @@ -33,11 +33,48 @@ */ #include <stdlib.h> +#include <uk/plat/lcpu.h> +#include <_time.h> #include <linuxu/syscall.h> +#include <linuxu/irq.h> #include <uk/print.h> -#include <uk/plat/lcpu.h> -void ukplat_lcpu_halt(void) + +void ukplat_lcpu_enable_irq(void) +{ + irq_enable(); +} + +void ukplat_lcpu_disable_irq(void) +{ + irq_disable(); +} + +unsigned long ukplat_lcpu_save_irqf(void) +{ + unsigned long flags; + + flags = irq_save(); + + return flags; +} + +void ukplat_lcpu_restore_irqf(unsigned long flags) +{ + irq_restore(flags); +} + +int ukplat_lcpu_irqs_disabled(void) +{ + return irq_disabled(); +} + +void ukplat_lcpu_irqs_handle_pending(void) +{ + +} + +static void do_pselect(struct timespec *timeout) { int ret; int nfds = 0; @@ -45,24 +82,22 @@ void ukplat_lcpu_halt(void) fd_set *writefds = NULL; fd_set *exceptfds = NULL; - ret = sys_pselect6(nfds, readfds, writefds, exceptfds, NULL, NULL); + ret = sys_pselect6(nfds, readfds, writefds, exceptfds, timeout, NULL); if (ret < 0) uk_printd(DLVL_WARN, "Failed to halt LCPU: %d\n", ret); } -void ukplat_lcpu_halt_to(unsigned long millis) +void halt(void) +{ + do_pselect(NULL); +} + +void time_block_until(__snsec until) { - int ret; - int nfds = 0; - fd_set *readfds = NULL; - fd_set *writefds = NULL; - fd_set *exceptfds = NULL; struct timespec timeout; - timeout.tv_sec = millis / 1000; - timeout.tv_nsec = millis % 1000 * 1000000; + timeout.tv_sec = until / ukarch_time_sec_to_nsec(1); + timeout.tv_nsec = until % ukarch_time_sec_to_nsec(1); - ret = sys_pselect6(nfds, readfds, writefds, exceptfds, &timeout, NULL); - if (ret < 0) - uk_printd(DLVL_WARN, "Failed to halt LCPU: %d\n", ret); + do_pselect(&timeout); } -- 2.1.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 |