Skip to content

Commit 8ffb8fa

Browse files
authored
Merge branch 'caliptra-2.0' into cherry-pick-certify-key-chunks-3765-v2
2 parents fe1609f + 3ce6611 commit 8ffb8fa

12 files changed

Lines changed: 284 additions & 159 deletions

File tree

FROZEN_IMAGES.sha384sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# WARNING: Do not update this file without the approval of the Caliptra TAC
2-
d9859df1c8456bc56e97c4f54aa524bb4e3e4c6006a7b6afcd1f0cb1fdf472ba918ca9b314c519f72adae3dd0256a173 caliptra-rom-no-log.bin
3-
53142b923c92a22f33a5468bb65f8fda194eaf73d906a669051aac85147f727ccb615bb5f5ae1df14c1f1d27174bebf7 caliptra-rom-with-log.bin
2+
4cb14746c57cfd81e1c816d1bf662b3d314d31d499ccbf8ba6b741d658a4a3069ef5ae7619171bfb8b22546129354506 caliptra-rom-no-log.bin
3+
715cb76928d869a393d0fc506d52047df03908ffaadb55dd3cbf82c9be53a882029830a6cdefd2289d05d468ed32f33d caliptra-rom-with-log.bin

common/src/uds_fe_programming.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,13 @@ impl UdsFeProgrammingFlow {
149149
let otp_ctrl = DmaOtpCtrl::new(AxiAddr::from(fuse_controller_base_addr), dma);
150150
let seed_dest_address = self.get_dest_address(soc_ifc);
151151
let dai_idle_bit_num = soc_ifc.otp_dai_idle_bit_num();
152+
let status_reg_offset = soc_ifc.otp_status_reg_offset();
153+
let status_reg_addr = if status_reg_offset != 0 {
154+
Some(fuse_controller_base_addr + status_reg_offset as u64)
155+
} else {
156+
// TODO: Remove this fallback once MCU programs the OTP status register offset.
157+
None
158+
};
152159
let direct_access_cmd_reg_addr =
153160
fuse_controller_base_addr + soc_ifc.otp_direct_access_cmd_reg_offset() as u64;
154161
let direct_access_address_reg_addr =
@@ -159,11 +166,15 @@ impl UdsFeProgrammingFlow {
159166
direct_access_cmd_reg_addr + DIRECT_ACCESS_WDATA_1_OFFSET;
160167

161168
let _ = otp_ctrl.with_regs_mut(|regs| {
162-
// Helper function to check if DAI is idle using the configurable bit number
163-
let is_dai_idle = || -> bool {
164-
let status: u32 = regs.status().read().into();
165-
(status & (1 << dai_idle_bit_num)) != 0
166-
};
169+
// Helper function to check if DAI is idle using the configurable bit number
170+
let is_dai_idle = || -> bool {
171+
let status = if let Some(status_reg_addr) = status_reg_addr {
172+
dma.read_dword(AxiAddr::from(status_reg_addr))
173+
} else {
174+
regs.status().read().into()
175+
};
176+
(status & (1 << dai_idle_bit_num)) != 0
177+
};
167178

168179
let seed = &seed[..self.seed_length_words()]; // Get random bytes of desired size
169180
let chunk_size = if uds_fuse_row_granularity_64 { 2 } else { 1 };

drivers/src/mailbox.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ impl Mailbox {
111111
}
112112
}
113113

114+
/// Wait until the mailbox FSM returns to idle.
115+
pub fn wait_until_idle(&self) {
116+
let mbox = self.mbox.regs();
117+
while !mbox.status().read().mbox_fsm_ps().mbox_idle() {}
118+
}
119+
114120
/// Aborts with failure any pending SoC->Uc transactions.
115121
///
116122
/// This is useful to call from a fatal-error-handling routine.

drivers/src/soc_ifc.rs

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -115,16 +115,24 @@ impl SocIfc {
115115
let lifecycle = self.lifecycle();
116116
let soc_ifc_regs = self.soc_ifc.regs_mut();
117117
match lifecycle {
118-
Lifecycle::Manufacturing => soc_ifc_regs.ss_dbg_manuf_service_reg_rsp().modify(|w| {
119-
w.tap_mailbox_available(in_progress)
120-
.manuf_dbg_unlock_in_progress(in_progress)
121-
}),
122-
DeviceLifecycleE::Production => {
123-
soc_ifc_regs.ss_dbg_manuf_service_reg_rsp().modify(|w| {
124-
w.tap_mailbox_available(in_progress)
125-
.prod_dbg_unlock_in_progress(in_progress)
126-
})
127-
}
118+
Lifecycle::Manufacturing => soc_ifc_regs
119+
.ss_dbg_manuf_service_reg_rsp()
120+
.modify(|w| w.manuf_dbg_unlock_in_progress(in_progress)),
121+
DeviceLifecycleE::Production => soc_ifc_regs
122+
.ss_dbg_manuf_service_reg_rsp()
123+
.modify(|w| w.prod_dbg_unlock_in_progress(in_progress)),
124+
_ => (),
125+
}
126+
}
127+
128+
/// Enable or disable TAP access to the mailbox for debug unlock.
129+
pub fn set_ss_dbg_unlock_tap_mailbox_available(&mut self, available: bool) {
130+
let lifecycle = self.lifecycle();
131+
let soc_ifc_regs = self.soc_ifc.regs_mut();
132+
match lifecycle {
133+
Lifecycle::Manufacturing | DeviceLifecycleE::Production => soc_ifc_regs
134+
.ss_dbg_manuf_service_reg_rsp()
135+
.modify(|w| w.tap_mailbox_available(available)),
128136
_ => (),
129137
}
130138
}
@@ -639,6 +647,10 @@ impl SocIfc {
639647
(self.soc_ifc.regs().ss_strap_generic().at(0).read() >> 16) & 0xFFFF
640648
}
641649

650+
pub fn otp_status_reg_offset(&self) -> u32 {
651+
self.soc_ifc.regs().ss_strap_generic().at(0).read() & 0xFFFF
652+
}
653+
642654
pub fn otp_direct_access_cmd_reg_offset(&self) -> u32 {
643655
self.soc_ifc.regs().ss_strap_generic().at(1).read() & 0xFFFF
644656
}

rom/dev/README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -277,11 +277,12 @@ The following flows are conducted when the ROM is operating in the manufacturing
277277
3. ROM then retrieves the UDS granularity from the `CPTRA_GENERIC_INPUT_WIRES` register0 Bit31 to learn if the fuse row is accessible with 32-bit or 64-bit granularity. If the bit is reset, it indicates 64-bit granularity; otherwise, it indicates 32-bit granularity.
278278

279279
4. ROM computes the following values:
280-
- DAI_IDLE bit offset: (`SS_STRAP_GENERIC` register0 >> 16) & 0xFFFF
281-
- `DIRECT_ACCESS_CMD` offset: (`SS_STRAP_GENERIC` register1) & 0xFFFF + Fuse Controller's base address.
280+
- `STATUS` register address: Fuse Controller's base address + ((`SS_STRAP_GENERIC` register0) & 0xFFFF).
281+
- DAI_IDLE bit index within the `STATUS` register: (`SS_STRAP_GENERIC` register0 >> 16) & 0xFFFF.
282+
- `DIRECT_ACCESS_CMD` register address: Fuse Controller's base address + ((`SS_STRAP_GENERIC` register1) & 0xFFFF).
282283

283284
4. ROM then performs the following steps until all the 512 bits of the UDS seed are programmed:
284-
1. The ROM verifies the idle state of the DAI by reading the `STATUS` register `DAI_IDLE` bit (offset retrieved above) of the Fuse Controller, located at offset 0x10 from the Fuse Controller's base address.
285+
1. The ROM verifies the idle state of the DAI by reading the `STATUS` register `DAI_IDLE` bit using the offset retrieved above.
285286
2. If the granularity is 32-bit, the ROM writes the next word from the UDS seed to the `DIRECT_ACCESS_WDATA_0` register. If the granularity is 64-bit, the ROM writes the next two words to `the DIRECT_ACCESS_WDATA_0` and `DIRECT_ACCESS_WDATA_1` registers, located at offsets 0x8 and 0xC respectively from the `DIRECT_ACCESS_CMD` register.
286287
3. The ROM writes the lower 32 bits of the UDS Seed programming base address to the `DIRECT_ACCESS_ADDRESS` register, located at offset 0x4 from the `DIRECT_ACCESS_CMD` register.
287288
4. The ROM triggers the UDS seed write command by writing 0x2 to the `DIRECT_ACCESS_CMD` register..

rom/dev/src/flow/debug_unlock.rs

Lines changed: 120 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ Abstract:
1212
1313
--*/
1414

15-
use core::mem::ManuallyDrop;
16-
1715
use crate::flow::cold_reset::fw_processor::FirmwareProcessor;
1816
use crate::CaliptraResult;
1917
use caliptra_api::mailbox::{
@@ -58,11 +56,24 @@ pub fn debug_unlock(env: &mut RomEnv) -> CaliptraResult<()> {
5856
}
5957
}
6058

59+
fn start_debug_unlock(env: &mut RomEnv) {
60+
env.soc_ifc.set_ss_dbg_unlock_tap_mailbox_available(true);
61+
env.soc_ifc.set_ss_dbg_unlock_in_progress(true);
62+
}
63+
64+
fn finish_debug_unlock(env: &mut RomEnv, response_sent: bool) {
65+
env.soc_ifc.set_ss_dbg_unlock_in_progress(false);
66+
if response_sent {
67+
env.mbox.wait_until_idle();
68+
env.soc_ifc.set_ss_dbg_unlock_tap_mailbox_available(false);
69+
}
70+
}
71+
6172
fn handle_manufacturing(env: &mut RomEnv) -> CaliptraResult<()> {
6273
cprintln!("[dbg_manuf] ++");
6374

6475
// Set debug unlock in progress and unlock the mailbox for tap access.
65-
env.soc_ifc.set_ss_dbg_unlock_in_progress(true);
76+
start_debug_unlock(env);
6677

6778
let mbox = &mut env.mbox;
6879
let txn = loop {
@@ -81,7 +92,7 @@ fn handle_manufacturing(env: &mut RomEnv) -> CaliptraResult<()> {
8192
Err(CaliptraError::SS_DBG_UNLOCK_MANUF_INVALID_MBOX_CMD)?;
8293
}
8394

84-
let mut txn = ManuallyDrop::new(txn.start_txn());
95+
let mut txn = txn.start_txn();
8596

8697
let result = (|| {
8798
let mut request = ManufDebugUnlockTokenReq::default();
@@ -115,124 +126,139 @@ fn handle_manufacturing(env: &mut RomEnv) -> CaliptraResult<()> {
115126
}
116127
}
117128

118-
env.soc_ifc.set_ss_dbg_unlock_in_progress(false);
129+
drop(txn);
130+
finish_debug_unlock(env, true);
119131

120132
cprintln!("[dbg_manuf] --");
121133
result
122134
}
123135

124136
fn handle_auth_debug_unlock_request(
125137
env: &mut RomEnv,
126-
) -> CaliptraResult<(
127-
ProductionAuthDebugUnlockReq,
128-
ProductionAuthDebugUnlockChallenge,
129-
)> {
130-
let mbox = &mut env.mbox;
131-
let txn = loop {
132-
// Random delay for CFI glitch protection.
133-
CfiCounter::delay();
134-
135-
match mbox.peek_recv() {
136-
Some(txn) => break txn,
137-
None => continue,
138+
) -> (
139+
CaliptraResult<(
140+
ProductionAuthDebugUnlockReq,
141+
ProductionAuthDebugUnlockChallenge,
142+
)>,
143+
bool,
144+
) {
145+
let mut response_sent = false;
146+
let result = (|| {
147+
let mbox = &mut env.mbox;
148+
let txn = loop {
149+
// Random delay for CFI glitch protection.
150+
CfiCounter::delay();
151+
152+
match mbox.peek_recv() {
153+
Some(txn) => break txn,
154+
None => continue,
155+
}
156+
};
157+
158+
if CommandId::from(txn.cmd()) != CommandId::PRODUCTION_AUTH_DEBUG_UNLOCK_REQ {
159+
Err(CaliptraError::SS_DBG_UNLOCK_PROD_INVALID_REQ_MBOX_CMD)?
138160
}
139-
};
140161

141-
if CommandId::from(txn.cmd()) != CommandId::PRODUCTION_AUTH_DEBUG_UNLOCK_REQ {
142-
cprintln!(
143-
"Invalid command: {:?}, was expecting PRODUCTION_AUTH_DEBUG_UNLOCK_REQ",
144-
txn.cmd()
162+
let mut txn = txn.start_txn();
163+
164+
// Copy request data since it needs to persist
165+
let mut request = ProductionAuthDebugUnlockReq::default();
166+
FirmwareProcessor::copy_req_verify_chksum(&mut txn, request.as_mut_bytes(), false)?;
167+
168+
// Use common function to create challenge
169+
let challenge = debug_unlock::create_debug_unlock_challenge(
170+
&mut env.trng,
171+
&env.soc_ifc,
172+
&mut env.dma,
173+
&request,
145174
);
146-
Err(CaliptraError::SS_DBG_UNLOCK_PROD_INVALID_REQ_MBOX_CMD)?
147-
}
148175

149-
let mut txn = ManuallyDrop::new(txn.start_txn());
150-
151-
// Process request and create challenge
152-
let mut request = ProductionAuthDebugUnlockReq::default();
153-
FirmwareProcessor::copy_req_verify_chksum(&mut txn, request.as_mut_bytes(), false)?;
154-
155-
// Use common function to create challenge
156-
let challenge = debug_unlock::create_debug_unlock_challenge(
157-
&mut env.trng,
158-
&env.soc_ifc,
159-
&mut env.dma,
160-
&request,
161-
);
162-
163-
// Send response
164-
match challenge {
165-
Err(err) => {
166-
txn.send_response(MailboxRespHeader::default().as_bytes())?;
167-
Err(err)
168-
}
169-
Ok(challenge_resp) => {
170-
txn.send_response(challenge_resp.as_bytes())?;
171-
Ok((request, challenge_resp))
176+
// Send response
177+
match challenge {
178+
Err(err) => {
179+
txn.send_response(MailboxRespHeader::default().as_bytes())?;
180+
response_sent = true;
181+
Err(err)
182+
}
183+
Ok(challenge_resp) => {
184+
txn.send_response(challenge_resp.as_bytes())?;
185+
response_sent = true;
186+
Ok((request, challenge_resp))
187+
}
172188
}
173-
}
189+
})();
190+
(result, response_sent)
174191
}
175192

176193
fn handle_auth_debug_unlock_token(
177194
env: &mut RomEnv,
178195
request: &ProductionAuthDebugUnlockReq,
179196
challenge: &ProductionAuthDebugUnlockChallenge,
180-
) -> CaliptraResult<()> {
181-
let mbox = &mut env.mbox;
182-
let txn = loop {
183-
// Random delay for CFI glitch protection.
184-
CfiCounter::delay();
185-
186-
match mbox.peek_recv() {
187-
Some(txn) => break txn,
188-
None => continue,
197+
) -> (CaliptraResult<()>, bool) {
198+
let mut response_sent = false;
199+
let result = (|| {
200+
let mbox = &mut env.mbox;
201+
let txn = loop {
202+
// Random delay for CFI glitch protection.
203+
CfiCounter::delay();
204+
205+
match mbox.peek_recv() {
206+
Some(txn) => break txn,
207+
None => continue,
208+
}
209+
};
210+
211+
if CommandId::from(txn.cmd()) != CommandId::PRODUCTION_AUTH_DEBUG_UNLOCK_TOKEN {
212+
Err(CaliptraError::SS_DBG_UNLOCK_PROD_INVALID_TOKEN_MBOX_CMD)?;
189213
}
190-
};
191214

192-
if CommandId::from(txn.cmd()) != CommandId::PRODUCTION_AUTH_DEBUG_UNLOCK_TOKEN {
193-
cprintln!(
194-
"Invalid command: {:?}, was expecting PRODUCTION_AUTH_DEBUG_UNLOCK_TOKEN",
195-
txn.cmd()
215+
let mut txn = txn.start_txn();
216+
217+
// Copy token data
218+
let mut token = ProductionAuthDebugUnlockToken::default();
219+
FirmwareProcessor::copy_req_verify_chksum(&mut txn, token.as_mut_bytes(), false)?;
220+
221+
// Use common validation function
222+
let result = debug_unlock::validate_debug_unlock_token(
223+
&env.soc_ifc,
224+
&mut env.sha2_512_384,
225+
&mut env.sha2_512_384_acc,
226+
&mut env.ecc384,
227+
&mut env.mldsa87,
228+
&mut env.dma,
229+
request,
230+
challenge,
231+
&token,
196232
);
197-
Err(CaliptraError::SS_DBG_UNLOCK_PROD_INVALID_TOKEN_MBOX_CMD)?;
198-
}
199233

200-
let mut txn = ManuallyDrop::new(txn.start_txn());
201-
202-
// Copy token from mailbox
203-
let mut token = ProductionAuthDebugUnlockToken::default();
204-
FirmwareProcessor::copy_req_verify_chksum(&mut txn, token.as_mut_bytes(), false)?;
205-
206-
// Use common validation function
207-
let result = debug_unlock::validate_debug_unlock_token(
208-
&env.soc_ifc,
209-
&mut env.sha2_512_384,
210-
&mut env.sha2_512_384_acc,
211-
&mut env.ecc384,
212-
&mut env.mldsa87,
213-
&mut env.dma,
214-
request,
215-
challenge,
216-
&token,
217-
);
218-
219-
// Send response
220-
let _ = txn.send_response(MailboxRespHeader::default().as_bytes());
221-
result
234+
// Send response
235+
if txn
236+
.send_response(MailboxRespHeader::default().as_bytes())
237+
.is_ok()
238+
{
239+
response_sent = true;
240+
}
241+
result
242+
})();
243+
(result, response_sent)
222244
}
223245

224246
fn handle_production(env: &mut RomEnv) -> CaliptraResult<()> {
225247
cprintln!("[dbg_prod] ++");
226248

227-
env.soc_ifc.set_ss_dbg_unlock_in_progress(true);
249+
start_debug_unlock(env);
228250

229-
let mut debug_unlock_op = || -> CaliptraResult<u8> {
230-
let (request, challenge) = handle_auth_debug_unlock_request(env)?;
231-
handle_auth_debug_unlock_token(env, &request, &challenge)?;
232-
Ok(request.unlock_level)
251+
let (result, response_sent) = match handle_auth_debug_unlock_request(env) {
252+
(Ok((request, challenge)), request_response_sent) => {
253+
let (token_result, token_response_sent) =
254+
handle_auth_debug_unlock_token(env, &request, &challenge);
255+
(
256+
token_result.map(|_| request.unlock_level),
257+
request_response_sent || token_response_sent,
258+
)
259+
}
260+
(Err(err), response_sent) => (Err(err), response_sent),
233261
};
234-
235-
let result = debug_unlock_op();
236262
match result {
237263
Ok(unlock_level) => {
238264
env.soc_ifc.set_ss_dbg_unlock_level(unlock_level);
@@ -245,7 +271,7 @@ fn handle_production(env: &mut RomEnv) -> CaliptraResult<()> {
245271
env.soc_ifc.set_ss_dbg_unlock_result(false);
246272
}
247273
}
248-
env.soc_ifc.set_ss_dbg_unlock_in_progress(false);
274+
finish_debug_unlock(env, response_sent);
249275

250276
cprintln!("[dbg_prod] --");
251277
result.map(|_| ())

0 commit comments

Comments
 (0)