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