ううむ (割り込みの禁止関連)
ひらたさんに色々とコメントを頂き、amazon:Linux カーネル解析入門の 3 章をあまりにもざっくり読み過ぎている自分を発見。
まず、sti と cli の意味を正反対に理解していた。(爆
コメントのやりとりの中でスッとボケたコメントを投入している。
sti してる時に割り込みが発行された時の PIC の挙動ってどうなるんだろ。cli が発行されるまで wait するんかな。
set で割り込みを禁止、で clear で許可って勝手読みスギだしー。(笑えん
で、今 include/linux/spinlock.h を見てるんですが、精緻にオイカケる暇が微妙。ざっくり微妙な部分も含め、整理するための材料という事で。
以下に enable_8259A_irq()#arch/i386/kernel/i8259.c を使用例として。
void enable_8259A_irq(unsigned int irq) { unsigned int mask = ~(1 << irq); unsigned long flags; spin_lock_irqsave(&i8259A_lock, flags); cached_irq_mask &= mask; if (irq & 8) outb(cached_slave_mask, PIC_SLAVE_IMR); else outb(cached_master_mask, PIC_MASTER_IMR); spin_unlock_irqrestore(&i8259A_lock, flags); }
spin_lock_irqsave() とか spin_unlock_irqresotre() 等は上記の include/linux/spinlock.h となっている。とりあえず、UP なナニで探してみると
#define spin_lock_irqsave(lock, flags) _spin_lock_irqsave(lock, flags) #define spin_unlock_irqrestore(lock, flags) _spin_unlock_irqrestore(lock, flags)
という記述あり。
で、_spin_lock_irqsave は以下のマクロと見た。
#define _spin_lock_irqsave(lock, flags) \ do { \ local_irq_save(flags); \ preempt_disable(); \ _raw_spin_lock(lock); \ __acquire(lock); \ } while (0)
又、_spin_unlock_irqrestore は以下の模様。
#define _spin_unlock_irqrestore(lock, flags) \ do { \ _raw_spin_unlock(lock); \ local_irq_restore(flags); \ preempt_enable(); \ __release(lock); \ } while (0)
いくつかある命令は別途なペンディングとして local_irq_save と local_irq_restore な定義元な記述を以下にまとめて (これは amazon:LInux カーネル解析入門にも記述あり)。しかも微妙に編集。
local_irq_save (include/asm-i386/system.h)
#define local_irq_save(x) \ __asm__ __volatile__("pushfl ; popl %0 ; cli" \ :"=g" (x) \ : /* no input */ \ :"memory")
local_irq_restore (include/asm-i386/system.h)
#define local_irq_restore(x) \ do { \ typecheck(unsigned long,x); \ __asm__ __volatile__("pushl %0 ; popfl" \ : /* no output */ \ :"g" (x) \ :"memory", "cc"); \ } while (0)
随分 (インライン) アセンブラが読めるようになってきてるのか意味が分かるようになってきている。最初にこの章 (3 章) を読んだ時には意味不明だった記憶あり。ってか、無理矢理スルーして割り込みを読み始めたんだろな。これはこれで結果オーライとしたい (こらー
amazon:Linux カーネル解析入門にもある通り、フラグレジスタは mov が使えないとの事にて呼出し元の enable_8259A_irq() から渡された flags に格納するために、スタックに一旦 push して取り出している。で enable_8259A_irq() の末端で flags からフラグレジスタに戻しているという事か。(ちなみに local_irq_{save,store} の呼出しに限定しています。)
とり急ぎ備忘録まで。もう少しきちんと追いかける必要あるな。
調査中にこんな文書 (cli-sti-removal.txt) を発見していたりする。