Skip to content

Commit 3f200ac

Browse files
authored
Writing non-existent CSRs, access FPRs with mstatus.FS=0 (riscv-software-src#311)
* Don't corrupt s0 when abstract CSR write fails. * Support abstract FPR access then mstatus.FS=0 Discussion on the spec list leans towards this being a requirement. Certainly users want their debugger to be able to access all registers regardless of target state.
1 parent b1bde2b commit 3f200ac

File tree

7 files changed

+60
-16
lines changed

7 files changed

+60
-16
lines changed

debug_rom/debug_rom.S

+4
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ entry_loop:
4343
jal zero, entry_loop
4444

4545
_exception:
46+
// Restore S0, which we always save to dscratch.
47+
// We need this in case the user tried an abstract write to a
48+
// non-existent CSR.
49+
csrr s0, CSR_DSCRATCH
4650
sw zero, DEBUG_ROM_EXCEPTION(zero) // Let debug module know you got an exception.
4751
ebreak
4852

debug_rom/debug_rom.h

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
static const unsigned char debug_rom_raw[] = {
2-
0x6f, 0x00, 0xc0, 0x00, 0x6f, 0x00, 0xc0, 0x05, 0x6f, 0x00, 0x80, 0x03,
2+
0x6f, 0x00, 0xc0, 0x00, 0x6f, 0x00, 0x00, 0x06, 0x6f, 0x00, 0x80, 0x03,
33
0x0f, 0x00, 0xf0, 0x0f, 0x73, 0x10, 0x24, 0x7b, 0x73, 0x24, 0x40, 0xf1,
44
0x23, 0x20, 0x80, 0x10, 0x03, 0x44, 0x04, 0x40, 0x13, 0x74, 0x14, 0x00,
5-
0x63, 0x12, 0x04, 0x02, 0x73, 0x24, 0x40, 0xf1, 0x03, 0x44, 0x04, 0x40,
6-
0x13, 0x74, 0x24, 0x00, 0x63, 0x16, 0x04, 0x02, 0x73, 0x00, 0x50, 0x10,
7-
0x6f, 0xf0, 0x9f, 0xfd, 0x23, 0x26, 0x00, 0x10, 0x73, 0x00, 0x10, 0x00,
8-
0x73, 0x24, 0x40, 0xf1, 0x23, 0x22, 0x80, 0x10, 0x73, 0x24, 0x20, 0x7b,
9-
0x0f, 0x00, 0xf0, 0x0f, 0x0f, 0x10, 0x00, 0x00, 0x67, 0x00, 0x00, 0x30,
10-
0x73, 0x24, 0x40, 0xf1, 0x23, 0x24, 0x80, 0x10, 0x73, 0x24, 0x20, 0x7b,
11-
0x73, 0x00, 0x20, 0x7b
5+
0x63, 0x14, 0x04, 0x02, 0x73, 0x24, 0x40, 0xf1, 0x03, 0x44, 0x04, 0x40,
6+
0x13, 0x74, 0x24, 0x00, 0x63, 0x18, 0x04, 0x02, 0x73, 0x00, 0x50, 0x10,
7+
0x6f, 0xf0, 0x9f, 0xfd, 0x73, 0x24, 0x20, 0x7b, 0x23, 0x26, 0x00, 0x10,
8+
0x73, 0x00, 0x10, 0x00, 0x73, 0x24, 0x40, 0xf1, 0x23, 0x22, 0x80, 0x10,
9+
0x73, 0x24, 0x20, 0x7b, 0x0f, 0x00, 0xf0, 0x0f, 0x0f, 0x10, 0x00, 0x00,
10+
0x67, 0x00, 0x00, 0x30, 0x73, 0x24, 0x40, 0xf1, 0x23, 0x24, 0x80, 0x10,
11+
0x73, 0x24, 0x20, 0x7b, 0x73, 0x00, 0x20, 0x7b
1212
};
13-
static const unsigned int debug_rom_raw_len = 112;
13+
static const unsigned int debug_rom_raw_len = 116;

riscv/debug_module.cc

+32-2
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,12 @@ void debug_module_t::run_test_idle()
557557
}
558558
}
559559

