When block unchaining is needed?

16
When block unchaining is needed? • Host SIGALRM, DMA, IO Thread, Single step… cpu_exit -> cpu_unlink_tb • Virtual device raise interrupt cpu_interrupt -> cpu_unlink_tb • Invalidate TB tb_phys_invalidate -> tb_jmp_remove Before doing tb_jmp_remove, we need 1.Remove tb from tb_phys_hash 2.Remove tb from it’s corresponding guest page 3.Remove tb from tb_jmp_cache

description

When block unchaining is needed?. Host SIGALRM, DMA, IO Thread, Single step… cpu_exit -> cpu_unlink_tb Virtual device raise interrupt cpu_interrupt -> cpu_unlink_tb Invalidate TB tb_phys_invalidate -> tb_jmp_remove Before doing tb_jmp_remove , we need Remove tb from tb_phys_hash - PowerPoint PPT Presentation

Transcript of When block unchaining is needed?

Page 1: When block unchaining is needed?

When block unchaining is needed?

• Host SIGALRM, DMA, IO Thread, Single step…cpu_exit -> cpu_unlink_tb

• Virtual device raise interrupt cpu_interrupt -> cpu_unlink_tb

• Invalidate TBtb_phys_invalidate -> tb_jmp_removeBefore doing tb_jmp_remove, we need1. Remove tb from tb_phys_hash2. Remove tb from it’s corresponding guest page3. Remove tb from tb_jmp_cache

Page 2: When block unchaining is needed?

Example- cpu_interrupt

• cpu_interrupt does two things:Raise env->interrupt_requestcpu_unlink_tb(env)

for (; ;) { // exception handling for (; ; ) { // check interrupt_request // setup env->exception_index // env->current_tb = NULL // longjmp to the outer for loop

// enter into code cache }}

cpu_interrupt

cpu_exec

Handle interrupt

Page 3: When block unchaining is needed?

Example- cpu_interrupt

• cpu_interrupt dispatches the interrupt todo_interrupt_real (real mode interrupt)do_interrupt_protected (protected mode

interrupt)do_interrupt_64 (64-bit interrupt)

Page 4: When block unchaining is needed?

Example- cpu_interrupt_real

• User mode and kernel mode uses different stacks

• Push (guest) user mode registers onto (guest) kernel stack, use {ld,st}*_kernelss, esp, eflags, cs and eip

• Set env->eip, env->cs and env->eflagsISR = env->eip + env->cs

• Return to cpu_exec to execute ISR

Page 5: When block unchaining is needed?

Example- cpu_exit

• cpu_exit is called whenHost SIGALRM, DMA, IO Thread, Single step…

• cpu_exit does two things:Raise env->exit_requestcpu_unlink_tb(env)

• Control is gave back to QEMU from the code cache

Page 6: When block unchaining is needed?

cpu_exit comes into play

for (; ;) { /* successfully delivered */ env->old_exception = -1;

for (; ; ) { // check exit_request, SIGALRM cause exit_request to be 1 // setup env->exception_index // env->current_tb = NULL // longjmp to the outer for loop

// enter into code cache }}

Execute ISR

Page 7: When block unchaining is needed?

Example- cpu_interrupt_real

• After completing ISR, (guest) iret pops up user mode registers stored on the kernel stackGuest iret is implemented by a helper function,

helper_iret_real, for example

• Set env->eip, env->cs and env->eflagsUser mode pc = env->eip + env->cs

• Return to cpu_exec to execute user mode program

Page 8: When block unchaining is needed?

How block chaining is done?

jmp_next[0] jmp_next[1]

jmp_first

struct TranslationBlock {

struct TranslationBlock *jmp_next[2];struct TranslationBlock *jmp_first;

};

QEMU uses the last two bits of the pointer to TranslationBlock to encodethe direction of block chaining:

0 -> branch taken1 -> branch not taken2 -> EOF

Page 9: When block unchaining is needed?

Example

TB2

TB1 TB3TB1 -> jmp_next = TB2 | 2

TB3 -> jmp_next = TB2->jmp_first = TB1 | 0

struct TranslationBlock QEMU code cache

TB2 -> jmp_first = TB1 | 0

TB2 -> jmp_first = TB3 | 0

Page 10: When block unchaining is needed?

Example

TB2

TB1 TB3jmp_next = TB1 | 0

jmp_next = TB2 | 2

jmp_first = TB3 | 0

struct TranslationBlock QEMU code cache

unlink (TB3, 0)

Page 11: When block unchaining is needed?

Block unchaining- tb_reset_jump_recursive2

// Find TB3 -> TB2 (tb -> tb_next)tb1 = tb->jmp_next[n]; // tb now is TB3for(;;) { // Iterate jmp_next}tb_next = tb1; // tb_next now is TB2

// Remove TB3 from the circular listptb = &tb_next->jmp_first;for(;;) {}*ptb = tb->jmp_next[n];tb->jmp_next[n] = NULL;

Page 12: When block unchaining is needed?

TB2

TB1 TB3jmp_next = NULL

jmp_next = TB2 | 2 jmp_first = TB1 | 0

jmp_first = TB3 | 0

jmp_next = TB1 | 0

struct TranslationBlock QEMU code cache

Page 13: When block unchaining is needed?

Block unchaining- tb_reset_jump_recursive2

// Remove TB3 from the circular listptb = &tb_next->jmp_first;for(;;) {}*ptb = tb->jmp_next[n];tb->jmp_next[n] = NULL;

// Suppress the jump to next tb in generated codetb_reset_jump(tb, n); // tb now is TB3

Page 14: When block unchaining is needed?

TB2

TB1 TB3jmp_next = NULL

jmp_next = TB2 | 2 jmp_first = TB1 | 0

struct TranslationBlock QEMU code cache

Page 15: When block unchaining is needed?

Block unchaining- tb_reset_jump_recursive2

// Remove TB3 from the circular listptb = &tb_next->jmp_first;for(;;) {}*ptb = tb->jmp_next[n];tb->jmp_next[n] = NULL;

// Suppress the jump to next tb in generated codetb_reset_jump(tb, n); // tb now is TB3

// Suppress jumps in the tb on which we could have jumpedtb_reset_jump_recursive(tb_next); // tb_next now is TB2

Page 16: When block unchaining is needed?

TB2

TB1 TB3jmp_next = NULL

jmp_next = TB2 | 2

jmp_first = TB1 | 0

? Recursive unlink