Certifying Low-Level Programs with Hardware Interrupts and Preemptive Threads Xinyu Feng Toyota Technological Institute at Chicago Joint work with Zhong Shao (Yale), Yuan Dong (Tsinghua Univ.) and Yu Guo (USTC)
How to verify safety & correctness of OS kernels / Hypervisors? Code loading Many challenges: Interrupts … Device drivers & I/O Concurrency Low-level C/Assembly code Is verification possible? How to do it in a clean & modular way?
Layering of Simplified Kernel Code B: concurrent code with explicit interrupts How to verify ???
Concurrency with Interrupts: Challenges irq0 irq1 (1) (2) (3) (4) (5) Asymmetric preemption between handlers and non-handler code Intertwining between threads and handlers Asymmetric synchronization: cli/sti are different from locks
Our Contributions A Hoare-style program logic for modular verification of low-level programs with interrupts and concurrency.
AIM – I : Single Threaded-Code with Interrupts I1I1 f1:f1: I2I2 f2:f2: ISR ih: … (code heap) C 0 r1r1 12… r2r2 r3r3 …rnrn (data heap) H (register file) R (state) S addu … cli sti iret … j f (program) P::=(C,S,pc) ::=(H,R,ie) ::={f I} * pc ie
Example: Teeter-Totter while(true){ cli; if([right] == 0){ sti; break; } [right] := [right]-1; [left] := [left]+1; sti; } print(“left wins!”); timer: if([left] == 0){ print(“right wins!”); iret; } [left] := [left]-1; [right] := [right]+1; iret; 50 left right How to guarantee non-interference?
Non-Interference? Program invariant: There is always a partition of memory among concurrent entities, and each concurrent entity only access its own part. But note: The partition is dynamic: ownership of memory can be dynamically transferred. cli/sti can be modeled as operations that trigger memory ownership transfer.
- { P h }INV AIM – I : The Memory Model Non-handler sti iret Handler BA cli … Memory … - { P h }INV The memory partition is logical, not physical!
Separation Logic to Enforce Partition l n n l p qp q pq emp empty heap p qp q p q [Ithtiaq & O’Hearn’01, Reynolds’02]
AIM – I : cli/sti BA INV BB B BA B B cli sti ie = 1ie = 0
Example: Teeter-Totter while(true){ -{emp ie=1} cli; -{emp * INV}... [right] := [right]-1; [left] := [left]+1; -{INV} sti; -{emp ie=1} } timer: -{INV} if([left] == 0){ print(“right wins!”); -{INV} iret; } [left] := [left]-1; [right] := [right]+1; -{INV} iret; INV: m, n. (left m) (right n) (m+n = 100) 50 left right sti cli
AIM-II : Multi-threaded code with interrupts f1:f1: f2:f2: ih: (code heap) C (state) S (program) P::=(C,S,B,Q,pc) ::=(H,R,ie) cli/sti switch block w unblock w pc 0 r1r1 1 2 … r2r2 r3r3 …rnrn (data heap) H (register file) R ie pc R R R … (ready. queue) Q … w1w1 w2w2 wnwn B
Non-interference? f1:f1: f2:f2: ih: (code heap) C (state) S::=(H,R,ie) cli/sti switch block w unblock w pc 0 r1r1 1 2 … r2r2 r3r3 …rnrn (data heap) H (register file) R ie pc R R R … (ready. queue) Q … w1w1 w2w2 wnwn B Use memory partition to control interference!
AIM – II : Memory Model BA INV A C T1T1 T2T2 INV1
AIM – II : cli/sti T 1 : cli CA INV T1T1 T2T2 INV1 T 1 : CT 1 : A INV T1T1 T2T2 INV1 ie = 1ie = 0 C'A' INV T1T1 T2T2 INV1 T 1 : C'T 1 : A' INV T1T1 T2T2 INV1 T 1 : sti
AIM – II : switch T 1 : CT 1 : A INV T1T1 T2T2 INV1 T 1 : switch T 2 : CT 2 : A INV T1T1 T2T2 INV1 ie = 0 T 2 : switch T 1 : C'T 1 : A' INV T1T1 T2T2 INV1 T 2 : C'T 2 : A' INV T1T1 T2T2 INV1 switch untouched INV1 * INV preserved … sti … cli …
block switch T 1 : CT 1 : A INV T1T1 T2T2 INV1 ? ! T 2 : CT 2 : A INV T1T1 T2T2 INV1 ! T 2 : C'T 2 : A' INV INV1 T1T1 T2T2 T 1 : C'T 1 : A' INV T1T1 INV1 T2T2 ! unblock Thread 1 T2T2 ! AIM-II: block/unblock Thread 2 block
AIM-II : block/unblock Threads block themselves to wait for resources. … w1w1 w2w2 wnwn B locks: wait for resources protected by locks condition variables: wait for conditions to come true R1R1 R2R2 RnRn R can be empty Unifies different semantics of Condition Variables: Mesa style Hoare style Brinch-Hansen style Read our paper for details!
Implementations – An Infrastructure for x86 verification Coq (Higher-Order Logic with Inductive Def.) x86 semantics (a subset) Sep. LogicUtilities (e.g. Queues) AIM Logic & Soundness Locks, Condition variables Timer handler, yield/sleep SCAP switch, block, unblock 26,00012,000 26,0003,000 6,3004,000 Around 82,000 lines of Coq code 3,300 See
Summary Abstract Machine & Program Logic –Hardware interrupts + preemptive threads –Ownership transfer semantics cli, sti, switch, block, unblock Implementations –Infrastructure for x86 code verification –Certified x86 modules Future work –Multi-processor platforms –Liveness properties –Verification of C programs
Thank you!