From patchwork Mon Dec 17 20:08:21 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Goldschmidt X-Patchwork-Id: 1014739 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="moEBZslX"; dkim-atps=neutral Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 43JXKY4n0Wz9s1c for ; Tue, 18 Dec 2018 07:08:49 +1100 (AEDT) Received: by lists.denx.de (Postfix, from userid 105) id 5CD4AC221B1; Mon, 17 Dec 2018 20:08:46 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=FREEMAIL_FROM, RCVD_IN_MSPIKE_H2, T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 4A975C21E96; Mon, 17 Dec 2018 20:08:42 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 3D9B5C21FD2; Mon, 17 Dec 2018 20:08:39 +0000 (UTC) Received: from mail-wr1-f68.google.com (mail-wr1-f68.google.com [209.85.221.68]) by lists.denx.de (Postfix) with ESMTPS id A721CC21E96 for ; Mon, 17 Dec 2018 20:08:38 +0000 (UTC) Received: by mail-wr1-f68.google.com with SMTP id t27so13612608wra.6 for ; Mon, 17 Dec 2018 12:08:38 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=A/BRqxxnqzBaMZhqEVMK4iHPJ5Kcs2SOKv7siC2qMdc=; b=moEBZslXotkYSlvDCvguvqaGlMRRra3ppkGADVdGIsyUoSAkxJJDfOuRk2DZpPob3q bPWmkyU7aLazvtYQ7DAg0KI+ETsl712FXxvGm10vmnLRNds/1zTWsyrnn+sNcZ+5XMcb N4NYVVjI+UCyu0VqWhWKxrNHksHcupB39dzC79Ct2fQl25TEkGDgjZ3u1VMtT4tnznTF dFb1MZ7SXUJaOC0keoWmDxfz0p5B/am7p/B+wojIf4pcY9xWjcXivEPUmjDnniA3bZMI XWpemghVi+fIn0M+ORsN1ZBzbqhV+NOdmdCOaXPC+thdi9mWj6VubT13qJHXEDSIVUq0 k2wQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=A/BRqxxnqzBaMZhqEVMK4iHPJ5Kcs2SOKv7siC2qMdc=; b=F3shwXu2L7+dAAwKcGsTgqtAJHEXVAo2b2DheWYL8YeHdD/bh8+So+seM/qq+0j9ut GUzybnoix5J+XIpAeVo4NbiCxU3cJ9mW+itRIDrJElRbirOCNYIz7M0DSIkSpSVkmBHT /C90NJgyVOozLlsRA4pUMv+G0Nn2TY4SsyBRVl2Hdo5TMO+taYzfWQzPp9wffcQYwWiY 4qz5qd2v9B1mNwTU+KWRtr55WKrjjO8mHsmztbyButOatC4nQ3NHce049ihYnVDEq5Tw WsQa8sm12CNEPcdcL5SU0wzAe36Zst8cpOBIn7UfTeD53xiLd7kDeKG+bm4LsTKZVBV4 1+CQ== X-Gm-Message-State: AA+aEWZGuWV1PQ77zbEL4vHLsfHtOAKaw7PZKLC9ts1jtszmnNGprkAr 2C/Wit3xf+GVbQ+/QAdY2nsc3SKwSsA= X-Google-Smtp-Source: AFSGD/VdgHH5IBP8h9p3zjbEredScrKkHJGJ+6hZi5nWA9HVZmx/dbbkwytx99YevR+GUq3NRrohcg== X-Received: by 2002:adf:b649:: with SMTP id i9mr12422770wre.70.1545077318072; Mon, 17 Dec 2018 12:08:38 -0800 (PST) Received: from ubuntu.home ([2a02:8071:6a3:700:80b1:ba3d:111a:23c5]) by smtp.gmail.com with ESMTPSA id q9sm1066472wrv.26.2018.12.17.12.08.36 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 17 Dec 2018 12:08:37 -0800 (PST) From: Simon Goldschmidt To: Tom Rini , u-boot@lists.denx.de, Joe Hershberger Date: Mon, 17 Dec 2018 21:08:21 +0100 Message-Id: <20181217200830.32585-2-simon.k.r.goldschmidt@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181217200830.32585-1-simon.k.r.goldschmidt@gmail.com> References: <20181217200830.32585-1-simon.k.r.goldschmidt@gmail.com> Cc: Heinrich Schuchardt , Andrea Barisani Subject: [U-Boot] [PATCH v8 01/10] test: add test for lib/lmb.c X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" Add basic tests for the lmb memory allocation code used to reserve and allocate memory during boot. Signed-off-by: Simon Goldschmidt --- Changes in v8: None Changes in v7: None Changes in v6: None Changes in v5: - this patch is new in v5 Changes in v4: None Changes in v2: None test/lib/Makefile | 1 + test/lib/lmb.c | 297 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 298 insertions(+) create mode 100644 test/lib/lmb.c diff --git a/test/lib/Makefile b/test/lib/Makefile index ea68fae566..5a636aac74 100644 --- a/test/lib/Makefile +++ b/test/lib/Makefile @@ -3,3 +3,4 @@ # (C) Copyright 2018 # Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc obj-y += hexdump.o +obj-y += lmb.o diff --git a/test/lib/lmb.c b/test/lib/lmb.c new file mode 100644 index 0000000000..dd7ba14b34 --- /dev/null +++ b/test/lib/lmb.c @@ -0,0 +1,297 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2018 Simon Goldschmidt + */ + +#include +#include +#include +#include + +static int check_lmb(struct unit_test_state *uts, struct lmb *lmb, + phys_addr_t ram_base, phys_size_t ram_size, + unsigned long num_reserved, + phys_addr_t base1, phys_size_t size1, + phys_addr_t base2, phys_size_t size2, + phys_addr_t base3, phys_size_t size3) +{ + ut_asserteq(lmb->memory.cnt, 1); + ut_asserteq(lmb->memory.region[0].base, ram_base); + ut_asserteq(lmb->memory.region[0].size, ram_size); + + ut_asserteq(lmb->reserved.cnt, num_reserved); + if (num_reserved > 0) { + ut_asserteq(lmb->reserved.region[0].base, base1); + ut_asserteq(lmb->reserved.region[0].size, size1); + } + if (num_reserved > 1) { + ut_asserteq(lmb->reserved.region[1].base, base2); + ut_asserteq(lmb->reserved.region[1].size, size2); + } + if (num_reserved > 2) { + ut_asserteq(lmb->reserved.region[2].base, base3); + ut_asserteq(lmb->reserved.region[2].size, size3); + } + return 0; +} + +#define ASSERT_LMB(lmb, ram_base, ram_size, num_reserved, base1, size1, \ + base2, size2, base3, size3) \ + ut_assert(!check_lmb(uts, lmb, ram_base, ram_size, \ + num_reserved, base1, size1, base2, size2, base3, \ + size3)) + +/* + * Test helper function that reserves 64 KiB somewhere in the simulated RAM and + * then does some alloc + free tests. + */ +static int test_multi_alloc(struct unit_test_state *uts, + const phys_addr_t ram, const phys_size_t ram_size, + const phys_addr_t alloc_64k_addr) +{ + const phys_addr_t ram_end = ram + ram_size; + const phys_addr_t alloc_64k_end = alloc_64k_addr + 0x10000; + + struct lmb lmb; + long ret; + phys_addr_t a, a2, b, b2, c, d; + + /* check for overflow */ + ut_assert(ram_end == 0 || ram_end > ram); + ut_assert(alloc_64k_end > alloc_64k_addr); + /* check input addresses + size */ + ut_assert(alloc_64k_addr >= ram + 8); + ut_assert(alloc_64k_end <= ram_end - 8); + + lmb_init(&lmb); + + ret = lmb_add(&lmb, ram, ram_size); + ut_asserteq(ret, 0); + + /* reserve 64KiB somewhere */ + ret = lmb_reserve(&lmb, alloc_64k_addr, 0x10000); + ut_asserteq(ret, 0); + ASSERT_LMB(&lmb, ram, ram_size, 1, alloc_64k_addr, 0x10000, + 0, 0, 0, 0); + + /* allocate somewhere, should be at the end of RAM */ + a = lmb_alloc(&lmb, 4, 1); + ut_asserteq(a, ram_end - 4); + ASSERT_LMB(&lmb, ram, ram_size, 2, alloc_64k_addr, 0x10000, + ram_end - 4, 4, 0, 0); + /* alloc below end of reserved region -> below reserved region */ + b = lmb_alloc_base(&lmb, 4, 1, alloc_64k_end); + ut_asserteq(b, alloc_64k_addr - 4); + ASSERT_LMB(&lmb, ram, ram_size, 2, + alloc_64k_addr - 4, 0x10000 + 4, ram_end - 4, 4, 0, 0); + + /* 2nd time */ + c = lmb_alloc(&lmb, 4, 1); + ut_asserteq(c, ram_end - 8); + ASSERT_LMB(&lmb, ram, ram_size, 2, + alloc_64k_addr - 4, 0x10000 + 4, ram_end - 8, 8, 0, 0); + d = lmb_alloc_base(&lmb, 4, 1, alloc_64k_end); + ut_asserteq(d, alloc_64k_addr - 8); + ASSERT_LMB(&lmb, ram, ram_size, 2, + alloc_64k_addr - 8, 0x10000 + 8, ram_end - 8, 8, 0, 0); + + ret = lmb_free(&lmb, a, 4); + ut_asserteq(ret, 0); + ASSERT_LMB(&lmb, ram, ram_size, 2, + alloc_64k_addr - 8, 0x10000 + 8, ram_end - 8, 4, 0, 0); + /* allocate again to ensure we get the same address */ + a2 = lmb_alloc(&lmb, 4, 1); + ut_asserteq(a, a2); + ASSERT_LMB(&lmb, ram, ram_size, 2, + alloc_64k_addr - 8, 0x10000 + 8, ram_end - 8, 8, 0, 0); + ret = lmb_free(&lmb, a2, 4); + ut_asserteq(ret, 0); + ASSERT_LMB(&lmb, ram, ram_size, 2, + alloc_64k_addr - 8, 0x10000 + 8, ram_end - 8, 4, 0, 0); + + ret = lmb_free(&lmb, b, 4); + ut_asserteq(ret, 0); + ASSERT_LMB(&lmb, ram, ram_size, 3, + alloc_64k_addr - 8, 4, alloc_64k_addr, 0x10000, + ram_end - 8, 4); + /* allocate again to ensure we get the same address */ + b2 = lmb_alloc_base(&lmb, 4, 1, alloc_64k_end); + ut_asserteq(b, b2); + ASSERT_LMB(&lmb, ram, ram_size, 2, + alloc_64k_addr - 8, 0x10000 + 8, ram_end - 8, 4, 0, 0); + ret = lmb_free(&lmb, b2, 4); + ut_asserteq(ret, 0); + ASSERT_LMB(&lmb, ram, ram_size, 3, + alloc_64k_addr - 8, 4, alloc_64k_addr, 0x10000, + ram_end - 8, 4); + + ret = lmb_free(&lmb, c, 4); + ut_asserteq(ret, 0); + ASSERT_LMB(&lmb, ram, ram_size, 2, + alloc_64k_addr - 8, 4, alloc_64k_addr, 0x10000, 0, 0); + ret = lmb_free(&lmb, d, 4); + ut_asserteq(ret, 0); + ASSERT_LMB(&lmb, ram, ram_size, 1, alloc_64k_addr, 0x10000, + 0, 0, 0, 0); + + return 0; +} + +static int test_multi_alloc_512mb(struct unit_test_state *uts, + const phys_addr_t ram) +{ + return test_multi_alloc(uts, ram, 0x20000000, ram + 0x10000000); +} + +/* Create a memory region with one reserved region and allocate */ +static int lib_test_lmb_simple(struct unit_test_state *uts) +{ + /* simulate 512 MiB RAM beginning at 1GiB */ + return test_multi_alloc_512mb(uts, 0x40000000); +} + +DM_TEST(lib_test_lmb_simple, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Simulate 512 MiB RAM, allocate some blocks that fit/don't fit */ +static int test_bigblock(struct unit_test_state *uts, const phys_addr_t ram) +{ + const phys_size_t ram_size = 0x20000000; + const phys_size_t big_block_size = 0x10000000; + const phys_addr_t ram_end = ram + ram_size; + const phys_addr_t alloc_64k_addr = ram + 0x10000000; + struct lmb lmb; + long ret; + phys_addr_t a, b; + + /* check for overflow */ + ut_assert(ram_end == 0 || ram_end > ram); + + lmb_init(&lmb); + + ret = lmb_add(&lmb, ram, ram_size); + ut_asserteq(ret, 0); + + /* reserve 64KiB in the middle of RAM */ + ret = lmb_reserve(&lmb, alloc_64k_addr, 0x10000); + ut_asserteq(ret, 0); + ASSERT_LMB(&lmb, ram, ram_size, 1, alloc_64k_addr, 0x10000, + 0, 0, 0, 0); + + /* allocate a big block, should be below reserved */ + a = lmb_alloc(&lmb, big_block_size, 1); + ut_asserteq(a, ram); + ASSERT_LMB(&lmb, ram, ram_size, 1, a, + big_block_size + 0x10000, 0, 0, 0, 0); + /* allocate 2nd big block */ + /* This should fail, printing an error */ + b = lmb_alloc(&lmb, big_block_size, 1); + ut_asserteq(b, 0); + ASSERT_LMB(&lmb, ram, ram_size, 1, a, + big_block_size + 0x10000, 0, 0, 0, 0); + + ret = lmb_free(&lmb, a, big_block_size); + ut_asserteq(ret, 0); + ASSERT_LMB(&lmb, ram, ram_size, 1, alloc_64k_addr, 0x10000, + 0, 0, 0, 0); + + /* allocate too big block */ + /* This should fail, printing an error */ + a = lmb_alloc(&lmb, ram_size, 1); + ut_asserteq(a, 0); + ASSERT_LMB(&lmb, ram, ram_size, 1, alloc_64k_addr, 0x10000, + 0, 0, 0, 0); + + return 0; +} + +static int lib_test_lmb_big(struct unit_test_state *uts) +{ + return test_bigblock(uts, 0x40000000); +} + +DM_TEST(lib_test_lmb_big, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Simulate 512 MiB RAM, allocate a block without previous reservation */ +static int test_noreserved(struct unit_test_state *uts, const phys_addr_t ram) +{ + const phys_size_t ram_size = 0x20000000; + const phys_addr_t ram_end = ram + ram_size; + struct lmb lmb; + long ret; + phys_addr_t a, b; + + /* check for overflow */ + ut_assert(ram_end == 0 || ram_end > ram); + + lmb_init(&lmb); + + ret = lmb_add(&lmb, ram, ram_size); + ut_asserteq(ret, 0); + + /* allocate a block */ + a = lmb_alloc(&lmb, 4, 1); + ut_assert(a != 0); + /* and free it */ + ret = lmb_free(&lmb, a, 4); + ut_asserteq(ret, 0); + + /* allocate a block with base*/ + b = lmb_alloc_base(&lmb, 4, 1, ram_end); + ut_assert(a == b); + /* and free it */ + ret = lmb_free(&lmb, b, 4); + ut_asserteq(ret, 0); + + return 0; +} + +static int lib_test_lmb_noreserved(struct unit_test_state *uts) +{ + return test_noreserved(uts, 0x40000000); +} + +DM_TEST(lib_test_lmb_noreserved, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* + * Simulate a RAM that starts at 0 and allocate down to address 0, which must + * fail as '0' means failure for the lmb_alloc functions. + */ +static int lib_test_lmb_at_0(struct unit_test_state *uts) +{ + const phys_addr_t ram = 0; + const phys_size_t ram_size = 0x20000000; + struct lmb lmb; + long ret; + phys_addr_t a, b; + + lmb_init(&lmb); + + ret = lmb_add(&lmb, ram, ram_size); + ut_asserteq(ret, 0); + + /* allocate nearly everything */ + a = lmb_alloc(&lmb, ram_size - 4, 1); + ut_asserteq(a, ram + 4); + ASSERT_LMB(&lmb, ram, ram_size, 1, a, ram_size - 4, + 0, 0, 0, 0); + /* allocate the rest */ + /* This should fail as the allocated address would be 0 */ + b = lmb_alloc(&lmb, 4, 1); + ut_asserteq(b, 0); + /* check that this was an error by checking lmb */ + ASSERT_LMB(&lmb, ram, ram_size, 1, a, ram_size - 4, + 0, 0, 0, 0); + /* check that this was an error by freeing b */ + ret = lmb_free(&lmb, b, 4); + ut_asserteq(ret, -1); + ASSERT_LMB(&lmb, ram, ram_size, 1, a, ram_size - 4, + 0, 0, 0, 0); + + ret = lmb_free(&lmb, a, ram_size - 4); + ut_asserteq(ret, 0); + ASSERT_LMB(&lmb, ram, ram_size, 0, 0, 0, 0, 0, 0, 0); + + return 0; +} + +DM_TEST(lib_test_lmb_at_0, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);