diff mbox series

[v1,07/14] xen/riscv: introduce exception handlers implementation

Message ID 7a459ea843d5823ee2c50b0e44dded5bdb554ca6.1674226563.git.oleksii.kurochko@gmail.com (mailing list archive)
State Superseded
Headers show
Series RISCV basic exception handling implementation | expand

Commit Message

Oleksii Kurochko Jan. 20, 2023, 2:59 p.m. UTC
The patch introduces an implementation of basic exception handlers:
- to save/restore context
- to handle an exception itself. The handler calls wait_for_interrupt
  now, nothing more.

Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
---
 xen/arch/riscv/Makefile            |  2 +
 xen/arch/riscv/entry.S             | 97 ++++++++++++++++++++++++++++++
 xen/arch/riscv/include/asm/traps.h | 13 ++++
 xen/arch/riscv/traps.c             | 13 ++++
 4 files changed, 125 insertions(+)
 create mode 100644 xen/arch/riscv/entry.S
 create mode 100644 xen/arch/riscv/include/asm/traps.h
 create mode 100644 xen/arch/riscv/traps.c

Comments

Alistair Francis Jan. 22, 2023, 11:29 p.m. UTC | #1
On Sat, Jan 21, 2023 at 1:00 AM Oleksii Kurochko
<oleksii.kurochko@gmail.com> wrote:
>
> The patch introduces an implementation of basic exception handlers:
> - to save/restore context
> - to handle an exception itself. The handler calls wait_for_interrupt
>   now, nothing more.
>
> Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  xen/arch/riscv/Makefile            |  2 +
>  xen/arch/riscv/entry.S             | 97 ++++++++++++++++++++++++++++++
>  xen/arch/riscv/include/asm/traps.h | 13 ++++
>  xen/arch/riscv/traps.c             | 13 ++++
>  4 files changed, 125 insertions(+)
>  create mode 100644 xen/arch/riscv/entry.S
>  create mode 100644 xen/arch/riscv/include/asm/traps.h
>  create mode 100644 xen/arch/riscv/traps.c
>
> diff --git a/xen/arch/riscv/Makefile b/xen/arch/riscv/Makefile
> index 1a4f1a6015..443f6bf15f 100644
> --- a/xen/arch/riscv/Makefile
> +++ b/xen/arch/riscv/Makefile
> @@ -1,7 +1,9 @@
>  obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
> +obj-y += entry.o
>  obj-$(CONFIG_RISCV_64) += riscv64/
>  obj-y += sbi.o
>  obj-y += setup.o
> +obj-y += traps.o
>
>  $(TARGET): $(TARGET)-syms
>         $(OBJCOPY) -O binary -S $< $@
> diff --git a/xen/arch/riscv/entry.S b/xen/arch/riscv/entry.S
> new file mode 100644
> index 0000000000..f7d46f42bb
> --- /dev/null
> +++ b/xen/arch/riscv/entry.S
> @@ -0,0 +1,97 @@
> +#include <asm/asm.h>
> +#include <asm/processor.h>
> +#include <asm/riscv_encoding.h>
> +#include <asm/traps.h>
> +
> +        .global handle_exception
> +        .align 4
> +
> +handle_exception:
> +
> +    /* Exceptions from xen */
> +save_to_stack:
> +        /* Save context to stack */
> +        REG_S   sp, (RISCV_CPU_USER_REGS_OFFSET(sp) - RISCV_CPU_USER_REGS_SIZE) (sp)
> +        addi    sp, sp, -RISCV_CPU_USER_REGS_SIZE
> +        REG_S   t0, RISCV_CPU_USER_REGS_OFFSET(t0)(sp)
> +        j       save_context
> +
> +save_context:
> +        /* Save registers */
> +        REG_S   ra, RISCV_CPU_USER_REGS_OFFSET(ra)(sp)
> +        REG_S   gp, RISCV_CPU_USER_REGS_OFFSET(gp)(sp)
> +        REG_S   t1, RISCV_CPU_USER_REGS_OFFSET(t1)(sp)
> +        REG_S   t2, RISCV_CPU_USER_REGS_OFFSET(t2)(sp)
> +        REG_S   s0, RISCV_CPU_USER_REGS_OFFSET(s0)(sp)
> +        REG_S   s1, RISCV_CPU_USER_REGS_OFFSET(s1)(sp)
> +        REG_S   a0, RISCV_CPU_USER_REGS_OFFSET(a0)(sp)
> +        REG_S   a1, RISCV_CPU_USER_REGS_OFFSET(a1)(sp)
> +        REG_S   a2, RISCV_CPU_USER_REGS_OFFSET(a2)(sp)
> +        REG_S   a3, RISCV_CPU_USER_REGS_OFFSET(a3)(sp)
> +        REG_S   a4, RISCV_CPU_USER_REGS_OFFSET(a4)(sp)
> +        REG_S   a5, RISCV_CPU_USER_REGS_OFFSET(a5)(sp)
> +        REG_S   a6, RISCV_CPU_USER_REGS_OFFSET(a6)(sp)
> +        REG_S   a7, RISCV_CPU_USER_REGS_OFFSET(a7)(sp)
> +        REG_S   s2, RISCV_CPU_USER_REGS_OFFSET(s2)(sp)
> +        REG_S   s3, RISCV_CPU_USER_REGS_OFFSET(s3)(sp)
> +        REG_S   s4, RISCV_CPU_USER_REGS_OFFSET(s4)(sp)
> +        REG_S   s5, RISCV_CPU_USER_REGS_OFFSET(s5)(sp)
> +        REG_S   s6, RISCV_CPU_USER_REGS_OFFSET(s6)(sp)
> +        REG_S   s7, RISCV_CPU_USER_REGS_OFFSET(s7)(sp)
> +        REG_S   s8, RISCV_CPU_USER_REGS_OFFSET(s8)(sp)
> +        REG_S   s9, RISCV_CPU_USER_REGS_OFFSET(s9)(sp)
> +        REG_S   s10, RISCV_CPU_USER_REGS_OFFSET(s10)(sp)
> +        REG_S   s11, RISCV_CPU_USER_REGS_OFFSET(s11)(sp)
> +        REG_S   t3, RISCV_CPU_USER_REGS_OFFSET(t3)(sp)
> +        REG_S   t4, RISCV_CPU_USER_REGS_OFFSET(t4)(sp)
> +        REG_S   t5, RISCV_CPU_USER_REGS_OFFSET(t5)(sp)
> +        REG_S   t6, RISCV_CPU_USER_REGS_OFFSET(t6)(sp)
> +        csrr    t0, CSR_SEPC
> +        REG_S   t0, RISCV_CPU_USER_REGS_OFFSET(sepc)(sp)
> +        csrr    t0, CSR_SSTATUS
> +        REG_S   t0, RISCV_CPU_USER_REGS_OFFSET(sstatus)(sp)
> +
> +        mv      a0, sp
> +        jal     __handle_exception
> +
> +restore_registers:
> +        /* Restore stack_cpu_regs */
> +        REG_L   t0, RISCV_CPU_USER_REGS_OFFSET(sepc)(sp)
> +        csrw    CSR_SEPC, t0
> +        REG_L   t0, RISCV_CPU_USER_REGS_OFFSET(sstatus)(sp)
> +        csrw    CSR_SSTATUS, t0
> +
> +        REG_L   ra, RISCV_CPU_USER_REGS_OFFSET(ra)(sp)
> +        REG_L   gp, RISCV_CPU_USER_REGS_OFFSET(gp)(sp)
> +        REG_L   t0, RISCV_CPU_USER_REGS_OFFSET(t0)(sp)
> +        REG_L   t1, RISCV_CPU_USER_REGS_OFFSET(t1)(sp)
> +        REG_L   t2, RISCV_CPU_USER_REGS_OFFSET(t2)(sp)
> +        REG_L   s0, RISCV_CPU_USER_REGS_OFFSET(s0)(sp)
> +        REG_L   s1, RISCV_CPU_USER_REGS_OFFSET(s1)(sp)
> +        REG_L   a0, RISCV_CPU_USER_REGS_OFFSET(a0)(sp)
> +        REG_L   a1, RISCV_CPU_USER_REGS_OFFSET(a1)(sp)
> +        REG_L   a2, RISCV_CPU_USER_REGS_OFFSET(a2)(sp)
> +        REG_L   a3, RISCV_CPU_USER_REGS_OFFSET(a3)(sp)
> +        REG_L   a4, RISCV_CPU_USER_REGS_OFFSET(a4)(sp)
> +        REG_L   a5, RISCV_CPU_USER_REGS_OFFSET(a5)(sp)
> +        REG_L   a6, RISCV_CPU_USER_REGS_OFFSET(a6)(sp)
> +        REG_L   a7, RISCV_CPU_USER_REGS_OFFSET(a7)(sp)
> +        REG_L   s2, RISCV_CPU_USER_REGS_OFFSET(s2)(sp)
> +        REG_L   s3, RISCV_CPU_USER_REGS_OFFSET(s3)(sp)
> +        REG_L   s4, RISCV_CPU_USER_REGS_OFFSET(s4)(sp)
> +        REG_L   s5, RISCV_CPU_USER_REGS_OFFSET(s5)(sp)
> +        REG_L   s6, RISCV_CPU_USER_REGS_OFFSET(s6)(sp)
> +        REG_L   s7, RISCV_CPU_USER_REGS_OFFSET(s7)(sp)
> +        REG_L   s8, RISCV_CPU_USER_REGS_OFFSET(s8)(sp)
> +        REG_L   s9, RISCV_CPU_USER_REGS_OFFSET(s9)(sp)
> +        REG_L   s10, RISCV_CPU_USER_REGS_OFFSET(s10)(sp)
> +        REG_L   s11, RISCV_CPU_USER_REGS_OFFSET(s11)(sp)
> +        REG_L   t3, RISCV_CPU_USER_REGS_OFFSET(t3)(sp)
> +        REG_L   t4, RISCV_CPU_USER_REGS_OFFSET(t4)(sp)
> +        REG_L   t5, RISCV_CPU_USER_REGS_OFFSET(t5)(sp)
> +        REG_L   t6, RISCV_CPU_USER_REGS_OFFSET(t6)(sp)
> +
> +        /* Restore sp */
> +        REG_L   sp, RISCV_CPU_USER_REGS_OFFSET(sp)(sp)
> +
> +        sret
> diff --git a/xen/arch/riscv/include/asm/traps.h b/xen/arch/riscv/include/asm/traps.h
> new file mode 100644
> index 0000000000..816ab1178a
> --- /dev/null
> +++ b/xen/arch/riscv/include/asm/traps.h
> @@ -0,0 +1,13 @@
> +#ifndef __ASM_TRAPS_H__
> +#define __ASM_TRAPS_H__
> +
> +#include <asm/processor.h>
> +
> +#ifndef __ASSEMBLY__
> +
> +void __handle_exception(struct cpu_user_regs *cpu_regs);
> +void handle_exception(void);
> +
> +#endif /* __ASSEMBLY__ */
> +
> +#endif /* __ASM_TRAPS_H__ */
> diff --git a/xen/arch/riscv/traps.c b/xen/arch/riscv/traps.c
> new file mode 100644
> index 0000000000..3201b851ef
> --- /dev/null
> +++ b/xen/arch/riscv/traps.c
> @@ -0,0 +1,13 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Copyright (C) 2023 Vates
> + *
> + * RISC-V Trap handlers
> + */
> +#include <asm/processor.h>
> +#include <asm/traps.h>
> +
> +void __handle_exception(struct cpu_user_regs *cpu_regs)
> +{
> +    wait_for_interrupt();
> +}
> --
> 2.39.0
>
>
Jan Beulich Jan. 23, 2023, 11:17 a.m. UTC | #2
On 20.01.2023 15:59, Oleksii Kurochko wrote:
> --- /dev/null
> +++ b/xen/arch/riscv/entry.S
> @@ -0,0 +1,97 @@
> +#include <asm/asm.h>
> +#include <asm/processor.h>
> +#include <asm/riscv_encoding.h>
> +#include <asm/traps.h>
> +
> +        .global handle_exception
> +        .align 4
> +
> +handle_exception:
> +
> +    /* Exceptions from xen */
> +save_to_stack:
> +        /* Save context to stack */
> +        REG_S   sp, (RISCV_CPU_USER_REGS_OFFSET(sp) - RISCV_CPU_USER_REGS_SIZE) (sp)
> +        addi    sp, sp, -RISCV_CPU_USER_REGS_SIZE
> +        REG_S   t0, RISCV_CPU_USER_REGS_OFFSET(t0)(sp)
> +        j       save_context
> +
> +save_context:

