Commit graph

5 commits

Author SHA1 Message Date
Andy Ross
e694656345 kernel: Move per-cpu _kernel_t fields into separate struct
When in SMP mode, the nested/irq_stack/current fields are specific to
the current CPU and not to the kernel as a whole, so we need an array
of these.  Place them in a _cpu_t struct and implement a
_arch_curr_cpu() function to retrieve the pointer.

When not in SMP mode, the first CPU's fields are defined as a unioned
with the first _cpu_t record.  This permits compatibility with legacy
assembly on other platforms.  Long term, all users, including
uniprocessor architectures, should be updated to use the new scheme.

Fundamentally this is just renaming: the structure layout and runtime
code do not change on any existing platforms and won't until someone
defines a second CPU.

Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
2018-02-16 10:44:29 -05:00
Andy Ross
865bbd6b69 xtensa-asm2: Handle alloca/movsp exceptions
Xtensa register windows have a special exception that happens when the
stack pointer needs to be moved, but the caller function has already
spilled its registers below it.

I thought these were unexercised in Zephyr code, but they turn out to
be thrown by the existing mem_pool tests when run in the 32-register
qemu environment (but not on 64-register hardwre).  Because the effect
of the exception is to unspill the caller, there is no good way to
handle this in a traditional handler.  Instead put a 5-instruction
stub in front of the user exception handler (i.e. incurring that cost
on every trap and every L1 interrupt) to test before doing the normal
entry.

Works, but would be nicer to optimize this in the future so that only
true alloca exceptions take that cost.

Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
2018-02-16 10:44:29 -05:00
Andy Ross
60932d1427 xtensa: Add hook to do register window spills
This macro was already available add an external symbol so C code can
access it (via CALL0 -- it's not and can't be an actual function).

Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
2018-02-16 10:44:29 -05:00
Andy Ross
bf2139331c xtensa: Add exception/interrupt vectors in asm2 mode
This adds vectors for all interrupt levels defined by core-isa.h.

Modify the entry code a little bit to select correct linker sections
(levels 1, 6 and 7 get special names for... no particularly good
reason) and to constructed the interrupted PS value correctly (no EPS1
register for exceptions since they had to have interrupted level 0
code and thus differ only in the EXCM bit).

Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
2018-02-16 10:44:29 -05:00
Andy Ross
a34f884f23 xtensa: New asm layer to support SMP
SMP needs a new context switch primitive (to disentangle _swap() from
the scheduler) and new interrupt entry behavior (to be able to take a
global spinlock on behalf of legacy drivers).  The existing code is
very obtuse, and working with it led me down a long path of "this
would be so much better if..."  So this is a new context and entry
framework, intended to replace the code that exists now, at least on
SMP platforms.

New features:

* The new context switch primitive is xtensa_switch(), which takes a
  "new" context handle as an argument instead of getting it from the
  scheduler, returns an "old" context handle through a pointer
  (e.g. to save it to the old thread context), and restores the lock
  state(PS register) exactly as it is at entry instead of taking it as
  an argument.

* The register spill code understands wrap-around register windows and
  can avoid spilling A4-A15 registers when they are unused by the
  interrupted function, saving as much as 48 bytes of stack space on
  the interrupted stacks.

* The "spill register windows" routine is entirely different, using a
  different mechanism, and is MUCH FASTER (to the tune of almost 200
  cycles).  See notes in comments.

* Even better, interrupt entry can be done via a clever "cross stack
  call" I worked up, meaning that the interrupted thread's registers
  do not need to be spilled at all until they are naturally pushed out
  by the interrupt handler or until we return from the interrupt into
  a different thread.  This is a big efficiency win for tiny
  interrupts (e.g. timers), and a big latency win for all interrupts.

* Interrupt entry is 100% symmetric with respect to medium/high
  interrupts, avoiding the problems seen with hooking high priority
  interrupts with the current code (e.g. ESP-32's watchdog driver).

* Much smaller code size.  No cut and paste assembly.  No use of HAL
  calls.

* Assumes "XEA2" interrupt architecture, the register window extension
  (i.e. no CALL0 ABI), and the "high priority interrupts" extension.
  Does not support the legacy processor variants for which we have no
  targets.  The old code has some stuff in there to support this, but
  it seems bitrotten, untestable, and I'm all but certain it doesn't
  work.

Note that this simply adds the primitives to the existing tree in a
form where they can be unit tested.  It does not replace the existing
interrupt/exception handling or _Swap() implementation.

Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
2018-02-16 10:44:29 -05:00