@@ -156,18 +156,61 @@ fn set_pmp() {
156
156
// todo: 根据QEMU的loader device等等,设置这里的权限配置
157
157
// read fdt tree value, parse, and calculate proper pmp configuration for this device tree (issue #7)
158
158
// integrate with `count_harts`
159
- unsafe {
160
- asm ! (
161
- "li {tmp}, ((0x08 << 16) | (0x1F << 8) | (0x1F << 0) )" , // 0 = NAPOT,ARWX; 1 = NAPOT,ARWX; 2 = TOR,A;
162
- "csrw 0x3A0, {tmp}" ,
163
- "li {tmp}, ((0x0000000010001000 >> 2) | 0x3ff)" , // 0 = 0x0000000010001000-0x0000000010001fff
164
- "csrw 0x3B0, {tmp}" ,
165
- "li {tmp}, ((0x0000000080000000 >> 2) | 0x3ffffff)" , // 1 = 0x0000000080000000-0x000000008fffffff
166
- "csrw 0x3B1, {tmp}" ,
167
- "sfence.vma" ,
168
- tmp = out( reg) _
169
- )
159
+ //
160
+ // Qemu MMIO config ref: https://github.com/qemu/qemu/blob/master/hw/riscv/virt.c#L46
161
+ //
162
+ // About PMP:
163
+ //
164
+ // CSR: pmpcfg0(0x3A0)~pmpcfg15(0x3AF); pmpaddr0(0x3B0)~pmpaddr63(0x3EF)
165
+ // pmpcfg packs pmp entries each of which is of 8-bit
166
+ // on RV64 only even pmpcfg CSRs(0,2,...,14) are available, each of which contains 8 PMP
167
+ // entries
168
+ // every pmp entry and its corresponding pmpaddr describe a pmp region
169
+ //
170
+ // layout of PMP entries:
171
+ // ------------------------------------------------------
172
+ // 7 | [5:6] | [3:4] | 2 | 1 | 0 |
173
+ // L | 0(WARL) | A | X | W | R |
174
+ // ------------------------------------------------------
175
+ // A = OFF(0), disabled;
176
+ // A = TOR(top of range, 1), match address y so that pmpaddr_{i-1}<=y<pmpaddr_i irrespective of
177
+ // the value pmp entry i-1
178
+ // A = NA4(naturally aligned 4-byte region, 2), only support a 4-byte pmp region
179
+ // A = NAPOT(naturally aligned power-of-two region, 3), support a >=8-byte pmp region
180
+ // When using NAPOT to match a address range [S,S+L), then the pmpaddr_i should be set to (S>>2)|((L>>2)-1)
181
+ let calc_pmpaddr = |start_addr : usize , length : usize | {
182
+ ( start_addr >> 2 ) | ( ( length >> 2 ) - 1 )
170
183
} ;
184
+ let mut pmpcfg0: usize = 0 ;
185
+ // pmp region 0: RW, A=NAPOT, address range {0x1000_1000, 0x1000}, VIRT_VIRTIO
186
+ // address range {0x1000_0000, 0x100}, VIRT_UART0
187
+ // aligned address range {0x1000_0000, 0x2000}
188
+ pmpcfg0 |= 0b11011 ;
189
+ let pmpaddr0 = calc_pmpaddr ( 0x1000_0000 , 0x2000 ) ;
190
+ // pmp region 2: RW, A=NAPOT, address range {0x200_0000, 0x1_0000}, VIRT_CLINT
191
+ pmpcfg0 |= 0b11011 << 8 ;
192
+ let pmpaddr1 = calc_pmpaddr ( 0x200_0000 , 0x1_0000 ) ;
193
+ // pmp region 3: RW, A=NAPOT, address range {0xC00_0000, 0x40_0000}, VIRT_PLIC
194
+ // VIRT_PLIC_SIZE = 0x20_0000 + 0x1000 * harts, thus supports up to 512 harts
195
+ pmpcfg0 |= 0b11011 << 16 ;
196
+ let pmpaddr2 = calc_pmpaddr ( 0xC00_0000 , 0x40_0000 ) ;
197
+ // pmp region 4: RWX, A=NAPOT, address range {0x8000_0000, 0x1000_0000}, VIRT_DRAM
198
+ pmpcfg0 |= 0b11111 << 24 ;
199
+ let pmpaddr3 = calc_pmpaddr ( 0x8000_0000 , 0x1000_0000 ) ;
200
+ unsafe {
201
+ core:: arch:: asm!( "csrw pmpcfg0, {}" ,
202
+ "csrw pmpaddr0, {}" ,
203
+ "csrw pmpaddr1, {}" ,
204
+ "csrw pmpaddr2, {}" ,
205
+ "csrw pmpaddr3, {}" ,
206
+ "sfence.vma" ,
207
+ in( reg) pmpcfg0,
208
+ in( reg) pmpaddr0,
209
+ in( reg) pmpaddr1,
210
+ in( reg) pmpaddr2,
211
+ in( reg) pmpaddr3,
212
+ ) ;
213
+ }
171
214
}
172
215
173
216
#[ naked]
0 commit comments