Chapter 6 GICv3 Architecture and Interrupt Handling Practice
6.3 Interrupt State Machine and Priority Preemption Mechanism
6.3.1 Overview of Interrupt State Machine
In the GICv3 architecture, each interrupt has a precise state machine to track its lifecycle. Understanding the interrupt state machine is crucial for correctly configuring interrupt handling, diagnosing interrupt issues, and implementing a reliable interrupt handling system.
Design Philosophy of Interrupt State Machine
The design of the interrupt state machine is based on the following core principles:
-
Determinism: Each state transition has clear triggering conditions.
-
Completeness: Covers the entire lifecycle from interrupt generation to handling completion.
-
Observability: Provides register interfaces to monitor interrupt states.
-
Reliability: Ensures atomicity and consistency of state transitions.
6.3.2 Detailed Analysis of Interrupt State Machine
Four-State Model
GICv3 defines four basic states for each interrupt:

Detailed Definition of States
Inactive:
- The interrupt has not occurred or has been completely handled.
- The interrupt signal line is inactive.
- The corresponding pending and active bits are both 0.
Pending:
- The interrupt has occurred but has not yet been acknowledged by the processor.
- The interrupt signal has been received by the GIC but has not yet been delivered to the CPU.
- The corresponding pending bit is 1, and the active bit is 0.
Active:
- The interrupt has been acknowledged by the processor and is being processed.
- The CPU has read the interrupt ID but has not yet notified completion.
- The corresponding pending bit is 0, and the active bit is 1.
Active and Pending:
- The same interrupt occurs again while the processor is processing it.
- This indicates that the interrupt handling cannot keep up with the frequency of interrupt occurrences.
- The corresponding pending and active bits are both 1.
State Transition Conditions
State Transition Trigger Condition Matrix:
|
Transition Path |
Trigger Condition |
Hardware/Software Control |
|
Inactive → Pending |
Interrupt signal triggers or software writes to the pending bit. |
Hardware/Software |
|
Pending → Active |
The processor reads ICC_IARn_EL1. |
Hardware |
|
Active → Inactive |
The processor writes to ICC_EOIRn_EL1. |
Software |
|
Active → Active and Pending |
The interrupt occurs again while in the Active state. |
Hardware |
|
Active and Pending → Pending |
The processor writes to ICC_EOIRn_EL1. |
Software |
6.3.3 State Registers and State Management
State Register Architecture
GICv3 manages and monitors interrupt states through a set of registers:
// Interrupt state register grouptypedef struct { // Pending state register volatile uint32_t GICD_ISPENDR[32]; // Pending state set register volatile uint32_t GICD_ICPENDR[32]; // Pending state clear register // Active state register volatile uint32_t GICD_ISACTIVER[32]; // Active state set register volatile uint32_t GICD_ICACTIVER[32]; // Active state clear register // State read register (read-only) volatile uint32_t GICD_ISPENDR_R[32]; // Pending state read volatile uint32_t GICD_ISACTIVER_R[32]; // Active state read} gic_state_registers_t; // State monitoring and diagnosis // Interrupt state monitoring functionvoid monitor_interrupt_state(uint32_t interrupt_id) { uint32_t pending, active; if (interrupt_id < 32) { // SGI or PPI - in redistributor pending = gicr->GICR_ISPENDR0 & (1 << interrupt_id); active = gicr->GICR_ISACTIVER0 & (1 << interrupt_id); } else { // SPI - in distributor uint32_t reg = interrupt_id / 32; uint32_t bit = interrupt_id % 32; pending = gicd->GICD_ISPENDR_R[reg] & (1 << bit); active = gicd->GICD_ISACTIVER_R[reg] & (1 << bit); } printf("Interrupt %d state: ", interrupt_id); if (pending && active) { printf("Active and Pending\n"); } else if (pending) { printf("Pending\n"); } else if (active) { printf("Active\n"); } else { printf("Inactive\n"); }} // Batch state diagnosisvoid diagnose_interrupt_states(uint32_t start_id, uint32_t count) { printf("=== Interrupt State Diagnosis (ID %d-%d) ===\n", start_id, start_id + count - 1); uint32_t inactive_count = 0, pending_count = 0; uint32_t active_count = 0, active_pending_count = 0; for (uint32_t i = start_id; i < start_id + count; i++) { uint32_t pending, active; if (i < 32) { pending = gicr->GICR_ISPENDR0 & (1 << i); active = gicr->GICR_ISACTIVER0 & (1 << i); } else { uint32_t reg = i / 32; uint32_t bit = i % 32; pending = gicd->GICD_ISPENDR_R[reg] & (1 << bit); active = gicd->GICD_ISACTIVER_R[reg] & (1 << bit); } if (pending && active) active_pending_count++; else if (pending) pending_count++; else if (active) active_count++; else inactive_count++; } printf("Statistics:\n"); printf(" Inactive: %d\n", inactive_count); printf(" Pending: %d\n", pending_count); printf(" Active: %d\n", active_count); printf(" Active and Pending: %d\n", active_pending_count); if (active_pending_count > 0) { printf("Warning: Found %d interrupts in Active and Pending state\n", active_pending_count); printf("This may indicate that the interrupt handling speed cannot keep up with the frequency of interrupt occurrences\n"); }}
6.3.4 Priority Preemption Mechanism
Priority Architecture Principles
GICv3 uses an 8-bit priority field, supporting 256 priority levels (0-255), with lower values indicating higher priority:

Priority Grouping and Preemption Strategy
Priority Bit Field Division:
typedef struct { uint8_t group_priority : 4; // Group priority (high 4 bits) uint8_t sub_priority : 4; // Sub-priority (low 4 bits)} priority_field_t;
Preemption Rules:
-
Group Priority Comparison: Determines whether preemption occurs.
-
Sub-Priority Comparison: Determines the processing order when group priorities are the same.
-
Running Priority: The priority of the interrupt currently being processed by the CPU.
Priority Mask and Masking
// Priority mask register operationvoid configure_priority_mask(uint8_t priority_threshold) { // Set the priority mask register // Only interrupts with a priority higher than this value can be processed write_icc_pmr_el1(priority_threshold); printf("Priority mask set to: 0x%02X\n", priority_threshold);}// Dynamic priority adjustmentvoid dynamic_priority_management(void) { uint32_t current_priority = read_icc_rpr_el1(); // Dynamically adjust the priority mask based on system load if (system_load_high()) { // Under high load, only process critical interrupts write_icc_pmr_el1(0x20); // Only process interrupts with priority 0x00-0x1F } else { // Under normal load, process all interrupts write_icc_pmr_el1(0xFF); // Process all priority interrupts } printf("Dynamic priority adjustment completed - Current running priority: 0x%02X\n", current_priority);}
6.3.5 Detailed Analysis of Preemption Mechanism
Preemption Conditions and Process
The complete condition judgment process for preemption:

Preemption Context Management
// Preemption context structuretypedef struct { uint32_t saved_priority; // Saved running priority uint32_t return_address; // Return address uint32_t processor_state; // Processor state uint32_t interrupted_isr_id; // ID of the interrupted ISR} preemption_context_t;// Preemption handling functionvoid handle_preemption(uint32_t new_interrupt_id, uint32_t new_priority) { uint32_t current_priority = read_icc_rpr_el1(); printf("Preemption occurred: New interrupt ID=%d (Priority 0x%02X) > Current priority 0x%02X\n", new_interrupt_id, new_priority, current_priority); // Save current context preemption_context_t context; save_preemption_context(&context); // Update running priority update_running_priority(new_priority); // Execute high-priority interrupt handling execute_high_priority_isr(new_interrupt_id); // Restore context restore_preemption_context(&context); printf("Preemption handling completed, restored priority: 0x%02X\n", current_priority);}// Context savingvoid save_preemption_context(preemption_context_t *context) { context->saved_priority = read_icc_rpr_el1(); // Save return address and processor state asm volatile("mov %0, lr" : "=r" (context->return_address)); asm volatile("mrs %0, SPSR_EL1" : "=r" (context->processor_state)); // Record the interrupted ISR (through stack analysis or other mechanisms) context->interrupted_isr_id = get_current_isr_id(); printf("Preemption context saved - Saved priority: 0x%02X\n", context->saved_priority);}
6.3.6 Implementation on Domestic Chips
Complete State Machine and Preemption Management
Complete implementation based on domestic Cortex-R52+ chip:
// Interrupt state machine and preemption management systemvoid interrupt_state_preemption_system(void) { printf("=== Interrupt State Machine and Preemption Management System Initialization ===\n"); // 1. Initialize state monitoring initialize_state_monitoring(); // 2. Configure priority preemption strategy configure_priority_preemption_policy(); // 3. Set up preemption context management setup_preemption_context_management(); // 4. Enable advanced preemption features enable_advanced_preemption_features(); printf("Interrupt State Machine and Preemption Management System Ready\n");}// Initialize state monitoringvoid initialize_state_monitoring(void) { printf("Initializing interrupt state monitoring...\n"); // Set state change callbacks register_state_change_callbacks(); // Enable state audit logging enable_state_audit_logging(); // Configure periodic state checks setup_periodic_state_checks(); printf("Interrupt state monitoring initialization completed\n");}// Configure priority preemption strategyvoid configure_priority_preemption_policy(void) { printf("Configuring priority preemption strategy...\n"); // Set critical interrupts to the highest priority set_interrupt_priority(SPI_WATCHDOG, 0x00); // Watchdog - highest priority set_interrupt_priority(SPI_SAFETY_MONITOR, 0x10); // Safety monitor - high priority set_interrupt_priority(PPI_LOCAL_TIMER, 0x20); // Local timer - medium priority set_interrupt_priority(SPI_UART0, 0x80); // UART - normal priority // Configure priority mask configure_priority_mask(0xF0); // Only process interrupts with priority 0x00-0xEF // Enable preemption enable_preemption(); printf("Priority preemption strategy configuration completed\n");}// Interrupt handler and state managementvoid advanced_irq_handler(void) { // Read interrupt ID and acknowledge the interrupt uint32_t interrupt_id = read_icc_iar1_el1(); uint32_t current_priority = read_icc_rpr_el1(); // Log interrupt start log_interrupt_start(interrupt_id, current_priority); // Check interrupt state if (!validate_interrupt_state(interrupt_id)) { printf("Error: Interrupt %d state abnormal\n", interrupt_id); handle_interrupt_state_error(interrupt_id); return; } // Handle interrupt switch (interrupt_id) { case SPI_WATCHDOG: handle_watchdog_interrupt_with_preemption(); break; case SPI_SAFETY_MONITOR: handle_safety_monitor_interrupt(); break; default: handle_general_interrupt(interrupt_id); break; } // Interrupt handling completed write_icc_eoir1_el1(interrupt_id); // Log interrupt completion log_interrupt_completion(interrupt_id);}// Watchdog interrupt with preemptionvoid handle_watchdog_interrupt_with_preemption(void) { uint32_t start_time = read_high_resolution_timer(); printf("Watchdog interrupt handling started - Time: %d\n", start_time); // Critical safety operation - prevent preemption disable_preemption_temporarily(); // Perform critical safety tasks perform_critical_safety_operations(); // Restore preemption enable_preemption(); // Non-critical operation - allow preemption perform_non_critical_operations(); uint32_t end_time = read_high_resolution_timer(); printf("Watchdog interrupt handling completed - Duration: %d cycles\n", end_time - start_time); // Check if handling time is within expected range if ((end_time - start_time) > MAX_WATCHDOG_HANDLING_TIME) { log_performance_warning("Watchdog interrupt handling timeout", end_time - start_time); }}
State Machine Validation and Diagnosis
// State machine validation systemvoid state_machine_validation_system(void) { printf("=== State Machine Validation System ===\n"); // 1. State consistency check validate_state_consistency(); // 2. State transition validation validate_state_transitions(); // 3. Preemption behavior analysis analyze_preemption_behavior(); // 4. Performance monitoring monitor_state_machine_performance(); printf("State machine validation completed\n");}// State consistency checkvoid validate_state_consistency(void) { printf("Performing state consistency check...\n"); for (int i = 0; i < MAX_INTERRUPTS; i++) { uint32_t pending = get_interrupt_pending_state(i); uint32_t active = get_interrupt_active_state(i); // Check the legality of state combinations if (pending && active) { // Active and Pending state - needs further checking if (!is_active_pending_state_valid(i)) { log_state_inconsistency("Illegal Active and Pending state", i); correct_interrupt_state(i); } } // Check interrupts that have been in a specific state for a long time check_stuck_interrupts(i); } printf("State consistency check completed\n");}// State transition validationvoid validate_state_transitions(void) { printf("Validating state transitions...\n"); // Test typical state transition sequences test_state_transition_sequence(SPI_TEST_INTERRUPT); // Validate preemption state transitions test_preemption_state_transitions(); // Check state transition timing validate_state_transition_timing(); printf("State transition validation completed\n");}// Test state transition sequencevoid test_state_transition_sequence(uint32_t test_interrupt_id) { printf("Testing interrupt %d state transition sequence\n", test_interrupt_id); // Initial state should be Inactive assert(get_interrupt_state(test_interrupt_id) == STATE_INACTIVE); // Trigger interrupt - should transition to Pending trigger_test_interrupt(test_interrupt_id); assert(get_interrupt_state(test_interrupt_id) == STATE_PENDING); // Acknowledge interrupt - should transition to Active uint32_t id = read_icc_iar1_el1(); assert(id == test_interrupt_id); assert(get_interrupt_state(test_interrupt_id) == STATE_ACTIVE); // Complete interrupt - should transition back to Inactive write_icc_eoir1_el1(test_interrupt_id); assert(get_interrupt_state(test_interrupt_id) == STATE_INACTIVE); printf("State transition sequence test passed\n");}
6.3.7 Functional Safety Considerations
ASIL D State Machine Protection
In functionally safety-critical systems, the interrupt state machine requires additional protection mechanisms:
// ASIL D state machine protectionvoid asil_d_state_machine_protection(void) { printf("=== ASIL D State Machine Protection Configuration ===\n"); // 1. State machine redundancy verification configure_state_machine_redundancy(); // 2. State transition monitoring configure_state_transition_monitoring(); // 3. Preemption safety controls configure_preemption_safety_controls(); // 4. Error detection and recovery configure_error_detection_recovery(); printf("ASIL D state machine protection configuration completed\n");}// State machine redundancy verificationvoid configure_state_machine_redundancy(void) { printf("Configuring state machine redundancy verification...\n"); // Enable hardware state verification enable_hardware_state_verification(); // Set up software state shadow tracking setup_software_shadow_tracking(); // Configure state consistency checker configure_state_consistency_checker(); printf("State machine redundancy verification configuration completed\n");}// State transition monitoringvoid configure_state_transition_monitoring(void) { printf("Configuring state transition monitoring...\n"); // Set up illegal state transition detection setup_illegal_transition_detection(); // Configure state residency time monitoring configure_state_residency_monitoring(); // Enable transition timing verification enable_transition_timing_verification(); printf("State transition monitoring configuration completed\n");}// Critical interrupt state protectionvoid protect_critical_interrupt_states(void) { static uint32_t last_protection_check = 0; uint32_t current_time = read_system_timer(); if (current_time - last_protection_check > STATE_PROTECTION_INTERVAL) { // Validate critical interrupt states for (int i = 0; i < CRITICAL_INTERRUPT_COUNT; i++) { uint32_t intid = critical_interrupts[i]; if (!validate_critical_interrupt_state(intid)) { log_safety_violation("Critical interrupt state abnormal", intid); // Attempt automatic recovery if (!recover_critical_interrupt_state(intid)) { trigger_safety_shutdown("Critical interrupt state recovery failed"); } } } last_protection_check = current_time; }}
6.3.8 Performance Optimization and Debugging
State Machine Performance Optimization
// State machine performance optimizationvoid state_machine_performance_optimization(void) { printf("=== State Machine Performance Optimization ===\n"); // 1. State query optimization optimize_state_queries(); // 2. Transition path optimization optimize_transition_paths(); // 3. Preemption overhead control optimize_preemption_overhead(); // 4. Cache-friendly design optimize_cache_friendly_design(); printf("State machine performance optimization completed\n");}// State query optimizationvoid optimize_state_queries(void) { printf("Optimizing state queries...\n"); // Use batch state reading enable_batch_state_reads(); // Cache commonly used state information setup_state_caching_mechanism(); // Prefetch state data enable_state_prefetching(); printf("State query optimization completed\n");}// Debugging and diagnosis toolsvoid state_machine_debugging_tools(void) { printf("=== State Machine Debugging Tools ===\n"); // 1. Real-time state monitoring enable_real_time_state_monitoring(); // 2. State history recording setup_state_history_recording(); // 3. Performance analysis tools setup_performance_analysis_tools(); // 4. Visual state display setup_visual_state_display(); printf("State machine debugging tools ready\n");}// State history recordingvoid setup_state_history_recording(void) { printf("Setting up state history recording...\n"); // Allocate history recording buffer state_history_buffer = allocate_state_history_memory(STATE_HISTORY_SIZE); // Configure state change callback recording register_state_change_history_callback(); // Enable periodic state snapshots enable_periodic_state_snapshots(); printf("State history recording setup completed - Buffer size: %d entries\n", STATE_HISTORY_SIZE);}
Conclusion
The interrupt state machine and priority preemption mechanism are core mechanisms in the GICv3 architecture that ensure the correctness and real-time performance of interrupt handling:
Core Mechanism Summary
-
Four-State Model:
-
Inactive: The interrupt is in an inactive state.
-
Pending: The interrupt has occurred and is waiting for processing.
-
Active: The interrupt is being processed.
-
Active and Pending: The interrupt occurs again while being processed.
Priority Preemption:
-
Fine control based on an 8-bit priority field.
-
Group priority determines preemption, sub-priority determines order within the group.
-
Dynamic interrupt filtering through priority masks.
State Transition Control:
-
Hardware automatically handles state transitions.
-
Software drives transitions through ICC_IAR and ICC_EOIR registers.
-
Ensures atomicity and consistency of state transitions.
Key Technical Values
-
Determinism: Clear state transition rules ensure predictable behavior.
-
Real-time Performance: Priority preemption guarantees timely response to critical interrupts.
-
Reliability: Comprehensive state tracking and error detection mechanisms.
-
Debuggability: Rich state monitoring and diagnostic tools.
Practical Guidance Principles
In the practical application of the domestic Cortex-R52+ chip:
-
Reasonable Priority Planning: Assign the highest priority to critical interrupts to ensure timely response.
-
Monitor State Health: Regularly check interrupt states to promptly identify anomalies.
-
Optimize Preemption Strategy: Balance real-time performance and system overhead to avoid excessive preemption.
-
Implement Safety Protections: Configure state machine redundancy and monitoring mechanisms in ASIL D systems.
By deeply understanding the principles and practices of the interrupt state machine and priority preemption mechanism, developers can build efficient and reliable interrupt handling systems that meet the stringent requirements for real-time performance and functional safety in automotive electronics, industrial control, and other fields.