Just curious: Why not simply fall through here, i.e. why the J which really
is a NOP in this case?

Jan
Andrew Cooper Jan. 23, 2023, 11:50 a.m. UTC | #3
On 20/01/2023 2:59 pm, Oleksii Kurochko wrote:
> diff --git a/xen/arch/riscv/entry.S b/xen/arch/riscv/entry.S
> new file mode 100644
> index 0000000000..f7d46f42bb
> --- /dev/null
> +++ b/xen/arch/riscv/entry.S
> @@ -0,0 +1,97 @@
> +#include <asm/asm.h>
> +#include <asm/processor.h>
> +#include <asm/riscv_encoding.h>
> +#include <asm/traps.h>
> +
> +        .global handle_exception
> +        .align 4
> +
> +handle_exception:

ENTRY() which takes care of the global and the align.

Also, you want a size and type at the end, just like in head.S  (Sorry,
we *still* don't have any sane infrastructure for doing that nicely. 
Opencode it for now.)

> +
> +    /* Exceptions from xen */
> +save_to_stack:

This label isn't used at all, is it?

> +        /* Save context to stack */
> +        REG_S   sp, (RISCV_CPU_USER_REGS_OFFSET(sp) - RISCV_CPU_USER_REGS_SIZE) (sp)
> +        addi    sp, sp, -RISCV_CPU_USER_REGS_SIZE
> +        REG_S   t0, RISCV_CPU_USER_REGS_OFFSET(t0)(sp)

