diff options
author | Huang Ying <ying.huang@intel.com> | 2013-04-02 10:58:31 +0200 |
---|---|---|
committer | Jan Beulich <jbeulich@suse.com> | 2013-04-02 10:58:31 +0200 |
commit | a44b0a5538c26f993b72fbd083c3d3c216fa8ca8 (patch) | |
tree | 01e7a9d6b0d297ead6105a5522161fce3d2d0eb4 | |
parent | 77c1e88c14bb6705f6fca091e12d2aa4d8882207 (diff) | |
download | xen-a44b0a5538c26f993b72fbd083c3d3c216fa8ca8.tar.gz xen-a44b0a5538c26f993b72fbd083c3d3c216fa8ca8.tar.bz2 xen-a44b0a5538c26f993b72fbd083c3d3c216fa8ca8.zip |
ACPI/APEI: fix ERST MOVE_DATA instruction implementation
The src_base and dst_base fields in apei_exec_context are physical
address, so they should be ioremaped before being used in ERST
MOVE_DATA instruction.
Reported-by: Javier Martinez Canillas <martinez.javier@gmail.com>
Reported-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Huang Ying <ying.huang@intel.com>
Replace use of ioremap() by __acpi_map_table()/set_fixmap(). Fix error
handling.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Keir Fraser <keir@xen.org>
master changeset: df2cf6a726b815fafa12e503c9a36707c3962f22
master date: 2012-10-17 14:12:06 +0200
-rw-r--r-- | xen/drivers/acpi/apei/erst.c | 57 |
1 files changed, 53 insertions, 4 deletions
diff --git a/xen/drivers/acpi/apei/erst.c b/xen/drivers/acpi/apei/erst.c index eb666a6fca..46fcff570c 100644 --- a/xen/drivers/acpi/apei/erst.c +++ b/xen/drivers/acpi/apei/erst.c @@ -247,15 +247,64 @@ static int erst_exec_move_data(struct apei_exec_context *ctx, { int rc; u64 offset; +#ifdef CONFIG_X86 + enum fixed_addresses idx; +#endif + void *src, *dst; + + /* ioremap does not work in interrupt context */ + if (in_irq()) { + printk(KERN_WARNING + "MOVE_DATA cannot be used in interrupt context\n"); + return -EBUSY; + } rc = __apei_exec_read_register(entry, &offset); if (rc) return rc; - memmove((void *)(unsigned long)(ctx->dst_base + offset), - (void *)(unsigned long)(ctx->src_base + offset), - ctx->var2); - return 0; +#ifdef CONFIG_X86 + switch (ctx->var2) { + case 0: + return 0; + case 1 ... PAGE_SIZE: + break; + default: + printk(KERN_WARNING + "MOVE_DATA cannot be used for %#"PRIx64" bytes of data\n", + ctx->var2); + return -EOPNOTSUPP; + } + + src = __acpi_map_table(ctx->src_base + offset, ctx->var2); +#else + src = ioremap(ctx->src_base + offset, ctx->var2); +#endif + if (!src) + return -ENOMEM; + +#ifdef CONFIG_X86 + BUILD_BUG_ON(FIX_ACPI_PAGES < 4); + idx = virt_to_fix((unsigned long)src + 2 * PAGE_SIZE); + offset += ctx->dst_base; + dst = (void *)fix_to_virt(idx) + (offset & ~PAGE_MASK); + set_fixmap(idx, offset); + if (PFN_DOWN(offset) != PFN_DOWN(offset + ctx->var2 - 1)) { + idx = virt_to_fix((unsigned long)dst + PAGE_SIZE); + set_fixmap(idx, offset + PAGE_SIZE); + } +#else + dst = ioremap(ctx->dst_base + offset, ctx->var2); +#endif + if (dst) { + memmove(dst, src, ctx->var2); + iounmap(dst); + } else + rc = -ENOMEM; + + iounmap(src); + + return rc; } static struct apei_exec_ins_type erst_ins_type[] = { |