irq_desc_t 型
掘り下げていってるんですが、まだまだ穴は深いんだろうな。(当たり前
include/linux/irq.h によると
typedef struct irq_desc { hw_irq_controller *handler; void *handler_data; struct irqaction *action; /* IRQ action list */ unsigned int status; /* IRQ status */ unsigned int depth; /* nested irq disables */ unsigned int irq_count; /* For detecting broken interrupts */ unsigned int irqs_unhandled; spinlock_t lock; } ____cacheline_aligned irq_desc_t;
て感じで定義されている。
メンバの用途、意味合い等は追いかけながら見ていきたい。気になるのは以下のメンバ。
- handler (hw_irq_controller 型)
- action (struct irqaction * 型)
- lock (spinlock_t 型)
探してみる。まず hw_irq_controller 型は M-. したら include/linux/irq.h が開いた。同じファイルやっさ。
struct hw_interrupt_type { const char * typename; unsigned int (*startup)(unsigned int irq); void (*shutdown)(unsigned int irq); void (*enable)(unsigned int irq); void (*disable)(unsigned int irq); void (*ack)(unsigned int irq); void (*end)(unsigned int irq); void (*set_affinity)(unsigned int irq, cpumask_t dest); }; typedef struct hw_interrupt_type hw_irq_controller;
メンバはほとんど関数ポインタになっている。メンバの用途、意味合いは同様に別途調査とゆー事で。
次、struct irqaction 型は include/linux/interrupt.h にて定義。
struct irqaction { irqreturn_t (*handler)(int, void *, struct pt_regs *); unsigned long flags; cpumask_t mask; const char *name; void *dev_id; struct irqaction *next; int irq; struct proc_dir_entry *dir; };
struct irqaction *next ってメンバがあるんでリンクリストだな、と。いくつか意味不明なデータ型あり。
- irqreturn_t 型
- cpumask_t 型
- struct proc_dir_entry 型
ちなみに irqreturn_t 型は直上にて typedef されている。
typedef int irqreturn_t;
cpumask_t 型。
include/linux/cpumask.h にて
typedef struct { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t;
な記述あり。DECLARE_BITMAP は include/linux/types.h にて
#define BITS_TO_LONGS(bits) \ (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG) #define DECLARE_BITMAP(name,bits) \ unsigned long name[BITS_TO_LONGS(bits)]
こんなマクロがあった。NR_CPUS は CPU の数と勝手読みして、ユニ・プロセッサの場合には以下のようなカンジで展開されるはず。
typedef struct { unsigned long bits[1]; } cpumask_t;
おそらくはビットマップなんで 33 以上 CPU が無い限りは long 一発でなんとなるんだろう、と勝手読み。(勝手読みが多すぎゃしないッスか?
次。struct proc_dir_entry 型なんですが、これについては必要がある時に中身を見ます。ちなみにありかは include/linux/proc_fs.h です。推測ですが、proc ファイルシステムのディレクトリエントリな構造体かと。
最後の spinlock_t 型は include/linux/spinlock.h に。
がしかし、CONFIG_DEBUG_SPINLOCK ってナニな人向けなカーネルコンフィグレーションなのかな。2.4 時代からあるのはこっちみたい。
/* * gcc versions before ~2.95 have a nasty bug with empty initializers. */ #if (__GNUC__ > 2) typedef struct { } spinlock_t; #define SPIN_LOCK_UNLOCKED (spinlock_t) { } #else typedef struct { int gcc_is_buggy; } spinlock_t; #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } #endif
これ、凄いな。sizeof(spinlock_t) は 0 になります。0 バイトの変数か。でも SPIN_LOCK_UNLOCKED でない状態ってどうやるんでしょ。とりあえずこれも保留。
で、kernel/irq/handle.c で定義されておる irq_desc はカーネルがロードされた時点で領域が確保されて初期化される、と。
irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { [0 ... NR_IRQS-1] = { .status = IRQ_DISABLED, .handler = &no_irq_type, .lock = SPIN_LOCK_UNLOCKED } };
メンバとその状態はロードされた時点で以下??
- hw_irq_controller * 型の handler
&no_irq_type が代入されている
- void * (汎用ポインタ) 型の handler_data
NULL
- struct irqaction * 型の action
NULL
- unsigned int 型の status
IRQ_DISABLED
- unsigned int 型の depth
- unsigned int 型の irq_count
- unsigned int 型の irqs_unhandled
- spinlock_t 型の lock
SPIN_LOCK_UNLOCKED
最後に、IRQ_DISABLED 関連と no_irq_type 関連についてトレース。
- IRQ_DISABLED
include/linux/irq.h にて定義。コメントには IRQ line status. とあり。
#define IRQ_INPROGRESS 1 /* IRQ handler active - do not enter! */ #define IRQ_DISABLED 2 /* IRQ disabled - do not enter! */ #define IRQ_PENDING 4 /* IRQ pending - replay on enable */ #define IRQ_REPLAY 8 /* IRQ has been replayed but not acked yet */ #define IRQ_AUTODETECT 16 /* IRQ is being autodetected */ #define IRQ_WAITING 32 /* IRQ not yet seen - for autodetection */ #define IRQ_LEVEL 64 /* IRQ level triggered */ #define IRQ_MASKED 128 /* IRQ masked - shouldn't be seen again */ #define IRQ_PER_CPU 256 /* IRQ is per CPU */
- no_irq_type
kernel/irq/handle.c にて定義。
/* * Generic 'no controller' code */ static void end_none(unsigned int irq) { } static void enable_none(unsigned int irq) { } static void disable_none(unsigned int irq) { } static void shutdown_none(unsigned int irq) { } static unsigned int startup_none(unsigned int irq) { return 0; } static void ack_none(unsigned int irq) { /* * 'what should we do if we get a hw irq event on an illegal vector'. * each architecture has to answer this themself. */ ack_bad_irq(irq); } struct hw_interrupt_type no_irq_type = { .typename = "none", .startup = startup_none, .shutdown = shutdown_none, .enable = enable_none, .disable = disable_none, .ack = ack_none, .end = end_none, .set_affinity = NULL };
何もナシ。というのがハッキリしてて気持ち良し。
関数の型、引数の型が同一なのに名前を変えているのがあるが、何か意味があんのかなぁ。
てか、irq_desc 配列って、「いつ、どこで」本当の意味での初期設定がなされるのでしょうね。とりあえず次のエントリ以降で init_IRQ() に戻ってみたいと。(irq_desc 配列への登録はデバイスドライバが行なっている模様。amazon:Linux カーネル解析入門にて「ネットワーク・ドライバを読む」などという章がありますんで、そこらへんで出てくるのかな)