Commit bce6824c authored by Ingo Molnar's avatar Ingo Molnar

Merge branch 'x86/core' into x86/build, to avoid conflicts

Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 494b5168 c0554d2d
...@@ -15,7 +15,8 @@ than x86. Check the v86d documentation for a list of currently supported ...@@ -15,7 +15,8 @@ than x86. Check the v86d documentation for a list of currently supported
arches. arches.
v86d source code can be downloaded from the following website: v86d source code can be downloaded from the following website:
http://dev.gentoo.org/~spock/projects/uvesafb
https://github.com/mjanusz/v86d
Please refer to the v86d documentation for detailed configuration and Please refer to the v86d documentation for detailed configuration and
installation instructions. installation instructions.
...@@ -177,7 +178,7 @@ from the Video BIOS if you set pixclock to 0 in fb_var_screeninfo. ...@@ -177,7 +178,7 @@ from the Video BIOS if you set pixclock to 0 in fb_var_screeninfo.
-- --
Michal Januszewski <spock@gentoo.org> Michal Januszewski <spock@gentoo.org>
Last updated: 2009-03-30 Last updated: 2017-10-10
Documentation of the uvesafb options is loosely based on vesafb.txt. Documentation of the uvesafb options is loosely based on vesafb.txt.
...@@ -1251,7 +1251,7 @@ N: meson ...@@ -1251,7 +1251,7 @@ N: meson
ARM/Annapurna Labs ALPINE ARCHITECTURE ARM/Annapurna Labs ALPINE ARCHITECTURE
M: Tsahee Zidenberg <tsahee@annapurnalabs.com> M: Tsahee Zidenberg <tsahee@annapurnalabs.com>
M: Antoine Tenart <antoine.tenart@free-electrons.com> M: Antoine Tenart <antoine.tenart@bootlin.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained S: Maintained
F: arch/arm/mach-alpine/ F: arch/arm/mach-alpine/
...@@ -15395,7 +15395,7 @@ S: Maintained ...@@ -15395,7 +15395,7 @@ S: Maintained
UVESAFB DRIVER UVESAFB DRIVER
M: Michal Januszewski <spock@gentoo.org> M: Michal Januszewski <spock@gentoo.org>
L: linux-fbdev@vger.kernel.org L: linux-fbdev@vger.kernel.org
W: http://dev.gentoo.org/~spock/projects/uvesafb/ W: https://github.com/mjanusz/v86d
S: Maintained S: Maintained
F: Documentation/fb/uvesafb.txt F: Documentation/fb/uvesafb.txt
F: drivers/video/fbdev/uvesafb.* F: drivers/video/fbdev/uvesafb.*
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "sama5d2-pinfunc.h" #include "sama5d2-pinfunc.h"
#include <dt-bindings/mfd/atmel-flexcom.h> #include <dt-bindings/mfd/atmel-flexcom.h>
#include <dt-bindings/gpio/gpio.h> #include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/pinctrl/at91.h>
/ { / {
model = "Atmel SAMA5D2 PTC EK"; model = "Atmel SAMA5D2 PTC EK";
...@@ -299,6 +300,7 @@ re_we_data { ...@@ -299,6 +300,7 @@ re_we_data {
<PIN_PA30__NWE_NANDWE>, <PIN_PA30__NWE_NANDWE>,
<PIN_PB2__NRD_NANDOE>; <PIN_PB2__NRD_NANDOE>;
bias-pull-up; bias-pull-up;
atmel,drive-strength = <ATMEL_PIO_DRVSTR_ME>;
}; };
ale_cle_rdy_cs { ale_cle_rdy_cs {
......
...@@ -106,21 +106,23 @@ gic: interrupt-controller@1e100 { ...@@ -106,21 +106,23 @@ gic: interrupt-controller@1e100 {
global_timer: timer@1e200 { global_timer: timer@1e200 {
compatible = "arm,cortex-a9-global-timer"; compatible = "arm,cortex-a9-global-timer";
reg = <0x1e200 0x20>; reg = <0x1e200 0x20>;
interrupts = <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_PPI 11 IRQ_TYPE_EDGE_RISING>;
clocks = <&axi_clk>; clocks = <&axi_clk>;
}; };
local_timer: local-timer@1e600 { local_timer: local-timer@1e600 {
compatible = "arm,cortex-a9-twd-timer"; compatible = "arm,cortex-a9-twd-timer";
reg = <0x1e600 0x20>; reg = <0x1e600 0x20>;
interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) |
IRQ_TYPE_EDGE_RISING)>;
clocks = <&axi_clk>; clocks = <&axi_clk>;
}; };
twd_watchdog: watchdog@1e620 { twd_watchdog: watchdog@1e620 {
compatible = "arm,cortex-a9-twd-wdt"; compatible = "arm,cortex-a9-twd-wdt";
reg = <0x1e620 0x20>; reg = <0x1e620 0x20>;
interrupts = <GIC_PPI 14 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) |
IRQ_TYPE_LEVEL_HIGH)>;
}; };
armpll: armpll { armpll: armpll {
...@@ -158,7 +160,7 @@ timer: timer@80 { ...@@ -158,7 +160,7 @@ timer: timer@80 {
serial0: serial@600 { serial0: serial@600 {
compatible = "brcm,bcm6345-uart"; compatible = "brcm,bcm6345-uart";
reg = <0x600 0x1b>; reg = <0x600 0x1b>;
interrupts = <GIC_SPI 32 0>; interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&periph_clk>; clocks = <&periph_clk>;
clock-names = "periph"; clock-names = "periph";
status = "disabled"; status = "disabled";
...@@ -167,7 +169,7 @@ serial0: serial@600 { ...@@ -167,7 +169,7 @@ serial0: serial@600 {
serial1: serial@620 { serial1: serial@620 {
compatible = "brcm,bcm6345-uart"; compatible = "brcm,bcm6345-uart";
reg = <0x620 0x1b>; reg = <0x620 0x1b>;
interrupts = <GIC_SPI 33 0>; interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&periph_clk>; clocks = <&periph_clk>;
clock-names = "periph"; clock-names = "periph";
status = "disabled"; status = "disabled";
...@@ -180,7 +182,7 @@ nand: nand@2000 { ...@@ -180,7 +182,7 @@ nand: nand@2000 {
reg = <0x2000 0x600>, <0xf0 0x10>; reg = <0x2000 0x600>, <0xf0 0x10>;
reg-names = "nand", "nand-int-base"; reg-names = "nand", "nand-int-base";
status = "disabled"; status = "disabled";
interrupts = <GIC_SPI 38 0>; interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "nand"; interrupt-names = "nand";
}; };
......
...@@ -1078,8 +1078,8 @@ spi6: spi@5c001000 { ...@@ -1078,8 +1078,8 @@ spi6: spi@5c001000 {
interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&rcc SPI6_K>; clocks = <&rcc SPI6_K>;
resets = <&rcc SPI6_R>; resets = <&rcc SPI6_R>;
dmas = <&mdma1 34 0x0 0x40008 0x0 0x0 0>, dmas = <&mdma1 34 0x0 0x40008 0x0 0x0>,
<&mdma1 35 0x0 0x40002 0x0 0x0 0>; <&mdma1 35 0x0 0x40002 0x0 0x0>;
dma-names = "rx", "tx"; dma-names = "rx", "tx";
status = "disabled"; status = "disabled";
}; };
......
...@@ -800,8 +800,7 @@ hdmi_out: port@1 { ...@@ -800,8 +800,7 @@ hdmi_out: port@1 {
}; };
hdmi_phy: hdmi-phy@1ef0000 { hdmi_phy: hdmi-phy@1ef0000 {
compatible = "allwinner,sun8i-r40-hdmi-phy", compatible = "allwinner,sun8i-r40-hdmi-phy";
"allwinner,sun50i-a64-hdmi-phy";
reg = <0x01ef0000 0x10000>; reg = <0x01ef0000 0x10000>;
clocks = <&ccu CLK_BUS_HDMI1>, <&ccu CLK_HDMI_SLOW>, clocks = <&ccu CLK_BUS_HDMI1>, <&ccu CLK_HDMI_SLOW>,
<&ccu 7>, <&ccu 16>; <&ccu 7>, <&ccu 16>;
......
...@@ -57,6 +57,45 @@ static u64 core_reg_offset_from_id(u64 id) ...@@ -57,6 +57,45 @@ static u64 core_reg_offset_from_id(u64 id)
return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE); return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE);
} }
static int validate_core_offset(const struct kvm_one_reg *reg)
{
u64 off = core_reg_offset_from_id(reg->id);
int size;
switch (off) {
case KVM_REG_ARM_CORE_REG(regs.regs[0]) ...
KVM_REG_ARM_CORE_REG(regs.regs[30]):
case KVM_REG_ARM_CORE_REG(regs.sp):
case KVM_REG_ARM_CORE_REG(regs.pc):
case KVM_REG_ARM_CORE_REG(regs.pstate):
case KVM_REG_ARM_CORE_REG(sp_el1):
case KVM_REG_ARM_CORE_REG(elr_el1):
case KVM_REG_ARM_CORE_REG(spsr[0]) ...
KVM_REG_ARM_CORE_REG(spsr[KVM_NR_SPSR - 1]):
size = sizeof(__u64);
break;
case KVM_REG_ARM_CORE_REG(fp_regs.vregs[0]) ...
KVM_REG_ARM_CORE_REG(fp_regs.vregs[31]):
size = sizeof(__uint128_t);
break;
case KVM_REG_ARM_CORE_REG(fp_regs.fpsr):
case KVM_REG_ARM_CORE_REG(fp_regs.fpcr):
size = sizeof(__u32);
break;
default:
return -EINVAL;
}
if (KVM_REG_SIZE(reg->id) == size &&
IS_ALIGNED(off, size / sizeof(__u32)))
return 0;
return -EINVAL;
}
static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
{ {
/* /*
...@@ -76,6 +115,9 @@ static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) ...@@ -76,6 +115,9 @@ static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
(off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs) (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
return -ENOENT; return -ENOENT;
if (validate_core_offset(reg))
return -EINVAL;
if (copy_to_user(uaddr, ((u32 *)regs) + off, KVM_REG_SIZE(reg->id))) if (copy_to_user(uaddr, ((u32 *)regs) + off, KVM_REG_SIZE(reg->id)))
return -EFAULT; return -EFAULT;
...@@ -98,6 +140,9 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) ...@@ -98,6 +140,9 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
(off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs) (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
return -ENOENT; return -ENOENT;
if (validate_core_offset(reg))
return -EINVAL;
if (KVM_REG_SIZE(reg->id) > sizeof(tmp)) if (KVM_REG_SIZE(reg->id) > sizeof(tmp))
return -EINVAL; return -EINVAL;
...@@ -107,17 +152,25 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) ...@@ -107,17 +152,25 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
} }
if (off == KVM_REG_ARM_CORE_REG(regs.pstate)) { if (off == KVM_REG_ARM_CORE_REG(regs.pstate)) {
u32 mode = (*(u32 *)valp) & PSR_AA32_MODE_MASK; u64 mode = (*(u64 *)valp) & PSR_AA32_MODE_MASK;
switch (mode) { switch (mode) {
case PSR_AA32_MODE_USR: case PSR_AA32_MODE_USR:
if (!system_supports_32bit_el0())
return -EINVAL;
break;
case PSR_AA32_MODE_FIQ: case PSR_AA32_MODE_FIQ:
case PSR_AA32_MODE_IRQ: case PSR_AA32_MODE_IRQ:
case PSR_AA32_MODE_SVC: case PSR_AA32_MODE_SVC:
case PSR_AA32_MODE_ABT: case PSR_AA32_MODE_ABT:
case PSR_AA32_MODE_UND: case PSR_AA32_MODE_UND:
if (!vcpu_el1_is_32bit(vcpu))
return -EINVAL;
break;
case PSR_MODE_EL0t: case PSR_MODE_EL0t:
case PSR_MODE_EL1t: case PSR_MODE_EL1t:
case PSR_MODE_EL1h: case PSR_MODE_EL1h:
if (vcpu_el1_is_32bit(vcpu))
return -EINVAL;
break; break;
default: default:
err = -EINVAL; err = -EINVAL;
......
...@@ -117,11 +117,14 @@ static pte_t get_clear_flush(struct mm_struct *mm, ...@@ -117,11 +117,14 @@ static pte_t get_clear_flush(struct mm_struct *mm,
/* /*
* If HW_AFDBM is enabled, then the HW could turn on * If HW_AFDBM is enabled, then the HW could turn on
* the dirty bit for any page in the set, so check * the dirty or accessed bit for any page in the set,
* them all. All hugetlb entries are already young. * so check them all.
*/ */
if (pte_dirty(pte)) if (pte_dirty(pte))
orig_pte = pte_mkdirty(orig_pte); orig_pte = pte_mkdirty(orig_pte);
if (pte_young(pte))
orig_pte = pte_mkyoung(orig_pte);
} }
if (valid) { if (valid) {
...@@ -320,11 +323,40 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm, ...@@ -320,11 +323,40 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
return get_clear_flush(mm, addr, ptep, pgsize, ncontig); return get_clear_flush(mm, addr, ptep, pgsize, ncontig);
} }
/*
* huge_ptep_set_access_flags will update access flags (dirty, accesssed)
* and write permission.
*
* For a contiguous huge pte range we need to check whether or not write
* permission has to change only on the first pte in the set. Then for
* all the contiguous ptes we need to check whether or not there is a
* discrepancy between dirty or young.
*/
static int __cont_access_flags_changed(pte_t *ptep, pte_t pte, int ncontig)
{
int i;
if (pte_write(pte) != pte_write(huge_ptep_get(ptep)))
return 1;
for (i = 0; i < ncontig; i++) {
pte_t orig_pte = huge_ptep_get(ptep + i);
if (pte_dirty(pte) != pte_dirty(orig_pte))
return 1;
if (pte_young(pte) != pte_young(orig_pte))
return 1;
}
return 0;
}
int huge_ptep_set_access_flags(struct vm_area_struct *vma, int huge_ptep_set_access_flags(struct vm_area_struct *vma,
unsigned long addr, pte_t *ptep, unsigned long addr, pte_t *ptep,
pte_t pte, int dirty) pte_t pte, int dirty)
{ {
int ncontig, i, changed = 0; int ncontig, i;
size_t pgsize = 0; size_t pgsize = 0;
unsigned long pfn = pte_pfn(pte), dpfn; unsigned long pfn = pte_pfn(pte), dpfn;
pgprot_t hugeprot; pgprot_t hugeprot;
...@@ -336,19 +368,23 @@ int huge_ptep_set_access_flags(struct vm_area_struct *vma, ...@@ -336,19 +368,23 @@ int huge_ptep_set_access_flags(struct vm_area_struct *vma,
ncontig = find_num_contig(vma->vm_mm, addr, ptep, &pgsize); ncontig = find_num_contig(vma->vm_mm, addr, ptep, &pgsize);
dpfn = pgsize >> PAGE_SHIFT; dpfn = pgsize >> PAGE_SHIFT;
if (!__cont_access_flags_changed(ptep, pte, ncontig))
return 0;
orig_pte = get_clear_flush(vma->vm_mm, addr, ptep, pgsize, ncontig); orig_pte = get_clear_flush(vma->vm_mm, addr, ptep, pgsize, ncontig);
if (!pte_same(orig_pte, pte))
changed = 1;
/* Make sure we don't lose the dirty state */ /* Make sure we don't lose the dirty or young state */
if (pte_dirty(orig_pte)) if (pte_dirty(orig_pte))
pte = pte_mkdirty(pte); pte = pte_mkdirty(pte);
if (pte_young(orig_pte))
pte = pte_mkyoung(pte);
hugeprot = pte_pgprot(pte); hugeprot = pte_pgprot(pte);
for (i = 0; i < ncontig; i++, ptep++, addr += pgsize, pfn += dpfn) for (i = 0; i < ncontig; i++, ptep++, addr += pgsize, pfn += dpfn)
set_pte_at(vma->vm_mm, addr, ptep, pfn_pte(pfn, hugeprot)); set_pte_at(vma->vm_mm, addr, ptep, pfn_pte(pfn, hugeprot));
return changed; return 1;
} }
void huge_ptep_set_wrprotect(struct mm_struct *mm, void huge_ptep_set_wrprotect(struct mm_struct *mm,
......
...@@ -130,6 +130,9 @@ ...@@ -130,6 +130,9 @@
# define _ASM_EXTABLE(from, to) \ # define _ASM_EXTABLE(from, to) \
_ASM_EXTABLE_HANDLE(from, to, ex_handler_default) _ASM_EXTABLE_HANDLE(from, to, ex_handler_default)
# define _ASM_EXTABLE_UA(from, to) \
_ASM_EXTABLE_HANDLE(from, to, ex_handler_uaccess)
# define _ASM_EXTABLE_FAULT(from, to) \ # define _ASM_EXTABLE_FAULT(from, to) \
_ASM_EXTABLE_HANDLE(from, to, ex_handler_fault) _ASM_EXTABLE_HANDLE(from, to, ex_handler_fault)
...@@ -165,8 +168,8 @@ ...@@ -165,8 +168,8 @@
jmp copy_user_handle_tail jmp copy_user_handle_tail
.previous .previous
_ASM_EXTABLE(100b,103b) _ASM_EXTABLE_UA(100b, 103b)
_ASM_EXTABLE(101b,103b) _ASM_EXTABLE_UA(101b, 103b)
.endm .endm
#else #else
...@@ -182,6 +185,9 @@ ...@@ -182,6 +185,9 @@
# define _ASM_EXTABLE(from, to) \ # define _ASM_EXTABLE(from, to) \
_ASM_EXTABLE_HANDLE(from, to, ex_handler_default) _ASM_EXTABLE_HANDLE(from, to, ex_handler_default)
# define _ASM_EXTABLE_UA(from, to) \
_ASM_EXTABLE_HANDLE(from, to, ex_handler_uaccess)
# define _ASM_EXTABLE_FAULT(from, to) \ # define _ASM_EXTABLE_FAULT(from, to) \
_ASM_EXTABLE_HANDLE(from, to, ex_handler_fault) _ASM_EXTABLE_HANDLE(from, to, ex_handler_fault)
......
...@@ -29,7 +29,8 @@ struct pt_regs; ...@@ -29,7 +29,8 @@ struct pt_regs;
(b)->handler = (tmp).handler - (delta); \ (b)->handler = (tmp).handler - (delta); \
} while (0) } while (0)
extern int fixup_exception(struct pt_regs *regs, int trapnr); extern int fixup_exception(struct pt_regs *regs, int trapnr,
unsigned long error_code, unsigned long fault_addr);
extern int fixup_bug(struct pt_regs *regs, int trapnr); extern int fixup_bug(struct pt_regs *regs, int trapnr);
extern bool ex_has_fault_handler(unsigned long ip); extern bool ex_has_fault_handler(unsigned long ip);
extern void early_fixup_exception(struct pt_regs *regs, int trapnr); extern void early_fixup_exception(struct pt_regs *regs, int trapnr);
......
...@@ -226,7 +226,7 @@ static inline void copy_fxregs_to_kernel(struct fpu *fpu) ...@@ -226,7 +226,7 @@ static inline void copy_fxregs_to_kernel(struct fpu *fpu)
"3: movl $-2,%[err]\n\t" \ "3: movl $-2,%[err]\n\t" \
"jmp 2b\n\t" \ "jmp 2b\n\t" \
".popsection\n\t" \ ".popsection\n\t" \
_ASM_EXTABLE(1b, 3b) \ _ASM_EXTABLE_UA(1b, 3b) \
: [err] "=r" (err) \ : [err] "=r" (err) \
: "D" (st), "m" (*st), "a" (lmask), "d" (hmask) \ : "D" (st), "m" (*st), "a" (lmask), "d" (hmask) \
: "memory") : "memory")
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
"3:\tmov\t%3, %1\n" \ "3:\tmov\t%3, %1\n" \
"\tjmp\t2b\n" \ "\tjmp\t2b\n" \
"\t.previous\n" \ "\t.previous\n" \
_ASM_EXTABLE(1b, 3b) \ _ASM_EXTABLE_UA(1b, 3b) \
: "=r" (oldval), "=r" (ret), "+m" (*uaddr) \ : "=r" (oldval), "=r" (ret), "+m" (*uaddr) \
: "i" (-EFAULT), "0" (oparg), "1" (0)) : "i" (-EFAULT), "0" (oparg), "1" (0))
...@@ -36,8 +36,8 @@ ...@@ -36,8 +36,8 @@
"4:\tmov\t%5, %1\n" \ "4:\tmov\t%5, %1\n" \
"\tjmp\t3b\n" \ "\tjmp\t3b\n" \
"\t.previous\n" \ "\t.previous\n" \
_ASM_EXTABLE(1b, 4b) \ _ASM_EXTABLE_UA(1b, 4b) \
_ASM_EXTABLE(2b, 4b) \ _ASM_EXTABLE_UA(2b, 4b) \
: "=&a" (oldval), "=&r" (ret), \ : "=&a" (oldval), "=&r" (ret), \
"+m" (*uaddr), "=&r" (tem) \ "+m" (*uaddr), "=&r" (tem) \
: "r" (oparg), "i" (-EFAULT), "1" (0)) : "r" (oparg), "i" (-EFAULT), "1" (0))
......
...@@ -37,8 +37,10 @@ struct pt_regs { ...@@ -37,8 +37,10 @@ struct pt_regs {
unsigned short __esh; unsigned short __esh;
unsigned short fs; unsigned short fs;
unsigned short __fsh; unsigned short __fsh;
/* On interrupt, gs and __gsh store the vector number. */
unsigned short gs; unsigned short gs;
unsigned short __gsh; unsigned short __gsh;
/* On interrupt, this is the error code. */
unsigned long orig_ax; unsigned long orig_ax;
unsigned long ip; unsigned long ip;
unsigned short cs; unsigned short cs;
......
...@@ -198,8 +198,8 @@ __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL)) ...@@ -198,8 +198,8 @@ __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))
"4: movl %3,%0\n" \ "4: movl %3,%0\n" \
" jmp 3b\n" \ " jmp 3b\n" \
".previous\n" \ ".previous\n" \
_ASM_EXTABLE(1b, 4b) \ _ASM_EXTABLE_UA(1b, 4b) \
_ASM_EXTABLE(2b, 4b) \ _ASM_EXTABLE_UA(2b, 4b) \
: "=r" (err) \ : "=r" (err) \
: "A" (x), "r" (addr), "i" (errret), "0" (err)) : "A" (x), "r" (addr), "i" (errret), "0" (err))
...@@ -340,8 +340,8 @@ do { \ ...@@ -340,8 +340,8 @@ do { \
" xorl %%edx,%%edx\n" \ " xorl %%edx,%%edx\n" \
" jmp 3b\n" \ " jmp 3b\n" \
".previous\n" \ ".previous\n" \
_ASM_EXTABLE(1b, 4b) \ _ASM_EXTABLE_UA(1b, 4b) \
_ASM_EXTABLE(2b, 4b) \ _ASM_EXTABLE_UA(2b, 4b) \
: "=r" (retval), "=&A"(x) \ : "=r" (retval), "=&A"(x) \
: "m" (__m(__ptr)), "m" __m(((u32 __user *)(__ptr)) + 1), \ : "m" (__m(__ptr)), "m" __m(((u32 __user *)(__ptr)) + 1), \
"i" (errret), "0" (retval)); \ "i" (errret), "0" (retval)); \
...@@ -386,7 +386,7 @@ do { \ ...@@ -386,7 +386,7 @@ do { \
" xor"itype" %"rtype"1,%"rtype"1\n" \ " xor"itype" %"rtype"1,%"rtype"1\n" \
" jmp 2b\n" \ " jmp 2b\n" \
".previous\n" \ ".previous\n" \
_ASM_EXTABLE(1b, 3b) \ _ASM_EXTABLE_UA(1b, 3b) \
: "=r" (err), ltype(x) \ : "=r" (err), ltype(x) \
: "m" (__m(addr)), "i" (errret), "0" (err)) : "m" (__m(addr)), "i" (errret), "0" (err))
...@@ -398,7 +398,7 @@ do { \ ...@@ -398,7 +398,7 @@ do { \
"3: mov %3,%0\n" \ "3: mov %3,%0\n" \
" jmp 2b\n" \ " jmp 2b\n" \
".previous\n" \ ".previous\n" \
_ASM_EXTABLE(1b, 3b) \ _ASM_EXTABLE_UA(1b, 3b) \
: "=r" (err), ltype(x) \ : "=r" (err), ltype(x) \
: "m" (__m(addr)), "i" (errret), "0" (err)) : "m" (__m(addr)), "i" (errret), "0" (err))
...@@ -474,7 +474,7 @@ struct __large_struct { unsigned long buf[100]; }; ...@@ -474,7 +474,7 @@ struct __large_struct { unsigned long buf[100]; };
"3: mov %3,%0\n" \ "3: mov %3,%0\n" \
" jmp 2b\n" \ " jmp 2b\n" \
".previous\n" \ ".previous\n" \
_ASM_EXTABLE(1b, 3b) \ _ASM_EXTABLE_UA(1b, 3b) \
: "=r"(err) \ : "=r"(err) \
: ltype(x), "m" (__m(addr)), "i" (errret), "0" (err)) : ltype(x), "m" (__m(addr)), "i" (errret), "0" (err))
...@@ -602,7 +602,7 @@ extern void __cmpxchg_wrong_size(void) ...@@ -602,7 +602,7 @@ extern void __cmpxchg_wrong_size(void)
"3:\tmov %3, %0\n" \ "3:\tmov %3, %0\n" \
"\tjmp 2b\n" \ "\tjmp 2b\n" \
"\t.previous\n" \ "\t.previous\n" \
_ASM_EXTABLE(1b, 3b) \ _ASM_EXTABLE_UA(1b, 3b) \
: "+r" (__ret), "=a" (__old), "+m" (*(ptr)) \ : "+r" (__ret), "=a" (__old), "+m" (*(ptr)) \
: "i" (-EFAULT), "q" (__new), "1" (__old) \ : "i" (-EFAULT), "q" (__new), "1" (__old) \
: "memory" \ : "memory" \
...@@ -618,7 +618,7 @@ extern void __cmpxchg_wrong_size(void) ...@@ -618,7 +618,7 @@ extern void __cmpxchg_wrong_size(void)
"3:\tmov %3, %0\n" \ "3:\tmov %3, %0\n" \
"\tjmp 2b\n" \ "\tjmp 2b\n" \
"\t.previous\n" \ "\t.previous\n" \
_ASM_EXTABLE(1b, 3b) \ _ASM_EXTABLE_UA(1b, 3b) \
: "+r" (__ret), "=a" (__old), "+m" (*(ptr)) \ : "+r" (__ret), "=a" (__old), "+m" (*(ptr)) \
: "i" (-EFAULT), "r" (__new), "1" (__old) \ : "i" (-EFAULT), "r" (__new), "1" (__old) \
: "memory" \ : "memory" \
...@@ -634,7 +634,7 @@ extern void __cmpxchg_wrong_size(void) ...@@ -634,7 +634,7 @@ extern void __cmpxchg_wrong_size(void)
"3:\tmov %3, %0\n" \ "3:\tmov %3, %0\n" \
"\tjmp 2b\n" \ "\tjmp 2b\n" \
"\t.previous\n" \ "\t.previous\n" \
_ASM_EXTABLE(1b, 3b) \ _ASM_EXTABLE_UA(1b, 3b) \
: "+r" (__ret), "=a" (__old), "+m" (*(ptr)) \ : "+r" (__ret), "=a" (__old), "+m" (*(ptr)) \
: "i" (-EFAULT), "r" (__new), "1" (__old) \ : "i" (-EFAULT), "r" (__new), "1" (__old) \
: "memory" \ : "memory" \
...@@ -653,7 +653,7 @@ extern void __cmpxchg_wrong_size(void) ...@@ -653,7 +653,7 @@ extern void __cmpxchg_wrong_size(void)
"3:\tmov %3, %0\n" \ "3:\tmov %3, %0\n" \
"\tjmp 2b\n" \ "\tjmp 2b\n" \
"\t.previous\n" \ "\t.previous\n" \
_ASM_EXTABLE(1b, 3b) \ _ASM_EXTABLE_UA(1b, 3b) \
: "+r" (__ret), "=a" (__old), "+m" (*(ptr)) \ : "+r" (__ret), "=a" (__old), "+m" (*(ptr)) \
: "i" (-EFAULT), "r" (__new), "1" (__old) \ : "i" (-EFAULT), "r" (__new), "1" (__old) \
: "memory" \ : "memory" \
......
...@@ -1315,7 +1315,7 @@ void do_machine_check(struct pt_regs *regs, long error_code) ...@@ -1315,7 +1315,7 @@ void do_machine_check(struct pt_regs *regs, long error_code)
local_irq_disable(); local_irq_disable();
ist_end_non_atomic(); ist_end_non_atomic();
} else { } else {
if (!fixup_exception(regs, X86_TRAP_MC)) if (!fixup_exception(regs, X86_TRAP_MC, error_code, 0))
mce_panic("Failed kernel mode recovery", &m, NULL); mce_panic("Failed kernel mode recovery", &m, NULL);
} }
......
...@@ -1020,50 +1020,12 @@ int kprobe_fault_handler(struct pt_regs *regs, int trapnr) ...@@ -1020,50 +1020,12 @@ int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
*/ */
if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
return 1; return 1;
/*
* In case the user-specified fault handler returned
* zero, try to fix up.
*/
if (fixup_exception(regs, trapnr))
return 1;
/*
* fixup routine could not handle it,
* Let do_page_fault() fix it.
*/
} }
return 0; return 0;
} }
NOKPROBE_SYMBOL(kprobe_fault_handler); NOKPROBE_SYMBOL(kprobe_fault_handler);
/*
* Wrapper routine for handling exceptions.
*/
int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
void *data)
{
struct die_args *args = data;
int ret = NOTIFY_DONE;
if (args->regs && user_mode(args->regs))
return ret;
if (val == DIE_GPF) {
/*
* To be potentially processing a kprobe fault and to
* trust the result from kprobe_running(), we have
* be non-preemptible.
*/
if (!preemptible() && kprobe_running() &&
kprobe_fault_handler(args->regs, args->trapnr))
ret = NOTIFY_STOP;
}
return ret;
}
NOKPROBE_SYMBOL(kprobe_exceptions_notify);
bool arch_within_kprobe_blacklist(unsigned long addr) bool arch_within_kprobe_blacklist(unsigned long addr)
{ {
bool is_in_entry_trampoline_section = false; bool is_in_entry_trampoline_section = false;
......
...@@ -206,7 +206,7 @@ do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str, ...@@ -206,7 +206,7 @@ do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str,
} }
if (!user_mode(regs)) { if (!user_mode(regs)) {
if (fixup_exception(regs, trapnr)) if (fixup_exception(regs, trapnr, error_code, 0))
return 0; return 0;
tsk->thread.error_code = error_code; tsk->thread.error_code = error_code;
...@@ -551,11 +551,21 @@ do_general_protection(struct pt_regs *regs, long error_code) ...@@ -551,11 +551,21 @@ do_general_protection(struct pt_regs *regs, long error_code)
tsk = current; tsk = current;
if (!user_mode(regs)) { if (!user_mode(regs)) {
if (fixup_exception(regs, X86_TRAP_GP)) if (fixup_exception(regs, X86_TRAP_GP, error_code, 0))
return; return;
tsk->thread.error_code = error_code; tsk->thread.error_code = error_code;
tsk->thread.trap_nr = X86_TRAP_GP; tsk->thread.trap_nr = X86_TRAP_GP;
/*
* To be potentially processing a kprobe fault and to
* trust the result from kprobe_running(), we have to
* be non-preemptible.
*/
if (!preemptible() && kprobe_running() &&
kprobe_fault_handler(regs, X86_TRAP_GP))
return;
if (notify_die(DIE_GPF, "general protection fault", regs, error_code, if (notify_die(DIE_GPF, "general protection fault", regs, error_code,
X86_TRAP_GP, SIGSEGV) != NOTIFY_STOP) X86_TRAP_GP, SIGSEGV) != NOTIFY_STOP)
die("general protection fault", regs, error_code); die("general protection fault", regs, error_code);
...@@ -838,7 +848,7 @@ static void math_error(struct pt_regs *regs, int error_code, int trapnr) ...@@ -838,7 +848,7 @@ static void math_error(struct pt_regs *regs, int error_code, int trapnr)
cond_local_irq_enable(regs); cond_local_irq_enable(regs);
if (!user_mode(regs)) { if (!user_mode(regs)) {
if (fixup_exception(regs, trapnr)) if (fixup_exception(regs, trapnr, error_code, 0))
return; return;
task->thread.error_code = error_code; task->thread.error_code = error_code;
......
...@@ -273,11 +273,11 @@ unsigned int csum_partial_copy_generic (const char *src, char *dst, ...@@ -273,11 +273,11 @@ unsigned int csum_partial_copy_generic (const char *src, char *dst,
#define SRC(y...) \ #define SRC(y...) \
9999: y; \ 9999: y; \
_ASM_EXTABLE(9999b, 6001f) _ASM_EXTABLE_UA(9999b, 6001f)
#define DST(y...) \ #define DST(y...) \
9999: y; \ 9999: y; \
_ASM_EXTABLE(9999b, 6002f) _ASM_EXTABLE_UA(9999b, 6002f)
#ifndef CONFIG_X86_USE_PPRO_CHECKSUM #ifndef CONFIG_X86_USE_PPRO_CHECKSUM
......
...@@ -92,26 +92,26 @@ ENTRY(copy_user_generic_unrolled) ...@@ -92,26 +92,26 @@ ENTRY(copy_user_generic_unrolled)
60: jmp copy_user_handle_tail /* ecx is zerorest also */ 60: jmp copy_user_handle_tail /* ecx is zerorest also */
.previous .previous
_ASM_EXTABLE(1b,30b) _ASM_EXTABLE_UA(1b, 30b)
_ASM_EXTABLE(2b,30b) _ASM_EXTABLE_UA(2b, 30b)
_ASM_EXTABLE(3b,30b) _ASM_EXTABLE_UA(3b, 30b)
_ASM_EXTABLE(4b,30b) _ASM_EXTABLE_UA(4b, 30b)
_ASM_EXTABLE(5b,30b) _ASM_EXTABLE_UA(5b, 30b)
_ASM_EXTABLE(6b,30b) _ASM_EXTABLE_UA(6b, 30b)
_ASM_EXTABLE(7b,30b) _ASM_EXTABLE_UA(7b, 30b)
_ASM_EXTABLE(8b,30b) _ASM_EXTABLE_UA(8b, 30b)
_ASM_EXTABLE(9b,30b) _ASM_EXTABLE_UA(9b, 30b)
_ASM_EXTABLE(10b,30b) _ASM_EXTABLE_UA(10b, 30b)
_ASM_EXTABLE(11b,30b) _ASM_EXTABLE_UA(11b, 30b)
_ASM_EXTABLE(12b,30b) _ASM_EXTABLE_UA(12b, 30b)
_ASM_EXTABLE(13b,30b) _ASM_EXTABLE_UA(13b, 30b)
_ASM_EXTABLE(14b,30b) _ASM_EXTABLE_UA(14b, 30b)
_ASM_EXTABLE(15b,30b) _ASM_EXTABLE_UA(15b, 30b)
_ASM_EXTABLE(16b,30b) _ASM_EXTABLE_UA(16b, 30b)
_ASM_EXTABLE(18b,40b) _ASM_EXTABLE_UA(18b, 40b)
_ASM_EXTABLE(19b,40b) _ASM_EXTABLE_UA(19b, 40b)
_ASM_EXTABLE(21b,50b) _ASM_EXTABLE_UA(21b, 50b)
_ASM_EXTABLE(22b,50b) _ASM_EXTABLE_UA(22b, 50b)
ENDPROC(copy_user_generic_unrolled) ENDPROC(copy_user_generic_unrolled)
EXPORT_SYMBOL(copy_user_generic_unrolled) EXPORT_SYMBOL(copy_user_generic_unrolled)
...@@ -156,8 +156,8 @@ ENTRY(copy_user_generic_string) ...@@ -156,8 +156,8 @@ ENTRY(copy_user_generic_string)
jmp copy_user_handle_tail jmp copy_user_handle_tail
.previous .previous
_ASM_EXTABLE(1b,11b) _ASM_EXTABLE_UA(1b, 11b)
_ASM_EXTABLE(3b,12b) _ASM_EXTABLE_UA(3b, 12b)
ENDPROC(copy_user_generic_string) ENDPROC(copy_user_generic_string)
EXPORT_SYMBOL(copy_user_generic_string) EXPORT_SYMBOL(copy_user_generic_string)
...@@ -189,7 +189,7 @@ ENTRY(copy_user_enhanced_fast_string) ...@@ -189,7 +189,7 @@ ENTRY(copy_user_enhanced_fast_string)
jmp copy_user_handle_tail jmp copy_user_handle_tail
.previous .previous
_ASM_EXTABLE(1b,12b) _ASM_EXTABLE_UA(1b, 12b)
ENDPROC(copy_user_enhanced_fast_string) ENDPROC(copy_user_enhanced_fast_string)
EXPORT_SYMBOL(copy_user_enhanced_fast_string) EXPORT_SYMBOL(copy_user_enhanced_fast_string)
...@@ -319,27 +319,27 @@ ENTRY(__copy_user_nocache) ...@@ -319,27 +319,27 @@ ENTRY(__copy_user_nocache)
jmp copy_user_handle_tail jmp copy_user_handle_tail
.previous .previous
_ASM_EXTABLE(1b,.L_fixup_4x8b_copy) _ASM_EXTABLE_UA(1b, .L_fixup_4x8b_copy)
_ASM_EXTABLE(2b,.L_fixup_4x8b_copy) _ASM_EXTABLE_UA(2b, .L_fixup_4x8b_copy)
_ASM_EXTABLE(3b,.L_fixup_4x8b_copy) _ASM_EXTABLE_UA(3b, .L_fixup_4x8b_copy)
_ASM_EXTABLE(4b,.L_fixup_4x8b_copy) _ASM_EXTABLE_UA(4b, .L_fixup_4x8b_copy)
_ASM_EXTABLE(5b,.L_fixup_4x8b_copy) _ASM_EXTABLE_UA(5b, .L_fixup_4x8b_copy)
_ASM_EXTABLE(6b,.L_fixup_4x8b_copy) _ASM_EXTABLE_UA(6b, .L_fixup_4x8b_copy)
_ASM_EXTABLE(7b,.L_fixup_4x8b_copy) _ASM_EXTABLE_UA(7b, .L_fixup_4x8b_copy)
_ASM_EXTABLE(8b,.L_fixup_4x8b_copy) _ASM_EXTABLE_UA(8b, .L_fixup_4x8b_copy)
_ASM_EXTABLE(9b,.L_fixup_4x8b_copy) _ASM_EXTABLE_UA(9b, .L_fixup_4x8b_copy)
_ASM_EXTABLE(10b,.L_fixup_4x8b_copy) _ASM_EXTABLE_UA(10b, .L_fixup_4x8b_copy)
_ASM_EXTABLE(11b,.L_fixup_4x8b_copy) _ASM_EXTABLE_UA(11b, .L_fixup_4x8b_copy)
_ASM_EXTABLE(12b,.L_fixup_4x8b_copy) _ASM_EXTABLE_UA(12b, .L_fixup_4x8b_copy)
_ASM_EXTABLE(13b,.L_fixup_4x8b_copy) _ASM_EXTABLE_UA(13b, .L_fixup_4x8b_copy)
_ASM_EXTABLE(14b,.L_fixup_4x8b_copy) _ASM_EXTABLE_UA(14b, .L_fixup_4x8b_copy)
_ASM_EXTABLE(15b,.L_fixup_4x8b_copy) _ASM_EXTABLE_UA(15b, .L_fixup_4x8b_copy)
_ASM_EXTABLE(16b,.L_fixup_4x8b_copy) _ASM_EXTABLE_UA(16b, .L_fixup_4x8b_copy)
_ASM_EXTABLE(20b,.L_fixup_8b_copy) _ASM_EXTABLE_UA(20b, .L_fixup_8b_copy)
_ASM_EXTABLE(21b,.L_fixup_8b_copy) _ASM_EXTABLE_UA(21b, .L_fixup_8b_copy)
_ASM_EXTABLE(30b,.L_fixup_4b_copy) _ASM_EXTABLE_UA(30b, .L_fixup_4b_copy)
_ASM_EXTABLE(31b,.L_fixup_4b_copy) _ASM_EXTABLE_UA(31b, .L_fixup_4b_copy)
_ASM_EXTABLE(40b,.L_fixup_1b_copy) _ASM_EXTABLE_UA(40b, .L_fixup_1b_copy)
_ASM_EXTABLE(41b,.L_fixup_1b_copy) _ASM_EXTABLE_UA(41b, .L_fixup_1b_copy)
ENDPROC(__copy_user_nocache) ENDPROC(__copy_user_nocache)
EXPORT_SYMBOL(__copy_user_nocache) EXPORT_SYMBOL(__copy_user_nocache)
...@@ -31,14 +31,18 @@ ...@@ -31,14 +31,18 @@
.macro source .macro source
10: 10:
_ASM_EXTABLE(10b, .Lbad_source) _ASM_EXTABLE_UA(10b, .Lbad_source)
.endm .endm
.macro dest .macro dest
20: 20:
_ASM_EXTABLE(20b, .Lbad_dest) _ASM_EXTABLE_UA(20b, .Lbad_dest)
.endm .endm
/*
* No _ASM_EXTABLE_UA; this is used for intentional prefetch on a
* potentially unmapped kernel address.
*/
.macro ignore L=.Lignore .macro ignore L=.Lignore
30: 30:
_ASM_EXTABLE(30b, \L) _ASM_EXTABLE(30b, \L)
......
...@@ -132,12 +132,12 @@ bad_get_user_8: ...@@ -132,12 +132,12 @@ bad_get_user_8:
END(bad_get_user_8) END(bad_get_user_8)
#endif #endif
_ASM_EXTABLE(1b,bad_get_user) _ASM_EXTABLE_UA(1b, bad_get_user)
_ASM_EXTABLE(2b,bad_get_user) _ASM_EXTABLE_UA(2b, bad_get_user)
_ASM_EXTABLE(3b,bad_get_user) _ASM_EXTABLE_UA(3b, bad_get_user)
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
_ASM_EXTABLE(4b,bad_get_user) _ASM_EXTABLE_UA(4b, bad_get_user)
#else #else
_ASM_EXTABLE(4b,bad_get_user_8) _ASM_EXTABLE_UA(4b, bad_get_user_8)
_ASM_EXTABLE(5b,bad_get_user_8) _ASM_EXTABLE_UA(5b, bad_get_user_8)
#endif #endif
...@@ -94,10 +94,10 @@ bad_put_user: ...@@ -94,10 +94,10 @@ bad_put_user:
EXIT EXIT
END(bad_put_user) END(bad_put_user)
_ASM_EXTABLE(1b,bad_put_user) _ASM_EXTABLE_UA(1b, bad_put_user)
_ASM_EXTABLE(2b,bad_put_user) _ASM_EXTABLE_UA(2b, bad_put_user)
_ASM_EXTABLE(3b,bad_put_user) _ASM_EXTABLE_UA(3b, bad_put_user)
_ASM_EXTABLE(4b,bad_put_user) _ASM_EXTABLE_UA(4b, bad_put_user)
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
_ASM_EXTABLE(5b,bad_put_user) _ASM_EXTABLE_UA(5b, bad_put_user)
#endif #endif
...@@ -47,8 +47,8 @@ do { \ ...@@ -47,8 +47,8 @@ do { \
"3: lea 0(%2,%0,4),%0\n" \ "3: lea 0(%2,%0,4),%0\n" \
" jmp 2b\n" \ " jmp 2b\n" \
".previous\n" \ ".previous\n" \
_ASM_EXTABLE(0b,3b) \ _ASM_EXTABLE_UA(0b, 3b) \
_ASM_EXTABLE(1b,2b) \ _ASM_EXTABLE_UA(1b, 2b) \
: "=&c"(size), "=&D" (__d0) \ : "=&c"(size), "=&D" (__d0) \
: "r"(size & 3), "0"(size / 4), "1"(addr), "a"(0)); \ : "r"(size & 3), "0"(size / 4), "1"(addr), "a"(0)); \
} while (0) } while (0)
...@@ -153,44 +153,44 @@ __copy_user_intel(void __user *to, const void *from, unsigned long size) ...@@ -153,44 +153,44 @@ __copy_user_intel(void __user *to, const void *from, unsigned long size)
"101: lea 0(%%eax,%0,4),%0\n" "101: lea 0(%%eax,%0,4),%0\n"
" jmp 100b\n" " jmp 100b\n"
".previous\n" ".previous\n"
_ASM_EXTABLE(1b,100b) _ASM_EXTABLE_UA(1b, 100b)
_ASM_EXTABLE(2b,100b) _ASM_EXTABLE_UA(2b, 100b)
_ASM_EXTABLE(3b,100b) _ASM_EXTABLE_UA(3b, 100b)
_ASM_EXTABLE(4b,100b) _ASM_EXTABLE_UA(4b, 100b)
_ASM_EXTABLE(5b,100b) _ASM_EXTABLE_UA(5b, 100b)
_ASM_EXTABLE(6b,100b) _ASM_EXTABLE_UA(6b, 100b)
_ASM_EXTABLE(7b,100b) _ASM_EXTABLE_UA(7b, 100b)
_ASM_EXTABLE(8b,100b) _ASM_EXTABLE_UA(8b, 100b)
_ASM_EXTABLE(9b,100b) _ASM_EXTABLE_UA(9b, 100b)
_ASM_EXTABLE(10b,100b) _ASM_EXTABLE_UA(10b, 100b)
_ASM_EXTABLE(11b,100b) _ASM_EXTABLE_UA(11b, 100b)
_ASM_EXTABLE(12b,100b) _ASM_EXTABLE_UA(12b, 100b)
_ASM_EXTABLE(13b,100b) _ASM_EXTABLE_UA(13b, 100b)
_ASM_EXTABLE(14b,100b) _ASM_EXTABLE_UA(14b, 100b)
_ASM_EXTABLE(15b,100b) _ASM_EXTABLE_UA(15b, 100b)
_ASM_EXTABLE(16b,100b) _ASM_EXTABLE_UA(16b, 100b)
_ASM_EXTABLE(17b,100b) _ASM_EXTABLE_UA(17b, 100b)
_ASM_EXTABLE(18b,100b) _ASM_EXTABLE_UA(18b, 100b)
_ASM_EXTABLE(19b,100b) _ASM_EXTABLE_UA(19b, 100b)
_ASM_EXTABLE(20b,100b) _ASM_EXTABLE_UA(20b, 100b)
_ASM_EXTABLE(21b,100b) _ASM_EXTABLE_UA(21b, 100b)
_ASM_EXTABLE(22b,100b) _ASM_EXTABLE_UA(22b, 100b)
_ASM_EXTABLE(23b,100b) _ASM_EXTABLE_UA(23b, 100b)
_ASM_EXTABLE(24b,100b) _ASM_EXTABLE_UA(24b, 100b)
_ASM_EXTABLE(25b,100b) _ASM_EXTABLE_UA(25b, 100b)
_ASM_EXTABLE(26b,100b) _ASM_EXTABLE_UA(26b, 100b)
_ASM_EXTABLE(27b,100b) _ASM_EXTABLE_UA(27b, 100b)
_ASM_EXTABLE(28b,100b) _ASM_EXTABLE_UA(28b, 100b)
_ASM_EXTABLE(29b,100b) _ASM_EXTABLE_UA(29b, 100b)
_ASM_EXTABLE(30b,100b) _ASM_EXTABLE_UA(30b, 100b)
_ASM_EXTABLE(31b,100b) _ASM_EXTABLE_UA(31b, 100b)
_ASM_EXTABLE(32b,100b) _ASM_EXTABLE_UA(32b, 100b)
_ASM_EXTABLE(33b,100b) _ASM_EXTABLE_UA(33b, 100b)
_ASM_EXTABLE(34b,100b) _ASM_EXTABLE_UA(34b, 100b)
_ASM_EXTABLE(35b,100b) _ASM_EXTABLE_UA(35b, 100b)
_ASM_EXTABLE(36b,100b) _ASM_EXTABLE_UA(36b, 100b)
_ASM_EXTABLE(37b,100b) _ASM_EXTABLE_UA(37b, 100b)
_ASM_EXTABLE(99b,101b) _ASM_EXTABLE_UA(99b, 101b)
: "=&c"(size), "=&D" (d0), "=&S" (d1) : "=&c"(size), "=&D" (d0), "=&S" (d1)
: "1"(to), "2"(from), "0"(size) : "1"(to), "2"(from), "0"(size)
: "eax", "edx", "memory"); : "eax", "edx", "memory");
...@@ -259,26 +259,26 @@ static unsigned long __copy_user_intel_nocache(void *to, ...@@ -259,26 +259,26 @@ static unsigned long __copy_user_intel_nocache(void *to,
"9: lea 0(%%eax,%0,4),%0\n" "9: lea 0(%%eax,%0,4),%0\n"
"16: jmp 8b\n" "16: jmp 8b\n"
".previous\n" ".previous\n"
_ASM_EXTABLE(0b,16b) _ASM_EXTABLE_UA(0b, 16b)
_ASM_EXTABLE(1b,16b) _ASM_EXTABLE_UA(1b, 16b)
_ASM_EXTABLE(2b,16b) _ASM_EXTABLE_UA(2b, 16b)
_ASM_EXTABLE(21b,16b) _ASM_EXTABLE_UA(21b, 16b)
_ASM_EXTABLE(3b,16b) _ASM_EXTABLE_UA(3b, 16b)
_ASM_EXTABLE(31b,16b) _ASM_EXTABLE_UA(31b, 16b)
_ASM_EXTABLE(4b,16b) _ASM_EXTABLE_UA(4b, 16b)
_ASM_EXTABLE(41b,16b) _ASM_EXTABLE_UA(41b, 16b)
_ASM_EXTABLE(10b,16b) _ASM_EXTABLE_UA(10b, 16b)
_ASM_EXTABLE(51b,16b) _ASM_EXTABLE_UA(51b, 16b)
_ASM_EXTABLE(11b,16b) _ASM_EXTABLE_UA(11b, 16b)
_ASM_EXTABLE(61b,16b) _ASM_EXTABLE_UA(61b, 16b)
_ASM_EXTABLE(12b,16b) _ASM_EXTABLE_UA(12b, 16b)
_ASM_EXTABLE(71b,16b) _ASM_EXTABLE_UA(71b, 16b)
_ASM_EXTABLE(13b,16b) _ASM_EXTABLE_UA(13b, 16b)
_ASM_EXTABLE(81b,16b) _ASM_EXTABLE_UA(81b, 16b)
_ASM_EXTABLE(14b,16b) _ASM_EXTABLE_UA(14b, 16b)
_ASM_EXTABLE(91b,16b) _ASM_EXTABLE_UA(91b, 16b)
_ASM_EXTABLE(6b,9b) _ASM_EXTABLE_UA(6b, 9b)
_ASM_EXTABLE(7b,16b) _ASM_EXTABLE_UA(7b, 16b)
: "=&c"(size), "=&D" (d0), "=&S" (d1) : "=&c"(size), "=&D" (d0), "=&S" (d1)
: "1"(to), "2"(from), "0"(size) : "1"(to), "2"(from), "0"(size)
: "eax", "edx", "memory"); : "eax", "edx", "memory");
...@@ -321,9 +321,9 @@ do { \ ...@@ -321,9 +321,9 @@ do { \
"3: lea 0(%3,%0,4),%0\n" \ "3: lea 0(%3,%0,4),%0\n" \
" jmp 2b\n" \ " jmp 2b\n" \
".previous\n" \ ".previous\n" \
_ASM_EXTABLE(4b,5b) \ _ASM_EXTABLE_UA(4b, 5b) \
_ASM_EXTABLE(0b,3b) \ _ASM_EXTABLE_UA(0b, 3b) \
_ASM_EXTABLE(1b,2b) \ _ASM_EXTABLE_UA(1b, 2b) \
: "=&c"(size), "=&D" (__d0), "=&S" (__d1), "=r"(__d2) \ : "=&c"(size), "=&D" (__d0), "=&S" (__d1), "=r"(__d2) \
: "3"(size), "0"(size), "1"(to), "2"(from) \ : "3"(size), "0"(size), "1"(to), "2"(from) \
: "memory"); \ : "memory"); \
......
...@@ -37,8 +37,8 @@ unsigned long __clear_user(void __user *addr, unsigned long size) ...@@ -37,8 +37,8 @@ unsigned long __clear_user(void __user *addr, unsigned long size)
"3: lea 0(%[size1],%[size8],8),%[size8]\n" "3: lea 0(%[size1],%[size8],8),%[size8]\n"
" jmp 2b\n" " jmp 2b\n"
".previous\n" ".previous\n"
_ASM_EXTABLE(0b,3b) _ASM_EXTABLE_UA(0b, 3b)
_ASM_EXTABLE(1b,2b) _ASM_EXTABLE_UA(1b, 2b)
: [size8] "=&c"(size), [dst] "=&D" (__d0) : [size8] "=&c"(size), [dst] "=&D" (__d0)
: [size1] "r"(size & 7), "[size8]" (size / 8), "[dst]"(addr)); : [size1] "r"(size & 7), "[size8]" (size / 8), "[dst]"(addr));
clac(); clac();
......
...@@ -8,7 +8,8 @@ ...@@ -8,7 +8,8 @@
#include <asm/kdebug.h> #include <asm/kdebug.h>
typedef bool (*ex_handler_t)(const struct exception_table_entry *, typedef bool (*ex_handler_t)(const struct exception_table_entry *,
struct pt_regs *, int); struct pt_regs *, int, unsigned long,
unsigned long);
static inline unsigned long static inline unsigned long
ex_fixup_addr(const struct exception_table_entry *x) ex_fixup_addr(const struct exception_table_entry *x)
...@@ -22,7 +23,9 @@ ex_fixup_handler(const struct exception_table_entry *x) ...@@ -22,7 +23,9 @@ ex_fixup_handler(const struct exception_table_entry *x)
} }
__visible bool ex_handler_default(const struct exception_table_entry *fixup, __visible bool ex_handler_default(const struct exception_table_entry *fixup,
struct pt_regs *regs, int trapnr) struct pt_regs *regs, int trapnr,
unsigned long error_code,
unsigned long fault_addr)
{ {
regs->ip = ex_fixup_addr(fixup); regs->ip = ex_fixup_addr(fixup);
return true; return true;
...@@ -30,7 +33,9 @@ __visible bool ex_handler_default(const struct exception_table_entry *fixup, ...@@ -30,7 +33,9 @@ __visible bool ex_handler_default(const struct exception_table_entry *fixup,
EXPORT_SYMBOL(ex_handler_default); EXPORT_SYMBOL(ex_handler_default);
__visible bool ex_handler_fault(const struct exception_table_entry *fixup, __visible bool ex_handler_fault(const struct exception_table_entry *fixup,
struct pt_regs *regs, int trapnr) struct pt_regs *regs, int trapnr,
unsigned long error_code,
unsigned long fault_addr)
{ {
regs->ip = ex_fixup_addr(fixup); regs->ip = ex_fixup_addr(fixup);
regs->ax = trapnr; regs->ax = trapnr;
...@@ -43,7 +48,9 @@ EXPORT_SYMBOL_GPL(ex_handler_fault); ...@@ -43,7 +48,9 @@ EXPORT_SYMBOL_GPL(ex_handler_fault);
* result of a refcount inc/dec/add/sub. * result of a refcount inc/dec/add/sub.
*/ */
__visible bool ex_handler_refcount(const struct exception_table_entry *fixup, __visible bool ex_handler_refcount(const struct exception_table_entry *fixup,
struct pt_regs *regs, int trapnr) struct pt_regs *regs, int trapnr,
unsigned long error_code,
unsigned long fault_addr)
{ {
/* First unconditionally saturate the refcount. */ /* First unconditionally saturate the refcount. */
*(int *)regs->cx = INT_MIN / 2; *(int *)regs->cx = INT_MIN / 2;
...@@ -96,7 +103,9 @@ EXPORT_SYMBOL(ex_handler_refcount); ...@@ -96,7 +103,9 @@ EXPORT_SYMBOL(ex_handler_refcount);
* out all the FPU registers) if we can't restore from the task's FPU state. * out all the FPU registers) if we can't restore from the task's FPU state.
*/ */
__visible bool ex_handler_fprestore(const struct exception_table_entry *fixup, __visible bool ex_handler_fprestore(const struct exception_table_entry *fixup,
struct pt_regs *regs, int trapnr) struct pt_regs *regs, int trapnr,
unsigned long error_code,
unsigned long fault_addr)
{ {
regs->ip = ex_fixup_addr(fixup); regs->ip = ex_fixup_addr(fixup);
...@@ -108,9 +117,79 @@ __visible bool ex_handler_fprestore(const struct exception_table_entry *fixup, ...@@ -108,9 +117,79 @@ __visible bool ex_handler_fprestore(const struct exception_table_entry *fixup,
} }
EXPORT_SYMBOL_GPL(ex_handler_fprestore); EXPORT_SYMBOL_GPL(ex_handler_fprestore);
/* Helper to check whether a uaccess fault indicates a kernel bug. */
static bool bogus_uaccess(struct pt_regs *regs, int trapnr,
unsigned long fault_addr)
{
/* This is the normal case: #PF with a fault address in userspace. */
if (trapnr == X86_TRAP_PF && fault_addr < TASK_SIZE_MAX)
return false;
/*
* This code can be reached for machine checks, but only if the #MC
* handler has already decided that it looks like a candidate for fixup.
* This e.g. happens when attempting to access userspace memory which
* the CPU can't access because of uncorrectable bad memory.
*/
if (trapnr == X86_TRAP_MC)
return false;
/*
* There are two remaining exception types we might encounter here:
* - #PF for faulting accesses to kernel addresses
* - #GP for faulting accesses to noncanonical addresses
* Complain about anything else.
*/
if (trapnr != X86_TRAP_PF && trapnr != X86_TRAP_GP) {
WARN(1, "unexpected trap %d in uaccess\n", trapnr);
return false;
}
/*
* This is a faulting memory access in kernel space, on a kernel
* address, in a usercopy function. This can e.g. be caused by improper
* use of helpers like __put_user and by improper attempts to access
* userspace addresses in KERNEL_DS regions.
* The one (semi-)legitimate exception are probe_kernel_{read,write}(),
* which can be invoked from places like kgdb, /dev/mem (for reading)
* and privileged BPF code (for reading).
* The probe_kernel_*() functions set the kernel_uaccess_faults_ok flag
* to tell us that faulting on kernel addresses, and even noncanonical
* addresses, in a userspace accessor does not necessarily imply a
* kernel bug, root might just be doing weird stuff.
*/
if (current->kernel_uaccess_faults_ok)
return false;
/* This is bad. Refuse the fixup so that we go into die(). */
if (trapnr == X86_TRAP_PF) {
pr_emerg("BUG: pagefault on kernel address 0x%lx in non-whitelisted uaccess\n",
fault_addr);
} else {
pr_emerg("BUG: GPF in non-whitelisted uaccess (non-canonical address?)\n");
}
return true;
}
__visible bool ex_handler_uaccess(const struct exception_table_entry *fixup,
struct pt_regs *regs, int trapnr,
unsigned long error_code,
unsigned long fault_addr)
{
if (bogus_uaccess(regs, trapnr, fault_addr))
return false;
regs->ip = ex_fixup_addr(fixup);
return true;
}
EXPORT_SYMBOL(ex_handler_uaccess);
__visible bool ex_handler_ext(const struct exception_table_entry *fixup, __visible bool ex_handler_ext(const struct exception_table_entry *fixup,
struct pt_regs *regs, int trapnr) struct pt_regs *regs, int trapnr,
unsigned long error_code,
unsigned long fault_addr)
{ {
if (bogus_uaccess(regs, trapnr, fault_addr))
return false;
/* Special hack for uaccess_err */ /* Special hack for uaccess_err */
current->thread.uaccess_err = 1; current->thread.uaccess_err = 1;
regs->ip = ex_fixup_addr(fixup); regs->ip = ex_fixup_addr(fixup);
...@@ -119,7 +198,9 @@ __visible bool ex_handler_ext(const struct exception_table_entry *fixup, ...@@ -119,7 +198,9 @@ __visible bool ex_handler_ext(const struct exception_table_entry *fixup,
EXPORT_SYMBOL(ex_handler_ext); EXPORT_SYMBOL(ex_handler_ext);
__visible bool ex_handler_rdmsr_unsafe(const struct exception_table_entry *fixup, __visible bool ex_handler_rdmsr_unsafe(const struct exception_table_entry *fixup,
struct pt_regs *regs, int trapnr) struct pt_regs *regs, int trapnr,
unsigned long error_code,
unsigned long fault_addr)
{ {
if (pr_warn_once("unchecked MSR access error: RDMSR from 0x%x at rIP: 0x%lx (%pF)\n", if (pr_warn_once("unchecked MSR access error: RDMSR from 0x%x at rIP: 0x%lx (%pF)\n",
(unsigned int)regs->cx, regs->ip, (void *)regs->ip)) (unsigned int)regs->cx, regs->ip, (void *)regs->ip))
...@@ -134,7 +215,9 @@ __visible bool ex_handler_rdmsr_unsafe(const struct exception_table_entry *fixup ...@@ -134,7 +215,9 @@ __visible bool ex_handler_rdmsr_unsafe(const struct exception_table_entry *fixup
EXPORT_SYMBOL(ex_handler_rdmsr_unsafe); EXPORT_SYMBOL(ex_handler_rdmsr_unsafe);
__visible bool ex_handler_wrmsr_unsafe(const struct exception_table_entry *fixup, __visible bool ex_handler_wrmsr_unsafe(const struct exception_table_entry *fixup,
struct pt_regs *regs, int trapnr) struct pt_regs *regs, int trapnr,
unsigned long error_code,
unsigned long fault_addr)
{ {
if (pr_warn_once("unchecked MSR access error: WRMSR to 0x%x (tried to write 0x%08x%08x) at rIP: 0x%lx (%pF)\n", if (pr_warn_once("unchecked MSR access error: WRMSR to 0x%x (tried to write 0x%08x%08x) at rIP: 0x%lx (%pF)\n",
(unsigned int)regs->cx, (unsigned int)regs->dx, (unsigned int)regs->cx, (unsigned int)regs->dx,
...@@ -148,12 +231,14 @@ __visible bool ex_handler_wrmsr_unsafe(const struct exception_table_entry *fixup ...@@ -148,12 +231,14 @@ __visible bool ex_handler_wrmsr_unsafe(const struct exception_table_entry *fixup
EXPORT_SYMBOL(ex_handler_wrmsr_unsafe); EXPORT_SYMBOL(ex_handler_wrmsr_unsafe);
__visible bool ex_handler_clear_fs(const struct exception_table_entry *fixup, __visible bool ex_handler_clear_fs(const struct exception_table_entry *fixup,
struct pt_regs *regs, int trapnr) struct pt_regs *regs, int trapnr,
unsigned long error_code,
unsigned long fault_addr)
{ {
if (static_cpu_has(X86_BUG_NULL_SEG)) if (static_cpu_has(X86_BUG_NULL_SEG))
asm volatile ("mov %0, %%fs" : : "rm" (__USER_DS)); asm volatile ("mov %0, %%fs" : : "rm" (__USER_DS));
asm volatile ("mov %0, %%fs" : : "rm" (0)); asm volatile ("mov %0, %%fs" : : "rm" (0));
return ex_handler_default(fixup, regs, trapnr); return ex_handler_default(fixup, regs, trapnr, error_code, fault_addr);
} }
EXPORT_SYMBOL(ex_handler_clear_fs); EXPORT_SYMBOL(ex_handler_clear_fs);
...@@ -170,7 +255,8 @@ __visible bool ex_has_fault_handler(unsigned long ip) ...@@ -170,7 +255,8 @@ __visible bool ex_has_fault_handler(unsigned long ip)
return handler == ex_handler_fault; return handler == ex_handler_fault;
} }
int fixup_exception(struct pt_regs *regs, int trapnr) int fixup_exception(struct pt_regs *regs, int trapnr, unsigned long error_code,
unsigned long fault_addr)
{ {
const struct exception_table_entry *e; const struct exception_table_entry *e;
ex_handler_t handler; ex_handler_t handler;
...@@ -194,7 +280,7 @@ int fixup_exception(struct pt_regs *regs, int trapnr) ...@@ -194,7 +280,7 @@ int fixup_exception(struct pt_regs *regs, int trapnr)
return 0; return 0;
handler = ex_fixup_handler(e); handler = ex_fixup_handler(e);
return handler(e, regs, trapnr); return handler(e, regs, trapnr, error_code, fault_addr);
} }
extern unsigned int early_recursion_flag; extern unsigned int early_recursion_flag;
...@@ -230,9 +316,9 @@ void __init early_fixup_exception(struct pt_regs *regs, int trapnr) ...@@ -230,9 +316,9 @@ void __init early_fixup_exception(struct pt_regs *regs, int trapnr)
* result in a hard-to-debug panic. * result in a hard-to-debug panic.
* *
* Keep in mind that not all vectors actually get here. Early * Keep in mind that not all vectors actually get here. Early
* fage faults, for example, are special. * page faults, for example, are special.
*/ */
if (fixup_exception(regs, trapnr)) if (fixup_exception(regs, trapnr, regs->orig_ax, 0))
return; return;
if (fixup_bug(regs, trapnr)) if (fixup_bug(regs, trapnr))
......
...@@ -44,17 +44,19 @@ kmmio_fault(struct pt_regs *regs, unsigned long addr) ...@@ -44,17 +44,19 @@ kmmio_fault(struct pt_regs *regs, unsigned long addr)
static nokprobe_inline int kprobes_fault(struct pt_regs *regs) static nokprobe_inline int kprobes_fault(struct pt_regs *regs)
{ {
int ret = 0; if (!kprobes_built_in())
return 0;
/* kprobe_running() needs smp_processor_id() */ if (user_mode(regs))
if (kprobes_built_in() && !user_mode(regs)) { return 0;
preempt_disable(); /*
if (kprobe_running() && kprobe_fault_handler(regs, 14)) * To be potentially processing a kprobe fault and to be allowed to call
ret = 1; * kprobe_running(), we have to be non-preemptible.
preempt_enable(); */
} if (preemptible())
return 0;
return ret; if (!kprobe_running())
return 0;
return kprobe_fault_handler(regs, X86_TRAP_PF);
} }
/* /*
...@@ -709,7 +711,7 @@ no_context(struct pt_regs *regs, unsigned long error_code, ...@@ -709,7 +711,7 @@ no_context(struct pt_regs *regs, unsigned long error_code,
int sig; int sig;
/* Are we prepared to handle this kernel fault? */ /* Are we prepared to handle this kernel fault? */
if (fixup_exception(regs, X86_TRAP_PF)) { if (fixup_exception(regs, X86_TRAP_PF, error_code, address)) {
/* /*
* Any interrupt that takes a fault gets the fixup. This makes * Any interrupt that takes a fault gets the fixup. This makes
* the below recursive fault logic only apply to a faults from * the below recursive fault logic only apply to a faults from
......
...@@ -183,6 +183,7 @@ static const struct crashtype crashtypes[] = { ...@@ -183,6 +183,7 @@ static const struct crashtype crashtypes[] = {
CRASHTYPE(USERCOPY_STACK_FRAME_FROM), CRASHTYPE(USERCOPY_STACK_FRAME_FROM),
CRASHTYPE(USERCOPY_STACK_BEYOND), CRASHTYPE(USERCOPY_STACK_BEYOND),
CRASHTYPE(USERCOPY_KERNEL), CRASHTYPE(USERCOPY_KERNEL),
CRASHTYPE(USERCOPY_KERNEL_DS),
}; };
......
...@@ -82,5 +82,6 @@ void lkdtm_USERCOPY_STACK_FRAME_TO(void); ...@@ -82,5 +82,6 @@ void lkdtm_USERCOPY_STACK_FRAME_TO(void);
void lkdtm_USERCOPY_STACK_FRAME_FROM(void); void lkdtm_USERCOPY_STACK_FRAME_FROM(void);
void lkdtm_USERCOPY_STACK_BEYOND(void); void lkdtm_USERCOPY_STACK_BEYOND(void);
void lkdtm_USERCOPY_KERNEL(void); void lkdtm_USERCOPY_KERNEL(void);
void lkdtm_USERCOPY_KERNEL_DS(void);
#endif #endif
...@@ -322,6 +322,19 @@ void lkdtm_USERCOPY_KERNEL(void) ...@@ -322,6 +322,19 @@ void lkdtm_USERCOPY_KERNEL(void)
vm_munmap(user_addr, PAGE_SIZE); vm_munmap(user_addr, PAGE_SIZE);
} }
void lkdtm_USERCOPY_KERNEL_DS(void)
{
char __user *user_ptr = (char __user *)ERR_PTR(-EINVAL);
mm_segment_t old_fs = get_fs();
char buf[10] = {0};
pr_info("attempting copy_to_user on unmapped kernel address\n");
set_fs(KERNEL_DS);
if (copy_to_user(user_ptr, buf, sizeof(buf)))
pr_info("copy_to_user un unmapped kernel address failed\n");
set_fs(old_fs);
}
void __init lkdtm_usercopy_init(void) void __init lkdtm_usercopy_init(void)
{ {
/* Prepare cache that lacks SLAB_USERCOPY flag. */ /* Prepare cache that lacks SLAB_USERCOPY flag. */
......
...@@ -235,7 +235,7 @@ int mmc_of_parse(struct mmc_host *host) ...@@ -235,7 +235,7 @@ int mmc_of_parse(struct mmc_host *host)
host->caps |= MMC_CAP_NEEDS_POLL; host->caps |= MMC_CAP_NEEDS_POLL;
ret = mmc_gpiod_request_cd(host, "cd", 0, true, ret = mmc_gpiod_request_cd(host, "cd", 0, true,
cd_debounce_delay_ms, cd_debounce_delay_ms * 1000,
&cd_gpio_invert); &cd_gpio_invert);
if (!ret) if (!ret)
dev_info(host->parent, "Got CD GPIO\n"); dev_info(host->parent, "Got CD GPIO\n");
......
...@@ -271,7 +271,7 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id, ...@@ -271,7 +271,7 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
if (debounce) { if (debounce) {
ret = gpiod_set_debounce(desc, debounce); ret = gpiod_set_debounce(desc, debounce);
if (ret < 0) if (ret < 0)
ctx->cd_debounce_delay_ms = debounce; ctx->cd_debounce_delay_ms = debounce / 1000;
} }
if (gpio_invert) if (gpio_invert)
......
...@@ -498,7 +498,8 @@ static const struct soc_device_attribute gen3_soc_whitelist[] = { ...@@ -498,7 +498,8 @@ static const struct soc_device_attribute gen3_soc_whitelist[] = {
static int renesas_sdhi_sys_dmac_probe(struct platform_device *pdev) static int renesas_sdhi_sys_dmac_probe(struct platform_device *pdev)
{ {
if (of_device_get_match_data(&pdev->dev) == &of_rcar_gen3_compatible && if ((of_device_get_match_data(&pdev->dev) == &of_rcar_gen3_compatible ||
of_device_get_match_data(&pdev->dev) == &of_rcar_r8a7795_compatible) &&
!soc_device_match(gen3_soc_whitelist)) !soc_device_match(gen3_soc_whitelist))
return -ENODEV; return -ENODEV;
......
...@@ -2729,6 +2729,9 @@ static int qman_alloc_range(struct gen_pool *p, u32 *result, u32 cnt) ...@@ -2729,6 +2729,9 @@ static int qman_alloc_range(struct gen_pool *p, u32 *result, u32 cnt)
{ {
unsigned long addr; unsigned long addr;
if (!p)
return -ENODEV;
addr = gen_pool_alloc(p, cnt); addr = gen_pool_alloc(p, cnt);
if (!addr) if (!addr)
return -ENOMEM; return -ENOMEM;
......
...@@ -626,7 +626,7 @@ static u32 ucc_get_tdm_sync_shift(enum comm_dir mode, u32 tdm_num) ...@@ -626,7 +626,7 @@ static u32 ucc_get_tdm_sync_shift(enum comm_dir mode, u32 tdm_num)
{ {
u32 shift; u32 shift;
shift = (mode == COMM_DIR_RX) ? RX_SYNC_SHIFT_BASE : RX_SYNC_SHIFT_BASE; shift = (mode == COMM_DIR_RX) ? RX_SYNC_SHIFT_BASE : TX_SYNC_SHIFT_BASE;
shift -= tdm_num * 2; shift -= tdm_num * 2;
return shift; return shift;
......
...@@ -42,6 +42,7 @@ struct bmp_dib_header { ...@@ -42,6 +42,7 @@ struct bmp_dib_header {
u32 colors_important; u32 colors_important;
} __packed; } __packed;
static bool use_bgrt = true;
static bool request_mem_succeeded = false; static bool request_mem_succeeded = false;
static u64 mem_flags = EFI_MEMORY_WC | EFI_MEMORY_UC; static u64 mem_flags = EFI_MEMORY_WC | EFI_MEMORY_UC;
...@@ -160,6 +161,9 @@ static void efifb_show_boot_graphics(struct fb_info *info) ...@@ -160,6 +161,9 @@ static void efifb_show_boot_graphics(struct fb_info *info)
void *bgrt_image = NULL; void *bgrt_image = NULL;
u8 *dst = info->screen_base; u8 *dst = info->screen_base;
if (!use_bgrt)
return;
if (!bgrt_tab.image_address) { if (!bgrt_tab.image_address) {
pr_info("efifb: No BGRT, not showing boot graphics\n"); pr_info("efifb: No BGRT, not showing boot graphics\n");
return; return;
...@@ -290,6 +294,8 @@ static int efifb_setup(char *options) ...@@ -290,6 +294,8 @@ static int efifb_setup(char *options)
screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0); screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0);
else if (!strcmp(this_opt, "nowc")) else if (!strcmp(this_opt, "nowc"))
mem_flags &= ~EFI_MEMORY_WC; mem_flags &= ~EFI_MEMORY_WC;
else if (!strcmp(this_opt, "nobgrt"))
use_bgrt = false;
} }
} }
......
...@@ -496,6 +496,9 @@ static int omapfb_memory_read(struct fb_info *fbi, ...@@ -496,6 +496,9 @@ static int omapfb_memory_read(struct fb_info *fbi,
if (!access_ok(VERIFY_WRITE, mr->buffer, mr->buffer_size)) if (!access_ok(VERIFY_WRITE, mr->buffer, mr->buffer_size))
return -EFAULT; return -EFAULT;
if (mr->w > 4096 || mr->h > 4096)
return -EINVAL;
if (mr->w * mr->h * 3 > mr->buffer_size) if (mr->w * mr->h * 3 > mr->buffer_size)
return -EINVAL; return -EINVAL;
...@@ -509,7 +512,7 @@ static int omapfb_memory_read(struct fb_info *fbi, ...@@ -509,7 +512,7 @@ static int omapfb_memory_read(struct fb_info *fbi,
mr->x, mr->y, mr->w, mr->h); mr->x, mr->y, mr->w, mr->h);
if (r > 0) { if (r > 0) {
if (copy_to_user(mr->buffer, buf, mr->buffer_size)) if (copy_to_user(mr->buffer, buf, r))
r = -EFAULT; r = -EFAULT;
} }
......
...@@ -712,7 +712,7 @@ static int pxa168fb_probe(struct platform_device *pdev) ...@@ -712,7 +712,7 @@ static int pxa168fb_probe(struct platform_device *pdev)
/* /*
* enable controller clock * enable controller clock
*/ */
clk_enable(fbi->clk); clk_prepare_enable(fbi->clk);
pxa168fb_set_par(info); pxa168fb_set_par(info);
...@@ -767,7 +767,7 @@ static int pxa168fb_probe(struct platform_device *pdev) ...@@ -767,7 +767,7 @@ static int pxa168fb_probe(struct platform_device *pdev)
failed_free_cmap: failed_free_cmap:
fb_dealloc_cmap(&info->cmap); fb_dealloc_cmap(&info->cmap);
failed_free_clk: failed_free_clk:
clk_disable(fbi->clk); clk_disable_unprepare(fbi->clk);
failed_free_fbmem: failed_free_fbmem:
dma_free_coherent(fbi->dev, info->fix.smem_len, dma_free_coherent(fbi->dev, info->fix.smem_len,
info->screen_base, fbi->fb_start_dma); info->screen_base, fbi->fb_start_dma);
...@@ -807,7 +807,7 @@ static int pxa168fb_remove(struct platform_device *pdev) ...@@ -807,7 +807,7 @@ static int pxa168fb_remove(struct platform_device *pdev)
dma_free_wc(fbi->dev, PAGE_ALIGN(info->fix.smem_len), dma_free_wc(fbi->dev, PAGE_ALIGN(info->fix.smem_len),
info->screen_base, info->fix.smem_start); info->screen_base, info->fix.smem_start);
clk_disable(fbi->clk); clk_disable_unprepare(fbi->clk);
framebuffer_release(info); framebuffer_release(info);
......
...@@ -1157,7 +1157,7 @@ static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref) ...@@ -1157,7 +1157,7 @@ static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref)
dev_name); dev_name);
goto out_err0; goto out_err0;
} }
/* fall though */ /* fall through */
case S9000_ID_ARTIST: case S9000_ID_ARTIST:
case S9000_ID_HCRX: case S9000_ID_HCRX:
case S9000_ID_TIMBER: case S9000_ID_TIMBER:
......
...@@ -2642,6 +2642,7 @@ static long exact_copy_from_user(void *to, const void __user * from, ...@@ -2642,6 +2642,7 @@ static long exact_copy_from_user(void *to, const void __user * from,
if (!access_ok(VERIFY_READ, from, n)) if (!access_ok(VERIFY_READ, from, n))
return n; return n;
current->kernel_uaccess_faults_ok++;
while (n) { while (n) {
if (__get_user(c, f)) { if (__get_user(c, f)) {
memset(t, 0, n); memset(t, 0, n);
...@@ -2651,6 +2652,7 @@ static long exact_copy_from_user(void *to, const void __user * from, ...@@ -2651,6 +2652,7 @@ static long exact_copy_from_user(void *to, const void __user * from,
f++; f++;
n--; n--;
} }
current->kernel_uaccess_faults_ok--;
return n; return n;
} }
......
...@@ -898,8 +898,22 @@ static struct platform_driver ramoops_driver = { ...@@ -898,8 +898,22 @@ static struct platform_driver ramoops_driver = {
}, },
}; };
static void ramoops_register_dummy(void) static inline void ramoops_unregister_dummy(void)
{ {
platform_device_unregister(dummy);
dummy = NULL;
kfree(dummy_data);
dummy_data = NULL;
}
static void __init ramoops_register_dummy(void)
{
/*
* Prepare a dummy platform data structure to carry the module
* parameters. If mem_size isn't set, then there are no module
* parameters, and we can skip this.
*/
if (!mem_size) if (!mem_size)
return; return;
...@@ -932,21 +946,28 @@ static void ramoops_register_dummy(void) ...@@ -932,21 +946,28 @@ static void ramoops_register_dummy(void)
if (IS_ERR(dummy)) { if (IS_ERR(dummy)) {
pr_info("could not create platform device: %ld\n", pr_info("could not create platform device: %ld\n",
PTR_ERR(dummy)); PTR_ERR(dummy));
dummy = NULL;
ramoops_unregister_dummy();
} }
} }
static int __init ramoops_init(void) static int __init ramoops_init(void)
{ {
int ret;
ramoops_register_dummy(); ramoops_register_dummy();
return platform_driver_register(&ramoops_driver); ret = platform_driver_register(&ramoops_driver);
if (ret != 0)
ramoops_unregister_dummy();
return ret;
} }
late_initcall(ramoops_init); late_initcall(ramoops_init);
static void __exit ramoops_exit(void) static void __exit ramoops_exit(void)
{ {
platform_driver_unregister(&ramoops_driver); platform_driver_unregister(&ramoops_driver);
platform_device_unregister(dummy); ramoops_unregister_dummy();
kfree(dummy_data);
} }
module_exit(ramoops_exit); module_exit(ramoops_exit);
......
...@@ -739,6 +739,12 @@ struct task_struct { ...@@ -739,6 +739,12 @@ struct task_struct {
unsigned use_memdelay:1; unsigned use_memdelay:1;
#endif #endif
/*
* May usercopy functions fault on kernel addresses?
* This is not just a single bit because this can potentially nest.
*/
unsigned int kernel_uaccess_faults_ok;
unsigned long atomic_flags; /* Flags requiring atomic access. */ unsigned long atomic_flags; /* Flags requiring atomic access. */
struct restart_block restart_block; struct restart_block restart_block;
......
...@@ -30,8 +30,10 @@ long __probe_kernel_read(void *dst, const void *src, size_t size) ...@@ -30,8 +30,10 @@ long __probe_kernel_read(void *dst, const void *src, size_t size)
set_fs(KERNEL_DS); set_fs(KERNEL_DS);
pagefault_disable(); pagefault_disable();
current->kernel_uaccess_faults_ok++;
ret = __copy_from_user_inatomic(dst, ret = __copy_from_user_inatomic(dst,
(__force const void __user *)src, size); (__force const void __user *)src, size);
current->kernel_uaccess_faults_ok--;
pagefault_enable(); pagefault_enable();
set_fs(old_fs); set_fs(old_fs);
...@@ -58,7 +60,9 @@ long __probe_kernel_write(void *dst, const void *src, size_t size) ...@@ -58,7 +60,9 @@ long __probe_kernel_write(void *dst, const void *src, size_t size)
set_fs(KERNEL_DS); set_fs(KERNEL_DS);
pagefault_disable(); pagefault_disable();
current->kernel_uaccess_faults_ok++;
ret = __copy_to_user_inatomic((__force void __user *)dst, src, size); ret = __copy_to_user_inatomic((__force void __user *)dst, src, size);
current->kernel_uaccess_faults_ok--;
pagefault_enable(); pagefault_enable();
set_fs(old_fs); set_fs(old_fs);
...@@ -94,11 +98,13 @@ long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count) ...@@ -94,11 +98,13 @@ long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count)
set_fs(KERNEL_DS); set_fs(KERNEL_DS);
pagefault_disable(); pagefault_disable();
current->kernel_uaccess_faults_ok++;
do { do {
ret = __get_user(*dst++, (const char __user __force *)src++); ret = __get_user(*dst++, (const char __user __force *)src++);
} while (dst[-1] && ret == 0 && src - unsafe_addr < count); } while (dst[-1] && ret == 0 && src - unsafe_addr < count);
current->kernel_uaccess_faults_ok--;
dst[-1] = '\0'; dst[-1] = '\0';
pagefault_enable(); pagefault_enable();
set_fs(old_fs); set_fs(old_fs);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment