bc3e77b356
If there are any TLB misses during interrupt handling, the user, kernel and double exception vector will be triggered for the miss and the DEPC and EXCCAUSE overwritten as the TLB missse are be handled in the assembly code and execution returned to the original vector code. Because of this, both DEPC and EXCCAUSE being read in the C handler are not the ones that triggered the original exception (for example, level-1 interrupt). So stash both DEPC and EXCCAUSE such that the original cause of exception is visible in the C handler. Signed-off-by: Daniel Leung <daniel.leung@intel.com>
110 lines
3.7 KiB
Python
Executable file
110 lines
3.7 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
# Copyright (c) 2022 Intel corporation
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
import argparse
|
|
import re
|
|
|
|
# Scratch register allocator. Zephyr uses multiple Xtensa SRs as
|
|
# scratch space for various special purposes. Unfortunately the
|
|
# configurable architecture means that not all registers will be the
|
|
# same on every device. This script parses a pre-cooked ("gcc -E
|
|
# -dM") core-isa.h file for the current architecture and assigns
|
|
# registers to usages.
|
|
|
|
def parse_args():
|
|
parser = argparse.ArgumentParser(allow_abbrev=False)
|
|
|
|
parser.add_argument("--coherence", action="store_true",
|
|
help="Enable scratch registers for CONFIG_KERNEL_COHERENCE")
|
|
parser.add_argument("--mmu", action="store_true",
|
|
help="Enable scratch registers for MMU usage")
|
|
parser.add_argument("--syscall-scratch", action="store_true",
|
|
help="Enable scratch registers for syscalls if needed")
|
|
parser.add_argument("coreisa",
|
|
help="Path to preprocessed core-isa.h")
|
|
parser.add_argument("outfile",
|
|
help="Output file")
|
|
|
|
return parser.parse_args()
|
|
|
|
args = parse_args()
|
|
|
|
NEEDED = ["A0SAVE", "CPU"]
|
|
if args.mmu:
|
|
NEEDED += ["DBLEXC", "DEPC_SAVE", "EXCCAUSE_SAVE"]
|
|
if args.coherence:
|
|
NEEDED += ["FLUSH"]
|
|
|
|
coreisa = args.coreisa
|
|
outfile = args.outfile
|
|
|
|
syms = {}
|
|
|
|
def get(s):
|
|
return syms[s] if s in syms else 0
|
|
|
|
with open(coreisa) as infile:
|
|
for line in infile.readlines():
|
|
m = re.match(r"^#define\s+([^ ]+)\s*(.*)", line.rstrip())
|
|
if m:
|
|
syms[m.group(1)] = m.group(2)
|
|
|
|
# Use MISC registers first if available, that's what they're for
|
|
regs = [ f"MISC{n}" for n in range(0, int(get("XCHAL_NUM_MISC_REGS"))) ]
|
|
|
|
if args.syscall_scratch:
|
|
# If there is no THREADPTR, we need to use syscall for
|
|
# arch_is_user_context() where the code needs a scratch
|
|
# register.
|
|
have_threadptr = int(get("XCHAL_HAVE_THREADPTR"))
|
|
if have_threadptr == 0:
|
|
NEEDED.append("SYSCALL_SCRATCH")
|
|
|
|
# Next come EXCSAVE. Also record our highest non-debug interrupt level.
|
|
maxint = 0
|
|
for il in range(1, 1 + int(get("XCHAL_NUM_INTLEVELS"))):
|
|
regs.append(f"EXCSAVE{il}")
|
|
if il != int(get("XCHAL_DEBUGLEVEL")):
|
|
maxint = max(il, maxint)
|
|
|
|
# Find the highest priority software interrupt. We'll use that for
|
|
# arch_irq_offload().
|
|
irqoff_level = -1
|
|
irqoff_int = -1
|
|
for sym, val in syms.items():
|
|
if val == "XTHAL_INTTYPE_SOFTWARE":
|
|
m = re.match(r"XCHAL_INT(\d+)_TYPE", sym)
|
|
if m:
|
|
intnum = int(m.group(1))
|
|
levelsym = f"XCHAL_INT{intnum}_LEVEL"
|
|
if levelsym in syms:
|
|
intlevel = int(syms[levelsym])
|
|
if intlevel > irqoff_level:
|
|
irqoff_int = intnum
|
|
irqoff_level = intlevel
|
|
|
|
# Now emit our output header with the assignments we chose
|
|
with open(outfile, "w") as f:
|
|
f.write("/* Generated File, see gen_zsr.py */\n")
|
|
f.write("#ifndef ZEPHYR_ZSR_H\n")
|
|
f.write("#define ZEPHYR_ZSR_H\n")
|
|
for i, need in enumerate(NEEDED):
|
|
f.write(f"# define ZSR_{need} {regs[i]}\n")
|
|
f.write(f"# define ZSR_{need}_STR \"{regs[i]}\"\n")
|
|
|
|
# Emit any remaining registers as generics
|
|
for i in range(len(NEEDED), len(regs)):
|
|
f.write(f"# define ZSR_EXTRA{i - len(NEEDED)} {regs[i]}\n")
|
|
f.write(f"# define ZSR_EXTRA{i - len(NEEDED)}_STR \"{regs[i]}\"\n")
|
|
|
|
# Also, our highest level EPC/EPS registers
|
|
f.write(f"# define ZSR_RFI_LEVEL {maxint}\n")
|
|
f.write(f"# define ZSR_EPC EPC{maxint}\n")
|
|
f.write(f"# define ZSR_EPS EPS{maxint}\n")
|
|
|
|
# And the irq offset interrupt
|
|
if irqoff_int >= 0:
|
|
f.write(f"# define ZSR_IRQ_OFFLOAD_INT {irqoff_int}\n")
|
|
|
|
f.write("#endif\n")
|