riscv: initial support for hifive unmatched
This commit is contained in:
@@ -2,7 +2,8 @@ use alloc::{sync::Arc, vec::Vec};
|
||||
use device_api::{
|
||||
device::{Device, DeviceInitContext},
|
||||
interrupt::{
|
||||
ExternalInterruptController, InterruptHandler, Irq, IrqHandle, IrqOptions, IrqVector,
|
||||
ExternalInterruptController, InterruptHandler, Irq, IrqHandle, IrqOptions, IrqPriority,
|
||||
IrqVector,
|
||||
},
|
||||
};
|
||||
use device_tree::{
|
||||
@@ -103,6 +104,64 @@ pub struct Plic {
|
||||
}
|
||||
|
||||
impl Plic {
|
||||
fn ensure_init(&self) -> Result<(), Error> {
|
||||
self.inner.or_try_init_with(|| {
|
||||
log::info!("Initialize RISC-V PLIC");
|
||||
|
||||
let common =
|
||||
unsafe { DeviceMemoryIo::<CommonRegs>::map(self.base, Default::default())? };
|
||||
|
||||
for i in 0..self.max_irq {
|
||||
common.PRIORITY[i].set(0);
|
||||
}
|
||||
|
||||
for context in self.context_map.iter() {
|
||||
let enable_offset = ENABLE_BASE + context.index * ENABLE_STRIDE;
|
||||
let control_offset = CONTROL_BASE + context.index * CONTROL_STRIDE;
|
||||
|
||||
log::info!(
|
||||
"* HART {}: context {}, enable={:#x}, control={:#x}",
|
||||
context.hart,
|
||||
context.index,
|
||||
enable_offset,
|
||||
control_offset
|
||||
);
|
||||
let enable = unsafe {
|
||||
DeviceMemoryIo::<ContextEnableRegs>::map(
|
||||
self.base.add(enable_offset),
|
||||
Default::default(),
|
||||
)?
|
||||
};
|
||||
let control = unsafe {
|
||||
DeviceMemoryIo::<ContextControlRegs>::map(
|
||||
self.base.add(control_offset),
|
||||
Default::default(),
|
||||
)?
|
||||
};
|
||||
|
||||
for i in 0..self.max_irq.div_ceil(32) {
|
||||
enable.ENABLE[i].set(0);
|
||||
}
|
||||
control.THRESHOLD.set(0);
|
||||
|
||||
context.context.init(Context {
|
||||
enable: IrqSafeRwLock::new(enable),
|
||||
control: IrqSafeRwLock::new(control),
|
||||
table: FixedInterruptTable::new(MAX_IRQS), // table: IrqSafeRwLock::new(FixedInterruptTable::new()),
|
||||
});
|
||||
}
|
||||
|
||||
// self.inner.init(Inner {
|
||||
// common: IrqSafeRwLock::new(common),
|
||||
// });
|
||||
|
||||
Ok(Inner {
|
||||
common: IrqSafeRwLock::new(common),
|
||||
})
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn hart_context(&self, hart: u32) -> Option<&HartContext> {
|
||||
self.context_map.iter().find(|c| c.hart == hart)
|
||||
}
|
||||
@@ -153,11 +212,20 @@ impl ExternalInterruptController for Plic {
|
||||
fn register_irq(
|
||||
&self,
|
||||
irq: Irq,
|
||||
_options: IrqOptions,
|
||||
options: IrqOptions,
|
||||
handler: Arc<dyn InterruptHandler>,
|
||||
) -> Result<(), Error> {
|
||||
self.ensure_init()?;
|
||||
let bsp_hart_id = boot_hart_id() as u32;
|
||||
let irq = self.validate_irq(irq)?;
|
||||
let prioval = match options.priority {
|
||||
IrqPriority::Low => 3,
|
||||
IrqPriority::Normal => 5,
|
||||
IrqPriority::High => 7,
|
||||
};
|
||||
let inner = self.inner.get();
|
||||
let common = inner.common.write();
|
||||
common.PRIORITY[irq as usize - 1].set(prioval);
|
||||
let context = self
|
||||
.hart_context(bsp_hart_id)
|
||||
.ok_or(Error::InvalidArgument)
|
||||
@@ -186,68 +254,24 @@ impl ExternalInterruptController for Plic {
|
||||
let control = context.control.write();
|
||||
// let table = context.table.read();
|
||||
|
||||
loop {
|
||||
let irq = control.CLAIM.get();
|
||||
if irq == 0 {
|
||||
break;
|
||||
}
|
||||
let vector = IrqVector::Irq(Irq::External(irq));
|
||||
|
||||
if !context.table.handle_irq_line(irq as usize, vector) {
|
||||
log::warn!("plic: no handler for IRQ #{irq}");
|
||||
}
|
||||
|
||||
// Done servicing
|
||||
control.CLAIM.set(irq);
|
||||
let irq = control.CLAIM.get();
|
||||
if irq == 0 {
|
||||
return;
|
||||
}
|
||||
let vector = IrqVector::Irq(Irq::External(irq));
|
||||
|
||||
if !context.table.handle_irq_line(irq as usize, vector) {
|
||||
log::warn!("plic: no handler for IRQ #{irq}");
|
||||
}
|
||||
|
||||
// Done servicing
|
||||
control.CLAIM.set(irq);
|
||||
}
|
||||
}
|
||||
|
||||
impl Device for Plic {
|
||||
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
|
||||
log::info!("Initialize RISC-V PLIC");
|
||||
|
||||
let common = DeviceMemoryIo::<CommonRegs>::map(self.base, Default::default())?;
|
||||
|
||||
for i in 0..self.max_irq {
|
||||
common.PRIORITY[i].set(3);
|
||||
}
|
||||
|
||||
for context in self.context_map.iter() {
|
||||
let enable_offset = ENABLE_BASE + context.index * ENABLE_STRIDE;
|
||||
let control_offset = CONTROL_BASE + context.index * CONTROL_STRIDE;
|
||||
|
||||
log::info!(
|
||||
"* HART {}: context {}, enable={:#x}, control={:#x}",
|
||||
context.hart,
|
||||
context.index,
|
||||
enable_offset,
|
||||
control_offset
|
||||
);
|
||||
let enable = DeviceMemoryIo::<ContextEnableRegs>::map(
|
||||
self.base.add(enable_offset),
|
||||
Default::default(),
|
||||
)?;
|
||||
let control = DeviceMemoryIo::<ContextControlRegs>::map(
|
||||
self.base.add(control_offset),
|
||||
Default::default(),
|
||||
)?;
|
||||
|
||||
for i in 0..self.max_irq.div_ceil(32) {
|
||||
enable.ENABLE[i].set(0);
|
||||
}
|
||||
control.THRESHOLD.set(0);
|
||||
|
||||
context.context.init(Context {
|
||||
enable: IrqSafeRwLock::new(enable),
|
||||
control: IrqSafeRwLock::new(control),
|
||||
table: FixedInterruptTable::new(MAX_IRQS), // table: IrqSafeRwLock::new(FixedInterruptTable::new()),
|
||||
});
|
||||
}
|
||||
|
||||
self.inner.init(Inner {
|
||||
common: IrqSafeRwLock::new(common),
|
||||
});
|
||||
self.ensure_init()?;
|
||||
|
||||
register_external_interrupt_controller(self);
|
||||
|
||||
@@ -301,6 +325,7 @@ device_tree_driver! {
|
||||
) else {
|
||||
continue;
|
||||
};
|
||||
log::info!("Context #{context}: mode={mode:?}, hart={hart_id}");
|
||||
if mode != ContextMode::ExternalS {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
clock::{ClockController, ClockHandle, Hertz},
|
||||
device::Device,
|
||||
};
|
||||
use device_tree::{
|
||||
DeviceTreePropertyRead, TProp,
|
||||
driver::{DeviceTreeClockController, Node, ProbeContext, device_tree_driver},
|
||||
};
|
||||
use libk::error::Error;
|
||||
use libk_mm::device::DeviceMemoryIo;
|
||||
use libk_util::sync::IrqSafeSpinlock;
|
||||
use tock_registers::{
|
||||
interfaces::Readable,
|
||||
register_bitfields, register_structs,
|
||||
registers::{ReadOnly, ReadWrite},
|
||||
};
|
||||
|
||||
// const CLK_COREPLL: u32 = 0;
|
||||
// const CLK_DDRPLL: u32 = 1;
|
||||
// const CLK_GEMGXLPLL: u32 = 2;
|
||||
// const CLK_DVFSCOREPLL: u32 = 3;
|
||||
// const CLK_HFPCLKPLL: u32 = 4;
|
||||
// const CLK_CLTXPLL: u32 = 5;
|
||||
// const CLK_TLCLK: u32 = 6;
|
||||
const CLK_PCLK: u32 = 7;
|
||||
// const CLK_PCIE_AUX: u32 = 8;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct WrpllData {
|
||||
divr: u32,
|
||||
divf: u32,
|
||||
divq: u32,
|
||||
int_feedback: bool,
|
||||
}
|
||||
|
||||
register_bitfields! {
|
||||
u32,
|
||||
PllCfg [
|
||||
PLLR OFFSET(0) NUMBITS(6) [],
|
||||
PLLF OFFSET(6) NUMBITS(9) [],
|
||||
PLLQ OFFSET(15) NUMBITS(3) [],
|
||||
PLLBYPASS OFFSET(24) NUMBITS(1) [],
|
||||
PLLFSEBYPASS OFFSET(25) NUMBITS(1) [],
|
||||
PLLLOCK OFFSET(31) NUMBITS(1) [],
|
||||
]
|
||||
}
|
||||
|
||||
impl WrpllData {
|
||||
fn fbdiv(&self) -> u32 {
|
||||
if self.int_feedback { 2 } else { 1 }
|
||||
}
|
||||
|
||||
fn output_rate(&self, input_rate: Hertz) -> Hertz {
|
||||
let fbdiv = self.fbdiv();
|
||||
let n = input_rate * fbdiv * (self.divf + 1);
|
||||
let n = n / (self.divr + 1);
|
||||
n >> self.divq
|
||||
}
|
||||
}
|
||||
|
||||
register_structs! {
|
||||
Regs {
|
||||
(0x00 => hfxosccfg: ReadWrite<u32>),
|
||||
(0x04 => core_pllcfg: ReadWrite<u32>),
|
||||
(0x08 => core_plloutdiv: ReadWrite<u32>),
|
||||
(0x0C => ddr_pllcfg: ReadWrite<u32>),
|
||||
(0x10 => ddr_plloutdiv: ReadWrite<u32>),
|
||||
(0x14 => _0),
|
||||
(0x1C => gemgxl_pllcfg: ReadWrite<u32, PllCfg::Register>),
|
||||
(0x20 => gemgxl_plloutdiv: ReadWrite<u32>),
|
||||
(0x24 => core_clk_sel_reg: ReadWrite<u32>),
|
||||
(0x28 => devices_reset_n: ReadWrite<u32>),
|
||||
(0x2C => clk_mux_status: ReadOnly<u32>),
|
||||
(0x30 => _1),
|
||||
(0x38 => dvfs_core_pllcfg: ReadWrite<u32>),
|
||||
(0x3C => dvfs_core_plloutdiv: ReadWrite<u32>),
|
||||
(0x40 => corepllsel: ReadWrite<u32>),
|
||||
(0x44 => _2),
|
||||
(0x50 => hfpclk_pllcfg: ReadWrite<u32, PllCfg::Register>),
|
||||
(0x54 => hfpclk_plloutdiv: ReadWrite<u32>),
|
||||
(0x58 => hfpclkpllsel: ReadWrite<u32>),
|
||||
(0x5C => hfpclk_div_reg: ReadWrite<u32>),
|
||||
(0x60 => _3),
|
||||
(0xE0 => prci_plls: ReadOnly<u32>),
|
||||
(0xE4 => _4),
|
||||
(0x100 => @END),
|
||||
}
|
||||
}
|
||||
|
||||
struct Prci {
|
||||
clk_hfclk: ClockHandle,
|
||||
clk_rtcclk: ClockHandle,
|
||||
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
|
||||
}
|
||||
|
||||
impl Regs {
|
||||
fn read_hfpclk_pll(&self) -> WrpllData {
|
||||
let reg = self.hfpclk_pllcfg.extract();
|
||||
let divr = reg.read(PllCfg::PLLR);
|
||||
let divq = reg.read(PllCfg::PLLQ);
|
||||
let divf = reg.read(PllCfg::PLLF);
|
||||
WrpllData {
|
||||
divq,
|
||||
divr,
|
||||
divf,
|
||||
int_feedback: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Device for Prci {
|
||||
fn display_name(&self) -> &str {
|
||||
"sifive,fu740-c000-prci"
|
||||
}
|
||||
}
|
||||
|
||||
impl ClockController for Prci {
|
||||
fn clock_rate(&self, clock: Option<u32>) -> Result<Hertz, Error> {
|
||||
// hart frequency: coreclk, supplied either by corepll or dvfscorepll, selected by
|
||||
// corepllsel
|
||||
// hfpclkpll: clock for SPI, UART, GPIO, I2C, PWM
|
||||
//
|
||||
let _ = &self.clk_rtcclk;
|
||||
let regs = self.regs.lock();
|
||||
match clock {
|
||||
Some(CLK_PCLK) => {
|
||||
// PCLK calculation:
|
||||
// pclk <- X / hfpclkdiv
|
||||
// case [hfpclkpllsel]:
|
||||
// 1: X <- (hfclk)
|
||||
// 0: X <- hfpclkpllcfg/out & hfpclkpll
|
||||
// hfpclkdiv <- [hfpclk_div_reg] + 2
|
||||
|
||||
let hfpclkpllsel = regs.hfpclkpllsel.get() & 1 != 0;
|
||||
let hfpclk_div_reg = regs.hfpclk_div_reg.get() + 2;
|
||||
let x = match hfpclkpllsel {
|
||||
true => self.clk_hfclk.rate()?,
|
||||
false => {
|
||||
let pclk_pll = regs.read_hfpclk_pll();
|
||||
pclk_pll.output_rate(self.clk_hfclk.rate()?)
|
||||
}
|
||||
};
|
||||
Ok(x / hfpclk_div_reg)
|
||||
}
|
||||
Some(_) => {
|
||||
todo!();
|
||||
}
|
||||
None => {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn set_clock_rate(&self, _clock: Option<u32>, _rate: Hertz) -> Result<Hertz, Error> {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
|
||||
fn enable_clock(&self, _clock: Option<u32>) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn disable_clock(&self, _clock: Option<u32>) -> Result<(), Error> {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceTreeClockController for Prci {
|
||||
fn map_clock(self: Arc<Self>, property: &TProp, offset: usize) -> Option<(ClockHandle, usize)> {
|
||||
let clock = property.read_cell(offset, 1)? as u32;
|
||||
Some((
|
||||
ClockHandle {
|
||||
parent: self.clone(),
|
||||
clock: Some(clock),
|
||||
},
|
||||
1,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
device_tree_driver! {
|
||||
compatible: ["sifive,fu740-c000-prci"],
|
||||
driver: {
|
||||
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
let base = node.map_base(context, 0)?;
|
||||
let clk_hfclk = node.clock(0)?;
|
||||
let clk_rtcclk = node.clock(1)?;
|
||||
|
||||
let regs = unsafe { DeviceMemoryIo::map(base, Default::default()) }.ok()?;
|
||||
|
||||
let prci = Arc::new(Prci {
|
||||
regs: IrqSafeSpinlock::new(regs),
|
||||
clk_hfclk,
|
||||
clk_rtcclk
|
||||
});
|
||||
|
||||
node.make_clock_controller(prci.clone());
|
||||
|
||||
Some(prci)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
mod clock;
|
||||
mod clock_fu540;
|
||||
mod clock_fu740;
|
||||
mod ethernet;
|
||||
mod uart;
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
clock::{ClockHandle, Hertz},
|
||||
device::{Device, DeviceInitContext},
|
||||
interrupt::{InterruptHandler, IrqHandle, IrqVector},
|
||||
interrupt::{InterruptHandler, IrqHandle, IrqPriority, IrqVector},
|
||||
};
|
||||
use device_tree::driver::{Node, ProbeContext, device_tree_driver};
|
||||
use libk::{
|
||||
@@ -16,9 +18,12 @@ use libk_util::{OneTimeInit, sync::IrqSafeSpinlock};
|
||||
use tock_registers::{
|
||||
interfaces::{Readable, Writeable},
|
||||
register_bitfields, register_structs,
|
||||
registers::{ReadOnly, ReadWrite, WriteOnly},
|
||||
registers::{ReadOnly, ReadWrite},
|
||||
};
|
||||
use yggdrasil_abi::{
|
||||
io::{TerminalOptions, TerminalOutputOptions},
|
||||
process::ProcessId,
|
||||
};
|
||||
use yggdrasil_abi::io::{TerminalOptions, TerminalOutputOptions};
|
||||
|
||||
register_bitfields! {
|
||||
u32,
|
||||
@@ -42,7 +47,7 @@ register_bitfields! {
|
||||
|
||||
register_structs! {
|
||||
Regs {
|
||||
(0x00 => txdata: WriteOnly<u32>),
|
||||
(0x00 => txdata: ReadWrite<u32>),
|
||||
(0x04 => rxdata: ReadOnly<u32>),
|
||||
(0x08 => txctrl: ReadWrite<u32, txctrl::Register>),
|
||||
(0x0C => rxctrl: ReadWrite<u32, rxctrl::Register>),
|
||||
@@ -57,6 +62,7 @@ register_structs! {
|
||||
struct Inner {
|
||||
clock: ClockHandle,
|
||||
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
|
||||
active: AtomicBool,
|
||||
}
|
||||
|
||||
struct Uart {
|
||||
@@ -69,6 +75,7 @@ struct Uart {
|
||||
|
||||
impl Regs {
|
||||
fn set_baud_rate(&self, input_clk: Hertz, baud: u32) -> Result<(), Error> {
|
||||
// Check: given f_in=130MHz, baud=115200 should give div = 0x468
|
||||
let div = Hertz::divider(input_clk, Hertz::from(baud)).ok_or(Error::InvalidArgument)?;
|
||||
if div >= (1 << 20) || div == 0 {
|
||||
return Err(Error::InvalidArgument);
|
||||
@@ -84,9 +91,25 @@ impl Regs {
|
||||
(input_clk / div).0 as u32
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_txfifo_full(&self) -> bool {
|
||||
self.txdata.get() & (1 << 31) != 0
|
||||
}
|
||||
|
||||
fn read(&self) -> Option<u8> {
|
||||
let val = self.rxdata.get();
|
||||
if val & (1 << 31) == 0 {
|
||||
Some(val as u8)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn write(&self, byte: u8) {
|
||||
while !self.ip.matches_all(interrupt::txwm::SET) {
|
||||
core::hint::spin_loop();
|
||||
while self.is_txfifo_full() {
|
||||
for _ in 0..10000 {
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
}
|
||||
self.txdata.set(byte as u32);
|
||||
}
|
||||
@@ -98,6 +121,7 @@ impl Device for Uart {
|
||||
|
||||
self.clock.enable()?;
|
||||
let input_clk = self.clock.rate()?;
|
||||
log::info!("input_clk = {input_clk}");
|
||||
|
||||
{
|
||||
let _guard = debug::MuteGuard::acquire();
|
||||
@@ -106,13 +130,18 @@ impl Device for Uart {
|
||||
regs.rxctrl.write(rxctrl::rxen::CLEAR);
|
||||
regs.set_baud_rate(input_clk, 115200)?;
|
||||
regs.txctrl.write(txctrl::txen::SET + txctrl::txcnt.val(3));
|
||||
regs.rxctrl.write(rxctrl::rxen::SET + rxctrl::rxcnt.val(0));
|
||||
}
|
||||
|
||||
// Drain Rx FIFO
|
||||
while regs.read().is_some() {
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
|
||||
let input = TerminalInput::with_capacity(64)?;
|
||||
let output = Inner {
|
||||
regs: IrqSafeSpinlock::new(regs),
|
||||
clock: self.clock.clone(),
|
||||
active: AtomicBool::new(false),
|
||||
};
|
||||
|
||||
let terminal = self.inner.init(Arc::new(Terminal::from_parts(
|
||||
@@ -130,10 +159,9 @@ impl Device for Uart {
|
||||
}
|
||||
|
||||
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
|
||||
self.irq.register(self.clone())?;
|
||||
self.irq
|
||||
.register_with_priority(IrqPriority::Low, self.clone())?;
|
||||
self.irq.enable()?;
|
||||
let regs = self.inner.get().output().regs.lock();
|
||||
regs.ie.write(interrupt::rxwm::SET);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -145,15 +173,27 @@ impl Device for Uart {
|
||||
impl InterruptHandler for Uart {
|
||||
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
|
||||
let terminal = self.inner.get();
|
||||
let byte = {
|
||||
let regs = terminal.output().regs.lock();
|
||||
if regs.ip.matches_all(interrupt::rxwm::SET) {
|
||||
regs.rxdata.get() as u8
|
||||
} else {
|
||||
return false;
|
||||
let regs = terminal.output().regs.lock();
|
||||
let ip = regs.ip.extract();
|
||||
if ip.get() == 0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut count = 0;
|
||||
let mut bytes = [0; 32];
|
||||
// if ip.matches_all(interrupt::rxwm::SET) {
|
||||
while let Some(byte) = regs.read() {
|
||||
bytes[count] = byte;
|
||||
count += 1;
|
||||
}
|
||||
// }
|
||||
drop(regs);
|
||||
for &byte in &bytes[..count] {
|
||||
if byte != 0 {
|
||||
terminal.write_to_input(byte);
|
||||
}
|
||||
};
|
||||
terminal.write_to_input(byte);
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
@@ -172,6 +212,20 @@ impl DebugSink for Uart {
|
||||
}
|
||||
|
||||
impl TerminalOutput for Inner {
|
||||
fn open(&self, _pid: ProcessId) -> Result<(), Error> {
|
||||
if !self.active.swap(true, Ordering::Acquire) {
|
||||
log::info!("sifive-uart: start");
|
||||
let regs = self.regs.lock();
|
||||
regs.rxctrl.write(rxctrl::rxen::SET + rxctrl::rxcnt.val(0));
|
||||
// Drain Rx FIFO
|
||||
while regs.read().is_some() {
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
regs.ie.write(interrupt::rxwm::SET);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write(&self, byte: u8, options: &TerminalOutputOptions) -> Result<(), Error> {
|
||||
let regs = self.regs.lock();
|
||||
if byte == b'\n' && options.contains(TerminalOutputOptions::NL_TO_CRNL) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use core::{
|
||||
fmt,
|
||||
ops::{Div, Mul},
|
||||
ops::{Div, Mul, Shr},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
@@ -48,6 +48,14 @@ impl From<u64> for Hertz {
|
||||
}
|
||||
}
|
||||
|
||||
impl Shr<u32> for Hertz {
|
||||
type Output = Hertz;
|
||||
|
||||
fn shr(self, rhs: u32) -> Self::Output {
|
||||
Self(self.0 >> rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<u32> for Hertz {
|
||||
type Output = Hertz;
|
||||
|
||||
|
||||
@@ -34,10 +34,19 @@ pub enum IrqTrigger {
|
||||
Level,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum IrqPriority {
|
||||
Low,
|
||||
#[default]
|
||||
Normal,
|
||||
High,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct IrqOptions {
|
||||
pub level: IrqLevel,
|
||||
pub trigger: IrqTrigger,
|
||||
pub priority: IrqPriority,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
@@ -152,6 +161,18 @@ impl IrqHandle {
|
||||
self.intc.register_irq(self.irq, self.options, handler)
|
||||
}
|
||||
|
||||
pub fn register_with_priority(
|
||||
&self,
|
||||
priority: IrqPriority,
|
||||
handler: Arc<dyn InterruptHandler>,
|
||||
) -> Result<(), Error> {
|
||||
let options = IrqOptions {
|
||||
priority,
|
||||
..self.options
|
||||
};
|
||||
self.intc.register_irq(self.irq, options, handler)
|
||||
}
|
||||
|
||||
pub fn enable(&self) -> Result<(), Error> {
|
||||
self.intc.enable_irq(self.irq)
|
||||
}
|
||||
|
||||
@@ -54,11 +54,7 @@ impl<K: Eq, V> LruCacheBucket<K, V> {
|
||||
pub fn entry_mut(&mut self, key: &K) -> EntryMut<'_, K, V> {
|
||||
let mut cursor = self.data.cursor_front_mut();
|
||||
|
||||
loop {
|
||||
let Some(node) = cursor.current() else {
|
||||
break;
|
||||
};
|
||||
|
||||
while let Some(node) = cursor.current() {
|
||||
// If entry found corresponding to the key, remove it and reinsert at the front
|
||||
if &node.0 == key {
|
||||
// Safety: just checked it's not None above, so safe
|
||||
|
||||
@@ -26,7 +26,7 @@ pub struct DeviceTreeOptions {
|
||||
impl Default for DebugOptions {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
serial_level: LogLevel::Info,
|
||||
serial_level: LogLevel::Debug,
|
||||
display_level: LogLevel::Info,
|
||||
disable_program_trace: false,
|
||||
}
|
||||
|
||||
@@ -102,6 +102,8 @@ pub fn kinit() -> Result<(), Error> {
|
||||
load_kernel_symbol_table(&mut ioctx, "/kernel.sym")?;
|
||||
}
|
||||
|
||||
log::info!("Starting init");
|
||||
|
||||
{
|
||||
let group_id = Process::create_group();
|
||||
let options = LoadOptions {
|
||||
|
||||
Reference in New Issue
Block a user