560+
static bool is_fpu_reg(unsigned regno)
561+
{
562+
return (regno >= 0x1020 && regno <= 0x103f) || regno == CSR_FFLAGS ||
563+
regno == CSR_FRM || regno == CSR_FCSR;
564+
}
565+
560566
bool debug_module_t::perform_abstract_command()
561567
{
562568
if (abstractcs.cmderr != CMDERR_NONE)
@@ -580,8 +586,22 @@ bool debug_module_t::perform_abstract_command()
580586
unsigned i = 0;
581587
if (get_field(command, AC_ACCESS_REGISTER_TRANSFER)) {
582588

583-
if (regno < 0x1000 && config.support_abstract_csr_access) {
589+
if (is_fpu_reg(regno)) {
590+
// Save S0
584591
write32(debug_abstract, i++, csrw(S0, CSR_DSCRATCH));
592+
// Save mstatus
593+
write32(debug_abstract, i++, csrr(S0, CSR_MSTATUS));
594+
write32(debug_abstract, i++, csrw(S0, CSR_DSCRATCH + 1));
595+
// Set mstatus.fs
596+
assert((MSTATUS_FS & 0xfff) == 0);
597+
write32(debug_abstract, i++, lui(S0, MSTATUS_FS >> 12));
598+
write32(debug_abstract, i++, csrrs(ZERO, S0, CSR_MSTATUS));
599+
}
600+
601+
if (regno < 0x1000 && config.support_abstract_csr_access) {
602+
if (!is_fpu_reg(regno)) {
603+
write32(debug_abstract, i++, csrw(S0, CSR_DSCRATCH));
604+
}
585605

586606
if (write) {
587607
switch (size) {
@@ -611,7 +631,9 @@ bool debug_module_t::perform_abstract_command()
611631
return true;
612632
}
613633
}
614-
write32(debug_abstract, i++, csrr(S0, CSR_DSCRATCH));
634+
if (!is_fpu_reg(regno)) {
635+
write32(debug_abstract, i++, csrr(S0, CSR_DSCRATCH));
636+
}
615637

616638
} else if (regno >= 0x1000 && regno < 0x1020) {
617639
unsigned regnum = regno - 0x1000;
@@ -682,6 +704,14 @@ bool debug_module_t::perform_abstract_command()
682704
abstractcs.cmderr = CMDERR_NOTSUP;
683705
return true;
684706
}
707+
708+
if (is_fpu_reg(regno)) {
709+
// restore mstatus
710+
write32(debug_abstract, i++, csrr(S0, CSR_DSCRATCH + 1));
711+
write32(debug_abstract, i++, csrw(S0, CSR_MSTATUS));
712+
// restore s0
713+
write32(debug_abstract, i++, csrr(S0, CSR_DSCRATCH));
714+
}
685715
}
686716

687717
if (get_field(command, AC_ACCESS_REGISTER_POSTEXEC)) {

riscv/debug_module.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ class debug_module_t : public abstract_device_t
135135
static const unsigned debug_data_start = 0x380;
136136
unsigned debug_progbuf_start;
137137

138-
static const unsigned debug_abstract_size = 5;
138+
static const unsigned debug_abstract_size = 12;
139139
unsigned debug_abstract_start;
140140
// R/W this through custom registers, to allow debuggers to test that
141141
// functionality.

riscv/opcodes.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@ static uint32_t csrr(unsigned int rd, unsigned int csr) {
125125
return (csr << 20) | (rd << 7) | MATCH_CSRRS;
126126
}
127127

128+
static uint32_t csrrs(unsigned int rd, unsigned int rs1, unsigned int csr) __attribute__ ((unused));
129+
static uint32_t csrrs(unsigned int rd, unsigned int rs1, unsigned int csr) {
130+
return (csr << 20) | (rs1 << 15) | (rd << 7) | MATCH_CSRRS;
131+
}
132+
128133
static uint32_t fsw(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
129134
static uint32_t fsw(unsigned int src, unsigned int base, uint16_t offset)
130135
{
@@ -177,7 +182,6 @@ static uint32_t fence_i(void)
177182
return MATCH_FENCE_I;
178183
}
179184

180-
/*
181185
static uint32_t lui(unsigned int dest, uint32_t imm) __attribute__ ((unused));
182186
static uint32_t lui(unsigned int dest, uint32_t imm)
183187
{
@@ -186,6 +190,7 @@ static uint32_t lui(unsigned int dest, uint32_t imm)
186190
MATCH_LUI;
187191
}
188192

193+
/*
189194
static uint32_t csrci(unsigned int csr, uint16_t imm) __attribute__ ((unused));
190195
static uint32_t csrci(unsigned int csr, uint16_t imm) {
191196
return (csr << 20) |

riscv/processor.cc

+7-2
Original file line numberDiff line numberDiff line change
@@ -651,7 +651,10 @@ void processor_t::set_csr(int which, reg_t val)
651651
state.dpc = val & ~(reg_t)1;
652652
break;
653653
case CSR_DSCRATCH:
654-
state.dscratch = val;
654+
state.dscratch0 = val;
655+
break;
656+
case CSR_DSCRATCH + 1:
657+
state.dscratch1 = val;
655658
break;
656659
case CSR_VSTART:
657660
VU.vstart = val;
@@ -840,7 +843,9 @@ reg_t processor_t::get_csr(int which)
840843
case CSR_DPC:
841844
return state.dpc & pc_alignment_mask();
842845
case CSR_DSCRATCH:
843-
return state.dscratch;
846+
return state.dscratch0;
847+
case CSR_DSCRATCH + 1:
848+
return state.dscratch1;
844849
case CSR_VSTART:
845850
return VU.vstart;
846851
case CSR_VXSAT:

riscv/processor.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ struct state_t
234234
reg_t scause;
235235

236236
reg_t dpc;
237-
reg_t dscratch;
237+
reg_t dscratch0, dscratch1;
238238
dcsr_t dcsr;
239239
reg_t tselect;
240240
mcontrol_t mcontrol[num_triggers];

0 commit comments

Comments
 (0)