11mod reg;
2+
23use core:: ptr:: NonNull ;
4+ use tock_registers:: interfaces:: * ;
35
46use reg:: * ;
57
6-
78/// GICv2 driver. (support GICv1)
89pub struct Gic {
9- gicd : NonNull < Distributor > ,
10- gicc : NonNull < CpuInterface > ,
10+ gicd : NonNull < DistributorReg > ,
11+ gicc : NonNull < CpuInterfaceReg > ,
1112}
1213
1314unsafe impl Send for Gic { }
@@ -25,7 +26,125 @@ impl Gic {
2526 }
2627 }
2728
28- fn gicd ( & self ) -> & Distributor {
29+ fn gicd ( & self ) -> & DistributorReg {
2930 unsafe { self . gicd . as_ref ( ) }
3031 }
31- }
32+
33+ pub fn init_cpu_interface ( & self ) -> CpuInterface {
34+ let mut c = CpuInterface {
35+ gicc : self . gicc ,
36+ } ;
37+ c. init ( ) ;
38+ c
39+ }
40+
41+ /// Initialize the GIC according to GICv2 specification
42+ /// This includes both Distributor and CPU Interface initialization
43+ pub fn init ( & self ) {
44+ // Initialize the Distributor
45+ self . gicd ( ) . init ( ) ;
46+ }
47+
48+ /// Enable a specific interrupt
49+ pub fn enable_interrupt ( & self , interrupt_id : u32 ) {
50+ self . gicd ( ) . enable_interrupt ( interrupt_id) ;
51+ }
52+
53+ /// Disable a specific interrupt
54+ pub fn disable_interrupt ( & self , interrupt_id : u32 ) {
55+ self . gicd ( ) . disable_interrupt ( interrupt_id) ;
56+ }
57+
58+ /// Set interrupt priority (0 = highest priority, 255 = lowest priority)
59+ pub fn set_interrupt_priority ( & self , interrupt_id : u32 , priority : u8 ) {
60+ self . gicd ( ) . set_interrupt_priority ( interrupt_id, priority) ;
61+ }
62+
63+ /// Set interrupt target CPU for SPIs (bit mask, bit 0 = CPU 0, etc.)
64+ pub fn set_interrupt_target ( & self , interrupt_id : u32 , target_cpu_mask : u8 ) {
65+ self . gicd ( ) . set_interrupt_target ( interrupt_id, target_cpu_mask) ;
66+ }
67+
68+ /// Configure interrupt as Group 0 (Secure) or Group 1 (Non-secure)
69+ pub fn set_interrupt_group ( & self , interrupt_id : u32 , group1 : bool ) {
70+ self . gicd ( ) . set_interrupt_group ( interrupt_id, group1) ;
71+ }
72+
73+ /// Send a Software Generated Interrupt (SGI) to target CPUs
74+ ///
75+ /// # Arguments
76+ /// * `sgi_id` - SGI interrupt ID (0-15)
77+ /// * `target_list` - Target CPU list (bit mask)
78+ /// * `filter` - Target list filter:
79+ /// - 0: Forward to CPUs listed in target_list
80+ /// - 1: Forward to all CPUs except requesting CPU
81+ /// - 2: Forward only to requesting CPU
82+ pub fn send_sgi ( & self , sgi_id : u32 , target_list : u8 , filter : u32 ) {
83+ self . gicd ( ) . send_sgi ( sgi_id, target_list, filter) ;
84+ }
85+ }
86+
87+ pub struct CpuInterface {
88+ gicc : NonNull < CpuInterfaceReg > ,
89+ }
90+
91+ impl CpuInterface {
92+ fn gicc ( & self ) -> & CpuInterfaceReg {
93+ unsafe { self . gicc . as_ref ( ) }
94+ }
95+
96+ fn init ( & mut self ) {
97+ let gicc = self . gicc ( ) ;
98+
99+ // 1. Disable CPU interface first
100+ gicc. CTLR . set ( 0 ) ;
101+
102+ // 2. Set priority mask to allow all interrupts (lowest priority)
103+ gicc. PMR . write ( PMR :: Priority . val ( 0xFF ) ) ;
104+
105+ // 3. Set binary point to default value (no preemption)
106+ gicc. BPR . write ( BPR :: BinaryPoint . val ( 0x2 ) ) ;
107+
108+ // 4. Set aliased binary point for Group 1 interrupts
109+ gicc. ABPR . write ( ABPR :: BinaryPoint . val ( 0x3 ) ) ;
110+
111+ // 5. Enable CPU interface for both Group 0 and Group 1 interrupts
112+ gicc. CTLR . write (
113+ GICC_CTLR :: EnableGrp0 :: SET +
114+ GICC_CTLR :: EnableGrp1 :: SET +
115+ GICC_CTLR :: FIQEn :: CLEAR + // Use IRQ for Group 0 interrupts
116+ GICC_CTLR :: AckCtl :: CLEAR // Separate acknowledge for groups
117+ ) ;
118+ }
119+
120+ /// Acknowledge an interrupt and return the interrupt ID
121+ /// Returns the interrupt ID and source CPU ID (for SGIs)
122+ pub fn acknowledge_interrupt ( & self ) -> ( u32 , u32 ) {
123+ let iar = self . gicc ( ) . IAR . get ( ) ;
124+ let interrupt_id = iar & 0x3FF ; // Bits [9:0]
125+ let cpu_id = ( iar >> 10 ) & 0x7 ; // Bits [12:10]
126+ ( interrupt_id, cpu_id)
127+ }
128+
129+ /// Signal end of interrupt processing
130+ pub fn end_of_interrupt ( & self , interrupt_id : u32 , cpu_id : u32 ) {
131+ let eoir_val = interrupt_id | ( cpu_id << 10 ) ;
132+ self . gicc ( ) . EOIR . set ( eoir_val) ;
133+ }
134+
135+ /// Get the highest priority pending interrupt ID
136+ pub fn get_highest_priority_pending ( & self ) -> u32 {
137+ let hppir = self . gicc ( ) . HPPIR . get ( ) ;
138+ hppir & 0x3FF // Bits [9:0]
139+ }
140+
141+ /// Get the current running priority
142+ pub fn get_running_priority ( & self ) -> u8 {
143+ ( self . gicc ( ) . RPR . get ( ) & 0xFF ) as u8
144+ }
145+
146+ /// Set the priority mask (interrupts with priority >= mask will be masked)
147+ pub fn set_priority_mask ( & self , mask : u8 ) {
148+ self . gicc ( ) . PMR . write ( PMR :: Priority . val ( mask as u32 ) ) ;
149+ }
150+ }
0 commit comments