Merge branch 'x86/asm' into x86/core, to merge dependent commits
Prepare to resolve conflicts with an upstream series of fixes that conflict with pending x86 changes: 6f5bf947bab0 Merge tag 'its-for-linus-20250509' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
fa6b90ee4f
@ -34,7 +34,7 @@
|
||||
extern struct setup_header hdr;
|
||||
extern struct boot_params boot_params;
|
||||
|
||||
#define cpu_relax() asm volatile("rep; nop")
|
||||
#define cpu_relax() asm volatile("pause")
|
||||
|
||||
static inline void io_delay(void)
|
||||
{
|
||||
|
||||
@ -16,8 +16,7 @@ static __always_inline unsigned int __arch_hweight32(unsigned int w)
|
||||
{
|
||||
unsigned int res;
|
||||
|
||||
asm_inline (ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE
|
||||
"call __sw_hweight32",
|
||||
asm_inline (ALTERNATIVE("call __sw_hweight32",
|
||||
"popcntl %[val], %[cnt]", X86_FEATURE_POPCNT)
|
||||
: [cnt] "=" REG_OUT (res), ASM_CALL_CONSTRAINT
|
||||
: [val] REG_IN (w));
|
||||
@ -46,8 +45,7 @@ static __always_inline unsigned long __arch_hweight64(__u64 w)
|
||||
{
|
||||
unsigned long res;
|
||||
|
||||
asm_inline (ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE
|
||||
"call __sw_hweight64",
|
||||
asm_inline (ALTERNATIVE("call __sw_hweight64",
|
||||
"popcntq %[val], %[cnt]", X86_FEATURE_POPCNT)
|
||||
: [cnt] "=" REG_OUT (res), ASM_CALL_CONSTRAINT
|
||||
: [val] REG_IN (w));
|
||||
|
||||
@ -248,7 +248,7 @@ arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr)
|
||||
|
||||
static __always_inline unsigned long variable__ffs(unsigned long word)
|
||||
{
|
||||
asm("rep; bsf %1,%0"
|
||||
asm("tzcnt %1,%0"
|
||||
: "=r" (word)
|
||||
: ASM_INPUT_RM (word));
|
||||
return word;
|
||||
@ -267,10 +267,7 @@ static __always_inline unsigned long variable__ffs(unsigned long word)
|
||||
|
||||
static __always_inline unsigned long variable_ffz(unsigned long word)
|
||||
{
|
||||
asm("rep; bsf %1,%0"
|
||||
: "=r" (word)
|
||||
: "r" (~word));
|
||||
return word;
|
||||
return variable__ffs(~word);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -23,7 +23,7 @@ DECLARE_PER_CPU(unsigned long, cpu_dr7);
|
||||
|
||||
static __always_inline unsigned long native_get_debugreg(int regno)
|
||||
{
|
||||
unsigned long val = 0; /* Damn you, gcc! */
|
||||
unsigned long val;
|
||||
|
||||
switch (regno) {
|
||||
case 0:
|
||||
@ -43,7 +43,7 @@ static __always_inline unsigned long native_get_debugreg(int regno)
|
||||
break;
|
||||
case 7:
|
||||
/*
|
||||
* Apply __FORCE_ORDER to DR7 reads to forbid re-ordering them
|
||||
* 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
|
||||
@ -55,7 +55,7 @@ static __always_inline unsigned long native_get_debugreg(int regno)
|
||||
* re-ordered to happen before the call to sev_es_ist_enter(),
|
||||
* causing stack recursion.
|
||||
*/
|
||||
asm volatile("mov %%db7, %0" : "=r" (val) : __FORCE_ORDER);
|
||||
asm volatile("mov %%db7, %0" : "=r" (val));
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
@ -83,15 +83,15 @@ static __always_inline void native_set_debugreg(int regno, unsigned long value)
|
||||
break;
|
||||
case 7:
|
||||
/*
|
||||
* Apply __FORCE_ORDER to DR7 writes to forbid re-ordering them
|
||||
* 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
|
||||
* __FORCE_ORDER here too to avoid similar problems in the
|
||||
* "asm volatile" here too to avoid similar problems in the
|
||||
* future.
|
||||
*/
|
||||
asm volatile("mov %0, %%db7" ::"r" (value), __FORCE_ORDER);
|
||||
asm volatile("mov %0, %%db7" ::"r" (value));
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
|
||||
@ -82,6 +82,7 @@
|
||||
#define INAT_NO_REX2 (1 << (INAT_FLAG_OFFS + 8))
|
||||
#define INAT_REX2_VARIANT (1 << (INAT_FLAG_OFFS + 9))
|
||||
#define INAT_EVEX_SCALABLE (1 << (INAT_FLAG_OFFS + 10))
|
||||
#define INAT_INV64 (1 << (INAT_FLAG_OFFS + 11))
|
||||
/* Attribute making macros for attribute tables */
|
||||
#define INAT_MAKE_PREFIX(pfx) (pfx << INAT_PFX_OFFS)
|
||||
#define INAT_MAKE_ESCAPE(esc) (esc << INAT_ESC_OFFS)
|
||||
@ -242,4 +243,9 @@ static inline int inat_evex_scalable(insn_attr_t attr)
|
||||
{
|
||||
return attr & INAT_EVEX_SCALABLE;
|
||||
}
|
||||
|
||||
static inline int inat_is_invalid64(insn_attr_t attr)
|
||||
{
|
||||
return attr & INAT_INV64;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -217,7 +217,7 @@ void memset_io(volatile void __iomem *, int, size_t);
|
||||
static inline void __iowrite32_copy(void __iomem *to, const void *from,
|
||||
size_t count)
|
||||
{
|
||||
asm volatile("rep ; movsl"
|
||||
asm volatile("rep movsl"
|
||||
: "=&c"(count), "=&D"(to), "=&S"(from)
|
||||
: "0"(count), "1"(to), "2"(from)
|
||||
: "memory");
|
||||
@ -282,7 +282,7 @@ static inline void outs##bwl(u16 port, const void *addr, unsigned long count) \
|
||||
count--; \
|
||||
} \
|
||||
} else { \
|
||||
asm volatile("rep; outs" #bwl \
|
||||
asm volatile("rep outs" #bwl \
|
||||
: "+S"(addr), "+c"(count) \
|
||||
: "d"(port) : "memory"); \
|
||||
} \
|
||||
@ -298,7 +298,7 @@ static inline void ins##bwl(u16 port, void *addr, unsigned long count) \
|
||||
count--; \
|
||||
} \
|
||||
} else { \
|
||||
asm volatile("rep; ins" #bwl \
|
||||
asm volatile("rep ins" #bwl \
|
||||
: "+D"(addr), "+c"(count) \
|
||||
: "d"(port) : "memory"); \
|
||||
} \
|
||||
|
||||
@ -8,6 +8,9 @@
|
||||
# define PA_PGD 2
|
||||
# define PA_SWAP_PAGE 3
|
||||
# define PAGES_NR 4
|
||||
#else
|
||||
/* Size of each exception handler referenced by the IDT */
|
||||
# define KEXEC_DEBUG_EXC_HANDLER_SIZE 6 /* PUSHI, PUSHI, 2-byte JMP */
|
||||
#endif
|
||||
|
||||
# define KEXEC_CONTROL_PAGE_SIZE 4096
|
||||
@ -59,6 +62,10 @@ struct kimage;
|
||||
extern unsigned long kexec_va_control_page;
|
||||
extern unsigned long kexec_pa_table_page;
|
||||
extern unsigned long kexec_pa_swap_page;
|
||||
extern gate_desc kexec_debug_idt[];
|
||||
extern unsigned char kexec_debug_exc_vectors[];
|
||||
extern uint16_t kexec_debug_8250_port;
|
||||
extern unsigned long kexec_debug_8250_mmio32;
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
@ -29,6 +29,8 @@
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
|
||||
#define __force_percpu_prefix "%%"__stringify(__percpu_seg)":"
|
||||
|
||||
#ifdef CONFIG_CC_HAS_NAMED_AS
|
||||
|
||||
#ifdef __CHECKER__
|
||||
@ -36,23 +38,23 @@
|
||||
# define __seg_fs __attribute__((address_space(__seg_fs)))
|
||||
#endif
|
||||
|
||||
#define __percpu_prefix
|
||||
#define __percpu_seg_override CONCATENATE(__seg_, __percpu_seg)
|
||||
#define __percpu_prefix ""
|
||||
|
||||
#else /* !CONFIG_CC_HAS_NAMED_AS: */
|
||||
|
||||
#define __percpu_prefix __force_percpu_prefix
|
||||
#define __percpu_seg_override
|
||||
#define __percpu_prefix "%%"__stringify(__percpu_seg)":"
|
||||
|
||||
#endif /* CONFIG_CC_HAS_NAMED_AS */
|
||||
|
||||
#define __force_percpu_prefix "%%"__stringify(__percpu_seg)":"
|
||||
#define __my_cpu_offset this_cpu_read(this_cpu_off)
|
||||
|
||||
/*
|
||||
* Compared to the generic __my_cpu_offset version, the following
|
||||
* saves one instruction and avoids clobbering a temp register.
|
||||
*
|
||||
*/
|
||||
#define __my_cpu_offset this_cpu_read(this_cpu_off)
|
||||
|
||||
/*
|
||||
* arch_raw_cpu_ptr should not be used in 32-bit VDSO for a 64-bit
|
||||
* kernel, because games are played with CONFIG_X86_64 there and
|
||||
* sizeof(this_cpu_off) becames 4.
|
||||
@ -77,9 +79,9 @@
|
||||
|
||||
#else /* !CONFIG_SMP: */
|
||||
|
||||
#define __force_percpu_prefix
|
||||
#define __percpu_prefix
|
||||
#define __percpu_seg_override
|
||||
#define __percpu_prefix ""
|
||||
#define __force_percpu_prefix ""
|
||||
|
||||
#define PER_CPU_VAR(var) (var)__percpu_rel
|
||||
|
||||
@ -97,8 +99,8 @@
|
||||
# define __my_cpu_var(var) (*__my_cpu_ptr(&(var)))
|
||||
#endif
|
||||
|
||||
#define __percpu_arg(x) __percpu_prefix "%" #x
|
||||
#define __force_percpu_arg(x) __force_percpu_prefix "%" #x
|
||||
#define __percpu_arg(x) __percpu_prefix "%" #x
|
||||
|
||||
/*
|
||||
* For arch-specific code, we can use direct single-insn ops (they
|
||||
|
||||
@ -10,30 +10,19 @@
|
||||
#include <linux/irqflags.h>
|
||||
#include <linux/jump_label.h>
|
||||
|
||||
/*
|
||||
* The compiler should not reorder volatile asm statements with respect to each
|
||||
* other: they should execute in program order. However GCC 4.9.x and 5.x have
|
||||
* a bug (which was fixed in 8.1, 7.3 and 6.5) where they might reorder
|
||||
* volatile asm. The write functions are not affected since they have memory
|
||||
* clobbers preventing reordering. To prevent reads from being reordered with
|
||||
* respect to writes, use a dummy memory operand.
|
||||
*/
|
||||
|
||||
#define __FORCE_ORDER "m"(*(unsigned int *)0x1000UL)
|
||||
|
||||
void native_write_cr0(unsigned long val);
|
||||
|
||||
static inline unsigned long native_read_cr0(void)
|
||||
{
|
||||
unsigned long val;
|
||||
asm volatile("mov %%cr0,%0\n\t" : "=r" (val) : __FORCE_ORDER);
|
||||
asm volatile("mov %%cr0,%0" : "=r" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
static __always_inline unsigned long native_read_cr2(void)
|
||||
{
|
||||
unsigned long val;
|
||||
asm volatile("mov %%cr2,%0\n\t" : "=r" (val) : __FORCE_ORDER);
|
||||
asm volatile("mov %%cr2,%0" : "=r" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
@ -45,7 +34,7 @@ static __always_inline void native_write_cr2(unsigned long val)
|
||||
static __always_inline unsigned long __native_read_cr3(void)
|
||||
{
|
||||
unsigned long val;
|
||||
asm volatile("mov %%cr3,%0\n\t" : "=r" (val) : __FORCE_ORDER);
|
||||
asm volatile("mov %%cr3,%0" : "=r" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
@ -66,10 +55,10 @@ static inline unsigned long native_read_cr4(void)
|
||||
asm volatile("1: mov %%cr4, %0\n"
|
||||
"2:\n"
|
||||
_ASM_EXTABLE(1b, 2b)
|
||||
: "=r" (val) : "0" (0), __FORCE_ORDER);
|
||||
: "=r" (val) : "0" (0));
|
||||
#else
|
||||
/* CR4 always exists on x86_64. */
|
||||
asm volatile("mov %%cr4,%0\n\t" : "=r" (val) : __FORCE_ORDER);
|
||||
asm volatile("mov %%cr4,%0" : "=r" (val));
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
@ -33,11 +33,11 @@ extern size_t strlen(const char *s);
|
||||
static __always_inline void *__memcpy(void *to, const void *from, size_t n)
|
||||
{
|
||||
int d0, d1, d2;
|
||||
asm volatile("rep ; movsl\n\t"
|
||||
asm volatile("rep movsl\n\t"
|
||||
"movl %4,%%ecx\n\t"
|
||||
"andl $3,%%ecx\n\t"
|
||||
"jz 1f\n\t"
|
||||
"rep ; movsb\n\t"
|
||||
"rep movsb\n\t"
|
||||
"1:"
|
||||
: "=&c" (d0), "=&D" (d1), "=&S" (d2)
|
||||
: "0" (n / 4), "g" (n), "1" ((long)to), "2" ((long)from)
|
||||
@ -89,7 +89,7 @@ static __always_inline void *__constant_memcpy(void *to, const void *from,
|
||||
if (n >= 5 * 4) {
|
||||
/* large block: use rep prefix */
|
||||
int ecx;
|
||||
asm volatile("rep ; movsl"
|
||||
asm volatile("rep movsl"
|
||||
: "=&c" (ecx), "=&D" (edi), "=&S" (esi)
|
||||
: "0" (n / 4), "1" (edi), "2" (esi)
|
||||
: "memory"
|
||||
@ -165,8 +165,7 @@ extern void *memchr(const void *cs, int c, size_t count);
|
||||
static inline void *__memset_generic(void *s, char c, size_t count)
|
||||
{
|
||||
int d0, d1;
|
||||
asm volatile("rep\n\t"
|
||||
"stosb"
|
||||
asm volatile("rep stosb"
|
||||
: "=&c" (d0), "=&D" (d1)
|
||||
: "a" (c), "1" (s), "0" (count)
|
||||
: "memory");
|
||||
@ -199,8 +198,7 @@ extern void *memset(void *, int, size_t);
|
||||
static inline void *memset16(uint16_t *s, uint16_t v, size_t n)
|
||||
{
|
||||
int d0, d1;
|
||||
asm volatile("rep\n\t"
|
||||
"stosw"
|
||||
asm volatile("rep stosw"
|
||||
: "=&c" (d0), "=&D" (d1)
|
||||
: "a" (v), "1" (s), "0" (n)
|
||||
: "memory");
|
||||
@ -211,8 +209,7 @@ static inline void *memset16(uint16_t *s, uint16_t v, size_t n)
|
||||
static inline void *memset32(uint32_t *s, uint32_t v, size_t n)
|
||||
{
|
||||
int d0, d1;
|
||||
asm volatile("rep\n\t"
|
||||
"stosl"
|
||||
asm volatile("rep stosl"
|
||||
: "=&c" (d0), "=&D" (d1)
|
||||
: "a" (v), "1" (s), "0" (n)
|
||||
: "memory");
|
||||
|
||||
@ -26,8 +26,8 @@ extern unsigned long USER_PTR_MAX;
|
||||
*/
|
||||
static inline unsigned long __untagged_addr(unsigned long addr)
|
||||
{
|
||||
asm (ALTERNATIVE("",
|
||||
"and " __percpu_arg([mask]) ", %[addr]", X86_FEATURE_LAM)
|
||||
asm_inline (ALTERNATIVE("", "and " __percpu_arg([mask]) ", %[addr]",
|
||||
X86_FEATURE_LAM)
|
||||
: [addr] "+r" (addr)
|
||||
: [mask] "m" (__my_cpu_var(tlbstate_untag_mask)));
|
||||
|
||||
@ -54,7 +54,7 @@ static inline unsigned long __untagged_addr_remote(struct mm_struct *mm,
|
||||
#endif
|
||||
|
||||
#define valid_user_address(x) \
|
||||
((__force unsigned long)(x) <= runtime_const_ptr(USER_PTR_MAX))
|
||||
likely((__force unsigned long)(x) <= runtime_const_ptr(USER_PTR_MAX))
|
||||
|
||||
/*
|
||||
* Masking the user address is an alternative to a conditional
|
||||
|
||||
@ -7,15 +7,15 @@
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
|
||||
static __always_inline void rep_nop(void)
|
||||
/* PAUSE is a good thing to insert into busy-wait loops. */
|
||||
static __always_inline void native_pause(void)
|
||||
{
|
||||
asm volatile("rep; nop" ::: "memory");
|
||||
asm volatile("pause" ::: "memory");
|
||||
}
|
||||
|
||||
static __always_inline void cpu_relax(void)
|
||||
{
|
||||
rep_nop();
|
||||
native_pause();
|
||||
}
|
||||
|
||||
struct getcpu_cache;
|
||||
|
||||
@ -1486,7 +1486,7 @@ static void __init delay_with_tsc(void)
|
||||
* 1 GHz == 40 jiffies
|
||||
*/
|
||||
do {
|
||||
rep_nop();
|
||||
native_pause();
|
||||
now = rdtsc();
|
||||
} while ((now - start) < 40000000000ULL / HZ && time_before_eq(jiffies, end));
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/console.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kexec.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/screen_info.h>
|
||||
@ -144,6 +145,11 @@ static __init void early_serial_hw_init(unsigned divisor)
|
||||
static_call(serial_out)(early_serial_base, DLL, divisor & 0xff);
|
||||
static_call(serial_out)(early_serial_base, DLH, (divisor >> 8) & 0xff);
|
||||
static_call(serial_out)(early_serial_base, LCR, c & ~DLAB);
|
||||
|
||||
#if defined(CONFIG_KEXEC_CORE) && defined(CONFIG_X86_64)
|
||||
if (static_call_query(serial_in) == io_serial_in)
|
||||
kexec_debug_8250_port = early_serial_base;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define DEFAULT_BAUD 9600
|
||||
@ -327,6 +333,9 @@ static __init void early_pci_serial_init(char *s)
|
||||
/* WARNING! assuming the address is always in the first 4G */
|
||||
early_serial_base =
|
||||
(unsigned long)early_ioremap(bar0 & PCI_BASE_ADDRESS_MEM_MASK, 0x10);
|
||||
#if defined(CONFIG_KEXEC_CORE) && defined(CONFIG_X86_64)
|
||||
kexec_debug_8250_mmio32 = bar0 & PCI_BASE_ADDRESS_MEM_MASK;
|
||||
#endif
|
||||
write_pci_config(bus, slot, func, PCI_COMMAND,
|
||||
cmdreg|PCI_COMMAND_MEMORY);
|
||||
}
|
||||
|
||||
@ -86,7 +86,7 @@ SYM_CODE_START(startup_32)
|
||||
movl $pa(__bss_stop),%ecx
|
||||
subl %edi,%ecx
|
||||
shrl $2,%ecx
|
||||
rep ; stosl
|
||||
rep stosl
|
||||
/*
|
||||
* Copy bootup parameters out of the way.
|
||||
* Note: %esi still has the pointer to the real-mode data.
|
||||
@ -98,15 +98,13 @@ SYM_CODE_START(startup_32)
|
||||
movl $pa(boot_params),%edi
|
||||
movl $(PARAM_SIZE/4),%ecx
|
||||
cld
|
||||
rep
|
||||
movsl
|
||||
rep movsl
|
||||
movl pa(boot_params) + NEW_CL_POINTER,%esi
|
||||
andl %esi,%esi
|
||||
jz 1f # No command line
|
||||
movl $pa(boot_command_line),%edi
|
||||
movl $(COMMAND_LINE_SIZE/4),%ecx
|
||||
rep
|
||||
movsl
|
||||
rep movsl
|
||||
1:
|
||||
|
||||
#ifdef CONFIG_OLPC
|
||||
|
||||
@ -76,6 +76,19 @@ map_acpi_tables(struct x86_mapping_info *info, pgd_t *level4p)
|
||||
static int map_acpi_tables(struct x86_mapping_info *info, pgd_t *level4p) { return 0; }
|
||||
#endif
|
||||
|
||||
static int map_mmio_serial(struct x86_mapping_info *info, pgd_t *level4p)
|
||||
{
|
||||
unsigned long mstart, mend;
|
||||
|
||||
if (!kexec_debug_8250_mmio32)
|
||||
return 0;
|
||||
|
||||
mstart = kexec_debug_8250_mmio32 & PAGE_MASK;
|
||||
mend = (kexec_debug_8250_mmio32 + PAGE_SIZE + 23) & PAGE_MASK;
|
||||
pr_info("Map PCI serial at %lx - %lx\n", mstart, mend);
|
||||
return kernel_ident_mapping_init(info, level4p, mstart, mend);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KEXEC_FILE
|
||||
const struct kexec_file_ops * const kexec_file_loaders[] = {
|
||||
&kexec_bzImage64_ops,
|
||||
@ -285,6 +298,10 @@ static int init_pgtable(struct kimage *image, unsigned long control_page)
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
result = map_mmio_serial(&info, image->arch.pgd);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
/*
|
||||
* This must be last because the intermediate page table pages it
|
||||
* allocates will not be control pages and may overlap the image.
|
||||
@ -304,6 +321,24 @@ static void load_segments(void)
|
||||
);
|
||||
}
|
||||
|
||||
static void prepare_debug_idt(unsigned long control_page, unsigned long vec_ofs)
|
||||
{
|
||||
gate_desc idtentry = { 0 };
|
||||
int i;
|
||||
|
||||
idtentry.bits.p = 1;
|
||||
idtentry.bits.type = GATE_TRAP;
|
||||
idtentry.segment = __KERNEL_CS;
|
||||
idtentry.offset_low = (control_page & 0xFFFF) + vec_ofs;
|
||||
idtentry.offset_middle = (control_page >> 16) & 0xFFFF;
|
||||
idtentry.offset_high = control_page >> 32;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
kexec_debug_idt[i] = idtentry;
|
||||
idtentry.offset_low += KEXEC_DEBUG_EXC_HANDLER_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
int machine_kexec_prepare(struct kimage *image)
|
||||
{
|
||||
void *control_page = page_address(image->control_code_page);
|
||||
@ -321,6 +356,9 @@ int machine_kexec_prepare(struct kimage *image)
|
||||
if (image->type == KEXEC_TYPE_DEFAULT)
|
||||
kexec_pa_swap_page = page_to_pfn(image->swap_page) << PAGE_SHIFT;
|
||||
|
||||
prepare_debug_idt((unsigned long)__pa(control_page),
|
||||
(unsigned long)kexec_debug_exc_vectors - reloc_start);
|
||||
|
||||
__memcpy(control_page, __relocate_kernel_start, reloc_end - reloc_start);
|
||||
|
||||
set_memory_rox((unsigned long)control_page, 1);
|
||||
@ -396,16 +434,10 @@ void __nocfi machine_kexec(struct kimage *image)
|
||||
* with from a table in memory. At no other time is the
|
||||
* descriptor table in memory accessed.
|
||||
*
|
||||
* I take advantage of this here by force loading the
|
||||
* segments, before I zap the gdt with an invalid value.
|
||||
* Take advantage of this here by force loading the segments,
|
||||
* before the GDT is zapped with an invalid value.
|
||||
*/
|
||||
load_segments();
|
||||
/*
|
||||
* The gdt & idt are now invalid.
|
||||
* If you want to load them you must set up your own idt & gdt.
|
||||
*/
|
||||
native_idt_invalidate();
|
||||
native_gdt_invalidate();
|
||||
|
||||
/* now call it */
|
||||
image->start = relocate_kernel_ptr((unsigned long)image->head,
|
||||
|
||||
@ -263,17 +263,17 @@ SYM_CODE_START_LOCAL_NOALIGN(swap_pages)
|
||||
|
||||
movl %edx, %edi
|
||||
movl $1024, %ecx
|
||||
rep ; movsl
|
||||
rep movsl
|
||||
|
||||
movl %ebp, %edi
|
||||
movl %eax, %esi
|
||||
movl $1024, %ecx
|
||||
rep ; movsl
|
||||
rep movsl
|
||||
|
||||
movl %eax, %edi
|
||||
movl %edx, %esi
|
||||
movl $1024, %ecx
|
||||
rep ; movsl
|
||||
rep movsl
|
||||
|
||||
lea PAGE_SIZE(%ebp), %esi
|
||||
jmp 0b
|
||||
|
||||
@ -39,6 +39,8 @@ SYM_DATA(kexec_va_control_page, .quad 0)
|
||||
SYM_DATA(kexec_pa_table_page, .quad 0)
|
||||
SYM_DATA(kexec_pa_swap_page, .quad 0)
|
||||
SYM_DATA_LOCAL(pa_backup_pages_map, .quad 0)
|
||||
SYM_DATA(kexec_debug_8250_mmio32, .quad 0)
|
||||
SYM_DATA(kexec_debug_8250_port, .word 0)
|
||||
|
||||
.balign 16
|
||||
SYM_DATA_START_LOCAL(kexec_debug_gdt)
|
||||
@ -50,6 +52,11 @@ SYM_DATA_START_LOCAL(kexec_debug_gdt)
|
||||
.quad 0x00cf92000000ffff /* __KERNEL_DS */
|
||||
SYM_DATA_END_LABEL(kexec_debug_gdt, SYM_L_LOCAL, kexec_debug_gdt_end)
|
||||
|
||||
.balign 8
|
||||
SYM_DATA_START(kexec_debug_idt)
|
||||
.skip 0x100, 0x00
|
||||
SYM_DATA_END(kexec_debug_idt)
|
||||
|
||||
.section .text..relocate_kernel,"ax";
|
||||
.code64
|
||||
SYM_CODE_START_NOALIGN(relocate_kernel)
|
||||
@ -72,8 +79,13 @@ SYM_CODE_START_NOALIGN(relocate_kernel)
|
||||
pushq %r15
|
||||
pushf
|
||||
|
||||
/* zero out flags, and disable interrupts */
|
||||
pushq $0
|
||||
/* Invalidate GDT/IDT, zero out flags */
|
||||
pushq $0
|
||||
pushq $0
|
||||
|
||||
lidt (%rsp)
|
||||
lgdt (%rsp)
|
||||
addq $8, %rsp
|
||||
popfq
|
||||
|
||||
/* Switch to the identity mapped page tables */
|
||||
@ -139,6 +151,15 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
|
||||
movq %ds, %rax
|
||||
movq %rax, %ds
|
||||
|
||||
/* Now an IDTR on the stack to load the IDT the kernel created */
|
||||
leaq kexec_debug_idt(%rip), %rsi
|
||||
pushq %rsi
|
||||
pushw $0xff
|
||||
lidt (%rsp)
|
||||
addq $10, %rsp
|
||||
|
||||
//int3
|
||||
|
||||
/*
|
||||
* Clear X86_CR4_CET (if it was set) such that we can clear CR0_WP
|
||||
* below.
|
||||
@ -342,20 +363,20 @@ SYM_CODE_START_LOCAL_NOALIGN(swap_pages)
|
||||
/* copy source page to swap page */
|
||||
movq kexec_pa_swap_page(%rip), %rdi
|
||||
movl $512, %ecx
|
||||
rep ; movsq
|
||||
rep movsq
|
||||
|
||||
/* copy destination page to source page */
|
||||
movq %rax, %rdi
|
||||
movq %rdx, %rsi
|
||||
movl $512, %ecx
|
||||
rep ; movsq
|
||||
rep movsq
|
||||
|
||||
/* copy swap page to destination page */
|
||||
movq %rdx, %rdi
|
||||
movq kexec_pa_swap_page(%rip), %rsi
|
||||
.Lnoswap:
|
||||
movl $512, %ecx
|
||||
rep ; movsq
|
||||
rep movsq
|
||||
|
||||
lea PAGE_SIZE(%rax), %rsi
|
||||
jmp .Lloop
|
||||
@ -364,3 +385,222 @@ SYM_CODE_START_LOCAL_NOALIGN(swap_pages)
|
||||
ret
|
||||
int3
|
||||
SYM_CODE_END(swap_pages)
|
||||
|
||||
/*
|
||||
* Generic 'print character' routine
|
||||
* - %al: Character to be printed (may clobber %rax)
|
||||
* - %rdx: MMIO address or port.
|
||||
*/
|
||||
#define XMTRDY 0x20
|
||||
|
||||
#define TXR 0 /* Transmit register (WRITE) */
|
||||
#define LSR 5 /* Line Status */
|
||||
|
||||
SYM_CODE_START_LOCAL_NOALIGN(pr_char_8250)
|
||||
UNWIND_HINT_FUNC
|
||||
ANNOTATE_NOENDBR
|
||||
addw $LSR, %dx
|
||||
xchg %al, %ah
|
||||
.Lxmtrdy_loop:
|
||||
inb %dx, %al
|
||||
testb $XMTRDY, %al
|
||||
jnz .Lready
|
||||
pause
|
||||
jmp .Lxmtrdy_loop
|
||||
|
||||
.Lready:
|
||||
subw $LSR, %dx
|
||||
xchg %al, %ah
|
||||
outb %al, %dx
|
||||
pr_char_null:
|
||||
ANNOTATE_NOENDBR
|
||||
|
||||
ANNOTATE_UNRET_SAFE
|
||||
ret
|
||||
SYM_CODE_END(pr_char_8250)
|
||||
|
||||
SYM_CODE_START_LOCAL_NOALIGN(pr_char_8250_mmio32)
|
||||
UNWIND_HINT_FUNC
|
||||
ANNOTATE_NOENDBR
|
||||
.Lxmtrdy_loop_mmio:
|
||||
movb (LSR*4)(%rdx), %ah
|
||||
testb $XMTRDY, %ah
|
||||
jnz .Lready_mmio
|
||||
pause
|
||||
jmp .Lxmtrdy_loop_mmio
|
||||
|
||||
.Lready_mmio:
|
||||
movb %al, (%rdx)
|
||||
ANNOTATE_UNRET_SAFE
|
||||
ret
|
||||
SYM_CODE_END(pr_char_8250_mmio32)
|
||||
|
||||
/*
|
||||
* Load pr_char function pointer into %rsi and load %rdx with whatever
|
||||
* that function wants to see there (typically port/MMIO address).
|
||||
*/
|
||||
.macro pr_setup
|
||||
leaq pr_char_8250(%rip), %rsi
|
||||
movw kexec_debug_8250_port(%rip), %dx
|
||||
testw %dx, %dx
|
||||
jnz 1f
|
||||
|
||||
leaq pr_char_8250_mmio32(%rip), %rsi
|
||||
movq kexec_debug_8250_mmio32(%rip), %rdx
|
||||
testq %rdx, %rdx
|
||||
jnz 1f
|
||||
|
||||
leaq pr_char_null(%rip), %rsi
|
||||
1:
|
||||
.endm
|
||||
|
||||
/* Print the nybble in %bl, clobber %rax */
|
||||
SYM_CODE_START_LOCAL_NOALIGN(pr_nybble)
|
||||
UNWIND_HINT_FUNC
|
||||
movb %bl, %al
|
||||
nop
|
||||
andb $0x0f, %al
|
||||
addb $0x30, %al
|
||||
cmpb $0x3a, %al
|
||||
jb 1f
|
||||
addb $('a' - '0' - 10), %al
|
||||
ANNOTATE_RETPOLINE_SAFE
|
||||
1: jmp *%rsi
|
||||
SYM_CODE_END(pr_nybble)
|
||||
|
||||
SYM_CODE_START_LOCAL_NOALIGN(pr_qword)
|
||||
UNWIND_HINT_FUNC
|
||||
movq $16, %rcx
|
||||
1: rolq $4, %rbx
|
||||
call pr_nybble
|
||||
loop 1b
|
||||
movb $'\n', %al
|
||||
ANNOTATE_RETPOLINE_SAFE
|
||||
jmp *%rsi
|
||||
SYM_CODE_END(pr_qword)
|
||||
|
||||
.macro print_reg a, b, c, d, r
|
||||
movb $\a, %al
|
||||
ANNOTATE_RETPOLINE_SAFE
|
||||
call *%rsi
|
||||
movb $\b, %al
|
||||
ANNOTATE_RETPOLINE_SAFE
|
||||
call *%rsi
|
||||
movb $\c, %al
|
||||
ANNOTATE_RETPOLINE_SAFE
|
||||
call *%rsi
|
||||
movb $\d, %al
|
||||
ANNOTATE_RETPOLINE_SAFE
|
||||
call *%rsi
|
||||
movq \r, %rbx
|
||||
call pr_qword
|
||||
.endm
|
||||
|
||||
SYM_CODE_START_NOALIGN(kexec_debug_exc_vectors)
|
||||
/* Each of these is 6 bytes. */
|
||||
.macro vec_err exc
|
||||
UNWIND_HINT_ENTRY
|
||||
. = kexec_debug_exc_vectors + (\exc * KEXEC_DEBUG_EXC_HANDLER_SIZE)
|
||||
nop
|
||||
nop
|
||||
pushq $\exc
|
||||
jmp exc_handler
|
||||
.endm
|
||||
|
||||
.macro vec_noerr exc
|
||||
UNWIND_HINT_ENTRY
|
||||
. = kexec_debug_exc_vectors + (\exc * KEXEC_DEBUG_EXC_HANDLER_SIZE)
|
||||
pushq $0
|
||||
pushq $\exc
|
||||
jmp exc_handler
|
||||
.endm
|
||||
|
||||
ANNOTATE_NOENDBR
|
||||
vec_noerr 0 // #DE
|
||||
vec_noerr 1 // #DB
|
||||
vec_noerr 2 // #NMI
|
||||
vec_noerr 3 // #BP
|
||||
vec_noerr 4 // #OF
|
||||
vec_noerr 5 // #BR
|
||||
vec_noerr 6 // #UD
|
||||
vec_noerr 7 // #NM
|
||||
vec_err 8 // #DF
|
||||
vec_noerr 9
|
||||
vec_err 10 // #TS
|
||||
vec_err 11 // #NP
|
||||
vec_err 12 // #SS
|
||||
vec_err 13 // #GP
|
||||
vec_err 14 // #PF
|
||||
vec_noerr 15
|
||||
SYM_CODE_END(kexec_debug_exc_vectors)
|
||||
|
||||
SYM_CODE_START_LOCAL_NOALIGN(exc_handler)
|
||||
/* No need for RET mitigations during kexec */
|
||||
VALIDATE_UNRET_END
|
||||
|
||||
pushq %rax
|
||||
pushq %rbx
|
||||
pushq %rcx
|
||||
pushq %rdx
|
||||
pushq %rsi
|
||||
|
||||
/* Stack frame */
|
||||
#define EXC_SS 0x58 /* Architectural... */
|
||||
#define EXC_RSP 0x50
|
||||
#define EXC_EFLAGS 0x48
|
||||
#define EXC_CS 0x40
|
||||
#define EXC_RIP 0x38
|
||||
#define EXC_ERRORCODE 0x30 /* Either architectural or zero pushed by handler */
|
||||
#define EXC_EXCEPTION 0x28 /* Pushed by handler entry point */
|
||||
#define EXC_RAX 0x20 /* Pushed just above in exc_handler */
|
||||
#define EXC_RBX 0x18
|
||||
#define EXC_RCX 0x10
|
||||
#define EXC_RDX 0x08
|
||||
#define EXC_RSI 0x00
|
||||
|
||||
/* Set up %rdx/%rsi for debug output */
|
||||
pr_setup
|
||||
|
||||
/* rip and exception info */
|
||||
print_reg 'E', 'x', 'c', ':', EXC_EXCEPTION(%rsp)
|
||||
print_reg 'E', 'r', 'r', ':', EXC_ERRORCODE(%rsp)
|
||||
print_reg 'r', 'i', 'p', ':', EXC_RIP(%rsp)
|
||||
print_reg 'r', 's', 'p', ':', EXC_RSP(%rsp)
|
||||
|
||||
/* We spilled these to the stack */
|
||||
print_reg 'r', 'a', 'x', ':', EXC_RAX(%rsp)
|
||||
print_reg 'r', 'b', 'x', ':', EXC_RBX(%rsp)
|
||||
print_reg 'r', 'c', 'x', ':', EXC_RCX(%rsp)
|
||||
print_reg 'r', 'd', 'x', ':', EXC_RDX(%rsp)
|
||||
print_reg 'r', 's', 'i', ':', EXC_RSI(%rsp)
|
||||
|
||||
/* Other registers untouched */
|
||||
print_reg 'r', 'd', 'i', ':', %rdi
|
||||
print_reg 'r', '8', ' ', ':', %r8
|
||||
print_reg 'r', '9', ' ', ':', %r9
|
||||
print_reg 'r', '1', '0', ':', %r10
|
||||
print_reg 'r', '1', '1', ':', %r11
|
||||
print_reg 'r', '1', '2', ':', %r12
|
||||
print_reg 'r', '1', '3', ':', %r13
|
||||
print_reg 'r', '1', '4', ':', %r14
|
||||
print_reg 'r', '1', '5', ':', %r15
|
||||
print_reg 'c', 'r', '2', ':', %cr2
|
||||
|
||||
/* Only return from INT3 */
|
||||
cmpq $3, EXC_EXCEPTION(%rsp)
|
||||
jne .Ldie
|
||||
|
||||
popq %rsi
|
||||
popq %rdx
|
||||
popq %rcx
|
||||
popq %rbx
|
||||
popq %rax
|
||||
|
||||
addq $16, %rsp
|
||||
iretq
|
||||
|
||||
.Ldie:
|
||||
hlt
|
||||
jmp .Ldie
|
||||
|
||||
SYM_CODE_END(exc_handler)
|
||||
|
||||
@ -75,7 +75,7 @@ static void delay_tsc(u64 cycles)
|
||||
|
||||
/* Allow RT tasks to run */
|
||||
preempt_enable();
|
||||
rep_nop();
|
||||
native_pause();
|
||||
preempt_disable();
|
||||
|
||||
/*
|
||||
|
||||
@ -324,6 +324,11 @@ int insn_get_opcode(struct insn *insn)
|
||||
}
|
||||
|
||||
insn->attr = inat_get_opcode_attribute(op);
|
||||
if (insn->x86_64 && inat_is_invalid64(insn->attr)) {
|
||||
/* This instruction is invalid, like UD2. Stop decoding. */
|
||||
insn->attr &= INAT_INV64;
|
||||
}
|
||||
|
||||
while (inat_is_escape(insn->attr)) {
|
||||
/* Get escaped opcode */
|
||||
op = get_next(insn_byte_t, insn);
|
||||
@ -337,6 +342,7 @@ int insn_get_opcode(struct insn *insn)
|
||||
insn->attr = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
end:
|
||||
opcode->got = 1;
|
||||
return 0;
|
||||
@ -658,7 +664,6 @@ int insn_get_immediate(struct insn *insn)
|
||||
}
|
||||
|
||||
if (!inat_has_immediate(insn->attr))
|
||||
/* no immediates */
|
||||
goto done;
|
||||
|
||||
switch (inat_immediate_size(insn->attr)) {
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
static __always_inline void rep_movs(void *to, const void *from, size_t n)
|
||||
{
|
||||
unsigned long d0, d1, d2;
|
||||
asm volatile("rep ; movsl\n\t"
|
||||
asm volatile("rep movsl\n\t"
|
||||
"testb $2,%b4\n\t"
|
||||
"je 1f\n\t"
|
||||
"movsw\n"
|
||||
|
||||
@ -40,8 +40,7 @@ char *strncpy(char *dest, const char *src, size_t count)
|
||||
"stosb\n\t"
|
||||
"testb %%al,%%al\n\t"
|
||||
"jne 1b\n\t"
|
||||
"rep\n\t"
|
||||
"stosb\n"
|
||||
"rep stosb\n"
|
||||
"2:"
|
||||
: "=&S" (d0), "=&D" (d1), "=&c" (d2), "=&a" (d3)
|
||||
: "0" (src), "1" (dest), "2" (count) : "memory");
|
||||
@ -54,8 +53,7 @@ EXPORT_SYMBOL(strncpy);
|
||||
char *strcat(char *dest, const char *src)
|
||||
{
|
||||
int d0, d1, d2, d3;
|
||||
asm volatile("repne\n\t"
|
||||
"scasb\n\t"
|
||||
asm volatile("repne scasb\n\t"
|
||||
"decl %1\n"
|
||||
"1:\tlodsb\n\t"
|
||||
"stosb\n\t"
|
||||
@ -72,8 +70,7 @@ EXPORT_SYMBOL(strcat);
|
||||
char *strncat(char *dest, const char *src, size_t count)
|
||||
{
|
||||
int d0, d1, d2, d3;
|
||||
asm volatile("repne\n\t"
|
||||
"scasb\n\t"
|
||||
asm volatile("repne scasb\n\t"
|
||||
"decl %1\n\t"
|
||||
"movl %8,%3\n"
|
||||
"1:\tdecl %3\n\t"
|
||||
@ -167,8 +164,7 @@ size_t strlen(const char *s)
|
||||
{
|
||||
int d0;
|
||||
size_t res;
|
||||
asm volatile("repne\n\t"
|
||||
"scasb"
|
||||
asm volatile("repne scasb"
|
||||
: "=c" (res), "=&D" (d0)
|
||||
: "1" (s), "a" (0), "0" (0xffffffffu)
|
||||
: "memory");
|
||||
@ -184,8 +180,7 @@ void *memchr(const void *cs, int c, size_t count)
|
||||
void *res;
|
||||
if (!count)
|
||||
return NULL;
|
||||
asm volatile("repne\n\t"
|
||||
"scasb\n\t"
|
||||
asm volatile("repne scasb\n\t"
|
||||
"je 1f\n\t"
|
||||
"movl $1,%0\n"
|
||||
"1:\tdecl %0"
|
||||
@ -202,7 +197,7 @@ void *memscan(void *addr, int c, size_t size)
|
||||
{
|
||||
if (!size)
|
||||
return addr;
|
||||
asm volatile("repnz; scasb\n\t"
|
||||
asm volatile("repnz scasb\n\t"
|
||||
"jnz 1f\n\t"
|
||||
"dec %%edi\n"
|
||||
"1:"
|
||||
|
||||
@ -8,16 +8,14 @@ int d0, d1;
|
||||
register char *__res;
|
||||
__asm__ __volatile__(
|
||||
"movl %6,%%edi\n\t"
|
||||
"repne\n\t"
|
||||
"scasb\n\t"
|
||||
"repne scasb\n\t"
|
||||
"notl %%ecx\n\t"
|
||||
"decl %%ecx\n\t" /* NOTE! This also sets Z if searchstring='' */
|
||||
"movl %%ecx,%%edx\n"
|
||||
"1:\tmovl %6,%%edi\n\t"
|
||||
"movl %%esi,%%eax\n\t"
|
||||
"movl %%edx,%%ecx\n\t"
|
||||
"repe\n\t"
|
||||
"cmpsb\n\t"
|
||||
"repe cmpsb\n\t"
|
||||
"je 2f\n\t" /* also works for empty string, see above */
|
||||
"xchgl %%eax,%%esi\n\t"
|
||||
"incl %%esi\n\t"
|
||||
|
||||
@ -38,9 +38,9 @@ do { \
|
||||
might_fault(); \
|
||||
__asm__ __volatile__( \
|
||||
ASM_STAC "\n" \
|
||||
"0: rep; stosl\n" \
|
||||
"0: rep stosl\n" \
|
||||
" movl %2,%0\n" \
|
||||
"1: rep; stosb\n" \
|
||||
"1: rep stosb\n" \
|
||||
"2: " ASM_CLAC "\n" \
|
||||
_ASM_EXTABLE_TYPE_REG(0b, 2b, EX_TYPE_UCOPY_LEN4, %2) \
|
||||
_ASM_EXTABLE_UA(1b, 2b) \
|
||||
@ -140,9 +140,9 @@ __copy_user_intel(void __user *to, const void *from, unsigned long size)
|
||||
" shrl $2, %0\n"
|
||||
" andl $3, %%eax\n"
|
||||
" cld\n"
|
||||
"99: rep; movsl\n"
|
||||
"99: rep movsl\n"
|
||||
"36: movl %%eax, %0\n"
|
||||
"37: rep; movsb\n"
|
||||
"37: rep movsb\n"
|
||||
"100:\n"
|
||||
_ASM_EXTABLE_UA(1b, 100b)
|
||||
_ASM_EXTABLE_UA(2b, 100b)
|
||||
@ -242,9 +242,9 @@ static unsigned long __copy_user_intel_nocache(void *to,
|
||||
" shrl $2, %0\n"
|
||||
" andl $3, %%eax\n"
|
||||
" cld\n"
|
||||
"6: rep; movsl\n"
|
||||
"6: rep movsl\n"
|
||||
" movl %%eax,%0\n"
|
||||
"7: rep; movsb\n"
|
||||
"7: rep movsb\n"
|
||||
"8:\n"
|
||||
_ASM_EXTABLE_UA(0b, 8b)
|
||||
_ASM_EXTABLE_UA(1b, 8b)
|
||||
@ -293,14 +293,14 @@ do { \
|
||||
" negl %0\n" \
|
||||
" andl $7,%0\n" \
|
||||
" subl %0,%3\n" \
|
||||
"4: rep; movsb\n" \
|
||||
"4: rep movsb\n" \
|
||||
" movl %3,%0\n" \
|
||||
" shrl $2,%0\n" \
|
||||
" andl $3,%3\n" \
|
||||
" .align 2,0x90\n" \
|
||||
"0: rep; movsl\n" \
|
||||
"0: rep movsl\n" \
|
||||
" movl %3,%0\n" \
|
||||
"1: rep; movsb\n" \
|
||||
"1: rep movsb\n" \
|
||||
"2:\n" \
|
||||
_ASM_EXTABLE_TYPE_REG(4b, 2b, EX_TYPE_UCOPY_LEN1, %3) \
|
||||
_ASM_EXTABLE_TYPE_REG(0b, 2b, EX_TYPE_UCOPY_LEN4, %3) \
|
||||
|
||||
@ -35,7 +35,7 @@
|
||||
# - (!F3) : the last prefix is not 0xF3 (including non-last prefix case)
|
||||
# - (66&F2): Both 0x66 and 0xF2 prefixes are specified.
|
||||
#
|
||||
# REX2 Prefix
|
||||
# REX2 Prefix Superscripts
|
||||
# - (!REX2): REX2 is not allowed
|
||||
# - (REX2): REX2 variant e.g. JMPABS
|
||||
|
||||
@ -147,7 +147,7 @@ AVXcode:
|
||||
# 0x60 - 0x6f
|
||||
60: PUSHA/PUSHAD (i64)
|
||||
61: POPA/POPAD (i64)
|
||||
62: BOUND Gv,Ma (i64) | EVEX (Prefix)
|
||||
62: BOUND Gv,Ma (i64) | EVEX (Prefix),(o64)
|
||||
63: ARPL Ew,Gw (i64) | MOVSXD Gv,Ev (o64)
|
||||
64: SEG=FS (Prefix)
|
||||
65: SEG=GS (Prefix)
|
||||
@ -253,8 +253,8 @@ c0: Grp2 Eb,Ib (1A)
|
||||
c1: Grp2 Ev,Ib (1A)
|
||||
c2: RETN Iw (f64)
|
||||
c3: RETN
|
||||
c4: LES Gz,Mp (i64) | VEX+2byte (Prefix)
|
||||
c5: LDS Gz,Mp (i64) | VEX+1byte (Prefix)
|
||||
c4: LES Gz,Mp (i64) | VEX+2byte (Prefix),(o64)
|
||||
c5: LDS Gz,Mp (i64) | VEX+1byte (Prefix),(o64)
|
||||
c6: Grp11A Eb,Ib (1A)
|
||||
c7: Grp11B Ev,Iz (1A)
|
||||
c8: ENTER Iw,Ib
|
||||
@ -286,10 +286,10 @@ df: ESC
|
||||
# Note: "forced64" is Intel CPU behavior: they ignore 0x66 prefix
|
||||
# in 64-bit mode. AMD CPUs accept 0x66 prefix, it causes RIP truncation
|
||||
# to 16 bits. In 32-bit mode, 0x66 is accepted by both Intel and AMD.
|
||||
e0: LOOPNE/LOOPNZ Jb (f64) (!REX2)
|
||||
e1: LOOPE/LOOPZ Jb (f64) (!REX2)
|
||||
e2: LOOP Jb (f64) (!REX2)
|
||||
e3: JrCXZ Jb (f64) (!REX2)
|
||||
e0: LOOPNE/LOOPNZ Jb (f64),(!REX2)
|
||||
e1: LOOPE/LOOPZ Jb (f64),(!REX2)
|
||||
e2: LOOP Jb (f64),(!REX2)
|
||||
e3: JrCXZ Jb (f64),(!REX2)
|
||||
e4: IN AL,Ib (!REX2)
|
||||
e5: IN eAX,Ib (!REX2)
|
||||
e6: OUT Ib,AL (!REX2)
|
||||
@ -298,10 +298,10 @@ e7: OUT Ib,eAX (!REX2)
|
||||
# in "near" jumps and calls is 16-bit. For CALL,
|
||||
# push of return address is 16-bit wide, RSP is decremented by 2
|
||||
# but is not truncated to 16 bits, unlike RIP.
|
||||
e8: CALL Jz (f64) (!REX2)
|
||||
e9: JMP-near Jz (f64) (!REX2)
|
||||
ea: JMP-far Ap (i64) (!REX2)
|
||||
eb: JMP-short Jb (f64) (!REX2)
|
||||
e8: CALL Jz (f64),(!REX2)
|
||||
e9: JMP-near Jz (f64),(!REX2)
|
||||
ea: JMP-far Ap (i64),(!REX2)
|
||||
eb: JMP-short Jb (f64),(!REX2)
|
||||
ec: IN AL,DX (!REX2)
|
||||
ed: IN eAX,DX (!REX2)
|
||||
ee: OUT DX,AL (!REX2)
|
||||
@ -478,22 +478,22 @@ AVXcode: 1
|
||||
7f: movq Qq,Pq | vmovdqa Wx,Vx (66) | vmovdqa32/64 Wx,Vx (66),(evo) | vmovdqu Wx,Vx (F3) | vmovdqu32/64 Wx,Vx (F3),(evo) | vmovdqu8/16 Wx,Vx (F2),(ev)
|
||||
# 0x0f 0x80-0x8f
|
||||
# Note: "forced64" is Intel CPU behavior (see comment about CALL insn).
|
||||
80: JO Jz (f64) (!REX2)
|
||||
81: JNO Jz (f64) (!REX2)
|
||||
82: JB/JC/JNAE Jz (f64) (!REX2)
|
||||
83: JAE/JNB/JNC Jz (f64) (!REX2)
|
||||
84: JE/JZ Jz (f64) (!REX2)
|
||||
85: JNE/JNZ Jz (f64) (!REX2)
|
||||
86: JBE/JNA Jz (f64) (!REX2)
|
||||
87: JA/JNBE Jz (f64) (!REX2)
|
||||
88: JS Jz (f64) (!REX2)
|
||||
89: JNS Jz (f64) (!REX2)
|
||||
8a: JP/JPE Jz (f64) (!REX2)
|
||||
8b: JNP/JPO Jz (f64) (!REX2)
|
||||
8c: JL/JNGE Jz (f64) (!REX2)
|
||||
8d: JNL/JGE Jz (f64) (!REX2)
|
||||
8e: JLE/JNG Jz (f64) (!REX2)
|
||||
8f: JNLE/JG Jz (f64) (!REX2)
|
||||
80: JO Jz (f64),(!REX2)
|
||||
81: JNO Jz (f64),(!REX2)
|
||||
82: JB/JC/JNAE Jz (f64),(!REX2)
|
||||
83: JAE/JNB/JNC Jz (f64),(!REX2)
|
||||
84: JE/JZ Jz (f64),(!REX2)
|
||||
85: JNE/JNZ Jz (f64),(!REX2)
|
||||
86: JBE/JNA Jz (f64),(!REX2)
|
||||
87: JA/JNBE Jz (f64),(!REX2)
|
||||
88: JS Jz (f64),(!REX2)
|
||||
89: JNS Jz (f64),(!REX2)
|
||||
8a: JP/JPE Jz (f64),(!REX2)
|
||||
8b: JNP/JPO Jz (f64),(!REX2)
|
||||
8c: JL/JNGE Jz (f64),(!REX2)
|
||||
8d: JNL/JGE Jz (f64),(!REX2)
|
||||
8e: JLE/JNG Jz (f64),(!REX2)
|
||||
8f: JNLE/JG Jz (f64),(!REX2)
|
||||
# 0x0f 0x90-0x9f
|
||||
90: SETO Eb | kmovw/q Vk,Wk | kmovb/d Vk,Wk (66)
|
||||
91: SETNO Eb | kmovw/q Mv,Vk | kmovb/d Mv,Vk (66)
|
||||
|
||||
@ -87,8 +87,7 @@ SYM_CODE_START(pvh_start_xen)
|
||||
mov %ebx, %esi
|
||||
movl rva(pvh_start_info_sz)(%ebp), %ecx
|
||||
shr $2,%ecx
|
||||
rep
|
||||
movsl
|
||||
rep movsl
|
||||
|
||||
leal rva(early_stack_end)(%ebp), %esp
|
||||
|
||||
|
||||
@ -69,8 +69,7 @@ copy_loop:
|
||||
movl pbe_orig_address(%edx), %edi
|
||||
|
||||
movl $(PAGE_SIZE >> 2), %ecx
|
||||
rep
|
||||
movsl
|
||||
rep movsl
|
||||
|
||||
movl pbe_next(%edx), %edx
|
||||
jmp copy_loop
|
||||
|
||||
@ -138,8 +138,7 @@ SYM_FUNC_START(core_restore_code)
|
||||
movq pbe_address(%rdx), %rsi
|
||||
movq pbe_orig_address(%rdx), %rdi
|
||||
movq $(PAGE_SIZE >> 3), %rcx
|
||||
rep
|
||||
movsq
|
||||
rep movsq
|
||||
|
||||
/* progress to the next pbe */
|
||||
movq pbe_next(%rdx), %rdx
|
||||
|
||||
@ -64,6 +64,8 @@ BEGIN {
|
||||
|
||||
modrm_expr = "^([CDEGMNPQRSUVW/][a-z]+|NTA|T[012])"
|
||||
force64_expr = "\\([df]64\\)"
|
||||
invalid64_expr = "\\(i64\\)"
|
||||
only64_expr = "\\(o64\\)"
|
||||
rex_expr = "^((REX(\\.[XRWB]+)+)|(REX$))"
|
||||
rex2_expr = "\\(REX2\\)"
|
||||
no_rex2_expr = "\\(!REX2\\)"
|
||||
@ -319,6 +321,11 @@ function convert_operands(count,opnd, i,j,imm,mod)
|
||||
if (match(ext, force64_expr))
|
||||
flags = add_flags(flags, "INAT_FORCE64")
|
||||
|
||||
# check invalid in 64-bit (and no only64)
|
||||
if (match(ext, invalid64_expr) &&
|
||||
!match($0, only64_expr))
|
||||
flags = add_flags(flags, "INAT_INV64")
|
||||
|
||||
# check REX2 not allowed
|
||||
if (match(ext, no_rex2_expr))
|
||||
flags = add_flags(flags, "INAT_NO_REX2")
|
||||
|
||||
@ -82,6 +82,7 @@
|
||||
#define INAT_NO_REX2 (1 << (INAT_FLAG_OFFS + 8))
|
||||
#define INAT_REX2_VARIANT (1 << (INAT_FLAG_OFFS + 9))
|
||||
#define INAT_EVEX_SCALABLE (1 << (INAT_FLAG_OFFS + 10))
|
||||
#define INAT_INV64 (1 << (INAT_FLAG_OFFS + 11))
|
||||
/* Attribute making macros for attribute tables */
|
||||
#define INAT_MAKE_PREFIX(pfx) (pfx << INAT_PFX_OFFS)
|
||||
#define INAT_MAKE_ESCAPE(esc) (esc << INAT_ESC_OFFS)
|
||||
@ -242,4 +243,9 @@ static inline int inat_evex_scalable(insn_attr_t attr)
|
||||
{
|
||||
return attr & INAT_EVEX_SCALABLE;
|
||||
}
|
||||
|
||||
static inline int inat_is_invalid64(insn_attr_t attr)
|
||||
{
|
||||
return attr & INAT_INV64;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -324,6 +324,11 @@ int insn_get_opcode(struct insn *insn)
|
||||
}
|
||||
|
||||
insn->attr = inat_get_opcode_attribute(op);
|
||||
if (insn->x86_64 && inat_is_invalid64(insn->attr)) {
|
||||
/* This instruction is invalid, like UD2. Stop decoding. */
|
||||
insn->attr &= INAT_INV64;
|
||||
}
|
||||
|
||||
while (inat_is_escape(insn->attr)) {
|
||||
/* Get escaped opcode */
|
||||
op = get_next(insn_byte_t, insn);
|
||||
@ -337,6 +342,7 @@ int insn_get_opcode(struct insn *insn)
|
||||
insn->attr = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
end:
|
||||
opcode->got = 1;
|
||||
return 0;
|
||||
@ -658,7 +664,6 @@ int insn_get_immediate(struct insn *insn)
|
||||
}
|
||||
|
||||
if (!inat_has_immediate(insn->attr))
|
||||
/* no immediates */
|
||||
goto done;
|
||||
|
||||
switch (inat_immediate_size(insn->attr)) {
|
||||
|
||||
@ -35,7 +35,7 @@
|
||||
# - (!F3) : the last prefix is not 0xF3 (including non-last prefix case)
|
||||
# - (66&F2): Both 0x66 and 0xF2 prefixes are specified.
|
||||
#
|
||||
# REX2 Prefix
|
||||
# REX2 Prefix Superscripts
|
||||
# - (!REX2): REX2 is not allowed
|
||||
# - (REX2): REX2 variant e.g. JMPABS
|
||||
|
||||
@ -147,7 +147,7 @@ AVXcode:
|
||||
# 0x60 - 0x6f
|
||||
60: PUSHA/PUSHAD (i64)
|
||||
61: POPA/POPAD (i64)
|
||||
62: BOUND Gv,Ma (i64) | EVEX (Prefix)
|
||||
62: BOUND Gv,Ma (i64) | EVEX (Prefix),(o64)
|
||||
63: ARPL Ew,Gw (i64) | MOVSXD Gv,Ev (o64)
|
||||
64: SEG=FS (Prefix)
|
||||
65: SEG=GS (Prefix)
|
||||
@ -253,8 +253,8 @@ c0: Grp2 Eb,Ib (1A)
|
||||
c1: Grp2 Ev,Ib (1A)
|
||||
c2: RETN Iw (f64)
|
||||
c3: RETN
|
||||
c4: LES Gz,Mp (i64) | VEX+2byte (Prefix)
|
||||
c5: LDS Gz,Mp (i64) | VEX+1byte (Prefix)
|
||||
c4: LES Gz,Mp (i64) | VEX+2byte (Prefix),(o64)
|
||||
c5: LDS Gz,Mp (i64) | VEX+1byte (Prefix),(o64)
|
||||
c6: Grp11A Eb,Ib (1A)
|
||||
c7: Grp11B Ev,Iz (1A)
|
||||
c8: ENTER Iw,Ib
|
||||
@ -286,10 +286,10 @@ df: ESC
|
||||
# Note: "forced64" is Intel CPU behavior: they ignore 0x66 prefix
|
||||
# in 64-bit mode. AMD CPUs accept 0x66 prefix, it causes RIP truncation
|
||||
# to 16 bits. In 32-bit mode, 0x66 is accepted by both Intel and AMD.
|
||||
e0: LOOPNE/LOOPNZ Jb (f64) (!REX2)
|
||||
e1: LOOPE/LOOPZ Jb (f64) (!REX2)
|
||||
e2: LOOP Jb (f64) (!REX2)
|
||||
e3: JrCXZ Jb (f64) (!REX2)
|
||||
e0: LOOPNE/LOOPNZ Jb (f64),(!REX2)
|
||||
e1: LOOPE/LOOPZ Jb (f64),(!REX2)
|
||||
e2: LOOP Jb (f64),(!REX2)
|
||||
e3: JrCXZ Jb (f64),(!REX2)
|
||||
e4: IN AL,Ib (!REX2)
|
||||
e5: IN eAX,Ib (!REX2)
|
||||
e6: OUT Ib,AL (!REX2)
|
||||
@ -298,10 +298,10 @@ e7: OUT Ib,eAX (!REX2)
|
||||
# in "near" jumps and calls is 16-bit. For CALL,
|
||||
# push of return address is 16-bit wide, RSP is decremented by 2
|
||||
# but is not truncated to 16 bits, unlike RIP.
|
||||
e8: CALL Jz (f64) (!REX2)
|
||||
e9: JMP-near Jz (f64) (!REX2)
|
||||
ea: JMP-far Ap (i64) (!REX2)
|
||||
eb: JMP-short Jb (f64) (!REX2)
|
||||
e8: CALL Jz (f64),(!REX2)
|
||||
e9: JMP-near Jz (f64),(!REX2)
|
||||
ea: JMP-far Ap (i64),(!REX2)
|
||||
eb: JMP-short Jb (f64),(!REX2)
|
||||
ec: IN AL,DX (!REX2)
|
||||
ed: IN eAX,DX (!REX2)
|
||||
ee: OUT DX,AL (!REX2)
|
||||
@ -478,22 +478,22 @@ AVXcode: 1
|
||||
7f: movq Qq,Pq | vmovdqa Wx,Vx (66) | vmovdqa32/64 Wx,Vx (66),(evo) | vmovdqu Wx,Vx (F3) | vmovdqu32/64 Wx,Vx (F3),(evo) | vmovdqu8/16 Wx,Vx (F2),(ev)
|
||||
# 0x0f 0x80-0x8f
|
||||
# Note: "forced64" is Intel CPU behavior (see comment about CALL insn).
|
||||
80: JO Jz (f64) (!REX2)
|
||||
81: JNO Jz (f64) (!REX2)
|
||||
82: JB/JC/JNAE Jz (f64) (!REX2)
|
||||
83: JAE/JNB/JNC Jz (f64) (!REX2)
|
||||
84: JE/JZ Jz (f64) (!REX2)
|
||||
85: JNE/JNZ Jz (f64) (!REX2)
|
||||
86: JBE/JNA Jz (f64) (!REX2)
|
||||
87: JA/JNBE Jz (f64) (!REX2)
|
||||
88: JS Jz (f64) (!REX2)
|
||||
89: JNS Jz (f64) (!REX2)
|
||||
8a: JP/JPE Jz (f64) (!REX2)
|
||||
8b: JNP/JPO Jz (f64) (!REX2)
|
||||
8c: JL/JNGE Jz (f64) (!REX2)
|
||||
8d: JNL/JGE Jz (f64) (!REX2)
|
||||
8e: JLE/JNG Jz (f64) (!REX2)
|
||||
8f: JNLE/JG Jz (f64) (!REX2)
|
||||
80: JO Jz (f64),(!REX2)
|
||||
81: JNO Jz (f64),(!REX2)
|
||||
82: JB/JC/JNAE Jz (f64),(!REX2)
|
||||
83: JAE/JNB/JNC Jz (f64),(!REX2)
|
||||
84: JE/JZ Jz (f64),(!REX2)
|
||||
85: JNE/JNZ Jz (f64),(!REX2)
|
||||
86: JBE/JNA Jz (f64),(!REX2)
|
||||
87: JA/JNBE Jz (f64),(!REX2)
|
||||
88: JS Jz (f64),(!REX2)
|
||||
89: JNS Jz (f64),(!REX2)
|
||||
8a: JP/JPE Jz (f64),(!REX2)
|
||||
8b: JNP/JPO Jz (f64),(!REX2)
|
||||
8c: JL/JNGE Jz (f64),(!REX2)
|
||||
8d: JNL/JGE Jz (f64),(!REX2)
|
||||
8e: JLE/JNG Jz (f64),(!REX2)
|
||||
8f: JNLE/JG Jz (f64),(!REX2)
|
||||
# 0x0f 0x90-0x9f
|
||||
90: SETO Eb | kmovw/q Vk,Wk | kmovb/d Vk,Wk (66)
|
||||
91: SETNO Eb | kmovw/q Mv,Vk | kmovb/d Mv,Vk (66)
|
||||
|
||||
@ -64,6 +64,8 @@ BEGIN {
|
||||
|
||||
modrm_expr = "^([CDEGMNPQRSUVW/][a-z]+|NTA|T[012])"
|
||||
force64_expr = "\\([df]64\\)"
|
||||
invalid64_expr = "\\(i64\\)"
|
||||
only64_expr = "\\(o64\\)"
|
||||
rex_expr = "^((REX(\\.[XRWB]+)+)|(REX$))"
|
||||
rex2_expr = "\\(REX2\\)"
|
||||
no_rex2_expr = "\\(!REX2\\)"
|
||||
@ -319,6 +321,11 @@ function convert_operands(count,opnd, i,j,imm,mod)
|
||||
if (match(ext, force64_expr))
|
||||
flags = add_flags(flags, "INAT_FORCE64")
|
||||
|
||||
# check invalid in 64-bit (and no only64)
|
||||
if (match(ext, invalid64_expr) &&
|
||||
!match($0, only64_expr))
|
||||
flags = add_flags(flags, "INAT_INV64")
|
||||
|
||||
# check REX2 not allowed
|
||||
if (match(ext, no_rex2_expr))
|
||||
flags = add_flags(flags, "INAT_NO_REX2")
|
||||
|
||||
@ -8,6 +8,13 @@ ifeq ($(ARCH_PROCESSED),$(filter $(ARCH_PROCESSED),x86 ppc64le))
|
||||
TEST_PROGS := test_kexec_load.sh test_kexec_file_load.sh
|
||||
TEST_FILES := kexec_common_lib.sh
|
||||
|
||||
include ../../../scripts/Makefile.arch
|
||||
|
||||
ifeq ($(IS_64_BIT)$(ARCH_PROCESSED),1x86)
|
||||
TEST_PROGS += test_kexec_jump.sh
|
||||
test_kexec_jump.sh: $(OUTPUT)/test_kexec_jump
|
||||
endif
|
||||
|
||||
include ../lib.mk
|
||||
|
||||
endif
|
||||
|
||||
72
tools/testing/selftests/kexec/test_kexec_jump.c
Normal file
72
tools/testing/selftests/kexec/test_kexec_jump.c
Normal file
@ -0,0 +1,72 @@
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <linux/kexec.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
asm(
|
||||
" .code64\n"
|
||||
" .data\n"
|
||||
"purgatory_start:\n"
|
||||
|
||||
// Trigger kexec debug exception handling
|
||||
" int3\n"
|
||||
|
||||
// Set load address for next time
|
||||
" leaq purgatory_start_b(%rip), %r11\n"
|
||||
" movq %r11, 8(%rsp)\n"
|
||||
|
||||
// Back to Linux
|
||||
" ret\n"
|
||||
|
||||
// Same again
|
||||
"purgatory_start_b:\n"
|
||||
|
||||
// Trigger kexec debug exception handling
|
||||
" int3\n"
|
||||
|
||||
// Set load address for next time
|
||||
" leaq purgatory_start(%rip), %r11\n"
|
||||
" movq %r11, 8(%rsp)\n"
|
||||
|
||||
// Back to Linux
|
||||
" ret\n"
|
||||
|
||||
"purgatory_end:\n"
|
||||
".previous"
|
||||
);
|
||||
extern char purgatory_start[], purgatory_end[];
|
||||
|
||||
int main (void)
|
||||
{
|
||||
struct kexec_segment segment = {};
|
||||
int ret;
|
||||
|
||||
segment.buf = purgatory_start;
|
||||
segment.bufsz = purgatory_end - purgatory_start;
|
||||
segment.mem = (void *)0x400000;
|
||||
segment.memsz = 0x1000;
|
||||
ret = syscall(__NR_kexec_load, 0x400000, 1, &segment, KEXEC_PRESERVE_CONTEXT);
|
||||
if (ret) {
|
||||
perror("kexec_load");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_KEXEC);
|
||||
if (ret) {
|
||||
perror("kexec reboot");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_KEXEC);
|
||||
if (ret) {
|
||||
perror("kexec reboot");
|
||||
exit(1);
|
||||
}
|
||||
printf("Success\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
42
tools/testing/selftests/kexec/test_kexec_jump.sh
Executable file
42
tools/testing/selftests/kexec/test_kexec_jump.sh
Executable file
@ -0,0 +1,42 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Prevent loading a kernel image via the kexec_load syscall when
|
||||
# signatures are required. (Dependent on CONFIG_IMA_ARCH_POLICY.)
|
||||
|
||||
TEST="$0"
|
||||
. ./kexec_common_lib.sh
|
||||
|
||||
# kexec requires root privileges
|
||||
require_root_privileges
|
||||
|
||||
# get the kernel config
|
||||
get_kconfig
|
||||
|
||||
kconfig_enabled "CONFIG_KEXEC_JUMP=y" "kexec_jump is enabled"
|
||||
if [ $? -eq 0 ]; then
|
||||
log_skip "kexec_jump is not enabled"
|
||||
fi
|
||||
|
||||
kconfig_enabled "CONFIG_IMA_APPRAISE=y" "IMA enabled"
|
||||
ima_appraise=$?
|
||||
|
||||
kconfig_enabled "CONFIG_IMA_ARCH_POLICY=y" \
|
||||
"IMA architecture specific policy enabled"
|
||||
arch_policy=$?
|
||||
|
||||
get_secureboot_mode
|
||||
secureboot=$?
|
||||
|
||||
if [ $secureboot -eq 1 ] && [ $arch_policy -eq 1 ]; then
|
||||
log_skip "Secure boot and CONFIG_IMA_ARCH_POLICY are enabled"
|
||||
fi
|
||||
|
||||
./test_kexec_jump
|
||||
if [ $? -eq 0 ]; then
|
||||
log_pass "kexec_jump succeeded"
|
||||
else
|
||||
# The more likely failure mode if anything went wrong is that the
|
||||
# kernel just crashes. But if we get back here, sure, whine anyway.
|
||||
log_fail "kexec_jump failed"
|
||||
fi
|
||||
Loading…
Reference in New Issue
Block a user