Received: by 2002:ac0:a5b6:0:0:0:0:0 with SMTP id m51-v6csp17216imm; Fri, 25 May 2018 15:05:38 -0700 (PDT) X-Google-Smtp-Source: AB8JxZrts7pPCafFCYqM86Hn1Zwq5Yej/DiNN3YgZzYGyAMi+VzAdY6hpRPupY/1mHZeQQpG8ZjB X-Received: by 2002:a17:902:10c:: with SMTP id 12-v6mr4285476plb.252.1527285938520; Fri, 25 May 2018 15:05:38 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1527285938; cv=none; d=google.com; s=arc-20160816; b=BWxO9zWsPNWl9VZM3JU2Cny9guGEi3cTUXdkgalSBlb/94Dk7+InW4hLJICkZlPMFi 7g9CRKifHT8NV5AbLuDxYByr44Pt5xuD5RfWOmfdF34YCOQm22+HFUlmUEQQxbArcK3n PWjs/dE/bHICekWsn0fHvTB0Ik678TvWOaSDURgadWaNTM7uS0jkcv2W6m5e7CTae+/4 k1jmfJnDEp6dwCAAlYyhgDpqyR3UFRGOexBBdDUy6mr2O2PWjT9KMa2+vbF68PDut9Il CoPrKh7088MTcYBp07Fpd0VlIbM7A+TWNwWK/R+K55ZDAp3M7AFWAwcB9djxompcEHVL WuYA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=FRy8Gcx/a3xVzBb/RWuV+3tQBaYsacDNSsJ5WxAxhuY=; b=vkTeQbda+T0H6XLPoOKAajXEH7bIOrUsTMOwFQSPeB+2cewl8IXCSnSgq+ipnlHxRz Fc9CycjdDecyaKxZqISho/WgJh4B5AlY60ndCYRJ+1Yvq2F3qjIvaSJTj7Vj9WfOuDKc kvZlwGa+/kQB48Nf5WW2nVpM+CbAQZ+iA9AJIQn0SiTCcSK2rruQXKckB3OKs4t9Qiei /6wNu/Wh6wUEyQzKOc1RIcb/jkTLQj7ii7t+YbkCCFbHa5NhY8MqZyv+jk9WOEH7zZaU 4uwGpo3LnlYHVaaBOUiqQsrVaa4KgEofVtNSamr/auDfqXzZFXLS651/ilnYOq0fyzON Rr7A== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id j7-v6si24246692pfj.267.2018.05.25.15.05.23; Fri, 25 May 2018 15:05:38 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1030706AbeEYWFS (ORCPT + 99 others); Fri, 25 May 2018 18:05:18 -0400 Received: from mga01.intel.com ([192.55.52.88]:50944 "EHLO mga01.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1030394AbeEYWFM (ORCPT ); Fri, 25 May 2018 18:05:12 -0400 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by fmsmga101.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 25 May 2018 15:05:12 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.49,441,1520924400"; d="scan'208";a="231749062" Received: from sai-dev-mach.sc.intel.com ([143.183.140.145]) by fmsmga005.fm.intel.com with ESMTP; 25 May 2018 15:05:12 -0700 From: Sai Praneeth Prakhya To: linux-efi@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Sai Praneeth , Lee Chun-Yi , Borislav Petkov , Tony Luck , Will Deacon , Dave Hansen , Mark Rutland , Bhupesh Sharma , Naresh Bhat , Ricardo Neri , Peter Zijlstra , Ravi Shankar , Matt Fleming , Dan Williams , Ard Biesheuvel , Miguel Ojeda Subject: [PATCH V4 2/3] efi: Create efi_rts_wq and efi_queue_work() to invoke all efi_runtime_services() Date: Fri, 25 May 2018 15:05:02 -0700 Message-Id: <1527285903-31799-3-git-send-email-sai.praneeth.prakhya@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1527285903-31799-1-git-send-email-sai.praneeth.prakhya@intel.com> References: <1527285903-31799-1-git-send-email-sai.praneeth.prakhya@intel.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Sai Praneeth When a process requests the kernel to execute any efi_runtime_service(), the requested efi_runtime_service (represented as an identifier) and its arguments are packed into a struct named efi_runtime_work and queued onto work queue named efi_rts_wq. The caller then waits until the work is completed. Introduce some infrastructure: 1. Creating workqueue named efi_rts_wq 2. A macro (efi_queue_work()) that a. Populates efi_runtime_work b. Queues work onto efi_rts_wq and c. Waits until worker thread completes The caller thread has to wait until the worker thread completes, because it depends on the return status of efi_runtime_service() and, in specific cases, the arguments populated by efi_runtime_service(). Some efi_runtime_services() takes a pointer to buffer as an argument and fills up the buffer with requested data. For instance, efi_get_variable() and efi_get_next_variable(). Hence, caller process cannot just post the work and get going. Some facts about efi_runtime_services(): 1. A quick look at all the efi_runtime_services() shows that any efi_runtime_service() has five or less arguments. 2. An argument of efi_runtime_service() can be a value (of any type) or a pointer (of any type). Hence, efi_runtime_work has five void pointers to store these arguments. Signed-off-by: Sai Praneeth Prakhya Suggested-by: Andy Lutomirski Cc: Lee Chun-Yi Cc: Borislav Petkov Cc: Tony Luck Cc: Will Deacon Cc: Dave Hansen Cc: Mark Rutland Cc: Bhupesh Sharma Cc: Naresh Bhat Cc: Ricardo Neri Cc: Peter Zijlstra Cc: Ravi Shankar Cc: Matt Fleming Cc: Dan Williams Cc: Ard Biesheuvel Cc: Miguel Ojeda --- drivers/firmware/efi/efi.c | 14 ++++++ drivers/firmware/efi/runtime-wrappers.c | 85 +++++++++++++++++++++++++++++++++ include/linux/efi.h | 3 ++ 3 files changed, 102 insertions(+) diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 1176af664013..2632294eb33f 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -84,6 +84,8 @@ struct mm_struct efi_mm = { .mmlist = LIST_HEAD_INIT(efi_mm.mmlist), }; +struct workqueue_struct *efi_rts_wq; + static bool disable_runtime; static int __init setup_noefi(char *arg) { @@ -338,6 +340,18 @@ static int __init efisubsys_init(void) return 0; /* + * Since we process only one efi_runtime_service() at a time, an + * ordered workqueue (which creates only one execution context) + * should suffice all our needs. + */ + efi_rts_wq = alloc_ordered_workqueue("efi_rts_wq", 0); + if (!efi_rts_wq) { + pr_err("Creating efi_rts_wq failed, EFI runtime services disabled.\n"); + clear_bit(EFI_RUNTIME_SERVICES, &efi.flags); + return 0; + } + + /* * Clean DUMMY object calls EFI Runtime Service, set_variable(), so * it should be invoked only after efi_rts_wq is ready. */ diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c index ae54870b2788..534bd348feca 100644 --- a/drivers/firmware/efi/runtime-wrappers.c +++ b/drivers/firmware/efi/runtime-wrappers.c @@ -1,6 +1,15 @@ /* * runtime-wrappers.c - Runtime Services function call wrappers * + * Implementation summary: + * ----------------------- + * 1. When user/kernel thread requests to execute efi_runtime_service(), + * enqueue work to efi_rts_wq. + * 2. Caller thread waits for completion until the work is finished + * because it's dependent on the return status and execution of + * efi_runtime_service(). + * For instance, get_variable() and get_next_variable(). + * * Copyright (C) 2014 Linaro Ltd. * * Split off from arch/x86/platform/efi/efi.c @@ -22,6 +31,9 @@ #include #include #include +#include +#include + #include /* @@ -33,6 +45,79 @@ #define __efi_call_virt(f, args...) \ __efi_call_virt_pointer(efi.systab->runtime, f, args) +/* efi_runtime_service() function identifiers */ +enum efi_rts_ids { + GET_TIME, + SET_TIME, + GET_WAKEUP_TIME, + SET_WAKEUP_TIME, + GET_VARIABLE, + GET_NEXT_VARIABLE, + SET_VARIABLE, + SET_VARIABLE_NONBLOCKING, + QUERY_VARIABLE_INFO, + QUERY_VARIABLE_INFO_NONBLOCKING, + GET_NEXT_HIGH_MONO_COUNT, + RESET_SYSTEM, + UPDATE_CAPSULE, + QUERY_CAPSULE_CAPS, +}; + +/* + * efi_runtime_work: Details of EFI Runtime Service work + * @arg<1-5>: EFI Runtime Service function arguments + * @status: Status of executing EFI Runtime Service + * @efi_rts_id: EFI Runtime Service function identifier + * @efi_rts_comp: Struct used for handling completions + */ +struct efi_runtime_work { + void *arg1; + void *arg2; + void *arg3; + void *arg4; + void *arg5; + efi_status_t status; + struct work_struct work; + enum efi_rts_ids efi_rts_id; + struct completion efi_rts_comp; +}; + +/* + * efi_queue_work: Queue efi_runtime_service() and wait until it's done + * @rts: efi_runtime_service() function identifier + * @rts_arg<1-5>: efi_runtime_service() function arguments + * + * Accesses to efi_runtime_services() are serialized by a binary + * semaphore (efi_runtime_lock) and caller waits until the work is + * finished, hence _only_ one work is queued at a time and the caller + * thread waits for completion. + */ +#define efi_queue_work(_rts, _arg1, _arg2, _arg3, _arg4, _arg5) \ +({ \ + struct efi_runtime_work efi_rts_work; \ + efi_rts_work.status = EFI_ABORTED; \ + \ + init_completion(&efi_rts_work.efi_rts_comp); \ + INIT_WORK_ONSTACK(&efi_rts_work.work, efi_call_rts); \ + efi_rts_work.arg1 = _arg1; \ + efi_rts_work.arg2 = _arg2; \ + efi_rts_work.arg3 = _arg3; \ + efi_rts_work.arg4 = _arg4; \ + efi_rts_work.arg5 = _arg5; \ + efi_rts_work.efi_rts_id = _rts; \ + \ + /* \ + * queue_work() returns 0 if work was already on queue, \ + * _ideally_ this should never happen. \ + */ \ + if (queue_work(efi_rts_wq, &efi_rts_work.work)) \ + wait_for_completion(&efi_rts_work.efi_rts_comp); \ + else \ + pr_err("Failed to queue work to efi_rts_wq.\n"); \ + \ + efi_rts_work.status; \ +}) + void efi_call_virt_check_flags(unsigned long flags, const char *call) { unsigned long cur_flags, mismatch; diff --git a/include/linux/efi.h b/include/linux/efi.h index 1b79939d0b1e..8fb1af15be67 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -1654,4 +1654,7 @@ struct linux_efi_tpm_eventlog { extern int efi_tpm_eventlog_init(void); +/* Workqueue to queue EFI Runtime Services */ +extern struct workqueue_struct *efi_rts_wq; + #endif /* _LINUX_EFI_H */ -- 2.7.4