genode/repos/base-hw/src/core/spec/riscv/mode_transition.s

269 lines
4.7 KiB
ArmAsm

/*
* \brief Transition between kernel/userland
* \date 2011-11-15
*/
/*
* Copyright (C) 2011-2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
.set USER_MODE, 0
.set SUPERVISOR_MODE, 1
.set MACHINE_MODE, 3
.set CALL_PUT_CHAR, 0xff
.set CPU_IP, 0
.set CPU_EXCEPTION, 8
.set CPU_X1, 2*8
.set CPU_SP, 3*8
.set CPU_SASID, 33*8
.set CPU_SPTBR, 34*8
.macro _save_scratch_registers mode
.if \mode == USER_MODE
csrrw sp, mscratch, sp
.endif
addi sp, sp, -24
sd t0, 0(sp)
sd t1, 8(sp)
sd t2, 16(sp)
.endm
.macro _restore_scratch_registers mode
ld t0, 0(sp)
ld t1, 8(sp)
ld t2, 16(sp)
addi sp, sp, 24
.if \mode == USER_MODE
csrrw sp, mscratch, sp
.endif
.endm
.macro _put_char mode
/* check if ecall (8 - 11) */
csrr t0, mcause
li t1, 8
bltu t0, t1, 9f
li t1, 12
bgtu t0, t1, 9f
/* check for put char ecall number */
li t1, CALL_PUT_CHAR
bne t1, a0, 9f
/* output character */
csrw mtohost, a1
1:
li t0, 0
csrrw t0, mfromhost, t0
beqz t0, 1b
/* advance epc */
csrr t0, mepc
addi t0, t0, 4
csrw mepc, t0
_restore_scratch_registers \mode
eret
9:
.endm
.section .text
/*
* Page aligned base of mode transition code.
*
* This position independent code switches between a kernel context and a
* user context and thereby between their address spaces. Due to the latter
* it must be mapped executable to the same region in every address space.
* To enable such switching, the kernel context must be stored within this
* region, thus one should map it solely accessable for privileged modes.
*/
.p2align 8
.global _machine_begin
_machine_begin:
/* 0x100 user mode */
j user_trap
.space 0x3c
/* 0x140 supervisor */
j supervisor_trap
.space 0x3c
/* 0x180 hypervisor */
1: j 1b
.space 0x3c
/* 0x1c0 machine */
j machine_trap
.space 0x38
/* 0x1fc non-maksable interrupt */
1: j 1b
user_trap:
_save_scratch_registers USER_MODE
_put_char USER_MODE
_restore_scratch_registers USER_MODE
mrts
supervisor_trap:
_save_scratch_registers SUPERVISOR_MODE
_put_char SUPERVISOR_MODE
j fault
machine_trap:
_save_scratch_registers MACHINE_MODE
_put_char MACHINE_MODE
j fault
fault:j fault /* TODO: handle trap from supervisor or machine mode */
.global _machine_end
_machine_end:
.p2align 12
.global _mt_begin
_mt_begin:
/* 0x100 user mode */
j _mt_kernel_entry_pic
.space 0x3c
/* 0x140 supervisor */
1: j 1b
.space 0x3c
/* 0x180 hypervisor */
1: j 1b
.space 0x3c
/* 0x1c0 machine */
1: j 1b
.space 0x38
/* 0x1fc non-maksable interrupt */
1: j 1b
/* space for a client context-pointer per CPU */
.p2align 2
.global _mt_client_context_ptr
_mt_client_context_ptr:
.space 8
/* space for a copy of the kernel context */
.global _mt_master_context_begin
_mt_master_context_begin:
/* space must be at least as large as 'Context' */
.space 35*8
.global _mt_master_context_end
_mt_master_context_end:
.global _mt_kernel_entry_pic
_mt_kernel_entry_pic:
/* master context */
csrrw x31, sscratch, x31
addi x31, x31, 8
/* save x29, x30 in master */
sd x29, CPU_X1 + 8 * 28(x31)
sd x30, CPU_X1 + 8 * 29(x31)
/* load kernel page table */
ld x29, CPU_SASID(x31)
ld x30, CPU_SPTBR(x31)
csrw sasid, x29
csrw sptbr, x30
/* save x29 - x31 in user context */
mv x29, x31
addi x29, x29, -8
ld x29, (x29)
.irp reg,29,30
ld x30, CPU_X1 + 8 * (\reg - 1)(x31)
sd x30, CPU_X1 + 8 * (\reg - 1)(x29)
.endr
csrr x30, sscratch /* x31 */
sd x30, CPU_X1 + 8 * 30(x29)
/* save x1 - x28 */
.irp reg,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28
sd x\reg, CPU_X1 + 8 * (\reg - 1)(x29)
.endr
/* trap reason */
csrr x30, scause
sd x30, CPU_EXCEPTION(x29)
/* ip */
csrr x30, sepc
sd x30, CPU_IP(x29)
/* load kernel stack and ip */
ld sp, CPU_SP(x31)
ld x30, CPU_IP(x31)
/* restore scratch */
addi x31, x31, -8
csrw sscratch, x31
jalr x30
.global _mt_user_entry_pic
_mt_user_entry_pic:
/* client context pointer */
csrr x30, sscratch
ld x30, (x30)
/* set return IP */
ld x31, CPU_IP(x30)
csrw sepc, x31
/* restore x1-x28 */
.irp reg,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28
ld x\reg, CPU_X1 + 8 * (\reg - 1)(x30)
.endr
/* save x29, x30, x31 to master context */
csrr x29, sscratch
addi x29, x29, 8 /* master context */
.irp reg,29,30,31
ld x31, CPU_X1 + 8 * (\reg - 1)(x30)
sd x31, CPU_X1 + 8 * (\reg - 1)(x29)
.endr
/* switch page table */
ld x31, CPU_SASID(x30)
ld x30, CPU_SPTBR(x30)
csrw sasid, x31
csrw sptbr, x30
/* restore x29 - x31 from master context */
.irp reg,31,30,29
ld x\reg, CPU_X1 + 8 * (\reg - 1)(x29)
.endr
eret
/* end of the mode transition code */
.global _mt_end
_mt_end: