Patchwork [2/4] Add support for execution from ROMs in IO device mode

login
register
mail settings
Submitter Jan Kiszka
Date May 13, 2010, 2:16 p.m.
Message ID <5b7efeb30fe6f93a369b6a9f964a2cb7c0519222.1273760202.git.jan.kiszka@web.de>
Download mbox | patch
Permalink /patch/52484/
State New
Headers show

Comments

Jan Kiszka - May 13, 2010, 2:16 p.m.
While IO_MEM_ROMD marks an I/O memory region as "read/execute from RAM,
but write to I/O handler", there is no flag indicating that an I/O
region which is fully managed by I/O handlers can still be hosting
executable code. One use case for this are flash device models that
switch to I/O mode during reprogramming. Not all reprogramming states
modify to read data, thus practically allow to continue execution.
Moreover, we need to avoid switching the modes too frequently for
performance reasons which requires fetching opcodes while still in I/O
device mode.

So this patch introduces the IO_MEM_EXEC flag. Flash devices need to set
it independent of their access mode. The flag is propagated from
PhysPageDesc into the TLB, and get_page_addr_code is evaluating it
instead of IO_MEM_ROMD. Testing for the latter was so far a nop anyway
as this flag never made it into the TLB.

Signed-off-by: Jan Kiszka <jan.kiszka@web.de>
---
 cpu-common.h |    2 ++
 exec-all.h   |    2 +-
 exec.c       |    2 +-
 3 files changed, 4 insertions(+), 2 deletions(-)
Jamie Lokier - May 13, 2010, 7:23 p.m.
Jan Kiszka wrote:
> While IO_MEM_ROMD marks an I/O memory region as "read/execute from RAM,
> but write to I/O handler", there is no flag indicating that an I/O
> region which is fully managed by I/O handlers can still be hosting
> executable code. One use case for this are flash device models that
> switch to I/O mode during reprogramming. Not all reprogramming states
> modify to read data, thus practically allow to continue execution.
> Moreover, we need to avoid switching the modes too frequently for
> performance reasons which requires fetching opcodes while still in I/O
> device mode.

I like this change.

Does "fetching opcodes while still in I/O device mode" fetch opcodes
from the RAM backing, or via the I/O read handlers?

If the latter, I'm wondering how KVM would cope with that.

Thanks,
-- Jamie
Jan Kiszka - May 13, 2010, 8:10 p.m.
Jamie Lokier wrote:
> Jan Kiszka wrote:
>> While IO_MEM_ROMD marks an I/O memory region as "read/execute from RAM,
>> but write to I/O handler", there is no flag indicating that an I/O
>> region which is fully managed by I/O handlers can still be hosting
>> executable code. One use case for this are flash device models that
>> switch to I/O mode during reprogramming. Not all reprogramming states
>> modify to read data, thus practically allow to continue execution.
>> Moreover, we need to avoid switching the modes too frequently for
>> performance reasons which requires fetching opcodes while still in I/O
>> device mode.
> 
> I like this change.
> 
> Does "fetching opcodes while still in I/O device mode" fetch opcodes
> from the RAM backing, or via the I/O read handlers?

Via the latter. This is most "correct" in that broken guests that jump
to the ROM while it's in some critical write cycle will properly crash.

> 
> If the latter, I'm wondering how KVM would cope with that.

I think it won't work without extending KVM to fetch - as a last resort
- also from I/O devices. Or we give up the "correctness" and keep the
RAM-base KVM slot for IO_MEM_EXEC regions. That should be solvable in a
transparent way in kvm_set_phys_mem.

Jan
Jan Kiszka - May 13, 2010, 8:24 p.m.
Jan Kiszka wrote:
> Jamie Lokier wrote:
>> Jan Kiszka wrote:
>>> While IO_MEM_ROMD marks an I/O memory region as "read/execute from RAM,
>>> but write to I/O handler", there is no flag indicating that an I/O
>>> region which is fully managed by I/O handlers can still be hosting
>>> executable code. One use case for this are flash device models that
>>> switch to I/O mode during reprogramming. Not all reprogramming states
>>> modify to read data, thus practically allow to continue execution.
>>> Moreover, we need to avoid switching the modes too frequently for
>>> performance reasons which requires fetching opcodes while still in I/O
>>> device mode.
>> I like this change.
>>
>> Does "fetching opcodes while still in I/O device mode" fetch opcodes
>> from the RAM backing, or via the I/O read handlers?
> 
> Via the latter. This is most "correct" in that broken guests that jump
> to the ROM while it's in some critical write cycle will properly crash.
> 
>> If the latter, I'm wondering how KVM would cope with that.
> 
> I think it won't work without extending KVM to fetch - as a last resort
> - also from I/O devices. Or we give up the "correctness" and keep the
> RAM-base KVM slot for IO_MEM_EXEC regions. That should be solvable in a
> transparent way in kvm_set_phys_mem.

Which, of course, would break CFI reads etc. for KVM guest. So this
feature actually requires additional support by KVM to fetch code from
I/O devices.

Jan

Patch

diff --git a/cpu-common.h b/cpu-common.h
index b24cecc..e106e33 100644
--- a/cpu-common.h
+++ b/cpu-common.h
@@ -125,6 +125,8 @@  void cpu_physical_memory_write_rom(target_phys_addr_t addr,
 /* Acts like a ROM when read and like a device when written.  */
 #define IO_MEM_ROMD        (1)
 #define IO_MEM_SUBPAGE     (2)
+/* Can run code from memory-mapped device */
+#define IO_MEM_EXEC        (4)
 
 #endif
 
diff --git a/exec-all.h b/exec-all.h
index 1016de2..7bc2b5b 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -331,7 +331,7 @@  static inline tb_page_addr_t get_page_addr_code(CPUState *env1, target_ulong add
         ldub_code(addr);
     }
     pd = env1->tlb_table[mmu_idx][page_index].addr_code & ~TARGET_PAGE_MASK;
-    if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
+    if (pd > IO_MEM_ROM && !(pd & IO_MEM_EXEC)) {
 #if defined(TARGET_SPARC) || defined(TARGET_MIPS)
         do_unassigned_access(addr, 0, 1, 0, 4);
 #else
diff --git a/exec.c b/exec.c
index 3416aed..14c1770 100644
--- a/exec.c
+++ b/exec.c
@@ -2227,7 +2227,7 @@  void tlb_set_page(CPUState *env, target_ulong vaddr,
     }
 
     if (prot & PAGE_EXEC) {
-        te->addr_code = code_address;
+        te->addr_code = code_address | (pd & IO_MEM_EXEC);
     } else {
         te->addr_code = -1;
     }