| /* |
| * Copyright (c) 2018 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| #ifndef _XUK_H |
| #define _XUK_H |
| |
| #include <xuk-switch.h> |
| #include "shared-page.h" |
| |
| /* |
| * APIs exposed by the xuk layer to OS integration: |
| */ |
| |
| /* Set a single CPU-specific pointer which can be retrieved (on that |
| * CPU!) with get_f_ptr() |
| */ |
| static inline void xuk_set_f_ptr(int cpu, void *p) |
| { |
| _shared.fs_ptrs[cpu] = (long)p; |
| } |
| |
| /* Likewise, but "G" */ |
| static inline void xuk_set_g_ptr(int cpu, void *p) |
| { |
| _shared.gs_ptrs[cpu] = (long)p; |
| } |
| |
| /* Retrieves the pointer set by set_f_ptr() for the current CPU */ |
| static inline void *xuk_get_f_ptr() |
| { |
| long long ret, off = 0; |
| |
| __asm__("movq %%fs:(%1), %0" : "=r"(ret) : "r"(off)); |
| return (void *)(long)ret; |
| } |
| |
| /* Retrieves the pointer set by set_g_ptr() for the current CPU */ |
| static inline void *xuk_get_g_ptr() |
| { |
| long long ret, off = 0; |
| |
| __asm__("movq %%gs:(%1), %0" : "=r"(ret) : "r"(off)); |
| return (void *)(long)ret; |
| } |
| |
| /** |
| * @brief Sets a global handler for the specified interrupt. |
| * |
| * Interrupt numbers live in a partitioned space: |
| * |
| * + Values from 0 - 0xff are mapped to INTIx interrupts in the global |
| * index of IO-APIC inputs, which on many systems correspond to |
| * legacy IRQ0-IRQ15 interrupts at the bottom of the interrupt |
| * range. These handlers are not passed a meaningful value in their |
| * first argument, though the function pointer type declares one. |
| * |
| * + Values from 0x100 to 0x1ff are mapped to raw vectors 0x00-0xff |
| * and can be used for handling exceptions, for INT instructions, or |
| * for MSI- or IPI-directed interrupts that specify specific |
| * vectors. |
| * |
| * + Values outside this range may be exposed symbolically for other |
| * interrupts sources, for example local APIC LVT interrupts. |
| * |
| * If there is a pre-existing handler specified for a specified raw |
| * vector, this function will replace it. |
| * |
| * @param interrupt Interrupt number. See above for interpretation. |
| * @param priority Integer in the range 2-15. Higher-valued interrupts |
| * can interrupt lower ones. Ignored for raw vector |
| * numbers, as their priority is encoded in the top |
| * four bits of the vector number. A priority of zero |
| * is treated as "don't care" and the interrupt will |
| * be assigned the lowest available vector. |
| * @param handler Function pointer to invoke on interrupt receipt. It |
| * will be passed the specified argument as the first |
| * argument and the x86 exception error code (if any) |
| * in the second. |
| * @param arg Opaque value to pass to the handler when invoked. |
| * |
| */ |
| void xuk_set_isr(int interrupt, int priority, |
| void (*handler)(void *, int), void *arg); |
| |
| #define INT_APIC_LVT_TIMER 0x200 |
| |
| #define XUK_INT_RAW_VECTOR(vector) ((vector)+0x100) |
| |
| void xuk_set_isr_mask(int interrupt, int masked); |
| |
| /* Stack frame on interrupt entry. Obviously they get pushed onto the |
| * stack in the opposite order than they appear here; the last few |
| * entries are the hardware frame. Note that not all registers are |
| * present, the ABI caller-save registers don't get pushed until after |
| * the handler as an optimization. |
| */ |
| struct xuk_entry_frame { |
| unsigned long long r11; |
| unsigned long long r10; |
| unsigned long long r9; |
| unsigned long long r8; |
| unsigned long long rsi; |
| unsigned long long rcx; |
| unsigned long long rax; |
| unsigned long long rdx; |
| unsigned long long rdi; |
| unsigned long long rip; |
| unsigned long long cs; |
| unsigned long long rflags; |
| unsigned long long rsp; |
| unsigned long long ss; |
| }; |
| |
| /* Full stack frame, i.e. the one used as the handles in xuk_switch(). |
| * Once more, the registers declared here are NOT POPULATED during the |
| * execution of an interrupt service routine. |
| */ |
| struct xuk_stack_frame { |
| unsigned long long r15; |
| unsigned long long r14; |
| unsigned long long r13; |
| unsigned long long r12; |
| unsigned long long rbp; |
| unsigned long long rbx; |
| struct xuk_entry_frame entry; |
| }; |
| |
| /* Sets up a new stack. The sp argument should point to the quadword |
| * above (!) the allocated stack area (i.e. the frame will be pushed |
| * below it). The frame will be set up to enter the function in the |
| * specified code segment with the specified flags register. An array |
| * of up to 6 function arguments may also be provided. Returns a |
| * handle suitable for passing to switch() or for returning from |
| * isr_exit_restore_stack(). |
| */ |
| long xuk_setup_stack(long sp, void *fn, unsigned int eflags, |
| long *args, int nargs); |
| |
| |
| /* Starts the numbered CPU running with the specified initial stack |
| * pointer |
| */ |
| |
| void xuk_start_cpu(int cpu, unsigned int stack); |
| /* |
| * OS-defined utilities required by the xuk layer: |
| */ |
| |
| /* OS CPU startup entry point, running on the stack returned by |
| * init_cpu_stack() |
| */ |
| void z_cpu_start(int cpu); |
| |
| /* Called on receipt of an unregistered interrupt/exception. Passes |
| * the vector number and the CPU error code, if any. |
| */ |
| void z_unhandled_vector(int vector, int err, struct xuk_entry_frame *f); |
| |
| /* Called on ISR entry before nested interrupts are enabled so the OS |
| * can arrange bookeeping. Really should be exposed as an inline and |
| * not a function call; cycles on interrupt entry are precious. |
| */ |
| void z_isr_entry(void); |
| |
| /* Called on ISR exit to choose a next thread to run. The argument is |
| * a context pointer to the thread that was interrupted. |
| */ |
| void *z_isr_exit_restore_stack(void *interrupted); |
| |
| #endif /* _XUK_H */ |