diff --git a/spec/std/isa/csr/H/henvcfg.yaml b/spec/std/isa/csr/H/henvcfg.yaml index 0bd10fe663..1b9e5656a8 100644 --- a/spec/std/isa/csr/H/henvcfg.yaml +++ b/spec/std/isa/csr/H/henvcfg.yaml @@ -248,6 +248,36 @@ fields: return CSR[menvcfg].CBIE; } reset_value: UNDEFINED_LEGAL + SSE: + location: 3 + description: | + *Shadow Stack Enable* + + If the SSE field is set to 1, the Zicfiss extension is activated in VS-mode. When the SSE + field is 0, the Zicfiss extension remains inactive in VS-mode, and the following rules apply + when V=1 : + + - 32-bit Zicfiss instructions will revert to their behavior as defined by Zimop. + + - 16-bit Zicfiss instructions will revert to their behavior as defined by Zcmop. + + - The pte.xwr=010b encoding in VS-stage page tables becomes reserved. + + - The senvcfg.SSE field will read as zero and is read-only. + + - When menvcfg.SSE is one, SSAMOSWAP.W/D raises a virtual-instruction exception. + definedBy: + extension: + name: Zicfiss + type(): | + return (implemented?(ExtensionName::Zicfiss)) ? CsrFieldType::RW : CsrFieldType::RO; + reset_value(): | + return (implemented?(ExtensionName::Zicfiss)) ? UNDEFINED_LEGAL : 0; + sw_write(csr_value): | + if (CSR[menvcfg].SSE == 0){ + return 0; + } + return csr_value.SSE; FIOM: location: 0 description: | @@ -291,4 +321,8 @@ sw_read(): | # henvcfg.ADUE must read-as-zero value = value & ~(1 `<< 61); } + if (implemented?(ExtensionName::Zicfiss) && CSR[menvcfg].SSE == 0) { + # henvcfg.SSE must read-as-zero + value = value & ~(1 `<< 3); + } return value; diff --git a/spec/std/isa/csr/menvcfg.yaml b/spec/std/isa/csr/menvcfg.yaml index c30b3d01ad..b5cb992e59 100644 --- a/spec/std/isa/csr/menvcfg.yaml +++ b/spec/std/isa/csr/menvcfg.yaml @@ -261,6 +261,30 @@ fields: return CSR[menvcfg].CBIE; } reset_value: UNDEFINED_LEGAL + SSE: + location: 3 + description: | + *Shadow Stack Enable* + + When the SSE field is set to 1 the Zicfiss extension isactivated in S-mode. When SSE + field is 0, the following rules apply to privilege modes that are less than M: + + - 32-bit Zicfiss instructions will revert to their behavior as defined by Zimop. + + - 16-bit Zicfiss instructions will revert to their behavior as defined by Zcmop. + + - The pte.xwr=010b encoding in VS/S-stage page tables becomes reserved. + + - SSAMOSWAP.W/D raises an illegal-instruction exception. + + When menvcfg.SSE is 0, the henvcfg.SSE and senvcfg.SSE fields are read-only zero. + definedBy: + extension: + name: Zicfiss + type(): | + return (implemented?(ExtensionName::Zicfiss)) ? CsrFieldType::RW : CsrFieldType::RO; + reset_value(): | + return (implemented?(ExtensionName::Zicfiss)) ? UNDEFINED_LEGAL : 0; FIOM: location: 0 description: | diff --git a/spec/std/isa/csr/senvcfg.yaml b/spec/std/isa/csr/senvcfg.yaml index 843e02470c..2ebe2f4a7c 100644 --- a/spec/std/isa/csr/senvcfg.yaml +++ b/spec/std/isa/csr/senvcfg.yaml @@ -117,6 +117,33 @@ fields: return UNDEFINED_LEGAL_DETERMINISTIC; } reset_value: UNDEFINED_LEGAL + SSE: + location: 3 + description: | + *Shadow Stack Enable* + + When the SSE field is set to 1, the Zicfiss extension is + activated in VU/U-mode. When the SSE field is 0, the Zicfiss extension remains inactive + in VU/U-mode, and the following rules apply: + + - 32-bit Zicfiss instructions will revert to their behavior as defined by Zimop. + + - 16-bit Zicfiss instructions will revert to their behavior as defined by Zcmop. + + - When menvcfg.SSE is one, SSAMOSWAP.W/D raises an illegal-instruction exception in U-mode + and a virtual-instruction exception in VU-mode. + definedBy: + extension: + name: Zicfiss + type(): | + return (implemented?(ExtensionName::Zicfiss)) ? CsrFieldType::RW : CsrFieldType::RO; + reset_value(): | + return (implemented?(ExtensionName::Zicfiss)) ? UNDEFINED_LEGAL : 0; + sw_write(csr_value): | + if (CSR[menvcfg].SSE == 0 || CSR[henvcfg].SSE == 0){ + return 0; + } + return csr_value.SSE; FIOM: location: 0 description: | @@ -148,3 +175,10 @@ fields: type: RW reset_value: 0 +sw_read(): | + Bits<64> value = $bits(CSR[senvcfg]); + if (implemented?(ExtensionName::Zicfiss) && (CSR[menvcfg].SSE == 0 || CSR[henvcfg].SSE == 0)) { + # senvcfg.SSE must read-as-zero + value = value & ~(1 `<< 3); + } + return value; diff --git a/spec/std/isa/csr/ssp.yaml b/spec/std/isa/csr/ssp.yaml new file mode 100644 index 0000000000..22aa5bb0cc --- /dev/null +++ b/spec/std/isa/csr/ssp.yaml @@ -0,0 +1,55 @@ +# Copyright (c) Katherine Hsu +# SPDX-License-Identifier: BSD-3-Clause-Clear + +# yaml-language-server: $schema=../../../schemas/csr_schema.json + +$schema: "csr_schema.json#" +kind: csr +name: ssp +long_name: Shadow Stack Pointer +address: 0x011 +writable: true +description: + - id: csr-ssp-purpose + normative: true + text: | + The `ssp` CSR is an unprivileged read-write (URW) CSR that reads and writes + XLEN low order bits of the shadow stack pointer. The `ssp` is always as wide + as the XLEN of the current privilege mode. The bits 1:0 of ssp are read-only + zero. If the UXLEN or SXLEN may never be 32, then the bit 2 is also read-only + zero. +priv_mode: U +length: XLEN +definedBy: + extension: + name: Zicfiss +fields: + VALUE: + location_rv64: 63-3 + location_rv32: 31-2 + description: | + The value in ssp points to the top of the shadow stack, which is the address + of the last element stored on the shadow stack. + type: RW + reset_value: UNDEFINED_LEGAL + sw_write(csr_value): | + if ((mode() < PrivilegeMode::M && CSR[menvcfg].SSE == 0) || + (mode() == PrivilegeMode::U && CSR[senvcfg].SSE == 0)) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } else if ((mode() == PrivilegeMode::VS && CSR[henvcfg].SSE == 0) || + (mode() == PrivilegeMode::VU && (CSR[henvcfg].SSE == 0 || CSR[senvcfg].SSE == 0))) { + raise(ExceptionCode::VirtualInstruction, mode(), $encoding); + } else { + return csr_value.VALUE; + } +sw_read(): | + if ((mode() < PrivilegeMode::M && CSR[menvcfg].SSE == 0) || + (mode() == PrivilegeMode::U && CSR[senvcfg].SSE == 0)) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } else if ((mode() == PrivilegeMode::VS && CSR[henvcfg].SSE == 0) || + (mode() == PrivilegeMode::VU && (CSR[henvcfg].SSE == 0 || CSR[senvcfg].SSE == 0))) { + raise(ExceptionCode::VirtualInstruction, mode(), $encoding); + } else if (XLEN == 32) { + return ($bits(CSR[ssp]) & ~3); + } + return ($bits(CSR[ssp]) & ~7); diff --git a/tools/ruby-gems/udb/lib/udb/obj/csr_field.rb b/tools/ruby-gems/udb/lib/udb/obj/csr_field.rb index 2e8d46a70f..690f66621f 100644 --- a/tools/ruby-gems/udb/lib/udb/obj/csr_field.rb +++ b/tools/ruby-gems/udb/lib/udb/obj/csr_field.rb @@ -754,21 +754,25 @@ def location_pretty(effective_xlen = nil) if dynamic_location? condition = - case csr.priv_mode - when "M" - "CSR[misa].MXL == %%" - when "S" - "CSR[mstatus].SXL == %%" - when "VS" - "CSR[hstatus].VSXL == %%" + if csr.data["length"] == "XLEN" + "the current XLEN is $$" else - raise "Unexpected priv mode #{csr.priv_mode} for #{csr.name}" + case csr.priv_mode + when "M" + "CSR[misa].MXL == %%" + when "S" + "CSR[mstatus].SXL == %%" + when "VS" + "CSR[hstatus].VSXL == %%" + else + raise "Unexpected priv mode #{csr.priv_mode} for #{csr.name}" + end end if effective_xlen.nil? <<~LOC - * #{derangeify.call(location(32))} when #{condition.sub('%%', '0')} - * #{derangeify.call(location(64))} when #{condition.sub('%%', '1')} + * #{derangeify.call(location(32))} when #{condition.sub('%%', '0').sub('$$', '32')} + * #{derangeify.call(location(64))} when #{condition.sub('%%', '1').sub('$$', '64')} LOC else derangeify.call(location(effective_xlen))