部分中断相关函数浅析

为君一笑 提交于 2020-04-05 23:37:12

1. /kernel/irq.c softirq_init 2.6.32.25

1.1 for_each_possible_cpu

for ( ( ( cpu ) ) = - 1 ; ( ( cpu ) ) = cpumask_next ( ( ( cpu ) ) , ( cpu_possible_mask ) ) , ( ( cpu ) ) < nr_cpu_ids ; )

1.2 per_cpu(tasklet_vec, cpu);

//取per_cpu_tasklet_vec[cpu],即cpu的tasklet_vec结构。

per_cpu(tasklet_vec, cpu);

( * ( { unsigned long __ptr ; __ptr = ( unsigned long ) ( ( & per_cpu__tasklet_vec ) ) ; ( typeof ( ( & per_cpu__tasklet_vec ) ) ) ( __ptr + ( ( ( __per_cpu_offset [ cpu ] ) ) ) ) ; } ) ) ;

1.3 tasklet_vec / tasklet_hi_vec

clip_image002

static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec);

 

static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec);

static __attribute__ ( ( section ( ".data.percpu" ) ) ) __typeof__ ( struct tasklet_head ) per_cpu__tasklet_vec ;

clip_image004

static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec);

static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec);

static __attribute__ ( ( section ( ".data.percpu" ) ) ) __typeof__ ( struct tasklet_head ) per_cpu__tasklet_hi_vec ;

struct tasklet_head

struct tasklet_head{

struct tasklet_struct *head;

struct tasklet_struct **tail;

};

struct tasklet_struct

struct tasklet_struct{

struct tasklet_struct *next;

unsigned long state;

atomic_t count;

void (*func)(unsigned long);

unsigned long data;

};

1.4 softirq_work_list

DECLARE_PER_CPU(struct list_head [NR_SOFTIRQS], softirq_work_list);

DECLARE_PER_CPU(struct list_head [NR_SOFTIRQS], softirq_work_list);

extern __attribute__ ( ( section ( ".data.percpu" ) ) ) __typeof__ ( struct list_head [ NR_SOFTIRQS ] ) per_cpu__softirq_work_list ;

DEFINE_PER_CPU(struct list_head [NR_SOFTIRQS], softirq_work_list);

DEFINE_PER_CPU(struct list_head [NR_SOFTIRQS], softirq_work_list);

__attribute__ ( ( section ( ".data.percpu" ) ) ) __typeof__ ( struct list_head [ NR_SOFTIRQS ] ) per_cpu__softirq_work_list ;

1.5 x86_init

extern struct x86_init_ops x86_init;

struct x86_init_ops {

struct x86_init_resources resources;

struct x86_init_mpparse mpparse;

struct x86_init_irqs irqs;

struct x86_init_oem oem;

struct x86_init_paging paging;

struct x86_init_timers timers;

};

struct x86_init_resources {

void (*probe_roms)(void);

void (*reserve_resources)(void);

char *(*memory_setup)(void);

};

struct x86_init_mpparse {

void (*mpc_record)(unsigned int mode);

void (*setup_ioapic_ids)(void);

int (*mpc_apic_id)(struct mpc_cpu *m);

void (*smp_read_mpc_oem)(struct mpc_table *mpc);

void (*mpc_oem_pci_bus)(struct mpc_bus *m);

void (*mpc_oem_bus_info)(struct mpc_bus *m, char *name);

void (*find_smp_config)(unsigned int reserve);

void (*get_smp_config)(unsigned int early);

};

struct x86_init_irqs {

void (*pre_vector_init)(void);

void (*intr_init)(void);

void (*trap_init)(void);

};

struct x86_init_oem {

void (*arch_setup)(void);

void (*banner)(void);

};

struct x86_init_paging {

void (*pagetable_setup_start)(pgd_t *base);

void (*pagetable_setup_done)(pgd_t *base);

};

struct x86_init_timers {

void (*setup_percpu_clockev)(void);

void (*tsc_pre_init)(void);

void (*timer_init)(void);

};

1.6 test_and_set_bit

BTS—Bit Test and Set

Description:

Selects the bit in a bit string (specified with the first operand, called the bit base) at the bit-position designated by the bit offset operand (second operand), stores the value of the bit in the CF flag, and sets the selected bit in the bit string to 1. The bit base operand can be a register or a memory location; the bit offset operand can be a register or an immediate value:

• If the bit base operand specifies a register, the instruction takes the modulo 16, 32, or 64 of the bit offset operand (modulo size depends on the mode and register size; 64-bit operands are available only in 64-bit mode). This allows any bit position to be selected.

• If the bit base operand specifies a memory location, the operand represents the address of the byte in memory that contains the bit base (bit 0 of the specified byte) of the bit string. The range of the bit position that can be referenced by the offset operand depends on the operand size.

See also: Bit(BitBase, BitOffset) on page 3-14.

Some assemblers support immediate bit offsets larger than 31 by using the imme-diate bit offset field in combination with the displacement field of the memory operand. See “BT—Bit Test” in this chapter for more information on this addressing mechanism.

