Merge branch 'x86/cleanups' into x86/mm

Merge recent cleanups to the x86 MM code to resolve a conflict.

Conflicts:
	arch/x86/mm/fault.c

Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
Ingo Molnar 2021-02-12 13:39:32 +01:00
Родитель c46f52231e 3228e1dc80
Коммит 40c1fa52cd
15 изменённых файлов: 60 добавлений и 111 удалений

Просмотреть файл

@ -889,7 +889,7 @@ config HPET_TIMER
config HPET_EMULATE_RTC config HPET_EMULATE_RTC
def_bool y def_bool y
depends on HPET_TIMER && (RTC=y || RTC=m || RTC_DRV_CMOS=m || RTC_DRV_CMOS=y) depends on HPET_TIMER && (RTC_DRV_CMOS=m || RTC_DRV_CMOS=y)
config APB_TIMER config APB_TIMER
def_bool y if X86_INTEL_MID def_bool y if X86_INTEL_MID

Просмотреть файл

@ -40,8 +40,6 @@ extern void native_init_IRQ(void);
extern void __handle_irq(struct irq_desc *desc, struct pt_regs *regs); extern void __handle_irq(struct irq_desc *desc, struct pt_regs *regs);
extern __visible void do_IRQ(struct pt_regs *regs, unsigned long vector);
extern void init_ISA_irqs(void); extern void init_ISA_irqs(void);
extern void __init init_IRQ(void); extern void __init init_IRQ(void);

Просмотреть файл

@ -66,7 +66,7 @@
* On Intel CPUs, if a SYSCALL instruction is at the highest canonical * On Intel CPUs, if a SYSCALL instruction is at the highest canonical
* address, then that syscall will enter the kernel with a * address, then that syscall will enter the kernel with a
* non-canonical return address, and SYSRET will explode dangerously. * non-canonical return address, and SYSRET will explode dangerously.
* We avoid this particular problem by preventing anything executable * We avoid this particular problem by preventing anything
* from being mapped at the maximum canonical address. * from being mapped at the maximum canonical address.
* *
* On AMD CPUs in the Ryzen family, there's a nasty bug in which the * On AMD CPUs in the Ryzen family, there's a nasty bug in which the

Просмотреть файл

@ -177,8 +177,6 @@ enum page_cache_mode {
#define __pgprot(x) ((pgprot_t) { (x) } ) #define __pgprot(x) ((pgprot_t) { (x) } )
#define __pg(x) __pgprot(x) #define __pg(x) __pgprot(x)
#define _PAGE_PAT_LARGE (_AT(pteval_t, 1) << _PAGE_BIT_PAT_LARGE)
#define PAGE_NONE __pg( 0| 0| 0|___A| 0| 0| 0|___G) #define PAGE_NONE __pg( 0| 0| 0|___A| 0| 0| 0|___G)
#define PAGE_SHARED __pg(__PP|__RW|_USR|___A|__NX| 0| 0| 0) #define PAGE_SHARED __pg(__PP|__RW|_USR|___A|__NX| 0| 0| 0)
#define PAGE_SHARED_EXEC __pg(__PP|__RW|_USR|___A| 0| 0| 0| 0) #define PAGE_SHARED_EXEC __pg(__PP|__RW|_USR|___A| 0| 0| 0| 0)

Просмотреть файл

@ -36,7 +36,6 @@ struct vm86 {
unsigned long saved_sp0; unsigned long saved_sp0;
unsigned long flags; unsigned long flags;
unsigned long screen_bitmap;
unsigned long cpu_type; unsigned long cpu_type;
struct revectored_struct int_revectored; struct revectored_struct int_revectored;
struct revectored_struct int21_revectored; struct revectored_struct int21_revectored;

Просмотреть файл

@ -97,7 +97,7 @@ struct revectored_struct {
struct vm86_struct { struct vm86_struct {
struct vm86_regs regs; struct vm86_regs regs;
unsigned long flags; unsigned long flags;
unsigned long screen_bitmap; unsigned long screen_bitmap; /* unused, preserved by vm86() */
unsigned long cpu_type; unsigned long cpu_type;
struct revectored_struct int_revectored; struct revectored_struct int_revectored;
struct revectored_struct int21_revectored; struct revectored_struct int21_revectored;
@ -106,7 +106,7 @@ struct vm86_struct {
/* /*
* flags masks * flags masks
*/ */
#define VM86_SCREEN_BITMAP 0x0001 #define VM86_SCREEN_BITMAP 0x0001 /* no longer supported */
struct vm86plus_info_struct { struct vm86plus_info_struct {
unsigned long force_return_for_pic:1; unsigned long force_return_for_pic:1;

Просмотреть файл

@ -537,9 +537,9 @@ static void __init print_out_mtrr_range_state(void)
if (!size_base) if (!size_base)
continue; continue;
size_base = to_size_factor(size_base, &size_factor), size_base = to_size_factor(size_base, &size_factor);
start_base = range_state[i].base_pfn << (PAGE_SHIFT - 10); start_base = range_state[i].base_pfn << (PAGE_SHIFT - 10);
start_base = to_size_factor(start_base, &start_factor), start_base = to_size_factor(start_base, &start_factor);
type = range_state[i].type; type = range_state[i].type;
pr_debug("reg %d, base: %ld%cB, range: %ld%cB, type %s\n", pr_debug("reg %d, base: %ld%cB, range: %ld%cB, type %s\n",

Просмотреть файл

@ -3,7 +3,6 @@
* This only handles 32bit MTRR on 32bit hosts. This is strictly wrong * This only handles 32bit MTRR on 32bit hosts. This is strictly wrong
* because MTRRs can span up to 40 bits (36bits on most modern x86) * because MTRRs can span up to 40 bits (36bits on most modern x86)
*/ */
#define DEBUG
#include <linux/export.h> #include <linux/export.h>
#include <linux/init.h> #include <linux/init.h>

Просмотреть файл

@ -31,8 +31,6 @@
System Programming Guide; Section 9.11. (1997 edition - PPro). System Programming Guide; Section 9.11. (1997 edition - PPro).
*/ */
#define DEBUG
#include <linux/types.h> /* FIXME: kvm_para.h needs this */ #include <linux/types.h> /* FIXME: kvm_para.h needs this */
#include <linux/stop_machine.h> #include <linux/stop_machine.h>

Просмотреть файл

@ -4,9 +4,6 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/kallsyms.h> #include <linux/kallsyms.h>
#define DEBUG 1
static struct iommu_table_entry * __init static struct iommu_table_entry * __init
find_dependents_of(struct iommu_table_entry *start, find_dependents_of(struct iommu_table_entry *start,
struct iommu_table_entry *finish, struct iommu_table_entry *finish,

Просмотреть файл

@ -704,6 +704,9 @@ void ptrace_disable(struct task_struct *child)
#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
static const struct user_regset_view user_x86_32_view; /* Initialized below. */ static const struct user_regset_view user_x86_32_view; /* Initialized below. */
#endif #endif
#ifdef CONFIG_X86_64
static const struct user_regset_view user_x86_64_view; /* Initialized below. */
#endif
long arch_ptrace(struct task_struct *child, long request, long arch_ptrace(struct task_struct *child, long request,
unsigned long addr, unsigned long data) unsigned long addr, unsigned long data)
@ -711,6 +714,14 @@ long arch_ptrace(struct task_struct *child, long request,
int ret; int ret;
unsigned long __user *datap = (unsigned long __user *)data; unsigned long __user *datap = (unsigned long __user *)data;
#ifdef CONFIG_X86_64
/* This is native 64-bit ptrace() */
const struct user_regset_view *regset_view = &user_x86_64_view;
#else
/* This is native 32-bit ptrace() */
const struct user_regset_view *regset_view = &user_x86_32_view;
#endif
switch (request) { switch (request) {
/* read the word at location addr in the USER area. */ /* read the word at location addr in the USER area. */
case PTRACE_PEEKUSR: { case PTRACE_PEEKUSR: {
@ -749,28 +760,28 @@ long arch_ptrace(struct task_struct *child, long request,
case PTRACE_GETREGS: /* Get all gp regs from the child. */ case PTRACE_GETREGS: /* Get all gp regs from the child. */
return copy_regset_to_user(child, return copy_regset_to_user(child,
task_user_regset_view(current), regset_view,
REGSET_GENERAL, REGSET_GENERAL,
0, sizeof(struct user_regs_struct), 0, sizeof(struct user_regs_struct),
datap); datap);
case PTRACE_SETREGS: /* Set all gp regs in the child. */ case PTRACE_SETREGS: /* Set all gp regs in the child. */
return copy_regset_from_user(child, return copy_regset_from_user(child,
task_user_regset_view(current), regset_view,
REGSET_GENERAL, REGSET_GENERAL,
0, sizeof(struct user_regs_struct), 0, sizeof(struct user_regs_struct),
datap); datap);
case PTRACE_GETFPREGS: /* Get the child FPU state. */ case PTRACE_GETFPREGS: /* Get the child FPU state. */
return copy_regset_to_user(child, return copy_regset_to_user(child,
task_user_regset_view(current), regset_view,
REGSET_FP, REGSET_FP,
0, sizeof(struct user_i387_struct), 0, sizeof(struct user_i387_struct),
datap); datap);
case PTRACE_SETFPREGS: /* Set the child FPU state. */ case PTRACE_SETFPREGS: /* Set the child FPU state. */
return copy_regset_from_user(child, return copy_regset_from_user(child,
task_user_regset_view(current), regset_view,
REGSET_FP, REGSET_FP,
0, sizeof(struct user_i387_struct), 0, sizeof(struct user_i387_struct),
datap); datap);
@ -1152,28 +1163,28 @@ static long x32_arch_ptrace(struct task_struct *child,
case PTRACE_GETREGS: /* Get all gp regs from the child. */ case PTRACE_GETREGS: /* Get all gp regs from the child. */
return copy_regset_to_user(child, return copy_regset_to_user(child,
task_user_regset_view(current), &user_x86_64_view,
REGSET_GENERAL, REGSET_GENERAL,
0, sizeof(struct user_regs_struct), 0, sizeof(struct user_regs_struct),
datap); datap);
case PTRACE_SETREGS: /* Set all gp regs in the child. */ case PTRACE_SETREGS: /* Set all gp regs in the child. */
return copy_regset_from_user(child, return copy_regset_from_user(child,
task_user_regset_view(current), &user_x86_64_view,
REGSET_GENERAL, REGSET_GENERAL,
0, sizeof(struct user_regs_struct), 0, sizeof(struct user_regs_struct),
datap); datap);
case PTRACE_GETFPREGS: /* Get the child FPU state. */ case PTRACE_GETFPREGS: /* Get the child FPU state. */
return copy_regset_to_user(child, return copy_regset_to_user(child,
task_user_regset_view(current), &user_x86_64_view,
REGSET_FP, REGSET_FP,
0, sizeof(struct user_i387_struct), 0, sizeof(struct user_i387_struct),
datap); datap);
case PTRACE_SETFPREGS: /* Set the child FPU state. */ case PTRACE_SETFPREGS: /* Set the child FPU state. */
return copy_regset_from_user(child, return copy_regset_from_user(child,
task_user_regset_view(current), &user_x86_64_view,
REGSET_FP, REGSET_FP,
0, sizeof(struct user_i387_struct), 0, sizeof(struct user_i387_struct),
datap); datap);
@ -1309,6 +1320,25 @@ void __init update_regset_xstate_info(unsigned int size, u64 xstate_mask)
xstate_fx_sw_bytes[USER_XSTATE_XCR0_WORD] = xstate_mask; xstate_fx_sw_bytes[USER_XSTATE_XCR0_WORD] = xstate_mask;
} }
/*
* This is used by the core dump code to decide which regset to dump. The
* core dump code writes out the resulting .e_machine and the corresponding
* regsets. This is suboptimal if the task is messing around with its CS.L
* field, but at worst the core dump will end up missing some information.
*
* Unfortunately, it is also used by the broken PTRACE_GETREGSET and
* PTRACE_SETREGSET APIs. These APIs look at the .regsets field but have
* no way to make sure that the e_machine they use matches the caller's
* expectations. The result is that the data format returned by
* PTRACE_GETREGSET depends on the returned CS field (and even the offset
* of the returned CS field depends on its value!) and the data format
* accepted by PTRACE_SETREGSET is determined by the old CS value. The
* upshot is that it is basically impossible to use these APIs correctly.
*
* The best way to fix it in the long run would probably be to add new
* improved ptrace() APIs to read and write registers reliably, possibly by
* allowing userspace to select the ELF e_machine variant that they expect.
*/
const struct user_regset_view *task_user_regset_view(struct task_struct *task) const struct user_regset_view *task_user_regset_view(struct task_struct *task)
{ {
#ifdef CONFIG_IA32_EMULATION #ifdef CONFIG_IA32_EMULATION

Просмотреть файл

@ -90,14 +90,10 @@ SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
unsigned long, prot, unsigned long, flags, unsigned long, prot, unsigned long, flags,
unsigned long, fd, unsigned long, off) unsigned long, fd, unsigned long, off)
{ {
long error;
error = -EINVAL;
if (off & ~PAGE_MASK) if (off & ~PAGE_MASK)
goto out; return -EINVAL;
error = ksys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT); return ksys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
out:
return error;
} }
static void find_start_end(unsigned long addr, unsigned long flags, static void find_start_end(unsigned long addr, unsigned long flags,

Просмотреть файл

@ -134,7 +134,11 @@ void save_v86_state(struct kernel_vm86_regs *regs, int retval)
unsafe_put_user(regs->ds, &user->regs.ds, Efault_end); unsafe_put_user(regs->ds, &user->regs.ds, Efault_end);
unsafe_put_user(regs->fs, &user->regs.fs, Efault_end); unsafe_put_user(regs->fs, &user->regs.fs, Efault_end);
unsafe_put_user(regs->gs, &user->regs.gs, Efault_end); unsafe_put_user(regs->gs, &user->regs.gs, Efault_end);
unsafe_put_user(vm86->screen_bitmap, &user->screen_bitmap, Efault_end);
/*
* Don't write screen_bitmap in case some user had a value there
* and expected it to remain unchanged.
*/
user_access_end(); user_access_end();
@ -160,49 +164,6 @@ Efault:
do_exit(SIGSEGV); do_exit(SIGSEGV);
} }
static void mark_screen_rdonly(struct mm_struct *mm)
{
struct vm_area_struct *vma;
spinlock_t *ptl;
pgd_t *pgd;
p4d_t *p4d;
pud_t *pud;
pmd_t *pmd;
pte_t *pte;
int i;
mmap_write_lock(mm);
pgd = pgd_offset(mm, 0xA0000);
if (pgd_none_or_clear_bad(pgd))
goto out;
p4d = p4d_offset(pgd, 0xA0000);
if (p4d_none_or_clear_bad(p4d))
goto out;
pud = pud_offset(p4d, 0xA0000);
if (pud_none_or_clear_bad(pud))
goto out;
pmd = pmd_offset(pud, 0xA0000);
if (pmd_trans_huge(*pmd)) {
vma = find_vma(mm, 0xA0000);
split_huge_pmd(vma, pmd, 0xA0000);
}
if (pmd_none_or_clear_bad(pmd))
goto out;
pte = pte_offset_map_lock(mm, pmd, 0xA0000, &ptl);
for (i = 0; i < 32; i++) {
if (pte_present(*pte))
set_pte(pte, pte_wrprotect(*pte));
pte++;
}
pte_unmap_unlock(pte, ptl);
out:
mmap_write_unlock(mm);
flush_tlb_mm_range(mm, 0xA0000, 0xA0000 + 32*PAGE_SIZE, PAGE_SHIFT, false);
}
static int do_vm86_irq_handling(int subfunction, int irqnumber); static int do_vm86_irq_handling(int subfunction, int irqnumber);
static long do_sys_vm86(struct vm86plus_struct __user *user_vm86, bool plus); static long do_sys_vm86(struct vm86plus_struct __user *user_vm86, bool plus);
@ -282,6 +243,15 @@ static long do_sys_vm86(struct vm86plus_struct __user *user_vm86, bool plus)
offsetof(struct vm86_struct, int_revectored))) offsetof(struct vm86_struct, int_revectored)))
return -EFAULT; return -EFAULT;
/* VM86_SCREEN_BITMAP had numerous bugs and appears to have no users. */
if (v.flags & VM86_SCREEN_BITMAP) {
char comm[TASK_COMM_LEN];
pr_info_once("vm86: '%s' uses VM86_SCREEN_BITMAP, which is no longer supported\n", get_task_comm(comm, current));
return -EINVAL;
}
memset(&vm86regs, 0, sizeof(vm86regs)); memset(&vm86regs, 0, sizeof(vm86regs));
vm86regs.pt.bx = v.regs.ebx; vm86regs.pt.bx = v.regs.ebx;
@ -302,7 +272,6 @@ static long do_sys_vm86(struct vm86plus_struct __user *user_vm86, bool plus)
vm86regs.gs = v.regs.gs; vm86regs.gs = v.regs.gs;
vm86->flags = v.flags; vm86->flags = v.flags;
vm86->screen_bitmap = v.screen_bitmap;
vm86->cpu_type = v.cpu_type; vm86->cpu_type = v.cpu_type;
if (copy_from_user(&vm86->int_revectored, if (copy_from_user(&vm86->int_revectored,
@ -370,9 +339,6 @@ static long do_sys_vm86(struct vm86plus_struct __user *user_vm86, bool plus)
update_task_stack(tsk); update_task_stack(tsk);
preempt_enable(); preempt_enable();
if (vm86->flags & VM86_SCREEN_BITMAP)
mark_screen_rdonly(tsk->mm);
memcpy((struct kernel_vm86_regs *)regs, &vm86regs, sizeof(vm86regs)); memcpy((struct kernel_vm86_regs *)regs, &vm86regs, sizeof(vm86regs));
return regs->ax; return regs->ax;
} }

Просмотреть файл

@ -282,25 +282,6 @@ void arch_sync_kernel_mappings(unsigned long start, unsigned long end)
} }
} }
/*
* Did it hit the DOS screen memory VA from vm86 mode?
*/
static inline void
check_v8086_mode(struct pt_regs *regs, unsigned long address,
struct task_struct *tsk)
{
#ifdef CONFIG_VM86
unsigned long bit;
if (!v8086_mode(regs) || !tsk->thread.vm86)
return;
bit = (address - 0xA0000) >> PAGE_SHIFT;
if (bit < 32)
tsk->thread.vm86->screen_bitmap |= 1 << bit;
#endif
}
static bool low_pfn(unsigned long pfn) static bool low_pfn(unsigned long pfn)
{ {
return pfn < max_low_pfn; return pfn < max_low_pfn;
@ -355,15 +336,6 @@ KERN_ERR
"******* Disabling USB legacy in the BIOS may also help.\n"; "******* Disabling USB legacy in the BIOS may also help.\n";
#endif #endif
/*
* No vm86 mode in 64-bit mode:
*/
static inline void
check_v8086_mode(struct pt_regs *regs, unsigned long address,
struct task_struct *tsk)
{
}
static int bad_address(void *p) static int bad_address(void *p)
{ {
unsigned long dummy; unsigned long dummy;
@ -1465,8 +1437,6 @@ good_area:
else else
BUG(); BUG();
} }
check_v8086_mode(regs, address, tsk);
} }
NOKPROBE_SYMBOL(do_user_addr_fault); NOKPROBE_SYMBOL(do_user_addr_fault);

Просмотреть файл

@ -10,8 +10,6 @@
#define pr_fmt(fmt) "mmiotrace: " fmt #define pr_fmt(fmt) "mmiotrace: " fmt
#define DEBUG 1
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/slab.h> #include <linux/slab.h>