231 lines
5.9 KiB
ArmAsm
231 lines
5.9 KiB
ArmAsm
.option norvc
|
|
.option norelax
|
|
|
|
# ==================================================
|
|
# Text section
|
|
# ==================================================
|
|
.section .text
|
|
.globl _start
|
|
.globl vm_boot
|
|
|
|
_start:
|
|
vm_boot:
|
|
# --------------------------------------------------
|
|
# Only hart 0 runs
|
|
# --------------------------------------------------
|
|
csrr a0, mhartid
|
|
bnez a0, hang
|
|
|
|
# --------------------------------------------------
|
|
# Build page tables
|
|
# --------------------------------------------------
|
|
|
|
#
|
|
# Page table setup (Sv39) — binary + hex example
|
|
#
|
|
# Purpose:
|
|
# Build a VALID page table entry (PTE) in the root page table
|
|
# that points to the next-level page table (l1_pt).
|
|
#
|
|
# Assume:
|
|
# l1_pt physical address =
|
|
# binary: 00000000 10000000 01000000 00110000 00000000
|
|
# hex: 0x0000000080403000
|
|
# (page aligned, lower 12 bits = 0)
|
|
#
|
|
# Step-by-step instruction meaning:
|
|
#
|
|
# la t0, l1_pt
|
|
# Load physical address of l1_pt.
|
|
#
|
|
# t0 =
|
|
# binary: 00000000 10000000 01000000 00110000 00000000
|
|
# hex: 0x0000000080403000
|
|
#
|
|
# srli t0, t0, 12
|
|
# Drop 12-bit page offset → extract Physical Page Number (PPN).
|
|
#
|
|
# t0 (PPN) =
|
|
# binary: 00000000 00000000 10000000 01000000 0011
|
|
# hex: 0x0000000000080403
|
|
#
|
|
# slli t0, t0, 10
|
|
# Shift PPN into PTE bit positions [63:10].
|
|
# Bits [9:0] are flags.
|
|
#
|
|
# t0 =
|
|
# binary: 00000000 00000000 10000000 01000000 0011 0000000000
|
|
# hex: 0x0000000020100C00
|
|
#
|
|
# ori t0, t0, 1
|
|
# Set bit 0 (V = Valid).
|
|
#
|
|
# t0 (final PTE) =
|
|
# binary: 00000000 00000000 10000000 01000000 0011 0000000001
|
|
# hex: 0x0000000020100C01
|
|
#
|
|
# Memory effect:
|
|
#
|
|
# root_pt[0] =
|
|
# bit index:
|
|
# 63 10 9 0
|
|
# +----------------------------------+----------+
|
|
# | PPN = 0x0000000000080403 | V = 1 |
|
|
# +----------------------------------+----------+
|
|
#
|
|
# binary: 00000000 00000000 10000000 01000000 0011 0000000001
|
|
# hex: 0x0000000020100C01
|
|
#
|
|
# Result:
|
|
# Root page table entry 0 is VALID and points to l1_pt.
|
|
# The MMU uses this entry to continue the Sv39 page-table walk.
|
|
#
|
|
|
|
|
|
# root_pt[0] -> l1_pt
|
|
la t0, l1_pt
|
|
srli t0, t0, 12 # PPN
|
|
slli t0, t0, 10 # PTE format
|
|
ori t0, t0, 0x1 # V
|
|
la t1, root_pt
|
|
sd t0, 0(t1)
|
|
|
|
# l1_pt[0] -> l0_pt
|
|
la t0, l0_pt
|
|
srli t0, t0, 12
|
|
slli t0, t0, 10
|
|
ori t0, t0, 0x1 # V
|
|
la t1, l1_pt
|
|
sd t0, 0(t1)
|
|
|
|
# l0_pt[0] -> identity mapping (RWX)
|
|
li t0, (1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<6) # V R W X A
|
|
la t1, l0_pt
|
|
sd t0, 0(t1)
|
|
|
|
# --------------------------------------------------
|
|
# Enable Sv39 paging
|
|
# --------------------------------------------------
|
|
|
|
# Enable virtual memory (Sv39) — SATP setup diagram (binary)
|
|
#
|
|
# Assume:
|
|
# root_pt physical address =
|
|
# 00000000 10000000 01000000 00010000 00000000
|
|
# (4 KB aligned, lower 12 bits = 0)
|
|
#
|
|
# Instruction flow:
|
|
#
|
|
# la t0, root_pt
|
|
# t0 =
|
|
# 00000000 10000000 01000000 00010000 00000000
|
|
#
|
|
# srli t0, t0, 12 ; extract PPN
|
|
# t0 (PPN) =
|
|
# 00000000 00000000 10000000 01000000 0001
|
|
#
|
|
# li t1, (8 << 60) ; MODE = Sv39
|
|
# t1 =
|
|
# 1000 0000000000000000000000000000000000000000000000000000
|
|
# ^^^^
|
|
# MODE[63:60] = 1000 (Sv39)
|
|
#
|
|
# or t0, t0, t1
|
|
# satp value =
|
|
# 1000 0000000000000000000000000000000010000000010000000001
|
|
# |<-- MODE -->|<----------- ASID ---------->|<---- PPN ---->|
|
|
#
|
|
# csrw satp, t0
|
|
# satp register loaded:
|
|
#
|
|
# 63 60 59 44 43 0
|
|
# +------+----------------------------------+----------------+
|
|
# |1000 |0000000000000000 |0000000010000000010000000001|
|
|
# +------+----------------------------------+----------------+
|
|
# MODE=Sv39 ASID=0 root_pt PPN
|
|
#
|
|
# sfence.vma zero, zero
|
|
# Flush all TLB entries so new page tables are used
|
|
#
|
|
# Meaning:
|
|
# - Virtual memory enabled in Sv39 mode
|
|
# - Root page table base = root_pt
|
|
# - ASID = 0
|
|
# - MMU now performs 3-level page table walks
|
|
#
|
|
|
|
la t0, root_pt
|
|
srli t0, t0, 12
|
|
li t1, (8 << 60) # MODE=Sv39
|
|
or t0, t0, t1
|
|
csrw satp, t0
|
|
sfence.vma zero, zero
|
|
|
|
# --------------------------------------------------
|
|
# Write data to memory (safe area)
|
|
# --------------------------------------------------
|
|
la t2, test_buf
|
|
li t3, 0x1122334455667788
|
|
sd t3, 0(t2)
|
|
|
|
# --------------------------------------------------
|
|
# Read data back
|
|
# --------------------------------------------------
|
|
ld t4, 0(t2)
|
|
|
|
# Optional check (simple)
|
|
bne t3, t4, hang
|
|
|
|
# --------------------------------------------------
|
|
# Signal success
|
|
# --------------------------------------------------
|
|
la t0, tohost
|
|
li t1, 1
|
|
sd t1, 0(t0)
|
|
|
|
hang:
|
|
wfi
|
|
j hang
|
|
|
|
# ==================================================
|
|
# Required test symbol
|
|
# ==================================================
|
|
.globl exit
|
|
exit:
|
|
j exit
|
|
|
|
# ==================================================
|
|
# Data section
|
|
# ==================================================
|
|
.section .data
|
|
.align 3
|
|
|
|
.globl tohost
|
|
.globl fromhost
|
|
tohost:
|
|
.dword 0
|
|
fromhost:
|
|
.dword 0
|
|
|
|
# --------------------------------------------------
|
|
# Test buffer (safe data memory)
|
|
# --------------------------------------------------
|
|
.align 3
|
|
test_buf:
|
|
.zero 16
|
|
|
|
# --------------------------------------------------
|
|
# Page tables (must be 4 KiB each)
|
|
# --------------------------------------------------
|
|
.align 12
|
|
root_pt:
|
|
.zero 4096
|
|
|
|
.align 12
|
|
l1_pt:
|
|
.zero 4096
|
|
|
|
.align 12
|
|
l0_pt:
|
|
.zero 4096
|