This instruction can be used with a LOCK prefix to allow the instruction to be executed atomically.

In 64-bit mode, the instruction’s default operation size is 32 bits. Using a REX prefix in the form of REX.R permits access to additional registers (R8-R15). Using a REX prefix in the form of REX.W promotes operation to 64 bits. See the summary chart at the beginning of this section for encoding data and limits.

Operation

CF ← Bit(BitBase, BitOffset);

Bit(BitBase, BitOffset) ← 1;

Flags Affected

The CF flag contains the value of the selected bit before it is set. The ZF flag is unaf-

fected. The OF, SF, AF, and PF flags are undefined.

SBB—Integer Subtraction with Borrow;

Description:

Adds the source operand (second operand) and the carry (CF) flag, and subtracts the result from the destination operand (first operand). The result of the subtraction is stored in the destination operand. The destination operand can be a register or a memory location; the source operand can be an immediate, a register, or a memory location. (However, two memory operands cannot be used in one instruction.) The state of the CF flag represents a borrow from a previous subtraction.

When an immediate value is used as an operand, it is sign-extended to the length of the destination operand format.

The SBB instruction does not distinguish between signed or unsigned operands. Instead, the processor evaluates the result for both data types and sets the OF and CF flags to indicate a borrow in the signed or unsigned result, respectively. The SF flag indicates the sign of the signed result.

The SBB instruction is usually executed as part of a multibyte or multiword subtrac-tion in which a SUB instruction is followed by a SBB instruction.

This instruction can be used with a LOCK prefix to allow the instruction to be executed atomically.

In 64-bit mode, the instruction’s default operation size is 32 bits. Using a REX prefix in the form of REX.R permits access to additional registers (R8-R15). Using a REX prefix in the form of REX.W promotes operation to 64 bits. See the summary chart at the beginning of this section for encoding data and limits.

Operation

DEST ← (DEST – (SRC + CF));

Flags Affected

The OF, SF, ZF, AF, PF, and CF flags are set according to the result.

// \linux-2.6.32.25\arch\x86\include\asm\ bitops.h

static inline int test_and_set_bit(int nr, volatile unsigned long *addr){

int oldbit;

asm volatile(LOCK_PREFIX "bts %2,%1\n\t"

"sbb %0,%0" : "=r" (oldbit), ADDR : "Ir" (nr) : "memory");

return oldbit;

}

#define ADDR BITOP_ADDR(addr)

#define BITOP_ADDR(x) "=m" (*(volatile long *) (x))

#define LOCK_PREFIX \

".section .smp_locks,\"a\"\n" \

_ASM_ALIGN "\n" \

_ASM_PTR "661f\n" /* address */ \

".previous\n" \

"661:\n\tlock; "

#define _ASM_ALIGN __ASM_SEL(.balign 4, .balign 8)

#define _ASM_PTR __ASM_SEL(.long, .quad)

#define __ASM_SEL(a,b) __ASM_FORM(a)

#ifdef __ASSEMBLY__

#define __ASM_FORM(x) x

#define __ASM_EX_SEC .section __ex_table, "a"

#else

# define __ASM_FORM(x) " " #x " "

# define __ASM_EX_SEC " .section __ex_table,\"a\"\n"

#endif

LOCK_PRIFIX根据宏定义展开过后为:".section .smp_locks,\"a\"\n .balign 4 \n .long 661f\n.previous\n661:\n\tlock; " ;

//\linux-2.6.32.25\include\asm-generic\bitops\ atomic.h

static inline int test_and_set_bit(int nr, volatile unsigned long *addr)

{

unsigned long mask = BIT_MASK(nr);

unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);

unsigned long old;

unsigned long flags;

_atomic_spin_lock_irqsave(p, flags);

old = *p;

*p = old | mask;

_atomic_spin_unlock_irqrestore(p, flags);

return (old & mask) != 0;

}

有两个test_and_set_bit定义,一直搞不清楚到底是用的哪一个,什么时候用哪一个?分析了第一个,第二个还没来得及分析。

2. raise_softirq_irqoff softirq.c 2.6.38.2

2.1 重要宏定义和数据结构

1. /*Softirq.c*/

2. void raise_softirq(unsigned int nr)

3. {

4. unsigned long flags;

5.

6. local_irq_save(flags);

7. raise_softirq_irqoff(nr);

8. local_irq_restore(flags);

9. }

10.

11. /*Softirq.c*/

12. inline void raise_softirq_irqoff(unsigned int nr)

13. {

14. __raise_softirq_irqoff(nr);

15.

16. /*

17. * If we're in an interrupt or softirq, we're done

18. * (this also catches softirq-disabled code). We will

19. * actually run the softirq once we return from

20. * the irq or softirq.

21. *

22. * Otherwise we wake up ksoftirqd to make sure we

23. * schedule the softirq soon.

24. */

25. if (!in_interrupt())

26. wakeup_softirqd();

27. }

28.

29. /*include/linux/Interrupt.h*/

30. static inline void __raise_softirq_irqoff(unsigned int nr)

31. {

32. trace_softirq_raise(nr);

33. or_softirq_pending(1UL << nr);

34. }

35.

36. /*include/linux/Interrupt.h*/

37. #ifndef __ARCH_SET_SOFTIRQ_PENDING

38. #define set_softirq_pending(x) (local_softirq_pending() = (x))

39. #define or_softirq_pending(x) (local_softirq_pending() |= (x))

40. #endif

41.

42.

43. /*include/linux/Interrupt.h*/

44. #ifndef __ARCH_IRQ_STAT

45. extern irq_cpustat_t irq_stat[]; /* defined in asm/hardirq.h */

46. #define __IRQ_STAT(cpu, member) (irq_stat[cpu].member)

47. #endif

48.

49. /* arch independent irq_stat fields */

50. #define local_softirq_pending() \

51. __IRQ_STAT(smp_processor_id(), __softirq_pending)

52. /********************************************************/

53. /*arch/x86/include/asm/Hardirq.h*/

54. typedef struct {

55. unsigned int __softirq_pending;

56. unsigned int __nmi_count; /* arch dependent */

57. unsigned int irq0_irqs;

58. #ifdef CONFIG_X86_LOCAL_APIC

59. unsigned int apic_timer_irqs; /* arch dependent */

60. unsigned int irq_spurious_count;

61. #endif

62. unsigned int x86_platform_ipis; /* arch dependent */

63. unsigned int apic_perf_irqs;

64. unsigned int apic_irq_work_irqs;

65. #ifdef CONFIG_SMP

66. unsigned int irq_resched_count;

67. unsigned int irq_call_count;

68. unsigned int irq_tlb_count;

69. #endif

70. #ifdef CONFIG_X86_THERMAL_VECTOR

71. unsigned int irq_thermal_count;

72. #endif

73. #ifdef CONFIG_X86_MCE_THRESHOLD

74. unsigned int irq_threshold_count;

75. #endif

76. } ____cacheline_aligned irq_cpustat_t;

77.

78. DECLARE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);

79.

80. /*include/linux/percpu_defs.h*/

81. #define DECLARE_PER_CPU_SHARED_ALIGNED(type, name) \

82. DECLARE_PER_CPU_SECTION(type, name, PER_CPU_SHARED_ALIGNED_SECTION) \

83. ____cacheline_aligned_in_smp

84. #define DECLARE_PER_CPU_SECTION(type, name, sec) \

85. extern __PCPU_ATTRS(sec) __typeof__(type) name

86.

87. #define __PCPU_DUMMY_ATTRS \

88. __attribute__((section(".discard"), unused))

89.

90. #define __PCPU_ATTRS(sec) \

91. __percpu __attribute__((section(PER_CPU_BASE_SECTION sec))) \

92. PER_CPU_ATTRIBUTES

93.

94.

95. /*include/asm-generic/Percpu.h*/

96. #define PER_CPU_SHARED_ALIGNED_SECTION "..shared_aligned"

97.

98. #ifndef PER_CPU_ATTRIBUTES

99. #define PER_CPU_ATTRIBUTES

100. #endif

101. /*include/linux/Cache.h*/

102. #define ____cacheline_aligned_in_smp ____cacheline_aligned

103.

104.

105. /*include/linux/compiler.h*/

106. # define __percpu

2.2 or_softirq_pending ( 1UL << nr ) ;

( irq_stat [ smp_processor_id ( ) ] . __softirq_pending ) |= ( 1UL << nr ) ) ;

2.3 local_softirq_pending();

( irq_stat [ smp_processor_id ( ) ] . __softirq_pending ) ;

2.4 DECLARE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);

extern __attribute__ ( ( section ( PER_CPU_BASE_SECTION "..shared_aligned" ) ) ) __typeof__ ( irq_cpustat_t ) irq_stat ____cacheline_aligned ;

2.5 irq_cpustat_t

/*arch/x86/include/asm/Hardirq.h*/

typedef struct {

unsigned int __softirq_pending;

unsigned int __nmi_count; /* arch dependent */

unsigned int irq0_irqs;

#ifdef CONFIG_X86_LOCAL_APIC

unsigned int apic_timer_irqs; /* arch dependent */

unsigned int irq_spurious_count;

#endif

unsigned int x86_platform_ipis; /* arch dependent */

unsigned int apic_perf_irqs;

unsigned int apic_irq_work_irqs;

#ifdef CONFIG_SMP

unsigned int irq_resched_count;

unsigned int irq_call_count;

unsigned int irq_tlb_count;

#endif

#ifdef CONFIG_X86_THERMAL_VECTOR

unsigned int irq_thermal_count;

#endif

#ifdef CONFIG_X86_MCE_THRESHOLD

unsigned int irq_threshold_count;

#endif

} ____cacheline_aligned irq_cpustat_t;

2.6 流程总结

clip_image005

clip_image007

clip_image009

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!