From 24b209c485b573d237fdb78a3668d7f19ad644f9 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Fri, 15 Mar 2024 08:54:14 -0700 Subject: [PATCH 01/22] initial skeleton for `irq_status` --- sys/abi/src/lib.rs | 17 +++++++++++++++++ sys/kern/src/syscalls.rs | 20 ++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/sys/abi/src/lib.rs b/sys/abi/src/lib.rs index f94ea1e43..68edbe18f 100644 --- a/sys/abi/src/lib.rs +++ b/sys/abi/src/lib.rs @@ -446,6 +446,7 @@ pub enum Sysnum { RefreshTaskId = 10, Post = 11, ReplyFault = 12, + IrqStatus = 13, } /// We're using an explicit `TryFrom` impl for `Sysnum` instead of @@ -469,6 +470,7 @@ impl core::convert::TryFrom for Sysnum { 10 => Ok(Self::RefreshTaskId), 11 => Ok(Self::Post), 12 => Ok(Self::ReplyFault), + 13 => Ok(Self::IrqStatus), _ => Err(()), } } @@ -532,3 +534,18 @@ pub struct ImageVectors { pub sp: u32, pub entry: u32, } + +#[derive(Copy, Clone, Debug, FromBytes)] +#[repr(transparent)] +pub struct IrqStatus(u32); + +bitflags::bitflags! { + impl IrqStatus: u32 { + /// If 1, this interrupt is enabled. + const ENABLED = 1 << 0; + /// If 1, an IRQ is currently pending for this interrupt. + const PENDING = 1 << 1; + + const POSTED = 1 << 2; + } +} diff --git a/sys/kern/src/syscalls.rs b/sys/kern/src/syscalls.rs index 4f63c36f2..8954c9ac9 100644 --- a/sys/kern/src/syscalls.rs +++ b/sys/kern/src/syscalls.rs @@ -112,6 +112,7 @@ fn safe_syscall_entry(nr: u32, current: usize, tasks: &mut [Task]) -> NextTask { Ok(Sysnum::ReplyFault) => { reply_fault(tasks, current).map_err(UserError::from) } + Ok(Sysnum::IrqStatus) => irq_status(tasks, current), Err(_) => { // Bogus syscall number! That's a fault. Err(FaultInfo::SyscallUsage(UsageError::BadSyscallNumber).into()) @@ -819,3 +820,22 @@ fn reply_fault( // the task using it faults. Ok(NextTask::Same) } + +/// Implementation of the `IRQ_STATUS` syscall. +/// +/// `caller` is a valid task index (i.e. not directly from user code). +/// +/// # Syscall arguments +/// +/// - a notification mask +/// +/// # Syscall returns +/// +/// - an [`IrqStatus`] structure representing the current state of the interrupts +/// mapped to the provided notification mask. +fn irq_status( + tasks: &mut [Task], + caller: usize, +) -> Result { + Ok(NextTask::Same) +} From 309f7864a2960867dd799c6ee260a7d1c1861f2d Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Fri, 15 Mar 2024 08:58:45 -0700 Subject: [PATCH 02/22] lookup IRQ by mask --- sys/kern/src/syscalls.rs | 13 +++++++++++++ sys/kern/src/task.rs | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/sys/kern/src/syscalls.rs b/sys/kern/src/syscalls.rs index 8954c9ac9..f25bd51a5 100644 --- a/sys/kern/src/syscalls.rs +++ b/sys/kern/src/syscalls.rs @@ -837,5 +837,18 @@ fn irq_status( tasks: &mut [Task], caller: usize, ) -> Result { + let args = tasks[caller].save().as_irq_status_args(); + + let caller = caller as u32; + + let irqs = crate::startup::HUBRIS_TASK_IRQ_LOOKUP + .get(abi::InterruptOwner { + task: caller, + notification: args.notification_bitmask, + }) + .ok_or(UserError::Unrecoverable(FaultInfo::SyscallUsage( + UsageError::NoIrq, + )))?; + Ok(NextTask::Same) } diff --git a/sys/kern/src/task.rs b/sys/kern/src/task.rs index ea323dde8..86aac38bd 100644 --- a/sys/kern/src/task.rs +++ b/sys/kern/src/task.rs @@ -561,6 +561,13 @@ pub trait ArchState: Default { } } + /// Interprets arguments as for the `IRQ_STATUS` syscall and returns the results. + fn as_irq_status_args(&self) -> IrqStatusArgs { + IrqStatusArgs { + notification_bitmask: self.arg0(), + } + } + /// Sets a recoverable error code using the generic ABI. fn set_error_response(&mut self, resp: u32) { self.ret0(resp); @@ -702,6 +709,12 @@ pub struct PostArgs { pub notification_bits: NotificationSet, } +/// Decoded arguments for the `IRQ_STATUS` syscall. +#[derive(Clone, Debug)] +pub struct IrqStatusArgs { + pub notification_bitmask: u32, +} + /// State for a task timer. /// /// Task timers are used to multiplex the hardware timer. From d2112322f0a14e73d03250a1f742b4bfc33c35ba Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Fri, 15 Mar 2024 09:15:16 -0700 Subject: [PATCH 03/22] plumbing --- sys/abi/src/lib.rs | 4 ++-- sys/kern/src/arch/arm_m.rs | 6 ++++++ sys/kern/src/syscalls.rs | 24 +++++++++++++++++++----- sys/kern/src/task.rs | 8 ++++++++ 4 files changed, 35 insertions(+), 7 deletions(-) diff --git a/sys/abi/src/lib.rs b/sys/abi/src/lib.rs index 68edbe18f..9eca723f3 100644 --- a/sys/abi/src/lib.rs +++ b/sys/abi/src/lib.rs @@ -537,7 +537,7 @@ pub struct ImageVectors { #[derive(Copy, Clone, Debug, FromBytes)] #[repr(transparent)] -pub struct IrqStatus(u32); +pub struct IrqStatus(pub u32); bitflags::bitflags! { impl IrqStatus: u32 { @@ -545,7 +545,7 @@ bitflags::bitflags! { const ENABLED = 1 << 0; /// If 1, an IRQ is currently pending for this interrupt. const PENDING = 1 << 1; - + ///If 1, a notification has been posted for this interrupt. const POSTED = 1 << 2; } } diff --git a/sys/kern/src/arch/arm_m.rs b/sys/kern/src/arch/arm_m.rs index f1ab8a03a..5a8c99a21 100644 --- a/sys/kern/src/arch/arm_m.rs +++ b/sys/kern/src/arch/arm_m.rs @@ -1159,6 +1159,12 @@ pub fn enable_irq(n: u32) { } } +/// Looks up an interrupt in the NVIC and returns a cross-platform +/// representation of that interrupt's status. +pub fn irq_status(n: u32) -> abi::IrqStatus { + todo!("eliza") +} + #[repr(u8)] #[allow(dead_code)] #[cfg(any(armv7m, armv8m))] diff --git a/sys/kern/src/syscalls.rs b/sys/kern/src/syscalls.rs index f25bd51a5..90912073e 100644 --- a/sys/kern/src/syscalls.rs +++ b/sys/kern/src/syscalls.rs @@ -30,8 +30,8 @@ use core::convert::TryFrom; use abi::{ - FaultInfo, LeaseAttributes, SchedState, Sysnum, TaskId, TaskState, ULease, - UsageError, + FaultInfo, IrqStatus, LeaseAttributes, SchedState, Sysnum, TaskId, + TaskState, ULease, UsageError, }; use unwrap_lite::UnwrapLite; @@ -827,12 +827,16 @@ fn reply_fault( /// /// # Syscall arguments /// -/// - a notification mask +/// 0. a notification mask /// /// # Syscall returns /// -/// - an [`IrqStatus`] structure representing the current state of the interrupts -/// mapped to the provided notification mask. +/// 0. An [`IrqStatus`] structure representing the current state of the +/// interrupts mapped to the provided notification mask. If the notification +/// mask contains multiple IRQs, the returned status will be the boolean OR +/// of all the IRQs in the notification mask (e.g.., if *any* of the IRQs in +/// the notification mask is pending, the [`IrqStatus::PENDING`] bit will be +/// set, and so on). fn irq_status( tasks: &mut [Task], caller: usize, @@ -841,6 +845,7 @@ fn irq_status( let caller = caller as u32; + // Look up which IRQs are mapped to the calling task. let irqs = crate::startup::HUBRIS_TASK_IRQ_LOOKUP .get(abi::InterruptOwner { task: caller, @@ -850,5 +855,14 @@ fn irq_status( UsageError::NoIrq, )))?; + // Combine the status of all the IRQs in the notification set and return + // them to the caller. + let status = irqs.fold(IrqStatus::empty(), |status, irq| { + status | crate::arch::irq_status(irq.0) + }); + + tasks[caller].save_mut().set_irq_status_result(status); + + // Continue running the same task. Ok(NextTask::Same) } diff --git a/sys/kern/src/task.rs b/sys/kern/src/task.rs index 86aac38bd..a6130195b 100644 --- a/sys/kern/src/task.rs +++ b/sys/kern/src/task.rs @@ -632,6 +632,14 @@ pub trait ArchState: Default { fn set_refresh_task_id_result(&mut self, id: TaskId) { self.ret0(id.0 as u32); } + + /// Sets the results of IRQ_STATUS. + fn set_irq_status_result( + &mut self, + abi::IrqStatus(status): abi::IrqStatus, + ) { + self.ret0(status); + } } /// Decoded arguments for the `SEND` syscall. From 0975969aedcbb32d817a3b4ecbd6f54654151eac Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Fri, 15 Mar 2024 09:22:51 -0700 Subject: [PATCH 04/22] read pending and enabled --- sys/kern/src/arch/arm_m.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/sys/kern/src/arch/arm_m.rs b/sys/kern/src/arch/arm_m.rs index 5a8c99a21..8ff44a77d 100644 --- a/sys/kern/src/arch/arm_m.rs +++ b/sys/kern/src/arch/arm_m.rs @@ -1162,7 +1162,23 @@ pub fn enable_irq(n: u32) { /// Looks up an interrupt in the NVIC and returns a cross-platform /// representation of that interrupt's status. pub fn irq_status(n: u32) -> abi::IrqStatus { - todo!("eliza") + let mut status = abi::IrqStatus::empty(); + + let nvic = unsafe { &*cortex_m::peripheral::NVIC::PTR }; + let reg_num = (n / 32) as usize; + let bit_mask = 1 << (n % 32); + + // See if the interrupt is enabled by checking the bit in the Interrupt Set + // Enable Register. + let enabled = unsafe { nvic.iser[reg_num].read() & bit_mask == bit_mask }; + status.set(abi::IrqStatus::ENABLED, enabled); + + // See if the interrupt is pending by checking the bit in the Interrupt + // Set Pending Register (ISPR). + let pending = unsafe { nvic.ispr[reg_num].read() & bit_mask != bit_mask }; + status.set(abi::IrqStatus::ENABLED, pending); + + status } #[repr(u8)] From 1f4b2aea3208855ec24f68dea601c65a16b7f85d Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Fri, 15 Mar 2024 09:36:20 -0700 Subject: [PATCH 05/22] also check if posted --- sys/kern/src/syscalls.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sys/kern/src/syscalls.rs b/sys/kern/src/syscalls.rs index 90912073e..1b744de96 100644 --- a/sys/kern/src/syscalls.rs +++ b/sys/kern/src/syscalls.rs @@ -855,12 +855,16 @@ fn irq_status( UsageError::NoIrq, )))?; - // Combine the status of all the IRQs in the notification set and return - // them to the caller. - let status = irqs.fold(IrqStatus::empty(), |status, irq| { + // Combine the platform-level status of all the IRQs in the notification set. + let mut status = irqs.fold(IrqStatus::empty(), |status, irq| { status | crate::arch::irq_status(irq.0) }); + // If any bits in the notification mask are set in the caller's notification + // set, then a notification has been posted to the task and not yet consumed. + let posted = tasks[caller].notifications & args.notification_bitmask != 0; + status.set(IrqStatus::POSTED, posted); + tasks[caller].save_mut().set_irq_status_result(status); // Continue running the same task. From 29acd72af94541146b7687ffa90a83302f048b0a Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Fri, 15 Mar 2024 10:11:15 -0700 Subject: [PATCH 06/22] draw the rest of the syscall --- doc/syscalls.adoc | 40 +++++++++++++++++++ sys/abi/src/lib.rs | 2 + sys/kern/src/syscalls.rs | 8 ++-- sys/kern/src/task.rs | 8 ++++ sys/userlib/src/lib.rs | 84 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 137 insertions(+), 5 deletions(-) diff --git a/doc/syscalls.adoc b/doc/syscalls.adoc index d6e1305c2..096bc8326 100644 --- a/doc/syscalls.adoc +++ b/doc/syscalls.adoc @@ -659,3 +659,43 @@ return registers 0 and 1 for future compatibility. Like `REPLY`, this syscall just silently ignores replies to the wrong generation, under the assumption that the task got restarted for some reason while we were processing its request. (It can happen.) + +[#sys_irq_status] +=== `IRQ_STATUS` (13) + +Returns the current status of interrupts mapped to the calling task. + +==== Arguments + +- 0: notification bitmask corresponding to the interrupt(s) to query + +==== Return values + +- 0: an `IrqStatus` (see the `abi` crate) describing the status of the + interrupts in the notification mask. Currently, the following bits in + `IrqStatus` are significant: + ** `0b0001`: set if any interrupt in the mask is enabled + ** `0b0010`: set if an IRQ is pending for any interrupt in the mask + ** `0b0100`: set if a notification has been posted to the caller but + not yet consumed + +==== Faults + +|=== +| Condition | Fault taken + +| The given notification bitmask is not mapped to an interrupt in this task. +| `NoIrq` + +|=== + +==== Notes + +As discussed in the notes for the <> syscall, +tasks refer to interrupts using their notification bits. + +If the provided notification mask is zero, the syscall will return a `NoIrq` +fault. If the provided notification mask has multiple bits set, the returned +`IrqStatus` value will be the boolean OR of the status of all interrupts in the +map (e.g. if any interrupt in the mask is pending, the `PENDING` bit will be +set, and so on). diff --git a/sys/abi/src/lib.rs b/sys/abi/src/lib.rs index 9eca723f3..444117d77 100644 --- a/sys/abi/src/lib.rs +++ b/sys/abi/src/lib.rs @@ -535,6 +535,8 @@ pub struct ImageVectors { pub entry: u32, } +/// A set of bitflags representing the status of the interrupts mapped to a +/// notification mask. #[derive(Copy, Clone, Debug, FromBytes)] #[repr(transparent)] pub struct IrqStatus(pub u32); diff --git a/sys/kern/src/syscalls.rs b/sys/kern/src/syscalls.rs index 1b744de96..f61a1ca53 100644 --- a/sys/kern/src/syscalls.rs +++ b/sys/kern/src/syscalls.rs @@ -843,12 +843,10 @@ fn irq_status( ) -> Result { let args = tasks[caller].save().as_irq_status_args(); - let caller = caller as u32; - // Look up which IRQs are mapped to the calling task. let irqs = crate::startup::HUBRIS_TASK_IRQ_LOOKUP .get(abi::InterruptOwner { - task: caller, + task: caller as u32, notification: args.notification_bitmask, }) .ok_or(UserError::Unrecoverable(FaultInfo::SyscallUsage( @@ -856,13 +854,13 @@ fn irq_status( )))?; // Combine the platform-level status of all the IRQs in the notification set. - let mut status = irqs.fold(IrqStatus::empty(), |status, irq| { + let mut status = irqs.iter().fold(IrqStatus::empty(), |status, irq| { status | crate::arch::irq_status(irq.0) }); // If any bits in the notification mask are set in the caller's notification // set, then a notification has been posted to the task and not yet consumed. - let posted = tasks[caller].notifications & args.notification_bitmask != 0; + let posted = tasks[caller].has_notifications(args.notification_bitmask); status.set(IrqStatus::POSTED, posted); tasks[caller].save_mut().set_irq_status_result(status); diff --git a/sys/kern/src/task.rs b/sys/kern/src/task.rs index a6130195b..c8e980a0e 100644 --- a/sys/kern/src/task.rs +++ b/sys/kern/src/task.rs @@ -281,6 +281,14 @@ impl Task { None } + /// Returns `true` if any of the notification bits in `mask` are set in this + /// task's notification set. + /// + /// This does *not* clear any bits in the task's notification set. + pub fn has_notifications(&self, mask: u32) -> bool { + self.notifications & mask != 0 + } + /// Checks if this task is in a potentially schedulable state. pub fn is_runnable(&self) -> bool { self.state == TaskState::Healthy(SchedState::Runnable) diff --git a/sys/userlib/src/lib.rs b/sys/userlib/src/lib.rs index 67bcb071a..20e26faff 100644 --- a/sys/userlib/src/lib.rs +++ b/sys/userlib/src/lib.rs @@ -1652,3 +1652,87 @@ unsafe extern "C" fn sys_reply_fault_stub(_tid: u32, _reason: u32) { } } } + +/// Returns the current status of any interrupts mapped to the provided +/// notification mask. +/// +/// # Arguments +/// +/// - `mask`: a notification mask for interrupts mapped to the current task. +/// +/// # Returns +/// +/// An [`IrqStatus`] (see the `abi` crate) describing the status of the +/// interrupts in the notification mask. +/// +/// # Faults +/// +/// This syscall faults the caller if the given notification bitmask is not +/// mapped to an interrupt in this task. +#[inline(always)] +pub fn sys_irq_status(mask: u32) -> abi::IrqStatus { + let status = unsafe { sys_irq_status_stub(mask) }; + abi::IrqStatus::from_bits_truncate(status) +} + +/// Core implementation of the IRQ_STATUS syscall. +/// +/// See the note on syscall stubs at the top of this module for rationale. +#[naked] +unsafe extern "C" fn sys_irq_status_stub(_mask: u32) -> u32 { + cfg_if::cfg_if! { + if #[cfg(armv6m)] { + arch::asm!(" + @ Spill the registers we're about to use to pass stuff. + push {{r4, lr}} + mov r4, r11 + push {{r4}} + + @ Load the constant syscall number. + eors r4, r4 + adds r4, #{sysnum} + mov r11, r4 + @ Move register arguments into place. + mov r4, r0 + + @ To the kernel! + svc #0 + + @ Move result into place. + mov r0, r4 + + @ Restore the registers we used and return. + pop {{r4}} + mov r11, r4 + pop {{r4, r5, pc}} + ", + sysnum = const Sysnum::IrqStatus as u32, + options(noreturn), + ) + } else if #[cfg(any(armv7m, armv8m))] { + arch::asm!(" + @ Spill the registers we're about to use to pass stuff. + push {{r4, r11, lr}} + + @ Move register arguments into place. + mov r4, r0 + @ Load the constant syscall number. + mov r11, {sysnum} + + @ To the kernel! + svc #0 + + @ Move result into place. + mov r0, r4 + + @ Restore the registers we used and return. + pop {{r4, r11, pc}} + ", + sysnum = const Sysnum::IrqStatus as u32, + options(noreturn), + ) + } else { + compile_error!("missing sys_irq_status stub for ARM profile") + } + } +} From 11f41fd3bc867c896a94643fd9bf156b91f00168 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Fri, 15 Mar 2024 12:01:18 -0700 Subject: [PATCH 07/22] add kipc for pending soft irqs we'll use this for testing the `IRQ_STATUS` syscall. --- sys/abi/src/lib.rs | 2 ++ sys/kern/src/arch/arm_m.rs | 12 +++++++++++- sys/kern/src/kipc.rs | 35 +++++++++++++++++++++++++++++++++++ sys/userlib/src/kipc.rs | 17 +++++++++++++++++ 4 files changed, 65 insertions(+), 1 deletion(-) diff --git a/sys/abi/src/lib.rs b/sys/abi/src/lib.rs index 444117d77..0e1e07af5 100644 --- a/sys/abi/src/lib.rs +++ b/sys/abi/src/lib.rs @@ -492,6 +492,7 @@ pub enum Kipcnum { Reset = 5, GetTaskDumpRegion = 6, ReadTaskDumpRegion = 7, + SoftwareIrq = 8, } impl core::convert::TryFrom for Kipcnum { @@ -506,6 +507,7 @@ impl core::convert::TryFrom for Kipcnum { 5 => Ok(Self::Reset), 6 => Ok(Self::GetTaskDumpRegion), 7 => Ok(Self::ReadTaskDumpRegion), + 8 => Ok(Self::SoftwareIrq), _ => Err(()), } } diff --git a/sys/kern/src/arch/arm_m.rs b/sys/kern/src/arch/arm_m.rs index 8ff44a77d..15849a01b 100644 --- a/sys/kern/src/arch/arm_m.rs +++ b/sys/kern/src/arch/arm_m.rs @@ -81,9 +81,9 @@ use crate::startup::with_task_table; use crate::task; use crate::time::Timestamp; use crate::umem::USlice; -use abi::FaultInfo; #[cfg(any(armv7m, armv8m))] use abi::FaultSource; +use abi::{FaultInfo, InterruptNum}; #[cfg(armv8m)] use armv8_m_mpu::{disable_mpu, enable_mpu}; use unwrap_lite::UnwrapLite; @@ -1181,6 +1181,16 @@ pub fn irq_status(n: u32) -> abi::IrqStatus { status } +pub fn pend_software_irq(InterruptNum(n): InterruptNum) { + let nvic = unsafe { &*cortex_m::peripheral::NVIC::PTR }; + let reg_num = (n / 32) as usize; + let bit_mask = 1 << (n % 32); + + // Pend the IRQ by poking the corresponding bit in the Interrupt Set Pending + // Register (ISPR). + unsafe { nvic.ispr[reg_num].write(bit_mask) }; +} + #[repr(u8)] #[allow(dead_code)] #[cfg(any(armv7m, armv8m))] diff --git a/sys/kern/src/kipc.rs b/sys/kern/src/kipc.rs index 9a87d0e30..c36fdb4f1 100644 --- a/sys/kern/src/kipc.rs +++ b/sys/kern/src/kipc.rs @@ -39,6 +39,9 @@ pub fn handle_kernel_message( Ok(Kipcnum::ReadTaskDumpRegion) => { read_task_dump_region(tasks, caller, args.message?, args.response?) } + Ok(Kipcnum::SoftwareIrq) => { + software_irq(tasks, caller, args.message?, args.response?) + } _ => { // Task has sent an unknown message to the kernel. That's bad. @@ -427,3 +430,35 @@ fn read_task_dump_region( .set_send_response_and_length(0, response_len); Ok(NextTask::Same) } + +fn software_irq( + tasks: &mut [Task], + caller: usize, + message: USlice, + response: USlice, +) -> Result { + let (index, notification): (u32, u32) = + deserialize_message(&tasks[caller], message)?; + if index as usize >= tasks.len() { + return Err(UserError::Unrecoverable(FaultInfo::SyscallUsage( + UsageError::TaskOutOfRange, + ))); + } + + // Look up which IRQs are mapped to the target task. + let irqs = crate::startup::HUBRIS_TASK_IRQ_LOOKUP + .get(abi::InterruptOwner { + task: index, + notification, + }) + .ok_or(UserError::Unrecoverable(FaultInfo::SyscallUsage( + UsageError::NoIrq, + )))?; + + for &irq in irqs.iter() { + crate::arch::pend_software_irq(irq); + } + + tasks[caller].save_mut().set_send_response_and_length(0, 0); + Ok(NextTask::Same) +} diff --git a/sys/userlib/src/kipc.rs b/sys/userlib/src/kipc.rs index 52eb65b15..42e7c5d60 100644 --- a/sys/userlib/src/kipc.rs +++ b/sys/userlib/src/kipc.rs @@ -110,3 +110,20 @@ pub fn read_image_id() -> u64 { assert_eq!(len, 8); // we *really* expect this to be a u64 ssmarshal::deserialize(&response[..len]).unwrap_lite().0 } + +/// Trigger the interrupt(s) mapped to the given task's notification mask. +pub fn software_irq(task: usize, mask: u32) { + // Coerce `task` to a known size (Rust doesn't assume that usize == u32) + let msg = (task as u32, mask); + let mut buf = [0; core::mem::size_of::<(u32, u32)>()]; + ssmarshal::serialize(&mut buf, &msg).unwrap_lite(); + + let (rc, _len) = sys_send( + TaskId::KERNEL, + Kipcnum::SoftwareIrq as u16, + &buf, + &mut [], + &[], + ); + assert_eq!(rc, 0); +} From 34e75ffcb6404373eb5fac05a7afd958fb68d356 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Fri, 15 Mar 2024 13:06:23 -0700 Subject: [PATCH 08/22] only allow the supervisor to pend soft irqs --- sys/kern/src/kipc.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sys/kern/src/kipc.rs b/sys/kern/src/kipc.rs index c36fdb4f1..bfc49d559 100644 --- a/sys/kern/src/kipc.rs +++ b/sys/kern/src/kipc.rs @@ -437,8 +437,15 @@ fn software_irq( message: USlice, response: USlice, ) -> Result { + if caller != 0 { + return Err(UserError::Unrecoverable(FaultInfo::SyscallUsage( + UsageError::NotSupervisor, + ))); + } + let (index, notification): (u32, u32) = deserialize_message(&tasks[caller], message)?; + if index as usize >= tasks.len() { return Err(UserError::Unrecoverable(FaultInfo::SyscallUsage( UsageError::TaskOutOfRange, From 10ef22b59c5101b092b63c0915a198d8e836914a Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Fri, 15 Mar 2024 14:05:34 -0700 Subject: [PATCH 09/22] add tests (hopefully these are correct...) --- test/test-api/build.rs | 2 +- test/test-api/src/lib.rs | 3 ++ test/test-runner/src/main.rs | 9 +++++ test/test-suite/build.rs | 2 + test/test-suite/src/main.rs | 67 +++++++++++++++++++++++++++++--- test/tests-gemini-bu/app.toml | 6 ++- test/tests-gimletlet/app.toml | 6 ++- test/tests-lpc55xpresso/app.toml | 6 ++- test/tests-psc/app.toml | 5 +++ test/tests-rot-carrier/app.toml | 5 +++ test/tests-stm32fx/app-f3.toml | 5 +++ test/tests-stm32fx/app.toml | 5 +++ test/tests-stm32g0/app-g070.toml | 5 +++ test/tests-stm32h7/app-h743.toml | 5 +++ test/tests-stm32h7/app-h753.toml | 5 +++ 15 files changed, 127 insertions(+), 9 deletions(-) diff --git a/test/test-api/build.rs b/test/test-api/build.rs index 5e7432aa4..c9151143d 100644 --- a/test/test-api/build.rs +++ b/test/test-api/build.rs @@ -3,6 +3,6 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. fn main() -> Result<(), Box> { - build_util::expose_m_profile(); + build_util::expose_m_profile()?; Ok(()) } diff --git a/test/test-api/src/lib.rs b/test/test-api/src/lib.rs index a5e332d05..aae9d9ae9 100644 --- a/test/test-api/src/lib.rs +++ b/test/test-api/src/lib.rs @@ -51,6 +51,9 @@ pub enum RunnerOp { /// Reads out, and clears, the accumulated set of notifications we've /// received (`() -> u32`). ReadAndClearNotes = 0, + /// Indicates that the test suite would like the test runner to trigger an + /// IRQ. + SoftIrq = 1, /// Signals that a test is complete, and that the runner is switching back /// to passive mode (`() -> ()`). TestComplete = 0xfffe, diff --git a/test/test-runner/src/main.rs b/test/test-runner/src/main.rs index 3d0153c68..68d985f31 100644 --- a/test/test-runner/src/main.rs +++ b/test/test-runner/src/main.rs @@ -67,6 +67,7 @@ enum Trace { Notification, TestComplete(TaskId), TestResult(TaskId), + SoftIrq(TaskId, u32), None, } @@ -110,6 +111,14 @@ fn main() -> ! { caller.reply(state.received_notes); state.received_notes = 0; } + RunnerOp::SoftIrq => { + // The test is asking us to trigger an IRQ. + let (&mask, caller) = + msg.fixed::().ok_or(2u32)?; + ringbuf_entry!(Trace::SoftIrq(caller.task_id(), mask)); + kipc::software_irq(caller.task_id().index(), mask); + caller.reply(()) + } RunnerOp::TestComplete => { let (_, caller) = msg.fixed::<(), ()>().ok_or(2u32)?; ringbuf_entry!(Trace::TestComplete(caller.task_id())); diff --git a/test/test-suite/build.rs b/test/test-suite/build.rs index 666fafe4b..2513783f9 100644 --- a/test/test-suite/build.rs +++ b/test/test-suite/build.rs @@ -8,5 +8,7 @@ fn main() -> Result<(), Box> { #[cfg(feature = "i2c-devices")] build_i2c::codegen(build_i2c::Disposition::Devices)?; + build_util::build_notifications()?; + Ok(()) } diff --git a/test/test-suite/src/main.rs b/test/test-suite/src/main.rs index 7252411f2..cc02dd6ef 100644 --- a/test/test-suite/src/main.rs +++ b/test/test-suite/src/main.rs @@ -124,6 +124,8 @@ test_cases! { test_idol_ssmarshal, test_idol_ssmarshal_multiarg, test_idol_ssmarshal_multiarg_enum, + test_irq_notif, + test_irq_status, #[cfg(feature = "fru-id-eeprom")] at24csw080::test_at24csw080, } @@ -989,15 +991,15 @@ fn test_borrow_info() { // Borrow 0 is expected to be 16 bytes long and R/W. let info0 = caller.borrow(0).info().unwrap(); - assert_eq!( - info0.attributes, - LeaseAttributes::READ | LeaseAttributes::WRITE - ); + // assert_eq!( + // info0.attributes, + // LeaseAttributes::READ | LeaseAttributes::WRITE + // ); assert_eq!(info0.len, 16); // Borrow 1 is expected to be 5 bytes long and R/O. let info1 = caller.borrow(1).info().unwrap(); - assert_eq!(info1.attributes, LeaseAttributes::READ); + // assert_eq!(info1.attributes, LeaseAttributes::READ); assert_eq!(info1.len, 5); caller.reply(0); @@ -1409,6 +1411,59 @@ fn test_post() { assert_eq!(response, ARBITRARY_MASK); } +/// Tests that a task is notified on receipt of a hardware interrupt. +fn test_irq_notif() { + sys_irq_control(notifications::TEST_IRQ_MASK, true); + + trigger_test_irq(); + + let rm = + sys_recv_closed(&mut [], notifications::TEST_IRQ_MASK, TaskId::KERNEL) + .unwrap(); + + assert_eq!(rm.sender, TaskId::KERNEL); + assert_eq!(rm.operation, notifications::TEST_IRQ_MASK); + assert_eq!(rm.message_len, 0); + assert_eq!(rm.response_capacity, 0); + assert_eq!(rm.lease_count, 0); +} + +/// Tests the IRQ_STATUS syscall. +fn test_irq_status() { + sys_irq_control(notifications::TEST_IRQ_MASK, false); + + // the interrupt should not be pending + let status = sys_irq_status(notifications::TEST_IRQ_MASK); + assert_eq!(status.contains(IrqStatus::ENABLED), false); + assert_eq!(status.contains(IrqStatus::PENDING), false); + assert_eq!(status.contains(IrqStatus::POSTED), false); + + // enable the interrupt + sys_irq_control(notifications::TEST_IRQ_MASK, true); + + // okay, let's get interrupted! + trigger_test_irq(); + + // now, there should be an IRQ pending, and a notification waiting for us + let status = sys_irq_status(notifications::TEST_IRQ_MASK); + assert_eq!(status.contains(IrqStatus::ENABLED), true); + assert_eq!(status.contains(IrqStatus::PENDING), true); + assert_eq!(status.contains(IrqStatus::POSTED), true); +} + +/// Asks the test runner (running as supervisor) to please trigger a software +/// interrupt for `notifications::TEST_IRQ`, thank you. +fn trigger_test_irq() { + let runner = RUNNER.get_task_id(); + let mut response = 0u32; + let op = RunnerOp::SoftIrq as u16; + let arg = notifications::TEST_IRQ_MASK; + let (rc, len) = + sys_send(runner, op, arg.as_bytes(), response.as_bytes_mut(), &[]); + assert_eq!(rc, 0); + assert_eq!(len, 4); +} + /////////////////////////////////////////////////////////////////////////////// // Frameworky bits follow @@ -1504,3 +1559,5 @@ fn main() -> ! { ) } } + +include!(concat!(env!("OUT_DIR"), "/notifications.rs")); diff --git a/test/tests-gemini-bu/app.toml b/test/tests-gemini-bu/app.toml index c33fd5e76..b30ef9345 100644 --- a/test/tests-gemini-bu/app.toml +++ b/test/tests-gemini-bu/app.toml @@ -19,7 +19,11 @@ name = "test-suite" priority = 2 max-sizes = {flash = 65536, ram = 4096} start = true -task-slots = ["assist", "idol", "suite", "runner"] +task-slots = ["assist", "idol", "suite", "runner"]# this doesn't actually use SPI; we're just mapping that interrupt to test +# interrupt handling. chosen completely arbitrarily. +uses = ["spi1"] +notifications = ["test-irq"] +interrupts = {"spi1.irq" = "test-irq"} # This block is used to test the task_config macro [tasks.suite.config] diff --git a/test/tests-gimletlet/app.toml b/test/tests-gimletlet/app.toml index 3b8d3e37b..752d376f3 100644 --- a/test/tests-gimletlet/app.toml +++ b/test/tests-gimletlet/app.toml @@ -19,7 +19,11 @@ name = "test-suite" priority = 2 max-sizes = {flash = 65536, ram = 4096} start = true -task-slots = ["assist", "idol", "suite", "runner"] +task-slots = ["assist", "idol", "suite", "runner"]# this doesn't actually use SPI; we're just mapping that interrupt to test +# interrupt handling. chosen completely arbitrarily. +uses = ["spi1"] +notifications = ["test-irq"] +interrupts = {"spi1.irq" = "test-irq"} # This block is used to test the task_config macro [tasks.suite.config] diff --git a/test/tests-lpc55xpresso/app.toml b/test/tests-lpc55xpresso/app.toml index de1713e75..e839f4497 100644 --- a/test/tests-lpc55xpresso/app.toml +++ b/test/tests-lpc55xpresso/app.toml @@ -22,6 +22,11 @@ max-sizes = {flash = 65536, ram = 4096} start = true stacksize = 2048 task-slots = ["assist", "idol", "suite", "runner"] +# this doesn't actually use hashcrypt; we're just mapping that interrupt to test +# interrupt handling. chosen completely arbitrarily. +uses = ["hash_crypt"] +notifications = ["test-irq"] +interrupts = {"hash_crypt.irq" = "test-irq"} # This block is used to test the task_config macro [tasks.suite.config] @@ -63,4 +68,3 @@ start = true signing-certs = ["../../support/fake_certs/fake_certificate.der.crt"] root-certs = ["../../support/fake_certs/fake_certificate.der.crt"] private-key = "../../support/fake_certs/fake_private_key.pem" - diff --git a/test/tests-psc/app.toml b/test/tests-psc/app.toml index 08178b77a..c84ab1c73 100644 --- a/test/tests-psc/app.toml +++ b/test/tests-psc/app.toml @@ -22,6 +22,11 @@ start = true stacksize = 2048 features = ["fru-id-eeprom"] task-slots = ["assist", "idol", "suite", "runner", "i2c_driver"] +# this doesn't actually use SPI; we're just mapping that interrupt to test +# interrupt handling. chosen completely arbitrarily. +uses = ["spi1"] +notifications = ["test-irq"] +interrupts = {"spi1.irq" = "test-irq"} # This block is used to test the task_config macro [tasks.suite.config] diff --git a/test/tests-rot-carrier/app.toml b/test/tests-rot-carrier/app.toml index 040403ce5..fd77d9ae7 100644 --- a/test/tests-rot-carrier/app.toml +++ b/test/tests-rot-carrier/app.toml @@ -22,6 +22,11 @@ max-sizes = {flash = 65536, ram = 4096} start = true stacksize = 2048 task-slots = ["assist", "idol", "suite", "runner"] +# this doesn't actually use hashcrypt; we're just mapping that interrupt to test +# interrupt handling. chosen completely arbitrarily. +uses = ["hash_crypt"] +notifications = ["test-irq"] +interrupts = {"hash_crypt.irq" = "test-irq"} # This block is used to test the task_config macro [tasks.suite.config] diff --git a/test/tests-stm32fx/app-f3.toml b/test/tests-stm32fx/app-f3.toml index 838064030..2c94251d0 100644 --- a/test/tests-stm32fx/app-f3.toml +++ b/test/tests-stm32fx/app-f3.toml @@ -21,6 +21,11 @@ priority = 2 max-sizes = {flash = 65536, ram = 4096} start = true task-slots = ["assist", "idol", "suite", "runner"] +# this doesn't actually use the USART; we're just mapping that interrupt to test +# interrupt handling. chosen completely arbitrarily. +uses = ["usart2"] +notifications = ["test-irq"] +interrupts = {"usart2.irq" = "test-irq"} # This block is used to test the task_config macro [tasks.suite.config] diff --git a/test/tests-stm32fx/app.toml b/test/tests-stm32fx/app.toml index 8d29f7710..bff063060 100644 --- a/test/tests-stm32fx/app.toml +++ b/test/tests-stm32fx/app.toml @@ -21,6 +21,11 @@ priority = 2 max-sizes = {flash = 65536, ram = 4096} start = true task-slots = ["assist", "idol", "suite", "runner"] +# this doesn't actually use the USART; we're just mapping that interrupt to test +# interrupt handling. chosen completely arbitrarily. +uses = ["usart2"] +notifications = ["test-irq"] +interrupts = {"usart2.irq" = "test-irq"} # This block is used to test the task_config macro [tasks.suite.config] diff --git a/test/tests-stm32g0/app-g070.toml b/test/tests-stm32g0/app-g070.toml index e4a048767..225a31377 100644 --- a/test/tests-stm32g0/app-g070.toml +++ b/test/tests-stm32g0/app-g070.toml @@ -24,6 +24,11 @@ max-sizes = {flash = 65536, ram = 4096} start = true task-slots = ["assist", "idol", "suite", "runner"] stacksize = 1504 +# this doesn't actually use SPI; we're just mapping that interrupt to test +# interrupt handling. chosen completely arbitrarily. +uses = ["spi1"] +notifications = ["test-irq"] +interrupts = {"spi1.irq" = "test-irq"} # This block is used to test the task_config macro [tasks.suite.config] diff --git a/test/tests-stm32h7/app-h743.toml b/test/tests-stm32h7/app-h743.toml index f37fad34d..3903b3106 100644 --- a/test/tests-stm32h7/app-h743.toml +++ b/test/tests-stm32h7/app-h743.toml @@ -21,6 +21,11 @@ priority = 2 max-sizes = {flash = 65536, ram = 4096} start = true task-slots = ["assist", "idol", "suite", "runner"] +# this doesn't actually use SPI; we're just mapping that interrupt to test +# interrupt handling. chosen completely arbitrarily. +uses = ["spi1"] +notifications = ["test-irq"] +interrupts = {"spi1.irq" = "test-irq"} # This block is used to test the task_config macro [tasks.suite.config] diff --git a/test/tests-stm32h7/app-h753.toml b/test/tests-stm32h7/app-h753.toml index 29a58631a..e16fab134 100644 --- a/test/tests-stm32h7/app-h753.toml +++ b/test/tests-stm32h7/app-h753.toml @@ -21,6 +21,11 @@ priority = 2 max-sizes = {flash = 65536, ram = 4096} start = true task-slots = ["assist", "idol", "suite", "runner"] +# this doesn't actually use SPI; we're just mapping that interrupt to test +# interrupt handling. chosen completely arbitrarily. +uses = ["spi1"] +notifications = ["test-irq"] +interrupts = {"spi1.irq" = "test-irq"} # This block is used to test the task_config macro [tasks.suite.config] From 6862889131b00abd3162665916846a1d62c3f822 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Fri, 15 Mar 2024 14:07:08 -0700 Subject: [PATCH 10/22] de-warn --- sys/kern/src/arch/arm_m.rs | 4 ++-- sys/kern/src/kipc.rs | 5 +---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/sys/kern/src/arch/arm_m.rs b/sys/kern/src/arch/arm_m.rs index 15849a01b..ff534e480 100644 --- a/sys/kern/src/arch/arm_m.rs +++ b/sys/kern/src/arch/arm_m.rs @@ -1170,12 +1170,12 @@ pub fn irq_status(n: u32) -> abi::IrqStatus { // See if the interrupt is enabled by checking the bit in the Interrupt Set // Enable Register. - let enabled = unsafe { nvic.iser[reg_num].read() & bit_mask == bit_mask }; + let enabled = nvic.iser[reg_num].read() & bit_mask == bit_mask; status.set(abi::IrqStatus::ENABLED, enabled); // See if the interrupt is pending by checking the bit in the Interrupt // Set Pending Register (ISPR). - let pending = unsafe { nvic.ispr[reg_num].read() & bit_mask != bit_mask }; + let pending = nvic.ispr[reg_num].read() & bit_mask != bit_mask; status.set(abi::IrqStatus::ENABLED, pending); status diff --git a/sys/kern/src/kipc.rs b/sys/kern/src/kipc.rs index bfc49d559..6dbd2227d 100644 --- a/sys/kern/src/kipc.rs +++ b/sys/kern/src/kipc.rs @@ -39,9 +39,7 @@ pub fn handle_kernel_message( Ok(Kipcnum::ReadTaskDumpRegion) => { read_task_dump_region(tasks, caller, args.message?, args.response?) } - Ok(Kipcnum::SoftwareIrq) => { - software_irq(tasks, caller, args.message?, args.response?) - } + Ok(Kipcnum::SoftwareIrq) => software_irq(tasks, caller, args.message?), _ => { // Task has sent an unknown message to the kernel. That's bad. @@ -435,7 +433,6 @@ fn software_irq( tasks: &mut [Task], caller: usize, message: USlice, - response: USlice, ) -> Result { if caller != 0 { return Err(UserError::Unrecoverable(FaultInfo::SyscallUsage( From dc8d3a79a062d0eddb10aa7bffc1caef567a0544 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Sat, 16 Mar 2024 11:40:13 -0700 Subject: [PATCH 11/22] embiggen some kernel flash sizes --- app/demo-stm32g0-nucleo/app-g031.toml | 2 +- app/demo-stm32g0-nucleo/app-g070.toml | 2 +- app/demo-stm32h7-nucleo/app-h753.toml | 2 +- app/donglet/app-g031-i2c.toml | 2 +- app/donglet/app-g031.toml | 2 +- app/lpc55xpresso/app-sprot.toml | 4 ++-- app/lpc55xpresso/app.toml | 2 +- app/oxide-rot-1/app-dev.toml | 2 +- app/oxide-rot-1/app.toml | 2 +- app/rot-carrier/app.toml | 2 +- app/sidecar/base.toml | 2 +- test/tests-psc/app.toml | 18 +++++++++--------- 12 files changed, 21 insertions(+), 21 deletions(-) diff --git a/app/demo-stm32g0-nucleo/app-g031.toml b/app/demo-stm32g0-nucleo/app-g031.toml index cc15721eb..7bfe0f7ca 100644 --- a/app/demo-stm32g0-nucleo/app-g031.toml +++ b/app/demo-stm32g0-nucleo/app-g031.toml @@ -6,7 +6,7 @@ board = "stm32g031-nucleo" [kernel] name = "demo-stm32g0-nucleo" -requires = {flash = 10752, ram = 1296} +requires = {flash = 11104, ram = 1296} features = ["g031"] stacksize = 640 diff --git a/app/demo-stm32g0-nucleo/app-g070.toml b/app/demo-stm32g0-nucleo/app-g070.toml index 1cb740646..23d65209e 100644 --- a/app/demo-stm32g0-nucleo/app-g070.toml +++ b/app/demo-stm32g0-nucleo/app-g070.toml @@ -7,7 +7,7 @@ stacksize = 944 [kernel] name = "demo-stm32g0-nucleo" -requires = {flash = 18448, ram = 1632} +requires = {flash = 18976, ram = 1632} features = ["g070"] stacksize = 640 diff --git a/app/demo-stm32h7-nucleo/app-h753.toml b/app/demo-stm32h7-nucleo/app-h753.toml index ce49a814a..b8dc6fe6a 100644 --- a/app/demo-stm32h7-nucleo/app-h753.toml +++ b/app/demo-stm32h7-nucleo/app-h753.toml @@ -6,7 +6,7 @@ stacksize = 896 [kernel] name = "demo-stm32h7-nucleo" -requires = {flash = 24000, ram = 5120} +requires = {flash = 24320, ram = 5120} features = ["h753", "dump"] [tasks.jefe] diff --git a/app/donglet/app-g031-i2c.toml b/app/donglet/app-g031-i2c.toml index ac780ee7b..189c7a438 100644 --- a/app/donglet/app-g031-i2c.toml +++ b/app/donglet/app-g031-i2c.toml @@ -6,7 +6,7 @@ board = "donglet-g031" [kernel] name = "app-donglet" -requires = {flash = 18144, ram = 1616} +requires = {flash = 18656, ram = 1616} features = ["g031"] stacksize = 936 diff --git a/app/donglet/app-g031.toml b/app/donglet/app-g031.toml index 28a841129..9252df242 100644 --- a/app/donglet/app-g031.toml +++ b/app/donglet/app-g031.toml @@ -6,7 +6,7 @@ board = "donglet-g031" [kernel] name = "app-donglet" -requires = {flash = 18272, ram = 1820} +requires = {flash = 18880, ram = 1820} features = ["g031"] stacksize = 936 diff --git a/app/lpc55xpresso/app-sprot.toml b/app/lpc55xpresso/app-sprot.toml index 91a6ca9e9..30833c77e 100644 --- a/app/lpc55xpresso/app-sprot.toml +++ b/app/lpc55xpresso/app-sprot.toml @@ -17,7 +17,7 @@ fwid = true [kernel] name = "lpc55xpresso" features = ["dice-self"] -requires = {flash = 53248, ram = 4096} +requires = {flash = 53312, ram = 4096} [caboose] region = "flash" @@ -183,7 +183,7 @@ task-slots = ["swd"] [tasks.sprot] name = "drv-lpc55-sprot-server" priority = 6 -max-sizes = {flash = 47360, ram = 32768} +max-sizes = {flash = 48512, ram = 32768} uses = ["flexcomm8", "bootrom"] features = ["spi0"] start = true diff --git a/app/lpc55xpresso/app.toml b/app/lpc55xpresso/app.toml index e0b499e7b..668d13270 100644 --- a/app/lpc55xpresso/app.toml +++ b/app/lpc55xpresso/app.toml @@ -9,7 +9,7 @@ fwid = true [kernel] name = "lpc55xpresso" features = ["dump", "dice-self"] -requires = {flash = 54116, ram = 4096} +requires = {flash = 54336, ram = 4096} [caboose] region = "flash" diff --git a/app/oxide-rot-1/app-dev.toml b/app/oxide-rot-1/app-dev.toml index b6d7d8cc4..1d0097b86 100644 --- a/app/oxide-rot-1/app-dev.toml +++ b/app/oxide-rot-1/app-dev.toml @@ -10,7 +10,7 @@ fwid = true [kernel] name = "oxide-rot-1" -requires = {flash = 52512, ram = 4096} +requires = {flash = 61124, ram = 4096} features = ["dice-self"] [caboose] diff --git a/app/oxide-rot-1/app.toml b/app/oxide-rot-1/app.toml index 482b3cd9e..9d20f495c 100644 --- a/app/oxide-rot-1/app.toml +++ b/app/oxide-rot-1/app.toml @@ -10,7 +10,7 @@ fwid = true [kernel] name = "oxide-rot-1" -requires = {flash = 60644, ram = 2696} +requires = {flash = 61124, ram = 2696} features = ["dice-mfg"] [caboose] diff --git a/app/rot-carrier/app.toml b/app/rot-carrier/app.toml index 5bbe84f0e..7129a008b 100644 --- a/app/rot-carrier/app.toml +++ b/app/rot-carrier/app.toml @@ -11,7 +11,7 @@ fwid = true [kernel] name = "rot-carrier" features = ["dice-self"] -requires = {flash = 53000, ram = 4096} +requires = {flash = 53408, ram = 4096} [caboose] tasks = ["caboose_reader", "sprot"] diff --git a/app/sidecar/base.toml b/app/sidecar/base.toml index 1a5af3c76..6b17e0c09 100644 --- a/app/sidecar/base.toml +++ b/app/sidecar/base.toml @@ -6,7 +6,7 @@ fwid = true [kernel] name = "sidecar" -requires = {flash = 25384, ram = 6256} +requires = {flash = 25792, ram = 6256} features = ["dump"] [caboose] diff --git a/test/tests-psc/app.toml b/test/tests-psc/app.toml index c84ab1c73..d877364fe 100644 --- a/test/tests-psc/app.toml +++ b/test/tests-psc/app.toml @@ -16,7 +16,7 @@ start = true [tasks.suite] name = "test-suite" -priority = 2 +priority = 3 max-sizes = {flash = 65536, ram = 4096} start = true stacksize = 2048 @@ -66,16 +66,16 @@ start = true task-slots = ["sys"] [tasks.i2c_driver.interrupts] -"i2c2.event" = 0b0000_0010 -"i2c2.error" = 0b0000_0010 -"i2c3.event" = 0b0000_0100 -"i2c3.error" = 0b0000_0100 -"i2c4.event" = 0b0000_1000 -"i2c4.error" = 0b0000_1000 +"i2c2.event" = "0b0000_0010" +"i2c2.error" = "0b0000_0010" +"i2c3.event" = "0b0000_0100" +"i2c3.error" = "0b0000_0100" +"i2c4.event" = "0b0000_1000" +"i2c4.error" = "0b0000_1000" [tasks.hiffy] name = "task-hiffy" -priority = 3 +priority = 4 features = ["testsuite"] max-sizes = {flash = 32768, ram = 32768 } stacksize = 2048 @@ -84,7 +84,7 @@ task-slots = ["suite", "runner"] [tasks.idle] name = "task-idle" -priority = 4 +priority = 5 max-sizes = {flash = 128, ram = 256} stacksize = 256 start = true From 3253d086ea500c825983e197111c5e1cf40ec396 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Mon, 18 Mar 2024 11:56:44 -0700 Subject: [PATCH 12/22] fix test SoftIrq op failing on 0-size buf --- test/test-runner/src/main.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/test-runner/src/main.rs b/test/test-runner/src/main.rs index 68d985f31..d1d8e673e 100644 --- a/test/test-runner/src/main.rs +++ b/test/test-runner/src/main.rs @@ -85,9 +85,12 @@ fn main() -> ! { test_status: None, }; + // N.B. that this must be at least four bytes to recv a u32 notification + // mask in the `SoftIrq` IPC op. + let mut buf = [0u8; 4]; loop { hl::recv( - &mut [], + &mut buf, ALL_NOTIFICATIONS, &mut state, |state, bits| { From a2749f425ff9407b6efad2fa431023b39f1de299 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Mon, 18 Mar 2024 11:57:10 -0700 Subject: [PATCH 13/22] nicer assertion --- sys/abi/src/lib.rs | 2 +- test/test-suite/src/main.rs | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/sys/abi/src/lib.rs b/sys/abi/src/lib.rs index 0e1e07af5..a85c62a6d 100644 --- a/sys/abi/src/lib.rs +++ b/sys/abi/src/lib.rs @@ -539,7 +539,7 @@ pub struct ImageVectors { /// A set of bitflags representing the status of the interrupts mapped to a /// notification mask. -#[derive(Copy, Clone, Debug, FromBytes)] +#[derive(Copy, Clone, Debug, FromBytes, PartialEq, Eq)] #[repr(transparent)] pub struct IrqStatus(pub u32); diff --git a/test/test-suite/src/main.rs b/test/test-suite/src/main.rs index cc02dd6ef..4c4efe250 100644 --- a/test/test-suite/src/main.rs +++ b/test/test-suite/src/main.rs @@ -1434,9 +1434,7 @@ fn test_irq_status() { // the interrupt should not be pending let status = sys_irq_status(notifications::TEST_IRQ_MASK); - assert_eq!(status.contains(IrqStatus::ENABLED), false); - assert_eq!(status.contains(IrqStatus::PENDING), false); - assert_eq!(status.contains(IrqStatus::POSTED), false); + assert_eq!(status, IrqStatus::empty()); // enable the interrupt sys_irq_control(notifications::TEST_IRQ_MASK, true); @@ -1446,13 +1444,14 @@ fn test_irq_status() { // now, there should be an IRQ pending, and a notification waiting for us let status = sys_irq_status(notifications::TEST_IRQ_MASK); - assert_eq!(status.contains(IrqStatus::ENABLED), true); - assert_eq!(status.contains(IrqStatus::PENDING), true); - assert_eq!(status.contains(IrqStatus::POSTED), true); + let expected_status = + IrqStatus::ENABLED | IrqStatus::PENDING | IrqStatus::POSTED; + assert_eq!(status, expected_status); } /// Asks the test runner (running as supervisor) to please trigger a software /// interrupt for `notifications::TEST_IRQ`, thank you. +#[track_caller] fn trigger_test_irq() { let runner = RUNNER.get_task_id(); let mut response = 0u32; @@ -1461,7 +1460,7 @@ fn trigger_test_irq() { let (rc, len) = sys_send(runner, op, arg.as_bytes(), response.as_bytes_mut(), &[]); assert_eq!(rc, 0); - assert_eq!(len, 4); + assert_eq!(len, 0); } /////////////////////////////////////////////////////////////////////////////// From 2b3483c8499e886c96f3b50d390b9eb275f826d7 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Mon, 18 Mar 2024 12:14:29 -0700 Subject: [PATCH 14/22] get the good bitflags debug format --- sys/abi/src/lib.rs | 11 ++++------- sys/kern/src/task.rs | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/sys/abi/src/lib.rs b/sys/abi/src/lib.rs index a85c62a6d..16a3488b1 100644 --- a/sys/abi/src/lib.rs +++ b/sys/abi/src/lib.rs @@ -537,14 +537,11 @@ pub struct ImageVectors { pub entry: u32, } -/// A set of bitflags representing the status of the interrupts mapped to a -/// notification mask. -#[derive(Copy, Clone, Debug, FromBytes, PartialEq, Eq)] -#[repr(transparent)] -pub struct IrqStatus(pub u32); - bitflags::bitflags! { - impl IrqStatus: u32 { + /// A set of bitflags representing the status of the interrupts mapped to a + /// notification mask. + #[derive(Copy, Clone, Debug, PartialEq, Eq)] + pub struct IrqStatus: u32 { /// If 1, this interrupt is enabled. const ENABLED = 1 << 0; /// If 1, an IRQ is currently pending for this interrupt. diff --git a/sys/kern/src/task.rs b/sys/kern/src/task.rs index c8e980a0e..7d4bb5939 100644 --- a/sys/kern/src/task.rs +++ b/sys/kern/src/task.rs @@ -646,7 +646,7 @@ pub trait ArchState: Default { &mut self, abi::IrqStatus(status): abi::IrqStatus, ) { - self.ret0(status); + self.ret0(status.bits()); } } From 213778da11cfd2b153918db849fc4fa7588b561f Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Mon, 18 Mar 2024 12:15:25 -0700 Subject: [PATCH 15/22] fix arch fn returning wildly wrong statuses --- sys/kern/src/arch/arm_m.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/kern/src/arch/arm_m.rs b/sys/kern/src/arch/arm_m.rs index ff534e480..278f4721f 100644 --- a/sys/kern/src/arch/arm_m.rs +++ b/sys/kern/src/arch/arm_m.rs @@ -1175,8 +1175,8 @@ pub fn irq_status(n: u32) -> abi::IrqStatus { // See if the interrupt is pending by checking the bit in the Interrupt // Set Pending Register (ISPR). - let pending = nvic.ispr[reg_num].read() & bit_mask != bit_mask; - status.set(abi::IrqStatus::ENABLED, pending); + let pending = nvic.ispr[reg_num].read() & bit_mask == bit_mask; + status.set(abi::IrqStatus::PENDING, pending); status } From 7031d743d70b401afe9c7622348c019f4e912ad9 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Mon, 18 Mar 2024 12:17:34 -0700 Subject: [PATCH 16/22] whoops --- sys/kern/src/task.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sys/kern/src/task.rs b/sys/kern/src/task.rs index 7d4bb5939..811f74576 100644 --- a/sys/kern/src/task.rs +++ b/sys/kern/src/task.rs @@ -642,10 +642,7 @@ pub trait ArchState: Default { } /// Sets the results of IRQ_STATUS. - fn set_irq_status_result( - &mut self, - abi::IrqStatus(status): abi::IrqStatus, - ) { + fn set_irq_status_result(&mut self, status: abi::IrqStatus) { self.ret0(status.bits()); } } From dc9a321c33dea17899b2fdce4b459db443c249d9 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Mon, 18 Mar 2024 12:37:30 -0700 Subject: [PATCH 17/22] add several more tests --- test/test-suite/src/main.rs | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/test/test-suite/src/main.rs b/test/test-suite/src/main.rs index 4c4efe250..bb11dd0c2 100644 --- a/test/test-suite/src/main.rs +++ b/test/test-suite/src/main.rs @@ -1436,16 +1436,40 @@ fn test_irq_status() { let status = sys_irq_status(notifications::TEST_IRQ_MASK); assert_eq!(status, IrqStatus::empty()); + // trigger an interrupt *without* setting the enabled flag. now, the + // interrupt should be pending but not posted. + trigger_test_irq(); + + let status = sys_irq_status(notifications::TEST_IRQ_MASK); + let expected_status = IrqStatus::PENDING; + assert_eq!(status, expected_status); + // enable the interrupt sys_irq_control(notifications::TEST_IRQ_MASK, true); - // okay, let's get interrupted! + // now, the pending IRQ should be posted to this task. + let status = sys_irq_status(notifications::TEST_IRQ_MASK); + let expected_status = IrqStatus::POSTED; + assert_eq!(status, expected_status); + + // if we trigger the same IRQ again, we should observe both the `PENDING` + // and `POSTED` bits, as one interrupt has been posted to our notification + // set, and the subsequent interrupt will be pending as we have not yet + // unmasked the IRQ. N.B. that because the `RECV` call in `trigger_test_irq` + // does *not* include the notification mask, we will not consume the posted + // notification. trigger_test_irq(); + let status = sys_irq_status(notifications::TEST_IRQ_MASK); + let expected_status = IrqStatus::POSTED | IrqStatus::PENDING; + assert_eq!(status, expected_status); + + // do a `RECV` call to consume the posted notification. Now, we have the + // second IRQ pending, and no notification posted. + sys_recv_closed(&mut [], notifications::TEST_IRQ_MASK, TaskId::KERNEL) + .unwrap(); - // now, there should be an IRQ pending, and a notification waiting for us let status = sys_irq_status(notifications::TEST_IRQ_MASK); - let expected_status = - IrqStatus::ENABLED | IrqStatus::PENDING | IrqStatus::POSTED; + let expected_status = IrqStatus::PENDING; assert_eq!(status, expected_status); } From e99621c1f43accb9ae6eb94dfec99b4cc4039025 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Mon, 18 Mar 2024 15:01:09 -0700 Subject: [PATCH 18/22] embiggen g070 demo flash --- app/demo-stm32g0-nucleo/app-g070.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/demo-stm32g0-nucleo/app-g070.toml b/app/demo-stm32g0-nucleo/app-g070.toml index 23d65209e..8918b93ad 100644 --- a/app/demo-stm32g0-nucleo/app-g070.toml +++ b/app/demo-stm32g0-nucleo/app-g070.toml @@ -7,7 +7,7 @@ stacksize = 944 [kernel] name = "demo-stm32g0-nucleo" -requires = {flash = 18976, ram = 1632} +requires = {flash = 19040, ram = 1632} features = ["g070"] stacksize = 640 From 6774e4734516dbf4c0d5a5282531a567cf80cfb5 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Mon, 18 Mar 2024 15:50:51 -0700 Subject: [PATCH 19/22] leave psc stuff broken --- test/tests-psc/app.toml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/tests-psc/app.toml b/test/tests-psc/app.toml index d877364fe..74dd0b367 100644 --- a/test/tests-psc/app.toml +++ b/test/tests-psc/app.toml @@ -66,12 +66,12 @@ start = true task-slots = ["sys"] [tasks.i2c_driver.interrupts] -"i2c2.event" = "0b0000_0010" -"i2c2.error" = "0b0000_0010" -"i2c3.event" = "0b0000_0100" -"i2c3.error" = "0b0000_0100" -"i2c4.event" = "0b0000_1000" -"i2c4.error" = "0b0000_1000" +"i2c2.event" = 0b0000_0010 +"i2c2.error" = 0b0000_0010 +"i2c3.event" = 0b0000_0100 +"i2c3.error" = 0b0000_0100 +"i2c4.event" = 0b0000_1000 +"i2c4.error" = 0b0000_1000 [tasks.hiffy] name = "task-hiffy" From b327e56ed29dccea6a879984808cba75b0baded8 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Mon, 18 Mar 2024 15:54:19 -0700 Subject: [PATCH 20/22] fix test compilation --- sys/abi/src/lib.rs | 2 +- test/test-suite/src/main.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sys/abi/src/lib.rs b/sys/abi/src/lib.rs index 16a3488b1..812afac57 100644 --- a/sys/abi/src/lib.rs +++ b/sys/abi/src/lib.rs @@ -182,7 +182,7 @@ pub struct ULease { pub length: u32, } -#[derive(Copy, Clone, Debug, FromBytes)] +#[derive(Copy, Clone, Debug, FromBytes, PartialEq, Eq)] #[repr(transparent)] pub struct LeaseAttributes(u32); diff --git a/test/test-suite/src/main.rs b/test/test-suite/src/main.rs index bb11dd0c2..7a882fa40 100644 --- a/test/test-suite/src/main.rs +++ b/test/test-suite/src/main.rs @@ -991,15 +991,15 @@ fn test_borrow_info() { // Borrow 0 is expected to be 16 bytes long and R/W. let info0 = caller.borrow(0).info().unwrap(); - // assert_eq!( - // info0.attributes, - // LeaseAttributes::READ | LeaseAttributes::WRITE - // ); + assert_eq!( + info0.attributes, + LeaseAttributes::READ | LeaseAttributes::WRITE + ); assert_eq!(info0.len, 16); // Borrow 1 is expected to be 5 bytes long and R/O. let info1 = caller.borrow(1).info().unwrap(); - // assert_eq!(info1.attributes, LeaseAttributes::READ); + assert_eq!(info1.attributes, LeaseAttributes::READ); assert_eq!(info1.len, 5); caller.reply(0); From 7e023008adf8e8a11d70d9eb4c5ea160b6076a0c Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Mon, 18 Mar 2024 15:58:36 -0700 Subject: [PATCH 21/22] remove stray register --- sys/userlib/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/userlib/src/lib.rs b/sys/userlib/src/lib.rs index 20e26faff..2f94942bd 100644 --- a/sys/userlib/src/lib.rs +++ b/sys/userlib/src/lib.rs @@ -1704,7 +1704,7 @@ unsafe extern "C" fn sys_irq_status_stub(_mask: u32) -> u32 { @ Restore the registers we used and return. pop {{r4}} mov r11, r4 - pop {{r4, r5, pc}} + pop {{r4, pc}} ", sysnum = const Sysnum::IrqStatus as u32, options(noreturn), From 6823016f8d1e4e217f8b979f7a5763757783136c Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Mon, 18 Mar 2024 16:05:43 -0700 Subject: [PATCH 22/22] embiggen donglets --- app/donglet/app-g031-i2c.toml | 2 +- app/donglet/app-g031.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/donglet/app-g031-i2c.toml b/app/donglet/app-g031-i2c.toml index 189c7a438..1b5fb04df 100644 --- a/app/donglet/app-g031-i2c.toml +++ b/app/donglet/app-g031-i2c.toml @@ -6,7 +6,7 @@ board = "donglet-g031" [kernel] name = "app-donglet" -requires = {flash = 18656, ram = 1616} +requires = {flash = 18720, ram = 1616} features = ["g031"] stacksize = 936 diff --git a/app/donglet/app-g031.toml b/app/donglet/app-g031.toml index 9252df242..f7252e00e 100644 --- a/app/donglet/app-g031.toml +++ b/app/donglet/app-g031.toml @@ -6,7 +6,7 @@ board = "donglet-g031" [kernel] name = "app-donglet" -requires = {flash = 18880, ram = 1820} +requires = {flash = 18944, ram = 1820} features = ["g031"] stacksize = 936