mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-10 12:57:06 +09:00
Merge branch 'linux-linaro-lsk' into linux-linaro-lsk-android
This commit is contained in:
@@ -451,205 +451,6 @@
|
||||
};
|
||||
};
|
||||
|
||||
etb@0,20010000 {
|
||||
compatible = "arm,coresight-etb10", "arm,primecell";
|
||||
reg = <0 0x20010000 0 0x1000>;
|
||||
|
||||
coresight-default-sink;
|
||||
clocks = <&oscclk6a>;
|
||||
clock-names = "apb_pclk";
|
||||
port {
|
||||
etb_in_port: endpoint@0 {
|
||||
slave-mode;
|
||||
remote-endpoint = <&replicator_out_port0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
tpiu@0,20030000 {
|
||||
compatible = "arm,coresight-tpiu", "arm,primecell";
|
||||
reg = <0 0x20030000 0 0x1000>;
|
||||
|
||||
clocks = <&oscclk6a>;
|
||||
clock-names = "apb_pclk";
|
||||
port {
|
||||
tpiu_in_port: endpoint@0 {
|
||||
slave-mode;
|
||||
remote-endpoint = <&replicator_out_port1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
replicator {
|
||||
/* non-configurable replicators don't show up on the
|
||||
* AMBA bus. As such no need to add "arm,primecell".
|
||||
*/
|
||||
compatible = "arm,coresight-replicator";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
/* replicator output ports */
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
replicator_out_port0: endpoint {
|
||||
remote-endpoint = <&etb_in_port>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
replicator_out_port1: endpoint {
|
||||
remote-endpoint = <&tpiu_in_port>;
|
||||
};
|
||||
};
|
||||
|
||||
/* replicator input port */
|
||||
port@2 {
|
||||
reg = <0>;
|
||||
replicator_in_port0: endpoint {
|
||||
slave-mode;
|
||||
remote-endpoint = <&funnel_out_port0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
funnel@0,20040000 {
|
||||
compatible = "arm,coresight-funnel", "arm,primecell";
|
||||
reg = <0 0x20040000 0 0x1000>;
|
||||
|
||||
clocks = <&oscclk6a>;
|
||||
clock-names = "apb_pclk";
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
/* funnel output port */
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
funnel_out_port0: endpoint {
|
||||
remote-endpoint =
|
||||
<&replicator_in_port0>;
|
||||
};
|
||||
};
|
||||
|
||||
/* funnel input ports */
|
||||
port@1 {
|
||||
reg = <0>;
|
||||
funnel_in_port0: endpoint {
|
||||
slave-mode;
|
||||
remote-endpoint = <&ptm0_out_port>;
|
||||
};
|
||||
};
|
||||
|
||||
port@2 {
|
||||
reg = <1>;
|
||||
funnel_in_port1: endpoint {
|
||||
slave-mode;
|
||||
remote-endpoint = <&ptm1_out_port>;
|
||||
};
|
||||
};
|
||||
|
||||
port@3 {
|
||||
reg = <2>;
|
||||
funnel_in_port2: endpoint {
|
||||
slave-mode;
|
||||
remote-endpoint = <&etm0_out_port>;
|
||||
};
|
||||
};
|
||||
|
||||
/* Input port #3 is for ITM, not supported here */
|
||||
|
||||
port@4 {
|
||||
reg = <4>;
|
||||
funnel_in_port4: endpoint {
|
||||
slave-mode;
|
||||
remote-endpoint = <&etm1_out_port>;
|
||||
};
|
||||
};
|
||||
|
||||
port@5 {
|
||||
reg = <5>;
|
||||
funnel_in_port5: endpoint {
|
||||
slave-mode;
|
||||
remote-endpoint = <&etm2_out_port>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
ptm@0,2201c000 {
|
||||
compatible = "arm,coresight-etm3x", "arm,primecell";
|
||||
reg = <0 0x2201c000 0 0x1000>;
|
||||
|
||||
cpu = <&cpu0>;
|
||||
clocks = <&oscclk6a>;
|
||||
clock-names = "apb_pclk";
|
||||
port {
|
||||
ptm0_out_port: endpoint {
|
||||
remote-endpoint = <&funnel_in_port0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
ptm@0,2201d000 {
|
||||
compatible = "arm,coresight-etm3x", "arm,primecell";
|
||||
reg = <0 0x2201d000 0 0x1000>;
|
||||
|
||||
cpu = <&cpu1>;
|
||||
clocks = <&oscclk6a>;
|
||||
clock-names = "apb_pclk";
|
||||
port {
|
||||
ptm1_out_port: endpoint {
|
||||
remote-endpoint = <&funnel_in_port1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
etm@0,2203c000 {
|
||||
compatible = "arm,coresight-etm3x", "arm,primecell";
|
||||
reg = <0 0x2203c000 0 0x1000>;
|
||||
|
||||
cpu = <&cpu2>;
|
||||
clocks = <&oscclk6a>;
|
||||
clock-names = "apb_pclk";
|
||||
port {
|
||||
etm0_out_port: endpoint {
|
||||
remote-endpoint = <&funnel_in_port2>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
etm@0,2203d000 {
|
||||
compatible = "arm,coresight-etm3x", "arm,primecell";
|
||||
reg = <0 0x2203d000 0 0x1000>;
|
||||
|
||||
cpu = <&cpu3>;
|
||||
clocks = <&oscclk6a>;
|
||||
clock-names = "apb_pclk";
|
||||
port {
|
||||
etm1_out_port: endpoint {
|
||||
remote-endpoint = <&funnel_in_port4>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
etm@0,2203e000 {
|
||||
compatible = "arm,coresight-etm3x", "arm,primecell";
|
||||
reg = <0 0x2203e000 0 0x1000>;
|
||||
|
||||
cpu = <&cpu4>;
|
||||
clocks = <&oscclk6a>;
|
||||
clock-names = "apb_pclk";
|
||||
port {
|
||||
etm2_out_port: endpoint {
|
||||
remote-endpoint = <&funnel_in_port5>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
smb {
|
||||
compatible = "simple-bus";
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ config ARM64
|
||||
select COMMON_CLK
|
||||
select CPU_PM if (SUSPEND || CPU_IDLE)
|
||||
select DCACHE_WORD_ACCESS
|
||||
select GENERIC_ALLOCATOR
|
||||
select GENERIC_CLOCKEVENTS
|
||||
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
|
||||
select GENERIC_CPU_AUTOPROBE
|
||||
|
||||
@@ -44,4 +44,15 @@ config PID_IN_CONTEXTIDR
|
||||
instructions during context switch. Say Y here only if you are
|
||||
planning to use hardware trace tools with this kernel.
|
||||
|
||||
config DEBUG_SET_MODULE_RONX
|
||||
bool "Set loadable kernel module data as NX and text as RO"
|
||||
depends on MODULES
|
||||
help
|
||||
This option helps catch unintended modifications to loadable
|
||||
kernel module's text and read-only data. It also prevents execution
|
||||
of module data. Such protection may interfere with run-time code
|
||||
patching and dynamic kernel tracing - and they might also protect
|
||||
against certain classes of kernel exploits.
|
||||
If in doubt, say "N".
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -39,7 +39,11 @@ CHECKFLAGS += -D__aarch64__
|
||||
head-y := arch/arm64/kernel/head.o
|
||||
|
||||
# The byte offset of the kernel image in RAM from the start of RAM.
|
||||
ifeq ($(CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET), y)
|
||||
TEXT_OFFSET := $(shell awk 'BEGIN {srand(); printf "0x%03x000\n", int(512 * rand())}')
|
||||
else
|
||||
TEXT_OFFSET := 0x00080000
|
||||
endif
|
||||
|
||||
export TEXT_OFFSET GZFLAGS
|
||||
|
||||
|
||||
@@ -148,4 +148,8 @@ static inline void flush_cache_vunmap(unsigned long start, unsigned long end)
|
||||
{
|
||||
}
|
||||
|
||||
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);
|
||||
#endif
|
||||
|
||||
@@ -36,15 +36,34 @@
|
||||
__val; \
|
||||
})
|
||||
|
||||
#define MIDR_REVISION_MASK 0xf
|
||||
#define MIDR_REVISION(midr) ((midr) & MIDR_REVISION_MASK)
|
||||
#define MIDR_PARTNUM_SHIFT 4
|
||||
#define MIDR_PARTNUM_MASK (0xfff << MIDR_PARTNUM_SHIFT)
|
||||
#define MIDR_PARTNUM(midr) \
|
||||
(((midr) & MIDR_PARTNUM_MASK) >> MIDR_PARTNUM_SHIFT)
|
||||
#define MIDR_ARCHITECTURE_SHIFT 16
|
||||
#define MIDR_ARCHITECTURE_MASK (0xf << MIDR_ARCHITECTURE_SHIFT)
|
||||
#define MIDR_ARCHITECTURE(midr) \
|
||||
(((midr) & MIDR_ARCHITECTURE_MASK) >> MIDR_ARCHITECTURE_SHIFT)
|
||||
#define MIDR_VARIANT_SHIFT 20
|
||||
#define MIDR_VARIANT_MASK (0xf << MIDR_VARIANT_SHIFT)
|
||||
#define MIDR_VARIANT(midr) \
|
||||
(((midr) & MIDR_VARIANT_MASK) >> MIDR_VARIANT_SHIFT)
|
||||
#define MIDR_IMPLEMENTOR_SHIFT 24
|
||||
#define MIDR_IMPLEMENTOR_MASK (0xff << MIDR_IMPLEMENTOR_SHIFT)
|
||||
#define MIDR_IMPLEMENTOR(midr) \
|
||||
(((midr) & MIDR_IMPLEMENTOR_MASK) >> MIDR_IMPLEMENTOR_SHIFT)
|
||||
|
||||
#define ARM_CPU_IMP_ARM 0x41
|
||||
#define ARM_CPU_IMP_APM 0x50
|
||||
|
||||
#define ARM_CPU_PART_AEM_V8 0xD0F0
|
||||
#define ARM_CPU_PART_FOUNDATION 0xD000
|
||||
#define ARM_CPU_PART_CORTEX_A53 0xD030
|
||||
#define ARM_CPU_PART_CORTEX_A57 0xD070
|
||||
#define ARM_CPU_PART_AEM_V8 0xD0F
|
||||
#define ARM_CPU_PART_FOUNDATION 0xD00
|
||||
#define ARM_CPU_PART_CORTEX_A57 0xD07
|
||||
#define ARM_CPU_PART_CORTEX_A53 0xD03
|
||||
|
||||
#define APM_CPU_PART_POTENZA 0x0000
|
||||
#define APM_CPU_PART_POTENZA 0x000
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
@@ -65,12 +84,12 @@ static inline u64 __attribute_const__ read_cpuid_mpidr(void)
|
||||
|
||||
static inline unsigned int __attribute_const__ read_cpuid_implementor(void)
|
||||
{
|
||||
return (read_cpuid_id() & 0xFF000000) >> 24;
|
||||
return MIDR_IMPLEMENTOR(read_cpuid_id());
|
||||
}
|
||||
|
||||
static inline unsigned int __attribute_const__ read_cpuid_part_number(void)
|
||||
{
|
||||
return (read_cpuid_id() & 0xFFF0);
|
||||
return MIDR_PARTNUM(read_cpuid_id());
|
||||
}
|
||||
|
||||
static inline u32 __attribute_const__ read_cpuid_cachetype(void)
|
||||
|
||||
@@ -33,11 +33,11 @@
|
||||
|
||||
/*
|
||||
* The idmap and swapper page tables need some space reserved in the kernel
|
||||
* image. The idmap only requires a pgd and a next level table to (section) map
|
||||
* the kernel, while the swapper also maps the FDT and requires an additional
|
||||
* table to map an early UART. See __create_page_tables for more information.
|
||||
* image. Both require a pgd and a next level table to (section) map the
|
||||
* kernel. The the swapper also maps the FDT (see __create_page_tables for
|
||||
* more information).
|
||||
*/
|
||||
#define SWAPPER_DIR_SIZE (3 * PAGE_SIZE)
|
||||
#define SWAPPER_DIR_SIZE (2 * PAGE_SIZE)
|
||||
#define IDMAP_DIR_SIZE (2 * PAGE_SIZE)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
@@ -26,13 +26,13 @@ static inline void set_my_cpu_offset(unsigned long off)
|
||||
static inline unsigned long __my_cpu_offset(void)
|
||||
{
|
||||
unsigned long off;
|
||||
register unsigned long *sp asm ("sp");
|
||||
|
||||
/*
|
||||
* We want to allow caching the value, so avoid using volatile and
|
||||
* instead use a fake stack read to hazard against barrier().
|
||||
*/
|
||||
asm("mrs %0, tpidr_el1" : "=r" (off) : "Q" (*sp));
|
||||
asm("mrs %0, tpidr_el1" : "=r" (off) :
|
||||
"Q" (*(const unsigned long *)current_stack_pointer));
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
@@ -141,46 +141,51 @@ extern struct page *empty_zero_page;
|
||||
#define pte_valid_not_user(pte) \
|
||||
((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID)
|
||||
|
||||
static inline pte_t clear_pte_bit(pte_t pte, pgprot_t prot)
|
||||
{
|
||||
pte_val(pte) &= ~pgprot_val(prot);
|
||||
return pte;
|
||||
}
|
||||
|
||||
static inline pte_t set_pte_bit(pte_t pte, pgprot_t prot)
|
||||
{
|
||||
pte_val(pte) |= pgprot_val(prot);
|
||||
return pte;
|
||||
}
|
||||
|
||||
static inline pte_t pte_wrprotect(pte_t pte)
|
||||
{
|
||||
pte_val(pte) &= ~PTE_WRITE;
|
||||
return pte;
|
||||
return clear_pte_bit(pte, __pgprot(PTE_WRITE));
|
||||
}
|
||||
|
||||
static inline pte_t pte_mkwrite(pte_t pte)
|
||||
{
|
||||
pte_val(pte) |= PTE_WRITE;
|
||||
return pte;
|
||||
return set_pte_bit(pte, __pgprot(PTE_WRITE));
|
||||
}
|
||||
|
||||
static inline pte_t pte_mkclean(pte_t pte)
|
||||
{
|
||||
pte_val(pte) &= ~PTE_DIRTY;
|
||||
return pte;
|
||||
return clear_pte_bit(pte, __pgprot(PTE_DIRTY));
|
||||
}
|
||||
|
||||
static inline pte_t pte_mkdirty(pte_t pte)
|
||||
{
|
||||
pte_val(pte) |= PTE_DIRTY;
|
||||
return pte;
|
||||
return set_pte_bit(pte, __pgprot(PTE_DIRTY));
|
||||
}
|
||||
|
||||
static inline pte_t pte_mkold(pte_t pte)
|
||||
{
|
||||
pte_val(pte) &= ~PTE_AF;
|
||||
return pte;
|
||||
return clear_pte_bit(pte, __pgprot(PTE_AF));
|
||||
}
|
||||
|
||||
static inline pte_t pte_mkyoung(pte_t pte)
|
||||
{
|
||||
pte_val(pte) |= PTE_AF;
|
||||
return pte;
|
||||
return set_pte_bit(pte, __pgprot(PTE_AF));
|
||||
}
|
||||
|
||||
static inline pte_t pte_mkspecial(pte_t pte)
|
||||
{
|
||||
pte_val(pte) |= PTE_SPECIAL;
|
||||
return pte;
|
||||
return set_pte_bit(pte, __pgprot(PTE_SPECIAL));
|
||||
}
|
||||
|
||||
static inline void set_pte(pte_t *ptep, pte_t pte)
|
||||
|
||||
@@ -34,6 +34,8 @@ extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm);
|
||||
extern void cpu_reset(unsigned long addr) __attribute__((noreturn));
|
||||
extern void cpu_do_suspend(struct cpu_suspend_ctx *ptr);
|
||||
extern u64 cpu_do_resume(phys_addr_t ptr, u64 idmap_ttbr);
|
||||
void cpu_soft_restart(phys_addr_t cpu_reset,
|
||||
unsigned long addr) __attribute__((noreturn));
|
||||
|
||||
#include <asm/memory.h>
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#define __ASM_SPARSEMEM_H
|
||||
|
||||
#ifdef CONFIG_SPARSEMEM
|
||||
#define MAX_PHYSMEM_BITS 40
|
||||
#define MAX_PHYSMEM_BITS 48
|
||||
#define SECTION_SIZE_BITS 30
|
||||
#endif
|
||||
|
||||
|
||||
@@ -68,6 +68,11 @@ struct thread_info {
|
||||
#define init_thread_info (init_thread_union.thread_info)
|
||||
#define init_stack (init_thread_union.stack)
|
||||
|
||||
/*
|
||||
* how to get the current stack pointer from C
|
||||
*/
|
||||
register unsigned long current_stack_pointer asm ("sp");
|
||||
|
||||
/*
|
||||
* how to get the thread information struct from C
|
||||
*/
|
||||
@@ -75,8 +80,8 @@ static inline struct thread_info *current_thread_info(void) __attribute_const__;
|
||||
|
||||
static inline struct thread_info *current_thread_info(void)
|
||||
{
|
||||
register unsigned long sp asm ("sp");
|
||||
return (struct thread_info *)(sp & ~(THREAD_SIZE - 1));
|
||||
return (struct thread_info *)
|
||||
(current_stack_pointer & ~(THREAD_SIZE - 1));
|
||||
}
|
||||
|
||||
#define thread_saved_pc(tsk) \
|
||||
|
||||
@@ -98,8 +98,8 @@ static inline void flush_tlb_page(struct vm_area_struct *vma,
|
||||
dsb(ish);
|
||||
}
|
||||
|
||||
static inline void flush_tlb_range(struct vm_area_struct *vma,
|
||||
unsigned long start, unsigned long end)
|
||||
static inline void __flush_tlb_range(struct vm_area_struct *vma,
|
||||
unsigned long start, unsigned long end)
|
||||
{
|
||||
unsigned long asid = (unsigned long)ASID(vma->vm_mm) << 48;
|
||||
unsigned long addr;
|
||||
@@ -112,7 +112,7 @@ static inline void flush_tlb_range(struct vm_area_struct *vma,
|
||||
dsb(ish);
|
||||
}
|
||||
|
||||
static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end)
|
||||
static inline void __flush_tlb_kernel_range(unsigned long start, unsigned long end)
|
||||
{
|
||||
unsigned long addr;
|
||||
start >>= 12;
|
||||
@@ -125,6 +125,29 @@ static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end
|
||||
isb();
|
||||
}
|
||||
|
||||
/*
|
||||
* This is meant to avoid soft lock-ups on large TLB flushing ranges and not
|
||||
* necessarily a performance improvement.
|
||||
*/
|
||||
#define MAX_TLB_RANGE (1024UL << PAGE_SHIFT)
|
||||
|
||||
static inline void flush_tlb_range(struct vm_area_struct *vma,
|
||||
unsigned long start, unsigned long end)
|
||||
{
|
||||
if ((end - start) <= MAX_TLB_RANGE)
|
||||
__flush_tlb_range(vma, start, end);
|
||||
else
|
||||
flush_tlb_mm(vma->vm_mm);
|
||||
}
|
||||
|
||||
static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end)
|
||||
{
|
||||
if ((end - start) <= MAX_TLB_RANGE)
|
||||
__flush_tlb_kernel_range(start, end);
|
||||
else
|
||||
flush_tlb_all();
|
||||
}
|
||||
|
||||
/*
|
||||
* On AArch64, the cache coherency is handled via the set_pte_at() function.
|
||||
*/
|
||||
|
||||
@@ -30,8 +30,8 @@ const struct cpu_operations *cpu_ops[NR_CPUS];
|
||||
static const struct cpu_operations *supported_cpu_ops[] __initconst = {
|
||||
#ifdef CONFIG_SMP
|
||||
&smp_spin_table_ops,
|
||||
&cpu_psci_ops,
|
||||
#endif
|
||||
&cpu_psci_ops,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
||||
@@ -303,20 +303,20 @@ static int brk_handler(unsigned long addr, unsigned int esr,
|
||||
{
|
||||
siginfo_t info;
|
||||
|
||||
if (call_break_hook(regs, esr) == DBG_HOOK_HANDLED)
|
||||
return 0;
|
||||
if (user_mode(regs)) {
|
||||
info = (siginfo_t) {
|
||||
.si_signo = SIGTRAP,
|
||||
.si_errno = 0,
|
||||
.si_code = TRAP_BRKPT,
|
||||
.si_addr = (void __user *)instruction_pointer(regs),
|
||||
};
|
||||
|
||||
if (!user_mode(regs))
|
||||
force_sig_info(SIGTRAP, &info, current);
|
||||
} else if (call_break_hook(regs, esr) != DBG_HOOK_HANDLED) {
|
||||
pr_warning("Unexpected kernel BRK exception at EL1\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
info = (siginfo_t) {
|
||||
.si_signo = SIGTRAP,
|
||||
.si_errno = 0,
|
||||
.si_code = TRAP_BRKPT,
|
||||
.si_addr = (void __user *)instruction_pointer(regs),
|
||||
};
|
||||
|
||||
force_sig_info(SIGTRAP, &info, current);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,8 +38,12 @@
|
||||
|
||||
#define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET)
|
||||
|
||||
#if (KERNEL_RAM_VADDR & 0xfffff) != 0x80000
|
||||
#error KERNEL_RAM_VADDR must start at 0xXXX80000
|
||||
#if (TEXT_OFFSET & 0xfff) != 0
|
||||
#error TEXT_OFFSET must be at least 4KB aligned
|
||||
#elif (PAGE_OFFSET & 0x1fffff) != 0
|
||||
#error PAGE_OFFSET must be at least 2MB aligned
|
||||
#elif TEXT_OFFSET > 0x1fffff
|
||||
#error TEXT_OFFSET must be less than 2MB
|
||||
#endif
|
||||
|
||||
.macro pgtbl, ttb0, ttb1, virt_to_phys
|
||||
@@ -368,10 +372,6 @@ ENTRY(__boot_cpu_mode)
|
||||
.long 0
|
||||
.popsection
|
||||
|
||||
.align 3
|
||||
2: .quad .
|
||||
.quad PAGE_OFFSET
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
.align 3
|
||||
1: .quad .
|
||||
@@ -596,13 +596,6 @@ __create_page_tables:
|
||||
sub x6, x6, #1 // inclusive range
|
||||
create_block_map x0, x7, x3, x5, x6
|
||||
1:
|
||||
/*
|
||||
* Create the pgd entry for the fixed mappings.
|
||||
*/
|
||||
ldr x5, =FIXADDR_TOP // Fixed mapping virtual address
|
||||
add x0, x26, #2 * PAGE_SIZE // section table address
|
||||
create_pgd_entry x26, x0, x5, x6, x7
|
||||
|
||||
/*
|
||||
* Since the page tables have been populated with non-cacheable
|
||||
* accesses (MMU disabled), invalidate the idmap and swapper page
|
||||
|
||||
@@ -105,7 +105,7 @@ static bool migrate_one_irq(struct irq_desc *desc)
|
||||
c = irq_data_get_irq_chip(d);
|
||||
if (!c->irq_set_affinity)
|
||||
pr_debug("IRQ%u: unable to set affinity\n", d->irq);
|
||||
else if (c->irq_set_affinity(d, affinity, true) == IRQ_SET_MASK_OK && ret)
|
||||
else if (c->irq_set_affinity(d, affinity, false) == IRQ_SET_MASK_OK && ret)
|
||||
cpumask_copy(d->affinity, affinity);
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -58,36 +58,10 @@ unsigned long __stack_chk_guard __read_mostly;
|
||||
EXPORT_SYMBOL(__stack_chk_guard);
|
||||
#endif
|
||||
|
||||
static void setup_restart(void)
|
||||
{
|
||||
/*
|
||||
* Tell the mm system that we are going to reboot -
|
||||
* we may need it to insert some 1:1 mappings so that
|
||||
* soft boot works.
|
||||
*/
|
||||
setup_mm_for_reboot();
|
||||
|
||||
/* Clean and invalidate caches */
|
||||
flush_cache_all();
|
||||
|
||||
/* Turn D-cache off */
|
||||
cpu_cache_off();
|
||||
|
||||
/* Push out any further dirty data, and ensure cache is empty */
|
||||
flush_cache_all();
|
||||
}
|
||||
|
||||
void soft_restart(unsigned long addr)
|
||||
{
|
||||
typedef void (*phys_reset_t)(unsigned long);
|
||||
phys_reset_t phys_reset;
|
||||
|
||||
setup_restart();
|
||||
|
||||
/* Switch to the identity mapping */
|
||||
phys_reset = (phys_reset_t)virt_to_phys(cpu_reset);
|
||||
phys_reset(addr);
|
||||
|
||||
setup_mm_for_reboot();
|
||||
cpu_soft_restart(virt_to_phys(cpu_reset), addr);
|
||||
/* Should never get here */
|
||||
BUG();
|
||||
}
|
||||
|
||||
@@ -251,7 +251,7 @@ static void psci_sys_poweroff(void)
|
||||
* PSCI Function IDs for v0.2+ are well defined so use
|
||||
* standard values.
|
||||
*/
|
||||
static int psci_0_2_init(struct device_node *np)
|
||||
static int __init psci_0_2_init(struct device_node *np)
|
||||
{
|
||||
int err, ver;
|
||||
|
||||
@@ -312,7 +312,7 @@ out_put_node:
|
||||
/*
|
||||
* PSCI < v0.2 get PSCI Function IDs via DT.
|
||||
*/
|
||||
static int psci_0_1_init(struct device_node *np)
|
||||
static int __init psci_0_1_init(struct device_node *np)
|
||||
{
|
||||
u32 id;
|
||||
int err;
|
||||
@@ -450,6 +450,7 @@ static int cpu_psci_cpu_kill(unsigned int cpu)
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARM64_CPU_SUSPEND
|
||||
static int cpu_psci_cpu_suspend(unsigned long index)
|
||||
@@ -465,6 +466,7 @@ static int cpu_psci_cpu_suspend(unsigned long index)
|
||||
|
||||
const struct cpu_operations cpu_psci_ops = {
|
||||
.name = "psci",
|
||||
#ifdef CONFIG_SMP
|
||||
.cpu_init = cpu_psci_cpu_init,
|
||||
.cpu_prepare = cpu_psci_cpu_prepare,
|
||||
.cpu_boot = cpu_psci_cpu_boot,
|
||||
@@ -473,9 +475,9 @@ const struct cpu_operations cpu_psci_ops = {
|
||||
.cpu_die = cpu_psci_cpu_die,
|
||||
.cpu_kill = cpu_psci_cpu_kill,
|
||||
#endif
|
||||
#endif
|
||||
#ifdef CONFIG_ARM64_CPU_SUSPEND
|
||||
.cpu_suspend = cpu_psci_cpu_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -664,8 +664,10 @@ static int compat_gpr_get(struct task_struct *target,
|
||||
kbuf += sizeof(reg);
|
||||
} else {
|
||||
ret = copy_to_user(ubuf, ®, sizeof(reg));
|
||||
if (ret)
|
||||
if (ret) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
ubuf += sizeof(reg);
|
||||
}
|
||||
@@ -703,8 +705,10 @@ static int compat_gpr_set(struct task_struct *target,
|
||||
kbuf += sizeof(reg);
|
||||
} else {
|
||||
ret = copy_from_user(®, ubuf, sizeof(reg));
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ret) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
ubuf += sizeof(reg);
|
||||
}
|
||||
|
||||
@@ -111,10 +111,9 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
|
||||
frame.sp = thread_saved_sp(tsk);
|
||||
frame.pc = thread_saved_pc(tsk);
|
||||
} else {
|
||||
register unsigned long current_sp asm("sp");
|
||||
data.no_sched_functions = 0;
|
||||
frame.fp = (unsigned long)__builtin_frame_address(0);
|
||||
frame.sp = current_sp;
|
||||
frame.sp = current_stack_pointer;
|
||||
frame.pc = (unsigned long)save_stack_trace_tsk;
|
||||
}
|
||||
|
||||
|
||||
@@ -133,7 +133,6 @@ static void dump_instr(const char *lvl, struct pt_regs *regs)
|
||||
static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
|
||||
{
|
||||
struct stackframe frame;
|
||||
const register unsigned long current_sp asm ("sp");
|
||||
|
||||
pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk);
|
||||
|
||||
@@ -146,7 +145,7 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
|
||||
frame.pc = regs->pc;
|
||||
} else if (tsk == current) {
|
||||
frame.fp = (unsigned long)__builtin_frame_address(0);
|
||||
frame.sp = current_sp;
|
||||
frame.sp = current_stack_pointer;
|
||||
frame.pc = (unsigned long)dump_backtrace;
|
||||
} else {
|
||||
/*
|
||||
@@ -157,7 +156,7 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
|
||||
frame.pc = thread_saved_pc(tsk);
|
||||
}
|
||||
|
||||
printk("Call trace:\n");
|
||||
pr_emerg("Call trace:\n");
|
||||
while (1) {
|
||||
unsigned long where = frame.pc;
|
||||
int ret;
|
||||
@@ -372,17 +371,17 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr)
|
||||
|
||||
void __pte_error(const char *file, int line, unsigned long val)
|
||||
{
|
||||
printk("%s:%d: bad pte %016lx.\n", file, line, val);
|
||||
pr_crit("%s:%d: bad pte %016lx.\n", file, line, val);
|
||||
}
|
||||
|
||||
void __pmd_error(const char *file, int line, unsigned long val)
|
||||
{
|
||||
printk("%s:%d: bad pmd %016lx.\n", file, line, val);
|
||||
pr_crit("%s:%d: bad pmd %016lx.\n", file, line, val);
|
||||
}
|
||||
|
||||
void __pgd_error(const char *file, int line, unsigned long val)
|
||||
{
|
||||
printk("%s:%d: bad pgd %016lx.\n", file, line, val);
|
||||
pr_crit("%s:%d: bad pgd %016lx.\n", file, line, val);
|
||||
}
|
||||
|
||||
void __init trap_init(void)
|
||||
|
||||
@@ -43,7 +43,7 @@ $(obj)/vdso-offsets.h: $(obj)/vdso.so.dbg FORCE
|
||||
$(call if_changed,vdsosym)
|
||||
|
||||
# Assembly rules for the .S files
|
||||
$(obj-vdso): %.o: %.S
|
||||
$(obj-vdso): %.o: %.S FORCE
|
||||
$(call if_changed_dep,vdsoas)
|
||||
|
||||
# Actual build commands
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
obj-y := dma-mapping.o extable.o fault.o init.o \
|
||||
cache.o copypage.o flush.o \
|
||||
ioremap.o mmap.o pgd.o mmu.o \
|
||||
context.o proc.o
|
||||
context.o proc.o pageattr.o
|
||||
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/genalloc.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dma-contiguous.h>
|
||||
#include <linux/of.h>
|
||||
@@ -43,6 +44,54 @@ static pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot,
|
||||
return prot;
|
||||
}
|
||||
|
||||
static struct gen_pool *atomic_pool;
|
||||
|
||||
#define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K
|
||||
static size_t atomic_pool_size = DEFAULT_DMA_COHERENT_POOL_SIZE;
|
||||
|
||||
static int __init early_coherent_pool(char *p)
|
||||
{
|
||||
atomic_pool_size = memparse(p, &p);
|
||||
return 0;
|
||||
}
|
||||
early_param("coherent_pool", early_coherent_pool);
|
||||
|
||||
static void *__alloc_from_pool(size_t size, struct page **ret_page)
|
||||
{
|
||||
unsigned long val;
|
||||
void *ptr = NULL;
|
||||
|
||||
if (!atomic_pool) {
|
||||
WARN(1, "coherent pool not initialised!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
val = gen_pool_alloc(atomic_pool, size);
|
||||
if (val) {
|
||||
phys_addr_t phys = gen_pool_virt_to_phys(atomic_pool, val);
|
||||
|
||||
*ret_page = phys_to_page(phys);
|
||||
ptr = (void *)val;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static bool __in_atomic_pool(void *start, size_t size)
|
||||
{
|
||||
return addr_in_gen_pool(atomic_pool, (unsigned long)start, size);
|
||||
}
|
||||
|
||||
static int __free_from_pool(void *start, size_t size)
|
||||
{
|
||||
if (!__in_atomic_pool(start, size))
|
||||
return 0;
|
||||
|
||||
gen_pool_free(atomic_pool, (unsigned long)start, size);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void *__dma_alloc_coherent(struct device *dev, size_t size,
|
||||
dma_addr_t *dma_handle, gfp_t flags,
|
||||
struct dma_attrs *attrs)
|
||||
@@ -50,7 +99,7 @@ static void *__dma_alloc_coherent(struct device *dev, size_t size,
|
||||
if (IS_ENABLED(CONFIG_ZONE_DMA) &&
|
||||
dev->coherent_dma_mask <= DMA_BIT_MASK(32))
|
||||
flags |= GFP_DMA;
|
||||
if (IS_ENABLED(CONFIG_DMA_CMA)) {
|
||||
if (IS_ENABLED(CONFIG_DMA_CMA) && (flags & __GFP_WAIT)) {
|
||||
struct page *page;
|
||||
|
||||
size = PAGE_ALIGN(size);
|
||||
@@ -70,50 +119,54 @@ static void __dma_free_coherent(struct device *dev, size_t size,
|
||||
void *vaddr, dma_addr_t dma_handle,
|
||||
struct dma_attrs *attrs)
|
||||
{
|
||||
bool freed;
|
||||
phys_addr_t paddr = dma_to_phys(dev, dma_handle);
|
||||
|
||||
if (dev == NULL) {
|
||||
WARN_ONCE(1, "Use an actual device structure for DMA allocation\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_DMA_CMA)) {
|
||||
phys_addr_t paddr = dma_to_phys(dev, dma_handle);
|
||||
|
||||
dma_release_from_contiguous(dev,
|
||||
freed = dma_release_from_contiguous(dev,
|
||||
phys_to_page(paddr),
|
||||
size >> PAGE_SHIFT);
|
||||
} else {
|
||||
if (!freed)
|
||||
swiotlb_free_coherent(dev, size, vaddr, dma_handle);
|
||||
}
|
||||
}
|
||||
|
||||
static void *__dma_alloc_noncoherent(struct device *dev, size_t size,
|
||||
dma_addr_t *dma_handle, gfp_t flags,
|
||||
struct dma_attrs *attrs)
|
||||
{
|
||||
struct page *page, **map;
|
||||
struct page *page;
|
||||
void *ptr, *coherent_ptr;
|
||||
int order, i;
|
||||
|
||||
size = PAGE_ALIGN(size);
|
||||
order = get_order(size);
|
||||
|
||||
if (!(flags & __GFP_WAIT)) {
|
||||
struct page *page = NULL;
|
||||
void *addr = __alloc_from_pool(size, &page);
|
||||
|
||||
if (addr)
|
||||
*dma_handle = phys_to_dma(dev, page_to_phys(page));
|
||||
|
||||
return addr;
|
||||
|
||||
}
|
||||
|
||||
ptr = __dma_alloc_coherent(dev, size, dma_handle, flags, attrs);
|
||||
if (!ptr)
|
||||
goto no_mem;
|
||||
map = kmalloc(sizeof(struct page *) << order, flags & ~GFP_DMA);
|
||||
if (!map)
|
||||
goto no_map;
|
||||
|
||||
/* remove any dirty cache lines on the kernel alias */
|
||||
__dma_flush_range(ptr, ptr + size);
|
||||
|
||||
/* create a coherent mapping */
|
||||
page = virt_to_page(ptr);
|
||||
for (i = 0; i < (size >> PAGE_SHIFT); i++)
|
||||
map[i] = page + i;
|
||||
coherent_ptr = vmap(map, size >> PAGE_SHIFT, VM_MAP,
|
||||
__get_dma_pgprot(attrs, __pgprot(PROT_NORMAL_NC), false));
|
||||
kfree(map);
|
||||
coherent_ptr = dma_common_contiguous_remap(page, size, VM_USERMAP,
|
||||
__get_dma_pgprot(attrs,
|
||||
__pgprot(PROT_NORMAL_NC), false),
|
||||
NULL);
|
||||
if (!coherent_ptr)
|
||||
goto no_map;
|
||||
|
||||
@@ -132,6 +185,8 @@ static void __dma_free_noncoherent(struct device *dev, size_t size,
|
||||
{
|
||||
void *swiotlb_addr = phys_to_virt(dma_to_phys(dev, dma_handle));
|
||||
|
||||
if (__free_from_pool(vaddr, size))
|
||||
return;
|
||||
vunmap(vaddr);
|
||||
__dma_free_coherent(dev, size, swiotlb_addr, dma_handle, attrs);
|
||||
}
|
||||
@@ -329,6 +384,67 @@ static struct notifier_block amba_bus_nb = {
|
||||
|
||||
extern int swiotlb_late_init_with_default_size(size_t default_size);
|
||||
|
||||
static int __init atomic_pool_init(void)
|
||||
{
|
||||
pgprot_t prot = __pgprot(PROT_NORMAL_NC);
|
||||
unsigned long nr_pages = atomic_pool_size >> PAGE_SHIFT;
|
||||
struct page *page;
|
||||
void *addr;
|
||||
unsigned int pool_size_order = get_order(atomic_pool_size);
|
||||
|
||||
if (dev_get_cma_area(NULL))
|
||||
page = dma_alloc_from_contiguous(NULL, nr_pages,
|
||||
pool_size_order);
|
||||
else
|
||||
page = alloc_pages(GFP_DMA, pool_size_order);
|
||||
|
||||
if (page) {
|
||||
int ret;
|
||||
void *page_addr = page_address(page);
|
||||
|
||||
memset(page_addr, 0, atomic_pool_size);
|
||||
__dma_flush_range(page_addr, page_addr + atomic_pool_size);
|
||||
|
||||
atomic_pool = gen_pool_create(PAGE_SHIFT, -1);
|
||||
if (!atomic_pool)
|
||||
goto free_page;
|
||||
|
||||
addr = dma_common_contiguous_remap(page, atomic_pool_size,
|
||||
VM_USERMAP, prot, atomic_pool_init);
|
||||
|
||||
if (!addr)
|
||||
goto destroy_genpool;
|
||||
|
||||
ret = gen_pool_add_virt(atomic_pool, (unsigned long)addr,
|
||||
page_to_phys(page),
|
||||
atomic_pool_size, -1);
|
||||
if (ret)
|
||||
goto remove_mapping;
|
||||
|
||||
gen_pool_set_algo(atomic_pool,
|
||||
gen_pool_first_fit_order_align,
|
||||
(void *)PAGE_SHIFT);
|
||||
|
||||
pr_info("DMA: preallocated %zu KiB pool for atomic allocations\n",
|
||||
atomic_pool_size / 1024);
|
||||
return 0;
|
||||
}
|
||||
goto out;
|
||||
|
||||
remove_mapping:
|
||||
dma_common_free_remap(addr, atomic_pool_size, VM_USERMAP);
|
||||
destroy_genpool:
|
||||
gen_pool_destroy(atomic_pool);
|
||||
atomic_pool = NULL;
|
||||
free_page:
|
||||
if (!dma_release_from_contiguous(NULL, page, nr_pages))
|
||||
__free_pages(page, pool_size_order);
|
||||
out:
|
||||
pr_err("DMA: failed to allocate %zu KiB pool for atomic coherent allocation\n",
|
||||
atomic_pool_size / 1024);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int __init swiotlb_late_init(void)
|
||||
{
|
||||
size_t swiotlb_size = min(SZ_64M, MAX_ORDER_NR_PAGES << PAGE_SHIFT);
|
||||
@@ -343,7 +459,17 @@ static int __init swiotlb_late_init(void)
|
||||
|
||||
return swiotlb_late_init_with_default_size(swiotlb_size);
|
||||
}
|
||||
arch_initcall(swiotlb_late_init);
|
||||
|
||||
static int __init arm64_dma_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret |= swiotlb_late_init();
|
||||
ret |= atomic_pool_init();
|
||||
|
||||
return ret;
|
||||
}
|
||||
arch_initcall(arm64_dma_init);
|
||||
|
||||
#define PREALLOC_DMA_DEBUG_ENTRIES 4096
|
||||
|
||||
|
||||
@@ -68,6 +68,17 @@ static int __init early_initrd(char *p)
|
||||
}
|
||||
early_param("initrd", early_initrd);
|
||||
|
||||
/*
|
||||
* Return the maximum physical address for ZONE_DMA (DMA_BIT_MASK(32)). It
|
||||
* currently assumes that for memory starting above 4G, 32-bit devices will
|
||||
* use a DMA offset.
|
||||
*/
|
||||
static phys_addr_t max_zone_dma_phys(void)
|
||||
{
|
||||
phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, 32);
|
||||
return min(offset + (1ULL << 32), memblock_end_of_DRAM());
|
||||
}
|
||||
|
||||
static void __init zone_sizes_init(unsigned long min, unsigned long max)
|
||||
{
|
||||
struct memblock_region *reg;
|
||||
@@ -78,9 +89,7 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
|
||||
|
||||
/* 4GB maximum for 32-bit only capable devices */
|
||||
if (IS_ENABLED(CONFIG_ZONE_DMA)) {
|
||||
unsigned long max_dma_phys =
|
||||
(unsigned long)dma_to_phys(NULL, DMA_BIT_MASK(32) + 1);
|
||||
max_dma = max(min, min(max, max_dma_phys >> PAGE_SHIFT));
|
||||
max_dma = PFN_DOWN(max_zone_dma_phys());
|
||||
zone_size[ZONE_DMA] = max_dma - min;
|
||||
}
|
||||
zone_size[ZONE_NORMAL] = max - max_dma;
|
||||
@@ -137,6 +146,7 @@ static void arm64_memory_present(void)
|
||||
void __init arm64_memblock_init(void)
|
||||
{
|
||||
u64 *reserve_map, base, size;
|
||||
phys_addr_t dma_phys_limit = 0;
|
||||
|
||||
/*
|
||||
* Register the kernel text, kernel data, initrd, and initial
|
||||
@@ -173,7 +183,11 @@ void __init arm64_memblock_init(void)
|
||||
}
|
||||
|
||||
early_init_fdt_scan_reserved_mem();
|
||||
dma_contiguous_reserve(0);
|
||||
|
||||
/* 4GB maximum for 32-bit only capable devices */
|
||||
if (IS_ENABLED(CONFIG_ZONE_DMA))
|
||||
dma_phys_limit = max_zone_dma_phys();
|
||||
dma_contiguous_reserve(dma_phys_limit);
|
||||
|
||||
memblock_allow_resize();
|
||||
memblock_dump_all();
|
||||
|
||||
@@ -98,19 +98,25 @@ void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size)
|
||||
}
|
||||
EXPORT_SYMBOL(ioremap_cache);
|
||||
|
||||
#ifndef CONFIG_ARM64_64K_PAGES
|
||||
static pte_t bm_pte[PTRS_PER_PTE] __page_aligned_bss;
|
||||
#ifndef CONFIG_ARM64_64K_PAGES
|
||||
static pte_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss;
|
||||
#endif
|
||||
|
||||
static inline pmd_t * __init early_ioremap_pmd(unsigned long addr)
|
||||
static inline pud_t * __init early_ioremap_pud(unsigned long addr)
|
||||
{
|
||||
pgd_t *pgd;
|
||||
pud_t *pud;
|
||||
|
||||
pgd = pgd_offset_k(addr);
|
||||
BUG_ON(pgd_none(*pgd) || pgd_bad(*pgd));
|
||||
|
||||
pud = pud_offset(pgd, addr);
|
||||
return pud_offset(pgd, addr);
|
||||
}
|
||||
|
||||
static inline pmd_t * __init early_ioremap_pmd(unsigned long addr)
|
||||
{
|
||||
pud_t *pud = early_ioremap_pud(addr);
|
||||
|
||||
BUG_ON(pud_none(*pud) || pud_bad(*pud));
|
||||
|
||||
return pmd_offset(pud, addr);
|
||||
@@ -127,13 +133,17 @@ static inline pte_t * __init early_ioremap_pte(unsigned long addr)
|
||||
|
||||
void __init early_ioremap_init(void)
|
||||
{
|
||||
pgd_t *pgd;
|
||||
pud_t *pud;
|
||||
pmd_t *pmd;
|
||||
unsigned long addr = fix_to_virt(FIX_BTMAP_BEGIN);
|
||||
|
||||
pmd = early_ioremap_pmd(fix_to_virt(FIX_BTMAP_BEGIN));
|
||||
#ifndef CONFIG_ARM64_64K_PAGES
|
||||
/* need to populate pmd for 4k pagesize only */
|
||||
pgd = pgd_offset_k(addr);
|
||||
pud = pud_offset(pgd, addr);
|
||||
pud_populate(&init_mm, pud, bm_pmd);
|
||||
pmd = pmd_offset(pud, addr);
|
||||
pmd_populate_kernel(&init_mm, pmd, bm_pte);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The boot-ioremap range spans multiple pmds, for which
|
||||
* we are not prepared:
|
||||
|
||||
96
arch/arm64/mm/pageattr.c
Normal file
96
arch/arm64/mm/pageattr.c
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/tlbflush.h>
|
||||
|
||||
struct page_change_data {
|
||||
pgprot_t set_mask;
|
||||
pgprot_t clear_mask;
|
||||
};
|
||||
|
||||
static int change_page_range(pte_t *ptep, pgtable_t token, unsigned long addr,
|
||||
void *data)
|
||||
{
|
||||
struct page_change_data *cdata = data;
|
||||
pte_t pte = *ptep;
|
||||
|
||||
pte = clear_pte_bit(pte, cdata->clear_mask);
|
||||
pte = set_pte_bit(pte, cdata->set_mask);
|
||||
|
||||
set_pte(ptep, pte);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int change_memory_common(unsigned long addr, int numpages,
|
||||
pgprot_t set_mask, pgprot_t clear_mask)
|
||||
{
|
||||
unsigned long start = addr;
|
||||
unsigned long size = PAGE_SIZE*numpages;
|
||||
unsigned long end = start + size;
|
||||
int ret;
|
||||
struct page_change_data data;
|
||||
|
||||
if (!IS_ALIGNED(addr, PAGE_SIZE)) {
|
||||
addr &= PAGE_MASK;
|
||||
WARN_ON_ONCE(1);
|
||||
}
|
||||
|
||||
if (!is_module_address(start) || !is_module_address(end - 1))
|
||||
return -EINVAL;
|
||||
|
||||
data.set_mask = set_mask;
|
||||
data.clear_mask = clear_mask;
|
||||
|
||||
ret = apply_to_page_range(&init_mm, start, size, change_page_range,
|
||||
&data);
|
||||
|
||||
flush_tlb_kernel_range(start, end);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int set_memory_ro(unsigned long addr, int numpages)
|
||||
{
|
||||
return change_memory_common(addr, numpages,
|
||||
__pgprot(PTE_RDONLY),
|
||||
__pgprot(PTE_WRITE));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(set_memory_ro);
|
||||
|
||||
int set_memory_rw(unsigned long addr, int numpages)
|
||||
{
|
||||
return change_memory_common(addr, numpages,
|
||||
__pgprot(PTE_WRITE),
|
||||
__pgprot(PTE_RDONLY));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(set_memory_rw);
|
||||
|
||||
int set_memory_nx(unsigned long addr, int numpages)
|
||||
{
|
||||
return change_memory_common(addr, numpages,
|
||||
__pgprot(PTE_PXN),
|
||||
__pgprot(0));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(set_memory_nx);
|
||||
|
||||
int set_memory_x(unsigned long addr, int numpages)
|
||||
{
|
||||
return change_memory_common(addr, numpages,
|
||||
__pgprot(0),
|
||||
__pgprot(PTE_PXN));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(set_memory_x);
|
||||
@@ -69,6 +69,21 @@ ENTRY(cpu_reset)
|
||||
ret x0
|
||||
ENDPROC(cpu_reset)
|
||||
|
||||
ENTRY(cpu_soft_restart)
|
||||
/* Save address of cpu_reset() and reset address */
|
||||
mov x19, x0
|
||||
mov x20, x1
|
||||
|
||||
/* Turn D-cache off */
|
||||
bl cpu_cache_off
|
||||
|
||||
/* Push out all dirty data, and ensure cache is empty */
|
||||
bl flush_cache_all
|
||||
|
||||
mov x0, x20
|
||||
ret x19
|
||||
ENDPROC(cpu_soft_restart)
|
||||
|
||||
/*
|
||||
* cpu_do_idle()
|
||||
*
|
||||
|
||||
@@ -287,7 +287,7 @@ void *dma_common_pages_remap(struct page **pages, size_t size,
|
||||
|
||||
area->pages = pages;
|
||||
|
||||
if (map_vm_area(area, prot, pages)) {
|
||||
if (map_vm_area(area, prot, &pages)) {
|
||||
vunmap(area->addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user