Commit ad14f089 authored by Andrew Jones's avatar Andrew Jones Committed by Marcelo Tosatti
Browse files

arm/arm64: maintain per thread exception handlers



Add exception handlers to thread info. And, since we allow threads
running in user mode to install exception handlers too (a convenience
for unit test developers), check for handlers on the user mode stack
thread info too. But, unit test developers will likely also expect the
installation of exception handlers done in kernel mode, before switching
to user mode, to work. So, if there's no handler in the thread info
hanging off the user mode stack, then still check the kernel mode stack
thread info for one.

Use THREAD_SIZE == PAGE_SIZE, when PAGE_SIZE is larger than 16K.
This is for arm64, which uses 64K pages, because the exception
handler arrays are 8K together, making the stack too small with
THREAD_SIZE == 16K.
Signed-off-by: Andrew Jones's avatarAndrew Jones <drjones@redhat.com>
Signed-off-by: default avatarMarcelo Tosatti <mtosatti@redhat.com>
parent f6d10793
......@@ -19,7 +19,7 @@ SECTIONS
. += 64K;
. = ALIGN(64K);
/*
* stack depth is ~16K, see THREAD_SIZE
* stack depth is 16K for arm and PAGE_SIZE for arm64, see THREAD_SIZE
* sp must be 16 byte aligned for arm64, and 8 byte aligned for arm
* sp must always be strictly less than the true stacktop
*/
......
......@@ -7,8 +7,15 @@
*
* This work is licensed under the terms of the GNU LGPL, version 2.
*/
#define THREAD_SIZE 16384
#include <asm/processor.h>
#include <asm/page.h>
#define __MIN_THREAD_SIZE 16384
#if PAGE_SIZE > __MIN_THREAD_SIZE
#define THREAD_SIZE PAGE_SIZE
#else
#define THREAD_SIZE __MIN_THREAD_SIZE
#endif
#define THREAD_START_SP (THREAD_SIZE - 16)
#define TIF_USER_MODE (1U << 0)
......@@ -16,6 +23,12 @@
struct thread_info {
int cpu;
unsigned int flags;
#ifdef __arm__
exception_fn exception_handlers[EXCPTN_MAX];
#else
vector_fn vector_handlers[VECTOR_MAX];
exception_fn exception_handlers[VECTOR_MAX][EC_MAX];
#endif
char ext[0]; /* allow unit tests to add extended info */
};
......
......@@ -8,6 +8,7 @@
#include <libcflat.h>
#include <asm/ptrace.h>
#include <asm/processor.h>
#include <asm/thread_info.h>
static const char *processor_modes[] = {
"USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" ,
......@@ -64,18 +65,28 @@ void show_regs(struct pt_regs *regs)
}
}
static exception_fn exception_handlers[EXCPTN_MAX];
void install_exception_handler(enum vector v, exception_fn fn)
{
struct thread_info *ti = current_thread_info();
if (v < EXCPTN_MAX)
exception_handlers[v] = fn;
ti->exception_handlers[v] = fn;
}
void do_handle_exception(enum vector v, struct pt_regs *regs)
{
if (v < EXCPTN_MAX && exception_handlers[v]) {
exception_handlers[v](regs);
struct thread_info *ti = thread_info_sp(regs->ARM_sp);
if (ti->flags & TIF_USER_MODE) {
if (v < EXCPTN_MAX && ti->exception_handlers[v]) {
ti->exception_handlers[v](regs);
return;
}
ti = current_thread_info();
}
if (v < EXCPTN_MAX && ti->exception_handlers[v]) {
ti->exception_handlers[v](regs);
return;
}
......
......@@ -49,6 +49,7 @@ extern void install_exception_handler(enum vector v, unsigned int ec,
exception_fn fn);
extern void default_vector_handler(enum vector v, struct pt_regs *regs,
unsigned int esr);
extern void vector_handlers_default_init(vector_fn *handlers);
extern void show_regs(struct pt_regs *regs);
extern bool get_far(unsigned int esr, unsigned long *far);
......
......@@ -9,6 +9,7 @@
#include <asm/ptrace.h>
#include <asm/processor.h>
#include <asm/esr.h>
#include <asm/thread_info.h>
static const char *vector_names[] = {
"el1t_sync",
......@@ -128,44 +129,66 @@ static void bad_exception(enum vector v, struct pt_regs *regs,
abort();
}
static exception_fn exception_handlers[VECTOR_MAX][EC_MAX];
void install_exception_handler(enum vector v, unsigned int ec, exception_fn fn)
{
struct thread_info *ti = current_thread_info();
if (v < VECTOR_MAX && ec < EC_MAX)
exception_handlers[v][ec] = fn;
ti->exception_handlers[v][ec] = fn;
}
void default_vector_handler(enum vector v, struct pt_regs *regs,
unsigned int esr)
{
struct thread_info *ti = thread_info_sp(regs->sp);
unsigned int ec = esr >> ESR_EL1_EC_SHIFT;
if (ec < EC_MAX && exception_handlers[v][ec])
exception_handlers[v][ec](regs, esr);
if (ti->flags & TIF_USER_MODE) {
if (ec < EC_MAX && ti->exception_handlers[v][ec]) {
ti->exception_handlers[v][ec](regs, esr);
return;
}
ti = current_thread_info();
}
if (ec < EC_MAX && ti->exception_handlers[v][ec])
ti->exception_handlers[v][ec](regs, esr);
else
bad_exception(v, regs, esr, false);
}
static vector_fn vector_handlers[VECTOR_MAX] = {
[EL1H_SYNC] = default_vector_handler,
[EL1H_IRQ] = default_vector_handler,
[EL0_SYNC_64] = default_vector_handler,
[EL0_IRQ_64] = default_vector_handler,
};
void vector_handlers_default_init(vector_fn *handlers)
{
handlers[EL1H_SYNC] = default_vector_handler;
handlers[EL1H_IRQ] = default_vector_handler;
handlers[EL0_SYNC_64] = default_vector_handler;
handlers[EL0_IRQ_64] = default_vector_handler;
}
void do_handle_exception(enum vector v, struct pt_regs *regs, unsigned int esr)
{
if (v < VECTOR_MAX && vector_handlers[v])
vector_handlers[v](v, regs, esr);
struct thread_info *ti = thread_info_sp(regs->sp);
if (ti->flags & TIF_USER_MODE) {
if (v < VECTOR_MAX && ti->vector_handlers[v]) {
ti->vector_handlers[v](v, regs, esr);
return;
}
ti = current_thread_info();
}
if (v < VECTOR_MAX && ti->vector_handlers[v])
ti->vector_handlers[v](v, regs, esr);
else
bad_exception(v, regs, esr, true);
}
void install_vector_handler(enum vector v, vector_fn fn)
{
struct thread_info *ti = current_thread_info();
if (v < VECTOR_MAX)
vector_handlers[v] = fn;
ti->vector_handlers[v] = fn;
}
void thread_info_init(struct thread_info *ti, unsigned int flags)
......@@ -173,6 +196,7 @@ void thread_info_init(struct thread_info *ti, unsigned int flags)
memset(ti, 0, sizeof(struct thread_info));
ti->cpu = mpidr_to_cpu(get_mpidr());
ti->flags = flags;
vector_handlers_default_init(ti->vector_handlers);
}
void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr)
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment