1pub use esp_riscv_rt::TrapFrame;
16use riscv::register::{mcause, mtvec};
17
18#[cfg(not(plic))]
19pub use self::classic::*;
20#[cfg(plic)]
21pub use self::plic::*;
22pub use self::vectored::*;
23use super::InterruptStatus;
24use crate::{
25 pac,
26 peripherals::{INTERRUPT_CORE0, Interrupt},
27 system::Cpu,
28};
29
30#[derive(Copy, Clone, Debug, PartialEq, Eq)]
32#[cfg_attr(feature = "defmt", derive(defmt::Format))]
33pub enum Error {
34 InvalidInterruptPriority,
36 CpuInterruptReserved,
38}
39
40#[cfg_attr(feature = "defmt", derive(defmt::Format))]
42pub enum InterruptKind {
43 Level,
45 Edge,
47}
48
49#[repr(u32)]
53#[derive(Debug, Copy, Clone)]
54#[cfg_attr(feature = "defmt", derive(defmt::Format))]
55pub enum CpuInterrupt {
56 Interrupt1 = 1,
58 Interrupt2,
60 Interrupt3,
62 Interrupt4,
64 Interrupt5,
66 Interrupt6,
68 Interrupt7,
70 Interrupt8,
72 Interrupt9,
74 Interrupt10,
76 Interrupt11,
78 Interrupt12,
80 Interrupt13,
82 Interrupt14,
84 Interrupt15,
86 Interrupt16,
88 Interrupt17,
90 Interrupt18,
92 Interrupt19,
94 Interrupt20,
96 Interrupt21,
98 Interrupt22,
100 Interrupt23,
102 Interrupt24,
104 Interrupt25,
106 Interrupt26,
108 Interrupt27,
110 Interrupt28,
112 Interrupt29,
114 Interrupt30,
116 Interrupt31,
118}
119
120#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
122#[cfg_attr(feature = "defmt", derive(defmt::Format))]
123#[repr(u8)]
124pub enum Priority {
125 None = 0,
127 Priority1,
129 Priority2,
131 Priority3,
133 Priority4,
135 Priority5,
137 Priority6,
139 Priority7,
141 Priority8,
143 Priority9,
145 Priority10,
147 Priority11,
149 Priority12,
151 Priority13,
153 Priority14,
155 Priority15,
157}
158
159impl Priority {
160 pub const fn max() -> Priority {
162 Priority::Priority15
163 }
164
165 pub const fn min() -> Priority {
167 Priority::Priority1
168 }
169}
170
171impl TryFrom<u32> for Priority {
172 type Error = Error;
173
174 fn try_from(value: u32) -> Result<Self, Self::Error> {
175 match value {
176 0 => Ok(Priority::None),
177 1 => Ok(Priority::Priority1),
178 2 => Ok(Priority::Priority2),
179 3 => Ok(Priority::Priority3),
180 4 => Ok(Priority::Priority4),
181 5 => Ok(Priority::Priority5),
182 6 => Ok(Priority::Priority6),
183 7 => Ok(Priority::Priority7),
184 8 => Ok(Priority::Priority8),
185 9 => Ok(Priority::Priority9),
186 10 => Ok(Priority::Priority10),
187 11 => Ok(Priority::Priority11),
188 12 => Ok(Priority::Priority12),
189 13 => Ok(Priority::Priority13),
190 14 => Ok(Priority::Priority14),
191 15 => Ok(Priority::Priority15),
192 _ => Err(Error::InvalidInterruptPriority),
193 }
194 }
195}
196
197impl TryFrom<u8> for Priority {
198 type Error = Error;
199
200 fn try_from(value: u8) -> Result<Self, Self::Error> {
201 Priority::try_from(value as u32)
202 }
203}
204
205#[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))]
207pub static RESERVED_INTERRUPTS: &[usize] = PRIORITY_TO_INTERRUPT;
208
209#[doc(hidden)]
213#[unsafe(link_section = ".trap.rust")]
214#[unsafe(export_name = "_start_trap_rust_hal")]
215pub unsafe extern "C" fn start_trap_rust_hal(trap_frame: *mut TrapFrame) {
216 assert!(
217 mcause::read().is_exception(),
218 "Arrived into _start_trap_rust_hal but mcause is not an exception!"
219 );
220 unsafe extern "C" {
221 fn ExceptionHandler(tf: *mut TrapFrame);
222 }
223 unsafe {
224 ExceptionHandler(trap_frame);
225 }
226}
227
228#[doc(hidden)]
229#[unsafe(no_mangle)]
230pub fn _setup_interrupts() {
231 unsafe extern "C" {
232 static _vector_table: *const u32;
233 }
234
235 unsafe {
236 for peripheral_interrupt in 0..255 {
240 crate::peripherals::Interrupt::try_from(peripheral_interrupt)
241 .map(|intr| {
242 #[cfg(multi_core)]
243 disable(Cpu::AppCpu, intr);
244 disable(Cpu::ProCpu, intr);
245 })
246 .ok();
247 }
248
249 let vec_table = &_vector_table as *const _ as usize;
250 mtvec::write(vec_table, mtvec::TrapMode::Vectored);
251
252 crate::interrupt::init_vectoring();
253 };
254
255 #[cfg(plic)]
256 unsafe {
257 core::arch::asm!("csrw mie, {0}", in(reg) u32::MAX);
258 }
259}
260
261pub fn enable_direct(
268 interrupt: Interrupt,
269 level: Priority,
270 cpu_interrupt: CpuInterrupt,
271) -> Result<(), Error> {
272 if RESERVED_INTERRUPTS.contains(&(cpu_interrupt as _)) {
273 return Err(Error::CpuInterruptReserved);
274 }
275 if matches!(level, Priority::None) {
276 return Err(Error::InvalidInterruptPriority);
277 }
278 unsafe {
279 map(Cpu::current(), interrupt, cpu_interrupt);
280 set_priority(Cpu::current(), cpu_interrupt, level);
281 enable_cpu_interrupt(cpu_interrupt);
282 }
283 Ok(())
284}
285
286pub fn disable(_core: Cpu, interrupt: Interrupt) {
288 unsafe {
289 let interrupt_number = interrupt as isize;
290 let intr_map_base = crate::soc::registers::INTERRUPT_MAP_BASE as *mut u32;
291
292 intr_map_base
295 .offset(interrupt_number)
296 .write_volatile(DISABLED_CPU_INTERRUPT);
297 }
298}
299
300#[inline]
302pub fn status(_core: Cpu) -> InterruptStatus {
303 cfg_if::cfg_if! {
304 if #[cfg(large_intr_status)] {
305 InterruptStatus::from(
306 INTERRUPT_CORE0::regs().intr_status_reg_0().read().bits(),
307 INTERRUPT_CORE0::regs().intr_status_reg_1().read().bits(),
308 INTERRUPT_CORE0::regs().int_status_reg_2().read().bits(),
309 )
310 } else if #[cfg(very_large_intr_status)] {
311 InterruptStatus::from(
312 INTERRUPT_CORE0::regs().intr_status_reg_0().read().bits(),
313 INTERRUPT_CORE0::regs().intr_status_reg_1().read().bits(),
314 INTERRUPT_CORE0::regs().intr_status_reg_2().read().bits(),
315 INTERRUPT_CORE0::regs().intr_status_reg_3().read().bits(),
316 )
317 } else {
318 InterruptStatus::from(
319 INTERRUPT_CORE0::regs().intr_status_reg_0().read().bits(),
320 INTERRUPT_CORE0::regs().intr_status_reg_1().read().bits(),
321 )
322 }
323 }
324}
325
326pub unsafe fn map(_core: Cpu, interrupt: Interrupt, which: CpuInterrupt) {
332 let interrupt_number = interrupt as isize;
333 let cpu_interrupt_number = which as isize;
334 #[cfg(not(multi_core))]
335 let intr_map_base = crate::soc::registers::INTERRUPT_MAP_BASE as *mut u32;
336 #[cfg(multi_core)]
337 let intr_map_base = match _core {
338 Cpu::ProCpu => crate::soc::registers::INTERRUPT_MAP_BASE as *mut u32,
339 Cpu::AppCpu => crate::soc::registers::INTERRUPT_MAP_BASE_APP_CPU as *mut u32,
340 };
341
342 unsafe {
343 intr_map_base
344 .offset(interrupt_number)
345 .write_volatile(cpu_interrupt_number as u32 + EXTERNAL_INTERRUPT_OFFSET);
346 }
347}
348
349#[inline]
351unsafe fn assigned_cpu_interrupt(interrupt: Interrupt) -> Option<CpuInterrupt> {
352 let interrupt_number = interrupt as isize;
353 let intr_map_base = crate::soc::registers::INTERRUPT_MAP_BASE as *mut u32;
354
355 let cpu_intr = unsafe { intr_map_base.offset(interrupt_number).read_volatile() };
356 if cpu_intr > 0 && cpu_intr != DISABLED_CPU_INTERRUPT {
357 Some(unsafe {
358 core::mem::transmute::<u32, CpuInterrupt>(cpu_intr - EXTERNAL_INTERRUPT_OFFSET)
359 })
360 } else {
361 None
362 }
363}
364
365pub(crate) fn bound_cpu_interrupt_for(_cpu: Cpu, interrupt: Interrupt) -> Option<CpuInterrupt> {
366 unsafe { assigned_cpu_interrupt(interrupt) }
367}
368
369mod vectored {
370 use procmacros::ram;
371
372 use super::*;
373
374 #[doc(hidden)]
376 pub(crate) unsafe fn init_vectoring() {
377 for (prio, num) in PRIORITY_TO_INTERRUPT.iter().enumerate() {
378 unsafe {
379 set_kind(
380 Cpu::current(),
381 core::mem::transmute::<u32, CpuInterrupt>(*num as u32),
382 InterruptKind::Level,
383 );
384 set_priority(
385 Cpu::current(),
386 core::mem::transmute::<u32, CpuInterrupt>(*num as u32),
387 core::mem::transmute::<u8, Priority>((prio as u8) + 1),
388 );
389 enable_cpu_interrupt(core::mem::transmute::<u32, CpuInterrupt>(*num as u32));
390 }
391 }
392 }
393
394 #[inline]
397 fn configured_interrupts(
398 core: Cpu,
399 status: InterruptStatus,
400 priority: Priority,
401 ) -> InterruptStatus {
402 unsafe {
403 let mut res = InterruptStatus::empty();
404
405 for interrupt_nr in status.iterator() {
406 if let Some(cpu_interrupt) =
408 assigned_cpu_interrupt(core::mem::transmute::<u16, Interrupt>(
409 interrupt_nr as u16,
410 ))
411 {
412 if priority_by_core(core, cpu_interrupt) == priority {
413 res.set(interrupt_nr);
414 }
415 }
416 }
417 res
418 }
419 }
420
421 pub fn enable(interrupt: Interrupt, level: Priority) -> Result<(), Error> {
426 enable_on_cpu(Cpu::current(), interrupt, level)
427 }
428
429 pub(crate) fn enable_on_cpu(
430 cpu: Cpu,
431 interrupt: Interrupt,
432 level: Priority,
433 ) -> Result<(), Error> {
434 if matches!(level, Priority::None) {
435 return Err(Error::InvalidInterruptPriority);
436 }
437 unsafe {
438 let cpu_interrupt = core::mem::transmute::<u32, CpuInterrupt>(
439 PRIORITY_TO_INTERRUPT[(level as usize) - 1] as u32,
440 );
441 map(cpu, interrupt, cpu_interrupt);
442 enable_cpu_interrupt(cpu_interrupt);
443 }
444 Ok(())
445 }
446
447 pub unsafe fn bind_interrupt(interrupt: Interrupt, handler: unsafe extern "C" fn()) {
453 unsafe {
454 let ptr = &pac::__EXTERNAL_INTERRUPTS[interrupt as usize]._handler as *const _
455 as *mut unsafe extern "C" fn();
456 ptr.write_volatile(handler);
457 }
458 }
459
460 pub fn bound_handler(interrupt: Interrupt) -> Option<unsafe extern "C" fn()> {
462 unsafe {
463 let addr = pac::__EXTERNAL_INTERRUPTS[interrupt as usize]._handler;
464 if addr as usize == 0 {
465 return None;
466 }
467
468 Some(addr)
469 }
470 }
471
472 #[unsafe(no_mangle)]
473 #[ram]
474 unsafe fn handle_interrupts(cpu_intr: CpuInterrupt, context: &mut TrapFrame) {
475 let core = Cpu::current();
476 let status = status(core);
477
478 clear(core, cpu_intr);
481
482 let priority = INTERRUPT_TO_PRIORITY[cpu_intr as usize];
483 let prio: Priority = unsafe { core::mem::transmute(priority) };
484 let configured_interrupts = configured_interrupts(core, status, prio);
485
486 for interrupt_nr in configured_interrupts.iterator() {
487 let interrupt: Interrupt = unsafe { core::mem::transmute(interrupt_nr as u16) };
489 unsafe {
490 handle_interrupt(interrupt, context);
491 }
492 }
493 }
494
495 #[inline(always)]
496 unsafe fn handle_interrupt(interrupt: Interrupt, save_frame: &mut TrapFrame) {
497 unsafe extern "C" {
498 fn EspDefaultHandler(interrupt: Interrupt);
500 }
501
502 let handler = unsafe { pac::__EXTERNAL_INTERRUPTS[interrupt as usize]._handler };
503
504 if core::ptr::eq(
505 handler as *const _,
506 EspDefaultHandler as *const unsafe extern "C" fn(),
507 ) {
508 unsafe { EspDefaultHandler(interrupt) };
509 } else {
510 let handler: fn(&mut TrapFrame) = unsafe {
511 core::mem::transmute::<unsafe extern "C" fn(), fn(&mut TrapFrame)>(handler)
512 };
513 handler(save_frame);
514 }
515 }
516
517 macro_rules! interrupt_handler {
544 ($num:literal) => {
545 core::arch::global_asm! {
546 concat!(
547 r#"
548 .section .rwtext, "ax"
549 .global interrupt"#,$num,r#"
550
551 interrupt"#,$num,r#":
552 mv a1, a0
553 li a0,"#,$num,r#"
554 j handle_interrupts
555 "#
556 )
557 }
558 };
559 }
560
561 interrupt_handler!(1);
562 interrupt_handler!(2);
563 interrupt_handler!(3);
564 interrupt_handler!(4);
565 interrupt_handler!(5);
566 interrupt_handler!(6);
567 interrupt_handler!(7);
568 interrupt_handler!(8);
569 interrupt_handler!(9);
570 interrupt_handler!(10);
571 interrupt_handler!(11);
572 interrupt_handler!(12);
573 interrupt_handler!(13);
574 interrupt_handler!(14);
575 interrupt_handler!(15);
576
577 #[cfg(plic)]
578 interrupt_handler!(16);
579 #[cfg(plic)]
580 interrupt_handler!(17);
581 #[cfg(plic)]
582 interrupt_handler!(18);
583 #[cfg(plic)]
584 interrupt_handler!(19);
585}
586
587#[cfg(not(plic))]
588mod classic {
589 use super::{CpuInterrupt, InterruptKind, Priority};
590 use crate::{peripherals::INTERRUPT_CORE0, system::Cpu};
591
592 #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))]
593 pub(super) static DISABLED_CPU_INTERRUPT: u32 = 0;
594
595 #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))]
596 pub(super) static EXTERNAL_INTERRUPT_OFFSET: u32 = 0;
597
598 #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))]
599 pub(super) static PRIORITY_TO_INTERRUPT: &[usize] =
600 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
601
602 #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))]
604 pub(super) static INTERRUPT_TO_PRIORITY: [u8; 16] =
605 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
606
607 pub unsafe fn enable_cpu_interrupt(which: CpuInterrupt) {
613 let cpu_interrupt_number = which as isize;
614 let intr = INTERRUPT_CORE0::regs();
615 intr.cpu_int_enable()
616 .modify(|r, w| unsafe { w.bits((1 << cpu_interrupt_number) | r.bits()) });
617 }
618
619 pub fn set_kind(_core: Cpu, which: CpuInterrupt, kind: InterruptKind) {
624 unsafe {
625 let intr = INTERRUPT_CORE0::regs();
626 let cpu_interrupt_number = which as isize;
627
628 let interrupt_type = match kind {
629 InterruptKind::Level => 0,
630 InterruptKind::Edge => 1,
631 };
632 intr.cpu_int_type().modify(|r, w| {
633 w.bits(
634 r.bits() & !(1 << cpu_interrupt_number)
635 | (interrupt_type << cpu_interrupt_number),
636 )
637 });
638 }
639 }
640
641 pub unsafe fn set_priority(_core: Cpu, which: CpuInterrupt, priority: Priority) {
648 let intr = INTERRUPT_CORE0::regs();
649 intr.cpu_int_pri(which as usize)
650 .write(|w| unsafe { w.map().bits(priority as u8) });
651 }
652
653 #[inline]
655 pub fn clear(_core: Cpu, which: CpuInterrupt) {
656 unsafe {
657 let cpu_interrupt_number = which as usize;
658 let intr = INTERRUPT_CORE0::regs();
659 intr.cpu_int_clear()
660 .write(|w| w.bits(1 << cpu_interrupt_number));
661 }
662 }
663
664 #[inline]
666 pub(super) fn priority_by_core(_core: Cpu, cpu_interrupt: CpuInterrupt) -> Priority {
667 unsafe { priority(cpu_interrupt) }
668 }
669
670 #[inline]
672 pub(super) unsafe extern "C" fn priority(cpu_interrupt: CpuInterrupt) -> Priority {
673 let intr = INTERRUPT_CORE0::regs();
674 unsafe {
675 core::mem::transmute::<u8, Priority>(
676 intr.cpu_int_pri(cpu_interrupt as usize).read().map().bits(),
677 )
678 }
679 }
680 #[unsafe(no_mangle)]
681 #[unsafe(link_section = ".trap")]
682 pub(super) unsafe extern "C" fn _handle_priority() -> u32 {
683 use super::mcause;
684 let interrupt_id: usize = mcause::read().bits() & 0x1f;
687 let intr = INTERRUPT_CORE0::regs();
688 let interrupt_priority = unsafe {
689 intr.cpu_int_pri(0)
690 .as_ptr()
691 .add(interrupt_id)
692 .read_volatile()
693 };
694
695 let prev_interrupt_priority = intr.cpu_int_thresh().read().bits();
696 if interrupt_priority < 15 {
697 intr.cpu_int_thresh()
699 .write(|w| unsafe { w.bits(interrupt_priority + 1) }); unsafe { riscv::interrupt::enable() };
701 }
702 prev_interrupt_priority
703 }
704 #[unsafe(no_mangle)]
705 #[unsafe(link_section = ".trap")]
706 pub(super) unsafe extern "C" fn _restore_priority(stored_prio: u32) {
707 riscv::interrupt::disable();
708 let intr = INTERRUPT_CORE0::regs();
709 intr.cpu_int_thresh()
710 .write(|w| unsafe { w.bits(stored_prio) });
711 }
712
713 pub fn current_runlevel() -> Priority {
715 let intr = INTERRUPT_CORE0::regs();
716 let prev_interrupt_priority = intr.cpu_int_thresh().read().bits().saturating_sub(1) as u8;
717
718 unwrap!(Priority::try_from(prev_interrupt_priority))
719 }
720
721 pub(crate) unsafe fn change_current_runlevel(level: Priority) -> Priority {
730 let prev_interrupt_priority = current_runlevel();
731
732 INTERRUPT_CORE0::regs()
735 .cpu_int_thresh()
736 .write(|w| unsafe { w.bits(level as u32 + 1) });
737
738 prev_interrupt_priority
739 }
740}
741
742#[cfg(plic)]
743mod plic {
744 use super::{CpuInterrupt, InterruptKind, Priority};
745 use crate::{peripherals::PLIC_MX, system::Cpu};
746
747 #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))]
748 pub(super) static DISABLED_CPU_INTERRUPT: u32 = 31;
749
750 #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))]
751 pub(super) static EXTERNAL_INTERRUPT_OFFSET: u32 = 0;
752
753 #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))]
757 pub(super) static PRIORITY_TO_INTERRUPT: &[usize] =
758 &[1, 2, 5, 6, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19];
759
760 #[cfg_attr(place_switch_tables_in_ram, unsafe(link_section = ".rwtext"))]
762 pub(super) static INTERRUPT_TO_PRIORITY: [u8; 20] = [
763 0, 1, 2, 0, 0, 3, 4, 0, 0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
764 ];
765
766 pub unsafe fn enable_cpu_interrupt(which: CpuInterrupt) {
772 unsafe {
773 PLIC_MX::regs().mxint_enable().modify(|r, w| {
774 let old = r.cpu_mxint_enable().bits();
775 let new = old | (1 << (which as isize));
776 w.cpu_mxint_enable().bits(new)
777 });
778 }
779 }
780
781 pub fn set_kind(_core: Cpu, which: CpuInterrupt, kind: InterruptKind) {
786 let interrupt_type = match kind {
787 InterruptKind::Level => 0,
788 InterruptKind::Edge => 1,
789 };
790
791 unsafe {
792 PLIC_MX::regs().mxint_type().modify(|r, w| {
793 let old = r.cpu_mxint_type().bits();
794 let new = old & !(1 << (which as isize)) | (interrupt_type << (which as isize));
795 w.cpu_mxint_type().bits(new)
796 });
797 }
798 }
799
800 pub unsafe fn set_priority(_core: Cpu, which: CpuInterrupt, priority: Priority) {
807 unsafe {
808 PLIC_MX::regs()
809 .mxint_pri(which as usize)
810 .modify(|_, w| w.cpu_mxint_pri().bits(priority as u8));
811 }
812 }
813
814 #[inline]
816 pub fn clear(_core: Cpu, which: CpuInterrupt) {
817 unsafe {
818 PLIC_MX::regs().mxint_clear().modify(|r, w| {
819 let old = r.cpu_mxint_clear().bits();
820 let new = old | (1 << (which as isize));
821 w.cpu_mxint_clear().bits(new)
822 });
823 }
824 }
825
826 #[inline]
828 pub(super) unsafe extern "C" fn priority_by_core(
829 _core: Cpu,
830 cpu_interrupt: CpuInterrupt,
831 ) -> Priority {
832 unsafe { priority(cpu_interrupt) }
833 }
834
835 #[inline]
837 pub(super) unsafe extern "C" fn priority(cpu_interrupt: CpuInterrupt) -> Priority {
838 let prio = PLIC_MX::regs()
839 .mxint_pri(cpu_interrupt as usize)
840 .read()
841 .cpu_mxint_pri()
842 .bits();
843 unsafe { core::mem::transmute::<u8, Priority>(prio) }
844 }
845 #[unsafe(no_mangle)]
846 #[unsafe(link_section = ".trap")]
847 pub(super) unsafe extern "C" fn _handle_priority() -> u32 {
848 let interrupt_id: usize = super::mcause::read().code(); let interrupt_priority = PLIC_MX::regs()
850 .mxint_pri(interrupt_id)
851 .read()
852 .cpu_mxint_pri()
853 .bits();
854
855 let prev_interrupt_priority = PLIC_MX::regs()
856 .mxint_thresh()
857 .read()
858 .cpu_mxint_thresh()
859 .bits();
860 if interrupt_priority < 15 {
861 PLIC_MX::regs()
863 .mxint_thresh()
864 .write(|w| unsafe { w.cpu_mxint_thresh().bits(interrupt_priority + 1) });
865
866 unsafe {
867 riscv::interrupt::enable();
868 }
869 }
870 prev_interrupt_priority as u32
871 }
872 #[unsafe(no_mangle)]
873 #[unsafe(link_section = ".trap")]
874 pub(super) unsafe extern "C" fn _restore_priority(stored_prio: u32) {
875 riscv::interrupt::disable();
876 PLIC_MX::regs()
877 .mxint_thresh()
878 .write(|w| unsafe { w.cpu_mxint_thresh().bits(stored_prio as u8) });
879 }
880
881 pub fn current_runlevel() -> Priority {
883 let prev_interrupt_priority = PLIC_MX::regs()
884 .mxint_thresh()
885 .read()
886 .cpu_mxint_thresh()
887 .bits()
888 .saturating_sub(1);
889
890 unwrap!(Priority::try_from(prev_interrupt_priority))
891 }
892
893 pub(crate) unsafe fn change_current_runlevel(level: Priority) -> Priority {
902 let prev_interrupt_priority = current_runlevel();
903
904 PLIC_MX::regs()
907 .mxint_thresh()
908 .write(|w| unsafe { w.cpu_mxint_thresh().bits(level as u8 + 1) });
909
910 prev_interrupt_priority
911 }
912}