Merge tag 'v5.18-rc5' into android-mainline
Linux 5.18-rc5 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I57f4d16f93be06d1118821449eef752c90f95416
This commit is contained in:
@@ -5986,16 +5986,16 @@ should put the acknowledged interrupt vector into the 'epr' field.
|
||||
#define KVM_SYSTEM_EVENT_RESET 2
|
||||
#define KVM_SYSTEM_EVENT_CRASH 3
|
||||
__u32 type;
|
||||
__u64 flags;
|
||||
__u32 ndata;
|
||||
__u64 data[16];
|
||||
} system_event;
|
||||
|
||||
If exit_reason is KVM_EXIT_SYSTEM_EVENT then the vcpu has triggered
|
||||
a system-level event using some architecture specific mechanism (hypercall
|
||||
or some special instruction). In case of ARM64, this is triggered using
|
||||
HVC instruction based PSCI call from the vcpu. The 'type' field describes
|
||||
the system-level event type. The 'flags' field describes architecture
|
||||
specific flags for the system-level event.
|
||||
HVC instruction based PSCI call from the vcpu.
|
||||
|
||||
The 'type' field describes the system-level event type.
|
||||
Valid values for 'type' are:
|
||||
|
||||
- KVM_SYSTEM_EVENT_SHUTDOWN -- the guest has requested a shutdown of the
|
||||
@@ -6010,10 +6010,20 @@ Valid values for 'type' are:
|
||||
to ignore the request, or to gather VM memory core dump and/or
|
||||
reset/shutdown of the VM.
|
||||
|
||||
Valid flags are:
|
||||
If KVM_CAP_SYSTEM_EVENT_DATA is present, the 'data' field can contain
|
||||
architecture specific information for the system-level event. Only
|
||||
the first `ndata` items (possibly zero) of the data array are valid.
|
||||
|
||||
- KVM_SYSTEM_EVENT_RESET_FLAG_PSCI_RESET2 (arm64 only) -- the guest issued
|
||||
a SYSTEM_RESET2 call according to v1.1 of the PSCI specification.
|
||||
- for arm64, data[0] is set to KVM_SYSTEM_EVENT_RESET_FLAG_PSCI_RESET2 if
|
||||
the guest issued a SYSTEM_RESET2 call according to v1.1 of the PSCI
|
||||
specification.
|
||||
|
||||
- for RISC-V, data[0] is set to the value of the second argument of the
|
||||
``sbi_system_reset`` call.
|
||||
|
||||
Previous versions of Linux defined a `flags` member in this struct. The
|
||||
field is now aliased to `data[0]`. Userspace can assume that it is only
|
||||
written if ndata is greater than 0.
|
||||
|
||||
::
|
||||
|
||||
|
||||
@@ -21450,6 +21450,15 @@ F: arch/x86/include/asm/uv/
|
||||
F: arch/x86/kernel/apic/x2apic_uv_x.c
|
||||
F: arch/x86/platform/uv/
|
||||
|
||||
X86 STACK UNWINDING
|
||||
M: Josh Poimboeuf <jpoimboe@redhat.com>
|
||||
M: Peter Zijlstra <peterz@infradead.org>
|
||||
S: Supported
|
||||
F: arch/x86/include/asm/unwind*.h
|
||||
F: arch/x86/kernel/dumpstack.c
|
||||
F: arch/x86/kernel/stacktrace.c
|
||||
F: arch/x86/kernel/unwind_*.c
|
||||
|
||||
X86 VDSO
|
||||
M: Andy Lutomirski <luto@kernel.org>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
VERSION = 5
|
||||
PATCHLEVEL = 18
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc4
|
||||
EXTRAVERSION = -rc5
|
||||
NAME = Superb Owl
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
||||
@@ -40,6 +40,7 @@ void kvm_inject_undefined(struct kvm_vcpu *vcpu);
|
||||
void kvm_inject_vabt(struct kvm_vcpu *vcpu);
|
||||
void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr);
|
||||
void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr);
|
||||
void kvm_inject_size_fault(struct kvm_vcpu *vcpu);
|
||||
|
||||
void kvm_vcpu_wfi(struct kvm_vcpu *vcpu);
|
||||
|
||||
|
||||
@@ -198,15 +198,15 @@ SYM_CODE_START(__kvm_hyp_host_vector)
|
||||
invalid_host_el2_vect // FIQ EL2h
|
||||
invalid_host_el2_vect // Error EL2h
|
||||
|
||||
host_el1_sync_vect // Synchronous 64-bit EL1
|
||||
invalid_host_el1_vect // IRQ 64-bit EL1
|
||||
invalid_host_el1_vect // FIQ 64-bit EL1
|
||||
invalid_host_el1_vect // Error 64-bit EL1
|
||||
host_el1_sync_vect // Synchronous 64-bit EL1/EL0
|
||||
invalid_host_el1_vect // IRQ 64-bit EL1/EL0
|
||||
invalid_host_el1_vect // FIQ 64-bit EL1/EL0
|
||||
invalid_host_el1_vect // Error 64-bit EL1/EL0
|
||||
|
||||
invalid_host_el1_vect // Synchronous 32-bit EL1
|
||||
invalid_host_el1_vect // IRQ 32-bit EL1
|
||||
invalid_host_el1_vect // FIQ 32-bit EL1
|
||||
invalid_host_el1_vect // Error 32-bit EL1
|
||||
host_el1_sync_vect // Synchronous 32-bit EL1/EL0
|
||||
invalid_host_el1_vect // IRQ 32-bit EL1/EL0
|
||||
invalid_host_el1_vect // FIQ 32-bit EL1/EL0
|
||||
invalid_host_el1_vect // Error 32-bit EL1/EL0
|
||||
SYM_CODE_END(__kvm_hyp_host_vector)
|
||||
|
||||
/*
|
||||
|
||||
@@ -145,6 +145,34 @@ void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr)
|
||||
inject_abt64(vcpu, true, addr);
|
||||
}
|
||||
|
||||
void kvm_inject_size_fault(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
unsigned long addr, esr;
|
||||
|
||||
addr = kvm_vcpu_get_fault_ipa(vcpu);
|
||||
addr |= kvm_vcpu_get_hfar(vcpu) & GENMASK(11, 0);
|
||||
|
||||
if (kvm_vcpu_trap_is_iabt(vcpu))
|
||||
kvm_inject_pabt(vcpu, addr);
|
||||
else
|
||||
kvm_inject_dabt(vcpu, addr);
|
||||
|
||||
/*
|
||||
* If AArch64 or LPAE, set FSC to 0 to indicate an Address
|
||||
* Size Fault at level 0, as if exceeding PARange.
|
||||
*
|
||||
* Non-LPAE guests will only get the external abort, as there
|
||||
* is no way to to describe the ASF.
|
||||
*/
|
||||
if (vcpu_el1_is_32bit(vcpu) &&
|
||||
!(vcpu_read_sys_reg(vcpu, TCR_EL1) & TTBCR_EAE))
|
||||
return;
|
||||
|
||||
esr = vcpu_read_sys_reg(vcpu, ESR_EL1);
|
||||
esr &= ~GENMASK_ULL(5, 0);
|
||||
vcpu_write_sys_reg(vcpu, esr, ESR_EL1);
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_inject_undefined - inject an undefined instruction into the guest
|
||||
* @vcpu: The vCPU in which to inject the exception
|
||||
|
||||
@@ -1337,6 +1337,25 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
|
||||
fault_ipa = kvm_vcpu_get_fault_ipa(vcpu);
|
||||
is_iabt = kvm_vcpu_trap_is_iabt(vcpu);
|
||||
|
||||
if (fault_status == FSC_FAULT) {
|
||||
/* Beyond sanitised PARange (which is the IPA limit) */
|
||||
if (fault_ipa >= BIT_ULL(get_kvm_ipa_limit())) {
|
||||
kvm_inject_size_fault(vcpu);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Falls between the IPA range and the PARange? */
|
||||
if (fault_ipa >= BIT_ULL(vcpu->arch.hw_mmu->pgt->ia_bits)) {
|
||||
fault_ipa |= kvm_vcpu_get_hfar(vcpu) & GENMASK(11, 0);
|
||||
|
||||
if (is_iabt)
|
||||
kvm_inject_pabt(vcpu, fault_ipa);
|
||||
else
|
||||
kvm_inject_dabt(vcpu, fault_ipa);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Synchronous External Abort? */
|
||||
if (kvm_vcpu_abt_issea(vcpu)) {
|
||||
/*
|
||||
|
||||
@@ -177,6 +177,9 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
|
||||
struct kvm_pmu *pmu = &vcpu->arch.pmu;
|
||||
struct kvm_pmc *pmc = &pmu->pmc[select_idx];
|
||||
|
||||
if (!kvm_vcpu_has_pmu(vcpu))
|
||||
return 0;
|
||||
|
||||
counter = kvm_pmu_get_pair_counter_value(vcpu, pmc);
|
||||
|
||||
if (kvm_pmu_pmc_is_chained(pmc) &&
|
||||
@@ -198,6 +201,9 @@ void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu, u64 select_idx, u64 val)
|
||||
{
|
||||
u64 reg;
|
||||
|
||||
if (!kvm_vcpu_has_pmu(vcpu))
|
||||
return;
|
||||
|
||||
reg = (select_idx == ARMV8_PMU_CYCLE_IDX)
|
||||
? PMCCNTR_EL0 : PMEVCNTR0_EL0 + select_idx;
|
||||
__vcpu_sys_reg(vcpu, reg) += (s64)val - kvm_pmu_get_counter_value(vcpu, select_idx);
|
||||
@@ -322,6 +328,9 @@ void kvm_pmu_enable_counter_mask(struct kvm_vcpu *vcpu, u64 val)
|
||||
struct kvm_pmu *pmu = &vcpu->arch.pmu;
|
||||
struct kvm_pmc *pmc;
|
||||
|
||||
if (!kvm_vcpu_has_pmu(vcpu))
|
||||
return;
|
||||
|
||||
if (!(__vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E) || !val)
|
||||
return;
|
||||
|
||||
@@ -357,7 +366,7 @@ void kvm_pmu_disable_counter_mask(struct kvm_vcpu *vcpu, u64 val)
|
||||
struct kvm_pmu *pmu = &vcpu->arch.pmu;
|
||||
struct kvm_pmc *pmc;
|
||||
|
||||
if (!val)
|
||||
if (!kvm_vcpu_has_pmu(vcpu) || !val)
|
||||
return;
|
||||
|
||||
for (i = 0; i < ARMV8_PMU_MAX_COUNTERS; i++) {
|
||||
@@ -527,6 +536,9 @@ void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val)
|
||||
struct kvm_pmu *pmu = &vcpu->arch.pmu;
|
||||
int i;
|
||||
|
||||
if (!kvm_vcpu_has_pmu(vcpu))
|
||||
return;
|
||||
|
||||
if (!(__vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E))
|
||||
return;
|
||||
|
||||
@@ -576,6 +588,9 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!kvm_vcpu_has_pmu(vcpu))
|
||||
return;
|
||||
|
||||
if (val & ARMV8_PMU_PMCR_E) {
|
||||
kvm_pmu_enable_counter_mask(vcpu,
|
||||
__vcpu_sys_reg(vcpu, PMCNTENSET_EL0));
|
||||
@@ -739,6 +754,9 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
|
||||
{
|
||||
u64 reg, mask;
|
||||
|
||||
if (!kvm_vcpu_has_pmu(vcpu))
|
||||
return;
|
||||
|
||||
mask = ARMV8_PMU_EVTYPE_MASK;
|
||||
mask &= ~ARMV8_PMU_EVTYPE_EVENT;
|
||||
mask |= kvm_pmu_event_mask(vcpu->kvm);
|
||||
@@ -827,6 +845,9 @@ u64 kvm_pmu_get_pmceid(struct kvm_vcpu *vcpu, bool pmceid1)
|
||||
u64 val, mask = 0;
|
||||
int base, i, nr_events;
|
||||
|
||||
if (!kvm_vcpu_has_pmu(vcpu))
|
||||
return 0;
|
||||
|
||||
if (!pmceid1) {
|
||||
val = read_sysreg(pmceid0_el0);
|
||||
base = 0;
|
||||
|
||||
@@ -181,7 +181,8 @@ static void kvm_prepare_system_event(struct kvm_vcpu *vcpu, u32 type, u64 flags)
|
||||
|
||||
memset(&vcpu->run->system_event, 0, sizeof(vcpu->run->system_event));
|
||||
vcpu->run->system_event.type = type;
|
||||
vcpu->run->system_event.flags = flags;
|
||||
vcpu->run->system_event.ndata = 1;
|
||||
vcpu->run->system_event.data[0] = flags;
|
||||
vcpu->run->exit_reason = KVM_EXIT_SYSTEM_EVENT;
|
||||
}
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ void kvm_riscv_vcpu_sbi_forward(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
|
||||
void kvm_riscv_vcpu_sbi_system_reset(struct kvm_vcpu *vcpu,
|
||||
struct kvm_run *run,
|
||||
u32 type, u64 flags)
|
||||
u32 type, u64 reason)
|
||||
{
|
||||
unsigned long i;
|
||||
struct kvm_vcpu *tmp;
|
||||
@@ -94,7 +94,8 @@ void kvm_riscv_vcpu_sbi_system_reset(struct kvm_vcpu *vcpu,
|
||||
|
||||
memset(&run->system_event, 0, sizeof(run->system_event));
|
||||
run->system_event.type = type;
|
||||
run->system_event.flags = flags;
|
||||
run->system_event.ndata = 1;
|
||||
run->system_event.data[0] = reason;
|
||||
run->exit_reason = KVM_EXIT_SYSTEM_EVENT;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1866,7 +1866,7 @@ config X86_KERNEL_IBT
|
||||
code with them to make this happen.
|
||||
|
||||
In addition to building the kernel with IBT, seal all functions that
|
||||
are not indirect call targets, avoiding them ever becomming one.
|
||||
are not indirect call targets, avoiding them ever becoming one.
|
||||
|
||||
This requires LTO like objtool runs and will slow down the build. It
|
||||
does significantly reduce the number of ENDBR instructions in the
|
||||
|
||||
@@ -337,6 +337,9 @@ SYM_CODE_END(ret_from_fork)
|
||||
|
||||
call \cfunc
|
||||
|
||||
/* For some configurations \cfunc ends up being a noreturn. */
|
||||
REACHABLE
|
||||
|
||||
jmp error_return
|
||||
.endm
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
* _G - parts with extra graphics on
|
||||
* _X - regular server parts
|
||||
* _D - micro server parts
|
||||
* _N,_P - other mobile parts
|
||||
*
|
||||
* Historical OPTDIFFs:
|
||||
*
|
||||
@@ -107,8 +108,10 @@
|
||||
|
||||
#define INTEL_FAM6_ALDERLAKE 0x97 /* Golden Cove / Gracemont */
|
||||
#define INTEL_FAM6_ALDERLAKE_L 0x9A /* Golden Cove / Gracemont */
|
||||
#define INTEL_FAM6_ALDERLAKE_N 0xBE
|
||||
|
||||
#define INTEL_FAM6_RAPTORLAKE 0xB7
|
||||
#define INTEL_FAM6_RAPTORLAKE_P 0xBA
|
||||
|
||||
/* "Small Core" Processors (Atom) */
|
||||
|
||||
|
||||
@@ -131,10 +131,12 @@ extern void __init load_ucode_bsp(void);
|
||||
extern void load_ucode_ap(void);
|
||||
void reload_early_microcode(void);
|
||||
extern bool initrd_gone;
|
||||
void microcode_bsp_resume(void);
|
||||
#else
|
||||
static inline void __init load_ucode_bsp(void) { }
|
||||
static inline void load_ucode_ap(void) { }
|
||||
static inline void reload_early_microcode(void) { }
|
||||
static inline void microcode_bsp_resume(void) { }
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_X86_MICROCODE_H */
|
||||
|
||||
@@ -559,10 +559,6 @@ static inline void update_page_count(int level, unsigned long pages) { }
|
||||
extern pte_t *lookup_address(unsigned long address, unsigned int *level);
|
||||
extern pte_t *lookup_address_in_pgd(pgd_t *pgd, unsigned long address,
|
||||
unsigned int *level);
|
||||
|
||||
struct mm_struct;
|
||||
extern pte_t *lookup_address_in_mm(struct mm_struct *mm, unsigned long address,
|
||||
unsigned int *level);
|
||||
extern pmd_t *lookup_pmd_address(unsigned long address);
|
||||
extern phys_addr_t slow_virt_to_phys(void *__address);
|
||||
extern int __init kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn,
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
".align 4 \n" \
|
||||
".globl " STATIC_CALL_TRAMP_STR(name) " \n" \
|
||||
STATIC_CALL_TRAMP_STR(name) ": \n" \
|
||||
ANNOTATE_NOENDBR \
|
||||
insns " \n" \
|
||||
".byte 0x53, 0x43, 0x54 \n" \
|
||||
".type " STATIC_CALL_TRAMP_STR(name) ", @function \n" \
|
||||
|
||||
@@ -758,9 +758,9 @@ static struct subsys_interface mc_cpu_interface = {
|
||||
};
|
||||
|
||||
/**
|
||||
* mc_bp_resume - Update boot CPU microcode during resume.
|
||||
* microcode_bsp_resume - Update boot CPU microcode during resume.
|
||||
*/
|
||||
static void mc_bp_resume(void)
|
||||
void microcode_bsp_resume(void)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
|
||||
@@ -772,7 +772,7 @@ static void mc_bp_resume(void)
|
||||
}
|
||||
|
||||
static struct syscore_ops mc_syscore_ops = {
|
||||
.resume = mc_bp_resume,
|
||||
.resume = microcode_bsp_resume,
|
||||
};
|
||||
|
||||
static int mc_cpu_starting(unsigned int cpu)
|
||||
|
||||
@@ -339,11 +339,11 @@ static bool stack_access_ok(struct unwind_state *state, unsigned long _addr,
|
||||
struct stack_info *info = &state->stack_info;
|
||||
void *addr = (void *)_addr;
|
||||
|
||||
if (!on_stack(info, addr, len) &&
|
||||
(get_stack_info(addr, state->task, info, &state->stack_mask)))
|
||||
return false;
|
||||
if (on_stack(info, addr, len))
|
||||
return true;
|
||||
|
||||
return true;
|
||||
return !get_stack_info(addr, state->task, info, &state->stack_mask) &&
|
||||
on_stack(info, addr, len);
|
||||
}
|
||||
|
||||
static bool deref_stack_reg(struct unwind_state *state, unsigned long addr,
|
||||
|
||||
+14
-5
@@ -1085,12 +1085,21 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
|
||||
case 0x80000000:
|
||||
entry->eax = min(entry->eax, 0x80000021);
|
||||
/*
|
||||
* Serializing LFENCE is reported in a multitude of ways,
|
||||
* and NullSegClearsBase is not reported in CPUID on Zen2;
|
||||
* help userspace by providing the CPUID leaf ourselves.
|
||||
* Serializing LFENCE is reported in a multitude of ways, and
|
||||
* NullSegClearsBase is not reported in CPUID on Zen2; help
|
||||
* userspace by providing the CPUID leaf ourselves.
|
||||
*
|
||||
* However, only do it if the host has CPUID leaf 0x8000001d.
|
||||
* QEMU thinks that it can query the host blindly for that
|
||||
* CPUID leaf if KVM reports that it supports 0x8000001d or
|
||||
* above. The processor merrily returns values from the
|
||||
* highest Intel leaf which QEMU tries to use as the guest's
|
||||
* 0x8000001d. Even worse, this can result in an infinite
|
||||
* loop if said highest leaf has no subleaves indexed by ECX.
|
||||
*/
|
||||
if (static_cpu_has(X86_FEATURE_LFENCE_RDTSC)
|
||||
|| !static_cpu_has_bug(X86_BUG_NULL_SEG))
|
||||
if (entry->eax >= 0x8000001d &&
|
||||
(static_cpu_has(X86_FEATURE_LFENCE_RDTSC)
|
||||
|| !static_cpu_has_bug(X86_BUG_NULL_SEG)))
|
||||
entry->eax = max(entry->eax, 0x80000021);
|
||||
break;
|
||||
case 0x80000001:
|
||||
|
||||
@@ -65,6 +65,30 @@ static __always_inline u64 rsvd_bits(int s, int e)
|
||||
return ((2ULL << (e - s)) - 1) << s;
|
||||
}
|
||||
|
||||
/*
|
||||
* The number of non-reserved physical address bits irrespective of features
|
||||
* that repurpose legal bits, e.g. MKTME.
|
||||
*/
|
||||
extern u8 __read_mostly shadow_phys_bits;
|
||||
|
||||
static inline gfn_t kvm_mmu_max_gfn(void)
|
||||
{
|
||||
/*
|
||||
* Note that this uses the host MAXPHYADDR, not the guest's.
|
||||
* EPT/NPT cannot support GPAs that would exceed host.MAXPHYADDR;
|
||||
* assuming KVM is running on bare metal, guest accesses beyond
|
||||
* host.MAXPHYADDR will hit a #PF(RSVD) and never cause a vmexit
|
||||
* (either EPT Violation/Misconfig or #NPF), and so KVM will never
|
||||
* install a SPTE for such addresses. If KVM is running as a VM
|
||||
* itself, on the other hand, it might see a MAXPHYADDR that is less
|
||||
* than hardware's real MAXPHYADDR. Using the host MAXPHYADDR
|
||||
* disallows such SPTEs entirely and simplifies the TDP MMU.
|
||||
*/
|
||||
int max_gpa_bits = likely(tdp_enabled) ? shadow_phys_bits : 52;
|
||||
|
||||
return (1ULL << (max_gpa_bits - PAGE_SHIFT)) - 1;
|
||||
}
|
||||
|
||||
void kvm_mmu_set_mmio_spte_mask(u64 mmio_value, u64 mmio_mask, u64 access_mask);
|
||||
void kvm_mmu_set_ept_masks(bool has_ad_bits, bool has_exec_only);
|
||||
|
||||
|
||||
+50
-7
@@ -2804,8 +2804,12 @@ static int host_pfn_mapping_level(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn,
|
||||
const struct kvm_memory_slot *slot)
|
||||
{
|
||||
unsigned long hva;
|
||||
pte_t *pte;
|
||||
int level;
|
||||
unsigned long flags;
|
||||
int level = PG_LEVEL_4K;
|
||||
pgd_t pgd;
|
||||
p4d_t p4d;
|
||||
pud_t pud;
|
||||
pmd_t pmd;
|
||||
|
||||
if (!PageCompound(pfn_to_page(pfn)) && !kvm_is_zone_device_pfn(pfn))
|
||||
return PG_LEVEL_4K;
|
||||
@@ -2820,10 +2824,43 @@ static int host_pfn_mapping_level(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn,
|
||||
*/
|
||||
hva = __gfn_to_hva_memslot(slot, gfn);
|
||||
|
||||
pte = lookup_address_in_mm(kvm->mm, hva, &level);
|
||||
if (unlikely(!pte))
|
||||
return PG_LEVEL_4K;
|
||||
/*
|
||||
* Lookup the mapping level in the current mm. The information
|
||||
* may become stale soon, but it is safe to use as long as
|
||||
* 1) mmu_notifier_retry was checked after taking mmu_lock, and
|
||||
* 2) mmu_lock is taken now.
|
||||
*
|
||||
* We still need to disable IRQs to prevent concurrent tear down
|
||||
* of page tables.
|
||||
*/
|
||||
local_irq_save(flags);
|
||||
|
||||
pgd = READ_ONCE(*pgd_offset(kvm->mm, hva));
|
||||
if (pgd_none(pgd))
|
||||
goto out;
|
||||
|
||||
p4d = READ_ONCE(*p4d_offset(&pgd, hva));
|
||||
if (p4d_none(p4d) || !p4d_present(p4d))
|
||||
goto out;
|
||||
|
||||
pud = READ_ONCE(*pud_offset(&p4d, hva));
|
||||
if (pud_none(pud) || !pud_present(pud))
|
||||
goto out;
|
||||
|
||||
if (pud_large(pud)) {
|
||||
level = PG_LEVEL_1G;
|
||||
goto out;
|
||||
}
|
||||
|
||||
pmd = READ_ONCE(*pmd_offset(&pud, hva));
|
||||
if (pmd_none(pmd) || !pmd_present(pmd))
|
||||
goto out;
|
||||
|
||||
if (pmd_large(pmd))
|
||||
level = PG_LEVEL_2M;
|
||||
|
||||
out:
|
||||
local_irq_restore(flags);
|
||||
return level;
|
||||
}
|
||||
|
||||
@@ -2992,9 +3029,15 @@ static bool handle_abnormal_pfn(struct kvm_vcpu *vcpu, struct kvm_page_fault *fa
|
||||
/*
|
||||
* If MMIO caching is disabled, emulate immediately without
|
||||
* touching the shadow page tables as attempting to install an
|
||||
* MMIO SPTE will just be an expensive nop.
|
||||
* MMIO SPTE will just be an expensive nop. Do not cache MMIO
|
||||
* whose gfn is greater than host.MAXPHYADDR, any guest that
|
||||
* generates such gfns is running nested and is being tricked
|
||||
* by L0 userspace (you can observe gfn > L1.MAXPHYADDR if
|
||||
* and only if L1's MAXPHYADDR is inaccurate with respect to
|
||||
* the hardware's).
|
||||
*/
|
||||
if (unlikely(!shadow_mmio_value)) {
|
||||
if (unlikely(!shadow_mmio_value) ||
|
||||
unlikely(fault->gfn > kvm_mmu_max_gfn())) {
|
||||
*ret_val = RET_PF_EMULATE;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -201,12 +201,6 @@ static inline bool is_removed_spte(u64 spte)
|
||||
*/
|
||||
extern u64 __read_mostly shadow_nonpresent_or_rsvd_lower_gfn_mask;
|
||||
|
||||
/*
|
||||
* The number of non-reserved physical address bits irrespective of features
|
||||
* that repurpose legal bits, e.g. MKTME.
|
||||
*/
|
||||
extern u8 __read_mostly shadow_phys_bits;
|
||||
|
||||
static inline bool is_mmio_spte(u64 spte)
|
||||
{
|
||||
return (spte & shadow_mmio_mask) == shadow_mmio_value &&
|
||||
|
||||
@@ -815,14 +815,15 @@ static inline bool __must_check tdp_mmu_iter_cond_resched(struct kvm *kvm,
|
||||
return iter->yielded;
|
||||
}
|
||||
|
||||
static inline gfn_t tdp_mmu_max_gfn_host(void)
|
||||
static inline gfn_t tdp_mmu_max_gfn_exclusive(void)
|
||||
{
|
||||
/*
|
||||
* Bound TDP MMU walks at host.MAXPHYADDR, guest accesses beyond that
|
||||
* will hit a #PF(RSVD) and never hit an EPT Violation/Misconfig / #NPF,
|
||||
* and so KVM will never install a SPTE for such addresses.
|
||||
* Bound TDP MMU walks at host.MAXPHYADDR. KVM disallows memslots with
|
||||
* a gpa range that would exceed the max gfn, and KVM does not create
|
||||
* MMIO SPTEs for "impossible" gfns, instead sending such accesses down
|
||||
* the slow emulation path every time.
|
||||
*/
|
||||
return 1ULL << (shadow_phys_bits - PAGE_SHIFT);
|
||||
return kvm_mmu_max_gfn() + 1;
|
||||
}
|
||||
|
||||
static void __tdp_mmu_zap_root(struct kvm *kvm, struct kvm_mmu_page *root,
|
||||
@@ -830,7 +831,7 @@ static void __tdp_mmu_zap_root(struct kvm *kvm, struct kvm_mmu_page *root,
|
||||
{
|
||||
struct tdp_iter iter;
|
||||
|
||||
gfn_t end = tdp_mmu_max_gfn_host();
|
||||
gfn_t end = tdp_mmu_max_gfn_exclusive();
|
||||
gfn_t start = 0;
|
||||
|
||||
for_each_tdp_pte_min_level(iter, root, zap_level, start, end) {
|
||||
@@ -923,7 +924,7 @@ static bool tdp_mmu_zap_leafs(struct kvm *kvm, struct kvm_mmu_page *root,
|
||||
{
|
||||
struct tdp_iter iter;
|
||||
|
||||
end = min(end, tdp_mmu_max_gfn_host());
|
||||
end = min(end, tdp_mmu_max_gfn_exclusive());
|
||||
|
||||
lockdep_assert_held_write(&kvm->mmu_lock);
|
||||
|
||||
|
||||
+7
-1
@@ -10020,12 +10020,14 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
|
||||
if (kvm_check_request(KVM_REQ_HV_CRASH, vcpu)) {
|
||||
vcpu->run->exit_reason = KVM_EXIT_SYSTEM_EVENT;
|
||||
vcpu->run->system_event.type = KVM_SYSTEM_EVENT_CRASH;
|
||||
vcpu->run->system_event.ndata = 0;
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
if (kvm_check_request(KVM_REQ_HV_RESET, vcpu)) {
|
||||
vcpu->run->exit_reason = KVM_EXIT_SYSTEM_EVENT;
|
||||
vcpu->run->system_event.type = KVM_SYSTEM_EVENT_RESET;
|
||||
vcpu->run->system_event.ndata = 0;
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
@@ -12009,8 +12011,12 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
|
||||
struct kvm_memory_slot *new,
|
||||
enum kvm_mr_change change)
|
||||
{
|
||||
if (change == KVM_MR_CREATE || change == KVM_MR_MOVE)
|
||||
if (change == KVM_MR_CREATE || change == KVM_MR_MOVE) {
|
||||
if ((new->base_gfn + new->npages - 1) > kvm_mmu_max_gfn())
|
||||
return -EINVAL;
|
||||
|
||||
return kvm_alloc_memslot_metadata(kvm, new);
|
||||
}
|
||||
|
||||
if (change == KVM_MR_FLAGS_ONLY)
|
||||
memcpy(&new->arch, &old->arch, sizeof(old->arch));
|
||||
|
||||
+52
-35
@@ -53,12 +53,12 @@
|
||||
SYM_FUNC_START(copy_user_generic_unrolled)
|
||||
ASM_STAC
|
||||
cmpl $8,%edx
|
||||
jb 20f /* less then 8 bytes, go to byte copy loop */
|
||||
jb .Lcopy_user_short_string_bytes
|
||||
ALIGN_DESTINATION
|
||||
movl %edx,%ecx
|
||||
andl $63,%edx
|
||||
shrl $6,%ecx
|
||||
jz .L_copy_short_string
|
||||
jz copy_user_short_string
|
||||
1: movq (%rsi),%r8
|
||||
2: movq 1*8(%rsi),%r9
|
||||
3: movq 2*8(%rsi),%r10
|
||||
@@ -79,37 +79,11 @@ SYM_FUNC_START(copy_user_generic_unrolled)
|
||||
leaq 64(%rdi),%rdi
|
||||
decl %ecx
|
||||
jnz 1b
|
||||
.L_copy_short_string:
|
||||
movl %edx,%ecx
|
||||
andl $7,%edx
|
||||
shrl $3,%ecx
|
||||
jz 20f
|
||||
18: movq (%rsi),%r8
|
||||
19: movq %r8,(%rdi)
|
||||
leaq 8(%rsi),%rsi
|
||||
leaq 8(%rdi),%rdi
|
||||
decl %ecx
|
||||
jnz 18b
|
||||
20: andl %edx,%edx
|
||||
jz 23f
|
||||
movl %edx,%ecx
|
||||
21: movb (%rsi),%al
|
||||
22: movb %al,(%rdi)
|
||||
incq %rsi
|
||||
incq %rdi
|
||||
decl %ecx
|
||||
jnz 21b
|
||||
23: xor %eax,%eax
|
||||
ASM_CLAC
|
||||
RET
|
||||
jmp copy_user_short_string
|
||||
|
||||
30: shll $6,%ecx
|
||||
addl %ecx,%edx
|
||||
jmp 60f
|
||||
40: leal (%rdx,%rcx,8),%edx
|
||||
jmp 60f
|
||||
50: movl %ecx,%edx
|
||||
60: jmp .Lcopy_user_handle_tail /* ecx is zerorest also */
|
||||
jmp .Lcopy_user_handle_tail
|
||||
|
||||
_ASM_EXTABLE_CPY(1b, 30b)
|
||||
_ASM_EXTABLE_CPY(2b, 30b)
|
||||
@@ -127,10 +101,6 @@ SYM_FUNC_START(copy_user_generic_unrolled)
|
||||
_ASM_EXTABLE_CPY(14b, 30b)
|
||||
_ASM_EXTABLE_CPY(15b, 30b)
|
||||
_ASM_EXTABLE_CPY(16b, 30b)
|
||||
_ASM_EXTABLE_CPY(18b, 40b)
|
||||
_ASM_EXTABLE_CPY(19b, 40b)
|
||||
_ASM_EXTABLE_CPY(21b, 50b)
|
||||
_ASM_EXTABLE_CPY(22b, 50b)
|
||||
SYM_FUNC_END(copy_user_generic_unrolled)
|
||||
EXPORT_SYMBOL(copy_user_generic_unrolled)
|
||||
|
||||
@@ -191,7 +161,7 @@ EXPORT_SYMBOL(copy_user_generic_string)
|
||||
SYM_FUNC_START(copy_user_enhanced_fast_string)
|
||||
ASM_STAC
|
||||
/* CPUs without FSRM should avoid rep movsb for short copies */
|
||||
ALTERNATIVE "cmpl $64, %edx; jb .L_copy_short_string", "", X86_FEATURE_FSRM
|
||||
ALTERNATIVE "cmpl $64, %edx; jb copy_user_short_string", "", X86_FEATURE_FSRM
|
||||
movl %edx,%ecx
|
||||
1: rep movsb
|
||||
xorl %eax,%eax
|
||||
@@ -243,6 +213,53 @@ SYM_CODE_START_LOCAL(.Lcopy_user_handle_tail)
|
||||
|
||||
SYM_CODE_END(.Lcopy_user_handle_tail)
|
||||
|
||||
/*
|
||||
* Finish memcpy of less than 64 bytes. #AC should already be set.
|
||||
*
|
||||
* Input:
|
||||
* rdi destination
|
||||
* rsi source
|
||||
* rdx count (< 64)
|
||||
*
|
||||
* Output:
|
||||
* eax uncopied bytes or 0 if successful.
|
||||
*/
|
||||
SYM_CODE_START_LOCAL(copy_user_short_string)
|
||||
movl %edx,%ecx
|
||||
andl $7,%edx
|
||||
shrl $3,%ecx
|
||||
jz .Lcopy_user_short_string_bytes
|
||||
18: movq (%rsi),%r8
|
||||
19: movq %r8,(%rdi)
|
||||
leaq 8(%rsi),%rsi
|
||||
leaq 8(%rdi),%rdi
|
||||
decl %ecx
|
||||
jnz 18b
|
||||
.Lcopy_user_short_string_bytes:
|
||||
andl %edx,%edx
|
||||
jz 23f
|
||||
movl %edx,%ecx
|
||||
21: movb (%rsi),%al
|
||||
22: movb %al,(%rdi)
|
||||
incq %rsi
|
||||
incq %rdi
|
||||
decl %ecx
|
||||
jnz 21b
|
||||
23: xor %eax,%eax
|
||||
ASM_CLAC
|
||||
RET
|
||||
|
||||
40: leal (%rdx,%rcx,8),%edx
|
||||
jmp 60f
|
||||
50: movl %ecx,%edx /* ecx is zerorest also */
|
||||
60: jmp .Lcopy_user_handle_tail
|
||||
|
||||
_ASM_EXTABLE_CPY(18b, 40b)
|
||||
_ASM_EXTABLE_CPY(19b, 40b)
|
||||
_ASM_EXTABLE_CPY(21b, 50b)
|
||||
_ASM_EXTABLE_CPY(22b, 50b)
|
||||
SYM_CODE_END(copy_user_short_string)
|
||||
|
||||
/*
|
||||
* copy_user_nocache - Uncached memory copy with exception handling
|
||||
* This will force destination out of cache for more performance.
|
||||
|
||||
@@ -48,6 +48,7 @@ SYM_FUNC_START(__put_user_1)
|
||||
cmp %_ASM_BX,%_ASM_CX
|
||||
jae .Lbad_put_user
|
||||
SYM_INNER_LABEL(__put_user_nocheck_1, SYM_L_GLOBAL)
|
||||
ENDBR
|
||||
ASM_STAC
|
||||
1: movb %al,(%_ASM_CX)
|
||||
xor %ecx,%ecx
|
||||
@@ -62,6 +63,7 @@ SYM_FUNC_START(__put_user_2)
|
||||
cmp %_ASM_BX,%_ASM_CX
|
||||
jae .Lbad_put_user
|
||||
SYM_INNER_LABEL(__put_user_nocheck_2, SYM_L_GLOBAL)
|
||||
ENDBR
|
||||
ASM_STAC
|
||||
2: movw %ax,(%_ASM_CX)
|
||||
xor %ecx,%ecx
|
||||
@@ -76,6 +78,7 @@ SYM_FUNC_START(__put_user_4)
|
||||
cmp %_ASM_BX,%_ASM_CX
|
||||
jae .Lbad_put_user
|
||||
SYM_INNER_LABEL(__put_user_nocheck_4, SYM_L_GLOBAL)
|
||||
ENDBR
|
||||
ASM_STAC
|
||||
3: movl %eax,(%_ASM_CX)
|
||||
xor %ecx,%ecx
|
||||
@@ -90,6 +93,7 @@ SYM_FUNC_START(__put_user_8)
|
||||
cmp %_ASM_BX,%_ASM_CX
|
||||
jae .Lbad_put_user
|
||||
SYM_INNER_LABEL(__put_user_nocheck_8, SYM_L_GLOBAL)
|
||||
ENDBR
|
||||
ASM_STAC
|
||||
4: mov %_ASM_AX,(%_ASM_CX)
|
||||
#ifdef CONFIG_X86_32
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
.align RETPOLINE_THUNK_SIZE
|
||||
SYM_INNER_LABEL(__x86_indirect_thunk_\reg, SYM_L_GLOBAL)
|
||||
UNWIND_HINT_EMPTY
|
||||
ANNOTATE_NOENDBR
|
||||
|
||||
ALTERNATIVE_2 __stringify(ANNOTATE_RETPOLINE_SAFE; jmp *%\reg), \
|
||||
__stringify(RETPOLINE \reg), X86_FEATURE_RETPOLINE, \
|
||||
@@ -55,7 +56,6 @@ SYM_INNER_LABEL(__x86_indirect_thunk_\reg, SYM_L_GLOBAL)
|
||||
|
||||
.align RETPOLINE_THUNK_SIZE
|
||||
SYM_CODE_START(__x86_indirect_thunk_array)
|
||||
ANNOTATE_NOENDBR // apply_retpolines
|
||||
|
||||
#define GEN(reg) THUNK reg
|
||||
#include <asm/GEN-for-each-reg.h>
|
||||
|
||||
@@ -638,17 +638,6 @@ pte_t *lookup_address(unsigned long address, unsigned int *level)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lookup_address);
|
||||
|
||||
/*
|
||||
* Lookup the page table entry for a virtual address in a given mm. Return a
|
||||
* pointer to the entry and the level of the mapping.
|
||||
*/
|
||||
pte_t *lookup_address_in_mm(struct mm_struct *mm, unsigned long address,
|
||||
unsigned int *level)
|
||||
{
|
||||
return lookup_address_in_pgd(pgd_offset(mm, address), address, level);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lookup_address_in_mm);
|
||||
|
||||
static pte_t *_lookup_address_cpa(struct cpa_data *cpa, unsigned long address,
|
||||
unsigned int *level)
|
||||
{
|
||||
|
||||
+5
-1
@@ -467,7 +467,6 @@ static __init void xen_setup_pci_msi(void)
|
||||
else
|
||||
xen_msi_ops.setup_msi_irqs = xen_setup_msi_irqs;
|
||||
xen_msi_ops.teardown_msi_irqs = xen_pv_teardown_msi_irqs;
|
||||
pci_msi_ignore_mask = 1;
|
||||
} else if (xen_hvm_domain()) {
|
||||
xen_msi_ops.setup_msi_irqs = xen_hvm_setup_msi_irqs;
|
||||
xen_msi_ops.teardown_msi_irqs = xen_teardown_msi_irqs;
|
||||
@@ -481,6 +480,11 @@ static __init void xen_setup_pci_msi(void)
|
||||
* in allocating the native domain and never use it.
|
||||
*/
|
||||
x86_init.irqs.create_pci_msi_domain = xen_create_pci_msi_domain;
|
||||
/*
|
||||
* With XEN PIRQ/Eventchannels in use PCI/MSI[-X] masking is solely
|
||||
* controlled by the hypervisor.
|
||||
*/
|
||||
pci_msi_ignore_mask = 1;
|
||||
}
|
||||
|
||||
#else /* CONFIG_PCI_MSI */
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
#define PVH_DS_SEL (PVH_GDT_ENTRY_DS * 8)
|
||||
|
||||
SYM_CODE_START_LOCAL(pvh_start_xen)
|
||||
UNWIND_HINT_EMPTY
|
||||
cld
|
||||
|
||||
lgdt (_pa(gdt))
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/cpu_device_id.h>
|
||||
#include <asm/microcode.h>
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
__visible unsigned long saved_context_ebx;
|
||||
@@ -262,11 +263,18 @@ static void notrace __restore_processor_state(struct saved_context *ctxt)
|
||||
x86_platform.restore_sched_clock_state();
|
||||
mtrr_bp_restore();
|
||||
perf_restore_debug_store();
|
||||
msr_restore_context(ctxt);
|
||||
|
||||
c = &cpu_data(smp_processor_id());
|
||||
if (cpu_has(c, X86_FEATURE_MSR_IA32_FEAT_CTL))
|
||||
init_ia32_feat_ctl(c);
|
||||
|
||||
microcode_bsp_resume();
|
||||
|
||||
/*
|
||||
* This needs to happen after the microcode has been updated upon resume
|
||||
* because some of the MSRs are "emulated" in microcode.
|
||||
*/
|
||||
msr_restore_context(ctxt);
|
||||
}
|
||||
|
||||
/* Needed by apm.c */
|
||||
|
||||
@@ -45,6 +45,7 @@ SYM_CODE_END(hypercall_page)
|
||||
__INIT
|
||||
SYM_CODE_START(startup_xen)
|
||||
UNWIND_HINT_EMPTY
|
||||
ANNOTATE_NOENDBR
|
||||
cld
|
||||
|
||||
/* Clear .bss */
|
||||
|
||||
@@ -224,8 +224,12 @@ int fsl_mc_msi_domain_alloc_irqs(struct device *dev, unsigned int irq_count)
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
msi_lock_descs(dev);
|
||||
if (msi_first_desc(dev, MSI_DESC_ALL))
|
||||
return -EINVAL;
|
||||
error = -EINVAL;
|
||||
msi_unlock_descs(dev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/*
|
||||
* NOTE: Calling this function will trigger the invocation of the
|
||||
|
||||
@@ -21,6 +21,12 @@
|
||||
#include <linux/panic.h>
|
||||
#include <linux/printk.h>
|
||||
|
||||
struct warn_args;
|
||||
struct pt_regs;
|
||||
|
||||
void __warn(const char *file, int line, void *caller, unsigned taint,
|
||||
struct pt_regs *regs, struct warn_args *args);
|
||||
|
||||
#ifdef CONFIG_BUG
|
||||
|
||||
#ifdef CONFIG_GENERIC_BUG
|
||||
@@ -110,11 +116,6 @@ extern __printf(1, 2) void __warn_printk(const char *fmt, ...);
|
||||
#endif
|
||||
|
||||
/* used internally by panic.c */
|
||||
struct warn_args;
|
||||
struct pt_regs;
|
||||
|
||||
void __warn(const char *file, int line, void *caller, unsigned taint,
|
||||
struct pt_regs *regs, struct warn_args *args);
|
||||
|
||||
#ifndef WARN_ON
|
||||
#define WARN_ON(condition) ({ \
|
||||
|
||||
+1
-1
@@ -167,7 +167,7 @@ static inline int suspend_disable_secondary_cpus(void) { return 0; }
|
||||
static inline void suspend_enable_secondary_cpus(void) { }
|
||||
#endif /* !CONFIG_PM_SLEEP_SMP */
|
||||
|
||||
void cpu_startup_entry(enum cpuhp_state state);
|
||||
void __noreturn cpu_startup_entry(enum cpuhp_state state);
|
||||
|
||||
void cpu_idle_poll_ctrl(bool enable);
|
||||
|
||||
|
||||
@@ -445,7 +445,13 @@ struct kvm_run {
|
||||
#define KVM_SYSTEM_EVENT_RESET 2
|
||||
#define KVM_SYSTEM_EVENT_CRASH 3
|
||||
__u32 type;
|
||||
__u64 flags;
|
||||
__u32 ndata;
|
||||
union {
|
||||
#ifndef __KERNEL__
|
||||
__u64 flags;
|
||||
#endif
|
||||
__u64 data[16];
|
||||
};
|
||||
} system_event;
|
||||
/* KVM_EXIT_S390_STSI */
|
||||
struct {
|
||||
@@ -1144,6 +1150,8 @@ struct kvm_ppc_resize_hpt {
|
||||
#define KVM_CAP_S390_MEM_OP_EXTENSION 211
|
||||
#define KVM_CAP_PMU_CAPABILITY 212
|
||||
#define KVM_CAP_DISABLE_QUIRKS2 213
|
||||
/* #define KVM_CAP_VM_TSC_CONTROL 214 */
|
||||
#define KVM_CAP_SYSTEM_EVENT_DATA 215
|
||||
|
||||
#ifdef KVM_CAP_IRQ_ROUTING
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
* hit it), 'max' is the address space maximum (and we return
|
||||
* -EFAULT if we hit it).
|
||||
*/
|
||||
static inline long do_strncpy_from_user(char *dst, const char __user *src,
|
||||
static __always_inline long do_strncpy_from_user(char *dst, const char __user *src,
|
||||
unsigned long count, unsigned long max)
|
||||
{
|
||||
const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@
|
||||
* if it fits in a aligned 'long'. The caller needs to check
|
||||
* the return value against "> max".
|
||||
*/
|
||||
static inline long do_strnlen_user(const char __user *src, unsigned long count, unsigned long max)
|
||||
static __always_inline long do_strnlen_user(const char __user *src, unsigned long count, unsigned long max)
|
||||
{
|
||||
const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
|
||||
unsigned long align, res = 0;
|
||||
|
||||
@@ -231,7 +231,7 @@ objtool_args = \
|
||||
$(if $(part-of-module), --module) \
|
||||
$(if $(CONFIG_X86_KERNEL_IBT), --lto --ibt) \
|
||||
$(if $(CONFIG_FRAME_POINTER),, --no-fp) \
|
||||
$(if $(CONFIG_GCOV_KERNEL)$(CONFIG_LTO_CLANG), --no-unreachable)\
|
||||
$(if $(CONFIG_GCOV_KERNEL), --no-unreachable) \
|
||||
$(if $(CONFIG_RETPOLINE), --retpoline) \
|
||||
$(if $(CONFIG_X86_SMAP), --uaccess) \
|
||||
$(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount) \
|
||||
|
||||
@@ -140,7 +140,7 @@ objtool_link()
|
||||
if ! is_enabled CONFIG_FRAME_POINTER; then
|
||||
objtoolopt="${objtoolopt} --no-fp"
|
||||
fi
|
||||
if is_enabled CONFIG_GCOV_KERNEL || is_enabled CONFIG_LTO_CLANG; then
|
||||
if is_enabled CONFIG_GCOV_KERNEL; then
|
||||
objtoolopt="${objtoolopt} --no-unreachable"
|
||||
fi
|
||||
if is_enabled CONFIG_RETPOLINE; then
|
||||
|
||||
+49
-45
@@ -184,6 +184,7 @@ static bool __dead_end_function(struct objtool_file *file, struct symbol *func,
|
||||
"do_group_exit",
|
||||
"stop_this_cpu",
|
||||
"__invalid_creds",
|
||||
"cpu_startup_entry",
|
||||
};
|
||||
|
||||
if (!func)
|
||||
@@ -559,12 +560,12 @@ static int add_dead_ends(struct objtool_file *file)
|
||||
else if (reloc->addend == reloc->sym->sec->sh.sh_size) {
|
||||
insn = find_last_insn(file, reloc->sym->sec);
|
||||
if (!insn) {
|
||||
WARN("can't find unreachable insn at %s+0x%x",
|
||||
WARN("can't find unreachable insn at %s+0x%lx",
|
||||
reloc->sym->sec->name, reloc->addend);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
WARN("can't find unreachable insn at %s+0x%x",
|
||||
WARN("can't find unreachable insn at %s+0x%lx",
|
||||
reloc->sym->sec->name, reloc->addend);
|
||||
return -1;
|
||||
}
|
||||
@@ -594,12 +595,12 @@ reachable:
|
||||
else if (reloc->addend == reloc->sym->sec->sh.sh_size) {
|
||||
insn = find_last_insn(file, reloc->sym->sec);
|
||||
if (!insn) {
|
||||
WARN("can't find reachable insn at %s+0x%x",
|
||||
WARN("can't find reachable insn at %s+0x%lx",
|
||||
reloc->sym->sec->name, reloc->addend);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
WARN("can't find reachable insn at %s+0x%x",
|
||||
WARN("can't find reachable insn at %s+0x%lx",
|
||||
reloc->sym->sec->name, reloc->addend);
|
||||
return -1;
|
||||
}
|
||||
@@ -1271,12 +1272,19 @@ static bool is_first_func_insn(struct objtool_file *file, struct instruction *in
|
||||
*/
|
||||
static int add_jump_destinations(struct objtool_file *file)
|
||||
{
|
||||
struct instruction *insn;
|
||||
struct instruction *insn, *jump_dest;
|
||||
struct reloc *reloc;
|
||||
struct section *dest_sec;
|
||||
unsigned long dest_off;
|
||||
|
||||
for_each_insn(file, insn) {
|
||||
if (insn->jump_dest) {
|
||||
/*
|
||||
* handle_group_alt() may have previously set
|
||||
* 'jump_dest' for some alternatives.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
if (!is_static_jump(insn))
|
||||
continue;
|
||||
|
||||
@@ -1291,7 +1299,10 @@ static int add_jump_destinations(struct objtool_file *file)
|
||||
add_retpoline_call(file, insn);
|
||||
continue;
|
||||
} else if (insn->func) {
|
||||
/* internal or external sibling call (with reloc) */
|
||||
/*
|
||||
* External sibling call or internal sibling call with
|
||||
* STT_FUNC reloc.
|
||||
*/
|
||||
add_call_dest(file, insn, reloc->sym, true);
|
||||
continue;
|
||||
} else if (reloc->sym->sec->idx) {
|
||||
@@ -1303,17 +1314,8 @@ static int add_jump_destinations(struct objtool_file *file)
|
||||
continue;
|
||||
}
|
||||
|
||||
insn->jump_dest = find_insn(file, dest_sec, dest_off);
|
||||
if (!insn->jump_dest) {
|
||||
|
||||
/*
|
||||
* This is a special case where an alt instruction
|
||||
* jumps past the end of the section. These are
|
||||
* handled later in handle_group_alt().
|
||||
*/
|
||||
if (!strcmp(insn->sec->name, ".altinstr_replacement"))
|
||||
continue;
|
||||
|
||||
jump_dest = find_insn(file, dest_sec, dest_off);
|
||||
if (!jump_dest) {
|
||||
WARN_FUNC("can't find jump dest instruction at %s+0x%lx",
|
||||
insn->sec, insn->offset, dest_sec->name,
|
||||
dest_off);
|
||||
@@ -1323,8 +1325,8 @@ static int add_jump_destinations(struct objtool_file *file)
|
||||
/*
|
||||
* Cross-function jump.
|
||||
*/
|
||||
if (insn->func && insn->jump_dest->func &&
|
||||
insn->func != insn->jump_dest->func) {
|
||||
if (insn->func && jump_dest->func &&
|
||||
insn->func != jump_dest->func) {
|
||||
|
||||
/*
|
||||
* For GCC 8+, create parent/child links for any cold
|
||||
@@ -1342,16 +1344,22 @@ static int add_jump_destinations(struct objtool_file *file)
|
||||
* subfunction is through a jump table.
|
||||
*/
|
||||
if (!strstr(insn->func->name, ".cold") &&
|
||||
strstr(insn->jump_dest->func->name, ".cold")) {
|
||||
insn->func->cfunc = insn->jump_dest->func;
|
||||
insn->jump_dest->func->pfunc = insn->func;
|
||||
strstr(jump_dest->func->name, ".cold")) {
|
||||
insn->func->cfunc = jump_dest->func;
|
||||
jump_dest->func->pfunc = insn->func;
|
||||
|
||||
} else if (!same_function(insn, insn->jump_dest) &&
|
||||
is_first_func_insn(file, insn->jump_dest)) {
|
||||
/* internal sibling call (without reloc) */
|
||||
add_call_dest(file, insn, insn->jump_dest->func, true);
|
||||
} else if (!same_function(insn, jump_dest) &&
|
||||
is_first_func_insn(file, jump_dest)) {
|
||||
/*
|
||||
* Internal sibling call without reloc or with
|
||||
* STT_SECTION reloc.
|
||||
*/
|
||||
add_call_dest(file, insn, jump_dest->func, true);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
insn->jump_dest = jump_dest;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1540,13 +1548,13 @@ static int handle_group_alt(struct objtool_file *file,
|
||||
continue;
|
||||
|
||||
dest_off = arch_jump_destination(insn);
|
||||
if (dest_off == special_alt->new_off + special_alt->new_len)
|
||||
if (dest_off == special_alt->new_off + special_alt->new_len) {
|
||||
insn->jump_dest = next_insn_same_sec(file, last_orig_insn);
|
||||
|
||||
if (!insn->jump_dest) {
|
||||
WARN_FUNC("can't find alternative jump destination",
|
||||
insn->sec, insn->offset);
|
||||
return -1;
|
||||
if (!insn->jump_dest) {
|
||||
WARN_FUNC("can't find alternative jump destination",
|
||||
insn->sec, insn->offset);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2245,14 +2253,14 @@ static int decode_sections(struct objtool_file *file)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Must be before add_special_section_alts() as that depends on
|
||||
* jump_dest being set.
|
||||
* Must be before add_jump_destinations(), which depends on 'func'
|
||||
* being set for alternatives, to enable proper sibling call detection.
|
||||
*/
|
||||
ret = add_jump_destinations(file);
|
||||
ret = add_special_section_alts(file);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = add_special_section_alts(file);
|
||||
ret = add_jump_destinations(file);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -3210,9 +3218,8 @@ validate_ibt_reloc(struct objtool_file *file, struct reloc *reloc)
|
||||
static void warn_noendbr(const char *msg, struct section *sec, unsigned long offset,
|
||||
struct instruction *dest)
|
||||
{
|
||||
WARN_FUNC("%srelocation to !ENDBR: %s+0x%lx", sec, offset, msg,
|
||||
dest->func ? dest->func->name : dest->sec->name,
|
||||
dest->func ? dest->offset - dest->func->offset : dest->offset);
|
||||
WARN_FUNC("%srelocation to !ENDBR: %s", sec, offset, msg,
|
||||
offstr(dest->sec, dest->offset));
|
||||
}
|
||||
|
||||
static void validate_ibt_dest(struct objtool_file *file, struct instruction *insn,
|
||||
@@ -3303,7 +3310,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
|
||||
while (1) {
|
||||
next_insn = next_insn_to_validate(file, insn);
|
||||
|
||||
if (file->c_file && func && insn->func && func != insn->func->pfunc) {
|
||||
if (func && insn->func && func != insn->func->pfunc) {
|
||||
WARN("%s() falls through to next function %s()",
|
||||
func->name, insn->func->name);
|
||||
return 1;
|
||||
@@ -3816,11 +3823,8 @@ static int validate_ibt(struct objtool_file *file)
|
||||
struct instruction *dest;
|
||||
|
||||
dest = validate_ibt_reloc(file, reloc);
|
||||
if (is_data && dest && !dest->noendbr) {
|
||||
warn_noendbr("data ", reloc->sym->sec,
|
||||
reloc->sym->offset + reloc->addend,
|
||||
dest);
|
||||
}
|
||||
if (is_data && dest && !dest->noendbr)
|
||||
warn_noendbr("data ", sec, reloc->offset, dest);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+166
-23
@@ -546,7 +546,7 @@ static struct section *elf_create_reloc_section(struct elf *elf,
|
||||
int reltype);
|
||||
|
||||
int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset,
|
||||
unsigned int type, struct symbol *sym, int addend)
|
||||
unsigned int type, struct symbol *sym, long addend)
|
||||
{
|
||||
struct reloc *reloc;
|
||||
|
||||
@@ -575,37 +575,180 @@ int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure that any reloc section containing references to @sym is marked
|
||||
* changed such that it will get re-generated in elf_rebuild_reloc_sections()
|
||||
* with the new symbol index.
|
||||
*/
|
||||
static void elf_dirty_reloc_sym(struct elf *elf, struct symbol *sym)
|
||||
{
|
||||
struct section *sec;
|
||||
|
||||
list_for_each_entry(sec, &elf->sections, list) {
|
||||
struct reloc *reloc;
|
||||
|
||||
if (sec->changed)
|
||||
continue;
|
||||
|
||||
list_for_each_entry(reloc, &sec->reloc_list, list) {
|
||||
if (reloc->sym == sym) {
|
||||
sec->changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Move the first global symbol, as per sh_info, into a new, higher symbol
|
||||
* index. This fees up the shndx for a new local symbol.
|
||||
*/
|
||||
static int elf_move_global_symbol(struct elf *elf, struct section *symtab,
|
||||
struct section *symtab_shndx)
|
||||
{
|
||||
Elf_Data *data, *shndx_data = NULL;
|
||||
Elf32_Word first_non_local;
|
||||
struct symbol *sym;
|
||||
Elf_Scn *s;
|
||||
|
||||
first_non_local = symtab->sh.sh_info;
|
||||
|
||||
sym = find_symbol_by_index(elf, first_non_local);
|
||||
if (!sym) {
|
||||
WARN("no non-local symbols !?");
|
||||
return first_non_local;
|
||||
}
|
||||
|
||||
s = elf_getscn(elf->elf, symtab->idx);
|
||||
if (!s) {
|
||||
WARN_ELF("elf_getscn");
|
||||
return -1;
|
||||
}
|
||||
|
||||
data = elf_newdata(s);
|
||||
if (!data) {
|
||||
WARN_ELF("elf_newdata");
|
||||
return -1;
|
||||
}
|
||||
|
||||
data->d_buf = &sym->sym;
|
||||
data->d_size = sizeof(sym->sym);
|
||||
data->d_align = 1;
|
||||
data->d_type = ELF_T_SYM;
|
||||
|
||||
sym->idx = symtab->sh.sh_size / sizeof(sym->sym);
|
||||
elf_dirty_reloc_sym(elf, sym);
|
||||
|
||||
symtab->sh.sh_info += 1;
|
||||
symtab->sh.sh_size += data->d_size;
|
||||
symtab->changed = true;
|
||||
|
||||
if (symtab_shndx) {
|
||||
s = elf_getscn(elf->elf, symtab_shndx->idx);
|
||||
if (!s) {
|
||||
WARN_ELF("elf_getscn");
|
||||
return -1;
|
||||
}
|
||||
|
||||
shndx_data = elf_newdata(s);
|
||||
if (!shndx_data) {
|
||||
WARN_ELF("elf_newshndx_data");
|
||||
return -1;
|
||||
}
|
||||
|
||||
shndx_data->d_buf = &sym->sec->idx;
|
||||
shndx_data->d_size = sizeof(Elf32_Word);
|
||||
shndx_data->d_align = 4;
|
||||
shndx_data->d_type = ELF_T_WORD;
|
||||
|
||||
symtab_shndx->sh.sh_size += 4;
|
||||
symtab_shndx->changed = true;
|
||||
}
|
||||
|
||||
return first_non_local;
|
||||
}
|
||||
|
||||
static struct symbol *
|
||||
elf_create_section_symbol(struct elf *elf, struct section *sec)
|
||||
{
|
||||
struct section *symtab, *symtab_shndx;
|
||||
Elf_Data *shndx_data = NULL;
|
||||
struct symbol *sym;
|
||||
Elf32_Word shndx;
|
||||
|
||||
symtab = find_section_by_name(elf, ".symtab");
|
||||
if (symtab) {
|
||||
symtab_shndx = find_section_by_name(elf, ".symtab_shndx");
|
||||
if (symtab_shndx)
|
||||
shndx_data = symtab_shndx->data;
|
||||
} else {
|
||||
WARN("no .symtab");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sym = malloc(sizeof(*sym));
|
||||
if (!sym) {
|
||||
perror("malloc");
|
||||
return NULL;
|
||||
}
|
||||
memset(sym, 0, sizeof(*sym));
|
||||
|
||||
sym->idx = elf_move_global_symbol(elf, symtab, symtab_shndx);
|
||||
if (sym->idx < 0) {
|
||||
WARN("elf_move_global_symbol");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sym->name = sec->name;
|
||||
sym->sec = sec;
|
||||
|
||||
// st_name 0
|
||||
sym->sym.st_info = GELF_ST_INFO(STB_LOCAL, STT_SECTION);
|
||||
// st_other 0
|
||||
// st_value 0
|
||||
// st_size 0
|
||||
shndx = sec->idx;
|
||||
if (shndx >= SHN_UNDEF && shndx < SHN_LORESERVE) {
|
||||
sym->sym.st_shndx = shndx;
|
||||
if (!shndx_data)
|
||||
shndx = 0;
|
||||
} else {
|
||||
sym->sym.st_shndx = SHN_XINDEX;
|
||||
if (!shndx_data) {
|
||||
WARN("no .symtab_shndx");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!gelf_update_symshndx(symtab->data, shndx_data, sym->idx, &sym->sym, shndx)) {
|
||||
WARN_ELF("gelf_update_symshndx");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
elf_add_symbol(elf, sym);
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
int elf_add_reloc_to_insn(struct elf *elf, struct section *sec,
|
||||
unsigned long offset, unsigned int type,
|
||||
struct section *insn_sec, unsigned long insn_off)
|
||||
{
|
||||
struct symbol *sym;
|
||||
int addend;
|
||||
struct symbol *sym = insn_sec->sym;
|
||||
int addend = insn_off;
|
||||
|
||||
if (insn_sec->sym) {
|
||||
sym = insn_sec->sym;
|
||||
addend = insn_off;
|
||||
|
||||
} else {
|
||||
if (!sym) {
|
||||
/*
|
||||
* The Clang assembler strips section symbols, so we have to
|
||||
* reference the function symbol instead:
|
||||
* Due to how weak functions work, we must use section based
|
||||
* relocations. Symbol based relocations would result in the
|
||||
* weak and non-weak function annotations being overlaid on the
|
||||
* non-weak function after linking.
|
||||
*/
|
||||
sym = find_symbol_containing(insn_sec, insn_off);
|
||||
if (!sym) {
|
||||
/*
|
||||
* Hack alert. This happens when we need to reference
|
||||
* the NOP pad insn immediately after the function.
|
||||
*/
|
||||
sym = find_symbol_containing(insn_sec, insn_off - 1);
|
||||
}
|
||||
|
||||
if (!sym) {
|
||||
WARN("can't find symbol containing %s+0x%lx", insn_sec->name, insn_off);
|
||||
sym = elf_create_section_symbol(elf, insn_sec);
|
||||
if (!sym)
|
||||
return -1;
|
||||
}
|
||||
|
||||
addend = insn_off - sym->offset;
|
||||
insn_sec->sym = sym;
|
||||
}
|
||||
|
||||
return elf_add_reloc(elf, sec, offset, type, sym, addend);
|
||||
|
||||
@@ -73,7 +73,7 @@ struct reloc {
|
||||
struct symbol *sym;
|
||||
unsigned long offset;
|
||||
unsigned int type;
|
||||
int addend;
|
||||
long addend;
|
||||
int idx;
|
||||
bool jump_table_start;
|
||||
};
|
||||
@@ -135,7 +135,7 @@ struct elf *elf_open_read(const char *name, int flags);
|
||||
struct section *elf_create_section(struct elf *elf, const char *name, unsigned int sh_flags, size_t entsize, int nr);
|
||||
|
||||
int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset,
|
||||
unsigned int type, struct symbol *sym, int addend);
|
||||
unsigned int type, struct symbol *sym, long addend);
|
||||
int elf_add_reloc_to_insn(struct elf *elf, struct section *sec,
|
||||
unsigned long offset, unsigned int type,
|
||||
struct section *insn_sec, unsigned long insn_off);
|
||||
|
||||
@@ -27,7 +27,7 @@ struct objtool_file {
|
||||
struct list_head static_call_list;
|
||||
struct list_head mcount_loc_list;
|
||||
struct list_head endbr_list;
|
||||
bool ignore_unreachables, c_file, hints, rodata;
|
||||
bool ignore_unreachables, hints, rodata;
|
||||
|
||||
unsigned int nr_endbr;
|
||||
unsigned int nr_endbr_int;
|
||||
|
||||
@@ -129,7 +129,6 @@ struct objtool_file *objtool_open_read(const char *_objname)
|
||||
INIT_LIST_HEAD(&file.static_call_list);
|
||||
INIT_LIST_HEAD(&file.mcount_loc_list);
|
||||
INIT_LIST_HEAD(&file.endbr_list);
|
||||
file.c_file = !vmlinux && find_section_by_name(file.elf, ".comment");
|
||||
file.ignore_unreachables = no_unreachable;
|
||||
file.hints = false;
|
||||
|
||||
|
||||
@@ -4354,6 +4354,7 @@ static long kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg)
|
||||
return 0;
|
||||
#endif
|
||||
case KVM_CAP_BINARY_STATS_FD:
|
||||
case KVM_CAP_SYSTEM_EVENT_DATA:
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user