From: Tim Newsome Date: Thu, 28 Jul 2016 21:51:31 +0000 (-0700) Subject: Add support for virtual priv register. (#59) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=4fcc71ee8a23c3b4d96218a93a1842dab398be26;p=riscv-isa-sim.git Add support for virtual priv register. (#59) Users can use this register to inspect and change the privilege level of the core. It doesn't make any assumptions about the actual underlying debug mechanism (as opposed to having the user change DCSR directly, which may not exist in all debug implementations). --- diff --git a/riscv/gdbserver.cc b/riscv/gdbserver.cc index 4b8988e..c561390 100644 --- a/riscv/gdbserver.cc +++ b/riscv/gdbserver.cc @@ -29,8 +29,6 @@ # define D(x) #endif // DEBUG -const int debug_gdbserver = 0; - void die(const char* msg) { fprintf(stderr, "gdbserver code died: %s\n", msg); @@ -47,7 +45,7 @@ enum { REG_FPR31 = 64, REG_CSR0 = 65, REG_CSR4095 = 4160, - REG_END = 4161 + REG_PRIV = 4161 }; //////////////////////////////////////// Functions to generate RISC-V opcodes. @@ -618,6 +616,11 @@ class register_read_op_t : public operation_t // If we hit an exception reading the CSR, we'll end up returning ~0 as // the register's value, which is what we want. (Right?) gs.dr_write(SLOT_DATA0, ~(uint64_t) 0); + } else if (reg == REG_PRIV) { + gs.start_packet(); + gs.send((uint8_t) get_field(gs.dcsr, DCSR_PRV)); + gs.end_packet(); + return true; } else { gs.send_packet("E02"); return true; @@ -678,6 +681,9 @@ class register_write_op_t : public operation_t gs.sptbr = value; gs.sptbr_valid = true; } + } else if (reg == REG_PRIV) { + gs.dcsr = set_field(gs.dcsr, DCSR_PRV, value); + return true; } else { gs.send_packet("E02"); return true; @@ -746,7 +752,7 @@ class memory_read_op_t : public operation_t } value >>= 8; } - if (data && debug_gdbserver) { + if (data) { D(fprintf(stderr, "\n")); } length -= access_size; @@ -1843,6 +1849,13 @@ void gdbserver_t::send(uint32_t value) } } +void gdbserver_t::send(uint8_t value) +{ + char buffer[3]; + sprintf(buffer, "%02x", (int) value); + send(buffer); +} + void gdbserver_t::send_packet(const char* data) { start_packet(); diff --git a/riscv/gdbserver.h b/riscv/gdbserver.h index c45f184..f0e7fca 100644 --- a/riscv/gdbserver.h +++ b/riscv/gdbserver.h @@ -150,6 +150,8 @@ public: // Hex-encode a 32-bit value, and send it to gcc in target byte order (little // endian). void send(uint32_t value); + // Hex-encode an 8-bit value, and send it to gcc. + void send(uint8_t value); void send_packet(const char* data); uint8_t running_checksum; // Send "$" and clear running checksum. diff --git a/riscv/insns/dret.h b/riscv/insns/dret.h index 35c19cb..bef9ef2 100644 --- a/riscv/insns/dret.h +++ b/riscv/insns/dret.h @@ -1,6 +1,9 @@ require_privilege(PRV_M); set_pc_and_serialize(STATE.dpc); -p->set_privilege(STATE.dcsr.prv); +/* The debug spec says we can't crash when prv is set to an invalid value. */ +if (p->validate_priv(STATE.dcsr.prv)) { + p->set_privilege(STATE.dcsr.prv); +} /* We're not in Debug Mode anymore. */ STATE.dcsr.cause = 0; diff --git a/riscv/processor.cc b/riscv/processor.cc index 8c267f4..3576af3 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -179,7 +179,7 @@ void processor_t::take_interrupt() raise_interrupt(ctz(enabled_interrupts)); } -static bool validate_priv(reg_t priv) +bool processor_t::validate_priv(reg_t priv) { return priv == PRV_U || priv == PRV_S || priv == PRV_M; } diff --git a/riscv/processor.h b/riscv/processor.h index 090ebe7..4d0d5ab 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -118,6 +118,7 @@ public: if (ext >= 'a' && ext <= 'z') ext += 'A' - 'a'; return ext >= 'A' && ext <= 'Z' && ((isa >> (ext - 'A')) & 1); } + bool validate_priv(reg_t priv); void set_privilege(reg_t); void yield_load_reservation() { state.load_reservation = (reg_t)-1; } void update_histogram(reg_t pc);