480 likes | 608 Vues
Certified Concurrent Code with Interrupts. Xinyu Feng Joint work with Zhong Shao (Yale University) and Yuan Dong (Tsinghua University). We need firm control of the lowest-level software!. How to Guarantee Software Quality?. We need a “certified” computing platform!.
E N D
Certified Concurrent Code with Interrupts Xinyu Feng Joint work with Zhong Shao (Yale University) and Yuan Dong (Tsinghua University) TTI-C PL-Lunch
We need firm control of the lowest-level software! How to Guarantee Software Quality? We need a “certified” computing platform! Uncertified legacy code becomes second-class citizen! Buggy? Security Infrastructure Certified Security Infrastructure Buggy? Runtime Services & Libraries Certified Runtime Services & Libraries Buggy? Bootloader + OS + Device Driver Certified Bootloader + OS + Device Driver Hardware
CPU Components of a certified framework Specifications • certified code (proof + machine code) • machine model • specifications • mechanized meta-logic • proof checker No Proof Proof Checker Yes machine code
[Chuck Moor FCRC’07] A mini-OS 1300 lines of 16-bit x86 asm. Need a precise definition of abstraction layers! bootloader timer interrupt handler preemptive thread lib: spawn, exit, yield, scheduler, … sync. lib: locks and monitors keyboard driver keyboard interrupt handler … a multi-threaded user application
Layering of miniOS Code C: low-level sequential code, might be tricky (e.g. context switching) [Feng et al. PLDI’06, Feng et al. TLDI’07, Ni et al. TPHOLs’07]
Layering of miniOS Code A: concurrent code, Rely-Guarantee, CSL, … PCC: [Yu&Shao ICFP’04, Feng&Shao ICFP’05, Feng et al. ESOP’07]
Layering of miniOS Code B: concurrent code with explicit interrupts How to certify ???
IR0 IR1 Concurrency with Interrupts: Challenges (1) (4) (3) (2) (5) Asymmetric preemption between handlers and non-handler code Intertwining between threads and handlers Asymmetric synchronization: cli/sti are different from locks Nesting of handlers: may not respect priorities
Contributions of Our Work • An abstract machine and operational semantics • Interrupts, switch, block/unblock • Program logics • Modeling concurrency/interrupt primitives in terms of memory ownership transfer • Certify implementation of sync. primitives • Locks • Condition variables • Hoare style, Brinch-Hanson style, Mesa style
Outline of This Talk • Background: Separation Logic and Concurrency • Abstract Interrupt Machine (AIM) – I • Interrupts with sequential non-handler code • AIM – II • Interrupts with multi-threaded non-handler code • AIM – III • Adding block/unblock primitives
emp empty heap l n l n pq p q p q pq Separation Logic Assertions
Separation Logic for Concurrency Key ideas: There is always a partition of memory among threads, and each thread only access its own part. The partition is dynamic: ownership of memory can be dynamically transferred. When there is ownership transfer, certain agreement is followed. Synchronization primitives can be modeled as operations that trigger memory ownership transfer.
Outline of This Talk • Background: Separation Logic and Concurrency • Abstract Interrupt Machine (AIM) – I • Interrupts with sequential non-handler code • AIM – II • Interrupts with multi-threaded non-handler code • AIM – III • Adding block/unblock primitives
AIM – I : The Machine (data heap) H f1: I1 pc addu … cli sti iret … j f 0 1 2 … f2: I2 r1 r2 r3 … rn ih: ISR (register file) R ie … (code heap) C (state) S ::=(H,R,ie) ::={fI}* (program) P ::=(C,S,pc)
AIM – I : Operational Semantics Using non-determinism to model interrupts: NextS C(pc) (S, S') NextPC C(pc) (pc, pc') (seq) (C, S, pc) (C, S', pc') S.ie = 1 S' = S|ie=0 (irq) (C, S, pc) (C, S', ih) P P' P P' (step) P P'
Example: Teeter-Totter right left 50 50 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;
- { Ph } AIM – I : The Memory Model INV B A Memory Non-handler Handler - { Ph } INV sti … iret cli …
INV cli B B sti B A B B INV INV AIM – I : cli/sti INV B A B ie = 1 ie = 0
INV irq B A iret B A B A INV INV AIM – I : handler INV B A ie = 1 ie = 0
INV sti B A cli B A INV AIM – I : cli/stiin handler B . . . B ie = 0 ie = 1
Example: Teeter-Totter INV: m, n. (left m) (right n) (m+n = 100) while(true){ -{emp} cli; -{emp * INV} ... [right] := [right]-1; [left] := [left]+1; -{INV} sti; -{emp} } timer: -{INV} if([left] == 0){ print(“right wins!”); -{INV} iret; } [left] := [left]-1; [right] := [right]+1; -{INV} iret;
Soundness • Safety: • “Certified non-handler and hander would not get stuck”; • Partial correctness: • Inserted assertions as specifications always hold whenever the specified program points are reached. • Proof based on progress/preservation lemmas
Outline of This Talk • Background: Separation Logic and Concurrency • Abstract Interrupt Machine (AIM) – I • Interrupts with sequential non-handler code • AIM – II • Interrupts with multi-threaded non-handler code • AIM – III • Adding block/unblock primitives
… R R R pc pc pc (ready. queue) Q AIM – II : The Machine (data heap) H f1: I1 0 1 2 … f2: I2 pc cli sti … switch j f r1 r2 r3 … rn ih: ISR (register file) R ie … (code heap) C (state) S ::=(H,R,ie) ::={fI}* (program) P ::=(C,S,Q,pc)
AIM – II : switch • A primitive implemented at layer C • Interrupt must be disabled before executing switch • Operational semantics: • Put the current thread into ready Q • Resume a thread in Q(non-deterministic op)
Layer A: timer_0: ... switch ... iret yield: cli switch sti ret ie = 0: non-preemptive threads ie = 1 & timer_1: non-preemptive threads ie = 1 & timer_0: preemptive threads timer_1: iret Examples
Example: spin locks acquire (l): cli; while([l] == 0){ sti; cli; } [l] := 0; sti; return; release (l): cli; [l] := 1; sti; return; switch
T1 T2 C A INV1 INV0 AIM – II : Memory Model INV0 B A
T1 T2 T1: cli T1 T1 T1: sti INV1 INV0 AIM – II : cli/sti T1 T2 C A INV1 INV0 ie = 1 ie = 0
T1 T2 T1: switch T2 T2 INV1 INV0 AIM – II : switch T1 T2 T1 T1 INV1 INV0 ie = 0
l 0/1 R -{ emp } INV1:b. (l b) (b=0emp b=1R) -{ R } -{ emp } -{ R } Example: spin locks acquire (l): cli; while([l] == 0){ sti; cli; } [l] := 0; sti; return; release (l): cli; [l] := 1; sti; return;
l 0/1 R INV1:b. (l b) (b=0emp b=1R) -{ emp } -{ emp INV1 INV0} -{ emp INV1 INV0} -{ emp INV1 INV0} -{ (l 0) R INV0} -{ (l 1) R INV0} -{ R} -{ INV1 INV0 R} Example: spin locks -{ emp } acquire (l): cli; while([l] == 0){ sti; cli; } [l] := 0; sti; return; -{ R }
Outline of This Talk • Background: Separation Logic and Concurrency • Abstract Interrupt Machine (AIM) – I • Interrupts with sequential non-handler code • AIM – II • Interrupts with multi-threaded non-handler code • AIM – III • Adding block/unblock primitives
… (data heap) H R R R f1: pc pc pc (ready. queue) Q f2: … 2 1 0 ih: r1 r2 r3 … rn (register file) R ie pc block unblock … AIM – III : The Machine w1 w2 (code heap) C (state) S ::=(H,R,ie) … wn B (program) P ::=(C,S,B,Q,pc)
AIM – III : block and unblock • block rs • put current thread into the block queue B(rs) • pick a thread from ready queue to execute • unblock rs, rd • move a thread from B(rs) to the ready queue • put the thread id into rd, put 0 if B(rs) empty • no context switching!
Examples: locks l 0/1 R B(l) = Ql acquire_0(l): cli; if ([l] == 0) blockl; else [l] := 0; sti; return; acquire_1(l): cli; while ([l] == 0) blockl; [l] := 0; sti; return; release_0(l): local x; cli; unblockl x; if (x == 0) [l] := 1; sti; return; release_1(l): local x; cli; unblockl x; [l] := 1; sti; return;
R1 ::= {w0 R0, … , wn Rn} R2 Rican beemp ! Rn How to interpret block/unblock Threads block themselves to wait for resources. locks: wait for resources protected by locks condition variables: wait for resources over which the condition holds w1 w2 … wn B
T1 ! T2 block T2 T2 INV1 INV0 unblock block T1 ! T2 T1 T2 switch T1 T1 T2 T2 INV1 INV0 INV1 INV0 How to interpret block/unblock T1 T2 ? T2 T1 T1 INV1 INV0 ! ! Thread 1 Thread 2
-{ emp } -{ emp INV1 INV0} -{ emp INV1 INV0} -{ emp INV1 INV0 (l)} -{ emp (l 1) R INV0} -{ emp (l 0) R INV0} -{ emp INV1 INV0 R} -{ emp R} Examples: locks l 0/1 R B(l) = Ql (l) = R INV1:b, (l b) (b=0emp b=1R) -{ emp } acquire_0(l): cli; if ([l] == 0) blockl; else [l] := 0; sti; return; -{ R }
-{ R } -{ R INV1 INV0} -{(x=0 R x 0 emp) INV1 INV0} -{ R INV1 INV0} -{ (l 1) R INV0} -{ INV1 INV0} -{ emp } Examples: locks l 0/1 R B(l) = Ql (l) = R INV1:b, (l b) (b=0emp b=1R) -{ R } release_0(l): local x; cli; unblockl x; if (x == 0) [l] := 1; sti; return; -{ (l 0) R INV0} -{ emp }
Examples: locks l 0/1 R B(l) = Ql (l) = R (l) = emp INV1:b, (l b) (b=0emp b=1R) -{ emp } -{ R } acquire_1(l): cli; while ([l] == 0) blockl; [l] := 0; sti; return; release_1(l): local x; cli; unblockl x; [l] := 1; sti; return; -{ R } -{ emp }
Examples : Condition Variables • wait()/notify() • Hoare Style / Brinch-Hanson Style • Mesa style • See the technical report: http://flint.cs.yale.edu/publications/aim.html
Conclusion • AIM machine • low-level • can implement interrupt handlers and thread libraries • A program logic • following local reasoning in separation logic • modeling cli/sti, switch, block/unblock in terms of memory ownership transfer • can certify different implementation of locks and C.V.s
Future Work • Linking layers A, B and C • operational semantics of switch and block/unblock can be used as spec. for layer C • may derive a logic for layer A as a specialization of B • expose spec. of locks and CVs to A
B A An … A1 A0 Future Work • Linking layers A, B and C • operational semantics of switch and block/unblock can be used as spec. for layer C • may derive a logic for layer A as a specialization of B • expose spec. of locks and CVs to A • Multiple interrupts • Dynamic creation of block queues in B • Device drivers and I/O
Thank you! Any Questions?
A Simple Example INV: b, (l b) (b=0emp b=1R) R R INV l l 1 1 if ([l] = 1) [l] := 0; R l 0 l R INV 0