xv6-riscv-kernel/kernel/trampoline.S

159 lines
4.1 KiB
ArmAsm
Raw Permalink Normal View History

# For a quick reference on RISC-V assembly:
# https://risc-v.guru/instructions/
# Trampoline code
#
# low-level code to handle traps from user space into
# the kernel, and returns from kernel to user.
#
# the kernel maps the page holding this code
# at the same virtual address (TRAMPOLINE)
# in user and kernel space so that it continues
# to work when it switches page tables.
# kernel.ld causes this code to start at
# a page boundary.
#include "riscv.h"
#include "memlayout.h"
2022-08-22 19:49:15 +02:00
.section trampsec
2019-07-26 10:53:46 +02:00
.globl trampoline
trampoline:
.align 4
2019-07-26 10:53:46 +02:00
.globl uservec
uservec:
2019-05-31 15:45:59 +02:00
#
# trap.c sets stvec to point here, so
# traps from user space start here,
2019-05-31 15:45:59 +02:00
# in supervisor mode, but with a
# user page table.
#
# save user a0 in sscratch so
# a0 can be used to get at TRAPFRAME.
2024-08-07 14:25:27 +02:00
# CSRW = Control and Status Register Write
csrw sscratch, a0 # Save the userspace a0 in sscratch
# each process has a separate p->trapframe memory area,
# but it's mapped to the same virtual address
2022-08-22 19:49:15 +02:00
# (TRAPFRAME) in every process's user page table.
li a0, TRAPFRAME
2024-08-07 14:25:27 +02:00
# INFO: To see the layout of TRAPFRAME, see: proc.h
2019-07-26 16:17:02 +02:00
# save the user registers in TRAPFRAME
sd ra, 40(a0)
sd sp, 48(a0)
sd gp, 56(a0)
sd tp, 64(a0)
sd t0, 72(a0)
sd t1, 80(a0)
sd t2, 88(a0)
sd s0, 96(a0)
sd s1, 104(a0)
2024-08-07 14:25:27 +02:00
// Note that we dont save a0
sd a1, 120(a0)
sd a2, 128(a0)
sd a3, 136(a0)
sd a4, 144(a0)
sd a5, 152(a0)
sd a6, 160(a0)
sd a7, 168(a0)
sd s2, 176(a0)
sd s3, 184(a0)
sd s4, 192(a0)
sd s5, 200(a0)
sd s6, 208(a0)
sd s7, 216(a0)
sd s8, 224(a0)
sd s9, 232(a0)
sd s10, 240(a0)
sd s11, 248(a0)
sd t3, 256(a0)
sd t4, 264(a0)
sd t5, 272(a0)
sd t6, 280(a0)
2019-05-31 15:45:59 +02:00
# save the user a0 in p->trapframe->a0
2024-08-07 14:25:27 +02:00
# CSRR = Control and Status Register Read
csrr t0, sscratch # Get the userspace a0 from where we stored it before
sd t0, 112(a0) # Store userspace a0 in p->trapframe->a0
2019-05-31 15:45:59 +02:00
2022-08-22 19:49:15 +02:00
# initialize kernel stack pointer, from p->trapframe->kernel_sp
2019-05-31 15:45:59 +02:00
ld sp, 8(a0)
# make tp hold the current hartid, from p->trapframe->kernel_hartid
2019-06-05 17:42:03 +02:00
ld tp, 32(a0)
2022-08-22 19:49:15 +02:00
# load the address of usertrap(), from p->trapframe->kernel_trap
2019-05-31 15:45:59 +02:00
ld t0, 16(a0)
2022-08-24 19:47:47 +02:00
# fetch the kernel page table address, from p->trapframe->kernel_satp.
2019-05-31 15:45:59 +02:00
ld t1, 0(a0)
2022-08-24 19:47:47 +02:00
# wait for any previous memory operations to complete, so that
# they use the user page table.
sfence.vma zero, zero
2022-08-24 19:47:47 +02:00
# install the kernel page table.
2019-05-31 15:45:59 +02:00
csrw satp, t1
2022-08-24 19:47:47 +02:00
2024-08-07 14:25:27 +02:00
# flush now-stale user entries from the TLB (Translation Lookaside Buffer)
2019-09-03 22:29:48 +02:00
sfence.vma zero, zero
2019-05-31 15:45:59 +02:00
# jump to usertrap(), which does not return
jr t0
.globl userret
userret:
# userret(pagetable)
2022-08-22 19:49:15 +02:00
# called by usertrapret() in trap.c to
# switch from kernel to user.
# a0: user page table, for satp.
2019-09-03 22:29:48 +02:00
# switch to the user page table.
sfence.vma zero, zero
csrw satp, a0
2019-09-03 22:29:48 +02:00
sfence.vma zero, zero
li a0, TRAPFRAME
2019-07-26 16:17:02 +02:00
# restore all but a0 from TRAPFRAME
ld ra, 40(a0)
ld sp, 48(a0)
ld gp, 56(a0)
ld tp, 64(a0)
ld t0, 72(a0)
ld t1, 80(a0)
ld t2, 88(a0)
ld s0, 96(a0)
ld s1, 104(a0)
ld a1, 120(a0)
ld a2, 128(a0)
ld a3, 136(a0)
ld a4, 144(a0)
ld a5, 152(a0)
ld a6, 160(a0)
ld a7, 168(a0)
ld s2, 176(a0)
ld s3, 184(a0)
ld s4, 192(a0)
ld s5, 200(a0)
ld s6, 208(a0)
ld s7, 216(a0)
ld s8, 224(a0)
ld s9, 232(a0)
ld s10, 240(a0)
ld s11, 248(a0)
ld t3, 256(a0)
ld t4, 264(a0)
ld t5, 272(a0)
ld t6, 280(a0)
# restore user a0
ld a0, 112(a0)
# return to user mode and user pc.
# usertrapret() set up sstatus and sepc.
sret