Interrupt State Machine and Priority Preemption Mechanism

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:

Interrupt State Machine and Priority Preemption Mechanism

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:

Interrupt State Machine and Priority Preemption Mechanism

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:

Interrupt State Machine and Priority Preemption Mechanism

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

  1. 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.

    Leave a Comment