mirror of
https://github.com/torvalds/linux.git
synced 2024-12-30 14:52:05 +00:00
RISC-V Patches for the 5.11 Merge Window, Part 1
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. There are two merge conflicts, both in build files. They're both a bit clunky: arch/riscv/Kconfig is out of order (I have a script that's supposed to keep them in order, I'll fix it) and lib/Makefile is out of order (though GENERIC_LIB here doesn't mean quite what it does above). -----BEGIN PGP SIGNATURE----- iQJHBAABCgAxFiEEKzw3R0RoQ7JKlDp6LhMZ81+7GIkFAl/cHO4THHBhbG1lckBk YWJiZWx0LmNvbQAKCRAuExnzX7sYiTlmD/4uDyNHBM1XH/XD4fSEwTYJvGLqt/Jo vtrGR/fm0SlQFUKCcywSzxcVAeGn56CACbEIDYLuL4xXRJmbwEuaRrHVx2sEhS9p pNhy+wus/SgDz5EUAawMyR2AEWgzl77hY5T/+AAo4yv65SGGBfsIdz5noIVwGNqW r0g5cw2O99z0vwu1aSrK4isWHconG9MfQnnVyepPSh67pyWS4aUCr1K3vLiqD2dE XcgtwdcgzUIY5aEoJNrWo5qTrcaG8m6MRNCDAKJ6MKdDA2wdGIN868G0wQnoURRm Y+yW7w3P20kM0b87zH50jujTWg38NBKOfaXb0mAfawZMapL60veTVmvs2kNtFXCy F6JWRkgTiRnGY72FtRR0igWXT5M7fz0EiLFXLMItGcgj79TUget4l/3sRMN47S/O cA/WiwptJH3mh8IkL6z5ZxWEThdOrbFt8F1T+Gyq/ayblcPnJaLn/wrWoeOwviWR fvEC7smuF5SBTbWZK5tBOP21Nvhb7bfr49Sgr8Tvdjl15tz97qK+2tsLXwkBoQnJ wU45jcXfzr5wgiGBOQANRite5bLsJ0TuOrTgA5gsGpv+JSDGbpcJbm0833x00nX/ 3GsW5xr+vsLCvljgPAtKsyDNRlGQu908Gxrat2+s8u92bLr1bwn30uKL5h6i/n1w QgWATuPPGXZZdw== =GWIH -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
e2ae634014
@ -23,7 +23,7 @@
|
||||
| openrisc: | TODO |
|
||||
| parisc: | .. |
|
||||
| powerpc: | ok |
|
||||
| riscv: | TODO |
|
||||
| riscv: | ok |
|
||||
| s390: | .. |
|
||||
| sh: | TODO |
|
||||
| sparc: | .. |
|
||||
|
@ -5,7 +5,6 @@ config ARM
|
||||
select ARCH_32BIT_OFF_T
|
||||
select ARCH_HAS_BINFMT_FLAT
|
||||
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_ELF_RANDOMIZE
|
||||
select ARCH_HAS_FORTIFY_SOURCE
|
||||
@ -57,6 +56,7 @@ config ARM
|
||||
select GENERIC_IRQ_PROBE
|
||||
select GENERIC_IRQ_SHOW
|
||||
select GENERIC_IRQ_SHOW_LEVEL
|
||||
select GENERIC_LIB_DEVMEM_IS_ALLOWED
|
||||
select GENERIC_PCI_IOMAP
|
||||
select GENERIC_SCHED_CLOCK
|
||||
select GENERIC_SMP_IDLE_THREAD
|
||||
|
@ -441,7 +441,6 @@ extern void pci_iounmap(struct pci_dev *dev, void __iomem *addr);
|
||||
#define ARCH_HAS_VALID_PHYS_ADDR_RANGE
|
||||
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 devmem_is_allowed(unsigned long pfn);
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
#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
|
||||
select ARCH_BINFMT_ELF_STATE
|
||||
select ARCH_HAS_DEBUG_VIRTUAL
|
||||
select ARCH_HAS_DEBUG_VM_PGTABLE
|
||||
select ARCH_HAS_DEVMEM_IS_ALLOWED
|
||||
select ARCH_HAS_DMA_PREP_COHERENT
|
||||
select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI
|
||||
select ARCH_HAS_FAST_MULTIPLIER
|
||||
@ -113,6 +112,7 @@ config ARM64
|
||||
select GENERIC_IRQ_PROBE
|
||||
select GENERIC_IRQ_SHOW
|
||||
select GENERIC_IRQ_SHOW_LEVEL
|
||||
select GENERIC_LIB_DEVMEM_IS_ALLOWED
|
||||
select GENERIC_PCI_IOMAP
|
||||
select GENERIC_PTDUMP
|
||||
select GENERIC_SCHED_CLOCK
|
||||
|
@ -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_mmap_phys_addr_range(unsigned long pfn, size_t size);
|
||||
|
||||
extern int devmem_is_allowed(unsigned long pfn);
|
||||
|
||||
#endif /* __ASM_IO_H */
|
||||
|
@ -47,24 +47,3 @@ int valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
|
||||
{
|
||||
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
|
||||
select ARCH_CLOCKSOURCE_INIT
|
||||
select ARCH_SUPPORTS_ATOMIC_RMW
|
||||
select ARCH_SUPPORTS_DEBUG_PAGEALLOC if MMU
|
||||
select ARCH_STACKWALK
|
||||
select ARCH_HAS_BINFMT_FLAT
|
||||
select ARCH_HAS_DEBUG_VM_PGTABLE
|
||||
select ARCH_HAS_DEBUG_VIRTUAL if MMU
|
||||
@ -43,6 +44,7 @@ config RISCV
|
||||
select GENERIC_IOREMAP
|
||||
select GENERIC_IRQ_MULTI_HANDLER
|
||||
select GENERIC_IRQ_SHOW
|
||||
select GENERIC_LIB_DEVMEM_IS_ALLOWED
|
||||
select GENERIC_PCI_IOMAP
|
||||
select GENERIC_PTDUMP if MMU
|
||||
select GENERIC_SCHED_CLOCK
|
||||
@ -68,6 +70,7 @@ config RISCV
|
||||
select HAVE_FUTEX_CMPXCHG if FUTEX
|
||||
select HAVE_GCC_PLUGINS
|
||||
select HAVE_GENERIC_VDSO if MMU && 64BIT
|
||||
select HAVE_IRQ_TIME_ACCOUNTING
|
||||
select HAVE_PCI
|
||||
select HAVE_PERF_EVENTS
|
||||
select HAVE_PERF_REGS
|
||||
|
@ -96,5 +96,11 @@ $(BOOT_TARGETS): vmlinux
|
||||
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
|
||||
@$(kecho) ' Kernel: $(boot)/$@ is ready'
|
||||
|
||||
Image.%: Image
|
||||
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
|
||||
|
||||
zinstall install:
|
||||
$(Q)$(MAKE) $(build)=$(boot) $@
|
||||
|
||||
archclean:
|
||||
$(Q)$(MAKE) $(clean)=$(boot)
|
||||
|
3
arch/riscv/boot/.gitignore
vendored
3
arch/riscv/boot/.gitignore
vendored
@ -1,5 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
Image
|
||||
Image.gz
|
||||
Image.*
|
||||
loader
|
||||
loader.lds
|
||||
loader.bin
|
||||
|
@ -18,7 +18,7 @@ KCOV_INSTRUMENT := n
|
||||
|
||||
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
|
||||
$(call if_changed,objcopy)
|
||||
|
@ -9,5 +9,7 @@
|
||||
|
||||
extern char _start[];
|
||||
extern char _start_kernel[];
|
||||
extern char __init_data_begin[], __init_data_end[];
|
||||
extern char __init_text_begin[], __init_text_end[];
|
||||
|
||||
#endif /* __ASM_SECTIONS_H */
|
||||
|
@ -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_x(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
|
||||
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_x(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
|
||||
|
||||
int set_direct_map_invalid_noflush(struct page *page);
|
||||
|
17
arch/riscv/include/asm/stacktrace.h
Normal file
17
arch/riscv/include/asm/stacktrace.h
Normal file
@ -0,0 +1,17 @@
|
||||
/* 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 @@
|
||||
#define __HAVE_ARCH_MEMSET
|
||||
extern asmlinkage void *memset(void *, int, size_t);
|
||||
extern asmlinkage void *__memset(void *, int, size_t);
|
||||
|
||||
#define __HAVE_ARCH_MEMCPY
|
||||
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. */
|
||||
#if defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__)
|
||||
|
||||
#define memcpy(dst, src, len) __memcpy(dst, src, len)
|
||||
#define memset(s, c, n) __memset(s, c, n)
|
||||
|
||||
#define memmove(dst, src, len) __memmove(dst, src, len)
|
||||
#endif
|
||||
#endif /* _ASM_RISCV_STRING_H */
|
||||
|
@ -56,5 +56,3 @@ obj-$(CONFIG_KGDB) += kgdb.o
|
||||
obj-$(CONFIG_JUMP_LABEL) += jump_label.o
|
||||
|
||||
obj-$(CONFIG_EFI) += efi.o
|
||||
|
||||
clean:
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include <asm/thread_info.h>
|
||||
#include <asm/ptrace.h>
|
||||
|
||||
void asm_offsets(void);
|
||||
|
||||
void asm_offsets(void)
|
||||
{
|
||||
OFFSET(TASK_THREAD_RA, task_struct, thread.ra);
|
||||
|
@ -182,7 +182,6 @@ setup_trap_vector:
|
||||
|
||||
END(_start)
|
||||
|
||||
__INIT
|
||||
ENTRY(_start_kernel)
|
||||
/* Mask all interrupts */
|
||||
csrw CSR_IE, zero
|
||||
|
@ -4,11 +4,7 @@
|
||||
#include <linux/perf_event.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
/* Kernel callchain */
|
||||
struct stackframe {
|
||||
unsigned long fp;
|
||||
unsigned long ra;
|
||||
};
|
||||
#include <asm/stacktrace.h>
|
||||
|
||||
/*
|
||||
* 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,
|
||||
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);
|
||||
}
|
||||
|
||||
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,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
|
@ -11,5 +11,7 @@
|
||||
*/
|
||||
EXPORT_SYMBOL(memset);
|
||||
EXPORT_SYMBOL(memcpy);
|
||||
EXPORT_SYMBOL(memmove);
|
||||
EXPORT_SYMBOL(__memset);
|
||||
EXPORT_SYMBOL(__memcpy);
|
||||
EXPORT_SYMBOL(__memmove);
|
||||
|
@ -4,6 +4,8 @@
|
||||
* Chen Liqin <liqin.chen@sunplusct.com>
|
||||
* Lennox Wu <lennox.wu@sunplusct.com>
|
||||
* 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>
|
||||
@ -22,6 +24,7 @@
|
||||
#include <asm/cpu_ops.h>
|
||||
#include <asm/early_ioremap.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/set_memory.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/sbi.h>
|
||||
#include <asm/tlbflush.h>
|
||||
@ -51,6 +54,163 @@ atomic_t hart_lottery __section(".sdata");
|
||||
unsigned long boot_cpu_hartid;
|
||||
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)
|
||||
{
|
||||
/* Early scan of device tree from init memory */
|
||||
@ -81,6 +241,7 @@ void __init setup_arch(char **cmdline_p)
|
||||
efi_init();
|
||||
setup_bootmem();
|
||||
paging_init();
|
||||
init_resources();
|
||||
#if IS_ENABLED(CONFIG_BUILTIN_DTB)
|
||||
unflatten_and_copy_device_tree();
|
||||
#else
|
||||
@ -90,6 +251,11 @@ void __init setup_arch(char **cmdline_p)
|
||||
pr_err("No DTB found in kernel mappings\n");
|
||||
#endif
|
||||
|
||||
if (IS_ENABLED(CONFIG_RISCV_SBI))
|
||||
sbi_init();
|
||||
|
||||
if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX))
|
||||
protect_kernel_text_data();
|
||||
#ifdef CONFIG_SWIOTLB
|
||||
swiotlb_init(1);
|
||||
#endif
|
||||
@ -98,10 +264,6 @@ void __init setup_arch(char **cmdline_p)
|
||||
kasan_init();
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_RISCV_SBI)
|
||||
sbi_init();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
setup_smp();
|
||||
#endif
|
||||
@ -123,3 +285,12 @@ static int __init topology_init(void)
|
||||
return 0;
|
||||
}
|
||||
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 @@
|
||||
#include <linux/stacktrace.h>
|
||||
#include <linux/ftrace.h>
|
||||
|
||||
#include <asm/stacktrace.h>
|
||||
|
||||
register unsigned long sp_in_global __asm__("sp");
|
||||
|
||||
#ifdef CONFIG_FRAME_POINTER
|
||||
|
||||
struct stackframe {
|
||||
unsigned long fp;
|
||||
unsigned long ra;
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
@ -46,7 +43,7 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
|
||||
unsigned long low, high;
|
||||
struct stackframe *frame;
|
||||
|
||||
if (unlikely(!__kernel_text_address(pc) || fn(pc, arg)))
|
||||
if (unlikely(!__kernel_text_address(pc) || !fn(arg, pc)))
|
||||
break;
|
||||
|
||||
/* Validate frame pointer */
|
||||
@ -66,7 +63,7 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
|
||||
#else /* !CONFIG_FRAME_POINTER */
|
||||
|
||||
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 *ksp;
|
||||
@ -88,7 +85,7 @@ void notrace walk_stackframe(struct task_struct *task,
|
||||
|
||||
ksp = (unsigned long *)sp;
|
||||
while (!kstack_end(ksp)) {
|
||||
if (__kernel_text_address(pc) && unlikely(fn(pc, arg)))
|
||||
if (__kernel_text_address(pc) && unlikely(!fn(arg, pc)))
|
||||
break;
|
||||
pc = (*ksp++) - 0x4;
|
||||
}
|
||||
@ -96,13 +93,12 @@ void notrace walk_stackframe(struct task_struct *task,
|
||||
|
||||
#endif /* CONFIG_FRAME_POINTER */
|
||||
|
||||
|
||||
static bool print_trace_address(unsigned long pc, void *arg)
|
||||
static bool print_trace_address(void *arg, unsigned long pc)
|
||||
{
|
||||
const char *loglvl = arg;
|
||||
|
||||
print_ip_sym(loglvl, pc);
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static bool save_wchan(unsigned long pc, void *arg)
|
||||
static bool save_wchan(void *arg, unsigned long pc)
|
||||
{
|
||||
if (!in_sched_functions(pc)) {
|
||||
unsigned long *p = arg;
|
||||
*p = pc;
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned long get_wchan(struct task_struct *task)
|
||||
@ -130,42 +126,12 @@ unsigned long get_wchan(struct task_struct *task)
|
||||
return pc;
|
||||
}
|
||||
|
||||
|
||||
#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);
|
||||
walk_stackframe(task, regs, consume_entry, cookie);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(save_stack_trace);
|
||||
|
||||
#endif /* CONFIG_STACKTRACE */
|
||||
|
@ -29,8 +29,30 @@ SECTIONS
|
||||
HEAD_TEXT_SECTION
|
||||
. = 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_TEXT_SECTION(PAGE_SIZE)
|
||||
__init_text_begin = .;
|
||||
.init.text : AT(ADDR(.init.text) - LOAD_OFFSET) ALIGN(SECTION_ALIGN) { \
|
||||
_sinittext = .; \
|
||||
INIT_TEXT \
|
||||
_einittext = .; \
|
||||
}
|
||||
|
||||
. = ALIGN(8);
|
||||
__soc_early_init_table : {
|
||||
__soc_early_init_table_start = .;
|
||||
@ -47,35 +69,28 @@ SECTIONS
|
||||
{
|
||||
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
|
||||
}
|
||||
PERCPU_SECTION(L1_CACHE_BYTES)
|
||||
__init_end = .;
|
||||
|
||||
. = ALIGN(SECTION_ALIGN);
|
||||
.text : {
|
||||
_text = .;
|
||||
_stext = .;
|
||||
TEXT_TEXT
|
||||
SCHED_TEXT
|
||||
CPUIDLE_TEXT
|
||||
LOCK_TEXT
|
||||
KPROBES_TEXT
|
||||
ENTRY_TEXT
|
||||
IRQENTRY_TEXT
|
||||
SOFTIRQENTRY_TEXT
|
||||
*(.fixup)
|
||||
_etext = .;
|
||||
.rel.dyn : {
|
||||
*(.rel.dyn*)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EFI
|
||||
. = ALIGN(PECOFF_SECTION_ALIGNMENT);
|
||||
__pecoff_text_end = .;
|
||||
#endif
|
||||
|
||||
INIT_DATA_SECTION(16)
|
||||
__init_data_end = .;
|
||||
__init_end = .;
|
||||
|
||||
/* Start of data section */
|
||||
_sdata = .;
|
||||
@ -105,10 +120,6 @@ SECTIONS
|
||||
|
||||
BSS_SECTION(PAGE_SIZE, PAGE_SIZE, 0)
|
||||
|
||||
.rel.dyn : {
|
||||
*(.rel.dyn*)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EFI
|
||||
. = ALIGN(PECOFF_SECTION_ALIGNMENT);
|
||||
__pecoff_data_virt_size = ABSOLUTE(. - __pecoff_text_end);
|
||||
|
@ -2,5 +2,6 @@
|
||||
lib-y += delay.o
|
||||
lib-y += memcpy.o
|
||||
lib-y += memset.o
|
||||
lib-y += memmove.o
|
||||
lib-$(CONFIG_MMU) += uaccess.o
|
||||
lib-$(CONFIG_64BIT) += tishift.o
|
||||
|
64
arch/riscv/lib/memmove.S
Normal file
64
arch/riscv/lib/memmove.S
Normal file
@ -0,0 +1,64 @@
|
||||
/* 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 @@
|
||||
#include <linux/of_fdt.h>
|
||||
#include <linux/libfdt.h>
|
||||
#include <linux/set_memory.h>
|
||||
#include <linux/dma-map-ops.h>
|
||||
|
||||
#include <asm/fixmap.h>
|
||||
#include <asm/tlbflush.h>
|
||||
@ -41,13 +42,14 @@ struct pt_alloc_ops {
|
||||
#endif
|
||||
};
|
||||
|
||||
static phys_addr_t dma32_phys_limit __ro_after_init;
|
||||
|
||||
static void __init zone_sizes_init(void)
|
||||
{
|
||||
unsigned long max_zone_pfns[MAX_NR_ZONES] = { 0, };
|
||||
|
||||
#ifdef CONFIG_ZONE_DMA32
|
||||
max_zone_pfns[ZONE_DMA32] = PFN_DOWN(min(4UL * SZ_1G,
|
||||
(unsigned long) PFN_PHYS(max_low_pfn)));
|
||||
max_zone_pfns[ZONE_DMA32] = PFN_DOWN(dma32_phys_limit);
|
||||
#endif
|
||||
max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
|
||||
|
||||
@ -181,6 +183,7 @@ void __init setup_bootmem(void)
|
||||
|
||||
max_pfn = PFN_DOWN(memblock_end_of_DRAM());
|
||||
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);
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_INITRD
|
||||
@ -194,6 +197,7 @@ void __init setup_bootmem(void)
|
||||
memblock_reserve(dtb_early_pa, fdt_totalsize(dtb_early_va));
|
||||
|
||||
early_init_fdt_scan_reserved_mem();
|
||||
dma_contiguous_reserve(dma32_phys_limit);
|
||||
memblock_allow_resize();
|
||||
memblock_dump_all();
|
||||
}
|
||||
@ -618,56 +622,40 @@ static inline void setup_vm_final(void)
|
||||
#endif /* CONFIG_MMU */
|
||||
|
||||
#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_end = (unsigned long)_etext;
|
||||
unsigned long text_start = (unsigned long)_start;
|
||||
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 data_start = (unsigned long)_data;
|
||||
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(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT);
|
||||
set_memory_ro(text_start, (init_text_start - text_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(data_start, (max_low - data_start) >> PAGE_SHIFT);
|
||||
}
|
||||
|
||||
void mark_rodata_ro(void)
|
||||
{
|
||||
unsigned long rodata_start = (unsigned long)__start_rodata;
|
||||
unsigned long data_start = (unsigned long)_data;
|
||||
|
||||
set_memory_ro(rodata_start, (data_start - rodata_start) >> PAGE_SHIFT);
|
||||
|
||||
debug_checkwx();
|
||||
}
|
||||
#endif
|
||||
|
||||
static void __init resource_init(void)
|
||||
{
|
||||
struct memblock_region *region;
|
||||
|
||||
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)) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void __init paging_init(void)
|
||||
{
|
||||
setup_vm_final();
|
||||
sparse_init();
|
||||
setup_zero_page();
|
||||
zone_sizes_init();
|
||||
resource_init();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPARSEMEM_VMEMMAP
|
||||
|
@ -128,6 +128,12 @@ static int __set_memory(unsigned long addr, int numpages, pgprot_t set_mask,
|
||||
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)
|
||||
{
|
||||
return __set_memory(addr, numpages, __pgprot(_PAGE_READ),
|
||||
|
@ -1137,6 +1137,10 @@ static inline void memcpy_toio(volatile void __iomem *addr, const void *buffer,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_GENERIC_DEVMEM_IS_ALLOWED
|
||||
extern int devmem_is_allowed(unsigned long pfn);
|
||||
#endif
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* __ASM_GENERIC_IO_H */
|
||||
|
@ -686,6 +686,9 @@ config GENERIC_LIB_CMPDI2
|
||||
config GENERIC_LIB_UCMPDI2
|
||||
bool
|
||||
|
||||
config GENERIC_LIB_DEVMEM_IS_ALLOWED
|
||||
bool
|
||||
|
||||
config PLDMFW
|
||||
bool
|
||||
default n
|
||||
|
@ -1676,7 +1676,7 @@ config ARCH_HAS_DEVMEM_IS_ALLOWED
|
||||
config STRICT_DEVMEM
|
||||
bool "Filter access to /dev/mem"
|
||||
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
|
||||
help
|
||||
If this option is disabled, you allow userspace (root) access to all
|
||||
|
@ -354,3 +354,5 @@ obj-$(CONFIG_LIST_KUNIT_TEST) += list-test.o
|
||||
obj-$(CONFIG_LINEAR_RANGES_TEST) += test_linear_ranges.o
|
||||
obj-$(CONFIG_BITS_TEST) += test_bits.o
|
||||
obj-$(CONFIG_CMDLINE_KUNIT_TEST) += cmdline_kunit.o
|
||||
|
||||
obj-$(CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED) += devmem_is_allowed.o
|
||||
|
27
lib/devmem_is_allowed.c
Normal file
27
lib/devmem_is_allowed.c
Normal file
@ -0,0 +1,27 @@
|
||||
// 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user