From 3aeefd225078ba92234c0364982260ced68bede4 Mon Sep 17 00:00:00 2001 From: Andy Ross Date: Mon, 31 Jul 2023 12:32:45 -0700 Subject: [PATCH] arch/xtensa: Add automatic vector linkage generation Existing solutions for linking the Xtensa vector table are a cut-and-paste mess of inherited code, with more than a dozen special sections that need to be linked into many special MEMORY{} regions. Accept the existing convention used by C/asm code, but automatically detect the needed offsets for the platform from core-isa.h (it can share the preprocessing with gen_zsr.py) and emit a file that can be included in lieu of all the existing boilerplate. Signed-off-by: Andy Ross --- arch/xtensa/core/CMakeLists.txt | 8 +++ arch/xtensa/core/gen_vectors.py | 122 ++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100755 arch/xtensa/core/gen_vectors.py diff --git a/arch/xtensa/core/CMakeLists.txt b/arch/xtensa/core/CMakeLists.txt index 40906a0a326..4c2ce8173ca 100644 --- a/arch/xtensa/core/CMakeLists.txt +++ b/arch/xtensa/core/CMakeLists.txt @@ -103,3 +103,11 @@ add_custom_command( add_custom_target(xtensa_handlers_h DEPENDS ${HANDLERS}.h) add_dependencies(zephyr_interface xtensa_handlers_h) + +# Auto-generate interrupt vector entry +set(VECS_LD ${CMAKE_BINARY_DIR}/zephyr/include/generated/xtensa_vectors.ld) +add_custom_command(OUTPUT ${VECS_LD} DEPENDS ${CORE_ISA_DM} + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/gen_vectors.py + ${CORE_ISA_DM} > ${VECS_LD}) +add_custom_target(xtensa_vectors_ld DEPENDS ${VECS_LD}) +add_dependencies(zephyr_interface xtensa_vectors_ld) diff --git a/arch/xtensa/core/gen_vectors.py b/arch/xtensa/core/gen_vectors.py new file mode 100755 index 00000000000..e9e60e30fe5 --- /dev/null +++ b/arch/xtensa/core/gen_vectors.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python3 +# Copyright 2023 The ChromiumOS Authors +# SPDX-License-Identifier: Apache-2.0 +import sys +import re + +# Xtensa Vector Table linker generator +# +# Takes a pre-processed (gcc -dM) core-isa.h file as its first +# argument, and emits a GNU linker section declartion which will +# correctly load the exception vectors and literals as long as their +# code is declared using standard conventions (see below). +# +# The section name will be ".z_xtensa_vectors", and a symbol +# "z_xtensa_vecbase" is emitted containing a valid value for the +# VECBASE SR at runtime. +# +# Obviously, this requires that XCHAL_HAVE_VECBASE=1. A similar trick +# could be played to load vectors at fixed addresses on hardware that +# lacks VECBASE, but the core-isa.h interface is inexplicably +# different. +# +# Because the "standard conventions" (which descend from somewhere in +# Cadence) are not documented anywhere and just end up cut and pasted +# between devices, here's an attempt at a specification: +# +# + The six register window exception vectors are defined with offsets +# internal to their assembly code. They are linked in a single +# section named ".WindowVectors.text". +# +# + The "kernel", "user" and "double exception" vectors are emitted in +# sections named ".KernelExceptionVector.text", +# "UserExceptionVector.text" and "DoubleExceptionVector.text" +# respectively. +# +# + XEA2 interrupt vectors are in sections named +# ".LevelInterruptVector.text", except (!) for ones which are +# given special names. The "debug" and "NMI" interrupts (if they +# exist) are technically implemented as standard interrupt vectors +# (of a platform-dependent level), but the code for them is emitted +# in ".DebugExceptionVector.text" and ".NMIExceptionVector.text", +# and not a section corresponding to their interrupt level. +# +# + Any unused bytes at the end of a vector are made available as +# storage for immediate values used by the following vector (Xtensa +# can only back-reference immediates for MOVI/L32R instructions) as +# a "Vector.literal" section. Note that there is no guarantee +# of how much space is available, it depends on the previous +# vector's code size. Zephyr code has historically not used this +# space, as support in existing linker scripts is inconsistent. But +# it's exposed here. + +coreisa = sys.argv[1] + +debug_level = 0 + +# Translation for the core-isa.h vs. linker section naming conventions +sect_names = { "DOUBLEEXC" : "DoubleException", + "KERNEL" : "KernelException", + "NMI" : "NMIException", + "USER" : "UserException" } + +offsets = {} + +with open(coreisa) as infile: + for line in infile.readlines(): + m = re.match(r"^#define\s+XCHAL_([^ ]+)_VECOFS\s*(.*)", line.rstrip()) + if m: + (sym, val) = (m.group(1), m.group(2)) + if sym == "WINDOW_OF4": + # This must be the start of the section + assert eval(val) == 0 + elif sym.startswith("WINDOW"): + # Ignore the other window exceptions, they're internally sorted + pass + elif sym == "RESET": + # Ignore, not actually part of the vector table + pass + elif sym == "DEBUG": + # This one is a recursive macro that doesn't expand, + # so handle manually + m = re.match(r"XCHAL_INTLEVEL(\d+)_VECOFS", val) + if not m: + print(f"no intlevel match for debug val {val}") + assert m + debug_level = eval(m.group(1)) + else: + if val == "XCHAL_NMI_VECOFS": + # This gets recursively defined in the other + # direction, so ignore the INTLEVEL + pass + else: + addr = eval(val) + m = re.match(r"^INTLEVEL(\d+)", sym) + if m: + offsets[f"Level{m.group(1)}Interrupt"] = addr + else: + offsets[sect_names[sym]] = addr + +if debug_level > 0: + old = f"Level{debug_level}Interrupt" + offsets[f"DebugException"] = offsets[old] + del offsets[old] + +sects = list(offsets) +sects.sort(key=lambda s: offsets[s]) + +print("/* Automatically Generated Code - Do Not Edit */") +print("/* See arch/xtensa/core/gen_vector.py */") +print("") + +# The 1k alignment is experimental, the docs on the Relocatable Vector +# Option doesn't specify an alignment at all, but writes to the +# bottom bits don't take... +print( " .z_xtensa_vectors : ALIGN(1024) {") +print( " z_xtensa_vecbase = .;") +print(f" KEEP(*(.WindowVectors.text));") +for s in sects: + print(f" KEEP(*(.{s}Vector.literal));") + print( " . = 0x%3.3x;" % (offsets[s])) + print(f" KEEP(*(.{s}Vector.text));") +print(" }")