From patchwork Mon Aug 19 01:25:25 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Chao Gao X-Patchwork-Id: 11100107 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 8FDB714F7 for ; Mon, 19 Aug 2019 01:23:15 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7FA7D28587 for ; Mon, 19 Aug 2019 01:23:15 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6EC662856D; Mon, 19 Aug 2019 01:23:15 +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.2 required=2.0 tests=BAYES_00,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 C740E2856D for ; Mon, 19 Aug 2019 01:23:14 +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 1hzWN0-0001Qq-O9; Mon, 19 Aug 2019 01:22:02 +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 1hzWMz-0001Px-RL for xen-devel@lists.xenproject.org; Mon, 19 Aug 2019 01:22:01 +0000 X-Inumbo-ID: bebbd22c-c21f-11e9-8be6-12813bfff9fa Received: from mga03.intel.com (unknown [134.134.136.65]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id bebbd22c-c21f-11e9-8be6-12813bfff9fa; Mon, 19 Aug 2019 01:22:01 +0000 (UTC) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga103.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 18 Aug 2019 18:22:01 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.64,403,1559545200"; d="scan'208";a="261683947" Received: from gao-cwp.sh.intel.com ([10.239.159.26]) by orsmga001.jf.intel.com with ESMTP; 18 Aug 2019 18:21:59 -0700 From: Chao Gao To: xen-devel@lists.xenproject.org Date: Mon, 19 Aug 2019 09:25:25 +0800 Message-Id: <1566177928-19114-13-git-send-email-chao.gao@intel.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1566177928-19114-1-git-send-email-chao.gao@intel.com> References: <1566177928-19114-1-git-send-email-chao.gao@intel.com> Subject: [Xen-devel] [PATCH v9 12/15] microcode: reduce memory allocation and copy when creating a patch 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: Ashok Raj , Wei Liu , Andrew Cooper , Jan Beulich , Chao Gao , =?utf-8?q?Roger_Pau_Monn=C3=A9?= MIME-Version: 1.0 Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP To create a microcode patch from a vendor-specific update, allocate_microcode_patch() copied everything from the update. It is not efficient. Essentially, we just need to go through ucodes in the blob, find the one with the newest revision and install it into the microcode_patch. In the process, buffers like mc_amd, equiv_cpu_table (on AMD side), and mc (on Intel side) can be reused. microcode_patch now is allocated after it is sure that there is a matching ucode. Signed-off-by: Chao Gao Reviewed-by: Roger Pau Monné --- Changes in v9: - new --- xen/arch/x86/microcode_amd.c | 99 +++++++++++++++--------------------------- xen/arch/x86/microcode_intel.c | 65 ++++++++++----------------- 2 files changed, 58 insertions(+), 106 deletions(-) diff --git a/xen/arch/x86/microcode_amd.c b/xen/arch/x86/microcode_amd.c index 6353323..ec1c2eb 100644 --- a/xen/arch/x86/microcode_amd.c +++ b/xen/arch/x86/microcode_amd.c @@ -194,36 +194,6 @@ static bool match_cpu(const struct microcode_patch *patch) return patch && (microcode_fits(patch->mc_amd) == NEW_UCODE); } -static struct microcode_patch *alloc_microcode_patch( - const struct microcode_amd *mc_amd) -{ - struct microcode_patch *microcode_patch = xmalloc(struct microcode_patch); - struct microcode_amd *cache = xmalloc(struct microcode_amd); - void *mpb = xmalloc_bytes(mc_amd->mpb_size); - struct equiv_cpu_entry *equiv_cpu_table = - xmalloc_bytes(mc_amd->equiv_cpu_table_size); - - if ( !microcode_patch || !cache || !mpb || !equiv_cpu_table ) - { - xfree(microcode_patch); - xfree(cache); - xfree(mpb); - xfree(equiv_cpu_table); - return ERR_PTR(-ENOMEM); - } - - memcpy(mpb, mc_amd->mpb, mc_amd->mpb_size); - cache->mpb = mpb; - cache->mpb_size = mc_amd->mpb_size; - memcpy(equiv_cpu_table, mc_amd->equiv_cpu_table, - mc_amd->equiv_cpu_table_size); - cache->equiv_cpu_table = equiv_cpu_table; - cache->equiv_cpu_table_size = mc_amd->equiv_cpu_table_size; - microcode_patch->mc_amd = cache; - - return microcode_patch; -} - static void free_patch(void *mc) { struct microcode_amd *mc_amd = mc; @@ -320,18 +290,10 @@ static int get_ucode_from_buffer_amd( return -EINVAL; } - if ( mc_amd->mpb_size < mpbuf->len ) - { - if ( mc_amd->mpb ) - { - xfree(mc_amd->mpb); - mc_amd->mpb_size = 0; - } - mc_amd->mpb = xmalloc_bytes(mpbuf->len); - if ( mc_amd->mpb == NULL ) - return -ENOMEM; - mc_amd->mpb_size = mpbuf->len; - } + mc_amd->mpb = xmalloc_bytes(mpbuf->len); + if ( mc_amd->mpb == NULL ) + return -ENOMEM; + mc_amd->mpb_size = mpbuf->len; memcpy(mc_amd->mpb, mpbuf->data, mpbuf->len); pr_debug("microcode: CPU%d size %zu, block size %u offset %zu equivID %#x rev %#x\n", @@ -451,8 +413,9 @@ static struct microcode_patch *cpu_request_microcode(const void *buf, size_t bufsize) { struct microcode_amd *mc_amd; + struct microcode_header_amd *saved = NULL; struct microcode_patch *patch = NULL; - size_t offset = 0; + size_t offset = 0, saved_size = 0; int error = 0; unsigned int current_cpu_id; unsigned int equiv_cpu_id; @@ -542,29 +505,21 @@ static struct microcode_patch *cpu_request_microcode(const void *buf, while ( (error = get_ucode_from_buffer_amd(mc_amd, buf, bufsize, &offset)) == 0 ) { - struct microcode_patch *new_patch = alloc_microcode_patch(mc_amd); - - if ( IS_ERR(new_patch) ) - { - error = PTR_ERR(new_patch); - break; - } - /* - * If the new patch covers current CPU, compare patches and store the + * If the new ucode covers current CPU, compare ucodes and store the * one with higher revision. */ - if ( (microcode_fits(new_patch->mc_amd) != MIS_UCODE) && - (!patch || (compare_patch(new_patch, patch) == NEW_UCODE)) ) +#define REV_ID(mpb) (((struct microcode_header_amd *)(mpb))->processor_rev_id) + if ( (microcode_fits(mc_amd) != MIS_UCODE) && + (!saved || (REV_ID(mc_amd->mpb) > REV_ID(saved))) ) +#undef REV_ID { - struct microcode_patch *tmp = patch; - - patch = new_patch; - new_patch = tmp; + xfree(saved); + saved = mc_amd->mpb; + saved_size = mc_amd->mpb_size; } - - if ( new_patch ) - microcode_free_patch(new_patch); + else + xfree(mc_amd->mpb); if ( offset >= bufsize ) break; @@ -593,9 +548,25 @@ static struct microcode_patch *cpu_request_microcode(const void *buf, *(const uint32_t *)(buf + offset) == UCODE_MAGIC ) break; } - xfree(mc_amd->mpb); - xfree(mc_amd->equiv_cpu_table); - xfree(mc_amd); + + if ( saved ) + { + mc_amd->mpb = saved; + mc_amd->mpb_size = saved_size; + patch = xmalloc(struct microcode_patch); + if ( patch ) + patch->mc_amd = mc_amd; + else + { + free_patch(mc_amd); + error = -ENOMEM; + } + } + else + { + mc_amd->mpb = NULL; + free_patch(mc_amd); + } out: if ( error && !patch ) diff --git a/xen/arch/x86/microcode_intel.c b/xen/arch/x86/microcode_intel.c index 96b38f8..ae5759f 100644 --- a/xen/arch/x86/microcode_intel.c +++ b/xen/arch/x86/microcode_intel.c @@ -282,25 +282,6 @@ static enum microcode_match_result compare_patch( OLD_UCODE; } -static struct microcode_patch *alloc_microcode_patch( - const struct microcode_header_intel *mc_header) -{ - unsigned long total_size = get_totalsize(mc_header); - void *new_mc = xmalloc_bytes(total_size); - struct microcode_patch *new_patch = xmalloc(struct microcode_patch); - - if ( !new_patch || !new_mc ) - { - xfree(new_patch); - xfree(new_mc); - return ERR_PTR(-ENOMEM); - } - memcpy(new_mc, mc_header, total_size); - new_patch->mc_intel = new_mc; - - return new_patch; -} - static int apply_microcode(const struct microcode_patch *patch) { unsigned long flags; @@ -379,47 +360,47 @@ static struct microcode_patch *cpu_request_microcode(const void *buf, { long offset = 0; int error = 0; - void *mc; + struct microcode_intel *mc, *saved = NULL; struct microcode_patch *patch = NULL; - while ( (offset = get_next_ucode_from_buffer(&mc, buf, size, offset)) > 0 ) + while ( (offset = get_next_ucode_from_buffer((void **)&mc, buf, + size, offset)) > 0 ) { - struct microcode_patch *new_patch; - error = microcode_sanity_check(mc); if ( error ) - break; - - new_patch = alloc_microcode_patch(mc); - if ( IS_ERR(new_patch) ) { - error = PTR_ERR(new_patch); + xfree(mc); break; } /* - * If the new patch covers current CPU, compare patches and store the + * If the new update covers current CPU, compare updates and store the * one with higher revision. */ - if ( (microcode_update_match(&new_patch->mc_intel->hdr) != MIS_UCODE) && - (!patch || (compare_patch(new_patch, patch) == NEW_UCODE)) ) + if ( (microcode_update_match(&mc->hdr) != MIS_UCODE) && + (!saved || (mc->hdr.rev > saved->hdr.rev)) ) { - struct microcode_patch *tmp = patch; - - patch = new_patch; - new_patch = tmp; + xfree(saved); + saved = mc; } - - if ( new_patch ) - microcode_free_patch(new_patch); - - xfree(mc); + else + xfree(mc); } - if ( offset > 0 ) - xfree(mc); if ( offset < 0 ) error = offset; + if ( saved ) + { + patch = xmalloc(struct microcode_patch); + if ( patch ) + patch->mc_intel = saved; + else + { + xfree(saved); + error = -ENOMEM; + } + } + if ( error && !patch ) patch = ERR_PTR(error);