blob: c46b53163868cfd5df399f8aaed6d0d88be973cc [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
{ name: "otbn"
clocking: [
{clock: "clk_i", reset: "rst_ni", idle: "idle_o", primary: true},
{clock: "clk_edn_i", reset: "rst_edn_ni", idle: "idle_o"},
{clock: "clk_otp_i", reset: "rst_otp_ni", idle: "idle_otp_o"}
]
bus_interfaces: [
{ protocol: "tlul", direction: "device" }
],
param_list: [
{ name: "Stub",
type: "bit",
default: "0",
desc: "Stub out the core of Otbn logic"
local: "false",
expose: "true"
},
{ name: "RegFile",
type: "otbn_pkg::regfile_e",
default: "otbn_pkg::RegFileFF",
desc: "Selection of the register file implementation. See otbn_pkg.sv."
local: "false",
expose: "true"
},
{ name: "RndCnstUrndPrngSeed",
type: "otbn_pkg::urnd_prng_seed_t",
desc: '''
Default seed of the PRNG used for URND.
'''
randcount: "256",
randtype: "data"
},
{ name: "RndCnstOtbnKey",
type: "otp_ctrl_pkg::otbn_key_t",
desc: '''
Compile-time random reset value for IMem/DMem scrambling key.
'''
randcount: "128",
randtype: "data"
},
{ name: "RndCnstOtbnNonce",
type: "otp_ctrl_pkg::otbn_nonce_t",
desc: '''
Compile-time random reset value for IMem/DMem scrambling nonce.
'''
randcount: "64",
randtype: "data"
},
]
interrupt_list: [
{ name: "done"
desc: "OTBN has completed the operation."
}
]
alert_list: [
{ name: "fatal"
desc: "A fatal error. Fatal alerts are non-recoverable and will be asserted until a hard reset."
}
{ name: "recov"
desc: "A recoverable error. Just sent once (as the processor stops)."
}
]
inter_signal_list: [
// Key request to OTP
{ struct: "otbn_otp_key"
type: "req_rsp"
name: "otbn_otp_key"
act: "req"
default: "'0"
package: "otp_ctrl_pkg"
},
// EDN interface for RND
{ struct: "edn"
type: "req_rsp"
name: "edn_rnd"
act: "req"
package: "edn_pkg"
},
// EDN interface for URND
{ struct: "edn"
type: "req_rsp"
name: "edn_urnd"
act: "req"
package: "edn_pkg"
},
// OTBN is not performing any operation and can be clock/power-gated.
{ name: "idle",
type: "uni",
struct: "mubi4",
width: "1",
act: "req",
package: "prim_mubi_pkg"
},
// ram configuration
{ struct: "ram_1p_cfg",
package: "prim_ram_1p_pkg",
type: "uni",
name: "ram_cfg",
act: "rcv"
},
// Lifecycle escalation
{ struct: "lc_tx"
type: "uni"
name: "lc_escalate_en"
act: "rcv"
default: "lc_ctrl_pkg::Off"
package: "lc_ctrl_pkg"
},
// Key sideload
{ struct: "otbn_key_req"
type: "uni"
name: "keymgr_key"
act: "rcv"
package: "keymgr_pkg"
},
],
countermeasures: [
{ name: "BUS.INTEGRITY",
desc: "End-to-end bus integrity scheme."
}
{ name: "CONTROLLER.FSM.GLOBAL_ESC",
desc: "The controller FSM moves to a terminal error state upon global escalation."
}
{ name: "CONTROLLER.FSM.LOCAL_ESC",
desc: '''
The controller FSM moves to a terminal error state upon local escalation.
Can be triggered by CONTROLLER.FSM.SPARSE, SCRAMBLE_CTRL.FSM.SPARSE, and START_STOP_CTRL.FSM.SPARSE.
'''
}
{ name: "CONTROLLER.FSM.SPARSE",
desc: "The controller FSM uses a sparse state encoding."
}
{ name: "SCRAMBLE.KEY.SIDELOAD",
desc: "The scrambling key is sideloaded from OTP and thus unreadable by SW."
}
{ name: "SCRAMBLE_CTRL.FSM.LOCAL_ESC",
desc: '''
The scramble control FSM moves to a terminal error state upon local escalation.
Can be triggered by SCRAMBLE_CTRL.FSM.SPARSE.
'''
}
{ name: "SCRAMBLE_CTRL.FSM.SPARSE",
desc: "The scramble control FSM uses a sparse state encoding."
}
{ name: "START_STOP_CTRL.FSM.LOCAL_ESC",
desc: '''
The start-stop control FSM moves to a terminal error state upon local escalation.
Can be triggered by START_STOP_CTRL.FSM.SPARSE.
'''
}
{ name: "START_STOP_CTRL.FSM.SPARSE",
desc: "The start-stop control FSM uses a sparse state encoding."
}
{ name: "DATA_REG_SW.SCA",
desc: "Blanking of bignum data paths when unused by the executing instruction."
}
{ name: "CTRL.REDUN",
desc: "Check pre-decoded control used for blanking matches seperately decoded control from main decoder."
}
{ name: "RND.BUS.CONSISTENCY",
desc: "Comparison on successive bus values received over the EDN RND interface."
}
{ name: "RND.RNG.DIGEST",
desc: "Checking that the random numbers received over the EDN RND interface have not been generated from entropy that failed the FIPS health checks in the entropy source."
}
{ name: "RF_BASE.DATA_REG_SW.GLITCH_DETECT"
desc: '''
This countermeasure checks for spurious write-enable signals on the register
file by monitoring the one-hot0 property of the individual write-enable strobes.
'''
}
{ name: "STACK_WR_PTR.CTR.REDUN"
desc: '''
The write pointer of the stack (used for calls and loops) is redundant. If the two
instances of the counter mismatch, an error is emitted.
'''
}
{ name: "STACK_WR_PTR.CTR.GLITCH_DETECT"
desc: "Glitches are detected on the stack counter increment / decrement control signal."
}
{ name: "RF_BIGNUM.DATA_REG_SW.GLITCH_DETECT"
desc: '''
This countermeasure checks for spurious write-enable signals on the register
file by monitoring the one-hot0 property of the individual write-enable strobes.
'''
}
]
regwidth: "32"
registers: [
// The magic values for EXECUTE, SEC_WIPE_DMEM and SEC_WIPE_IMEM in the CMD
// register below were generated with the sparse-fsm-encode.py script:
//
// util/design/sparse-fsm-encode.py -d 4 -m 3 -n 8 --avoid-zero -s 1
//
// and have a hamming distance of at least 4 from one another and the zero
// word.
{ name: "CMD"
desc: '''
Command Register
A command initiates an OTBN operation. While performing the operation,
OTBN is busy; the !!STATUS register reflects that.
All operations signal their completion by raising the done
interrupt; alternatively, software may poll the !!STATUS register.
Writes are ignored if OTBN is not idle.
Unrecognized commands are ignored.
''',
swaccess: "wo",
hwaccess: "hro",
hwext: "true",
hwqe: "true",
fields: [
{ bits: "7:0"
name: "cmd"
resval: 0,
desc: '''
The operation to perform.
<table>
<thead>
<tr>
<th>Value</th>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>0xd8</td>
<td>EXECUTE</td>
<td>
Starts the execution of the program stored in the
instruction memory, starting at address zero.
</td>
</tr>
<tr>
<td>0xc3</td>
<td>SEC_WIPE_DMEM</td>
<td>Securely removes all contents from the data memory.</td>
</tr>
<tr>
<td>0x1e</td>
<td>SEC_WIPE_IMEM</td>
<td>
Securely removes all contents from the instruction memory.
</td>
</tr>
</tbody>
</table>
'''
tags: [
// Don't write this field in the automated CSR tests: it would
// start an operation!
"excl:CsrAllTests:CsrExclWrite"
]
}
],
}
{ name: "CTRL",
desc: "Control Register",
hwext: "true",
swaccess: "rw",
hwaccess: "hrw",
hwqe: "true",
fields: [
{ bits: "0",
name: "software_errs_fatal",
resval: 0,
desc: '''
Controls the reaction to software errors.
When set software errors produce fatal errors, rather than
recoverable errors.
Writes are ignored if OTBN is not idle.
'''
}
],
}
{ name: "STATUS",
desc: "Status Register",
swaccess: "ro",
hwaccess: "hwo",
fields: [
{ bits: "7:0",
name: "status",
resval: 0,
// Note: Keep the list of status codes in sync with status_e in
// otbn_pkg.sv.
desc: '''
Indicates the current operational state OTBN is in.
All BUSY values represent an operation started by a write to the
!!CMD register.
<table>
<thead>
<tr>
<th>Value</th>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>0x00</td>
<td>IDLE</td>
<td>OTBN is idle: it is not performing any action.</td>
</tr>
<tr>
<td>0x01</td>
<td>BUSY_EXECUTE</td>
<td>OTBN is busy executing software.</td>
</tr>
<tr>
<td>0x02</td>
<td>BUSY_SEC_WIPE_DMEM</td>
<td>OTBN is busy securely wiping the data memory.</td>
</tr>
<tr>
<td>0x03</td>
<td>BUSY_SEC_WIPE_IMEM</td>
<td>OTBN is busy securely wiping the instruction memory.</td>
</tr>
<tr>
<td>0xFF</td>
<td>LOCKED</td>
<td>
OTBN is locked as reaction to a fatal error, and must be
reset to unlock it again. See also the the section
"Reaction to Fatal Errors".
</td>
</tr>
</tbody>
</table>
'''
tags: [
// Don't write this field in the automated CSR tests. Despite this being RO for software
// (so you might think we couldn't write it), the csr_hw_reset test does write this by
// by default (using a backdoor access). The idea of that test is to write bogus values
// to registers, reset the block and then check that everything has its reset value.
// Doing this causes various assertions to fire and it isn't really necessary: we
// already have strong checks between this register and the output of the model.
"excl:CsrAllTests:CsrExclWrite"
]
}
]
}
{ name: "ERR_BITS",
desc: '''
Operation Result Register
Describes the errors detected during an operation.
Refer to the "List of Errors" section for a detailed description of the
errors.
The host CPU can clear this register when OTBN is not running,
by writing any value. Write attempts while OTBN is running are ignored.
''',
swaccess: "rw",
hwaccess: "hrw",
hwext: "true",
hwqe: "true",
tags: [
// Don't use this register in the automated CSR tests. Its behaviour is
// "write any value to clear", which we don't model in those tests.
"excl:CsrAllTests:CsrExclWrite"
],
fields: [
// Software errors
{ bits: "0",
name: "bad_data_addr"
resval: 0,
desc: "A `BAD_DATA_ADDR` error was observed."
}
{ bits: "1",
name: "bad_insn_addr"
resval: 0,
desc: "A `BAD_INSN_ADDR` error was observed."
}
{ bits: "2",
resval: 0,
name: "call_stack"
desc: "A `CALL_STACK` error was observed."
}
{ bits: "3",
resval: 0,
name: "illegal_insn"
desc: "An `ILLEGAL_INSN` error was observed."
}
{ bits: "4",
name: "loop"
resval: 0,
desc: "A `LOOP` error was observed."
}
{ bits: "5",
name: "key_invalid"
resval: 0,
desc: "A `KEY_INVALID` error was observed."
}
// Recoverable errors
{ bits: "6",
name: "rnd_rep_chk_fail"
resval: 0,
desc: "An `RND_REP_CHK_FAIL` error was observed."
}
{ bits: "7",
name: "rnd_fips_chk_fail"
resval: 0,
desc: "An `RND_FIPS_CHK_FAIL` error was observed."
}
// Fatal errors. Keep in sync with list in FATAL_ALERT_CAUSE.
{ bits: "16",
name: "imem_intg_violation"
resval: 0,
desc: "A `IMEM_INTG_VIOLATION` error was observed."
}
{ bits: "17",
name: "dmem_intg_violation"
resval: 0,
desc: "A `DMEM_INTG_VIOLATION` error was observed."
}
{ bits: "18",
name: "reg_intg_violation"
resval: 0,
desc: "A `REG_INTG_VIOLATION` error was observed."
}
{ bits: "19",
name: "bus_intg_violation"
resval: 0,
desc: "A `BUS_INTG_VIOLATION` error was observed."
}
{ bits: "20",
name: "bad_internal_state",
resval: 0,
desc: "A `BAD_INTERNAL_STATE` error was observed."
}
{ bits: "21",
name: "illegal_bus_access"
resval: 0,
desc: "An `ILLEGAL_BUS_ACCESS` error was observed."
}
{ bits: "22",
name: "lifecycle_escalation"
resval: 0,
desc: "A `LIFECYCLE_ESCALATION` error was observed."
}
{ bits: "23",
name: "fatal_software"
resval: 0,
desc: "A `FATAL_SOFTWARE` error was observed."
}
]
}
{ name: "FATAL_ALERT_CAUSE",
desc: '''
Fatal Alert Cause Register
Describes any errors that led to a fatal alert.
A fatal error puts OTBN in locked state; the value of this register
does not change until OTBN is reset.
Refer to the "List of Errors" section for a detailed description of the
errors.
'''
swaccess: "ro",
hwaccess: "hwo",
fields: [
// Keep the list in sync with the fatal errors in ERR_BITS.
{ bits: "0",
name: "imem_intg_violation",
resval: 0,
desc: "A `IMEM_INTG_VIOLATION` error was observed."
}
{ bits: "1",
name: "dmem_intg_violation",
resval: 0,
desc: "A `DMEM_INTG_VIOLATION` error was observed."
}
{ bits: "2",
name: "reg_intg_violation",
resval: 0,
desc: "A `REG_INTG_VIOLATION` error was observed."
}
{ bits: "3",
name: "bus_intg_violation",
resval: 0,
desc: "A `BUS_INTG_VIOLATION` error was observed."
}
{ bits: "4",
name: "bad_internal_state",
resval: 0,
desc: "A `BAD_INTERNAL_STATE` error was observed."
}
{ bits: "5",
name: "illegal_bus_access"
resval: 0,
desc: "A `ILLEGAL_BUS_ACCESS` error was observed."
}
{ bits: "6",
name: "lifecycle_escalation"
resval: 0,
desc: "A `LIFECYCLE_ESCALATION` error was observed."
}
{ bits: "7",
name: "fatal_software"
resval: 0,
desc: "A `FATAL_SOFTWARE` error was observed."
}
]
}
{ name: "INSN_CNT",
desc: '''
Instruction Count Register
Returns the number of instructions executed in the current or last
operation. The counter saturates at 2^32-1 and is reset to 0 at the
start of a new operation.
Only the EXECUTE operation counts instructions; for all other operations
this register remains at 0. Instructions triggering an error do not
count towards the total.
Always reads as 0 if OTBN is locked.
The host CPU can clear this register when OTBN is not running,
by writing any value. Write attempts while OTBN is running are ignored.
''',
swaccess: "rw",
hwaccess: "hrw",
hwext: "true",
hwqe: "true",
fields: [
{ bits: "31:0",
name: "insn_cnt",
resval: 0,
desc: '''
The number of executed instructions.
'''
tags: [
// Don't write this field in the automated CSR tests. Like
// ERR_BITS, its behaviour is "write any value to clear", which we
// don't model in those tests.
"excl:CsrAllTests:CsrExclWrite"
]
}
]
}
{ name: "LOAD_CHECKSUM",
desc: '''
A 32-bit CRC checksum of data written to memory
See the "Memory Load Integrity" section of the manual for full details.
'''
hwext: "true",
hwqe: "true",
swaccess: "rw",
hwaccess: "hrw",
fields: [
{ bits: "31:0",
name: "checksum",
resval: 0,
desc: "Checksum accumulator"
}
]
tags: [
// Don't read this field in any of the automated CSR tests (they
// will predict the value wrongly because they don't know that it
// updates on memory writes).
"excl:CsrAllTests:CsrExclAll"
]
}
// Give IMEM and DMEM 16 KiB address space, each, to allow for easy expansion
// of the actual IMEM and DMEM sizes without changing the address map.
{ skipto: "0x4000" }
// Imem size (given as `items` below) must be a power of two.
{ window: {
name: "IMEM",
items: "1024", // 4 kB
swaccess: "rw",
data-intg-passthru: "true",
byte-write: "false",
desc: '''
Instruction Memory Access
The instruction memory may only be accessed through this window
while OTBN is idle.
If OTBN is busy or locked, read accesses return 0 and write accesses
are ignored.
If OTBN is busy, any access additionally triggers an
ILLEGAL_BUS_ACCESS fatal error.
'''
}
}
{ skipto: "0x8000" }
// Dmem size (given as `items` below) must be a power of two.
{ window: {
name: "DMEM",
items: "512", // 2 kB visible over the bus
swaccess: "rw",
data-intg-passthru: "true",
byte-write: "false",
desc: '''
Data Memory Access
The data memory may only be accessed through this window while OTBN
is idle.
If OTBN is busy or locked, read accesses return 0 and write accesses
are ignored.
If OTBN is busy, any access additionally triggers an
ILLEGAL_BUS_ACCESS fatal error.
Note that DMEM is actually 4kiB in size, but only the first 2kiB of
the memory is visible through this register interface.
'''
}
}
]
}