From patchwork Fri Apr 16 08:47:21 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Youling Tang X-Patchwork-Id: 12207103 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3A340C433ED for ; Fri, 16 Apr 2021 08:48:32 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 142566115B for ; Fri, 16 Apr 2021 08:48:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241433AbhDPIsy (ORCPT ); Fri, 16 Apr 2021 04:48:54 -0400 Received: from mail.loongson.cn ([114.242.206.163]:42360 "EHLO loongson.cn" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S241188AbhDPIsY (ORCPT ); Fri, 16 Apr 2021 04:48:24 -0400 Received: from bogon.localdomain (unknown [113.200.148.30]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9AxbcgiT3lg36UIAA--.12141S2; Fri, 16 Apr 2021 16:47:30 +0800 (CST) From: Youling Tang To: Thomas Bogendoerfer Cc: linux-mips@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 1/2] MIPS: mm: Add ARCH_HAS_SET_MEMORY support Date: Fri, 16 Apr 2021 16:47:21 +0800 Message-Id: <1618562842-20915-1-git-send-email-tangyouling@loongson.cn> X-Mailer: git-send-email 2.1.0 X-CM-TRANSID: AQAAf9AxbcgiT3lg36UIAA--.12141S2 X-Coremail-Antispam: 1UD129KBjvJXoW3GrWrKF1kKFWDAw4kKry7Awb_yoWxJFy7pa 1kAa4kArW2g343GayxuryDur1fJwn5GFW8tFyay34j9asxXFyYvr93trW7tr1UGrWDWF47 GayYga4UuF47X37anT9S1TB71UUUUUUqnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUkSb7Iv0xC_KF4lb4IE77IF4wAFF20E14v26r1j6r4UM7CY07I2 0VC2zVCF04k26cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28lY4IEw2IIxxk0rw A2F7IY1VAKz4vEj48ve4kI8wA2z4x0Y4vE2Ix0cI8IcVAFwI0_Ar0_tr1l84ACjcxK6xII jxv20xvEc7CjxVAFwI0_Gr1j6F4UJwA2z4x0Y4vEx4A2jsIE14v26rxl6s0DM28EF7xvwV C2z280aVCY1x0267AKxVW0oVCq3wAS0I0E0xvYzxvE52x082IY62kv0487Mc02F40EFcxC 0VAKzVAqx4xG6I80ewAv7VC0I7IYx2IY67AKxVWUtVWrXwAv7VC2z280aVAFwI0_Cr0_Gr 1UMcvjeVCFs4IE7xkEbVWUJVW8JwACjcxG0xvY0x0EwIxGrwCY02Avz4vE14v_GFyl42xK 82IYc2Ij64vIr41l4I8I3I0E4IkC6x0Yz7v_Jr0_Gr1lx2IqxVAqx4xG67AKxVWUJVWUGw C20s026x8GjcxK67AKxVWUGVWUWwC2zVAF1VAY17CE14v26r1Y6r17MIIYrxkI7VAKI48J MIIF0xvE2Ix0cI8IcVAFwI0_Jr0_JF4lIxAIcVC0I7IYx2IY6xkF7I0E14v26r1j6r4UMI IF0xvE42xK8VAvwI8IcIk0rVWrJr0_WFyUJwCI42IY6I8E87Iv67AKxVWUJVW8JwCI42IY 6I8E87Iv6xkF7I0E14v26r4j6r4UJbIYCTnIWIevJa73UjIFyTuYvjxU48sqDUUUU X-CM-SenderInfo: 5wdqw5prxox03j6o00pqjv00gofq/ Precedence: bulk List-ID: X-Mailing-List: linux-mips@vger.kernel.org Add set_memory_ro/rw/x/nx/rw_nx architecture hooks. These set_memory_* and set_pages_* APIs can make it easier to change the attributes of memory or pages. Similar to the implementation of riscv. The declaration of set_memory_* functions uses the general set_memory.h (i.e. include/asm-generic/set_memory.h). Signed-off-by: Youling Tang --- arch/mips/Kconfig | 1 + arch/mips/include/asm/set_memory.h | 19 +++++ arch/mips/mm/Makefile | 1 + arch/mips/mm/pageattr.c | 157 +++++++++++++++++++++++++++++++++++++ 4 files changed, 178 insertions(+) create mode 100644 arch/mips/include/asm/set_memory.h create mode 100644 arch/mips/mm/pageattr.c diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index e9893cd..ddeefd4 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -12,6 +12,7 @@ config MIPS select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST select ARCH_HAS_UBSAN_SANITIZE_ALL select ARCH_HAS_GCOV_PROFILE_ALL + select ARCH_HAS_SET_MEMORY select ARCH_KEEP_MEMBLOCK if DEBUG_KERNEL select ARCH_SUPPORTS_UPROBES select ARCH_USE_BUILTIN_BSWAP diff --git a/arch/mips/include/asm/set_memory.h b/arch/mips/include/asm/set_memory.h new file mode 100644 index 0000000..42217eb --- /dev/null +++ b/arch/mips/include/asm/set_memory.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _ASM_MIPS_SET_MEMORY_H +#define _ASM_MIPS_SET_MEMORY_H + +#include + +struct pageattr_masks { + pgprot_t set_mask; + pgprot_t clear_mask; +}; + +/* + * Functions to change pages attributes. + */ +int set_pages_ro(struct page *page, int numpages); +int set_pages_rw(struct page *page, int numpages); + +#endif /* _ASM_MIPS_SET_MEMORY_H */ diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile index 4acc4f3..2022940 100644 --- a/arch/mips/mm/Makefile +++ b/arch/mips/mm/Makefile @@ -12,6 +12,7 @@ obj-y += mmap.o obj-y += page.o obj-y += page-funcs.o obj-y += pgtable.o +obj-y += pageattr.o obj-y += tlbex.o obj-y += tlbex-fault.o obj-y += tlb-funcs.o diff --git a/arch/mips/mm/pageattr.c b/arch/mips/mm/pageattr.c new file mode 100644 index 0000000..59db16e --- /dev/null +++ b/arch/mips/mm/pageattr.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include + +static unsigned long set_pageattr_masks(unsigned long val, struct mm_walk *walk) +{ + struct pageattr_masks *masks = walk->private; + unsigned long new_val = val; + + new_val &= ~(pgprot_val(masks->clear_mask)); + new_val |= (pgprot_val(masks->set_mask)); + + return new_val; +} + +static int pageattr_pgd_entry(pgd_t *pgd, unsigned long addr, + unsigned long next, struct mm_walk *walk) +{ + pgd_t val = READ_ONCE(*pgd); + + if (pgd_leaf(val)) { + val = __pgd(set_pageattr_masks(pgd_val(val), walk)); + set_pgd(pgd, val); + } + + return 0; +} + +static int pageattr_p4d_entry(p4d_t *p4d, unsigned long addr, + unsigned long next, struct mm_walk *walk) +{ + p4d_t val = READ_ONCE(*p4d); + + if (p4d_leaf(val)) { + val = __p4d(set_pageattr_masks(p4d_val(val), walk)); + set_p4d(p4d, val); + } + + return 0; +} + +static int pageattr_pud_entry(pud_t *pud, unsigned long addr, + unsigned long next, struct mm_walk *walk) +{ + pud_t val = READ_ONCE(*pud); + + if (pud_leaf(val)) { + val = __pud(set_pageattr_masks(pud_val(val), walk)); + set_pud(pud, val); + } + + return 0; +} + +static int pageattr_pmd_entry(pmd_t *pmd, unsigned long addr, + unsigned long next, struct mm_walk *walk) +{ + pmd_t val = READ_ONCE(*pmd); + + if (pmd_leaf(val)) { + val = __pmd(set_pageattr_masks(pmd_val(val), walk)); + set_pmd(pmd, val); + } + + return 0; +} + +static int pageattr_pte_entry(pte_t *pte, unsigned long addr, + unsigned long next, struct mm_walk *walk) +{ + pte_t val = READ_ONCE(*pte); + + val = __pte(set_pageattr_masks(pte_val(val), walk)); + set_pte(pte, val); + + return 0; +} + +static int pageattr_pte_hole(unsigned long addr, unsigned long next, + int depth, struct mm_walk *walk) +{ + /* Nothing to do here */ + return 0; +} + +static const struct mm_walk_ops pageattr_ops = { + .pgd_entry = pageattr_pgd_entry, + .p4d_entry = pageattr_p4d_entry, + .pud_entry = pageattr_pud_entry, + .pmd_entry = pageattr_pmd_entry, + .pte_entry = pageattr_pte_entry, + .pte_hole = pageattr_pte_hole, +}; + +static int __set_memory(unsigned long addr, int numpages, pgprot_t set_mask, + pgprot_t clear_mask) +{ + int ret; + unsigned long start = addr; + unsigned long end = start + PAGE_SIZE * numpages; + struct pageattr_masks masks = { + .set_mask = set_mask, + .clear_mask = clear_mask + }; + + if (!numpages) + return 0; + + mmap_read_lock(&init_mm); + ret = walk_page_range_novma(&init_mm, start, end, &pageattr_ops, NULL, + &masks); + mmap_read_unlock(&init_mm); + + flush_tlb_kernel_range(start, end); + + return ret; +} + +int set_memory_ro(unsigned long addr, int numpages) +{ + return __set_memory(addr, numpages, __pgprot(__READABLE), + __pgprot(_PAGE_WRITE)); +} + +int set_memory_rw(unsigned long addr, int numpages) +{ + return __set_memory(addr, numpages, __pgprot(__WRITEABLE | __READABLE), + __pgprot(0)); +} + +int set_memory_x(unsigned long addr, int numpages) +{ + return __set_memory(addr, numpages, __pgprot(0), __pgprot(_PAGE_NO_EXEC)); +} + +int set_memory_nx(unsigned long addr, int numpages) +{ + return __set_memory(addr, numpages, __pgprot(_PAGE_NO_EXEC), __pgprot(0)); +} + +int set_pages_ro(struct page *page, int numpages) +{ + unsigned long addr = (unsigned long)page_address(page); + + return set_memory_ro(addr, numpages); +} + +int set_pages_rw(struct page *page, int numpages) +{ + unsigned long addr = (unsigned long)page_address(page); + + return set_memory_rw(addr, numpages); +} From patchwork Fri Apr 16 08:47:22 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Youling Tang X-Patchwork-Id: 12207101 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 99BC1C433ED for ; Fri, 16 Apr 2021 08:48:00 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7BE6E61153 for ; Fri, 16 Apr 2021 08:48:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241183AbhDPIsW (ORCPT ); Fri, 16 Apr 2021 04:48:22 -0400 Received: from mail.loongson.cn ([114.242.206.163]:42236 "EHLO loongson.cn" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S240851AbhDPIr6 (ORCPT ); Fri, 16 Apr 2021 04:47:58 -0400 Received: from bogon.localdomain (unknown [113.200.148.30]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9AxbcgiT3lg36UIAA--.12141S3; Fri, 16 Apr 2021 16:47:30 +0800 (CST) From: Youling Tang To: Thomas Bogendoerfer Cc: linux-mips@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 2/2] MIPS: kdump: Provide arch_kexec_protect(unprotect)_crashkres() Date: Fri, 16 Apr 2021 16:47:22 +0800 Message-Id: <1618562842-20915-2-git-send-email-tangyouling@loongson.cn> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1618562842-20915-1-git-send-email-tangyouling@loongson.cn> References: <1618562842-20915-1-git-send-email-tangyouling@loongson.cn> X-CM-TRANSID: AQAAf9AxbcgiT3lg36UIAA--.12141S3 X-Coremail-Antispam: 1UD129KBjvJXoW7ur48Aw4xJFykJw1xKw15urg_yoW8tw1fpF 4DC345KrWUZFnIyr93Ars7u34rX3Z5Xay5K3s7Cr95ZasrXry5Xr97WF10qry8tryfKF1x ZFs8XFs8uwsrAaDanT9S1TB71UUUUUDqnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUBFb7Iv0xC_Kw4lb4IE77IF4wAFF20E14v26r4j6ryUM7CY07I2 0VC2zVCF04k26cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28IrcIa0xkI8VA2jI 8067AKxVWUGwA2048vs2IY020Ec7CjxVAFwI0_Jrv_JF4l8cAvFVAK0II2c7xJM28CjxkF 64kEwVA0rcxSw2x7M28EF7xvwVC0I7IYx2IY67AKxVW7JVWDJwA2z4x0Y4vE2Ix0cI8IcV CY1x0267AKxVW8Jr0_Cr1UM28EF7xvwVC2z280aVAFwI0_GcCE3s1l84ACjcxK6I8E87Iv 6xkF7I0E14v26rxl6s0DM2AIxVAIcxkEcVAq07x20xvEncxIr21l5I8CrVACY4xI64kE6c 02F40Ex7xfMcIj6xIIjxv20xvE14v26r1q6rW5McIj6I8E87Iv67AKxVWxJVW8Jr1lOx8S 6xCaFVCjc4AY6r1j6r4UM4x0Y48IcxkI7VAKI48JMxkIecxEwVAFwVW8ZwCF04k20xvY0x 0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC20s026c02F40E14v26r1j6r18MI8I3I0E 7480Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_Jrv_JF1lIxkGc2Ij64vIr41lIxAIcV C0I7IYx2IY67AKxVWUJVWUCwCI42IY6xIIjxv20xvEc7CjxVAFwI0_Jr0_Gr1lIxAIcVCF 04k26cxKx2IYs7xG6r1j6r1xMIIF0xvEx4A2jsIE14v26r1j6r4UMIIF0xvEx4A2jsIEc7 CjxVAFwI0_Gr0_Gr1UYxBIdaVFxhVjvjDU0xZFpf9x07bYrchUUUUU= X-CM-SenderInfo: 5wdqw5prxox03j6o00pqjv00gofq/ Precedence: bulk List-ID: X-Mailing-List: linux-mips@vger.kernel.org Commit 9b492cf58077 ("kexec: introduce a protection mechanism for the crashkernel reserved memory") , provides a mechanism to protect the memory reserved by the crashed kernel. 1) After each crash kexec loading, it simply marks the reserved memory regions readonly since we no longer access it after that. When someone stamps the region, the first kernel will panic and trigger the kdump. This arch_kexec_protect_crashkres() will actually protect the reserved memory. 2) To allow multiple loading, once 1) was done we also need to remark the reserved memory to readwrite each time a system call related to kdump is made. This arch_kexec_unprotect_crashkres() will undo the protection of the reserved memory. Signed-off-by: Youling Tang --- arch/mips/kernel/machine_kexec.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/arch/mips/kernel/machine_kexec.c b/arch/mips/kernel/machine_kexec.c index 432bfd3..379c2c3 100644 --- a/arch/mips/kernel/machine_kexec.c +++ b/arch/mips/kernel/machine_kexec.c @@ -11,6 +11,7 @@ #include #include +#include extern const unsigned char relocate_new_kernel[]; extern const size_t relocate_new_kernel_size; @@ -205,6 +206,45 @@ void kexec_reboot(void) do_kexec(); } +static int +kexec_mark_range(unsigned long start, unsigned long end, bool protect) +{ + struct page *page; + unsigned int nr_pages; + + /* + * For physical range: [start, end]. We must skip the unassigned + * crashk resource with zero-valued "end" member. + */ + if (!end || start > end) + return 0; + + page = pfn_to_page(start >> PAGE_SHIFT); + nr_pages = (end >> PAGE_SHIFT) - (start >> PAGE_SHIFT) + 1; + if (protect) + return set_pages_ro(page, nr_pages); + else + return set_pages_rw(page, nr_pages); +} + +static void +kexec_mark_crashkres(bool protect) +{ + kexec_mark_range(crashk_res.start, crashk_res.end, protect); +} + +void +arch_kexec_protect_crashkres(void) +{ + kexec_mark_crashkres(true); +} + +void +arch_kexec_unprotect_crashkres(void) +{ + kexec_mark_crashkres(false); +} + void machine_kexec(struct kimage *image) {