text: /*
   * 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 specifiy 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 */
  