11use alloc:: collections:: { BTreeMap , VecDeque } ;
2- use alloc:: vec:: Vec ;
32use core:: arch:: asm;
4- use core:: ptr;
53use core:: sync:: atomic:: { AtomicU64 , Ordering } ;
64
75use aarch64:: regs:: * ;
86use ahash:: RandomState ;
97use arm_gic:: gicv3:: { GicV3 , InterruptGroup , SgiTarget , SgiTargetGroup } ;
108use arm_gic:: { IntId , Trigger } ;
9+ use fdt:: standard_nodes:: Compatible ;
1110use free_list:: PageLayout ;
1211use hashbrown:: HashMap ;
13- use hermit_dtb:: Dtb ;
1412use hermit_sync:: { InterruptSpinMutex , InterruptTicketMutex , OnceCell , SpinMutex } ;
1513use memory_addresses:: VirtAddr ;
1614use memory_addresses:: arch:: aarch64:: PhysAddr ;
@@ -268,35 +266,25 @@ pub fn wakeup_core(core_id: CoreId) {
268266pub ( crate ) fn init ( ) {
269267 info ! ( "Initialize generic interrupt controller" ) ;
270268
271- let dtb = unsafe {
272- Dtb :: from_raw ( ptr:: with_exposed_provenance (
273- env:: boot_info ( ) . hardware_info . device_tree . unwrap ( ) . get ( ) as usize ,
274- ) )
275- . expect ( ".dtb file has invalid header" )
276- } ;
269+ let fdt = env:: fdt ( ) . unwrap ( ) ;
270+
271+ let intc_node = fdt. find_node ( "/intc" ) . unwrap ( ) ;
272+ let mut reg_iter = intc_node. reg ( ) . unwrap ( ) ;
273+ let gicd_reg = reg_iter. next ( ) . unwrap ( ) ;
274+ let gicr_reg = reg_iter. next ( ) . unwrap ( ) ;
275+ let gicd_start = PhysAddr :: from ( gicd_reg. starting_address . addr ( ) ) ;
276+ let gicr_start = PhysAddr :: from ( gicr_reg. starting_address . addr ( ) ) ;
277+ let gicd_size = u64:: try_from ( gicd_reg. size . unwrap ( ) ) . unwrap ( ) ;
278+ let gicr_size = u64:: try_from ( gicr_reg. size . unwrap ( ) ) . unwrap ( ) ;
279+
280+ let num_cpus = fdt. cpus ( ) . count ( ) ;
277281
278- let reg = dtb. get_property ( "/intc" , "reg" ) . unwrap ( ) ;
279- let ( slice, residual_slice) = reg. split_at ( core:: mem:: size_of :: < u64 > ( ) ) ;
280- let gicd_start = PhysAddr :: new ( u64:: from_be_bytes ( slice. try_into ( ) . unwrap ( ) ) ) ;
281- let ( slice, residual_slice) = residual_slice. split_at ( core:: mem:: size_of :: < u64 > ( ) ) ;
282- let gicd_size = u64:: from_be_bytes ( slice. try_into ( ) . unwrap ( ) ) ;
283- let ( slice, residual_slice) = residual_slice. split_at ( core:: mem:: size_of :: < u64 > ( ) ) ;
284- let gicr_start = PhysAddr :: new ( u64:: from_be_bytes ( slice. try_into ( ) . unwrap ( ) ) ) ;
285- let ( slice, _residual_slice) = residual_slice. split_at ( core:: mem:: size_of :: < u64 > ( ) ) ;
286- let gicr_size = u64:: from_be_bytes ( slice. try_into ( ) . unwrap ( ) ) ;
287-
288- let num_cpus = dtb
289- . enum_subnodes ( "/cpus" )
290- . filter ( |name| name. contains ( "cpu@" ) )
291- . count ( ) ;
292282 let cpu_id: usize = core_id ( ) . try_into ( ) . unwrap ( ) ;
293283
294- let compatible = core:: str:: from_utf8 (
295- dtb. get_property ( "/intc" , "compatible" )
296- . unwrap_or ( b"unknown" ) ,
297- )
298- . unwrap ( )
299- . replace ( '\0' , "" ) ;
284+ let compatible = intc_node
285+ . compatible ( )
286+ . map ( Compatible :: first)
287+ . unwrap_or ( "unknown" ) ;
300288 let is_gic_v4 = if compatible == "arm,gic-v4" {
301289 info ! ( "Found GIC v4 with {num_cpus} cpus" ) ;
302290 true
@@ -348,15 +336,71 @@ pub(crate) fn init() {
348336 gic. setup ( cpu_id) ;
349337 GicV3 :: set_priority_mask ( 0xff ) ;
350338
351- for node in dtb. enum_subnodes ( "/" ) {
352- let parts: Vec < _ > = node. split ( '@' ) . collect ( ) ;
339+ if let Some ( timer_node) = fdt. find_compatible ( & [ "arm,armv8-timer" , "arm,armv7-timer" ] ) {
340+ let irq_slice = timer_node. property ( "interrupts" ) . unwrap ( ) . value ;
341+
342+ /* Secure Phys IRQ */
343+ let ( _irqtype, irq_slice) = irq_slice. split_at ( core:: mem:: size_of :: < u32 > ( ) ) ;
344+ let ( _irq, irq_slice) = irq_slice. split_at ( core:: mem:: size_of :: < u32 > ( ) ) ;
345+ let ( _irqflags, irq_slice) = irq_slice. split_at ( core:: mem:: size_of :: < u32 > ( ) ) ;
346+ /* Non-secure Phys IRQ */
347+ let ( irqtype, irq_slice) = irq_slice. split_at ( core:: mem:: size_of :: < u32 > ( ) ) ;
348+ let ( irq, irq_slice) = irq_slice. split_at ( core:: mem:: size_of :: < u32 > ( ) ) ;
349+ let ( irqflags, _irq_slice) = irq_slice. split_at ( core:: mem:: size_of :: < u32 > ( ) ) ;
350+ let irqtype = u32:: from_be_bytes ( irqtype. try_into ( ) . unwrap ( ) ) ;
351+ let irq = u32:: from_be_bytes ( irq. try_into ( ) . unwrap ( ) ) ;
352+ let irqflags = u32:: from_be_bytes ( irqflags. try_into ( ) . unwrap ( ) ) ;
353+ unsafe {
354+ TIMER_INTERRUPT = irq;
355+ }
356+
357+ debug ! ( "Timer interrupt: {irq}, type {irqtype}, flags {irqflags}" ) ;
353358
354- if let Some ( compatible) = dtb. get_property ( parts. first ( ) . unwrap ( ) , "compatible" )
355- && core:: str:: from_utf8 ( compatible) . unwrap ( ) . contains ( "timer" )
356- {
357- let irq_slice = dtb
358- . get_property ( parts. first ( ) . unwrap ( ) , "interrupts" )
359- . unwrap ( ) ;
359+ IRQ_NAMES
360+ . lock ( )
361+ . insert ( u8:: try_from ( irq) . unwrap ( ) + PPI_START , "Timer" ) ;
362+
363+ // enable timer interrupt
364+ let timer_irqid = if irqtype == 1 {
365+ IntId :: ppi ( irq)
366+ } else if irqtype == 0 {
367+ IntId :: spi ( irq)
368+ } else {
369+ panic ! ( "Invalid interrupt type" ) ;
370+ } ;
371+ gic. set_interrupt_priority ( timer_irqid, Some ( cpu_id) , 0x00 ) ;
372+ if ( irqflags & 0xf ) == 4 || ( irqflags & 0xf ) == 8 {
373+ gic. set_trigger ( timer_irqid, Some ( cpu_id) , Trigger :: Level ) ;
374+ } else if ( irqflags & 0xf ) == 2 || ( irqflags & 0xf ) == 1 {
375+ gic. set_trigger ( timer_irqid, Some ( cpu_id) , Trigger :: Edge ) ;
376+ } else {
377+ panic ! ( "Invalid interrupt level!" ) ;
378+ }
379+ gic. enable_interrupt ( timer_irqid, Some ( cpu_id) , true ) ;
380+ }
381+
382+ let reschedid = IntId :: sgi ( SGI_RESCHED . into ( ) ) ;
383+ gic. set_interrupt_priority ( reschedid, Some ( cpu_id) , 0x01 ) ;
384+ gic. enable_interrupt ( reschedid, Some ( cpu_id) , true ) ;
385+ IRQ_NAMES . lock ( ) . insert ( SGI_RESCHED , "Reschedule" ) ;
386+
387+ * GIC . lock ( ) = Some ( gic) ;
388+ }
389+
390+ // marks the given CPU core as awake
391+ pub fn init_cpu ( ) {
392+ let cpu_id: usize = core_id ( ) . try_into ( ) . unwrap ( ) ;
393+
394+ if let Some ( ref mut gic) = * GIC . lock ( ) {
395+ debug ! ( "Mark cpu {cpu_id} as awake" ) ;
396+
397+ gic. setup ( cpu_id) ;
398+ GicV3 :: set_priority_mask ( 0xff ) ;
399+
400+ let fdt = env:: fdt ( ) . unwrap ( ) ;
401+
402+ if let Some ( timer_node) = fdt. find_compatible ( & [ "arm,armv8-timer" , "arm,armv7-timer" ] ) {
403+ let irq_slice = timer_node. property ( "interrupts" ) . unwrap ( ) . value ;
360404 /* Secure Phys IRQ */
361405 let ( _irqtype, irq_slice) = irq_slice. split_at ( core:: mem:: size_of :: < u32 > ( ) ) ;
362406 let ( _irq, irq_slice) = irq_slice. split_at ( core:: mem:: size_of :: < u32 > ( ) ) ;
@@ -368,15 +412,6 @@ pub(crate) fn init() {
368412 let irqtype = u32:: from_be_bytes ( irqtype. try_into ( ) . unwrap ( ) ) ;
369413 let irq = u32:: from_be_bytes ( irq. try_into ( ) . unwrap ( ) ) ;
370414 let irqflags = u32:: from_be_bytes ( irqflags. try_into ( ) . unwrap ( ) ) ;
371- unsafe {
372- TIMER_INTERRUPT = irq;
373- }
374-
375- debug ! ( "Timer interrupt: {irq}, type {irqtype}, flags {irqflags}" ) ;
376-
377- IRQ_NAMES
378- . lock ( )
379- . insert ( u8:: try_from ( irq) . unwrap ( ) + PPI_START , "Timer" ) ;
380415
381416 // enable timer interrupt
382417 let timer_irqid = if irqtype == 1 {
@@ -396,73 +431,6 @@ pub(crate) fn init() {
396431 }
397432 gic. enable_interrupt ( timer_irqid, Some ( cpu_id) , true ) ;
398433 }
399- }
400-
401- let reschedid = IntId :: sgi ( SGI_RESCHED . into ( ) ) ;
402- gic. set_interrupt_priority ( reschedid, Some ( cpu_id) , 0x01 ) ;
403- gic. enable_interrupt ( reschedid, Some ( cpu_id) , true ) ;
404- IRQ_NAMES . lock ( ) . insert ( SGI_RESCHED , "Reschedule" ) ;
405-
406- * GIC . lock ( ) = Some ( gic) ;
407- }
408-
409- // marks the given CPU core as awake
410- pub fn init_cpu ( ) {
411- let cpu_id: usize = core_id ( ) . try_into ( ) . unwrap ( ) ;
412-
413- if let Some ( ref mut gic) = * GIC . lock ( ) {
414- debug ! ( "Mark cpu {cpu_id} as awake" ) ;
415-
416- gic. setup ( cpu_id) ;
417- GicV3 :: set_priority_mask ( 0xff ) ;
418-
419- let dtb = unsafe {
420- Dtb :: from_raw ( ptr:: with_exposed_provenance (
421- env:: boot_info ( ) . hardware_info . device_tree . unwrap ( ) . get ( ) as usize ,
422- ) )
423- . expect ( ".dtb file has invalid header" )
424- } ;
425-
426- for node in dtb. enum_subnodes ( "/" ) {
427- let parts: Vec < _ > = node. split ( '@' ) . collect ( ) ;
428-
429- if let Some ( compatible) = dtb. get_property ( parts. first ( ) . unwrap ( ) , "compatible" )
430- && core:: str:: from_utf8 ( compatible) . unwrap ( ) . contains ( "timer" )
431- {
432- let irq_slice = dtb
433- . get_property ( parts. first ( ) . unwrap ( ) , "interrupts" )
434- . unwrap ( ) ;
435- /* Secure Phys IRQ */
436- let ( _irqtype, irq_slice) = irq_slice. split_at ( core:: mem:: size_of :: < u32 > ( ) ) ;
437- let ( _irq, irq_slice) = irq_slice. split_at ( core:: mem:: size_of :: < u32 > ( ) ) ;
438- let ( _irqflags, irq_slice) = irq_slice. split_at ( core:: mem:: size_of :: < u32 > ( ) ) ;
439- /* Non-secure Phys IRQ */
440- let ( irqtype, irq_slice) = irq_slice. split_at ( core:: mem:: size_of :: < u32 > ( ) ) ;
441- let ( irq, irq_slice) = irq_slice. split_at ( core:: mem:: size_of :: < u32 > ( ) ) ;
442- let ( irqflags, _irq_slice) = irq_slice. split_at ( core:: mem:: size_of :: < u32 > ( ) ) ;
443- let irqtype = u32:: from_be_bytes ( irqtype. try_into ( ) . unwrap ( ) ) ;
444- let irq = u32:: from_be_bytes ( irq. try_into ( ) . unwrap ( ) ) ;
445- let irqflags = u32:: from_be_bytes ( irqflags. try_into ( ) . unwrap ( ) ) ;
446-
447- // enable timer interrupt
448- let timer_irqid = if irqtype == 1 {
449- IntId :: ppi ( irq)
450- } else if irqtype == 0 {
451- IntId :: spi ( irq)
452- } else {
453- panic ! ( "Invalid interrupt type" ) ;
454- } ;
455- gic. set_interrupt_priority ( timer_irqid, Some ( cpu_id) , 0x00 ) ;
456- if ( irqflags & 0xf ) == 4 || ( irqflags & 0xf ) == 8 {
457- gic. set_trigger ( timer_irqid, Some ( cpu_id) , Trigger :: Level ) ;
458- } else if ( irqflags & 0xf ) == 2 || ( irqflags & 0xf ) == 1 {
459- gic. set_trigger ( timer_irqid, Some ( cpu_id) , Trigger :: Edge ) ;
460- } else {
461- panic ! ( "Invalid interrupt level!" ) ;
462- }
463- gic. enable_interrupt ( timer_irqid, Some ( cpu_id) , true ) ;
464- }
465- }
466434
467435 let reschedid = IntId :: sgi ( SGI_RESCHED . into ( ) ) ;
468436 gic. set_interrupt_priority ( reschedid, Some ( cpu_id) , 0x01 ) ;
0 commit comments