Exceptions on RISC-V don't adjust the stack pointer.  This logic depends
on interrupting Xen code, and Xen not having suffered a stack overflow
(and actually, that the space on the stack for all registers also
doesn't overflow).

Which might be fine for now, but I think it warrants a comment somewhere
(probably at handle_exception itself) stating the expectations while
it's still a work in progress.  So in this case something like:

/* Work-in-progress:  Depends on interrupting Xen, and the stack being
good. */


But, do we want to allocate stemp right away (even with an empty
struct), and get tp set up properly?

That said, aren't we going to have to rewrite this when enabling H mode
anyway?

> +        j       save_context
> +
> +save_context:

I'd drop this.  It's a nop right now.

> <snip>
> +        csrr    t0, CSR_SEPC
> +        REG_S   t0, RISCV_CPU_USER_REGS_OFFSET(sepc)(sp)
> +        csrr    t0, CSR_SSTATUS
> +        REG_S   t0, RISCV_CPU_USER_REGS_OFFSET(sstatus)(sp)

So something I've noticed about CSRs through this series.

The C CSR macros are set up to use real CSR names, but the CSR_*
constants used in C and ASM are raw numbers.

If we're using raw numbers, then the C CSR accessors should be static
inlines instead, but the advantage of using names is the toolchain can
issue an error when we reference a CSR not supported by the current
extensions.

We ought to use a single form, consistently through Xen.  How feasible
will it be to use names throughout?

~Andrew
Jan Beulich Jan. 23, 2023, 12:41 p.m. UTC | #4
On 23.01.2023 12:50, Andrew Cooper wrote:
> On 20/01/2023 2:59 pm, Oleksii Kurochko wrote:
>> +        csrr    t0, CSR_SEPC
>> +        REG_S   t0, RISCV_CPU_USER_REGS_OFFSET(sepc)(sp)
>> +        csrr    t0, CSR_SSTATUS
>> +        REG_S   t0, RISCV_CPU_USER_REGS_OFFSET(sstatus)(sp)
> 
> So something I've noticed about CSRs through this series.
> 
> The C CSR macros are set up to use real CSR names, but the CSR_*
> constants used in C and ASM are raw numbers.
> 
> If we're using raw numbers, then the C CSR accessors should be static
> inlines instead, but the advantage of using names is the toolchain can
> issue an error when we reference a CSR not supported by the current
> extensions.

That's a default-off diagnostic iirc, so we'd gain something here only
when explicitly turning that on as well.

Jan
Oleksii Kurochko Jan. 23, 2023, 3:04 p.m. UTC | #5
On Mon, 2023-01-23 at 12:17 +0100, Jan Beulich wrote:
> On 20.01.2023 15:59, Oleksii Kurochko wrote:
> > --- /dev/null
> > +++ b/xen/arch/riscv/entry.S
> > @@ -0,0 +1,97 @@
> > +#include <asm/asm.h>
> > +#include <asm/processor.h>
> > +#include <asm/riscv_encoding.h>
> > +#include <asm/traps.h>
> > +
> > +        .global handle_exception
> > +        .align 4
> > +
> > +handle_exception:
> > +
> > +    /* Exceptions from xen */
> > +save_to_stack:
> > +        /* Save context to stack */
> > +        REG_S   sp, (RISCV_CPU_USER_REGS_OFFSET(sp) -
> > RISCV_CPU_USER_REGS_SIZE) (sp)
> > +        addi    sp, sp, -RISCV_CPU_USER_REGS_SIZE
> > +        REG_S   t0, RISCV_CPU_USER_REGS_OFFSET(t0)(sp)
> > +        j       save_context
> > +
> > +save_context:
> 
> Just curious: Why not simply fall through here, i.e. why the J which
> really
> is a NOP in this case?
> 
There is no any specific reason.
I left it for future.
Will remove it in the next patch version.
> Jan
Oleksii Kurochko Jan. 23, 2023, 3:17 p.m. UTC | #6
On Mon, 2023-01-23 at 11:50 +0000, Andrew Cooper wrote:
> On 20/01/2023 2:59 pm, Oleksii Kurochko wrote:
> > diff --git a/xen/arch/riscv/entry.S b/xen/arch/riscv/entry.S
> > new file mode 100644
> > index 0000000000..f7d46f42bb
> > --- /dev/null
> > +++ b/xen/arch/riscv/entry.S
> > @@ -0,0 +1,97 @@
> > +#include <asm/asm.h>
> > +#include <asm/processor.h>
> > +#include <asm/riscv_encoding.h>
> > +#include <asm/traps.h>
> > +
> > +        .global handle_exception
> > +        .align 4
> > +
> > +handle_exception:
> 
> ENTRY() which takes care of the global and the align.
> 
> Also, you want a size and type at the end, just like in head.S 
> (Sorry,
> we *still* don't have any sane infrastructure for doing that nicely. 
> Opencode it for now.)
> 
> > +
> > +    /* Exceptions from xen */
> > +save_to_stack:
> 
> This label isn't used at all, is it?
> 
> > +        /* Save context to stack */
> > +        REG_S   sp, (RISCV_CPU_USER_REGS_OFFSET(sp) -
> > RISCV_CPU_USER_REGS_SIZE) (sp)
> > +        addi    sp, sp, -RISCV_CPU_USER_REGS_SIZE
> > +        REG_S   t0, RISCV_CPU_USER_REGS_OFFSET(t0)(sp)
> 
> Exceptions on RISC-V don't adjust the stack pointer.  This logic
> depends
> on interrupting Xen code, and Xen not having suffered a stack
> overflow
> (and actually, that the space on the stack for all registers also
> doesn't overflow).
> 
> Which might be fine for now, but I think it warrants a comment
> somewhere
> (probably at handle_exception itself) stating the expectations while
> it's still a work in progress.  So in this case something like:
> 
> /* Work-in-progress:  Depends on interrupting Xen, and the stack
> being
> good. */
> 
> 
> But, do we want to allocate stemp right away (even with an empty
> struct), and get tp set up properly?
> 
I am not sure that I get you here about stemp. Could you please clarify
a little bit.

> That said, aren't we going to have to rewrite this when enabling H
> mode
> anyway?
I based these code on a code from Bobby's repo ( on top of which with
some additional patches I've successfully ran Dom0 ) so I am not sure
that it will be re-written.
Probably I don't understand about which one part you are talking about.

Regarding H mode if to be honest I didn't see where it is switched to
it.
Maybe Bobby or Alistair can explain me?
> 
> > +        j       save_context
> > +
> > +save_context:
> 
> I'd drop this.  It's a nop right now.
> 
> > <snip>
> > +        csrr    t0, CSR_SEPC
> > +        REG_S   t0, RISCV_CPU_USER_REGS_OFFSET(sepc)(sp)
> > +        csrr    t0, CSR_SSTATUS
> > +        REG_S   t0, RISCV_CPU_USER_REGS_OFFSET(sstatus)(sp)
> 
> So something I've noticed about CSRs through this series.
> 
> The C CSR macros are set up to use real CSR names, but the CSR_*
> constants used in C and ASM are raw numbers.
> 
> If we're using raw numbers, then the C CSR accessors should be static
> inlines instead, but the advantage of using names is the toolchain
> can
> issue an error when we reference a CSR not supported by the current
> extensions.
> 
> We ought to use a single form, consistently through Xen.  How
> feasible
> will it be to use names throughout?
> 
> ~Andrew
Andrew Cooper Jan. 23, 2023, 8:09 p.m. UTC | #7
On 23/01/2023 3:17 pm, Oleksii wrote:
> On Mon, 2023-01-23 at 11:50 +0000, Andrew Cooper wrote:
>> On 20/01/2023 2:59 pm, Oleksii Kurochko wrote:
>>> +        /* Save context to stack */
>>> +        REG_S   sp, (RISCV_CPU_USER_REGS_OFFSET(sp) -
>>> RISCV_CPU_USER_REGS_SIZE) (sp)
>>> +        addi    sp, sp, -RISCV_CPU_USER_REGS_SIZE
>>> +        REG_S   t0, RISCV_CPU_USER_REGS_OFFSET(t0)(sp)
>> Exceptions on RISC-V don't adjust the stack pointer.  This logic
>> depends
>> on interrupting Xen code, and Xen not having suffered a stack
>> overflow
>> (and actually, that the space on the stack for all registers also
>> doesn't overflow).
>>
>> Which might be fine for now, but I think it warrants a comment
>> somewhere
>> (probably at handle_exception itself) stating the expectations while
>> it's still a work in progress.  So in this case something like:
>>
>> /* Work-in-progress:  Depends on interrupting Xen, and the stack
>> being
>> good. */
>>
>>
>> But, do we want to allocate stemp right away (even with an empty
>> struct), and get tp set up properly?
>>
> I am not sure that I get you here about stemp. Could you please clarify
> a little bit.

Sorry - sscratch, not stemp - I got the name wrong.

All registers are the interrupted context, not Xen's context.  This
includes the stack pointer, global pointer, and thread pointer.

Trap setup is supposed to stash Xen's tp in sscratch so on an
interrupt/exception, it can exchange sscratch with tp and recover the
stack pointer.

Linux plays games with having sscratch be 0 while in kernel and uses
this to determine whether the exception occurred in kernel or user
mode.  This is massive can of re-entrancy bugs that appears to be baked
into the architecture.

I genuinely can't figure out a safe way to cope with a stack overflow,
or a bad tp, because it is not safe to a pagefault until the exception
prologue has completed.  If you do, you'll switch back to the
interrupted task's tp and use that as if it were Xen's.

~Andrew
Oleksii Kurochko Jan. 25, 2023, 2:44 p.m. UTC | #8
On Mon, 2023-01-23 at 11:50 +0000, Andrew Cooper wrote:
> 
> 
> > +        /* Save context to stack */
> > +        REG_S   sp, (RISCV_CPU_USER_REGS_OFFSET(sp) -
> > RISCV_CPU_USER_REGS_SIZE) (sp)
> > +        addi    sp, sp, -RISCV_CPU_USER_REGS_SIZE
> > +        REG_S   t0, RISCV_CPU_USER_REGS_OFFSET(t0)(sp)
> 
> Exceptions on RISC-V don't adjust the stack pointer.  This logic
> depends
> on interrupting Xen code, and Xen not having suffered a stack
> overflow
> (and actually, that the space on the stack for all registers also
> doesn't overflow).
> 
Probably I missed something but an idea of the code above was to
reserve memory on a stack to save the registers which can be changed
in __handler_expception() as the line of code where exception occurs
will expect that registers value weren't changed.
Otherwise if we won't reserve memory on stack it will be corrupted by
REG_S which basically is SD instruction.
diff mbox series

Patch

diff --git a/xen/arch/riscv/Makefile b/xen/arch/riscv/Makefile
index 1a4f1a6015..443f6bf15f 100644
--- a/xen/arch/riscv/Makefile
+++ b/xen/arch/riscv/Makefile
@@ -1,7 +1,9 @@ 
 obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+obj-y += entry.o
 obj-$(CONFIG_RISCV_64) += riscv64/
 obj-y += sbi.o
 obj-y += setup.o
+obj-y += traps.o
 
 $(TARGET): $(TARGET)-syms
 	$(OBJCOPY) -O binary -S $< $@
diff --git a/xen/arch/riscv/entry.S b/xen/arch/riscv/entry.S
new file mode 100644
index 0000000000..f7d46f42bb
--- /dev/null
+++ b/xen/arch/riscv/entry.S
@@ -0,0 +1,97 @@ 
+#include <asm/asm.h>
+#include <asm/processor.h>
+#include <asm/riscv_encoding.h>
+#include <asm/traps.h>
+
+        .global handle_exception
+        .align 4
+
+handle_exception:
+
+    /* Exceptions from xen */
+save_to_stack:
+        /* Save context to stack */
+        REG_S   sp, (RISCV_CPU_USER_REGS_OFFSET(sp) - RISCV_CPU_USER_REGS_SIZE) (sp)
+        addi    sp, sp, -RISCV_CPU_USER_REGS_SIZE
+        REG_S   t0, RISCV_CPU_USER_REGS_OFFSET(t0)(sp)
+        j       save_context
+
+save_context:
+        /* Save registers */
+        REG_S   ra, RISCV_CPU_USER_REGS_OFFSET(ra)(sp)
+        REG_S   gp, RISCV_CPU_USER_REGS_OFFSET(gp)(sp)
+        REG_S   t1, RISCV_CPU_USER_REGS_OFFSET(t1)(sp)
+        REG_S   t2, RISCV_CPU_USER_REGS_OFFSET(t2)(sp)
+        REG_S   s0, RISCV_CPU_USER_REGS_OFFSET(s0)(sp)
+        REG_S   s1, RISCV_CPU_USER_REGS_OFFSET(s1)(sp)
+        REG_S   a0, RISCV_CPU_USER_REGS_OFFSET(a0)(sp)
+        REG_S   a1, RISCV_CPU_USER_REGS_OFFSET(a1)(sp)
+        REG_S   a2, RISCV_CPU_USER_REGS_OFFSET(a2)(sp)
+        REG_S   a3, RISCV_CPU_USER_REGS_OFFSET(a3)(sp)
+        REG_S   a4, RISCV_CPU_USER_REGS_OFFSET(a4)(sp)
+        REG_S   a5, RISCV_CPU_USER_REGS_OFFSET(a5)(sp)
+        REG_S   a6, RISCV_CPU_USER_REGS_OFFSET(a6)(sp)
+        REG_S   a7, RISCV_CPU_USER_REGS_OFFSET(a7)(sp)
+        REG_S   s2, RISCV_CPU_USER_REGS_OFFSET(s2)(sp)
+        REG_S   s3, RISCV_CPU_USER_REGS_OFFSET(s3)(sp)
+        REG_S   s4, RISCV_CPU_USER_REGS_OFFSET(s4)(sp)
+        REG_S   s5, RISCV_CPU_USER_REGS_OFFSET(s5)(sp)
+        REG_S   s6, RISCV_CPU_USER_REGS_OFFSET(s6)(sp)
+        REG_S   s7, RISCV_CPU_USER_REGS_OFFSET(s7)(sp)
+        REG_S   s8, RISCV_CPU_USER_REGS_OFFSET(s8)(sp)
+        REG_S   s9, RISCV_CPU_USER_REGS_OFFSET(s9)(sp)
+        REG_S   s10, RISCV_CPU_USER_REGS_OFFSET(s10)(sp)
+        REG_S   s11, RISCV_CPU_USER_REGS_OFFSET(s11)(sp)
+        REG_S   t3, RISCV_CPU_USER_REGS_OFFSET(t3)(sp)
+        REG_S   t4, RISCV_CPU_USER_REGS_OFFSET(t4)(sp)
+        REG_S   t5, RISCV_CPU_USER_REGS_OFFSET(t5)(sp)
+        REG_S   t6, RISCV_CPU_USER_REGS_OFFSET(t6)(sp)
+        csrr    t0, CSR_SEPC
+        REG_S   t0, RISCV_CPU_USER_REGS_OFFSET(sepc)(sp)
+        csrr    t0, CSR_SSTATUS
+        REG_S   t0, RISCV_CPU_USER_REGS_OFFSET(sstatus)(sp)
+
+        mv      a0, sp
+        jal     __handle_exception
+
+restore_registers:
+        /* Restore stack_cpu_regs */
+        REG_L   t0, RISCV_CPU_USER_REGS_OFFSET(sepc)(sp)
+        csrw    CSR_SEPC, t0
+        REG_L   t0, RISCV_CPU_USER_REGS_OFFSET(sstatus)(sp)
+        csrw    CSR_SSTATUS, t0
+
+        REG_L   ra, RISCV_CPU_USER_REGS_OFFSET(ra)(sp)
+        REG_L   gp, RISCV_CPU_USER_REGS_OFFSET(gp)(sp)
+        REG_L   t0, RISCV_CPU_USER_REGS_OFFSET(t0)(sp)
+        REG_L   t1, RISCV_CPU_USER_REGS_OFFSET(t1)(sp)
+        REG_L   t2, RISCV_CPU_USER_REGS_OFFSET(t2)(sp)
+        REG_L   s0, RISCV_CPU_USER_REGS_OFFSET(s0)(sp)
+        REG_L   s1, RISCV_CPU_USER_REGS_OFFSET(s1)(sp)
+        REG_L   a0, RISCV_CPU_USER_REGS_OFFSET(a0)(sp)
+        REG_L   a1, RISCV_CPU_USER_REGS_OFFSET(a1)(sp)
+        REG_L   a2, RISCV_CPU_USER_REGS_OFFSET(a2)(sp)
+        REG_L   a3, RISCV_CPU_USER_REGS_OFFSET(a3)(sp)
+        REG_L   a4, RISCV_CPU_USER_REGS_OFFSET(a4)(sp)
+        REG_L   a5, RISCV_CPU_USER_REGS_OFFSET(a5)(sp)
+        REG_L   a6, RISCV_CPU_USER_REGS_OFFSET(a6)(sp)
+        REG_L   a7, RISCV_CPU_USER_REGS_OFFSET(a7)(sp)
+        REG_L   s2, RISCV_CPU_USER_REGS_OFFSET(s2)(sp)
+        REG_L   s3, RISCV_CPU_USER_REGS_OFFSET(s3)(sp)
+        REG_L   s4, RISCV_CPU_USER_REGS_OFFSET(s4)(sp)
+        REG_L   s5, RISCV_CPU_USER_REGS_OFFSET(s5)(sp)
+        REG_L   s6, RISCV_CPU_USER_REGS_OFFSET(s6)(sp)
+        REG_L   s7, RISCV_CPU_USER_REGS_OFFSET(s7)(sp)
+        REG_L   s8, RISCV_CPU_USER_REGS_OFFSET(s8)(sp)
+        REG_L   s9, RISCV_CPU_USER_REGS_OFFSET(s9)(sp)
+        REG_L   s10, RISCV_CPU_USER_REGS_OFFSET(s10)(sp)
+        REG_L   s11, RISCV_CPU_USER_REGS_OFFSET(s11)(sp)
+        REG_L   t3, RISCV_CPU_USER_REGS_OFFSET(t3)(sp)
+        REG_L   t4, RISCV_CPU_USER_REGS_OFFSET(t4)(sp)
+        REG_L   t5, RISCV_CPU_USER_REGS_OFFSET(t5)(sp)
+        REG_L   t6, RISCV_CPU_USER_REGS_OFFSET(t6)(sp)
+
+        /* Restore sp */
+        REG_L   sp, RISCV_CPU_USER_REGS_OFFSET(sp)(sp)
+
+        sret
diff --git a/xen/arch/riscv/include/asm/traps.h b/xen/arch/riscv/include/asm/traps.h
new file mode 100644
index 0000000000..816ab1178a
--- /dev/null
+++ b/xen/arch/riscv/include/asm/traps.h
@@ -0,0 +1,13 @@ 
+#ifndef __ASM_TRAPS_H__
+#define __ASM_TRAPS_H__
+
+#include <asm/processor.h>
+
+#ifndef __ASSEMBLY__
+
+void __handle_exception(struct cpu_user_regs *cpu_regs);
+void handle_exception(void);
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_TRAPS_H__ */
diff --git a/xen/arch/riscv/traps.c b/xen/arch/riscv/traps.c
new file mode 100644
index 0000000000..3201b851ef
--- /dev/null
+++ b/xen/arch/riscv/traps.c
@@ -0,0 +1,13 @@ 
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2023 Vates
+ *
+ * RISC-V Trap handlers
+ */
+#include <asm/processor.h>
+#include <asm/traps.h>
+
+void __handle_exception(struct cpu_user_regs *cpu_regs)
+{
+    wait_for_interrupt();
+}