Skip to content

Commit

Permalink
Use SoC interface to talk to Caliptra
Browse files Browse the repository at this point in the history
`caliptra-sw`'s emulator has an "external" SoC interface that can be
used to communicate with it via the standard SoC interface.

This writes a simple adapter layer so that the MCU emulator can mount
that external interface as a peripheral on our root bus.

I also added some code to the ROM that reads the flow status from the
SoC interface as a basic check that the functionality is working. When
running the MCU with a Caliptra ROM and runtime FW, it outputs:

```
Caliptra flow status 40000000
```

When no Caliptra ROM or firmware are provided, the status is 0, so we
can skip straight to Tock in that case (for now).
  • Loading branch information
swenson committed Jan 3, 2025
1 parent ebb25ae commit 04045f4
Show file tree
Hide file tree
Showing 24 changed files with 485 additions and 330 deletions.
5 changes: 5 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ caliptra-api-types = { git = "https://github.com/chipsalliance/caliptra-sw.git",
caliptra-emu-bus = { git = "https://github.com/chipsalliance/caliptra-sw.git", rev = "2f6de531e321b7bb24b17b1bd02b43d2854aef3a" }
caliptra-emu-cpu = { git = "https://github.com/chipsalliance/caliptra-sw.git", rev = "2f6de531e321b7bb24b17b1bd02b43d2854aef3a" }
caliptra-emu-periph = { git = "https://github.com/chipsalliance/caliptra-sw.git", rev = "2f6de531e321b7bb24b17b1bd02b43d2854aef3a" }
caliptra-emu-types = { git = "https://github.com/chipsalliance/caliptra-sw.git", rev = "2f6de531e321b7bb24b17b1bd02b43d2854aef3a" }
caliptra-hw-model = { git = "https://github.com/chipsalliance/caliptra-sw.git", rev = "2f6de531e321b7bb24b17b1bd02b43d2854aef3a" }
caliptra-registers = { git = "https://github.com/chipsalliance/caliptra-sw.git", rev = "2f6de531e321b7bb24b17b1bd02b43d2854aef3a" }

Expand Down
39 changes: 26 additions & 13 deletions emulator/app/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@ use caliptra_emu_cpu::{Cpu as CaliptraMainCpu, StepAction as CaliptraMainStepAct
use caliptra_emu_periph::CaliptraRootBus as CaliptraMainRootBus;
use clap::{ArgAction, Parser};
use crossterm::event::{Event, KeyCode, KeyEvent};
use emulator_bus::{Clock, Timer};
use emulator_bus::{Bus, BusConverter, Clock, Timer};
use emulator_caliptra::{start_caliptra, StartCaliptraArgs};
use emulator_cpu::{Cpu, Pic, RvInstr, StepAction};
use emulator_periph::{CaliptraRootBus, CaliptraRootBusArgs, DummyFlashCtrl, I3c, I3cController};
use emulator_registers_generated::root_bus::AutoRootBus;
use emulator_registers_generated::soc::SocPeripheral;
use emulator_types::ROM_SIZE;
use gdb::gdb_state;
use gdb::gdb_target::GdbTarget;
Expand Down Expand Up @@ -268,7 +269,7 @@ fn run(cli: Emulator, capture_uart_output: bool) -> io::Result<Vec<u8>> {
exit(-1);
}

let caliptra_cpu = if cli.caliptra {
let (caliptra_cpu, soc_to_caliptra) = if cli.caliptra {
if cli.gdb_port.is_some() {
println!("Caliptra CPU cannot be started with GDB enabled");
exit(-1);
Expand All @@ -281,16 +282,15 @@ fn run(cli: Emulator, capture_uart_output: bool) -> io::Result<Vec<u8>> {
println!("Caliptra ROM File is required if Caliptra is enabled");
exit(-1);
}
Some(
start_caliptra(&StartCaliptraArgs {
rom: cli.caliptra_rom.unwrap(),
firmware: cli.caliptra_firmware,
..Default::default()
})
.expect("Failed to start Caliptra CPU"),
)
let (caliptra_cpu, soc_to_caliptra) = start_caliptra(&StartCaliptraArgs {
rom: cli.caliptra_rom.unwrap(),
firmware: cli.caliptra_firmware,
..Default::default()
})
.expect("Failed to start Caliptra CPU");
(Some(caliptra_cpu), Some(soc_to_caliptra))
} else {
None
(None, None)
};

let rom_buffer = read_binary(args_rom, 0)?;
Expand Down Expand Up @@ -397,15 +397,24 @@ fn run(cli: Emulator, capture_uart_output: bool) -> io::Result<Vec<u8>> {
)
.unwrap();

let mut delegates: Vec<Box<dyn Bus>> = vec![Box::new(root_bus)];
let soc_periph = if let Some(soc_to_caliptra) = soc_to_caliptra {
delegates.push(Box::new(BusConverter::new(Box::new(soc_to_caliptra))));
None
} else {
// pass an empty SoC interface that returns 0 for everything
Some(Box::new(FakeSoc {}) as Box<dyn SocPeripheral>)
};

let mut auto_root_bus = AutoRootBus::new(
Some(Box::new(root_bus)),
delegates,
Some(Box::new(i3c)),
Some(Box::new(flash_controller)),
None,
None,
None,
None,
None,
soc_periph,
None,
);

Expand Down Expand Up @@ -442,3 +451,7 @@ fn run(cli: Emulator, capture_uart_output: bool) -> io::Result<Vec<u8>> {

Ok(uart_output.map(|o| o.borrow().clone()).unwrap_or_default())
}

struct FakeSoc {}

impl SocPeripheral for FakeSoc {}
2 changes: 2 additions & 0 deletions emulator/bus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
caliptra-emu-bus.workspace = true
caliptra-emu-types.workspace = true
emulator-types.workspace = true
tock-registers.workspace = true
51 changes: 51 additions & 0 deletions emulator/bus/src/bus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,18 @@ pub enum BusError {
StoreAccessFault,
}

impl From<caliptra_emu_bus::BusError> for BusError {
fn from(value: caliptra_emu_bus::BusError) -> Self {
match value {
caliptra_emu_bus::BusError::InstrAccessFault => BusError::InstrAccessFault,
caliptra_emu_bus::BusError::LoadAddrMisaligned => BusError::LoadAddrMisaligned,
caliptra_emu_bus::BusError::LoadAccessFault => BusError::LoadAccessFault,
caliptra_emu_bus::BusError::StoreAddrMisaligned => BusError::StoreAddrMisaligned,
caliptra_emu_bus::BusError::StoreAccessFault => BusError::StoreAccessFault,
}
}
}

/// Represents an abstract memory bus. Used to read and write from RAM and
/// peripheral addresses.
pub trait Bus {
Expand Down Expand Up @@ -78,3 +90,42 @@ pub trait Bus {
// By default, do nothing
}
}

pub struct BusConverter {
caliptra_bus: Box<dyn caliptra_emu_bus::Bus>,
}

impl BusConverter {
pub fn new(caliptra_bus: Box<dyn caliptra_emu_bus::Bus>) -> Self {
Self { caliptra_bus }
}
}

impl Bus for BusConverter {
fn read(&mut self, size: RvSize, addr: RvAddr) -> Result<RvData, BusError> {
self.caliptra_bus
.read((size as usize).into(), addr as caliptra_emu_types::RvAddr)
.map_err(|x| x.into())
}

fn write(&mut self, size: RvSize, addr: RvAddr, val: RvData) -> Result<(), BusError> {
self.caliptra_bus
.write(
(size as usize).into(),
addr as caliptra_emu_types::RvAddr,
val,
)
.map_err(|x| x.into())
}
fn poll(&mut self) {
self.caliptra_bus.poll();
}

fn warm_reset(&mut self) {
self.caliptra_bus.warm_reset();
}

fn update_reset(&mut self) {
self.caliptra_bus.update_reset();
}
}
2 changes: 1 addition & 1 deletion emulator/bus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ mod register_array;
mod rom;
pub mod testing;

pub use crate::bus::{Bus, BusError, Trap};
pub use crate::bus::{Bus, BusConverter, BusError, Trap};
pub use crate::clock::{ActionHandle, Clock, Timer, TimerAction};
pub use crate::dynamic_bus::DynamicBus;
pub use crate::ram::Ram;
Expand Down
9 changes: 6 additions & 3 deletions emulator/caliptra/src/caliptra.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use caliptra_emu_cpu::Cpu;
use caliptra_emu_periph::soc_reg::DebugManufService;
use caliptra_emu_periph::{
CaliptraRootBus, CaliptraRootBusArgs, DownloadIdevidCsrCb, MailboxInternal, ReadyForFwCb,
TbServicesCb, UploadUpdateFwCb,
SocToCaliptraBus, TbServicesCb, UploadUpdateFwCb,
};
use caliptra_hw_model::BusMmio;
use std::fs::File;
Expand Down Expand Up @@ -64,7 +64,9 @@ pub struct StartCaliptraArgs {
}

/// Creates and returns an initialized a Caliptra emulator CPU.
pub fn start_caliptra(args: &StartCaliptraArgs) -> io::Result<Cpu<CaliptraRootBus>> {
pub fn start_caliptra(
args: &StartCaliptraArgs,
) -> io::Result<(Cpu<CaliptraRootBus>, SocToCaliptraBus)> {
let args_rom = &args.rom;
let args_current_fw = &args.firmware;
let args_update_fw = &args.update_firmware;
Expand Down Expand Up @@ -295,7 +297,8 @@ pub fn start_caliptra(args: &StartCaliptraArgs) -> io::Result<Cpu<CaliptraRootBu
.write(|_| (wdt_timeout >> 32) as u32);
}

Ok(Cpu::new(root_bus, clock))
let ext_soc_ifc = root_bus.soc_to_caliptra_bus();
Ok((Cpu::new(root_bus, clock), ext_soc_ifc))
}

fn change_dword_endianess(data: &mut [u8]) {
Expand Down
2 changes: 1 addition & 1 deletion emulator/periph/src/flash_ctrl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,7 @@ mod test {
}

AutoRootBus::new(
None,
vec![],
None,
Some(flash_controller),
None,
Expand Down
2 changes: 1 addition & 1 deletion emulator/periph/src/i3c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ mod tests {
.tcri_send(DynamicI3cAddress::new(8).unwrap(), cmd)
.unwrap();

let mut bus = AutoRootBus::new(None, Some(i3c), None, None, None, None, None, None, None);
let mut bus = AutoRootBus::new(vec![], Some(i3c), None, None, None, None, None, None, None);
for _ in 0..10000 {
clock.increment_and_process_timer_actions(1, &mut bus);
}
Expand Down
1 change: 1 addition & 0 deletions registers/generated-emulator/src/entropy_src.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#[allow(unused_imports)]
use tock_registers::interfaces::{Readable, Writeable};
pub trait EntropySrcPeripheral {
fn set_dma_ram(&mut self, _ram: std::rc::Rc<std::cell::RefCell<emulator_bus::Ram>>) {}
fn poll(&mut self) {}
fn warm_reset(&mut self) {}
fn update_reset(&mut self) {}
Expand Down
1 change: 1 addition & 0 deletions registers/generated-emulator/src/otp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#[allow(unused_imports)]
use tock_registers::interfaces::{Readable, Writeable};
pub trait OtpPeripheral {
fn set_dma_ram(&mut self, _ram: std::rc::Rc<std::cell::RefCell<emulator_bus::Ram>>) {}
fn poll(&mut self) {}
fn warm_reset(&mut self) {}
fn update_reset(&mut self) {}
Expand Down
40 changes: 22 additions & 18 deletions registers/generated-emulator/src/root_bus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// generated by registers_generator with caliptra-ss repo at a621fff9df7015821eda6f7f73265fef74a01375
//
pub struct AutoRootBus {
delegate: Option<Box<dyn emulator_bus::Bus>>,
delegates: Vec<Box<dyn emulator_bus::Bus>>,
pub i3c_periph: Option<crate::i3c::I3cBus>,
pub flash_periph: Option<crate::flash::FlashBus>,
pub entropy_src_periph: Option<crate::entropy_src::EntropySrcBus>,
Expand All @@ -16,7 +16,7 @@ pub struct AutoRootBus {
impl AutoRootBus {
#[allow(clippy::too_many_arguments)]
pub fn new(
delegate: Option<Box<dyn emulator_bus::Bus>>,
delegates: Vec<Box<dyn emulator_bus::Bus>>,
i3c_periph: Option<Box<dyn crate::i3c::I3cPeripheral>>,
flash_periph: Option<Box<dyn crate::flash::FlashPeripheral>>,
entropy_src_periph: Option<Box<dyn crate::entropy_src::EntropySrcPeripheral>>,
Expand All @@ -27,7 +27,7 @@ impl AutoRootBus {
el2_pic_periph: Option<Box<dyn crate::el2_pic::El2PicPeripheral>>,
) -> Self {
Self {
delegate,
delegates,
i3c_periph: i3c_periph.map(|p| crate::i3c::I3cBus { periph: p }),
flash_periph: flash_periph.map(|p| crate::flash::FlashBus { periph: p }),
entropy_src_periph: entropy_src_periph
Expand Down Expand Up @@ -106,14 +106,16 @@ impl emulator_bus::Bus for AutoRootBus {
}
_ => Err(emulator_bus::BusError::LoadAccessFault),
};
if let Some(delegate) = self.delegate.as_mut() {
match result {
Err(emulator_bus::BusError::LoadAccessFault) => delegate.read(size, addr),
_ => result,
if !matches!(result, Err(emulator_bus::BusError::LoadAccessFault)) {
return result;
}
for delegate in self.delegates.iter_mut() {
let result = delegate.read(size, addr);
if !matches!(result, Err(emulator_bus::BusError::LoadAccessFault)) {
return result;
}
} else {
result
}
result
}
fn write(
&mut self,
Expand Down Expand Up @@ -180,14 +182,16 @@ impl emulator_bus::Bus for AutoRootBus {
}
_ => Err(emulator_bus::BusError::StoreAccessFault),
};
if let Some(delegate) = self.delegate.as_mut() {
match result {
Err(emulator_bus::BusError::StoreAccessFault) => delegate.write(size, addr, val),
_ => result,
if !matches!(result, Err(emulator_bus::BusError::StoreAccessFault)) {
return result;
}
for delegate in self.delegates.iter_mut() {
let result = delegate.write(size, addr, val);
if !matches!(result, Err(emulator_bus::BusError::StoreAccessFault)) {
return result;
}
} else {
result
}
result
}
fn poll(&mut self) {
if let Some(periph) = self.i3c_periph.as_mut() {
Expand All @@ -214,7 +218,7 @@ impl emulator_bus::Bus for AutoRootBus {
if let Some(periph) = self.el2_pic_periph.as_mut() {
periph.poll();
}
if let Some(delegate) = self.delegate.as_mut() {
for delegate in self.delegates.iter_mut() {
delegate.poll();
}
}
Expand Down Expand Up @@ -243,7 +247,7 @@ impl emulator_bus::Bus for AutoRootBus {
if let Some(periph) = self.el2_pic_periph.as_mut() {
periph.warm_reset();
}
if let Some(delegate) = self.delegate.as_mut() {
for delegate in self.delegates.iter_mut() {
delegate.warm_reset();
}
}
Expand Down Expand Up @@ -272,7 +276,7 @@ impl emulator_bus::Bus for AutoRootBus {
if let Some(periph) = self.el2_pic_periph.as_mut() {
periph.update_reset();
}
if let Some(delegate) = self.delegate.as_mut() {
for delegate in self.delegates.iter_mut() {
delegate.update_reset();
}
}
Expand Down
Loading

0 comments on commit 04045f4

Please sign in to comment.