aboutsummaryrefslogtreecommitdiff
path: root/isa/rv64ssvnapot/napot.S
blob: fbc4014dda639360e098dc51d6a0b93ecd6933e6 (plain)
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# See LICENSE for license details.

#*****************************************************************************
# napot.S
#-----------------------------------------------------------------------------
#
# Test Svnapot
#

#include "riscv_test.h"
#include "test_macros.h"

#if (DRAM_BASE >> 30 << 30) != DRAM_BASE
# error This test requires DRAM_BASE be SV39 superpage-aligned
#endif

#if __riscv_xlen != 64
# error This test requires RV64
#endif

RVTEST_RV64M
RVTEST_CODE_BEGIN

  # Construct the page table

#define MY_VA 0x40201010
  # VPN 2 == VPN 1 == VPN 0 == 0x1
  # Page offset == 0x10

  ####

  # Level 0 PTE contents

  # PPN
  la a0, my_data
  srl a0, a0, 12

  # adjust the PPN to be in NAPOT form
  li a1, ~0xF
  and a0, a0, a1
  ori a0, a0, 0x8

  # attributes
  sll a0, a0, PTE_PPN_SHIFT
  li a1, PTE_V | PTE_U | PTE_R | PTE_W | PTE_X | PTE_A | PTE_D | PTE_N
  or a0, a0, a1

  # Level 0 PTE address
  la a1, page_table
  addi a1, a1, ((MY_VA >> 12) & 0x1FF) * 8

  # Level 0 PTE store
  sd a0, (a1)

  ####

  # Level 1 PTE contents
  la a0, page_table
  srl a0, a0, 12
  sll a0, a0, PTE_PPN_SHIFT
  li a1, PTE_V
  or a0, a0, a1

  # Level 1 PTE address
  la a1, page_table
  addi a1, a1, ((MY_VA >> 21) & 0x1FF) * 8
  li a2, 1 << 12
  add a1, a1, a2

  # Level 1 PTE store
  sd a0, (a1)

  ####

  # Level 2 PTE contents
  la a0, page_table
  li a1, 1 << 12
  add a0, a0, a1
  srl a0, a0, 12
  sll a0, a0, PTE_PPN_SHIFT
  li a1, PTE_V
  or a0, a0, a1

  # Level 2 PTE address
  la a1, page_table
  addi a1, a1, ((MY_VA >> 30) & 0x1FF) * 8
  li a2, 2 << 12
  add a1, a1, a2

  # Level 2 PTE store
  sd a0, (a1)

  ####

  # Do a load from the PA that would be written if the PTE were misinterpreted as non-NAPOT
  la a0, my_data
  li a1, ~0xFFFF
  and a0, a0, a1
  li a1, 0x8000 | (MY_VA & 0xFFF)
  or a3, a0, a1
  li a1, 0
  sw a1, (a3)

  ####
  li TESTNUM, 1

  ## Turn on VM
  la a1, page_table
  li a2, 2 << 12
  add a1, a1, a2
  srl a1, a1, 12
  li a0, (SATP_MODE & ~(SATP_MODE<<1)) * SATP_MODE_SV39
  or a0, a0, a1
  csrw satp, a0
  sfence.vma

  # Set up MPRV with MPP=S and SUM=1, so loads and stores use S-mode and S can access U pages
  li a1, ((MSTATUS_MPP & ~(MSTATUS_MPP<<1)) * PRV_S) | MSTATUS_MPRV | MSTATUS_SUM
  csrs mstatus, a1

  # Do a store to MY_VA
  li a0, MY_VA
  li a1, 42
napot_store:
  sw a1, (a0)

  # Clear MPRV
  li a1, MSTATUS_MPRV
  csrc mstatus, a1

  # Do a load from the PA that would be written if the PTE were misinterpreted as non-NAPOT
  lw a1, (a3)

  # Check the result
  li a0, 42
  beq a1, a0, die

  # Do a load from the PA for MY_VA
  la a0, my_data
  li a1, MY_VA & 0xFFFF
  add a0, a0, a1
  lw a1, (a0)
  li a2, 42

  # Check the result
  bne a1, a2, die

  ####

  RVTEST_PASS

  TEST_PASSFAIL

  .align 2
  .global mtvec_handler
mtvec_handler:
  # Skip if Svnapot is not implemented.
  csrr t5, mcause
  li t6, CAUSE_STORE_PAGE_FAULT
  bne t5, t6, die
  csrr t5, mepc
  la t6, napot_store
  bne t5, t6, die
  csrr t5, mtval
  li t6, MY_VA
  beq t5, t6, pass
die:
  RVTEST_FAIL

RVTEST_CODE_END

  .data
RVTEST_DATA_BEGIN

  TEST_DATA

.align 20
page_table: .dword 0

.align 20
my_data: .dword 0

RVTEST_DATA_END