[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Minios-devel] [UNIKRAFT PATCH 2/3] plat/kvm: Add KVM (x86_64) interrupts support
On 01.05.2018 01:40, Costin Lupu wrote: On 04/30/2018 03:44 PM, Simon Kuenzer wrote:See my comments inline. On 05.04.2018 17:21, Costin Lupu wrote:Changes: * PIC support * KVM specific traps * traps and interrupt assembly stubs * shared IRQ handlers Signed-off-by: Costin Lupu <costin.lupu@xxxxxxxxx> --- plat/kvm/Makefile.uk | 9 +- plat/kvm/include/kvm-x86/cpu_x86_64.h | 42 ------- plat/kvm/include/kvm-x86/cpu_x86_64_defs.h | 42 ------- plat/kvm/include/kvm-x86/traps.h | 45 +++++++ plat/kvm/include/kvm/intctrl.h | 38 ++++++ plat/kvm/include/kvm/irq.h | 45 +++++++ plat/kvm/irq.c | 97 +++++++++++++++ plat/kvm/shutdown.c | 9 ++ plat/kvm/x86/cpu_vectors_x86_64.S | 142 ++++++++++++++++++++++ plat/kvm/x86/cpu_x86_64.c | 71 ----------- plat/kvm/x86/entry64.S | 1 + plat/kvm/x86/intctrl.c | 111 +++++++++++++++++ plat/kvm/x86/lcpu.c | 37 ++++++ plat/kvm/x86/setup.c | 6 +- plat/kvm/x86/traps.c | 186 +++++++++++++++++++++++++++++ 15 files changed, 722 insertions(+), 159 deletions(-) delete mode 100644 plat/kvm/include/kvm-x86/cpu_x86_64.h delete mode 100644 plat/kvm/include/kvm-x86/cpu_x86_64_defs.h create mode 100644 plat/kvm/include/kvm-x86/traps.h create mode 100644 plat/kvm/include/kvm/intctrl.h create mode 100644 plat/kvm/include/kvm/irq.h create mode 100644 plat/kvm/irq.c create mode 100644 plat/kvm/x86/cpu_vectors_x86_64.S delete mode 100644 plat/kvm/x86/cpu_x86_64.c create mode 100644 plat/kvm/x86/intctrl.c create mode 100644 plat/kvm/x86/traps.c diff --git a/plat/kvm/Makefile.uk b/plat/kvm/Makefile.uk index 823e785..46258ff 100644 --- a/plat/kvm/Makefile.uk +++ b/plat/kvm/Makefile.uk @@ -16,17 +16,22 @@ LIBKVMPLAT_ASINCLUDES-y += -I$(UK_PLAT_COMMON_BASE)/include LIBKVMPLAT_CINCLUDES-y += -I$(LIBKVMPLAT_BASE)/include LIBKVMPLAT_CINCLUDES-y += -I$(UK_PLAT_COMMON_BASE)/include +LIBKVMPLAT_SRCS-$(ARCH_X86_64) += $(UK_PLAT_COMMON_BASE)/x86/trace.c|common +LIBKVMPLAT_SRCS-$(ARCH_X86_64) += $(UK_PLAT_COMMON_BASE)/x86/traps.c|common +LIBKVMPLAT_SRCS-$(ARCH_X86_64) += $(UK_PLAT_COMMON_BASE)/x86/cpu_native.c|common ifeq ($(HAVE_SCHED),y) LIBKVMPLAT_SRCS-$(ARCH_X86_64) += $(UK_PLAT_COMMON_BASE)/x86/thread_start.S|common LIBKVMPLAT_SRCS-$(ARCH_X86_64) += $(UK_PLAT_COMMON_BASE)/thread.c|common LIBKVMPLAT_SRCS-$(ARCH_X86_64) += $(UK_PLAT_COMMON_BASE)/sw_ctx.c|common endif LIBKVMPLAT_SRCS-$(ARCH_X86_64) += $(LIBKVMPLAT_BASE)/x86/entry64.S -LIBKVMPLAT_SRCS-$(ARCH_X86_64) += $(LIBKVMPLAT_BASE)/x86/cpu_x86_64.c +LIBKVMPLAT_SRCS-$(ARCH_X86_64) += $(LIBKVMPLAT_BASE)/x86/traps.c +LIBKVMPLAT_SRCS-$(ARCH_X86_64) += $(LIBKVMPLAT_BASE)/x86/cpu_vectors_x86_64.S LIBKVMPLAT_SRCS-$(ARCH_X86_64) += $(LIBKVMPLAT_BASE)/x86/setup.c LIBKVMPLAT_SRCS-$(ARCH_X86_64) += $(LIBKVMPLAT_BASE)/x86/console.c LIBKVMPLAT_SRCS-$(ARCH_X86_64) += $(LIBKVMPLAT_BASE)/x86/lcpu.c -LIBKVMPLAT_SRCS-$(ARCH_X86_64) += $(LIBKVMPLAT_BASE)/x86/time.c +LIBKVMPLAT_SRCS-$(ARCH_X86_64) += $(LIBKVMPLAT_BASE)/x86/intctrl.c LIBKVMPLAT_SRCS-y += $(LIBKVMPLAT_BASE)/shutdown.c LIBKVMPLAT_SRCS-y += $(LIBKVMPLAT_BASE)/memory.c +LIBKVMPLAT_SRCS-y += $(LIBKVMPLAT_BASE)/irq.c LIBKVMPLAT_SRCS-y += $(UK_PLAT_COMMON_BASE)/lcpu.c|common diff --git a/plat/kvm/include/kvm-x86/cpu_x86_64.h b/plat/kvm/include/kvm-x86/cpu_x86_64.h deleted file mode 100644 index 427c705..0000000 --- a/plat/kvm/include/kvm-x86/cpu_x86_64.h +++ /dev/null @@ -1,42 +0,0 @@ -/* SPDX-License-Identifier: ISC */ -/* - * Authors: Martin Lucina - * - * Copyright (c) 2016-2017 Docker, Inc. - * - * 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. - */ -#include <inttypes.h> - -/* accessing devices via port space */ -static inline void outb(uint16_t port, uint8_t v) -{ - __asm__ __volatile__("outb %0,%1" : : "a"(v), "dN"(port)); -} - -static inline void outw(uint16_t port, uint16_t v) -{ - __asm__ __volatile__("outw %0,%1" : : "a"(v), "dN"(port)); -} -static inline uint8_t inb(uint16_t port) -{ - uint8_t v; - - __asm__ __volatile__("inb %1,%0" : "=a"(v) : "dN"(port)); - return v; -} - -void cpu_halt(void) __attribute__((noreturn)); -void cpu_init(void); diff --git a/plat/kvm/include/kvm-x86/cpu_x86_64_defs.h b/plat/kvm/include/kvm-x86/cpu_x86_64_defs.h deleted file mode 100644 index 985f8d3..0000000 --- a/plat/kvm/include/kvm-x86/cpu_x86_64_defs.h +++ /dev/null @@ -1,42 +0,0 @@ -/* SPDX-License-Identifier: ISC */ -/* - * Authors: Martin Lucina - * - * Copyright (c) 2016-2017 Docker, Inc. - * - * 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. - */ - -#include <x86/cpu_defs.h> - -/* - * GDT layout - * - * This should be kept consistent with the layout used by the ukvm target (as - * defined in ukvm/ukvm_cpu_x86_64.h. - */ -#define GDT_DESC_NULL 0 -#define GDT_DESC_CODE 1 -#define GDT_DESC_CODE32 2 /* Used by boot.S on virtio targets */ -#define GDT_DESC_DATA 3 -#define GDT_DESC_TSS_LO 4 -#define GDT_DESC_TSS_HI 5 -#define GDT_DESC_TSS GDT_DESC_TSS_LO - -#define GDT_DESC_OFFSET(n) ((n) * 0x8) -#define GDT_NUM_ENTRIES 6 - -#define GDT_DESC_CODE_VAL 0x00af99000000ffff -#define GDT_DESC_DATA_VAL 0x00cf93000000ffff diff --git a/plat/kvm/include/kvm-x86/traps.h b/plat/kvm/include/kvm-x86/traps.h new file mode 100644 index 0000000..8210613 --- /dev/null +++ b/plat/kvm/include/kvm-x86/traps.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: ISC */ +/* + * Authors: Martin Lucina + * + * Copyright (c) 2016-2017 Docker, Inc. + * + * 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. + */ + +#include <x86/traps.h> + +/* + * GDT layout + * + * This should be kept consistent with the layout used by the ukvm target (as + * defined in ukvm/ukvm_cpu_x86_64.h. + */ +#define GDT_DESC_NULL 0 +#define GDT_DESC_CODE 1 +#define GDT_DESC_CODE32 2 /* Used by boot.S on virtio targets */ +#define GDT_DESC_DATA 3 +#define GDT_DESC_TSS_LO 4 +#define GDT_DESC_TSS_HI 5 +#define GDT_DESC_TSS GDT_DESC_TSS_LO + +#define GDT_DESC_OFFSET(n) ((n) * 0x8) +#define GDT_NUM_ENTRIES 6 + +#define GDT_DESC_CODE_VAL 0x00af99000000ffff +#define GDT_DESC_DATA_VAL 0x00cf93000000ffff + + +#define IDT_NUM_ENTRIES 48 diff --git a/plat/kvm/include/kvm/intctrl.h b/plat/kvm/include/kvm/intctrl.h new file mode 100644 index 0000000..a6ce307 --- /dev/null +++ b/plat/kvm/include/kvm/intctrl.h @@ -0,0 +1,38 @@ +/* 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. + */ + +void intctrl_init(void); +void intctrl_clear_irq(unsigned int irq); +void intctrl_mask_irq(unsigned int irq); +void intctrl_ack_irq(unsigned int irq); diff --git a/plat/kvm/include/kvm/irq.h b/plat/kvm/include/kvm/irq.h new file mode 100644 index 0000000..606acf2 --- /dev/null +++ b/plat/kvm/include/kvm/irq.h @@ -0,0 +1,45 @@ +/* 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 __KVM_IRQ_H_ +#define __KVM_IRQ_H_ + +#include <sys/types.h> + +typedef int (*irq_handler_func_t)(void *); +Since you worked on interrupts for all platforms. Do you think it makes sense to introduce an UKPLAT API for interrupts, like ukplat_irq_register()? If not, then I would prefix those functions with "libkvmplat_".It's clear that the implementations on all platforms (Xen, KVM and linuxu in the next patch series) show that they converge to a common API. This should be implemented when we'll add more variables into equation, such as more drivers, a different interrupt controller (APIC) and a full ARM porting. I would converge this API before introducing ARM64 as another platform. I am concerned that we loose track if we delay converging too much. I am fine if we do the converge with a patch after we integrated also your linux user space scheduling series. So, you have my okay ;-). +void irq_register(unsigned long irq, irq_handler_func_t func, void *arg); +void irq_handle(unsigned long irq); + +#endif /* __KVM_IRQ_H_ */ diff --git a/plat/kvm/irq.c b/plat/kvm/irq.c new file mode 100644 index 0000000..55f8e67 --- /dev/null +++ b/plat/kvm/irq.c @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: ISC */ +/* + * Authors: Dan Williams + * Martin Lucina + * Ricardo Koller + * Costin Lupu <costin.lupu@xxxxxxxxx> + * + * 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/list.h> +#include <uk/plat/lcpu.h> +#include <x86/cpu.h> +#include <kvm/irq.h> +#include <kvm/intctrl.h> +#include <uk/assert.h> + + +static struct uk_alloc *allocator; + +struct irq_handler { + irq_handler_func_t func; + void *arg; + + UK_SLIST_ENTRY(struct irq_handler) entries; +}; + +UK_SLIST_HEAD(irq_handler_head, struct irq_handler); +static struct irq_handler_head irq_handlers[16]; + +void irq_register(unsigned long irq, irq_handler_func_t func, void *arg) +{ + struct irq_handler *h; + unsigned long flags; + + UK_ASSERT(irq < 16); + UK_ASSERT(allocator != NULL); + + h = uk_malloc(allocator, sizeof(struct irq_handler)); + UK_ASSERT(h != NULL);I would actually return an error value (-ENOMEM) instead of failing with an assertion.My opinion is that the IRQ registering is pretty critical for the system and if memory isn't available then it's clearly an issue with how the system is designed or configured or both. At this stage of Unikraft we shouldn't complicate the error handling too much since it's not a general purpose OS. I'd rather make it fail fast than let it generate weird side effects that can be difficult to debug. Also, the IRQ API implementation should shed some light on which way would be better. I rather prefer that this decision is made by the according driver, by lets say: ret = ukplat_irq_register(netdev->rxirq, netdev_rxirqhandler, netdev); if (ret != 0) UK_CRASH("%p: Failed to register interrupt handler %d\n", netdev, ret); This wouldn't cost you much overhead.It is right that during bootstrapping the essential platform drivers better crash than trying to handle the case but I would move this decision to the driver. On the other hand, I foresee that we want hot-plugging support at some point. You do not want to crash your machine because of a hot-plugged device (which could be a communication channel to a different Unikernel instance that is added dynamically at runtime) that was added because you run out of memory. So yes, on one hand, this API is critical but on the other hand it might be even called from non-bootstrapping code. + + h->func = func; + h->arg = arg; + + flags = ukplat_lcpu_save_irqf(); + UK_SLIST_INSERT_HEAD(&irq_handlers[irq], h, entries); + ukplat_lcpu_restore_irqf(flags); + + intctrl_clear_irq(irq); +} + +void irq_handle(unsigned long 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=%lu\n", irq); + else + /* Only ACK the IRQ if handled; we only need to know + * about an unhandled IRQ the first time round. + */ + intctrl_ack_irq(irq); +} + +int ukplat_irq_init(struct uk_alloc *a) +{ + UK_ASSERT(allocator == NULL); + allocator = a; + return 0; +} diff --git a/plat/kvm/shutdown.c b/plat/kvm/shutdown.c index 673d065..a513df9 100644 --- a/plat/kvm/shutdown.c +++ b/plat/kvm/shutdown.c @@ -26,6 +26,8 @@ #include <uk/print.h> #include <uk/plat/bootstrap.h> +static void cpu_halt(void) __noreturn; + /* TODO: implement CPU reset */ void ukplat_terminate(enum ukplat_gstate request __unused) { @@ -45,6 +47,13 @@ void ukplat_terminate(enum ukplat_gstate request __unused) cpu_halt(); } +static void cpu_halt(void) +{ + __asm__ __volatile__("cli; hlt"); + for (;;) + ; +} + int ukplat_suspend(void) { return -EBUSY; diff --git a/plat/kvm/x86/cpu_vectors_x86_64.S b/plat/kvm/x86/cpu_vectors_x86_64.S new file mode 100644 index 0000000..c30f2ee --- /dev/null +++ b/plat/kvm/x86/cpu_vectors_x86_64.S @@ -0,0 +1,142 @@ +/* SPDX-License-Identifier: ISC */ +/* + * Authors: Dan Williams + * Martin Lucina + * Costin Lupu <costin.lupu@xxxxxxxxx> + * + * 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 */ + +#include <x86/traps.h> +#include <x86/regs.h> + +#define ENTRY(X) .global X ; .type X, @function ; X: + +.macro PUSH_CALLER_SAVE + pushq %rdi + pushq %rsi + pushq %rdx + pushq %rcx + pushq %rax + pushq %r8 + pushq %r9 + pushq %r10 + pushq %r11 + pushq %rbx + pushq %rbp + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 +.endm + +.macro POP_CALLER_SAVE + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %rbp + popq %rbx + popq %r11 + popq %r10 + popq %r9 + popq %r8 + popq %rax + popq %rcx + popq %rdx + popq %rsi + popq %rdi +.endm + +.macro TRAP_ENTRY trapname, has_ec +ENTRY(ASM_TRAP_SYM(\trapname)) + cld + +.if !\has_ec + pushq $0 /* no error code, pass 0 */ +.endif + PUSH_CALLER_SAVE + subq $REGS_PAD_SIZE, %rsp /* we have some padding */ + + movq %rsp, %rdi + movq OFFSETOF_REGS_ORIG_RAX(%rsp), %rsi + call do_\trapname + + addq $REGS_PAD_SIZE, %rsp /* we have some padding */ + POP_CALLER_SAVE + addq $8, %rsp /* discard error code */ + + iretq +.endm + +.macro IRQ_ENTRY irqno +ENTRY(cpu_irq_\irqno) + cld + + pushq $0 /* no error code */ + PUSH_CALLER_SAVE + subq $REGS_PAD_SIZE, %rsp /* we have some padding */ + + movq $\irqno, %rdi + call irq_handle + + addq $REGS_PAD_SIZE, %rsp /* we have some padding */ + POP_CALLER_SAVE + addq $8, %rsp + + iretq +.endm + +TRAP_ENTRY divide_error, 0 +TRAP_ENTRY debug, 0 +TRAP_ENTRY nmi, 0 +TRAP_ENTRY int3, 0 +TRAP_ENTRY overflow, 0 +TRAP_ENTRY bounds, 0 +TRAP_ENTRY invalid_op, 0 +TRAP_ENTRY no_device, 0 +TRAP_ENTRY double_fault, 1 +TRAP_ENTRY invalid_tss, 1 +TRAP_ENTRY no_segment, 1 +TRAP_ENTRY stack_error, 1 +TRAP_ENTRY gp_fault, 1 +TRAP_ENTRY page_fault, 1 +TRAP_ENTRY coproc_error, 0 +TRAP_ENTRY alignment_check, 1 +TRAP_ENTRY machine_check, 0 +TRAP_ENTRY simd_error, 0 +TRAP_ENTRY virt_error, 0 + +IRQ_ENTRY 0 +IRQ_ENTRY 1 +IRQ_ENTRY 2 +IRQ_ENTRY 3 +IRQ_ENTRY 4 +IRQ_ENTRY 5 +IRQ_ENTRY 6 +IRQ_ENTRY 7 +IRQ_ENTRY 8 +IRQ_ENTRY 9 +IRQ_ENTRY 10 +IRQ_ENTRY 11 +IRQ_ENTRY 12 +IRQ_ENTRY 13 +IRQ_ENTRY 14 +IRQ_ENTRY 15 diff --git a/plat/kvm/x86/cpu_x86_64.c b/plat/kvm/x86/cpu_x86_64.c deleted file mode 100644 index 2f98b95..0000000 --- a/plat/kvm/x86/cpu_x86_64.c +++ /dev/null @@ -1,71 +0,0 @@ -/* SPDX-License-Identifier: ISC */ -/* - * Authors: Dan Williams - * Martin Lucina - * Felipe Huici <felipe.huici@xxxxxxxxx> - * Florian Schmidt <florian.schmidt@xxxxxxxxx> - * - * Copyright (c) 2015-2017 IBM - * Copyright (c) 2016-2017 Docker, Inc. - * Copyright (c) 2017 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. - */ - -#include <string.h> -#include <x86/desc.h> -#include <kvm/setup.h> -#include <kvm-x86/cpu_x86_64_defs.h> -#include <kvm-x86/cpu_x86_64.h> - -static struct seg_desc32 cpu_gdt64[GDT_NUM_ENTRIES] ALIGN_64_BIT; - -/* - * The monitor (ukvm) or bootloader + bootstrap (virtio) starts us up with a - * bootstrap GDT which is "invisible" to the guest, init and switch to our own - * GDT. - * - * This is done primarily since we need to do LTR later in a predictable - * fashion. - */ -static void gdt_init(void) -{ - volatile struct desc_table_ptr64 gdtptr; - - memset(cpu_gdt64, 0, sizeof(cpu_gdt64)); - cpu_gdt64[GDT_DESC_CODE].raw = GDT_DESC_CODE_VAL; - cpu_gdt64[GDT_DESC_DATA].raw = GDT_DESC_DATA_VAL; - - gdtptr.limit = sizeof(cpu_gdt64) - 1; - gdtptr.base = (__u64) &cpu_gdt64; - __asm__ __volatile__("lgdt (%0)" ::"r"(&gdtptr)); - /* - * TODO: Technically we should reload all segment registers here, in - * practice this doesn't matter since the bootstrap GDT matches ours, - * for now. - */ -} - -void cpu_init(void) -{ - gdt_init(); -} - -void cpu_halt(void) -{ - __asm__ __volatile__("cli; hlt"); - for (;;) - ; -} diff --git a/plat/kvm/x86/entry64.S b/plat/kvm/x86/entry64.S index 6570c47..f034908 100644 --- a/plat/kvm/x86/entry64.S +++ b/plat/kvm/x86/entry64.S @@ -28,6 +28,7 @@ */ #include <x86/cpu_defs.h> +#include <kvm-x86/traps.h> #include <kvm-x86/multiboot_defs.h> #define ENTRY(x) .text; .globl x; .type x,%function; x: diff --git a/plat/kvm/x86/intctrl.c b/plat/kvm/x86/intctrl.c new file mode 100644 index 0000000..dc40555 --- /dev/null +++ b/plat/kvm/x86/intctrl.c @@ -0,0 +1,111 @@ +/* SPDX-License-Identifier: ISC */ +/* + * Authors: Dan Williams + * Martin Lucina + * + * Copyright (c) 2015-2017 IBM + * Copyright (c) 2016-2017 Docker, Inc. + * + * 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 platform_intr.c */ + +#include <stdint.h> +#include <x86/cpu.h> +#include <kvm/intctrl.h> + +#define PIC1 0x20 /* IO base address for master PIC */ +#define PIC2 0xA0 /* IO base address for slave PIC */ +#define PIC1_COMMAND PIC1 +#define PIC1_DATA (PIC1 + 1) +#define PIC2_COMMAND PIC2 +#define PIC2_DATA (PIC2 + 1) +#define IRQ_ON_MASTER(n) ((n) < 8) +#define IRQ_PORT(n) (IRQ_ON_MASTER(n) ? PIC1_DATA : PIC2_DATA) +#define IRQ_OFFSET(n) (IRQ_ON_MASTER(n) ? (n) : ((n) - 8)) + +#define PIC_EOI 0x20 /* End-of-interrupt command code */ +#define ICW1_ICW4 0x01 /* ICW4 (not) needed */ +#define ICW1_SINGLE 0x02 /* Single (cascade) mode */ +#define ICW1_INTERVAL 0x04 /* Call address interval 4 (8) */ +#define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */ +#define ICW1_INIT 0x10 /* Initialization - required! */ +#define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */ +#define ICW4_AUTO 0x02 /* Auto (normal) EOI */ +#define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */ +#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */ +#define ICW4_SFN 0x10 /* Special fully nested (not) */ + +/* + * arguments: + * offset1 - vector offset for master PIC vectors on the master become + * offset1..offset1+7 + * offset2 - same for slave PIC: offset2..offset2+7 + */ +static void PIC_remap(int offset1, int offset2) +{ + unsigned char a1, a2; + + /* save masks */ + a1 = inb(PIC1_DATA); + a2 = inb(PIC2_DATA); + + /* start init seq (cascade) */ + outb(PIC1_COMMAND, ICW1_INIT + ICW1_ICW4); + outb(PIC2_COMMAND, ICW1_INIT + ICW1_ICW4); + /* ICW2: Master PIC vector off */ + outb(PIC1_DATA, offset1); + /* ICW2: Slave PIC vector off */ + outb(PIC2_DATA, offset2); + /* ICW3: tell Master PIC there is a slave PIC at IRQ2 (0000 0100) */ + outb(PIC1_DATA, 4); + /* ICW3: tell Slave PIC its cascade identity (0000 0010) */ + outb(PIC2_DATA, 2); + + outb(PIC1_DATA, ICW4_8086); + outb(PIC2_DATA, ICW4_8086); + + outb(PIC1_DATA, a1); /* restore saved masks. */ + outb(PIC2_DATA, a2); +} +We should prefix these funcitons, too.I don't understand which prefix that would be. AFAIK, PIC can be used on Xen as well in an HVM. Please correct if I'm wrong. Again, when revisiting the IRQ handling, the interrupt controllers implementation may be moved outside the platform specific code, in a common module/area/etc. Yes, you are right. Hum...Would you agree on "_ukplat_" (platform libs internal) prefixes for such symbols? I also thought of using "_libcommonplat_" but this might be less intuitive for symbols that a platform-specific driver uses at the platform (imagine libxenbus, or libpcibus that use platform-specific features that are not part of the common ukplat API). Alterntively, we could start introducing a symbols file that declares symbols internally that are not part of any API for the libkvmplat.o object. However, this still does not fit with platform-specific driver libraries... What do you think? +void intctrl_init(void) +{ + PIC_remap(32, 40); +} + +void intctrl_ack_irq(unsigned int irq) +{ + if (!IRQ_ON_MASTER(irq)) + outb(PIC2_COMMAND, PIC_EOI); + + outb(PIC1_COMMAND, PIC_EOI); +} + +void intctrl_mask_irq(unsigned int irq) +{ + __u16 port; + + port = IRQ_PORT(irq); + outb(port, inb(port) | (1 << IRQ_OFFSET(irq))); +} + +void intctrl_clear_irq(unsigned int irq) +{ + __u16 port; + + port = IRQ_PORT(irq); + outb(port, inb(port) & ~(1 << IRQ_OFFSET(irq))); +} diff --git a/plat/kvm/x86/lcpu.c b/plat/kvm/x86/lcpu.c index 985c670..42e2faa 100644 --- a/plat/kvm/x86/lcpu.c +++ b/plat/kvm/x86/lcpu.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause */ /* * Authors: Simon Kuenzer <simon.kuenzer@xxxxxxxxx> + * Costin Lupu <costin.lupu@xxxxxxxxx> * * Copyright (c) 2017, NEC Europe Ltd., NEC Corporation. All rights reserved. * @@ -34,3 +35,39 @@ #include <stdint.h> #include <uk/plat/lcpu.h> +#include <x86/irq.h> + + +void ukplat_lcpu_enable_irq(void) +{ + local_irq_enable(); +} + +void ukplat_lcpu_disable_irq(void) +{ + local_irq_disable(); +} + +unsigned long ukplat_lcpu_save_irqf(void) +{ + unsigned long flags; + + local_irq_save(flags); + + return flags; +} + +void ukplat_lcpu_restore_irqf(unsigned long flags) +{ + local_irq_restore(flags); +} + +int ukplat_lcpu_irqs_disabled(void) +{ + return irqs_disabled(); +} + +void ukplat_lcpu_irqs_handle_pending(void) +{ + +} diff --git a/plat/kvm/x86/setup.c b/plat/kvm/x86/setup.c index 96d80e9..f56d07e 100644 --- a/plat/kvm/x86/setup.c +++ b/plat/kvm/x86/setup.c @@ -27,10 +27,11 @@ */ #include <string.h> +#include <x86/traps.h> #include <kvm/console.h> +#include <kvm/intctrl.h> #include <kvm-x86/multiboot.h> #include <kvm-x86/multiboot_defs.h> -#include <kvm-x86/cpu_x86_64.h> #include <uk/arch/limits.h> #include <uk/arch/types.h> #include <uk/plat/console.h> @@ -134,7 +135,8 @@ void _libkvmplat_entry(void *arg) _libkvmplat_init_console(); _init_cpufeatures(); - cpu_init(); + traps_init(); + intctrl_init(); uk_printd(DLVL_INFO, "Entering from KVM (x86)...\n"); uk_printd(DLVL_INFO, " multiboot: %p\n", mi); diff --git a/plat/kvm/x86/traps.c b/plat/kvm/x86/traps.c new file mode 100644 index 0000000..27ef6d9 --- /dev/null +++ b/plat/kvm/x86/traps.c @@ -0,0 +1,186 @@ +/* SPDX-License-Identifier: ISC */ +/* + * Authors: Dan Williams + * Martin Lucina + * Felipe Huici <felipe.huici@xxxxxxxxx> + * Florian Schmidt <florian.schmidt@xxxxxxxxx> + * + * Copyright (c) 2015-2017 IBM + * Copyright (c) 2016-2017 Docker, Inc. + * Copyright (c) 2017 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. + */ + +#include <string.h> +#include <uk/arch/lcpu.h> +#include <x86/desc.h> +#include <kvm-x86/traps.h> + +static struct seg_desc32 cpu_gdt64[GDT_NUM_ENTRIES] __align64b; + +/* + * The monitor (ukvm) or bootloader + bootstrap (virtio) starts us up with a + * bootstrap GDT which is "invisible" to the guest, init and switch to our own + * GDT. + * + * This is done primarily since we need to do LTR later in a predictable + * fashion. + */ +static void gdt_init(void) +{ + volatile struct desc_table_ptr64 gdtptr; + + memset(cpu_gdt64, 0, sizeof(cpu_gdt64)); + cpu_gdt64[GDT_DESC_CODE].raw = GDT_DESC_CODE_VAL; + cpu_gdt64[GDT_DESC_DATA].raw = GDT_DESC_DATA_VAL; + + gdtptr.limit = sizeof(cpu_gdt64) - 1; + gdtptr.base = (__u64) &cpu_gdt64; + __asm__ __volatile__("lgdt (%0)" ::"r"(&gdtptr)); + /* + * TODO: Technically we should reload all segment registers here, in + * practice this doesn't matter since the bootstrap GDT matches ours, + * for now. + */ +} + +static struct tss64 cpu_tss; + +static char cpu_intr_stack[4096]; /* IST1 */ +static char cpu_trap_stack[4096]; /* IST2 */ +static char cpu_nmi_stack[4096]; /* IST3 */ + +static void tss_init(void) +{ + struct seg_desc64 *td = (void *) &cpu_gdt64[GDT_DESC_TSS_LO]; + + cpu_tss.ist[0] = (__u64) &cpu_intr_stack[sizeof(cpu_intr_stack)]; + cpu_tss.ist[1] = (__u64) &cpu_trap_stack[sizeof(cpu_trap_stack)]; + cpu_tss.ist[2] = (__u64) &cpu_nmi_stack[sizeof(cpu_nmi_stack)]; + + td->limit_lo = sizeof(cpu_tss); + td->base_lo = (__u64) &cpu_tss; + td->type = 0x9; + td->zero = 0; + td->dpl = 0; + td->p = 1; + td->limit_hi = 0; + td->gran = 0; + td->base_hi = (__u64) &cpu_tss >> 24; + td->zero1 = 0; + + barrier(); + __asm__ __volatile__( + "ltr %0" + : + : "r" ((unsigned short) (GDT_DESC_TSS_LO * 8)) + ); +} + + +/* Declare the traps used only by this platform: */ +DECLARE_TRAP_EC(nmi, "NMI") +DECLARE_TRAP_EC(double_fault, "double fault") +DECLARE_TRAP_EC(virt_error, "virtualization error") + + +static struct seg_gate_desc64 cpu_idt[IDT_NUM_ENTRIES] __align64b; + +static void idt_fillgate(unsigned int num, void *fun, unsigned int ist) +{ + struct seg_gate_desc64 *desc = &cpu_idt[num]; + + /* + * All gates are interrupt gates, all handlers run with interrupts off. + */ + desc->offset_hi = (__u64) fun >> 16; + desc->offset_lo = (__u64) fun & 0xffff; + desc->selector = GDT_DESC_OFFSET(GDT_DESC_CODE); + desc->ist = ist; + desc->type = 14; /* == 0b1110 */ + desc->dpl = 0; + desc->p = 1; +} + +volatile struct desc_table_ptr64 idtptr; + +static void idt_init(void) +{ + /* + * Load trap vectors. All traps run on IST2 (cpu_trap_stack), except for + * the exceptions. + */ +#define FILL_TRAP_GATE(name, ist) extern void cpu_trap_##name(void); \ + idt_fillgate(TRAP_##name, ASM_TRAP_SYM(name), ist) + FILL_TRAP_GATE(divide_error, 2); + FILL_TRAP_GATE(debug, 2); + FILL_TRAP_GATE(nmi, 3); /* #NMI runs on IST3 (cpu_nmi_stack) */ + FILL_TRAP_GATE(int3, 2); + FILL_TRAP_GATE(overflow, 2); + FILL_TRAP_GATE(bounds, 2); + FILL_TRAP_GATE(invalid_op, 2); + FILL_TRAP_GATE(no_device, 2); + FILL_TRAP_GATE(double_fault, 3); /* #DF runs on IST3 (cpu_nmi_stack) */ + + FILL_TRAP_GATE(invalid_tss, 2); + FILL_TRAP_GATE(no_segment, 2); + FILL_TRAP_GATE(stack_error, 2); + FILL_TRAP_GATE(gp_fault, 2); + FILL_TRAP_GATE(page_fault, 2); + + FILL_TRAP_GATE(coproc_error, 2); + FILL_TRAP_GATE(alignment_check, 2); + FILL_TRAP_GATE(machine_check, 2); + FILL_TRAP_GATE(simd_error, 2); + FILL_TRAP_GATE(virt_error, 2); + + /* + * Load irq vectors. All irqs run on IST1 (cpu_intr_stack). + */ +#define FILL_IRQ_GATE(num, ist) extern void cpu_irq_##num(void); \ + idt_fillgate(32 + num, cpu_irq_##num, ist) + FILL_IRQ_GATE(0, 1); + FILL_IRQ_GATE(1, 1); + FILL_IRQ_GATE(2, 1); + FILL_IRQ_GATE(3, 1); + FILL_IRQ_GATE(4, 1); + FILL_IRQ_GATE(5, 1); + FILL_IRQ_GATE(6, 1); + FILL_IRQ_GATE(7, 1); + FILL_IRQ_GATE(8, 1); + FILL_IRQ_GATE(9, 1); + FILL_IRQ_GATE(10, 1); + FILL_IRQ_GATE(11, 1); + FILL_IRQ_GATE(12, 1); + FILL_IRQ_GATE(13, 1); + FILL_IRQ_GATE(14, 1); + FILL_IRQ_GATE(15, 1); + + idtptr.limit = sizeof(cpu_idt) - 1; + idtptr.base = (__u64) &cpu_idt; + __asm__ __volatile__("lidt (%0)" :: "r" (&idtptr)); +} +Can you prefix these functions, too?Although this would make sense now, I expect the trap handling on KVM to be very similar, if not the same, with the trap handling on Xen/HVM. Which doesn't make it very KVM specific. The names here were chosen on purpose to reflect the similarity with the implementation for Xen/HVM. Understood. It is the same discussion as ahead. +void traps_init(void) +{ + gdt_init(); + tss_init(); + idt_init(); +} + +void traps_fini(void) +{ +}_______________________________________________ Minios-devel mailing list Minios-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/minios-devel _______________________________________________ Minios-devel mailing list Minios-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/minios-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |