From patchwork Tue May 21 21:26:05 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Volodymyr Babchuk X-Patchwork-Id: 10954537 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8AE9C1708 for ; Tue, 21 May 2019 21:27:30 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 796D1289F7 for ; Tue, 21 May 2019 21:27:30 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6D38428A61; Tue, 21 May 2019 21:27:30 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.0 required=2.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id AD744289F7 for ; Tue, 21 May 2019 21:27:29 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1hTCGx-0008Jg-GW; Tue, 21 May 2019 21:26:11 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1hTCGw-0008Im-3Q for xen-devel@lists.xenproject.org; Tue, 21 May 2019 21:26:10 +0000 X-Inumbo-ID: 0b6f62f2-7c0f-11e9-a5b1-ffe046f5e668 Received: from EUR04-DB3-obe.outbound.protection.outlook.com (unknown [40.107.6.64]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id 0b6f62f2-7c0f-11e9-a5b1-ffe046f5e668; Tue, 21 May 2019 21:26:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=epam.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=E99IeKFTeNZsWGy49mjVrouix5e5qPT7szY4jcQ940M=; b=S83lE1gbe6R71DVPl15mMX0/BjZXw8ygf9DP9E8Xk7jYuNC3XYP7lBuhTXvBtzgwET9yUV9O7Z2iekaMH7jsgkCHwv1bebi0ELuQjuujwrGiyDjtFVFoogeivpO64BDxjKtgg1h6vShBGBubq6+FgtmwjJS11dTl5hqu9IsgRLZHR4z9LHZFrtJvv4b3ei6KTUSCN1sMO7N/RCxL+cv85pJ0rQmU4kEXJ+Zq/jW/9bVuNl0k5ZmueV8iZL5hufBJVxAo3Qr9ruQ6HyUPydTQzPpuQX8JYGvME2OwBNPCtReK456uaPuv3Uy3LQWAEA3YsPGlaE5vEzsiSBCwJOlRPQ== Received: from AM0PR03MB4148.eurprd03.prod.outlook.com (20.176.214.210) by AM0PR03MB5698.eurprd03.prod.outlook.com (20.179.254.155) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.1900.16; Tue, 21 May 2019 21:26:05 +0000 Received: from AM0PR03MB4148.eurprd03.prod.outlook.com ([fe80::55c5:599a:1f80:208a]) by AM0PR03MB4148.eurprd03.prod.outlook.com ([fe80::55c5:599a:1f80:208a%3]) with mapi id 15.20.1900.020; Tue, 21 May 2019 21:26:05 +0000 From: Volodymyr Babchuk To: "xen-devel@lists.xenproject.org" Thread-Topic: [PATCH v5 06/10] xen/arm: optee: add support for RPC SHM buffers Thread-Index: AQHVEBvMDSPWy7l6v0m6qxmKWo4AHw== Date: Tue, 21 May 2019 21:26:05 +0000 Message-ID: <20190521212530.12706-7-volodymyr_babchuk@epam.com> References: <20190521212530.12706-1-volodymyr_babchuk@epam.com> In-Reply-To: <20190521212530.12706-1-volodymyr_babchuk@epam.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: authentication-results: spf=none (sender IP is ) smtp.mailfrom=Volodymyr_Babchuk@epam.com; x-originating-ip: [85.223.209.22] x-ms-publictraffictype: Email x-ms-office365-filtering-correlation-id: cf1d3ae9-2120-411f-055f-08d6de32eeda x-microsoft-antispam: BCL:0; PCL:0; RULEID:(2390118)(7020095)(4652040)(8989299)(4534185)(7168020)(4627221)(201703031133081)(201702281549075)(8990200)(5600141)(711020)(4605104)(2017052603328)(7193020); SRVR:AM0PR03MB5698; x-ms-traffictypediagnostic: AM0PR03MB5698: x-microsoft-antispam-prvs: x-ms-oob-tlc-oobclassifiers: OLM:2201; x-forefront-prvs: 0044C17179 x-forefront-antispam-report: SFV:NSPM; SFS:(10009020)(376002)(136003)(366004)(346002)(396003)(39860400002)(189003)(199004)(6512007)(6486002)(5640700003)(6436002)(68736007)(3846002)(2616005)(476003)(11346002)(6916009)(486006)(6116002)(76116006)(14444005)(256004)(64756008)(66476007)(478600001)(305945005)(66946007)(54906003)(316002)(7736002)(73956011)(71190400001)(72206003)(2501003)(66556008)(80792005)(71200400001)(66446008)(26005)(4326008)(14454004)(25786009)(102836004)(2906002)(55236004)(8936002)(81166006)(5660300002)(99286004)(66066001)(1076003)(36756003)(86362001)(53936002)(6506007)(81156014)(446003)(2351001)(186003)(8676002)(76176011); DIR:OUT; SFP:1101; SCL:1; SRVR:AM0PR03MB5698; H:AM0PR03MB4148.eurprd03.prod.outlook.com; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; MX:1; A:1; received-spf: None (protection.outlook.com: epam.com does not designate permitted sender hosts) x-ms-exchange-senderadcheck: 1 x-microsoft-antispam-message-info: fJQiUceXXZmvKbjSF+Ns9m2N8zKqhlg7O34st7W/bgGYjD/ZE9zg+no/18J9a/aUHgp5RWZkZYXLndXwyhrJpJgWnmWUOTx4fetV2ZO5oHjuRVJZFM1SBg4gQ1g8tRn430bR9jUp5Ot0YSJwjXseg6Ix+bKjj2nLPlaOPOdNA44umnojXi5k2o/eNVcxGjD1EOQETxiC/DB5C24Rz5d8puEgbTmYyePTWTArs3Bx6FUedtSssYlSliIVkpvatFxDf0spH8+TrJe7xO5QhTJCAUVwHchWvUo53iordgavs+TyQvLmH/9ToKH6L3ykRLFUKhMFJSR+Ot9ZkV1Dr1DTqfnOiUuHROnWXlx3kQiZaZqBnyupDJ98ekTAX915oeYT2AEOyEyHjvr3JzRts3wCsMBw9SolDTiyv9zlW7pUPU8= MIME-Version: 1.0 X-OriginatorOrg: epam.com X-MS-Exchange-CrossTenant-Network-Message-Id: cf1d3ae9-2120-411f-055f-08d6de32eeda X-MS-Exchange-CrossTenant-originalarrivaltime: 21 May 2019 21:26:05.5751 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: b41b72d0-4e9f-4c26-8a69-f949f367c91d X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM0PR03MB5698 Subject: [Xen-devel] [PATCH v5 06/10] xen/arm: optee: add support for RPC SHM buffers X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: "tee-dev@lists.linaro.org" , Julien Grall , Stefano Stabellini , Volodymyr Babchuk Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP OP-TEE usually uses the same idea with command buffers (see previous commit) to issue RPC requests. Problem is that initially it has no buffer, where it can write request. So the first RPC request it makes is special: it requests NW to allocate shared buffer for other RPC requests. Usually this buffer is allocated only once for every OP-TEE thread and it remains allocated all the time until guest shuts down. Guest can ask OP-TEE to disable RPC buffers caching, in this case OP-TEE will ask guest to allocate/free buffer for the each RPC. Mediator needs to pin this buffer to make sure that page will be not free while it is shared with OP-TEE. Life cycle of this buffer is controlled by OP-TEE. It asks guest to create buffer and it asks it to free it. So it there is not much sense to limit number of those buffers, because we already limit the number of concurrent standard calls and prevention of RPC buffer allocation will impair OP-TEE functionality. Those buffers can be freed in two ways: either OP-TEE issues OPTEE_SMC_RPC_FUNC_FREE RPC request or guest tries to disable buffer caching by calling OPTEE_SMC_DISABLE_SHM_CACHE function. In the latter case OP-TEE will return cookie of the SHM buffer it just freed. OP-TEE expects that this RPC buffer have size of OPTEE_MSG_NONCONTIG_PAGE_SIZE, which equals to 4096 and is aligned with the same size. So, basically it expects one 4k page from the guest. This is the same as Xen's PAGE_SIZE. Signed-off-by: Volodymyr Babchuk Acked-by: Julien Grall --- All the patches to optee.c should be merged together. They were split to ease up review. But they depend heavily on each other. Changes from v4: - handle_rpc_func_alloc() now calls do_call_with_arg() directly Changes from v3: - Removed MAX_RPC_SHMS constant. Now this value depends on number of OP-TEE threads - Various formatting fixes - Added checks for guest memory type Changes from v2: - Added check to ensure that guests does not return two SHM buffers with the same cookie - Fixed coding style - Storing RPC parameters during RPC return to make sure, that guest will not change them during call continuation --- xen/arch/arm/tee/optee.c | 149 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 145 insertions(+), 4 deletions(-) diff --git a/xen/arch/arm/tee/optee.c b/xen/arch/arm/tee/optee.c index f092492849..175789fb00 100644 --- a/xen/arch/arm/tee/optee.c +++ b/xen/arch/arm/tee/optee.c @@ -81,9 +81,17 @@ struct optee_std_call { register_t rpc_params[2]; }; +/* Pre-allocated SHM buffer for RPC commands */ +struct shm_rpc { + struct list_head list; + struct page_info *guest_page; + uint64_t cookie; +}; + /* Domain context */ struct optee_domain { struct list_head call_list; + struct list_head shm_rpc_list; atomic_t call_count; spinlock_t lock; }; @@ -158,6 +166,7 @@ static int optee_domain_init(struct domain *d) } INIT_LIST_HEAD(&ctx->call_list); + INIT_LIST_HEAD(&ctx->shm_rpc_list); atomic_set(&ctx->call_count, 0); spin_lock_init(&ctx->lock); @@ -199,7 +208,11 @@ static struct optee_std_call *allocate_std_call(struct optee_domain *ctx) struct optee_std_call *call; int count; - /* Make sure that guest does not execute more than max_optee_threads */ + /* + * Make sure that guest does not execute more than max_optee_threads. + * This also indirectly limits number of RPC SHM buffers, because OP-TEE + * allocates one such buffer per standard call. + */ count = atomic_add_unless(&ctx->call_count, 1, max_optee_threads); if ( count == max_optee_threads ) return ERR_PTR(-ENOSPC); @@ -294,10 +307,80 @@ static void put_std_call(struct optee_domain *ctx, struct optee_std_call *call) spin_unlock(&ctx->lock); } +static struct shm_rpc *allocate_and_pin_shm_rpc(struct optee_domain *ctx, + gfn_t gfn, uint64_t cookie) +{ + struct shm_rpc *shm_rpc, *shm_rpc_tmp; + + shm_rpc = xzalloc(struct shm_rpc); + if ( !shm_rpc ) + return ERR_PTR(-ENOMEM); + + /* This page will be shared with OP-TEE, so we need to pin it. */ + shm_rpc->guest_page = get_domain_ram_page(gfn); + if ( !shm_rpc->guest_page ) + goto err; + + shm_rpc->cookie = cookie; + + spin_lock(&ctx->lock); + /* Check if there is existing SHM with the same cookie. */ + list_for_each_entry( shm_rpc_tmp, &ctx->shm_rpc_list, list ) + { + if ( shm_rpc_tmp->cookie == cookie ) + { + spin_unlock(&ctx->lock); + gdprintk(XENLOG_WARNING, "Guest tries to use the same RPC SHM cookie %lx\n", + cookie); + goto err; + } + } + + list_add_tail(&shm_rpc->list, &ctx->shm_rpc_list); + spin_unlock(&ctx->lock); + + return shm_rpc; + +err: + if ( shm_rpc->guest_page ) + put_page(shm_rpc->guest_page); + xfree(shm_rpc); + + return ERR_PTR(-EINVAL); +} + +static void free_shm_rpc(struct optee_domain *ctx, uint64_t cookie) +{ + struct shm_rpc *shm_rpc; + bool found = false; + + spin_lock(&ctx->lock); + + list_for_each_entry( shm_rpc, &ctx->shm_rpc_list, list ) + { + if ( shm_rpc->cookie == cookie ) + { + found = true; + list_del(&shm_rpc->list); + break; + } + } + spin_unlock(&ctx->lock); + + if ( !found ) + return; + + ASSERT(shm_rpc->guest_page); + put_page(shm_rpc->guest_page); + + xfree(shm_rpc); +} + static int optee_relinquish_resources(struct domain *d) { struct arm_smccc_res resp; struct optee_std_call *call, *call_tmp; + struct shm_rpc *shm_rpc, *shm_rpc_tmp; struct optee_domain *ctx = d->arch.tee; if ( !ctx ) @@ -314,6 +397,16 @@ static int optee_relinquish_resources(struct domain *d) if ( hypercall_preempt_check() ) return -ERESTART; + /* + * Number of this buffers also depends on max_optee_threads, so + * check the comment above. + */ + list_for_each_entry_safe( shm_rpc, shm_rpc_tmp, &ctx->shm_rpc_list, list ) + free_shm_rpc(ctx, shm_rpc->cookie); + + if ( hypercall_preempt_check() ) + return -ERESTART; + /* * Inform OP-TEE that domain is shutting down. This is * also a fast SMC call, like OPTEE_SMC_VM_CREATED, so @@ -328,6 +421,7 @@ static int optee_relinquish_resources(struct domain *d) ASSERT(!spin_is_locked(&ctx->lock)); ASSERT(!atomic_read(&ctx->call_count)); + ASSERT(list_empty(&ctx->shm_rpc_list)); XFREE(d->arch.tee); @@ -587,6 +681,48 @@ err: * request from OP-TEE and wished to resume the interrupted standard * call. */ +static void handle_rpc_func_alloc(struct optee_domain *ctx, + struct cpu_user_regs *regs, + struct optee_std_call *call) +{ + struct shm_rpc *shm_rpc; + register_t r1, r2; + paddr_t ptr = regpair_to_uint64(get_user_reg(regs, 1), + get_user_reg(regs, 2)); + uint64_t cookie = regpair_to_uint64(get_user_reg(regs, 4), + get_user_reg(regs, 5)); + + if ( ptr & (OPTEE_MSG_NONCONTIG_PAGE_SIZE - 1) ) + { + gdprintk(XENLOG_WARNING, "Domain returned invalid RPC command buffer\n"); + /* + * OP-TEE is waiting for a response to the RPC. We can't just + * return error to the guest. We need to provide some invalid + * value to OP-TEE, so it can handle error on its side. + */ + ptr = 0; + goto out; + } + + shm_rpc = allocate_and_pin_shm_rpc(ctx, gaddr_to_gfn(ptr), cookie); + if ( IS_ERR(shm_rpc) ) + { + gdprintk(XENLOG_WARNING, "Failed to allocate shm_rpc object: %ld\n", + PTR_ERR(shm_rpc)); + ptr = 0; + } + else + ptr = page_to_maddr(shm_rpc->guest_page); + +out: + uint64_to_regpair(&r1, &r2, ptr); + + do_call_with_arg(ctx, call, regs, OPTEE_SMC_CALL_RETURN_FROM_RPC, r1, r2, + get_user_reg(regs, 3), + get_user_reg(regs, 4), + get_user_reg(regs, 5)); +} + static void handle_rpc(struct optee_domain *ctx, struct cpu_user_regs *regs) { struct optee_std_call *call; @@ -610,11 +746,15 @@ static void handle_rpc(struct optee_domain *ctx, struct cpu_user_regs *regs) switch ( call->rpc_op ) { case OPTEE_SMC_RPC_FUNC_ALLOC: - /* TODO: Add handling */ - break; + handle_rpc_func_alloc(ctx, regs, call); + return; case OPTEE_SMC_RPC_FUNC_FREE: - /* TODO: Add handling */ + { + uint64_t cookie = regpair_to_uint64(call->rpc_params[0], + call->rpc_params[1]); + free_shm_rpc(ctx, cookie); break; + } case OPTEE_SMC_RPC_FUNC_FOREIGN_INTR: break; case OPTEE_SMC_RPC_FUNC_CMD: @@ -720,6 +860,7 @@ static bool optee_handle_call(struct cpu_user_regs *regs) OPTEE_CLIENT_ID(current->domain), &resp); set_user_reg(regs, 0, resp.a0); if ( resp.a0 == OPTEE_SMC_RETURN_OK ) { + free_shm_rpc(ctx, regpair_to_uint64(resp.a1, resp.a2)); set_user_reg(regs, 1, resp.a1); set_user_reg(regs, 2, resp.a2); }