Commit e2ae6340 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'riscv-for-linus-5.11-mw0' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux

Pull RISC-V updates from Palmer Dabbelt:
 "We have a handful of new kernel features for 5.11:

   - Support for the contiguous memory allocator.

   - Support for IRQ Time Accounting

   - Support for stack tracing

   - Support for strict /dev/mem

   - Support for kernel section protection

  I'm being a bit conservative on the cutoff for this round due to the
  timing, so this is all the new development I'm going to take for this
  cycle (even if some of it probably normally would have been OK). There
  are, however, some fixes on the list that I will likely be sending
  along either later this week or early next week.

  There is one issue in here: one of my test configurations
  (PREEMPT{,_DEBUG}=y) fails to boot on QEMU 5.0.0 (from April) as of
  the .text.init alignment patch.

  With any luck we'll sort out the issue, but given how many bugs get
  fixed all over the place and how unrelated those features seem my
  guess is that we're just running into something that's been lurking
  for a while and has already been fixed in the newer QEMU (though I
  wouldn't be surprised if it's one of these implicit assumptions we
  have in the boot flow). If it was hardware I'd be strongly inclined to
  look more closely, but given that users can upgrade their simulators
  I'm less worried about it"

* tag 'riscv-for-linus-5.11-mw0' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux:
  arm64: Use the generic devmem_is_allowed()
  arm: Use the generic devmem_is_allowed()
  RISC-V: Use the new generic devmem_is_allowed()
  lib: Add a generic version of devmem_is_allowed()
  riscv: Fixed kernel test robot warning
  riscv: kernel: Drop unused clean rule
  riscv: provide memmove implementation
  RISC-V: Move dynamic relocation section under __init
  RISC-V: Protect all kernel sections including init early
  RISC-V: Align the .init.text section
  RISC-V: Initialize SBI early
  riscv: Enable ARCH_STACKWALK
  riscv: Make stack walk callback consistent with generic code
  riscv: Cleanup stacktrace
  riscv: Add HAVE_IRQ_TIME_ACCOUNTING
  riscv: Enable CMA support
  riscv: Ignore Image.* and loader.bin
  riscv: Clean up boot dir
  riscv: Fix compressed Image formats build
  RISC-V: Add kernel image sections to the resource tree
parents a409ed15 7d95a88f
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
| openrisc: | TODO | | openrisc: | TODO |
| parisc: | .. | | parisc: | .. |
| powerpc: | ok | | powerpc: | ok |
| riscv: | TODO | | riscv: | ok |
| s390: | .. | | s390: | .. |
| sh: | TODO | | sh: | TODO |
| sparc: | .. | | sparc: | .. |
......
...@@ -5,7 +5,6 @@ config ARM ...@@ -5,7 +5,6 @@ config ARM
select ARCH_32BIT_OFF_T select ARCH_32BIT_OFF_T
select ARCH_HAS_BINFMT_FLAT select ARCH_HAS_BINFMT_FLAT
select ARCH_HAS_DEBUG_VIRTUAL if MMU select ARCH_HAS_DEBUG_VIRTUAL if MMU
select ARCH_HAS_DEVMEM_IS_ALLOWED
select ARCH_HAS_DMA_WRITE_COMBINE if !ARM_DMA_MEM_BUFFERABLE select ARCH_HAS_DMA_WRITE_COMBINE if !ARM_DMA_MEM_BUFFERABLE
select ARCH_HAS_ELF_RANDOMIZE select ARCH_HAS_ELF_RANDOMIZE
select ARCH_HAS_FORTIFY_SOURCE select ARCH_HAS_FORTIFY_SOURCE
...@@ -57,6 +56,7 @@ config ARM ...@@ -57,6 +56,7 @@ config ARM
select GENERIC_IRQ_PROBE select GENERIC_IRQ_PROBE
select GENERIC_IRQ_SHOW select GENERIC_IRQ_SHOW
select GENERIC_IRQ_SHOW_LEVEL select GENERIC_IRQ_SHOW_LEVEL
select GENERIC_LIB_DEVMEM_IS_ALLOWED
select GENERIC_PCI_IOMAP select GENERIC_PCI_IOMAP
select GENERIC_SCHED_CLOCK select GENERIC_SCHED_CLOCK
select GENERIC_SMP_IDLE_THREAD select GENERIC_SMP_IDLE_THREAD
......
...@@ -441,7 +441,6 @@ extern void pci_iounmap(struct pci_dev *dev, void __iomem *addr); ...@@ -441,7 +441,6 @@ extern void pci_iounmap(struct pci_dev *dev, void __iomem *addr);
#define ARCH_HAS_VALID_PHYS_ADDR_RANGE #define ARCH_HAS_VALID_PHYS_ADDR_RANGE
extern int valid_phys_addr_range(phys_addr_t addr, size_t size); extern int valid_phys_addr_range(phys_addr_t addr, size_t size);
extern int valid_mmap_phys_addr_range(unsigned long pfn, size_t size); extern int valid_mmap_phys_addr_range(unsigned long pfn, size_t size);
extern int devmem_is_allowed(unsigned long pfn);
#endif #endif
/* /*
......
...@@ -165,25 +165,3 @@ int valid_mmap_phys_addr_range(unsigned long pfn, size_t size) ...@@ -165,25 +165,3 @@ int valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
{ {
return (pfn + (size >> PAGE_SHIFT)) <= (1 + (PHYS_MASK >> PAGE_SHIFT)); return (pfn + (size >> PAGE_SHIFT)) <= (1 + (PHYS_MASK >> PAGE_SHIFT));
} }
#ifdef CONFIG_STRICT_DEVMEM
#include <linux/ioport.h>
/*
* devmem_is_allowed() checks to see if /dev/mem access to a certain
* address is valid. The argument is a physical page number.
* We mimic x86 here by disallowing access to system RAM as well as
* device-exclusive MMIO regions. This effectively disable read()/write()
* on /dev/mem.
*/
int devmem_is_allowed(unsigned long pfn)
{
if (iomem_is_exclusive(pfn << PAGE_SHIFT))
return 0;
if (!page_is_ram(pfn))
return 1;
return 0;
}
#endif
...@@ -13,7 +13,6 @@ config ARM64 ...@@ -13,7 +13,6 @@ config ARM64
select ARCH_BINFMT_ELF_STATE select ARCH_BINFMT_ELF_STATE
select ARCH_HAS_DEBUG_VIRTUAL select ARCH_HAS_DEBUG_VIRTUAL
select ARCH_HAS_DEBUG_VM_PGTABLE select ARCH_HAS_DEBUG_VM_PGTABLE
select ARCH_HAS_DEVMEM_IS_ALLOWED
select ARCH_HAS_DMA_PREP_COHERENT select ARCH_HAS_DMA_PREP_COHERENT
select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI
select ARCH_HAS_FAST_MULTIPLIER select ARCH_HAS_FAST_MULTIPLIER
...@@ -113,6 +112,7 @@ config ARM64 ...@@ -113,6 +112,7 @@ config ARM64
select GENERIC_IRQ_PROBE select GENERIC_IRQ_PROBE
select GENERIC_IRQ_SHOW select GENERIC_IRQ_SHOW
select GENERIC_IRQ_SHOW_LEVEL select GENERIC_IRQ_SHOW_LEVEL
select GENERIC_LIB_DEVMEM_IS_ALLOWED
select GENERIC_PCI_IOMAP select GENERIC_PCI_IOMAP
select GENERIC_PTDUMP select GENERIC_PTDUMP
select GENERIC_SCHED_CLOCK select GENERIC_SCHED_CLOCK
......
...@@ -201,6 +201,4 @@ extern void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size); ...@@ -201,6 +201,4 @@ extern void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size);
extern int valid_phys_addr_range(phys_addr_t addr, size_t size); extern int valid_phys_addr_range(phys_addr_t addr, size_t size);
extern int valid_mmap_phys_addr_range(unsigned long pfn, size_t size); extern int valid_mmap_phys_addr_range(unsigned long pfn, size_t size);
extern int devmem_is_allowed(unsigned long pfn);
#endif /* __ASM_IO_H */ #endif /* __ASM_IO_H */
...@@ -47,24 +47,3 @@ int valid_mmap_phys_addr_range(unsigned long pfn, size_t size) ...@@ -47,24 +47,3 @@ int valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
{ {
return !(((pfn << PAGE_SHIFT) + size) & ~PHYS_MASK); return !(((pfn << PAGE_SHIFT) + size) & ~PHYS_MASK);
} }
#ifdef CONFIG_STRICT_DEVMEM
#include <linux/ioport.h>
/*
* devmem_is_allowed() checks to see if /dev/mem access to a certain address
* is valid. The argument is a physical page number. We mimic x86 here by
* disallowing access to system RAM as well as device-exclusive MMIO regions.
* This effectively disable read()/write() on /dev/mem.
*/
int devmem_is_allowed(unsigned long pfn)
{
if (iomem_is_exclusive(pfn << PAGE_SHIFT))
return 0;
if (!page_is_ram(pfn))
return 1;
return 0;
}
#endif
...@@ -15,6 +15,7 @@ config RISCV ...@@ -15,6 +15,7 @@ config RISCV
select ARCH_CLOCKSOURCE_INIT select ARCH_CLOCKSOURCE_INIT
select ARCH_SUPPORTS_ATOMIC_RMW select ARCH_SUPPORTS_ATOMIC_RMW
select ARCH_SUPPORTS_DEBUG_PAGEALLOC if MMU select ARCH_SUPPORTS_DEBUG_PAGEALLOC if MMU
select ARCH_STACKWALK
select ARCH_HAS_BINFMT_FLAT select ARCH_HAS_BINFMT_FLAT
select ARCH_HAS_DEBUG_VM_PGTABLE select ARCH_HAS_DEBUG_VM_PGTABLE
select ARCH_HAS_DEBUG_VIRTUAL if MMU select ARCH_HAS_DEBUG_VIRTUAL if MMU
...@@ -43,6 +44,7 @@ config RISCV ...@@ -43,6 +44,7 @@ config RISCV
select GENERIC_IOREMAP select GENERIC_IOREMAP
select GENERIC_IRQ_MULTI_HANDLER select GENERIC_IRQ_MULTI_HANDLER
select GENERIC_IRQ_SHOW select GENERIC_IRQ_SHOW
select GENERIC_LIB_DEVMEM_IS_ALLOWED
select GENERIC_PCI_IOMAP select GENERIC_PCI_IOMAP
select GENERIC_PTDUMP if MMU select GENERIC_PTDUMP if MMU
select GENERIC_SCHED_CLOCK select GENERIC_SCHED_CLOCK
...@@ -68,6 +70,7 @@ config RISCV ...@@ -68,6 +70,7 @@ config RISCV
select HAVE_FUTEX_CMPXCHG if FUTEX select HAVE_FUTEX_CMPXCHG if FUTEX
select HAVE_GCC_PLUGINS select HAVE_GCC_PLUGINS
select HAVE_GENERIC_VDSO if MMU && 64BIT select HAVE_GENERIC_VDSO if MMU && 64BIT
select HAVE_IRQ_TIME_ACCOUNTING
select HAVE_PCI select HAVE_PCI
select HAVE_PERF_EVENTS select HAVE_PERF_EVENTS
select HAVE_PERF_REGS select HAVE_PERF_REGS
......
...@@ -96,5 +96,11 @@ $(BOOT_TARGETS): vmlinux ...@@ -96,5 +96,11 @@ $(BOOT_TARGETS): vmlinux
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
@$(kecho) ' Kernel: $(boot)/$@ is ready' @$(kecho) ' Kernel: $(boot)/$@ is ready'
Image.%: Image
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
zinstall install: zinstall install:
$(Q)$(MAKE) $(build)=$(boot) $@ $(Q)$(MAKE) $(build)=$(boot) $@
archclean:
$(Q)$(MAKE) $(clean)=$(boot)
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
Image Image
Image.gz Image.*
loader loader
loader.lds loader.lds
loader.bin
...@@ -18,7 +18,7 @@ KCOV_INSTRUMENT := n ...@@ -18,7 +18,7 @@ KCOV_INSTRUMENT := n
OBJCOPYFLAGS_Image :=-O binary -R .note -R .note.gnu.build-id -R .comment -S OBJCOPYFLAGS_Image :=-O binary -R .note -R .note.gnu.build-id -R .comment -S
targets := Image loader targets := Image Image.* loader loader.o loader.lds loader.bin
$(obj)/Image: vmlinux FORCE $(obj)/Image: vmlinux FORCE
$(call if_changed,objcopy) $(call if_changed,objcopy)
......
...@@ -9,5 +9,7 @@ ...@@ -9,5 +9,7 @@
extern char _start[]; extern char _start[];
extern char _start_kernel[]; extern char _start_kernel[];
extern char __init_data_begin[], __init_data_end[];
extern char __init_text_begin[], __init_text_end[];
#endif /* __ASM_SECTIONS_H */ #endif /* __ASM_SECTIONS_H */
...@@ -15,11 +15,15 @@ int set_memory_ro(unsigned long addr, int numpages); ...@@ -15,11 +15,15 @@ int set_memory_ro(unsigned long addr, int numpages);
int set_memory_rw(unsigned long addr, int numpages); int set_memory_rw(unsigned long addr, int numpages);
int set_memory_x(unsigned long addr, int numpages); int set_memory_x(unsigned long addr, int numpages);
int set_memory_nx(unsigned long addr, int numpages); int set_memory_nx(unsigned long addr, int numpages);
int set_memory_rw_nx(unsigned long addr, int numpages);
void protect_kernel_text_data(void);
#else #else
static inline int set_memory_ro(unsigned long addr, int numpages) { return 0; } static inline int set_memory_ro(unsigned long addr, int numpages) { return 0; }
static inline int set_memory_rw(unsigned long addr, int numpages) { return 0; } static inline int set_memory_rw(unsigned long addr, int numpages) { return 0; }
static inline int set_memory_x(unsigned long addr, int numpages) { return 0; } static inline int set_memory_x(unsigned long addr, int numpages) { return 0; }
static inline int set_memory_nx(unsigned long addr, int numpages) { return 0; } static inline int set_memory_nx(unsigned long addr, int numpages) { return 0; }
static inline void protect_kernel_text_data(void) {};
static inline int set_memory_rw_nx(unsigned long addr, int numpages) { return 0; }
#endif #endif
int set_direct_map_invalid_noflush(struct page *page); int set_direct_map_invalid_noflush(struct page *page);
......
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_RISCV_STACKTRACE_H
#define _ASM_RISCV_STACKTRACE_H
#include <linux/sched.h>
#include <asm/ptrace.h>
struct stackframe {
unsigned long fp;
unsigned long ra;
};
extern void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
bool (*fn)(void *, unsigned long), void *arg);
#endif /* _ASM_RISCV_STACKTRACE_H */
...@@ -12,16 +12,16 @@ ...@@ -12,16 +12,16 @@
#define __HAVE_ARCH_MEMSET #define __HAVE_ARCH_MEMSET
extern asmlinkage void *memset(void *, int, size_t); extern asmlinkage void *memset(void *, int, size_t);
extern asmlinkage void *__memset(void *, int, size_t); extern asmlinkage void *__memset(void *, int, size_t);
#define __HAVE_ARCH_MEMCPY #define __HAVE_ARCH_MEMCPY
extern asmlinkage void *memcpy(void *, const void *, size_t); extern asmlinkage void *memcpy(void *, const void *, size_t);
extern asmlinkage void *__memcpy(void *, const void *, size_t); extern asmlinkage void *__memcpy(void *, const void *, size_t);
#define __HAVE_ARCH_MEMMOVE
extern asmlinkage void *memmove(void *, const void *, size_t);
extern asmlinkage void *__memmove(void *, const void *, size_t);
/* For those files which don't want to check by kasan. */ /* For those files which don't want to check by kasan. */
#if defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__) #if defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__)
#define memcpy(dst, src, len) __memcpy(dst, src, len) #define memcpy(dst, src, len) __memcpy(dst, src, len)
#define memset(s, c, n) __memset(s, c, n) #define memset(s, c, n) __memset(s, c, n)
#define memmove(dst, src, len) __memmove(dst, src, len)
#endif #endif
#endif /* _ASM_RISCV_STRING_H */ #endif /* _ASM_RISCV_STRING_H */
...@@ -56,5 +56,3 @@ obj-$(CONFIG_KGDB) += kgdb.o ...@@ -56,5 +56,3 @@ obj-$(CONFIG_KGDB) += kgdb.o
obj-$(CONFIG_JUMP_LABEL) += jump_label.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o
obj-$(CONFIG_EFI) += efi.o obj-$(CONFIG_EFI) += efi.o
clean:
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
#include <asm/thread_info.h> #include <asm/thread_info.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>
void asm_offsets(void);
void asm_offsets(void) void asm_offsets(void)
{ {
OFFSET(TASK_THREAD_RA, task_struct, thread.ra); OFFSET(TASK_THREAD_RA, task_struct, thread.ra);
......
...@@ -182,7 +182,6 @@ setup_trap_vector: ...@@ -182,7 +182,6 @@ setup_trap_vector:
END(_start) END(_start)
__INIT
ENTRY(_start_kernel) ENTRY(_start_kernel)
/* Mask all interrupts */ /* Mask all interrupts */
csrw CSR_IE, zero csrw CSR_IE, zero
......
...@@ -4,11 +4,7 @@ ...@@ -4,11 +4,7 @@
#include <linux/perf_event.h> #include <linux/perf_event.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
/* Kernel callchain */ #include <asm/stacktrace.h>
struct stackframe {
unsigned long fp;
unsigned long ra;
};
/* /*
* Get the return address for a single stackframe and return a pointer to the * Get the return address for a single stackframe and return a pointer to the
...@@ -74,13 +70,11 @@ void perf_callchain_user(struct perf_callchain_entry_ctx *entry, ...@@ -74,13 +70,11 @@ void perf_callchain_user(struct perf_callchain_entry_ctx *entry,
fp = user_backtrace(entry, fp, 0); fp = user_backtrace(entry, fp, 0);
} }
bool fill_callchain(unsigned long pc, void *entry) static bool fill_callchain(void *entry, unsigned long pc)
{ {
return perf_callchain_store(entry, pc); return perf_callchain_store(entry, pc);
} }
void notrace walk_stackframe(struct task_struct *task,
struct pt_regs *regs, bool (*fn)(unsigned long, void *), void *arg);
void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
struct pt_regs *regs) struct pt_regs *regs)
{ {
......
...@@ -11,5 +11,7 @@ ...@@ -11,5 +11,7 @@
*/ */
EXPORT_SYMBOL(memset); EXPORT_SYMBOL(memset);
EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(memcpy);
EXPORT_SYMBOL(memmove);
EXPORT_SYMBOL(__memset); EXPORT_SYMBOL(__memset);
EXPORT_SYMBOL(__memcpy); EXPORT_SYMBOL(__memcpy);
EXPORT_SYMBOL(__memmove);
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
* Chen Liqin <liqin.chen@sunplusct.com> * Chen Liqin <liqin.chen@sunplusct.com>
* Lennox Wu <lennox.wu@sunplusct.com> * Lennox Wu <lennox.wu@sunplusct.com>
* Copyright (C) 2012 Regents of the University of California * Copyright (C) 2012 Regents of the University of California
* Copyright (C) 2020 FORTH-ICS/CARV
* Nick Kossifidis <mick@ics.forth.gr>
*/ */
#include <linux/init.h> #include <linux/init.h>
...@@ -22,6 +24,7 @@ ...@@ -22,6 +24,7 @@
#include <asm/cpu_ops.h> #include <asm/cpu_ops.h>
#include <asm/early_ioremap.h> #include <asm/early_ioremap.h>
#include <asm/setup.h> #include <asm/setup.h>
#include <asm/set_memory.h>
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/sbi.h> #include <asm/sbi.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
...@@ -51,6 +54,163 @@ atomic_t hart_lottery __section(".sdata"); ...@@ -51,6 +54,163 @@ atomic_t hart_lottery __section(".sdata");
unsigned long boot_cpu_hartid; unsigned long boot_cpu_hartid;
static DEFINE_PER_CPU(struct cpu, cpu_devices); static DEFINE_PER_CPU(struct cpu, cpu_devices);
/*
* Place kernel memory regions on the resource tree so that
* kexec-tools can retrieve them from /proc/iomem. While there
* also add "System RAM" regions for compatibility with other
* archs, and the rest of the known regions for completeness.
*/
static struct resource code_res = { .name = "Kernel code", };
static struct resource data_res = { .name = "Kernel data", };
static struct resource rodata_res = { .name = "Kernel rodata", };
static struct resource bss_res = { .name = "Kernel bss", };
static int __init add_resource(struct resource *parent,
struct resource *res)
{
int ret = 0;
ret = insert_resource(parent, res);
if (ret < 0) {
pr_err("Failed to add a %s resource at %llx\n",
res->name, (unsigned long long) res->start);
return ret;
}
return 1;
}
static int __init add_kernel_resources(struct resource *res)
{
int ret = 0;
/*
* The memory region of the kernel image is continuous and
* was reserved on setup_bootmem, find it here and register
* it as a resource, then register the various segments of
* the image as child nodes
*/
if (!(res->start <= code_res.start && res->end >= data_res.end))
return 0;
res->name = "Kernel image";
res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
/*
* We removed a part of this region on setup_bootmem so
* we need to expand the resource for the bss to fit in.
*/
res->end = bss_res.end;
ret = add_resource(&iomem_resource, res);
if (ret < 0)
return ret;
ret = add_resource(res, &code_res);
if (ret < 0)
return ret;
ret = add_resource(res, &rodata_res);
if (ret < 0)
return ret;
ret = add_resource(res, &data_res);
if (ret < 0)
return ret;
ret = add_resource(res, &bss_res);
return ret;
}
static void __init init_resources(void)
{
struct memblock_region *region = NULL;
struct resource *res = NULL;
int ret = 0;
code_res.start = __pa_symbol(_text);
code_res.end = __pa_symbol(_etext) - 1;
code_res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
rodata_res.start = __pa_symbol(__start_rodata);
rodata_res.end = __pa_symbol(__end_rodata) - 1;
rodata_res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
data_res.start = __pa_symbol(_data);
data_res.end = __pa_symbol(_edata) - 1;
data_res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
bss_res.start = __pa_symbol(__bss_start);
bss_res.end = __pa_symbol(__bss_stop) - 1;
bss_res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
/*
* Start by adding the reserved regions, if they overlap
* with /memory regions, insert_resource later on will take
* care of it.
*/
for_each_reserved_mem_region(region) {
res = memblock_alloc(sizeof(struct resource), SMP_CACHE_BYTES);
if (!res)
panic("%s: Failed to allocate %zu bytes\n", __func__,
sizeof(struct resource));
res->name = "Reserved";
res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
res->start = __pfn_to_phys(memblock_region_reserved_base_pfn(region));
res->end = __pfn_to_phys(memblock_region_reserved_end_pfn(region)) - 1;
ret = add_kernel_resources(res);
if (ret < 0)
goto error;
else if (ret)
continue;
/*
* Ignore any other reserved regions within
* system memory.
*/
if (memblock_is_memory(res->start))
continue;
ret = add_resource(&iomem_resource, res);
if (ret < 0)
goto error;
}
/* Add /memory regions to the resource tree */
for_each_mem_region(region) {
res = memblock_alloc(sizeof(struct resource), SMP_CACHE_BYTES);
if (!res)
panic("%s: Failed to allocate %zu bytes\n", __func__,
sizeof(struct resource));
if (unlikely(memblock_is_nomap(region))) {
res->name = "Reserved";
res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
} else {
res->name = "System RAM";
res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
}
res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region));
res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1;
ret = add_resource(&iomem_resource, res);
if (ret < 0)
goto error;
}
return;
error:
memblock_free((phys_addr_t) res, sizeof(struct resource));
/* Better an empty resource tree than an inconsistent one */
release_child_resources(&iomem_resource);
}
static void __init parse_dtb(void) static void __init parse_dtb(void)
{ {
/* Early scan of device tree from init memory */ /* Early scan of device tree from init memory */
...@@ -81,6 +241,7 @@ void __init setup_arch(char **cmdline_p) ...@@ -81,6 +241,7 @@ void __init setup_arch(char **cmdline_p)
efi_init(); efi_init();
setup_bootmem(); setup_bootmem();
paging_init(); paging_init();
init_resources();
#if IS_ENABLED(CONFIG_BUILTIN_DTB) #if IS_ENABLED(CONFIG_BUILTIN_DTB)
unflatten_and_copy_device_tree(); unflatten_and_copy_device_tree();
#else #else
...@@ -90,6 +251,11 @@ void __init setup_arch(char **cmdline_p) ...@@ -90,6 +251,11 @@ void __init setup_arch(char **cmdline_p)
pr_err("No DTB found in kernel mappings\n"); pr_err("No DTB found in kernel mappings\n");
#endif #endif
if (IS_ENABLED(CONFIG_RISCV_SBI))
sbi_init();
if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX))
protect_kernel_text_data();
#ifdef CONFIG_SWIOTLB #ifdef CONFIG_SWIOTLB
swiotlb_init(1); swiotlb_init(1);
#endif #endif
...@@ -98,10 +264,6 @@ void __init setup_arch(char **cmdline_p) ...@@ -98,10 +264,6 @@ void __init setup_arch(char **cmdline_p)
kasan_init(); kasan_init();
#endif #endif
#if IS_ENABLED(CONFIG_RISCV_SBI)
sbi_init();
#endif
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
setup_smp(); setup_smp();
#endif #endif
...@@ -123,3 +285,12 @@ static int __init topology_init(void) ...@@ -123,3 +285,12 @@ static int __init topology_init(void)
return 0; return 0;
} }
subsys_initcall(topology_init); subsys_initcall(topology_init);
void free_initmem(void)
{
unsigned long init_begin = (unsigned long)__init_begin;
unsigned long init_end = (unsigned long)__init_end;
set_memory_rw_nx(init_begin, (init_end - init_begin) >> PAGE_SHIFT);
free_initmem_default(POISON_FREE_INITMEM);
}
...@@ -12,17 +12,14 @@ ...@@ -12,17 +12,14 @@
#include <linux/stacktrace.h> #include <linux/stacktrace.h>
#include <linux/ftrace.h> #include <linux/ftrace.h>
#include <asm/stacktrace.h>
register unsigned long sp_in_global __asm__("sp"); register unsigned long sp_in_global __asm__("sp");
#ifdef CONFIG_FRAME_POINTER #ifdef CONFIG_FRAME_POINTER
struct stackframe {
unsigned long fp;
unsigned long ra;
};
void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs, void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
bool (*fn)(unsigned long, void *), void *arg) bool (*fn)(void *, unsigned long), void *arg)
{ {
unsigned long fp, sp, pc; unsigned long fp, sp, pc;
...@@ -46,7 +43,7 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs, ...@@ -46,7 +43,7 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
unsigned long low, high; unsigned long low, high;
struct stackframe *frame; struct stackframe *frame;
if (unlikely(!__kernel_text_address(pc) || fn(pc, arg))) if (unlikely(!__kernel_text_address(pc) || !fn(arg, pc)))
break; break;
/* Validate frame pointer */ /* Validate frame pointer */
...@@ -66,7 +63,7 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs, ...@@ -66,7 +63,7 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
#else /* !CONFIG_FRAME_POINTER */ #else /* !CONFIG_FRAME_POINTER */
void notrace walk_stackframe(struct task_struct *task, void notrace walk_stackframe(struct task_struct *task,
struct pt_regs *regs, bool (*fn)(unsigned long, void *), void *arg) struct pt_regs *regs, bool (*fn)(void *, unsigned long), void *arg)
{ {
unsigned long sp, pc; unsigned long sp, pc;
unsigned long *ksp; unsigned long *ksp;
...@@ -88,7 +85,7 @@ void notrace walk_stackframe(struct task_struct *task, ...@@ -88,7 +85,7 @@ void notrace walk_stackframe(struct task_struct *task,
ksp = (unsigned long *)sp; ksp = (unsigned long *)sp;
while (!kstack_end(ksp)) { while (!kstack_end(ksp)) {
if (__kernel_text_address(pc) && unlikely(fn(pc, arg))) if (__kernel_text_address(pc) && unlikely(!fn(arg, pc)))
break; break;
pc = (*ksp++) - 0x4; pc = (*ksp++) - 0x4;
} }
...@@ -96,13 +93,12 @@ void notrace walk_stackframe(struct task_struct *task, ...@@ -96,13 +93,12 @@ void notrace walk_stackframe(struct task_struct *task,
#endif /* CONFIG_FRAME_POINTER */ #endif /* CONFIG_FRAME_POINTER */
static bool print_trace_address(void *arg, unsigned long pc)
static bool print_trace_address(unsigned long pc, void *arg)
{ {
const char *loglvl = arg; const char *loglvl = arg;
print_ip_sym(loglvl, pc); print_ip_sym(loglvl, pc);
return false; return true;
} }
void show_stack(struct task_struct *task, unsigned long *sp, const char *loglvl) void show_stack(struct task_struct *task, unsigned long *sp, const char *loglvl)
...@@ -111,14 +107,14 @@ void show_stack(struct task_struct *task, unsigned long *sp, const char *loglvl) ...@@ -111,14 +107,14 @@ void show_stack(struct task_struct *task, unsigned long *sp, const char *loglvl)
walk_stackframe(task, NULL, print_trace_address, (void *)loglvl); walk_stackframe(task, NULL, print_trace_address, (void *)loglvl);
} }
static bool save_wchan(unsigned long pc, void *arg) static bool save_wchan(void *arg, unsigned long pc)
{ {
if (!in_sched_functions(pc)) { if (!in_sched_functions(pc)) {
unsigned long *p = arg; unsigned long *p = arg;
*p = pc; *p = pc;
return true; return false;
} }
return false; return true;
} }
unsigned long get_wchan(struct task_struct *task) unsigned long get_wchan(struct task_struct *task)
...@@ -130,42 +126,12 @@ unsigned long get_wchan(struct task_struct *task) ...@@ -130,42 +126,12 @@ unsigned long get_wchan(struct task_struct *task)
return pc; return pc;
} }
#ifdef CONFIG_STACKTRACE #ifdef CONFIG_STACKTRACE
static bool __save_trace(unsigned long pc, void *arg, bool nosched) void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie,
{ struct task_struct *task, struct pt_regs *regs)
struct stack_trace *trace = arg;
if (unlikely(nosched && in_sched_functions(pc)))
return false;
if (unlikely(trace->skip > 0)) {
trace->skip--;
return false;
}
trace->entries[trace->nr_entries++] = pc;
return (trace->nr_entries >= trace->max_entries);
}
static bool save_trace(unsigned long pc, void *arg)
{
return __save_trace(pc, arg, false);
}
/*
* Save stack-backtrace addresses into a stack_trace buffer.
*/
void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
{
walk_stackframe(tsk, NULL, save_trace, trace);
}
EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
void save_stack_trace(struct stack_trace *trace)
{ {
save_stack_trace_tsk(NULL, trace); walk_stackframe(task, regs, consume_entry, cookie);
} }
EXPORT_SYMBOL_GPL(save_stack_trace);
#endif /* CONFIG_STACKTRACE */ #endif /* CONFIG_STACKTRACE */
...@@ -29,8 +29,30 @@ SECTIONS ...@@ -29,8 +29,30 @@ SECTIONS
HEAD_TEXT_SECTION HEAD_TEXT_SECTION
. = ALIGN(PAGE_SIZE); . = ALIGN(PAGE_SIZE);
.text : {
_text = .;
_stext = .;
TEXT_TEXT
SCHED_TEXT
CPUIDLE_TEXT
LOCK_TEXT
KPROBES_TEXT
ENTRY_TEXT
IRQENTRY_TEXT
SOFTIRQENTRY_TEXT
*(.fixup)
_etext = .;
}
. = ALIGN(SECTION_ALIGN);
__init_begin = .; __init_begin = .;
INIT_TEXT_SECTION(PAGE_SIZE) __init_text_begin = .;
.init.text : AT(ADDR(.init.text) - LOAD_OFFSET) ALIGN(SECTION_ALIGN) { \
_sinittext = .; \
INIT_TEXT \
_einittext = .; \
}
. = ALIGN(8); . = ALIGN(8);
__soc_early_init_table : { __soc_early_init_table : {
__soc_early_init_table_start = .; __soc_early_init_table_start = .;
...@@ -47,35 +69,28 @@ SECTIONS ...@@ -47,35 +69,28 @@ SECTIONS
{ {
EXIT_TEXT EXIT_TEXT
} }
__init_text_end = .;
. = ALIGN(SECTION_ALIGN);
#ifdef CONFIG_EFI
. = ALIGN(PECOFF_SECTION_ALIGNMENT);
__pecoff_text_end = .;
#endif
/* Start of init data section */
__init_data_begin = .;
INIT_DATA_SECTION(16)
.exit.data : .exit.data :
{ {
EXIT_DATA EXIT_DATA
} }
PERCPU_SECTION(L1_CACHE_BYTES) PERCPU_SECTION(L1_CACHE_BYTES)
__init_end = .;
. = ALIGN(SECTION_ALIGN); .rel.dyn : {
.text : { *(.rel.dyn*)
_text = .;
_stext = .;
TEXT_TEXT
SCHED_TEXT
CPUIDLE_TEXT
LOCK_TEXT
KPROBES_TEXT
ENTRY_TEXT
IRQENTRY_TEXT
SOFTIRQENTRY_TEXT
*(.fixup)
_etext = .;
} }
#ifdef CONFIG_EFI __init_data_end = .;
. = ALIGN(PECOFF_SECTION_ALIGNMENT); __init_end = .;
__pecoff_text_end = .;
#endif
INIT_DATA_SECTION(16)
/* Start of data section */ /* Start of data section */
_sdata = .; _sdata = .;
...@@ -105,10 +120,6 @@ SECTIONS ...@@ -105,10 +120,6 @@ SECTIONS
BSS_SECTION(PAGE_SIZE, PAGE_SIZE, 0) BSS_SECTION(PAGE_SIZE, PAGE_SIZE, 0)
.rel.dyn : {
*(.rel.dyn*)
}
#ifdef CONFIG_EFI #ifdef CONFIG_EFI
. = ALIGN(PECOFF_SECTION_ALIGNMENT); . = ALIGN(PECOFF_SECTION_ALIGNMENT);
__pecoff_data_virt_size = ABSOLUTE(. - __pecoff_text_end); __pecoff_data_virt_size = ABSOLUTE(. - __pecoff_text_end);
......
...@@ -2,5 +2,6 @@ ...@@ -2,5 +2,6 @@
lib-y += delay.o lib-y += delay.o
lib-y += memcpy.o lib-y += memcpy.o
lib-y += memset.o lib-y += memset.o
lib-y += memmove.o
lib-$(CONFIG_MMU) += uaccess.o lib-$(CONFIG_MMU) += uaccess.o
lib-$(CONFIG_64BIT) += tishift.o lib-$(CONFIG_64BIT) += tishift.o
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/linkage.h>
#include <asm/asm.h>
ENTRY(__memmove)
WEAK(memmove)
move t0, a0
move t1, a1
beq a0, a1, exit_memcpy
beqz a2, exit_memcpy
srli t2, a2, 0x2
slt t3, a0, a1
beqz t3, do_reverse
andi a2, a2, 0x3
li t4, 1
beqz t2, byte_copy
word_copy:
lw t3, 0(a1)
addi t2, t2, -1
addi a1, a1, 4
sw t3, 0(a0)
addi a0, a0, 4
bnez t2, word_copy
beqz a2, exit_memcpy
j byte_copy
do_reverse:
add a0, a0, a2
add a1, a1, a2
andi a2, a2, 0x3
li t4, -1
beqz t2, reverse_byte_copy
reverse_word_copy:
addi a1, a1, -4
addi t2, t2, -1
lw t3, 0(a1)
addi a0, a0, -4
sw t3, 0(a0)
bnez t2, reverse_word_copy
beqz a2, exit_memcpy
reverse_byte_copy:
addi a0, a0, -1
addi a1, a1, -1
byte_copy:
lb t3, 0(a1)
addi a2, a2, -1
sb t3, 0(a0)
add a1, a1, t4
add a0, a0, t4
bnez a2, byte_copy
exit_memcpy:
move a0, t0
move a1, t1
ret
END(__memmove)
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/of_fdt.h> #include <linux/of_fdt.h>
#include <linux/libfdt.h> #include <linux/libfdt.h>
#include <linux/set_memory.h> #include <linux/set_memory.h>
#include <linux/dma-map-ops.h>
#include <asm/fixmap.h> #include <asm/fixmap.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
...@@ -41,13 +42,14 @@ struct pt_alloc_ops { ...@@ -41,13 +42,14 @@ struct pt_alloc_ops {
#endif #endif
}; };
static phys_addr_t dma32_phys_limit __ro_after_init;
static void __init zone_sizes_init(void) static void __init zone_sizes_init(void)
{ {
unsigned long max_zone_pfns[MAX_NR_ZONES] = { 0, }; unsigned long max_zone_pfns[MAX_NR_ZONES] = { 0, };
#ifdef CONFIG_ZONE_DMA32 #ifdef CONFIG_ZONE_DMA32
max_zone_pfns[ZONE_DMA32] = PFN_DOWN(min(4UL * SZ_1G, max_zone_pfns[ZONE_DMA32] = PFN_DOWN(dma32_phys_limit);
(unsigned long) PFN_PHYS(max_low_pfn)));
#endif #endif
max_zone_pfns[ZONE_NORMAL] = max_low_pfn; max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
...@@ -181,6 +183,7 @@ void __init setup_bootmem(void) ...@@ -181,6 +183,7 @@ void __init setup_bootmem(void)
max_pfn = PFN_DOWN(memblock_end_of_DRAM()); max_pfn = PFN_DOWN(memblock_end_of_DRAM());
max_low_pfn = max_pfn; max_low_pfn = max_pfn;
dma32_phys_limit = min(4UL * SZ_1G, (unsigned long)PFN_PHYS(max_low_pfn));
set_max_mapnr(max_low_pfn); set_max_mapnr(max_low_pfn);
#ifdef CONFIG_BLK_DEV_INITRD #ifdef CONFIG_BLK_DEV_INITRD
...@@ -194,6 +197,7 @@ void __init setup_bootmem(void) ...@@ -194,6 +197,7 @@ void __init setup_bootmem(void)
memblock_reserve(dtb_early_pa, fdt_totalsize(dtb_early_va)); memblock_reserve(dtb_early_pa, fdt_totalsize(dtb_early_va));
early_init_fdt_scan_reserved_mem(); early_init_fdt_scan_reserved_mem();
dma_contiguous_reserve(dma32_phys_limit);
memblock_allow_resize(); memblock_allow_resize();
memblock_dump_all(); memblock_dump_all();
} }
...@@ -618,48 +622,33 @@ static inline void setup_vm_final(void) ...@@ -618,48 +622,33 @@ static inline void setup_vm_final(void)
#endif /* CONFIG_MMU */ #endif /* CONFIG_MMU */
#ifdef CONFIG_STRICT_KERNEL_RWX #ifdef CONFIG_STRICT_KERNEL_RWX
void mark_rodata_ro(void) void protect_kernel_text_data(void)
{ {
unsigned long text_start = (unsigned long)_text; unsigned long text_start = (unsigned long)_start;
unsigned long text_end = (unsigned long)_etext; unsigned long init_text_start = (unsigned long)__init_text_begin;
unsigned long init_data_start = (unsigned long)__init_data_begin;
unsigned long rodata_start = (unsigned long)__start_rodata; unsigned long rodata_start = (unsigned long)__start_rodata;
unsigned long data_start = (unsigned long)_data; unsigned long data_start = (unsigned long)_data;
unsigned long max_low = (unsigned long)(__va(PFN_PHYS(max_low_pfn))); unsigned long max_low = (unsigned long)(__va(PFN_PHYS(max_low_pfn)));
set_memory_ro(text_start, (text_end - text_start) >> PAGE_SHIFT); set_memory_ro(text_start, (init_text_start - text_start) >> PAGE_SHIFT);
set_memory_ro(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT); set_memory_ro(init_text_start, (init_data_start - init_text_start) >> PAGE_SHIFT);
set_memory_nx(init_data_start, (rodata_start - init_data_start) >> PAGE_SHIFT);
/* rodata section is marked readonly in mark_rodata_ro */
set_memory_nx(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT); set_memory_nx(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT);
set_memory_nx(data_start, (max_low - data_start) >> PAGE_SHIFT); set_memory_nx(data_start, (max_low - data_start) >> PAGE_SHIFT);
debug_checkwx();
} }
#endif
static void __init resource_init(void) void mark_rodata_ro(void)
{ {
struct memblock_region *region; unsigned long rodata_start = (unsigned long)__start_rodata;
unsigned long data_start = (unsigned long)_data;
for_each_mem_region(region) {
struct resource *res;
res = memblock_alloc(sizeof(struct resource), SMP_CACHE_BYTES);
if (!res)
panic("%s: Failed to allocate %zu bytes\n", __func__,
sizeof(struct resource));
if (memblock_is_nomap(region)) { set_memory_ro(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT);
res->name = "reserved";
res->flags = IORESOURCE_MEM;
} else {
res->name = "System RAM";
res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
}
res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region));
res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1;
request_resource(&iomem_resource, res); debug_checkwx();
}
} }
#endif
void __init paging_init(void) void __init paging_init(void)
{ {
...@@ -667,7 +656,6 @@ void __init paging_init(void) ...@@ -667,7 +656,6 @@ void __init paging_init(void)
sparse_init(); sparse_init();
setup_zero_page(); setup_zero_page();
zone_sizes_init(); zone_sizes_init();
resource_init();
} }
#ifdef CONFIG_SPARSEMEM_VMEMMAP #ifdef CONFIG_SPARSEMEM_VMEMMAP
......
...@@ -128,6 +128,12 @@ static int __set_memory(unsigned long addr, int numpages, pgprot_t set_mask, ...@@ -128,6 +128,12 @@ static int __set_memory(unsigned long addr, int numpages, pgprot_t set_mask,
return ret; return ret;
} }
int set_memory_rw_nx(unsigned long addr, int numpages)
{
return __set_memory(addr, numpages, __pgprot(_PAGE_READ | _PAGE_WRITE),
__pgprot(_PAGE_EXEC));
}
int set_memory_ro(unsigned long addr, int numpages) int set_memory_ro(unsigned long addr, int numpages)
{ {
return __set_memory(addr, numpages, __pgprot(_PAGE_READ), return __set_memory(addr, numpages, __pgprot(_PAGE_READ),
......
...@@ -1137,6 +1137,10 @@ static inline void memcpy_toio(volatile void __iomem *addr, const void *buffer, ...@@ -1137,6 +1137,10 @@ static inline void memcpy_toio(volatile void __iomem *addr, const void *buffer,
} }
#endif #endif
#ifndef CONFIG_GENERIC_DEVMEM_IS_ALLOWED
extern int devmem_is_allowed(unsigned long pfn);
#endif
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* __ASM_GENERIC_IO_H */ #endif /* __ASM_GENERIC_IO_H */
...@@ -686,6 +686,9 @@ config GENERIC_LIB_CMPDI2 ...@@ -686,6 +686,9 @@ config GENERIC_LIB_CMPDI2
config GENERIC_LIB_UCMPDI2 config GENERIC_LIB_UCMPDI2
bool bool
config GENERIC_LIB_DEVMEM_IS_ALLOWED
bool
config PLDMFW config PLDMFW
bool bool
default n default n
...@@ -1676,7 +1676,7 @@ config ARCH_HAS_DEVMEM_IS_ALLOWED ...@@ -1676,7 +1676,7 @@ config ARCH_HAS_DEVMEM_IS_ALLOWED
config STRICT_DEVMEM config STRICT_DEVMEM
bool "Filter access to /dev/mem" bool "Filter access to /dev/mem"
depends on MMU && DEVMEM depends on MMU && DEVMEM
depends on ARCH_HAS_DEVMEM_IS_ALLOWED depends on ARCH_HAS_DEVMEM_IS_ALLOWED || GENERIC_LIB_DEVMEM_IS_ALLOWED
default y if PPC || X86 || ARM64 default y if PPC || X86 || ARM64
help help
If this option is disabled, you allow userspace (root) access to all If this option is disabled, you allow userspace (root) access to all
......
...@@ -354,3 +354,5 @@ obj-$(CONFIG_LIST_KUNIT_TEST) += list-test.o ...@@ -354,3 +354,5 @@ obj-$(CONFIG_LIST_KUNIT_TEST) += list-test.o
obj-$(CONFIG_LINEAR_RANGES_TEST) += test_linear_ranges.o obj-$(CONFIG_LINEAR_RANGES_TEST) += test_linear_ranges.o
obj-$(CONFIG_BITS_TEST) += test_bits.o obj-$(CONFIG_BITS_TEST) += test_bits.o
obj-$(CONFIG_CMDLINE_KUNIT_TEST) += cmdline_kunit.o obj-$(CONFIG_CMDLINE_KUNIT_TEST) += cmdline_kunit.o
obj-$(CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED) += devmem_is_allowed.o
// SPDX-License-Identifier: GPL-2.0-only
/*
* A generic version of devmem_is_allowed.
*
* Based on arch/arm64/mm/mmap.c
*
* Copyright (C) 2020 Google, Inc.
* Copyright (C) 2012 ARM Ltd.
*/
#include <linux/mm.h>
#include <linux/ioport.h>
/*
* devmem_is_allowed() checks to see if /dev/mem access to a certain address
* is valid. The argument is a physical page number. We mimic x86 here by
* disallowing access to system RAM as well as device-exclusive MMIO regions.
* This effectively disable read()/write() on /dev/mem.
*/
int devmem_is_allowed(unsigned long pfn)
{
if (iomem_is_exclusive(pfn << PAGE_SHIFT))
return 0;
if (!page_is_ram(pfn))
return 1;
return 0;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment