Stack initialisation in RISCV

483 views
Skip to first unread message

Abhav S Velidi.

unread,
Jul 11, 2023, 10:00:06 AM7/11/23
to RISC-V SW Dev
Hi everyone,
Had a few queries regarding stack initialisation. 
When in user mode a stack gets created to cater for user mode, let us assume a trap has occurred due to which the mode is switched to machine mode. The mscratch register points to a memory location where we can store the general purpose registers before we switch to machine mode.
1) Is this memory location(pointed by mscratch) present in the stack allotted for machine mode? 
2) If so how are the stack pointer and base pointer of the user mode stack stored?

Thank you in advance!!!

Bruce Hoult

unread,
Jul 13, 2023, 8:49:00 AM7/13/23
to Abhav S Velidi., RISC-V SW Dev
On Wed, Jul 12, 2023 at 2:00 AM 'Abhav S Velidi.' via RISC-V SW Dev <sw-...@groups.riscv.org> wrote:
Hi everyone,
Had a few queries regarding stack initialisation. 
When in user mode a stack gets created to cater for user mode,

OK, fine. You set up a stack in the user mode program using some X register as a stack pointer.
 

let us assume a trap has occurred due to which the mode is switched to machine mode.

ok.

 
The mscratch register points to a memory location where we can store the general purpose registers...

Your M-mode code previously set up mscratch to point to such a range of memory, ok.

 
... before we switch to machine mode.

What? No. Switching to machine mode simply switched to machine mode. It doesn't save any registers. Not at the address pointed to by mscratch -- you can put ANYTHING YOU WANT in mscratch. Not on a stack -- RISC-V does not have the concept of a stack in the instruction set.

 
1) Is this memory location(pointed by mscratch) present in the stack allotted for machine mode? 

What mscratch points to -- if it is even a pointer, which it doesn't have to be -- is entirely up to you, the M mode programmer.

The contents of mscratch might even be junk.  It would be perfectly valid for a trap handler to swap ... I don't know ... x23 ... with mscratch, then use LUI./ADDI to load a memory address into x23 and then use offsets from x23 to save some or all of the other registers.

 
2) If so how are the stack pointer and base pointer of the user mode stack stored?

The RISC-V ISA does not have a stack pointer or base pointer.

You might implement such a concept in your code, using some X register(s) of your choice, but the hardware knows nothing about that.

Also M mode can't assume that U mode code has any concept of a stack, or if so what one or more registers it might use as stack pointers.

 
Thank you in advance!!!

--
You received this message because you are subscribed to the Google Groups "RISC-V SW Dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sw-dev+un...@groups.riscv.org.
To view this discussion on the web visit https://groups.google.com/a/groups.riscv.org/d/msgid/sw-dev/f3073796-74ec-496b-9222-161d4cd61eb7n%40groups.riscv.org.

Valentin Nechayev

unread,
Nov 10, 2023, 2:34:11 AM11/10/23
to Abhav S Velidi., RISC-V SW Dev
hi,

Tue, Jul 11, 2023 at 07:00:06, sw-dev wrote about "[sw-dev] Stack initialisation in RISCV":

> Hi everyone,
> Had a few queries regarding stack initialisation.
> When in user mode a stack gets created to cater for user mode, let us
> assume a trap has occurred due to which the mode is switched to machine
> mode. The mscratch register points to a memory location where we can store
> the general purpose registers before we switch to machine mode.
> 1) Is this memory location(pointed by mscratch) present in the stack
> allotted for machine mode?

Itʼs fully a style issue. You may do this way or just extract stack
pointer from it and push everything to save onto stack.
Using mscratch for the current task kernel land stack pointer is at
least simple and handy.

> 2) If so how are the stack pointer and base pointer of the user mode stack
> stored?

Really, this is a kind of basic tutorial of trap implementation, but
letʼs recall it, while there is a pack of time and mood :)

CSRRW is the instruction to _exchange_ CSR and a register. Using "csrrw
sp,mscratch,sp" in a handler prologue, you will put userland stack
pointer to mscratch and extract your (machine land) stack pointer from
it. Then all other registers will be pushed to this stack. Just provide
a guarantee before switch to user land that the stack is present,
properly allocated and have enough size (a few kilobytes, at
least).

Of course, this is not the only variant. You may also use a more
generic structure like this (assume RV64):

struct trap_handler_save_area {
uint64_t saved_x9; // x9 is selected arbitrarily
uint64_t saved_sp;
uint64_t new_sp;
(...anything else needed to describe the current task,
for example, process and thread structure pointers...)
};

and in a prologue:

csrrw x9,mscratch,x9
sd sp,8(x9)
ld sp,16(x9)
addi sp,-8
sd x9,0(sp) ; save it onto stack and release for regular use

Just donʼt forget to do the reverse steps in epilogue before exit.

More variants with more indirection are possible, but, as having a
single mscratch is enough to implement full save/restore functionality
independently of used addresses, the standard spec does not provide
more CSRs to support this.

PS1: In case of guaranteedly a single hart, you may use lowest RAM
addresses (0-2047) for a fixed save/restore area, with commands like "sd
sp,104(0)". But this is not extendable to multiple harts. A platform
(SystemZ) which follows the legacy of this manner uses a per-hart
mapping of such a low address area according to, in RV terms, CSR.

PS2: Some implementations (Iʼve read of GD32VF103) implement
"mscratchcsw" CSR so exchange with it does nothing in M-mode but real
exchange otherwise. This is a nice trick to avoid having a separate
stack, and follows the manner of stack-based interrupt handling ISAs
(ARM, PDP-11, etc.); but it is not that inevitable to require
everywhere.


-netch-
Reply all
Reply to author
Forward
0 new messages