This is still very preliminary work, and is mostly designed to show how register fields can be turned into safe types that force us to handle invalid values.
Signed-off-by: Alexandre Courbot <acour...@nvidia.com> --- drivers/gpu/nova-core/driver.rs | 2 +- drivers/gpu/nova-core/falcon.rs | 618 +++++++++++++++++++++++++++++++++++++ drivers/gpu/nova-core/gpu.rs | 13 + drivers/gpu/nova-core/nova_core.rs | 1 + drivers/gpu/nova-core/regs.rs | 188 ++++++++++- 5 files changed, 820 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs index 0cd23aa306e4082405f480afc0530a41131485e7..dee5fd22eecb2ce1f4ea765338b0c1b68853b2d3 100644 --- a/drivers/gpu/nova-core/driver.rs +++ b/drivers/gpu/nova-core/driver.rs @@ -10,7 +10,7 @@ pub(crate) struct NovaCore { pub(crate) gpu: Gpu, } -const BAR0_SIZE: usize = 0x9500; +const BAR0_SIZE: usize = 0x1000000; pub(crate) type Bar0 = pci::Bar<BAR0_SIZE>; kernel::pci_device_table!( diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs new file mode 100644 index 0000000000000000000000000000000000000000..0dd4b45abbe0a62238efe24d899c55d5db348586 --- /dev/null +++ b/drivers/gpu/nova-core/falcon.rs @@ -0,0 +1,618 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Falcon microprocessor base support + +// TODO: remove this once this module is actively used. +#![allow(dead_code)] + +use core::hint::unreachable_unchecked; +use core::marker::PhantomData; +use core::time::Duration; +use kernel::bindings; +use kernel::devres::Devres; +use kernel::{pci, prelude::*}; + +use crate::driver::Bar0; +use crate::gpu::Chipset; +use crate::regs; +use crate::timer::Timer; + +#[repr(u8)] +#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub(crate) enum FalconCoreRev { + #[default] + Rev1 = 1, + Rev2 = 2, + Rev3 = 3, + Rev4 = 4, + Rev5 = 5, + Rev6 = 6, + Rev7 = 7, +} + +impl TryFrom<u32> for FalconCoreRev { + type Error = Error; + + fn try_from(value: u32) -> core::result::Result<Self, Self::Error> { + use FalconCoreRev::*; + + let rev = match value { + 1 => Rev1, + 2 => Rev2, + 3 => Rev3, + 4 => Rev4, + 5 => Rev5, + 6 => Rev6, + 7 => Rev7, + _ => return Err(EINVAL), + }; + + Ok(rev) + } +} + +#[repr(u8)] +#[derive(Debug, Default, Copy, Clone)] +pub(crate) enum FalconSecurityModel { + #[default] + None = 0, + Light = 2, + Heavy = 3, +} + +impl TryFrom<u32> for FalconSecurityModel { + type Error = Error; + + fn try_from(value: u32) -> core::result::Result<Self, Self::Error> { + use FalconSecurityModel::*; + + let sec_model = match value { + 0 => None, + 2 => Light, + 3 => Heavy, + _ => return Err(EINVAL), + }; + + Ok(sec_model) + } +} + +#[repr(u8)] +#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub(crate) enum FalconCoreRevSubversion { + #[default] + Subversion0 = 0, + Subversion1 = 1, + Subversion2 = 2, + Subversion3 = 3, +} + +impl From<u32> for FalconCoreRevSubversion { + fn from(value: u32) -> Self { + use FalconCoreRevSubversion::*; + + match value & 0b11 { + 0 => Subversion0, + 1 => Subversion1, + 2 => Subversion2, + 3 => Subversion3, + // SAFETY: the `0b11` mask limits the possible values to `0..=3`. + 4..=u32::MAX => unsafe { unreachable_unchecked() }, + } + } +} + +#[repr(u8)] +#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)] +pub(crate) enum FalconModSelAlgo { + #[default] + Rsa3k = 1, +} + +impl TryFrom<u32> for FalconModSelAlgo { + type Error = Error; + + fn try_from(value: u32) -> core::result::Result<Self, Self::Error> { + match value { + 1 => Ok(FalconModSelAlgo::Rsa3k), + _ => Err(EINVAL), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum RiscvCoreSelect { + Falcon = 0, + Riscv = 1, +} + +impl From<bool> for RiscvCoreSelect { + fn from(value: bool) -> Self { + match value { + false => RiscvCoreSelect::Falcon, + true => RiscvCoreSelect::Riscv, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum FalconMem { + Imem, + Dmem, +} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub(crate) struct FalconUCodeDescV3 { + pub(crate) hdr: u32, + pub(crate) stored_size: u32, + pub(crate) pkc_data_offset: u32, + pub(crate) interface_offset: u32, + pub(crate) imem_phys_base: u32, + pub(crate) imem_load_size: u32, + pub(crate) imem_virt_base: u32, + pub(crate) dmem_phys_base: u32, + pub(crate) dmem_load_size: u32, + pub(crate) engine_id_mask: u16, + pub(crate) ucode_id: u8, + pub(crate) signature_count: u8, + pub(crate) signature_versions: u16, + _reserved: u16, +} + +impl FalconUCodeDescV3 { + pub(crate) fn ver(&self) -> u8 { + ((self.hdr & 0xff00) >> 8) as u8 + } + + pub(crate) fn size(&self) -> usize { + ((self.hdr & 0xffff0000) >> 16) as usize + } +} + +/// Trait defining the parameters of a given Falcon instance. +pub(crate) trait FalconInstance { + /// Base I/O address for the falcon, relative from which its registers are accessed. + const BASE: usize; +} + +pub(crate) struct Gsp; +impl FalconInstance for Gsp { + const BASE: usize = 0x00110000; +} +pub(crate) type GspFalcon = Falcon<Gsp>; + +pub(crate) struct Sec2; +impl FalconInstance for Sec2 { + const BASE: usize = 0x00840000; +} +pub(crate) type Sec2Falcon = Falcon<Sec2>; + +/// Contains the base parameters common to all Falcon instances. +#[derive(Debug)] +pub(crate) struct Falcon<I: FalconInstance> { + /// Chipset this falcon belongs to. + chipset: Chipset, + /// Whether this falcon is part of a dual falcon/riscv engine. + has_riscv: bool, + _instance: PhantomData<I>, +} + +impl<I: FalconInstance> Falcon<I> { + pub(crate) fn new( + pdev: &pci::Device, + chipset: Chipset, + bar: &Devres<Bar0>, + need_riscv: bool, + ) -> Result<Self> { + let hwcfg1 = with_bar!(bar, |b| regs::FalconHwcfg1::read(b, I::BASE))?; + let rev = hwcfg1.core_rev()?; + let subver = hwcfg1.core_rev_subversion(); + let sec_model = hwcfg1.security_model()?; + + if need_riscv { + let hwcfg2 = with_bar!(bar, |b| regs::FalconHwcfg2::read(b, I::BASE))?; + if !hwcfg2.riscv() { + dev_err!( + pdev.as_ref(), + "riscv support requested on falcon that does not support it\n" + ); + return Err(EINVAL); + } + } + + dev_info!( + pdev.as_ref(), + "new falcon: {:?} {:?} {:?}", + rev, + subver, + sec_model + ); + + Ok(Self { + chipset, + has_riscv: need_riscv, + _instance: PhantomData, + }) + } + + fn select_falcon_core(&self, bar: &Devres<Bar0>, timer: &Timer) -> Result<()> { + if self.has_riscv { + let bcr_ctrl = with_bar!(bar, |b| regs::RiscvBcrCtrl::read(b, I::BASE))?; + if bcr_ctrl.core_select() != RiscvCoreSelect::Falcon { + with_bar!(bar, |b| regs::RiscvBcrCtrl::default() + .set_core_select(RiscvCoreSelect::Falcon) + .write(b, I::BASE))?; + + timer.wait_on(bar, Duration::from_millis(10), || { + bar.try_access_with(|b| regs::RiscvBcrCtrl::read(b, I::BASE)) + .and_then(|v| if v.valid() { Some(()) } else { None }) + })?; + } + } + + Ok(()) + } + + fn reset_wait_mem_scrubbing(&self, bar: &Devres<Bar0>, timer: &Timer) -> Result<()> { + /* TODO: is this needed? */ + with_bar!(bar, |b| regs::FalconMailbox0::alter(b, I::BASE, |v| v))?; + + timer.wait_on(bar, Duration::from_millis(20), || { + bar.try_access_with(|b| regs::FalconHwcfg2::read(b, I::BASE)) + .and_then(|r| if r.mem_scrubbing() { Some(()) } else { None }) + }) + } + + fn reset_prep(&self, bar: &Devres<Bar0>, timer: &Timer) -> Result<()> { + let _ = with_bar!(bar, |b| regs::FalconHwcfg2::read(b, I::BASE))?; + + // Expected to timeout apparently? + // TODO: check why with OpenRM. + let _ = timer.wait_on(bar, Duration::from_micros(150), || { + bar.try_access_with(|b| regs::FalconHwcfg2::read(b, I::BASE)) + .and_then(|r| if r.unk_31() { Some(()) } else { None }) + }); + + Ok(()) + } + + fn reset_eng(&self, bar: &Devres<Bar0>, timer: &Timer) -> Result<()> { + self.reset_prep(bar, timer)?; + + with_bar!(bar, |b| regs::RiscvUnk3c0::alter(b, I::BASE, |v| v + .set_unk0(true)))?; + + let _: Result<()> = timer.wait_on(bar, Duration::from_micros(10), || None); + + with_bar!(bar, |b| regs::RiscvUnk3c0::alter(b, I::BASE, |v| v + .set_unk0(false)))?; + + self.reset_wait_mem_scrubbing(bar, timer)?; + + Ok(()) + } + + fn disable(&self, bar: &Devres<Bar0>, timer: &Timer) -> Result<()> { + self.select_falcon_core(bar, timer)?; + + with_bar!(bar, |b| { + regs::FalconUnk0048::alter(b, I::BASE, |r| r.set_val0(0)); + + regs::FalconIrqmclr::default() + .set_val(u32::MAX) + .write(b, I::BASE) + })?; + + self.reset_eng(bar, timer) + } + + fn enable(&self, bar: &Devres<Bar0>, timer: &Timer) -> Result<()> { + self.reset_eng(bar, timer)?; + self.select_falcon_core(bar, timer)?; + self.reset_wait_mem_scrubbing(bar, timer)?; + + with_bar!(bar, |b| { + // We write Boot0 into FalconRm, for some reason... + regs::FalconRm::default() + .set_val(regs::Boot0::read(b).into()) + .write(b, I::BASE) + }) + } + + pub(crate) fn reset(&self, bar: &Devres<Bar0>, timer: &Timer) -> Result<()> { + self.disable(bar, timer)?; + self.enable(bar, timer) + } + + fn dma_init( + &self, + bar: &Devres<Bar0>, + dma_handle: bindings::dma_addr_t, + mem: FalconMem, + xfer_len: u32, + sec: bool, + ) -> Result<regs::FalconDmaTrfCmd> { + with_bar!(bar, |b| { + regs::FalconDmaTrfBase::default() + .set_base((dma_handle >> 8) as u32) + .write(b, I::BASE); + regs::FalconDmaTrfBase1::default() + .set_base((dma_handle >> 40) as u16) + .write(b, I::BASE) + })?; + + Ok(regs::FalconDmaTrfCmd::default() + .set_size((xfer_len.ilog2() - 2) as u8) + .set_imem(mem == FalconMem::Imem) + .set_sec(if sec { 1 } else { 0 })) + } + + fn dma_xfer( + &self, + bar: &Devres<Bar0>, + mem_base: u32, + dma_base: u32, + cmd: regs::FalconDmaTrfCmd, + ) -> Result<()> { + with_bar!(bar, |b| { + regs::FalconDmaTrfMOffs::default() + .set_offs(mem_base) + .write(b, I::BASE); + regs::FalconDmaTrfBOffs::default() + .set_offs(dma_base) + .write(b, I::BASE); + + cmd.write(b, I::BASE) + }) + } + + fn dma_done(&self, bar: &Devres<Bar0>, timer: &Timer) -> Result<()> { + timer.wait_on(bar, Duration::from_millis(2000), || { + bar.try_access_with(|b| regs::FalconDmaTrfCmd::read(b, I::BASE)) + .and_then(|v| if v.idle() { Some(()) } else { None }) + }) + } + + fn dma_wr( + &self, + bar: &Devres<Bar0>, + timer: &Timer, + dma_handle: bindings::dma_addr_t, + dma_base: u32, + mem: FalconMem, + mem_base: u32, + len: u32, + sec: bool, + ) -> Result<()> { + const DMA_LEN: u32 = 256; + + let (dma_start, dma_addr) = match mem { + FalconMem::Imem => (0, dma_handle), + FalconMem::Dmem => (dma_base, dma_handle + dma_base as bindings::dma_addr_t), + }; + + pr_info!( + "dma write {:?}: dma_handle {:x} dma_start {:x} dma_addr {:x} len {:x}\n", + mem, + dma_handle, + dma_start, + dma_addr, + len + ); + + let cmd = self.dma_init(bar, dma_addr, mem, DMA_LEN, sec)?; + + let mut dst = mem_base; + let mut src = dma_base; + let mut remain = len; + + while remain >= DMA_LEN { + self.dma_xfer(bar, dst, src - dma_start, cmd)?; + self.dma_done(bar, timer)?; + + src += DMA_LEN; + dst += DMA_LEN; + remain -= DMA_LEN; + } + + pr_info!("dma write remain: {} bytes\n", remain); + + Ok(()) + } + + pub(crate) fn dma_load( + &self, + bar: &Devres<Bar0>, + timer: &Timer, + dma_handle: bindings::dma_addr_t, + imem_params: (u32, u32, u32), + dmem_params: (u32, u32, u32), + ) -> Result<()> { + pr_info!("dma_load: {:?} {:?}\n", imem_params, dmem_params); + + with_bar!(bar, |b| { + regs::FalconUnk624::alter(b, I::BASE, |v| v.set_unk7(true)); + regs::FalconDmaCtl::default().write(b, I::BASE); + regs::FalconUnk600::alter(b, I::BASE, |v| v.set_unk16(false).set_unk2((1 << 2) | 1)); + })?; + + self.dma_wr( + bar, + timer, + dma_handle, + imem_params.0, + FalconMem::Imem, + imem_params.1, + imem_params.2, + true, + )?; + self.dma_wr( + bar, + timer, + dma_handle, + dmem_params.0, + FalconMem::Dmem, + dmem_params.1, + dmem_params.2, + true, + )?; + + Ok(()) + } + + pub(crate) fn boot( + &self, + bar: &Devres<Bar0>, + timer: &Timer, + v3_desc: &FalconUCodeDescV3, + mbox0: Option<u32>, + mbox1: Option<u32>, + ) -> Result<(u32, u32)> { + pr_info!("boot 0\n"); + + // Program BROM registers for PKC signature validation. + if self.chipset >= Chipset::GA102 { + let pkc_data_offset = v3_desc.pkc_data_offset; + let engine_id_mask = v3_desc.engine_id_mask; + let ucode_id = v3_desc.ucode_id; + + pr_info!( + "dmem_sign: {:#x}, engine_id: {:#x}, ucode_id: {:#x}", + pkc_data_offset, + engine_id_mask, + ucode_id + ); + + with_bar!(bar, |b| { + regs::FalconBromParaaddr0::default() + .set_addr(pkc_data_offset) + .write(b, I::BASE); + regs::FalconBromEngidmask::default() + .set_mask(engine_id_mask as u32) + .write(b, I::BASE); + regs::FalconBromCurrUcodeId::default() + .set_ucode_id(ucode_id as u32) + .write(b, I::BASE); + regs::FalconModSel::default() + .set_algo(FalconModSelAlgo::Rsa3k) + .write(b, I::BASE); + })?; + } + + pr_info!("boot 1\n"); + + with_bar!(bar, |b| { + if let Some(mbox0) = mbox0 { + regs::FalconMailbox0::default() + .set_mailbox0(mbox0) + .write(b, I::BASE); + } + + if let Some(mbox1) = mbox1 { + regs::FalconMailbox1::default() + .set_mailbox1(mbox1) + .write(b, I::BASE); + } + + // Set `BootVec` to start of non-secure code. + // TODO: use boot vector variable - apparently this is 0 on v3 hdr? + regs::FalconBootVec::default() + .set_boot_vec(0) + .write(b, I::BASE); + + regs::FalconCpuCtl::default() + .set_start_cpu(true) + .write(b, I::BASE); + })?; + + pr_info!("booted!\n"); + timer.wait_on(bar, Duration::from_secs(2), || { + bar.try_access() + .map(|b| regs::FalconCpuCtl::read(&*b, I::BASE)) + .and_then(|v| if v.halted() { Some(()) } else { None }) + })?; + + let (mbox0, mbox1) = with_bar!(bar, |b| { + let mbox0 = regs::FalconMailbox0::read(b, I::BASE).mailbox0(); + let mbox1 = regs::FalconMailbox1::read(b, I::BASE).mailbox1(); + + (mbox0, mbox1) + })?; + + pr_info!("successfully returned {} {}\n", mbox0, mbox1); + + Ok((mbox0, mbox1)) + } +} + +#[repr(C)] +#[derive(Debug)] +struct FalconAppifHdrV1 { + ver: u8, + hdr: u8, + len: u8, + cnt: u8, +} + +#[repr(C)] +#[derive(Debug)] +struct FalconAppifV1 { + id: u32, + dmem_base: u32, +} + +const NVFW_FALCON_APPIF_ID_DMEMMAPPER: u32 = 0x4; + +#[repr(C)] +#[derive(Debug)] +struct FalconAppifDmemmapperV3 { + signature: u32, + version: u16, + size: u16, + cmd_in_buffer_offset: u32, + cmd_in_buffer_size: u32, + cmd_out_buffer_offset: u32, + cmd_out_buffer_size: u32, + nvf_img_data_buffer_offset: u32, + nvf_img_data_buffer_size: u32, + printf_buffer_hdr: u32, + ucode_build_time_stamp: u32, + ucode_signature: u32, + init_cmd: u32, + ucode_feature: u32, + ucode_cmd_mask0: u32, + ucode_cmd_mask1: u32, + multi_tgt_tbl: u32, +} + +pub(crate) const NVFW_FALCON_APPIF_DMEMMAPPER_CMD_FRTS: u32 = 0x15; + +#[derive(Debug)] +#[repr(C)] +struct ReadVbios { + ver: u32, + hdr: u32, + addr: u64, + size: u32, + flags: u32, +} + +#[derive(Debug)] +#[repr(C)] +struct FrtsRegion { + ver: u32, + hdr: u32, + addr: u32, + size: u32, + ftype: u32, +} + +const NVFW_FRTS_CMD_REGION_TYPE_FB: u32 = 2; + +#[derive(Debug)] +#[repr(C)] +struct FrtsCmd { + read_vbios: ReadVbios, + frts_region: FrtsRegion, +} diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index f010d3152530b1cec032ca620e59de51a2fc1a13..ec745dd8175bd3164ed1b865293a526b09c59ab3 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -5,6 +5,7 @@ }; use crate::driver::Bar0; +use crate::falcon::{GspFalcon, Sec2Falcon}; use crate::regs; use crate::timer::Timer; use crate::util; @@ -198,6 +199,18 @@ pub(crate) fn new(pdev: &pci::Device, bar: Devres<Bar0>) -> Result<impl PinInit< ); let timer = Timer::new(); + let _gsp_falcon = GspFalcon::new( + pdev, + spec.chipset, + &bar, + if spec.chipset > Chipset::GA100 { + true + } else { + false + }, + )?; + + let _sec2_falcon = Sec2Falcon::new(pdev, spec.chipset, &bar, false)?; Ok(pin_init!(Self { spec, diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nova_core.rs index f54dcfc66490cb6b10090ef944ac14feca9f6972..35c030485532633a5dd59a8a4a1f6d385cb46c98 100644 --- a/drivers/gpu/nova-core/nova_core.rs +++ b/drivers/gpu/nova-core/nova_core.rs @@ -15,6 +15,7 @@ macro_rules! with_bar { } mod driver; +mod falcon; mod firmware; mod gpu; mod regs; diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs index 0d06e09b1ba62d55688c633500f37d3fe1aeb30e..2952fa7f84c274f122bc12e5506b0b2ac0fbb82d 100644 --- a/drivers/gpu/nova-core/regs.rs +++ b/drivers/gpu/nova-core/regs.rs @@ -2,8 +2,11 @@ use core::ops::Deref; use kernel::io::Io; -use kernel::register; +use kernel::{register, register_rel}; +use crate::falcon::{ + FalconCoreRev, FalconCoreRevSubversion, FalconModSelAlgo, FalconSecurityModel, RiscvCoreSelect, +}; use crate::gpu::Chipset; register!(Boot0@0x00000000, "Basic revision information about the GPU"; @@ -22,3 +25,186 @@ 31:0 hi => as u32, "high 32 bits of the timer" ); +/* PFALCON */ + +register_rel!(FalconIrqsclr@0x00000004; + 4:4 halt => as_bit bool; + 6:6 swgen0 => as_bit bool; +); + +register_rel!(FalconIrqstat@0x00000008; + 4:4 halt => as_bit bool; + 6:6 swgen0 => as_bit bool; +); + +register_rel!(FalconIrqmclr@0x00000014; + 31:0 val => as u32 +); + +register_rel!(FalconIrqmask@0x00000018; + 31:0 val => as u32 +); + +register_rel!(FalconRm@0x00000084; + 31:0 val => as u32 +); + +register_rel!(FalconIrqdest@0x0000001c; + 31:0 val => as u32 +); + +register_rel!(FalconMailbox0@0x00000040; + 31:0 mailbox0 => as u32 +); +register_rel!(FalconMailbox1@0x00000044; + 31:0 mailbox1 => as u32 +); + +register_rel!(FalconUnk0048@0x00000048; + 1:0 val0 => as u32 +); + +register_rel!(FalconHwcfg2@0x000000f4; + 10:10 riscv => as_bit bool; + 12:12 mem_scrubbing => as_bit bool; + 31:31 unk_31 => as_bit bool; +); + +register_rel!(FalconCpuCtl@0x00000100; + 1:1 start_cpu => as_bit bool; + 4:4 halted => as_bit bool; + 6:6 alias_en => as_bit bool; +); +register_rel!(FalconBootVec@0x00000104; + 31:0 boot_vec => as u32 +); + +register_rel!(FalconHwCfg@0x00000108; + 8:0 imem_size => as u32; + 17:9 dmem_size => as u32; +); + +register_rel!(FalconDmaCtl@0x0000010c; + 0:0 require_ctx => as_bit bool; + 1:1 dmem_scrubbing => as_bit bool; + 2:2 imem_scrubbing => as_bit bool; + 6:3 dmaq_num => as_bit u8; + 7:7 secure_stat => as_bit bool; +); + +register_rel!(FalconDmaTrfBase@0x00000110; + 31:0 base => as u32; +); + +register_rel!(FalconDmaTrfMOffs@0x00000114; + 23:0 offs => as u32; +); + +register_rel!(FalconDmaTrfCmd@0x00000118; + 0:0 full => as_bit bool; + 1:1 idle => as_bit bool; + 3:2 sec => as_bit u8; + 4:4 imem => as_bit bool; + 5:5 is_write => as_bit bool; + 10:8 size => as u8; + 14:12 ctxdma => as u8; + 16:16 set_dmtag => as u8; +); + +register_rel!(FalconDmaTrfBOffs@0x0000011c; + 31:0 offs => as u32; +); + +register_rel!(FalconDmaTrfBase1@0x00000128; + 8:0 base => as u16; +); + +register_rel!(FalconHwcfg1@0x0000012c; + 3:0 core_rev => try_into FalconCoreRev, "core revision of the falcon"; + 5:4 security_model => try_into FalconSecurityModel, "security model of the falcon"; + 7:6 core_rev_subversion => into FalconCoreRevSubversion; + 11:8 imem_ports => as u8; + 15:12 dmem_ports => as u8; +); + +// TODO: This should be able to take an index, like +0x180[16; 8]? Then the constructor or read +// method take the port we want to address as argument. +register_rel!(FalconImemC@0x00000180; + 7:2 offs => as u8; + 23:8 blk => as u8; + 24:24 aincw => as_bit bool; + 25:25 aincr => as_bit bool; + 28:28 secure => as_bit bool; + 29:29 sec_atomic => as_bit bool; +); + +register_rel!(FalconImemD@0x00000184; + 31:0 data => as u32; +); + +register_rel!(FalconImemT@0x00000188; + 15:0 data => as u16; +); + +register_rel!(FalconDmemC@0x000001c0; + 23:0 addr => as u32; + 7:2 offs => as u8; + 23:8 blk => as u8; + 24:24 aincw => as_bit bool; + 25:25 aincr => as_bit bool; + 26:26 settag => as_bit bool; + 27:27 setlvl => as_bit bool; + 28:28 va => as_bit bool; + 29:29 miss => as_bit bool; +); + +register_rel!(FalconDmemD@0x000001c4; + 31:0 data => as u32; +); + +register_rel!(FalconModSel@0x00001180; + 7:0 algo => try_into FalconModSelAlgo; +); +register_rel!(FalconBromCurrUcodeId@0x00001198; + 31:0 ucode_id => as u32; +); +register_rel!(FalconBromEngidmask@0x0000119c; + 31:0 mask => as u32; +); +register_rel!(FalconBromParaaddr0@0x00001210; + 31:0 addr => as u32; +); + +register_rel!(RiscvCpuCtl@0x00000388; + 0:0 startcpu => as_bit bool; + 4:4 halted => as_bit bool; + 5:5 stopped => as_bit bool; + 7:7 active_stat => as_bit bool; +); + +register_rel!(RiscvUnk3c0@0x000003c0; + 0:0 unk0 => as_bit bool; +); + +register_rel!(RiscvIrqmask@0x00000528; + 31:0 mask => as u32; +); + +register_rel!(RiscvIrqdest@0x0000052c; + 31:0 dest => as u32; +); + +register_rel!(FalconUnk600@0x00000600; + 16:16 unk16 => as_bit bool; + 2:0 unk2 => as u8; +); + +register_rel!(FalconUnk624@0x00000624; + 7:7 unk7 => as_bit bool; +); + +register_rel!(RiscvBcrCtrl@0x00001668; + 0:0 valid => as_bit bool; + 4:4 core_select => as_bit RiscvCoreSelect; + 8:8 br_fetch => as_bit bool; +); -- 2.48.1