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:
Ingo Molnar 2025-05-13 10:35:00 +02:00
commit fa6b90ee4f
36 changed files with 588 additions and 172 deletions

@ -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

@ -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;
}

@ -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