From patchwork Fri Jun 14 17:51:42 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julien Grall X-Patchwork-Id: 166869 Delivered-To: patch@linaro.org Received: by 2002:a92:4782:0:0:0:0:0 with SMTP id e2csp2351246ilk; Fri, 14 Jun 2019 10:53:31 -0700 (PDT) X-Google-Smtp-Source: APXvYqweeqjHUmcPLp4x0JptE/E+Y7bJKqbbwCIWSyYDCb1kKQsWwivmKqstJo5S5chkjyOv/s51 X-Received: by 2002:a05:6602:2248:: with SMTP id o8mr18650389ioo.90.1560534811799; Fri, 14 Jun 2019 10:53:31 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1560534811; cv=none; d=google.com; s=arc-20160816; b=tLM52yogZNY0OQdksI1CQ7kEFz+sMuzcykBIXxraldDZBsOkNZE2WH6TfsV9EF5eMZ 9FA2O89i4sAjPAeSQHzwgEop8uQJikPIR9t/9FceIMe6UvDrZ2aXkeUGJbJjkORZtWm6 P396yVl11PQsbr9zmD1l/SYwMb4hsH1NkluATx4V4rPuNe4MdoedCuN6TIymW3aq/zY+ NYtWV0g6YM3+Qsb4XKzyz35XNHLe1cnHhMp4e3I43MSdDKqENKj0gl0EtciZdZbTWp/4 aiULQ1nUVCtm6W5c6fQNzd3j9Lrndd8ZiitwX1lh7N3AGqkWJcPHGh8Ot2X+XI05kJUt uV1w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version:cc :list-subscribe:list-help:list-post:list-unsubscribe:list-id :precedence:subject:references:in-reply-to:message-id:date:to:from; bh=+0vFTbJdPHjly1Z7RnfvhN2UGJ201XvrJu1lZbYgJBo=; b=0CO8wr5t8N/wTe7FxbbN2NSTJlU8gFDtaxZhq6CVyb0upB+XTNGudbwjHeToWLeCJT sRjS8N7qTWIXcQqLa60lJOvikDTQBUh4qiw7pvbpnJX7oIHuoRaYbVaUYLWME2NpLEAk 0XCtQH7q3ljbykTIVcmwgqZ9U2ijnNnlie8u8zlmlFXvuOuGjOpELmIYJhumtKvBGCvB zT7tuPHjLIjwK+owRfXbi59/hxK5TnvPMBYOUopVy3i00wen80rFJe9RDGUDxwpVnwcr +yqE0MpPnfbOqgxRD0KM95KQDfU2m4N3KBZouPdoBPz6EDNz1kQtJ9rkPzqmujM7+OeT cttQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of xen-devel-bounces@lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Return-Path: Received: from lists.xenproject.org (lists.xenproject.org. [192.237.175.120]) by mx.google.com with ESMTPS id 73si3852984iou.65.2019.06.14.10.53.31 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Fri, 14 Jun 2019 10:53:31 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of xen-devel-bounces@lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of xen-devel-bounces@lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1hbqMx-0001v4-6E; Fri, 14 Jun 2019 17:52:07 +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 1hbqMv-0001uG-O5 for xen-devel@lists.xenproject.org; Fri, 14 Jun 2019 17:52:05 +0000 X-Inumbo-ID: 1c0310ca-8ecd-11e9-8bda-e7d4a65d852c Received: from foss.arm.com (unknown [217.140.110.172]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTP id 1c0310ca-8ecd-11e9-8bda-e7d4a65d852c; Fri, 14 Jun 2019 17:52:00 +0000 (UTC) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id E8DC63EF; Fri, 14 Jun 2019 10:51:59 -0700 (PDT) Received: from e108454-lin.cambridge.arm.com (e108454-lin.cambridge.arm.com [10.1.196.50]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 0CC423F718; Fri, 14 Jun 2019 10:51:58 -0700 (PDT) From: Julien Grall To: xen-devel@lists.xenproject.org Date: Fri, 14 Jun 2019 18:51:42 +0100 Message-Id: <20190614175144.20046-8-julien.grall@arm.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20190614175144.20046-1-julien.grall@arm.com> References: <20190614175144.20046-1-julien.grall@arm.com> Subject: [Xen-devel] [PATCH MM-PART3 v3 7/9] xen/arm: mm: Rework Xen page-tables walk during update 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: Oleksandr_Tyshchenko@epam.com, Julien Grall , Stefano Stabellini , Andrii Anisov MIME-Version: 1.0 Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" Currently, xen_pt_update_entry() is only able to update the region covered by xen_second (i.e 0 to 0x7fffffff). Because of the restriction we end to have multiple functions in mm.c modifying the page-tables differently. Furthermore, we never walked the page-tables fully. This means that any change in the layout may requires major rewrite of the page-tables code. Lastly, we have been quite lucky that no one ever tried to pass an address outside this range because it would have blown-up. xen_pt_update_entry() is reworked to walk over the page-tables every time. The logic has been borrowed from arch/arm/p2m.c and contain some limitations for the time being: - Superpage cannot be shattered - Only level 3 (i.e 4KB) can be done Note that the parameter 'addr' has been renamed to 'virt' to make clear we are dealing with a virtual address. Signed-off-by: Julien Grall Reviewed-by: Andrii Anisov Acked-by: Stefano Stabellini --- Changes in v3: - Remove an ASSERT() - Add Stefano's acked-by Changes in v2: - Add Andrii's reviewed-by --- xen/arch/arm/mm.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 104 insertions(+), 15 deletions(-) diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c index c3dd2c08ba..028fbd38ad 100644 --- a/xen/arch/arm/mm.c +++ b/xen/arch/arm/mm.c @@ -957,6 +957,51 @@ static void xen_unmap_table(const lpae_t *table) unmap_domain_page(table); } +#define XEN_TABLE_MAP_FAILED 0 +#define XEN_TABLE_SUPER_PAGE 1 +#define XEN_TABLE_NORMAL_PAGE 2 + +/* + * Take the currently mapped table, find the corresponding entry, + * and map the next table, if available. + * + * The read_only parameters indicates whether intermediate tables should + * be allocated when not present. + * + * Return values: + * XEN_TABLE_MAP_FAILED: Either read_only was set and the entry + * was empty, or allocating a new page failed. + * XEN_TABLE_NORMAL_PAGE: next level mapped normally + * XEN_TABLE_SUPER_PAGE: The next entry points to a superpage. + */ +static int xen_pt_next_level(bool read_only, unsigned int level, + lpae_t **table, unsigned int offset) +{ + lpae_t *entry; + int ret; + + entry = *table + offset; + + if ( !lpae_is_valid(*entry) ) + { + if ( read_only ) + return XEN_TABLE_MAP_FAILED; + + ret = create_xen_table(entry); + if ( ret ) + return XEN_TABLE_MAP_FAILED; + } + + /* The function xen_pt_next_level is never called at the 3rd level */ + if ( lpae_is_mapping(*entry, level) ) + return XEN_TABLE_SUPER_PAGE; + + xen_unmap_table(*table); + *table = xen_map_table(lpae_get_mfn(*entry)); + + return XEN_TABLE_NORMAL_PAGE; +} + /* Sanity check of the entry */ static bool xen_pt_check_entry(lpae_t entry, mfn_t mfn, unsigned int flags) { @@ -1023,30 +1068,65 @@ static bool xen_pt_check_entry(lpae_t entry, mfn_t mfn, unsigned int flags) return true; } -static int xen_pt_update_entry(unsigned long addr, mfn_t mfn, - unsigned int flags) +static int xen_pt_update_entry(mfn_t root, unsigned long virt, + mfn_t mfn, unsigned int flags) { int rc; + unsigned int level; + /* We only support 4KB mapping (i.e level 3) for now */ + unsigned int target = 3; + lpae_t *table; + /* + * The intermediate page tables are read-only when the MFN is not valid + * and we are not populating page table. + * This means we either modify permissions or remove an entry. + */ + bool read_only = mfn_eq(mfn, INVALID_MFN) && !(flags & _PAGE_POPULATE); lpae_t pte, *entry; - lpae_t *third = NULL; + + /* convenience aliases */ + DECLARE_OFFSETS(offsets, (paddr_t)virt); /* _PAGE_POPULATE and _PAGE_PRESENT should never be set together. */ ASSERT((flags & (_PAGE_POPULATE|_PAGE_PRESENT)) != (_PAGE_POPULATE|_PAGE_PRESENT)); - entry = &xen_second[second_linear_offset(addr)]; - if ( !lpae_is_valid(*entry) || !lpae_is_table(*entry, 2) ) + table = xen_map_table(root); + for ( level = HYP_PT_ROOT_LEVEL; level < target; level++ ) { - int rc = create_xen_table(entry); - if ( rc < 0 ) { - printk("%s: L2 failed\n", __func__); - return rc; + rc = xen_pt_next_level(read_only, level, &table, offsets[level]); + if ( rc == XEN_TABLE_MAP_FAILED ) + { + /* + * We are here because xen_pt_next_level has failed to map + * the intermediate page table (e.g the table does not exist + * and the pt is read-only). It is a valid case when + * removing a mapping as it may not exist in the page table. + * In this case, just ignore it. + */ + if ( flags & (_PAGE_PRESENT|_PAGE_POPULATE) ) + { + mm_printk("%s: Unable to map level %u\n", __func__, level); + rc = -ENOENT; + goto out; + } + else + { + rc = 0; + goto out; + } } + else if ( rc != XEN_TABLE_NORMAL_PAGE ) + break; } - BUG_ON(!lpae_is_valid(*entry)); + if ( level != target ) + { + mm_printk("%s: Shattering superpage is not supported\n", __func__); + rc = -EOPNOTSUPP; + goto out; + } - third = xen_map_table(lpae_get_mfn(*entry)); - entry = &third[third_table_offset(addr)]; + entry = table + offsets[level]; rc = -EINVAL; if ( !xen_pt_check_entry(*entry, mfn, flags) ) @@ -1083,7 +1163,7 @@ static int xen_pt_update_entry(unsigned long addr, mfn_t mfn, rc = 0; out: - xen_unmap_table(third); + xen_unmap_table(table); return rc; } @@ -1099,6 +1179,15 @@ static int xen_pt_update(unsigned long virt, unsigned long addr = virt, addr_end = addr + nr_mfns * PAGE_SIZE; /* + * For arm32, page-tables are different on each CPUs. Yet, they share + * some common mappings. It is assumed that only common mappings + * will be modified with this function. + * + * XXX: Add a check. + */ + const mfn_t root = virt_to_mfn(THIS_CPU_PGTABLE); + + /* * The hardware was configured to forbid mapping both writeable and * executable. * When modifying/creating mapping (i.e _PAGE_PRESENT is set), @@ -1119,9 +1208,9 @@ static int xen_pt_update(unsigned long virt, spin_lock(&xen_pt_lock); - for( ; addr < addr_end; addr += PAGE_SIZE ) + for ( ; addr < addr_end; addr += PAGE_SIZE ) { - rc = xen_pt_update_entry(addr, mfn, flags); + rc = xen_pt_update_entry(root, addr, mfn, flags); if ( rc ) break;