|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [RFC] WIP: optee: add OP-TEE mediator
Hi Julien,
On Mon, Dec 04, 2017 at 02:30:32PM +0000, Julien Grall wrote:
> Hi,
>
> I am going to answer both e-mails (Stefano and Volodymyr) at once.
>
> On 01/12/17 22:58, Stefano Stabellini wrote:
> >On Mon, 27 Nov 2017, Volodymyr Babchuk wrote:
> >>This is follow-up to our conversation during community call.
> >>You asked me to send OP-TEE mediator as a patch, so we can
> >>discuss it in the mailing list. So, there it is. I squashed
> >>two patches into one and skipped patches that we already
> >>discussed.
> >>
> >>So, this is basically all what is needed to support OP-TEE in XEN.
> >>There are some TODOs left all over the code. But, I don't
> >>expect that TODOs implementation would significantly
> >>increase codebase. Currently mediator parses requests to perform
> >>addresses translation and that's all what is should be done
> >>to allow guests to work with OP-TEE.
> >>
> >>This become possible because I completely revisited virtualization
> >>support in OP-TEE. I have found way to enforce complete isolation
> >>between different guest states. This lifts many questions like usage
> >>quotas, RPC routing, sudden guest death, data isolation, etc.
>
> I disagree here. You still have to handle sudden guest death in Xen and
> release any memory allocated in the hypervisor for that guests.
I was speaking from OP-TEE point-of-view.
From mediator side, there is callback optee_domain_destroy() with
comment "TODO: Clean call contexts and SHMs associated with
domain". This callback will be called during domain description and it
will free any resources that mediator allocated on behalf of the
guest.
> >>
> >>I'm aware that I didn't addressed all comments from previous
> >>discussion. Sorry for this. I'm currently busy with OP-TEE,
> >>and I think proper mediator implementation will be possible
> >>only after I'll stabilize OP-TEE part.
> >>
> >>So I don't ask anybody to do thorough review. I just want to
> >>share my status and discuss this code a whole.
> >
> >Thank you for sharing! Actually, I think it is not too bad as a starting
> >point.
> >
> >I'll also try to summarize some key concept we have been discussing
> >about OP-TEE support in Xen.
> >
> >
> >= Xen cannot protect the system from a broken/insecure OP-TEE =
> >
> >OP-TEE runs at a higher privilege level than Xen, thus, we can't really
> >expect Xen to protect the system from a broken OP-TEE. Also, Xen cannot
> >really protect OP-TEE from a malicious caller.
> >
> >What we can and should do is to protect Xen, the OP-TEE mediator in Xen
> >specifically, from malicious attackers.
> >
> >In other words, we are not responsible if a call, forwarded to OP-TEE by
> >Xen, ends up crashing OP-TEE, therefore taking down the system.
> >
> >However, we have to pay special care to avoid callers to crash or take
> >over the mediator in Xen. We also have to pay attention so that a caller
> >won't be able to exhaust Xen resources or DOS Xen (allocate too much
> >memory, infinite loops in Xen, etc). This brings me to the next topic.
> >
> >
> >= Error checking / DOS protection =
> >
> >We need powerful checks on arguments passed by the caller and evaluated
> >by the mediator.
> >
> >For example, we cannot expect the guest to actually pass arguments in
> >the format expected by translate_params. ctx->xen_arg could be
> >gibberish.
> >
> > From the resource allocation point of view, it looks like every
> >handle_std_call allocates a new context; every copy_std_request
> >allocates a new Xen page. It would be easy to exhaust Xen resources.
> >Maybe we need a max concurrent request limit or max page allocation per
> >domain or something of the kind.
> >
> >
> >= Locks and Lists =
> >
> >The current lock and list is global. Do you think it should actually be
> >global or per-domain? I do realize that only dom0 is allowed to make
> >calls now so the question for the moment is not too useful.
>
> Hmmm, the commit message says: "With this patch OP-TEE successfully passes
> own tests, while client is running in DomU.". As said above, we need to make
> sure that Xen will release memory allocated for SMC requests when a domain
> dies. So have a list/lock per domain would make more sense (easier to go
> through).
You are totaly right. I can't say why I did in a way I did :-) I think,
it was easier approach during initial implementation.
But I certainly plan to hold separete context with own lists/locks for
every domain. This will also ease cleanup, because you are holding
all domain data in one place.
> >
> >
> >= Xen command forwarding =
> >
> >In the code below, it looks like Xen is forwarding everything to OP-TEE.
> >Are there some commands Xen should avoid forwarding? Should we have a
> >whitelist or a blacklist?
> >
> >
> >= Long running OP-TEE commands and interruptions =
> >
> >I have been told that some OP-TEE RPC commands might take long to
> >complete. Is that right? Like for example one of the
> >OPTEE_MSG_RPC_CMD_*?
> >
> >If so, we need to think what to do in those cases. Specifically, do we
> >need a technique to restart certain commands in Xen, so that when they
> >run for too long and get interrupted by something (such as an
> >interrupt) we know how to restart them? In fact, do we need to setup a
> >timer interrupt to make sure the command doesn't block Xen for too long,
> >consuming the next vcpu's slot as well?
>
> I am not sure to understand your suggestion here. Where do you want that
> timer? In Xen? If so, I don't think this could work. That's OP-TEE job to
> break down long running operation.
>
> This is very similar to when a guest is doing an hypercall. Even if setup a
> timer, the interrupt will only be received once the hypercall is done (or
> Xen decided to preempt it).
>
> >
> >
> >= Page pinning =
> >
> >Guest pages passed to OP-TEE need to be pinned (otherwise Xen doesn't
> >guarantee they'll be available). I think the right function to call for
> >that is get_page_from_gfn or get_page.
>
> No direct use of get_page please. We already have plenty of helper to deal
> with the translation GFN -> Page or even copying data. I don't want to see
> more open-coding version because it makes difficult to interaction with
> other features such as memaccess and PoD.
Okay. Could you please suggest what API should be used in my case?
> >>---
> >>
> >>Add OP-TEE mediator as an example how TEE mediator framework
> >>works.
> >>
> >>OP-TEE mediator support address translation for DomUs.
> >>It tracks execution of STD calls, correctly handles memory-related RPC
> >>requests, tracks buffer allocated for RPCs.
> >>
> >>With this patch OP-TEE successfully passes own tests, while client is
> >>running in DomU. Currently it lacks some code for exceptional cases,
> >>because this patch was used mostly to debug virtualization in OP-TEE.
> >>Nevertheless, it provides all features needed for OP-TEE mediation.
> >>
> >>WARNING: This is a development patch, it does not cover all corner
> >>cases, so, please don't use it in production.
> >>
> >>It was tested on RCAR Salvator-M3 board.
> >>
> >>Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@xxxxxxxx>
> >>---
> >> xen/arch/arm/tee/Kconfig | 4 +
> >> xen/arch/arm/tee/Makefile | 1 +
> >> xen/arch/arm/tee/optee.c | 765
> >> +++++++++++++++++++++++++++++++++++++++++++
> >> xen/arch/arm/tee/optee_smc.h | 50 +++
> >> 4 files changed, 820 insertions(+)
> >> create mode 100644 xen/arch/arm/tee/optee.c
> >>
> >>diff --git a/xen/arch/arm/tee/Kconfig b/xen/arch/arm/tee/Kconfig
> >>index e69de29..7c6b5c6 100644
> >>--- a/xen/arch/arm/tee/Kconfig
> >>+++ b/xen/arch/arm/tee/Kconfig
> >>@@ -0,0 +1,4 @@
> >>+config ARM_OPTEE
> >>+ bool "Enable OP-TEE mediator"
> >>+ default n
> >>+ depends on ARM_TEE
> >>diff --git a/xen/arch/arm/tee/Makefile b/xen/arch/arm/tee/Makefile
> >>index c54d479..9d93b42 100644
> >>--- a/xen/arch/arm/tee/Makefile
> >>+++ b/xen/arch/arm/tee/Makefile
> >>@@ -1 +1,2 @@
> >> obj-y += tee.o
> >>+obj-$(CONFIG_ARM_OPTEE) += optee.o
> >>diff --git a/xen/arch/arm/tee/optee.c b/xen/arch/arm/tee/optee.c
> >>new file mode 100644
> >>index 0000000..59c3600
> >>--- /dev/null
> >>+++ b/xen/arch/arm/tee/optee.c
> >>@@ -0,0 +1,765 @@
> >>+/*
> >>+ * xen/arch/arm/tee/optee.c
> >>+ *
> >>+ * OP-TEE mediator
> >>+ *
> >>+ * Volodymyr Babchuk <volodymyr_babchuk@xxxxxxxx>
> >>+ * Copyright (c) 2017 EPAM Systems.
> >>+ *
> >>+ * This program is free software; you can redistribute it and/or modify
> >>+ * it under the terms of the GNU General Public License version 2 as
> >>+ * published by the Free Software Foundation.
> >>+ *
> >>+ * This program is distributed in the hope that it will be useful,
> >>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> >>+ * GNU General Public License for more details.
> >>+ */
> >>+
> >>+#include <xen/domain_page.h>
> >>+#include <xen/types.h>
> >>+#include <xen/sched.h>
> >>+
> >>+#include <asm/p2m.h>
> >>+#include <asm/tee.h>
> >>+
> >>+#include "optee_msg.h"
> >>+#include "optee_smc.h"
> >>+
> >>+/*
> >>+ * Global TODO:
> >>+ * 1. Create per-domain context, where call and shm will be stored
> >>+ * 2. Pin pages shared between OP-TEE and guest
> >>+ */
> >>+/*
> >>+ * OP-TEE violates SMCCC when it defines own UID. So we need
> >>+ * to place bytes in correct order.
> >>+ */
> >>+#define OPTEE_UID (xen_uuid_t){{
> >> \
> >>+ (uint8_t)(OPTEE_MSG_UID_0 >> 0), (uint8_t)(OPTEE_MSG_UID_0 >> 8),
> >> \
> >>+ (uint8_t)(OPTEE_MSG_UID_0 >> 16), (uint8_t)(OPTEE_MSG_UID_0 >> 24),
> >> \
> >>+ (uint8_t)(OPTEE_MSG_UID_1 >> 0), (uint8_t)(OPTEE_MSG_UID_1 >> 8),
> >> \
> >>+ (uint8_t)(OPTEE_MSG_UID_1 >> 16), (uint8_t)(OPTEE_MSG_UID_1 >> 24),
> >> \
> >>+ (uint8_t)(OPTEE_MSG_UID_2 >> 0), (uint8_t)(OPTEE_MSG_UID_2 >> 8),
> >> \
> >>+ (uint8_t)(OPTEE_MSG_UID_2 >> 16), (uint8_t)(OPTEE_MSG_UID_2 >> 24),
> >> \
> >>+ (uint8_t)(OPTEE_MSG_UID_3 >> 0), (uint8_t)(OPTEE_MSG_UID_3 >> 8),
> >> \
> >>+ (uint8_t)(OPTEE_MSG_UID_3 >> 16), (uint8_t)(OPTEE_MSG_UID_3 >> 24),
> >> \
> >>+ }}
> >>+
> >>+#define MAX_NONCONTIG_ENTRIES 8
> >>+
> >>+/*
> >>+ * Call context. OP-TEE can issue mulitple RPC returns during one call.
> >>+ * We need to preserve context during them.
> >>+ */
> >>+struct std_call_ctx {
> >>+ struct list_head list;
> >>+ struct optee_msg_arg *guest_arg;
> >>+ struct optee_msg_arg *xen_arg;
> >>+ void *non_contig[MAX_NONCONTIG_ENTRIES];
> >>+ int non_contig_order[MAX_NONCONTIG_ENTRIES];
> >>+ int optee_thread_id;
> >>+ int rpc_op;
> >>+ domid_t domid;
> >>+};
> >>+static LIST_HEAD(call_ctx_list);
> >>+static DEFINE_SPINLOCK(call_ctx_list_lock);
> >>+
> >>+/*
> >>+ * Command buffer shared between OP-TEE and guest.
> >>+ * Warning! In the proper implementation this SHM buffer *probably* should
> >>+ * by shadowed by XEN.
> >>+ * TODO: Reconsider this.
> >>+ */
> >>+struct shm {
> >>+ struct list_head list;
> >>+ struct optee_msg_arg *guest_arg;
> >>+ struct page *guest_page;
> >>+ mfn_t guest_mfn;
> >>+ uint64_t cookie;
> >>+ domid_t domid;
> >>+};
> >>+
> >>+static LIST_HEAD(shm_list);
> >>+static DEFINE_SPINLOCK(shm_list_lock);
> >>+
> >>+static int optee_init(void)
> >>+{
> >>+ printk("OP-TEE mediator init done\n");
> >>+ return 0;
> >>+}
> >>+
> >>+static void optee_domain_create(struct domain *d)
> >>+{
> >>+ register_t resp[4];
> >>+ call_smccc_smc(OPTEE_SMC_VM_CREATED,
> >>+ d->domain_id + 1, 0, 0, 0, 0, 0, 0, resp);
> >>+ if ( resp[0] != OPTEE_SMC_RETURN_OK )
> >>+ gprintk(XENLOG_WARNING, "OP-TEE don't want to support domain:
> >>%d\n",
> >>+ (uint32_t)resp[0]);
> >>+ /* TODO: Change function declaration to be able to retun error */
> >>+}
> >>+
> >>+static void optee_domain_destroy(struct domain *d)
> >>+{
> >>+ register_t resp[4];
> >>+ call_smccc_smc(OPTEE_SMC_VM_DESTROYED,
> >>+ d->domain_id + 1, 0, 0, 0, 0, 0, 0, resp);
> >>+ /* TODO: Clean call contexts and SHMs associated with domain */
> >>+}
> >>+
> >>+static bool forward_call(struct cpu_user_regs *regs)
> >>+{
> >>+ register_t resp[4];
> >>+
> >>+ /* TODO: Use separate registers set to prevent leakage to guest */
> >>+ call_smccc_smc(get_user_reg(regs, 0),
> >>+ get_user_reg(regs, 1),
> >>+ get_user_reg(regs, 2),
> >>+ get_user_reg(regs, 3),
> >>+ get_user_reg(regs, 4),
> >>+ get_user_reg(regs, 5),
> >>+ get_user_reg(regs, 6),
> >>+ /* VM id 0 is reserved for hypervisor itself */
> >>+ current->domain->domain_id + 1,
> >
> >This doesn't look like it would wrap around safely.
>
> Well ordinary domain will always have a domain ID < DOMID_FIRST_RESERVER
> (0x7FF0). So there are no issue here. Although, we may want a BUILD_BUG_ON()
> to catch change of DOMID_FIRST_RESERVED.
>
> >
> >
> >>+ resp);
> >>+
> >>+ set_user_reg(regs, 0, resp[0]);
> >>+ set_user_reg(regs, 1, resp[1]);
> >>+ set_user_reg(regs, 2, resp[2]);
> >>+ set_user_reg(regs, 3, resp[3]);
> >>+
> >>+ return true;
> >>+}
> >>+
> >>+static struct std_call_ctx *allocate_std_call_ctx(void)
> >>+{
> >>+ struct std_call_ctx *ret;
> >>+
> >>+ ret = xzalloc(struct std_call_ctx);
> >>+ if ( !ret )
> >>+ return NULL;
> >>+
> >>+ ret->optee_thread_id = -1;
>
> You set it to -1. But no-one is checking that value. So what is the purpose
> of setting to -1 and not 0?
>
> >>+ ret->domid = -1;
>
> Please use DOMID_INVALID rather than -1. You don't know whether the latter
> will be used in the future for a domain.
>
> >>+
> >>+ spin_lock(&call_ctx_list_lock);
> >>+ list_add_tail(&ret->list, &call_ctx_list);
> >>+ spin_unlock(&call_ctx_list_lock);
> >>+
> >>+ return ret;
> >>+}
> >>+
> >>+static void free_std_call_ctx(struct std_call_ctx *ctx)
> >>+{
> >>+ spin_lock(&call_ctx_list_lock);
> >>+ list_del(&ctx->list);
> >>+ spin_unlock(&call_ctx_list_lock);
> >>+
> >>+ if (ctx->xen_arg)
> >>+ free_xenheap_page(ctx->xen_arg);
> >>+
> >>+ if (ctx->guest_arg)
> >>+ unmap_domain_page(ctx->guest_arg);
> >>+
> >>+ for (int i = 0; i < MAX_NONCONTIG_ENTRIES; i++) {
> >>+ if (ctx->non_contig[i])
> >>+ free_xenheap_pages(ctx->non_contig[i],
> >>ctx->non_contig_order[i]);
> >>+ }
> >>+
> >>+ xfree(ctx);
> >>+}
> >>+
> >>+static struct std_call_ctx *find_ctx(int thread_id, domid_t domid)
> >>+{
> >>+ struct std_call_ctx *ctx;
> >>+
> >>+ spin_lock(&call_ctx_list_lock);
> >>+ list_for_each_entry( ctx, &call_ctx_list, list )
> >>+ {
> >>+ if (ctx->domid == domid && ctx->optee_thread_id == thread_id )
> >>+ {
> >>+ spin_unlock(&call_ctx_list_lock);
> >>+ return ctx;
> >>+ }
> >>+ }
> >>+ spin_unlock(&call_ctx_list_lock);
> >>+
> >>+ return NULL;
> >>+}
> >>+
> >>+#define PAGELIST_ENTRIES_PER_PAGE \
> >>+ ((OPTEE_MSG_NONCONTIG_PAGE_SIZE / sizeof(u64)) - 1)
> >>+
> >>+static size_t get_pages_list_size(size_t num_entries)
> >>+{
> >>+ int pages = DIV_ROUND_UP(num_entries, PAGELIST_ENTRIES_PER_PAGE);
> >>+
> >>+ return pages * OPTEE_MSG_NONCONTIG_PAGE_SIZE;
> >>+}
> >>+
> >>+static mfn_t lookup_guest_ram_addr(paddr_t gaddr)
> >>+{
> >>+ mfn_t mfn;
> >>+ gfn_t gfn;
> >>+ p2m_type_t t;
> >>+ gfn = gaddr_to_gfn(gaddr);
> >>+ mfn = p2m_lookup(current->domain, gfn, &t);
> >>+ if ( t != p2m_ram_rw || mfn_eq(mfn, INVALID_MFN) ) {
> >>+ gprintk(XENLOG_INFO, "Domain tries to use invalid gfn\n");
> >>+ return INVALID_MFN;
> >>+ }
> >>+ return mfn;
> >>+} >> +
> >>+static struct shm *allocate_and_map_shm(paddr_t gaddr, uint64_t cookie)
> >>+{
> >>+ struct shm *ret;
> >>+
> >>+ ret = xzalloc(struct shm);
> >>+ if ( !ret )
> >>+ return NULL;
> >>+
> >>+ ret->guest_mfn = lookup_guest_ram_addr(gaddr);
> >>+
> >>+ if ( mfn_eq(ret->guest_mfn, INVALID_MFN) )
> >>+ {
> >>+ xfree(ret);
> >>+ return NULL;
> >>+ }
> >>+
> >>+ ret->guest_arg = map_domain_page(ret->guest_mfn);
>
> map_domain_page() can never fail, but you use it the wrong way. The purpose
> of this function is to map the memory for a very short lifetime, and only a
> the current pCPU (when the all the RAM is not always mapped). Here, you seem
> to use across SMC call (e.g for RPC).
>
> Looking at the usage in the code, you only map it in order to copy the
> arguments to/from the guest.
>
> map_domain_page() will not take a reference on the page and prevent the page
> to disappear from the guest. So this bits is unsafe.
>
> For the arguments, the best is to use guest copy helpers (see
> access_guest_memory_by_ipa). You might want to look at [1] as it improves
> the use of access_guest_memory_by_ipa.
>
> >>+ if ( !ret->guest_arg )
> >>+ {
> >>+ gprintk(XENLOG_INFO, "Could not map domain page\n");
> >>+ xfree(ret);
> >>+ return NULL;
> >>+ }
> >>+ ret->cookie = cookie;
> >>+ ret->domid = current->domain->domain_id;
> >>+
> >>+ spin_lock(&shm_list_lock);
> >>+ list_add_tail(&ret->list, &shm_list);
> >>+ spin_unlock(&shm_list_lock);
> >>+ return ret;
> >>+}
> >>+
> >>+static void free_shm(uint64_t cookie, domid_t domid)
> >>+{
> >>+ struct shm *shm, *found = NULL;
> >>+ spin_lock(&shm_list_lock);
> >>+
> >>+ list_for_each_entry( shm, &shm_list, list )
> >>+ {
> >>+ if (shm->domid == domid && shm->cookie == cookie )
> >>+ {
> >>+ found = shm;
> >>+ list_del(&found->list);
> >>+ break;
> >>+ }
> >>+ }
> >>+ spin_unlock(&shm_list_lock);
> >>+
> >>+ if ( !found ) {
> >>+ return;
> >>+ }
> >>+
> >>+ if ( found->guest_arg )
> >>+ unmap_domain_page(found->guest_arg);
> >>+
> >>+ xfree(found);
> >>+}
> >>+
> >>+static struct shm *find_shm(uint64_t cookie, domid_t domid)
> >>+{
> >>+ struct shm *shm;
> >>+
> >>+ spin_lock(&shm_list_lock);
> >>+ list_for_each_entry( shm, &shm_list, list )
> >>+ {
> >>+ if ( shm->domid == domid && shm->cookie == cookie )
> >>+ {
> >>+ spin_unlock(&shm_list_lock);
> >>+ return shm;
> >>+ }
> >>+ }
> >>+ spin_unlock(&shm_list_lock);
> >>+
> >>+ return NULL;
> >>+}
> >>+
> >>+static bool translate_noncontig(struct std_call_ctx *ctx,
> >>+ struct optee_msg_param *param,
> >>+ int idx)
> >>+{
> >>+ /*
> >>+ * Refer to OPTEE_MSG_ATTR_NONCONTIG description in optee_msg.h for
> >>details.
> >>+ *
> >>+ * WARNING: This is test code. It works only with xen page size == 4096
>
> That's a call for a BUILD_BUG_ON().
>
> >>+ */
> >>+ uint64_t size;
> >>+ int page_offset;
> >>+ int num_pages;
> >>+ int order;
> >>+ int entries_on_page = 0;
> >>+ paddr_t gaddr;
> >>+ mfn_t guest_mfn;
> >>+ struct {
> >>+ uint64_t pages_list[PAGELIST_ENTRIES_PER_PAGE];
> >>+ uint64_t next_page_data;
> >>+ } *pages_data_guest, *pages_data_xen, *pages_data_xen_start;
> >>+
> >>+ page_offset = param->u.tmem.buf_ptr & (OPTEE_MSG_NONCONTIG_PAGE_SIZE -
> >>1);
> >>+
> >>+ size = ROUNDUP(param->u.tmem.size + page_offset,
> >>+ OPTEE_MSG_NONCONTIG_PAGE_SIZE);
> >>+
> >>+ num_pages = DIV_ROUND_UP(size, OPTEE_MSG_NONCONTIG_PAGE_SIZE);
>
> What is the limit for num_pages? I can't see anything in the code that
> prevent any high number and might exhaust Xen memory.
>
> >>+
> >>+ order = get_order_from_bytes(get_pages_list_size(num_pages));
> >>+
> >>+ pages_data_xen_start = alloc_xenheap_pages(order, 0);
> >>+ if (!pages_data_xen_start)
> >>+ return false;
> >>+
> >>+ gaddr = param->u.tmem.buf_ptr & ~(OPTEE_MSG_NONCONTIG_PAGE_SIZE - 1);
> >>+ guest_mfn = lookup_guest_ram_addr(gaddr);
> >>+ if ( mfn_eq(guest_mfn, INVALID_MFN) )
> >>+ goto err_free;
> >>+
> >>+ pages_data_guest = map_domain_page(guest_mfn);
>
> Similarly here, you may want to use access_guest_by_ipa. This will do all
> the safety check for copy from guest memory.
>
> Furthermore, I think this is going to simplify a lot this code.
>
>
> >>+ if (!pages_data_guest)
> >>+ goto err_free;
> >>+
> >>+ pages_data_xen = pages_data_xen_start;
> >>+ while ( num_pages ) {
> >>+ mfn_t entry_mfn = lookup_guest_ram_addr(
> >>+ pages_data_guest->pages_list[entries_on_page]);
> >>+
> >>+ if ( mfn_eq(entry_mfn, INVALID_MFN) )
> >>+ goto err_unmap;
>
> You would need to get a reference on each page, and release it in err_unmap
> or when the command is done. get_page_from_gfn could do it for you.
>
> >>+
> >>+ pages_data_xen->pages_list[entries_on_page] =
> >>mfn_to_maddr(entry_mfn);
> >>+ entries_on_page++;
> >>+
> >>+ if ( entries_on_page == PAGELIST_ENTRIES_PER_PAGE ) {
> >>+ pages_data_xen->next_page_data = virt_to_maddr(pages_data_xen
> >>+ 1);
> >>+ pages_data_xen++;
> >>+ gaddr = pages_data_guest->next_page_data;
> >>+ unmap_domain_page(pages_data_guest);
> >>+ guest_mfn = lookup_guest_ram_addr(gaddr);
> >>+ if ( mfn_eq(guest_mfn, INVALID_MFN) )
> >>+ goto err_free;
> >>+
> >>+ pages_data_guest = map_domain_page(guest_mfn);
> >>+ if ( !pages_data_guest )
> >>+ goto err_free;
> >>+ /* Roll over to the next page */
> >>+ entries_on_page = 0;
> >>+ }
> >>+ num_pages--;
> >>+ }
> >>+
> >>+ unmap_domain_page(pages_data_guest);
> >>+
> >>+ param->u.tmem.buf_ptr = virt_to_maddr(pages_data_xen_start) |
> >>page_offset;
>
> I am not sure to understand why you are apply the offset of the guest buffer
> to xen buffer.
>
> >>+
> >>+ ctx->non_contig[idx] = pages_data_xen_start;
> >>+ ctx->non_contig_order[idx] = order;
> >>+
> >>+ unmap_domain_page(pages_data_guest);
> >>+ return true;
> >>+
> >>+err_unmap:
> >>+ unmap_domain_page(pages_data_guest);
> >>+err_free:
> >>+ free_xenheap_pages(pages_data_xen_start, order);
> >>+ return false;
> >>+}
> >>+
> >>+static bool translate_params(struct std_call_ctx *ctx)
> >>+{
> >>+ unsigned int i;
> >>+ uint32_t attr;
> >>+
> >>+ for ( i = 0; i < ctx->xen_arg->num_params; i++ ) {
> >>+ attr = ctx->xen_arg->params[i].attr;
> >>+
> >>+ switch ( attr & OPTEE_MSG_ATTR_TYPE_MASK ) {
> >>+ case OPTEE_MSG_ATTR_TYPE_TMEM_INPUT:
> >>+ case OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT:
> >>+ case OPTEE_MSG_ATTR_TYPE_TMEM_INOUT:
> >>+ if ( attr & OPTEE_MSG_ATTR_NONCONTIG ) {
> >>+ if ( !translate_noncontig(ctx, ctx->xen_arg->params + i,
> >>i) )
> >>+ return false;
> >>+ }
> >>+ else {
> >>+ gprintk(XENLOG_WARNING, "Guest tries to use old tmem
> >>arg\n");
> >>+ return false;
> >>+ }
> >>+ break;
> >>+ case OPTEE_MSG_ATTR_TYPE_NONE:
> >>+ case OPTEE_MSG_ATTR_TYPE_VALUE_INPUT:
> >>+ case OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT:
> >>+ case OPTEE_MSG_ATTR_TYPE_VALUE_INOUT:
> >>+ case OPTEE_MSG_ATTR_TYPE_RMEM_INPUT:
> >>+ case OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT:
> >>+ case OPTEE_MSG_ATTR_TYPE_RMEM_INOUT:
> >>+ continue;
> >>+ }
> >>+ }
> >>+ return true;
> >>+}
> >>+
> >>+/*
> >>+ * Copy command buffer into xen memory to:
> >>+ * 1) Hide translated addresses from guest
> >>+ * 2) Make sure that guest wouldn't change data in command buffer during
> >>call
> >>+ */
> >>+static bool copy_std_request(struct cpu_user_regs *regs,
> >>+ struct std_call_ctx *ctx)
> >>+{
> >>+ paddr_t cmd_gaddr, xen_addr;
> >>+ mfn_t cmd_mfn;
> >>+
> >>+ cmd_gaddr = (paddr_t)get_user_reg(regs, 1) << 32 |
> >>+ get_user_reg(regs, 2);
> >>+
> >>+ /*
> >>+ * Command buffer should start at page boundary.
> >>+ * This is OP-TEE ABI requirement.
> >>+ */
> >>+ if ( cmd_gaddr & (OPTEE_MSG_NONCONTIG_PAGE_SIZE - 1) )
> >>+ return false;
> >>+
> >>+ cmd_mfn = lookup_guest_ram_addr(cmd_gaddr);
> >>+ if ( mfn_eq(cmd_mfn, INVALID_MFN) )
> >>+ return false;
> >>+
> >>+ ctx->guest_arg = map_domain_page(cmd_mfn);
> >>+ if ( !ctx->guest_arg )
> >>+ return false;
> >>+
> >>+ ctx->xen_arg = alloc_xenheap_page();
> >>+ if ( !ctx->xen_arg )
> >>+ return false;
> >>+
> >>+ memcpy(ctx->xen_arg, ctx->guest_arg, OPTEE_MSG_NONCONTIG_PAGE_SIZE);
>
> Have a look a guest copy helpers.
>
> Cheers,
>
> [1]
> https://lists.xenproject.org/archives/html/xen-devel/2017-11/msg01481.html
>
> --
> Julien Grall
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |