Received: by 2002:a05:6a10:5594:0:0:0:0 with SMTP id ee20csp312955pxb; Mon, 25 Apr 2022 10:25:31 -0700 (PDT) X-Google-Smtp-Source: ABdhPJx9fmWWN0AFIAi1n1K7OhDUuk8G7tktwCWw4uOhcSmellnhPo7QRb+7R1VdozZDmsjFYzNC X-Received: by 2002:a17:902:c78b:b0:15c:e5dc:4f63 with SMTP id w11-20020a170902c78b00b0015ce5dc4f63mr12595843pla.90.1650907531257; Mon, 25 Apr 2022 10:25:31 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1650907531; cv=none; d=google.com; s=arc-20160816; b=IctZ538zHqyOH+HJAP+NxasLEk1aN8/MFj/JAASi3Ja1wZEYhgH34taoBE2N7AMBUD fMfzg2SJ3FR1o0GmQ3u9CBTlHOY6cVnBcroA09trf8cwhowPCn3YxDCB4DaaRsL0sqDZ 79HhYJTG9qi4Ol2mXTuBe769/vIt67YfHWK+/pRwssTTMtf/1kD3jFqpo+XFkTANDeJ3 nIUTeOFv6246fjVkn7dNQDIJxZjJKVNRAMf34L/8gDIAofLX4sDor+IJkceg8erE0i8p 3af/7wasv0zmttlEH9J3n8VKBYaG4xdCiIQhwlizKSqOtjj/PiP4YRIAc1QTG2UvBCUQ 416w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=scNNecAxK89bCsIv0vpIcsFL1bTqr463ACa9Pmhvay4=; b=dDMEM4KIoDMPHk91ucQdYqW9ggTt6a4/uLh5++HUNtv/0dwkt3wnLBnwLiVZC9YCUZ yLRxkAsgQd4RGUGVpXqIpEhv1MV8Wpp+h3wtSBDTXsdNyMgrgHfH93USySR8tg8aECDw fLkOgRxWVWf3Nfggtf4Ny5UHsK2q0vG5FsAenmWuEzN/xq7+9tiirqOvxekfIBtL7H5u p6BmkFQZrKpnff2wqSopFhSlr89ONnbflQShLnqvls/R7ANECspVVcwzzd+FL3FcKZJE WYEBK146FgHWQueQDtToxu5nZo58yjILByrjgmMflsr4H0KUVa2eMVH6upoSDwerAlEv tFPA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@eclypsium.com header.s=google header.b="Xwe/HZQ7"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=eclypsium.com Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id t21-20020a17090aba9500b001d952fffcfcsi2575470pjr.31.2022.04.25.10.25.14; Mon, 25 Apr 2022 10:25:31 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@eclypsium.com header.s=google header.b="Xwe/HZQ7"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=eclypsium.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S243868AbiDYRT7 (ORCPT + 99 others); Mon, 25 Apr 2022 13:19:59 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39016 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S243890AbiDYRTc (ORCPT ); Mon, 25 Apr 2022 13:19:32 -0400 Received: from mail-oi1-x235.google.com (mail-oi1-x235.google.com [IPv6:2607:f8b0:4864:20::235]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AD4FD27B1D for ; Mon, 25 Apr 2022 10:16:03 -0700 (PDT) Received: by mail-oi1-x235.google.com with SMTP id b188so17797764oia.13 for ; Mon, 25 Apr 2022 10:16:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=eclypsium.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=scNNecAxK89bCsIv0vpIcsFL1bTqr463ACa9Pmhvay4=; b=Xwe/HZQ7QWugCsF4WnCrUGpuXwV1gaK3ZKZdlbT70p+37ejUk3CLqzzzPcu5CNkCLf CGrax6l11PoWQUWAiqepna03GEHKQuPCaABKVFzgk1+QB6dKZPw49cMsm2dI7OipMjGf 4p3gpErYOE85yNl37xI80+X0kBuIv8a27lPKf1GrFBbjhxbzGv6Ff97rQZQLsW4P5MBp 4dhjSTORIXAlRYu7rKmo5mqF78SpA5YnhC42lifS4/WCQAGP8Z0cVIe2jdgK6Ds0IgOv 9U7YRa3Dd0uYubs5wbYMhhiw+1OBoJ0kh1nuJi6TtmpkxTeJ4ecWP8jBdria2LZdCbkW fkMA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=scNNecAxK89bCsIv0vpIcsFL1bTqr463ACa9Pmhvay4=; b=4iyBOcIRBp5mvQKtMR+UWy8OPXuhFKzylsRM/31nAy9RuFaMjZek8JxPtAH1OhRkDn ZyPYHJnn4BY7v3sA9nPwGu6kOhRxqKj/brU9KrqK3ORegsjLn/miuhm8tKFidt1pOTzQ ZjPIBC4gPmkI3KikS/Wtrep6vwTO1dpFA/mkBs0z5pyRSE9estBu1vahRgIaRfBBnIqw FRV3gCM0cFSVAuUZmZPqle1ZSqx8gt0pLX8wUoYhEMMQDpUv78bFsFqN/YPRTUpofZNu wLTsKVw5xz1O5W+uAge13GKL203UrS5cbanryooO/Dj7g/uoCR45zq4aPvAgYBUvIZnP rJnQ== X-Gm-Message-State: AOAM530CVOl7cB+hHL8L7XS3GYsE0LP05GfrWB3wqUYpqy6rUhOwn6Cx ED/VJDj8IP3ukgHnEhaUkM3beIHN6KSAi3/wputqWPH+KRflXnuus2gU5NOSqYr/mra/oG6CouJ v7VazOqNWqXuM31alTeHSIvG1rKzghNdQEmrNWDFd/cJI4LgNe74ewaMr7elo7yzw0Jl0OsFAPK dQLMYYivOUGgQ4ghrF8g4QDA== X-Received: by 2002:aca:bd41:0:b0:2ec:ff42:814f with SMTP id n62-20020acabd41000000b002ecff42814fmr8838220oif.63.1650906961998; Mon, 25 Apr 2022 10:16:01 -0700 (PDT) Received: from localhost ([181.97.174.128]) by smtp.gmail.com with ESMTPSA id 1-20020a05687011c100b000de98359b43sm3502824oav.1.2022.04.25.10.15.56 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 25 Apr 2022 10:16:01 -0700 (PDT) From: Martin Fernandez To: linux-kernel@vger.kernel.org, linux-efi@vger.kernel.org, platform-driver-x86@vger.kernel.org, linux-mm@kvack.org Cc: tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org, hpa@zytor.com, ardb@kernel.org, dvhart@infradead.org, andy@infradead.org, gregkh@linuxfoundation.org, rafael@kernel.org, rppt@kernel.org, akpm@linux-foundation.org, daniel.gutson@eclypsium.com, hughsient@gmail.com, alex.bazhaniuk@eclypsium.com, alison.schofield@intel.com, keescook@chromium.org, Martin Fernandez Subject: [PATCH v7 3/8] x86/e820: Add infrastructure to refactor e820__range_{update,remove} Date: Mon, 25 Apr 2022 14:15:21 -0300 Message-Id: <20220425171526.44925-4-martin.fernandez@eclypsium.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220425171526.44925-1-martin.fernandez@eclypsium.com> References: <20220425171526.44925-1-martin.fernandez@eclypsium.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org __e820__range_update and e820__range_remove had a very similar flow in its implementation with a few lines different from each other, the lines that actually perform the modification over the e820_table. The similiraties were found in the checks for the different cases on how each entry intersects with the given range (if it does at all). These checks were very presice and error prone so it was not a good idea to have them in both places. Since I need to add a third one, similar to this two, in this and the following patches I'll propose a refactor of these functions. In this patch I introduce: - A new type e820_entry_updater that will carry three callbacks, those callbacks will decide WHEN to perform actions over the e820_table and WHAY actions are going to be performed. Note that there is a void pointer "data". This pointer will carry useful information for the callbacks, like the type that we want to update in e820__range_update or if we want to check the type in e820__range_remove. Check it out in the next patches where I do the rework of __e820__range_update and e820__range_remove. - A new function __e820__handle_range_update that has the flow of the original two functions to refactor. Together with e820_entry_updater will perform the desired update on the input table. On version 6 of this patch some people pointed out that this solution was over-complicated. Mike Rapoport suggested a another solution [1]. I took a look at that, and although it is indeed simpler it's more confusing at the same time. I think is manageable to have a single function to update or remove sections of the table (what Mike did), but when I added the functionality to also update the crypto_capable it became really hard to manage. I think that the approach presented in this patch it's complex but is easier to read, to extend and to test. [1] https://git.kernel.org/rppt/h/x86/e820-update-range Signed-off-by: Martin Fernandez --- arch/x86/kernel/e820.c | 148 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c index f267205f2d5a..923585ab8377 100644 --- a/arch/x86/kernel/e820.c +++ b/arch/x86/kernel/e820.c @@ -459,6 +459,154 @@ static int __init append_e820_table(struct boot_e820_entry *entries, u32 nr_entr return __append_e820_table(entries, nr_entries); } +/** + * struct e820_entry_updater - Helper type for + * __e820__handle_range_update(). + * @should_update: Return true if @entry needs to be updated, false + * otherwise. + * @update: Apply desired actions to an @entry that is inside the + * range and satisfies @should_update. + * @new: Create new entry in the table with information gathered from + * @original and @data. + * + * Each function corresponds to an action that + * __e820__handle_range_update() does. Callbacks need to cast @data back + * to the corresponding type. + */ +struct e820_entry_updater { + bool (*should_update)(const struct e820_entry *entry, const void *data); + void (*update)(struct e820_entry *entry, const void *data); + void (*new)(struct e820_table *table, u64 new_start, u64 new_size, + const struct e820_entry *original, const void *data); +}; + +/** + * __e820__handle_intersected_range_update() - Helper function for + * __e820__handle_range_update(). + * @table: Target e820_table. + * @start: Start of the range. + * @size: Size of the range. + * @entry: Current entry that __e820__handle_range_update() was + * looking into. + * @updater: updater parameter of __e820__handle_range_update(). + * @data: data parameter of __e820__handle_range_update(). + * + * Helper for __e820__handle_range_update to handle the case where + * neither the entry completely covers the range nor the range + * completely covers the entry. + * + * Return: The updated size. + */ +static u64 __init +__e820__handle_intersected_range_update(struct e820_table *table, + u64 start, + u64 size, + struct e820_entry *entry, + const struct e820_entry_updater *updater, + const void *data) +{ + u64 end; + u64 entry_end = entry->addr + entry->size; + u64 inner_start; + u64 inner_end; + u64 updated_size = 0; + + if (size > (ULLONG_MAX - start)) + size = ULLONG_MAX - start; + + end = start + size; + inner_start = max(start, entry->addr); + inner_end = min(end, entry_end); + + /* Range and entry do intersect and... */ + if (inner_start < inner_end) { + /* Entry is on the left */ + if (entry->addr < inner_start) { + /* Resize current entry */ + entry->size = inner_start - entry->addr; + /* Entry is on the right */ + } else { + /* Resize and move current section */ + entry->addr = inner_end; + entry->size = entry_end - inner_end; + } + /* Create new entry with intersected region */ + updater->new(table, inner_start, inner_end - inner_start, entry, data); + + updated_size += inner_end - inner_start; + } /* Else: [start, end) doesn't cover entry */ + + return updated_size; +} + +/** + * __e820__handle_range_update(): Helper function to update an address + * range in a e820_table + * @table: e820_table that we want to modify. + * @start: Start of the range. + * @size: Size of the range. + * @updater: Callbacks to modify the table. + * @data: Information to modify the table. This must be an struct + * e820_type_*_data. + * + * Update the table @table in [@start, @start + @size) doing the + * actions given in @updater. + * + * Return: The updated size. + */ +static u64 __init +__e820__handle_range_update(struct e820_table *table, + u64 start, + u64 size, + const struct e820_entry_updater *updater, + const void *data) +{ + u64 updated_size = 0; + u64 end; + unsigned int i; + + if (size > (ULLONG_MAX - start)) + size = ULLONG_MAX - start; + + end = start + size; + + for (i = 0; i < table->nr_entries; i++) { + struct e820_entry *entry = &table->entries[i]; + u64 entry_end = entry->addr + entry->size; + + if (updater->should_update(entry, data)) { + /* Range completely covers entry */ + if (entry->addr >= start && entry_end <= end) { + updated_size += entry->size; + updater->update(entry, data); + /* Entry completely covers range */ + } else if (start > entry->addr && end < entry_end) { + /* Resize current entry */ + entry->size = start - entry->addr; + + /* Create new entry with intersection region */ + updater->new(table, start, size, entry, data); + + /* + * Create a new entry for the leftover + * of the current entry + */ + __e820__range_add(table, end, entry_end - end, + entry->type, + entry->crypto_capable); + + updated_size += size; + } else { + updated_size += + __e820__handle_intersected_range_update(table, start, size, + entry, updater, data); + } + } + } + + return updated_size; +} + static u64 __init __e820__range_update(struct e820_table *table, u64 start, u64 size, enum e820_type old_type, enum e820_type new_type) { -- 2.30.2