From patchwork Wed Jul 31 18:16:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gregor Haas X-Patchwork-Id: 1967260 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20210309 header.b=EPkmObun; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=nndGNePY; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:3::133; helo=bombadil.infradead.org; envelope-from=opensbi-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=patchwork.ozlabs.org) Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:3::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4WZ0g24tcwz1yfG for ; Thu, 1 Aug 2024 04:17:02 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=ercJi1YdSjLb0aD3GCH+qXT26KZ5xuE4Yzw37LB8TWY=; b=EPkmObununAEIA EOCNzjy8f2qcgTzzw0WyqVgtB6Ig12I+91axQ+4wpR3WaBhdduYY2IZ2ONxqdqMb8Nu80ycFfxP2u NL2L3eii1gMjjTyI1wbj+fL7HFwfaoPMRvSzgPd1T3cCRhZ8hwicqwt2JRqCZmDMGAsC4AGP7nT+2 MtxQ84r9fhCtKelqYYTfffD0wb0V6Wwls2T9ROeT/chT3xAEsaaONHbZItgYKXmKH72b64ogudeHK qI1B48itZO1kYIF7fjs8SBV9pMABuu1YDX40juduPJw0mT5LvT/SXxcdwBtjyBuArMD7YABiSrIHk z/Fcz1K//e4PLArItKeA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.97.1 #2 (Red Hat Linux)) id 1sZDsV-000000026eS-1RJL; Wed, 31 Jul 2024 18:16:47 +0000 Received: from mail-pl1-x62c.google.com ([2607:f8b0:4864:20::62c]) by bombadil.infradead.org with esmtps (Exim 4.97.1 #2 (Red Hat Linux)) id 1sZDsR-000000026cW-0KRa for opensbi@lists.infradead.org; Wed, 31 Jul 2024 18:16:46 +0000 Received: by mail-pl1-x62c.google.com with SMTP id d9443c01a7336-1fc5549788eso46882455ad.1 for ; Wed, 31 Jul 2024 11:16:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1722449802; x=1723054602; darn=lists.infradead.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=pzGPvPAc8iCms8LPkot1g1BHBmp9zel+Wy37/RXW/HQ=; b=nndGNePY8oxD2IB2NaMQ09y9V656rIKFEFt81gMPq6SCQCn9MxjB8vOKXc5CiOpeya 9h46cgDJv/bHlf2Qg5QpdQ/ZuFeC6NGvSvoQ1kuI10upFG5zYg8JiD+kmPErCwORd7DJ XGmNtrZGH31fduzHUTrGSTf/lDyWDkqwids5oAzpEKXs7bTvHsIGz6sM7IJwyVtPIUld TMSroCuUDrX1dA9D3NGB18zdperUq0eftstTC2e6llE3MhAnqFa5KjkfMXzd8YjDDDot +YBGCe5BC2hHgjS5upCSzJW3fmiI/I/1H9XpCHznAKV+QwLbLaduESB/qkoH+eS4vtg2 cZEw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722449802; x=1723054602; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=pzGPvPAc8iCms8LPkot1g1BHBmp9zel+Wy37/RXW/HQ=; b=tL4EYdp7SkuiEjAV2qEuJhtdkUOwZOR50j5zqI1VUakcz8Vqt0RG1QO/Gf0GNkAHuR kLGdL4bEhYqDglSA+5qzZDXsy20TYVjadgMonjrkAG84rkzfOIqk4hgkH7ctbDYQBC+v Uo2DYGZcy+RztU/ZvxzETMOv6dC9E3XKEP35GESMuvKzZtPG/NR2XKzfPd/5BFCnQ31R zzyyRr0xqVvCRQv9TmuKarVnY7AWuPhIbcmF57yFx6Nm2FG1qHa0s4sy6kfL7mzUoPDg vHO1+BGjy9vHSSXdXDSOk4Uxk8Ef75AJpk0u+bczhrIuo21Sw8g4M675+Tu9lGeqO06g FbDw== X-Gm-Message-State: AOJu0YwYvZEldxBJSQ9Ly9yimfrbl7dWqSNd5KRDY+18L99/U3hDBd4x 1zWoOMQU4pDXLPYqGIoNxVXuK0f+SXGvSvIW1qrqBXnW3J4Fjmp5pZMB5vpQ X-Google-Smtp-Source: AGHT+IFbecxc7yS80Hv5e3nt5KQ+MOIZSUGuLeWX8rxKg+TmE/cEa9WIJPdoelewRfPQ0D/agZtrmA== X-Received: by 2002:a17:903:18d:b0:1fb:80cb:f577 with SMTP id d9443c01a7336-1ff4ce337a0mr2267905ad.5.1722449802004; Wed, 31 Jul 2024 11:16:42 -0700 (PDT) Received: from localhost ([136.27.11.53]) by smtp.gmail.com with UTF8SMTPSA id d9443c01a7336-1fed7cfe767sm123283635ad.97.2024.07.31.11.16.41 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Wed, 31 Jul 2024 11:16:41 -0700 (PDT) From: Gregor Haas To: opensbi@lists.infradead.org Cc: atishp@rivosinc.com, Gregor Haas Subject: [PATCH 1/8] lib: sbi: Separate domain-handling code from memregion-handling code Date: Wed, 31 Jul 2024 11:16:22 -0700 Message-ID: <20240731181629.269898-2-gregorhaas1997@gmail.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240731181629.269898-1-gregorhaas1997@gmail.com> References: <20240731181629.269898-1-gregorhaas1997@gmail.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20240731_111643_167574_45EB8FFD X-CRM114-Status: GOOD ( 21.80 ) X-Spam-Score: -1.8 (-) X-Spam-Report: Spam detection software, running on the system "bombadil.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: The next changes in this patch series will add a large amount of functionality to the domain memregion abstraction. Split out memregions from domains, since sbi_domain.c is already almost 900 lines lo [...] Content analysis details: (-1.8 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [2607:f8b0:4864:20:0:0:0:62c listed in] [list.dnswl.org] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] 0.2 FREEMAIL_ENVFROM_END_DIGIT Envelope-from freemail username ends in digit [gregorhaas1997(at)gmail.com] 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider [gregorhaas1997(at)gmail.com] X-BeenThere: opensbi@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "opensbi" Errors-To: opensbi-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org The next changes in this patch series will add a large amount of functionality to the domain memregion abstraction. Split out memregions from domains, since sbi_domain.c is already almost 900 lines long. This commit verbatim moves code without modifying it, except to add new includes and integrate sbi_memregion.c into the build system. --- include/sbi/sbi_domain.h | 184 +--------------------- include/sbi/sbi_memregion.h | 199 ++++++++++++++++++++++++ lib/sbi/objects.mk | 1 + lib/sbi/sbi_domain.c | 296 +---------------------------------- lib/sbi/sbi_memregion.c | 301 ++++++++++++++++++++++++++++++++++++ 5 files changed, 507 insertions(+), 474 deletions(-) create mode 100644 include/sbi/sbi_memregion.h create mode 100644 lib/sbi/sbi_memregion.c diff --git a/include/sbi/sbi_domain.h b/include/sbi/sbi_domain.h index a6e99c6..596bab3 100644 --- a/include/sbi/sbi_domain.h +++ b/include/sbi/sbi_domain.h @@ -14,150 +14,10 @@ #include #include #include +#include struct sbi_scratch; -/** Domain access types */ -enum sbi_domain_access { - SBI_DOMAIN_READ = (1UL << 0), - SBI_DOMAIN_WRITE = (1UL << 1), - SBI_DOMAIN_EXECUTE = (1UL << 2), - SBI_DOMAIN_MMIO = (1UL << 3) -}; - -/** Representation of OpenSBI domain memory region */ -struct sbi_domain_memregion { - /** - * Size of memory region as power of 2 - * It has to be minimum 3 and maximum __riscv_xlen - */ - unsigned long order; - /** - * Base address of memory region - * It must be 2^order aligned address - */ - unsigned long base; - /** Flags representing memory region attributes */ -#define SBI_DOMAIN_MEMREGION_M_READABLE (1UL << 0) -#define SBI_DOMAIN_MEMREGION_M_WRITABLE (1UL << 1) -#define SBI_DOMAIN_MEMREGION_M_EXECUTABLE (1UL << 2) -#define SBI_DOMAIN_MEMREGION_SU_READABLE (1UL << 3) -#define SBI_DOMAIN_MEMREGION_SU_WRITABLE (1UL << 4) -#define SBI_DOMAIN_MEMREGION_SU_EXECUTABLE (1UL << 5) - -#define SBI_DOMAIN_MEMREGION_ACCESS_MASK (0x3fUL) -#define SBI_DOMAIN_MEMREGION_M_ACCESS_MASK (0x7UL) -#define SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK (0x38UL) - -#define SBI_DOMAIN_MEMREGION_SU_ACCESS_SHIFT (3) - -#define SBI_DOMAIN_MEMREGION_SHARED_RDONLY \ - (SBI_DOMAIN_MEMREGION_M_READABLE | \ - SBI_DOMAIN_MEMREGION_SU_READABLE) - -#define SBI_DOMAIN_MEMREGION_SHARED_SUX_MRX \ - (SBI_DOMAIN_MEMREGION_M_READABLE | \ - SBI_DOMAIN_MEMREGION_M_EXECUTABLE | \ - SBI_DOMAIN_MEMREGION_SU_EXECUTABLE) - -#define SBI_DOMAIN_MEMREGION_SHARED_SUX_MX \ - (SBI_DOMAIN_MEMREGION_M_EXECUTABLE | \ - SBI_DOMAIN_MEMREGION_SU_EXECUTABLE) - -#define SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW \ - (SBI_DOMAIN_MEMREGION_M_READABLE | \ - SBI_DOMAIN_MEMREGION_M_WRITABLE | \ - SBI_DOMAIN_MEMREGION_SU_READABLE| \ - SBI_DOMAIN_MEMREGION_SU_WRITABLE) - -#define SBI_DOMAIN_MEMREGION_SHARED_SUR_MRW \ - (SBI_DOMAIN_MEMREGION_M_READABLE | \ - SBI_DOMAIN_MEMREGION_M_WRITABLE | \ - SBI_DOMAIN_MEMREGION_SU_READABLE) - - /* Shared read-only region between M and SU mode */ -#define SBI_DOMAIN_MEMREGION_IS_SUR_MR(__flags) \ - ((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \ - SBI_DOMAIN_MEMREGION_SHARED_RDONLY) - - /* Shared region: SU execute-only and M read/execute */ -#define SBI_DOMAIN_MEMREGION_IS_SUX_MRX(__flags) \ - ((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \ - SBI_DOMAIN_MEMREGION_SHARED_SUX_MRX) - - /* Shared region: SU and M execute-only */ -#define SBI_DOMAIN_MEMREGION_IS_SUX_MX(__flags) \ - ((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \ - SBI_DOMAIN_MEMREGION_SHARED_SUX_MX) - - /* Shared region: SU and M read/write */ -#define SBI_DOMAIN_MEMREGION_IS_SURW_MRW(__flags) \ - ((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \ - SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW) - - /* Shared region: SU read-only and M read/write */ -#define SBI_DOMAIN_MEMREGION_IS_SUR_MRW(__flags) \ - ((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \ - SBI_DOMAIN_MEMREGION_SHARED_SUR_MRW) - - /* - * Check if region flags match with any of the above - * mentioned shared region type - */ -#define SBI_DOMAIN_MEMREGION_IS_SHARED(_flags) \ - (SBI_DOMAIN_MEMREGION_IS_SUR_MR(_flags) || \ - SBI_DOMAIN_MEMREGION_IS_SUX_MRX(_flags) || \ - SBI_DOMAIN_MEMREGION_IS_SUX_MX(_flags) || \ - SBI_DOMAIN_MEMREGION_IS_SURW_MRW(_flags)|| \ - SBI_DOMAIN_MEMREGION_IS_SUR_MRW(_flags)) - -#define SBI_DOMAIN_MEMREGION_M_ONLY_ACCESS(__flags) \ - ((__flags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK) && \ - !(__flags & SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK)) - -#define SBI_DOMAIN_MEMREGION_SU_ONLY_ACCESS(__flags) \ - ((__flags & SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK) && \ - !(__flags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK)) - -/** Bit to control if permissions are enforced on all modes */ -#define SBI_DOMAIN_MEMREGION_ENF_PERMISSIONS (1UL << 6) - -#define SBI_DOMAIN_MEMREGION_M_RWX \ - (SBI_DOMAIN_MEMREGION_M_READABLE | \ - SBI_DOMAIN_MEMREGION_M_WRITABLE | \ - SBI_DOMAIN_MEMREGION_M_EXECUTABLE) - -#define SBI_DOMAIN_MEMREGION_SU_RWX \ - (SBI_DOMAIN_MEMREGION_SU_READABLE | \ - SBI_DOMAIN_MEMREGION_SU_WRITABLE | \ - SBI_DOMAIN_MEMREGION_SU_EXECUTABLE) - -/* Unrestricted M-mode accesses but enfoced on SU-mode */ -#define SBI_DOMAIN_MEMREGION_READABLE \ - (SBI_DOMAIN_MEMREGION_SU_READABLE | \ - SBI_DOMAIN_MEMREGION_M_RWX) -#define SBI_DOMAIN_MEMREGION_WRITEABLE \ - (SBI_DOMAIN_MEMREGION_SU_WRITABLE | \ - SBI_DOMAIN_MEMREGION_M_RWX) -#define SBI_DOMAIN_MEMREGION_EXECUTABLE \ - (SBI_DOMAIN_MEMREGION_SU_EXECUTABLE | \ - SBI_DOMAIN_MEMREGION_M_RWX) - -/* Enforced accesses across all modes */ -#define SBI_DOMAIN_MEMREGION_ENF_READABLE \ - (SBI_DOMAIN_MEMREGION_SU_READABLE | \ - SBI_DOMAIN_MEMREGION_M_READABLE) -#define SBI_DOMAIN_MEMREGION_ENF_WRITABLE \ - (SBI_DOMAIN_MEMREGION_SU_WRITABLE | \ - SBI_DOMAIN_MEMREGION_M_WRITABLE) -#define SBI_DOMAIN_MEMREGION_ENF_EXECUTABLE \ - (SBI_DOMAIN_MEMREGION_SU_EXECUTABLE | \ - SBI_DOMAIN_MEMREGION_M_EXECUTABLE) - -#define SBI_DOMAIN_MEMREGION_MMIO (1UL << 31) - unsigned long flags; -}; - /** Maximum number of domains */ #define SBI_DOMAIN_MAX_INDEX 32 @@ -246,48 +106,6 @@ bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartid); ulong sbi_domain_get_assigned_hartmask(const struct sbi_domain *dom, ulong hbase); -/** - * Initialize a domain memory region based on it's physical - * address and size. - * - * @param addr start physical address of memory region - * @param size physical size of memory region - * @param flags memory region flags - * @param reg pointer to memory region being initialized - */ -void sbi_domain_memregion_init(unsigned long addr, - unsigned long size, - unsigned long flags, - struct sbi_domain_memregion *reg); - -/** - * Check whether we can access specified address for given mode and - * memory region flags under a domain - * @param dom pointer to domain - * @param addr the address to be checked - * @param mode the privilege mode of access - * @param access_flags bitmask of domain access types (enum sbi_domain_access) - * @return true if access allowed otherwise false - */ -bool sbi_domain_check_addr(const struct sbi_domain *dom, - unsigned long addr, unsigned long mode, - unsigned long access_flags); - -/** - * Check whether we can access specified address range for given mode and - * memory region flags under a domain - * @param dom pointer to domain - * @param addr the start of the address range to be checked - * @param size the size of the address range to be checked - * @param mode the privilege mode of access - * @param access_flags bitmask of domain access types (enum sbi_domain_access) - * @return TRUE if access allowed otherwise FALSE - */ -bool sbi_domain_check_addr_range(const struct sbi_domain *dom, - unsigned long addr, unsigned long size, - unsigned long mode, - unsigned long access_flags); - /** Dump domain details on the console */ void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix); diff --git a/include/sbi/sbi_memregion.h b/include/sbi/sbi_memregion.h new file mode 100644 index 0000000..8a62fc0 --- /dev/null +++ b/include/sbi/sbi_memregion.h @@ -0,0 +1,199 @@ + +#ifndef __SBI_MEMREGION_H__ +#define __SBI_MEMREGION_H__ + +#include + +/** Domain access types */ +enum sbi_domain_access { + SBI_DOMAIN_READ = (1UL << 0), + SBI_DOMAIN_WRITE = (1UL << 1), + SBI_DOMAIN_EXECUTE = (1UL << 2), + SBI_DOMAIN_MMIO = (1UL << 3) +}; + +/** Representation of OpenSBI domain memory region */ +struct sbi_domain_memregion { + /** + * Size of memory region as power of 2 + * It has to be minimum 3 and maximum __riscv_xlen + */ + unsigned long order; + /** + * Base address of memory region + * It must be 2^order aligned address + */ + unsigned long base; + /** Flags representing memory region attributes */ +#define SBI_DOMAIN_MEMREGION_M_READABLE (1UL << 0) +#define SBI_DOMAIN_MEMREGION_M_WRITABLE (1UL << 1) +#define SBI_DOMAIN_MEMREGION_M_EXECUTABLE (1UL << 2) +#define SBI_DOMAIN_MEMREGION_SU_READABLE (1UL << 3) +#define SBI_DOMAIN_MEMREGION_SU_WRITABLE (1UL << 4) +#define SBI_DOMAIN_MEMREGION_SU_EXECUTABLE (1UL << 5) + +#define SBI_DOMAIN_MEMREGION_ACCESS_MASK (0x3fUL) +#define SBI_DOMAIN_MEMREGION_M_ACCESS_MASK (0x7UL) +#define SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK (0x38UL) + +#define SBI_DOMAIN_MEMREGION_SU_ACCESS_SHIFT (3) + +#define SBI_DOMAIN_MEMREGION_SHARED_RDONLY \ + (SBI_DOMAIN_MEMREGION_M_READABLE | \ + SBI_DOMAIN_MEMREGION_SU_READABLE) + +#define SBI_DOMAIN_MEMREGION_SHARED_SUX_MRX \ + (SBI_DOMAIN_MEMREGION_M_READABLE | \ + SBI_DOMAIN_MEMREGION_M_EXECUTABLE | \ + SBI_DOMAIN_MEMREGION_SU_EXECUTABLE) + +#define SBI_DOMAIN_MEMREGION_SHARED_SUX_MX \ + (SBI_DOMAIN_MEMREGION_M_EXECUTABLE | \ + SBI_DOMAIN_MEMREGION_SU_EXECUTABLE) + +#define SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW \ + (SBI_DOMAIN_MEMREGION_M_READABLE | \ + SBI_DOMAIN_MEMREGION_M_WRITABLE | \ + SBI_DOMAIN_MEMREGION_SU_READABLE| \ + SBI_DOMAIN_MEMREGION_SU_WRITABLE) + +#define SBI_DOMAIN_MEMREGION_SHARED_SUR_MRW \ + (SBI_DOMAIN_MEMREGION_M_READABLE | \ + SBI_DOMAIN_MEMREGION_M_WRITABLE | \ + SBI_DOMAIN_MEMREGION_SU_READABLE) + + /* Shared read-only region between M and SU mode */ +#define SBI_DOMAIN_MEMREGION_IS_SUR_MR(__flags) \ + ((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \ + SBI_DOMAIN_MEMREGION_SHARED_RDONLY) + + /* Shared region: SU execute-only and M read/execute */ +#define SBI_DOMAIN_MEMREGION_IS_SUX_MRX(__flags) \ + ((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \ + SBI_DOMAIN_MEMREGION_SHARED_SUX_MRX) + + /* Shared region: SU and M execute-only */ +#define SBI_DOMAIN_MEMREGION_IS_SUX_MX(__flags) \ + ((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \ + SBI_DOMAIN_MEMREGION_SHARED_SUX_MX) + + /* Shared region: SU and M read/write */ +#define SBI_DOMAIN_MEMREGION_IS_SURW_MRW(__flags) \ + ((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \ + SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW) + + /* Shared region: SU read-only and M read/write */ +#define SBI_DOMAIN_MEMREGION_IS_SUR_MRW(__flags) \ + ((__flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == \ + SBI_DOMAIN_MEMREGION_SHARED_SUR_MRW) + + /* + * Check if region flags match with any of the above + * mentioned shared region type + */ +#define SBI_DOMAIN_MEMREGION_IS_SHARED(_flags) \ + (SBI_DOMAIN_MEMREGION_IS_SUR_MR(_flags) || \ + SBI_DOMAIN_MEMREGION_IS_SUX_MRX(_flags) || \ + SBI_DOMAIN_MEMREGION_IS_SUX_MX(_flags) || \ + SBI_DOMAIN_MEMREGION_IS_SURW_MRW(_flags)|| \ + SBI_DOMAIN_MEMREGION_IS_SUR_MRW(_flags)) + +#define SBI_DOMAIN_MEMREGION_M_ONLY_ACCESS(__flags) \ + ((__flags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK) && \ + !(__flags & SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK)) + +#define SBI_DOMAIN_MEMREGION_SU_ONLY_ACCESS(__flags) \ + ((__flags & SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK) && \ + !(__flags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK)) + +/** Bit to control if permissions are enforced on all modes */ +#define SBI_DOMAIN_MEMREGION_ENF_PERMISSIONS (1UL << 6) + +#define SBI_DOMAIN_MEMREGION_M_RWX \ + (SBI_DOMAIN_MEMREGION_M_READABLE | \ + SBI_DOMAIN_MEMREGION_M_WRITABLE | \ + SBI_DOMAIN_MEMREGION_M_EXECUTABLE) + +#define SBI_DOMAIN_MEMREGION_SU_RWX \ + (SBI_DOMAIN_MEMREGION_SU_READABLE | \ + SBI_DOMAIN_MEMREGION_SU_WRITABLE | \ + SBI_DOMAIN_MEMREGION_SU_EXECUTABLE) + +/* Unrestricted M-mode accesses but enfoced on SU-mode */ +#define SBI_DOMAIN_MEMREGION_READABLE \ + (SBI_DOMAIN_MEMREGION_SU_READABLE | \ + SBI_DOMAIN_MEMREGION_M_RWX) +#define SBI_DOMAIN_MEMREGION_WRITEABLE \ + (SBI_DOMAIN_MEMREGION_SU_WRITABLE | \ + SBI_DOMAIN_MEMREGION_M_RWX) +#define SBI_DOMAIN_MEMREGION_EXECUTABLE \ + (SBI_DOMAIN_MEMREGION_SU_EXECUTABLE | \ + SBI_DOMAIN_MEMREGION_M_RWX) + +/* Enforced accesses across all modes */ +#define SBI_DOMAIN_MEMREGION_ENF_READABLE \ + (SBI_DOMAIN_MEMREGION_SU_READABLE | \ + SBI_DOMAIN_MEMREGION_M_READABLE) +#define SBI_DOMAIN_MEMREGION_ENF_WRITABLE \ + (SBI_DOMAIN_MEMREGION_SU_WRITABLE | \ + SBI_DOMAIN_MEMREGION_M_WRITABLE) +#define SBI_DOMAIN_MEMREGION_ENF_EXECUTABLE \ + (SBI_DOMAIN_MEMREGION_SU_EXECUTABLE | \ + SBI_DOMAIN_MEMREGION_M_EXECUTABLE) + +#define SBI_DOMAIN_MEMREGION_MMIO (1UL << 31) + unsigned long flags; +}; + +/** + * Initialize a domain memory region based on it's physical + * address and size. + * + * @param addr start physical address of memory region + * @param size physical size of memory region + * @param flags memory region flags + * @param reg pointer to memory region being initialized + */ +void sbi_domain_memregion_init(unsigned long addr, + unsigned long size, + unsigned long flags, + struct sbi_domain_memregion *reg); + +/** + * + * Traverse all of a domain's memory regions and sanitize + * them, while making sure they are formatted properly + * + * @param dom the domain for which to sanitize regions + */ +int sbi_domain_memregions_sanitize(struct sbi_domain *dom); + +/** + * Check whether we can access specified address for given mode and + * memory region flags under a domain + * @param dom pointer to domain + * @param addr the address to be checked + * @param mode the privilege mode of access + * @param access_flags bitmask of domain access types (enum sbi_domain_access) + * @return true if access allowed otherwise false + */ +bool sbi_domain_check_addr(const struct sbi_domain *dom, + unsigned long addr, unsigned long mode, + unsigned long access_flags); + +/** + * Check whether we can access specified address range for given mode and + * memory region flags under a domain + * @param dom pointer to domain + * @param addr the start of the address range to be checked + * @param size the size of the address range to be checked + * @param mode the privilege mode of access + * @param access_flags bitmask of domain access types (enum sbi_domain_access) + * @return TRUE if access allowed otherwise FALSE + */ +bool sbi_domain_check_addr_range(const struct sbi_domain *dom, + unsigned long addr, unsigned long size, + unsigned long mode, + unsigned long access_flags); + +#endif // __SBI_MEMREGION_H__ \ No newline at end of file diff --git a/lib/sbi/objects.mk b/lib/sbi/objects.mk index 535aa70..d80d6cc 100644 --- a/lib/sbi/objects.mk +++ b/lib/sbi/objects.mk @@ -66,6 +66,7 @@ libsbi-objs-y += sbi_bitops.o libsbi-objs-y += sbi_console.o libsbi-objs-y += sbi_domain_context.o libsbi-objs-y += sbi_domain.o +libsbi-objs-y += sbi_memregion.o libsbi-objs-y += sbi_emulate_csr.o libsbi-objs-y += sbi_fifo.o libsbi-objs-y += sbi_fwft.o diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c index 374ac36..00ba870 100644 --- a/lib/sbi/sbi_domain.c +++ b/lib/sbi/sbi_domain.c @@ -96,199 +96,9 @@ ulong sbi_domain_get_assigned_hartmask(const struct sbi_domain *dom, return ret; } -void sbi_domain_memregion_init(unsigned long addr, - unsigned long size, - unsigned long flags, - struct sbi_domain_memregion *reg) -{ - unsigned long base = 0, order; - - for (order = log2roundup(size) ; order <= __riscv_xlen; order++) { - if (order < __riscv_xlen) { - base = addr & ~((1UL << order) - 1UL); - if ((base <= addr) && - (addr < (base + (1UL << order))) && - (base <= (addr + size - 1UL)) && - ((addr + size - 1UL) < (base + (1UL << order)))) - break; - } else { - base = 0; - break; - } - - } - - if (reg) { - reg->base = base; - reg->order = order; - reg->flags = flags; - } -} - -bool sbi_domain_check_addr(const struct sbi_domain *dom, - unsigned long addr, unsigned long mode, - unsigned long access_flags) -{ - bool rmmio, mmio = false; - struct sbi_domain_memregion *reg; - unsigned long rstart, rend, rflags, rwx = 0, rrwx = 0; - - if (!dom) - return false; - - /* - * Use M_{R/W/X} bits because the SU-bits are at the - * same relative offsets. If the mode is not M, the SU - * bits will fall at same offsets after the shift. - */ - if (access_flags & SBI_DOMAIN_READ) - rwx |= SBI_DOMAIN_MEMREGION_M_READABLE; - - if (access_flags & SBI_DOMAIN_WRITE) - rwx |= SBI_DOMAIN_MEMREGION_M_WRITABLE; - - if (access_flags & SBI_DOMAIN_EXECUTE) - rwx |= SBI_DOMAIN_MEMREGION_M_EXECUTABLE; - - if (access_flags & SBI_DOMAIN_MMIO) - mmio = true; - - sbi_domain_for_each_memregion(dom, reg) { - rflags = reg->flags; - rrwx = (mode == PRV_M ? - (rflags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK) : - (rflags & SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK) - >> SBI_DOMAIN_MEMREGION_SU_ACCESS_SHIFT); - - rstart = reg->base; - rend = (reg->order < __riscv_xlen) ? - rstart + ((1UL << reg->order) - 1) : -1UL; - if (rstart <= addr && addr <= rend) { - rmmio = (rflags & SBI_DOMAIN_MEMREGION_MMIO) ? true : false; - if (mmio != rmmio) - return false; - return ((rrwx & rwx) == rwx) ? true : false; - } - } - - return (mode == PRV_M) ? true : false; -} - -/* Check if region complies with constraints */ -static bool is_region_valid(const struct sbi_domain_memregion *reg) -{ - if (reg->order < 3 || __riscv_xlen < reg->order) - return false; - - if (reg->order == __riscv_xlen && reg->base != 0) - return false; - - if (reg->order < __riscv_xlen && (reg->base & (BIT(reg->order) - 1))) - return false; - - return true; -} - -/** Check if regionA is sub-region of regionB */ -static bool is_region_subset(const struct sbi_domain_memregion *regA, - const struct sbi_domain_memregion *regB) -{ - ulong regA_start = regA->base; - ulong regA_end = regA->base + (BIT(regA->order) - 1); - ulong regB_start = regB->base; - ulong regB_end = regB->base + (BIT(regB->order) - 1); - - if ((regB_start <= regA_start) && - (regA_start < regB_end) && - (regB_start < regA_end) && - (regA_end <= regB_end)) - return true; - - return false; -} - -/** Check if regionA can be replaced by regionB */ -static bool is_region_compatible(const struct sbi_domain_memregion *regA, - const struct sbi_domain_memregion *regB) -{ - if (is_region_subset(regA, regB) && regA->flags == regB->flags) - return true; - - return false; -} - -/** Check if regionA should be placed before regionB */ -static bool is_region_before(const struct sbi_domain_memregion *regA, - const struct sbi_domain_memregion *regB) -{ - if (regA->order < regB->order) - return true; - - if ((regA->order == regB->order) && - (regA->base < regB->base)) - return true; - - return false; -} - -static const struct sbi_domain_memregion *find_region( - const struct sbi_domain *dom, - unsigned long addr) -{ - unsigned long rstart, rend; - struct sbi_domain_memregion *reg; - - sbi_domain_for_each_memregion(dom, reg) { - rstart = reg->base; - rend = (reg->order < __riscv_xlen) ? - rstart + ((1UL << reg->order) - 1) : -1UL; - if (rstart <= addr && addr <= rend) - return reg; - } - - return NULL; -} - -static const struct sbi_domain_memregion *find_next_subset_region( - const struct sbi_domain *dom, - const struct sbi_domain_memregion *reg, - unsigned long addr) -{ - struct sbi_domain_memregion *sreg, *ret = NULL; - - sbi_domain_for_each_memregion(dom, sreg) { - if (sreg == reg || (sreg->base <= addr) || - !is_region_subset(sreg, reg)) - continue; - - if (!ret || (sreg->base < ret->base) || - ((sreg->base == ret->base) && (sreg->order < ret->order))) - ret = sreg; - } - - return ret; -} - -static void swap_region(struct sbi_domain_memregion* reg1, - struct sbi_domain_memregion* reg2) -{ - struct sbi_domain_memregion treg; - - sbi_memcpy(&treg, reg1, sizeof(treg)); - sbi_memcpy(reg1, reg2, sizeof(treg)); - sbi_memcpy(reg2, &treg, sizeof(treg)); -} - -static void clear_region(struct sbi_domain_memregion* reg) -{ - sbi_memset(reg, 0x0, sizeof(*reg)); -} - static int sanitize_domain(struct sbi_domain *dom) { - u32 i, j, count; - bool is_covered; - struct sbi_domain_memregion *reg, *reg1; + u32 i, rc; /* Check possible HARTs */ if (!dom->possible_harts) { @@ -305,70 +115,11 @@ static int sanitize_domain(struct sbi_domain *dom) } } - /* Check memory regions */ - if (!dom->regions) { - sbi_printf("%s: %s regions is NULL\n", - __func__, dom->name); - return SBI_EINVAL; - } - sbi_domain_for_each_memregion(dom, reg) { - if (!is_region_valid(reg)) { - sbi_printf("%s: %s has invalid region base=0x%lx " - "order=%lu flags=0x%lx\n", __func__, - dom->name, reg->base, reg->order, - reg->flags); - return SBI_EINVAL; - } - } - - /* Count memory regions */ - count = 0; - sbi_domain_for_each_memregion(dom, reg) - count++; - - /* Check presence of firmware regions */ - if (!dom->fw_region_inited) { - sbi_printf("%s: %s does not have firmware region\n", + rc = sbi_domain_memregions_sanitize(dom); + if (rc) { + sbi_printf("%s: %s has unsanitizable regions\n", __func__, dom->name); - return SBI_EINVAL; - } - - /* Sort the memory regions */ - for (i = 0; i < (count - 1); i++) { - reg = &dom->regions[i]; - for (j = i + 1; j < count; j++) { - reg1 = &dom->regions[j]; - - if (!is_region_before(reg1, reg)) - continue; - - swap_region(reg, reg1); - } - } - - /* Remove covered regions */ - while(i < (count - 1)) { - is_covered = false; - reg = &dom->regions[i]; - - for (j = i + 1; j < count; j++) { - reg1 = &dom->regions[j]; - - if (is_region_compatible(reg, reg1)) { - is_covered = true; - break; - } - } - - /* find a region is superset of reg, remove reg */ - if (is_covered) { - for (j = i; j < (count - 1); j++) - swap_region(&dom->regions[j], - &dom->regions[j + 1]); - clear_region(&dom->regions[count - 1]); - count--; - } else - i++; + return rc; } /* @@ -401,37 +152,6 @@ static int sanitize_domain(struct sbi_domain *dom) return 0; } -bool sbi_domain_check_addr_range(const struct sbi_domain *dom, - unsigned long addr, unsigned long size, - unsigned long mode, - unsigned long access_flags) -{ - unsigned long max = addr + size; - const struct sbi_domain_memregion *reg, *sreg; - - if (!dom) - return false; - - while (addr < max) { - reg = find_region(dom, addr); - if (!reg) - return false; - - if (!sbi_domain_check_addr(dom, addr, mode, access_flags)) - return false; - - sreg = find_next_subset_region(dom, reg, addr); - if (sreg) - addr = sreg->base; - else if (reg->order < __riscv_xlen) - addr = reg->base + (1UL << reg->order); - else - break; - } - - return true; -} - void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix) { u32 i, j, k; @@ -613,12 +333,6 @@ int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg) (ROOT_REGION_MAX <= root_memregs_count)) return SBI_EINVAL; - /* Check whether compatible region exists for the new one */ - sbi_domain_for_each_memregion(&root, nreg) { - if (is_region_compatible(reg, nreg)) - return 0; - } - /* Append the memregion to root memregions */ nreg = &root.regions[root_memregs_count]; sbi_memcpy(nreg, reg, sizeof(*reg)); diff --git a/lib/sbi/sbi_memregion.c b/lib/sbi/sbi_memregion.c new file mode 100644 index 0000000..8cb1eed --- /dev/null +++ b/lib/sbi/sbi_memregion.c @@ -0,0 +1,301 @@ +#include +#include +#include +#include +#include + +void sbi_domain_memregion_init(unsigned long addr, + unsigned long size, + unsigned long flags, + struct sbi_domain_memregion *reg) +{ + unsigned long base = 0, order; + + for (order = log2roundup(size) ; order <= __riscv_xlen; order++) { + if (order < __riscv_xlen) { + base = addr & ~((1UL << order) - 1UL); + if ((base <= addr) && + (addr < (base + (1UL << order))) && + (base <= (addr + size - 1UL)) && + ((addr + size - 1UL) < (base + (1UL << order)))) + break; + } else { + base = 0; + break; + } + + } + + if (reg) { + reg->base = base; + reg->order = order; + reg->flags = flags; + } +} + +/** Check if regionA is sub-region of regionB */ +static bool is_region_subset(const struct sbi_domain_memregion *regA, + const struct sbi_domain_memregion *regB) +{ + ulong regA_start = regA->base; + ulong regA_end = regA->base + (BIT(regA->order) - 1); + ulong regB_start = regB->base; + ulong regB_end = regB->base + (BIT(regB->order) - 1); + + if ((regB_start <= regA_start) && + (regA_start < regB_end) && + (regB_start < regA_end) && + (regA_end <= regB_end)) + return true; + + return false; +} + +/** Check if regionA can be replaced by regionB */ +static bool is_region_compatible(const struct sbi_domain_memregion *regA, + const struct sbi_domain_memregion *regB) +{ + if (is_region_subset(regA, regB) && regA->flags == regB->flags) + return true; + + return false; +} + +/* Check if region complies with constraints */ +static bool is_region_valid(const struct sbi_domain_memregion *reg) +{ + if (reg->order < 3 || __riscv_xlen < reg->order) + return false; + + if (reg->order == __riscv_xlen && reg->base != 0) + return false; + + if (reg->order < __riscv_xlen && (reg->base & (BIT(reg->order) - 1))) + return false; + + return true; +} + +/** Check if regionA should be placed before regionB */ +static bool is_region_before(const struct sbi_domain_memregion *regA, + const struct sbi_domain_memregion *regB) +{ + if (regA->order < regB->order) + return true; + + if ((regA->order == regB->order) && + (regA->base < regB->base)) + return true; + + return false; +} + + +static void swap_region(struct sbi_domain_memregion* reg1, + struct sbi_domain_memregion* reg2) +{ + struct sbi_domain_memregion treg; + + sbi_memcpy(&treg, reg1, sizeof(treg)); + sbi_memcpy(reg1, reg2, sizeof(treg)); + sbi_memcpy(reg2, &treg, sizeof(treg)); +} + +static void clear_region(struct sbi_domain_memregion* reg) +{ + sbi_memset(reg, 0x0, sizeof(*reg)); +} + +int sbi_domain_memregions_sanitize(struct sbi_domain *dom) +{ + int i, j, count; + bool is_covered; + struct sbi_domain_memregion *reg, *reg1; + + /* Check memory regions */ + if (!dom->regions) { + sbi_printf("%s: %s regions is NULL\n", + __func__, dom->name); + return SBI_EINVAL; + } + sbi_domain_for_each_memregion(dom, reg) { + if (!is_region_valid(reg)) { + sbi_printf("%s: %s has invalid region base=0x%lx " + "order=%lu flags=0x%lx\n", __func__, + dom->name, reg->base, reg->order, + reg->flags); + return SBI_EINVAL; + } + } + + /* Count memory regions */ + count = 0; + sbi_domain_for_each_memregion(dom, reg) + count++; + + /* Check presence of firmware regions */ + if (!dom->fw_region_inited) { + sbi_printf("%s: %s does not have firmware region\n", + __func__, dom->name); + return SBI_EINVAL; + } + + /* Sort the memory regions */ + for (i = 0; i < (count - 1); i++) { + reg = &dom->regions[i]; + for (j = i + 1; j < count; j++) { + reg1 = &dom->regions[j]; + + if (!is_region_before(reg1, reg)) + continue; + + swap_region(reg, reg1); + } + } + + /* Remove covered regions */ + while(i < (count - 1)) { + is_covered = false; + reg = &dom->regions[i]; + + for (j = i + 1; j < count; j++) { + reg1 = &dom->regions[j]; + + if (is_region_compatible(reg, reg1)) { + is_covered = true; + break; + } + } + + /* find a region is superset of reg, remove reg */ + if (is_covered) { + for (j = i; j < (count - 1); j++) + swap_region(&dom->regions[j], + &dom->regions[j + 1]); + clear_region(&dom->regions[count - 1]); + count--; + } else + i++; + } + + return SBI_OK; +} + + +bool sbi_domain_check_addr(const struct sbi_domain *dom, + unsigned long addr, unsigned long mode, + unsigned long access_flags) +{ + bool rmmio, mmio = false; + struct sbi_domain_memregion *reg; + unsigned long rstart, rend, rflags, rwx = 0, rrwx = 0; + + if (!dom) + return false; + + /* + * Use M_{R/W/X} bits because the SU-bits are at the + * same relative offsets. If the mode is not M, the SU + * bits will fall at same offsets after the shift. + */ + if (access_flags & SBI_DOMAIN_READ) + rwx |= SBI_DOMAIN_MEMREGION_M_READABLE; + + if (access_flags & SBI_DOMAIN_WRITE) + rwx |= SBI_DOMAIN_MEMREGION_M_WRITABLE; + + if (access_flags & SBI_DOMAIN_EXECUTE) + rwx |= SBI_DOMAIN_MEMREGION_M_EXECUTABLE; + + if (access_flags & SBI_DOMAIN_MMIO) + mmio = true; + + sbi_domain_for_each_memregion(dom, reg) { + rflags = reg->flags; + rrwx = (mode == PRV_M ? + (rflags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK) : + (rflags & SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK) + >> SBI_DOMAIN_MEMREGION_SU_ACCESS_SHIFT); + + rstart = reg->base; + rend = (reg->order < __riscv_xlen) ? + rstart + ((1UL << reg->order) - 1) : -1UL; + if (rstart <= addr && addr <= rend) { + rmmio = (rflags & SBI_DOMAIN_MEMREGION_MMIO) ? true : false; + if (mmio != rmmio) + return false; + return ((rrwx & rwx) == rwx) ? true : false; + } + } + + return (mode == PRV_M) ? true : false; +} + +static const struct sbi_domain_memregion *find_region( + const struct sbi_domain *dom, + unsigned long addr) +{ + unsigned long rstart, rend; + struct sbi_domain_memregion *reg; + + sbi_domain_for_each_memregion(dom, reg) { + rstart = reg->base; + rend = (reg->order < __riscv_xlen) ? + rstart + ((1UL << reg->order) - 1) : -1UL; + if (rstart <= addr && addr <= rend) + return reg; + } + + return NULL; +} + +static const struct sbi_domain_memregion *find_next_subset_region( + const struct sbi_domain *dom, + const struct sbi_domain_memregion *reg, + unsigned long addr) +{ + struct sbi_domain_memregion *sreg, *ret = NULL; + + sbi_domain_for_each_memregion(dom, sreg) { + if (sreg == reg || (sreg->base <= addr) || + !is_region_subset(sreg, reg)) + continue; + + if (!ret || (sreg->base < ret->base) || + ((sreg->base == ret->base) && (sreg->order < ret->order))) + ret = sreg; + } + + return ret; +} + +bool sbi_domain_check_addr_range(const struct sbi_domain *dom, + unsigned long addr, unsigned long size, + unsigned long mode, + unsigned long access_flags) +{ + unsigned long max = addr + size; + const struct sbi_domain_memregion *reg, *sreg; + + if (!dom) + return false; + + while (addr < max) { + reg = find_region(dom, addr); + if (!reg) + return false; + + if (!sbi_domain_check_addr(dom, addr, mode, access_flags)) + return false; + + sreg = find_next_subset_region(dom, reg, addr); + if (sreg) + addr = sreg->base; + else if (reg->order < __riscv_xlen) + addr = reg->base + (1UL << reg->order); + else + break; + } + + return true; +} \ No newline at end of file