1
1
use alloc:: collections:: { BTreeMap , VecDeque } ;
2
- use alloc:: vec:: Vec ;
3
2
use core:: arch:: asm;
4
- use core:: ptr;
5
3
use core:: sync:: atomic:: { AtomicU64 , Ordering } ;
6
4
7
5
use aarch64:: regs:: * ;
8
6
use ahash:: RandomState ;
9
7
use arm_gic:: gicv3:: { GicV3 , InterruptGroup , SgiTarget , SgiTargetGroup } ;
10
8
use arm_gic:: { IntId , Trigger } ;
9
+ use fdt:: standard_nodes:: Compatible ;
11
10
use free_list:: PageLayout ;
12
11
use hashbrown:: HashMap ;
13
- use hermit_dtb:: Dtb ;
14
12
use hermit_sync:: { InterruptSpinMutex , InterruptTicketMutex , OnceCell , SpinMutex } ;
15
13
use memory_addresses:: VirtAddr ;
16
14
use memory_addresses:: arch:: aarch64:: PhysAddr ;
@@ -268,35 +266,25 @@ pub fn wakeup_core(core_id: CoreId) {
268
266
pub ( crate ) fn init ( ) {
269
267
info ! ( "Initialize generic interrupt controller" ) ;
270
268
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 ( ) ;
277
281
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 ( ) ;
292
282
let cpu_id: usize = core_id ( ) . try_into ( ) . unwrap ( ) ;
293
283
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" ) ;
300
288
let is_gic_v4 = if compatible == "arm,gic-v4" {
301
289
info ! ( "Found GIC v4 with {num_cpus} cpus" ) ;
302
290
true
@@ -348,15 +336,71 @@ pub(crate) fn init() {
348
336
gic. setup ( cpu_id) ;
349
337
GicV3 :: set_priority_mask ( 0xff ) ;
350
338
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}" ) ;
353
358
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 ;
360
404
/* Secure Phys IRQ */
361
405
let ( _irqtype, irq_slice) = irq_slice. split_at ( core:: mem:: size_of :: < u32 > ( ) ) ;
362
406
let ( _irq, irq_slice) = irq_slice. split_at ( core:: mem:: size_of :: < u32 > ( ) ) ;
@@ -368,15 +412,6 @@ pub(crate) fn init() {
368
412
let irqtype = u32:: from_be_bytes ( irqtype. try_into ( ) . unwrap ( ) ) ;
369
413
let irq = u32:: from_be_bytes ( irq. try_into ( ) . unwrap ( ) ) ;
370
414
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" ) ;
380
415
381
416
// enable timer interrupt
382
417
let timer_irqid = if irqtype == 1 {
@@ -396,73 +431,6 @@ pub(crate) fn init() {
396
431
}
397
432
gic. enable_interrupt ( timer_irqid, Some ( cpu_id) , true ) ;
398
433
}
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
- }
466
434
467
435
let reschedid = IntId :: sgi ( SGI_RESCHED . into ( ) ) ;
468
436
gic. set_interrupt_priority ( reschedid, Some ( cpu_id) , 0x01 ) ;
0 commit comments