2 * Jailhouse, a Linux-based partitioning hypervisor
4 * Copyright (c) Siemens AG, 2013
5 * Copyright (c) Valentine Sinitsyn, 2014
8 * Jan Kiszka <jan.kiszka@siemens.com>
9 * Valentine Sinitsyn <valentine.sinitsyn@gmail.com>
11 * This work is licensed under the terms of the GNU GPL, version 2. See
12 * the COPYING file in the top-level directory.
15 #include <jailhouse/mmio.h>
16 #include <jailhouse/paging.h>
17 #include <jailhouse/printk.h>
18 #include <asm/ioapic.h>
19 #include <asm/iommu.h>
22 #define X86_MAX_INST_LEN 15
27 u8 b:1, x:1, r:1, w:1;
29 } __attribute__((packed)) rex;
34 } __attribute__((packed)) modrm;
39 } __attribute__((packed)) sib;
42 struct parse_context {
43 unsigned int remaining;
48 static void ctx_move_next_byte(struct parse_context *ctx)
54 static bool ctx_maybe_get_bytes(struct parse_context *ctx,
56 const struct guest_paging_structures *pg)
59 ctx->size = ctx->remaining;
60 ctx->inst = vcpu_get_inst_bytes(pg, *pc, &ctx->size);
63 ctx->remaining -= ctx->size;
69 static bool ctx_advance(struct parse_context *ctx,
71 const struct guest_paging_structures *pg)
73 ctx_move_next_byte(ctx);
74 return ctx_maybe_get_bytes(ctx, pc, pg);
77 struct mmio_instruction x86_mmio_parse(unsigned long pc,
78 const struct guest_paging_structures *pg_structs, bool is_write)
80 struct parse_context ctx = { .remaining = X86_MAX_INST_LEN };
81 struct mmio_instruction inst = { .inst_len = 0 };
82 union opcode op[3] = { };
83 bool has_rex_r = false;
87 if (!ctx_maybe_get_bytes(&ctx, &pc, pg_structs))
90 op[0].raw = *(ctx.inst);
91 if (op[0].rex.code == X86_REX_CODE) {
92 /* REX.W is simply over-read since it is only affects the
93 * memory address in our supported modes which we get from the
94 * virtualization support. */
98 goto error_unsupported;
100 ctx_move_next_byte(&ctx);
105 case X86_OP_MOV_TO_MEM:
107 inst.access_size = 4;
110 case X86_OP_MOV_FROM_MEM:
112 inst.access_size = 4;
116 goto error_unsupported;
119 if (!ctx_advance(&ctx, &pc, pg_structs))
122 op[1].raw = *(ctx.inst);
123 switch (op[1].modrm.mod) {
125 if (op[1].modrm.rm == 5) /* 32-bit displacement */
126 goto error_unsupported;
127 else if (op[1].modrm.rm != 4) /* no SIB */
131 if (!ctx_advance(&ctx, &pc, pg_structs))
134 op[2].raw = *(ctx.inst);
135 if (op[2].sib.base == 5)
140 if (op[1].modrm.rm == 4) /* SIB */
141 goto error_unsupported;
142 inst.inst_len += op[1].modrm.mod == 1 ? 1 : 4;
145 goto error_unsupported;
148 inst.reg_num = 7 - op[1].modrm.reg;
149 else if (op[1].modrm.reg == 4)
150 goto error_unsupported;
152 inst.reg_num = 15 - op[1].modrm.reg;
154 if (does_write != is_write)
155 goto error_inconsitent;
160 panic_printk("FATAL: unable to get MMIO instruction\n");
164 panic_printk("FATAL: unsupported instruction (0x%02x 0x%02x 0x%02x)\n",
165 op[0].raw, op[1].raw, op[2].raw);
169 panic_printk("FATAL: inconsistent access, expected %s instruction\n",
170 is_write ? "write" : "read");
176 unsigned int arch_mmio_count_regions(struct cell *cell)
178 return ioapic_mmio_count_regions(cell) + iommu_mmio_count_regions(cell);