restore lost packages from 0.2.3 + fix overwritten 0.2.4 files
- Restore 29 recipe symlinks (libdrm, qtbase, dbus, sddm, pipewire, etc.) - Restore 33 patches (KDE, libdrm, mesa, pipewire, sddm, wireplumber) - Restore 20+ local/scripts (audit, lint, test, build helpers) - Restore src/cook/scheduler.rs, status.rs, gnu-config/ - Restore scripts/patch-inclusion-gate.sh, run_mini1.sh, validate-collision-log.sh - Recover TLC source from HEAD (was overwritten by 0.2.3 checkout) - Recover 11 local/docs plans from HEAD (were overwritten) - Recover qt6-wayland-smoke symlink from HEAD - Fix MOTD: remove garbled ASCII art, use clean text - Update version: 0.2.0 -> 0.2.4 in os-release, motd, config - Reduce filesystem_size: 1536 -> 512 MiB - Add ABSOLUTE RULE to AGENTS.md: never delete/ignore packages - Reduce pcid scheme log verbosity: info -> debug
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* These are in machine order; things rely on that.
|
||||
*/
|
||||
#ifdef CONFIG_64BIT
|
||||
GEN(rax)
|
||||
GEN(rcx)
|
||||
GEN(rdx)
|
||||
GEN(rbx)
|
||||
GEN(rsp)
|
||||
GEN(rbp)
|
||||
GEN(rsi)
|
||||
GEN(rdi)
|
||||
GEN(r8)
|
||||
GEN(r9)
|
||||
GEN(r10)
|
||||
GEN(r11)
|
||||
GEN(r12)
|
||||
GEN(r13)
|
||||
GEN(r14)
|
||||
GEN(r15)
|
||||
#else
|
||||
GEN(eax)
|
||||
GEN(ecx)
|
||||
GEN(edx)
|
||||
GEN(ebx)
|
||||
GEN(esp)
|
||||
GEN(ebp)
|
||||
GEN(esi)
|
||||
GEN(edi)
|
||||
#endif
|
||||
@@ -0,0 +1,54 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* X86 specific ACPICA environments and implementation
|
||||
*
|
||||
* Copyright (C) 2014, Intel Corporation
|
||||
* Author: Lv Zheng <lv.zheng@intel.com>
|
||||
*/
|
||||
|
||||
#ifndef _ASM_X86_ACENV_H
|
||||
#define _ASM_X86_ACENV_H
|
||||
|
||||
#include <asm/special_insns.h>
|
||||
|
||||
/* Asm macros */
|
||||
|
||||
/*
|
||||
* ACPI_FLUSH_CPU_CACHE() flushes caches on entering sleep states.
|
||||
* It is required to prevent data loss.
|
||||
*
|
||||
* While running inside virtual machine, the kernel can bypass cache flushing.
|
||||
* Changing sleep state in a virtual machine doesn't affect the host system
|
||||
* sleep state and cannot lead to data loss.
|
||||
*/
|
||||
#define ACPI_FLUSH_CPU_CACHE() \
|
||||
do { \
|
||||
if (!cpu_feature_enabled(X86_FEATURE_HYPERVISOR)) \
|
||||
wbinvd(); \
|
||||
} while (0)
|
||||
|
||||
int __acpi_acquire_global_lock(unsigned int *lock);
|
||||
int __acpi_release_global_lock(unsigned int *lock);
|
||||
|
||||
#define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \
|
||||
((Acq) = __acpi_acquire_global_lock(&facs->global_lock))
|
||||
|
||||
#define ACPI_RELEASE_GLOBAL_LOCK(facs, Acq) \
|
||||
((Acq) = __acpi_release_global_lock(&facs->global_lock))
|
||||
|
||||
/*
|
||||
* Math helper asm macros
|
||||
*/
|
||||
#define ACPI_DIV_64_BY_32(n_hi, n_lo, d32, q32, r32) \
|
||||
asm("divl %2;" \
|
||||
: "=a"(q32), "=d"(r32) \
|
||||
: "r"(d32), \
|
||||
"0"(n_lo), "1"(n_hi))
|
||||
|
||||
#define ACPI_SHIFT_RIGHT_64(n_hi, n_lo) \
|
||||
asm("shrl $1,%2 ;" \
|
||||
"rcrl $1,%3;" \
|
||||
: "=r"(n_hi), "=r"(n_lo) \
|
||||
: "0"(n_hi), "1"(n_lo))
|
||||
|
||||
#endif /* _ASM_X86_ACENV_H */
|
||||
@@ -0,0 +1,244 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
#ifndef _ASM_X86_ACPI_H
|
||||
#define _ASM_X86_ACPI_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
|
||||
* Copyright (C) 2001 Patrick Mochel <mochel@osdl.org>
|
||||
*/
|
||||
#include <acpi/proc_cap_intel.h>
|
||||
|
||||
#include <asm/numa.h>
|
||||
#include <asm/fixmap.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/mmu.h>
|
||||
#include <asm/mpspec.h>
|
||||
#include <asm/x86_init.h>
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/irq_vectors.h>
|
||||
#include <asm/xen/hypervisor.h>
|
||||
|
||||
#include <xen/xen.h>
|
||||
|
||||
#ifdef CONFIG_ACPI_APEI
|
||||
# include <asm/pgtable_types.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
extern int acpi_lapic;
|
||||
extern int acpi_ioapic;
|
||||
extern int acpi_noirq;
|
||||
extern int acpi_strict;
|
||||
extern int acpi_disabled;
|
||||
extern int acpi_pci_disabled;
|
||||
extern int acpi_skip_timer_override;
|
||||
extern int acpi_use_timer_override;
|
||||
extern int acpi_fix_pin2_polarity;
|
||||
extern int acpi_disable_cmcff;
|
||||
extern bool acpi_int_src_ovr[NR_IRQS_LEGACY];
|
||||
|
||||
extern u8 acpi_sci_flags;
|
||||
extern u32 acpi_sci_override_gsi;
|
||||
void acpi_pic_sci_set_trigger(unsigned int, u16);
|
||||
|
||||
struct device;
|
||||
|
||||
extern int (*__acpi_register_gsi)(struct device *dev, u32 gsi,
|
||||
int trigger, int polarity);
|
||||
extern void (*__acpi_unregister_gsi)(u32 gsi);
|
||||
|
||||
static inline void disable_acpi(void)
|
||||
{
|
||||
acpi_disabled = 1;
|
||||
acpi_pci_disabled = 1;
|
||||
acpi_noirq = 1;
|
||||
}
|
||||
|
||||
extern int acpi_gsi_to_irq(u32 gsi, unsigned int *irq);
|
||||
|
||||
extern int acpi_blacklisted(void);
|
||||
|
||||
static inline void acpi_noirq_set(void) { acpi_noirq = 1; }
|
||||
static inline void acpi_disable_pci(void)
|
||||
{
|
||||
acpi_pci_disabled = 1;
|
||||
acpi_noirq_set();
|
||||
}
|
||||
|
||||
/* Low-level suspend routine. */
|
||||
extern int (*acpi_suspend_lowlevel)(void);
|
||||
|
||||
/* Physical address to resume after wakeup */
|
||||
unsigned long acpi_get_wakeup_address(void);
|
||||
|
||||
static inline bool acpi_skip_set_wakeup_address(void)
|
||||
{
|
||||
return cpu_feature_enabled(X86_FEATURE_XENPV);
|
||||
}
|
||||
|
||||
#define acpi_skip_set_wakeup_address acpi_skip_set_wakeup_address
|
||||
|
||||
union acpi_subtable_headers;
|
||||
|
||||
int __init acpi_parse_mp_wake(union acpi_subtable_headers *header,
|
||||
const unsigned long end);
|
||||
|
||||
void asm_acpi_mp_play_dead(u64 reset_vector, u64 pgd_pa);
|
||||
|
||||
/*
|
||||
* Check if the CPU can handle C2 and deeper
|
||||
*/
|
||||
static inline unsigned int acpi_processor_cstate_check(unsigned int max_cstate)
|
||||
{
|
||||
/*
|
||||
* Early models (<=5) of AMD Opterons are not supposed to go into
|
||||
* C2 state.
|
||||
*
|
||||
* Steppings 0x0A and later are good
|
||||
*/
|
||||
if (boot_cpu_data.x86 == 0x0F &&
|
||||
boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
|
||||
boot_cpu_data.x86_model <= 0x05 &&
|
||||
boot_cpu_data.x86_stepping < 0x0A)
|
||||
return 1;
|
||||
else if (boot_cpu_has(X86_BUG_AMD_APIC_C1E))
|
||||
return 1;
|
||||
else
|
||||
return max_cstate;
|
||||
}
|
||||
|
||||
static inline bool arch_has_acpi_pdc(void)
|
||||
{
|
||||
struct cpuinfo_x86 *c = &cpu_data(0);
|
||||
return (c->x86_vendor == X86_VENDOR_INTEL ||
|
||||
c->x86_vendor == X86_VENDOR_CENTAUR);
|
||||
}
|
||||
|
||||
static inline void arch_acpi_set_proc_cap_bits(u32 *cap)
|
||||
{
|
||||
struct cpuinfo_x86 *c = &cpu_data(0);
|
||||
|
||||
*cap |= ACPI_PROC_CAP_C_CAPABILITY_SMP;
|
||||
|
||||
/* Enable coordination with firmware's _TSD info */
|
||||
*cap |= ACPI_PROC_CAP_SMP_T_SWCOORD;
|
||||
|
||||
if (cpu_has(c, X86_FEATURE_EST))
|
||||
*cap |= ACPI_PROC_CAP_EST_CAPABILITY_SWSMP;
|
||||
|
||||
if (cpu_has(c, X86_FEATURE_ACPI))
|
||||
*cap |= ACPI_PROC_CAP_T_FFH;
|
||||
|
||||
if (cpu_has(c, X86_FEATURE_HWP))
|
||||
*cap |= ACPI_PROC_CAP_COLLAB_PROC_PERF;
|
||||
|
||||
/*
|
||||
* If mwait/monitor is unsupported, C_C1_FFH and
|
||||
* C2/C3_FFH will be disabled.
|
||||
*/
|
||||
if (!cpu_has(c, X86_FEATURE_MWAIT) ||
|
||||
boot_option_idle_override == IDLE_NOMWAIT)
|
||||
*cap &= ~(ACPI_PROC_CAP_C_C1_FFH | ACPI_PROC_CAP_C_C2C3_FFH);
|
||||
|
||||
if (xen_initial_domain()) {
|
||||
/*
|
||||
* When Linux is running as Xen dom0, the hypervisor is the
|
||||
* entity in charge of the processor power management, and so
|
||||
* Xen needs to check the OS capabilities reported in the
|
||||
* processor capabilities buffer matches what the hypervisor
|
||||
* driver supports.
|
||||
*/
|
||||
xen_sanitize_proc_cap_bits(cap);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool acpi_has_cpu_in_madt(void)
|
||||
{
|
||||
return !!acpi_lapic;
|
||||
}
|
||||
|
||||
#define ACPI_HAVE_ARCH_SET_ROOT_POINTER
|
||||
static __always_inline void acpi_arch_set_root_pointer(u64 addr)
|
||||
{
|
||||
x86_init.acpi.set_root_pointer(addr);
|
||||
}
|
||||
|
||||
#define ACPI_HAVE_ARCH_GET_ROOT_POINTER
|
||||
static __always_inline u64 acpi_arch_get_root_pointer(void)
|
||||
{
|
||||
return x86_init.acpi.get_root_pointer();
|
||||
}
|
||||
|
||||
void acpi_generic_reduced_hw_init(void);
|
||||
|
||||
void x86_default_set_root_pointer(u64 addr);
|
||||
u64 x86_default_get_root_pointer(void);
|
||||
|
||||
#ifdef CONFIG_XEN_PV
|
||||
/* A Xen PV domain needs a special acpi_os_ioremap() handling. */
|
||||
extern void __iomem * (*acpi_os_ioremap)(acpi_physical_address phys,
|
||||
acpi_size size);
|
||||
void __iomem *x86_acpi_os_ioremap(acpi_physical_address phys, acpi_size size);
|
||||
#define acpi_os_ioremap acpi_os_ioremap
|
||||
#endif
|
||||
|
||||
#else /* !CONFIG_ACPI */
|
||||
|
||||
#define acpi_lapic 0
|
||||
#define acpi_ioapic 0
|
||||
#define acpi_disable_cmcff 0
|
||||
static inline void acpi_noirq_set(void) { }
|
||||
static inline void acpi_disable_pci(void) { }
|
||||
static inline void disable_acpi(void) { }
|
||||
|
||||
static inline void acpi_generic_reduced_hw_init(void) { }
|
||||
|
||||
static inline void x86_default_set_root_pointer(u64 addr) { }
|
||||
|
||||
static inline u64 x86_default_get_root_pointer(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_ACPI */
|
||||
|
||||
#define ARCH_HAS_POWER_INIT 1
|
||||
|
||||
#ifdef CONFIG_ACPI_NUMA
|
||||
extern int x86_acpi_numa_init(void);
|
||||
#endif /* CONFIG_ACPI_NUMA */
|
||||
|
||||
struct cper_ia_proc_ctx;
|
||||
|
||||
#ifdef CONFIG_ACPI_APEI
|
||||
static inline pgprot_t arch_apei_get_mem_attribute(phys_addr_t addr)
|
||||
{
|
||||
/*
|
||||
* We currently have no way to look up the EFI memory map
|
||||
* attributes for a region in a consistent way, because the
|
||||
* memmap is discarded after efi_free_boot_services(). So if
|
||||
* you call efi_mem_attributes() during boot and at runtime,
|
||||
* you could theoretically see different attributes.
|
||||
*
|
||||
* We are yet to see any x86 platforms that require anything
|
||||
* other than PAGE_KERNEL (some ARM64 platforms require the
|
||||
* equivalent of PAGE_KERNEL_NOCACHE). Additionally, if SME
|
||||
* is active, the ACPI information will not be encrypted,
|
||||
* so return PAGE_KERNEL_NOENC until we know differently.
|
||||
*/
|
||||
return PAGE_KERNEL_NOENC;
|
||||
}
|
||||
|
||||
int arch_apei_report_x86_error(struct cper_ia_proc_ctx *ctx_info,
|
||||
u64 lapic_id);
|
||||
#else
|
||||
static inline int arch_apei_report_x86_error(struct cper_ia_proc_ctx *ctx_info,
|
||||
u64 lapic_id)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define ACPI_TABLE_UPGRADE_MAX_PHYS (max_low_pfn_mapped << PAGE_SHIFT)
|
||||
|
||||
#endif /* _ASM_X86_ACPI_H */
|
||||
@@ -0,0 +1,92 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_ACRN_H
|
||||
#define _ASM_X86_ACRN_H
|
||||
|
||||
/*
|
||||
* This CPUID returns feature bitmaps in EAX.
|
||||
* Guest VM uses this to detect the appropriate feature bit.
|
||||
*/
|
||||
#define ACRN_CPUID_FEATURES 0x40000001
|
||||
/* Bit 0 indicates whether guest VM is privileged */
|
||||
#define ACRN_FEATURE_PRIVILEGED_VM BIT(0)
|
||||
|
||||
/*
|
||||
* Timing Information.
|
||||
* This leaf returns the current TSC frequency in kHz.
|
||||
*
|
||||
* EAX: (Virtual) TSC frequency in kHz.
|
||||
* EBX, ECX, EDX: RESERVED (reserved fields are set to zero).
|
||||
*/
|
||||
#define ACRN_CPUID_TIMING_INFO 0x40000010
|
||||
|
||||
void acrn_setup_intr_handler(void (*handler)(void));
|
||||
void acrn_remove_intr_handler(void);
|
||||
|
||||
static inline u32 acrn_cpuid_base(void)
|
||||
{
|
||||
if (boot_cpu_has(X86_FEATURE_HYPERVISOR))
|
||||
return cpuid_base_hypervisor("ACRNACRNACRN", 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline unsigned long acrn_get_tsc_khz(void)
|
||||
{
|
||||
return cpuid_eax(ACRN_CPUID_TIMING_INFO);
|
||||
}
|
||||
|
||||
/*
|
||||
* Hypercalls for ACRN
|
||||
*
|
||||
* - VMCALL instruction is used to implement ACRN hypercalls.
|
||||
* - ACRN hypercall ABI:
|
||||
* - Hypercall number is passed in R8 register.
|
||||
* - Up to 2 arguments are passed in RDI, RSI.
|
||||
* - Return value will be placed in RAX.
|
||||
*
|
||||
* Because GCC doesn't support R8 register as direct register constraints, use
|
||||
* supported constraint as input with a explicit MOV to R8 in beginning of asm.
|
||||
*/
|
||||
static inline long acrn_hypercall0(unsigned long hcall_id)
|
||||
{
|
||||
long result;
|
||||
|
||||
asm volatile("movl %1, %%r8d\n\t"
|
||||
"vmcall\n\t"
|
||||
: "=a" (result)
|
||||
: "g" (hcall_id)
|
||||
: "r8", "memory");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline long acrn_hypercall1(unsigned long hcall_id,
|
||||
unsigned long param1)
|
||||
{
|
||||
long result;
|
||||
|
||||
asm volatile("movl %1, %%r8d\n\t"
|
||||
"vmcall\n\t"
|
||||
: "=a" (result)
|
||||
: "g" (hcall_id), "D" (param1)
|
||||
: "r8", "memory");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline long acrn_hypercall2(unsigned long hcall_id,
|
||||
unsigned long param1,
|
||||
unsigned long param2)
|
||||
{
|
||||
long result;
|
||||
|
||||
asm volatile("movl %1, %%r8d\n\t"
|
||||
"vmcall\n\t"
|
||||
: "=a" (result)
|
||||
: "g" (hcall_id), "D" (param1), "S" (param2)
|
||||
: "r8", "memory");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* _ASM_X86_ACRN_H */
|
||||
@@ -0,0 +1,26 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_AGP_H
|
||||
#define _ASM_X86_AGP_H
|
||||
|
||||
#include <linux/pgtable.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
/*
|
||||
* Functions to keep the agpgart mappings coherent with the MMU. The
|
||||
* GART gives the CPU a physical alias of pages in memory. The alias
|
||||
* region is mapped uncacheable. Make sure there are no conflicting
|
||||
* mappings with different cacheability attributes for the same
|
||||
* page. This avoids data corruption on some CPUs.
|
||||
*/
|
||||
|
||||
#define map_page_into_agp(page) set_pages_uc(page, 1)
|
||||
#define unmap_page_from_agp(page) set_pages_wb(page, 1)
|
||||
|
||||
/*
|
||||
* Could use CLFLUSH here if the cpu supports it. But then it would
|
||||
* need to be called for each cacheline of the whole page so it may
|
||||
* not be worth it. Would need a page for it.
|
||||
*/
|
||||
#define flush_agp_cache() wbinvd()
|
||||
|
||||
#endif /* _ASM_X86_AGP_H */
|
||||
@@ -0,0 +1,401 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_ALTERNATIVE_H
|
||||
#define _ASM_X86_ALTERNATIVE_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/stringify.h>
|
||||
#include <linux/objtool.h>
|
||||
#include <asm/asm.h>
|
||||
#include <asm/bug.h>
|
||||
|
||||
#define ALT_FLAGS_SHIFT 16
|
||||
|
||||
#define ALT_FLAG_NOT (1 << 0)
|
||||
#define ALT_NOT(feature) ((ALT_FLAG_NOT << ALT_FLAGS_SHIFT) | (feature))
|
||||
#define ALT_FLAG_DIRECT_CALL (1 << 1)
|
||||
#define ALT_DIRECT_CALL(feature) ((ALT_FLAG_DIRECT_CALL << ALT_FLAGS_SHIFT) | (feature))
|
||||
#define ALT_CALL_ALWAYS ALT_DIRECT_CALL(X86_FEATURE_ALWAYS)
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#include <linux/stddef.h>
|
||||
|
||||
/*
|
||||
* Alternative inline assembly for SMP.
|
||||
*
|
||||
* The LOCK_PREFIX macro defined here replaces the LOCK and
|
||||
* LOCK_PREFIX macros used everywhere in the source tree.
|
||||
*
|
||||
* SMP alternatives use the same data structures as the other
|
||||
* alternatives and the X86_FEATURE_UP flag to indicate the case of a
|
||||
* UP system running a SMP kernel. The existing apply_alternatives()
|
||||
* works fine for patching a SMP kernel for UP.
|
||||
*
|
||||
* The SMP alternative tables can be kept after boot and contain both
|
||||
* UP and SMP versions of the instructions to allow switching back to
|
||||
* SMP at runtime, when hotplugging in a new CPU, which is especially
|
||||
* useful in virtualized environments.
|
||||
*
|
||||
* The very common lock prefix is handled as special case in a
|
||||
* separate table which is a pure address list without replacement ptr
|
||||
* and size information. That keeps the table sizes small.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
#define LOCK_PREFIX_HERE \
|
||||
".pushsection .smp_locks,\"a\"\n" \
|
||||
".balign 4\n" \
|
||||
".long 671f - .\n" /* offset */ \
|
||||
".popsection\n" \
|
||||
"671:"
|
||||
|
||||
#define LOCK_PREFIX LOCK_PREFIX_HERE "\n\tlock "
|
||||
|
||||
#else /* ! CONFIG_SMP */
|
||||
#define LOCK_PREFIX_HERE ""
|
||||
#define LOCK_PREFIX ""
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The patching flags are part of the upper bits of the @ft_flags parameter when
|
||||
* specifying them. The split is currently like this:
|
||||
*
|
||||
* [31... flags ...16][15... CPUID feature bit ...0]
|
||||
*
|
||||
* but since this is all hidden in the macros argument being split, those fields can be
|
||||
* extended in the future to fit in a u64 or however the need arises.
|
||||
*/
|
||||
struct alt_instr {
|
||||
s32 instr_offset; /* original instruction */
|
||||
s32 repl_offset; /* offset to replacement instruction */
|
||||
|
||||
union {
|
||||
struct {
|
||||
u32 cpuid: 16; /* CPUID bit set for replacement */
|
||||
u32 flags: 16; /* patching control flags */
|
||||
};
|
||||
u32 ft_flags;
|
||||
};
|
||||
|
||||
u8 instrlen; /* length of original instruction */
|
||||
u8 replacementlen; /* length of new instruction */
|
||||
} __packed;
|
||||
|
||||
extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
|
||||
|
||||
extern s32 __retpoline_sites[], __retpoline_sites_end[];
|
||||
extern s32 __return_sites[], __return_sites_end[];
|
||||
extern s32 __cfi_sites[], __cfi_sites_end[];
|
||||
extern s32 __ibt_endbr_seal[], __ibt_endbr_seal_end[];
|
||||
extern s32 __smp_locks[], __smp_locks_end[];
|
||||
|
||||
/*
|
||||
* Debug flag that can be tested to see whether alternative
|
||||
* instructions were patched in already:
|
||||
*/
|
||||
extern int alternatives_patched;
|
||||
|
||||
extern void alternative_instructions(void);
|
||||
extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
|
||||
extern void apply_retpolines(s32 *start, s32 *end);
|
||||
extern void apply_returns(s32 *start, s32 *end);
|
||||
extern void apply_seal_endbr(s32 *start, s32 *end);
|
||||
extern void apply_fineibt(s32 *start_retpoline, s32 *end_retpoine,
|
||||
s32 *start_cfi, s32 *end_cfi);
|
||||
|
||||
struct module;
|
||||
|
||||
struct callthunk_sites {
|
||||
s32 *call_start, *call_end;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_CALL_THUNKS
|
||||
extern void callthunks_patch_builtin_calls(void);
|
||||
extern void callthunks_patch_module_calls(struct callthunk_sites *sites,
|
||||
struct module *mod);
|
||||
extern void *callthunks_translate_call_dest(void *dest);
|
||||
extern int x86_call_depth_emit_accounting(u8 **pprog, void *func, void *ip);
|
||||
#else
|
||||
static __always_inline void callthunks_patch_builtin_calls(void) {}
|
||||
static __always_inline void
|
||||
callthunks_patch_module_calls(struct callthunk_sites *sites,
|
||||
struct module *mod) {}
|
||||
static __always_inline void *callthunks_translate_call_dest(void *dest)
|
||||
{
|
||||
return dest;
|
||||
}
|
||||
static __always_inline int x86_call_depth_emit_accounting(u8 **pprog,
|
||||
void *func, void *ip)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MITIGATION_ITS
|
||||
extern void its_init_mod(struct module *mod);
|
||||
extern void its_fini_mod(struct module *mod);
|
||||
extern void its_free_mod(struct module *mod);
|
||||
extern u8 *its_static_thunk(int reg);
|
||||
#else /* CONFIG_MITIGATION_ITS */
|
||||
static inline void its_init_mod(struct module *mod) { }
|
||||
static inline void its_fini_mod(struct module *mod) { }
|
||||
static inline void its_free_mod(struct module *mod) { }
|
||||
static inline u8 *its_static_thunk(int reg)
|
||||
{
|
||||
WARN_ONCE(1, "ITS not compiled in");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_MITIGATION_RETHUNK) && defined(CONFIG_OBJTOOL)
|
||||
extern bool cpu_wants_rethunk(void);
|
||||
extern bool cpu_wants_rethunk_at(void *addr);
|
||||
#else
|
||||
static __always_inline bool cpu_wants_rethunk(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
static __always_inline bool cpu_wants_rethunk_at(void *addr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
extern void alternatives_smp_module_add(struct module *mod, char *name,
|
||||
void *locks, void *locks_end,
|
||||
void *text, void *text_end);
|
||||
extern void alternatives_smp_module_del(struct module *mod);
|
||||
extern void alternatives_enable_smp(void);
|
||||
extern int alternatives_text_reserved(void *start, void *end);
|
||||
extern bool skip_smp_alternatives;
|
||||
#else
|
||||
static inline void alternatives_smp_module_add(struct module *mod, char *name,
|
||||
void *locks, void *locks_end,
|
||||
void *text, void *text_end) {}
|
||||
static inline void alternatives_smp_module_del(struct module *mod) {}
|
||||
static inline void alternatives_enable_smp(void) {}
|
||||
static inline int alternatives_text_reserved(void *start, void *end)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
#define ALT_CALL_INSTR "call BUG_func"
|
||||
|
||||
#define alt_slen "772b-771b"
|
||||
#define alt_total_slen "773b-771b"
|
||||
#define alt_rlen "775f-774f"
|
||||
|
||||
#define OLDINSTR(oldinstr) \
|
||||
"# ALT: oldinstr\n" \
|
||||
"771:\n\t" oldinstr "\n772:\n" \
|
||||
"# ALT: padding\n" \
|
||||
".skip -(((" alt_rlen ")-(" alt_slen ")) > 0) * " \
|
||||
"((" alt_rlen ")-(" alt_slen ")),0x90\n" \
|
||||
"773:\n"
|
||||
|
||||
#define ALTINSTR_ENTRY(ft_flags) \
|
||||
".pushsection .altinstructions, \"aM\", @progbits, " \
|
||||
__stringify(ALT_INSTR_SIZE) "\n" \
|
||||
" .long 771b - .\n" /* label */ \
|
||||
" .long 774f - .\n" /* new instruction */ \
|
||||
" .4byte " __stringify(ft_flags) "\n" /* feature + flags */ \
|
||||
" .byte " alt_total_slen "\n" /* source len */ \
|
||||
" .byte " alt_rlen "\n" /* replacement len */ \
|
||||
".popsection\n"
|
||||
|
||||
#define ALTINSTR_REPLACEMENT(newinstr) /* replacement */ \
|
||||
".pushsection .altinstr_replacement, \"ax\"\n" \
|
||||
ANNOTATE_DATA_SPECIAL "\n" \
|
||||
"# ALT: replacement\n" \
|
||||
"774:\n\t" newinstr "\n775:\n" \
|
||||
".popsection\n"
|
||||
|
||||
/* alternative assembly primitive: */
|
||||
#define ALTERNATIVE(oldinstr, newinstr, ft_flags) \
|
||||
OLDINSTR(oldinstr) \
|
||||
ALTINSTR_ENTRY(ft_flags) \
|
||||
ALTINSTR_REPLACEMENT(newinstr)
|
||||
|
||||
#define ALTERNATIVE_2(oldinstr, newinstr1, ft_flags1, newinstr2, ft_flags2) \
|
||||
ALTERNATIVE(ALTERNATIVE(oldinstr, newinstr1, ft_flags1), newinstr2, ft_flags2)
|
||||
|
||||
/* If @feature is set, patch in @newinstr_yes, otherwise @newinstr_no. */
|
||||
#define ALTERNATIVE_TERNARY(oldinstr, ft_flags, newinstr_yes, newinstr_no) \
|
||||
ALTERNATIVE_2(oldinstr, newinstr_no, X86_FEATURE_ALWAYS, newinstr_yes, ft_flags)
|
||||
|
||||
#define ALTERNATIVE_3(oldinstr, newinstr1, ft_flags1, newinstr2, ft_flags2, \
|
||||
newinstr3, ft_flags3) \
|
||||
ALTERNATIVE(ALTERNATIVE_2(oldinstr, newinstr1, ft_flags1, newinstr2, ft_flags2), \
|
||||
newinstr3, ft_flags3)
|
||||
|
||||
/*
|
||||
* Alternative instructions for different CPU types or capabilities.
|
||||
*
|
||||
* This allows to use optimized instructions even on generic binary
|
||||
* kernels.
|
||||
*
|
||||
* length of oldinstr must be longer or equal the length of newinstr
|
||||
* It can be padded with nops as needed.
|
||||
*
|
||||
* For non barrier like inlines please define new variants
|
||||
* without volatile and memory clobber.
|
||||
*/
|
||||
#define alternative(oldinstr, newinstr, ft_flags) \
|
||||
asm_inline volatile(ALTERNATIVE(oldinstr, newinstr, ft_flags) : : : "memory")
|
||||
|
||||
#define alternative_2(oldinstr, newinstr1, ft_flags1, newinstr2, ft_flags2) \
|
||||
asm_inline volatile(ALTERNATIVE_2(oldinstr, newinstr1, ft_flags1, newinstr2, ft_flags2) ::: "memory")
|
||||
|
||||
/*
|
||||
* Alternative inline assembly with input.
|
||||
*
|
||||
* Peculiarities:
|
||||
* No memory clobber here.
|
||||
* Argument numbers start with 1.
|
||||
* Leaving an unused argument 0 to keep API compatibility.
|
||||
*/
|
||||
#define alternative_input(oldinstr, newinstr, ft_flags, input...) \
|
||||
asm_inline volatile(ALTERNATIVE(oldinstr, newinstr, ft_flags) \
|
||||
: : "i" (0), ## input)
|
||||
|
||||
/* Like alternative_input, but with a single output argument */
|
||||
#define alternative_io(oldinstr, newinstr, ft_flags, output, input...) \
|
||||
asm_inline volatile(ALTERNATIVE(oldinstr, newinstr, ft_flags) \
|
||||
: output : "i" (0), ## input)
|
||||
|
||||
/*
|
||||
* Like alternative_io, but for replacing a direct call with another one.
|
||||
*
|
||||
* Use the %c operand modifier which is the generic way to print a bare
|
||||
* constant expression with all syntax-specific punctuation omitted. %P
|
||||
* is the x86-specific variant which can handle constants too, for
|
||||
* historical reasons, but it should be used primarily for PIC
|
||||
* references: i.e., if used for a function, it would add the PLT
|
||||
* suffix.
|
||||
*/
|
||||
#define alternative_call(oldfunc, newfunc, ft_flags, output, input, clobbers...) \
|
||||
asm_inline volatile(ALTERNATIVE("call %c[old]", "call %c[new]", ft_flags) \
|
||||
: ALT_OUTPUT_SP(output) \
|
||||
: [old] "i" (oldfunc), [new] "i" (newfunc) \
|
||||
COMMA(input) \
|
||||
: clobbers)
|
||||
|
||||
/*
|
||||
* Like alternative_call, but there are two features and respective functions.
|
||||
* If CPU has feature2, function2 is used.
|
||||
* Otherwise, if CPU has feature1, function1 is used.
|
||||
* Otherwise, old function is used.
|
||||
*/
|
||||
#define alternative_call_2(oldfunc, newfunc1, ft_flags1, newfunc2, ft_flags2, \
|
||||
output, input, clobbers...) \
|
||||
asm_inline volatile(ALTERNATIVE_2("call %c[old]", "call %c[new1]", ft_flags1, \
|
||||
"call %c[new2]", ft_flags2) \
|
||||
: ALT_OUTPUT_SP(output) \
|
||||
: [old] "i" (oldfunc), [new1] "i" (newfunc1), \
|
||||
[new2] "i" (newfunc2) \
|
||||
COMMA(input) \
|
||||
: clobbers)
|
||||
|
||||
#define ALT_OUTPUT_SP(...) ASM_CALL_CONSTRAINT, ## __VA_ARGS__
|
||||
|
||||
/* Macro for creating assembler functions avoiding any C magic. */
|
||||
#define DEFINE_ASM_FUNC(func, instr, sec) \
|
||||
asm (".pushsection " #sec ", \"ax\"\n" \
|
||||
".global " #func "\n\t" \
|
||||
".type " #func ", @function\n\t" \
|
||||
ASM_FUNC_ALIGN "\n" \
|
||||
#func ":\n\t" \
|
||||
ASM_ENDBR \
|
||||
instr "\n\t" \
|
||||
ASM_RET \
|
||||
".size " #func ", . - " #func "\n\t" \
|
||||
".popsection")
|
||||
|
||||
void BUG_func(void);
|
||||
void nop_func(void);
|
||||
|
||||
#else /* __ASSEMBLER__ */
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
.macro LOCK_PREFIX
|
||||
672: lock
|
||||
.pushsection .smp_locks,"a"
|
||||
.balign 4
|
||||
.long 672b - .
|
||||
.popsection
|
||||
.endm
|
||||
#else
|
||||
.macro LOCK_PREFIX
|
||||
.endm
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Issue one struct alt_instr descriptor entry (need to put it into
|
||||
* the section .altinstructions, see below). This entry contains
|
||||
* enough information for the alternatives patching code to patch an
|
||||
* instruction. See apply_alternatives().
|
||||
*/
|
||||
.macro altinstr_entry orig alt ft_flags orig_len alt_len
|
||||
.long \orig - .
|
||||
.long \alt - .
|
||||
.4byte \ft_flags
|
||||
.byte \orig_len
|
||||
.byte \alt_len
|
||||
.endm
|
||||
|
||||
.macro ALT_CALL_INSTR
|
||||
call BUG_func
|
||||
.endm
|
||||
|
||||
/*
|
||||
* Define an alternative between two instructions. If @feature is
|
||||
* present, early code in apply_alternatives() replaces @oldinstr with
|
||||
* @newinstr. ".skip" directive takes care of proper instruction padding
|
||||
* in case @newinstr is longer than @oldinstr.
|
||||
*/
|
||||
#define __ALTERNATIVE(oldinst, newinst, flag) \
|
||||
740: \
|
||||
oldinst ; \
|
||||
741: \
|
||||
.skip -(((744f-743f)-(741b-740b)) > 0) * ((744f-743f)-(741b-740b)),0x90 ;\
|
||||
742: \
|
||||
.pushsection .altinstructions, "aM", @progbits, ALT_INSTR_SIZE ;\
|
||||
altinstr_entry 740b,743f,flag,742b-740b,744f-743f ; \
|
||||
.popsection ; \
|
||||
.pushsection .altinstr_replacement,"ax" ; \
|
||||
743: \
|
||||
ANNOTATE_DATA_SPECIAL ; \
|
||||
newinst ; \
|
||||
744: \
|
||||
.popsection ;
|
||||
|
||||
.macro ALTERNATIVE oldinstr, newinstr, ft_flags
|
||||
__ALTERNATIVE(\oldinstr, \newinstr, \ft_flags)
|
||||
.endm
|
||||
|
||||
/*
|
||||
* Same as ALTERNATIVE macro above but for two alternatives. If CPU
|
||||
* has @feature1, it replaces @oldinstr with @newinstr1. If CPU has
|
||||
* @feature2, it replaces @oldinstr with @feature2.
|
||||
*/
|
||||
.macro ALTERNATIVE_2 oldinstr, newinstr1, ft_flags1, newinstr2, ft_flags2
|
||||
__ALTERNATIVE(__ALTERNATIVE(\oldinstr, \newinstr1, \ft_flags1),
|
||||
\newinstr2, \ft_flags2)
|
||||
.endm
|
||||
|
||||
.macro ALTERNATIVE_3 oldinstr, newinstr1, ft_flags1, newinstr2, ft_flags2, newinstr3, ft_flags3
|
||||
__ALTERNATIVE(ALTERNATIVE_2(\oldinstr, \newinstr1, \ft_flags1, \newinstr2, \ft_flags2),
|
||||
\newinstr3, \ft_flags3)
|
||||
.endm
|
||||
|
||||
/* If @feature is set, patch in @newinstr_yes, otherwise @newinstr_no. */
|
||||
#define ALTERNATIVE_TERNARY(oldinstr, ft_flags, newinstr_yes, newinstr_no) \
|
||||
ALTERNATIVE_2 oldinstr, newinstr_no, X86_FEATURE_ALWAYS, \
|
||||
newinstr_yes, ft_flags
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
|
||||
#endif /* _ASM_X86_ALTERNATIVE_H */
|
||||
@@ -0,0 +1,16 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
#ifndef _ASM_X86_AMD_HSMP_H_
|
||||
#define _ASM_X86_AMD_HSMP_H_
|
||||
|
||||
#include <uapi/asm/amd_hsmp.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_AMD_HSMP)
|
||||
int hsmp_send_message(struct hsmp_message *msg);
|
||||
#else
|
||||
static inline int hsmp_send_message(struct hsmp_message *msg)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*_ASM_X86_AMD_HSMP_H_*/
|
||||
@@ -0,0 +1,158 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_AMD_IBS_H
|
||||
#define _ASM_X86_AMD_IBS_H
|
||||
|
||||
/*
|
||||
* From PPR Vol 1 for AMD Family 19h Model 01h B1
|
||||
* 55898 Rev 0.35 - Feb 5, 2021
|
||||
*/
|
||||
|
||||
#include <asm/msr-index.h>
|
||||
|
||||
/* IBS_OP_DATA2 DataSrc */
|
||||
#define IBS_DATA_SRC_LOC_CACHE 2
|
||||
#define IBS_DATA_SRC_DRAM 3
|
||||
#define IBS_DATA_SRC_REM_CACHE 4
|
||||
#define IBS_DATA_SRC_IO 7
|
||||
|
||||
/* IBS_OP_DATA2 DataSrc Extension */
|
||||
#define IBS_DATA_SRC_EXT_LOC_CACHE 1
|
||||
#define IBS_DATA_SRC_EXT_NEAR_CCX_CACHE 2
|
||||
#define IBS_DATA_SRC_EXT_DRAM 3
|
||||
#define IBS_DATA_SRC_EXT_FAR_CCX_CACHE 5
|
||||
#define IBS_DATA_SRC_EXT_PMEM 6
|
||||
#define IBS_DATA_SRC_EXT_IO 7
|
||||
#define IBS_DATA_SRC_EXT_EXT_MEM 8
|
||||
#define IBS_DATA_SRC_EXT_PEER_AGENT_MEM 12
|
||||
|
||||
/*
|
||||
* IBS Hardware MSRs
|
||||
*/
|
||||
|
||||
/* MSR 0xc0011030: IBS Fetch Control */
|
||||
union ibs_fetch_ctl {
|
||||
__u64 val;
|
||||
struct {
|
||||
__u64 fetch_maxcnt:16,/* 0-15: instruction fetch max. count */
|
||||
fetch_cnt:16, /* 16-31: instruction fetch count */
|
||||
fetch_lat:16, /* 32-47: instruction fetch latency */
|
||||
fetch_en:1, /* 48: instruction fetch enable */
|
||||
fetch_val:1, /* 49: instruction fetch valid */
|
||||
fetch_comp:1, /* 50: instruction fetch complete */
|
||||
ic_miss:1, /* 51: i-cache miss */
|
||||
phy_addr_valid:1,/* 52: physical address valid */
|
||||
l1tlb_pgsz:2, /* 53-54: i-cache L1TLB page size
|
||||
* (needs IbsPhyAddrValid) */
|
||||
l1tlb_miss:1, /* 55: i-cache fetch missed in L1TLB */
|
||||
l2tlb_miss:1, /* 56: i-cache fetch missed in L2TLB */
|
||||
rand_en:1, /* 57: random tagging enable */
|
||||
fetch_l2_miss:1,/* 58: L2 miss for sampled fetch
|
||||
* (needs IbsFetchComp) */
|
||||
l3_miss_only:1, /* 59: Collect L3 miss samples only */
|
||||
fetch_oc_miss:1,/* 60: Op cache miss for the sampled fetch */
|
||||
fetch_l3_miss:1,/* 61: L3 cache miss for the sampled fetch */
|
||||
reserved:2; /* 62-63: reserved */
|
||||
};
|
||||
};
|
||||
|
||||
/* MSR 0xc0011033: IBS Execution Control */
|
||||
union ibs_op_ctl {
|
||||
__u64 val;
|
||||
struct {
|
||||
__u64 opmaxcnt:16, /* 0-15: periodic op max. count */
|
||||
l3_miss_only:1, /* 16: Collect L3 miss samples only */
|
||||
op_en:1, /* 17: op sampling enable */
|
||||
op_val:1, /* 18: op sample valid */
|
||||
cnt_ctl:1, /* 19: periodic op counter control */
|
||||
opmaxcnt_ext:7, /* 20-26: upper 7 bits of periodic op maximum count */
|
||||
reserved0:5, /* 27-31: reserved */
|
||||
opcurcnt:27, /* 32-58: periodic op counter current count */
|
||||
ldlat_thrsh:4, /* 59-62: Load Latency threshold */
|
||||
ldlat_en:1; /* 63: Load Latency enabled */
|
||||
};
|
||||
};
|
||||
|
||||
/* MSR 0xc0011035: IBS Op Data 1 */
|
||||
union ibs_op_data {
|
||||
__u64 val;
|
||||
struct {
|
||||
__u64 comp_to_ret_ctr:16, /* 0-15: op completion to retire count */
|
||||
tag_to_ret_ctr:16, /* 15-31: op tag to retire count */
|
||||
reserved1:2, /* 32-33: reserved */
|
||||
op_return:1, /* 34: return op */
|
||||
op_brn_taken:1, /* 35: taken branch op */
|
||||
op_brn_misp:1, /* 36: mispredicted branch op */
|
||||
op_brn_ret:1, /* 37: branch op retired */
|
||||
op_rip_invalid:1, /* 38: RIP is invalid */
|
||||
op_brn_fuse:1, /* 39: fused branch op */
|
||||
op_microcode:1, /* 40: microcode op */
|
||||
reserved2:23; /* 41-63: reserved */
|
||||
};
|
||||
};
|
||||
|
||||
/* MSR 0xc0011036: IBS Op Data 2 */
|
||||
union ibs_op_data2 {
|
||||
__u64 val;
|
||||
struct {
|
||||
__u64 data_src_lo:3, /* 0-2: data source low */
|
||||
reserved0:1, /* 3: reserved */
|
||||
rmt_node:1, /* 4: destination node */
|
||||
cache_hit_st:1, /* 5: cache hit state */
|
||||
data_src_hi:2, /* 6-7: data source high */
|
||||
reserved1:56; /* 8-63: reserved */
|
||||
};
|
||||
};
|
||||
|
||||
/* MSR 0xc0011037: IBS Op Data 3 */
|
||||
union ibs_op_data3 {
|
||||
__u64 val;
|
||||
struct {
|
||||
__u64 ld_op:1, /* 0: load op */
|
||||
st_op:1, /* 1: store op */
|
||||
dc_l1tlb_miss:1, /* 2: data cache L1TLB miss */
|
||||
dc_l2tlb_miss:1, /* 3: data cache L2TLB miss in 2M page */
|
||||
dc_l1tlb_hit_2m:1, /* 4: data cache L1TLB hit in 2M page */
|
||||
dc_l1tlb_hit_1g:1, /* 5: data cache L1TLB hit in 1G page */
|
||||
dc_l2tlb_hit_2m:1, /* 6: data cache L2TLB hit in 2M page */
|
||||
dc_miss:1, /* 7: data cache miss */
|
||||
dc_mis_acc:1, /* 8: misaligned access */
|
||||
reserved:4, /* 9-12: reserved */
|
||||
dc_wc_mem_acc:1, /* 13: write combining memory access */
|
||||
dc_uc_mem_acc:1, /* 14: uncacheable memory access */
|
||||
dc_locked_op:1, /* 15: locked operation */
|
||||
dc_miss_no_mab_alloc:1, /* 16: DC miss with no MAB allocated */
|
||||
dc_lin_addr_valid:1, /* 17: data cache linear address valid */
|
||||
dc_phy_addr_valid:1, /* 18: data cache physical address valid */
|
||||
dc_l2_tlb_hit_1g:1, /* 19: data cache L2 hit in 1GB page */
|
||||
l2_miss:1, /* 20: L2 cache miss */
|
||||
sw_pf:1, /* 21: software prefetch */
|
||||
op_mem_width:4, /* 22-25: load/store size in bytes */
|
||||
op_dc_miss_open_mem_reqs:6, /* 26-31: outstanding mem reqs on DC fill */
|
||||
dc_miss_lat:16, /* 32-47: data cache miss latency */
|
||||
tlb_refill_lat:16; /* 48-63: L1 TLB refill latency */
|
||||
};
|
||||
};
|
||||
|
||||
/* MSR 0xc001103c: IBS Fetch Control Extended */
|
||||
union ic_ibs_extd_ctl {
|
||||
__u64 val;
|
||||
struct {
|
||||
__u64 itlb_refill_lat:16, /* 0-15: ITLB Refill latency for sampled fetch */
|
||||
reserved:48; /* 16-63: reserved */
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* IBS driver related
|
||||
*/
|
||||
|
||||
struct perf_ibs_data {
|
||||
u32 size;
|
||||
union {
|
||||
u32 data[0]; /* data buffer starts here */
|
||||
u32 caps;
|
||||
};
|
||||
u64 regs[MSR_AMD64_IBS_REG_COUNT_MAX];
|
||||
};
|
||||
|
||||
#endif /* _ASM_X86_AMD_IBS_H */
|
||||
@@ -0,0 +1,77 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_AMD_NB_H
|
||||
#define _ASM_X86_AMD_NB_H
|
||||
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/pci.h>
|
||||
#include <asm/amd/node.h>
|
||||
|
||||
struct amd_nb_bus_dev_range {
|
||||
u8 bus;
|
||||
u8 dev_base;
|
||||
u8 dev_limit;
|
||||
};
|
||||
|
||||
extern const struct amd_nb_bus_dev_range amd_nb_bus_dev_ranges[];
|
||||
|
||||
extern bool early_is_amd_nb(u32 value);
|
||||
extern struct resource *amd_get_mmconfig_range(struct resource *res);
|
||||
extern void amd_flush_garts(void);
|
||||
extern int amd_numa_init(void);
|
||||
extern int amd_get_subcaches(int);
|
||||
extern int amd_set_subcaches(int, unsigned long);
|
||||
|
||||
struct amd_l3_cache {
|
||||
unsigned indices;
|
||||
u8 subcaches[4];
|
||||
};
|
||||
|
||||
struct amd_northbridge {
|
||||
struct pci_dev *misc;
|
||||
struct pci_dev *link;
|
||||
struct amd_l3_cache l3_cache;
|
||||
};
|
||||
|
||||
struct amd_northbridge_info {
|
||||
u16 num;
|
||||
u64 flags;
|
||||
struct amd_northbridge *nb;
|
||||
};
|
||||
|
||||
#define AMD_NB_GART BIT(0)
|
||||
#define AMD_NB_L3_INDEX_DISABLE BIT(1)
|
||||
#define AMD_NB_L3_PARTITIONING BIT(2)
|
||||
|
||||
#ifdef CONFIG_AMD_NB
|
||||
|
||||
u16 amd_nb_num(void);
|
||||
bool amd_nb_has_feature(unsigned int feature);
|
||||
struct amd_northbridge *node_to_amd_nb(int node);
|
||||
|
||||
static inline bool amd_gart_present(void)
|
||||
{
|
||||
if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
|
||||
return false;
|
||||
|
||||
/* GART present only on Fam15h, up to model 0fh */
|
||||
if (boot_cpu_data.x86 == 0xf || boot_cpu_data.x86 == 0x10 ||
|
||||
(boot_cpu_data.x86 == 0x15 && boot_cpu_data.x86_model < 0x10))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define amd_nb_num(x) 0
|
||||
#define amd_nb_has_feature(x) false
|
||||
static inline struct amd_northbridge *node_to_amd_nb(int node)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#define amd_gart_present(x) false
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _ASM_X86_AMD_NB_H */
|
||||
@@ -0,0 +1,59 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* AMD Node helper functions and common defines
|
||||
*
|
||||
* Copyright (c) 2024, Advanced Micro Devices, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Author: Yazen Ghannam <Yazen.Ghannam@amd.com>
|
||||
*
|
||||
* Note:
|
||||
* Items in this file may only be used in a single place.
|
||||
* However, it's prudent to keep all AMD Node functionality
|
||||
* in a unified place rather than spreading throughout the
|
||||
* kernel.
|
||||
*/
|
||||
|
||||
#ifndef _ASM_X86_AMD_NODE_H_
|
||||
#define _ASM_X86_AMD_NODE_H_
|
||||
|
||||
#include <linux/pci.h>
|
||||
|
||||
#define MAX_AMD_NUM_NODES 8
|
||||
#define AMD_NODE0_PCI_SLOT 0x18
|
||||
|
||||
struct pci_dev *amd_node_get_func(u16 node, u8 func);
|
||||
|
||||
static inline u16 amd_num_nodes(void)
|
||||
{
|
||||
return topology_amd_nodes_per_pkg() * topology_max_packages();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_AMD_NODE
|
||||
int __must_check amd_smn_read(u16 node, u32 address, u32 *value);
|
||||
int __must_check amd_smn_write(u16 node, u32 address, u32 value);
|
||||
|
||||
/* Should only be used by the HSMP driver. */
|
||||
int __must_check amd_smn_hsmp_rdwr(u16 node, u32 address, u32 *value, bool write);
|
||||
#else
|
||||
static inline int __must_check amd_smn_read(u16 node, u32 address, u32 *value) { return -ENODEV; }
|
||||
static inline int __must_check amd_smn_write(u16 node, u32 address, u32 value) { return -ENODEV; }
|
||||
|
||||
static inline int __must_check amd_smn_hsmp_rdwr(u16 node, u32 address, u32 *value, bool write)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif /* CONFIG_AMD_NODE */
|
||||
|
||||
/* helper for use with read_poll_timeout */
|
||||
static inline int smn_read_register(u32 reg)
|
||||
{
|
||||
int data, rc;
|
||||
|
||||
rc = amd_smn_read(0, reg, &data);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return data;
|
||||
}
|
||||
#endif /*_ASM_X86_AMD_NODE_H_*/
|
||||
@@ -0,0 +1,627 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
#ifndef _ASM_X86_APIC_H
|
||||
#define _ASM_X86_APIC_H
|
||||
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/static_call.h>
|
||||
|
||||
#include <asm/alternative.h>
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/apicdef.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <asm/fixmap.h>
|
||||
#include <asm/mpspec.h>
|
||||
#include <asm/msr.h>
|
||||
#include <asm/hardirq.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/posted_intr.h>
|
||||
|
||||
#define ARCH_APICTIMER_STOPS_ON_C3 1
|
||||
|
||||
/* Macros for apic_extnmi which controls external NMI masking */
|
||||
#define APIC_EXTNMI_BSP 0 /* Default */
|
||||
#define APIC_EXTNMI_ALL 1
|
||||
#define APIC_EXTNMI_NONE 2
|
||||
|
||||
/*
|
||||
* Debugging macros
|
||||
*/
|
||||
#define APIC_QUIET 0
|
||||
#define APIC_VERBOSE 1
|
||||
#define APIC_DEBUG 2
|
||||
|
||||
/*
|
||||
* Define the default level of output to be very little This can be turned
|
||||
* up by using apic=verbose for more information and apic=debug for _lots_
|
||||
* of information. apic_verbosity is defined in apic.c
|
||||
*/
|
||||
#define apic_printk(v, s, a...) \
|
||||
do { \
|
||||
if ((v) <= apic_verbosity) \
|
||||
printk(s, ##a); \
|
||||
} while (0)
|
||||
|
||||
#define apic_pr_verbose(s, a...) apic_printk(APIC_VERBOSE, KERN_INFO s, ##a)
|
||||
#define apic_pr_debug(s, a...) apic_printk(APIC_DEBUG, KERN_DEBUG s, ##a)
|
||||
#define apic_pr_debug_cont(s, a...) apic_printk(APIC_DEBUG, KERN_CONT s, ##a)
|
||||
/* Unconditional debug prints for code which is guarded by apic_verbosity already */
|
||||
#define apic_dbg(s, a...) printk(KERN_DEBUG s, ##a)
|
||||
|
||||
#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_32)
|
||||
extern void x86_32_probe_apic(void);
|
||||
#else
|
||||
static inline void x86_32_probe_apic(void) { }
|
||||
#endif
|
||||
|
||||
extern u32 cpuid_to_apicid[];
|
||||
|
||||
#define CPU_ACPIID_INVALID U32_MAX
|
||||
|
||||
#ifdef CONFIG_X86_LOCAL_APIC
|
||||
|
||||
extern int apic_verbosity;
|
||||
extern int local_apic_timer_c2_ok;
|
||||
|
||||
extern bool apic_is_disabled;
|
||||
extern unsigned int lapic_timer_period;
|
||||
|
||||
extern enum apic_intr_mode_id apic_intr_mode;
|
||||
enum apic_intr_mode_id {
|
||||
APIC_PIC,
|
||||
APIC_VIRTUAL_WIRE,
|
||||
APIC_VIRTUAL_WIRE_NO_CONFIG,
|
||||
APIC_SYMMETRIC_IO,
|
||||
APIC_SYMMETRIC_IO_NO_ROUTING
|
||||
};
|
||||
|
||||
/*
|
||||
* With 82489DX we can't rely on apic feature bit
|
||||
* retrieved via cpuid but still have to deal with
|
||||
* such an apic chip so we assume that SMP configuration
|
||||
* is found from MP table (64bit case uses ACPI mostly
|
||||
* which set smp presence flag as well so we are safe
|
||||
* to use this helper too).
|
||||
*/
|
||||
static inline bool apic_from_smp_config(void)
|
||||
{
|
||||
return smp_found_config && !apic_is_disabled;
|
||||
}
|
||||
|
||||
/*
|
||||
* Basic functions accessing APICs.
|
||||
*/
|
||||
static inline void native_apic_mem_write(u32 reg, u32 v)
|
||||
{
|
||||
volatile u32 *addr = (volatile u32 *)(APIC_BASE + reg);
|
||||
|
||||
alternative_io("movl %0, %1", "xchgl %0, %1", X86_BUG_11AP,
|
||||
ASM_OUTPUT("=r" (v), "=m" (*addr)),
|
||||
ASM_INPUT("0" (v), "m" (*addr)));
|
||||
}
|
||||
|
||||
static inline u32 native_apic_mem_read(u32 reg)
|
||||
{
|
||||
return readl((void __iomem *)(APIC_BASE + reg));
|
||||
}
|
||||
|
||||
static inline void native_apic_mem_eoi(void)
|
||||
{
|
||||
native_apic_mem_write(APIC_EOI, APIC_EOI_ACK);
|
||||
}
|
||||
|
||||
extern void native_apic_icr_write(u32 low, u32 id);
|
||||
extern u64 native_apic_icr_read(void);
|
||||
|
||||
static inline bool apic_is_x2apic_enabled(void)
|
||||
{
|
||||
u64 msr;
|
||||
|
||||
if (rdmsrq_safe(MSR_IA32_APICBASE, &msr))
|
||||
return false;
|
||||
return msr & X2APIC_ENABLE;
|
||||
}
|
||||
|
||||
extern void enable_IR_x2apic(void);
|
||||
|
||||
extern int lapic_get_maxlvt(void);
|
||||
extern void clear_local_APIC(void);
|
||||
extern void disconnect_bsp_APIC(int virt_wire_setup);
|
||||
extern void disable_local_APIC(void);
|
||||
extern void apic_soft_disable(void);
|
||||
extern void lapic_shutdown(void);
|
||||
extern void sync_Arb_IDs(void);
|
||||
extern void init_bsp_APIC(void);
|
||||
extern void apic_intr_mode_select(void);
|
||||
extern void apic_intr_mode_init(void);
|
||||
extern void init_apic_mappings(void);
|
||||
void register_lapic_address(unsigned long address);
|
||||
extern void setup_boot_APIC_clock(void);
|
||||
extern void setup_secondary_APIC_clock(void);
|
||||
extern void lapic_update_tsc_freq(void);
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
static inline bool apic_force_enable(unsigned long addr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
extern bool apic_force_enable(unsigned long addr);
|
||||
#endif
|
||||
|
||||
extern void apic_ap_setup(void);
|
||||
|
||||
/*
|
||||
* On 32bit this is mach-xxx local
|
||||
*/
|
||||
#ifdef CONFIG_X86_64
|
||||
extern int apic_is_clustered_box(void);
|
||||
#else
|
||||
static inline int apic_is_clustered_box(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern int setup_APIC_eilvt(u8 lvt_off, u8 vector, u8 msg_type, u8 mask);
|
||||
extern void lapic_assign_system_vectors(void);
|
||||
extern void lapic_assign_legacy_vector(unsigned int isairq, bool replace);
|
||||
extern void lapic_update_legacy_vectors(void);
|
||||
extern void lapic_online(void);
|
||||
extern void lapic_offline(void);
|
||||
extern bool apic_needs_pit(void);
|
||||
|
||||
extern void apic_send_IPI_allbutself(unsigned int vector);
|
||||
|
||||
extern void topology_register_apic(u32 apic_id, u32 acpi_id, bool present);
|
||||
extern void topology_register_boot_apic(u32 apic_id);
|
||||
extern int topology_hotplug_apic(u32 apic_id, u32 acpi_id);
|
||||
extern void topology_hotunplug_apic(unsigned int cpu);
|
||||
extern void topology_apply_cmdline_limits_early(void);
|
||||
extern void topology_init_possible_cpus(void);
|
||||
extern void topology_reset_possible_cpus_up(void);
|
||||
|
||||
#else /* !CONFIG_X86_LOCAL_APIC */
|
||||
static inline void lapic_shutdown(void) { }
|
||||
#define local_apic_timer_c2_ok 1
|
||||
static inline void init_apic_mappings(void) { }
|
||||
static inline void disable_local_APIC(void) { }
|
||||
# define setup_boot_APIC_clock x86_init_noop
|
||||
# define setup_secondary_APIC_clock x86_init_noop
|
||||
static inline void lapic_update_tsc_freq(void) { }
|
||||
static inline void init_bsp_APIC(void) { }
|
||||
static inline void apic_intr_mode_select(void) { }
|
||||
static inline void apic_intr_mode_init(void) { }
|
||||
static inline void lapic_assign_system_vectors(void) { }
|
||||
static inline void lapic_assign_legacy_vector(unsigned int i, bool r) { }
|
||||
static inline bool apic_needs_pit(void) { return true; }
|
||||
static inline void topology_apply_cmdline_limits_early(void) { }
|
||||
static inline void topology_init_possible_cpus(void) { }
|
||||
#endif /* !CONFIG_X86_LOCAL_APIC */
|
||||
|
||||
#ifdef CONFIG_X86_X2APIC
|
||||
static inline void native_apic_msr_write(u32 reg, u32 v)
|
||||
{
|
||||
if (reg == APIC_DFR || reg == APIC_ID || reg == APIC_LDR ||
|
||||
reg == APIC_LVR)
|
||||
return;
|
||||
|
||||
wrmsrq(APIC_BASE_MSR + (reg >> 4), v);
|
||||
}
|
||||
|
||||
static inline void native_apic_msr_eoi(void)
|
||||
{
|
||||
native_wrmsrq(APIC_BASE_MSR + (APIC_EOI >> 4), APIC_EOI_ACK);
|
||||
}
|
||||
|
||||
static inline u32 native_apic_msr_read(u32 reg)
|
||||
{
|
||||
u64 msr;
|
||||
|
||||
if (reg == APIC_DFR)
|
||||
return -1;
|
||||
|
||||
rdmsrq(APIC_BASE_MSR + (reg >> 4), msr);
|
||||
return (u32)msr;
|
||||
}
|
||||
|
||||
static inline void native_x2apic_icr_write(u32 low, u32 id)
|
||||
{
|
||||
wrmsrq(APIC_BASE_MSR + (APIC_ICR >> 4), ((__u64) id) << 32 | low);
|
||||
}
|
||||
|
||||
static inline u64 native_x2apic_icr_read(void)
|
||||
{
|
||||
unsigned long val;
|
||||
|
||||
rdmsrq(APIC_BASE_MSR + (APIC_ICR >> 4), val);
|
||||
return val;
|
||||
}
|
||||
|
||||
extern int x2apic_mode;
|
||||
extern int x2apic_phys;
|
||||
extern void __init x2apic_set_max_apicid(u32 apicid);
|
||||
extern void x2apic_setup(void);
|
||||
static inline int x2apic_enabled(void)
|
||||
{
|
||||
return boot_cpu_has(X86_FEATURE_X2APIC) && apic_is_x2apic_enabled();
|
||||
}
|
||||
|
||||
#define x2apic_supported() (boot_cpu_has(X86_FEATURE_X2APIC))
|
||||
#else /* !CONFIG_X86_X2APIC */
|
||||
static inline void x2apic_setup(void) { }
|
||||
static inline int x2apic_enabled(void) { return 0; }
|
||||
static inline u32 native_apic_msr_read(u32 reg) { BUG(); }
|
||||
#define x2apic_mode (0)
|
||||
#define x2apic_supported() (0)
|
||||
#endif /* !CONFIG_X86_X2APIC */
|
||||
extern void __init check_x2apic(void);
|
||||
|
||||
struct irq_data;
|
||||
|
||||
/*
|
||||
* Copyright 2004 James Cleverdon, IBM.
|
||||
*
|
||||
* Generic APIC sub-arch data struct.
|
||||
*
|
||||
* Hacked for x86-64 by James Cleverdon from i386 architecture code by
|
||||
* Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
|
||||
* James Cleverdon.
|
||||
*/
|
||||
struct apic {
|
||||
/* Hotpath functions first */
|
||||
void (*eoi)(void);
|
||||
void (*native_eoi)(void);
|
||||
void (*write)(u32 reg, u32 v);
|
||||
u32 (*read)(u32 reg);
|
||||
|
||||
/* IPI related functions */
|
||||
void (*wait_icr_idle)(void);
|
||||
u32 (*safe_wait_icr_idle)(void);
|
||||
|
||||
void (*send_IPI)(int cpu, int vector);
|
||||
void (*send_IPI_mask)(const struct cpumask *mask, int vector);
|
||||
void (*send_IPI_mask_allbutself)(const struct cpumask *msk, int vec);
|
||||
void (*send_IPI_allbutself)(int vector);
|
||||
void (*send_IPI_all)(int vector);
|
||||
void (*send_IPI_self)(int vector);
|
||||
|
||||
u32 disable_esr : 1,
|
||||
dest_mode_logical : 1,
|
||||
x2apic_set_max_apicid : 1,
|
||||
nmi_to_offline_cpu : 1;
|
||||
|
||||
u32 (*calc_dest_apicid)(unsigned int cpu);
|
||||
|
||||
/* ICR related functions */
|
||||
u64 (*icr_read)(void);
|
||||
void (*icr_write)(u32 low, u32 high);
|
||||
|
||||
/* The limit of the APIC ID space. */
|
||||
u32 max_apic_id;
|
||||
|
||||
/* Probe, setup and smpboot functions */
|
||||
int (*probe)(void);
|
||||
void (*setup)(void);
|
||||
void (*teardown)(void);
|
||||
int (*acpi_madt_oem_check)(char *oem_id, char *oem_table_id);
|
||||
|
||||
void (*init_apic_ldr)(void);
|
||||
u32 (*cpu_present_to_apicid)(int mps_cpu);
|
||||
|
||||
u32 (*get_apic_id)(u32 id);
|
||||
|
||||
/* wakeup_secondary_cpu */
|
||||
int (*wakeup_secondary_cpu)(u32 apicid, unsigned long start_eip, unsigned int cpu);
|
||||
/* wakeup secondary CPU using 64-bit wakeup point */
|
||||
int (*wakeup_secondary_cpu_64)(u32 apicid, unsigned long start_eip, unsigned int cpu);
|
||||
|
||||
void (*update_vector)(unsigned int cpu, unsigned int vector, bool set);
|
||||
|
||||
char *name;
|
||||
};
|
||||
|
||||
struct apic_override {
|
||||
void (*eoi)(void);
|
||||
void (*native_eoi)(void);
|
||||
void (*write)(u32 reg, u32 v);
|
||||
u32 (*read)(u32 reg);
|
||||
void (*send_IPI)(int cpu, int vector);
|
||||
void (*send_IPI_mask)(const struct cpumask *mask, int vector);
|
||||
void (*send_IPI_mask_allbutself)(const struct cpumask *msk, int vec);
|
||||
void (*send_IPI_allbutself)(int vector);
|
||||
void (*send_IPI_all)(int vector);
|
||||
void (*send_IPI_self)(int vector);
|
||||
u64 (*icr_read)(void);
|
||||
void (*icr_write)(u32 low, u32 high);
|
||||
int (*wakeup_secondary_cpu)(u32 apicid, unsigned long start_eip, unsigned int cpu);
|
||||
int (*wakeup_secondary_cpu_64)(u32 apicid, unsigned long start_eip, unsigned int cpu);
|
||||
};
|
||||
|
||||
/*
|
||||
* Pointer to the local APIC driver in use on this system (there's
|
||||
* always just one such driver in use - the kernel decides via an
|
||||
* early probing process which one it picks - and then sticks to it):
|
||||
*/
|
||||
extern struct apic *apic;
|
||||
|
||||
/*
|
||||
* APIC drivers are probed based on how they are listed in the .apicdrivers
|
||||
* section. So the order is important and enforced by the ordering
|
||||
* of different apic driver files in the Makefile.
|
||||
*/
|
||||
#define apic_driver(sym) \
|
||||
static const struct apic *__apicdrivers_##sym __used \
|
||||
__aligned(sizeof(struct apic *)) \
|
||||
__section(".apicdrivers") = { &sym }
|
||||
|
||||
extern struct apic *__apicdrivers[], *__apicdrivers_end[];
|
||||
|
||||
/*
|
||||
* APIC functionality to boot other CPUs - only used on SMP:
|
||||
*/
|
||||
#ifdef CONFIG_SMP
|
||||
extern int lapic_can_unplug_cpu(void);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86_LOCAL_APIC
|
||||
extern struct apic_override __x86_apic_override;
|
||||
|
||||
void __init apic_setup_apic_calls(void);
|
||||
void __init apic_install_driver(struct apic *driver);
|
||||
|
||||
#define apic_update_callback(_callback, _fn) { \
|
||||
__x86_apic_override._callback = _fn; \
|
||||
apic->_callback = _fn; \
|
||||
static_call_update(apic_call_##_callback, _fn); \
|
||||
pr_info("APIC: %s() replaced with %ps()\n", #_callback, _fn); \
|
||||
}
|
||||
|
||||
#define DECLARE_APIC_CALL(__cb) \
|
||||
DECLARE_STATIC_CALL(apic_call_##__cb, *apic->__cb)
|
||||
|
||||
DECLARE_APIC_CALL(eoi);
|
||||
DECLARE_APIC_CALL(native_eoi);
|
||||
DECLARE_APIC_CALL(icr_read);
|
||||
DECLARE_APIC_CALL(icr_write);
|
||||
DECLARE_APIC_CALL(read);
|
||||
DECLARE_APIC_CALL(send_IPI);
|
||||
DECLARE_APIC_CALL(send_IPI_mask);
|
||||
DECLARE_APIC_CALL(send_IPI_mask_allbutself);
|
||||
DECLARE_APIC_CALL(send_IPI_allbutself);
|
||||
DECLARE_APIC_CALL(send_IPI_all);
|
||||
DECLARE_APIC_CALL(send_IPI_self);
|
||||
DECLARE_APIC_CALL(wait_icr_idle);
|
||||
DECLARE_APIC_CALL(wakeup_secondary_cpu);
|
||||
DECLARE_APIC_CALL(wakeup_secondary_cpu_64);
|
||||
DECLARE_APIC_CALL(write);
|
||||
|
||||
static __always_inline u32 apic_read(u32 reg)
|
||||
{
|
||||
return static_call(apic_call_read)(reg);
|
||||
}
|
||||
|
||||
static __always_inline void apic_write(u32 reg, u32 val)
|
||||
{
|
||||
static_call(apic_call_write)(reg, val);
|
||||
}
|
||||
|
||||
static __always_inline void apic_eoi(void)
|
||||
{
|
||||
static_call(apic_call_eoi)();
|
||||
}
|
||||
|
||||
static __always_inline void apic_native_eoi(void)
|
||||
{
|
||||
static_call(apic_call_native_eoi)();
|
||||
}
|
||||
|
||||
static __always_inline u64 apic_icr_read(void)
|
||||
{
|
||||
return static_call(apic_call_icr_read)();
|
||||
}
|
||||
|
||||
static __always_inline void apic_icr_write(u32 low, u32 high)
|
||||
{
|
||||
static_call(apic_call_icr_write)(low, high);
|
||||
}
|
||||
|
||||
static __always_inline void __apic_send_IPI(int cpu, int vector)
|
||||
{
|
||||
static_call(apic_call_send_IPI)(cpu, vector);
|
||||
}
|
||||
|
||||
static __always_inline void __apic_send_IPI_mask(const struct cpumask *mask, int vector)
|
||||
{
|
||||
static_call_mod(apic_call_send_IPI_mask)(mask, vector);
|
||||
}
|
||||
|
||||
static __always_inline void __apic_send_IPI_mask_allbutself(const struct cpumask *mask, int vector)
|
||||
{
|
||||
static_call(apic_call_send_IPI_mask_allbutself)(mask, vector);
|
||||
}
|
||||
|
||||
static __always_inline void __apic_send_IPI_allbutself(int vector)
|
||||
{
|
||||
static_call(apic_call_send_IPI_allbutself)(vector);
|
||||
}
|
||||
|
||||
static __always_inline void __apic_send_IPI_all(int vector)
|
||||
{
|
||||
static_call(apic_call_send_IPI_all)(vector);
|
||||
}
|
||||
|
||||
static __always_inline void __apic_send_IPI_self(int vector)
|
||||
{
|
||||
static_call_mod(apic_call_send_IPI_self)(vector);
|
||||
}
|
||||
|
||||
static __always_inline void apic_wait_icr_idle(void)
|
||||
{
|
||||
static_call_cond(apic_call_wait_icr_idle)();
|
||||
}
|
||||
|
||||
static __always_inline u32 safe_apic_wait_icr_idle(void)
|
||||
{
|
||||
return apic->safe_wait_icr_idle ? apic->safe_wait_icr_idle() : 0;
|
||||
}
|
||||
|
||||
static __always_inline bool apic_id_valid(u32 apic_id)
|
||||
{
|
||||
return apic_id <= apic->max_apic_id;
|
||||
}
|
||||
|
||||
static __always_inline void apic_update_vector(unsigned int cpu, unsigned int vector, bool set)
|
||||
{
|
||||
if (apic->update_vector)
|
||||
apic->update_vector(cpu, vector, set);
|
||||
}
|
||||
|
||||
#else /* CONFIG_X86_LOCAL_APIC */
|
||||
|
||||
static inline u32 apic_read(u32 reg) { return 0; }
|
||||
static inline void apic_write(u32 reg, u32 val) { }
|
||||
static inline void apic_eoi(void) { }
|
||||
static inline u64 apic_icr_read(void) { return 0; }
|
||||
static inline void apic_icr_write(u32 low, u32 high) { }
|
||||
static inline void apic_wait_icr_idle(void) { }
|
||||
static inline u32 safe_apic_wait_icr_idle(void) { return 0; }
|
||||
static inline void apic_native_eoi(void) { WARN_ON_ONCE(1); }
|
||||
static inline void apic_setup_apic_calls(void) { }
|
||||
static inline void apic_update_vector(unsigned int cpu, unsigned int vector, bool set) { }
|
||||
|
||||
#define apic_update_callback(_callback, _fn) do { } while (0)
|
||||
|
||||
#endif /* CONFIG_X86_LOCAL_APIC */
|
||||
|
||||
extern void apic_ack_irq(struct irq_data *data);
|
||||
|
||||
#define APIC_VECTOR_TO_BIT_NUMBER(v) ((unsigned int)(v) % 32)
|
||||
#define APIC_VECTOR_TO_REG_OFFSET(v) ((unsigned int)(v) / 32 * 0x10)
|
||||
|
||||
static inline bool lapic_vector_set_in_irr(unsigned int vector)
|
||||
{
|
||||
u32 irr = apic_read(APIC_IRR + APIC_VECTOR_TO_REG_OFFSET(vector));
|
||||
|
||||
return !!(irr & (1U << APIC_VECTOR_TO_BIT_NUMBER(vector)));
|
||||
}
|
||||
|
||||
static inline bool is_vector_pending(unsigned int vector)
|
||||
{
|
||||
return lapic_vector_set_in_irr(vector) || pi_pending_this_cpu(vector);
|
||||
}
|
||||
|
||||
#define MAX_APIC_VECTOR 256
|
||||
#define APIC_VECTORS_PER_REG 32
|
||||
|
||||
/*
|
||||
* Vector states are maintained by APIC in 32-bit registers that are
|
||||
* 16 bytes aligned. The status of each vector is kept in a single
|
||||
* bit.
|
||||
*/
|
||||
static inline int apic_find_highest_vector(void *bitmap)
|
||||
{
|
||||
int vec;
|
||||
u32 *reg;
|
||||
|
||||
for (vec = MAX_APIC_VECTOR - APIC_VECTORS_PER_REG; vec >= 0; vec -= APIC_VECTORS_PER_REG) {
|
||||
reg = bitmap + APIC_VECTOR_TO_REG_OFFSET(vec);
|
||||
if (*reg)
|
||||
return __fls(*reg) + vec;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline u32 apic_get_reg(void *regs, int reg)
|
||||
{
|
||||
return *((u32 *) (regs + reg));
|
||||
}
|
||||
|
||||
static inline void apic_set_reg(void *regs, int reg, u32 val)
|
||||
{
|
||||
*((u32 *) (regs + reg)) = val;
|
||||
}
|
||||
|
||||
static __always_inline u64 apic_get_reg64(void *regs, int reg)
|
||||
{
|
||||
BUILD_BUG_ON(reg != APIC_ICR);
|
||||
return *((u64 *) (regs + reg));
|
||||
}
|
||||
|
||||
static __always_inline void apic_set_reg64(void *regs, int reg, u64 val)
|
||||
{
|
||||
BUILD_BUG_ON(reg != APIC_ICR);
|
||||
*((u64 *) (regs + reg)) = val;
|
||||
}
|
||||
|
||||
static inline void apic_clear_vector(int vec, void *bitmap)
|
||||
{
|
||||
clear_bit(APIC_VECTOR_TO_BIT_NUMBER(vec), bitmap + APIC_VECTOR_TO_REG_OFFSET(vec));
|
||||
}
|
||||
|
||||
static inline void apic_set_vector(int vec, void *bitmap)
|
||||
{
|
||||
set_bit(APIC_VECTOR_TO_BIT_NUMBER(vec), bitmap + APIC_VECTOR_TO_REG_OFFSET(vec));
|
||||
}
|
||||
|
||||
static inline int apic_test_vector(int vec, void *bitmap)
|
||||
{
|
||||
return test_bit(APIC_VECTOR_TO_BIT_NUMBER(vec), bitmap + APIC_VECTOR_TO_REG_OFFSET(vec));
|
||||
}
|
||||
|
||||
/*
|
||||
* Warm reset vector position:
|
||||
*/
|
||||
#define TRAMPOLINE_PHYS_LOW 0x467
|
||||
#define TRAMPOLINE_PHYS_HIGH 0x469
|
||||
|
||||
#ifdef CONFIG_X86_LOCAL_APIC
|
||||
|
||||
#include <asm/smp.h>
|
||||
|
||||
extern struct apic apic_noop;
|
||||
|
||||
static inline u32 read_apic_id(void)
|
||||
{
|
||||
u32 reg = apic_read(APIC_ID);
|
||||
|
||||
return apic->get_apic_id(reg);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
typedef int (*wakeup_cpu_handler)(int apicid, unsigned long start_eip);
|
||||
extern int default_acpi_madt_oem_check(char *, char *);
|
||||
extern void x86_64_probe_apic(void);
|
||||
#else
|
||||
static inline int default_acpi_madt_oem_check(char *a, char *b) { return 0; }
|
||||
static inline void x86_64_probe_apic(void) { }
|
||||
#endif
|
||||
|
||||
extern u32 apic_default_calc_apicid(unsigned int cpu);
|
||||
extern u32 apic_flat_calc_apicid(unsigned int cpu);
|
||||
|
||||
extern u32 default_cpu_present_to_apicid(int mps_cpu);
|
||||
|
||||
void apic_send_nmi_to_offline_cpu(unsigned int cpu);
|
||||
|
||||
#else /* CONFIG_X86_LOCAL_APIC */
|
||||
|
||||
static inline u32 read_apic_id(void) { return 0; }
|
||||
|
||||
#endif /* !CONFIG_X86_LOCAL_APIC */
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
void apic_smt_update(void);
|
||||
#else
|
||||
static inline void apic_smt_update(void) { }
|
||||
#endif
|
||||
|
||||
struct msi_msg;
|
||||
struct irq_cfg;
|
||||
|
||||
extern void __irq_msi_compose_msg(struct irq_cfg *cfg, struct msi_msg *msg,
|
||||
bool dmar);
|
||||
|
||||
extern void ioapic_zap_locks(void);
|
||||
|
||||
#endif /* _ASM_X86_APIC_H */
|
||||
@@ -0,0 +1,183 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_APICDEF_H
|
||||
#define _ASM_X86_APICDEF_H
|
||||
|
||||
#include <linux/bits.h>
|
||||
|
||||
/*
|
||||
* Constants for various Intel APICs. (local APIC, IOAPIC, etc.)
|
||||
*
|
||||
* Alan Cox <Alan.Cox@linux.org>, 1995.
|
||||
* Ingo Molnar <mingo@redhat.com>, 1999, 2000
|
||||
*/
|
||||
|
||||
#define IO_APIC_DEFAULT_PHYS_BASE 0xfec00000
|
||||
#define APIC_DEFAULT_PHYS_BASE 0xfee00000
|
||||
|
||||
/*
|
||||
* This is the IO-APIC register space as specified
|
||||
* by Intel docs:
|
||||
*/
|
||||
#define IO_APIC_SLOT_SIZE 1024
|
||||
|
||||
#define APIC_DELIVERY_MODE_FIXED 0
|
||||
#define APIC_DELIVERY_MODE_LOWESTPRIO 1
|
||||
#define APIC_DELIVERY_MODE_SMI 2
|
||||
#define APIC_DELIVERY_MODE_NMI 4
|
||||
#define APIC_DELIVERY_MODE_INIT 5
|
||||
#define APIC_DELIVERY_MODE_EXTINT 7
|
||||
|
||||
#define APIC_ID 0x20
|
||||
|
||||
#define APIC_LVR 0x30
|
||||
#define APIC_LVR_MASK 0xFF00FF
|
||||
#define APIC_LVR_DIRECTED_EOI (1 << 24)
|
||||
#define GET_APIC_VERSION(x) ((x) & 0xFFu)
|
||||
#define GET_APIC_MAXLVT(x) (((x) >> 16) & 0xFFu)
|
||||
#ifdef CONFIG_X86_32
|
||||
# define APIC_INTEGRATED(x) ((x) & 0xF0u)
|
||||
#else
|
||||
# define APIC_INTEGRATED(x) (1)
|
||||
#endif
|
||||
#define APIC_XAPIC(x) ((x) >= 0x14)
|
||||
#define APIC_EXT_SPACE(x) ((x) & 0x80000000)
|
||||
#define APIC_TASKPRI 0x80
|
||||
#define APIC_TPRI_MASK 0xFFu
|
||||
#define APIC_ARBPRI 0x90
|
||||
#define APIC_ARBPRI_MASK 0xFFu
|
||||
#define APIC_PROCPRI 0xA0
|
||||
#define APIC_EOI 0xB0
|
||||
#define APIC_EOI_ACK 0x0 /* Docs say 0 for future compat. */
|
||||
#define APIC_RRR 0xC0
|
||||
#define APIC_LDR 0xD0
|
||||
#define APIC_LDR_MASK (0xFFu << 24)
|
||||
#define GET_APIC_LOGICAL_ID(x) (((x) >> 24) & 0xFFu)
|
||||
#define SET_APIC_LOGICAL_ID(x) (((x) << 24))
|
||||
#define APIC_ALL_CPUS 0xFFu
|
||||
#define APIC_DFR 0xE0
|
||||
#define APIC_DFR_CLUSTER 0x0FFFFFFFul
|
||||
#define APIC_DFR_FLAT 0xFFFFFFFFul
|
||||
#define APIC_SPIV 0xF0
|
||||
#define APIC_SPIV_DIRECTED_EOI (1 << 12)
|
||||
#define APIC_SPIV_FOCUS_DISABLED (1 << 9)
|
||||
#define APIC_SPIV_APIC_ENABLED (1 << 8)
|
||||
#define APIC_ISR 0x100
|
||||
#define APIC_ISR_NR 0x8 /* Number of 32 bit ISR registers. */
|
||||
#define APIC_TMR 0x180
|
||||
#define APIC_IRR 0x200
|
||||
#define APIC_ESR 0x280
|
||||
#define APIC_ESR_SEND_CS 0x00001
|
||||
#define APIC_ESR_RECV_CS 0x00002
|
||||
#define APIC_ESR_SEND_ACC 0x00004
|
||||
#define APIC_ESR_RECV_ACC 0x00008
|
||||
#define APIC_ESR_SENDILL 0x00020
|
||||
#define APIC_ESR_RECVILL 0x00040
|
||||
#define APIC_ESR_ILLREGA 0x00080
|
||||
#define APIC_LVTCMCI 0x2f0
|
||||
#define APIC_ICR 0x300
|
||||
#define APIC_DEST_SELF 0x40000
|
||||
#define APIC_DEST_ALLINC 0x80000
|
||||
#define APIC_DEST_ALLBUT 0xC0000
|
||||
#define APIC_ICR_RR_MASK 0x30000
|
||||
#define APIC_ICR_RR_INVALID 0x00000
|
||||
#define APIC_ICR_RR_INPROG 0x10000
|
||||
#define APIC_ICR_RR_VALID 0x20000
|
||||
#define APIC_INT_LEVELTRIG 0x08000
|
||||
#define APIC_INT_ASSERT 0x04000
|
||||
#define APIC_ICR_BUSY 0x01000
|
||||
#define APIC_DEST_LOGICAL 0x00800
|
||||
#define APIC_DEST_PHYSICAL 0x00000
|
||||
#define APIC_DM_FIXED 0x00000
|
||||
#define APIC_DM_FIXED_MASK 0x00700
|
||||
#define APIC_DM_LOWEST 0x00100
|
||||
#define APIC_DM_SMI 0x00200
|
||||
#define APIC_DM_REMRD 0x00300
|
||||
#define APIC_DM_NMI 0x00400
|
||||
#define APIC_DM_INIT 0x00500
|
||||
#define APIC_DM_STARTUP 0x00600
|
||||
#define APIC_DM_EXTINT 0x00700
|
||||
#define APIC_VECTOR_MASK 0x000FF
|
||||
#define APIC_ICR2 0x310
|
||||
#define GET_XAPIC_DEST_FIELD(x) (((x) >> 24) & 0xFF)
|
||||
#define SET_XAPIC_DEST_FIELD(x) ((x) << 24)
|
||||
#define APIC_LVTT 0x320
|
||||
#define APIC_LVTTHMR 0x330
|
||||
#define APIC_LVTPC 0x340
|
||||
#define APIC_LVT0 0x350
|
||||
#define APIC_LVT_TIMER_ONESHOT (0 << 17)
|
||||
#define APIC_LVT_TIMER_PERIODIC (1 << 17)
|
||||
#define APIC_LVT_TIMER_TSCDEADLINE (2 << 17)
|
||||
#define APIC_LVT_MASKED (1 << 16)
|
||||
#define APIC_LVT_LEVEL_TRIGGER (1 << 15)
|
||||
#define APIC_LVT_REMOTE_IRR (1 << 14)
|
||||
#define APIC_INPUT_POLARITY (1 << 13)
|
||||
#define APIC_SEND_PENDING (1 << 12)
|
||||
#define APIC_MODE_MASK 0x700
|
||||
#define GET_APIC_DELIVERY_MODE(x) (((x) >> 8) & 0x7)
|
||||
#define SET_APIC_DELIVERY_MODE(x, y) (((x) & ~0x700) | ((y) << 8))
|
||||
#define APIC_MODE_FIXED 0x0
|
||||
#define APIC_MODE_NMI 0x4
|
||||
#define APIC_MODE_EXTINT 0x7
|
||||
#define APIC_LVT1 0x360
|
||||
#define APIC_LVTERR 0x370
|
||||
#define APIC_TMICT 0x380
|
||||
#define APIC_TMCCT 0x390
|
||||
#define APIC_TDCR 0x3E0
|
||||
#define APIC_SELF_IPI 0x3F0
|
||||
#define APIC_TDR_DIV_TMBASE (1 << 2)
|
||||
#define APIC_TDR_DIV_1 0xB
|
||||
#define APIC_TDR_DIV_2 0x0
|
||||
#define APIC_TDR_DIV_4 0x1
|
||||
#define APIC_TDR_DIV_8 0x2
|
||||
#define APIC_TDR_DIV_16 0x3
|
||||
#define APIC_TDR_DIV_32 0x8
|
||||
#define APIC_TDR_DIV_64 0x9
|
||||
#define APIC_TDR_DIV_128 0xA
|
||||
#define APIC_EFEAT 0x400
|
||||
#define APIC_ECTRL 0x410
|
||||
#define APIC_SEOI 0x420
|
||||
#define APIC_IER 0x480
|
||||
#define APIC_EILVTn(n) (0x500 + 0x10 * n)
|
||||
#define APIC_EILVT_NR_AMD_K8 1 /* # of extended interrupts */
|
||||
#define APIC_EILVT_NR_AMD_10H 4
|
||||
#define APIC_EILVT_NR_MAX APIC_EILVT_NR_AMD_10H
|
||||
#define APIC_EILVT_LVTOFF(x) (((x) >> 4) & 0xF)
|
||||
#define APIC_EILVT_MSG_FIX 0x0
|
||||
#define APIC_EILVT_MSG_SMI 0x2
|
||||
#define APIC_EILVT_MSG_NMI 0x4
|
||||
#define APIC_EILVT_MSG_EXT 0x7
|
||||
#define APIC_EILVT_MASKED (1 << 16)
|
||||
|
||||
#define APIC_BASE (fix_to_virt(FIX_APIC_BASE))
|
||||
#define APIC_BASE_MSR 0x800
|
||||
#define APIC_X2APIC_ID_MSR 0x802
|
||||
#define XAPIC_ENABLE BIT(11)
|
||||
#define X2APIC_ENABLE BIT(10)
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
# define MAX_IO_APICS 64
|
||||
# define MAX_LOCAL_APIC 256
|
||||
#else
|
||||
# define MAX_IO_APICS 128
|
||||
# define MAX_LOCAL_APIC 32768
|
||||
#endif
|
||||
|
||||
/*
|
||||
* All x86-64 systems are xAPIC compatible.
|
||||
* In the following, "apicid" is a physical APIC ID.
|
||||
*/
|
||||
#define XAPIC_DEST_CPUS_SHIFT 4
|
||||
#define XAPIC_DEST_CPUS_MASK ((1u << XAPIC_DEST_CPUS_SHIFT) - 1)
|
||||
#define XAPIC_DEST_CLUSTER_MASK (XAPIC_DEST_CPUS_MASK << XAPIC_DEST_CPUS_SHIFT)
|
||||
#define APIC_CLUSTER(apicid) ((apicid) & XAPIC_DEST_CLUSTER_MASK)
|
||||
#define APIC_CLUSTERID(apicid) (APIC_CLUSTER(apicid) >> XAPIC_DEST_CPUS_SHIFT)
|
||||
#define APIC_CPUID(apicid) ((apicid) & XAPIC_DEST_CPUS_MASK)
|
||||
#define NUM_APIC_CLUSTERS ((BAD_APICID + 1) >> XAPIC_DEST_CPUS_SHIFT)
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
#define BAD_APICID 0xFFu
|
||||
#else
|
||||
#define BAD_APICID 0xFFFFu
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_X86_APICDEF_H */
|
||||
@@ -0,0 +1,74 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Machine specific APM BIOS functions for generic.
|
||||
* Split out from apm.c by Osamu Tomita <tomita@cinet.co.jp>
|
||||
*/
|
||||
|
||||
#ifndef _ASM_X86_MACH_DEFAULT_APM_H
|
||||
#define _ASM_X86_MACH_DEFAULT_APM_H
|
||||
|
||||
#ifdef APM_ZERO_SEGS
|
||||
# define APM_DO_ZERO_SEGS \
|
||||
"pushl %%ds\n\t" \
|
||||
"pushl %%es\n\t" \
|
||||
"xorl %%edx, %%edx\n\t" \
|
||||
"mov %%dx, %%ds\n\t" \
|
||||
"mov %%dx, %%es\n\t" \
|
||||
"mov %%dx, %%fs\n\t" \
|
||||
"mov %%dx, %%gs\n\t"
|
||||
# define APM_DO_POP_SEGS \
|
||||
"popl %%es\n\t" \
|
||||
"popl %%ds\n\t"
|
||||
#else
|
||||
# define APM_DO_ZERO_SEGS
|
||||
# define APM_DO_POP_SEGS
|
||||
#endif
|
||||
|
||||
static inline void apm_bios_call_asm(u32 func, u32 ebx_in, u32 ecx_in,
|
||||
u32 *eax, u32 *ebx, u32 *ecx,
|
||||
u32 *edx, u32 *esi)
|
||||
{
|
||||
/*
|
||||
* N.B. We do NOT need a cld after the BIOS call
|
||||
* because we always save and restore the flags.
|
||||
*/
|
||||
__asm__ __volatile__(APM_DO_ZERO_SEGS
|
||||
"pushl %%edi\n\t"
|
||||
"pushl %%ebp\n\t"
|
||||
"lcall *%%cs:apm_bios_entry\n\t"
|
||||
"setc %%al\n\t"
|
||||
"popl %%ebp\n\t"
|
||||
"popl %%edi\n\t"
|
||||
APM_DO_POP_SEGS
|
||||
: "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx),
|
||||
"=S" (*esi)
|
||||
: "a" (func), "b" (ebx_in), "c" (ecx_in)
|
||||
: "memory", "cc");
|
||||
}
|
||||
|
||||
static inline bool apm_bios_call_simple_asm(u32 func, u32 ebx_in,
|
||||
u32 ecx_in, u32 *eax)
|
||||
{
|
||||
int cx, dx, si;
|
||||
bool error;
|
||||
|
||||
/*
|
||||
* N.B. We do NOT need a cld after the BIOS call
|
||||
* because we always save and restore the flags.
|
||||
*/
|
||||
__asm__ __volatile__(APM_DO_ZERO_SEGS
|
||||
"pushl %%edi\n\t"
|
||||
"pushl %%ebp\n\t"
|
||||
"lcall *%%cs:apm_bios_entry\n\t"
|
||||
"setc %%bl\n\t"
|
||||
"popl %%ebp\n\t"
|
||||
"popl %%edi\n\t"
|
||||
APM_DO_POP_SEGS
|
||||
: "=a" (*eax), "=b" (error), "=c" (cx), "=d" (dx),
|
||||
"=S" (si)
|
||||
: "a" (func), "b" (ebx_in), "c" (ecx_in)
|
||||
: "memory", "cc");
|
||||
return error;
|
||||
}
|
||||
|
||||
#endif /* _ASM_X86_MACH_DEFAULT_APM_H */
|
||||
@@ -0,0 +1,57 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_HWEIGHT_H
|
||||
#define _ASM_X86_HWEIGHT_H
|
||||
|
||||
#include <asm/cpufeatures.h>
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
#define REG_IN "D"
|
||||
#define REG_OUT "a"
|
||||
#else
|
||||
#define REG_IN "a"
|
||||
#define REG_OUT "a"
|
||||
#endif
|
||||
|
||||
static __always_inline unsigned int __arch_hweight32(unsigned int w)
|
||||
{
|
||||
unsigned int res;
|
||||
|
||||
asm_inline (ALTERNATIVE("call __sw_hweight32",
|
||||
"popcntl %[val], %[cnt]", X86_FEATURE_POPCNT)
|
||||
: [cnt] "=" REG_OUT (res), ASM_CALL_CONSTRAINT
|
||||
: [val] REG_IN (w));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline unsigned int __arch_hweight16(unsigned int w)
|
||||
{
|
||||
return __arch_hweight32(w & 0xffff);
|
||||
}
|
||||
|
||||
static inline unsigned int __arch_hweight8(unsigned int w)
|
||||
{
|
||||
return __arch_hweight32(w & 0xff);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
static inline unsigned long __arch_hweight64(__u64 w)
|
||||
{
|
||||
return __arch_hweight32((u32)w) +
|
||||
__arch_hweight32((u32)(w >> 32));
|
||||
}
|
||||
#else
|
||||
static __always_inline unsigned long __arch_hweight64(__u64 w)
|
||||
{
|
||||
unsigned long res;
|
||||
|
||||
asm_inline (ALTERNATIVE("call __sw_hweight64",
|
||||
"popcntq %[val], %[cnt]", X86_FEATURE_POPCNT)
|
||||
: [cnt] "=" REG_OUT (res), ASM_CALL_CONSTRAINT
|
||||
: [val] REG_IN (w));
|
||||
|
||||
return res;
|
||||
}
|
||||
#endif /* CONFIG_X86_32 */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,60 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* This file is part of the Linux kernel.
|
||||
*
|
||||
* Copyright (c) 2011-2014, Intel Corporation
|
||||
* Authors: Fenghua Yu <fenghua.yu@intel.com>,
|
||||
* H. Peter Anvin <hpa@linux.intel.com>
|
||||
*/
|
||||
|
||||
#ifndef ASM_X86_ARCHRANDOM_H
|
||||
#define ASM_X86_ARCHRANDOM_H
|
||||
|
||||
#include <asm/processor.h>
|
||||
#include <asm/cpufeature.h>
|
||||
|
||||
#define RDRAND_RETRY_LOOPS 10
|
||||
|
||||
/* Unconditional execution of RDRAND and RDSEED */
|
||||
|
||||
static inline bool __must_check rdrand_long(unsigned long *v)
|
||||
{
|
||||
bool ok;
|
||||
unsigned int retry = RDRAND_RETRY_LOOPS;
|
||||
do {
|
||||
asm volatile("rdrand %[out]"
|
||||
: "=@ccc" (ok), [out] "=r" (*v));
|
||||
if (ok)
|
||||
return true;
|
||||
} while (--retry);
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool __must_check rdseed_long(unsigned long *v)
|
||||
{
|
||||
bool ok;
|
||||
asm volatile("rdseed %[out]"
|
||||
: "=@ccc" (ok), [out] "=r" (*v));
|
||||
return ok;
|
||||
}
|
||||
|
||||
/*
|
||||
* These are the generic interfaces; they must not be declared if the
|
||||
* stubs in <linux/random.h> are to be invoked.
|
||||
*/
|
||||
|
||||
static inline size_t __must_check arch_get_random_longs(unsigned long *v, size_t max_longs)
|
||||
{
|
||||
return max_longs && static_cpu_has(X86_FEATURE_RDRAND) && rdrand_long(v) ? 1 : 0;
|
||||
}
|
||||
|
||||
static inline size_t __must_check arch_get_random_seed_longs(unsigned long *v, size_t max_longs)
|
||||
{
|
||||
return max_longs && static_cpu_has(X86_FEATURE_RDSEED) && rdseed_long(v) ? 1 : 0;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_UML
|
||||
void x86_init_rdrand(struct cpuinfo_x86 *c);
|
||||
#endif
|
||||
|
||||
#endif /* ASM_X86_ARCHRANDOM_H */
|
||||
@@ -0,0 +1 @@
|
||||
#include <generated/asm-offsets.h>
|
||||
@@ -0,0 +1,25 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#include <asm/ftrace.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/pgtable.h>
|
||||
#include <asm/string.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/checksum.h>
|
||||
#include <asm/mce.h>
|
||||
|
||||
#include <asm-generic/asm-prototypes.h>
|
||||
|
||||
#include <asm/special_insns.h>
|
||||
#include <asm/preempt.h>
|
||||
#include <asm/asm.h>
|
||||
#include <asm/fred.h>
|
||||
#include <asm/gsseg.h>
|
||||
#include <asm/nospec-branch.h>
|
||||
|
||||
#ifndef CONFIG_X86_CX8
|
||||
extern void cmpxchg8b_emu(void);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_STACKPROTECTOR
|
||||
extern unsigned long __ref_stack_chk_guard;
|
||||
#endif
|
||||
@@ -0,0 +1,257 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_ASM_H
|
||||
#define _ASM_X86_ASM_H
|
||||
|
||||
#include <linux/annotate.h>
|
||||
|
||||
#ifdef __ASSEMBLER__
|
||||
# define __ASM_FORM(x, ...) x,## __VA_ARGS__
|
||||
# define __ASM_FORM_RAW(x, ...) x,## __VA_ARGS__
|
||||
# define __ASM_FORM_COMMA(x, ...) x,## __VA_ARGS__,
|
||||
# define __ASM_REGPFX %
|
||||
#else
|
||||
#include <linux/stringify.h>
|
||||
# define __ASM_FORM(x, ...) " " __stringify(x,##__VA_ARGS__) " "
|
||||
# define __ASM_FORM_RAW(x, ...) __stringify(x,##__VA_ARGS__)
|
||||
# define __ASM_FORM_COMMA(x, ...) " " __stringify(x,##__VA_ARGS__) ","
|
||||
# define __ASM_REGPFX %%
|
||||
#endif
|
||||
|
||||
#define _ASM_BYTES(x, ...) __ASM_FORM(.byte x,##__VA_ARGS__ ;)
|
||||
|
||||
#ifndef __x86_64__
|
||||
/* 32 bit */
|
||||
# define __ASM_SEL(a,b) __ASM_FORM(a)
|
||||
# define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(a)
|
||||
#else
|
||||
/* 64 bit */
|
||||
# define __ASM_SEL(a,b) __ASM_FORM(b)
|
||||
# define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(b)
|
||||
#endif
|
||||
|
||||
#define __ASM_SIZE(inst, ...) __ASM_SEL(inst##l##__VA_ARGS__, \
|
||||
inst##q##__VA_ARGS__)
|
||||
#define __ASM_REG(reg) __ASM_SEL_RAW(e##reg, r##reg)
|
||||
|
||||
#define _ASM_PTR __ASM_SEL(.long, .quad)
|
||||
#define _ASM_ALIGN __ASM_SEL(.balign 4, .balign 8)
|
||||
|
||||
#define _ASM_MOV __ASM_SIZE(mov)
|
||||
#define _ASM_INC __ASM_SIZE(inc)
|
||||
#define _ASM_DEC __ASM_SIZE(dec)
|
||||
#define _ASM_ADD __ASM_SIZE(add)
|
||||
#define _ASM_SUB __ASM_SIZE(sub)
|
||||
#define _ASM_XADD __ASM_SIZE(xadd)
|
||||
#define _ASM_MUL __ASM_SIZE(mul)
|
||||
|
||||
#define _ASM_AX __ASM_REG(ax)
|
||||
#define _ASM_BX __ASM_REG(bx)
|
||||
#define _ASM_CX __ASM_REG(cx)
|
||||
#define _ASM_DX __ASM_REG(dx)
|
||||
#define _ASM_SP __ASM_REG(sp)
|
||||
#define _ASM_BP __ASM_REG(bp)
|
||||
#define _ASM_SI __ASM_REG(si)
|
||||
#define _ASM_DI __ASM_REG(di)
|
||||
|
||||
/* Adds a (%rip) suffix on 64 bits only; for immediate memory references */
|
||||
#define _ASM_RIP(x) __ASM_SEL_RAW(x, x (__ASM_REGPFX rip))
|
||||
|
||||
#ifndef __x86_64__
|
||||
/* 32 bit */
|
||||
|
||||
#define _ASM_ARG1 _ASM_AX
|
||||
#define _ASM_ARG2 _ASM_DX
|
||||
#define _ASM_ARG3 _ASM_CX
|
||||
|
||||
#define _ASM_ARG1L eax
|
||||
#define _ASM_ARG2L edx
|
||||
#define _ASM_ARG3L ecx
|
||||
|
||||
#define _ASM_ARG1W ax
|
||||
#define _ASM_ARG2W dx
|
||||
#define _ASM_ARG3W cx
|
||||
|
||||
#define _ASM_ARG1B al
|
||||
#define _ASM_ARG2B dl
|
||||
#define _ASM_ARG3B cl
|
||||
|
||||
#else
|
||||
/* 64 bit */
|
||||
|
||||
#define _ASM_ARG1 _ASM_DI
|
||||
#define _ASM_ARG2 _ASM_SI
|
||||
#define _ASM_ARG3 _ASM_DX
|
||||
#define _ASM_ARG4 _ASM_CX
|
||||
#define _ASM_ARG5 r8
|
||||
#define _ASM_ARG6 r9
|
||||
|
||||
#define _ASM_ARG1Q rdi
|
||||
#define _ASM_ARG2Q rsi
|
||||
#define _ASM_ARG3Q rdx
|
||||
#define _ASM_ARG4Q rcx
|
||||
#define _ASM_ARG5Q r8
|
||||
#define _ASM_ARG6Q r9
|
||||
|
||||
#define _ASM_ARG1L edi
|
||||
#define _ASM_ARG2L esi
|
||||
#define _ASM_ARG3L edx
|
||||
#define _ASM_ARG4L ecx
|
||||
#define _ASM_ARG5L r8d
|
||||
#define _ASM_ARG6L r9d
|
||||
|
||||
#define _ASM_ARG1W di
|
||||
#define _ASM_ARG2W si
|
||||
#define _ASM_ARG3W dx
|
||||
#define _ASM_ARG4W cx
|
||||
#define _ASM_ARG5W r8w
|
||||
#define _ASM_ARG6W r9w
|
||||
|
||||
#define _ASM_ARG1B dil
|
||||
#define _ASM_ARG2B sil
|
||||
#define _ASM_ARG3B dl
|
||||
#define _ASM_ARG4B cl
|
||||
#define _ASM_ARG5B r8b
|
||||
#define _ASM_ARG6B r9b
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
static __always_inline __pure void *rip_rel_ptr(void *p)
|
||||
{
|
||||
asm("leaq %c1(%%rip), %0" : "=r"(p) : "i"(p));
|
||||
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#ifndef COMPILE_OFFSETS
|
||||
#include <asm/asm-offsets.h>
|
||||
#endif
|
||||
|
||||
# include <asm/extable_fixup_types.h>
|
||||
|
||||
/* Exception table entry */
|
||||
#ifdef __ASSEMBLER__
|
||||
|
||||
# define _ASM_EXTABLE_TYPE(from, to, type) \
|
||||
.pushsection "__ex_table", "aM", @progbits, EXTABLE_SIZE ; \
|
||||
.balign 4 ; \
|
||||
.long (from) - . ; \
|
||||
.long (to) - . ; \
|
||||
.long type ; \
|
||||
.popsection
|
||||
|
||||
# ifdef CONFIG_KPROBES
|
||||
# define _ASM_NOKPROBE(entry) \
|
||||
.pushsection "_kprobe_blacklist","aw" ; \
|
||||
_ASM_ALIGN ; \
|
||||
_ASM_PTR (entry); \
|
||||
.popsection
|
||||
# else
|
||||
# define _ASM_NOKPROBE(entry)
|
||||
# endif
|
||||
|
||||
#else /* ! __ASSEMBLER__ */
|
||||
|
||||
# define DEFINE_EXTABLE_TYPE_REG \
|
||||
".macro extable_type_reg type:req reg:req\n" \
|
||||
".set .Lfound, 0\n" \
|
||||
".set .Lregnr, 0\n" \
|
||||
".irp rs,rax,rcx,rdx,rbx,rsp,rbp,rsi,rdi,r8,r9,r10,r11,r12,r13,r14,r15\n" \
|
||||
".ifc \\reg, %%\\rs\n" \
|
||||
".set .Lfound, .Lfound+1\n" \
|
||||
".long \\type + (.Lregnr << 8)\n" \
|
||||
".endif\n" \
|
||||
".set .Lregnr, .Lregnr+1\n" \
|
||||
".endr\n" \
|
||||
".set .Lregnr, 0\n" \
|
||||
".irp rs,eax,ecx,edx,ebx,esp,ebp,esi,edi,r8d,r9d,r10d,r11d,r12d,r13d,r14d,r15d\n" \
|
||||
".ifc \\reg, %%\\rs\n" \
|
||||
".set .Lfound, .Lfound+1\n" \
|
||||
".long \\type + (.Lregnr << 8)\n" \
|
||||
".endif\n" \
|
||||
".set .Lregnr, .Lregnr+1\n" \
|
||||
".endr\n" \
|
||||
".if (.Lfound != 1)\n" \
|
||||
".error \"extable_type_reg: bad register argument\"\n" \
|
||||
".endif\n" \
|
||||
".endm\n"
|
||||
|
||||
# define UNDEFINE_EXTABLE_TYPE_REG \
|
||||
".purgem extable_type_reg\n"
|
||||
|
||||
# define _ASM_EXTABLE_TYPE(from, to, type) \
|
||||
" .pushsection __ex_table, \"aM\", @progbits, " \
|
||||
__stringify(EXTABLE_SIZE) "\n" \
|
||||
" .balign 4\n" \
|
||||
" .long (" #from ") - .\n" \
|
||||
" .long (" #to ") - .\n" \
|
||||
" .long " __stringify(type) " \n" \
|
||||
" .popsection\n"
|
||||
|
||||
# define _ASM_EXTABLE_TYPE_REG(from, to, type, reg) \
|
||||
" .pushsection __ex_table, \"aM\", @progbits, " \
|
||||
__stringify(EXTABLE_SIZE) "\n" \
|
||||
" .balign 4\n" \
|
||||
" .long (" #from ") - .\n" \
|
||||
" .long (" #to ") - .\n" \
|
||||
DEFINE_EXTABLE_TYPE_REG \
|
||||
"extable_type_reg reg=" __stringify(reg) ", type=" __stringify(type) " \n"\
|
||||
UNDEFINE_EXTABLE_TYPE_REG \
|
||||
" .popsection\n"
|
||||
|
||||
/* For C file, we already have NOKPROBE_SYMBOL macro */
|
||||
|
||||
/* Insert a comma if args are non-empty */
|
||||
#define COMMA(x...) __COMMA(x)
|
||||
#define __COMMA(...) , ##__VA_ARGS__
|
||||
|
||||
/*
|
||||
* Combine multiple asm inline constraint args into a single arg for passing to
|
||||
* another macro.
|
||||
*/
|
||||
#define ASM_OUTPUT(x...) x
|
||||
#define ASM_INPUT(x...) x
|
||||
|
||||
/*
|
||||
* This output constraint should be used for any inline asm which has a "call"
|
||||
* instruction. Otherwise the asm may be inserted before the frame pointer
|
||||
* gets set up by the containing function. If you forget to do this, objtool
|
||||
* may print a "call without frame pointer save/setup" warning.
|
||||
*/
|
||||
register unsigned long current_stack_pointer asm(_ASM_SP);
|
||||
#define ASM_CALL_CONSTRAINT "+r" (current_stack_pointer)
|
||||
#endif /* __ASSEMBLER__ */
|
||||
|
||||
#define _ASM_EXTABLE(from, to) \
|
||||
_ASM_EXTABLE_TYPE(from, to, EX_TYPE_DEFAULT)
|
||||
|
||||
#define _ASM_EXTABLE_UA(from, to) \
|
||||
_ASM_EXTABLE_TYPE(from, to, EX_TYPE_UACCESS)
|
||||
|
||||
#define _ASM_EXTABLE_FAULT(from, to) \
|
||||
_ASM_EXTABLE_TYPE(from, to, EX_TYPE_FAULT)
|
||||
|
||||
/*
|
||||
* Both i386 and x86_64 returns 64-bit values in edx:eax for certain
|
||||
* instructions, but GCC's "A" constraint has different meanings.
|
||||
* For i386, "A" means exactly edx:eax, while for x86_64 it
|
||||
* means rax *or* rdx.
|
||||
*
|
||||
* These helpers wrapping these semantic differences save one instruction
|
||||
* clearing the high half of 'low':
|
||||
*/
|
||||
#ifdef CONFIG_X86_64
|
||||
# define EAX_EDX_DECLARE_ARGS(val, low, high) unsigned long low, high
|
||||
# define EAX_EDX_VAL(val, low, high) ((low) | (high) << 32)
|
||||
# define EAX_EDX_RET(val, low, high) "=a" (low), "=d" (high)
|
||||
#else
|
||||
# define EAX_EDX_DECLARE_ARGS(val, low, high) u64 val
|
||||
# define EAX_EDX_VAL(val, low, high) (val)
|
||||
# define EAX_EDX_RET(val, low, high) "=A" (val)
|
||||
#endif
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* _ASM_X86_ASM_H */
|
||||
@@ -0,0 +1,177 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_ATOMIC_H
|
||||
#define _ASM_X86_ATOMIC_H
|
||||
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/types.h>
|
||||
#include <asm/alternative.h>
|
||||
#include <asm/cmpxchg.h>
|
||||
#include <asm/rmwcc.h>
|
||||
#include <asm/barrier.h>
|
||||
|
||||
/*
|
||||
* Atomic operations that C can't guarantee us. Useful for
|
||||
* resource counting etc..
|
||||
*/
|
||||
|
||||
static __always_inline int arch_atomic_read(const atomic_t *v)
|
||||
{
|
||||
/*
|
||||
* Note for KASAN: we deliberately don't use READ_ONCE_NOCHECK() here,
|
||||
* it's non-inlined function that increases binary size and stack usage.
|
||||
*/
|
||||
return __READ_ONCE((v)->counter);
|
||||
}
|
||||
|
||||
static __always_inline void arch_atomic_set(atomic_t *v, int i)
|
||||
{
|
||||
__WRITE_ONCE(v->counter, i);
|
||||
}
|
||||
|
||||
static __always_inline void arch_atomic_add(int i, atomic_t *v)
|
||||
{
|
||||
asm_inline volatile(LOCK_PREFIX "addl %1, %0"
|
||||
: "+m" (v->counter)
|
||||
: "ir" (i) : "memory");
|
||||
}
|
||||
|
||||
static __always_inline void arch_atomic_sub(int i, atomic_t *v)
|
||||
{
|
||||
asm_inline volatile(LOCK_PREFIX "subl %1, %0"
|
||||
: "+m" (v->counter)
|
||||
: "ir" (i) : "memory");
|
||||
}
|
||||
|
||||
static __always_inline bool arch_atomic_sub_and_test(int i, atomic_t *v)
|
||||
{
|
||||
return GEN_BINARY_RMWcc(LOCK_PREFIX "subl", v->counter, e, "er", i);
|
||||
}
|
||||
#define arch_atomic_sub_and_test arch_atomic_sub_and_test
|
||||
|
||||
static __always_inline void arch_atomic_inc(atomic_t *v)
|
||||
{
|
||||
asm_inline volatile(LOCK_PREFIX "incl %0"
|
||||
: "+m" (v->counter) :: "memory");
|
||||
}
|
||||
#define arch_atomic_inc arch_atomic_inc
|
||||
|
||||
static __always_inline void arch_atomic_dec(atomic_t *v)
|
||||
{
|
||||
asm_inline volatile(LOCK_PREFIX "decl %0"
|
||||
: "+m" (v->counter) :: "memory");
|
||||
}
|
||||
#define arch_atomic_dec arch_atomic_dec
|
||||
|
||||
static __always_inline bool arch_atomic_dec_and_test(atomic_t *v)
|
||||
{
|
||||
return GEN_UNARY_RMWcc(LOCK_PREFIX "decl", v->counter, e);
|
||||
}
|
||||
#define arch_atomic_dec_and_test arch_atomic_dec_and_test
|
||||
|
||||
static __always_inline bool arch_atomic_inc_and_test(atomic_t *v)
|
||||
{
|
||||
return GEN_UNARY_RMWcc(LOCK_PREFIX "incl", v->counter, e);
|
||||
}
|
||||
#define arch_atomic_inc_and_test arch_atomic_inc_and_test
|
||||
|
||||
static __always_inline bool arch_atomic_add_negative(int i, atomic_t *v)
|
||||
{
|
||||
return GEN_BINARY_RMWcc(LOCK_PREFIX "addl", v->counter, s, "er", i);
|
||||
}
|
||||
#define arch_atomic_add_negative arch_atomic_add_negative
|
||||
|
||||
static __always_inline int arch_atomic_add_return(int i, atomic_t *v)
|
||||
{
|
||||
return i + xadd(&v->counter, i);
|
||||
}
|
||||
#define arch_atomic_add_return arch_atomic_add_return
|
||||
|
||||
#define arch_atomic_sub_return(i, v) arch_atomic_add_return(-(i), v)
|
||||
|
||||
static __always_inline int arch_atomic_fetch_add(int i, atomic_t *v)
|
||||
{
|
||||
return xadd(&v->counter, i);
|
||||
}
|
||||
#define arch_atomic_fetch_add arch_atomic_fetch_add
|
||||
|
||||
#define arch_atomic_fetch_sub(i, v) arch_atomic_fetch_add(-(i), v)
|
||||
|
||||
static __always_inline int arch_atomic_cmpxchg(atomic_t *v, int old, int new)
|
||||
{
|
||||
return arch_cmpxchg(&v->counter, old, new);
|
||||
}
|
||||
#define arch_atomic_cmpxchg arch_atomic_cmpxchg
|
||||
|
||||
static __always_inline bool arch_atomic_try_cmpxchg(atomic_t *v, int *old, int new)
|
||||
{
|
||||
return arch_try_cmpxchg(&v->counter, old, new);
|
||||
}
|
||||
#define arch_atomic_try_cmpxchg arch_atomic_try_cmpxchg
|
||||
|
||||
static __always_inline int arch_atomic_xchg(atomic_t *v, int new)
|
||||
{
|
||||
return arch_xchg(&v->counter, new);
|
||||
}
|
||||
#define arch_atomic_xchg arch_atomic_xchg
|
||||
|
||||
static __always_inline void arch_atomic_and(int i, atomic_t *v)
|
||||
{
|
||||
asm_inline volatile(LOCK_PREFIX "andl %1, %0"
|
||||
: "+m" (v->counter)
|
||||
: "ir" (i)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
static __always_inline int arch_atomic_fetch_and(int i, atomic_t *v)
|
||||
{
|
||||
int val = arch_atomic_read(v);
|
||||
|
||||
do { } while (!arch_atomic_try_cmpxchg(v, &val, val & i));
|
||||
|
||||
return val;
|
||||
}
|
||||
#define arch_atomic_fetch_and arch_atomic_fetch_and
|
||||
|
||||
static __always_inline void arch_atomic_or(int i, atomic_t *v)
|
||||
{
|
||||
asm_inline volatile(LOCK_PREFIX "orl %1, %0"
|
||||
: "+m" (v->counter)
|
||||
: "ir" (i)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
static __always_inline int arch_atomic_fetch_or(int i, atomic_t *v)
|
||||
{
|
||||
int val = arch_atomic_read(v);
|
||||
|
||||
do { } while (!arch_atomic_try_cmpxchg(v, &val, val | i));
|
||||
|
||||
return val;
|
||||
}
|
||||
#define arch_atomic_fetch_or arch_atomic_fetch_or
|
||||
|
||||
static __always_inline void arch_atomic_xor(int i, atomic_t *v)
|
||||
{
|
||||
asm_inline volatile(LOCK_PREFIX "xorl %1, %0"
|
||||
: "+m" (v->counter)
|
||||
: "ir" (i)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
static __always_inline int arch_atomic_fetch_xor(int i, atomic_t *v)
|
||||
{
|
||||
int val = arch_atomic_read(v);
|
||||
|
||||
do { } while (!arch_atomic_try_cmpxchg(v, &val, val ^ i));
|
||||
|
||||
return val;
|
||||
}
|
||||
#define arch_atomic_fetch_xor arch_atomic_fetch_xor
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
# include <asm/atomic64_32.h>
|
||||
#else
|
||||
# include <asm/atomic64_64.h>
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_X86_ATOMIC_H */
|
||||
@@ -0,0 +1,312 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_ATOMIC64_32_H
|
||||
#define _ASM_X86_ATOMIC64_32_H
|
||||
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/types.h>
|
||||
//#include <asm/cmpxchg.h>
|
||||
|
||||
/* An 64bit atomic type */
|
||||
|
||||
typedef struct {
|
||||
s64 __aligned(8) counter;
|
||||
} atomic64_t;
|
||||
|
||||
#define ATOMIC64_INIT(val) { (val) }
|
||||
|
||||
/*
|
||||
* Read an atomic64_t non-atomically.
|
||||
*
|
||||
* This is intended to be used in cases where a subsequent atomic operation
|
||||
* will handle the torn value, and can be used to prime the first iteration
|
||||
* of unconditional try_cmpxchg() loops, e.g.:
|
||||
*
|
||||
* s64 val = arch_atomic64_read_nonatomic(v);
|
||||
* do { } while (!arch_atomic64_try_cmpxchg(v, &val, val OP i);
|
||||
*
|
||||
* This is NOT safe to use where the value is not always checked by a
|
||||
* subsequent atomic operation, such as in conditional try_cmpxchg() loops
|
||||
* that can break before the atomic operation, e.g.:
|
||||
*
|
||||
* s64 val = arch_atomic64_read_nonatomic(v);
|
||||
* do {
|
||||
* if (condition(val))
|
||||
* break;
|
||||
* } while (!arch_atomic64_try_cmpxchg(v, &val, val OP i);
|
||||
*/
|
||||
static __always_inline s64 arch_atomic64_read_nonatomic(const atomic64_t *v)
|
||||
{
|
||||
/* See comment in arch_atomic_read(). */
|
||||
return __READ_ONCE(v->counter);
|
||||
}
|
||||
|
||||
#define __ATOMIC64_DECL(sym) void atomic64_##sym(atomic64_t *, ...)
|
||||
#ifndef ATOMIC64_EXPORT
|
||||
#define ATOMIC64_DECL_ONE __ATOMIC64_DECL
|
||||
#else
|
||||
#define ATOMIC64_DECL_ONE(sym) __ATOMIC64_DECL(sym); \
|
||||
ATOMIC64_EXPORT(atomic64_##sym)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86_CX8
|
||||
#define __alternative_atomic64(f, g, out, in, clobbers...) \
|
||||
asm volatile("call %c[func]" \
|
||||
: ALT_OUTPUT_SP(out) \
|
||||
: [func] "i" (atomic64_##g##_cx8) \
|
||||
COMMA(in) \
|
||||
: clobbers)
|
||||
|
||||
#define ATOMIC64_DECL(sym) ATOMIC64_DECL_ONE(sym##_cx8)
|
||||
#else
|
||||
#define __alternative_atomic64(f, g, out, in, clobbers...) \
|
||||
alternative_call(atomic64_##f##_386, atomic64_##g##_cx8, \
|
||||
X86_FEATURE_CX8, ASM_OUTPUT(out), \
|
||||
ASM_INPUT(in), clobbers)
|
||||
|
||||
#define ATOMIC64_DECL(sym) ATOMIC64_DECL_ONE(sym##_cx8); \
|
||||
ATOMIC64_DECL_ONE(sym##_386)
|
||||
|
||||
ATOMIC64_DECL_ONE(add_386);
|
||||
ATOMIC64_DECL_ONE(sub_386);
|
||||
ATOMIC64_DECL_ONE(inc_386);
|
||||
ATOMIC64_DECL_ONE(dec_386);
|
||||
#endif
|
||||
|
||||
#define alternative_atomic64(f, out, in, clobbers...) \
|
||||
__alternative_atomic64(f, f, ASM_OUTPUT(out), ASM_INPUT(in), clobbers)
|
||||
|
||||
ATOMIC64_DECL(read);
|
||||
ATOMIC64_DECL(set);
|
||||
ATOMIC64_DECL(xchg);
|
||||
ATOMIC64_DECL(add_return);
|
||||
ATOMIC64_DECL(sub_return);
|
||||
ATOMIC64_DECL(inc_return);
|
||||
ATOMIC64_DECL(dec_return);
|
||||
ATOMIC64_DECL(dec_if_positive);
|
||||
ATOMIC64_DECL(inc_not_zero);
|
||||
ATOMIC64_DECL(add_unless);
|
||||
|
||||
#undef ATOMIC64_DECL
|
||||
#undef ATOMIC64_DECL_ONE
|
||||
#undef __ATOMIC64_DECL
|
||||
#undef ATOMIC64_EXPORT
|
||||
|
||||
static __always_inline s64 arch_atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new)
|
||||
{
|
||||
return arch_cmpxchg64(&v->counter, old, new);
|
||||
}
|
||||
#define arch_atomic64_cmpxchg arch_atomic64_cmpxchg
|
||||
|
||||
static __always_inline bool arch_atomic64_try_cmpxchg(atomic64_t *v, s64 *old, s64 new)
|
||||
{
|
||||
return arch_try_cmpxchg64(&v->counter, old, new);
|
||||
}
|
||||
#define arch_atomic64_try_cmpxchg arch_atomic64_try_cmpxchg
|
||||
|
||||
static __always_inline s64 arch_atomic64_xchg(atomic64_t *v, s64 n)
|
||||
{
|
||||
s64 o;
|
||||
unsigned high = (unsigned)(n >> 32);
|
||||
unsigned low = (unsigned)n;
|
||||
alternative_atomic64(xchg,
|
||||
"=&A" (o),
|
||||
ASM_INPUT("S" (v), "b" (low), "c" (high)),
|
||||
"memory");
|
||||
return o;
|
||||
}
|
||||
#define arch_atomic64_xchg arch_atomic64_xchg
|
||||
|
||||
static __always_inline void arch_atomic64_set(atomic64_t *v, s64 i)
|
||||
{
|
||||
unsigned high = (unsigned)(i >> 32);
|
||||
unsigned low = (unsigned)i;
|
||||
alternative_atomic64(set,
|
||||
/* no output */,
|
||||
ASM_INPUT("S" (v), "b" (low), "c" (high)),
|
||||
"eax", "edx", "memory");
|
||||
}
|
||||
|
||||
static __always_inline s64 arch_atomic64_read(const atomic64_t *v)
|
||||
{
|
||||
s64 r;
|
||||
alternative_atomic64(read, "=&A" (r), "c" (v), "memory");
|
||||
return r;
|
||||
}
|
||||
|
||||
static __always_inline s64 arch_atomic64_add_return(s64 i, atomic64_t *v)
|
||||
{
|
||||
alternative_atomic64(add_return,
|
||||
ASM_OUTPUT("+A" (i), "+c" (v)),
|
||||
/* no input */,
|
||||
"memory");
|
||||
return i;
|
||||
}
|
||||
#define arch_atomic64_add_return arch_atomic64_add_return
|
||||
|
||||
static __always_inline s64 arch_atomic64_sub_return(s64 i, atomic64_t *v)
|
||||
{
|
||||
alternative_atomic64(sub_return,
|
||||
ASM_OUTPUT("+A" (i), "+c" (v)),
|
||||
/* no input */,
|
||||
"memory");
|
||||
return i;
|
||||
}
|
||||
#define arch_atomic64_sub_return arch_atomic64_sub_return
|
||||
|
||||
static __always_inline s64 arch_atomic64_inc_return(atomic64_t *v)
|
||||
{
|
||||
s64 a;
|
||||
alternative_atomic64(inc_return,
|
||||
"=&A" (a),
|
||||
"S" (v),
|
||||
"memory", "ecx");
|
||||
return a;
|
||||
}
|
||||
#define arch_atomic64_inc_return arch_atomic64_inc_return
|
||||
|
||||
static __always_inline s64 arch_atomic64_dec_return(atomic64_t *v)
|
||||
{
|
||||
s64 a;
|
||||
alternative_atomic64(dec_return,
|
||||
"=&A" (a),
|
||||
"S" (v),
|
||||
"memory", "ecx");
|
||||
return a;
|
||||
}
|
||||
#define arch_atomic64_dec_return arch_atomic64_dec_return
|
||||
|
||||
static __always_inline void arch_atomic64_add(s64 i, atomic64_t *v)
|
||||
{
|
||||
__alternative_atomic64(add, add_return,
|
||||
ASM_OUTPUT("+A" (i), "+c" (v)),
|
||||
/* no input */,
|
||||
"memory");
|
||||
}
|
||||
|
||||
static __always_inline void arch_atomic64_sub(s64 i, atomic64_t *v)
|
||||
{
|
||||
__alternative_atomic64(sub, sub_return,
|
||||
ASM_OUTPUT("+A" (i), "+c" (v)),
|
||||
/* no input */,
|
||||
"memory");
|
||||
}
|
||||
|
||||
static __always_inline void arch_atomic64_inc(atomic64_t *v)
|
||||
{
|
||||
__alternative_atomic64(inc, inc_return,
|
||||
/* no output */,
|
||||
"S" (v),
|
||||
"memory", "eax", "ecx", "edx");
|
||||
}
|
||||
#define arch_atomic64_inc arch_atomic64_inc
|
||||
|
||||
static __always_inline void arch_atomic64_dec(atomic64_t *v)
|
||||
{
|
||||
__alternative_atomic64(dec, dec_return,
|
||||
/* no output */,
|
||||
"S" (v),
|
||||
"memory", "eax", "ecx", "edx");
|
||||
}
|
||||
#define arch_atomic64_dec arch_atomic64_dec
|
||||
|
||||
static __always_inline int arch_atomic64_add_unless(atomic64_t *v, s64 a, s64 u)
|
||||
{
|
||||
unsigned low = (unsigned)u;
|
||||
unsigned high = (unsigned)(u >> 32);
|
||||
alternative_atomic64(add_unless,
|
||||
ASM_OUTPUT("+A" (a), "+c" (low), "+D" (high)),
|
||||
"S" (v),
|
||||
"memory");
|
||||
return (int)a;
|
||||
}
|
||||
#define arch_atomic64_add_unless arch_atomic64_add_unless
|
||||
|
||||
static __always_inline int arch_atomic64_inc_not_zero(atomic64_t *v)
|
||||
{
|
||||
int r;
|
||||
alternative_atomic64(inc_not_zero,
|
||||
"=&a" (r),
|
||||
"S" (v),
|
||||
"ecx", "edx", "memory");
|
||||
return r;
|
||||
}
|
||||
#define arch_atomic64_inc_not_zero arch_atomic64_inc_not_zero
|
||||
|
||||
static __always_inline s64 arch_atomic64_dec_if_positive(atomic64_t *v)
|
||||
{
|
||||
s64 r;
|
||||
alternative_atomic64(dec_if_positive,
|
||||
"=&A" (r),
|
||||
"S" (v),
|
||||
"ecx", "memory");
|
||||
return r;
|
||||
}
|
||||
#define arch_atomic64_dec_if_positive arch_atomic64_dec_if_positive
|
||||
|
||||
#undef alternative_atomic64
|
||||
#undef __alternative_atomic64
|
||||
|
||||
static __always_inline void arch_atomic64_and(s64 i, atomic64_t *v)
|
||||
{
|
||||
s64 val = arch_atomic64_read_nonatomic(v);
|
||||
|
||||
do { } while (!arch_atomic64_try_cmpxchg(v, &val, val & i));
|
||||
}
|
||||
|
||||
static __always_inline s64 arch_atomic64_fetch_and(s64 i, atomic64_t *v)
|
||||
{
|
||||
s64 val = arch_atomic64_read_nonatomic(v);
|
||||
|
||||
do { } while (!arch_atomic64_try_cmpxchg(v, &val, val & i));
|
||||
|
||||
return val;
|
||||
}
|
||||
#define arch_atomic64_fetch_and arch_atomic64_fetch_and
|
||||
|
||||
static __always_inline void arch_atomic64_or(s64 i, atomic64_t *v)
|
||||
{
|
||||
s64 val = arch_atomic64_read_nonatomic(v);
|
||||
|
||||
do { } while (!arch_atomic64_try_cmpxchg(v, &val, val | i));
|
||||
}
|
||||
|
||||
static __always_inline s64 arch_atomic64_fetch_or(s64 i, atomic64_t *v)
|
||||
{
|
||||
s64 val = arch_atomic64_read_nonatomic(v);
|
||||
|
||||
do { } while (!arch_atomic64_try_cmpxchg(v, &val, val | i));
|
||||
|
||||
return val;
|
||||
}
|
||||
#define arch_atomic64_fetch_or arch_atomic64_fetch_or
|
||||
|
||||
static __always_inline void arch_atomic64_xor(s64 i, atomic64_t *v)
|
||||
{
|
||||
s64 val = arch_atomic64_read_nonatomic(v);
|
||||
|
||||
do { } while (!arch_atomic64_try_cmpxchg(v, &val, val ^ i));
|
||||
}
|
||||
|
||||
static __always_inline s64 arch_atomic64_fetch_xor(s64 i, atomic64_t *v)
|
||||
{
|
||||
s64 val = arch_atomic64_read_nonatomic(v);
|
||||
|
||||
do { } while (!arch_atomic64_try_cmpxchg(v, &val, val ^ i));
|
||||
|
||||
return val;
|
||||
}
|
||||
#define arch_atomic64_fetch_xor arch_atomic64_fetch_xor
|
||||
|
||||
static __always_inline s64 arch_atomic64_fetch_add(s64 i, atomic64_t *v)
|
||||
{
|
||||
s64 val = arch_atomic64_read_nonatomic(v);
|
||||
|
||||
do { } while (!arch_atomic64_try_cmpxchg(v, &val, val + i));
|
||||
|
||||
return val;
|
||||
}
|
||||
#define arch_atomic64_fetch_add arch_atomic64_fetch_add
|
||||
|
||||
#define arch_atomic64_fetch_sub(i, v) arch_atomic64_fetch_add(-(i), (v))
|
||||
|
||||
#endif /* _ASM_X86_ATOMIC64_32_H */
|
||||
@@ -0,0 +1,165 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_ATOMIC64_64_H
|
||||
#define _ASM_X86_ATOMIC64_64_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <asm/alternative.h>
|
||||
#include <asm/cmpxchg.h>
|
||||
|
||||
/* The 64-bit atomic type */
|
||||
|
||||
#define ATOMIC64_INIT(i) { (i) }
|
||||
|
||||
static __always_inline s64 arch_atomic64_read(const atomic64_t *v)
|
||||
{
|
||||
return __READ_ONCE((v)->counter);
|
||||
}
|
||||
|
||||
static __always_inline void arch_atomic64_set(atomic64_t *v, s64 i)
|
||||
{
|
||||
__WRITE_ONCE(v->counter, i);
|
||||
}
|
||||
|
||||
static __always_inline void arch_atomic64_add(s64 i, atomic64_t *v)
|
||||
{
|
||||
asm_inline volatile(LOCK_PREFIX "addq %1, %0"
|
||||
: "=m" (v->counter)
|
||||
: "er" (i), "m" (v->counter) : "memory");
|
||||
}
|
||||
|
||||
static __always_inline void arch_atomic64_sub(s64 i, atomic64_t *v)
|
||||
{
|
||||
asm_inline volatile(LOCK_PREFIX "subq %1, %0"
|
||||
: "=m" (v->counter)
|
||||
: "er" (i), "m" (v->counter) : "memory");
|
||||
}
|
||||
|
||||
static __always_inline bool arch_atomic64_sub_and_test(s64 i, atomic64_t *v)
|
||||
{
|
||||
return GEN_BINARY_RMWcc(LOCK_PREFIX "subq", v->counter, e, "er", i);
|
||||
}
|
||||
#define arch_atomic64_sub_and_test arch_atomic64_sub_and_test
|
||||
|
||||
static __always_inline void arch_atomic64_inc(atomic64_t *v)
|
||||
{
|
||||
asm_inline volatile(LOCK_PREFIX "incq %0"
|
||||
: "=m" (v->counter)
|
||||
: "m" (v->counter) : "memory");
|
||||
}
|
||||
#define arch_atomic64_inc arch_atomic64_inc
|
||||
|
||||
static __always_inline void arch_atomic64_dec(atomic64_t *v)
|
||||
{
|
||||
asm_inline volatile(LOCK_PREFIX "decq %0"
|
||||
: "=m" (v->counter)
|
||||
: "m" (v->counter) : "memory");
|
||||
}
|
||||
#define arch_atomic64_dec arch_atomic64_dec
|
||||
|
||||
static __always_inline bool arch_atomic64_dec_and_test(atomic64_t *v)
|
||||
{
|
||||
return GEN_UNARY_RMWcc(LOCK_PREFIX "decq", v->counter, e);
|
||||
}
|
||||
#define arch_atomic64_dec_and_test arch_atomic64_dec_and_test
|
||||
|
||||
static __always_inline bool arch_atomic64_inc_and_test(atomic64_t *v)
|
||||
{
|
||||
return GEN_UNARY_RMWcc(LOCK_PREFIX "incq", v->counter, e);
|
||||
}
|
||||
#define arch_atomic64_inc_and_test arch_atomic64_inc_and_test
|
||||
|
||||
static __always_inline bool arch_atomic64_add_negative(s64 i, atomic64_t *v)
|
||||
{
|
||||
return GEN_BINARY_RMWcc(LOCK_PREFIX "addq", v->counter, s, "er", i);
|
||||
}
|
||||
#define arch_atomic64_add_negative arch_atomic64_add_negative
|
||||
|
||||
static __always_inline s64 arch_atomic64_add_return(s64 i, atomic64_t *v)
|
||||
{
|
||||
return i + xadd(&v->counter, i);
|
||||
}
|
||||
#define arch_atomic64_add_return arch_atomic64_add_return
|
||||
|
||||
#define arch_atomic64_sub_return(i, v) arch_atomic64_add_return(-(i), v)
|
||||
|
||||
static __always_inline s64 arch_atomic64_fetch_add(s64 i, atomic64_t *v)
|
||||
{
|
||||
return xadd(&v->counter, i);
|
||||
}
|
||||
#define arch_atomic64_fetch_add arch_atomic64_fetch_add
|
||||
|
||||
#define arch_atomic64_fetch_sub(i, v) arch_atomic64_fetch_add(-(i), v)
|
||||
|
||||
static __always_inline s64 arch_atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new)
|
||||
{
|
||||
return arch_cmpxchg(&v->counter, old, new);
|
||||
}
|
||||
#define arch_atomic64_cmpxchg arch_atomic64_cmpxchg
|
||||
|
||||
static __always_inline bool arch_atomic64_try_cmpxchg(atomic64_t *v, s64 *old, s64 new)
|
||||
{
|
||||
return arch_try_cmpxchg(&v->counter, old, new);
|
||||
}
|
||||
#define arch_atomic64_try_cmpxchg arch_atomic64_try_cmpxchg
|
||||
|
||||
static __always_inline s64 arch_atomic64_xchg(atomic64_t *v, s64 new)
|
||||
{
|
||||
return arch_xchg(&v->counter, new);
|
||||
}
|
||||
#define arch_atomic64_xchg arch_atomic64_xchg
|
||||
|
||||
static __always_inline void arch_atomic64_and(s64 i, atomic64_t *v)
|
||||
{
|
||||
asm_inline volatile(LOCK_PREFIX "andq %1, %0"
|
||||
: "+m" (v->counter)
|
||||
: "er" (i)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
static __always_inline s64 arch_atomic64_fetch_and(s64 i, atomic64_t *v)
|
||||
{
|
||||
s64 val = arch_atomic64_read(v);
|
||||
|
||||
do {
|
||||
} while (!arch_atomic64_try_cmpxchg(v, &val, val & i));
|
||||
return val;
|
||||
}
|
||||
#define arch_atomic64_fetch_and arch_atomic64_fetch_and
|
||||
|
||||
static __always_inline void arch_atomic64_or(s64 i, atomic64_t *v)
|
||||
{
|
||||
asm_inline volatile(LOCK_PREFIX "orq %1, %0"
|
||||
: "+m" (v->counter)
|
||||
: "er" (i)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
static __always_inline s64 arch_atomic64_fetch_or(s64 i, atomic64_t *v)
|
||||
{
|
||||
s64 val = arch_atomic64_read(v);
|
||||
|
||||
do {
|
||||
} while (!arch_atomic64_try_cmpxchg(v, &val, val | i));
|
||||
return val;
|
||||
}
|
||||
#define arch_atomic64_fetch_or arch_atomic64_fetch_or
|
||||
|
||||
static __always_inline void arch_atomic64_xor(s64 i, atomic64_t *v)
|
||||
{
|
||||
asm_inline volatile(LOCK_PREFIX "xorq %1, %0"
|
||||
: "+m" (v->counter)
|
||||
: "er" (i)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
static __always_inline s64 arch_atomic64_fetch_xor(s64 i, atomic64_t *v)
|
||||
{
|
||||
s64 val = arch_atomic64_read(v);
|
||||
|
||||
do {
|
||||
} while (!arch_atomic64_try_cmpxchg(v, &val, val ^ i));
|
||||
return val;
|
||||
}
|
||||
#define arch_atomic64_fetch_xor arch_atomic64_fetch_xor
|
||||
|
||||
#endif /* _ASM_X86_ATOMIC64_64_H */
|
||||
@@ -0,0 +1,14 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_AUDIT_H
|
||||
#define _ASM_X86_AUDIT_H
|
||||
|
||||
int ia32_classify_syscall(unsigned int syscall);
|
||||
|
||||
extern unsigned ia32_dir_class[];
|
||||
extern unsigned ia32_write_class[];
|
||||
extern unsigned ia32_read_class[];
|
||||
extern unsigned ia32_chattr_class[];
|
||||
extern unsigned ia32_signal_class[];
|
||||
|
||||
|
||||
#endif /* _ASM_X86_AUDIT_H */
|
||||
@@ -0,0 +1,83 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_BARRIER_H
|
||||
#define _ASM_X86_BARRIER_H
|
||||
|
||||
#include <asm/alternative.h>
|
||||
#include <asm/nops.h>
|
||||
|
||||
/*
|
||||
* Force strict CPU ordering.
|
||||
* And yes, this might be required on UP too when we're talking
|
||||
* to devices.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
#define mb() asm volatile(ALTERNATIVE("lock addl $0,-4(%%esp)", "mfence", \
|
||||
X86_FEATURE_XMM2) ::: "memory", "cc")
|
||||
#define rmb() asm volatile(ALTERNATIVE("lock addl $0,-4(%%esp)", "lfence", \
|
||||
X86_FEATURE_XMM2) ::: "memory", "cc")
|
||||
#define wmb() asm volatile(ALTERNATIVE("lock addl $0,-4(%%esp)", "sfence", \
|
||||
X86_FEATURE_XMM2) ::: "memory", "cc")
|
||||
#else
|
||||
#define __mb() asm volatile("mfence":::"memory")
|
||||
#define __rmb() asm volatile("lfence":::"memory")
|
||||
#define __wmb() asm volatile("sfence" ::: "memory")
|
||||
#endif
|
||||
|
||||
/**
|
||||
* array_index_mask_nospec() - generate a mask that is ~0UL when the
|
||||
* bounds check succeeds and 0 otherwise
|
||||
* @index: array element index
|
||||
* @size: number of elements in array
|
||||
*
|
||||
* Returns:
|
||||
* 0 - (index < size)
|
||||
*/
|
||||
#define array_index_mask_nospec(idx,sz) ({ \
|
||||
typeof((idx)+(sz)) __idx = (idx); \
|
||||
typeof(__idx) __sz = (sz); \
|
||||
unsigned long __mask; \
|
||||
asm volatile ("cmp %1,%2; sbb %0,%0" \
|
||||
:"=r" (__mask) \
|
||||
:ASM_INPUT_G (__sz), \
|
||||
"r" (__idx) \
|
||||
:"cc"); \
|
||||
__mask; })
|
||||
|
||||
/* Prevent speculative execution past this barrier. */
|
||||
#define barrier_nospec() alternative("", "lfence", X86_FEATURE_LFENCE_RDTSC)
|
||||
|
||||
#define __dma_rmb() barrier()
|
||||
#define __dma_wmb() barrier()
|
||||
|
||||
#define __smp_mb() asm volatile("lock addl $0,-4(%%" _ASM_SP ")" ::: "memory", "cc")
|
||||
|
||||
#define __smp_rmb() dma_rmb()
|
||||
#define __smp_wmb() barrier()
|
||||
#define __smp_store_mb(var, value) do { (void)xchg(&var, value); } while (0)
|
||||
|
||||
#define __smp_store_release(p, v) \
|
||||
do { \
|
||||
compiletime_assert_atomic_type(*p); \
|
||||
barrier(); \
|
||||
WRITE_ONCE(*p, v); \
|
||||
} while (0)
|
||||
|
||||
#define __smp_load_acquire(p) \
|
||||
({ \
|
||||
typeof(*p) ___p1 = READ_ONCE(*p); \
|
||||
compiletime_assert_atomic_type(*p); \
|
||||
barrier(); \
|
||||
___p1; \
|
||||
})
|
||||
|
||||
/* Atomic operations are already serializing on x86 */
|
||||
#define __smp_mb__before_atomic() do { } while (0)
|
||||
#define __smp_mb__after_atomic() do { } while (0)
|
||||
|
||||
/* Writing to CR3 provides a full memory barrier in switch_mm(). */
|
||||
#define smp_mb__after_switch_mm() do { } while (0)
|
||||
|
||||
#include <asm-generic/barrier.h>
|
||||
|
||||
#endif /* _ASM_X86_BARRIER_H */
|
||||
@@ -0,0 +1,40 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_BIOS_EBDA_H
|
||||
#define _ASM_X86_BIOS_EBDA_H
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
/*
|
||||
* Returns physical address of EBDA. Returns 0 if there is no EBDA.
|
||||
*/
|
||||
static inline unsigned int get_bios_ebda(void)
|
||||
{
|
||||
/*
|
||||
* There is a real-mode segmented pointer pointing to the
|
||||
* 4K EBDA area at 0x40E.
|
||||
*/
|
||||
unsigned int address = *(unsigned short *)phys_to_virt(0x40E);
|
||||
address <<= 4;
|
||||
return address; /* 0 means none */
|
||||
}
|
||||
|
||||
void reserve_bios_regions(void);
|
||||
|
||||
#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
|
||||
/*
|
||||
* This is obviously not a great place for this, but we want to be
|
||||
* able to scatter it around anywhere in the kernel.
|
||||
*/
|
||||
void check_for_bios_corruption(void);
|
||||
void start_periodic_check_for_corruption(void);
|
||||
#else
|
||||
static inline void check_for_bios_corruption(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void start_periodic_check_for_corruption(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_X86_BIOS_EBDA_H */
|
||||
@@ -0,0 +1,432 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_BITOPS_H
|
||||
#define _ASM_X86_BITOPS_H
|
||||
|
||||
/*
|
||||
* Copyright 1992, Linus Torvalds.
|
||||
*
|
||||
* Note: inlines with more than a single statement should be marked
|
||||
* __always_inline to avoid problems with older gcc's inlining heuristics.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_BITOPS_H
|
||||
#error only <linux/bitops.h> can be included directly
|
||||
#endif
|
||||
|
||||
#include <linux/compiler.h>
|
||||
#include <asm/alternative.h>
|
||||
#include <asm/rmwcc.h>
|
||||
#include <asm/barrier.h>
|
||||
|
||||
#if BITS_PER_LONG == 32
|
||||
# define _BITOPS_LONG_SHIFT 5
|
||||
#elif BITS_PER_LONG == 64
|
||||
# define _BITOPS_LONG_SHIFT 6
|
||||
#else
|
||||
# error "Unexpected BITS_PER_LONG"
|
||||
#endif
|
||||
|
||||
#define BIT_64(n) (U64_C(1) << (n))
|
||||
|
||||
/*
|
||||
* These have to be done with inline assembly: that way the bit-setting
|
||||
* is guaranteed to be atomic. All bit operations return 0 if the bit
|
||||
* was cleared before the operation and != 0 if it was not.
|
||||
*
|
||||
* bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
|
||||
*/
|
||||
|
||||
#define RLONG_ADDR(x) "m" (*(volatile long *) (x))
|
||||
#define WBYTE_ADDR(x) "+m" (*(volatile char *) (x))
|
||||
|
||||
#define ADDR RLONG_ADDR(addr)
|
||||
|
||||
/*
|
||||
* We do the locked ops that don't return the old value as
|
||||
* a mask operation on a byte.
|
||||
*/
|
||||
#define CONST_MASK_ADDR(nr, addr) WBYTE_ADDR((void *)(addr) + ((nr)>>3))
|
||||
#define CONST_MASK(nr) (1 << ((nr) & 7))
|
||||
|
||||
static __always_inline void
|
||||
arch_set_bit(long nr, volatile unsigned long *addr)
|
||||
{
|
||||
if (__builtin_constant_p(nr)) {
|
||||
asm_inline volatile(LOCK_PREFIX "orb %b1,%0"
|
||||
: CONST_MASK_ADDR(nr, addr)
|
||||
: "iq" (CONST_MASK(nr))
|
||||
: "memory");
|
||||
} else {
|
||||
asm_inline volatile(LOCK_PREFIX __ASM_SIZE(bts) " %1,%0"
|
||||
: : RLONG_ADDR(addr), "Ir" (nr) : "memory");
|
||||
}
|
||||
}
|
||||
|
||||
static __always_inline void
|
||||
arch___set_bit(unsigned long nr, volatile unsigned long *addr)
|
||||
{
|
||||
asm volatile(__ASM_SIZE(bts) " %1,%0" : : ADDR, "Ir" (nr) : "memory");
|
||||
}
|
||||
|
||||
static __always_inline void
|
||||
arch_clear_bit(long nr, volatile unsigned long *addr)
|
||||
{
|
||||
if (__builtin_constant_p(nr)) {
|
||||
asm_inline volatile(LOCK_PREFIX "andb %b1,%0"
|
||||
: CONST_MASK_ADDR(nr, addr)
|
||||
: "iq" (~CONST_MASK(nr)));
|
||||
} else {
|
||||
asm_inline volatile(LOCK_PREFIX __ASM_SIZE(btr) " %1,%0"
|
||||
: : RLONG_ADDR(addr), "Ir" (nr) : "memory");
|
||||
}
|
||||
}
|
||||
|
||||
static __always_inline void
|
||||
arch_clear_bit_unlock(long nr, volatile unsigned long *addr)
|
||||
{
|
||||
barrier();
|
||||
arch_clear_bit(nr, addr);
|
||||
}
|
||||
|
||||
static __always_inline void
|
||||
arch___clear_bit(unsigned long nr, volatile unsigned long *addr)
|
||||
{
|
||||
asm volatile(__ASM_SIZE(btr) " %1,%0" : : ADDR, "Ir" (nr) : "memory");
|
||||
}
|
||||
|
||||
static __always_inline bool arch_xor_unlock_is_negative_byte(unsigned long mask,
|
||||
volatile unsigned long *addr)
|
||||
{
|
||||
bool negative;
|
||||
asm_inline volatile(LOCK_PREFIX "xorb %2,%1"
|
||||
: "=@ccs" (negative), WBYTE_ADDR(addr)
|
||||
: "iq" ((char)mask) : "memory");
|
||||
return negative;
|
||||
}
|
||||
#define arch_xor_unlock_is_negative_byte arch_xor_unlock_is_negative_byte
|
||||
|
||||
static __always_inline void
|
||||
arch___clear_bit_unlock(long nr, volatile unsigned long *addr)
|
||||
{
|
||||
arch___clear_bit(nr, addr);
|
||||
}
|
||||
|
||||
static __always_inline void
|
||||
arch___change_bit(unsigned long nr, volatile unsigned long *addr)
|
||||
{
|
||||
asm volatile(__ASM_SIZE(btc) " %1,%0" : : ADDR, "Ir" (nr) : "memory");
|
||||
}
|
||||
|
||||
static __always_inline void
|
||||
arch_change_bit(long nr, volatile unsigned long *addr)
|
||||
{
|
||||
if (__builtin_constant_p(nr)) {
|
||||
asm_inline volatile(LOCK_PREFIX "xorb %b1,%0"
|
||||
: CONST_MASK_ADDR(nr, addr)
|
||||
: "iq" (CONST_MASK(nr)));
|
||||
} else {
|
||||
asm_inline volatile(LOCK_PREFIX __ASM_SIZE(btc) " %1,%0"
|
||||
: : RLONG_ADDR(addr), "Ir" (nr) : "memory");
|
||||
}
|
||||
}
|
||||
|
||||
static __always_inline bool
|
||||
arch_test_and_set_bit(long nr, volatile unsigned long *addr)
|
||||
{
|
||||
return GEN_BINARY_RMWcc(LOCK_PREFIX __ASM_SIZE(bts), *addr, c, "Ir", nr);
|
||||
}
|
||||
|
||||
static __always_inline bool
|
||||
arch_test_and_set_bit_lock(long nr, volatile unsigned long *addr)
|
||||
{
|
||||
return arch_test_and_set_bit(nr, addr);
|
||||
}
|
||||
|
||||
static __always_inline bool
|
||||
arch___test_and_set_bit(unsigned long nr, volatile unsigned long *addr)
|
||||
{
|
||||
bool oldbit;
|
||||
|
||||
asm(__ASM_SIZE(bts) " %2,%1"
|
||||
: "=@ccc" (oldbit)
|
||||
: ADDR, "Ir" (nr) : "memory");
|
||||
return oldbit;
|
||||
}
|
||||
|
||||
static __always_inline bool
|
||||
arch_test_and_clear_bit(long nr, volatile unsigned long *addr)
|
||||
{
|
||||
return GEN_BINARY_RMWcc(LOCK_PREFIX __ASM_SIZE(btr), *addr, c, "Ir", nr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: the operation is performed atomically with respect to
|
||||
* the local CPU, but not other CPUs. Portable code should not
|
||||
* rely on this behaviour.
|
||||
* KVM relies on this behaviour on x86 for modifying memory that is also
|
||||
* accessed from a hypervisor on the same CPU if running in a VM: don't change
|
||||
* this without also updating arch/x86/kernel/kvm.c
|
||||
*/
|
||||
static __always_inline bool
|
||||
arch___test_and_clear_bit(unsigned long nr, volatile unsigned long *addr)
|
||||
{
|
||||
bool oldbit;
|
||||
|
||||
asm volatile(__ASM_SIZE(btr) " %2,%1"
|
||||
: "=@ccc" (oldbit)
|
||||
: ADDR, "Ir" (nr) : "memory");
|
||||
return oldbit;
|
||||
}
|
||||
|
||||
static __always_inline bool
|
||||
arch___test_and_change_bit(unsigned long nr, volatile unsigned long *addr)
|
||||
{
|
||||
bool oldbit;
|
||||
|
||||
asm volatile(__ASM_SIZE(btc) " %2,%1"
|
||||
: "=@ccc" (oldbit)
|
||||
: ADDR, "Ir" (nr) : "memory");
|
||||
|
||||
return oldbit;
|
||||
}
|
||||
|
||||
static __always_inline bool
|
||||
arch_test_and_change_bit(long nr, volatile unsigned long *addr)
|
||||
{
|
||||
return GEN_BINARY_RMWcc(LOCK_PREFIX __ASM_SIZE(btc), *addr, c, "Ir", nr);
|
||||
}
|
||||
|
||||
static __always_inline bool constant_test_bit(long nr, const volatile unsigned long *addr)
|
||||
{
|
||||
return ((1UL << (nr & (BITS_PER_LONG-1))) &
|
||||
(addr[nr >> _BITOPS_LONG_SHIFT])) != 0;
|
||||
}
|
||||
|
||||
static __always_inline bool constant_test_bit_acquire(long nr, const volatile unsigned long *addr)
|
||||
{
|
||||
bool oldbit;
|
||||
|
||||
asm volatile("testb %2,%1"
|
||||
: "=@ccnz" (oldbit)
|
||||
: "m" (((unsigned char *)addr)[nr >> 3]),
|
||||
"i" (1 << (nr & 7))
|
||||
:"memory");
|
||||
|
||||
return oldbit;
|
||||
}
|
||||
|
||||
static __always_inline bool variable_test_bit(long nr, volatile const unsigned long *addr)
|
||||
{
|
||||
bool oldbit;
|
||||
|
||||
asm volatile(__ASM_SIZE(bt) " %2,%1"
|
||||
: "=@ccc" (oldbit)
|
||||
: "m" (*(unsigned long *)addr), "Ir" (nr) : "memory");
|
||||
|
||||
return oldbit;
|
||||
}
|
||||
|
||||
static __always_inline bool
|
||||
arch_test_bit(unsigned long nr, const volatile unsigned long *addr)
|
||||
{
|
||||
return __builtin_constant_p(nr) ? constant_test_bit(nr, addr) :
|
||||
variable_test_bit(nr, addr);
|
||||
}
|
||||
|
||||
static __always_inline bool
|
||||
arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr)
|
||||
{
|
||||
return __builtin_constant_p(nr) ? constant_test_bit_acquire(nr, addr) :
|
||||
variable_test_bit(nr, addr);
|
||||
}
|
||||
|
||||
static __always_inline __attribute_const__ unsigned long variable__ffs(unsigned long word)
|
||||
{
|
||||
asm("tzcnt %1,%0"
|
||||
: "=r" (word)
|
||||
: ASM_INPUT_RM (word));
|
||||
return word;
|
||||
}
|
||||
|
||||
/**
|
||||
* __ffs - find first set bit in word
|
||||
* @word: The word to search
|
||||
*
|
||||
* Undefined if no bit exists, so code should check against 0 first.
|
||||
*/
|
||||
#define __ffs(word) \
|
||||
(__builtin_constant_p(word) ? \
|
||||
(unsigned long)__builtin_ctzl(word) : \
|
||||
variable__ffs(word))
|
||||
|
||||
static __always_inline __attribute_const__ unsigned long variable_ffz(unsigned long word)
|
||||
{
|
||||
return variable__ffs(~word);
|
||||
}
|
||||
|
||||
/**
|
||||
* ffz - find first zero bit in word
|
||||
* @word: The word to search
|
||||
*
|
||||
* Undefined if no zero exists, so code should check against ~0UL first.
|
||||
*/
|
||||
#define ffz(word) \
|
||||
(__builtin_constant_p(word) ? \
|
||||
(unsigned long)__builtin_ctzl(~word) : \
|
||||
variable_ffz(word))
|
||||
|
||||
/*
|
||||
* __fls: find last set bit in word
|
||||
* @word: The word to search
|
||||
*
|
||||
* Undefined if no set bit exists, so code should check against 0 first.
|
||||
*/
|
||||
static __always_inline __attribute_const__ unsigned long __fls(unsigned long word)
|
||||
{
|
||||
if (__builtin_constant_p(word))
|
||||
return BITS_PER_LONG - 1 - __builtin_clzl(word);
|
||||
|
||||
asm("bsr %1,%0"
|
||||
: "=r" (word)
|
||||
: ASM_INPUT_RM (word));
|
||||
return word;
|
||||
}
|
||||
|
||||
#undef ADDR
|
||||
|
||||
#ifdef __KERNEL__
|
||||
static __always_inline __attribute_const__ int variable_ffs(int x)
|
||||
{
|
||||
int r;
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
/*
|
||||
* AMD64 says BSFL won't clobber the dest reg if x==0; Intel64 says the
|
||||
* dest reg is undefined if x==0, but their CPU architect says its
|
||||
* value is written to set it to the same as before, except that the
|
||||
* top 32 bits will be cleared.
|
||||
*
|
||||
* We cannot do this on 32 bits because at the very least some
|
||||
* 486 CPUs did not behave this way.
|
||||
*/
|
||||
asm("bsfl %1,%0"
|
||||
: "=r" (r)
|
||||
: ASM_INPUT_RM (x), "0" (-1));
|
||||
#elif defined(CONFIG_X86_CMOV)
|
||||
asm("bsfl %1,%0\n\t"
|
||||
"cmovzl %2,%0"
|
||||
: "=&r" (r) : "rm" (x), "r" (-1));
|
||||
#else
|
||||
asm("bsfl %1,%0\n\t"
|
||||
"jnz 1f\n\t"
|
||||
"movl $-1,%0\n"
|
||||
"1:" : "=r" (r) : "rm" (x));
|
||||
#endif
|
||||
return r + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ffs - find first set bit in word
|
||||
* @x: the word to search
|
||||
*
|
||||
* This is defined the same way as the libc and compiler builtin ffs
|
||||
* routines, therefore differs in spirit from the other bitops.
|
||||
*
|
||||
* ffs(value) returns 0 if value is 0 or the position of the first
|
||||
* set bit if value is nonzero. The first (least significant) bit
|
||||
* is at position 1.
|
||||
*/
|
||||
#define ffs(x) (__builtin_constant_p(x) ? __builtin_ffs(x) : variable_ffs(x))
|
||||
|
||||
/**
|
||||
* fls - find last set bit in word
|
||||
* @x: the word to search
|
||||
*
|
||||
* This is defined in a similar way as the libc and compiler builtin
|
||||
* ffs, but returns the position of the most significant set bit.
|
||||
*
|
||||
* fls(value) returns 0 if value is 0 or the position of the last
|
||||
* set bit if value is nonzero. The last (most significant) bit is
|
||||
* at position 32.
|
||||
*/
|
||||
static __always_inline __attribute_const__ int fls(unsigned int x)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (__builtin_constant_p(x))
|
||||
return x ? 32 - __builtin_clz(x) : 0;
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
/*
|
||||
* AMD64 says BSRL won't clobber the dest reg if x==0; Intel64 says the
|
||||
* dest reg is undefined if x==0, but their CPU architect says its
|
||||
* value is written to set it to the same as before, except that the
|
||||
* top 32 bits will be cleared.
|
||||
*
|
||||
* We cannot do this on 32 bits because at the very least some
|
||||
* 486 CPUs did not behave this way.
|
||||
*/
|
||||
asm("bsrl %1,%0"
|
||||
: "=r" (r)
|
||||
: ASM_INPUT_RM (x), "0" (-1));
|
||||
#elif defined(CONFIG_X86_CMOV)
|
||||
asm("bsrl %1,%0\n\t"
|
||||
"cmovzl %2,%0"
|
||||
: "=&r" (r) : "rm" (x), "rm" (-1));
|
||||
#else
|
||||
asm("bsrl %1,%0\n\t"
|
||||
"jnz 1f\n\t"
|
||||
"movl $-1,%0\n"
|
||||
"1:" : "=r" (r) : "rm" (x));
|
||||
#endif
|
||||
return r + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* fls64 - find last set bit in a 64-bit word
|
||||
* @x: the word to search
|
||||
*
|
||||
* This is defined in a similar way as the libc and compiler builtin
|
||||
* ffsll, but returns the position of the most significant set bit.
|
||||
*
|
||||
* fls64(value) returns 0 if value is 0 or the position of the last
|
||||
* set bit if value is nonzero. The last (most significant) bit is
|
||||
* at position 64.
|
||||
*/
|
||||
#ifdef CONFIG_X86_64
|
||||
static __always_inline __attribute_const__ int fls64(__u64 x)
|
||||
{
|
||||
int bitpos = -1;
|
||||
|
||||
if (__builtin_constant_p(x))
|
||||
return x ? 64 - __builtin_clzll(x) : 0;
|
||||
/*
|
||||
* AMD64 says BSRQ won't clobber the dest reg if x==0; Intel64 says the
|
||||
* dest reg is undefined if x==0, but their CPU architect says its
|
||||
* value is written to set it to the same as before.
|
||||
*/
|
||||
asm("bsrq %1,%q0"
|
||||
: "+r" (bitpos)
|
||||
: ASM_INPUT_RM (x));
|
||||
return bitpos + 1;
|
||||
}
|
||||
#else
|
||||
#include <asm-generic/bitops/fls64.h>
|
||||
#endif
|
||||
|
||||
#include <asm-generic/bitops/sched.h>
|
||||
|
||||
#include <asm/arch_hweight.h>
|
||||
|
||||
#include <asm-generic/bitops/const_hweight.h>
|
||||
|
||||
#include <asm-generic/bitops/instrumented-atomic.h>
|
||||
#include <asm-generic/bitops/instrumented-non-atomic.h>
|
||||
#include <asm-generic/bitops/instrumented-lock.h>
|
||||
|
||||
#include <asm-generic/bitops/le.h>
|
||||
|
||||
#include <asm-generic/bitops/ext2-atomic-setbit.h>
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* _ASM_X86_BITOPS_H */
|
||||
@@ -0,0 +1,100 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_BOOT_H
|
||||
#define _ASM_X86_BOOT_H
|
||||
|
||||
|
||||
#include <asm/pgtable_types.h>
|
||||
#include <uapi/asm/boot.h>
|
||||
|
||||
/* Minimum kernel alignment, as a power of two */
|
||||
#ifdef CONFIG_X86_64
|
||||
# define MIN_KERNEL_ALIGN_LG2 PMD_SHIFT
|
||||
#else
|
||||
# define MIN_KERNEL_ALIGN_LG2 (PAGE_SHIFT + THREAD_SIZE_ORDER)
|
||||
#endif
|
||||
#define MIN_KERNEL_ALIGN (_AC(1, UL) << MIN_KERNEL_ALIGN_LG2)
|
||||
|
||||
#if (CONFIG_PHYSICAL_ALIGN & (CONFIG_PHYSICAL_ALIGN-1)) || \
|
||||
(CONFIG_PHYSICAL_ALIGN < MIN_KERNEL_ALIGN)
|
||||
# error "Invalid value for CONFIG_PHYSICAL_ALIGN"
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_KERNEL_BZIP2)
|
||||
# define BOOT_HEAP_SIZE 0x400000
|
||||
#elif defined(CONFIG_KERNEL_ZSTD)
|
||||
/*
|
||||
* Zstd needs to allocate the ZSTD_DCtx in order to decompress the kernel.
|
||||
* The ZSTD_DCtx is ~160KB, so set the heap size to 192KB because it is a
|
||||
* round number and to allow some slack.
|
||||
*/
|
||||
# define BOOT_HEAP_SIZE 0x30000
|
||||
#else
|
||||
# define BOOT_HEAP_SIZE 0x10000
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
# define BOOT_STACK_SIZE 0x4000
|
||||
|
||||
/*
|
||||
* Used by decompressor's startup_32() to allocate page tables for identity
|
||||
* mapping of the 4G of RAM in 4-level paging mode:
|
||||
* - 1 level4 table;
|
||||
* - 1 level3 table;
|
||||
* - 4 level2 table that maps everything with 2M pages;
|
||||
*
|
||||
* The additional level5 table needed for 5-level paging is allocated from
|
||||
* trampoline_32bit memory.
|
||||
*/
|
||||
# define BOOT_INIT_PGT_SIZE (6*4096)
|
||||
|
||||
/*
|
||||
* Total number of page tables kernel_add_identity_map() can allocate,
|
||||
* including page tables consumed by startup_32().
|
||||
*
|
||||
* Worst-case scenario:
|
||||
* - 5-level paging needs 1 level5 table;
|
||||
* - KASLR needs to map kernel, boot_params, cmdline and randomized kernel,
|
||||
* assuming all of them cross 256T boundary:
|
||||
* + 4*2 level4 table;
|
||||
* + 4*2 level3 table;
|
||||
* + 4*2 level2 table;
|
||||
* - X86_VERBOSE_BOOTUP needs to map the first 2M (video RAM):
|
||||
* + 1 level4 table;
|
||||
* + 1 level3 table;
|
||||
* + 1 level2 table;
|
||||
* Total: 28 tables
|
||||
*
|
||||
* Add 4 spare table in case decompressor touches anything beyond what is
|
||||
* accounted above. Warn if it happens.
|
||||
*/
|
||||
# define BOOT_PGT_SIZE_WARN (28*4096)
|
||||
# define BOOT_PGT_SIZE (32*4096)
|
||||
|
||||
#else /* !CONFIG_X86_64 */
|
||||
# define BOOT_STACK_SIZE 0x1000
|
||||
#endif
|
||||
|
||||
#define TRAMPOLINE_32BIT_SIZE (2 * PAGE_SIZE)
|
||||
|
||||
#define TRAMPOLINE_32BIT_CODE_OFFSET PAGE_SIZE
|
||||
#define TRAMPOLINE_32BIT_CODE_SIZE 0xA0
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
extern unsigned int output_len;
|
||||
extern const unsigned long kernel_text_size;
|
||||
extern const unsigned long kernel_inittext_offset;
|
||||
extern const unsigned long kernel_inittext_size;
|
||||
extern const unsigned long kernel_total_size;
|
||||
|
||||
unsigned long decompress_kernel(unsigned char *outbuf, unsigned long virt_addr,
|
||||
void (*error)(char *x));
|
||||
|
||||
extern struct boot_params *boot_params_ptr;
|
||||
extern unsigned long *trampoline_32bit;
|
||||
extern const u16 trampoline_ljmp_imm_offset;
|
||||
|
||||
void trampoline_32bit_src(void *trampoline, bool enable_5lvl);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_X86_BOOT_H */
|
||||
@@ -0,0 +1,91 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_BOOTPARAM_UTILS_H
|
||||
#define _ASM_X86_BOOTPARAM_UTILS_H
|
||||
|
||||
#include <asm/bootparam.h>
|
||||
|
||||
/*
|
||||
* This file is included from multiple environments. Do not
|
||||
* add completing #includes to make it standalone.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Deal with bootloaders which fail to initialize unknown fields in
|
||||
* boot_params to zero. The list fields in this list are taken from
|
||||
* analysis of kexec-tools; if other broken bootloaders initialize a
|
||||
* different set of fields we will need to figure out how to disambiguate.
|
||||
*
|
||||
* Note: efi_info is commonly left uninitialized, but that field has a
|
||||
* private magic, so it is better to leave it unchanged.
|
||||
*/
|
||||
|
||||
#define sizeof_mbr(type, member) ({ sizeof(((type *)0)->member); })
|
||||
|
||||
#define BOOT_PARAM_PRESERVE(struct_member) \
|
||||
{ \
|
||||
.start = offsetof(struct boot_params, struct_member), \
|
||||
.len = sizeof_mbr(struct boot_params, struct_member), \
|
||||
}
|
||||
|
||||
struct boot_params_to_save {
|
||||
unsigned int start;
|
||||
unsigned int len;
|
||||
};
|
||||
|
||||
static void sanitize_boot_params(struct boot_params *boot_params)
|
||||
{
|
||||
/*
|
||||
* IMPORTANT NOTE TO BOOTLOADER AUTHORS: do not simply clear
|
||||
* this field. The purpose of this field is to guarantee
|
||||
* compliance with the x86 boot spec located in
|
||||
* Documentation/arch/x86/boot.rst . That spec says that the
|
||||
* *whole* structure should be cleared, after which only the
|
||||
* portion defined by struct setup_header (boot_params->hdr)
|
||||
* should be copied in.
|
||||
*
|
||||
* If you're having an issue because the sentinel is set, you
|
||||
* need to change the whole structure to be cleared, not this
|
||||
* (or any other) individual field, or you will soon have
|
||||
* problems again.
|
||||
*/
|
||||
if (boot_params->sentinel) {
|
||||
static struct boot_params scratch;
|
||||
char *bp_base = (char *)boot_params;
|
||||
char *save_base = (char *)&scratch;
|
||||
int i;
|
||||
|
||||
const struct boot_params_to_save to_save[] = {
|
||||
BOOT_PARAM_PRESERVE(screen_info),
|
||||
BOOT_PARAM_PRESERVE(apm_bios_info),
|
||||
BOOT_PARAM_PRESERVE(tboot_addr),
|
||||
BOOT_PARAM_PRESERVE(ist_info),
|
||||
BOOT_PARAM_PRESERVE(hd0_info),
|
||||
BOOT_PARAM_PRESERVE(hd1_info),
|
||||
BOOT_PARAM_PRESERVE(sys_desc_table),
|
||||
BOOT_PARAM_PRESERVE(olpc_ofw_header),
|
||||
BOOT_PARAM_PRESERVE(efi_info),
|
||||
BOOT_PARAM_PRESERVE(alt_mem_k),
|
||||
BOOT_PARAM_PRESERVE(scratch),
|
||||
BOOT_PARAM_PRESERVE(e820_entries),
|
||||
BOOT_PARAM_PRESERVE(eddbuf_entries),
|
||||
BOOT_PARAM_PRESERVE(edd_mbr_sig_buf_entries),
|
||||
BOOT_PARAM_PRESERVE(edd_mbr_sig_buffer),
|
||||
BOOT_PARAM_PRESERVE(secure_boot),
|
||||
BOOT_PARAM_PRESERVE(hdr),
|
||||
BOOT_PARAM_PRESERVE(e820_table),
|
||||
BOOT_PARAM_PRESERVE(eddbuf),
|
||||
BOOT_PARAM_PRESERVE(cc_blob_address),
|
||||
};
|
||||
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(to_save); i++) {
|
||||
memcpy(save_base + to_save[i].start,
|
||||
bp_base + to_save[i].start, to_save[i].len);
|
||||
}
|
||||
|
||||
memcpy(boot_params, save_base, sizeof(*boot_params));
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _ASM_X86_BOOTPARAM_UTILS_H */
|
||||
@@ -0,0 +1,195 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_BUG_H
|
||||
#define _ASM_X86_BUG_H
|
||||
|
||||
#include <linux/stringify.h>
|
||||
#include <linux/instrumentation.h>
|
||||
#include <linux/objtool.h>
|
||||
#include <asm/asm.h>
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
struct bug_entry;
|
||||
extern void __WARN_trap(struct bug_entry *bug, ...);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Despite that some emulators terminate on UD2, we use it for WARN().
|
||||
*/
|
||||
#define ASM_UD2 __ASM_FORM(ud2)
|
||||
#define INSN_UD2 0x0b0f
|
||||
#define LEN_UD2 2
|
||||
|
||||
#define ASM_UDB _ASM_BYTES(0xd6)
|
||||
#define INSN_UDB 0xd6
|
||||
#define LEN_UDB 1
|
||||
|
||||
/*
|
||||
* In clang we have UD1s reporting UBSAN failures on X86, 64 and 32bit.
|
||||
*/
|
||||
#define INSN_ASOP 0x67
|
||||
#define INSN_LOCK 0xf0
|
||||
#define OPCODE_ESCAPE 0x0f
|
||||
#define SECOND_BYTE_OPCODE_UD1 0xb9
|
||||
#define SECOND_BYTE_OPCODE_UD2 0x0b
|
||||
|
||||
#define BUG_NONE 0xffff
|
||||
#define BUG_UD2 0xfffe
|
||||
#define BUG_UD1 0xfffd
|
||||
#define BUG_UD1_UBSAN 0xfffc
|
||||
#define BUG_UD1_WARN 0xfffb
|
||||
#define BUG_UDB 0xffd6
|
||||
#define BUG_LOCK 0xfff0
|
||||
|
||||
#ifdef CONFIG_GENERIC_BUG
|
||||
|
||||
#ifdef CONFIG_DEBUG_BUGVERBOSE
|
||||
#define __BUG_ENTRY_VERBOSE(file, line) \
|
||||
"\t.long " file " - .\t# bug_entry::file\n" \
|
||||
"\t.word " line "\t# bug_entry::line\n"
|
||||
#else
|
||||
#define __BUG_ENTRY_VERBOSE(file, line)
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_X86_64) || defined(CONFIG_DEBUG_BUGVERBOSE_DETAILED)
|
||||
#define HAVE_ARCH_BUG_FORMAT
|
||||
#define __BUG_ENTRY_FORMAT(format) \
|
||||
"\t.long " format " - .\t# bug_entry::format\n"
|
||||
#else
|
||||
#define __BUG_ENTRY_FORMAT(format)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
#define HAVE_ARCH_BUG_FORMAT_ARGS
|
||||
#endif
|
||||
|
||||
#define __BUG_ENTRY(format, file, line, flags) \
|
||||
"\t.long 1b - ." "\t# bug_entry::bug_addr\n" \
|
||||
__BUG_ENTRY_FORMAT(format) \
|
||||
__BUG_ENTRY_VERBOSE(file, line) \
|
||||
"\t.word " flags "\t# bug_entry::flags\n"
|
||||
|
||||
#define _BUG_FLAGS_ASM(format, file, line, flags, size, extra) \
|
||||
".pushsection __bug_table,\"aw\"\n\t" \
|
||||
ANNOTATE_DATA_SPECIAL "\n\t" \
|
||||
"2:\n\t" \
|
||||
__BUG_ENTRY(format, file, line, flags) \
|
||||
"\t.org 2b + " size "\n" \
|
||||
".popsection\n" \
|
||||
extra
|
||||
|
||||
#ifdef CONFIG_DEBUG_BUGVERBOSE_DETAILED
|
||||
#define WARN_CONDITION_STR(cond_str) cond_str
|
||||
#else
|
||||
#define WARN_CONDITION_STR(cond_str) ""
|
||||
#endif
|
||||
|
||||
#define _BUG_FLAGS(cond_str, ins, flags, extra) \
|
||||
do { \
|
||||
asm_inline volatile("1:\t" ins "\n" \
|
||||
_BUG_FLAGS_ASM("%c[fmt]", "%c[file]", \
|
||||
"%c[line]", "%c[fl]", \
|
||||
"%c[size]", extra) \
|
||||
: : [fmt] "i" (WARN_CONDITION_STR(cond_str)), \
|
||||
[file] "i" (__FILE__), \
|
||||
[line] "i" (__LINE__), \
|
||||
[fl] "i" (flags), \
|
||||
[size] "i" (sizeof(struct bug_entry))); \
|
||||
} while (0)
|
||||
|
||||
#define ARCH_WARN_ASM(file, line, flags, size) \
|
||||
".pushsection .rodata.str1.1, \"aMS\", @progbits, 1\n" \
|
||||
"99:\n" \
|
||||
"\t.string \"\"\n" \
|
||||
".popsection\n" \
|
||||
"1:\t " ASM_UD2 "\n" \
|
||||
_BUG_FLAGS_ASM("99b", file, line, flags, size, "")
|
||||
|
||||
#else
|
||||
|
||||
#define _BUG_FLAGS(cond_str, ins, flags, extra) asm volatile(ins)
|
||||
|
||||
#endif /* CONFIG_GENERIC_BUG */
|
||||
|
||||
#define HAVE_ARCH_BUG
|
||||
#define BUG() \
|
||||
do { \
|
||||
instrumentation_begin(); \
|
||||
_BUG_FLAGS("", ASM_UD2, 0, ""); \
|
||||
__builtin_unreachable(); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* This instrumentation_begin() is strictly speaking incorrect; but it
|
||||
* suppresses the complaints from WARN()s in noinstr code. If such a WARN()
|
||||
* were to trigger, we'd rather wreck the machine in an attempt to get the
|
||||
* message out than not know about it.
|
||||
*/
|
||||
|
||||
#define ARCH_WARN_REACHABLE ANNOTATE_REACHABLE(1b)
|
||||
|
||||
#define __WARN_FLAGS(cond_str, flags) \
|
||||
do { \
|
||||
auto __flags = BUGFLAG_WARNING|(flags); \
|
||||
instrumentation_begin(); \
|
||||
_BUG_FLAGS(cond_str, ASM_UD2, __flags, ARCH_WARN_REACHABLE); \
|
||||
instrumentation_end(); \
|
||||
} while (0)
|
||||
|
||||
#ifdef HAVE_ARCH_BUG_FORMAT_ARGS
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
#include <linux/static_call_types.h>
|
||||
DECLARE_STATIC_CALL(WARN_trap, __WARN_trap);
|
||||
|
||||
struct pt_regs;
|
||||
struct sysv_va_list { /* from AMD64 System V ABI */
|
||||
unsigned int gp_offset;
|
||||
unsigned int fp_offset;
|
||||
void *overflow_arg_area;
|
||||
void *reg_save_area;
|
||||
};
|
||||
struct arch_va_list {
|
||||
unsigned long regs[6];
|
||||
struct sysv_va_list args;
|
||||
};
|
||||
extern void *__warn_args(struct arch_va_list *args, struct pt_regs *regs);
|
||||
#endif /* __ASSEMBLER__ */
|
||||
|
||||
#define __WARN_bug_entry(flags, format) ({ \
|
||||
struct bug_entry *bug; \
|
||||
asm_inline volatile("lea (2f)(%%rip), %[addr]\n1:\n" \
|
||||
_BUG_FLAGS_ASM("%c[fmt]", "%c[file]", \
|
||||
"%c[line]", "%c[fl]", \
|
||||
"%c[size]", "") \
|
||||
: [addr] "=r" (bug) \
|
||||
: [fmt] "i" (format), \
|
||||
[file] "i" (__FILE__), \
|
||||
[line] "i" (__LINE__), \
|
||||
[fl] "i" (flags), \
|
||||
[size] "i" (sizeof(struct bug_entry))); \
|
||||
bug; })
|
||||
|
||||
#define __WARN_print_arg(flags, format, arg...) \
|
||||
do { \
|
||||
int __flags = (flags) | BUGFLAG_WARNING | BUGFLAG_ARGS ; \
|
||||
static_call_mod(WARN_trap)(__WARN_bug_entry(__flags, format), ## arg); \
|
||||
asm (""); /* inhibit tail-call optimization */ \
|
||||
} while (0)
|
||||
|
||||
#define __WARN_printf(taint, fmt, arg...) \
|
||||
__WARN_print_arg(BUGFLAG_TAINT(taint), fmt, ## arg)
|
||||
|
||||
#define WARN_ONCE(cond, format, arg...) ({ \
|
||||
int __ret_warn_on = !!(cond); \
|
||||
if (unlikely(__ret_warn_on)) { \
|
||||
__WARN_print_arg(BUGFLAG_ONCE|BUGFLAG_TAINT(TAINT_WARN),\
|
||||
format, ## arg); \
|
||||
} \
|
||||
__ret_warn_on; \
|
||||
})
|
||||
|
||||
#endif /* HAVE_ARCH_BUG_FORMAT_ARGS */
|
||||
|
||||
#include <asm-generic/bug.h>
|
||||
|
||||
#endif /* _ASM_X86_BUG_H */
|
||||
@@ -0,0 +1,15 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_BUGS_H
|
||||
#define _ASM_X86_BUGS_H
|
||||
|
||||
#include <asm/processor.h>
|
||||
|
||||
#if defined(CONFIG_CPU_SUP_INTEL) && defined(CONFIG_X86_32)
|
||||
int ppro_with_ram_bug(void);
|
||||
#else
|
||||
static inline int ppro_with_ram_bug(void) { return 0; }
|
||||
#endif
|
||||
|
||||
extern void cpu_bugs_smt_update(void);
|
||||
|
||||
#endif /* _ASM_X86_BUGS_H */
|
||||
@@ -0,0 +1,24 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_CACHE_H
|
||||
#define _ASM_X86_CACHE_H
|
||||
|
||||
#include <linux/linkage.h>
|
||||
|
||||
/* L1 cache line size */
|
||||
#define L1_CACHE_SHIFT (CONFIG_X86_L1_CACHE_SHIFT)
|
||||
#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
|
||||
|
||||
#define __read_mostly __section(".data..read_mostly")
|
||||
|
||||
#define INTERNODE_CACHE_SHIFT CONFIG_X86_INTERNODE_CACHE_SHIFT
|
||||
#define INTERNODE_CACHE_BYTES (1 << INTERNODE_CACHE_SHIFT)
|
||||
|
||||
#ifdef CONFIG_X86_VSMP
|
||||
#ifdef CONFIG_SMP
|
||||
#define __cacheline_aligned_in_smp \
|
||||
__attribute__((__aligned__(INTERNODE_CACHE_BYTES))) \
|
||||
__page_aligned_data
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_X86_CACHE_H */
|
||||
@@ -0,0 +1,13 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_CACHEFLUSH_H
|
||||
#define _ASM_X86_CACHEFLUSH_H
|
||||
|
||||
#include <linux/mm.h>
|
||||
|
||||
/* Caches aren't brain-dead on the intel. */
|
||||
#include <asm-generic/cacheflush.h>
|
||||
#include <asm/special_insns.h>
|
||||
|
||||
void clflush_cache_range(void *addr, unsigned int size);
|
||||
|
||||
#endif /* _ASM_X86_CACHEFLUSH_H */
|
||||
@@ -0,0 +1,18 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_CACHEINFO_H
|
||||
#define _ASM_X86_CACHEINFO_H
|
||||
|
||||
/* Kernel controls MTRR and/or PAT MSRs. */
|
||||
extern unsigned int memory_caching_control;
|
||||
#define CACHE_MTRR 0x01
|
||||
#define CACHE_PAT 0x02
|
||||
|
||||
void cache_disable(void);
|
||||
void cache_enable(void);
|
||||
void set_cache_aps_delayed_init(bool val);
|
||||
bool get_cache_aps_delayed_init(void);
|
||||
void cache_bp_init(void);
|
||||
void cache_bp_restore(void);
|
||||
void cache_aps_init(void);
|
||||
|
||||
#endif /* _ASM_X86_CACHEINFO_H */
|
||||
@@ -0,0 +1,13 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_CE4100_H_
|
||||
#define _ASM_CE4100_H_
|
||||
|
||||
int ce4100_pci_init(void);
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250
|
||||
void __init sdv_serial_fixup(void);
|
||||
#else
|
||||
static inline void sdv_serial_fixup(void) {};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,168 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_CFI_H
|
||||
#define _ASM_X86_CFI_H
|
||||
|
||||
/*
|
||||
* Clang Control Flow Integrity (CFI) support.
|
||||
*
|
||||
* Copyright (C) 2022 Google LLC
|
||||
*/
|
||||
#include <linux/bug.h>
|
||||
#include <asm/ibt.h>
|
||||
|
||||
/*
|
||||
* An overview of the various calling conventions...
|
||||
*
|
||||
* Traditional:
|
||||
*
|
||||
* foo:
|
||||
* ... code here ...
|
||||
* ret
|
||||
*
|
||||
* direct caller:
|
||||
* call foo
|
||||
*
|
||||
* indirect caller:
|
||||
* lea foo(%rip), %r11
|
||||
* ...
|
||||
* call *%r11
|
||||
*
|
||||
*
|
||||
* IBT:
|
||||
*
|
||||
* foo:
|
||||
* endbr64
|
||||
* ... code here ...
|
||||
* ret
|
||||
*
|
||||
* direct caller:
|
||||
* call foo / call foo+4
|
||||
*
|
||||
* indirect caller:
|
||||
* lea foo(%rip), %r11
|
||||
* ...
|
||||
* call *%r11
|
||||
*
|
||||
*
|
||||
* kCFI:
|
||||
*
|
||||
* __cfi_foo:
|
||||
* movl $0x12345678, %eax
|
||||
* # 11 nops when CONFIG_CALL_PADDING
|
||||
* foo:
|
||||
* endbr64 # when IBT
|
||||
* ... code here ...
|
||||
* ret
|
||||
*
|
||||
* direct call:
|
||||
* call foo # / call foo+4 when IBT
|
||||
*
|
||||
* indirect call:
|
||||
* lea foo(%rip), %r11
|
||||
* ...
|
||||
* movl $(-0x12345678), %r10d
|
||||
* addl -4(%r11), %r10d # -15 when CONFIG_CALL_PADDING
|
||||
* jz 1f
|
||||
* ud2
|
||||
* 1:call *%r11
|
||||
*
|
||||
*
|
||||
* FineIBT (builds as kCFI + CALL_PADDING + IBT + RETPOLINE and runtime patches into):
|
||||
*
|
||||
* __cfi_foo:
|
||||
* endbr64
|
||||
* subl 0x12345678, %eax
|
||||
* jne.32,pn foo+3
|
||||
* foo:
|
||||
* nopl -42(%rax) # was endbr64
|
||||
* ... code here ...
|
||||
* ret
|
||||
*
|
||||
* direct caller:
|
||||
* call foo / call foo+4
|
||||
*
|
||||
* indirect caller:
|
||||
* lea foo(%rip), %r11
|
||||
* ...
|
||||
* movl $0x12345678, %eax
|
||||
* lea -0x10(%r11), %r11
|
||||
* nop5
|
||||
* call *%r11
|
||||
*
|
||||
*/
|
||||
enum cfi_mode {
|
||||
CFI_AUTO, /* FineIBT if hardware has IBT, otherwise kCFI */
|
||||
CFI_OFF, /* Taditional / IBT depending on .config */
|
||||
CFI_KCFI, /* Optionally CALL_PADDING, IBT, RETPOLINE */
|
||||
CFI_FINEIBT, /* see arch/x86/kernel/alternative.c */
|
||||
};
|
||||
|
||||
extern enum cfi_mode cfi_mode;
|
||||
|
||||
#ifdef CONFIG_FINEIBT_BHI
|
||||
extern bool cfi_bhi;
|
||||
#else
|
||||
#define cfi_bhi (0)
|
||||
#endif
|
||||
|
||||
typedef u8 bhi_thunk[32];
|
||||
extern bhi_thunk __bhi_args[];
|
||||
extern bhi_thunk __bhi_args_end[];
|
||||
|
||||
struct pt_regs;
|
||||
|
||||
#ifdef CONFIG_CALL_PADDING
|
||||
#define CFI_OFFSET (CONFIG_FUNCTION_PADDING_CFI+5)
|
||||
#else
|
||||
#define CFI_OFFSET 5
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CFI
|
||||
enum bug_trap_type handle_cfi_failure(struct pt_regs *regs);
|
||||
#define __bpfcall
|
||||
|
||||
static inline int cfi_get_offset(void)
|
||||
{
|
||||
switch (cfi_mode) {
|
||||
case CFI_FINEIBT:
|
||||
return /* fineibt_prefix_size */ 16;
|
||||
case CFI_KCFI:
|
||||
return CFI_OFFSET;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#define cfi_get_offset cfi_get_offset
|
||||
|
||||
extern u32 cfi_get_func_hash(void *func);
|
||||
#define cfi_get_func_hash cfi_get_func_hash
|
||||
|
||||
extern int cfi_get_func_arity(void *func);
|
||||
|
||||
#ifdef CONFIG_FINEIBT
|
||||
extern bool decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type);
|
||||
#else
|
||||
static inline bool
|
||||
decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
static inline enum bug_trap_type handle_cfi_failure(struct pt_regs *regs)
|
||||
{
|
||||
return BUG_TRAP_TYPE_NONE;
|
||||
}
|
||||
static inline int cfi_get_func_arity(void *func)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_CFI */
|
||||
|
||||
#if HAS_KERNEL_IBT == 1
|
||||
#define CFI_NOSEAL(x) asm(IBT_NOSEAL(__stringify(x)))
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_X86_CFI_H */
|
||||
@@ -0,0 +1,13 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifdef CONFIG_GENERIC_CSUM
|
||||
# include <asm-generic/checksum.h>
|
||||
#else
|
||||
# define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER 1
|
||||
# define HAVE_CSUM_COPY_USER
|
||||
# define _HAVE_ARCH_CSUM_AND_COPY
|
||||
# ifdef CONFIG_X86_32
|
||||
# include <asm/checksum_32.h>
|
||||
# else
|
||||
# include <asm/checksum_64.h>
|
||||
# endif
|
||||
#endif
|
||||
@@ -0,0 +1,186 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_CHECKSUM_32_H
|
||||
#define _ASM_X86_CHECKSUM_32_H
|
||||
|
||||
#include <linux/in6.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
/*
|
||||
* computes the checksum of a memory block at buff, length len,
|
||||
* and adds in "sum" (32-bit)
|
||||
*
|
||||
* returns a 32-bit number suitable for feeding into itself
|
||||
* or csum_tcpudp_magic
|
||||
*
|
||||
* this function must be called with even lengths, except
|
||||
* for the last fragment, which may be odd
|
||||
*
|
||||
* it's best to have buff aligned on a 32-bit boundary
|
||||
*/
|
||||
asmlinkage __wsum csum_partial(const void *buff, int len, __wsum sum);
|
||||
|
||||
/*
|
||||
* the same as csum_partial, but copies from src while it
|
||||
* checksums, and handles user-space pointer exceptions correctly, when needed.
|
||||
*
|
||||
* here even more important to align src and dst on a 32-bit (or even
|
||||
* better 64-bit) boundary
|
||||
*/
|
||||
|
||||
asmlinkage __wsum csum_partial_copy_generic(const void *src, void *dst, int len);
|
||||
|
||||
/*
|
||||
* Note: when you get a NULL pointer exception here this means someone
|
||||
* passed in an incorrect kernel address to one of these functions.
|
||||
*
|
||||
* If you use these functions directly please don't forget the
|
||||
* access_ok().
|
||||
*/
|
||||
static inline __wsum csum_partial_copy_nocheck(const void *src, void *dst, int len)
|
||||
{
|
||||
return csum_partial_copy_generic(src, dst, len);
|
||||
}
|
||||
|
||||
static inline __wsum csum_and_copy_from_user(const void __user *src,
|
||||
void *dst, int len)
|
||||
{
|
||||
__wsum ret;
|
||||
|
||||
might_sleep();
|
||||
if (!user_access_begin(src, len))
|
||||
return 0;
|
||||
ret = csum_partial_copy_generic((__force void *)src, dst, len);
|
||||
user_access_end();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a version of ip_compute_csum() optimized for IP headers,
|
||||
* which always checksum on 4 octet boundaries.
|
||||
*
|
||||
* By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
|
||||
* Arnt Gulbrandsen.
|
||||
*/
|
||||
static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
|
||||
{
|
||||
unsigned int sum;
|
||||
|
||||
asm volatile("movl (%1), %0 ;\n"
|
||||
"subl $4, %2 ;\n"
|
||||
"jbe 2f ;\n"
|
||||
"addl 4(%1), %0 ;\n"
|
||||
"adcl 8(%1), %0 ;\n"
|
||||
"adcl 12(%1), %0;\n"
|
||||
"1: adcl 16(%1), %0 ;\n"
|
||||
"lea 4(%1), %1 ;\n"
|
||||
"decl %2 ;\n"
|
||||
"jne 1b ;\n"
|
||||
"adcl $0, %0 ;\n"
|
||||
"movl %0, %2 ;\n"
|
||||
"shrl $16, %0 ;\n"
|
||||
"addw %w2, %w0 ;\n"
|
||||
"adcl $0, %0 ;\n"
|
||||
"notl %0 ;\n"
|
||||
"2: ;\n"
|
||||
/* Since the input registers which are loaded with iph and ihl
|
||||
are modified, we must also specify them as outputs, or gcc
|
||||
will assume they contain their original values. */
|
||||
: "=r" (sum), "=r" (iph), "=r" (ihl)
|
||||
: "1" (iph), "2" (ihl)
|
||||
: "memory");
|
||||
return (__force __sum16)sum;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fold a partial checksum
|
||||
*/
|
||||
|
||||
static inline __sum16 csum_fold(__wsum sum)
|
||||
{
|
||||
asm("addl %1, %0 ;\n"
|
||||
"adcl $0xffff, %0 ;\n"
|
||||
: "=r" (sum)
|
||||
: "r" ((__force u32)sum << 16),
|
||||
"0" ((__force u32)sum & 0xffff0000));
|
||||
return (__force __sum16)(~(__force u32)sum >> 16);
|
||||
}
|
||||
|
||||
static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
|
||||
__u32 len, __u8 proto,
|
||||
__wsum sum)
|
||||
{
|
||||
asm("addl %1, %0 ;\n"
|
||||
"adcl %2, %0 ;\n"
|
||||
"adcl %3, %0 ;\n"
|
||||
"adcl $0, %0 ;\n"
|
||||
: "=r" (sum)
|
||||
: "g" (daddr), "g"(saddr),
|
||||
"g" ((len + proto) << 8), "0" (sum));
|
||||
return sum;
|
||||
}
|
||||
|
||||
/*
|
||||
* computes the checksum of the TCP/UDP pseudo-header
|
||||
* returns a 16-bit checksum, already complemented
|
||||
*/
|
||||
static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
|
||||
__u32 len, __u8 proto,
|
||||
__wsum sum)
|
||||
{
|
||||
return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
|
||||
}
|
||||
|
||||
/*
|
||||
* this routine is used for miscellaneous IP-like checksums, mainly
|
||||
* in icmp.c
|
||||
*/
|
||||
|
||||
static inline __sum16 ip_compute_csum(const void *buff, int len)
|
||||
{
|
||||
return csum_fold(csum_partial(buff, len, 0));
|
||||
}
|
||||
|
||||
#define _HAVE_ARCH_IPV6_CSUM
|
||||
static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
|
||||
const struct in6_addr *daddr,
|
||||
__u32 len, __u8 proto, __wsum sum)
|
||||
{
|
||||
asm("addl 0(%1), %0 ;\n"
|
||||
"adcl 4(%1), %0 ;\n"
|
||||
"adcl 8(%1), %0 ;\n"
|
||||
"adcl 12(%1), %0 ;\n"
|
||||
"adcl 0(%2), %0 ;\n"
|
||||
"adcl 4(%2), %0 ;\n"
|
||||
"adcl 8(%2), %0 ;\n"
|
||||
"adcl 12(%2), %0 ;\n"
|
||||
"adcl %3, %0 ;\n"
|
||||
"adcl %4, %0 ;\n"
|
||||
"adcl $0, %0 ;\n"
|
||||
: "=&r" (sum)
|
||||
: "r" (saddr), "r" (daddr),
|
||||
"r" (htonl(len)), "r" (htonl(proto)), "0" (sum)
|
||||
: "memory");
|
||||
|
||||
return csum_fold(sum);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy and checksum to user
|
||||
*/
|
||||
static inline __wsum csum_and_copy_to_user(const void *src,
|
||||
void __user *dst,
|
||||
int len)
|
||||
{
|
||||
__wsum ret;
|
||||
|
||||
might_sleep();
|
||||
if (!user_access_begin(dst, len))
|
||||
return 0;
|
||||
|
||||
ret = csum_partial_copy_generic(src, (__force void *)dst, len);
|
||||
user_access_end();
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* _ASM_X86_CHECKSUM_32_H */
|
||||
@@ -0,0 +1,205 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_CHECKSUM_64_H
|
||||
#define _ASM_X86_CHECKSUM_64_H
|
||||
|
||||
/*
|
||||
* Checksums for x86-64
|
||||
* Copyright 2002 by Andi Kleen, SuSE Labs
|
||||
* with some code from asm-x86/checksum.h
|
||||
*/
|
||||
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/in6.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
/**
|
||||
* csum_fold - Fold and invert a 32bit checksum.
|
||||
* sum: 32bit unfolded sum
|
||||
*
|
||||
* Fold a 32bit running checksum to 16bit and invert it. This is usually
|
||||
* the last step before putting a checksum into a packet.
|
||||
* Make sure not to mix with 64bit checksums.
|
||||
*/
|
||||
static inline __sum16 csum_fold(__wsum sum)
|
||||
{
|
||||
asm(" addl %1,%0\n"
|
||||
" adcl $0xffff,%0"
|
||||
: "=r" (sum)
|
||||
: "r" ((__force u32)sum << 16),
|
||||
"0" ((__force u32)sum & 0xffff0000));
|
||||
return (__force __sum16)(~(__force u32)sum >> 16);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a version of ip_compute_csum() optimized for IP headers,
|
||||
* which always checksum on 4 octet boundaries.
|
||||
*
|
||||
* By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
|
||||
* Arnt Gulbrandsen.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ip_fast_csum - Compute the IPv4 header checksum efficiently.
|
||||
* iph: ipv4 header
|
||||
* ihl: length of header / 4
|
||||
*/
|
||||
static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
|
||||
{
|
||||
unsigned int sum;
|
||||
|
||||
asm(" movl (%1), %0\n"
|
||||
" subl $4, %2\n"
|
||||
" jbe 2f\n"
|
||||
" addl 4(%1), %0\n"
|
||||
" adcl 8(%1), %0\n"
|
||||
" adcl 12(%1), %0\n"
|
||||
"1: adcl 16(%1), %0\n"
|
||||
" lea 4(%1), %1\n"
|
||||
" decl %2\n"
|
||||
" jne 1b\n"
|
||||
" adcl $0, %0\n"
|
||||
" movl %0, %2\n"
|
||||
" shrl $16, %0\n"
|
||||
" addw %w2, %w0\n"
|
||||
" adcl $0, %0\n"
|
||||
" notl %0\n"
|
||||
"2:"
|
||||
/* Since the input registers which are loaded with iph and ihl
|
||||
are modified, we must also specify them as outputs, or gcc
|
||||
will assume they contain their original values. */
|
||||
: "=r" (sum), "=r" (iph), "=r" (ihl)
|
||||
: "1" (iph), "2" (ihl)
|
||||
: "memory");
|
||||
return (__force __sum16)sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* csum_tcpup_nofold - Compute an IPv4 pseudo header checksum.
|
||||
* @saddr: source address
|
||||
* @daddr: destination address
|
||||
* @len: length of packet
|
||||
* @proto: ip protocol of packet
|
||||
* @sum: initial sum to be added in (32bit unfolded)
|
||||
*
|
||||
* Returns the pseudo header checksum the input data. Result is
|
||||
* 32bit unfolded.
|
||||
*/
|
||||
static inline __wsum
|
||||
csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len,
|
||||
__u8 proto, __wsum sum)
|
||||
{
|
||||
asm(" addl %1, %0\n"
|
||||
" adcl %2, %0\n"
|
||||
" adcl %3, %0\n"
|
||||
" adcl $0, %0\n"
|
||||
: "=r" (sum)
|
||||
: "g" (daddr), "g" (saddr),
|
||||
"g" ((len + proto)<<8), "0" (sum));
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* csum_tcpup_magic - Compute an IPv4 pseudo header checksum.
|
||||
* @saddr: source address
|
||||
* @daddr: destination address
|
||||
* @len: length of packet
|
||||
* @proto: ip protocol of packet
|
||||
* @sum: initial sum to be added in (32bit unfolded)
|
||||
*
|
||||
* Returns the 16bit pseudo header checksum the input data already
|
||||
* complemented and ready to be filled in.
|
||||
*/
|
||||
static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
|
||||
__u32 len, __u8 proto,
|
||||
__wsum sum)
|
||||
{
|
||||
return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
|
||||
}
|
||||
|
||||
/**
|
||||
* csum_partial - Compute an internet checksum.
|
||||
* @buff: buffer to be checksummed
|
||||
* @len: length of buffer.
|
||||
* @sum: initial sum to be added in (32bit unfolded)
|
||||
*
|
||||
* Returns the 32bit unfolded internet checksum of the buffer.
|
||||
* Before filling it in it needs to be csum_fold()'ed.
|
||||
* buff should be aligned to a 64bit boundary if possible.
|
||||
*/
|
||||
extern __wsum csum_partial(const void *buff, int len, __wsum sum);
|
||||
|
||||
/* Do not call this directly. Use the wrappers below */
|
||||
extern __visible __wsum csum_partial_copy_generic(const void *src, void *dst, int len);
|
||||
|
||||
extern __wsum csum_and_copy_from_user(const void __user *src, void *dst, int len);
|
||||
extern __wsum csum_and_copy_to_user(const void *src, void __user *dst, int len);
|
||||
extern __wsum csum_partial_copy_nocheck(const void *src, void *dst, int len);
|
||||
|
||||
/**
|
||||
* ip_compute_csum - Compute an 16bit IP checksum.
|
||||
* @buff: buffer address.
|
||||
* @len: length of buffer.
|
||||
*
|
||||
* Returns the 16bit folded/inverted checksum of the passed buffer.
|
||||
* Ready to fill in.
|
||||
*/
|
||||
extern __sum16 ip_compute_csum(const void *buff, int len);
|
||||
|
||||
static inline unsigned add32_with_carry(unsigned a, unsigned b)
|
||||
{
|
||||
asm("addl %2,%0\n\t"
|
||||
"adcl $0,%0"
|
||||
: "=r" (a)
|
||||
: "0" (a), "rm" (b));
|
||||
return a;
|
||||
}
|
||||
|
||||
#define _HAVE_ARCH_IPV6_CSUM 1
|
||||
|
||||
/**
|
||||
* csum_ipv6_magic - Compute checksum of an IPv6 pseudo header.
|
||||
* @saddr: source address
|
||||
* @daddr: destination address
|
||||
* @len: length of packet
|
||||
* @proto: protocol of packet
|
||||
* @sum: initial sum (32bit unfolded) to be added in
|
||||
*
|
||||
* Computes an IPv6 pseudo header checksum. This sum is added the checksum
|
||||
* into UDP/TCP packets and contains some link layer information.
|
||||
* Returns the unfolded 32bit checksum.
|
||||
*/
|
||||
|
||||
static inline __sum16 csum_ipv6_magic(
|
||||
const struct in6_addr *_saddr, const struct in6_addr *_daddr,
|
||||
__u32 len, __u8 proto, __wsum sum)
|
||||
{
|
||||
const unsigned long *saddr = (const unsigned long *)_saddr;
|
||||
const unsigned long *daddr = (const unsigned long *)_daddr;
|
||||
__u64 sum64;
|
||||
|
||||
sum64 = (__force __u64)htonl(len) + (__force __u64)htons(proto) +
|
||||
(__force __u64)sum;
|
||||
|
||||
asm(" addq %1,%[sum64]\n"
|
||||
" adcq %2,%[sum64]\n"
|
||||
" adcq %3,%[sum64]\n"
|
||||
" adcq %4,%[sum64]\n"
|
||||
" adcq $0,%[sum64]\n"
|
||||
|
||||
: [sum64] "+r" (sum64)
|
||||
: "m" (saddr[0]), "m" (saddr[1]),
|
||||
"m" (daddr[0]), "m" (daddr[1]));
|
||||
|
||||
return csum_fold(
|
||||
(__force __wsum)add32_with_carry(sum64 & 0xffffffff, sum64>>32));
|
||||
}
|
||||
|
||||
#define HAVE_ARCH_CSUM_ADD
|
||||
static inline __wsum csum_add(__wsum csum, __wsum addend)
|
||||
{
|
||||
return (__force __wsum)add32_with_carry((__force unsigned)csum,
|
||||
(__force unsigned)addend);
|
||||
}
|
||||
|
||||
#endif /* _ASM_X86_CHECKSUM_64_H */
|
||||
@@ -0,0 +1,21 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* x86-specific clocksource additions */
|
||||
|
||||
#ifndef _ASM_X86_CLOCKSOURCE_H
|
||||
#define _ASM_X86_CLOCKSOURCE_H
|
||||
|
||||
#include <asm/vdso/clocksource.h>
|
||||
|
||||
extern unsigned int vclocks_used;
|
||||
|
||||
static inline bool vclock_was_used(int vclock)
|
||||
{
|
||||
return READ_ONCE(vclocks_used) & (1U << vclock);
|
||||
}
|
||||
|
||||
static inline void vclocks_set_used(unsigned int which)
|
||||
{
|
||||
WRITE_ONCE(vclocks_used, READ_ONCE(vclocks_used) | (1 << which));
|
||||
}
|
||||
|
||||
#endif /* _ASM_X86_CLOCKSOURCE_H */
|
||||
@@ -0,0 +1,13 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_CMDLINE_H
|
||||
#define _ASM_X86_CMDLINE_H
|
||||
|
||||
#include <asm/setup.h>
|
||||
|
||||
extern char builtin_cmdline[COMMAND_LINE_SIZE];
|
||||
|
||||
int cmdline_find_option_bool(const char *cmdline_ptr, const char *option);
|
||||
int cmdline_find_option(const char *cmdline_ptr, const char *option,
|
||||
char *buffer, int bufsize);
|
||||
|
||||
#endif /* _ASM_X86_CMDLINE_H */
|
||||
@@ -0,0 +1,244 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef ASM_X86_CMPXCHG_H
|
||||
#define ASM_X86_CMPXCHG_H
|
||||
|
||||
#include <linux/compiler.h>
|
||||
#include <asm/cpufeatures.h>
|
||||
#include <asm/alternative.h> /* Provides LOCK_PREFIX */
|
||||
|
||||
/*
|
||||
* Non-existent functions to indicate usage errors at link time
|
||||
* (or compile-time if the compiler implements __compiletime_error().
|
||||
*/
|
||||
extern void __xchg_wrong_size(void)
|
||||
__compiletime_error("Bad argument size for xchg");
|
||||
extern void __cmpxchg_wrong_size(void)
|
||||
__compiletime_error("Bad argument size for cmpxchg");
|
||||
extern void __xadd_wrong_size(void)
|
||||
__compiletime_error("Bad argument size for xadd");
|
||||
extern void __add_wrong_size(void)
|
||||
__compiletime_error("Bad argument size for add");
|
||||
|
||||
/*
|
||||
* Constants for operation sizes. On 32-bit, the 64-bit size it set to
|
||||
* -1 because sizeof will never return -1, thereby making those switch
|
||||
* case statements guaranteed dead code which the compiler will
|
||||
* eliminate, and allowing the "missing symbol in the default case" to
|
||||
* indicate a usage error.
|
||||
*/
|
||||
#define __X86_CASE_B 1
|
||||
#define __X86_CASE_W 2
|
||||
#define __X86_CASE_L 4
|
||||
#ifdef CONFIG_64BIT
|
||||
#define __X86_CASE_Q 8
|
||||
#else
|
||||
#define __X86_CASE_Q -1 /* sizeof will never return -1 */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* An exchange-type operation, which takes a value and a pointer, and
|
||||
* returns the old value.
|
||||
*/
|
||||
#define __xchg_op(ptr, arg, op, lock) \
|
||||
({ \
|
||||
__typeof__ (*(ptr)) __ret = (arg); \
|
||||
switch (sizeof(*(ptr))) { \
|
||||
case __X86_CASE_B: \
|
||||
asm_inline volatile (lock #op "b %b0, %1" \
|
||||
: "+q" (__ret), "+m" (*(ptr)) \
|
||||
: : "memory", "cc"); \
|
||||
break; \
|
||||
case __X86_CASE_W: \
|
||||
asm_inline volatile (lock #op "w %w0, %1" \
|
||||
: "+r" (__ret), "+m" (*(ptr)) \
|
||||
: : "memory", "cc"); \
|
||||
break; \
|
||||
case __X86_CASE_L: \
|
||||
asm_inline volatile (lock #op "l %0, %1" \
|
||||
: "+r" (__ret), "+m" (*(ptr)) \
|
||||
: : "memory", "cc"); \
|
||||
break; \
|
||||
case __X86_CASE_Q: \
|
||||
asm_inline volatile (lock #op "q %q0, %1" \
|
||||
: "+r" (__ret), "+m" (*(ptr)) \
|
||||
: : "memory", "cc"); \
|
||||
break; \
|
||||
default: \
|
||||
__ ## op ## _wrong_size(); \
|
||||
} \
|
||||
__ret; \
|
||||
})
|
||||
|
||||
/*
|
||||
* Note: no "lock" prefix even on SMP: xchg always implies lock anyway.
|
||||
* Since this is generally used to protect other memory information, we
|
||||
* use "asm volatile" and "memory" clobbers to prevent gcc from moving
|
||||
* information around.
|
||||
*/
|
||||
#define arch_xchg(ptr, v) __xchg_op((ptr), (v), xchg, "")
|
||||
|
||||
/*
|
||||
* Atomic compare and exchange. Compare OLD with MEM, if identical,
|
||||
* store NEW in MEM. Return the initial value in MEM. Success is
|
||||
* indicated by comparing RETURN with OLD.
|
||||
*/
|
||||
#define __raw_cmpxchg(ptr, old, new, size, lock) \
|
||||
({ \
|
||||
__typeof__(*(ptr)) __ret; \
|
||||
__typeof__(*(ptr)) __old = (old); \
|
||||
__typeof__(*(ptr)) __new = (new); \
|
||||
switch (size) { \
|
||||
case __X86_CASE_B: \
|
||||
{ \
|
||||
volatile u8 *__ptr = (volatile u8 *)(ptr); \
|
||||
asm_inline volatile(lock "cmpxchgb %2, %1" \
|
||||
: "=a" (__ret), "+m" (*__ptr) \
|
||||
: "q" (__new), "0" (__old) \
|
||||
: "memory"); \
|
||||
break; \
|
||||
} \
|
||||
case __X86_CASE_W: \
|
||||
{ \
|
||||
volatile u16 *__ptr = (volatile u16 *)(ptr); \
|
||||
asm_inline volatile(lock "cmpxchgw %2, %1" \
|
||||
: "=a" (__ret), "+m" (*__ptr) \
|
||||
: "r" (__new), "0" (__old) \
|
||||
: "memory"); \
|
||||
break; \
|
||||
} \
|
||||
case __X86_CASE_L: \
|
||||
{ \
|
||||
volatile u32 *__ptr = (volatile u32 *)(ptr); \
|
||||
asm_inline volatile(lock "cmpxchgl %2, %1" \
|
||||
: "=a" (__ret), "+m" (*__ptr) \
|
||||
: "r" (__new), "0" (__old) \
|
||||
: "memory"); \
|
||||
break; \
|
||||
} \
|
||||
case __X86_CASE_Q: \
|
||||
{ \
|
||||
volatile u64 *__ptr = (volatile u64 *)(ptr); \
|
||||
asm_inline volatile(lock "cmpxchgq %2, %1" \
|
||||
: "=a" (__ret), "+m" (*__ptr) \
|
||||
: "r" (__new), "0" (__old) \
|
||||
: "memory"); \
|
||||
break; \
|
||||
} \
|
||||
default: \
|
||||
__cmpxchg_wrong_size(); \
|
||||
} \
|
||||
__ret; \
|
||||
})
|
||||
|
||||
#define __cmpxchg(ptr, old, new, size) \
|
||||
__raw_cmpxchg((ptr), (old), (new), (size), LOCK_PREFIX)
|
||||
|
||||
#define __sync_cmpxchg(ptr, old, new, size) \
|
||||
__raw_cmpxchg((ptr), (old), (new), (size), "lock ")
|
||||
|
||||
#define __cmpxchg_local(ptr, old, new, size) \
|
||||
__raw_cmpxchg((ptr), (old), (new), (size), "")
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
# include <asm/cmpxchg_32.h>
|
||||
#else
|
||||
# include <asm/cmpxchg_64.h>
|
||||
#endif
|
||||
|
||||
#define arch_cmpxchg(ptr, old, new) \
|
||||
__cmpxchg(ptr, old, new, sizeof(*(ptr)))
|
||||
|
||||
#define arch_sync_cmpxchg(ptr, old, new) \
|
||||
__sync_cmpxchg(ptr, old, new, sizeof(*(ptr)))
|
||||
|
||||
#define arch_cmpxchg_local(ptr, old, new) \
|
||||
__cmpxchg_local(ptr, old, new, sizeof(*(ptr)))
|
||||
|
||||
|
||||
#define __raw_try_cmpxchg(_ptr, _pold, _new, size, lock) \
|
||||
({ \
|
||||
bool success; \
|
||||
__typeof__(_ptr) _old = (__typeof__(_ptr))(_pold); \
|
||||
__typeof__(*(_ptr)) __old = *_old; \
|
||||
__typeof__(*(_ptr)) __new = (_new); \
|
||||
switch (size) { \
|
||||
case __X86_CASE_B: \
|
||||
{ \
|
||||
volatile u8 *__ptr = (volatile u8 *)(_ptr); \
|
||||
asm_inline volatile(lock "cmpxchgb %[new], %[ptr]" \
|
||||
: "=@ccz" (success), \
|
||||
[ptr] "+m" (*__ptr), \
|
||||
[old] "+a" (__old) \
|
||||
: [new] "q" (__new) \
|
||||
: "memory"); \
|
||||
break; \
|
||||
} \
|
||||
case __X86_CASE_W: \
|
||||
{ \
|
||||
volatile u16 *__ptr = (volatile u16 *)(_ptr); \
|
||||
asm_inline volatile(lock "cmpxchgw %[new], %[ptr]" \
|
||||
: "=@ccz" (success), \
|
||||
[ptr] "+m" (*__ptr), \
|
||||
[old] "+a" (__old) \
|
||||
: [new] "r" (__new) \
|
||||
: "memory"); \
|
||||
break; \
|
||||
} \
|
||||
case __X86_CASE_L: \
|
||||
{ \
|
||||
volatile u32 *__ptr = (volatile u32 *)(_ptr); \
|
||||
asm_inline volatile(lock "cmpxchgl %[new], %[ptr]" \
|
||||
: "=@ccz" (success), \
|
||||
[ptr] "+m" (*__ptr), \
|
||||
[old] "+a" (__old) \
|
||||
: [new] "r" (__new) \
|
||||
: "memory"); \
|
||||
break; \
|
||||
} \
|
||||
case __X86_CASE_Q: \
|
||||
{ \
|
||||
volatile u64 *__ptr = (volatile u64 *)(_ptr); \
|
||||
asm_inline volatile(lock "cmpxchgq %[new], %[ptr]" \
|
||||
: "=@ccz" (success), \
|
||||
[ptr] "+m" (*__ptr), \
|
||||
[old] "+a" (__old) \
|
||||
: [new] "r" (__new) \
|
||||
: "memory"); \
|
||||
break; \
|
||||
} \
|
||||
default: \
|
||||
__cmpxchg_wrong_size(); \
|
||||
} \
|
||||
if (unlikely(!success)) \
|
||||
*_old = __old; \
|
||||
likely(success); \
|
||||
})
|
||||
|
||||
#define __try_cmpxchg(ptr, pold, new, size) \
|
||||
__raw_try_cmpxchg((ptr), (pold), (new), (size), LOCK_PREFIX)
|
||||
|
||||
#define __sync_try_cmpxchg(ptr, pold, new, size) \
|
||||
__raw_try_cmpxchg((ptr), (pold), (new), (size), "lock ")
|
||||
|
||||
#define __try_cmpxchg_local(ptr, pold, new, size) \
|
||||
__raw_try_cmpxchg((ptr), (pold), (new), (size), "")
|
||||
|
||||
#define arch_try_cmpxchg(ptr, pold, new) \
|
||||
__try_cmpxchg((ptr), (pold), (new), sizeof(*(ptr)))
|
||||
|
||||
#define arch_sync_try_cmpxchg(ptr, pold, new) \
|
||||
__sync_try_cmpxchg((ptr), (pold), (new), sizeof(*(ptr)))
|
||||
|
||||
#define arch_try_cmpxchg_local(ptr, pold, new) \
|
||||
__try_cmpxchg_local((ptr), (pold), (new), sizeof(*(ptr)))
|
||||
|
||||
/*
|
||||
* xadd() adds "inc" to "*ptr" and atomically returns the previous
|
||||
* value of "*ptr".
|
||||
*
|
||||
* xadd() is locked when multiple CPUs are online
|
||||
*/
|
||||
#define __xadd(ptr, inc, lock) __xchg_op((ptr), (inc), xadd, lock)
|
||||
#define xadd(ptr, inc) __xadd((ptr), (inc), LOCK_PREFIX)
|
||||
|
||||
#endif /* ASM_X86_CMPXCHG_H */
|
||||
@@ -0,0 +1,155 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_CMPXCHG_32_H
|
||||
#define _ASM_X86_CMPXCHG_32_H
|
||||
|
||||
/*
|
||||
* Note: if you use __cmpxchg64(), or their variants,
|
||||
* you need to test for the feature in boot_cpu_data.
|
||||
*/
|
||||
|
||||
union __u64_halves {
|
||||
u64 full;
|
||||
struct {
|
||||
u32 low, high;
|
||||
};
|
||||
};
|
||||
|
||||
#define __arch_cmpxchg64(_ptr, _old, _new, _lock) \
|
||||
({ \
|
||||
union __u64_halves o = { .full = (_old), }, \
|
||||
n = { .full = (_new), }; \
|
||||
\
|
||||
asm_inline volatile(_lock "cmpxchg8b %[ptr]" \
|
||||
: [ptr] "+m" (*(_ptr)), \
|
||||
"+a" (o.low), "+d" (o.high) \
|
||||
: "b" (n.low), "c" (n.high) \
|
||||
: "memory"); \
|
||||
\
|
||||
o.full; \
|
||||
})
|
||||
|
||||
|
||||
static __always_inline u64 __cmpxchg64(volatile u64 *ptr, u64 old, u64 new)
|
||||
{
|
||||
return __arch_cmpxchg64(ptr, old, new, LOCK_PREFIX);
|
||||
}
|
||||
|
||||
static __always_inline u64 __cmpxchg64_local(volatile u64 *ptr, u64 old, u64 new)
|
||||
{
|
||||
return __arch_cmpxchg64(ptr, old, new,);
|
||||
}
|
||||
|
||||
#define __arch_try_cmpxchg64(_ptr, _oldp, _new, _lock) \
|
||||
({ \
|
||||
union __u64_halves o = { .full = *(_oldp), }, \
|
||||
n = { .full = (_new), }; \
|
||||
bool ret; \
|
||||
\
|
||||
asm_inline volatile(_lock "cmpxchg8b %[ptr]" \
|
||||
: "=@ccz" (ret), \
|
||||
[ptr] "+m" (*(_ptr)), \
|
||||
"+a" (o.low), "+d" (o.high) \
|
||||
: "b" (n.low), "c" (n.high) \
|
||||
: "memory"); \
|
||||
\
|
||||
if (unlikely(!ret)) \
|
||||
*(_oldp) = o.full; \
|
||||
\
|
||||
likely(ret); \
|
||||
})
|
||||
|
||||
static __always_inline bool __try_cmpxchg64(volatile u64 *ptr, u64 *oldp, u64 new)
|
||||
{
|
||||
return __arch_try_cmpxchg64(ptr, oldp, new, LOCK_PREFIX);
|
||||
}
|
||||
|
||||
static __always_inline bool __try_cmpxchg64_local(volatile u64 *ptr, u64 *oldp, u64 new)
|
||||
{
|
||||
return __arch_try_cmpxchg64(ptr, oldp, new,);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_CX8
|
||||
|
||||
#define arch_cmpxchg64 __cmpxchg64
|
||||
|
||||
#define arch_cmpxchg64_local __cmpxchg64_local
|
||||
|
||||
#define arch_try_cmpxchg64 __try_cmpxchg64
|
||||
|
||||
#define arch_try_cmpxchg64_local __try_cmpxchg64_local
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* Building a kernel capable running on 80386 and 80486. It may be necessary
|
||||
* to simulate the cmpxchg8b on the 80386 and 80486 CPU.
|
||||
*/
|
||||
|
||||
#define __arch_cmpxchg64_emu(_ptr, _old, _new, _lock_loc, _lock) \
|
||||
({ \
|
||||
union __u64_halves o = { .full = (_old), }, \
|
||||
n = { .full = (_new), }; \
|
||||
\
|
||||
asm_inline volatile( \
|
||||
ALTERNATIVE(_lock_loc \
|
||||
"call cmpxchg8b_emu", \
|
||||
_lock "cmpxchg8b %a[ptr]", X86_FEATURE_CX8) \
|
||||
: ALT_OUTPUT_SP("+a" (o.low), "+d" (o.high)) \
|
||||
: "b" (n.low), "c" (n.high), \
|
||||
[ptr] "S" (_ptr) \
|
||||
: "memory"); \
|
||||
\
|
||||
o.full; \
|
||||
})
|
||||
|
||||
static __always_inline u64 arch_cmpxchg64(volatile u64 *ptr, u64 old, u64 new)
|
||||
{
|
||||
return __arch_cmpxchg64_emu(ptr, old, new, LOCK_PREFIX_HERE, "lock ");
|
||||
}
|
||||
#define arch_cmpxchg64 arch_cmpxchg64
|
||||
|
||||
static __always_inline u64 arch_cmpxchg64_local(volatile u64 *ptr, u64 old, u64 new)
|
||||
{
|
||||
return __arch_cmpxchg64_emu(ptr, old, new, ,);
|
||||
}
|
||||
#define arch_cmpxchg64_local arch_cmpxchg64_local
|
||||
|
||||
#define __arch_try_cmpxchg64_emu(_ptr, _oldp, _new, _lock_loc, _lock) \
|
||||
({ \
|
||||
union __u64_halves o = { .full = *(_oldp), }, \
|
||||
n = { .full = (_new), }; \
|
||||
bool ret; \
|
||||
\
|
||||
asm_inline volatile( \
|
||||
ALTERNATIVE(_lock_loc \
|
||||
"call cmpxchg8b_emu", \
|
||||
_lock "cmpxchg8b %a[ptr]", X86_FEATURE_CX8) \
|
||||
: ALT_OUTPUT_SP("=@ccz" (ret), \
|
||||
"+a" (o.low), "+d" (o.high)) \
|
||||
: "b" (n.low), "c" (n.high), \
|
||||
[ptr] "S" (_ptr) \
|
||||
: "memory"); \
|
||||
\
|
||||
if (unlikely(!ret)) \
|
||||
*(_oldp) = o.full; \
|
||||
\
|
||||
likely(ret); \
|
||||
})
|
||||
|
||||
static __always_inline bool arch_try_cmpxchg64(volatile u64 *ptr, u64 *oldp, u64 new)
|
||||
{
|
||||
return __arch_try_cmpxchg64_emu(ptr, oldp, new, LOCK_PREFIX_HERE, "lock ");
|
||||
}
|
||||
#define arch_try_cmpxchg64 arch_try_cmpxchg64
|
||||
|
||||
static __always_inline bool arch_try_cmpxchg64_local(volatile u64 *ptr, u64 *oldp, u64 new)
|
||||
{
|
||||
return __arch_try_cmpxchg64_emu(ptr, oldp, new, ,);
|
||||
}
|
||||
#define arch_try_cmpxchg64_local arch_try_cmpxchg64_local
|
||||
|
||||
#endif
|
||||
|
||||
#define system_has_cmpxchg64() boot_cpu_has(X86_FEATURE_CX8)
|
||||
|
||||
#endif /* _ASM_X86_CMPXCHG_32_H */
|
||||
@@ -0,0 +1,95 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_CMPXCHG_64_H
|
||||
#define _ASM_X86_CMPXCHG_64_H
|
||||
|
||||
#define arch_cmpxchg64(ptr, o, n) \
|
||||
({ \
|
||||
BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
|
||||
arch_cmpxchg((ptr), (o), (n)); \
|
||||
})
|
||||
|
||||
#define arch_cmpxchg64_local(ptr, o, n) \
|
||||
({ \
|
||||
BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
|
||||
arch_cmpxchg_local((ptr), (o), (n)); \
|
||||
})
|
||||
|
||||
#define arch_try_cmpxchg64(ptr, po, n) \
|
||||
({ \
|
||||
BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
|
||||
arch_try_cmpxchg((ptr), (po), (n)); \
|
||||
})
|
||||
|
||||
#define arch_try_cmpxchg64_local(ptr, po, n) \
|
||||
({ \
|
||||
BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
|
||||
arch_try_cmpxchg_local((ptr), (po), (n)); \
|
||||
})
|
||||
|
||||
union __u128_halves {
|
||||
u128 full;
|
||||
struct {
|
||||
u64 low, high;
|
||||
};
|
||||
};
|
||||
|
||||
#define __arch_cmpxchg128(_ptr, _old, _new, _lock) \
|
||||
({ \
|
||||
union __u128_halves o = { .full = (_old), }, \
|
||||
n = { .full = (_new), }; \
|
||||
\
|
||||
asm_inline volatile(_lock "cmpxchg16b %[ptr]" \
|
||||
: [ptr] "+m" (*(_ptr)), \
|
||||
"+a" (o.low), "+d" (o.high) \
|
||||
: "b" (n.low), "c" (n.high) \
|
||||
: "memory"); \
|
||||
\
|
||||
o.full; \
|
||||
})
|
||||
|
||||
static __always_inline u128 arch_cmpxchg128(volatile u128 *ptr, u128 old, u128 new)
|
||||
{
|
||||
return __arch_cmpxchg128(ptr, old, new, LOCK_PREFIX);
|
||||
}
|
||||
#define arch_cmpxchg128 arch_cmpxchg128
|
||||
|
||||
static __always_inline u128 arch_cmpxchg128_local(volatile u128 *ptr, u128 old, u128 new)
|
||||
{
|
||||
return __arch_cmpxchg128(ptr, old, new,);
|
||||
}
|
||||
#define arch_cmpxchg128_local arch_cmpxchg128_local
|
||||
|
||||
#define __arch_try_cmpxchg128(_ptr, _oldp, _new, _lock) \
|
||||
({ \
|
||||
union __u128_halves o = { .full = *(_oldp), }, \
|
||||
n = { .full = (_new), }; \
|
||||
bool ret; \
|
||||
\
|
||||
asm_inline volatile(_lock "cmpxchg16b %[ptr]" \
|
||||
: "=@ccz" (ret), \
|
||||
[ptr] "+m" (*(_ptr)), \
|
||||
"+a" (o.low), "+d" (o.high) \
|
||||
: "b" (n.low), "c" (n.high) \
|
||||
: "memory"); \
|
||||
\
|
||||
if (unlikely(!ret)) \
|
||||
*(_oldp) = o.full; \
|
||||
\
|
||||
likely(ret); \
|
||||
})
|
||||
|
||||
static __always_inline bool arch_try_cmpxchg128(volatile u128 *ptr, u128 *oldp, u128 new)
|
||||
{
|
||||
return __arch_try_cmpxchg128(ptr, oldp, new, LOCK_PREFIX);
|
||||
}
|
||||
#define arch_try_cmpxchg128 arch_try_cmpxchg128
|
||||
|
||||
static __always_inline bool arch_try_cmpxchg128_local(volatile u128 *ptr, u128 *oldp, u128 new)
|
||||
{
|
||||
return __arch_try_cmpxchg128(ptr, oldp, new,);
|
||||
}
|
||||
#define arch_try_cmpxchg128_local arch_try_cmpxchg128_local
|
||||
|
||||
#define system_has_cmpxchg128() boot_cpu_has(X86_FEATURE_CX16)
|
||||
|
||||
#endif /* _ASM_X86_CMPXCHG_64_H */
|
||||
@@ -0,0 +1,50 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_COCO_H
|
||||
#define _ASM_X86_COCO_H
|
||||
|
||||
#include <asm/asm.h>
|
||||
#include <asm/types.h>
|
||||
|
||||
enum cc_vendor {
|
||||
CC_VENDOR_NONE,
|
||||
CC_VENDOR_AMD,
|
||||
CC_VENDOR_INTEL,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ARCH_HAS_CC_PLATFORM
|
||||
extern enum cc_vendor cc_vendor;
|
||||
extern u64 cc_mask;
|
||||
|
||||
static inline u64 cc_get_mask(void)
|
||||
{
|
||||
return cc_mask;
|
||||
}
|
||||
|
||||
static inline void cc_set_mask(u64 mask)
|
||||
{
|
||||
cc_mask = mask;
|
||||
}
|
||||
|
||||
u64 cc_mkenc(u64 val);
|
||||
u64 cc_mkdec(u64 val);
|
||||
void cc_random_init(void);
|
||||
#else
|
||||
#define cc_vendor (CC_VENDOR_NONE)
|
||||
static inline u64 cc_get_mask(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u64 cc_mkenc(u64 val)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline u64 cc_mkdec(u64 val)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
static inline void cc_random_init(void) { }
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_X86_COCO_H */
|
||||
@@ -0,0 +1,114 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_COMPAT_H
|
||||
#define _ASM_X86_COMPAT_H
|
||||
|
||||
/*
|
||||
* Architecture specific compatibility types
|
||||
*/
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/sched/task_stack.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/user32.h>
|
||||
#include <asm/unistd.h>
|
||||
|
||||
#define compat_mode_t compat_mode_t
|
||||
typedef u16 compat_mode_t;
|
||||
|
||||
#define __compat_uid_t __compat_uid_t
|
||||
typedef u16 __compat_uid_t;
|
||||
typedef u16 __compat_gid_t;
|
||||
|
||||
#define compat_dev_t compat_dev_t
|
||||
typedef u16 compat_dev_t;
|
||||
|
||||
#define compat_ipc_pid_t compat_ipc_pid_t
|
||||
typedef u16 compat_ipc_pid_t;
|
||||
|
||||
#define compat_statfs compat_statfs
|
||||
|
||||
#include <asm-generic/compat.h>
|
||||
|
||||
#define COMPAT_UTS_MACHINE "i686\0\0"
|
||||
|
||||
typedef u16 compat_nlink_t;
|
||||
|
||||
struct compat_stat {
|
||||
u32 st_dev;
|
||||
compat_ino_t st_ino;
|
||||
compat_mode_t st_mode;
|
||||
compat_nlink_t st_nlink;
|
||||
__compat_uid_t st_uid;
|
||||
__compat_gid_t st_gid;
|
||||
u32 st_rdev;
|
||||
u32 st_size;
|
||||
u32 st_blksize;
|
||||
u32 st_blocks;
|
||||
u32 st_atime;
|
||||
u32 st_atime_nsec;
|
||||
u32 st_mtime;
|
||||
u32 st_mtime_nsec;
|
||||
u32 st_ctime;
|
||||
u32 st_ctime_nsec;
|
||||
u32 __unused4;
|
||||
u32 __unused5;
|
||||
};
|
||||
|
||||
/*
|
||||
* IA32 uses 4 byte alignment for 64 bit quantities, so we need to pack the
|
||||
* compat flock64 structure.
|
||||
*/
|
||||
#define __ARCH_NEED_COMPAT_FLOCK64_PACKED
|
||||
|
||||
struct compat_statfs {
|
||||
int f_type;
|
||||
int f_bsize;
|
||||
int f_blocks;
|
||||
int f_bfree;
|
||||
int f_bavail;
|
||||
int f_files;
|
||||
int f_ffree;
|
||||
compat_fsid_t f_fsid;
|
||||
int f_namelen; /* SunOS ignores this field. */
|
||||
int f_frsize;
|
||||
int f_flags;
|
||||
int f_spare[4];
|
||||
};
|
||||
|
||||
#ifdef CONFIG_X86_X32_ABI
|
||||
#define COMPAT_USE_64BIT_TIME \
|
||||
(!!(task_pt_regs(current)->orig_ax & __X32_SYSCALL_BIT))
|
||||
#endif
|
||||
|
||||
static inline bool in_x32_syscall(void)
|
||||
{
|
||||
#ifdef CONFIG_X86_X32_ABI
|
||||
if (task_pt_regs(current)->orig_ax & __X32_SYSCALL_BIT)
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool in_32bit_syscall(void)
|
||||
{
|
||||
return in_ia32_syscall() || in_x32_syscall();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
static inline bool in_compat_syscall(void)
|
||||
{
|
||||
return in_32bit_syscall();
|
||||
}
|
||||
#define in_compat_syscall in_compat_syscall /* override the generic impl */
|
||||
#define compat_need_64bit_alignment_fixup in_ia32_syscall
|
||||
#endif
|
||||
|
||||
struct compat_siginfo;
|
||||
|
||||
#ifdef CONFIG_X86_X32_ABI
|
||||
int copy_siginfo_to_user32(struct compat_siginfo __user *to,
|
||||
const kernel_siginfo_t *from);
|
||||
#define copy_siginfo_to_user32 copy_siginfo_to_user32
|
||||
#endif /* CONFIG_X86_X32_ABI */
|
||||
|
||||
#endif /* _ASM_X86_COMPAT_H */
|
||||
@@ -0,0 +1,70 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_CPU_H
|
||||
#define _ASM_X86_CPU_H
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/topology.h>
|
||||
#include <linux/nodemask.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <asm/ibt.h>
|
||||
|
||||
#ifndef CONFIG_SMP
|
||||
#define cpu_physical_id(cpu) boot_cpu_physical_apicid
|
||||
#define cpu_acpi_id(cpu) 0
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
extern void soft_restart_cpu(void);
|
||||
#endif
|
||||
|
||||
extern void ap_init_aperfmperf(void);
|
||||
|
||||
int mwait_usable(const struct cpuinfo_x86 *);
|
||||
|
||||
unsigned int x86_family(unsigned int sig);
|
||||
unsigned int x86_model(unsigned int sig);
|
||||
unsigned int x86_stepping(unsigned int sig);
|
||||
#ifdef CONFIG_X86_BUS_LOCK_DETECT
|
||||
extern void __init sld_setup(struct cpuinfo_x86 *c);
|
||||
extern bool handle_user_split_lock(struct pt_regs *regs, long error_code);
|
||||
extern bool handle_guest_split_lock(unsigned long ip);
|
||||
extern void handle_bus_lock(struct pt_regs *regs);
|
||||
void split_lock_init(void);
|
||||
void bus_lock_init(void);
|
||||
#else
|
||||
static inline void __init sld_setup(struct cpuinfo_x86 *c) {}
|
||||
static inline bool handle_user_split_lock(struct pt_regs *regs, long error_code)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool handle_guest_split_lock(unsigned long ip)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void handle_bus_lock(struct pt_regs *regs) {}
|
||||
static inline void split_lock_init(void) {}
|
||||
static inline void bus_lock_init(void) {}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IA32_FEAT_CTL
|
||||
void init_ia32_feat_ctl(struct cpuinfo_x86 *c);
|
||||
#else
|
||||
static inline void init_ia32_feat_ctl(struct cpuinfo_x86 *c) {}
|
||||
#endif
|
||||
|
||||
extern __noendbr void cet_disable(void);
|
||||
|
||||
struct cpu_signature;
|
||||
|
||||
void intel_collect_cpu_info(struct cpu_signature *sig);
|
||||
|
||||
extern u64 x86_read_arch_cap_msr(void);
|
||||
bool intel_find_matching_signature(void *mc, struct cpu_signature *sig);
|
||||
int intel_microcode_sanity_check(void *mc, bool print_err, int hdr_type);
|
||||
|
||||
extern struct cpumask cpus_stop_mask;
|
||||
|
||||
#endif /* _ASM_X86_CPU_H */
|
||||
@@ -0,0 +1,207 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_CPU_DEVICE_ID
|
||||
#define _ASM_X86_CPU_DEVICE_ID
|
||||
|
||||
/*
|
||||
* Can't use <linux/bitfield.h> because it generates expressions that
|
||||
* cannot be used in structure initializers. Bitfield construction
|
||||
* here must match the union in struct cpuinfo_86:
|
||||
* union {
|
||||
* struct {
|
||||
* __u8 x86_model;
|
||||
* __u8 x86;
|
||||
* __u8 x86_vendor;
|
||||
* __u8 x86_reserved;
|
||||
* };
|
||||
* __u32 x86_vfm;
|
||||
* };
|
||||
*/
|
||||
#define VFM_MODEL_BIT 0
|
||||
#define VFM_FAMILY_BIT 8
|
||||
#define VFM_VENDOR_BIT 16
|
||||
#define VFM_RSVD_BIT 24
|
||||
|
||||
#define VFM_MODEL_MASK GENMASK(VFM_FAMILY_BIT - 1, VFM_MODEL_BIT)
|
||||
#define VFM_FAMILY_MASK GENMASK(VFM_VENDOR_BIT - 1, VFM_FAMILY_BIT)
|
||||
#define VFM_VENDOR_MASK GENMASK(VFM_RSVD_BIT - 1, VFM_VENDOR_BIT)
|
||||
|
||||
#define VFM_MODEL(vfm) (((vfm) & VFM_MODEL_MASK) >> VFM_MODEL_BIT)
|
||||
#define VFM_FAMILY(vfm) (((vfm) & VFM_FAMILY_MASK) >> VFM_FAMILY_BIT)
|
||||
#define VFM_VENDOR(vfm) (((vfm) & VFM_VENDOR_MASK) >> VFM_VENDOR_BIT)
|
||||
|
||||
#define VFM_MAKE(_vendor, _family, _model) ( \
|
||||
((_model) << VFM_MODEL_BIT) | \
|
||||
((_family) << VFM_FAMILY_BIT) | \
|
||||
((_vendor) << VFM_VENDOR_BIT) \
|
||||
)
|
||||
|
||||
/*
|
||||
* Declare drivers belonging to specific x86 CPUs
|
||||
* Similar in spirit to pci_device_id and related PCI functions
|
||||
*
|
||||
* The wildcard initializers are in mod_devicetable.h because
|
||||
* file2alias needs them. Sigh.
|
||||
*/
|
||||
#include <linux/mod_devicetable.h>
|
||||
/* Get the INTEL_FAM* model defines */
|
||||
#include <asm/intel-family.h>
|
||||
/* And the X86_VENDOR_* ones */
|
||||
#include <asm/processor.h>
|
||||
|
||||
/* Centaur FAM6 models */
|
||||
#define X86_CENTAUR_FAM6_C7_A 0xa
|
||||
#define X86_CENTAUR_FAM6_C7_D 0xd
|
||||
#define X86_CENTAUR_FAM6_NANO 0xf
|
||||
|
||||
/* x86_cpu_id::flags */
|
||||
#define X86_CPU_ID_FLAG_ENTRY_VALID BIT(0)
|
||||
|
||||
/**
|
||||
* X86_MATCH_CPU - Base macro for CPU matching
|
||||
* @_vendor: The vendor name, e.g. INTEL, AMD, HYGON, ..., ANY
|
||||
* The name is expanded to X86_VENDOR_@_vendor
|
||||
* @_family: The family number or X86_FAMILY_ANY
|
||||
* @_model: The model number, model constant or X86_MODEL_ANY
|
||||
* @_steppings: Bitmask for steppings, stepping constant or X86_STEPPING_ANY
|
||||
* @_feature: A X86_FEATURE bit or X86_FEATURE_ANY
|
||||
* @_data: Driver specific data or NULL. The internal storage
|
||||
* format is unsigned long. The supplied value, pointer
|
||||
* etc. is casted to unsigned long internally.
|
||||
*
|
||||
* Use only if you need all selectors. Otherwise use one of the shorter
|
||||
* macros of the X86_MATCH_* family. If there is no matching shorthand
|
||||
* macro, consider to add one. If you really need to wrap one of the macros
|
||||
* into another macro at the usage site for good reasons, then please
|
||||
* start this local macro with X86_MATCH to allow easy grepping.
|
||||
*/
|
||||
#define X86_MATCH_CPU(_vendor, _family, _model, _steppings, _feature, _type, _data) { \
|
||||
.vendor = _vendor, \
|
||||
.family = _family, \
|
||||
.model = _model, \
|
||||
.steppings = _steppings, \
|
||||
.feature = _feature, \
|
||||
.flags = X86_CPU_ID_FLAG_ENTRY_VALID, \
|
||||
.type = _type, \
|
||||
.driver_data = (unsigned long) _data \
|
||||
}
|
||||
|
||||
/**
|
||||
* X86_MATCH_VENDOR_FAM_FEATURE - Macro for matching vendor, family and CPU feature
|
||||
* @vendor: The vendor name, e.g. INTEL, AMD, HYGON, ..., ANY
|
||||
* The name is expanded to X86_VENDOR_@vendor
|
||||
* @family: The family number or X86_FAMILY_ANY
|
||||
* @feature: A X86_FEATURE bit
|
||||
* @data: Driver specific data or NULL. The internal storage
|
||||
* format is unsigned long. The supplied value, pointer
|
||||
* etc. is casted to unsigned long internally.
|
||||
*/
|
||||
#define X86_MATCH_VENDOR_FAM_FEATURE(vendor, family, feature, data) \
|
||||
X86_MATCH_CPU(X86_VENDOR_##vendor, family, X86_MODEL_ANY, \
|
||||
X86_STEPPING_ANY, feature, X86_CPU_TYPE_ANY, data)
|
||||
|
||||
/**
|
||||
* X86_MATCH_VENDOR_FEATURE - Macro for matching vendor and CPU feature
|
||||
* @vendor: The vendor name, e.g. INTEL, AMD, HYGON, ..., ANY
|
||||
* The name is expanded to X86_VENDOR_@vendor
|
||||
* @feature: A X86_FEATURE bit
|
||||
* @data: Driver specific data or NULL. The internal storage
|
||||
* format is unsigned long. The supplied value, pointer
|
||||
* etc. is casted to unsigned long internally.
|
||||
*/
|
||||
#define X86_MATCH_VENDOR_FEATURE(vendor, feature, data) \
|
||||
X86_MATCH_CPU(X86_VENDOR_##vendor, X86_FAMILY_ANY, X86_MODEL_ANY, \
|
||||
X86_STEPPING_ANY, feature, X86_CPU_TYPE_ANY, data)
|
||||
|
||||
/**
|
||||
* X86_MATCH_FEATURE - Macro for matching a CPU feature
|
||||
* @feature: A X86_FEATURE bit
|
||||
* @data: Driver specific data or NULL. The internal storage
|
||||
* format is unsigned long. The supplied value, pointer
|
||||
* etc. is casted to unsigned long internally.
|
||||
*/
|
||||
#define X86_MATCH_FEATURE(feature, data) \
|
||||
X86_MATCH_CPU(X86_VENDOR_ANY, X86_FAMILY_ANY, X86_MODEL_ANY, \
|
||||
X86_STEPPING_ANY, feature, X86_CPU_TYPE_ANY, data)
|
||||
|
||||
/**
|
||||
* X86_MATCH_VENDOR_FAM_MODEL - Match vendor, family and model
|
||||
* @vendor: The vendor name, e.g. INTEL, AMD, HYGON, ..., ANY
|
||||
* The name is expanded to X86_VENDOR_@vendor
|
||||
* @family: The family number or X86_FAMILY_ANY
|
||||
* @model: The model number, model constant or X86_MODEL_ANY
|
||||
* @data: Driver specific data or NULL. The internal storage
|
||||
* format is unsigned long. The supplied value, pointer
|
||||
* etc. is casted to unsigned long internally.
|
||||
*/
|
||||
#define X86_MATCH_VENDOR_FAM_MODEL(vendor, family, model, data) \
|
||||
X86_MATCH_CPU(X86_VENDOR_##vendor, family, model, X86_STEPPING_ANY, \
|
||||
X86_FEATURE_ANY, X86_CPU_TYPE_ANY, data)
|
||||
|
||||
/**
|
||||
* X86_MATCH_VENDOR_FAM - Match vendor and family
|
||||
* @vendor: The vendor name, e.g. INTEL, AMD, HYGON, ..., ANY
|
||||
* The name is expanded to X86_VENDOR_@vendor
|
||||
* @family: The family number or X86_FAMILY_ANY
|
||||
* @data: Driver specific data or NULL. The internal storage
|
||||
* format is unsigned long. The supplied value, pointer
|
||||
* etc. is casted to unsigned long internally.
|
||||
*/
|
||||
#define X86_MATCH_VENDOR_FAM(vendor, family, data) \
|
||||
X86_MATCH_CPU(X86_VENDOR_##vendor, family, X86_MODEL_ANY, \
|
||||
X86_STEPPING_ANY, X86_FEATURE_ANY, X86_CPU_TYPE_ANY, data)
|
||||
|
||||
/**
|
||||
* X86_MATCH_VFM - Match encoded vendor/family/model
|
||||
* @vfm: Encoded 8-bits each for vendor, family, model
|
||||
* @data: Driver specific data or NULL. The internal storage
|
||||
* format is unsigned long. The supplied value, pointer
|
||||
* etc. is cast to unsigned long internally.
|
||||
*/
|
||||
#define X86_MATCH_VFM(vfm, data) \
|
||||
X86_MATCH_CPU(VFM_VENDOR(vfm), VFM_FAMILY(vfm), VFM_MODEL(vfm), \
|
||||
X86_STEPPING_ANY, X86_FEATURE_ANY, X86_CPU_TYPE_ANY, data)
|
||||
|
||||
#define __X86_STEPPINGS(mins, maxs) GENMASK(maxs, mins)
|
||||
/**
|
||||
* X86_MATCH_VFM_STEPS - Match encoded vendor/family/model and steppings
|
||||
* range.
|
||||
* @vfm: Encoded 8-bits each for vendor, family, model
|
||||
* @min_step: Lowest stepping number to match
|
||||
* @max_step: Highest stepping number to match
|
||||
* @data: Driver specific data or NULL. The internal storage
|
||||
* format is unsigned long. The supplied value, pointer
|
||||
* etc. is cast to unsigned long internally.
|
||||
*/
|
||||
#define X86_MATCH_VFM_STEPS(vfm, min_step, max_step, data) \
|
||||
X86_MATCH_CPU(VFM_VENDOR(vfm), VFM_FAMILY(vfm), VFM_MODEL(vfm), \
|
||||
__X86_STEPPINGS(min_step, max_step), X86_FEATURE_ANY, \
|
||||
X86_CPU_TYPE_ANY, data)
|
||||
|
||||
/**
|
||||
* X86_MATCH_VFM_FEATURE - Match encoded vendor/family/model/feature
|
||||
* @vfm: Encoded 8-bits each for vendor, family, model
|
||||
* @feature: A X86_FEATURE bit
|
||||
* @data: Driver specific data or NULL. The internal storage
|
||||
* format is unsigned long. The supplied value, pointer
|
||||
* etc. is cast to unsigned long internally.
|
||||
*/
|
||||
#define X86_MATCH_VFM_FEATURE(vfm, feature, data) \
|
||||
X86_MATCH_CPU(VFM_VENDOR(vfm), VFM_FAMILY(vfm), VFM_MODEL(vfm), \
|
||||
X86_STEPPING_ANY, feature, X86_CPU_TYPE_ANY, data)
|
||||
|
||||
/**
|
||||
* X86_MATCH_VFM_CPU_TYPE - Match encoded vendor/family/model/type
|
||||
* @vfm: Encoded 8-bits each for vendor, family, model
|
||||
* @type: CPU type e.g. P-core, E-core
|
||||
* @data: Driver specific data or NULL. The internal storage
|
||||
* format is unsigned long. The supplied value, pointer
|
||||
* etc. is cast to unsigned long internally.
|
||||
*/
|
||||
#define X86_MATCH_VFM_CPU_TYPE(vfm, type, data) \
|
||||
X86_MATCH_CPU(VFM_VENDOR(vfm), VFM_FAMILY(vfm), VFM_MODEL(vfm), \
|
||||
X86_STEPPING_ANY, X86_FEATURE_ANY, type, data)
|
||||
|
||||
extern const struct x86_cpu_id *x86_match_cpu(const struct x86_cpu_id *match);
|
||||
extern bool x86_match_min_microcode_rev(const struct x86_cpu_id *table);
|
||||
|
||||
#endif /* _ASM_X86_CPU_DEVICE_ID */
|
||||
@@ -0,0 +1,153 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#ifndef _ASM_X86_CPU_ENTRY_AREA_H
|
||||
#define _ASM_X86_CPU_ENTRY_AREA_H
|
||||
|
||||
#include <linux/percpu-defs.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/intel_ds.h>
|
||||
#include <asm/pgtable_areas.h>
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
|
||||
#ifdef CONFIG_AMD_MEM_ENCRYPT
|
||||
#define VC_EXCEPTION_STKSZ EXCEPTION_STKSZ
|
||||
#else
|
||||
#define VC_EXCEPTION_STKSZ 0
|
||||
#endif
|
||||
|
||||
/* Macro to enforce the same ordering and stack sizes */
|
||||
#define ESTACKS_MEMBERS(guardsize, optional_stack_size) \
|
||||
char DF_stack_guard[guardsize]; \
|
||||
char DF_stack[EXCEPTION_STKSZ]; \
|
||||
char NMI_stack_guard[guardsize]; \
|
||||
char NMI_stack[EXCEPTION_STKSZ]; \
|
||||
char DB_stack_guard[guardsize]; \
|
||||
char DB_stack[EXCEPTION_STKSZ]; \
|
||||
char MCE_stack_guard[guardsize]; \
|
||||
char MCE_stack[EXCEPTION_STKSZ]; \
|
||||
char VC_stack_guard[guardsize]; \
|
||||
char VC_stack[optional_stack_size]; \
|
||||
char VC2_stack_guard[guardsize]; \
|
||||
char VC2_stack[optional_stack_size]; \
|
||||
char IST_top_guard[guardsize]; \
|
||||
|
||||
/* The exception stacks' physical storage. No guard pages required */
|
||||
struct exception_stacks {
|
||||
ESTACKS_MEMBERS(0, VC_EXCEPTION_STKSZ)
|
||||
};
|
||||
|
||||
/* The effective cpu entry area mapping with guard pages. */
|
||||
struct cea_exception_stacks {
|
||||
ESTACKS_MEMBERS(PAGE_SIZE, EXCEPTION_STKSZ)
|
||||
};
|
||||
|
||||
/*
|
||||
* The exception stack ordering in [cea_]exception_stacks
|
||||
*/
|
||||
enum exception_stack_ordering {
|
||||
ESTACK_DF,
|
||||
ESTACK_NMI,
|
||||
ESTACK_DB,
|
||||
ESTACK_MCE,
|
||||
ESTACK_VC,
|
||||
ESTACK_VC2,
|
||||
N_EXCEPTION_STACKS
|
||||
};
|
||||
|
||||
#define CEA_ESTACK_SIZE(st) \
|
||||
sizeof(((struct cea_exception_stacks *)0)->st## _stack)
|
||||
|
||||
#define CEA_ESTACK_BOT(ceastp, st) \
|
||||
((unsigned long)&(ceastp)->st## _stack)
|
||||
|
||||
#define CEA_ESTACK_TOP(ceastp, st) \
|
||||
(CEA_ESTACK_BOT(ceastp, st) + CEA_ESTACK_SIZE(st))
|
||||
|
||||
#define CEA_ESTACK_OFFS(st) \
|
||||
offsetof(struct cea_exception_stacks, st## _stack)
|
||||
|
||||
#define CEA_ESTACK_PAGES \
|
||||
(sizeof(struct cea_exception_stacks) / PAGE_SIZE)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
struct doublefault_stack {
|
||||
unsigned long stack[(PAGE_SIZE - sizeof(struct x86_hw_tss)) / sizeof(unsigned long)];
|
||||
struct x86_hw_tss tss;
|
||||
} __aligned(PAGE_SIZE);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* cpu_entry_area is a percpu region that contains things needed by the CPU
|
||||
* and early entry/exit code. Real types aren't used for all fields here
|
||||
* to avoid circular header dependencies.
|
||||
*
|
||||
* Every field is a virtual alias of some other allocated backing store.
|
||||
* There is no direct allocation of a struct cpu_entry_area.
|
||||
*/
|
||||
struct cpu_entry_area {
|
||||
char gdt[PAGE_SIZE];
|
||||
|
||||
/*
|
||||
* The GDT is just below entry_stack and thus serves (on x86_64) as
|
||||
* a read-only guard page. On 32-bit the GDT must be writeable, so
|
||||
* it needs an extra guard page.
|
||||
*/
|
||||
#ifdef CONFIG_X86_32
|
||||
char guard_entry_stack[PAGE_SIZE];
|
||||
#endif
|
||||
struct entry_stack_page entry_stack_page;
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
char guard_doublefault_stack[PAGE_SIZE];
|
||||
struct doublefault_stack doublefault_stack;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* On x86_64, the TSS is mapped RO. On x86_32, it's mapped RW because
|
||||
* we need task switches to work, and task switches write to the TSS.
|
||||
*/
|
||||
struct tss_struct tss;
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
/*
|
||||
* Exception stacks used for IST entries with guard pages.
|
||||
*/
|
||||
struct cea_exception_stacks estacks;
|
||||
#endif
|
||||
/*
|
||||
* Per CPU debug store for Intel performance monitoring. Wastes a
|
||||
* full page at the moment.
|
||||
*/
|
||||
struct debug_store cpu_debug_store;
|
||||
/*
|
||||
* The actual PEBS/BTS buffers must be mapped to user space
|
||||
* Reserve enough fixmap PTEs.
|
||||
*/
|
||||
struct debug_store_buffers cpu_debug_buffers;
|
||||
};
|
||||
|
||||
#define CPU_ENTRY_AREA_SIZE (sizeof(struct cpu_entry_area))
|
||||
|
||||
DECLARE_PER_CPU(struct cpu_entry_area *, cpu_entry_area);
|
||||
DECLARE_PER_CPU(struct cea_exception_stacks *, cea_exception_stacks);
|
||||
|
||||
extern void setup_cpu_entry_areas(void);
|
||||
extern void cea_set_pte(void *cea_vaddr, phys_addr_t pa, pgprot_t flags);
|
||||
|
||||
extern struct cpu_entry_area *get_cpu_entry_area(int cpu);
|
||||
|
||||
static __always_inline struct entry_stack *cpu_entry_stack(int cpu)
|
||||
{
|
||||
return &get_cpu_entry_area(cpu)->entry_stack_page.stack;
|
||||
}
|
||||
|
||||
#define __this_cpu_ist_top_va(name) \
|
||||
CEA_ESTACK_TOP(__this_cpu_read(cea_exception_stacks), name)
|
||||
|
||||
#define __this_cpu_ist_bottom_va(name) \
|
||||
CEA_ESTACK_BOT(__this_cpu_read(cea_exception_stacks), name)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,142 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_CPUFEATURE_H
|
||||
#define _ASM_X86_CPUFEATURE_H
|
||||
|
||||
#include <asm/processor.h>
|
||||
|
||||
#if defined(__KERNEL__) && !defined(__ASSEMBLER__)
|
||||
|
||||
#include <asm/asm.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <asm/alternative.h>
|
||||
#include <asm/cpufeaturemasks.h>
|
||||
|
||||
enum cpuid_leafs
|
||||
{
|
||||
CPUID_1_EDX = 0,
|
||||
CPUID_8000_0001_EDX,
|
||||
CPUID_8086_0001_EDX,
|
||||
CPUID_LNX_1,
|
||||
CPUID_1_ECX,
|
||||
CPUID_C000_0001_EDX,
|
||||
CPUID_8000_0001_ECX,
|
||||
CPUID_LNX_2,
|
||||
CPUID_LNX_3,
|
||||
CPUID_7_0_EBX,
|
||||
CPUID_D_1_EAX,
|
||||
CPUID_LNX_4,
|
||||
CPUID_7_1_EAX,
|
||||
CPUID_8000_0008_EBX,
|
||||
CPUID_6_EAX,
|
||||
CPUID_8000_000A_EDX,
|
||||
CPUID_7_ECX,
|
||||
CPUID_LNX_6,
|
||||
CPUID_7_EDX,
|
||||
CPUID_8000_001F_EAX,
|
||||
CPUID_8000_0021_EAX,
|
||||
CPUID_LNX_5,
|
||||
NR_CPUID_WORDS,
|
||||
};
|
||||
|
||||
extern const char * const x86_cap_flags[NCAPINTS*32];
|
||||
extern const char * const x86_power_flags[32];
|
||||
|
||||
/*
|
||||
* In order to save room, we index into this array by doing
|
||||
* X86_BUG_<name> - NCAPINTS*32.
|
||||
*/
|
||||
extern const char * const x86_bug_flags[NBUGINTS*32];
|
||||
#define x86_bug_flag(flag) x86_bug_flags[flag]
|
||||
|
||||
#define test_cpu_cap(c, bit) \
|
||||
arch_test_bit(bit, (unsigned long *)((c)->x86_capability))
|
||||
|
||||
#define cpu_has(c, bit) \
|
||||
(__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 : \
|
||||
test_cpu_cap(c, bit))
|
||||
|
||||
#define this_cpu_has(bit) \
|
||||
(__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 : \
|
||||
x86_this_cpu_test_bit(bit, cpu_info.x86_capability))
|
||||
|
||||
/*
|
||||
* This is the default CPU features testing macro to use in code.
|
||||
*
|
||||
* It is for detection of features which need kernel infrastructure to be
|
||||
* used. It may *not* directly test the CPU itself. Use the cpu_has() family
|
||||
* if you want true runtime testing of CPU features, like in hypervisor code
|
||||
* where you are supporting a possible guest feature where host support for it
|
||||
* is not relevant.
|
||||
*/
|
||||
#define cpu_feature_enabled(bit) \
|
||||
(__builtin_constant_p(bit) && DISABLED_MASK_BIT_SET(bit) ? 0 : static_cpu_has(bit))
|
||||
|
||||
#define boot_cpu_has(bit) cpu_has(&boot_cpu_data, bit)
|
||||
|
||||
#define set_cpu_cap(c, bit) set_bit(bit, (unsigned long *)((c)->x86_capability))
|
||||
|
||||
extern void setup_clear_cpu_cap(unsigned int bit);
|
||||
extern void clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int bit);
|
||||
void check_cpufeature_deps(struct cpuinfo_x86 *c);
|
||||
|
||||
#define setup_force_cpu_cap(bit) do { \
|
||||
\
|
||||
if (!boot_cpu_has(bit)) \
|
||||
WARN_ON(alternatives_patched); \
|
||||
\
|
||||
set_cpu_cap(&boot_cpu_data, bit); \
|
||||
set_bit(bit, (unsigned long *)cpu_caps_set); \
|
||||
} while (0)
|
||||
|
||||
#define setup_force_cpu_bug(bit) setup_force_cpu_cap(bit)
|
||||
|
||||
/*
|
||||
* Do not use an "m" constraint for [cap_byte] here: gcc doesn't know
|
||||
* that this is only used on a fallback path and will sometimes cause
|
||||
* it to manifest the address of boot_cpu_data in a register, fouling
|
||||
* the mainline (post-initialization) code.
|
||||
*/
|
||||
static __always_inline bool _static_cpu_has(u16 bit)
|
||||
{
|
||||
asm goto(ALTERNATIVE_TERNARY("jmp 6f", %c[feature], "", "jmp %l[t_no]")
|
||||
".pushsection .altinstr_aux,\"ax\"\n"
|
||||
"6:\n"
|
||||
ANNOTATE_DATA_SPECIAL "\n"
|
||||
" testb %[bitnum], %a[cap_byte]\n"
|
||||
" jnz %l[t_yes]\n"
|
||||
" jmp %l[t_no]\n"
|
||||
".popsection\n"
|
||||
: : [feature] "i" (bit),
|
||||
[bitnum] "i" (1 << (bit & 7)),
|
||||
[cap_byte] "i" (&((const char *)boot_cpu_data.x86_capability)[bit >> 3])
|
||||
: : t_yes, t_no);
|
||||
t_yes:
|
||||
return true;
|
||||
t_no:
|
||||
return false;
|
||||
}
|
||||
|
||||
#define static_cpu_has(bit) \
|
||||
( \
|
||||
__builtin_constant_p(boot_cpu_has(bit)) ? \
|
||||
boot_cpu_has(bit) : \
|
||||
_static_cpu_has(bit) \
|
||||
)
|
||||
|
||||
#define cpu_has_bug(c, bit) cpu_has(c, (bit))
|
||||
#define set_cpu_bug(c, bit) set_cpu_cap(c, (bit))
|
||||
#define clear_cpu_bug(c, bit) clear_cpu_cap(c, (bit))
|
||||
|
||||
#define static_cpu_has_bug(bit) static_cpu_has((bit))
|
||||
#define boot_cpu_has_bug(bit) cpu_has_bug(&boot_cpu_data, (bit))
|
||||
#define boot_cpu_set_bug(bit) set_cpu_cap(&boot_cpu_data, (bit))
|
||||
|
||||
#define MAX_CPU_FEATURES (NCAPINTS * 32)
|
||||
#define cpu_have_feature boot_cpu_has
|
||||
|
||||
#define CPU_FEATURE_TYPEFMT "x86,ven%04Xfam%04Xmod%04X"
|
||||
#define CPU_FEATURE_TYPEVAL boot_cpu_data.x86_vendor, boot_cpu_data.x86, \
|
||||
boot_cpu_data.x86_model
|
||||
|
||||
#endif /* defined(__KERNEL__) && !defined(__ASSEMBLER__) */
|
||||
#endif /* _ASM_X86_CPUFEATURE_H */
|
||||
@@ -0,0 +1,575 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_CPUFEATURES_H
|
||||
#define _ASM_X86_CPUFEATURES_H
|
||||
|
||||
/*
|
||||
* Defines x86 CPU feature bits
|
||||
*/
|
||||
#define NCAPINTS 22 /* N 32-bit words worth of info */
|
||||
#define NBUGINTS 2 /* N 32-bit bug flags */
|
||||
|
||||
/*
|
||||
* Note: If the comment begins with a quoted string, that string is used
|
||||
* in /proc/cpuinfo instead of the macro name. Otherwise, this feature
|
||||
* bit is not displayed in /proc/cpuinfo at all.
|
||||
*
|
||||
* When adding new features here that depend on other features,
|
||||
* please update the table in kernel/cpu/cpuid-deps.c as well.
|
||||
*/
|
||||
|
||||
/* Intel-defined CPU features, CPUID level 0x00000001 (EDX), word 0 */
|
||||
#define X86_FEATURE_FPU ( 0*32+ 0) /* "fpu" Onboard FPU */
|
||||
#define X86_FEATURE_VME ( 0*32+ 1) /* "vme" Virtual Mode Extensions */
|
||||
#define X86_FEATURE_DE ( 0*32+ 2) /* "de" Debugging Extensions */
|
||||
#define X86_FEATURE_PSE ( 0*32+ 3) /* "pse" Page Size Extensions */
|
||||
#define X86_FEATURE_TSC ( 0*32+ 4) /* "tsc" Time Stamp Counter */
|
||||
#define X86_FEATURE_MSR ( 0*32+ 5) /* "msr" Model-Specific Registers */
|
||||
#define X86_FEATURE_PAE ( 0*32+ 6) /* "pae" Physical Address Extensions */
|
||||
#define X86_FEATURE_MCE ( 0*32+ 7) /* "mce" Machine Check Exception */
|
||||
#define X86_FEATURE_CX8 ( 0*32+ 8) /* "cx8" CMPXCHG8 instruction */
|
||||
#define X86_FEATURE_APIC ( 0*32+ 9) /* "apic" Onboard APIC */
|
||||
#define X86_FEATURE_SEP ( 0*32+11) /* "sep" SYSENTER/SYSEXIT */
|
||||
#define X86_FEATURE_MTRR ( 0*32+12) /* "mtrr" Memory Type Range Registers */
|
||||
#define X86_FEATURE_PGE ( 0*32+13) /* "pge" Page Global Enable */
|
||||
#define X86_FEATURE_MCA ( 0*32+14) /* "mca" Machine Check Architecture */
|
||||
#define X86_FEATURE_CMOV ( 0*32+15) /* "cmov" CMOV instructions (plus FCMOVcc, FCOMI with FPU) */
|
||||
#define X86_FEATURE_PAT ( 0*32+16) /* "pat" Page Attribute Table */
|
||||
#define X86_FEATURE_PSE36 ( 0*32+17) /* "pse36" 36-bit PSEs */
|
||||
#define X86_FEATURE_PN ( 0*32+18) /* "pn" Processor serial number */
|
||||
#define X86_FEATURE_CLFLUSH ( 0*32+19) /* "clflush" CLFLUSH instruction */
|
||||
#define X86_FEATURE_DS ( 0*32+21) /* "dts" Debug Store */
|
||||
#define X86_FEATURE_ACPI ( 0*32+22) /* "acpi" ACPI via MSR */
|
||||
#define X86_FEATURE_MMX ( 0*32+23) /* "mmx" Multimedia Extensions */
|
||||
#define X86_FEATURE_FXSR ( 0*32+24) /* "fxsr" FXSAVE/FXRSTOR, CR4.OSFXSR */
|
||||
#define X86_FEATURE_XMM ( 0*32+25) /* "sse" */
|
||||
#define X86_FEATURE_XMM2 ( 0*32+26) /* "sse2" */
|
||||
#define X86_FEATURE_SELFSNOOP ( 0*32+27) /* "ss" CPU self snoop */
|
||||
#define X86_FEATURE_HT ( 0*32+28) /* "ht" Hyper-Threading */
|
||||
#define X86_FEATURE_ACC ( 0*32+29) /* "tm" Automatic clock control */
|
||||
#define X86_FEATURE_IA64 ( 0*32+30) /* "ia64" IA-64 processor */
|
||||
#define X86_FEATURE_PBE ( 0*32+31) /* "pbe" Pending Break Enable */
|
||||
|
||||
/* AMD-defined CPU features, CPUID level 0x80000001, word 1 */
|
||||
/* Don't duplicate feature flags which are redundant with Intel! */
|
||||
#define X86_FEATURE_SYSCALL ( 1*32+11) /* "syscall" SYSCALL/SYSRET */
|
||||
#define X86_FEATURE_MP ( 1*32+19) /* "mp" MP Capable */
|
||||
#define X86_FEATURE_NX ( 1*32+20) /* "nx" Execute Disable */
|
||||
#define X86_FEATURE_MMXEXT ( 1*32+22) /* "mmxext" AMD MMX extensions */
|
||||
#define X86_FEATURE_FXSR_OPT ( 1*32+25) /* "fxsr_opt" FXSAVE/FXRSTOR optimizations */
|
||||
#define X86_FEATURE_GBPAGES ( 1*32+26) /* "pdpe1gb" GB pages */
|
||||
#define X86_FEATURE_RDTSCP ( 1*32+27) /* "rdtscp" RDTSCP */
|
||||
#define X86_FEATURE_LM ( 1*32+29) /* "lm" Long Mode (x86-64, 64-bit support) */
|
||||
#define X86_FEATURE_3DNOWEXT ( 1*32+30) /* "3dnowext" AMD 3DNow extensions */
|
||||
#define X86_FEATURE_3DNOW ( 1*32+31) /* "3dnow" 3DNow */
|
||||
|
||||
/* Transmeta-defined CPU features, CPUID level 0x80860001, word 2 */
|
||||
#define X86_FEATURE_RECOVERY ( 2*32+ 0) /* "recovery" CPU in recovery mode */
|
||||
#define X86_FEATURE_LONGRUN ( 2*32+ 1) /* "longrun" Longrun power control */
|
||||
#define X86_FEATURE_LRTI ( 2*32+ 3) /* "lrti" LongRun table interface */
|
||||
|
||||
/* Other features, Linux-defined mapping, word 3 */
|
||||
/* This range is used for feature bits which conflict or are synthesized */
|
||||
#define X86_FEATURE_CXMMX ( 3*32+ 0) /* "cxmmx" Cyrix MMX extensions */
|
||||
#define X86_FEATURE_K6_MTRR ( 3*32+ 1) /* "k6_mtrr" AMD K6 nonstandard MTRRs */
|
||||
#define X86_FEATURE_CYRIX_ARR ( 3*32+ 2) /* "cyrix_arr" Cyrix ARRs (= MTRRs) */
|
||||
#define X86_FEATURE_CENTAUR_MCR ( 3*32+ 3) /* "centaur_mcr" Centaur MCRs (= MTRRs) */
|
||||
#define X86_FEATURE_K8 ( 3*32+ 4) /* Opteron, Athlon64 */
|
||||
#define X86_FEATURE_ZEN5 ( 3*32+ 5) /* CPU based on Zen5 microarchitecture */
|
||||
#define X86_FEATURE_ZEN6 ( 3*32+ 6) /* CPU based on Zen6 microarchitecture */
|
||||
/* Free ( 3*32+ 7) */
|
||||
#define X86_FEATURE_CONSTANT_TSC ( 3*32+ 8) /* "constant_tsc" TSC ticks at a constant rate */
|
||||
#define X86_FEATURE_UP ( 3*32+ 9) /* "up" SMP kernel running on UP */
|
||||
#define X86_FEATURE_ART ( 3*32+10) /* "art" Always running timer (ART) */
|
||||
#define X86_FEATURE_ARCH_PERFMON ( 3*32+11) /* "arch_perfmon" Intel Architectural PerfMon */
|
||||
#define X86_FEATURE_PEBS ( 3*32+12) /* "pebs" Precise-Event Based Sampling */
|
||||
#define X86_FEATURE_BTS ( 3*32+13) /* "bts" Branch Trace Store */
|
||||
#define X86_FEATURE_SYSCALL32 ( 3*32+14) /* syscall in IA32 userspace */
|
||||
#define X86_FEATURE_SYSFAST32 ( 3*32+15) /* sysenter/syscall in IA32 userspace */
|
||||
#define X86_FEATURE_REP_GOOD ( 3*32+16) /* "rep_good" REP microcode works well */
|
||||
#define X86_FEATURE_AMD_LBR_V2 ( 3*32+17) /* "amd_lbr_v2" AMD Last Branch Record Extension Version 2 */
|
||||
#define X86_FEATURE_CLEAR_CPU_BUF ( 3*32+18) /* Clear CPU buffers using VERW */
|
||||
#define X86_FEATURE_ACC_POWER ( 3*32+19) /* "acc_power" AMD Accumulated Power Mechanism */
|
||||
#define X86_FEATURE_NOPL ( 3*32+20) /* "nopl" The NOPL (0F 1F) instructions */
|
||||
#define X86_FEATURE_ALWAYS ( 3*32+21) /* Always-present feature */
|
||||
#define X86_FEATURE_XTOPOLOGY ( 3*32+22) /* "xtopology" CPU topology enum extensions */
|
||||
#define X86_FEATURE_TSC_RELIABLE ( 3*32+23) /* "tsc_reliable" TSC is known to be reliable */
|
||||
#define X86_FEATURE_NONSTOP_TSC ( 3*32+24) /* "nonstop_tsc" TSC does not stop in C states */
|
||||
#define X86_FEATURE_CPUID ( 3*32+25) /* "cpuid" CPU has CPUID instruction itself */
|
||||
#define X86_FEATURE_EXTD_APICID ( 3*32+26) /* "extd_apicid" Extended APICID (8 bits) */
|
||||
#define X86_FEATURE_AMD_DCM ( 3*32+27) /* "amd_dcm" AMD multi-node processor */
|
||||
#define X86_FEATURE_APERFMPERF ( 3*32+28) /* "aperfmperf" P-State hardware coordination feedback capability (APERF/MPERF MSRs) */
|
||||
#define X86_FEATURE_RAPL ( 3*32+29) /* "rapl" AMD/Hygon RAPL interface */
|
||||
#define X86_FEATURE_NONSTOP_TSC_S3 ( 3*32+30) /* "nonstop_tsc_s3" TSC doesn't stop in S3 state */
|
||||
#define X86_FEATURE_TSC_KNOWN_FREQ ( 3*32+31) /* "tsc_known_freq" TSC has known frequency */
|
||||
|
||||
/* Intel-defined CPU features, CPUID level 0x00000001 (ECX), word 4 */
|
||||
#define X86_FEATURE_XMM3 ( 4*32+ 0) /* "pni" SSE-3 */
|
||||
#define X86_FEATURE_PCLMULQDQ ( 4*32+ 1) /* "pclmulqdq" PCLMULQDQ instruction */
|
||||
#define X86_FEATURE_DTES64 ( 4*32+ 2) /* "dtes64" 64-bit Debug Store */
|
||||
#define X86_FEATURE_MWAIT ( 4*32+ 3) /* "monitor" MONITOR/MWAIT support */
|
||||
#define X86_FEATURE_DSCPL ( 4*32+ 4) /* "ds_cpl" CPL-qualified (filtered) Debug Store */
|
||||
#define X86_FEATURE_VMX ( 4*32+ 5) /* "vmx" Hardware virtualization */
|
||||
#define X86_FEATURE_SMX ( 4*32+ 6) /* "smx" Safer Mode eXtensions */
|
||||
#define X86_FEATURE_EST ( 4*32+ 7) /* "est" Enhanced SpeedStep */
|
||||
#define X86_FEATURE_TM2 ( 4*32+ 8) /* "tm2" Thermal Monitor 2 */
|
||||
#define X86_FEATURE_SSSE3 ( 4*32+ 9) /* "ssse3" Supplemental SSE-3 */
|
||||
#define X86_FEATURE_CID ( 4*32+10) /* "cid" Context ID */
|
||||
#define X86_FEATURE_SDBG ( 4*32+11) /* "sdbg" Silicon Debug */
|
||||
#define X86_FEATURE_FMA ( 4*32+12) /* "fma" Fused multiply-add */
|
||||
#define X86_FEATURE_CX16 ( 4*32+13) /* "cx16" CMPXCHG16B instruction */
|
||||
#define X86_FEATURE_XTPR ( 4*32+14) /* "xtpr" Send Task Priority Messages */
|
||||
#define X86_FEATURE_PDCM ( 4*32+15) /* "pdcm" Perf/Debug Capabilities MSR */
|
||||
#define X86_FEATURE_PCID ( 4*32+17) /* "pcid" Process Context Identifiers */
|
||||
#define X86_FEATURE_DCA ( 4*32+18) /* "dca" Direct Cache Access */
|
||||
#define X86_FEATURE_XMM4_1 ( 4*32+19) /* "sse4_1" SSE-4.1 */
|
||||
#define X86_FEATURE_XMM4_2 ( 4*32+20) /* "sse4_2" SSE-4.2 */
|
||||
#define X86_FEATURE_X2APIC ( 4*32+21) /* "x2apic" X2APIC */
|
||||
#define X86_FEATURE_MOVBE ( 4*32+22) /* "movbe" MOVBE instruction */
|
||||
#define X86_FEATURE_POPCNT ( 4*32+23) /* "popcnt" POPCNT instruction */
|
||||
#define X86_FEATURE_TSC_DEADLINE_TIMER ( 4*32+24) /* "tsc_deadline_timer" TSC deadline timer */
|
||||
#define X86_FEATURE_AES ( 4*32+25) /* "aes" AES instructions */
|
||||
#define X86_FEATURE_XSAVE ( 4*32+26) /* "xsave" XSAVE/XRSTOR/XSETBV/XGETBV instructions */
|
||||
#define X86_FEATURE_OSXSAVE ( 4*32+27) /* XSAVE instruction enabled in the OS */
|
||||
#define X86_FEATURE_AVX ( 4*32+28) /* "avx" Advanced Vector Extensions */
|
||||
#define X86_FEATURE_F16C ( 4*32+29) /* "f16c" 16-bit FP conversions */
|
||||
#define X86_FEATURE_RDRAND ( 4*32+30) /* "rdrand" RDRAND instruction */
|
||||
#define X86_FEATURE_HYPERVISOR ( 4*32+31) /* "hypervisor" Running on a hypervisor */
|
||||
|
||||
/* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */
|
||||
#define X86_FEATURE_XSTORE ( 5*32+ 2) /* "rng" RNG present (xstore) */
|
||||
#define X86_FEATURE_XSTORE_EN ( 5*32+ 3) /* "rng_en" RNG enabled */
|
||||
#define X86_FEATURE_XCRYPT ( 5*32+ 6) /* "ace" on-CPU crypto (xcrypt) */
|
||||
#define X86_FEATURE_XCRYPT_EN ( 5*32+ 7) /* "ace_en" on-CPU crypto enabled */
|
||||
#define X86_FEATURE_ACE2 ( 5*32+ 8) /* "ace2" Advanced Cryptography Engine v2 */
|
||||
#define X86_FEATURE_ACE2_EN ( 5*32+ 9) /* "ace2_en" ACE v2 enabled */
|
||||
#define X86_FEATURE_PHE ( 5*32+10) /* "phe" PadLock Hash Engine */
|
||||
#define X86_FEATURE_PHE_EN ( 5*32+11) /* "phe_en" PHE enabled */
|
||||
#define X86_FEATURE_PMM ( 5*32+12) /* "pmm" PadLock Montgomery Multiplier */
|
||||
#define X86_FEATURE_PMM_EN ( 5*32+13) /* "pmm_en" PMM enabled */
|
||||
|
||||
/* More extended AMD flags: CPUID level 0x80000001, ECX, word 6 */
|
||||
#define X86_FEATURE_LAHF_LM ( 6*32+ 0) /* "lahf_lm" LAHF/SAHF in long mode */
|
||||
#define X86_FEATURE_CMP_LEGACY ( 6*32+ 1) /* "cmp_legacy" If yes HyperThreading not valid */
|
||||
#define X86_FEATURE_SVM ( 6*32+ 2) /* "svm" Secure Virtual Machine */
|
||||
#define X86_FEATURE_EXTAPIC ( 6*32+ 3) /* "extapic" Extended APIC space */
|
||||
#define X86_FEATURE_CR8_LEGACY ( 6*32+ 4) /* "cr8_legacy" CR8 in 32-bit mode */
|
||||
#define X86_FEATURE_ABM ( 6*32+ 5) /* "abm" Advanced bit manipulation */
|
||||
#define X86_FEATURE_SSE4A ( 6*32+ 6) /* "sse4a" SSE-4A */
|
||||
#define X86_FEATURE_MISALIGNSSE ( 6*32+ 7) /* "misalignsse" Misaligned SSE mode */
|
||||
#define X86_FEATURE_3DNOWPREFETCH ( 6*32+ 8) /* "3dnowprefetch" 3DNow prefetch instructions */
|
||||
#define X86_FEATURE_OSVW ( 6*32+ 9) /* "osvw" OS Visible Workaround */
|
||||
#define X86_FEATURE_IBS ( 6*32+10) /* "ibs" Instruction Based Sampling */
|
||||
#define X86_FEATURE_XOP ( 6*32+11) /* "xop" Extended AVX instructions */
|
||||
#define X86_FEATURE_SKINIT ( 6*32+12) /* "skinit" SKINIT/STGI instructions */
|
||||
#define X86_FEATURE_WDT ( 6*32+13) /* "wdt" Watchdog timer */
|
||||
#define X86_FEATURE_LWP ( 6*32+15) /* "lwp" Light Weight Profiling */
|
||||
#define X86_FEATURE_FMA4 ( 6*32+16) /* "fma4" 4 operands MAC instructions */
|
||||
#define X86_FEATURE_TCE ( 6*32+17) /* "tce" Translation Cache Extension */
|
||||
#define X86_FEATURE_NODEID_MSR ( 6*32+19) /* "nodeid_msr" NodeId MSR */
|
||||
#define X86_FEATURE_TBM ( 6*32+21) /* "tbm" Trailing Bit Manipulations */
|
||||
#define X86_FEATURE_TOPOEXT ( 6*32+22) /* "topoext" Topology extensions CPUID leafs */
|
||||
#define X86_FEATURE_PERFCTR_CORE ( 6*32+23) /* "perfctr_core" Core performance counter extensions */
|
||||
#define X86_FEATURE_PERFCTR_NB ( 6*32+24) /* "perfctr_nb" NB performance counter extensions */
|
||||
#define X86_FEATURE_BPEXT ( 6*32+26) /* "bpext" Data breakpoint extension */
|
||||
#define X86_FEATURE_PTSC ( 6*32+27) /* "ptsc" Performance time-stamp counter */
|
||||
#define X86_FEATURE_PERFCTR_LLC ( 6*32+28) /* "perfctr_llc" Last Level Cache performance counter extensions */
|
||||
#define X86_FEATURE_MWAITX ( 6*32+29) /* "mwaitx" MWAIT extension (MONITORX/MWAITX instructions) */
|
||||
|
||||
/*
|
||||
* Auxiliary flags: Linux defined - For features scattered in various
|
||||
* CPUID levels like 0x6, 0xA etc, word 7.
|
||||
*
|
||||
* Reuse free bits when adding new feature flags!
|
||||
*/
|
||||
#define X86_FEATURE_RING3MWAIT ( 7*32+ 0) /* "ring3mwait" Ring 3 MONITOR/MWAIT instructions */
|
||||
#define X86_FEATURE_CPUID_FAULT ( 7*32+ 1) /* "cpuid_fault" Intel CPUID faulting */
|
||||
#define X86_FEATURE_CPB ( 7*32+ 2) /* "cpb" AMD Core Performance Boost */
|
||||
#define X86_FEATURE_EPB ( 7*32+ 3) /* "epb" IA32_ENERGY_PERF_BIAS support */
|
||||
#define X86_FEATURE_CAT_L3 ( 7*32+ 4) /* "cat_l3" Cache Allocation Technology L3 */
|
||||
#define X86_FEATURE_CAT_L2 ( 7*32+ 5) /* "cat_l2" Cache Allocation Technology L2 */
|
||||
#define X86_FEATURE_CDP_L3 ( 7*32+ 6) /* "cdp_l3" Code and Data Prioritization L3 */
|
||||
#define X86_FEATURE_TDX_HOST_PLATFORM ( 7*32+ 7) /* "tdx_host_platform" Platform supports being a TDX host */
|
||||
#define X86_FEATURE_HW_PSTATE ( 7*32+ 8) /* "hw_pstate" AMD HW-PState */
|
||||
#define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* "proc_feedback" AMD ProcFeedbackInterface */
|
||||
#define X86_FEATURE_XCOMPACTED ( 7*32+10) /* Use compacted XSTATE (XSAVES or XSAVEC) */
|
||||
#define X86_FEATURE_PTI ( 7*32+11) /* "pti" Kernel Page Table Isolation enabled */
|
||||
#define X86_FEATURE_KERNEL_IBRS ( 7*32+12) /* Set/clear IBRS on kernel entry/exit */
|
||||
#define X86_FEATURE_RSB_VMEXIT ( 7*32+13) /* Fill RSB on VM-Exit */
|
||||
#define X86_FEATURE_INTEL_PPIN ( 7*32+14) /* "intel_ppin" Intel Processor Inventory Number */
|
||||
#define X86_FEATURE_CDP_L2 ( 7*32+15) /* "cdp_l2" Code and Data Prioritization L2 */
|
||||
#define X86_FEATURE_MSR_SPEC_CTRL ( 7*32+16) /* MSR SPEC_CTRL is implemented */
|
||||
#define X86_FEATURE_SSBD ( 7*32+17) /* "ssbd" Speculative Store Bypass Disable */
|
||||
#define X86_FEATURE_MBA ( 7*32+18) /* "mba" Memory Bandwidth Allocation */
|
||||
#define X86_FEATURE_RSB_CTXSW ( 7*32+19) /* Fill RSB on context switches */
|
||||
#define X86_FEATURE_PERFMON_V2 ( 7*32+20) /* "perfmon_v2" AMD Performance Monitoring Version 2 */
|
||||
#define X86_FEATURE_USE_IBRS_FW ( 7*32+22) /* Use IBRS during runtime firmware calls */
|
||||
#define X86_FEATURE_SPEC_STORE_BYPASS_DISABLE ( 7*32+23) /* Disable Speculative Store Bypass. */
|
||||
#define X86_FEATURE_LS_CFG_SSBD ( 7*32+24) /* AMD SSBD implementation via LS_CFG MSR */
|
||||
#define X86_FEATURE_IBRS ( 7*32+25) /* "ibrs" Indirect Branch Restricted Speculation */
|
||||
#define X86_FEATURE_IBPB ( 7*32+26) /* "ibpb" Indirect Branch Prediction Barrier without a guaranteed RSB flush */
|
||||
#define X86_FEATURE_STIBP ( 7*32+27) /* "stibp" Single Thread Indirect Branch Predictors */
|
||||
#define X86_FEATURE_ZEN ( 7*32+28) /* Generic flag for all Zen and newer */
|
||||
#define X86_FEATURE_L1TF_PTEINV ( 7*32+29) /* L1TF workaround PTE inversion */
|
||||
#define X86_FEATURE_IBRS_ENHANCED ( 7*32+30) /* "ibrs_enhanced" Enhanced IBRS */
|
||||
#define X86_FEATURE_MSR_IA32_FEAT_CTL ( 7*32+31) /* MSR IA32_FEAT_CTL configured */
|
||||
|
||||
/* Virtualization flags: Linux defined, word 8 */
|
||||
#define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* "tpr_shadow" Intel TPR Shadow */
|
||||
#define X86_FEATURE_FLEXPRIORITY ( 8*32+ 1) /* "flexpriority" Intel FlexPriority */
|
||||
#define X86_FEATURE_EPT ( 8*32+ 2) /* "ept" Intel Extended Page Table */
|
||||
#define X86_FEATURE_VPID ( 8*32+ 3) /* "vpid" Intel Virtual Processor ID */
|
||||
#define X86_FEATURE_COHERENCY_SFW_NO ( 8*32+ 4) /* SNP cache coherency software work around not needed */
|
||||
|
||||
#define X86_FEATURE_VMMCALL ( 8*32+15) /* "vmmcall" Prefer VMMCALL to VMCALL */
|
||||
#define X86_FEATURE_XENPV ( 8*32+16) /* Xen paravirtual guest */
|
||||
#define X86_FEATURE_EPT_AD ( 8*32+17) /* "ept_ad" Intel Extended Page Table access-dirty bit */
|
||||
#define X86_FEATURE_VMCALL ( 8*32+18) /* Hypervisor supports the VMCALL instruction */
|
||||
#define X86_FEATURE_VMW_VMMCALL ( 8*32+19) /* VMware prefers VMMCALL hypercall instruction */
|
||||
#define X86_FEATURE_PVUNLOCK ( 8*32+20) /* PV unlock function */
|
||||
#define X86_FEATURE_VCPUPREEMPT ( 8*32+21) /* PV vcpu_is_preempted function */
|
||||
#define X86_FEATURE_TDX_GUEST ( 8*32+22) /* "tdx_guest" Intel Trust Domain Extensions Guest */
|
||||
|
||||
/* Intel-defined CPU features, CPUID level 0x00000007:0 (EBX), word 9 */
|
||||
#define X86_FEATURE_FSGSBASE ( 9*32+ 0) /* "fsgsbase" RDFSBASE, WRFSBASE, RDGSBASE, WRGSBASE instructions*/
|
||||
#define X86_FEATURE_TSC_ADJUST ( 9*32+ 1) /* "tsc_adjust" TSC adjustment MSR 0x3B */
|
||||
#define X86_FEATURE_SGX ( 9*32+ 2) /* "sgx" Software Guard Extensions */
|
||||
#define X86_FEATURE_BMI1 ( 9*32+ 3) /* "bmi1" 1st group bit manipulation extensions */
|
||||
#define X86_FEATURE_HLE ( 9*32+ 4) /* "hle" Hardware Lock Elision */
|
||||
#define X86_FEATURE_AVX2 ( 9*32+ 5) /* "avx2" AVX2 instructions */
|
||||
#define X86_FEATURE_FDP_EXCPTN_ONLY ( 9*32+ 6) /* FPU data pointer updated only on x87 exceptions */
|
||||
#define X86_FEATURE_SMEP ( 9*32+ 7) /* "smep" Supervisor Mode Execution Protection */
|
||||
#define X86_FEATURE_BMI2 ( 9*32+ 8) /* "bmi2" 2nd group bit manipulation extensions */
|
||||
#define X86_FEATURE_ERMS ( 9*32+ 9) /* "erms" Enhanced REP MOVSB/STOSB instructions */
|
||||
#define X86_FEATURE_INVPCID ( 9*32+10) /* "invpcid" Invalidate Processor Context ID */
|
||||
#define X86_FEATURE_RTM ( 9*32+11) /* "rtm" Restricted Transactional Memory */
|
||||
#define X86_FEATURE_CQM ( 9*32+12) /* "cqm" Cache QoS Monitoring */
|
||||
#define X86_FEATURE_ZERO_FCS_FDS ( 9*32+13) /* Zero out FPU CS and FPU DS */
|
||||
#define X86_FEATURE_MPX ( 9*32+14) /* "mpx" Memory Protection Extension */
|
||||
#define X86_FEATURE_RDT_A ( 9*32+15) /* "rdt_a" Resource Director Technology Allocation */
|
||||
#define X86_FEATURE_AVX512F ( 9*32+16) /* "avx512f" AVX-512 Foundation */
|
||||
#define X86_FEATURE_AVX512DQ ( 9*32+17) /* "avx512dq" AVX-512 DQ (Double/Quad granular) Instructions */
|
||||
#define X86_FEATURE_RDSEED ( 9*32+18) /* "rdseed" RDSEED instruction */
|
||||
#define X86_FEATURE_ADX ( 9*32+19) /* "adx" ADCX and ADOX instructions */
|
||||
#define X86_FEATURE_SMAP ( 9*32+20) /* "smap" Supervisor Mode Access Prevention */
|
||||
#define X86_FEATURE_AVX512IFMA ( 9*32+21) /* "avx512ifma" AVX-512 Integer Fused Multiply-Add instructions */
|
||||
#define X86_FEATURE_CLFLUSHOPT ( 9*32+23) /* "clflushopt" CLFLUSHOPT instruction */
|
||||
#define X86_FEATURE_CLWB ( 9*32+24) /* "clwb" CLWB instruction */
|
||||
#define X86_FEATURE_INTEL_PT ( 9*32+25) /* "intel_pt" Intel Processor Trace */
|
||||
#define X86_FEATURE_AVX512PF ( 9*32+26) /* "avx512pf" AVX-512 Prefetch */
|
||||
#define X86_FEATURE_AVX512ER ( 9*32+27) /* "avx512er" AVX-512 Exponential and Reciprocal */
|
||||
#define X86_FEATURE_AVX512CD ( 9*32+28) /* "avx512cd" AVX-512 Conflict Detection */
|
||||
#define X86_FEATURE_SHA_NI ( 9*32+29) /* "sha_ni" SHA1/SHA256 Instruction Extensions */
|
||||
#define X86_FEATURE_AVX512BW ( 9*32+30) /* "avx512bw" AVX-512 BW (Byte/Word granular) Instructions */
|
||||
#define X86_FEATURE_AVX512VL ( 9*32+31) /* "avx512vl" AVX-512 VL (128/256 Vector Length) Extensions */
|
||||
|
||||
/* Extended state features, CPUID level 0x0000000d:1 (EAX), word 10 */
|
||||
#define X86_FEATURE_XSAVEOPT (10*32+ 0) /* "xsaveopt" XSAVEOPT instruction */
|
||||
#define X86_FEATURE_XSAVEC (10*32+ 1) /* "xsavec" XSAVEC instruction */
|
||||
#define X86_FEATURE_XGETBV1 (10*32+ 2) /* "xgetbv1" XGETBV with ECX = 1 instruction */
|
||||
#define X86_FEATURE_XSAVES (10*32+ 3) /* "xsaves" XSAVES/XRSTORS instructions */
|
||||
#define X86_FEATURE_XFD (10*32+ 4) /* eXtended Feature Disabling */
|
||||
|
||||
/*
|
||||
* Extended auxiliary flags: Linux defined - for features scattered in various
|
||||
* CPUID levels like 0xf, etc.
|
||||
*
|
||||
* Reuse free bits when adding new feature flags!
|
||||
*/
|
||||
#define X86_FEATURE_CQM_LLC (11*32+ 0) /* "cqm_llc" LLC QoS if 1 */
|
||||
#define X86_FEATURE_CQM_OCCUP_LLC (11*32+ 1) /* "cqm_occup_llc" LLC occupancy monitoring */
|
||||
#define X86_FEATURE_CQM_MBM_TOTAL (11*32+ 2) /* "cqm_mbm_total" LLC Total MBM monitoring */
|
||||
#define X86_FEATURE_CQM_MBM_LOCAL (11*32+ 3) /* "cqm_mbm_local" LLC Local MBM monitoring */
|
||||
#define X86_FEATURE_FENCE_SWAPGS_USER (11*32+ 4) /* LFENCE in user entry SWAPGS path */
|
||||
#define X86_FEATURE_FENCE_SWAPGS_KERNEL (11*32+ 5) /* LFENCE in kernel entry SWAPGS path */
|
||||
#define X86_FEATURE_SPLIT_LOCK_DETECT (11*32+ 6) /* "split_lock_detect" #AC for split lock */
|
||||
#define X86_FEATURE_PER_THREAD_MBA (11*32+ 7) /* Per-thread Memory Bandwidth Allocation */
|
||||
#define X86_FEATURE_SGX1 (11*32+ 8) /* Basic SGX */
|
||||
#define X86_FEATURE_SGX2 (11*32+ 9) /* SGX Enclave Dynamic Memory Management (EDMM) */
|
||||
#define X86_FEATURE_ENTRY_IBPB (11*32+10) /* Issue an IBPB on kernel entry */
|
||||
#define X86_FEATURE_RRSBA_CTRL (11*32+11) /* RET prediction control */
|
||||
#define X86_FEATURE_RETPOLINE (11*32+12) /* Generic Retpoline mitigation for Spectre variant 2 */
|
||||
#define X86_FEATURE_RETPOLINE_LFENCE (11*32+13) /* Use LFENCE for Spectre variant 2 */
|
||||
#define X86_FEATURE_RETHUNK (11*32+14) /* Use REturn THUNK */
|
||||
#define X86_FEATURE_UNRET (11*32+15) /* AMD BTB untrain return */
|
||||
#define X86_FEATURE_USE_IBPB_FW (11*32+16) /* Use IBPB during runtime firmware calls */
|
||||
#define X86_FEATURE_RSB_VMEXIT_LITE (11*32+17) /* Fill RSB on VM exit when EIBRS is enabled */
|
||||
#define X86_FEATURE_SGX_EDECCSSA (11*32+18) /* SGX EDECCSSA user leaf function */
|
||||
#define X86_FEATURE_CALL_DEPTH (11*32+19) /* Call depth tracking for RSB stuffing */
|
||||
#define X86_FEATURE_MSR_TSX_CTRL (11*32+20) /* MSR IA32_TSX_CTRL (Intel) implemented */
|
||||
#define X86_FEATURE_SMBA (11*32+21) /* Slow Memory Bandwidth Allocation */
|
||||
#define X86_FEATURE_BMEC (11*32+22) /* Bandwidth Monitoring Event Configuration */
|
||||
#define X86_FEATURE_USER_SHSTK (11*32+23) /* "user_shstk" Shadow stack support for user mode applications */
|
||||
#define X86_FEATURE_SRSO (11*32+24) /* AMD BTB untrain RETs */
|
||||
#define X86_FEATURE_SRSO_ALIAS (11*32+25) /* AMD BTB untrain RETs through aliasing */
|
||||
#define X86_FEATURE_IBPB_ON_VMEXIT (11*32+26) /* Issue an IBPB only on VMEXIT */
|
||||
#define X86_FEATURE_APIC_MSRS_FENCE (11*32+27) /* IA32_TSC_DEADLINE and X2APIC MSRs need fencing */
|
||||
#define X86_FEATURE_ZEN2 (11*32+28) /* CPU based on Zen2 microarchitecture */
|
||||
#define X86_FEATURE_ZEN3 (11*32+29) /* CPU based on Zen3 microarchitecture */
|
||||
#define X86_FEATURE_ZEN4 (11*32+30) /* CPU based on Zen4 microarchitecture */
|
||||
#define X86_FEATURE_ZEN1 (11*32+31) /* CPU based on Zen1 microarchitecture */
|
||||
|
||||
/* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */
|
||||
#define X86_FEATURE_SHA512 (12*32+ 0) /* SHA512 instructions */
|
||||
#define X86_FEATURE_SM3 (12*32+ 1) /* SM3 instructions */
|
||||
#define X86_FEATURE_SM4 (12*32+ 2) /* SM4 instructions */
|
||||
#define X86_FEATURE_AVX_VNNI (12*32+ 4) /* "avx_vnni" AVX VNNI instructions */
|
||||
#define X86_FEATURE_AVX512_BF16 (12*32+ 5) /* "avx512_bf16" AVX512 BFLOAT16 instructions */
|
||||
#define X86_FEATURE_LASS (12*32+ 6) /* "lass" Linear Address Space Separation */
|
||||
#define X86_FEATURE_CMPCCXADD (12*32+ 7) /* CMPccXADD instructions */
|
||||
#define X86_FEATURE_ARCH_PERFMON_EXT (12*32+ 8) /* Intel Architectural PerfMon Extension */
|
||||
#define X86_FEATURE_FZRM (12*32+10) /* Fast zero-length REP MOVSB */
|
||||
#define X86_FEATURE_FSRS (12*32+11) /* Fast short REP STOSB */
|
||||
#define X86_FEATURE_FSRC (12*32+12) /* Fast short REP {CMPSB,SCASB} */
|
||||
#define X86_FEATURE_FRED (12*32+17) /* "fred" Flexible Return and Event Delivery */
|
||||
#define X86_FEATURE_LKGS (12*32+18) /* Like MOV_GS except MSR_KERNEL_GS_BASE = GS.base */
|
||||
#define X86_FEATURE_WRMSRNS (12*32+19) /* Non-serializing WRMSR */
|
||||
#define X86_FEATURE_AMX_FP16 (12*32+21) /* AMX fp16 Support */
|
||||
#define X86_FEATURE_AVX_IFMA (12*32+23) /* Support for VPMADD52[H,L]UQ */
|
||||
#define X86_FEATURE_LAM (12*32+26) /* "lam" Linear Address Masking */
|
||||
#define X86_FEATURE_MOVRS (12*32+31) /* MOVRS instructions */
|
||||
|
||||
/* AMD-defined CPU features, CPUID level 0x80000008 (EBX), word 13 */
|
||||
#define X86_FEATURE_CLZERO (13*32+ 0) /* "clzero" CLZERO instruction */
|
||||
#define X86_FEATURE_IRPERF (13*32+ 1) /* "irperf" Instructions Retired Count */
|
||||
#define X86_FEATURE_XSAVEERPTR (13*32+ 2) /* "xsaveerptr" Always save/restore FP error pointers */
|
||||
#define X86_FEATURE_INVLPGB (13*32+ 3) /* INVLPGB and TLBSYNC instructions supported */
|
||||
#define X86_FEATURE_RDPRU (13*32+ 4) /* "rdpru" Read processor register at user level */
|
||||
#define X86_FEATURE_WBNOINVD (13*32+ 9) /* "wbnoinvd" WBNOINVD instruction */
|
||||
#define X86_FEATURE_AMD_IBPB (13*32+12) /* Indirect Branch Prediction Barrier */
|
||||
#define X86_FEATURE_AMD_IBRS (13*32+14) /* Indirect Branch Restricted Speculation */
|
||||
#define X86_FEATURE_AMD_STIBP (13*32+15) /* Single Thread Indirect Branch Predictors */
|
||||
#define X86_FEATURE_AMD_STIBP_ALWAYS_ON (13*32+17) /* Single Thread Indirect Branch Predictors always-on preferred */
|
||||
#define X86_FEATURE_AMD_IBRS_SAME_MODE (13*32+19) /* Indirect Branch Restricted Speculation same mode protection*/
|
||||
#define X86_FEATURE_EFER_LMSLE_MBZ (13*32+20) /* EFER.LMSLE must be zero */
|
||||
#define X86_FEATURE_AMD_PPIN (13*32+23) /* "amd_ppin" Protected Processor Inventory Number */
|
||||
#define X86_FEATURE_AMD_SSBD (13*32+24) /* Speculative Store Bypass Disable */
|
||||
#define X86_FEATURE_VIRT_SSBD (13*32+25) /* "virt_ssbd" Virtualized Speculative Store Bypass Disable */
|
||||
#define X86_FEATURE_AMD_SSB_NO (13*32+26) /* Speculative Store Bypass is fixed in hardware. */
|
||||
#define X86_FEATURE_CPPC (13*32+27) /* "cppc" Collaborative Processor Performance Control */
|
||||
#define X86_FEATURE_AMD_PSFD (13*32+28) /* Predictive Store Forwarding Disable */
|
||||
#define X86_FEATURE_BTC_NO (13*32+29) /* Not vulnerable to Branch Type Confusion */
|
||||
#define X86_FEATURE_AMD_IBPB_RET (13*32+30) /* IBPB clears return address predictor */
|
||||
#define X86_FEATURE_BRS (13*32+31) /* "brs" Branch Sampling available */
|
||||
|
||||
/* Thermal and Power Management Leaf, CPUID level 0x00000006 (EAX), word 14 */
|
||||
#define X86_FEATURE_DTHERM (14*32+ 0) /* "dtherm" Digital Thermal Sensor */
|
||||
#define X86_FEATURE_IDA (14*32+ 1) /* "ida" Intel Dynamic Acceleration */
|
||||
#define X86_FEATURE_ARAT (14*32+ 2) /* "arat" Always Running APIC Timer */
|
||||
#define X86_FEATURE_PLN (14*32+ 4) /* "pln" Intel Power Limit Notification */
|
||||
#define X86_FEATURE_PTS (14*32+ 6) /* "pts" Intel Package Thermal Status */
|
||||
#define X86_FEATURE_HWP (14*32+ 7) /* "hwp" Intel Hardware P-states */
|
||||
#define X86_FEATURE_HWP_NOTIFY (14*32+ 8) /* "hwp_notify" HWP Notification */
|
||||
#define X86_FEATURE_HWP_ACT_WINDOW (14*32+ 9) /* "hwp_act_window" HWP Activity Window */
|
||||
#define X86_FEATURE_HWP_EPP (14*32+10) /* "hwp_epp" HWP Energy Perf. Preference */
|
||||
#define X86_FEATURE_HWP_PKG_REQ (14*32+11) /* "hwp_pkg_req" HWP Package Level Request */
|
||||
#define X86_FEATURE_HWP_HIGHEST_PERF_CHANGE (14*32+15) /* HWP Highest perf change */
|
||||
#define X86_FEATURE_HFI (14*32+19) /* "hfi" Hardware Feedback Interface */
|
||||
|
||||
/* AMD SVM Feature Identification, CPUID level 0x8000000a (EDX), word 15 */
|
||||
#define X86_FEATURE_NPT (15*32+ 0) /* "npt" Nested Page Table support */
|
||||
#define X86_FEATURE_LBRV (15*32+ 1) /* "lbrv" LBR Virtualization support */
|
||||
#define X86_FEATURE_SVML (15*32+ 2) /* "svm_lock" SVM locking MSR */
|
||||
#define X86_FEATURE_NRIPS (15*32+ 3) /* "nrip_save" SVM next_rip save */
|
||||
#define X86_FEATURE_TSCRATEMSR (15*32+ 4) /* "tsc_scale" TSC scaling support */
|
||||
#define X86_FEATURE_VMCBCLEAN (15*32+ 5) /* "vmcb_clean" VMCB clean bits support */
|
||||
#define X86_FEATURE_FLUSHBYASID (15*32+ 6) /* "flushbyasid" Flush-by-ASID support */
|
||||
#define X86_FEATURE_DECODEASSISTS (15*32+ 7) /* "decodeassists" Decode Assists support */
|
||||
#define X86_FEATURE_PAUSEFILTER (15*32+10) /* "pausefilter" Filtered pause intercept */
|
||||
#define X86_FEATURE_PFTHRESHOLD (15*32+12) /* "pfthreshold" Pause filter threshold */
|
||||
#define X86_FEATURE_AVIC (15*32+13) /* "avic" Virtual Interrupt Controller */
|
||||
#define X86_FEATURE_V_VMSAVE_VMLOAD (15*32+15) /* "v_vmsave_vmload" Virtual VMSAVE VMLOAD */
|
||||
#define X86_FEATURE_VGIF (15*32+16) /* "vgif" Virtual GIF */
|
||||
#define X86_FEATURE_X2AVIC (15*32+18) /* "x2avic" Virtual x2apic */
|
||||
#define X86_FEATURE_V_SPEC_CTRL (15*32+20) /* "v_spec_ctrl" Virtual SPEC_CTRL */
|
||||
#define X86_FEATURE_VNMI (15*32+25) /* "vnmi" Virtual NMI */
|
||||
#define X86_FEATURE_SVME_ADDR_CHK (15*32+28) /* SVME addr check */
|
||||
#define X86_FEATURE_BUS_LOCK_THRESHOLD (15*32+29) /* Bus lock threshold */
|
||||
#define X86_FEATURE_IDLE_HLT (15*32+30) /* IDLE HLT intercept */
|
||||
|
||||
/* Intel-defined CPU features, CPUID level 0x00000007:0 (ECX), word 16 */
|
||||
#define X86_FEATURE_AVX512VBMI (16*32+ 1) /* "avx512vbmi" AVX512 Vector Bit Manipulation instructions*/
|
||||
#define X86_FEATURE_UMIP (16*32+ 2) /* "umip" User Mode Instruction Protection */
|
||||
#define X86_FEATURE_PKU (16*32+ 3) /* "pku" Protection Keys for Userspace */
|
||||
#define X86_FEATURE_OSPKE (16*32+ 4) /* "ospke" OS Protection Keys Enable */
|
||||
#define X86_FEATURE_WAITPKG (16*32+ 5) /* "waitpkg" UMONITOR/UMWAIT/TPAUSE Instructions */
|
||||
#define X86_FEATURE_AVX512_VBMI2 (16*32+ 6) /* "avx512_vbmi2" Additional AVX512 Vector Bit Manipulation Instructions */
|
||||
#define X86_FEATURE_SHSTK (16*32+ 7) /* Shadow stack */
|
||||
#define X86_FEATURE_GFNI (16*32+ 8) /* "gfni" Galois Field New Instructions */
|
||||
#define X86_FEATURE_VAES (16*32+ 9) /* "vaes" Vector AES */
|
||||
#define X86_FEATURE_VPCLMULQDQ (16*32+10) /* "vpclmulqdq" Carry-Less Multiplication Double Quadword */
|
||||
#define X86_FEATURE_AVX512_VNNI (16*32+11) /* "avx512_vnni" Vector Neural Network Instructions */
|
||||
#define X86_FEATURE_AVX512_BITALG (16*32+12) /* "avx512_bitalg" Support for VPOPCNT[B,W] and VPSHUF-BITQMB instructions */
|
||||
#define X86_FEATURE_TME (16*32+13) /* "tme" Intel Total Memory Encryption */
|
||||
#define X86_FEATURE_AVX512_VPOPCNTDQ (16*32+14) /* "avx512_vpopcntdq" POPCNT for vectors of DW/QW */
|
||||
#define X86_FEATURE_LA57 (16*32+16) /* "la57" 5-level page tables */
|
||||
#define X86_FEATURE_RDPID (16*32+22) /* "rdpid" RDPID instruction */
|
||||
#define X86_FEATURE_BUS_LOCK_DETECT (16*32+24) /* "bus_lock_detect" Bus Lock detect */
|
||||
#define X86_FEATURE_CLDEMOTE (16*32+25) /* "cldemote" CLDEMOTE instruction */
|
||||
#define X86_FEATURE_MOVDIRI (16*32+27) /* "movdiri" MOVDIRI instruction */
|
||||
#define X86_FEATURE_MOVDIR64B (16*32+28) /* "movdir64b" MOVDIR64B instruction */
|
||||
#define X86_FEATURE_ENQCMD (16*32+29) /* "enqcmd" ENQCMD and ENQCMDS instructions */
|
||||
#define X86_FEATURE_SGX_LC (16*32+30) /* "sgx_lc" Software Guard Extensions Launch Control */
|
||||
|
||||
/*
|
||||
* Linux-defined word for use with scattered/synthetic bits.
|
||||
*/
|
||||
#define X86_FEATURE_OVERFLOW_RECOV (17*32+ 0) /* "overflow_recov" MCA overflow recovery support */
|
||||
#define X86_FEATURE_SUCCOR (17*32+ 1) /* "succor" Uncorrectable error containment and recovery */
|
||||
|
||||
#define X86_FEATURE_SMCA (17*32+ 3) /* "smca" Scalable MCA */
|
||||
|
||||
/* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */
|
||||
#define X86_FEATURE_AVX512_4VNNIW (18*32+ 2) /* "avx512_4vnniw" AVX-512 Neural Network Instructions */
|
||||
#define X86_FEATURE_AVX512_4FMAPS (18*32+ 3) /* "avx512_4fmaps" AVX-512 Multiply Accumulation Single precision */
|
||||
#define X86_FEATURE_FSRM (18*32+ 4) /* "fsrm" Fast Short Rep Mov */
|
||||
#define X86_FEATURE_AVX512_VP2INTERSECT (18*32+ 8) /* "avx512_vp2intersect" AVX-512 Intersect for D/Q */
|
||||
#define X86_FEATURE_SRBDS_CTRL (18*32+ 9) /* SRBDS mitigation MSR available */
|
||||
#define X86_FEATURE_MD_CLEAR (18*32+10) /* "md_clear" VERW clears CPU buffers */
|
||||
#define X86_FEATURE_RTM_ALWAYS_ABORT (18*32+11) /* RTM transaction always aborts */
|
||||
#define X86_FEATURE_TSX_FORCE_ABORT (18*32+13) /* TSX_FORCE_ABORT */
|
||||
#define X86_FEATURE_SERIALIZE (18*32+14) /* "serialize" SERIALIZE instruction */
|
||||
#define X86_FEATURE_HYBRID_CPU (18*32+15) /* This part has CPUs of more than one type */
|
||||
#define X86_FEATURE_TSXLDTRK (18*32+16) /* "tsxldtrk" TSX Suspend Load Address Tracking */
|
||||
#define X86_FEATURE_PCONFIG (18*32+18) /* "pconfig" Intel PCONFIG */
|
||||
#define X86_FEATURE_ARCH_LBR (18*32+19) /* "arch_lbr" Intel ARCH LBR */
|
||||
#define X86_FEATURE_IBT (18*32+20) /* "ibt" Indirect Branch Tracking */
|
||||
#define X86_FEATURE_AMX_BF16 (18*32+22) /* "amx_bf16" AMX bf16 Support */
|
||||
#define X86_FEATURE_AVX512_FP16 (18*32+23) /* "avx512_fp16" AVX512 FP16 */
|
||||
#define X86_FEATURE_AMX_TILE (18*32+24) /* "amx_tile" AMX tile Support */
|
||||
#define X86_FEATURE_AMX_INT8 (18*32+25) /* "amx_int8" AMX int8 Support */
|
||||
#define X86_FEATURE_SPEC_CTRL (18*32+26) /* Speculation Control (IBRS + IBPB) */
|
||||
#define X86_FEATURE_INTEL_STIBP (18*32+27) /* Single Thread Indirect Branch Predictors */
|
||||
#define X86_FEATURE_FLUSH_L1D (18*32+28) /* "flush_l1d" Flush L1D cache */
|
||||
#define X86_FEATURE_ARCH_CAPABILITIES (18*32+29) /* "arch_capabilities" IA32_ARCH_CAPABILITIES MSR (Intel) */
|
||||
#define X86_FEATURE_CORE_CAPABILITIES (18*32+30) /* IA32_CORE_CAPABILITIES MSR */
|
||||
#define X86_FEATURE_SPEC_CTRL_SSBD (18*32+31) /* Speculative Store Bypass Disable */
|
||||
|
||||
/* AMD-defined memory encryption features, CPUID level 0x8000001f (EAX), word 19 */
|
||||
#define X86_FEATURE_SME (19*32+ 0) /* "sme" Secure Memory Encryption */
|
||||
#define X86_FEATURE_SEV (19*32+ 1) /* "sev" Secure Encrypted Virtualization */
|
||||
#define X86_FEATURE_VM_PAGE_FLUSH (19*32+ 2) /* VM Page Flush MSR is supported */
|
||||
#define X86_FEATURE_SEV_ES (19*32+ 3) /* "sev_es" Secure Encrypted Virtualization - Encrypted State */
|
||||
#define X86_FEATURE_SEV_SNP (19*32+ 4) /* "sev_snp" Secure Encrypted Virtualization - Secure Nested Paging */
|
||||
#define X86_FEATURE_SNP_SECURE_TSC (19*32+ 8) /* SEV-SNP Secure TSC */
|
||||
#define X86_FEATURE_V_TSC_AUX (19*32+ 9) /* Virtual TSC_AUX */
|
||||
#define X86_FEATURE_SME_COHERENT (19*32+10) /* hardware-enforced cache coherency */
|
||||
#define X86_FEATURE_DEBUG_SWAP (19*32+14) /* "debug_swap" SEV-ES full debug state swap support */
|
||||
#define X86_FEATURE_RMPREAD (19*32+21) /* RMPREAD instruction */
|
||||
#define X86_FEATURE_SEGMENTED_RMP (19*32+23) /* Segmented RMP support */
|
||||
#define X86_FEATURE_ALLOWED_SEV_FEATURES (19*32+27) /* Allowed SEV Features */
|
||||
#define X86_FEATURE_SVSM (19*32+28) /* "svsm" SVSM present */
|
||||
#define X86_FEATURE_HV_INUSE_WR_ALLOWED (19*32+30) /* Allow Write to in-use hypervisor-owned pages */
|
||||
|
||||
/* AMD-defined Extended Feature 2 EAX, CPUID level 0x80000021 (EAX), word 20 */
|
||||
#define X86_FEATURE_NO_NESTED_DATA_BP (20*32+ 0) /* No Nested Data Breakpoints */
|
||||
#define X86_FEATURE_WRMSR_XX_BASE_NS (20*32+ 1) /* WRMSR to {FS,GS,KERNEL_GS}_BASE is non-serializing */
|
||||
#define X86_FEATURE_LFENCE_RDTSC (20*32+ 2) /* LFENCE always serializing / synchronizes RDTSC */
|
||||
#define X86_FEATURE_VERW_CLEAR (20*32+ 5) /* The memory form of VERW mitigates TSA */
|
||||
#define X86_FEATURE_NULL_SEL_CLR_BASE (20*32+ 6) /* Null Selector Clears Base */
|
||||
|
||||
#define X86_FEATURE_AUTOIBRS (20*32+ 8) /* Automatic IBRS */
|
||||
#define X86_FEATURE_NO_SMM_CTL_MSR (20*32+ 9) /* SMM_CTL MSR is not present */
|
||||
|
||||
#define X86_FEATURE_GP_ON_USER_CPUID (20*32+17) /* User CPUID faulting */
|
||||
|
||||
#define X86_FEATURE_PREFETCHI (20*32+20) /* Prefetch Data/Instruction to Cache Level */
|
||||
#define X86_FEATURE_ERAPS (20*32+24) /* Enhanced Return Address Predictor Security */
|
||||
#define X86_FEATURE_SBPB (20*32+27) /* Selective Branch Prediction Barrier */
|
||||
#define X86_FEATURE_IBPB_BRTYPE (20*32+28) /* MSR_PRED_CMD[IBPB] flushes all branch type predictions */
|
||||
#define X86_FEATURE_SRSO_NO (20*32+29) /* CPU is not affected by SRSO */
|
||||
#define X86_FEATURE_SRSO_USER_KERNEL_NO (20*32+30) /* CPU is not affected by SRSO across user/kernel boundaries */
|
||||
#define X86_FEATURE_SRSO_BP_SPEC_REDUCE (20*32+31) /*
|
||||
* BP_CFG[BpSpecReduce] can be used to mitigate SRSO for VMs.
|
||||
* (SRSO_MSR_FIX in the official doc).
|
||||
*/
|
||||
|
||||
/*
|
||||
* Extended auxiliary flags: Linux defined - for features scattered in various
|
||||
* CPUID levels like 0x80000022, etc and Linux defined features.
|
||||
*
|
||||
* Reuse free bits when adding new feature flags!
|
||||
*/
|
||||
#define X86_FEATURE_AMD_LBR_PMC_FREEZE (21*32+ 0) /* "amd_lbr_pmc_freeze" AMD LBR and PMC Freeze */
|
||||
#define X86_FEATURE_CLEAR_BHB_LOOP (21*32+ 1) /* Clear branch history at syscall entry using SW loop */
|
||||
#define X86_FEATURE_BHI_CTRL (21*32+ 2) /* BHI_DIS_S HW control available */
|
||||
#define X86_FEATURE_CLEAR_BHB_HW (21*32+ 3) /* BHI_DIS_S HW control enabled */
|
||||
#define X86_FEATURE_CLEAR_BHB_VMEXIT (21*32+ 4) /* Clear branch history at vmexit using SW loop */
|
||||
#define X86_FEATURE_AMD_FAST_CPPC (21*32+ 5) /* Fast CPPC */
|
||||
#define X86_FEATURE_AMD_HTR_CORES (21*32+ 6) /* Heterogeneous Core Topology */
|
||||
#define X86_FEATURE_AMD_WORKLOAD_CLASS (21*32+ 7) /* Workload Classification */
|
||||
#define X86_FEATURE_PREFER_YMM (21*32+ 8) /* Avoid ZMM registers due to downclocking */
|
||||
#define X86_FEATURE_APX (21*32+ 9) /* Advanced Performance Extensions */
|
||||
#define X86_FEATURE_INDIRECT_THUNK_ITS (21*32+10) /* Use thunk for indirect branches in lower half of cacheline */
|
||||
#define X86_FEATURE_TSA_SQ_NO (21*32+11) /* AMD CPU not vulnerable to TSA-SQ */
|
||||
#define X86_FEATURE_TSA_L1_NO (21*32+12) /* AMD CPU not vulnerable to TSA-L1 */
|
||||
#define X86_FEATURE_CLEAR_CPU_BUF_VM (21*32+13) /* Clear CPU buffers using VERW before VMRUN */
|
||||
#define X86_FEATURE_IBPB_EXIT_TO_USER (21*32+14) /* Use IBPB on exit-to-userspace, see VMSCAPE bug */
|
||||
#define X86_FEATURE_ABMC (21*32+15) /* Assignable Bandwidth Monitoring Counters */
|
||||
#define X86_FEATURE_MSR_IMM (21*32+16) /* MSR immediate form instructions */
|
||||
#define X86_FEATURE_SGX_EUPDATESVN (21*32+17) /* Support for ENCLS[EUPDATESVN] instruction */
|
||||
|
||||
#define X86_FEATURE_SDCIAE (21*32+18) /* L3 Smart Data Cache Injection Allocation Enforcement */
|
||||
#define X86_FEATURE_CLEAR_CPU_BUF_VM_MMIO (21*32+19) /*
|
||||
* Clear CPU buffers before VM-Enter if the vCPU
|
||||
* can access host MMIO (ignored for all intents
|
||||
* and purposes if CLEAR_CPU_BUF_VM is set).
|
||||
*/
|
||||
#define X86_FEATURE_X2AVIC_EXT (21*32+20) /* AMD SVM x2AVIC support for 4k vCPUs */
|
||||
|
||||
/*
|
||||
* BUG word(s)
|
||||
*/
|
||||
#define X86_BUG(x) (NCAPINTS*32 + (x))
|
||||
|
||||
#define X86_BUG_F00F X86_BUG(0) /* "f00f" Intel F00F */
|
||||
#define X86_BUG_FDIV X86_BUG(1) /* "fdiv" FPU FDIV */
|
||||
#define X86_BUG_COMA X86_BUG(2) /* "coma" Cyrix 6x86 coma */
|
||||
#define X86_BUG_AMD_TLB_MMATCH X86_BUG(3) /* "tlb_mmatch" AMD Erratum 383 */
|
||||
#define X86_BUG_AMD_APIC_C1E X86_BUG(4) /* "apic_c1e" AMD Erratum 400 */
|
||||
#define X86_BUG_11AP X86_BUG(5) /* "11ap" Bad local APIC aka 11AP */
|
||||
#define X86_BUG_FXSAVE_LEAK X86_BUG(6) /* "fxsave_leak" FXSAVE leaks FOP/FIP/FOP */
|
||||
#define X86_BUG_CLFLUSH_MONITOR X86_BUG(7) /* "clflush_monitor" AAI65, CLFLUSH required before MONITOR */
|
||||
#define X86_BUG_SYSRET_SS_ATTRS X86_BUG(8) /* "sysret_ss_attrs" SYSRET doesn't fix up SS attrs */
|
||||
#ifdef CONFIG_X86_32
|
||||
/*
|
||||
* 64-bit kernels don't use X86_BUG_ESPFIX. Make the define conditional
|
||||
* to avoid confusion.
|
||||
*/
|
||||
#define X86_BUG_ESPFIX X86_BUG(9) /* IRET to 16-bit SS corrupts ESP/RSP high bits */
|
||||
#endif
|
||||
#define X86_BUG_NULL_SEG X86_BUG(10) /* "null_seg" Nulling a selector preserves the base */
|
||||
#define X86_BUG_SWAPGS_FENCE X86_BUG(11) /* "swapgs_fence" SWAPGS without input dep on GS */
|
||||
#define X86_BUG_MONITOR X86_BUG(12) /* "monitor" IPI required to wake up remote CPU */
|
||||
#define X86_BUG_AMD_E400 X86_BUG(13) /* "amd_e400" CPU is among the affected by Erratum 400 */
|
||||
#define X86_BUG_CPU_MELTDOWN X86_BUG(14) /* "cpu_meltdown" CPU is affected by meltdown attack and needs kernel page table isolation */
|
||||
#define X86_BUG_SPECTRE_V1 X86_BUG(15) /* "spectre_v1" CPU is affected by Spectre variant 1 attack with conditional branches */
|
||||
#define X86_BUG_SPECTRE_V2 X86_BUG(16) /* "spectre_v2" CPU is affected by Spectre variant 2 attack with indirect branches */
|
||||
#define X86_BUG_SPEC_STORE_BYPASS X86_BUG(17) /* "spec_store_bypass" CPU is affected by speculative store bypass attack */
|
||||
#define X86_BUG_L1TF X86_BUG(18) /* "l1tf" CPU is affected by L1 Terminal Fault */
|
||||
#define X86_BUG_MDS X86_BUG(19) /* "mds" CPU is affected by Microarchitectural data sampling */
|
||||
#define X86_BUG_MSBDS_ONLY X86_BUG(20) /* "msbds_only" CPU is only affected by the MSDBS variant of BUG_MDS */
|
||||
#define X86_BUG_SWAPGS X86_BUG(21) /* "swapgs" CPU is affected by speculation through SWAPGS */
|
||||
#define X86_BUG_TAA X86_BUG(22) /* "taa" CPU is affected by TSX Async Abort(TAA) */
|
||||
#define X86_BUG_ITLB_MULTIHIT X86_BUG(23) /* "itlb_multihit" CPU may incur MCE during certain page attribute changes */
|
||||
#define X86_BUG_SRBDS X86_BUG(24) /* "srbds" CPU may leak RNG bits if not mitigated */
|
||||
#define X86_BUG_MMIO_STALE_DATA X86_BUG(25) /* "mmio_stale_data" CPU is affected by Processor MMIO Stale Data vulnerabilities */
|
||||
/* unused, was #define X86_BUG_MMIO_UNKNOWN X86_BUG(26) "mmio_unknown" CPU is too old and its MMIO Stale Data status is unknown */
|
||||
#define X86_BUG_RETBLEED X86_BUG(27) /* "retbleed" CPU is affected by RETBleed */
|
||||
#define X86_BUG_EIBRS_PBRSB X86_BUG(28) /* "eibrs_pbrsb" EIBRS is vulnerable to Post Barrier RSB Predictions */
|
||||
#define X86_BUG_SMT_RSB X86_BUG(29) /* "smt_rsb" CPU is vulnerable to Cross-Thread Return Address Predictions */
|
||||
#define X86_BUG_GDS X86_BUG(30) /* "gds" CPU is affected by Gather Data Sampling */
|
||||
#define X86_BUG_TDX_PW_MCE X86_BUG(31) /* "tdx_pw_mce" CPU may incur #MC if non-TD software does partial write to TDX private memory */
|
||||
|
||||
/* BUG word 2 */
|
||||
#define X86_BUG_SRSO X86_BUG( 1*32+ 0) /* "srso" AMD SRSO bug */
|
||||
#define X86_BUG_DIV0 X86_BUG( 1*32+ 1) /* "div0" AMD DIV0 speculation bug */
|
||||
#define X86_BUG_RFDS X86_BUG( 1*32+ 2) /* "rfds" CPU is vulnerable to Register File Data Sampling */
|
||||
#define X86_BUG_BHI X86_BUG( 1*32+ 3) /* "bhi" CPU is affected by Branch History Injection */
|
||||
#define X86_BUG_IBPB_NO_RET X86_BUG( 1*32+ 4) /* "ibpb_no_ret" IBPB omits return target predictions */
|
||||
#define X86_BUG_SPECTRE_V2_USER X86_BUG( 1*32+ 5) /* "spectre_v2_user" CPU is affected by Spectre variant 2 attack between user processes */
|
||||
#define X86_BUG_OLD_MICROCODE X86_BUG( 1*32+ 6) /* "old_microcode" CPU has old microcode, it is surely vulnerable to something */
|
||||
#define X86_BUG_ITS X86_BUG( 1*32+ 7) /* "its" CPU is affected by Indirect Target Selection */
|
||||
#define X86_BUG_ITS_NATIVE_ONLY X86_BUG( 1*32+ 8) /* "its_native_only" CPU is affected by ITS, VMX is not affected */
|
||||
#define X86_BUG_TSA X86_BUG( 1*32+ 9) /* "tsa" CPU is affected by Transient Scheduler Attacks */
|
||||
#define X86_BUG_VMSCAPE X86_BUG( 1*32+10) /* "vmscape" CPU is affected by VMSCAPE attacks from guests */
|
||||
#endif /* _ASM_X86_CPUFEATURES_H */
|
||||
@@ -0,0 +1,292 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_CPUID_API_H
|
||||
#define _ASM_X86_CPUID_API_H
|
||||
|
||||
#include <asm/cpuid/types.h>
|
||||
|
||||
#include <linux/build_bug.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/string.h>
|
||||
|
||||
/*
|
||||
* Raw CPUID accessors:
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
bool cpuid_feature(void);
|
||||
#else
|
||||
static inline bool cpuid_feature(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void native_cpuid(u32 *eax, u32 *ebx,
|
||||
u32 *ecx, u32 *edx)
|
||||
{
|
||||
/* ecx is often an input as well as an output. */
|
||||
asm volatile("cpuid"
|
||||
: "=a" (*eax),
|
||||
"=b" (*ebx),
|
||||
"=c" (*ecx),
|
||||
"=d" (*edx)
|
||||
: "0" (*eax), "2" (*ecx)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
#define NATIVE_CPUID_REG(reg) \
|
||||
static inline u32 native_cpuid_##reg(u32 op) \
|
||||
{ \
|
||||
u32 eax = op, ebx, ecx = 0, edx; \
|
||||
\
|
||||
native_cpuid(&eax, &ebx, &ecx, &edx); \
|
||||
\
|
||||
return reg; \
|
||||
}
|
||||
|
||||
/*
|
||||
* Native CPUID functions returning a single datum:
|
||||
*/
|
||||
NATIVE_CPUID_REG(eax)
|
||||
NATIVE_CPUID_REG(ebx)
|
||||
NATIVE_CPUID_REG(ecx)
|
||||
NATIVE_CPUID_REG(edx)
|
||||
|
||||
#ifdef CONFIG_PARAVIRT_XXL
|
||||
# include <asm/paravirt.h>
|
||||
#else
|
||||
# define __cpuid native_cpuid
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Generic CPUID function
|
||||
*
|
||||
* Clear ECX since some CPUs (Cyrix MII) do not set or clear ECX
|
||||
* resulting in stale register contents being returned.
|
||||
*/
|
||||
static inline void cpuid(u32 op,
|
||||
u32 *eax, u32 *ebx,
|
||||
u32 *ecx, u32 *edx)
|
||||
{
|
||||
*eax = op;
|
||||
*ecx = 0;
|
||||
__cpuid(eax, ebx, ecx, edx);
|
||||
}
|
||||
|
||||
/* Some CPUID calls want 'count' to be placed in ECX */
|
||||
static inline void cpuid_count(u32 op, int count,
|
||||
u32 *eax, u32 *ebx,
|
||||
u32 *ecx, u32 *edx)
|
||||
{
|
||||
*eax = op;
|
||||
*ecx = count;
|
||||
__cpuid(eax, ebx, ecx, edx);
|
||||
}
|
||||
|
||||
/*
|
||||
* CPUID functions returning a single datum:
|
||||
*/
|
||||
|
||||
static inline u32 cpuid_eax(u32 op)
|
||||
{
|
||||
u32 eax, ebx, ecx, edx;
|
||||
|
||||
cpuid(op, &eax, &ebx, &ecx, &edx);
|
||||
|
||||
return eax;
|
||||
}
|
||||
|
||||
static inline u32 cpuid_ebx(u32 op)
|
||||
{
|
||||
u32 eax, ebx, ecx, edx;
|
||||
|
||||
cpuid(op, &eax, &ebx, &ecx, &edx);
|
||||
|
||||
return ebx;
|
||||
}
|
||||
|
||||
static inline u32 cpuid_ecx(u32 op)
|
||||
{
|
||||
u32 eax, ebx, ecx, edx;
|
||||
|
||||
cpuid(op, &eax, &ebx, &ecx, &edx);
|
||||
|
||||
return ecx;
|
||||
}
|
||||
|
||||
static inline u32 cpuid_edx(u32 op)
|
||||
{
|
||||
u32 eax, ebx, ecx, edx;
|
||||
|
||||
cpuid(op, &eax, &ebx, &ecx, &edx);
|
||||
|
||||
return edx;
|
||||
}
|
||||
|
||||
static inline void __cpuid_read(u32 leaf, u32 subleaf, u32 *regs)
|
||||
{
|
||||
regs[CPUID_EAX] = leaf;
|
||||
regs[CPUID_ECX] = subleaf;
|
||||
__cpuid(regs + CPUID_EAX, regs + CPUID_EBX, regs + CPUID_ECX, regs + CPUID_EDX);
|
||||
}
|
||||
|
||||
#define cpuid_subleaf(leaf, subleaf, regs) { \
|
||||
static_assert(sizeof(*(regs)) == 16); \
|
||||
__cpuid_read(leaf, subleaf, (u32 *)(regs)); \
|
||||
}
|
||||
|
||||
#define cpuid_leaf(leaf, regs) { \
|
||||
static_assert(sizeof(*(regs)) == 16); \
|
||||
__cpuid_read(leaf, 0, (u32 *)(regs)); \
|
||||
}
|
||||
|
||||
static inline void __cpuid_read_reg(u32 leaf, u32 subleaf,
|
||||
enum cpuid_regs_idx regidx, u32 *reg)
|
||||
{
|
||||
u32 regs[4];
|
||||
|
||||
__cpuid_read(leaf, subleaf, regs);
|
||||
*reg = regs[regidx];
|
||||
}
|
||||
|
||||
#define cpuid_subleaf_reg(leaf, subleaf, regidx, reg) { \
|
||||
static_assert(sizeof(*(reg)) == 4); \
|
||||
__cpuid_read_reg(leaf, subleaf, regidx, (u32 *)(reg)); \
|
||||
}
|
||||
|
||||
#define cpuid_leaf_reg(leaf, regidx, reg) { \
|
||||
static_assert(sizeof(*(reg)) == 4); \
|
||||
__cpuid_read_reg(leaf, 0, regidx, (u32 *)(reg)); \
|
||||
}
|
||||
|
||||
/*
|
||||
* Hypervisor-related APIs:
|
||||
*/
|
||||
|
||||
static __always_inline bool cpuid_function_is_indexed(u32 function)
|
||||
{
|
||||
switch (function) {
|
||||
case 4:
|
||||
case 7:
|
||||
case 0xb:
|
||||
case 0xd:
|
||||
case 0xf:
|
||||
case 0x10:
|
||||
case 0x12:
|
||||
case 0x14:
|
||||
case 0x17:
|
||||
case 0x18:
|
||||
case 0x1d:
|
||||
case 0x1e:
|
||||
case 0x1f:
|
||||
case 0x24:
|
||||
case 0x8000001d:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#define for_each_possible_cpuid_base_hypervisor(function) \
|
||||
for (function = 0x40000000; function < 0x40010000; function += 0x100)
|
||||
|
||||
static inline u32 cpuid_base_hypervisor(const char *sig, u32 leaves)
|
||||
{
|
||||
u32 base, eax, signature[3];
|
||||
|
||||
for_each_possible_cpuid_base_hypervisor(base) {
|
||||
cpuid(base, &eax, &signature[0], &signature[1], &signature[2]);
|
||||
|
||||
/*
|
||||
* This must not compile to "call memcmp" because it's called
|
||||
* from PVH early boot code before instrumentation is set up
|
||||
* and memcmp() itself may be instrumented.
|
||||
*/
|
||||
if (!__builtin_memcmp(sig, signature, 12) &&
|
||||
(leaves == 0 || ((eax - base) >= leaves)))
|
||||
return base;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* CPUID(0x2) parsing:
|
||||
*/
|
||||
|
||||
/**
|
||||
* cpuid_leaf_0x2() - Return sanitized CPUID(0x2) register output
|
||||
* @regs: Output parameter
|
||||
*
|
||||
* Query CPUID(0x2) and store its output in @regs. Force set any
|
||||
* invalid 1-byte descriptor returned by the hardware to zero (the NULL
|
||||
* cache/TLB descriptor) before returning it to the caller.
|
||||
*
|
||||
* Use for_each_cpuid_0x2_desc() to iterate over the register output in
|
||||
* parsed form.
|
||||
*/
|
||||
static inline void cpuid_leaf_0x2(union leaf_0x2_regs *regs)
|
||||
{
|
||||
cpuid_leaf(0x2, regs);
|
||||
|
||||
/*
|
||||
* All Intel CPUs must report an iteration count of 1. In case
|
||||
* of bogus hardware, treat all returned descriptors as NULL.
|
||||
*/
|
||||
if (regs->desc[0] != 0x01) {
|
||||
for (int i = 0; i < 4; i++)
|
||||
regs->regv[i] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The most significant bit (MSB) of each register must be clear.
|
||||
* If a register is invalid, replace its descriptors with NULL.
|
||||
*/
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (regs->reg[i].invalid)
|
||||
regs->regv[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* for_each_cpuid_0x2_desc() - Iterator for parsed CPUID(0x2) descriptors
|
||||
* @_regs: CPUID(0x2) register output, as returned by cpuid_leaf_0x2()
|
||||
* @_ptr: u8 pointer, for macro internal use only
|
||||
* @_desc: Pointer to the parsed CPUID(0x2) descriptor at each iteration
|
||||
*
|
||||
* Loop over the 1-byte descriptors in the passed CPUID(0x2) output registers
|
||||
* @_regs. Provide the parsed information for each descriptor through @_desc.
|
||||
*
|
||||
* To handle cache-specific descriptors, switch on @_desc->c_type. For TLB
|
||||
* descriptors, switch on @_desc->t_type.
|
||||
*
|
||||
* Example usage for cache descriptors::
|
||||
*
|
||||
* const struct leaf_0x2_table *desc;
|
||||
* union leaf_0x2_regs regs;
|
||||
* u8 *ptr;
|
||||
*
|
||||
* cpuid_leaf_0x2(®s);
|
||||
* for_each_cpuid_0x2_desc(regs, ptr, desc) {
|
||||
* switch (desc->c_type) {
|
||||
* ...
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
#define for_each_cpuid_0x2_desc(_regs, _ptr, _desc) \
|
||||
for (_ptr = &(_regs).desc[1]; \
|
||||
_ptr < &(_regs).desc[16] && (_desc = &cpuid_0x2_table[*_ptr]); \
|
||||
_ptr++)
|
||||
|
||||
/*
|
||||
* CPUID(0x80000006) parsing:
|
||||
*/
|
||||
|
||||
static inline bool cpuid_amd_hygon_has_l3_cache(void)
|
||||
{
|
||||
return cpuid_edx(0x80000006);
|
||||
}
|
||||
|
||||
#endif /* _ASM_X86_CPUID_API_H */
|
||||
@@ -0,0 +1,127 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_CPUID_TYPES_H
|
||||
#define _ASM_X86_CPUID_TYPES_H
|
||||
|
||||
#include <linux/build_bug.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/*
|
||||
* Types for raw CPUID access:
|
||||
*/
|
||||
|
||||
struct cpuid_regs {
|
||||
u32 eax;
|
||||
u32 ebx;
|
||||
u32 ecx;
|
||||
u32 edx;
|
||||
};
|
||||
|
||||
enum cpuid_regs_idx {
|
||||
CPUID_EAX = 0,
|
||||
CPUID_EBX,
|
||||
CPUID_ECX,
|
||||
CPUID_EDX,
|
||||
};
|
||||
|
||||
#define CPUID_LEAF_MWAIT 0x05
|
||||
#define CPUID_LEAF_DCA 0x09
|
||||
#define CPUID_LEAF_XSTATE 0x0d
|
||||
#define CPUID_LEAF_TSC 0x15
|
||||
#define CPUID_LEAF_FREQ 0x16
|
||||
#define CPUID_LEAF_TILE 0x1d
|
||||
|
||||
/*
|
||||
* Types for CPUID(0x2) parsing:
|
||||
*/
|
||||
|
||||
struct leaf_0x2_reg {
|
||||
u32 : 31,
|
||||
invalid : 1;
|
||||
};
|
||||
|
||||
union leaf_0x2_regs {
|
||||
struct leaf_0x2_reg reg[4];
|
||||
u32 regv[4];
|
||||
u8 desc[16];
|
||||
};
|
||||
|
||||
/*
|
||||
* Leaf 0x2 1-byte descriptors' cache types
|
||||
* To be used for their mappings at cpuid_0x2_table[]
|
||||
*
|
||||
* Start at 1 since type 0 is reserved for HW byte descriptors which are
|
||||
* not recognized by the kernel; i.e., those without an explicit mapping.
|
||||
*/
|
||||
enum _cache_table_type {
|
||||
CACHE_L1_INST = 1,
|
||||
CACHE_L1_DATA,
|
||||
CACHE_L2,
|
||||
CACHE_L3
|
||||
/* Adjust __TLB_TABLE_TYPE_BEGIN before adding more types */
|
||||
} __packed;
|
||||
#ifndef __CHECKER__
|
||||
static_assert(sizeof(enum _cache_table_type) == 1);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Ensure that leaf 0x2 cache and TLB type values do not intersect,
|
||||
* since they share the same type field at struct cpuid_0x2_table.
|
||||
*/
|
||||
#define __TLB_TABLE_TYPE_BEGIN (CACHE_L3 + 1)
|
||||
|
||||
/*
|
||||
* Leaf 0x2 1-byte descriptors' TLB types
|
||||
* To be used for their mappings at cpuid_0x2_table[]
|
||||
*/
|
||||
enum _tlb_table_type {
|
||||
TLB_INST_4K = __TLB_TABLE_TYPE_BEGIN,
|
||||
TLB_INST_4M,
|
||||
TLB_INST_2M_4M,
|
||||
TLB_INST_ALL,
|
||||
|
||||
TLB_DATA_4K,
|
||||
TLB_DATA_4M,
|
||||
TLB_DATA_2M_4M,
|
||||
TLB_DATA_4K_4M,
|
||||
TLB_DATA_1G,
|
||||
TLB_DATA_1G_2M_4M,
|
||||
|
||||
TLB_DATA0_4K,
|
||||
TLB_DATA0_4M,
|
||||
TLB_DATA0_2M_4M,
|
||||
|
||||
STLB_4K,
|
||||
STLB_4K_2M,
|
||||
} __packed;
|
||||
#ifndef __CHECKER__
|
||||
static_assert(sizeof(enum _tlb_table_type) == 1);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Combined parsing table for leaf 0x2 cache and TLB descriptors.
|
||||
*/
|
||||
|
||||
struct leaf_0x2_table {
|
||||
union {
|
||||
enum _cache_table_type c_type;
|
||||
enum _tlb_table_type t_type;
|
||||
};
|
||||
union {
|
||||
short c_size;
|
||||
short entries;
|
||||
};
|
||||
};
|
||||
|
||||
extern const struct leaf_0x2_table cpuid_0x2_table[256];
|
||||
|
||||
/*
|
||||
* All of leaf 0x2's one-byte TLB descriptors implies the same number of entries
|
||||
* for their respective TLB types. TLB descriptor 0x63 is an exception: it
|
||||
* implies 4 dTLB entries for 1GB pages and 32 dTLB entries for 2MB or 4MB pages.
|
||||
*
|
||||
* Encode that descriptor's dTLB entry count for 2MB/4MB pages here, as the entry
|
||||
* count for dTLB 1GB pages is already encoded at the cpuid_0x2_table[]'s mapping.
|
||||
*/
|
||||
#define TLB_0x63_2M_4M_ENTRIES 32
|
||||
|
||||
#endif /* _ASM_X86_CPUID_TYPES_H */
|
||||
@@ -0,0 +1,8 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ARCH_HALTPOLL_H
|
||||
#define _ARCH_HALTPOLL_H
|
||||
|
||||
void arch_haltpoll_enable(unsigned int cpu);
|
||||
void arch_haltpoll_disable(unsigned int cpu);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,40 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_CPUMASK_H
|
||||
#define _ASM_X86_CPUMASK_H
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/cpumask.h>
|
||||
|
||||
extern void setup_cpu_local_masks(void);
|
||||
|
||||
/*
|
||||
* NMI and MCE exceptions need cpu_is_offline() _really_ early,
|
||||
* provide an arch_ special for them to avoid instrumentation.
|
||||
*/
|
||||
#if NR_CPUS > 1
|
||||
static __always_inline bool arch_cpu_online(int cpu)
|
||||
{
|
||||
return arch_test_bit(cpu, cpumask_bits(cpu_online_mask));
|
||||
}
|
||||
|
||||
static __always_inline void arch_cpumask_clear_cpu(int cpu, struct cpumask *dstp)
|
||||
{
|
||||
arch_clear_bit(cpumask_check(cpu), cpumask_bits(dstp));
|
||||
}
|
||||
#else
|
||||
static __always_inline bool arch_cpu_online(int cpu)
|
||||
{
|
||||
return cpu == 0;
|
||||
}
|
||||
|
||||
static __always_inline void arch_cpumask_clear_cpu(int cpu, struct cpumask *dstp)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define arch_cpu_is_offline(cpu) unlikely(!arch_cpu_online(cpu))
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
#endif /* _ASM_X86_CPUMASK_H */
|
||||
@@ -0,0 +1,12 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_CRASH_H
|
||||
#define _ASM_X86_CRASH_H
|
||||
|
||||
struct kimage;
|
||||
|
||||
int crash_load_segments(struct kimage *image);
|
||||
int crash_setup_memmap_entries(struct kimage *image,
|
||||
struct boot_params *params);
|
||||
void crash_smp_send_stop(void);
|
||||
|
||||
#endif /* _ASM_X86_CRASH_H */
|
||||
@@ -0,0 +1,44 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _X86_CRASH_RESERVE_H
|
||||
#define _X86_CRASH_RESERVE_H
|
||||
|
||||
/* 16M alignment for crash kernel regions */
|
||||
#define CRASH_ALIGN SZ_16M
|
||||
|
||||
/*
|
||||
* Keep the crash kernel below this limit.
|
||||
*
|
||||
* Earlier 32-bits kernels would limit the kernel to the low 512 MB range
|
||||
* due to mapping restrictions.
|
||||
*
|
||||
* 64-bit kdump kernels need to be restricted to be under 64 TB, which is
|
||||
* the upper limit of system RAM in 4-level paging mode. Since the kdump
|
||||
* jump could be from 5-level paging to 4-level paging, the jump will fail if
|
||||
* the kernel is put above 64 TB, and during the 1st kernel bootup there's
|
||||
* no good way to detect the paging mode of the target kernel which will be
|
||||
* loaded for dumping.
|
||||
*/
|
||||
extern unsigned long swiotlb_size_or_default(void);
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
# define CRASH_ADDR_LOW_MAX SZ_512M
|
||||
# define CRASH_ADDR_HIGH_MAX SZ_512M
|
||||
#else
|
||||
# define CRASH_ADDR_LOW_MAX SZ_4G
|
||||
# define CRASH_ADDR_HIGH_MAX SZ_64T
|
||||
#endif
|
||||
|
||||
# define DEFAULT_CRASH_KERNEL_LOW_SIZE crash_low_size_default()
|
||||
|
||||
static inline unsigned long crash_low_size_default(void)
|
||||
{
|
||||
#ifdef CONFIG_X86_64
|
||||
return max(swiotlb_size_or_default() + (8UL << 20), 256UL << 20);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define HAVE_ARCH_ADD_CRASH_RES_TO_IOMEM_EARLY
|
||||
|
||||
#endif /* _X86_CRASH_RESERVE_H */
|
||||
@@ -0,0 +1,32 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_CURRENT_H
|
||||
#define _ASM_X86_CURRENT_H
|
||||
|
||||
#include <linux/build_bug.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#include <linux/cache.h>
|
||||
#include <asm/percpu.h>
|
||||
|
||||
struct task_struct;
|
||||
|
||||
DECLARE_PER_CPU_CACHE_HOT(struct task_struct *, current_task);
|
||||
/* const-qualified alias provided by the linker. */
|
||||
DECLARE_PER_CPU_CACHE_HOT(struct task_struct * const __percpu_seg_override,
|
||||
const_current_task);
|
||||
|
||||
static __always_inline struct task_struct *get_current(void)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_USE_X86_SEG_SUPPORT))
|
||||
return this_cpu_read_const(const_current_task);
|
||||
|
||||
return this_cpu_read_stable(current_task);
|
||||
}
|
||||
|
||||
#define current get_current()
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
|
||||
#endif /* _ASM_X86_CURRENT_H */
|
||||
@@ -0,0 +1,197 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_DEBUGREG_H
|
||||
#define _ASM_X86_DEBUGREG_H
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <uapi/asm/debugreg.h>
|
||||
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/msr.h>
|
||||
|
||||
/*
|
||||
* Define bits that are always set to 1 in DR7, only bit 10 is
|
||||
* architecturally reserved to '1'.
|
||||
*
|
||||
* This is also the init/reset value for DR7.
|
||||
*/
|
||||
#define DR7_FIXED_1 0x00000400
|
||||
|
||||
DECLARE_PER_CPU(unsigned long, cpu_dr7);
|
||||
|
||||
#ifndef CONFIG_PARAVIRT_XXL
|
||||
/*
|
||||
* These special macros can be used to get or set a debugging register
|
||||
*/
|
||||
#define get_debugreg(var, register) \
|
||||
(var) = native_get_debugreg(register)
|
||||
#define set_debugreg(value, register) \
|
||||
native_set_debugreg(register, value)
|
||||
#endif
|
||||
|
||||
static __always_inline unsigned long native_get_debugreg(int regno)
|
||||
{
|
||||
unsigned long val;
|
||||
|
||||
switch (regno) {
|
||||
case 0:
|
||||
asm("mov %%db0, %0" :"=r" (val));
|
||||
break;
|
||||
case 1:
|
||||
asm("mov %%db1, %0" :"=r" (val));
|
||||
break;
|
||||
case 2:
|
||||
asm("mov %%db2, %0" :"=r" (val));
|
||||
break;
|
||||
case 3:
|
||||
asm("mov %%db3, %0" :"=r" (val));
|
||||
break;
|
||||
case 6:
|
||||
asm("mov %%db6, %0" :"=r" (val));
|
||||
break;
|
||||
case 7:
|
||||
/*
|
||||
* Use "asm volatile" for DR7 reads to forbid re-ordering them
|
||||
* with other code.
|
||||
*
|
||||
* This is needed because a DR7 access can cause a #VC exception
|
||||
* when running under SEV-ES. Taking a #VC exception is not a
|
||||
* safe thing to do just anywhere in the entry code and
|
||||
* re-ordering might place the access into an unsafe location.
|
||||
*
|
||||
* This happened in the NMI handler, where the DR7 read was
|
||||
* re-ordered to happen before the call to sev_es_ist_enter(),
|
||||
* causing stack recursion.
|
||||
*/
|
||||
asm volatile("mov %%db7, %0" : "=r" (val));
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static __always_inline void native_set_debugreg(int regno, unsigned long value)
|
||||
{
|
||||
switch (regno) {
|
||||
case 0:
|
||||
asm("mov %0, %%db0" ::"r" (value));
|
||||
break;
|
||||
case 1:
|
||||
asm("mov %0, %%db1" ::"r" (value));
|
||||
break;
|
||||
case 2:
|
||||
asm("mov %0, %%db2" ::"r" (value));
|
||||
break;
|
||||
case 3:
|
||||
asm("mov %0, %%db3" ::"r" (value));
|
||||
break;
|
||||
case 6:
|
||||
asm("mov %0, %%db6" ::"r" (value));
|
||||
break;
|
||||
case 7:
|
||||
/*
|
||||
* Use "asm volatile" for DR7 writes to forbid re-ordering them
|
||||
* with other code.
|
||||
*
|
||||
* While is didn't happen with a DR7 write (see the DR7 read
|
||||
* comment above which explains where it happened), add the
|
||||
* "asm volatile" here too to avoid similar problems in the
|
||||
* future.
|
||||
*/
|
||||
asm volatile("mov %0, %%db7" ::"r" (value));
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
static inline void hw_breakpoint_disable(void)
|
||||
{
|
||||
/* Reset the control register for HW Breakpoint */
|
||||
set_debugreg(DR7_FIXED_1, 7);
|
||||
|
||||
/* Zero-out the individual HW breakpoint address registers */
|
||||
set_debugreg(0UL, 0);
|
||||
set_debugreg(0UL, 1);
|
||||
set_debugreg(0UL, 2);
|
||||
set_debugreg(0UL, 3);
|
||||
}
|
||||
|
||||
static __always_inline bool hw_breakpoint_active(void)
|
||||
{
|
||||
return __this_cpu_read(cpu_dr7) & DR_GLOBAL_ENABLE_MASK;
|
||||
}
|
||||
|
||||
extern void hw_breakpoint_restore(void);
|
||||
|
||||
static __always_inline unsigned long local_db_save(void)
|
||||
{
|
||||
unsigned long dr7;
|
||||
|
||||
if (static_cpu_has(X86_FEATURE_HYPERVISOR) && !hw_breakpoint_active())
|
||||
return 0;
|
||||
|
||||
get_debugreg(dr7, 7);
|
||||
|
||||
/* Architecturally set bit */
|
||||
dr7 &= ~DR7_FIXED_1;
|
||||
if (dr7)
|
||||
set_debugreg(DR7_FIXED_1, 7);
|
||||
|
||||
/*
|
||||
* Ensure the compiler doesn't lower the above statements into
|
||||
* the critical section; disabling breakpoints late would not
|
||||
* be good.
|
||||
*/
|
||||
barrier();
|
||||
|
||||
return dr7;
|
||||
}
|
||||
|
||||
static __always_inline void local_db_restore(unsigned long dr7)
|
||||
{
|
||||
/*
|
||||
* Ensure the compiler doesn't raise this statement into
|
||||
* the critical section; enabling breakpoints early would
|
||||
* not be good.
|
||||
*/
|
||||
barrier();
|
||||
if (dr7)
|
||||
set_debugreg(dr7, 7);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_SUP_AMD
|
||||
extern void amd_set_dr_addr_mask(unsigned long mask, unsigned int dr);
|
||||
extern unsigned long amd_get_dr_addr_mask(unsigned int dr);
|
||||
#else
|
||||
static inline void amd_set_dr_addr_mask(unsigned long mask, unsigned int dr) { }
|
||||
static inline unsigned long amd_get_dr_addr_mask(unsigned int dr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline unsigned long get_debugctlmsr(void)
|
||||
{
|
||||
unsigned long debugctlmsr = 0;
|
||||
|
||||
#ifndef CONFIG_X86_DEBUGCTLMSR
|
||||
if (boot_cpu_data.x86 < 6)
|
||||
return 0;
|
||||
#endif
|
||||
rdmsrq(MSR_IA32_DEBUGCTLMSR, debugctlmsr);
|
||||
|
||||
return debugctlmsr;
|
||||
}
|
||||
|
||||
static inline void update_debugctlmsr(unsigned long debugctlmsr)
|
||||
{
|
||||
#ifndef CONFIG_X86_DEBUGCTLMSR
|
||||
if (boot_cpu_data.x86 < 6)
|
||||
return;
|
||||
#endif
|
||||
wrmsrq(MSR_IA32_DEBUGCTLMSR, debugctlmsr);
|
||||
}
|
||||
|
||||
#endif /* _ASM_X86_DEBUGREG_H */
|
||||
@@ -0,0 +1,12 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_DELAY_H
|
||||
#define _ASM_X86_DELAY_H
|
||||
|
||||
#include <asm-generic/delay.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
void __init use_tsc_delay(void);
|
||||
void __init use_tpause_delay(void);
|
||||
void use_mwaitx_delay(void);
|
||||
|
||||
#endif /* _ASM_X86_DELAY_H */
|
||||
@@ -0,0 +1,449 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_DESC_H
|
||||
#define _ASM_X86_DESC_H
|
||||
|
||||
#include <asm/desc_defs.h>
|
||||
#include <asm/ldt.h>
|
||||
#include <asm/mmu.h>
|
||||
#include <asm/fixmap.h>
|
||||
#include <asm/irq_vectors.h>
|
||||
#include <asm/cpu_entry_area.h>
|
||||
|
||||
#include <linux/debug_locks.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/percpu.h>
|
||||
|
||||
static inline void fill_ldt(struct desc_struct *desc, const struct user_desc *info)
|
||||
{
|
||||
desc->limit0 = info->limit & 0x0ffff;
|
||||
|
||||
desc->base0 = (info->base_addr & 0x0000ffff);
|
||||
desc->base1 = (info->base_addr & 0x00ff0000) >> 16;
|
||||
|
||||
desc->type = (info->read_exec_only ^ 1) << 1;
|
||||
desc->type |= info->contents << 2;
|
||||
/* Set the ACCESS bit so it can be mapped RO */
|
||||
desc->type |= 1;
|
||||
|
||||
desc->s = 1;
|
||||
desc->dpl = 0x3;
|
||||
desc->p = info->seg_not_present ^ 1;
|
||||
desc->limit1 = (info->limit & 0xf0000) >> 16;
|
||||
desc->avl = info->useable;
|
||||
desc->d = info->seg_32bit;
|
||||
desc->g = info->limit_in_pages;
|
||||
|
||||
desc->base2 = (info->base_addr & 0xff000000) >> 24;
|
||||
/*
|
||||
* Don't allow setting of the lm bit. It would confuse
|
||||
* user_64bit_mode and would get overridden by sysret anyway.
|
||||
*/
|
||||
desc->l = 0;
|
||||
}
|
||||
|
||||
struct gdt_page {
|
||||
struct desc_struct gdt[GDT_ENTRIES];
|
||||
} __attribute__((aligned(PAGE_SIZE)));
|
||||
|
||||
DECLARE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page);
|
||||
|
||||
/* Provide the original GDT */
|
||||
static inline struct desc_struct *get_cpu_gdt_rw(unsigned int cpu)
|
||||
{
|
||||
return per_cpu(gdt_page, cpu).gdt;
|
||||
}
|
||||
|
||||
/* Provide the current original GDT */
|
||||
static inline struct desc_struct *get_current_gdt_rw(void)
|
||||
{
|
||||
return this_cpu_ptr(&gdt_page)->gdt;
|
||||
}
|
||||
|
||||
/* Provide the fixmap address of the remapped GDT */
|
||||
static inline struct desc_struct *get_cpu_gdt_ro(int cpu)
|
||||
{
|
||||
return (struct desc_struct *)&get_cpu_entry_area(cpu)->gdt;
|
||||
}
|
||||
|
||||
/* Provide the current read-only GDT */
|
||||
static inline struct desc_struct *get_current_gdt_ro(void)
|
||||
{
|
||||
return get_cpu_gdt_ro(smp_processor_id());
|
||||
}
|
||||
|
||||
/* Provide the physical address of the GDT page. */
|
||||
static inline phys_addr_t get_cpu_gdt_paddr(unsigned int cpu)
|
||||
{
|
||||
return per_cpu_ptr_to_phys(get_cpu_gdt_rw(cpu));
|
||||
}
|
||||
|
||||
static inline void pack_gate(gate_desc *gate, unsigned type, unsigned long func,
|
||||
unsigned dpl, unsigned ist, unsigned seg)
|
||||
{
|
||||
gate->offset_low = (u16) func;
|
||||
gate->bits.p = 1;
|
||||
gate->bits.dpl = dpl;
|
||||
gate->bits.zero = 0;
|
||||
gate->bits.type = type;
|
||||
gate->offset_middle = (u16) (func >> 16);
|
||||
#ifdef CONFIG_X86_64
|
||||
gate->segment = __KERNEL_CS;
|
||||
gate->bits.ist = ist;
|
||||
gate->reserved = 0;
|
||||
gate->offset_high = (u32) (func >> 32);
|
||||
#else
|
||||
gate->segment = seg;
|
||||
gate->bits.ist = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int desc_empty(const void *ptr)
|
||||
{
|
||||
const u32 *desc = ptr;
|
||||
|
||||
return !(desc[0] | desc[1]);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PARAVIRT_XXL
|
||||
#include <asm/paravirt.h>
|
||||
#else
|
||||
#define load_TR_desc() native_load_tr_desc()
|
||||
#define load_gdt(dtr) native_load_gdt(dtr)
|
||||
#define load_idt(dtr) native_load_idt(dtr)
|
||||
#define load_tr(tr) asm volatile("ltr %0"::"m" (tr))
|
||||
#define load_ldt(ldt) asm volatile("lldt %0"::"m" (ldt))
|
||||
|
||||
#define store_gdt(dtr) native_store_gdt(dtr)
|
||||
#define store_tr(tr) (tr = native_store_tr())
|
||||
|
||||
#define load_TLS(t, cpu) native_load_tls(t, cpu)
|
||||
#define set_ldt native_set_ldt
|
||||
|
||||
#define write_ldt_entry(dt, entry, desc) native_write_ldt_entry(dt, entry, desc)
|
||||
#define write_gdt_entry(dt, entry, desc, type) native_write_gdt_entry(dt, entry, desc, type)
|
||||
#define write_idt_entry(dt, entry, g) native_write_idt_entry(dt, entry, g)
|
||||
|
||||
static inline void paravirt_alloc_ldt(struct desc_struct *ldt, unsigned entries)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void paravirt_free_ldt(struct desc_struct *ldt, unsigned entries)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_PARAVIRT_XXL */
|
||||
|
||||
#define store_ldt(ldt) asm("sldt %0" : "=m"(ldt))
|
||||
|
||||
static inline void native_write_idt_entry(gate_desc *idt, int entry, const gate_desc *gate)
|
||||
{
|
||||
memcpy(&idt[entry], gate, sizeof(*gate));
|
||||
}
|
||||
|
||||
static inline void native_write_ldt_entry(struct desc_struct *ldt, int entry, const void *desc)
|
||||
{
|
||||
memcpy(&ldt[entry], desc, 8);
|
||||
}
|
||||
|
||||
static inline void
|
||||
native_write_gdt_entry(struct desc_struct *gdt, int entry, const void *desc, int type)
|
||||
{
|
||||
unsigned int size;
|
||||
|
||||
switch (type) {
|
||||
case DESC_TSS: size = sizeof(tss_desc); break;
|
||||
case DESC_LDT: size = sizeof(ldt_desc); break;
|
||||
default: size = sizeof(*gdt); break;
|
||||
}
|
||||
|
||||
memcpy(&gdt[entry], desc, size);
|
||||
}
|
||||
|
||||
static inline void set_tssldt_descriptor(void *d, unsigned long addr,
|
||||
unsigned type, unsigned size)
|
||||
{
|
||||
struct ldttss_desc *desc = d;
|
||||
|
||||
memset(desc, 0, sizeof(*desc));
|
||||
|
||||
desc->limit0 = (u16) size;
|
||||
desc->base0 = (u16) addr;
|
||||
desc->base1 = (addr >> 16) & 0xFF;
|
||||
desc->type = type;
|
||||
desc->p = 1;
|
||||
desc->limit1 = (size >> 16) & 0xF;
|
||||
desc->base2 = (addr >> 24) & 0xFF;
|
||||
#ifdef CONFIG_X86_64
|
||||
desc->base3 = (u32) (addr >> 32);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __set_tss_desc(unsigned cpu, unsigned int entry, struct x86_hw_tss *addr)
|
||||
{
|
||||
struct desc_struct *d = get_cpu_gdt_rw(cpu);
|
||||
tss_desc tss;
|
||||
|
||||
set_tssldt_descriptor(&tss, (unsigned long)addr, DESC_TSS,
|
||||
__KERNEL_TSS_LIMIT);
|
||||
write_gdt_entry(d, entry, &tss, DESC_TSS);
|
||||
}
|
||||
|
||||
#define set_tss_desc(cpu, addr) __set_tss_desc(cpu, GDT_ENTRY_TSS, addr)
|
||||
|
||||
static inline void native_set_ldt(const void *addr, unsigned int entries)
|
||||
{
|
||||
if (likely(entries == 0))
|
||||
asm volatile("lldt %w0"::"q" (0));
|
||||
else {
|
||||
unsigned cpu = smp_processor_id();
|
||||
ldt_desc ldt;
|
||||
|
||||
set_tssldt_descriptor(&ldt, (unsigned long)addr, DESC_LDT,
|
||||
entries * LDT_ENTRY_SIZE - 1);
|
||||
write_gdt_entry(get_cpu_gdt_rw(cpu), GDT_ENTRY_LDT,
|
||||
&ldt, DESC_LDT);
|
||||
asm volatile("lldt %w0"::"q" (GDT_ENTRY_LDT*8));
|
||||
}
|
||||
}
|
||||
|
||||
static inline void native_load_gdt(const struct desc_ptr *dtr)
|
||||
{
|
||||
asm volatile("lgdt %0"::"m" (*dtr));
|
||||
}
|
||||
|
||||
static __always_inline void native_load_idt(const struct desc_ptr *dtr)
|
||||
{
|
||||
asm volatile("lidt %0"::"m" (*dtr));
|
||||
}
|
||||
|
||||
static inline void native_store_gdt(struct desc_ptr *dtr)
|
||||
{
|
||||
asm volatile("sgdt %0":"=m" (*dtr));
|
||||
}
|
||||
|
||||
static inline void store_idt(struct desc_ptr *dtr)
|
||||
{
|
||||
asm volatile("sidt %0":"=m" (*dtr));
|
||||
}
|
||||
|
||||
static inline void native_gdt_invalidate(void)
|
||||
{
|
||||
const struct desc_ptr invalid_gdt = {
|
||||
.address = 0,
|
||||
.size = 0
|
||||
};
|
||||
|
||||
native_load_gdt(&invalid_gdt);
|
||||
}
|
||||
|
||||
static inline void native_idt_invalidate(void)
|
||||
{
|
||||
const struct desc_ptr invalid_idt = {
|
||||
.address = 0,
|
||||
.size = 0
|
||||
};
|
||||
|
||||
native_load_idt(&invalid_idt);
|
||||
}
|
||||
|
||||
/*
|
||||
* The LTR instruction marks the TSS GDT entry as busy. On 64-bit, the GDT is
|
||||
* a read-only remapping. To prevent a page fault, the GDT is switched to the
|
||||
* original writeable version when needed.
|
||||
*/
|
||||
#ifdef CONFIG_X86_64
|
||||
static inline void native_load_tr_desc(void)
|
||||
{
|
||||
struct desc_ptr gdt;
|
||||
int cpu = raw_smp_processor_id();
|
||||
bool restore = 0;
|
||||
struct desc_struct *fixmap_gdt;
|
||||
|
||||
native_store_gdt(&gdt);
|
||||
fixmap_gdt = get_cpu_gdt_ro(cpu);
|
||||
|
||||
/*
|
||||
* If the current GDT is the read-only fixmap, swap to the original
|
||||
* writeable version. Swap back at the end.
|
||||
*/
|
||||
if (gdt.address == (unsigned long)fixmap_gdt) {
|
||||
load_direct_gdt(cpu);
|
||||
restore = 1;
|
||||
}
|
||||
asm volatile("ltr %w0"::"q" (GDT_ENTRY_TSS*8));
|
||||
if (restore)
|
||||
load_fixmap_gdt(cpu);
|
||||
}
|
||||
#else
|
||||
static inline void native_load_tr_desc(void)
|
||||
{
|
||||
asm volatile("ltr %w0"::"q" (GDT_ENTRY_TSS*8));
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline unsigned long native_store_tr(void)
|
||||
{
|
||||
unsigned long tr;
|
||||
|
||||
asm volatile("str %0":"=r" (tr));
|
||||
|
||||
return tr;
|
||||
}
|
||||
|
||||
static inline void native_load_tls(struct thread_struct *t, unsigned int cpu)
|
||||
{
|
||||
struct desc_struct *gdt = get_cpu_gdt_rw(cpu);
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++)
|
||||
gdt[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i];
|
||||
}
|
||||
|
||||
DECLARE_PER_CPU(bool, __tss_limit_invalid);
|
||||
|
||||
static inline void force_reload_TR(void)
|
||||
{
|
||||
struct desc_struct *d = get_current_gdt_rw();
|
||||
tss_desc tss;
|
||||
|
||||
memcpy(&tss, &d[GDT_ENTRY_TSS], sizeof(tss_desc));
|
||||
|
||||
/*
|
||||
* LTR requires an available TSS, and the TSS is currently
|
||||
* busy. Make it be available so that LTR will work.
|
||||
*/
|
||||
tss.type = DESC_TSS;
|
||||
write_gdt_entry(d, GDT_ENTRY_TSS, &tss, DESC_TSS);
|
||||
|
||||
load_TR_desc();
|
||||
this_cpu_write(__tss_limit_invalid, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Call this if you need the TSS limit to be correct, which should be the case
|
||||
* if and only if you have TIF_IO_BITMAP set or you're switching to a task
|
||||
* with TIF_IO_BITMAP set.
|
||||
*/
|
||||
static inline void refresh_tss_limit(void)
|
||||
{
|
||||
DEBUG_LOCKS_WARN_ON(preemptible());
|
||||
|
||||
if (unlikely(this_cpu_read(__tss_limit_invalid)))
|
||||
force_reload_TR();
|
||||
}
|
||||
|
||||
/*
|
||||
* If you do something evil that corrupts the cached TSS limit (I'm looking
|
||||
* at you, VMX exits), call this function.
|
||||
*
|
||||
* The optimization here is that the TSS limit only matters for Linux if the
|
||||
* IO bitmap is in use. If the TSS limit gets forced to its minimum value,
|
||||
* everything works except that IO bitmap will be ignored and all CPL 3 IO
|
||||
* instructions will #GP, which is exactly what we want for normal tasks.
|
||||
*/
|
||||
static inline void invalidate_tss_limit(void)
|
||||
{
|
||||
DEBUG_LOCKS_WARN_ON(preemptible());
|
||||
|
||||
if (unlikely(test_thread_flag(TIF_IO_BITMAP)))
|
||||
force_reload_TR();
|
||||
else
|
||||
this_cpu_write(__tss_limit_invalid, true);
|
||||
}
|
||||
|
||||
/* This intentionally ignores lm, since 32-bit apps don't have that field. */
|
||||
#define LDT_empty(info) \
|
||||
((info)->base_addr == 0 && \
|
||||
(info)->limit == 0 && \
|
||||
(info)->contents == 0 && \
|
||||
(info)->read_exec_only == 1 && \
|
||||
(info)->seg_32bit == 0 && \
|
||||
(info)->limit_in_pages == 0 && \
|
||||
(info)->seg_not_present == 1 && \
|
||||
(info)->useable == 0)
|
||||
|
||||
/* Lots of programs expect an all-zero user_desc to mean "no segment at all". */
|
||||
static inline bool LDT_zero(const struct user_desc *info)
|
||||
{
|
||||
return (info->base_addr == 0 &&
|
||||
info->limit == 0 &&
|
||||
info->contents == 0 &&
|
||||
info->read_exec_only == 0 &&
|
||||
info->seg_32bit == 0 &&
|
||||
info->limit_in_pages == 0 &&
|
||||
info->seg_not_present == 0 &&
|
||||
info->useable == 0);
|
||||
}
|
||||
|
||||
static inline void clear_LDT(void)
|
||||
{
|
||||
set_ldt(NULL, 0);
|
||||
}
|
||||
|
||||
static inline unsigned long get_desc_base(const struct desc_struct *desc)
|
||||
{
|
||||
return (unsigned)(desc->base0 | ((desc->base1) << 16) | ((desc->base2) << 24));
|
||||
}
|
||||
|
||||
static inline void set_desc_base(struct desc_struct *desc, unsigned long base)
|
||||
{
|
||||
desc->base0 = base & 0xffff;
|
||||
desc->base1 = (base >> 16) & 0xff;
|
||||
desc->base2 = (base >> 24) & 0xff;
|
||||
}
|
||||
|
||||
static inline unsigned long get_desc_limit(const struct desc_struct *desc)
|
||||
{
|
||||
return desc->limit0 | (desc->limit1 << 16);
|
||||
}
|
||||
|
||||
static inline void set_desc_limit(struct desc_struct *desc, unsigned long limit)
|
||||
{
|
||||
desc->limit0 = limit & 0xffff;
|
||||
desc->limit1 = (limit >> 16) & 0xf;
|
||||
}
|
||||
|
||||
static inline void init_idt_data(struct idt_data *data, unsigned int n,
|
||||
const void *addr)
|
||||
{
|
||||
BUG_ON(n > 0xFF);
|
||||
|
||||
memset(data, 0, sizeof(*data));
|
||||
data->vector = n;
|
||||
data->addr = addr;
|
||||
data->segment = __KERNEL_CS;
|
||||
data->bits.type = GATE_INTERRUPT;
|
||||
data->bits.p = 1;
|
||||
}
|
||||
|
||||
static inline void idt_init_desc(gate_desc *gate, const struct idt_data *d)
|
||||
{
|
||||
unsigned long addr = (unsigned long) d->addr;
|
||||
|
||||
gate->offset_low = (u16) addr;
|
||||
gate->segment = (u16) d->segment;
|
||||
gate->bits = d->bits;
|
||||
gate->offset_middle = (u16) (addr >> 16);
|
||||
#ifdef CONFIG_X86_64
|
||||
gate->offset_high = (u32) (addr >> 32);
|
||||
gate->reserved = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
extern unsigned long system_vectors[];
|
||||
|
||||
extern void load_current_idt(void);
|
||||
extern void idt_setup_early_handler(void);
|
||||
extern void idt_setup_early_traps(void);
|
||||
extern void idt_setup_traps(void);
|
||||
extern void idt_setup_apic_and_irq_gates(void);
|
||||
extern bool idt_is_f00f_address(unsigned long address);
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
extern void idt_setup_early_pf(void);
|
||||
#else
|
||||
static inline void idt_setup_early_pf(void) { }
|
||||
#endif
|
||||
|
||||
extern void idt_invalidate(void);
|
||||
|
||||
#endif /* _ASM_X86_DESC_H */
|
||||
@@ -0,0 +1,197 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Written 2000 by Andi Kleen */
|
||||
#ifndef _ASM_X86_DESC_DEFS_H
|
||||
#define _ASM_X86_DESC_DEFS_H
|
||||
|
||||
/*
|
||||
* Segment descriptor structure definitions, usable from both x86_64 and i386
|
||||
* archs.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Low-level interface mapping flags/field names to bits
|
||||
*/
|
||||
|
||||
/* Flags for _DESC_S (non-system) descriptors */
|
||||
#define _DESC_ACCESSED 0x0001
|
||||
#define _DESC_DATA_WRITABLE 0x0002
|
||||
#define _DESC_CODE_READABLE 0x0002
|
||||
#define _DESC_DATA_EXPAND_DOWN 0x0004
|
||||
#define _DESC_CODE_CONFORMING 0x0004
|
||||
#define _DESC_CODE_EXECUTABLE 0x0008
|
||||
|
||||
/* Common flags */
|
||||
#define _DESC_S 0x0010
|
||||
#define _DESC_DPL(dpl) ((dpl) << 5)
|
||||
#define _DESC_PRESENT 0x0080
|
||||
|
||||
#define _DESC_LONG_CODE 0x2000
|
||||
#define _DESC_DB 0x4000
|
||||
#define _DESC_GRANULARITY_4K 0x8000
|
||||
|
||||
/* System descriptors have a numeric "type" field instead of flags */
|
||||
#define _DESC_SYSTEM(code) (code)
|
||||
|
||||
/*
|
||||
* High-level interface mapping intended usage to low-level combinations
|
||||
* of flags
|
||||
*/
|
||||
|
||||
#define _DESC_DATA (_DESC_S | _DESC_PRESENT | _DESC_ACCESSED | \
|
||||
_DESC_DATA_WRITABLE)
|
||||
#define _DESC_CODE (_DESC_S | _DESC_PRESENT | _DESC_ACCESSED | \
|
||||
_DESC_CODE_READABLE | _DESC_CODE_EXECUTABLE)
|
||||
|
||||
#define DESC_DATA16 (_DESC_DATA)
|
||||
#define DESC_CODE16 (_DESC_CODE)
|
||||
|
||||
#define DESC_DATA32 (_DESC_DATA | _DESC_GRANULARITY_4K | _DESC_DB)
|
||||
#define DESC_DATA32_BIOS (_DESC_DATA | _DESC_DB)
|
||||
|
||||
#define DESC_CODE32 (_DESC_CODE | _DESC_GRANULARITY_4K | _DESC_DB)
|
||||
#define DESC_CODE32_BIOS (_DESC_CODE | _DESC_DB)
|
||||
|
||||
#define DESC_TSS32 (_DESC_SYSTEM(9) | _DESC_PRESENT)
|
||||
|
||||
#define DESC_DATA64 (_DESC_DATA | _DESC_GRANULARITY_4K | _DESC_DB)
|
||||
#define DESC_CODE64 (_DESC_CODE | _DESC_GRANULARITY_4K | _DESC_LONG_CODE)
|
||||
|
||||
#define DESC_USER (_DESC_DPL(3))
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/* 8 byte segment descriptor */
|
||||
struct desc_struct {
|
||||
u16 limit0;
|
||||
u16 base0;
|
||||
u16 base1: 8, type: 4, s: 1, dpl: 2, p: 1;
|
||||
u16 limit1: 4, avl: 1, l: 1, d: 1, g: 1, base2: 8;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define GDT_ENTRY_INIT(flags, base, limit) \
|
||||
{ \
|
||||
.limit0 = ((limit) >> 0) & 0xFFFF, \
|
||||
.limit1 = ((limit) >> 16) & 0x000F, \
|
||||
.base0 = ((base) >> 0) & 0xFFFF, \
|
||||
.base1 = ((base) >> 16) & 0x00FF, \
|
||||
.base2 = ((base) >> 24) & 0x00FF, \
|
||||
.type = ((flags) >> 0) & 0x000F, \
|
||||
.s = ((flags) >> 4) & 0x0001, \
|
||||
.dpl = ((flags) >> 5) & 0x0003, \
|
||||
.p = ((flags) >> 7) & 0x0001, \
|
||||
.avl = ((flags) >> 12) & 0x0001, \
|
||||
.l = ((flags) >> 13) & 0x0001, \
|
||||
.d = ((flags) >> 14) & 0x0001, \
|
||||
.g = ((flags) >> 15) & 0x0001, \
|
||||
}
|
||||
|
||||
enum {
|
||||
GATE_INTERRUPT = 0xE,
|
||||
GATE_TRAP = 0xF,
|
||||
GATE_CALL = 0xC,
|
||||
GATE_TASK = 0x5,
|
||||
};
|
||||
|
||||
enum {
|
||||
DESC_TSS = 0x9,
|
||||
DESC_LDT = 0x2,
|
||||
DESCTYPE_S = 0x10, /* !system */
|
||||
};
|
||||
|
||||
/* LDT or TSS descriptor in the GDT. */
|
||||
struct ldttss_desc {
|
||||
u16 limit0;
|
||||
u16 base0;
|
||||
|
||||
u16 base1 : 8, type : 5, dpl : 2, p : 1;
|
||||
u16 limit1 : 4, zero0 : 3, g : 1, base2 : 8;
|
||||
#ifdef CONFIG_X86_64
|
||||
u32 base3;
|
||||
u32 zero1;
|
||||
#endif
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct ldttss_desc ldt_desc;
|
||||
typedef struct ldttss_desc tss_desc;
|
||||
|
||||
struct idt_bits {
|
||||
u16 ist : 3,
|
||||
zero : 5,
|
||||
type : 5,
|
||||
dpl : 2,
|
||||
p : 1;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct idt_data {
|
||||
unsigned int vector;
|
||||
unsigned int segment;
|
||||
struct idt_bits bits;
|
||||
const void *addr;
|
||||
};
|
||||
|
||||
struct gate_struct {
|
||||
u16 offset_low;
|
||||
u16 segment;
|
||||
struct idt_bits bits;
|
||||
u16 offset_middle;
|
||||
#ifdef CONFIG_X86_64
|
||||
u32 offset_high;
|
||||
u32 reserved;
|
||||
#endif
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct gate_struct gate_desc;
|
||||
|
||||
#ifndef _SETUP
|
||||
static inline unsigned long gate_offset(const gate_desc *g)
|
||||
{
|
||||
#ifdef CONFIG_X86_64
|
||||
return g->offset_low | ((unsigned long)g->offset_middle << 16) |
|
||||
((unsigned long) g->offset_high << 32);
|
||||
#else
|
||||
return g->offset_low | ((unsigned long)g->offset_middle << 16);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline unsigned long gate_segment(const gate_desc *g)
|
||||
{
|
||||
return g->segment;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct desc_ptr {
|
||||
unsigned short size;
|
||||
unsigned long address;
|
||||
} __attribute__((packed)) ;
|
||||
|
||||
#endif /* !__ASSEMBLER__ */
|
||||
|
||||
/* Boot IDT definitions */
|
||||
#define BOOT_IDT_ENTRIES 32
|
||||
|
||||
/* Access rights as returned by LAR */
|
||||
#define AR_TYPE_RODATA (0 * (1 << 9))
|
||||
#define AR_TYPE_RWDATA (1 * (1 << 9))
|
||||
#define AR_TYPE_RODATA_EXPDOWN (2 * (1 << 9))
|
||||
#define AR_TYPE_RWDATA_EXPDOWN (3 * (1 << 9))
|
||||
#define AR_TYPE_XOCODE (4 * (1 << 9))
|
||||
#define AR_TYPE_XRCODE (5 * (1 << 9))
|
||||
#define AR_TYPE_XOCODE_CONF (6 * (1 << 9))
|
||||
#define AR_TYPE_XRCODE_CONF (7 * (1 << 9))
|
||||
#define AR_TYPE_MASK (7 * (1 << 9))
|
||||
|
||||
#define AR_DPL0 (0 * (1 << 13))
|
||||
#define AR_DPL3 (3 * (1 << 13))
|
||||
#define AR_DPL_MASK (3 * (1 << 13))
|
||||
|
||||
#define AR_A (1 << 8) /* "Accessed" */
|
||||
#define AR_S (1 << 12) /* If clear, "System" segment */
|
||||
#define AR_P (1 << 15) /* "Present" */
|
||||
#define AR_AVL (1 << 20) /* "AVaiLable" (no HW effect) */
|
||||
#define AR_L (1 << 21) /* "Long mode" for code segments */
|
||||
#define AR_DB (1 << 22) /* D/B, effect depends on type */
|
||||
#define AR_G (1 << 23) /* "Granularity" (limit in pages) */
|
||||
|
||||
#endif /* _ASM_X86_DESC_DEFS_H */
|
||||
@@ -0,0 +1,11 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_DEVICE_H
|
||||
#define _ASM_X86_DEVICE_H
|
||||
|
||||
struct dev_archdata {
|
||||
};
|
||||
|
||||
struct pdev_archdata {
|
||||
};
|
||||
|
||||
#endif /* _ASM_X86_DEVICE_H */
|
||||
@@ -0,0 +1,130 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_DIV64_H
|
||||
#define _ASM_X86_DIV64_H
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/log2.h>
|
||||
|
||||
/*
|
||||
* do_div() is NOT a C function. It wants to return
|
||||
* two values (the quotient and the remainder), but
|
||||
* since that doesn't work very well in C, what it
|
||||
* does is:
|
||||
*
|
||||
* - modifies the 64-bit dividend _in_place_
|
||||
* - returns the 32-bit remainder
|
||||
*
|
||||
* This ends up being the most efficient "calling
|
||||
* convention" on x86.
|
||||
*/
|
||||
#define do_div(n, base) \
|
||||
({ \
|
||||
unsigned long __upper, __low, __high, __mod, __base; \
|
||||
__base = (base); \
|
||||
if (__builtin_constant_p(__base) && is_power_of_2(__base)) { \
|
||||
__mod = n & (__base - 1); \
|
||||
n >>= ilog2(__base); \
|
||||
} else { \
|
||||
asm("" : "=a" (__low), "=d" (__high) : "A" (n));\
|
||||
__upper = __high; \
|
||||
if (__high) { \
|
||||
__upper = __high % (__base); \
|
||||
__high = __high / (__base); \
|
||||
} \
|
||||
asm("divl %2" : "=a" (__low), "=d" (__mod) \
|
||||
: "rm" (__base), "0" (__low), "1" (__upper)); \
|
||||
asm("" : "=A" (n) : "a" (__low), "d" (__high)); \
|
||||
} \
|
||||
__mod; \
|
||||
})
|
||||
|
||||
static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
|
||||
{
|
||||
union {
|
||||
u64 v64;
|
||||
u32 v32[2];
|
||||
} d = { dividend };
|
||||
u32 upper;
|
||||
|
||||
upper = d.v32[1];
|
||||
d.v32[1] = 0;
|
||||
if (upper >= divisor) {
|
||||
d.v32[1] = upper / divisor;
|
||||
upper %= divisor;
|
||||
}
|
||||
asm ("divl %2" : "=a" (d.v32[0]), "=d" (*remainder) :
|
||||
"rm" (divisor), "0" (d.v32[0]), "1" (upper));
|
||||
return d.v64;
|
||||
}
|
||||
#define div_u64_rem div_u64_rem
|
||||
|
||||
/*
|
||||
* gcc tends to zero extend 32bit values and do full 64bit maths.
|
||||
* Define asm functions that avoid this.
|
||||
* (clang generates better code for the C versions.)
|
||||
*/
|
||||
#ifndef __clang__
|
||||
static inline u64 mul_u32_u32(u32 a, u32 b)
|
||||
{
|
||||
u32 high, low;
|
||||
|
||||
asm ("mull %[b]" : "=a" (low), "=d" (high)
|
||||
: [a] "a" (a), [b] "rm" (b) );
|
||||
|
||||
return low | ((u64)high) << 32;
|
||||
}
|
||||
#define mul_u32_u32 mul_u32_u32
|
||||
|
||||
static inline u64 add_u64_u32(u64 a, u32 b)
|
||||
{
|
||||
u32 high = a >> 32, low = a;
|
||||
|
||||
asm ("addl %[b], %[low]; adcl $0, %[high]"
|
||||
: [low] "+r" (low), [high] "+r" (high)
|
||||
: [b] "rm" (b) );
|
||||
|
||||
return low | (u64)high << 32;
|
||||
}
|
||||
#define add_u64_u32 add_u64_u32
|
||||
#endif
|
||||
|
||||
/*
|
||||
* __div64_32() is never called on x86, so prevent the
|
||||
* generic definition from getting built.
|
||||
*/
|
||||
#define __div64_32
|
||||
|
||||
#else
|
||||
# include <asm-generic/div64.h>
|
||||
|
||||
/*
|
||||
* Will generate an #DE when the result doesn't fit u64, could fix with an
|
||||
* __ex_table[] entry when it becomes an issue.
|
||||
*/
|
||||
static inline u64 mul_u64_add_u64_div_u64(u64 rax, u64 mul, u64 add, u64 div)
|
||||
{
|
||||
u64 rdx;
|
||||
|
||||
asm ("mulq %[mul]" : "+a" (rax), "=d" (rdx) : [mul] "rm" (mul));
|
||||
|
||||
if (!statically_true(!add))
|
||||
asm ("addq %[add], %[lo]; adcq $0, %[hi]" :
|
||||
[lo] "+r" (rax), [hi] "+r" (rdx) : [add] "irm" (add));
|
||||
|
||||
asm ("divq %[div]" : "+a" (rax), "+d" (rdx) : [div] "rm" (div));
|
||||
|
||||
return rax;
|
||||
}
|
||||
#define mul_u64_add_u64_div_u64 mul_u64_add_u64_div_u64
|
||||
|
||||
static inline u64 mul_u64_u32_div(u64 a, u32 mul, u32 div)
|
||||
{
|
||||
return mul_u64_add_u64_div_u64(a, mul, 0, div);
|
||||
}
|
||||
#define mul_u64_u32_div mul_u64_u32_div
|
||||
|
||||
#endif /* CONFIG_X86_32 */
|
||||
|
||||
#endif /* _ASM_X86_DIV64_H */
|
||||
@@ -0,0 +1,12 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_DMA_MAPPING_H
|
||||
#define _ASM_X86_DMA_MAPPING_H
|
||||
|
||||
extern const struct dma_map_ops *dma_ops;
|
||||
|
||||
static inline const struct dma_map_ops *get_arch_dma_ops(void)
|
||||
{
|
||||
return dma_ops;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,310 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* linux/include/asm/dma.h: Defines for using and allocating dma channels.
|
||||
* Written by Hennus Bergman, 1992.
|
||||
* High DMA channel support & info by Hannu Savolainen
|
||||
* and John Boyd, Nov. 1992.
|
||||
*/
|
||||
|
||||
#ifndef _ASM_X86_DMA_H
|
||||
#define _ASM_X86_DMA_H
|
||||
|
||||
#include <linux/spinlock.h> /* And spinlocks */
|
||||
#include <asm/io.h> /* need byte IO */
|
||||
|
||||
#ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER
|
||||
#define dma_outb outb_p
|
||||
#else
|
||||
#define dma_outb outb
|
||||
#endif
|
||||
|
||||
#define dma_inb inb
|
||||
|
||||
/*
|
||||
* NOTES about DMA transfers:
|
||||
*
|
||||
* controller 1: channels 0-3, byte operations, ports 00-1F
|
||||
* controller 2: channels 4-7, word operations, ports C0-DF
|
||||
*
|
||||
* - ALL registers are 8 bits only, regardless of transfer size
|
||||
* - channel 4 is not used - cascades 1 into 2.
|
||||
* - channels 0-3 are byte - addresses/counts are for physical bytes
|
||||
* - channels 5-7 are word - addresses/counts are for physical words
|
||||
* - transfers must not cross physical 64K (0-3) or 128K (5-7) boundaries
|
||||
* - transfer count loaded to registers is 1 less than actual count
|
||||
* - controller 2 offsets are all even (2x offsets for controller 1)
|
||||
* - page registers for 5-7 don't use data bit 0, represent 128K pages
|
||||
* - page registers for 0-3 use bit 0, represent 64K pages
|
||||
*
|
||||
* DMA transfers are limited to the lower 16MB of _physical_ memory.
|
||||
* Note that addresses loaded into registers must be _physical_ addresses,
|
||||
* not logical addresses (which may differ if paging is active).
|
||||
*
|
||||
* Address mapping for channels 0-3:
|
||||
*
|
||||
* A23 ... A16 A15 ... A8 A7 ... A0 (Physical addresses)
|
||||
* | ... | | ... | | ... |
|
||||
* | ... | | ... | | ... |
|
||||
* | ... | | ... | | ... |
|
||||
* P7 ... P0 A7 ... A0 A7 ... A0
|
||||
* | Page | Addr MSB | Addr LSB | (DMA registers)
|
||||
*
|
||||
* Address mapping for channels 5-7:
|
||||
*
|
||||
* A23 ... A17 A16 A15 ... A9 A8 A7 ... A1 A0 (Physical addresses)
|
||||
* | ... | \ \ ... \ \ \ ... \ \
|
||||
* | ... | \ \ ... \ \ \ ... \ (not used)
|
||||
* | ... | \ \ ... \ \ \ ... \
|
||||
* P7 ... P1 (0) A7 A6 ... A0 A7 A6 ... A0
|
||||
* | Page | Addr MSB | Addr LSB | (DMA registers)
|
||||
*
|
||||
* Again, channels 5-7 transfer _physical_ words (16 bits), so addresses
|
||||
* and counts _must_ be word-aligned (the lowest address bit is _ignored_ at
|
||||
* the hardware level, so odd-byte transfers aren't possible).
|
||||
*
|
||||
* Transfer count (_not # bytes_) is limited to 64K, represented as actual
|
||||
* count - 1 : 64K => 0xFFFF, 1 => 0x0000. Thus, count is always 1 or more,
|
||||
* and up to 128K bytes may be transferred on channels 5-7 in one operation.
|
||||
*
|
||||
*/
|
||||
|
||||
#define MAX_DMA_CHANNELS 8
|
||||
|
||||
/* 16MB ISA DMA zone */
|
||||
#define MAX_DMA_PFN ((16UL * 1024 * 1024) >> PAGE_SHIFT)
|
||||
|
||||
/* 4GB broken PCI/AGP hardware bus master zone */
|
||||
#define MAX_DMA32_PFN (1UL << (32 - PAGE_SHIFT))
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
/* The maximum address that we can perform a DMA transfer to on this platform */
|
||||
#define MAX_DMA_ADDRESS (PAGE_OFFSET + 0x1000000)
|
||||
#else
|
||||
/* Compat define for old dma zone */
|
||||
#define MAX_DMA_ADDRESS ((unsigned long)__va(MAX_DMA_PFN << PAGE_SHIFT))
|
||||
#endif
|
||||
|
||||
/* 8237 DMA controllers */
|
||||
#define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */
|
||||
#define IO_DMA2_BASE 0xC0 /* 16 bit master DMA, ch 4(=slave input)..7 */
|
||||
|
||||
/* DMA controller registers */
|
||||
#define DMA1_CMD_REG 0x08 /* command register (w) */
|
||||
#define DMA1_STAT_REG 0x08 /* status register (r) */
|
||||
#define DMA1_REQ_REG 0x09 /* request register (w) */
|
||||
#define DMA1_MASK_REG 0x0A /* single-channel mask (w) */
|
||||
#define DMA1_MODE_REG 0x0B /* mode register (w) */
|
||||
#define DMA1_CLEAR_FF_REG 0x0C /* clear pointer flip-flop (w) */
|
||||
#define DMA1_TEMP_REG 0x0D /* Temporary Register (r) */
|
||||
#define DMA1_RESET_REG 0x0D /* Master Clear (w) */
|
||||
#define DMA1_CLR_MASK_REG 0x0E /* Clear Mask */
|
||||
#define DMA1_MASK_ALL_REG 0x0F /* all-channels mask (w) */
|
||||
|
||||
#define DMA2_CMD_REG 0xD0 /* command register (w) */
|
||||
#define DMA2_STAT_REG 0xD0 /* status register (r) */
|
||||
#define DMA2_REQ_REG 0xD2 /* request register (w) */
|
||||
#define DMA2_MASK_REG 0xD4 /* single-channel mask (w) */
|
||||
#define DMA2_MODE_REG 0xD6 /* mode register (w) */
|
||||
#define DMA2_CLEAR_FF_REG 0xD8 /* clear pointer flip-flop (w) */
|
||||
#define DMA2_TEMP_REG 0xDA /* Temporary Register (r) */
|
||||
#define DMA2_RESET_REG 0xDA /* Master Clear (w) */
|
||||
#define DMA2_CLR_MASK_REG 0xDC /* Clear Mask */
|
||||
#define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */
|
||||
|
||||
#define DMA_ADDR_0 0x00 /* DMA address registers */
|
||||
#define DMA_ADDR_1 0x02
|
||||
#define DMA_ADDR_2 0x04
|
||||
#define DMA_ADDR_3 0x06
|
||||
#define DMA_ADDR_4 0xC0
|
||||
#define DMA_ADDR_5 0xC4
|
||||
#define DMA_ADDR_6 0xC8
|
||||
#define DMA_ADDR_7 0xCC
|
||||
|
||||
#define DMA_CNT_0 0x01 /* DMA count registers */
|
||||
#define DMA_CNT_1 0x03
|
||||
#define DMA_CNT_2 0x05
|
||||
#define DMA_CNT_3 0x07
|
||||
#define DMA_CNT_4 0xC2
|
||||
#define DMA_CNT_5 0xC6
|
||||
#define DMA_CNT_6 0xCA
|
||||
#define DMA_CNT_7 0xCE
|
||||
|
||||
#define DMA_PAGE_0 0x87 /* DMA page registers */
|
||||
#define DMA_PAGE_1 0x83
|
||||
#define DMA_PAGE_2 0x81
|
||||
#define DMA_PAGE_3 0x82
|
||||
#define DMA_PAGE_5 0x8B
|
||||
#define DMA_PAGE_6 0x89
|
||||
#define DMA_PAGE_7 0x8A
|
||||
|
||||
/* I/O to memory, no autoinit, increment, single mode */
|
||||
#define DMA_MODE_READ 0x44
|
||||
/* memory to I/O, no autoinit, increment, single mode */
|
||||
#define DMA_MODE_WRITE 0x48
|
||||
/* pass thru DREQ->HRQ, DACK<-HLDA only */
|
||||
#define DMA_MODE_CASCADE 0xC0
|
||||
|
||||
#define DMA_AUTOINIT 0x10
|
||||
|
||||
|
||||
#ifdef CONFIG_ISA_DMA_API
|
||||
extern spinlock_t dma_spin_lock;
|
||||
|
||||
static inline unsigned long claim_dma_lock(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&dma_spin_lock, flags);
|
||||
return flags;
|
||||
}
|
||||
|
||||
static inline void release_dma_lock(unsigned long flags)
|
||||
{
|
||||
spin_unlock_irqrestore(&dma_spin_lock, flags);
|
||||
}
|
||||
#endif /* CONFIG_ISA_DMA_API */
|
||||
|
||||
/* enable/disable a specific DMA channel */
|
||||
static inline void enable_dma(unsigned int dmanr)
|
||||
{
|
||||
if (dmanr <= 3)
|
||||
dma_outb(dmanr, DMA1_MASK_REG);
|
||||
else
|
||||
dma_outb(dmanr & 3, DMA2_MASK_REG);
|
||||
}
|
||||
|
||||
static inline void disable_dma(unsigned int dmanr)
|
||||
{
|
||||
if (dmanr <= 3)
|
||||
dma_outb(dmanr | 4, DMA1_MASK_REG);
|
||||
else
|
||||
dma_outb((dmanr & 3) | 4, DMA2_MASK_REG);
|
||||
}
|
||||
|
||||
/* Clear the 'DMA Pointer Flip Flop'.
|
||||
* Write 0 for LSB/MSB, 1 for MSB/LSB access.
|
||||
* Use this once to initialize the FF to a known state.
|
||||
* After that, keep track of it. :-)
|
||||
* --- In order to do that, the DMA routines below should ---
|
||||
* --- only be used while holding the DMA lock ! ---
|
||||
*/
|
||||
static inline void clear_dma_ff(unsigned int dmanr)
|
||||
{
|
||||
if (dmanr <= 3)
|
||||
dma_outb(0, DMA1_CLEAR_FF_REG);
|
||||
else
|
||||
dma_outb(0, DMA2_CLEAR_FF_REG);
|
||||
}
|
||||
|
||||
/* set mode (above) for a specific DMA channel */
|
||||
static inline void set_dma_mode(unsigned int dmanr, char mode)
|
||||
{
|
||||
if (dmanr <= 3)
|
||||
dma_outb(mode | dmanr, DMA1_MODE_REG);
|
||||
else
|
||||
dma_outb(mode | (dmanr & 3), DMA2_MODE_REG);
|
||||
}
|
||||
|
||||
/* Set only the page register bits of the transfer address.
|
||||
* This is used for successive transfers when we know the contents of
|
||||
* the lower 16 bits of the DMA current address register, but a 64k boundary
|
||||
* may have been crossed.
|
||||
*/
|
||||
static inline void set_dma_page(unsigned int dmanr, char pagenr)
|
||||
{
|
||||
switch (dmanr) {
|
||||
case 0:
|
||||
dma_outb(pagenr, DMA_PAGE_0);
|
||||
break;
|
||||
case 1:
|
||||
dma_outb(pagenr, DMA_PAGE_1);
|
||||
break;
|
||||
case 2:
|
||||
dma_outb(pagenr, DMA_PAGE_2);
|
||||
break;
|
||||
case 3:
|
||||
dma_outb(pagenr, DMA_PAGE_3);
|
||||
break;
|
||||
case 5:
|
||||
dma_outb(pagenr & 0xfe, DMA_PAGE_5);
|
||||
break;
|
||||
case 6:
|
||||
dma_outb(pagenr & 0xfe, DMA_PAGE_6);
|
||||
break;
|
||||
case 7:
|
||||
dma_outb(pagenr & 0xfe, DMA_PAGE_7);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Set transfer address & page bits for specific DMA channel.
|
||||
* Assumes dma flipflop is clear.
|
||||
*/
|
||||
static inline void set_dma_addr(unsigned int dmanr, unsigned int a)
|
||||
{
|
||||
set_dma_page(dmanr, a>>16);
|
||||
if (dmanr <= 3) {
|
||||
dma_outb(a & 0xff, ((dmanr & 3) << 1) + IO_DMA1_BASE);
|
||||
dma_outb((a >> 8) & 0xff, ((dmanr & 3) << 1) + IO_DMA1_BASE);
|
||||
} else {
|
||||
dma_outb((a >> 1) & 0xff, ((dmanr & 3) << 2) + IO_DMA2_BASE);
|
||||
dma_outb((a >> 9) & 0xff, ((dmanr & 3) << 2) + IO_DMA2_BASE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Set transfer size (max 64k for DMA0..3, 128k for DMA5..7) for
|
||||
* a specific DMA channel.
|
||||
* You must ensure the parameters are valid.
|
||||
* NOTE: from a manual: "the number of transfers is one more
|
||||
* than the initial word count"! This is taken into account.
|
||||
* Assumes dma flip-flop is clear.
|
||||
* NOTE 2: "count" represents _bytes_ and must be even for channels 5-7.
|
||||
*/
|
||||
static inline void set_dma_count(unsigned int dmanr, unsigned int count)
|
||||
{
|
||||
count--;
|
||||
if (dmanr <= 3) {
|
||||
dma_outb(count & 0xff, ((dmanr & 3) << 1) + 1 + IO_DMA1_BASE);
|
||||
dma_outb((count >> 8) & 0xff,
|
||||
((dmanr & 3) << 1) + 1 + IO_DMA1_BASE);
|
||||
} else {
|
||||
dma_outb((count >> 1) & 0xff,
|
||||
((dmanr & 3) << 2) + 2 + IO_DMA2_BASE);
|
||||
dma_outb((count >> 9) & 0xff,
|
||||
((dmanr & 3) << 2) + 2 + IO_DMA2_BASE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Get DMA residue count. After a DMA transfer, this
|
||||
* should return zero. Reading this while a DMA transfer is
|
||||
* still in progress will return unpredictable results.
|
||||
* If called before the channel has been used, it may return 1.
|
||||
* Otherwise, it returns the number of _bytes_ left to transfer.
|
||||
*
|
||||
* Assumes DMA flip-flop is clear.
|
||||
*/
|
||||
static inline int get_dma_residue(unsigned int dmanr)
|
||||
{
|
||||
unsigned int io_port;
|
||||
/* using short to get 16-bit wrap around */
|
||||
unsigned short count;
|
||||
|
||||
io_port = (dmanr <= 3) ? ((dmanr & 3) << 1) + 1 + IO_DMA1_BASE
|
||||
: ((dmanr & 3) << 2) + 2 + IO_DMA2_BASE;
|
||||
|
||||
count = 1 + dma_inb(io_port);
|
||||
count += dma_inb(io_port) << 8;
|
||||
|
||||
return (dmanr <= 3) ? count : (count << 1);
|
||||
}
|
||||
|
||||
|
||||
/* These are in kernel/dma.c because x86 uses CONFIG_GENERIC_ISA_DMA */
|
||||
#ifdef CONFIG_ISA_DMA_API
|
||||
extern int request_dma(unsigned int dmanr, const char *device_id);
|
||||
extern void free_dma(unsigned int dmanr);
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_X86_DMA_H */
|
||||
@@ -0,0 +1,22 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_DMI_H
|
||||
#define _ASM_X86_DMI_H
|
||||
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <asm/setup.h>
|
||||
|
||||
static __always_inline __init void *dmi_alloc(unsigned len)
|
||||
{
|
||||
return extend_brk(len, sizeof(int));
|
||||
}
|
||||
|
||||
/* Use early IO mappings for DMI because it's initialized early */
|
||||
#define dmi_early_remap early_memremap
|
||||
#define dmi_early_unmap early_memunmap
|
||||
#define dmi_remap(_x, _l) memremap(_x, _l, MEMREMAP_WB)
|
||||
#define dmi_unmap(_x) memunmap(_x)
|
||||
|
||||
#endif /* _ASM_X86_DMI_H */
|
||||
@@ -0,0 +1,17 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_DOUBLEFAULT_H
|
||||
#define _ASM_X86_DOUBLEFAULT_H
|
||||
|
||||
#include <linux/linkage.h>
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
extern void doublefault_init_cpu_tss(void);
|
||||
#else
|
||||
static inline void doublefault_init_cpu_tss(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
asmlinkage void __noreturn doublefault_shim(void);
|
||||
|
||||
#endif /* _ASM_X86_DOUBLEFAULT_H */
|
||||
@@ -0,0 +1,42 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_DWARF2_H
|
||||
#define _ASM_X86_DWARF2_H
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
#warning "asm/dwarf2.h should be only included in pure assembly files"
|
||||
#endif
|
||||
|
||||
#define CFI_STARTPROC .cfi_startproc
|
||||
#define CFI_ENDPROC .cfi_endproc
|
||||
#define CFI_DEF_CFA .cfi_def_cfa
|
||||
#define CFI_DEF_CFA_REGISTER .cfi_def_cfa_register
|
||||
#define CFI_DEF_CFA_OFFSET .cfi_def_cfa_offset
|
||||
#define CFI_ADJUST_CFA_OFFSET .cfi_adjust_cfa_offset
|
||||
#define CFI_OFFSET .cfi_offset
|
||||
#define CFI_REL_OFFSET .cfi_rel_offset
|
||||
#define CFI_REGISTER .cfi_register
|
||||
#define CFI_RESTORE .cfi_restore
|
||||
#define CFI_REMEMBER_STATE .cfi_remember_state
|
||||
#define CFI_RESTORE_STATE .cfi_restore_state
|
||||
#define CFI_UNDEFINED .cfi_undefined
|
||||
#define CFI_ESCAPE .cfi_escape
|
||||
#define CFI_SIGNAL_FRAME .cfi_signal_frame
|
||||
|
||||
#ifndef BUILD_VDSO
|
||||
/*
|
||||
* Emit CFI data in .debug_frame sections, not .eh_frame sections.
|
||||
* The latter we currently just discard since we don't do DWARF
|
||||
* unwinding at runtime. So only the offline DWARF information is
|
||||
* useful to anyone. Note we should not use this directive if we
|
||||
* ever decide to enable DWARF unwinding at runtime.
|
||||
*/
|
||||
.cfi_sections .debug_frame
|
||||
#else
|
||||
/*
|
||||
* For the vDSO, emit both runtime unwind information and debug
|
||||
* symbols for the .dbg file.
|
||||
*/
|
||||
.cfi_sections .eh_frame, .debug_frame
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_X86_DWARF2_H */
|
||||
@@ -0,0 +1,54 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_E820_API_H
|
||||
#define _ASM_E820_API_H
|
||||
|
||||
#include <asm/e820/types.h>
|
||||
|
||||
extern struct e820_table *e820_table;
|
||||
extern struct e820_table *e820_table_kexec;
|
||||
extern struct e820_table *e820_table_firmware;
|
||||
|
||||
extern unsigned long pci_mem_start;
|
||||
|
||||
extern bool e820__mapped_raw_any(u64 start, u64 end, enum e820_type type);
|
||||
extern bool e820__mapped_any(u64 start, u64 end, enum e820_type type);
|
||||
extern bool e820__mapped_all(u64 start, u64 end, enum e820_type type);
|
||||
|
||||
extern void e820__range_add (u64 start, u64 size, enum e820_type type);
|
||||
extern u64 e820__range_update(u64 start, u64 size, enum e820_type old_type, enum e820_type new_type);
|
||||
extern void e820__range_remove(u64 start, u64 size, enum e820_type filter_type);
|
||||
extern u64 e820__range_update_table(struct e820_table *t, u64 start, u64 size, enum e820_type old_type, enum e820_type new_type);
|
||||
|
||||
extern int e820__update_table(struct e820_table *table);
|
||||
extern void e820__update_table_print(void);
|
||||
|
||||
extern unsigned long e820__end_of_ram_pfn(void);
|
||||
extern unsigned long e820__end_of_low_ram_pfn(void);
|
||||
|
||||
extern u64 e820__memblock_alloc_reserved(u64 size, u64 align);
|
||||
extern void e820__memblock_setup(void);
|
||||
|
||||
extern void e820__finish_early_params(void);
|
||||
extern void e820__reserve_resources(void);
|
||||
extern void e820__reserve_resources_late(void);
|
||||
|
||||
extern void e820__memory_setup(void);
|
||||
extern void e820__memory_setup_extended(u64 phys_addr, u32 data_len);
|
||||
extern char *e820__memory_setup_default(void);
|
||||
extern void e820__setup_pci_gap(void);
|
||||
|
||||
extern void e820__reallocate_tables(void);
|
||||
extern void e820__register_nosave_regions(unsigned long limit_pfn);
|
||||
|
||||
extern int e820__get_entry_type(u64 start, u64 end);
|
||||
|
||||
/*
|
||||
* Returns true iff the specified range [start,end) is completely contained inside
|
||||
* the ISA region.
|
||||
*/
|
||||
static inline bool is_ISA_range(u64 start, u64 end)
|
||||
{
|
||||
return start >= ISA_START_ADDRESS && end <= ISA_END_ADDRESS;
|
||||
}
|
||||
|
||||
#endif /* _ASM_E820_API_H */
|
||||
@@ -0,0 +1,104 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_E820_TYPES_H
|
||||
#define _ASM_E820_TYPES_H
|
||||
|
||||
#include <uapi/asm/bootparam.h>
|
||||
|
||||
/*
|
||||
* These are the E820 types known to the kernel:
|
||||
*/
|
||||
enum e820_type {
|
||||
E820_TYPE_RAM = 1,
|
||||
E820_TYPE_RESERVED = 2,
|
||||
E820_TYPE_ACPI = 3,
|
||||
E820_TYPE_NVS = 4,
|
||||
E820_TYPE_UNUSABLE = 5,
|
||||
E820_TYPE_PMEM = 7,
|
||||
|
||||
/*
|
||||
* This is a non-standardized way to represent ADR or
|
||||
* NVDIMM regions that persist over a reboot.
|
||||
*
|
||||
* The kernel will ignore their special capabilities
|
||||
* unless the CONFIG_X86_PMEM_LEGACY=y option is set.
|
||||
*
|
||||
* ( Note that older platforms also used 6 for the same
|
||||
* type of memory, but newer versions switched to 12 as
|
||||
* 6 was assigned differently. Some time they will learn... )
|
||||
*/
|
||||
E820_TYPE_PRAM = 12,
|
||||
|
||||
/*
|
||||
* Special-purpose memory is indicated to the system via the
|
||||
* EFI_MEMORY_SP attribute. Define an e820 translation of this
|
||||
* memory type for the purpose of reserving this range and
|
||||
* marking it with the IORES_DESC_SOFT_RESERVED designation.
|
||||
*/
|
||||
E820_TYPE_SOFT_RESERVED = 0xefffffff,
|
||||
};
|
||||
|
||||
/*
|
||||
* A single E820 map entry, describing a memory range of [addr...addr+size-1],
|
||||
* of 'type' memory type:
|
||||
*
|
||||
* (We pack it because there can be thousands of them on large systems.)
|
||||
*/
|
||||
struct e820_entry {
|
||||
u64 addr;
|
||||
u64 size;
|
||||
enum e820_type type;
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* The legacy E820 BIOS limits us to 128 (E820_MAX_ENTRIES_ZEROPAGE) nodes
|
||||
* due to the constrained space in the zeropage.
|
||||
*
|
||||
* On large systems we can easily have thousands of nodes with RAM,
|
||||
* which cannot be fit into so few entries - so we have a mechanism
|
||||
* to extend the e820 table size at build-time, via the E820_MAX_ENTRIES
|
||||
* define below.
|
||||
*
|
||||
* ( Those extra entries are enumerated via the EFI memory map, not
|
||||
* via the legacy zeropage mechanism. )
|
||||
*
|
||||
* Size our internal memory map tables to have room for these additional
|
||||
* entries, based on a heuristic calculation: up to three entries per
|
||||
* NUMA node, plus E820_MAX_ENTRIES_ZEROPAGE for some extra space.
|
||||
*
|
||||
* This allows for bootstrap/firmware quirks such as possible duplicate
|
||||
* E820 entries that might need room in the same arrays, prior to the
|
||||
* call to e820__update_table() to remove duplicates. The allowance
|
||||
* of three memory map entries per node is "enough" entries for
|
||||
* the initial hardware platform motivating this mechanism to make
|
||||
* use of additional EFI map entries. Future platforms may want
|
||||
* to allow more than three entries per node or otherwise refine
|
||||
* this size.
|
||||
*/
|
||||
|
||||
#include <linux/numa.h>
|
||||
|
||||
#define E820_MAX_ENTRIES (E820_MAX_ENTRIES_ZEROPAGE + 3*MAX_NUMNODES)
|
||||
|
||||
/*
|
||||
* The whole array of E820 entries:
|
||||
*/
|
||||
struct e820_table {
|
||||
u32 nr_entries;
|
||||
struct e820_entry entries[E820_MAX_ENTRIES];
|
||||
};
|
||||
|
||||
/*
|
||||
* Various well-known legacy memory ranges in physical memory:
|
||||
*/
|
||||
#define ISA_START_ADDRESS 0x000a0000
|
||||
#define ISA_END_ADDRESS 0x00100000
|
||||
|
||||
#define BIOS_BEGIN 0x000a0000
|
||||
#define BIOS_END 0x00100000
|
||||
|
||||
#define HIGH_MEMORY 0x00100000
|
||||
|
||||
#define BIOS_ROM_BASE 0xffe00000
|
||||
#define BIOS_ROM_END 0xffffffff
|
||||
|
||||
#endif /* _ASM_E820_TYPES_H */
|
||||
@@ -0,0 +1,19 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_EDAC_H
|
||||
#define _ASM_X86_EDAC_H
|
||||
|
||||
/* ECC atomic, DMA, SMP and interrupt safe scrub function */
|
||||
|
||||
static inline void edac_atomic_scrub(void *va, u32 size)
|
||||
{
|
||||
u32 i, *virt_addr = va;
|
||||
|
||||
/*
|
||||
* Very carefully read and write to memory atomically so we
|
||||
* are interrupt, DMA and SMP safe.
|
||||
*/
|
||||
for (i = 0; i < size / 4; i++, virt_addr++)
|
||||
asm volatile("lock addl $0, %0"::"m" (*virt_addr));
|
||||
}
|
||||
|
||||
#endif /* _ASM_X86_EDAC_H */
|
||||
@@ -0,0 +1,430 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_EFI_H
|
||||
#define _ASM_X86_EFI_H
|
||||
|
||||
#include <asm/fpu/api.h>
|
||||
#include <asm/processor-flags.h>
|
||||
#include <asm/tlb.h>
|
||||
#include <asm/nospec-branch.h>
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/ibt.h>
|
||||
#include <linux/build_bug.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pgtable.h>
|
||||
|
||||
extern unsigned long efi_fw_vendor, efi_config_table;
|
||||
extern unsigned long efi_mixed_mode_stack_pa;
|
||||
|
||||
/*
|
||||
* We map the EFI regions needed for runtime services non-contiguously,
|
||||
* with preserved alignment on virtual addresses starting from -4G down
|
||||
* for a total max space of 64G. This way, we provide for stable runtime
|
||||
* services addresses across kernels so that a kexec'd kernel can still
|
||||
* use them.
|
||||
*
|
||||
* This is the main reason why we're doing stable VA mappings for RT
|
||||
* services.
|
||||
*/
|
||||
|
||||
#define EFI32_LOADER_SIGNATURE "EL32"
|
||||
#define EFI64_LOADER_SIGNATURE "EL64"
|
||||
|
||||
#define ARCH_EFI_IRQ_FLAGS_MASK X86_EFLAGS_IF
|
||||
|
||||
#define EFI_UNACCEPTED_UNIT_SIZE PMD_SIZE
|
||||
|
||||
/*
|
||||
* The EFI services are called through variadic functions in many cases. These
|
||||
* functions are implemented in assembler and support only a fixed number of
|
||||
* arguments. The macros below allows us to check at build time that we don't
|
||||
* try to call them with too many arguments.
|
||||
*
|
||||
* __efi_nargs() will return the number of arguments if it is 7 or less, and
|
||||
* cause a BUILD_BUG otherwise. The limitations of the C preprocessor make it
|
||||
* impossible to calculate the exact number of arguments beyond some
|
||||
* pre-defined limit. The maximum number of arguments currently supported by
|
||||
* any of the thunks is 7, so this is good enough for now and can be extended
|
||||
* in the obvious way if we ever need more.
|
||||
*/
|
||||
|
||||
#define __efi_nargs(...) __efi_nargs_(__VA_ARGS__)
|
||||
#define __efi_nargs_(...) __efi_nargs__(0, ##__VA_ARGS__, \
|
||||
__efi_arg_sentinel(9), __efi_arg_sentinel(8), \
|
||||
__efi_arg_sentinel(7), __efi_arg_sentinel(6), \
|
||||
__efi_arg_sentinel(5), __efi_arg_sentinel(4), \
|
||||
__efi_arg_sentinel(3), __efi_arg_sentinel(2), \
|
||||
__efi_arg_sentinel(1), __efi_arg_sentinel(0))
|
||||
#define __efi_nargs__(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, n, ...) \
|
||||
__take_second_arg(n, \
|
||||
({ BUILD_BUG_ON_MSG(1, "__efi_nargs limit exceeded"); 10; }))
|
||||
#define __efi_arg_sentinel(n) , n
|
||||
|
||||
/*
|
||||
* __efi_nargs_check(f, n, ...) will cause a BUILD_BUG if the ellipsis
|
||||
* represents more than n arguments.
|
||||
*/
|
||||
|
||||
#define __efi_nargs_check(f, n, ...) \
|
||||
__efi_nargs_check_(f, __efi_nargs(__VA_ARGS__), n)
|
||||
#define __efi_nargs_check_(f, p, n) __efi_nargs_check__(f, p, n)
|
||||
#define __efi_nargs_check__(f, p, n) ({ \
|
||||
BUILD_BUG_ON_MSG( \
|
||||
(p) > (n), \
|
||||
#f " called with too many arguments (" #p ">" #n ")"); \
|
||||
})
|
||||
|
||||
static inline void efi_fpu_begin(void)
|
||||
{
|
||||
/*
|
||||
* The UEFI calling convention (UEFI spec 2.3.2 and 2.3.4) requires
|
||||
* that FCW and MXCSR (64-bit) must be initialized prior to calling
|
||||
* UEFI code. (Oddly the spec does not require that the FPU stack
|
||||
* be empty.)
|
||||
*/
|
||||
kernel_fpu_begin_mask(KFPU_387 | KFPU_MXCSR);
|
||||
}
|
||||
|
||||
static inline void efi_fpu_end(void)
|
||||
{
|
||||
kernel_fpu_end();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
#define EFI_X86_KERNEL_ALLOC_LIMIT (SZ_512M - 1)
|
||||
#else /* !CONFIG_X86_32 */
|
||||
#define EFI_X86_KERNEL_ALLOC_LIMIT EFI_ALLOC_LIMIT
|
||||
|
||||
extern asmlinkage u64 __efi_call(void *fp, ...);
|
||||
|
||||
extern bool efi_disable_ibt_for_runtime;
|
||||
|
||||
#define efi_call(...) ({ \
|
||||
__efi_nargs_check(efi_call, 7, __VA_ARGS__); \
|
||||
__efi_call(__VA_ARGS__); \
|
||||
})
|
||||
|
||||
#undef arch_efi_call_virt
|
||||
#define arch_efi_call_virt(p, f, args...) ({ \
|
||||
u64 ret, ibt = ibt_save(efi_disable_ibt_for_runtime); \
|
||||
ret = efi_call((void *)p->f, args); \
|
||||
ibt_restore(ibt); \
|
||||
ret; \
|
||||
})
|
||||
|
||||
#ifdef CONFIG_KASAN
|
||||
/*
|
||||
* CONFIG_KASAN may redefine memset to __memset. __memset function is present
|
||||
* only in kernel binary. Since the EFI stub linked into a separate binary it
|
||||
* doesn't have __memset(). So we should use standard memset from
|
||||
* arch/x86/boot/compressed/string.c. The same applies to memcpy and memmove.
|
||||
*/
|
||||
#undef memcpy
|
||||
#undef memset
|
||||
#undef memmove
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_X86_32 */
|
||||
|
||||
extern int __init efi_memblock_x86_reserve_range(void);
|
||||
extern void __init efi_print_memmap(void);
|
||||
extern void __init efi_map_region(efi_memory_desc_t *md);
|
||||
extern void __init efi_map_region_fixed(efi_memory_desc_t *md);
|
||||
extern void efi_sync_low_kernel_mappings(void);
|
||||
extern int __init efi_alloc_page_tables(void);
|
||||
extern int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages);
|
||||
extern void __init efi_runtime_update_mappings(void);
|
||||
extern void __init efi_dump_pagetable(void);
|
||||
extern void __init efi_apply_memmap_quirks(void);
|
||||
extern int __init efi_reuse_config(u64 tables, int nr_tables);
|
||||
extern void efi_delete_dummy_variable(void);
|
||||
extern void efi_crash_gracefully_on_page_fault(unsigned long phys_addr);
|
||||
extern void efi_unmap_boot_services(void);
|
||||
|
||||
void arch_efi_call_virt_setup(void);
|
||||
void arch_efi_call_virt_teardown(void);
|
||||
|
||||
extern u64 efi_setup;
|
||||
|
||||
#ifdef CONFIG_EFI
|
||||
extern u64 __efi64_thunk(u32, ...);
|
||||
|
||||
#define efi64_thunk(...) ({ \
|
||||
u64 __pad[3]; /* must have space for 3 args on the stack */ \
|
||||
__efi_nargs_check(efi64_thunk, 9, __VA_ARGS__); \
|
||||
__efi64_thunk(__VA_ARGS__, __pad); \
|
||||
})
|
||||
|
||||
static inline bool efi_is_mixed(void)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_EFI_MIXED))
|
||||
return false;
|
||||
return IS_ENABLED(CONFIG_X86_64) && !efi_enabled(EFI_64BIT);
|
||||
}
|
||||
|
||||
static inline bool efi_runtime_supported(void)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_X86_64) == efi_enabled(EFI_64BIT))
|
||||
return true;
|
||||
|
||||
return IS_ENABLED(CONFIG_EFI_MIXED);
|
||||
}
|
||||
|
||||
extern void parse_efi_setup(u64 phys_addr, u32 data_len);
|
||||
|
||||
extern void efi_thunk_runtime_setup(void);
|
||||
efi_status_t efi_set_virtual_address_map(unsigned long memory_map_size,
|
||||
unsigned long descriptor_size,
|
||||
u32 descriptor_version,
|
||||
efi_memory_desc_t *virtual_map,
|
||||
unsigned long systab_phys);
|
||||
|
||||
/* arch specific definitions used by the stub code */
|
||||
|
||||
#ifdef CONFIG_EFI_MIXED
|
||||
|
||||
#define EFI_ALLOC_LIMIT (efi_is_64bit() ? ULONG_MAX : U32_MAX)
|
||||
|
||||
#define ARCH_HAS_EFISTUB_WRAPPERS
|
||||
|
||||
static inline bool efi_is_64bit(void)
|
||||
{
|
||||
extern const bool efi_is64;
|
||||
|
||||
return efi_is64;
|
||||
}
|
||||
|
||||
static inline bool efi_is_native(void)
|
||||
{
|
||||
return efi_is_64bit();
|
||||
}
|
||||
|
||||
#define efi_table_attr(inst, attr) \
|
||||
(efi_is_native() ? (inst)->attr \
|
||||
: efi_mixed_table_attr((inst), attr))
|
||||
|
||||
#define efi_mixed_table_attr(inst, attr) \
|
||||
(__typeof__(inst->attr)) \
|
||||
_Generic(inst->mixed_mode.attr, \
|
||||
u32: (unsigned long)(inst->mixed_mode.attr), \
|
||||
default: (inst->mixed_mode.attr))
|
||||
|
||||
/*
|
||||
* The following macros allow translating arguments if necessary from native to
|
||||
* mixed mode. The use case for this is to initialize the upper 32 bits of
|
||||
* output parameters, and where the 32-bit method requires a 64-bit argument,
|
||||
* which must be split up into two arguments to be thunked properly.
|
||||
*
|
||||
* As examples, the AllocatePool boot service returns the address of the
|
||||
* allocation, but it will not set the high 32 bits of the address. To ensure
|
||||
* that the full 64-bit address is initialized, we zero-init the address before
|
||||
* calling the thunk.
|
||||
*
|
||||
* The FreePages boot service takes a 64-bit physical address even in 32-bit
|
||||
* mode. For the thunk to work correctly, a native 64-bit call of
|
||||
* free_pages(addr, size)
|
||||
* must be translated to
|
||||
* efi64_thunk(free_pages, addr & U32_MAX, addr >> 32, size)
|
||||
* so that the two 32-bit halves of addr get pushed onto the stack separately.
|
||||
*/
|
||||
|
||||
static inline void *efi64_zero_upper(void *p)
|
||||
{
|
||||
if (p)
|
||||
((u32 *)p)[1] = 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
static inline u32 efi64_convert_status(efi_status_t status)
|
||||
{
|
||||
return (u32)(status | (u64)status >> 32);
|
||||
}
|
||||
|
||||
#define __efi64_split(val) (val) & U32_MAX, (u64)(val) >> 32
|
||||
|
||||
#define __efi64_argmap_free_pages(addr, size) \
|
||||
((addr), 0, (size))
|
||||
|
||||
#define __efi64_argmap_get_memory_map(mm_size, mm, key, size, ver) \
|
||||
((mm_size), (mm), efi64_zero_upper(key), efi64_zero_upper(size), (ver))
|
||||
|
||||
#define __efi64_argmap_allocate_pool(type, size, buffer) \
|
||||
((type), (size), efi64_zero_upper(buffer))
|
||||
|
||||
#define __efi64_argmap_locate_handle_buffer(type, proto, key, num, buf) \
|
||||
((type), (proto), (key), efi64_zero_upper(num), efi64_zero_upper(buf))
|
||||
|
||||
#define __efi64_argmap_create_event(type, tpl, f, c, event) \
|
||||
((type), (tpl), (f), (c), efi64_zero_upper(event))
|
||||
|
||||
#define __efi64_argmap_set_timer(event, type, time) \
|
||||
((event), (type), lower_32_bits(time), upper_32_bits(time))
|
||||
|
||||
#define __efi64_argmap_wait_for_event(num, event, index) \
|
||||
((num), (event), efi64_zero_upper(index))
|
||||
|
||||
#define __efi64_argmap_handle_protocol(handle, protocol, interface) \
|
||||
((handle), (protocol), efi64_zero_upper(interface))
|
||||
|
||||
#define __efi64_argmap_locate_protocol(protocol, reg, interface) \
|
||||
((protocol), (reg), efi64_zero_upper(interface))
|
||||
|
||||
#define __efi64_argmap_locate_device_path(protocol, path, handle) \
|
||||
((protocol), (path), efi64_zero_upper(handle))
|
||||
|
||||
#define __efi64_argmap_exit(handle, status, size, data) \
|
||||
((handle), efi64_convert_status(status), (size), (data))
|
||||
|
||||
/* PCI I/O */
|
||||
#define __efi64_argmap_get_location(protocol, seg, bus, dev, func) \
|
||||
((protocol), efi64_zero_upper(seg), efi64_zero_upper(bus), \
|
||||
efi64_zero_upper(dev), efi64_zero_upper(func))
|
||||
|
||||
/* LoadFile */
|
||||
#define __efi64_argmap_load_file(protocol, path, policy, bufsize, buf) \
|
||||
((protocol), (path), (policy), efi64_zero_upper(bufsize), (buf))
|
||||
|
||||
/* Graphics Output Protocol */
|
||||
#define __efi64_argmap_query_mode(gop, mode, size, info) \
|
||||
((gop), (mode), efi64_zero_upper(size), efi64_zero_upper(info))
|
||||
|
||||
/* TCG2 protocol */
|
||||
#define __efi64_argmap_hash_log_extend_event(prot, fl, addr, size, ev) \
|
||||
((prot), (fl), 0ULL, (u64)(addr), 0ULL, (u64)(size), 0ULL, ev)
|
||||
|
||||
/* DXE services */
|
||||
#define __efi64_argmap_get_memory_space_descriptor(phys, desc) \
|
||||
(__efi64_split(phys), (desc))
|
||||
|
||||
#define __efi64_argmap_set_memory_space_attributes(phys, size, flags) \
|
||||
(__efi64_split(phys), __efi64_split(size), __efi64_split(flags))
|
||||
|
||||
/* file protocol */
|
||||
#define __efi64_argmap_open(prot, newh, fname, mode, attr) \
|
||||
((prot), efi64_zero_upper(newh), (fname), __efi64_split(mode), \
|
||||
__efi64_split(attr))
|
||||
|
||||
#define __efi64_argmap_set_position(pos) (__efi64_split(pos))
|
||||
|
||||
/* file system protocol */
|
||||
#define __efi64_argmap_open_volume(prot, file) \
|
||||
((prot), efi64_zero_upper(file))
|
||||
|
||||
/* Memory Attribute Protocol */
|
||||
#define __efi64_argmap_get_memory_attributes(protocol, phys, size, flags) \
|
||||
((protocol), __efi64_split(phys), __efi64_split(size), (flags))
|
||||
|
||||
#define __efi64_argmap_set_memory_attributes(protocol, phys, size, flags) \
|
||||
((protocol), __efi64_split(phys), __efi64_split(size), __efi64_split(flags))
|
||||
|
||||
#define __efi64_argmap_clear_memory_attributes(protocol, phys, size, flags) \
|
||||
((protocol), __efi64_split(phys), __efi64_split(size), __efi64_split(flags))
|
||||
|
||||
/* EFI SMBIOS protocol */
|
||||
#define __efi64_argmap_get_next(protocol, smbioshandle, type, record, phandle) \
|
||||
((protocol), (smbioshandle), (type), efi64_zero_upper(record), \
|
||||
efi64_zero_upper(phandle))
|
||||
/*
|
||||
* The macros below handle the plumbing for the argument mapping. To add a
|
||||
* mapping for a specific EFI method, simply define a macro
|
||||
* __efi64_argmap_<method name>, following the examples above.
|
||||
*/
|
||||
|
||||
#define __efi64_thunk_map(inst, func, ...) \
|
||||
efi64_thunk(inst->mixed_mode.func, \
|
||||
__efi64_argmap(__efi64_argmap_ ## func(__VA_ARGS__), \
|
||||
(__VA_ARGS__)))
|
||||
|
||||
#define __efi64_argmap(mapped, args) \
|
||||
__PASTE(__efi64_argmap__, __efi_nargs(__efi_eat mapped))(mapped, args)
|
||||
#define __efi64_argmap__0(mapped, args) __efi_eval mapped
|
||||
#define __efi64_argmap__1(mapped, args) __efi_eval args
|
||||
|
||||
#define __efi_eat(...)
|
||||
#define __efi_eval(...) __VA_ARGS__
|
||||
|
||||
static inline efi_status_t __efi64_widen_efi_status(u64 status)
|
||||
{
|
||||
/* use rotate to move the value of bit #31 into position #63 */
|
||||
return ror64(rol32(status, 1), 1);
|
||||
}
|
||||
|
||||
/* The macro below handles dispatching via the thunk if needed */
|
||||
|
||||
#define efi_fn_call(inst, func, ...) \
|
||||
(efi_is_native() ? (inst)->func(__VA_ARGS__) \
|
||||
: efi_mixed_call((inst), func, ##__VA_ARGS__))
|
||||
|
||||
#define efi_mixed_call(inst, func, ...) \
|
||||
_Generic(inst->func(__VA_ARGS__), \
|
||||
efi_status_t: \
|
||||
__efi64_widen_efi_status( \
|
||||
__efi64_thunk_map(inst, func, ##__VA_ARGS__)), \
|
||||
u64: ({ BUILD_BUG(); ULONG_MAX; }), \
|
||||
default: \
|
||||
(__typeof__(inst->func(__VA_ARGS__))) \
|
||||
__efi64_thunk_map(inst, func, ##__VA_ARGS__))
|
||||
|
||||
#else /* CONFIG_EFI_MIXED */
|
||||
|
||||
static inline bool efi_is_64bit(void)
|
||||
{
|
||||
return IS_ENABLED(CONFIG_X86_64);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_EFI_MIXED */
|
||||
|
||||
extern bool efi_reboot_required(void);
|
||||
extern bool efi_is_table_address(unsigned long phys_addr);
|
||||
|
||||
extern void efi_reserve_boot_services(void);
|
||||
#else
|
||||
static inline void parse_efi_setup(u64 phys_addr, u32 data_len) {}
|
||||
static inline bool efi_reboot_required(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
static inline bool efi_is_table_address(unsigned long phys_addr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
static inline void efi_reserve_boot_services(void)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_EFI */
|
||||
|
||||
extern int __init efi_memmap_alloc(unsigned int num_entries,
|
||||
struct efi_memory_map_data *data);
|
||||
|
||||
extern int __init efi_memmap_install(struct efi_memory_map_data *data);
|
||||
extern int __init efi_memmap_split_count(efi_memory_desc_t *md,
|
||||
struct range *range);
|
||||
extern void __init efi_memmap_insert(struct efi_memory_map *old_memmap,
|
||||
void *buf, struct efi_mem_range *mem);
|
||||
|
||||
extern enum efi_secureboot_mode __x86_ima_efi_boot_mode(void);
|
||||
|
||||
#define arch_ima_efi_boot_mode __x86_ima_efi_boot_mode()
|
||||
|
||||
#ifdef CONFIG_EFI_RUNTIME_MAP
|
||||
int efi_get_runtime_map_size(void);
|
||||
int efi_get_runtime_map_desc_size(void);
|
||||
int efi_runtime_map_copy(void *buf, size_t bufsz);
|
||||
#else
|
||||
static inline int efi_get_runtime_map_size(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int efi_get_runtime_map_desc_size(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int efi_runtime_map_copy(void *buf, size_t bufsz)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_X86_EFI_H */
|
||||
@@ -0,0 +1,392 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_ELF_H
|
||||
#define _ASM_X86_ELF_H
|
||||
|
||||
/*
|
||||
* ELF register definitions..
|
||||
*/
|
||||
#include <linux/thread_info.h>
|
||||
|
||||
#include <asm/ia32.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/user.h>
|
||||
#include <asm/auxvec.h>
|
||||
#include <asm/fsgsbase.h>
|
||||
|
||||
typedef unsigned long elf_greg_t;
|
||||
|
||||
#define ELF_NGREG (sizeof(struct user_regs_struct) / sizeof(elf_greg_t))
|
||||
typedef elf_greg_t elf_gregset_t[ELF_NGREG];
|
||||
|
||||
typedef struct user_i387_struct elf_fpregset_t;
|
||||
|
||||
#ifdef __i386__
|
||||
|
||||
#define R_386_NONE 0
|
||||
#define R_386_32 1
|
||||
#define R_386_PC32 2
|
||||
#define R_386_GOT32 3
|
||||
#define R_386_PLT32 4
|
||||
#define R_386_COPY 5
|
||||
#define R_386_GLOB_DAT 6
|
||||
#define R_386_JMP_SLOT 7
|
||||
#define R_386_RELATIVE 8
|
||||
#define R_386_GOTOFF 9
|
||||
#define R_386_GOTPC 10
|
||||
#define R_386_NUM 11
|
||||
|
||||
/*
|
||||
* These are used to set parameters in the core dumps.
|
||||
*/
|
||||
#define ELF_CLASS ELFCLASS32
|
||||
#define ELF_DATA ELFDATA2LSB
|
||||
#define ELF_ARCH EM_386
|
||||
|
||||
#else
|
||||
|
||||
/* x86-64 relocation types */
|
||||
#define R_X86_64_NONE 0 /* No reloc */
|
||||
#define R_X86_64_64 1 /* Direct 64 bit */
|
||||
#define R_X86_64_PC32 2 /* PC relative 32 bit signed */
|
||||
#define R_X86_64_GOT32 3 /* 32 bit GOT entry */
|
||||
#define R_X86_64_PLT32 4 /* 32 bit PLT address */
|
||||
#define R_X86_64_COPY 5 /* Copy symbol at runtime */
|
||||
#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */
|
||||
#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */
|
||||
#define R_X86_64_RELATIVE 8 /* Adjust by program base */
|
||||
#define R_X86_64_GOTPCREL 9 /* 32 bit signed pc relative offset to GOT */
|
||||
#define R_X86_64_GOTPCRELX 41
|
||||
#define R_X86_64_REX_GOTPCRELX 42
|
||||
#define R_X86_64_32 10 /* Direct 32 bit zero extended */
|
||||
#define R_X86_64_32S 11 /* Direct 32 bit sign extended */
|
||||
#define R_X86_64_16 12 /* Direct 16 bit zero extended */
|
||||
#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */
|
||||
#define R_X86_64_8 14 /* Direct 8 bit sign extended */
|
||||
#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */
|
||||
#define R_X86_64_PC64 24 /* Place relative 64-bit signed */
|
||||
|
||||
/*
|
||||
* These are used to set parameters in the core dumps.
|
||||
*/
|
||||
#define ELF_CLASS ELFCLASS64
|
||||
#define ELF_DATA ELFDATA2LSB
|
||||
#define ELF_ARCH EM_X86_64
|
||||
|
||||
#endif
|
||||
|
||||
#include <asm/vdso.h>
|
||||
|
||||
extern unsigned int vdso64_enabled;
|
||||
extern unsigned int vdso32_enabled;
|
||||
|
||||
/*
|
||||
* This is used to ensure we don't load something for the wrong architecture.
|
||||
*/
|
||||
#define elf_check_arch_ia32(x) \
|
||||
(((x)->e_machine == EM_386) || ((x)->e_machine == EM_486))
|
||||
|
||||
#include <asm/processor.h>
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
#include <asm/desc.h>
|
||||
|
||||
#define elf_check_arch(x) elf_check_arch_ia32(x)
|
||||
|
||||
/* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program starts %edx
|
||||
contains a pointer to a function which might be registered using `atexit'.
|
||||
This provides a mean for the dynamic linker to call DT_FINI functions for
|
||||
shared libraries that have been loaded before the code runs.
|
||||
|
||||
A value of 0 tells we have no such handler.
|
||||
|
||||
We might as well make sure everything else is cleared too (except for %esp),
|
||||
just to make things more deterministic.
|
||||
*/
|
||||
#define ELF_PLAT_INIT(_r, load_addr) \
|
||||
do { \
|
||||
_r->bx = 0; _r->cx = 0; _r->dx = 0; \
|
||||
_r->si = 0; _r->di = 0; _r->bp = 0; \
|
||||
_r->ax = 0; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* regs is struct pt_regs, pr_reg is elf_gregset_t (which is
|
||||
* now struct_user_regs, they are different)
|
||||
*/
|
||||
|
||||
#define ELF_CORE_COPY_REGS(pr_reg, regs) \
|
||||
do { \
|
||||
pr_reg[0] = regs->bx; \
|
||||
pr_reg[1] = regs->cx; \
|
||||
pr_reg[2] = regs->dx; \
|
||||
pr_reg[3] = regs->si; \
|
||||
pr_reg[4] = regs->di; \
|
||||
pr_reg[5] = regs->bp; \
|
||||
pr_reg[6] = regs->ax; \
|
||||
pr_reg[7] = regs->ds; \
|
||||
pr_reg[8] = regs->es; \
|
||||
pr_reg[9] = regs->fs; \
|
||||
savesegment(gs, pr_reg[10]); \
|
||||
pr_reg[11] = regs->orig_ax; \
|
||||
pr_reg[12] = regs->ip; \
|
||||
pr_reg[13] = regs->cs; \
|
||||
pr_reg[14] = regs->flags; \
|
||||
pr_reg[15] = regs->sp; \
|
||||
pr_reg[16] = regs->ss; \
|
||||
} while (0);
|
||||
|
||||
#define ELF_PLATFORM (utsname()->machine)
|
||||
#define set_personality_64bit() do { } while (0)
|
||||
|
||||
#else /* CONFIG_X86_32 */
|
||||
|
||||
/*
|
||||
* This is used to ensure we don't load something for the wrong architecture.
|
||||
*/
|
||||
#define elf_check_arch(x) \
|
||||
((x)->e_machine == EM_X86_64)
|
||||
|
||||
#define compat_elf_check_arch(x) \
|
||||
((elf_check_arch_ia32(x) && ia32_enabled_verbose()) || \
|
||||
(IS_ENABLED(CONFIG_X86_X32_ABI) && (x)->e_machine == EM_X86_64))
|
||||
|
||||
static inline void elf_common_init(struct thread_struct *t,
|
||||
struct pt_regs *regs, const u16 ds)
|
||||
{
|
||||
/* ax gets execve's return value. */
|
||||
/*regs->ax = */ regs->bx = regs->cx = regs->dx = 0;
|
||||
regs->si = regs->di = regs->bp = 0;
|
||||
regs->r8 = regs->r9 = regs->r10 = regs->r11 = 0;
|
||||
regs->r12 = regs->r13 = regs->r14 = regs->r15 = 0;
|
||||
t->fsbase = t->gsbase = 0;
|
||||
t->fsindex = t->gsindex = 0;
|
||||
t->ds = t->es = ds;
|
||||
}
|
||||
|
||||
#define ELF_PLAT_INIT(_r, load_addr) \
|
||||
elf_common_init(¤t->thread, _r, 0)
|
||||
|
||||
#define COMPAT_ELF_PLAT_INIT(regs, load_addr) \
|
||||
elf_common_init(¤t->thread, regs, __USER_DS)
|
||||
|
||||
void compat_start_thread(struct pt_regs *regs, u32 new_ip, u32 new_sp, bool x32);
|
||||
#define COMPAT_START_THREAD(ex, regs, new_ip, new_sp) \
|
||||
compat_start_thread(regs, new_ip, new_sp, ex->e_machine == EM_X86_64)
|
||||
|
||||
void set_personality_ia32(bool);
|
||||
#define COMPAT_SET_PERSONALITY(ex) \
|
||||
set_personality_ia32((ex).e_machine == EM_X86_64)
|
||||
|
||||
#define COMPAT_ELF_PLATFORM ("i686")
|
||||
|
||||
/*
|
||||
* regs is struct pt_regs, pr_reg is elf_gregset_t (which is
|
||||
* now struct_user_regs, they are different). Assumes current is the process
|
||||
* getting dumped.
|
||||
*/
|
||||
|
||||
#define ELF_CORE_COPY_REGS(pr_reg, regs) \
|
||||
do { \
|
||||
unsigned v; \
|
||||
(pr_reg)[0] = (regs)->r15; \
|
||||
(pr_reg)[1] = (regs)->r14; \
|
||||
(pr_reg)[2] = (regs)->r13; \
|
||||
(pr_reg)[3] = (regs)->r12; \
|
||||
(pr_reg)[4] = (regs)->bp; \
|
||||
(pr_reg)[5] = (regs)->bx; \
|
||||
(pr_reg)[6] = (regs)->r11; \
|
||||
(pr_reg)[7] = (regs)->r10; \
|
||||
(pr_reg)[8] = (regs)->r9; \
|
||||
(pr_reg)[9] = (regs)->r8; \
|
||||
(pr_reg)[10] = (regs)->ax; \
|
||||
(pr_reg)[11] = (regs)->cx; \
|
||||
(pr_reg)[12] = (regs)->dx; \
|
||||
(pr_reg)[13] = (regs)->si; \
|
||||
(pr_reg)[14] = (regs)->di; \
|
||||
(pr_reg)[15] = (regs)->orig_ax; \
|
||||
(pr_reg)[16] = (regs)->ip; \
|
||||
(pr_reg)[17] = (regs)->cs; \
|
||||
(pr_reg)[18] = (regs)->flags; \
|
||||
(pr_reg)[19] = (regs)->sp; \
|
||||
(pr_reg)[20] = (regs)->ss; \
|
||||
(pr_reg)[21] = x86_fsbase_read_cpu(); \
|
||||
(pr_reg)[22] = x86_gsbase_read_cpu_inactive(); \
|
||||
asm("movl %%ds,%0" : "=r" (v)); (pr_reg)[23] = v; \
|
||||
asm("movl %%es,%0" : "=r" (v)); (pr_reg)[24] = v; \
|
||||
asm("movl %%fs,%0" : "=r" (v)); (pr_reg)[25] = v; \
|
||||
asm("movl %%gs,%0" : "=r" (v)); (pr_reg)[26] = v; \
|
||||
} while (0);
|
||||
|
||||
/* I'm not sure if we can use '-' here */
|
||||
#define ELF_PLATFORM ("x86_64")
|
||||
extern void set_personality_64bit(void);
|
||||
extern int force_personality32;
|
||||
|
||||
#endif /* !CONFIG_X86_32 */
|
||||
|
||||
#define CORE_DUMP_USE_REGSET
|
||||
#define ELF_EXEC_PAGESIZE 4096
|
||||
|
||||
/*
|
||||
* This is the base location for PIE (ET_DYN with INTERP) loads. On
|
||||
* 64-bit, this is above 4GB to leave the entire 32-bit address
|
||||
* space open for things that want to use the area for 32-bit pointers.
|
||||
*/
|
||||
#define ELF_ET_DYN_BASE (mmap_is_ia32() ? 0x000400000UL : \
|
||||
(DEFAULT_MAP_WINDOW / 3 * 2))
|
||||
|
||||
/* This yields a mask that user programs can use to figure out what
|
||||
instruction set this CPU supports. This could be done in user space,
|
||||
but it's not easy, and we've already done it here. */
|
||||
|
||||
#define ELF_HWCAP (boot_cpu_data.x86_capability[CPUID_1_EDX])
|
||||
|
||||
extern u32 elf_hwcap2;
|
||||
|
||||
/*
|
||||
* HWCAP2 supplies mask with kernel enabled CPU features, so that
|
||||
* the application can discover that it can safely use them.
|
||||
* The bits are defined in uapi/asm/hwcap2.h.
|
||||
*/
|
||||
#define ELF_HWCAP2 (elf_hwcap2)
|
||||
|
||||
/* This yields a string that ld.so will use to load implementation
|
||||
specific libraries for optimization. This is more specific in
|
||||
intent than poking at uname or /proc/cpuinfo.
|
||||
|
||||
For the moment, we have only optimizations for the Intel generations,
|
||||
but that could change... */
|
||||
|
||||
#define SET_PERSONALITY(ex) set_personality_64bit()
|
||||
|
||||
/*
|
||||
* An executable for which elf_read_implies_exec() returns TRUE will
|
||||
* have the READ_IMPLIES_EXEC personality flag set automatically.
|
||||
*
|
||||
* The decision process for determining the results are:
|
||||
*
|
||||
* CPU: | lacks NX* | has NX, ia32 | has NX, x86_64 |
|
||||
* ELF: | | | |
|
||||
* ---------------------|------------|------------------|----------------|
|
||||
* missing PT_GNU_STACK | exec-all | exec-all | exec-none |
|
||||
* PT_GNU_STACK == RWX | exec-stack | exec-stack | exec-stack |
|
||||
* PT_GNU_STACK == RW | exec-none | exec-none | exec-none |
|
||||
*
|
||||
* exec-all : all PROT_READ user mappings are executable, except when
|
||||
* backed by files on a noexec-filesystem.
|
||||
* exec-none : only PROT_EXEC user mappings are executable.
|
||||
* exec-stack: only the stack and PROT_EXEC user mappings are executable.
|
||||
*
|
||||
* *this column has no architectural effect: NX markings are ignored by
|
||||
* hardware, but may have behavioral effects when "wants X" collides with
|
||||
* "cannot be X" constraints in memory permission flags, as in
|
||||
* https://lkml.kernel.org/r/20190418055759.GA3155@mellanox.com
|
||||
*
|
||||
*/
|
||||
#define elf_read_implies_exec(ex, executable_stack) \
|
||||
(mmap_is_ia32() && executable_stack == EXSTACK_DEFAULT)
|
||||
|
||||
struct task_struct;
|
||||
|
||||
#define ARCH_DLINFO_IA32 \
|
||||
do { \
|
||||
if (VDSO_CURRENT_BASE) { \
|
||||
NEW_AUX_ENT(AT_SYSINFO, VDSO_ENTRY); \
|
||||
NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_CURRENT_BASE); \
|
||||
} \
|
||||
NEW_AUX_ENT(AT_MINSIGSTKSZ, get_sigframe_size()); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* True on X86_32 or when emulating IA32 on X86_64
|
||||
*/
|
||||
static inline int mmap_is_ia32(void)
|
||||
{
|
||||
return IS_ENABLED(CONFIG_X86_32) ||
|
||||
(IS_ENABLED(CONFIG_COMPAT) &&
|
||||
test_thread_flag(TIF_ADDR32));
|
||||
}
|
||||
|
||||
extern unsigned long task_size_32bit(void);
|
||||
extern unsigned long task_size_64bit(int full_addr_space);
|
||||
extern unsigned long get_mmap_base(int is_legacy);
|
||||
extern bool mmap_address_hint_valid(unsigned long addr, unsigned long len);
|
||||
extern unsigned long get_sigframe_size(void);
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
|
||||
#define __STACK_RND_MASK(is32bit) (0x7ff)
|
||||
#define STACK_RND_MASK (0x7ff)
|
||||
|
||||
#define ARCH_DLINFO ARCH_DLINFO_IA32
|
||||
|
||||
/* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */
|
||||
|
||||
#else /* CONFIG_X86_32 */
|
||||
|
||||
/* 1GB for 64bit, 8MB for 32bit */
|
||||
#define __STACK_RND_MASK(is32bit) ((is32bit) ? 0x7ff : 0x3fffff)
|
||||
#define STACK_RND_MASK __STACK_RND_MASK(mmap_is_ia32())
|
||||
|
||||
#define ARCH_DLINFO \
|
||||
do { \
|
||||
if (vdso64_enabled) \
|
||||
NEW_AUX_ENT(AT_SYSINFO_EHDR, \
|
||||
(unsigned long __force)current->mm->context.vdso); \
|
||||
NEW_AUX_ENT(AT_MINSIGSTKSZ, get_sigframe_size()); \
|
||||
} while (0)
|
||||
|
||||
/* As a historical oddity, the x32 and x86_64 vDSOs are controlled together. */
|
||||
#define ARCH_DLINFO_X32 \
|
||||
do { \
|
||||
if (vdso64_enabled) \
|
||||
NEW_AUX_ENT(AT_SYSINFO_EHDR, \
|
||||
(unsigned long __force)current->mm->context.vdso); \
|
||||
NEW_AUX_ENT(AT_MINSIGSTKSZ, get_sigframe_size()); \
|
||||
} while (0)
|
||||
|
||||
#define AT_SYSINFO 32
|
||||
|
||||
#define COMPAT_ARCH_DLINFO \
|
||||
if (exec->e_machine == EM_X86_64) \
|
||||
ARCH_DLINFO_X32; \
|
||||
else if (IS_ENABLED(CONFIG_IA32_EMULATION)) \
|
||||
ARCH_DLINFO_IA32
|
||||
|
||||
#define COMPAT_ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE + 0x1000000)
|
||||
|
||||
#endif /* !CONFIG_X86_32 */
|
||||
|
||||
#define VDSO_CURRENT_BASE ((unsigned long)current->mm->context.vdso)
|
||||
|
||||
#define VDSO_ENTRY \
|
||||
((unsigned long)current->mm->context.vdso + \
|
||||
vdso32_image.sym___kernel_vsyscall)
|
||||
|
||||
struct linux_binprm;
|
||||
|
||||
#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
|
||||
extern int arch_setup_additional_pages(struct linux_binprm *bprm,
|
||||
int uses_interp);
|
||||
extern int compat_arch_setup_additional_pages(struct linux_binprm *bprm,
|
||||
int uses_interp, bool x32);
|
||||
#define COMPAT_ARCH_SETUP_ADDITIONAL_PAGES(bprm, ex, interpreter) \
|
||||
compat_arch_setup_additional_pages(bprm, interpreter, \
|
||||
(ex->e_machine == EM_X86_64))
|
||||
|
||||
extern bool arch_syscall_is_vdso_sigreturn(struct pt_regs *regs);
|
||||
|
||||
/* Do not change the values. See get_align_mask() */
|
||||
enum align_flags {
|
||||
ALIGN_VA_32 = BIT(0),
|
||||
ALIGN_VA_64 = BIT(1),
|
||||
};
|
||||
|
||||
struct va_alignment {
|
||||
int flags;
|
||||
unsigned long mask;
|
||||
unsigned long bits;
|
||||
} ____cacheline_aligned;
|
||||
|
||||
extern struct va_alignment va_align;
|
||||
#endif /* _ASM_X86_ELF_H */
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef _ASM_X86_ELFCORE_COMPAT_H
|
||||
#define _ASM_X86_ELFCORE_COMPAT_H
|
||||
|
||||
#include <asm/user32.h>
|
||||
|
||||
/*
|
||||
* On amd64 we have two 32bit ABIs - i386 and x32. The latter
|
||||
* has bigger registers, so we use it for compat_elf_regset_t.
|
||||
* The former uses i386_elf_prstatus and PRSTATUS_SIZE/SET_PR_FPVALID
|
||||
* are used to choose the size and location of ->pr_fpvalid of
|
||||
* the layout actually used.
|
||||
*/
|
||||
typedef struct user_regs_struct compat_elf_gregset_t;
|
||||
|
||||
struct i386_elf_prstatus
|
||||
{
|
||||
struct compat_elf_prstatus_common common;
|
||||
struct user_regs_struct32 pr_reg;
|
||||
compat_int_t pr_fpvalid;
|
||||
};
|
||||
|
||||
#define PRSTATUS_SIZE \
|
||||
(user_64bit_mode(task_pt_regs(current)) \
|
||||
? sizeof(struct compat_elf_prstatus) \
|
||||
: sizeof(struct i386_elf_prstatus))
|
||||
#define SET_PR_FPVALID(S) \
|
||||
(*(user_64bit_mode(task_pt_regs(current)) \
|
||||
? &(S)->pr_fpvalid \
|
||||
: &((struct i386_elf_prstatus *)(S))->pr_fpvalid) = 1)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_EMERGENCY_RESTART_H
|
||||
#define _ASM_X86_EMERGENCY_RESTART_H
|
||||
|
||||
extern void machine_emergency_restart(void);
|
||||
|
||||
#endif /* _ASM_X86_EMERGENCY_RESTART_H */
|
||||
@@ -0,0 +1,14 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_EMULATE_PREFIX_H
|
||||
#define _ASM_X86_EMULATE_PREFIX_H
|
||||
|
||||
/*
|
||||
* Virt escape sequences to trigger instruction emulation;
|
||||
* ideally these would decode to 'whole' instruction and not destroy
|
||||
* the instruction stream; sadly this is not true for the 'kvm' one :/
|
||||
*/
|
||||
|
||||
#define __XEN_EMULATE_PREFIX 0x0f,0x0b,0x78,0x65,0x6e /* ud2 ; .ascii "xen" */
|
||||
#define __KVM_EMULATE_PREFIX 0x0f,0x0b,0x6b,0x76,0x6d /* ud2 ; .ascii "kvm" */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_ENCLU_H
|
||||
#define _ASM_X86_ENCLU_H
|
||||
|
||||
#define EENTER 0x02
|
||||
#define ERESUME 0x03
|
||||
#define EEXIT 0x04
|
||||
|
||||
#endif /* _ASM_X86_ENCLU_H */
|
||||
@@ -0,0 +1,112 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
#ifndef _ASM_X86_ENTRY_COMMON_H
|
||||
#define _ASM_X86_ENTRY_COMMON_H
|
||||
|
||||
#include <linux/randomize_kstack.h>
|
||||
#include <linux/user-return-notifier.h>
|
||||
|
||||
#include <asm/nospec-branch.h>
|
||||
#include <asm/io_bitmap.h>
|
||||
#include <asm/fpu/api.h>
|
||||
#include <asm/fred.h>
|
||||
|
||||
/* Check that the stack and regs on entry from user mode are sane. */
|
||||
static __always_inline void arch_enter_from_user_mode(struct pt_regs *regs)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_DEBUG_ENTRY)) {
|
||||
/*
|
||||
* Make sure that the entry code gave us a sensible EFLAGS
|
||||
* register. Native because we want to check the actual CPU
|
||||
* state, not the interrupt state as imagined by Xen.
|
||||
*/
|
||||
unsigned long flags = native_save_fl();
|
||||
unsigned long mask = X86_EFLAGS_DF | X86_EFLAGS_NT;
|
||||
|
||||
/*
|
||||
* For !SMAP hardware we patch out CLAC on entry.
|
||||
*/
|
||||
if (cpu_feature_enabled(X86_FEATURE_SMAP) ||
|
||||
cpu_feature_enabled(X86_FEATURE_XENPV))
|
||||
mask |= X86_EFLAGS_AC;
|
||||
|
||||
WARN_ON_ONCE(flags & mask);
|
||||
|
||||
/* We think we came from user mode. Make sure pt_regs agrees. */
|
||||
WARN_ON_ONCE(!user_mode(regs));
|
||||
|
||||
/*
|
||||
* All entries from user mode (except #DF) should be on the
|
||||
* normal thread stack and should have user pt_regs in the
|
||||
* correct location.
|
||||
*/
|
||||
WARN_ON_ONCE(!on_thread_stack());
|
||||
WARN_ON_ONCE(regs != task_pt_regs(current));
|
||||
}
|
||||
}
|
||||
#define arch_enter_from_user_mode arch_enter_from_user_mode
|
||||
|
||||
static inline void arch_exit_work(unsigned long ti_work)
|
||||
{
|
||||
if (ti_work & _TIF_USER_RETURN_NOTIFY)
|
||||
fire_user_return_notifiers();
|
||||
|
||||
if (unlikely(ti_work & _TIF_IO_BITMAP))
|
||||
tss_update_io_bitmap();
|
||||
|
||||
if (unlikely(ti_work & _TIF_NEED_FPU_LOAD))
|
||||
switch_fpu_return();
|
||||
}
|
||||
|
||||
static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs,
|
||||
unsigned long ti_work)
|
||||
{
|
||||
fpregs_assert_state_consistent();
|
||||
|
||||
if (unlikely(ti_work))
|
||||
arch_exit_work(ti_work);
|
||||
|
||||
fred_update_rsp0();
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
/*
|
||||
* Compat syscalls set TS_COMPAT. Make sure we clear it before
|
||||
* returning to user mode. We need to clear it *after* signal
|
||||
* handling, because syscall restart has a fixup for compat
|
||||
* syscalls. The fixup is exercised by the ptrace_syscall_32
|
||||
* selftest.
|
||||
*
|
||||
* We also need to clear TS_REGS_POKED_I386: the 32-bit tracer
|
||||
* special case only applies after poking regs and before the
|
||||
* very next return to user mode.
|
||||
*/
|
||||
current_thread_info()->status &= ~(TS_COMPAT | TS_I386_REGS_POKED);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This value will get limited by KSTACK_OFFSET_MAX(), which is 10
|
||||
* bits. The actual entropy will be further reduced by the compiler
|
||||
* when applying stack alignment constraints (see cc_stack_align4/8 in
|
||||
* arch/x86/Makefile), which will remove the 3 (x86_64) or 2 (ia32)
|
||||
* low bits from any entropy chosen here.
|
||||
*
|
||||
* Therefore, final stack offset entropy will be 7 (x86_64) or
|
||||
* 8 (ia32) bits.
|
||||
*/
|
||||
choose_random_kstack_offset(rdtsc());
|
||||
|
||||
/* Avoid unnecessary reads of 'x86_ibpb_exit_to_user' */
|
||||
if (cpu_feature_enabled(X86_FEATURE_IBPB_EXIT_TO_USER) &&
|
||||
this_cpu_read(x86_ibpb_exit_to_user)) {
|
||||
indirect_branch_prediction_barrier();
|
||||
this_cpu_write(x86_ibpb_exit_to_user, false);
|
||||
}
|
||||
}
|
||||
#define arch_exit_to_user_mode_prepare arch_exit_to_user_mode_prepare
|
||||
|
||||
static __always_inline void arch_exit_to_user_mode(void)
|
||||
{
|
||||
amd_clear_divider();
|
||||
}
|
||||
#define arch_exit_to_user_mode arch_exit_to_user_mode
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_ESPFIX_H
|
||||
#define _ASM_X86_ESPFIX_H
|
||||
|
||||
#ifdef CONFIG_X86_ESPFIX64
|
||||
|
||||
#include <asm/percpu.h>
|
||||
|
||||
DECLARE_PER_CPU_READ_MOSTLY(unsigned long, espfix_stack);
|
||||
DECLARE_PER_CPU_READ_MOSTLY(unsigned long, espfix_waddr);
|
||||
|
||||
extern void init_espfix_bsp(void);
|
||||
extern void init_espfix_ap(int cpu);
|
||||
#else
|
||||
static inline void init_espfix_ap(int cpu) { }
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_X86_ESPFIX_H */
|
||||
@@ -0,0 +1 @@
|
||||
/* define arch_align_stack() here */
|
||||
@@ -0,0 +1,60 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_EXTABLE_H
|
||||
#define _ASM_X86_EXTABLE_H
|
||||
|
||||
#include <asm/extable_fixup_types.h>
|
||||
|
||||
/*
|
||||
* The exception table consists of two addresses relative to the
|
||||
* exception table entry itself and a type selector field.
|
||||
*
|
||||
* The first address is of an instruction that is allowed to fault, the
|
||||
* second is the target at which the program should continue.
|
||||
*
|
||||
* The type entry is used by fixup_exception() to select the handler to
|
||||
* deal with the fault caused by the instruction in the first field.
|
||||
*
|
||||
* All the routines below use bits of fixup code that are out of line
|
||||
* with the main instruction path. This means when everything is well,
|
||||
* we don't even have to jump over them. Further, they do not intrude
|
||||
* on our cache or tlb entries.
|
||||
*/
|
||||
|
||||
struct exception_table_entry {
|
||||
int insn, fixup, data;
|
||||
};
|
||||
struct pt_regs;
|
||||
|
||||
#define ARCH_HAS_RELATIVE_EXTABLE
|
||||
|
||||
#define swap_ex_entry_fixup(a, b, tmp, delta) \
|
||||
do { \
|
||||
(a)->fixup = (b)->fixup + (delta); \
|
||||
(b)->fixup = (tmp).fixup - (delta); \
|
||||
(a)->data = (b)->data; \
|
||||
(b)->data = (tmp).data; \
|
||||
} while (0)
|
||||
|
||||
extern int fixup_exception(struct pt_regs *regs, int trapnr,
|
||||
unsigned long error_code, unsigned long fault_addr);
|
||||
extern int ex_get_fixup_type(unsigned long ip);
|
||||
extern void early_fixup_exception(struct pt_regs *regs, int trapnr);
|
||||
|
||||
#ifdef CONFIG_X86_MCE
|
||||
extern void __noreturn ex_handler_msr_mce(struct pt_regs *regs, bool wrmsr);
|
||||
#else
|
||||
static inline void __noreturn ex_handler_msr_mce(struct pt_regs *regs, bool wrmsr)
|
||||
{
|
||||
for (;;)
|
||||
cpu_relax();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BPF_JIT) && defined(CONFIG_X86_64)
|
||||
bool ex_handler_bpf(const struct exception_table_entry *x, struct pt_regs *regs);
|
||||
#else
|
||||
static inline bool ex_handler_bpf(const struct exception_table_entry *x,
|
||||
struct pt_regs *regs) { return false; }
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,71 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_EXTABLE_FIXUP_TYPES_H
|
||||
#define _ASM_X86_EXTABLE_FIXUP_TYPES_H
|
||||
|
||||
/*
|
||||
* Our IMM is signed, as such it must live at the top end of the word. Also,
|
||||
* since C99 hex constants are of ambiguous type, force cast the mask to 'int'
|
||||
* so that FIELD_GET() will DTRT and sign extend the value when it extracts it.
|
||||
*/
|
||||
#define EX_DATA_TYPE_MASK ((int)0x000000FF)
|
||||
#define EX_DATA_REG_MASK ((int)0x00000F00)
|
||||
#define EX_DATA_FLAG_MASK ((int)0x0000F000)
|
||||
#define EX_DATA_IMM_MASK ((int)0xFFFF0000)
|
||||
|
||||
#define EX_DATA_REG_SHIFT 8
|
||||
#define EX_DATA_FLAG_SHIFT 12
|
||||
#define EX_DATA_IMM_SHIFT 16
|
||||
|
||||
#define EX_DATA_REG(reg) ((reg) << EX_DATA_REG_SHIFT)
|
||||
#define EX_DATA_FLAG(flag) ((flag) << EX_DATA_FLAG_SHIFT)
|
||||
#define EX_DATA_IMM(imm) ((imm) << EX_DATA_IMM_SHIFT)
|
||||
|
||||
/* segment regs */
|
||||
#define EX_REG_DS EX_DATA_REG(8)
|
||||
#define EX_REG_ES EX_DATA_REG(9)
|
||||
#define EX_REG_FS EX_DATA_REG(10)
|
||||
#define EX_REG_GS EX_DATA_REG(11)
|
||||
|
||||
/* flags */
|
||||
#define EX_FLAG_CLEAR_AX EX_DATA_FLAG(1)
|
||||
#define EX_FLAG_CLEAR_DX EX_DATA_FLAG(2)
|
||||
#define EX_FLAG_CLEAR_AX_DX EX_DATA_FLAG(3)
|
||||
|
||||
/* types */
|
||||
#define EX_TYPE_NONE 0
|
||||
#define EX_TYPE_DEFAULT 1
|
||||
#define EX_TYPE_FAULT 2
|
||||
#define EX_TYPE_UACCESS 3
|
||||
/* unused, was: #define EX_TYPE_COPY 4 */
|
||||
#define EX_TYPE_CLEAR_FS 5
|
||||
#define EX_TYPE_FPU_RESTORE 6
|
||||
#define EX_TYPE_BPF 7
|
||||
#define EX_TYPE_WRMSR 8
|
||||
#define EX_TYPE_RDMSR 9
|
||||
#define EX_TYPE_WRMSR_SAFE 10 /* reg := -EIO */
|
||||
#define EX_TYPE_RDMSR_SAFE 11 /* reg := -EIO */
|
||||
#define EX_TYPE_WRMSR_IN_MCE 12
|
||||
#define EX_TYPE_RDMSR_IN_MCE 13
|
||||
#define EX_TYPE_DEFAULT_MCE_SAFE 14
|
||||
#define EX_TYPE_FAULT_MCE_SAFE 15
|
||||
|
||||
#define EX_TYPE_POP_REG 16 /* sp += sizeof(long) */
|
||||
#define EX_TYPE_POP_ZERO (EX_TYPE_POP_REG | EX_DATA_IMM(0))
|
||||
|
||||
#define EX_TYPE_IMM_REG 17 /* reg := (long)imm */
|
||||
#define EX_TYPE_EFAULT_REG (EX_TYPE_IMM_REG | EX_DATA_IMM(-EFAULT))
|
||||
#define EX_TYPE_ZERO_REG (EX_TYPE_IMM_REG | EX_DATA_IMM(0))
|
||||
#define EX_TYPE_ONE_REG (EX_TYPE_IMM_REG | EX_DATA_IMM(1))
|
||||
|
||||
#define EX_TYPE_FAULT_SGX 18
|
||||
|
||||
#define EX_TYPE_UCOPY_LEN 19 /* cx := reg + imm*cx */
|
||||
#define EX_TYPE_UCOPY_LEN1 (EX_TYPE_UCOPY_LEN | EX_DATA_IMM(1))
|
||||
#define EX_TYPE_UCOPY_LEN4 (EX_TYPE_UCOPY_LEN | EX_DATA_IMM(4))
|
||||
#define EX_TYPE_UCOPY_LEN8 (EX_TYPE_UCOPY_LEN | EX_DATA_IMM(8))
|
||||
|
||||
#define EX_TYPE_ZEROPAD 20 /* longword load with zeropad on fault */
|
||||
|
||||
#define EX_TYPE_ERETU 21
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* fixmap.h: compile-time virtual memory allocation
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Copyright (C) 1998 Ingo Molnar
|
||||
*
|
||||
* Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
|
||||
* x86_32 and x86_64 integration by Gustavo F. Padovan, February 2009
|
||||
*/
|
||||
|
||||
#ifndef _ASM_X86_FIXMAP_H
|
||||
#define _ASM_X86_FIXMAP_H
|
||||
|
||||
#include <asm/kmap_size.h>
|
||||
|
||||
/*
|
||||
* Exposed to assembly code for setting up initial page tables. Cannot be
|
||||
* calculated in assembly code (fixmap entries are an enum), but is sanity
|
||||
* checked in the actual fixmap C code to make sure that the fixmap is
|
||||
* covered fully.
|
||||
*/
|
||||
#ifndef CONFIG_DEBUG_KMAP_LOCAL_FORCE_MAP
|
||||
# define FIXMAP_PMD_NUM 2
|
||||
#else
|
||||
# define KM_PMDS (KM_MAX_IDX * ((CONFIG_NR_CPUS + 511) / 512))
|
||||
# define FIXMAP_PMD_NUM (KM_PMDS + 2)
|
||||
#endif
|
||||
/* fixmap starts downwards from the 507th entry in level2_fixmap_pgt */
|
||||
#define FIXMAP_PMD_TOP 507
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/apicdef.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/pgtable_types.h>
|
||||
#ifdef CONFIG_X86_32
|
||||
#include <linux/threads.h>
|
||||
#else
|
||||
#include <uapi/asm/vsyscall.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We can't declare FIXADDR_TOP as variable for x86_64 because vsyscall
|
||||
* uses fixmaps that relies on FIXADDR_TOP for proper address calculation.
|
||||
* Because of this, FIXADDR_TOP x86 integration was left as later work.
|
||||
*/
|
||||
#ifdef CONFIG_X86_32
|
||||
/*
|
||||
* Leave one empty page between vmalloc'ed areas and
|
||||
* the start of the fixmap.
|
||||
*/
|
||||
extern unsigned long __FIXADDR_TOP;
|
||||
#define FIXADDR_TOP ((unsigned long)__FIXADDR_TOP)
|
||||
#else
|
||||
#define FIXADDR_TOP (round_up(VSYSCALL_ADDR + PAGE_SIZE, 1<<PMD_SHIFT) - \
|
||||
PAGE_SIZE)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Here we define all the compile-time 'special' virtual
|
||||
* addresses. The point is to have a constant address at
|
||||
* compile time, but to set the physical address only
|
||||
* in the boot process.
|
||||
* for x86_32: We allocate these special addresses
|
||||
* from the end of virtual memory (0xfffff000) backwards.
|
||||
* Also this lets us do fail-safe vmalloc(), we
|
||||
* can guarantee that these special addresses and
|
||||
* vmalloc()-ed addresses never overlap.
|
||||
*
|
||||
* These 'compile-time allocated' memory buffers are
|
||||
* fixed-size 4k pages (or larger if used with an increment
|
||||
* higher than 1). Use set_fixmap(idx,phys) to associate
|
||||
* physical memory with fixmap indices.
|
||||
*
|
||||
* TLB entries of such buffers will not be flushed across
|
||||
* task switches.
|
||||
*/
|
||||
enum fixed_addresses {
|
||||
#ifdef CONFIG_X86_32
|
||||
FIX_HOLE,
|
||||
#else
|
||||
#ifdef CONFIG_X86_VSYSCALL_EMULATION
|
||||
VSYSCALL_PAGE = (FIXADDR_TOP - VSYSCALL_ADDR) >> PAGE_SHIFT,
|
||||
#endif
|
||||
#endif
|
||||
FIX_DBGP_BASE,
|
||||
FIX_EARLYCON_MEM_BASE,
|
||||
#ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT
|
||||
FIX_OHCI1394_BASE,
|
||||
#endif
|
||||
#ifdef CONFIG_X86_LOCAL_APIC
|
||||
FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */
|
||||
#endif
|
||||
#ifdef CONFIG_X86_IO_APIC
|
||||
FIX_IO_APIC_BASE_0,
|
||||
FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS - 1,
|
||||
#endif
|
||||
#ifdef CONFIG_KMAP_LOCAL
|
||||
FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
|
||||
FIX_KMAP_END = FIX_KMAP_BEGIN + (KM_MAX_IDX * NR_CPUS) - 1,
|
||||
#ifdef CONFIG_PCI_MMCONFIG
|
||||
FIX_PCIE_MCFG,
|
||||
#endif
|
||||
#endif
|
||||
#ifdef CONFIG_PARAVIRT_XXL
|
||||
FIX_PARAVIRT_BOOTMAP,
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACPI_APEI_GHES
|
||||
/* Used for GHES mapping from assorted contexts */
|
||||
FIX_APEI_GHES_IRQ,
|
||||
FIX_APEI_GHES_NMI,
|
||||
#endif
|
||||
|
||||
__end_of_permanent_fixed_addresses,
|
||||
|
||||
/*
|
||||
* 512 temporary boot-time mappings, used by early_ioremap(),
|
||||
* before ioremap() is functional.
|
||||
*
|
||||
* If necessary we round it up to the next 512 pages boundary so
|
||||
* that we can have a single pmd entry and a single pte table:
|
||||
*/
|
||||
#define NR_FIX_BTMAPS 64
|
||||
#define FIX_BTMAPS_SLOTS 8
|
||||
#define TOTAL_FIX_BTMAPS (NR_FIX_BTMAPS * FIX_BTMAPS_SLOTS)
|
||||
FIX_BTMAP_END =
|
||||
(__end_of_permanent_fixed_addresses ^
|
||||
(__end_of_permanent_fixed_addresses + TOTAL_FIX_BTMAPS - 1)) &
|
||||
-PTRS_PER_PTE
|
||||
? __end_of_permanent_fixed_addresses + TOTAL_FIX_BTMAPS -
|
||||
(__end_of_permanent_fixed_addresses & (TOTAL_FIX_BTMAPS - 1))
|
||||
: __end_of_permanent_fixed_addresses,
|
||||
FIX_BTMAP_BEGIN = FIX_BTMAP_END + TOTAL_FIX_BTMAPS - 1,
|
||||
#ifdef CONFIG_X86_32
|
||||
FIX_WP_TEST,
|
||||
#endif
|
||||
#ifdef CONFIG_INTEL_TXT
|
||||
FIX_TBOOT_BASE,
|
||||
#endif
|
||||
__end_of_fixed_addresses
|
||||
};
|
||||
|
||||
|
||||
extern void reserve_top_address(unsigned long reserve);
|
||||
|
||||
#define FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT)
|
||||
#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE)
|
||||
#define FIXADDR_TOT_SIZE (__end_of_fixed_addresses << PAGE_SHIFT)
|
||||
#define FIXADDR_TOT_START (FIXADDR_TOP - FIXADDR_TOT_SIZE)
|
||||
|
||||
extern int fixmaps_set;
|
||||
|
||||
extern pte_t *pkmap_page_table;
|
||||
|
||||
void __native_set_fixmap(enum fixed_addresses idx, pte_t pte);
|
||||
void native_set_fixmap(unsigned /* enum fixed_addresses */ idx,
|
||||
phys_addr_t phys, pgprot_t flags);
|
||||
|
||||
#ifndef CONFIG_PARAVIRT_XXL
|
||||
static inline void __set_fixmap(enum fixed_addresses idx,
|
||||
phys_addr_t phys, pgprot_t flags)
|
||||
{
|
||||
native_set_fixmap(idx, phys, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* FIXMAP_PAGE_NOCACHE is used for MMIO. Memory encryption is not
|
||||
* supported for MMIO addresses, so make sure that the memory encryption
|
||||
* mask is not part of the page attributes.
|
||||
*/
|
||||
#define FIXMAP_PAGE_NOCACHE PAGE_KERNEL_IO_NOCACHE
|
||||
|
||||
/*
|
||||
* Early memremap routines used for in-place encryption. The mappings created
|
||||
* by these routines are intended to be used as temporary mappings.
|
||||
*/
|
||||
void __init *early_memremap_encrypted(resource_size_t phys_addr,
|
||||
unsigned long size);
|
||||
void __init *early_memremap_encrypted_wp(resource_size_t phys_addr,
|
||||
unsigned long size);
|
||||
void __init *early_memremap_decrypted(resource_size_t phys_addr,
|
||||
unsigned long size);
|
||||
void __init *early_memremap_decrypted_wp(resource_size_t phys_addr,
|
||||
unsigned long size);
|
||||
|
||||
#include <asm-generic/fixmap.h>
|
||||
|
||||
#define __late_set_fixmap(idx, phys, flags) __set_fixmap(idx, phys, flags)
|
||||
#define __late_clear_fixmap(idx) __set_fixmap(idx, 0, __pgprot(0))
|
||||
|
||||
void __early_set_fixmap(enum fixed_addresses idx,
|
||||
phys_addr_t phys, pgprot_t flags);
|
||||
|
||||
#endif /* !__ASSEMBLER__ */
|
||||
#endif /* _ASM_X86_FIXMAP_H */
|
||||
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Architecture specific parts of the Floppy driver
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Copyright (C) 1995
|
||||
*/
|
||||
#ifndef _ASM_X86_FLOPPY_H
|
||||
#define _ASM_X86_FLOPPY_H
|
||||
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
/*
|
||||
* The DMA channel used by the floppy controller cannot access data at
|
||||
* addresses >= 16MB
|
||||
*
|
||||
* Went back to the 1MB limit, as some people had problems with the floppy
|
||||
* driver otherwise. It doesn't matter much for performance anyway, as most
|
||||
* floppy accesses go through the track buffer.
|
||||
*/
|
||||
#define _CROSS_64KB(a, s, vdma) \
|
||||
(!(vdma) && \
|
||||
((unsigned long)(a) / SZ_64K != ((unsigned long)(a) + (s) - 1) / SZ_64K))
|
||||
|
||||
#define SW fd_routine[use_virtual_dma & 1]
|
||||
#define CSW fd_routine[can_use_virtual_dma & 1]
|
||||
|
||||
|
||||
#define fd_inb(base, reg) inb_p((base) + (reg))
|
||||
#define fd_outb(value, base, reg) outb_p(value, (base) + (reg))
|
||||
|
||||
#define fd_request_dma() CSW._request_dma(FLOPPY_DMA, "floppy")
|
||||
#define fd_free_dma() CSW._free_dma(FLOPPY_DMA)
|
||||
#define fd_enable_irq() enable_irq(FLOPPY_IRQ)
|
||||
#define fd_disable_irq() disable_irq(FLOPPY_IRQ)
|
||||
#define fd_free_irq() free_irq(FLOPPY_IRQ, NULL)
|
||||
#define fd_get_dma_residue() SW._get_dma_residue(FLOPPY_DMA)
|
||||
#define fd_dma_mem_alloc(size) SW._dma_mem_alloc(size)
|
||||
#define fd_dma_setup(addr, size, mode, io) SW._dma_setup(addr, size, mode, io)
|
||||
|
||||
#define FLOPPY_CAN_FALLBACK_ON_NODMA
|
||||
|
||||
static int virtual_dma_count;
|
||||
static int virtual_dma_residue;
|
||||
static char *virtual_dma_addr;
|
||||
static int virtual_dma_mode;
|
||||
static int doing_pdma;
|
||||
|
||||
static irqreturn_t floppy_hardint(int irq, void *dev_id)
|
||||
{
|
||||
unsigned char st;
|
||||
|
||||
#undef TRACE_FLPY_INT
|
||||
|
||||
#ifdef TRACE_FLPY_INT
|
||||
static int calls;
|
||||
static int bytes;
|
||||
static int dma_wait;
|
||||
#endif
|
||||
if (!doing_pdma)
|
||||
return floppy_interrupt(irq, dev_id);
|
||||
|
||||
#ifdef TRACE_FLPY_INT
|
||||
if (!calls)
|
||||
bytes = virtual_dma_count;
|
||||
#endif
|
||||
|
||||
{
|
||||
int lcount;
|
||||
char *lptr;
|
||||
|
||||
for (lcount = virtual_dma_count, lptr = virtual_dma_addr;
|
||||
lcount; lcount--, lptr++) {
|
||||
st = inb(virtual_dma_port + FD_STATUS);
|
||||
st &= STATUS_DMA | STATUS_READY;
|
||||
if (st != (STATUS_DMA | STATUS_READY))
|
||||
break;
|
||||
if (virtual_dma_mode)
|
||||
outb_p(*lptr, virtual_dma_port + FD_DATA);
|
||||
else
|
||||
*lptr = inb_p(virtual_dma_port + FD_DATA);
|
||||
}
|
||||
virtual_dma_count = lcount;
|
||||
virtual_dma_addr = lptr;
|
||||
st = inb(virtual_dma_port + FD_STATUS);
|
||||
}
|
||||
|
||||
#ifdef TRACE_FLPY_INT
|
||||
calls++;
|
||||
#endif
|
||||
if (st == STATUS_DMA)
|
||||
return IRQ_HANDLED;
|
||||
if (!(st & STATUS_DMA)) {
|
||||
virtual_dma_residue += virtual_dma_count;
|
||||
virtual_dma_count = 0;
|
||||
#ifdef TRACE_FLPY_INT
|
||||
printk(KERN_DEBUG "count=%x, residue=%x calls=%d bytes=%d dma_wait=%d\n",
|
||||
virtual_dma_count, virtual_dma_residue, calls, bytes,
|
||||
dma_wait);
|
||||
calls = 0;
|
||||
dma_wait = 0;
|
||||
#endif
|
||||
doing_pdma = 0;
|
||||
floppy_interrupt(irq, dev_id);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
#ifdef TRACE_FLPY_INT
|
||||
if (!virtual_dma_count)
|
||||
dma_wait++;
|
||||
#endif
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void fd_disable_dma(void)
|
||||
{
|
||||
if (!(can_use_virtual_dma & 1))
|
||||
disable_dma(FLOPPY_DMA);
|
||||
doing_pdma = 0;
|
||||
virtual_dma_residue += virtual_dma_count;
|
||||
virtual_dma_count = 0;
|
||||
}
|
||||
|
||||
static int vdma_request_dma(unsigned int dmanr, const char *device_id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vdma_nop(unsigned int dummy)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static int vdma_get_dma_residue(unsigned int dummy)
|
||||
{
|
||||
return virtual_dma_count + virtual_dma_residue;
|
||||
}
|
||||
|
||||
|
||||
static int fd_request_irq(void)
|
||||
{
|
||||
if (can_use_virtual_dma)
|
||||
return request_irq(FLOPPY_IRQ, floppy_hardint,
|
||||
0, "floppy", NULL);
|
||||
else
|
||||
return request_irq(FLOPPY_IRQ, floppy_interrupt,
|
||||
0, "floppy", NULL);
|
||||
}
|
||||
|
||||
static unsigned long dma_mem_alloc(unsigned long size)
|
||||
{
|
||||
return __get_dma_pages(GFP_KERNEL|__GFP_NORETRY, get_order(size));
|
||||
}
|
||||
|
||||
|
||||
static unsigned long vdma_mem_alloc(unsigned long size)
|
||||
{
|
||||
return (unsigned long)vmalloc(size);
|
||||
|
||||
}
|
||||
|
||||
#define nodma_mem_alloc(size) vdma_mem_alloc(size)
|
||||
|
||||
static void _fd_dma_mem_free(unsigned long addr, unsigned long size)
|
||||
{
|
||||
if ((unsigned long)addr >= (unsigned long)high_memory)
|
||||
vfree((void *)addr);
|
||||
else
|
||||
free_pages(addr, get_order(size));
|
||||
}
|
||||
|
||||
#define fd_dma_mem_free(addr, size) _fd_dma_mem_free(addr, size)
|
||||
|
||||
static void _fd_chose_dma_mode(char *addr, unsigned long size)
|
||||
{
|
||||
if (can_use_virtual_dma == 2) {
|
||||
if ((unsigned long)addr >= (unsigned long)high_memory ||
|
||||
isa_virt_to_bus(addr) >= 0x1000000 ||
|
||||
_CROSS_64KB(addr, size, 0))
|
||||
use_virtual_dma = 1;
|
||||
else
|
||||
use_virtual_dma = 0;
|
||||
} else {
|
||||
use_virtual_dma = can_use_virtual_dma & 1;
|
||||
}
|
||||
}
|
||||
|
||||
#define fd_chose_dma_mode(addr, size) _fd_chose_dma_mode(addr, size)
|
||||
|
||||
|
||||
static int vdma_dma_setup(char *addr, unsigned long size, int mode, int io)
|
||||
{
|
||||
doing_pdma = 1;
|
||||
virtual_dma_port = io;
|
||||
virtual_dma_mode = (mode == DMA_MODE_WRITE);
|
||||
virtual_dma_addr = addr;
|
||||
virtual_dma_count = size;
|
||||
virtual_dma_residue = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hard_dma_setup(char *addr, unsigned long size, int mode, int io)
|
||||
{
|
||||
#ifdef FLOPPY_SANITY_CHECK
|
||||
if (_CROSS_64KB(addr, size, use_virtual_dma & 1)) {
|
||||
printk("DMA crossing 64-K boundary %p-%p\n", addr, addr+size);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
/* actual, physical DMA */
|
||||
doing_pdma = 0;
|
||||
clear_dma_ff(FLOPPY_DMA);
|
||||
set_dma_mode(FLOPPY_DMA, mode);
|
||||
set_dma_addr(FLOPPY_DMA, isa_virt_to_bus(addr));
|
||||
set_dma_count(FLOPPY_DMA, size);
|
||||
enable_dma(FLOPPY_DMA);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct fd_routine_l {
|
||||
int (*_request_dma)(unsigned int dmanr, const char *device_id);
|
||||
void (*_free_dma)(unsigned int dmanr);
|
||||
int (*_get_dma_residue)(unsigned int dummy);
|
||||
unsigned long (*_dma_mem_alloc)(unsigned long size);
|
||||
int (*_dma_setup)(char *addr, unsigned long size, int mode, int io);
|
||||
} fd_routine[] = {
|
||||
{
|
||||
._request_dma = request_dma,
|
||||
._free_dma = free_dma,
|
||||
._get_dma_residue = get_dma_residue,
|
||||
._dma_mem_alloc = dma_mem_alloc,
|
||||
._dma_setup = hard_dma_setup
|
||||
},
|
||||
{
|
||||
._request_dma = vdma_request_dma,
|
||||
._free_dma = vdma_nop,
|
||||
._get_dma_residue = vdma_get_dma_residue,
|
||||
._dma_mem_alloc = vdma_mem_alloc,
|
||||
._dma_setup = vdma_dma_setup
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static int FDC1 = 0x3f0;
|
||||
static int FDC2 = -1;
|
||||
|
||||
/*
|
||||
* Floppy types are stored in the rtc's CMOS RAM and so rtc_lock
|
||||
* is needed to prevent corrupted CMOS RAM in case "insmod floppy"
|
||||
* coincides with another rtc CMOS user. Paul G.
|
||||
*/
|
||||
#define FLOPPY0_TYPE \
|
||||
({ \
|
||||
unsigned long flags; \
|
||||
unsigned char val; \
|
||||
spin_lock_irqsave(&rtc_lock, flags); \
|
||||
val = (CMOS_READ(0x10) >> 4) & 15; \
|
||||
spin_unlock_irqrestore(&rtc_lock, flags); \
|
||||
val; \
|
||||
})
|
||||
|
||||
#define FLOPPY1_TYPE \
|
||||
({ \
|
||||
unsigned long flags; \
|
||||
unsigned char val; \
|
||||
spin_lock_irqsave(&rtc_lock, flags); \
|
||||
val = CMOS_READ(0x10) & 15; \
|
||||
spin_unlock_irqrestore(&rtc_lock, flags); \
|
||||
val; \
|
||||
})
|
||||
|
||||
#define N_FDC 2
|
||||
#define N_DRIVE 8
|
||||
|
||||
#define EXTRA_FLOPPY_PARAMS
|
||||
|
||||
#endif /* _ASM_X86_FLOPPY_H */
|
||||
@@ -0,0 +1,13 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2023 SiFive
|
||||
*/
|
||||
|
||||
#ifndef _ASM_X86_FPU_H
|
||||
#define _ASM_X86_FPU_H
|
||||
|
||||
#include <asm/fpu/api.h>
|
||||
|
||||
#define kernel_fpu_available() true
|
||||
|
||||
#endif /* ! _ASM_X86_FPU_H */
|
||||
@@ -0,0 +1,180 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 1994 Linus Torvalds
|
||||
*
|
||||
* Pentium III FXSR, SSE support
|
||||
* General FPU state handling cleanups
|
||||
* Gareth Hughes <gareth@valinux.com>, May 2000
|
||||
* x86-64 work by Andi Kleen 2002
|
||||
*/
|
||||
|
||||
#ifndef _ASM_X86_FPU_API_H
|
||||
#define _ASM_X86_FPU_API_H
|
||||
#include <linux/bottom_half.h>
|
||||
|
||||
#include <asm/fpu/types.h>
|
||||
|
||||
/*
|
||||
* Use kernel_fpu_begin/end() if you intend to use FPU in kernel context. It
|
||||
* disables preemption and softirq processing, so be careful if you intend to
|
||||
* use it for long periods of time. Kernel-mode FPU cannot be used in all
|
||||
* contexts -- see irq_fpu_usable() for details.
|
||||
*/
|
||||
|
||||
/* Kernel FPU states to initialize in kernel_fpu_begin_mask() */
|
||||
#define KFPU_387 _BITUL(0) /* 387 state will be initialized */
|
||||
#define KFPU_MXCSR _BITUL(1) /* MXCSR will be initialized */
|
||||
|
||||
extern void kernel_fpu_begin_mask(unsigned int kfpu_mask);
|
||||
extern void kernel_fpu_end(void);
|
||||
extern bool irq_fpu_usable(void);
|
||||
extern void fpregs_mark_activate(void);
|
||||
|
||||
/* Code that is unaware of kernel_fpu_begin_mask() can use this */
|
||||
static inline void kernel_fpu_begin(void)
|
||||
{
|
||||
#ifdef CONFIG_X86_64
|
||||
/*
|
||||
* Any 64-bit code that uses 387 instructions must explicitly request
|
||||
* KFPU_387.
|
||||
*/
|
||||
kernel_fpu_begin_mask(KFPU_MXCSR);
|
||||
#else
|
||||
/*
|
||||
* 32-bit kernel code may use 387 operations as well as SSE2, etc,
|
||||
* as long as it checks that the CPU has the required capability.
|
||||
*/
|
||||
kernel_fpu_begin_mask(KFPU_387 | KFPU_MXCSR);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Use fpregs_lock() while editing CPU's FPU registers or fpu->fpstate, or while
|
||||
* using the FPU in kernel mode. A context switch will (and softirq might) save
|
||||
* CPU's FPU registers to fpu->fpstate.regs and set TIF_NEED_FPU_LOAD leaving
|
||||
* CPU's FPU registers in a random state.
|
||||
*
|
||||
* local_bh_disable() protects against both preemption and soft interrupts
|
||||
* on !RT kernels.
|
||||
*
|
||||
* On RT kernels local_bh_disable() is not sufficient because it only
|
||||
* serializes soft interrupt related sections via a local lock, but stays
|
||||
* preemptible. Disabling preemption is the right choice here as bottom
|
||||
* half processing is always in thread context on RT kernels so it
|
||||
* implicitly prevents bottom half processing as well.
|
||||
*/
|
||||
static inline void fpregs_lock(void)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_PREEMPT_RT))
|
||||
local_bh_disable();
|
||||
else
|
||||
preempt_disable();
|
||||
}
|
||||
|
||||
static inline void fpregs_unlock(void)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_PREEMPT_RT))
|
||||
local_bh_enable();
|
||||
else
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
/*
|
||||
* FPU state gets lazily restored before returning to userspace. So when in the
|
||||
* kernel, the valid FPU state may be kept in the buffer. This function will force
|
||||
* restore all the fpu state to the registers early if needed, and lock them from
|
||||
* being automatically saved/restored. Then FPU state can be modified safely in the
|
||||
* registers, before unlocking with fpregs_unlock().
|
||||
*/
|
||||
void fpregs_lock_and_load(void);
|
||||
|
||||
#ifdef CONFIG_X86_DEBUG_FPU
|
||||
extern void fpregs_assert_state_consistent(void);
|
||||
#else
|
||||
static inline void fpregs_assert_state_consistent(void) { }
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Load the task FPU state before returning to userspace.
|
||||
*/
|
||||
extern void switch_fpu_return(void);
|
||||
|
||||
/*
|
||||
* Query the presence of one or more xfeatures. Works on any legacy CPU as well.
|
||||
*
|
||||
* If 'feature_name' is set then put a human-readable description of
|
||||
* the feature there as well - this can be used to print error (or success)
|
||||
* messages.
|
||||
*/
|
||||
extern int cpu_has_xfeatures(u64 xfeatures_mask, const char **feature_name);
|
||||
|
||||
/* Trap handling */
|
||||
extern int fpu__exception_code(struct fpu *fpu, int trap_nr);
|
||||
extern void fpu_sync_fpstate(struct fpu *fpu);
|
||||
extern void fpu_reset_from_exception_fixup(void);
|
||||
|
||||
/* Boot, hotplug and resume */
|
||||
extern void fpu__init_cpu(void);
|
||||
extern void fpu__init_system(void);
|
||||
extern void fpu__init_check_bugs(void);
|
||||
extern void fpu__resume_cpu(void);
|
||||
|
||||
#ifdef CONFIG_MATH_EMULATION
|
||||
extern void fpstate_init_soft(struct swregs_state *soft);
|
||||
#else
|
||||
static inline void fpstate_init_soft(struct swregs_state *soft) {}
|
||||
#endif
|
||||
|
||||
/* State tracking */
|
||||
DECLARE_PER_CPU(bool, kernel_fpu_allowed);
|
||||
DECLARE_PER_CPU(struct fpu *, fpu_fpregs_owner_ctx);
|
||||
|
||||
/* Process cleanup */
|
||||
#ifdef CONFIG_X86_64
|
||||
extern void fpstate_free(struct fpu *fpu);
|
||||
#else
|
||||
static inline void fpstate_free(struct fpu *fpu) { }
|
||||
#endif
|
||||
|
||||
/* fpstate-related functions which are exported to KVM */
|
||||
extern void fpstate_clear_xstate_component(struct fpstate *fpstate, unsigned int xfeature);
|
||||
|
||||
extern u64 xstate_get_guest_group_perm(void);
|
||||
|
||||
extern void *get_xsave_addr(struct xregs_state *xsave, int xfeature_nr);
|
||||
|
||||
|
||||
/* KVM specific functions */
|
||||
extern bool fpu_alloc_guest_fpstate(struct fpu_guest *gfpu);
|
||||
extern void fpu_free_guest_fpstate(struct fpu_guest *gfpu);
|
||||
extern int fpu_swap_kvm_fpstate(struct fpu_guest *gfpu, bool enter_guest);
|
||||
extern int fpu_enable_guest_xfd_features(struct fpu_guest *guest_fpu, u64 xfeatures);
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
extern void fpu_update_guest_xfd(struct fpu_guest *guest_fpu, u64 xfd);
|
||||
extern void fpu_sync_guest_vmexit_xfd_state(void);
|
||||
#else
|
||||
static inline void fpu_update_guest_xfd(struct fpu_guest *guest_fpu, u64 xfd) { }
|
||||
static inline void fpu_sync_guest_vmexit_xfd_state(void) { }
|
||||
#endif
|
||||
|
||||
extern void fpu_copy_guest_fpstate_to_uabi(struct fpu_guest *gfpu, void *buf,
|
||||
unsigned int size, u64 xfeatures, u32 pkru);
|
||||
extern int fpu_copy_uabi_to_guest_fpstate(struct fpu_guest *gfpu, const void *buf, u64 xcr0, u32 *vpkru);
|
||||
|
||||
static inline void fpstate_set_confidential(struct fpu_guest *gfpu)
|
||||
{
|
||||
gfpu->fpstate->is_confidential = true;
|
||||
}
|
||||
|
||||
static inline bool fpstate_is_confidential(struct fpu_guest *gfpu)
|
||||
{
|
||||
return gfpu->fpstate->is_confidential;
|
||||
}
|
||||
|
||||
/* prctl */
|
||||
extern long fpu_xstate_prctl(int option, unsigned long arg2);
|
||||
|
||||
extern void fpu_idle_fpregs(void);
|
||||
|
||||
#endif /* _ASM_X86_FPU_API_H */
|
||||
@@ -0,0 +1,23 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* FPU regset handling methods:
|
||||
*/
|
||||
#ifndef _ASM_X86_FPU_REGSET_H
|
||||
#define _ASM_X86_FPU_REGSET_H
|
||||
|
||||
#include <linux/regset.h>
|
||||
|
||||
extern user_regset_active_fn regset_fpregs_active, regset_xregset_fpregs_active,
|
||||
ssp_active;
|
||||
extern user_regset_get2_fn fpregs_get, xfpregs_get, fpregs_soft_get,
|
||||
xstateregs_get, ssp_get;
|
||||
extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set,
|
||||
xstateregs_set, ssp_set;
|
||||
|
||||
/*
|
||||
* xstateregs_active == regset_fpregs_active. Please refer to the comment
|
||||
* at the definition of regset_fpregs_active.
|
||||
*/
|
||||
#define xstateregs_active regset_fpregs_active
|
||||
|
||||
#endif /* _ASM_X86_FPU_REGSET_H */
|
||||
@@ -0,0 +1,55 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_FPU_SCHED_H
|
||||
#define _ASM_X86_FPU_SCHED_H
|
||||
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/fpu/types.h>
|
||||
|
||||
#include <asm/trace/fpu.h>
|
||||
|
||||
extern void save_fpregs_to_fpstate(struct fpu *fpu);
|
||||
extern void fpu__drop(struct task_struct *tsk);
|
||||
extern int fpu_clone(struct task_struct *dst, u64 clone_flags, bool minimal,
|
||||
unsigned long shstk_addr);
|
||||
extern void fpu_flush_thread(void);
|
||||
|
||||
/*
|
||||
* FPU state switching for scheduling.
|
||||
*
|
||||
* switch_fpu() saves the old state and sets TIF_NEED_FPU_LOAD if
|
||||
* TIF_NEED_FPU_LOAD is not set. This is done within the context
|
||||
* of the old process.
|
||||
*
|
||||
* Once TIF_NEED_FPU_LOAD is set, it is required to load the
|
||||
* registers before returning to userland or using the content
|
||||
* otherwise.
|
||||
*
|
||||
* The FPU context is only stored/restored for a user task and
|
||||
* PF_KTHREAD is used to distinguish between kernel and user threads.
|
||||
*/
|
||||
static inline void switch_fpu(struct task_struct *old, int cpu)
|
||||
{
|
||||
if (!test_tsk_thread_flag(old, TIF_NEED_FPU_LOAD) &&
|
||||
cpu_feature_enabled(X86_FEATURE_FPU) &&
|
||||
!(old->flags & (PF_KTHREAD | PF_USER_WORKER))) {
|
||||
struct fpu *old_fpu = x86_task_fpu(old);
|
||||
|
||||
set_tsk_thread_flag(old, TIF_NEED_FPU_LOAD);
|
||||
save_fpregs_to_fpstate(old_fpu);
|
||||
/*
|
||||
* The save operation preserved register state, so the
|
||||
* fpu_fpregs_owner_ctx is still @old_fpu. Store the
|
||||
* current CPU number in @old_fpu, so the next return
|
||||
* to user space can avoid the FPU register restore
|
||||
* when is returns on the same CPU and still owns the
|
||||
* context. See fpregs_restore_userregs().
|
||||
*/
|
||||
old_fpu->last_cpu = cpu;
|
||||
|
||||
trace_x86_fpu_regs_deactivated(old_fpu);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _ASM_X86_FPU_SCHED_H */
|
||||
@@ -0,0 +1,37 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* x86 FPU signal frame handling methods:
|
||||
*/
|
||||
#ifndef _ASM_X86_FPU_SIGNAL_H
|
||||
#define _ASM_X86_FPU_SIGNAL_H
|
||||
|
||||
#include <linux/compat.h>
|
||||
#include <linux/user.h>
|
||||
|
||||
#include <asm/fpu/types.h>
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
# include <uapi/asm/sigcontext.h>
|
||||
# include <asm/user32.h>
|
||||
#else
|
||||
# define user_i387_ia32_struct user_i387_struct
|
||||
# define user32_fxsr_struct user_fxsr_struct
|
||||
#endif
|
||||
|
||||
extern void convert_from_fxsr(struct user_i387_ia32_struct *env,
|
||||
struct task_struct *tsk);
|
||||
extern void convert_to_fxsr(struct fxregs_state *fxsave,
|
||||
const struct user_i387_ia32_struct *env);
|
||||
|
||||
unsigned long
|
||||
fpu__alloc_mathframe(unsigned long sp, int ia32_frame,
|
||||
unsigned long *buf_fx, unsigned long *size);
|
||||
|
||||
unsigned long fpu__get_fpstate_size(void);
|
||||
|
||||
extern bool copy_fpstate_to_sigframe(void __user *buf, void __user *fp, int size, u32 pkru);
|
||||
extern void fpu__clear_user_states(struct fpu *fpu);
|
||||
extern bool fpu__restore_sig(void __user *buf, int ia32_frame);
|
||||
|
||||
extern void restore_fpregs_from_fpstate(struct fpstate *fpstate, u64 mask);
|
||||
#endif /* _ASM_X86_FPU_SIGNAL_H */
|
||||
@@ -0,0 +1,647 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* FPU data structures:
|
||||
*/
|
||||
#ifndef _ASM_X86_FPU_TYPES_H
|
||||
#define _ASM_X86_FPU_TYPES_H
|
||||
|
||||
#include <asm/page_types.h>
|
||||
|
||||
/*
|
||||
* The legacy x87 FPU state format, as saved by FSAVE and
|
||||
* restored by the FRSTOR instructions:
|
||||
*/
|
||||
struct fregs_state {
|
||||
u32 cwd; /* FPU Control Word */
|
||||
u32 swd; /* FPU Status Word */
|
||||
u32 twd; /* FPU Tag Word */
|
||||
u32 fip; /* FPU IP Offset */
|
||||
u32 fcs; /* FPU IP Selector */
|
||||
u32 foo; /* FPU Operand Pointer Offset */
|
||||
u32 fos; /* FPU Operand Pointer Selector */
|
||||
|
||||
/* 8*10 bytes for each FP-reg = 80 bytes: */
|
||||
u32 st_space[20];
|
||||
|
||||
/* Software status information [not touched by FSAVE]: */
|
||||
u32 status;
|
||||
};
|
||||
|
||||
/*
|
||||
* The legacy fx SSE/MMX FPU state format, as saved by FXSAVE and
|
||||
* restored by the FXRSTOR instructions. It's similar to the FSAVE
|
||||
* format, but differs in some areas, plus has extensions at
|
||||
* the end for the XMM registers.
|
||||
*/
|
||||
struct fxregs_state {
|
||||
u16 cwd; /* Control Word */
|
||||
u16 swd; /* Status Word */
|
||||
u16 twd; /* Tag Word */
|
||||
u16 fop; /* Last Instruction Opcode */
|
||||
union {
|
||||
struct {
|
||||
u64 rip; /* Instruction Pointer */
|
||||
u64 rdp; /* Data Pointer */
|
||||
};
|
||||
struct {
|
||||
u32 fip; /* FPU IP Offset */
|
||||
u32 fcs; /* FPU IP Selector */
|
||||
u32 foo; /* FPU Operand Offset */
|
||||
u32 fos; /* FPU Operand Selector */
|
||||
};
|
||||
};
|
||||
u32 mxcsr; /* MXCSR Register State */
|
||||
u32 mxcsr_mask; /* MXCSR Mask */
|
||||
|
||||
/* 8*16 bytes for each FP-reg = 128 bytes: */
|
||||
u32 st_space[32];
|
||||
|
||||
/* 16*16 bytes for each XMM-reg = 256 bytes: */
|
||||
u32 xmm_space[64];
|
||||
|
||||
u32 padding[12];
|
||||
|
||||
union {
|
||||
u32 padding1[12];
|
||||
u32 sw_reserved[12];
|
||||
};
|
||||
|
||||
} __attribute__((aligned(16)));
|
||||
|
||||
/* Default value for fxregs_state.mxcsr: */
|
||||
#define MXCSR_DEFAULT 0x1f80
|
||||
|
||||
/* Copy both mxcsr & mxcsr_flags with a single u64 memcpy: */
|
||||
#define MXCSR_AND_FLAGS_SIZE sizeof(u64)
|
||||
|
||||
/*
|
||||
* Software based FPU emulation state. This is arbitrary really,
|
||||
* it matches the x87 format to make it easier to understand:
|
||||
*/
|
||||
struct swregs_state {
|
||||
u32 cwd;
|
||||
u32 swd;
|
||||
u32 twd;
|
||||
u32 fip;
|
||||
u32 fcs;
|
||||
u32 foo;
|
||||
u32 fos;
|
||||
/* 8*10 bytes for each FP-reg = 80 bytes: */
|
||||
u32 st_space[20];
|
||||
u8 ftop;
|
||||
u8 changed;
|
||||
u8 lookahead;
|
||||
u8 no_update;
|
||||
u8 rm;
|
||||
u8 alimit;
|
||||
struct math_emu_info *info;
|
||||
u32 entry_eip;
|
||||
};
|
||||
|
||||
/*
|
||||
* List of XSAVE features Linux knows about:
|
||||
*/
|
||||
enum xfeature {
|
||||
XFEATURE_FP,
|
||||
XFEATURE_SSE,
|
||||
/*
|
||||
* Values above here are "legacy states".
|
||||
* Those below are "extended states".
|
||||
*/
|
||||
XFEATURE_YMM,
|
||||
XFEATURE_BNDREGS,
|
||||
XFEATURE_BNDCSR,
|
||||
XFEATURE_OPMASK,
|
||||
XFEATURE_ZMM_Hi256,
|
||||
XFEATURE_Hi16_ZMM,
|
||||
XFEATURE_PT_UNIMPLEMENTED_SO_FAR,
|
||||
XFEATURE_PKRU,
|
||||
XFEATURE_PASID,
|
||||
XFEATURE_CET_USER,
|
||||
XFEATURE_CET_KERNEL,
|
||||
XFEATURE_RSRVD_COMP_13,
|
||||
XFEATURE_RSRVD_COMP_14,
|
||||
XFEATURE_LBR,
|
||||
XFEATURE_RSRVD_COMP_16,
|
||||
XFEATURE_XTILE_CFG,
|
||||
XFEATURE_XTILE_DATA,
|
||||
XFEATURE_APX,
|
||||
|
||||
XFEATURE_MAX,
|
||||
};
|
||||
|
||||
#define XFEATURE_MASK_FP (1 << XFEATURE_FP)
|
||||
#define XFEATURE_MASK_SSE (1 << XFEATURE_SSE)
|
||||
#define XFEATURE_MASK_YMM (1 << XFEATURE_YMM)
|
||||
#define XFEATURE_MASK_BNDREGS (1 << XFEATURE_BNDREGS)
|
||||
#define XFEATURE_MASK_BNDCSR (1 << XFEATURE_BNDCSR)
|
||||
#define XFEATURE_MASK_OPMASK (1 << XFEATURE_OPMASK)
|
||||
#define XFEATURE_MASK_ZMM_Hi256 (1 << XFEATURE_ZMM_Hi256)
|
||||
#define XFEATURE_MASK_Hi16_ZMM (1 << XFEATURE_Hi16_ZMM)
|
||||
#define XFEATURE_MASK_PT (1 << XFEATURE_PT_UNIMPLEMENTED_SO_FAR)
|
||||
#define XFEATURE_MASK_PKRU (1 << XFEATURE_PKRU)
|
||||
#define XFEATURE_MASK_PASID (1 << XFEATURE_PASID)
|
||||
#define XFEATURE_MASK_CET_USER (1 << XFEATURE_CET_USER)
|
||||
#define XFEATURE_MASK_CET_KERNEL (1 << XFEATURE_CET_KERNEL)
|
||||
#define XFEATURE_MASK_LBR (1 << XFEATURE_LBR)
|
||||
#define XFEATURE_MASK_XTILE_CFG (1 << XFEATURE_XTILE_CFG)
|
||||
#define XFEATURE_MASK_XTILE_DATA (1 << XFEATURE_XTILE_DATA)
|
||||
#define XFEATURE_MASK_APX (1 << XFEATURE_APX)
|
||||
|
||||
#define XFEATURE_MASK_FPSSE (XFEATURE_MASK_FP | XFEATURE_MASK_SSE)
|
||||
#define XFEATURE_MASK_AVX512 (XFEATURE_MASK_OPMASK \
|
||||
| XFEATURE_MASK_ZMM_Hi256 \
|
||||
| XFEATURE_MASK_Hi16_ZMM)
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
# define XFEATURE_MASK_XTILE (XFEATURE_MASK_XTILE_DATA \
|
||||
| XFEATURE_MASK_XTILE_CFG)
|
||||
#else
|
||||
# define XFEATURE_MASK_XTILE (0)
|
||||
#endif
|
||||
|
||||
#define FIRST_EXTENDED_XFEATURE XFEATURE_YMM
|
||||
|
||||
struct reg_128_bit {
|
||||
u8 regbytes[128/8];
|
||||
};
|
||||
struct reg_256_bit {
|
||||
u8 regbytes[256/8];
|
||||
};
|
||||
struct reg_512_bit {
|
||||
u8 regbytes[512/8];
|
||||
};
|
||||
struct reg_1024_byte {
|
||||
u8 regbytes[1024];
|
||||
};
|
||||
|
||||
/*
|
||||
* State component 2:
|
||||
*
|
||||
* There are 16x 256-bit AVX registers named YMM0-YMM15.
|
||||
* The low 128 bits are aliased to the 16 SSE registers (XMM0-XMM15)
|
||||
* and are stored in 'struct fxregs_state::xmm_space[]' in the
|
||||
* "legacy" area.
|
||||
*
|
||||
* The high 128 bits are stored here.
|
||||
*/
|
||||
struct ymmh_struct {
|
||||
struct reg_128_bit hi_ymm[16];
|
||||
} __packed;
|
||||
|
||||
/* Intel MPX support: */
|
||||
|
||||
struct mpx_bndreg {
|
||||
u64 lower_bound;
|
||||
u64 upper_bound;
|
||||
} __packed;
|
||||
/*
|
||||
* State component 3 is used for the 4 128-bit bounds registers
|
||||
*/
|
||||
struct mpx_bndreg_state {
|
||||
struct mpx_bndreg bndreg[4];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* State component 4 is used for the 64-bit user-mode MPX
|
||||
* configuration register BNDCFGU and the 64-bit MPX status
|
||||
* register BNDSTATUS. We call the pair "BNDCSR".
|
||||
*/
|
||||
struct mpx_bndcsr {
|
||||
u64 bndcfgu;
|
||||
u64 bndstatus;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* The BNDCSR state is padded out to be 64-bytes in size.
|
||||
*/
|
||||
struct mpx_bndcsr_state {
|
||||
union {
|
||||
struct mpx_bndcsr bndcsr;
|
||||
u8 pad_to_64_bytes[64];
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* AVX-512 Components: */
|
||||
|
||||
/*
|
||||
* State component 5 is used for the 8 64-bit opmask registers
|
||||
* k0-k7 (opmask state).
|
||||
*/
|
||||
struct avx_512_opmask_state {
|
||||
u64 opmask_reg[8];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* State component 6 is used for the upper 256 bits of the
|
||||
* registers ZMM0-ZMM15. These 16 256-bit values are denoted
|
||||
* ZMM0_H-ZMM15_H (ZMM_Hi256 state).
|
||||
*/
|
||||
struct avx_512_zmm_uppers_state {
|
||||
struct reg_256_bit zmm_upper[16];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* State component 7 is used for the 16 512-bit registers
|
||||
* ZMM16-ZMM31 (Hi16_ZMM state).
|
||||
*/
|
||||
struct avx_512_hi16_state {
|
||||
struct reg_512_bit hi16_zmm[16];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* State component 9: 32-bit PKRU register. The state is
|
||||
* 8 bytes long but only 4 bytes is used currently.
|
||||
*/
|
||||
struct pkru_state {
|
||||
u32 pkru;
|
||||
u32 pad;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* State component 11 is Control-flow Enforcement user states
|
||||
*/
|
||||
struct cet_user_state {
|
||||
/* user control-flow settings */
|
||||
u64 user_cet;
|
||||
/* user shadow stack pointer */
|
||||
u64 user_ssp;
|
||||
};
|
||||
|
||||
/*
|
||||
* State component 12 is Control-flow Enforcement supervisor states.
|
||||
* This state includes SSP pointers for privilege levels 0 through 2.
|
||||
*/
|
||||
struct cet_supervisor_state {
|
||||
u64 pl0_ssp;
|
||||
u64 pl1_ssp;
|
||||
u64 pl2_ssp;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* State component 15: Architectural LBR configuration state.
|
||||
* The size of Arch LBR state depends on the number of LBRs (lbr_depth).
|
||||
*/
|
||||
|
||||
struct lbr_entry {
|
||||
u64 from;
|
||||
u64 to;
|
||||
u64 info;
|
||||
};
|
||||
|
||||
struct arch_lbr_state {
|
||||
u64 lbr_ctl;
|
||||
u64 lbr_depth;
|
||||
u64 ler_from;
|
||||
u64 ler_to;
|
||||
u64 ler_info;
|
||||
struct lbr_entry entries[];
|
||||
};
|
||||
|
||||
/*
|
||||
* State component 17: 64-byte tile configuration register.
|
||||
*/
|
||||
struct xtile_cfg {
|
||||
u64 tcfg[8];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* State component 18: 1KB tile data register.
|
||||
* Each register represents 16 64-byte rows of the matrix
|
||||
* data. But the number of registers depends on the actual
|
||||
* implementation.
|
||||
*/
|
||||
struct xtile_data {
|
||||
struct reg_1024_byte tmm;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* State component 19: 8B extended general purpose register.
|
||||
*/
|
||||
struct apx_state {
|
||||
u64 egpr[16];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* State component 10 is supervisor state used for context-switching the
|
||||
* PASID state.
|
||||
*/
|
||||
struct ia32_pasid_state {
|
||||
u64 pasid;
|
||||
} __packed;
|
||||
|
||||
struct xstate_header {
|
||||
u64 xfeatures;
|
||||
u64 xcomp_bv;
|
||||
u64 reserved[6];
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* xstate_header.xcomp_bv[63] indicates that the extended_state_area
|
||||
* is in compacted format.
|
||||
*/
|
||||
#define XCOMP_BV_COMPACTED_FORMAT ((u64)1 << 63)
|
||||
|
||||
/*
|
||||
* This is our most modern FPU state format, as saved by the XSAVE
|
||||
* and restored by the XRSTOR instructions.
|
||||
*
|
||||
* It consists of a legacy fxregs portion, an xstate header and
|
||||
* subsequent areas as defined by the xstate header. Not all CPUs
|
||||
* support all the extensions, so the size of the extended area
|
||||
* can vary quite a bit between CPUs.
|
||||
*/
|
||||
struct xregs_state {
|
||||
struct fxregs_state i387;
|
||||
struct xstate_header header;
|
||||
u8 extended_state_area[];
|
||||
} __attribute__ ((packed, aligned (64)));
|
||||
|
||||
/*
|
||||
* This is a union of all the possible FPU state formats
|
||||
* put together, so that we can pick the right one runtime.
|
||||
*
|
||||
* The size of the structure is determined by the largest
|
||||
* member - which is the xsave area. The padding is there
|
||||
* to ensure that statically-allocated task_structs (just
|
||||
* the init_task today) have enough space.
|
||||
*/
|
||||
union fpregs_state {
|
||||
struct fregs_state fsave;
|
||||
struct fxregs_state fxsave;
|
||||
struct swregs_state soft;
|
||||
struct xregs_state xsave;
|
||||
u8 __padding[PAGE_SIZE];
|
||||
};
|
||||
|
||||
struct fpstate {
|
||||
/* @kernel_size: The size of the kernel register image */
|
||||
unsigned int size;
|
||||
|
||||
/* @user_size: The size in non-compacted UABI format */
|
||||
unsigned int user_size;
|
||||
|
||||
/* @xfeatures: xfeatures for which the storage is sized */
|
||||
u64 xfeatures;
|
||||
|
||||
/* @user_xfeatures: xfeatures valid in UABI buffers */
|
||||
u64 user_xfeatures;
|
||||
|
||||
/* @xfd: xfeatures disabled to trap userspace use. */
|
||||
u64 xfd;
|
||||
|
||||
/* @is_valloc: Indicator for dynamically allocated state */
|
||||
unsigned int is_valloc : 1;
|
||||
|
||||
/* @is_guest: Indicator for guest state (KVM) */
|
||||
unsigned int is_guest : 1;
|
||||
|
||||
/*
|
||||
* @is_confidential: Indicator for KVM confidential mode.
|
||||
* The FPU registers are restored by the
|
||||
* vmentry firmware from encrypted guest
|
||||
* memory. On vmexit the FPU registers are
|
||||
* saved by firmware to encrypted guest memory
|
||||
* and the registers are scrubbed before
|
||||
* returning to the host. So there is no
|
||||
* content which is worth saving and restoring.
|
||||
* The fpstate has to be there so that
|
||||
* preemption and softirq FPU usage works
|
||||
* without special casing.
|
||||
*/
|
||||
unsigned int is_confidential : 1;
|
||||
|
||||
/* @in_use: State is in use */
|
||||
unsigned int in_use : 1;
|
||||
|
||||
/* @regs: The register state union for all supported formats */
|
||||
union fpregs_state regs;
|
||||
|
||||
/* @regs is dynamically sized! Don't add anything after @regs! */
|
||||
} __aligned(64);
|
||||
|
||||
#define FPU_GUEST_PERM_LOCKED BIT_ULL(63)
|
||||
|
||||
struct fpu_state_perm {
|
||||
/*
|
||||
* @__state_perm:
|
||||
*
|
||||
* This bitmap indicates the permission for state components
|
||||
* available to a thread group, including both user and supervisor
|
||||
* components and software-defined bits like FPU_GUEST_PERM_LOCKED.
|
||||
* The permission prctl() sets the enabled state bits in
|
||||
* thread_group_leader()->thread.fpu.
|
||||
*
|
||||
* All run time operations use the per thread information in the
|
||||
* currently active fpu.fpstate which contains the xfeature masks
|
||||
* and sizes for kernel and user space.
|
||||
*
|
||||
* This master permission field is only to be used when
|
||||
* task.fpu.fpstate based checks fail to validate whether the task
|
||||
* is allowed to expand its xfeatures set which requires to
|
||||
* allocate a larger sized fpstate buffer.
|
||||
*
|
||||
* Do not access this field directly. Use the provided helper
|
||||
* function. Unlocked access is possible for quick checks.
|
||||
*/
|
||||
u64 __state_perm;
|
||||
|
||||
/*
|
||||
* @__state_size:
|
||||
*
|
||||
* The size required for @__state_perm. Only valid to access
|
||||
* with sighand locked.
|
||||
*/
|
||||
unsigned int __state_size;
|
||||
|
||||
/*
|
||||
* @__user_state_size:
|
||||
*
|
||||
* The size required for @__state_perm user part. Only valid to
|
||||
* access with sighand locked.
|
||||
*/
|
||||
unsigned int __user_state_size;
|
||||
};
|
||||
|
||||
/*
|
||||
* Highest level per task FPU state data structure that
|
||||
* contains the FPU register state plus various FPU
|
||||
* state fields:
|
||||
*/
|
||||
struct fpu {
|
||||
/*
|
||||
* @last_cpu:
|
||||
*
|
||||
* Records the last CPU on which this context was loaded into
|
||||
* FPU registers. (In the lazy-restore case we might be
|
||||
* able to reuse FPU registers across multiple context switches
|
||||
* this way, if no intermediate task used the FPU.)
|
||||
*
|
||||
* A value of -1 is used to indicate that the FPU state in context
|
||||
* memory is newer than the FPU state in registers, and that the
|
||||
* FPU state should be reloaded next time the task is run.
|
||||
*/
|
||||
unsigned int last_cpu;
|
||||
|
||||
/*
|
||||
* @avx512_timestamp:
|
||||
*
|
||||
* Records the timestamp of AVX512 use during last context switch.
|
||||
*/
|
||||
unsigned long avx512_timestamp;
|
||||
|
||||
/*
|
||||
* @fpstate:
|
||||
*
|
||||
* Pointer to the active struct fpstate. Initialized to
|
||||
* point at @__fpstate below.
|
||||
*/
|
||||
struct fpstate *fpstate;
|
||||
|
||||
/*
|
||||
* @__task_fpstate:
|
||||
*
|
||||
* Pointer to an inactive struct fpstate. Initialized to NULL. Is
|
||||
* used only for KVM support to swap out the regular task fpstate.
|
||||
*/
|
||||
struct fpstate *__task_fpstate;
|
||||
|
||||
/*
|
||||
* @perm:
|
||||
*
|
||||
* Permission related information
|
||||
*/
|
||||
struct fpu_state_perm perm;
|
||||
|
||||
/*
|
||||
* @guest_perm:
|
||||
*
|
||||
* Permission related information for guest pseudo FPUs
|
||||
*/
|
||||
struct fpu_state_perm guest_perm;
|
||||
|
||||
/*
|
||||
* @__fpstate:
|
||||
*
|
||||
* Initial in-memory storage for FPU registers which are saved in
|
||||
* context switch and when the kernel uses the FPU. The registers
|
||||
* are restored from this storage on return to user space if they
|
||||
* are not longer containing the tasks FPU register state.
|
||||
*/
|
||||
struct fpstate __fpstate;
|
||||
/*
|
||||
* WARNING: '__fpstate' is dynamically-sized. Do not put
|
||||
* anything after it here.
|
||||
*/
|
||||
};
|
||||
|
||||
/*
|
||||
* Guest pseudo FPU container
|
||||
*/
|
||||
struct fpu_guest {
|
||||
/*
|
||||
* @xfeatures: xfeature bitmap of features which are
|
||||
* currently enabled for the guest vCPU.
|
||||
*/
|
||||
u64 xfeatures;
|
||||
|
||||
/*
|
||||
* @xfd_err: Save the guest value.
|
||||
*/
|
||||
u64 xfd_err;
|
||||
|
||||
/*
|
||||
* @uabi_size: Size required for save/restore
|
||||
*/
|
||||
unsigned int uabi_size;
|
||||
|
||||
/*
|
||||
* @fpstate: Pointer to the allocated guest fpstate
|
||||
*/
|
||||
struct fpstate *fpstate;
|
||||
};
|
||||
|
||||
/*
|
||||
* FPU state configuration data for fpu_guest.
|
||||
* Initialized at boot time. Read only after init.
|
||||
*/
|
||||
struct vcpu_fpu_config {
|
||||
/*
|
||||
* @size:
|
||||
*
|
||||
* The default size of the register state buffer in guest FPUs.
|
||||
* Includes all supported features except independent managed
|
||||
* features and features which have to be requested by user space
|
||||
* before usage.
|
||||
*/
|
||||
unsigned int size;
|
||||
|
||||
/*
|
||||
* @features:
|
||||
*
|
||||
* The default supported features bitmap in guest FPUs. Does not
|
||||
* include independent managed features and features which have to
|
||||
* be requested by user space before usage.
|
||||
*/
|
||||
u64 features;
|
||||
};
|
||||
|
||||
/*
|
||||
* FPU state configuration data. Initialized at boot time. Read only after init.
|
||||
*/
|
||||
struct fpu_state_config {
|
||||
/*
|
||||
* @max_size:
|
||||
*
|
||||
* The maximum size of the register state buffer. Includes all
|
||||
* supported features except independent managed features.
|
||||
*/
|
||||
unsigned int max_size;
|
||||
|
||||
/*
|
||||
* @default_size:
|
||||
*
|
||||
* The default size of the register state buffer. Includes all
|
||||
* supported features except independent managed features,
|
||||
* guest-only features and features which have to be requested by
|
||||
* user space before usage.
|
||||
*/
|
||||
unsigned int default_size;
|
||||
|
||||
/*
|
||||
* @max_features:
|
||||
*
|
||||
* The maximum supported features bitmap. Does not include
|
||||
* independent managed features.
|
||||
*/
|
||||
u64 max_features;
|
||||
|
||||
/*
|
||||
* @default_features:
|
||||
*
|
||||
* The default supported features bitmap. Does not include
|
||||
* independent managed features, guest-only features and features
|
||||
* which have to be requested by user space before usage.
|
||||
*/
|
||||
u64 default_features;
|
||||
/*
|
||||
* @legacy_features:
|
||||
*
|
||||
* Features which can be reported back to user space
|
||||
* even without XSAVE support, i.e. legacy features FP + SSE
|
||||
*/
|
||||
u64 legacy_features;
|
||||
/*
|
||||
* @independent_features:
|
||||
*
|
||||
* Features that are supported by XSAVES, but not managed as part of
|
||||
* the FPU core, such as LBR
|
||||
*/
|
||||
u64 independent_features;
|
||||
};
|
||||
|
||||
/* FPU state configuration information */
|
||||
extern struct fpu_state_config fpu_kernel_cfg, fpu_user_cfg;
|
||||
extern struct vcpu_fpu_config guest_default_cfg;
|
||||
|
||||
#endif /* _ASM_X86_FPU_TYPES_H */
|
||||
@@ -0,0 +1,35 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_FPU_XCR_H
|
||||
#define _ASM_X86_FPU_XCR_H
|
||||
|
||||
#define XCR_XFEATURE_ENABLED_MASK 0x00000000
|
||||
#define XCR_XFEATURE_IN_USE_MASK 0x00000001
|
||||
|
||||
static __always_inline u64 xgetbv(u32 index)
|
||||
{
|
||||
u32 eax, edx;
|
||||
|
||||
asm volatile("xgetbv" : "=a" (eax), "=d" (edx) : "c" (index));
|
||||
return eax + ((u64)edx << 32);
|
||||
}
|
||||
|
||||
static inline void xsetbv(u32 index, u64 value)
|
||||
{
|
||||
u32 eax = value;
|
||||
u32 edx = value >> 32;
|
||||
|
||||
asm volatile("xsetbv" :: "a" (eax), "d" (edx), "c" (index));
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a mask of xfeatures which are currently being tracked
|
||||
* by the processor as being in the initial configuration.
|
||||
*
|
||||
* Callers should check X86_FEATURE_XGETBV1.
|
||||
*/
|
||||
static __always_inline u64 xfeatures_in_use(void)
|
||||
{
|
||||
return xgetbv(XCR_XFEATURE_IN_USE_MASK);
|
||||
}
|
||||
|
||||
#endif /* _ASM_X86_FPU_XCR_H */
|
||||
@@ -0,0 +1,134 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __ASM_X86_XSAVE_H
|
||||
#define __ASM_X86_XSAVE_H
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/processor.h>
|
||||
#include <asm/fpu/api.h>
|
||||
#include <asm/user.h>
|
||||
|
||||
/* Bit 63 of XCR0 is reserved for future expansion */
|
||||
#define XFEATURE_MASK_EXTEND (~(XFEATURE_MASK_FPSSE | (1ULL << 63)))
|
||||
|
||||
#define FXSAVE_SIZE 512
|
||||
|
||||
#define XSAVE_HDR_SIZE 64
|
||||
#define XSAVE_HDR_OFFSET FXSAVE_SIZE
|
||||
|
||||
#define XSAVE_YMM_SIZE 256
|
||||
#define XSAVE_YMM_OFFSET (XSAVE_HDR_SIZE + XSAVE_HDR_OFFSET)
|
||||
|
||||
#define XSAVE_ALIGNMENT 64
|
||||
|
||||
/* All currently supported user features */
|
||||
#define XFEATURE_MASK_USER_SUPPORTED (XFEATURE_MASK_FP | \
|
||||
XFEATURE_MASK_SSE | \
|
||||
XFEATURE_MASK_YMM | \
|
||||
XFEATURE_MASK_OPMASK | \
|
||||
XFEATURE_MASK_ZMM_Hi256 | \
|
||||
XFEATURE_MASK_Hi16_ZMM | \
|
||||
XFEATURE_MASK_PKRU | \
|
||||
XFEATURE_MASK_BNDREGS | \
|
||||
XFEATURE_MASK_BNDCSR | \
|
||||
XFEATURE_MASK_XTILE | \
|
||||
XFEATURE_MASK_APX)
|
||||
|
||||
/*
|
||||
* Features which are restored when returning to user space.
|
||||
* PKRU is not restored on return to user space because PKRU
|
||||
* is switched eagerly in switch_to() and flush_thread()
|
||||
*/
|
||||
#define XFEATURE_MASK_USER_RESTORE \
|
||||
(XFEATURE_MASK_USER_SUPPORTED & ~XFEATURE_MASK_PKRU)
|
||||
|
||||
/* Features which are dynamically enabled for a process on request */
|
||||
#define XFEATURE_MASK_USER_DYNAMIC XFEATURE_MASK_XTILE_DATA
|
||||
|
||||
/* Supervisor features which are enabled only in guest FPUs */
|
||||
#define XFEATURE_MASK_GUEST_SUPERVISOR XFEATURE_MASK_CET_KERNEL
|
||||
|
||||
/* All currently supported supervisor features */
|
||||
#define XFEATURE_MASK_SUPERVISOR_SUPPORTED (XFEATURE_MASK_PASID | \
|
||||
XFEATURE_MASK_CET_USER | \
|
||||
XFEATURE_MASK_GUEST_SUPERVISOR)
|
||||
|
||||
/*
|
||||
* A supervisor state component may not always contain valuable information,
|
||||
* and its size may be huge. Saving/restoring such supervisor state components
|
||||
* at each context switch can cause high CPU and space overhead, which should
|
||||
* be avoided. Such supervisor state components should only be saved/restored
|
||||
* on demand. The on-demand supervisor features are set in this mask.
|
||||
*
|
||||
* Unlike the existing supported supervisor features, an independent supervisor
|
||||
* feature does not allocate a buffer in task->fpu, and the corresponding
|
||||
* supervisor state component cannot be saved/restored at each context switch.
|
||||
*
|
||||
* To support an independent supervisor feature, a developer should follow the
|
||||
* dos and don'ts as below:
|
||||
* - Do dynamically allocate a buffer for the supervisor state component.
|
||||
* - Do manually invoke the XSAVES/XRSTORS instruction to save/restore the
|
||||
* state component to/from the buffer.
|
||||
* - Don't set the bit corresponding to the independent supervisor feature in
|
||||
* IA32_XSS at run time, since it has been set at boot time.
|
||||
*/
|
||||
#define XFEATURE_MASK_INDEPENDENT (XFEATURE_MASK_LBR)
|
||||
|
||||
/*
|
||||
* Unsupported supervisor features. When a supervisor feature in this mask is
|
||||
* supported in the future, move it to the supported supervisor feature mask.
|
||||
*/
|
||||
#define XFEATURE_MASK_SUPERVISOR_UNSUPPORTED (XFEATURE_MASK_PT)
|
||||
|
||||
/* All supervisor states including supported and unsupported states. */
|
||||
#define XFEATURE_MASK_SUPERVISOR_ALL (XFEATURE_MASK_SUPERVISOR_SUPPORTED | \
|
||||
XFEATURE_MASK_INDEPENDENT | \
|
||||
XFEATURE_MASK_SUPERVISOR_UNSUPPORTED)
|
||||
|
||||
/*
|
||||
* The feature mask required to restore FPU state:
|
||||
* - All user states which are not eagerly switched in switch_to()/exec()
|
||||
* - The suporvisor states
|
||||
*/
|
||||
#define XFEATURE_MASK_FPSTATE (XFEATURE_MASK_USER_RESTORE | \
|
||||
XFEATURE_MASK_SUPERVISOR_SUPPORTED)
|
||||
|
||||
/*
|
||||
* Features in this mask have space allocated in the signal frame, but may not
|
||||
* have that space initialized when the feature is in its init state.
|
||||
*/
|
||||
#define XFEATURE_MASK_SIGFRAME_INITOPT (XFEATURE_MASK_XTILE | \
|
||||
XFEATURE_MASK_USER_DYNAMIC)
|
||||
|
||||
extern u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS];
|
||||
|
||||
extern void __init update_regset_xstate_info(unsigned int size,
|
||||
u64 xstate_mask);
|
||||
|
||||
int xfeature_size(int xfeature_nr);
|
||||
|
||||
void xsaves(struct xregs_state *xsave, u64 mask);
|
||||
void xrstors(struct xregs_state *xsave, u64 mask);
|
||||
|
||||
int xfd_enable_feature(u64 xfd_err);
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
DECLARE_STATIC_KEY_FALSE(__fpu_state_size_dynamic);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
DECLARE_STATIC_KEY_FALSE(__fpu_state_size_dynamic);
|
||||
|
||||
static __always_inline __pure bool fpu_state_size_dynamic(void)
|
||||
{
|
||||
return static_branch_unlikely(&__fpu_state_size_dynamic);
|
||||
}
|
||||
#else
|
||||
static __always_inline __pure bool fpu_state_size_dynamic(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,113 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_FRAME_H
|
||||
#define _ASM_X86_FRAME_H
|
||||
|
||||
#include <asm/asm.h>
|
||||
|
||||
/*
|
||||
* These are stack frame creation macros. They should be used by every
|
||||
* callable non-leaf asm function to make kernel stack traces more reliable.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_FRAME_POINTER
|
||||
|
||||
#ifdef __ASSEMBLER__
|
||||
|
||||
.macro FRAME_BEGIN
|
||||
push %_ASM_BP
|
||||
_ASM_MOV %_ASM_SP, %_ASM_BP
|
||||
.endm
|
||||
|
||||
.macro FRAME_END
|
||||
pop %_ASM_BP
|
||||
.endm
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
/*
|
||||
* This is a sneaky trick to help the unwinder find pt_regs on the stack. The
|
||||
* frame pointer is replaced with an encoded pointer to pt_regs. The encoding
|
||||
* is just setting the LSB, which makes it an invalid stack address and is also
|
||||
* a signal to the unwinder that it's a pt_regs pointer in disguise.
|
||||
*
|
||||
* NOTE: This macro must be used *after* PUSH_AND_CLEAR_REGS because it corrupts
|
||||
* the original rbp.
|
||||
*/
|
||||
.macro ENCODE_FRAME_POINTER ptregs_offset=0
|
||||
leaq 1+\ptregs_offset(%rsp), %rbp
|
||||
.endm
|
||||
#else /* !CONFIG_X86_64 */
|
||||
/*
|
||||
* This is a sneaky trick to help the unwinder find pt_regs on the stack. The
|
||||
* frame pointer is replaced with an encoded pointer to pt_regs. The encoding
|
||||
* is just clearing the MSB, which makes it an invalid stack address and is also
|
||||
* a signal to the unwinder that it's a pt_regs pointer in disguise.
|
||||
*
|
||||
* NOTE: This macro must be used *after* SAVE_ALL because it corrupts the
|
||||
* original ebp.
|
||||
*/
|
||||
.macro ENCODE_FRAME_POINTER
|
||||
mov %esp, %ebp
|
||||
andl $0x7fffffff, %ebp
|
||||
.endm
|
||||
#endif /* CONFIG_X86_64 */
|
||||
|
||||
#else /* !__ASSEMBLER__ */
|
||||
|
||||
#define FRAME_BEGIN \
|
||||
"push %" _ASM_BP "\n" \
|
||||
_ASM_MOV "%" _ASM_SP ", %" _ASM_BP "\n"
|
||||
|
||||
#define FRAME_END "pop %" _ASM_BP "\n"
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
|
||||
#define ENCODE_FRAME_POINTER \
|
||||
"lea 1(%rsp), %rbp\n\t"
|
||||
|
||||
static inline unsigned long encode_frame_pointer(struct pt_regs *regs)
|
||||
{
|
||||
return (unsigned long)regs + 1;
|
||||
}
|
||||
|
||||
#else /* !CONFIG_X86_64 */
|
||||
|
||||
#define ENCODE_FRAME_POINTER \
|
||||
"movl %esp, %ebp\n\t" \
|
||||
"andl $0x7fffffff, %ebp\n\t"
|
||||
|
||||
static inline unsigned long encode_frame_pointer(struct pt_regs *regs)
|
||||
{
|
||||
return (unsigned long)regs & 0x7fffffff;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_X86_64 */
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
|
||||
#define FRAME_OFFSET __ASM_SEL(4, 8)
|
||||
|
||||
#else /* !CONFIG_FRAME_POINTER */
|
||||
|
||||
#ifdef __ASSEMBLER__
|
||||
|
||||
.macro ENCODE_FRAME_POINTER ptregs_offset=0
|
||||
.endm
|
||||
|
||||
#else /* !__ASSEMBLER__ */
|
||||
|
||||
#define ENCODE_FRAME_POINTER
|
||||
|
||||
static inline unsigned long encode_frame_pointer(struct pt_regs *regs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define FRAME_BEGIN
|
||||
#define FRAME_END
|
||||
#define FRAME_OFFSET 0
|
||||
|
||||
#endif /* CONFIG_FRAME_POINTER */
|
||||
|
||||
#endif /* _ASM_X86_FRAME_H */
|
||||
@@ -0,0 +1,119 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Macros for Flexible Return and Event Delivery (FRED)
|
||||
*/
|
||||
|
||||
#ifndef ASM_X86_FRED_H
|
||||
#define ASM_X86_FRED_H
|
||||
|
||||
#include <linux/const.h>
|
||||
|
||||
#include <asm/asm.h>
|
||||
#include <asm/msr.h>
|
||||
#include <asm/trapnr.h>
|
||||
|
||||
/*
|
||||
* FRED event return instruction opcodes for ERET{S,U}; supported in
|
||||
* binutils >= 2.41.
|
||||
*/
|
||||
#define ERETS _ASM_BYTES(0xf2,0x0f,0x01,0xca)
|
||||
#define ERETU _ASM_BYTES(0xf3,0x0f,0x01,0xca)
|
||||
|
||||
/*
|
||||
* RSP is aligned to a 64-byte boundary before used to push a new stack frame
|
||||
*/
|
||||
#define FRED_STACK_FRAME_RSP_MASK _AT(unsigned long, (~0x3f))
|
||||
|
||||
/*
|
||||
* Used for the return address for call emulation during code patching,
|
||||
* and measured in 64-byte cache lines.
|
||||
*/
|
||||
#define FRED_CONFIG_REDZONE_AMOUNT 1
|
||||
#define FRED_CONFIG_REDZONE (_AT(unsigned long, FRED_CONFIG_REDZONE_AMOUNT) << 6)
|
||||
#define FRED_CONFIG_INT_STKLVL(l) (_AT(unsigned long, l) << 9)
|
||||
#define FRED_CONFIG_ENTRYPOINT(p) _AT(unsigned long, (p))
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#ifdef CONFIG_X86_FRED
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched/task_stack.h>
|
||||
|
||||
#include <asm/ptrace.h>
|
||||
|
||||
struct fred_info {
|
||||
/* Event data: CR2, DR6, ... */
|
||||
unsigned long edata;
|
||||
unsigned long resv;
|
||||
};
|
||||
|
||||
/* Full format of the FRED stack frame */
|
||||
struct fred_frame {
|
||||
struct pt_regs regs;
|
||||
struct fred_info info;
|
||||
};
|
||||
|
||||
static __always_inline struct fred_info *fred_info(struct pt_regs *regs)
|
||||
{
|
||||
return &container_of(regs, struct fred_frame, regs)->info;
|
||||
}
|
||||
|
||||
static __always_inline unsigned long fred_event_data(struct pt_regs *regs)
|
||||
{
|
||||
return fred_info(regs)->edata;
|
||||
}
|
||||
|
||||
void asm_fred_entrypoint_user(void);
|
||||
void asm_fred_entrypoint_kernel(void);
|
||||
void asm_fred_entry_from_kvm(struct fred_ss);
|
||||
|
||||
__visible void fred_entry_from_user(struct pt_regs *regs);
|
||||
__visible void fred_entry_from_kernel(struct pt_regs *regs);
|
||||
__visible void __fred_entry_from_kvm(struct pt_regs *regs);
|
||||
|
||||
/* Can be called from noinstr code, thus __always_inline */
|
||||
static __always_inline void fred_entry_from_kvm(unsigned int type, unsigned int vector)
|
||||
{
|
||||
struct fred_ss ss = {
|
||||
.ss =__KERNEL_DS,
|
||||
.type = type,
|
||||
.vector = vector,
|
||||
.nmi = type == EVENT_TYPE_NMI,
|
||||
.l = 1,
|
||||
};
|
||||
|
||||
asm_fred_entry_from_kvm(ss);
|
||||
}
|
||||
|
||||
void cpu_init_fred_exceptions(void);
|
||||
void cpu_init_fred_rsps(void);
|
||||
void fred_complete_exception_setup(void);
|
||||
|
||||
DECLARE_PER_CPU(unsigned long, fred_rsp0);
|
||||
|
||||
static __always_inline void fred_sync_rsp0(unsigned long rsp0)
|
||||
{
|
||||
__this_cpu_write(fred_rsp0, rsp0);
|
||||
}
|
||||
|
||||
static __always_inline void fred_update_rsp0(void)
|
||||
{
|
||||
unsigned long rsp0 = (unsigned long) task_stack_page(current) + THREAD_SIZE;
|
||||
|
||||
if (cpu_feature_enabled(X86_FEATURE_FRED) && (__this_cpu_read(fred_rsp0) != rsp0)) {
|
||||
wrmsrns(MSR_IA32_FRED_RSP0, rsp0);
|
||||
__this_cpu_write(fred_rsp0, rsp0);
|
||||
}
|
||||
}
|
||||
#else /* CONFIG_X86_FRED */
|
||||
static __always_inline unsigned long fred_event_data(struct pt_regs *regs) { return 0; }
|
||||
static inline void cpu_init_fred_exceptions(void) { }
|
||||
static inline void cpu_init_fred_rsps(void) { }
|
||||
static inline void fred_complete_exception_setup(void) { }
|
||||
static inline void fred_entry_from_kvm(unsigned int type, unsigned int vector) { }
|
||||
static inline void fred_sync_rsp0(unsigned long rsp0) { }
|
||||
static inline void fred_update_rsp0(void) { }
|
||||
#endif /* CONFIG_X86_FRED */
|
||||
#endif /* !__ASSEMBLER__ */
|
||||
|
||||
#endif /* ASM_X86_FRED_H */
|
||||
@@ -0,0 +1,85 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_FSGSBASE_H
|
||||
#define _ASM_FSGSBASE_H
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
|
||||
#include <asm/msr.h>
|
||||
|
||||
/*
|
||||
* Read/write a task's FSBASE or GSBASE. This returns the value that
|
||||
* the FS/GS base would have (if the task were to be resumed). These
|
||||
* work on the current task or on a non-running (typically stopped
|
||||
* ptrace child) task.
|
||||
*/
|
||||
extern unsigned long x86_fsbase_read_task(struct task_struct *task);
|
||||
extern unsigned long x86_gsbase_read_task(struct task_struct *task);
|
||||
extern void x86_fsbase_write_task(struct task_struct *task, unsigned long fsbase);
|
||||
extern void x86_gsbase_write_task(struct task_struct *task, unsigned long gsbase);
|
||||
|
||||
/* Must be protected by X86_FEATURE_FSGSBASE check. */
|
||||
|
||||
static __always_inline unsigned long rdfsbase(void)
|
||||
{
|
||||
unsigned long fsbase;
|
||||
|
||||
asm volatile("rdfsbase %0" : "=r" (fsbase) :: "memory");
|
||||
|
||||
return fsbase;
|
||||
}
|
||||
|
||||
static __always_inline unsigned long rdgsbase(void)
|
||||
{
|
||||
unsigned long gsbase;
|
||||
|
||||
asm volatile("rdgsbase %0" : "=r" (gsbase) :: "memory");
|
||||
|
||||
return gsbase;
|
||||
}
|
||||
|
||||
static __always_inline void wrfsbase(unsigned long fsbase)
|
||||
{
|
||||
asm volatile("wrfsbase %0" :: "r" (fsbase) : "memory");
|
||||
}
|
||||
|
||||
static __always_inline void wrgsbase(unsigned long gsbase)
|
||||
{
|
||||
asm volatile("wrgsbase %0" :: "r" (gsbase) : "memory");
|
||||
}
|
||||
|
||||
#include <asm/cpufeature.h>
|
||||
|
||||
/* Helper functions for reading/writing FS/GS base */
|
||||
|
||||
static inline unsigned long x86_fsbase_read_cpu(void)
|
||||
{
|
||||
unsigned long fsbase;
|
||||
|
||||
if (boot_cpu_has(X86_FEATURE_FSGSBASE))
|
||||
fsbase = rdfsbase();
|
||||
else
|
||||
rdmsrq(MSR_FS_BASE, fsbase);
|
||||
|
||||
return fsbase;
|
||||
}
|
||||
|
||||
static inline void x86_fsbase_write_cpu(unsigned long fsbase)
|
||||
{
|
||||
if (boot_cpu_has(X86_FEATURE_FSGSBASE))
|
||||
wrfsbase(fsbase);
|
||||
else
|
||||
wrmsrq(MSR_FS_BASE, fsbase);
|
||||
}
|
||||
|
||||
extern unsigned long x86_gsbase_read_cpu_inactive(void);
|
||||
extern void x86_gsbase_write_cpu_inactive(unsigned long gsbase);
|
||||
extern unsigned long x86_fsgsbase_read_task(struct task_struct *task,
|
||||
unsigned short selector);
|
||||
|
||||
#endif /* CONFIG_X86_64 */
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
|
||||
#endif /* _ASM_FSGSBASE_H */
|
||||
@@ -0,0 +1,164 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_FTRACE_H
|
||||
#define _ASM_X86_FTRACE_H
|
||||
|
||||
#include <asm/ptrace.h>
|
||||
|
||||
#ifdef CONFIG_FUNCTION_TRACER
|
||||
#ifndef CC_USING_FENTRY
|
||||
# error Compiler does not support fentry?
|
||||
#endif
|
||||
# define MCOUNT_ADDR ((unsigned long)(__fentry__))
|
||||
#define MCOUNT_INSN_SIZE 5 /* sizeof mcount call */
|
||||
|
||||
/* Ignore unused weak functions which will have non zero offsets */
|
||||
#ifdef CONFIG_HAVE_FENTRY
|
||||
# include <asm/ibt.h>
|
||||
/* Add offset for endbr64 if IBT enabled */
|
||||
# define FTRACE_MCOUNT_MAX_OFFSET ENDBR_INSN_SIZE
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||
#define ARCH_SUPPORTS_FTRACE_OPS 1
|
||||
#endif
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
extern void __fentry__(void);
|
||||
|
||||
static inline unsigned long ftrace_call_adjust(unsigned long addr)
|
||||
{
|
||||
/*
|
||||
* addr is the address of the mcount call instruction.
|
||||
* recordmcount does the necessary offset calculation.
|
||||
*/
|
||||
return addr;
|
||||
}
|
||||
|
||||
static inline unsigned long arch_ftrace_get_symaddr(unsigned long fentry_ip)
|
||||
{
|
||||
if (is_endbr((void*)(fentry_ip - ENDBR_INSN_SIZE)))
|
||||
fentry_ip -= ENDBR_INSN_SIZE;
|
||||
|
||||
return fentry_ip;
|
||||
}
|
||||
#define ftrace_get_symaddr(fentry_ip) arch_ftrace_get_symaddr(fentry_ip)
|
||||
|
||||
#ifdef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS
|
||||
|
||||
#include <linux/ftrace_regs.h>
|
||||
|
||||
static __always_inline struct pt_regs *
|
||||
arch_ftrace_get_regs(struct ftrace_regs *fregs)
|
||||
{
|
||||
/* Only when FL_SAVE_REGS is set, cs will be non zero */
|
||||
if (!arch_ftrace_regs(fregs)->regs.cs)
|
||||
return NULL;
|
||||
return &arch_ftrace_regs(fregs)->regs;
|
||||
}
|
||||
|
||||
#define arch_ftrace_partial_regs(regs) do { \
|
||||
regs->flags |= X86_EFLAGS_FIXED; \
|
||||
regs->cs = __KERNEL_CS; \
|
||||
} while (0)
|
||||
|
||||
#define arch_ftrace_fill_perf_regs(fregs, _regs) do { \
|
||||
(_regs)->ip = arch_ftrace_regs(fregs)->regs.ip; \
|
||||
(_regs)->sp = arch_ftrace_regs(fregs)->regs.sp; \
|
||||
(_regs)->cs = __KERNEL_CS; \
|
||||
(_regs)->flags = 0; \
|
||||
} while (0)
|
||||
|
||||
#define ftrace_regs_set_instruction_pointer(fregs, _ip) \
|
||||
do { arch_ftrace_regs(fregs)->regs.ip = (_ip); } while (0)
|
||||
|
||||
|
||||
static __always_inline unsigned long
|
||||
ftrace_regs_get_return_address(struct ftrace_regs *fregs)
|
||||
{
|
||||
return *(unsigned long *)ftrace_regs_get_stack_pointer(fregs);
|
||||
}
|
||||
|
||||
struct ftrace_ops;
|
||||
#define ftrace_graph_func ftrace_graph_func
|
||||
void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
|
||||
struct ftrace_ops *op, struct ftrace_regs *fregs);
|
||||
#else
|
||||
#define FTRACE_GRAPH_TRAMP_ADDR FTRACE_GRAPH_ADDR
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
|
||||
/*
|
||||
* When a ftrace registered caller is tracing a function that is
|
||||
* also set by a register_ftrace_direct() call, it needs to be
|
||||
* differentiated in the ftrace_caller trampoline. To do this, we
|
||||
* place the direct caller in the ORIG_AX part of pt_regs. This
|
||||
* tells the ftrace_caller that there's a direct caller.
|
||||
*/
|
||||
static inline void
|
||||
__arch_ftrace_set_direct_caller(struct pt_regs *regs, unsigned long addr)
|
||||
{
|
||||
/* Emulate a call */
|
||||
regs->orig_ax = addr;
|
||||
}
|
||||
#define arch_ftrace_set_direct_caller(fregs, addr) \
|
||||
__arch_ftrace_set_direct_caller(&arch_ftrace_regs(fregs)->regs, addr)
|
||||
#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
|
||||
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||
|
||||
struct dyn_arch_ftrace {
|
||||
/* No extra data needed for x86 */
|
||||
};
|
||||
|
||||
#endif /* CONFIG_DYNAMIC_FTRACE */
|
||||
#endif /* __ASSEMBLER__ */
|
||||
#endif /* CONFIG_FUNCTION_TRACER */
|
||||
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
void prepare_ftrace_return(unsigned long ip, unsigned long *parent,
|
||||
unsigned long frame_pointer);
|
||||
|
||||
#if defined(CONFIG_FUNCTION_TRACER) && defined(CONFIG_DYNAMIC_FTRACE)
|
||||
extern void set_ftrace_ops_ro(void);
|
||||
#else
|
||||
static inline void set_ftrace_ops_ro(void) { }
|
||||
#endif
|
||||
|
||||
#define ARCH_HAS_SYSCALL_MATCH_SYM_NAME
|
||||
static inline bool arch_syscall_match_sym_name(const char *sym, const char *name)
|
||||
{
|
||||
/*
|
||||
* Compare the symbol name with the system call name. Skip the
|
||||
* "__x64_sys", "__ia32_sys", "__do_sys" or simple "sys" prefix.
|
||||
*/
|
||||
return !strcmp(sym + 3, name + 3) ||
|
||||
(!strncmp(sym, "__x64_", 6) && !strcmp(sym + 9, name + 3)) ||
|
||||
(!strncmp(sym, "__ia32_", 7) && !strcmp(sym + 10, name + 3)) ||
|
||||
(!strncmp(sym, "__do_sys", 8) && !strcmp(sym + 8, name + 3));
|
||||
}
|
||||
|
||||
#ifndef COMPILE_OFFSETS
|
||||
|
||||
#if defined(CONFIG_FTRACE_SYSCALLS) && defined(CONFIG_IA32_EMULATION)
|
||||
#include <linux/compat.h>
|
||||
|
||||
/*
|
||||
* Because ia32 syscalls do not map to x86_64 syscall numbers
|
||||
* this screws up the trace output when tracing a ia32 task.
|
||||
* Instead of reporting bogus syscalls, just do not trace them.
|
||||
*
|
||||
* If the user really wants these, then they should use the
|
||||
* raw syscall tracepoints with filtering.
|
||||
*/
|
||||
#define ARCH_TRACE_IGNORE_COMPAT_SYSCALLS 1
|
||||
static inline bool arch_trace_is_compat_syscall(struct pt_regs *regs)
|
||||
{
|
||||
return in_32bit_syscall();
|
||||
}
|
||||
#endif /* CONFIG_FTRACE_SYSCALLS && CONFIG_IA32_EMULATION */
|
||||
#endif /* !COMPILE_OFFSETS */
|
||||
#endif /* !__ASSEMBLER__ */
|
||||
|
||||
#endif /* _ASM_X86_FTRACE_H */
|
||||
@@ -0,0 +1,98 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_FUTEX_H
|
||||
#define _ASM_X86_FUTEX_H
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/futex.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <asm/asm.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/smap.h>
|
||||
|
||||
#define unsafe_atomic_op1(insn, oval, uaddr, oparg, label) \
|
||||
do { \
|
||||
int oldval = 0, ret; \
|
||||
asm volatile("1:\t" insn "\n" \
|
||||
"2:\n" \
|
||||
_ASM_EXTABLE_TYPE_REG(1b, 2b, EX_TYPE_EFAULT_REG, %1) \
|
||||
: "=r" (oldval), "=r" (ret), "+m" (*uaddr) \
|
||||
: "0" (oparg), "1" (0)); \
|
||||
if (ret) \
|
||||
goto label; \
|
||||
*oval = oldval; \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define unsafe_atomic_op2(insn, oval, uaddr, oparg, label) \
|
||||
do { \
|
||||
int oldval = 0, ret, tem; \
|
||||
asm volatile("1:\tmovl %2, %0\n" \
|
||||
"2:\tmovl\t%0, %3\n" \
|
||||
"\t" insn "\n" \
|
||||
"3:\t" LOCK_PREFIX "cmpxchgl %3, %2\n" \
|
||||
"\tjnz\t2b\n" \
|
||||
"4:\n" \
|
||||
_ASM_EXTABLE_TYPE_REG(1b, 4b, EX_TYPE_EFAULT_REG, %1) \
|
||||
_ASM_EXTABLE_TYPE_REG(3b, 4b, EX_TYPE_EFAULT_REG, %1) \
|
||||
: "=&a" (oldval), "=&r" (ret), \
|
||||
"+m" (*uaddr), "=&r" (tem) \
|
||||
: "r" (oparg), "1" (0)); \
|
||||
if (ret) \
|
||||
goto label; \
|
||||
*oval = oldval; \
|
||||
} while(0)
|
||||
|
||||
static __always_inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
|
||||
u32 __user *uaddr)
|
||||
{
|
||||
scoped_user_rw_access(uaddr, Efault) {
|
||||
switch (op) {
|
||||
case FUTEX_OP_SET:
|
||||
unsafe_atomic_op1("xchgl %0, %2", oval, uaddr, oparg, Efault);
|
||||
break;
|
||||
case FUTEX_OP_ADD:
|
||||
unsafe_atomic_op1(LOCK_PREFIX "xaddl %0, %2", oval, uaddr, oparg, Efault);
|
||||
break;
|
||||
case FUTEX_OP_OR:
|
||||
unsafe_atomic_op2("orl %4, %3", oval, uaddr, oparg, Efault);
|
||||
break;
|
||||
case FUTEX_OP_ANDN:
|
||||
unsafe_atomic_op2("andl %4, %3", oval, uaddr, ~oparg, Efault);
|
||||
break;
|
||||
case FUTEX_OP_XOR:
|
||||
unsafe_atomic_op2("xorl %4, %3", oval, uaddr, oparg, Efault);
|
||||
break;
|
||||
default:
|
||||
return -ENOSYS;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
Efault:
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
|
||||
u32 oldval, u32 newval)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
scoped_user_rw_access(uaddr, Efault) {
|
||||
asm_inline volatile("\n"
|
||||
"1:\t" LOCK_PREFIX "cmpxchgl %3, %2\n"
|
||||
"2:\n"
|
||||
_ASM_EXTABLE_TYPE_REG(1b, 2b, EX_TYPE_EFAULT_REG, %0)
|
||||
: "+r" (ret), "=a" (oldval), "+m" (*uaddr)
|
||||
: "r" (newval), "1" (oldval)
|
||||
: "memory");
|
||||
*uval = oldval;
|
||||
}
|
||||
return ret;
|
||||
Efault:
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* _ASM_X86_FUTEX_H */
|
||||
@@ -0,0 +1,113 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_GART_H
|
||||
#define _ASM_X86_GART_H
|
||||
|
||||
#include <asm/e820/api.h>
|
||||
|
||||
extern void set_up_gart_resume(u32, u32);
|
||||
|
||||
extern int fallback_aper_order;
|
||||
extern int fallback_aper_force;
|
||||
extern int fix_aperture;
|
||||
|
||||
/* PTE bits. */
|
||||
#define GPTE_VALID 1
|
||||
#define GPTE_COHERENT 2
|
||||
|
||||
/* Aperture control register bits. */
|
||||
#define GARTEN (1<<0)
|
||||
#define DISGARTCPU (1<<4)
|
||||
#define DISGARTIO (1<<5)
|
||||
#define DISTLBWALKPRB (1<<6)
|
||||
|
||||
/* GART cache control register bits. */
|
||||
#define INVGART (1<<0)
|
||||
#define GARTPTEERR (1<<1)
|
||||
|
||||
/* K8 On-cpu GART registers */
|
||||
#define AMD64_GARTAPERTURECTL 0x90
|
||||
#define AMD64_GARTAPERTUREBASE 0x94
|
||||
#define AMD64_GARTTABLEBASE 0x98
|
||||
#define AMD64_GARTCACHECTL 0x9c
|
||||
|
||||
#ifdef CONFIG_GART_IOMMU
|
||||
extern int gart_iommu_aperture;
|
||||
extern int gart_iommu_aperture_allowed;
|
||||
extern int gart_iommu_aperture_disabled;
|
||||
|
||||
extern void early_gart_iommu_check(void);
|
||||
extern int gart_iommu_init(void);
|
||||
extern void __init gart_parse_options(char *);
|
||||
void gart_iommu_hole_init(void);
|
||||
|
||||
#else
|
||||
#define gart_iommu_aperture 0
|
||||
#define gart_iommu_aperture_allowed 0
|
||||
#define gart_iommu_aperture_disabled 1
|
||||
|
||||
static inline void early_gart_iommu_check(void)
|
||||
{
|
||||
}
|
||||
static inline void gart_parse_options(char *options)
|
||||
{
|
||||
}
|
||||
static inline void gart_iommu_hole_init(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
extern int agp_amd64_init(void);
|
||||
|
||||
static inline void gart_set_size_and_enable(struct pci_dev *dev, u32 order)
|
||||
{
|
||||
u32 ctl;
|
||||
|
||||
/*
|
||||
* Don't enable translation but enable GART IO and CPU accesses.
|
||||
* Also, set DISTLBWALKPRB since GART tables memory is UC.
|
||||
*/
|
||||
ctl = order << 1;
|
||||
|
||||
pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, ctl);
|
||||
}
|
||||
|
||||
static inline void enable_gart_translation(struct pci_dev *dev, u64 addr)
|
||||
{
|
||||
u32 tmp, ctl;
|
||||
|
||||
/* address of the mappings table */
|
||||
addr >>= 12;
|
||||
tmp = (u32) addr<<4;
|
||||
tmp &= ~0xf;
|
||||
pci_write_config_dword(dev, AMD64_GARTTABLEBASE, tmp);
|
||||
|
||||
/* Enable GART translation for this hammer. */
|
||||
pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &ctl);
|
||||
ctl |= GARTEN | DISTLBWALKPRB;
|
||||
ctl &= ~(DISGARTCPU | DISGARTIO);
|
||||
pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, ctl);
|
||||
}
|
||||
|
||||
static inline int aperture_valid(u64 aper_base, u32 aper_size, u32 min_size)
|
||||
{
|
||||
if (!aper_base)
|
||||
return 0;
|
||||
|
||||
if (aper_base + aper_size > 0x100000000ULL) {
|
||||
printk(KERN_INFO "Aperture beyond 4GB. Ignoring.\n");
|
||||
return 0;
|
||||
}
|
||||
if (e820__mapped_any(aper_base, aper_base + aper_size, E820_TYPE_RAM)) {
|
||||
printk(KERN_INFO "Aperture pointing to e820 RAM. Ignoring.\n");
|
||||
return 0;
|
||||
}
|
||||
if (aper_size < min_size) {
|
||||
printk(KERN_INFO "Aperture too small (%d MB) than (%d MB)\n",
|
||||
aper_size>>20, min_size>>20);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* _ASM_X86_GART_H */
|
||||
@@ -0,0 +1 @@
|
||||
#include <asm/apic.h>
|
||||
@@ -0,0 +1,33 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* AMD Geode definitions
|
||||
* Copyright (C) 2006, Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _ASM_X86_GEODE_H
|
||||
#define _ASM_X86_GEODE_H
|
||||
|
||||
#include <asm/processor.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/cs5535.h>
|
||||
|
||||
static inline int is_geode_gx(void)
|
||||
{
|
||||
return ((boot_cpu_data.x86_vendor == X86_VENDOR_NSC) &&
|
||||
(boot_cpu_data.x86 == 5) &&
|
||||
(boot_cpu_data.x86_model == 5));
|
||||
}
|
||||
|
||||
static inline int is_geode_lx(void)
|
||||
{
|
||||
return ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) &&
|
||||
(boot_cpu_data.x86 == 5) &&
|
||||
(boot_cpu_data.x86_model == 10));
|
||||
}
|
||||
|
||||
static inline int is_geode(void)
|
||||
{
|
||||
return (is_geode_gx() || is_geode_lx());
|
||||
}
|
||||
|
||||
#endif /* _ASM_X86_GEODE_H */
|
||||
@@ -0,0 +1,66 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
#ifndef _ASM_X86_GSSEG_H
|
||||
#define _ASM_X86_GSSEG_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/asm.h>
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/alternative.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/nops.h>
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
|
||||
extern asmlinkage void asm_load_gs_index(u16 selector);
|
||||
|
||||
/* Replace with "lkgs %di" once binutils support LKGS instruction */
|
||||
#define LKGS_DI _ASM_BYTES(0xf2,0x0f,0x00,0xf7)
|
||||
|
||||
static inline void native_lkgs(unsigned int selector)
|
||||
{
|
||||
u16 sel = selector;
|
||||
asm_inline volatile("1: " LKGS_DI
|
||||
_ASM_EXTABLE_TYPE_REG(1b, 1b, EX_TYPE_ZERO_REG, %k[sel])
|
||||
: [sel] "+D" (sel));
|
||||
}
|
||||
|
||||
static inline void native_load_gs_index(unsigned int selector)
|
||||
{
|
||||
if (cpu_feature_enabled(X86_FEATURE_LKGS)) {
|
||||
native_lkgs(selector);
|
||||
} else {
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
asm_load_gs_index(selector);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_X86_64 */
|
||||
|
||||
static inline void __init lkgs_init(void)
|
||||
{
|
||||
#ifdef CONFIG_PARAVIRT_XXL
|
||||
#ifdef CONFIG_X86_64
|
||||
if (cpu_feature_enabled(X86_FEATURE_LKGS))
|
||||
pv_ops.cpu.load_gs_index = native_lkgs;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef CONFIG_PARAVIRT_XXL
|
||||
|
||||
static inline void load_gs_index(unsigned int selector)
|
||||
{
|
||||
#ifdef CONFIG_X86_64
|
||||
native_load_gs_index(selector);
|
||||
#else
|
||||
loadsegment(gs, selector);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PARAVIRT_XXL */
|
||||
|
||||
#endif /* _ASM_X86_GSSEG_H */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user