Merge c891e98ab3 ("Merge tag 'smp-core-2023-10-29-v2' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip") into android-mainline
Steps on the way to 6.7-rc1 Change-Id: I7aaf8c98ad815312460cdfc4733ad8907087a4ab Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
@@ -1897,6 +1897,12 @@
|
||||
0 -- machine default
|
||||
1 -- force brightness inversion
|
||||
|
||||
ia32_emulation= [X86-64]
|
||||
Format: <bool>
|
||||
When true, allows loading 32-bit programs and executing 32-bit
|
||||
syscalls, essentially overriding IA32_EMULATION_DEFAULT_DISABLED at
|
||||
boot time. When false, unconditionally disables IA32 emulation.
|
||||
|
||||
icn= [HW,ISDN]
|
||||
Format: <io>[,<membase>[,<icn_id>[,<icn_id2>]]]
|
||||
|
||||
|
||||
@@ -130,4 +130,4 @@ SNP feature support.
|
||||
|
||||
More details in AMD64 APM[1] Vol 2: 15.34.10 SEV_STATUS MSR
|
||||
|
||||
[1] https://www.amd.com/system/files/TechDocs/40332.pdf
|
||||
[1] https://www.amd.com/content/dam/amd/en/documents/processor-tech-docs/programmer-references/24593.pdf
|
||||
|
||||
@@ -5,7 +5,7 @@ x86 IOMMU Support
|
||||
The architecture specs can be obtained from the below locations.
|
||||
|
||||
- Intel: http://www.intel.com/content/dam/www/public/us/en/documents/product-specifications/vt-directed-io-spec.pdf
|
||||
- AMD: https://www.amd.com/system/files/TechDocs/48882_IOMMU.pdf
|
||||
- AMD: https://www.amd.com/content/dam/amd/en/documents/processor-tech-docs/specifications/48882_3_07_PUB.pdf
|
||||
|
||||
This guide gives a quick cheat sheet for some basic understanding.
|
||||
|
||||
|
||||
@@ -2955,6 +2955,15 @@ config IA32_EMULATION
|
||||
64-bit kernel. You should likely turn this on, unless you're
|
||||
100% sure that you don't have any 32-bit programs left.
|
||||
|
||||
config IA32_EMULATION_DEFAULT_DISABLED
|
||||
bool "IA32 emulation disabled by default"
|
||||
default n
|
||||
depends on IA32_EMULATION
|
||||
help
|
||||
Make IA32 emulation disabled by default. This prevents loading 32-bit
|
||||
processes and access to 32-bit syscalls. If unsure, leave it to its
|
||||
default value.
|
||||
|
||||
config X86_X32_ABI
|
||||
bool "x32 ABI for 64-bit mode"
|
||||
depends on X86_64
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ endif
|
||||
|
||||
# How to compile the 16-bit code. Note we always compile for -march=i386;
|
||||
# that way we can complain to the user if the CPU is insufficient.
|
||||
REALMODE_CFLAGS := -m16 -g -Os -DDISABLE_BRANCH_PROFILING -D__DISABLE_EXPORTS \
|
||||
REALMODE_CFLAGS := -std=gnu11 -m16 -g -Os -DDISABLE_BRANCH_PROFILING -D__DISABLE_EXPORTS \
|
||||
-Wall -Wstrict-prototypes -march=i386 -mregparm=3 \
|
||||
-fno-strict-aliasing -fomit-frame-pointer -fno-pic \
|
||||
-mno-mmx -mno-sse $(call cc-option,-fcf-protection=none)
|
||||
|
||||
@@ -89,7 +89,7 @@ $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
|
||||
|
||||
SETUP_OBJS = $(addprefix $(obj)/,$(setup-y))
|
||||
|
||||
sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [a-zA-Z] \(startup_32\|startup_64\|efi32_stub_entry\|efi64_stub_entry\|efi_pe_entry\|efi32_pe_entry\|input_data\|kernel_info\|_end\|_ehead\|_text\|z_.*\)$$/\#define ZO_\2 0x\1/p'
|
||||
sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [a-zA-Z] \(startup_32\|efi.._stub_entry\|efi\(32\)\?_pe_entry\|input_data\|kernel_info\|_end\|_ehead\|_text\|_e\?data\|z_.*\)$$/\#define ZO_\2 0x\1/p'
|
||||
|
||||
quiet_cmd_zoffset = ZOFFSET $@
|
||||
cmd_zoffset = $(NM) $< | sed -n $(sed-zoffset) > $@
|
||||
|
||||
@@ -30,13 +30,13 @@ __efi_get_rsdp_addr(unsigned long cfg_tbl_pa, unsigned int cfg_tbl_len)
|
||||
* Search EFI system tables for RSDP. Preferred is ACPI_20_TABLE_GUID to
|
||||
* ACPI_TABLE_GUID because it has more features.
|
||||
*/
|
||||
rsdp_addr = efi_find_vendor_table(boot_params, cfg_tbl_pa, cfg_tbl_len,
|
||||
rsdp_addr = efi_find_vendor_table(boot_params_ptr, cfg_tbl_pa, cfg_tbl_len,
|
||||
ACPI_20_TABLE_GUID);
|
||||
if (rsdp_addr)
|
||||
return (acpi_physical_address)rsdp_addr;
|
||||
|
||||
/* No ACPI_20_TABLE_GUID found, fallback to ACPI_TABLE_GUID. */
|
||||
rsdp_addr = efi_find_vendor_table(boot_params, cfg_tbl_pa, cfg_tbl_len,
|
||||
rsdp_addr = efi_find_vendor_table(boot_params_ptr, cfg_tbl_pa, cfg_tbl_len,
|
||||
ACPI_TABLE_GUID);
|
||||
if (rsdp_addr)
|
||||
return (acpi_physical_address)rsdp_addr;
|
||||
@@ -56,15 +56,15 @@ static acpi_physical_address efi_get_rsdp_addr(void)
|
||||
enum efi_type et;
|
||||
int ret;
|
||||
|
||||
et = efi_get_type(boot_params);
|
||||
et = efi_get_type(boot_params_ptr);
|
||||
if (et == EFI_TYPE_NONE)
|
||||
return 0;
|
||||
|
||||
systab_pa = efi_get_system_table(boot_params);
|
||||
systab_pa = efi_get_system_table(boot_params_ptr);
|
||||
if (!systab_pa)
|
||||
error("EFI support advertised, but unable to locate system table.");
|
||||
|
||||
ret = efi_get_conf_table(boot_params, &cfg_tbl_pa, &cfg_tbl_len);
|
||||
ret = efi_get_conf_table(boot_params_ptr, &cfg_tbl_pa, &cfg_tbl_len);
|
||||
if (ret || !cfg_tbl_pa)
|
||||
error("EFI config table not found.");
|
||||
|
||||
@@ -156,7 +156,7 @@ acpi_physical_address get_rsdp_addr(void)
|
||||
{
|
||||
acpi_physical_address pa;
|
||||
|
||||
pa = boot_params->acpi_rsdp_addr;
|
||||
pa = boot_params_ptr->acpi_rsdp_addr;
|
||||
|
||||
if (!pa)
|
||||
pa = efi_get_rsdp_addr();
|
||||
@@ -210,7 +210,7 @@ static unsigned long get_acpi_srat_table(void)
|
||||
rsdp = (struct acpi_table_rsdp *)get_cmdline_acpi_rsdp();
|
||||
if (!rsdp)
|
||||
rsdp = (struct acpi_table_rsdp *)(long)
|
||||
boot_params->acpi_rsdp_addr;
|
||||
boot_params_ptr->acpi_rsdp_addr;
|
||||
|
||||
if (!rsdp)
|
||||
return 0;
|
||||
|
||||
@@ -14,9 +14,9 @@ static inline char rdfs8(addr_t addr)
|
||||
#include "../cmdline.c"
|
||||
unsigned long get_cmd_line_ptr(void)
|
||||
{
|
||||
unsigned long cmd_line_ptr = boot_params->hdr.cmd_line_ptr;
|
||||
unsigned long cmd_line_ptr = boot_params_ptr->hdr.cmd_line_ptr;
|
||||
|
||||
cmd_line_ptr |= (u64)boot_params->ext_cmd_line_ptr << 32;
|
||||
cmd_line_ptr |= (u64)boot_params_ptr->ext_cmd_line_ptr << 32;
|
||||
|
||||
return cmd_line_ptr;
|
||||
}
|
||||
|
||||
@@ -159,8 +159,9 @@ void initialize_identity_maps(void *rmode)
|
||||
* or does not touch all the pages covering them.
|
||||
*/
|
||||
kernel_add_identity_map((unsigned long)_head, (unsigned long)_end);
|
||||
boot_params = rmode;
|
||||
kernel_add_identity_map((unsigned long)boot_params, (unsigned long)(boot_params + 1));
|
||||
boot_params_ptr = rmode;
|
||||
kernel_add_identity_map((unsigned long)boot_params_ptr,
|
||||
(unsigned long)(boot_params_ptr + 1));
|
||||
cmdline = get_cmd_line_ptr();
|
||||
kernel_add_identity_map(cmdline, cmdline + COMMAND_LINE_SIZE);
|
||||
|
||||
@@ -168,7 +169,7 @@ void initialize_identity_maps(void *rmode)
|
||||
* Also map the setup_data entries passed via boot_params in case they
|
||||
* need to be accessed by uncompressed kernel via the identity mapping.
|
||||
*/
|
||||
sd = (struct setup_data *)boot_params->hdr.setup_data;
|
||||
sd = (struct setup_data *)boot_params_ptr->hdr.setup_data;
|
||||
while (sd) {
|
||||
unsigned long sd_addr = (unsigned long)sd;
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ static unsigned long get_boot_seed(void)
|
||||
unsigned long hash = 0;
|
||||
|
||||
hash = rotate_xor(hash, build_str, sizeof(build_str));
|
||||
hash = rotate_xor(hash, boot_params, sizeof(*boot_params));
|
||||
hash = rotate_xor(hash, boot_params_ptr, sizeof(*boot_params_ptr));
|
||||
|
||||
return hash;
|
||||
}
|
||||
@@ -383,7 +383,7 @@ static void handle_mem_options(void)
|
||||
static void mem_avoid_init(unsigned long input, unsigned long input_size,
|
||||
unsigned long output)
|
||||
{
|
||||
unsigned long init_size = boot_params->hdr.init_size;
|
||||
unsigned long init_size = boot_params_ptr->hdr.init_size;
|
||||
u64 initrd_start, initrd_size;
|
||||
unsigned long cmd_line, cmd_line_size;
|
||||
|
||||
@@ -395,10 +395,10 @@ static void mem_avoid_init(unsigned long input, unsigned long input_size,
|
||||
mem_avoid[MEM_AVOID_ZO_RANGE].size = (output + init_size) - input;
|
||||
|
||||
/* Avoid initrd. */
|
||||
initrd_start = (u64)boot_params->ext_ramdisk_image << 32;
|
||||
initrd_start |= boot_params->hdr.ramdisk_image;
|
||||
initrd_size = (u64)boot_params->ext_ramdisk_size << 32;
|
||||
initrd_size |= boot_params->hdr.ramdisk_size;
|
||||
initrd_start = (u64)boot_params_ptr->ext_ramdisk_image << 32;
|
||||
initrd_start |= boot_params_ptr->hdr.ramdisk_image;
|
||||
initrd_size = (u64)boot_params_ptr->ext_ramdisk_size << 32;
|
||||
initrd_size |= boot_params_ptr->hdr.ramdisk_size;
|
||||
mem_avoid[MEM_AVOID_INITRD].start = initrd_start;
|
||||
mem_avoid[MEM_AVOID_INITRD].size = initrd_size;
|
||||
/* No need to set mapping for initrd, it will be handled in VO. */
|
||||
@@ -413,8 +413,8 @@ static void mem_avoid_init(unsigned long input, unsigned long input_size,
|
||||
}
|
||||
|
||||
/* Avoid boot parameters. */
|
||||
mem_avoid[MEM_AVOID_BOOTPARAMS].start = (unsigned long)boot_params;
|
||||
mem_avoid[MEM_AVOID_BOOTPARAMS].size = sizeof(*boot_params);
|
||||
mem_avoid[MEM_AVOID_BOOTPARAMS].start = (unsigned long)boot_params_ptr;
|
||||
mem_avoid[MEM_AVOID_BOOTPARAMS].size = sizeof(*boot_params_ptr);
|
||||
|
||||
/* We don't need to set a mapping for setup_data. */
|
||||
|
||||
@@ -447,7 +447,7 @@ static bool mem_avoid_overlap(struct mem_vector *img,
|
||||
}
|
||||
|
||||
/* Avoid all entries in the setup_data linked list. */
|
||||
ptr = (struct setup_data *)(unsigned long)boot_params->hdr.setup_data;
|
||||
ptr = (struct setup_data *)(unsigned long)boot_params_ptr->hdr.setup_data;
|
||||
while (ptr) {
|
||||
struct mem_vector avoid;
|
||||
|
||||
@@ -706,7 +706,7 @@ static inline bool memory_type_is_free(efi_memory_desc_t *md)
|
||||
static bool
|
||||
process_efi_entries(unsigned long minimum, unsigned long image_size)
|
||||
{
|
||||
struct efi_info *e = &boot_params->efi_info;
|
||||
struct efi_info *e = &boot_params_ptr->efi_info;
|
||||
bool efi_mirror_found = false;
|
||||
struct mem_vector region;
|
||||
efi_memory_desc_t *md;
|
||||
@@ -777,8 +777,8 @@ static void process_e820_entries(unsigned long minimum,
|
||||
struct boot_e820_entry *entry;
|
||||
|
||||
/* Verify potential e820 positions, appending to slots list. */
|
||||
for (i = 0; i < boot_params->e820_entries; i++) {
|
||||
entry = &boot_params->e820_table[i];
|
||||
for (i = 0; i < boot_params_ptr->e820_entries; i++) {
|
||||
entry = &boot_params_ptr->e820_table[i];
|
||||
/* Skip non-RAM entries. */
|
||||
if (entry->type != E820_TYPE_RAM)
|
||||
continue;
|
||||
@@ -852,7 +852,7 @@ void choose_random_location(unsigned long input,
|
||||
return;
|
||||
}
|
||||
|
||||
boot_params->hdr.loadflags |= KASLR_FLAG;
|
||||
boot_params_ptr->hdr.loadflags |= KASLR_FLAG;
|
||||
|
||||
if (IS_ENABLED(CONFIG_X86_32))
|
||||
mem_limit = KERNEL_IMAGE_SIZE;
|
||||
|
||||
@@ -54,17 +54,17 @@ bool init_unaccepted_memory(void)
|
||||
enum efi_type et;
|
||||
int ret;
|
||||
|
||||
et = efi_get_type(boot_params);
|
||||
et = efi_get_type(boot_params_ptr);
|
||||
if (et == EFI_TYPE_NONE)
|
||||
return false;
|
||||
|
||||
ret = efi_get_conf_table(boot_params, &cfg_table_pa, &cfg_table_len);
|
||||
ret = efi_get_conf_table(boot_params_ptr, &cfg_table_pa, &cfg_table_len);
|
||||
if (ret) {
|
||||
warn("EFI config table not found.");
|
||||
return false;
|
||||
}
|
||||
|
||||
table = (void *)efi_find_vendor_table(boot_params, cfg_table_pa,
|
||||
table = (void *)efi_find_vendor_table(boot_params_ptr, cfg_table_pa,
|
||||
cfg_table_len, guid);
|
||||
if (!table)
|
||||
return false;
|
||||
|
||||
@@ -46,7 +46,7 @@ void *memmove(void *dest, const void *src, size_t n);
|
||||
/*
|
||||
* This is set up by the setup-routine at boot-time
|
||||
*/
|
||||
struct boot_params *boot_params;
|
||||
struct boot_params *boot_params_ptr;
|
||||
|
||||
struct port_io_ops pio_ops;
|
||||
|
||||
@@ -132,8 +132,8 @@ void __putstr(const char *s)
|
||||
if (lines == 0 || cols == 0)
|
||||
return;
|
||||
|
||||
x = boot_params->screen_info.orig_x;
|
||||
y = boot_params->screen_info.orig_y;
|
||||
x = boot_params_ptr->screen_info.orig_x;
|
||||
y = boot_params_ptr->screen_info.orig_y;
|
||||
|
||||
while ((c = *s++) != '\0') {
|
||||
if (c == '\n') {
|
||||
@@ -154,8 +154,8 @@ void __putstr(const char *s)
|
||||
}
|
||||
}
|
||||
|
||||
boot_params->screen_info.orig_x = x;
|
||||
boot_params->screen_info.orig_y = y;
|
||||
boot_params_ptr->screen_info.orig_x = x;
|
||||
boot_params_ptr->screen_info.orig_y = y;
|
||||
|
||||
pos = (x + cols * y) * 2; /* Update cursor position */
|
||||
outb(14, vidport);
|
||||
@@ -382,14 +382,14 @@ asmlinkage __visible void *extract_kernel(void *rmode, unsigned char *output)
|
||||
size_t entry_offset;
|
||||
|
||||
/* Retain x86 boot parameters pointer passed from startup_32/64. */
|
||||
boot_params = rmode;
|
||||
boot_params_ptr = rmode;
|
||||
|
||||
/* Clear flags intended for solely in-kernel use. */
|
||||
boot_params->hdr.loadflags &= ~KASLR_FLAG;
|
||||
boot_params_ptr->hdr.loadflags &= ~KASLR_FLAG;
|
||||
|
||||
sanitize_boot_params(boot_params);
|
||||
sanitize_boot_params(boot_params_ptr);
|
||||
|
||||
if (boot_params->screen_info.orig_video_mode == 7) {
|
||||
if (boot_params_ptr->screen_info.orig_video_mode == 7) {
|
||||
vidmem = (char *) 0xb0000;
|
||||
vidport = 0x3b4;
|
||||
} else {
|
||||
@@ -397,8 +397,8 @@ asmlinkage __visible void *extract_kernel(void *rmode, unsigned char *output)
|
||||
vidport = 0x3d4;
|
||||
}
|
||||
|
||||
lines = boot_params->screen_info.orig_video_lines;
|
||||
cols = boot_params->screen_info.orig_video_cols;
|
||||
lines = boot_params_ptr->screen_info.orig_video_lines;
|
||||
cols = boot_params_ptr->screen_info.orig_video_cols;
|
||||
|
||||
init_default_io_ops();
|
||||
|
||||
@@ -417,7 +417,7 @@ asmlinkage __visible void *extract_kernel(void *rmode, unsigned char *output)
|
||||
* so that early debugging output from the RSDP parsing code can be
|
||||
* collected.
|
||||
*/
|
||||
boot_params->acpi_rsdp_addr = get_rsdp_addr();
|
||||
boot_params_ptr->acpi_rsdp_addr = get_rsdp_addr();
|
||||
|
||||
debug_putstr("early console in extract_kernel\n");
|
||||
|
||||
|
||||
@@ -61,7 +61,6 @@ extern memptr free_mem_ptr;
|
||||
extern memptr free_mem_end_ptr;
|
||||
void *malloc(int size);
|
||||
void free(void *where);
|
||||
extern struct boot_params *boot_params;
|
||||
void __putstr(const char *s);
|
||||
void __puthex(unsigned long value);
|
||||
#define error_putstr(__x) __putstr(__x)
|
||||
|
||||
@@ -28,7 +28,6 @@ static char trampoline_save[TRAMPOLINE_32BIT_SIZE];
|
||||
*/
|
||||
unsigned long *trampoline_32bit __section(".data");
|
||||
|
||||
extern struct boot_params *boot_params;
|
||||
int cmdline_find_option_bool(const char *option);
|
||||
|
||||
static unsigned long find_trampoline_placement(void)
|
||||
@@ -49,7 +48,7 @@ static unsigned long find_trampoline_placement(void)
|
||||
*
|
||||
* Only look for values in the legacy ROM for non-EFI system.
|
||||
*/
|
||||
signature = (char *)&boot_params->efi_info.efi_loader_signature;
|
||||
signature = (char *)&boot_params_ptr->efi_info.efi_loader_signature;
|
||||
if (strncmp(signature, EFI32_LOADER_SIGNATURE, 4) &&
|
||||
strncmp(signature, EFI64_LOADER_SIGNATURE, 4)) {
|
||||
ebda_start = *(unsigned short *)0x40e << 4;
|
||||
@@ -65,10 +64,10 @@ static unsigned long find_trampoline_placement(void)
|
||||
bios_start = round_down(bios_start, PAGE_SIZE);
|
||||
|
||||
/* Find the first usable memory region under bios_start. */
|
||||
for (i = boot_params->e820_entries - 1; i >= 0; i--) {
|
||||
for (i = boot_params_ptr->e820_entries - 1; i >= 0; i--) {
|
||||
unsigned long new = bios_start;
|
||||
|
||||
entry = &boot_params->e820_table[i];
|
||||
entry = &boot_params_ptr->e820_table[i];
|
||||
|
||||
/* Skip all entries above bios_start. */
|
||||
if (bios_start <= entry->addr)
|
||||
@@ -107,7 +106,7 @@ asmlinkage void configure_5level_paging(struct boot_params *bp, void *pgtable)
|
||||
bool l5_required = false;
|
||||
|
||||
/* Initialize boot_params. Required for cmdline_find_option_bool(). */
|
||||
boot_params = bp;
|
||||
boot_params_ptr = bp;
|
||||
|
||||
/*
|
||||
* Check if LA57 is desired and supported.
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "error.h"
|
||||
#include "../msr.h"
|
||||
|
||||
struct ghcb boot_ghcb_page __aligned(PAGE_SIZE);
|
||||
static struct ghcb boot_ghcb_page __aligned(PAGE_SIZE);
|
||||
struct ghcb *boot_ghcb;
|
||||
|
||||
/*
|
||||
@@ -615,7 +615,7 @@ void sev_prep_identity_maps(unsigned long top_level_pgt)
|
||||
* accessed after switchover.
|
||||
*/
|
||||
if (sev_snp_enabled()) {
|
||||
unsigned long cc_info_pa = boot_params->cc_blob_address;
|
||||
unsigned long cc_info_pa = boot_params_ptr->cc_blob_address;
|
||||
struct cc_blob_sev_info *cc_info;
|
||||
|
||||
kernel_add_identity_map(cc_info_pa, cc_info_pa + sizeof(*cc_info));
|
||||
|
||||
@@ -43,11 +43,13 @@ SECTIONS
|
||||
*(.rodata.*)
|
||||
_erodata = . ;
|
||||
}
|
||||
.data : {
|
||||
.data : ALIGN(0x1000) {
|
||||
_data = . ;
|
||||
*(.data)
|
||||
*(.data.*)
|
||||
*(.bss.efistub)
|
||||
|
||||
/* Add 4 bytes of extra space for a CRC-32 checksum */
|
||||
. = ALIGN(. + 4, 0x200);
|
||||
_edata = . ;
|
||||
}
|
||||
. = ALIGN(L1_CACHE_BYTES);
|
||||
|
||||
+84
-129
@@ -36,66 +36,20 @@ SYSSEG = 0x1000 /* historical load address >> 4 */
|
||||
#define ROOT_RDONLY 1
|
||||
#endif
|
||||
|
||||
.set salign, 0x1000
|
||||
.set falign, 0x200
|
||||
|
||||
.code16
|
||||
.section ".bstext", "ax"
|
||||
|
||||
.global bootsect_start
|
||||
bootsect_start:
|
||||
#ifdef CONFIG_EFI_STUB
|
||||
# "MZ", MS-DOS header
|
||||
.word MZ_MAGIC
|
||||
#endif
|
||||
|
||||
# Normalize the start address
|
||||
ljmp $BOOTSEG, $start2
|
||||
|
||||
start2:
|
||||
movw %cs, %ax
|
||||
movw %ax, %ds
|
||||
movw %ax, %es
|
||||
movw %ax, %ss
|
||||
xorw %sp, %sp
|
||||
sti
|
||||
cld
|
||||
|
||||
movw $bugger_off_msg, %si
|
||||
|
||||
msg_loop:
|
||||
lodsb
|
||||
andb %al, %al
|
||||
jz bs_die
|
||||
movb $0xe, %ah
|
||||
movw $7, %bx
|
||||
int $0x10
|
||||
jmp msg_loop
|
||||
|
||||
bs_die:
|
||||
# Allow the user to press a key, then reboot
|
||||
xorw %ax, %ax
|
||||
int $0x16
|
||||
int $0x19
|
||||
|
||||
# int 0x19 should never return. In case it does anyway,
|
||||
# invoke the BIOS reset code...
|
||||
ljmp $0xf000,$0xfff0
|
||||
|
||||
#ifdef CONFIG_EFI_STUB
|
||||
.org 0x38
|
||||
#
|
||||
# Offset to the PE header.
|
||||
#
|
||||
.long LINUX_PE_MAGIC
|
||||
.long pe_header
|
||||
#endif /* CONFIG_EFI_STUB */
|
||||
|
||||
.section ".bsdata", "a"
|
||||
bugger_off_msg:
|
||||
.ascii "Use a boot loader.\r\n"
|
||||
.ascii "\n"
|
||||
.ascii "Remove disk and press any key to reboot...\r\n"
|
||||
.byte 0
|
||||
|
||||
#ifdef CONFIG_EFI_STUB
|
||||
pe_header:
|
||||
.long PE_MAGIC
|
||||
|
||||
@@ -124,30 +78,26 @@ optional_header:
|
||||
.byte 0x02 # MajorLinkerVersion
|
||||
.byte 0x14 # MinorLinkerVersion
|
||||
|
||||
# Filled in by build.c
|
||||
.long 0 # SizeOfCode
|
||||
.long ZO__data # SizeOfCode
|
||||
|
||||
.long 0 # SizeOfInitializedData
|
||||
.long ZO__end - ZO__data # SizeOfInitializedData
|
||||
.long 0 # SizeOfUninitializedData
|
||||
|
||||
# Filled in by build.c
|
||||
.long 0x0000 # AddressOfEntryPoint
|
||||
.long setup_size + ZO_efi_pe_entry # AddressOfEntryPoint
|
||||
|
||||
.long 0x0200 # BaseOfCode
|
||||
.long setup_size # BaseOfCode
|
||||
#ifdef CONFIG_X86_32
|
||||
.long 0 # data
|
||||
#endif
|
||||
|
||||
extra_header_fields:
|
||||
# PE specification requires ImageBase to be 64k aligned
|
||||
.set image_base, (LOAD_PHYSICAL_ADDR + 0xffff) & ~0xffff
|
||||
#ifdef CONFIG_X86_32
|
||||
.long image_base # ImageBase
|
||||
.long 0 # ImageBase
|
||||
#else
|
||||
.quad image_base # ImageBase
|
||||
.quad 0 # ImageBase
|
||||
#endif
|
||||
.long 0x20 # SectionAlignment
|
||||
.long 0x20 # FileAlignment
|
||||
.long salign # SectionAlignment
|
||||
.long falign # FileAlignment
|
||||
.word 0 # MajorOperatingSystemVersion
|
||||
.word 0 # MinorOperatingSystemVersion
|
||||
.word LINUX_EFISTUB_MAJOR_VERSION # MajorImageVersion
|
||||
@@ -156,12 +106,10 @@ extra_header_fields:
|
||||
.word 0 # MinorSubsystemVersion
|
||||
.long 0 # Win32VersionValue
|
||||
|
||||
#
|
||||
# The size of the bzImage is written in tools/build.c
|
||||
#
|
||||
.long 0 # SizeOfImage
|
||||
.long setup_size + ZO__end + pecompat_vsize
|
||||
# SizeOfImage
|
||||
|
||||
.long 0x200 # SizeOfHeaders
|
||||
.long salign # SizeOfHeaders
|
||||
.long 0 # CheckSum
|
||||
.word IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application)
|
||||
#ifdef CONFIG_EFI_DXE_MEM_ATTRIBUTES
|
||||
@@ -192,87 +140,78 @@ extra_header_fields:
|
||||
|
||||
# Section table
|
||||
section_table:
|
||||
#
|
||||
# The offset & size fields are filled in by build.c.
|
||||
#
|
||||
.ascii ".setup"
|
||||
.byte 0
|
||||
.byte 0
|
||||
.long 0
|
||||
.long 0x0 # startup_{32,64}
|
||||
.long 0 # Size of initialized data
|
||||
# on disk
|
||||
.long 0x0 # startup_{32,64}
|
||||
.long 0 # PointerToRelocations
|
||||
.long 0 # PointerToLineNumbers
|
||||
.word 0 # NumberOfRelocations
|
||||
.word 0 # NumberOfLineNumbers
|
||||
.long IMAGE_SCN_CNT_CODE | \
|
||||
IMAGE_SCN_MEM_READ | \
|
||||
IMAGE_SCN_MEM_EXECUTE | \
|
||||
IMAGE_SCN_ALIGN_16BYTES # Characteristics
|
||||
.long setup_size - salign # VirtualSize
|
||||
.long salign # VirtualAddress
|
||||
.long pecompat_fstart - salign # SizeOfRawData
|
||||
.long salign # PointerToRawData
|
||||
|
||||
#
|
||||
# The EFI application loader requires a relocation section
|
||||
# because EFI applications must be relocatable. The .reloc
|
||||
# offset & size fields are filled in by build.c.
|
||||
#
|
||||
.ascii ".reloc"
|
||||
.byte 0
|
||||
.byte 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0 # SizeOfRawData
|
||||
.long 0 # PointerToRawData
|
||||
.long 0 # PointerToRelocations
|
||||
.long 0 # PointerToLineNumbers
|
||||
.word 0 # NumberOfRelocations
|
||||
.word 0 # NumberOfLineNumbers
|
||||
.long 0, 0, 0
|
||||
.long IMAGE_SCN_CNT_INITIALIZED_DATA | \
|
||||
IMAGE_SCN_MEM_READ | \
|
||||
IMAGE_SCN_MEM_DISCARDABLE | \
|
||||
IMAGE_SCN_ALIGN_1BYTES # Characteristics
|
||||
IMAGE_SCN_MEM_DISCARDABLE # Characteristics
|
||||
|
||||
#ifdef CONFIG_EFI_MIXED
|
||||
#
|
||||
# The offset & size fields are filled in by build.c.
|
||||
#
|
||||
.asciz ".compat"
|
||||
.long 0
|
||||
.long 0x0
|
||||
.long 0 # Size of initialized data
|
||||
# on disk
|
||||
.long 0x0
|
||||
.long 0 # PointerToRelocations
|
||||
.long 0 # PointerToLineNumbers
|
||||
.word 0 # NumberOfRelocations
|
||||
.word 0 # NumberOfLineNumbers
|
||||
|
||||
.long 8 # VirtualSize
|
||||
.long setup_size + ZO__end # VirtualAddress
|
||||
.long pecompat_fsize # SizeOfRawData
|
||||
.long pecompat_fstart # PointerToRawData
|
||||
|
||||
.long 0, 0, 0
|
||||
.long IMAGE_SCN_CNT_INITIALIZED_DATA | \
|
||||
IMAGE_SCN_MEM_READ | \
|
||||
IMAGE_SCN_MEM_DISCARDABLE | \
|
||||
IMAGE_SCN_ALIGN_1BYTES # Characteristics
|
||||
#endif
|
||||
IMAGE_SCN_MEM_DISCARDABLE # Characteristics
|
||||
|
||||
#
|
||||
# The offset & size fields are filled in by build.c.
|
||||
#
|
||||
/*
|
||||
* Put the IA-32 machine type and the associated entry point address in
|
||||
* the .compat section, so loaders can figure out which other execution
|
||||
* modes this image supports.
|
||||
*/
|
||||
.pushsection ".pecompat", "a", @progbits
|
||||
.balign falign
|
||||
.set pecompat_vsize, salign
|
||||
.globl pecompat_fstart
|
||||
pecompat_fstart:
|
||||
.byte 0x1 # Version
|
||||
.byte 8 # Size
|
||||
.word IMAGE_FILE_MACHINE_I386 # PE machine type
|
||||
.long setup_size + ZO_efi32_pe_entry # Entrypoint
|
||||
.popsection
|
||||
#else
|
||||
.set pecompat_vsize, 0
|
||||
.set pecompat_fstart, setup_size
|
||||
#endif
|
||||
.ascii ".text"
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 0
|
||||
.long 0
|
||||
.long 0x0 # startup_{32,64}
|
||||
.long 0 # Size of initialized data
|
||||
.long ZO__data
|
||||
.long setup_size
|
||||
.long ZO__data # Size of initialized data
|
||||
# on disk
|
||||
.long 0x0 # startup_{32,64}
|
||||
.long setup_size
|
||||
.long 0 # PointerToRelocations
|
||||
.long 0 # PointerToLineNumbers
|
||||
.word 0 # NumberOfRelocations
|
||||
.word 0 # NumberOfLineNumbers
|
||||
.long IMAGE_SCN_CNT_CODE | \
|
||||
IMAGE_SCN_MEM_READ | \
|
||||
IMAGE_SCN_MEM_EXECUTE | \
|
||||
IMAGE_SCN_ALIGN_16BYTES # Characteristics
|
||||
IMAGE_SCN_MEM_EXECUTE # Characteristics
|
||||
|
||||
.ascii ".data\0\0\0"
|
||||
.long ZO__end - ZO__data # VirtualSize
|
||||
.long setup_size + ZO__data # VirtualAddress
|
||||
.long ZO__edata - ZO__data # SizeOfRawData
|
||||
.long setup_size + ZO__data # PointerToRawData
|
||||
|
||||
.long 0, 0, 0
|
||||
.long IMAGE_SCN_CNT_INITIALIZED_DATA | \
|
||||
IMAGE_SCN_MEM_READ | \
|
||||
IMAGE_SCN_MEM_WRITE # Characteristics
|
||||
|
||||
.set section_count, (. - section_table) / 40
|
||||
#endif /* CONFIG_EFI_STUB */
|
||||
@@ -286,12 +225,12 @@ sentinel: .byte 0xff, 0xff /* Used to detect broken loaders */
|
||||
|
||||
.globl hdr
|
||||
hdr:
|
||||
setup_sects: .byte 0 /* Filled in by build.c */
|
||||
.byte setup_sects - 1
|
||||
root_flags: .word ROOT_RDONLY
|
||||
syssize: .long 0 /* Filled in by build.c */
|
||||
syssize: .long ZO__edata / 16
|
||||
ram_size: .word 0 /* Obsolete */
|
||||
vid_mode: .word SVGA_MODE
|
||||
root_dev: .word 0 /* Filled in by build.c */
|
||||
root_dev: .word 0 /* Default to major/minor 0/0 */
|
||||
boot_flag: .word 0xAA55
|
||||
|
||||
# offset 512, entry point
|
||||
@@ -579,9 +518,25 @@ pref_address: .quad LOAD_PHYSICAL_ADDR # preferred load addr
|
||||
# define INIT_SIZE VO_INIT_SIZE
|
||||
#endif
|
||||
|
||||
.macro __handover_offset
|
||||
#ifndef CONFIG_EFI_HANDOVER_PROTOCOL
|
||||
.long 0
|
||||
#elif !defined(CONFIG_X86_64)
|
||||
.long ZO_efi32_stub_entry
|
||||
#else
|
||||
/* Yes, this is really how we defined it :( */
|
||||
.long ZO_efi64_stub_entry - 0x200
|
||||
#ifdef CONFIG_EFI_MIXED
|
||||
.if ZO_efi32_stub_entry != ZO_efi64_stub_entry - 0x200
|
||||
.error "32-bit and 64-bit EFI entry points do not match"
|
||||
.endif
|
||||
#endif
|
||||
#endif
|
||||
.endm
|
||||
|
||||
init_size: .long INIT_SIZE # kernel initialization size
|
||||
handover_offset: .long 0 # Filled in by build.c
|
||||
kernel_info_offset: .long 0 # Filled in by build.c
|
||||
handover_offset: __handover_offset
|
||||
kernel_info_offset: .long ZO_kernel_info
|
||||
|
||||
# End of setup header #####################################################
|
||||
|
||||
|
||||
+10
-4
@@ -10,10 +10,11 @@ ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
. = 0;
|
||||
.bstext : { *(.bstext) }
|
||||
.bsdata : { *(.bsdata) }
|
||||
.bstext : {
|
||||
*(.bstext)
|
||||
. = 495;
|
||||
} =0xffffffff
|
||||
|
||||
. = 495;
|
||||
.header : { *(.header) }
|
||||
.entrytext : { *(.entrytext) }
|
||||
.inittext : { *(.inittext) }
|
||||
@@ -35,11 +36,16 @@ SECTIONS
|
||||
. = ALIGN(16);
|
||||
.data : { *(.data*) }
|
||||
|
||||
.pecompat : { *(.pecompat) }
|
||||
PROVIDE(pecompat_fsize = setup_size - pecompat_fstart);
|
||||
|
||||
.signature : {
|
||||
setup_sig = .;
|
||||
LONG(0x5a5aaa55)
|
||||
}
|
||||
|
||||
setup_size = ALIGN(ABSOLUTE(.), 4096);
|
||||
setup_sects = ABSOLUTE(setup_size / 512);
|
||||
}
|
||||
|
||||
. = ALIGN(16);
|
||||
.bss :
|
||||
|
||||
+9
-264
@@ -40,10 +40,6 @@ typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
|
||||
#define DEFAULT_MAJOR_ROOT 0
|
||||
#define DEFAULT_MINOR_ROOT 0
|
||||
#define DEFAULT_ROOT_DEV (DEFAULT_MAJOR_ROOT << 8 | DEFAULT_MINOR_ROOT)
|
||||
|
||||
/* Minimal number of setup sectors */
|
||||
#define SETUP_SECT_MIN 5
|
||||
#define SETUP_SECT_MAX 64
|
||||
@@ -51,22 +47,7 @@ typedef unsigned int u32;
|
||||
/* This must be large enough to hold the entire setup */
|
||||
u8 buf[SETUP_SECT_MAX*512];
|
||||
|
||||
#define PECOFF_RELOC_RESERVE 0x20
|
||||
|
||||
#ifdef CONFIG_EFI_MIXED
|
||||
#define PECOFF_COMPAT_RESERVE 0x20
|
||||
#else
|
||||
#define PECOFF_COMPAT_RESERVE 0x0
|
||||
#endif
|
||||
|
||||
static unsigned long efi32_stub_entry;
|
||||
static unsigned long efi64_stub_entry;
|
||||
static unsigned long efi_pe_entry;
|
||||
static unsigned long efi32_pe_entry;
|
||||
static unsigned long kernel_info;
|
||||
static unsigned long startup_64;
|
||||
static unsigned long _ehead;
|
||||
static unsigned long _end;
|
||||
static unsigned long _edata;
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
@@ -152,180 +133,6 @@ static void usage(void)
|
||||
die("Usage: build setup system zoffset.h image");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EFI_STUB
|
||||
|
||||
static void update_pecoff_section_header_fields(char *section_name, u32 vma, u32 size, u32 datasz, u32 offset)
|
||||
{
|
||||
unsigned int pe_header;
|
||||
unsigned short num_sections;
|
||||
u8 *section;
|
||||
|
||||
pe_header = get_unaligned_le32(&buf[0x3c]);
|
||||
num_sections = get_unaligned_le16(&buf[pe_header + 6]);
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
section = &buf[pe_header + 0xa8];
|
||||
#else
|
||||
section = &buf[pe_header + 0xb8];
|
||||
#endif
|
||||
|
||||
while (num_sections > 0) {
|
||||
if (strncmp((char*)section, section_name, 8) == 0) {
|
||||
/* section header size field */
|
||||
put_unaligned_le32(size, section + 0x8);
|
||||
|
||||
/* section header vma field */
|
||||
put_unaligned_le32(vma, section + 0xc);
|
||||
|
||||
/* section header 'size of initialised data' field */
|
||||
put_unaligned_le32(datasz, section + 0x10);
|
||||
|
||||
/* section header 'file offset' field */
|
||||
put_unaligned_le32(offset, section + 0x14);
|
||||
|
||||
break;
|
||||
}
|
||||
section += 0x28;
|
||||
num_sections--;
|
||||
}
|
||||
}
|
||||
|
||||
static void update_pecoff_section_header(char *section_name, u32 offset, u32 size)
|
||||
{
|
||||
update_pecoff_section_header_fields(section_name, offset, size, size, offset);
|
||||
}
|
||||
|
||||
static void update_pecoff_setup_and_reloc(unsigned int size)
|
||||
{
|
||||
u32 setup_offset = 0x200;
|
||||
u32 reloc_offset = size - PECOFF_RELOC_RESERVE - PECOFF_COMPAT_RESERVE;
|
||||
#ifdef CONFIG_EFI_MIXED
|
||||
u32 compat_offset = reloc_offset + PECOFF_RELOC_RESERVE;
|
||||
#endif
|
||||
u32 setup_size = reloc_offset - setup_offset;
|
||||
|
||||
update_pecoff_section_header(".setup", setup_offset, setup_size);
|
||||
update_pecoff_section_header(".reloc", reloc_offset, PECOFF_RELOC_RESERVE);
|
||||
|
||||
/*
|
||||
* Modify .reloc section contents with a single entry. The
|
||||
* relocation is applied to offset 10 of the relocation section.
|
||||
*/
|
||||
put_unaligned_le32(reloc_offset + 10, &buf[reloc_offset]);
|
||||
put_unaligned_le32(10, &buf[reloc_offset + 4]);
|
||||
|
||||
#ifdef CONFIG_EFI_MIXED
|
||||
update_pecoff_section_header(".compat", compat_offset, PECOFF_COMPAT_RESERVE);
|
||||
|
||||
/*
|
||||
* Put the IA-32 machine type (0x14c) and the associated entry point
|
||||
* address in the .compat section, so loaders can figure out which other
|
||||
* execution modes this image supports.
|
||||
*/
|
||||
buf[compat_offset] = 0x1;
|
||||
buf[compat_offset + 1] = 0x8;
|
||||
put_unaligned_le16(0x14c, &buf[compat_offset + 2]);
|
||||
put_unaligned_le32(efi32_pe_entry + size, &buf[compat_offset + 4]);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void update_pecoff_text(unsigned int text_start, unsigned int file_sz,
|
||||
unsigned int init_sz)
|
||||
{
|
||||
unsigned int pe_header;
|
||||
unsigned int text_sz = file_sz - text_start;
|
||||
unsigned int bss_sz = init_sz - file_sz;
|
||||
|
||||
pe_header = get_unaligned_le32(&buf[0x3c]);
|
||||
|
||||
/*
|
||||
* The PE/COFF loader may load the image at an address which is
|
||||
* misaligned with respect to the kernel_alignment field in the setup
|
||||
* header.
|
||||
*
|
||||
* In order to avoid relocating the kernel to correct the misalignment,
|
||||
* add slack to allow the buffer to be aligned within the declared size
|
||||
* of the image.
|
||||
*/
|
||||
bss_sz += CONFIG_PHYSICAL_ALIGN;
|
||||
init_sz += CONFIG_PHYSICAL_ALIGN;
|
||||
|
||||
/*
|
||||
* Size of code: Subtract the size of the first sector (512 bytes)
|
||||
* which includes the header.
|
||||
*/
|
||||
put_unaligned_le32(file_sz - 512 + bss_sz, &buf[pe_header + 0x1c]);
|
||||
|
||||
/* Size of image */
|
||||
put_unaligned_le32(init_sz, &buf[pe_header + 0x50]);
|
||||
|
||||
/*
|
||||
* Address of entry point for PE/COFF executable
|
||||
*/
|
||||
put_unaligned_le32(text_start + efi_pe_entry, &buf[pe_header + 0x28]);
|
||||
|
||||
update_pecoff_section_header_fields(".text", text_start, text_sz + bss_sz,
|
||||
text_sz, text_start);
|
||||
}
|
||||
|
||||
static int reserve_pecoff_reloc_section(int c)
|
||||
{
|
||||
/* Reserve 0x20 bytes for .reloc section */
|
||||
memset(buf+c, 0, PECOFF_RELOC_RESERVE);
|
||||
return PECOFF_RELOC_RESERVE;
|
||||
}
|
||||
|
||||
static void efi_stub_defaults(void)
|
||||
{
|
||||
/* Defaults for old kernel */
|
||||
#ifdef CONFIG_X86_32
|
||||
efi_pe_entry = 0x10;
|
||||
#else
|
||||
efi_pe_entry = 0x210;
|
||||
startup_64 = 0x200;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void efi_stub_entry_update(void)
|
||||
{
|
||||
unsigned long addr = efi32_stub_entry;
|
||||
|
||||
#ifdef CONFIG_EFI_HANDOVER_PROTOCOL
|
||||
#ifdef CONFIG_X86_64
|
||||
/* Yes, this is really how we defined it :( */
|
||||
addr = efi64_stub_entry - 0x200;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_EFI_MIXED
|
||||
if (efi32_stub_entry != addr)
|
||||
die("32-bit and 64-bit EFI entry points do not match\n");
|
||||
#endif
|
||||
#endif
|
||||
put_unaligned_le32(addr, &buf[0x264]);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline void update_pecoff_setup_and_reloc(unsigned int size) {}
|
||||
static inline void update_pecoff_text(unsigned int text_start,
|
||||
unsigned int file_sz,
|
||||
unsigned int init_sz) {}
|
||||
static inline void efi_stub_defaults(void) {}
|
||||
static inline void efi_stub_entry_update(void) {}
|
||||
|
||||
static inline int reserve_pecoff_reloc_section(int c)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_EFI_STUB */
|
||||
|
||||
static int reserve_pecoff_compat_section(int c)
|
||||
{
|
||||
/* Reserve 0x20 bytes for .compat section */
|
||||
memset(buf+c, 0, PECOFF_COMPAT_RESERVE);
|
||||
return PECOFF_COMPAT_RESERVE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse zoffset.h and find the entry points. We could just #include zoffset.h
|
||||
* but that would mean tools/build would have to be rebuilt every time. It's
|
||||
@@ -354,14 +161,7 @@ static void parse_zoffset(char *fname)
|
||||
p = (char *)buf;
|
||||
|
||||
while (p && *p) {
|
||||
PARSE_ZOFS(p, efi32_stub_entry);
|
||||
PARSE_ZOFS(p, efi64_stub_entry);
|
||||
PARSE_ZOFS(p, efi_pe_entry);
|
||||
PARSE_ZOFS(p, efi32_pe_entry);
|
||||
PARSE_ZOFS(p, kernel_info);
|
||||
PARSE_ZOFS(p, startup_64);
|
||||
PARSE_ZOFS(p, _ehead);
|
||||
PARSE_ZOFS(p, _end);
|
||||
PARSE_ZOFS(p, _edata);
|
||||
|
||||
p = strchr(p, '\n');
|
||||
while (p && (*p == '\r' || *p == '\n'))
|
||||
@@ -371,17 +171,14 @@ static void parse_zoffset(char *fname)
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
unsigned int i, sz, setup_sectors, init_sz;
|
||||
unsigned int i, sz, setup_sectors;
|
||||
int c;
|
||||
u32 sys_size;
|
||||
struct stat sb;
|
||||
FILE *file, *dest;
|
||||
int fd;
|
||||
void *kernel;
|
||||
u32 crc = 0xffffffffUL;
|
||||
|
||||
efi_stub_defaults();
|
||||
|
||||
if (argc != 5)
|
||||
usage();
|
||||
parse_zoffset(argv[3]);
|
||||
@@ -403,72 +200,27 @@ int main(int argc, char ** argv)
|
||||
die("Boot block hasn't got boot flag (0xAA55)");
|
||||
fclose(file);
|
||||
|
||||
c += reserve_pecoff_compat_section(c);
|
||||
c += reserve_pecoff_reloc_section(c);
|
||||
|
||||
/* Pad unused space with zeros */
|
||||
setup_sectors = (c + 511) / 512;
|
||||
setup_sectors = (c + 4095) / 4096;
|
||||
setup_sectors *= 8;
|
||||
if (setup_sectors < SETUP_SECT_MIN)
|
||||
setup_sectors = SETUP_SECT_MIN;
|
||||
i = setup_sectors*512;
|
||||
memset(buf+c, 0, i-c);
|
||||
|
||||
update_pecoff_setup_and_reloc(i);
|
||||
|
||||
/* Set the default root device */
|
||||
put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]);
|
||||
|
||||
/* Open and stat the kernel file */
|
||||
fd = open(argv[2], O_RDONLY);
|
||||
if (fd < 0)
|
||||
die("Unable to open `%s': %m", argv[2]);
|
||||
if (fstat(fd, &sb))
|
||||
die("Unable to stat `%s': %m", argv[2]);
|
||||
sz = sb.st_size;
|
||||
if (_edata != sb.st_size)
|
||||
die("Unexpected file size `%s': %u != %u", argv[2], _edata,
|
||||
sb.st_size);
|
||||
sz = _edata - 4;
|
||||
kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
|
||||
if (kernel == MAP_FAILED)
|
||||
die("Unable to mmap '%s': %m", argv[2]);
|
||||
/* Number of 16-byte paragraphs, including space for a 4-byte CRC */
|
||||
sys_size = (sz + 15 + 4) / 16;
|
||||
#ifdef CONFIG_EFI_STUB
|
||||
/*
|
||||
* COFF requires minimum 32-byte alignment of sections, and
|
||||
* adding a signature is problematic without that alignment.
|
||||
*/
|
||||
sys_size = (sys_size + 1) & ~1;
|
||||
#endif
|
||||
|
||||
/* Patch the setup code with the appropriate size parameters */
|
||||
buf[0x1f1] = setup_sectors-1;
|
||||
put_unaligned_le32(sys_size, &buf[0x1f4]);
|
||||
|
||||
init_sz = get_unaligned_le32(&buf[0x260]);
|
||||
#ifdef CONFIG_EFI_STUB
|
||||
/*
|
||||
* The decompression buffer will start at ImageBase. When relocating
|
||||
* the compressed kernel to its end, we must ensure that the head
|
||||
* section does not get overwritten. The head section occupies
|
||||
* [i, i + _ehead), and the destination is [init_sz - _end, init_sz).
|
||||
*
|
||||
* At present these should never overlap, because 'i' is at most 32k
|
||||
* because of SETUP_SECT_MAX, '_ehead' is less than 1k, and the
|
||||
* calculation of INIT_SIZE in boot/header.S ensures that
|
||||
* 'init_sz - _end' is at least 64k.
|
||||
*
|
||||
* For future-proofing, increase init_sz if necessary.
|
||||
*/
|
||||
|
||||
if (init_sz - _end < i + _ehead) {
|
||||
init_sz = (i + _ehead + _end + 4095) & ~4095;
|
||||
put_unaligned_le32(init_sz, &buf[0x260]);
|
||||
}
|
||||
#endif
|
||||
update_pecoff_text(setup_sectors * 512, i + (sys_size * 16), init_sz);
|
||||
|
||||
efi_stub_entry_update();
|
||||
|
||||
/* Update kernel_info offset. */
|
||||
put_unaligned_le32(kernel_info, &buf[0x268]);
|
||||
|
||||
crc = partial_crc32(buf, i, crc);
|
||||
if (fwrite(buf, 1, i, dest) != i)
|
||||
@@ -479,13 +231,6 @@ int main(int argc, char ** argv)
|
||||
if (fwrite(kernel, 1, sz, dest) != sz)
|
||||
die("Writing kernel failed");
|
||||
|
||||
/* Add padding leaving 4 bytes for the checksum */
|
||||
while (sz++ < (sys_size*16) - 4) {
|
||||
crc = partial_crc32_one('\0', crc);
|
||||
if (fwrite("\0", 1, 1, dest) != 1)
|
||||
die("Writing padding failed");
|
||||
}
|
||||
|
||||
/* Write the CRC */
|
||||
put_unaligned_le32(crc, buf);
|
||||
if (fwrite(buf, 1, 4, dest) != 4)
|
||||
|
||||
@@ -119,7 +119,7 @@ static void __noreturn tdx_panic(const char *msg)
|
||||
} message;
|
||||
|
||||
/* VMM assumes '\0' in byte 65, if the message took all 64 bytes */
|
||||
strncpy(message.str, msg, 64);
|
||||
strtomem_pad(message.str, msg, '\0');
|
||||
|
||||
args.r8 = message.r8;
|
||||
args.r9 = message.r9;
|
||||
|
||||
@@ -281,4 +281,5 @@ CONFIG_PROVIDE_OHCI1394_DMA_INIT=y
|
||||
CONFIG_EARLY_PRINTK_DBGP=y
|
||||
CONFIG_DEBUG_BOOT_PARAMS=y
|
||||
CONFIG_UNWINDER_FRAME_POINTER=y
|
||||
CONFIG_DEBUG_ENTRY=y
|
||||
# CONFIG_64BIT is not set
|
||||
|
||||
@@ -276,3 +276,4 @@ CONFIG_BLK_DEV_IO_TRACE=y
|
||||
CONFIG_PROVIDE_OHCI1394_DMA_INIT=y
|
||||
CONFIG_EARLY_PRINTK_DBGP=y
|
||||
CONFIG_DEBUG_BOOT_PARAMS=y
|
||||
CONFIG_DEBUG_ENTRY=y
|
||||
|
||||
+80
-33
@@ -19,6 +19,7 @@
|
||||
#include <linux/nospec.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#ifdef CONFIG_XEN_PV
|
||||
#include <xen/xen-ops.h>
|
||||
@@ -70,7 +71,8 @@ static __always_inline bool do_syscall_x32(struct pt_regs *regs, int nr)
|
||||
return false;
|
||||
}
|
||||
|
||||
__visible noinstr void do_syscall_64(struct pt_regs *regs, int nr)
|
||||
/* Returns true to return using SYSRET, or false to use IRET */
|
||||
__visible noinstr bool do_syscall_64(struct pt_regs *regs, int nr)
|
||||
{
|
||||
add_random_kstack_offset();
|
||||
nr = syscall_enter_from_user_mode(regs, nr);
|
||||
@@ -84,6 +86,46 @@ __visible noinstr void do_syscall_64(struct pt_regs *regs, int nr)
|
||||
|
||||
instrumentation_end();
|
||||
syscall_exit_to_user_mode(regs);
|
||||
|
||||
/*
|
||||
* Check that the register state is valid for using SYSRET to exit
|
||||
* to userspace. Otherwise use the slower but fully capable IRET
|
||||
* exit path.
|
||||
*/
|
||||
|
||||
/* XEN PV guests always use the IRET path */
|
||||
if (cpu_feature_enabled(X86_FEATURE_XENPV))
|
||||
return false;
|
||||
|
||||
/* SYSRET requires RCX == RIP and R11 == EFLAGS */
|
||||
if (unlikely(regs->cx != regs->ip || regs->r11 != regs->flags))
|
||||
return false;
|
||||
|
||||
/* CS and SS must match the values set in MSR_STAR */
|
||||
if (unlikely(regs->cs != __USER_CS || regs->ss != __USER_DS))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* On Intel CPUs, SYSRET with non-canonical RCX/RIP will #GP
|
||||
* in kernel space. This essentially lets the user take over
|
||||
* the kernel, since userspace controls RSP.
|
||||
*
|
||||
* TASK_SIZE_MAX covers all user-accessible addresses other than
|
||||
* the deprecated vsyscall page.
|
||||
*/
|
||||
if (unlikely(regs->ip >= TASK_SIZE_MAX))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* SYSRET cannot restore RF. It can restore TF, but unlike IRET,
|
||||
* restoring TF results in a trap from userspace immediately after
|
||||
* SYSRET.
|
||||
*/
|
||||
if (unlikely(regs->flags & (X86_EFLAGS_RF | X86_EFLAGS_TF)))
|
||||
return false;
|
||||
|
||||
/* Use SYSRET to exit to userspace */
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -96,6 +138,16 @@ static __always_inline int syscall_32_enter(struct pt_regs *regs)
|
||||
return (int)regs->orig_ax;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IA32_EMULATION
|
||||
bool __ia32_enabled __ro_after_init = !IS_ENABLED(CONFIG_IA32_EMULATION_DEFAULT_DISABLED);
|
||||
|
||||
static int ia32_emulation_override_cmdline(char *arg)
|
||||
{
|
||||
return kstrtobool(arg, &__ia32_enabled);
|
||||
}
|
||||
early_param("ia32_emulation", ia32_emulation_override_cmdline);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Invoke a 32-bit syscall. Called with IRQs on in CONTEXT_KERNEL.
|
||||
*/
|
||||
@@ -182,8 +234,8 @@ static noinstr bool __do_fast_syscall_32(struct pt_regs *regs)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns 0 to return using IRET or 1 to return using SYSEXIT/SYSRETL. */
|
||||
__visible noinstr long do_fast_syscall_32(struct pt_regs *regs)
|
||||
/* Returns true to return using SYSEXIT/SYSRETL, or false to use IRET */
|
||||
__visible noinstr bool do_fast_syscall_32(struct pt_regs *regs)
|
||||
{
|
||||
/*
|
||||
* Called using the internal vDSO SYSENTER/SYSCALL32 calling
|
||||
@@ -201,41 +253,36 @@ __visible noinstr long do_fast_syscall_32(struct pt_regs *regs)
|
||||
|
||||
/* Invoke the syscall. If it failed, keep it simple: use IRET. */
|
||||
if (!__do_fast_syscall_32(regs))
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
/*
|
||||
* Opportunistic SYSRETL: if possible, try to return using SYSRETL.
|
||||
* SYSRETL is available on all 64-bit CPUs, so we don't need to
|
||||
* bother with SYSEXIT.
|
||||
*
|
||||
* Unlike 64-bit opportunistic SYSRET, we can't check that CX == IP,
|
||||
* because the ECX fixup above will ensure that this is essentially
|
||||
* never the case.
|
||||
* Check that the register state is valid for using SYSRETL/SYSEXIT
|
||||
* to exit to userspace. Otherwise use the slower but fully capable
|
||||
* IRET exit path.
|
||||
*/
|
||||
return regs->cs == __USER32_CS && regs->ss == __USER_DS &&
|
||||
regs->ip == landing_pad &&
|
||||
(regs->flags & (X86_EFLAGS_RF | X86_EFLAGS_TF)) == 0;
|
||||
#else
|
||||
/*
|
||||
* Opportunistic SYSEXIT: if possible, try to return using SYSEXIT.
|
||||
*
|
||||
* Unlike 64-bit opportunistic SYSRET, we can't check that CX == IP,
|
||||
* because the ECX fixup above will ensure that this is essentially
|
||||
* never the case.
|
||||
*
|
||||
* We don't allow syscalls at all from VM86 mode, but we still
|
||||
* need to check VM, because we might be returning from sys_vm86.
|
||||
*/
|
||||
return static_cpu_has(X86_FEATURE_SEP) &&
|
||||
regs->cs == __USER_CS && regs->ss == __USER_DS &&
|
||||
regs->ip == landing_pad &&
|
||||
(regs->flags & (X86_EFLAGS_RF | X86_EFLAGS_TF | X86_EFLAGS_VM)) == 0;
|
||||
#endif
|
||||
|
||||
/* XEN PV guests always use the IRET path */
|
||||
if (cpu_feature_enabled(X86_FEATURE_XENPV))
|
||||
return false;
|
||||
|
||||
/* EIP must point to the VDSO landing pad */
|
||||
if (unlikely(regs->ip != landing_pad))
|
||||
return false;
|
||||
|
||||
/* CS and SS must match the values set in MSR_STAR */
|
||||
if (unlikely(regs->cs != __USER32_CS || regs->ss != __USER_DS))
|
||||
return false;
|
||||
|
||||
/* If the TF, RF, or VM flags are set, use IRET */
|
||||
if (unlikely(regs->flags & (X86_EFLAGS_RF | X86_EFLAGS_TF | X86_EFLAGS_VM)))
|
||||
return false;
|
||||
|
||||
/* Use SYSRETL/SYSEXIT to exit to userspace */
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns 0 to return using IRET or 1 to return using SYSEXIT/SYSRETL. */
|
||||
__visible noinstr long do_SYSENTER_32(struct pt_regs *regs)
|
||||
/* Returns true to return using SYSEXIT/SYSRETL, or false to use IRET */
|
||||
__visible noinstr bool do_SYSENTER_32(struct pt_regs *regs)
|
||||
{
|
||||
/* SYSENTER loses RSP, but the vDSO saved it in RBP. */
|
||||
regs->sp = regs->bp;
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
* Common place for both 32- and 64-bit entry routines.
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/export.h>
|
||||
#include <asm/msr-index.h>
|
||||
|
||||
.pushsection .noinstr.text, "ax"
|
||||
|
||||
@@ -837,7 +837,7 @@ SYM_FUNC_START(entry_SYSENTER_32)
|
||||
|
||||
movl %esp, %eax
|
||||
call do_SYSENTER_32
|
||||
testl %eax, %eax
|
||||
testb %al, %al
|
||||
jz .Lsyscall_32_done
|
||||
|
||||
STACKLEAK_ERASE
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
* - SYM_FUNC_START/END:Define functions in the symbol table.
|
||||
* - idtentry: Define exception entry points.
|
||||
*/
|
||||
#include <linux/export.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/segment.h>
|
||||
#include <asm/cache.h>
|
||||
@@ -34,7 +35,6 @@
|
||||
#include <asm/asm.h>
|
||||
#include <asm/smap.h>
|
||||
#include <asm/pgtable_types.h>
|
||||
#include <asm/export.h>
|
||||
#include <asm/frame.h>
|
||||
#include <asm/trapnr.h>
|
||||
#include <asm/nospec-branch.h>
|
||||
@@ -126,70 +126,8 @@ SYM_INNER_LABEL(entry_SYSCALL_64_after_hwframe, SYM_L_GLOBAL)
|
||||
* In the Xen PV case we must use iret anyway.
|
||||
*/
|
||||
|
||||
ALTERNATIVE "", "jmp swapgs_restore_regs_and_return_to_usermode", \
|
||||
X86_FEATURE_XENPV
|
||||
|
||||
movq RCX(%rsp), %rcx
|
||||
movq RIP(%rsp), %r11
|
||||
|
||||
cmpq %rcx, %r11 /* SYSRET requires RCX == RIP */
|
||||
jne swapgs_restore_regs_and_return_to_usermode
|
||||
|
||||
/*
|
||||
* On Intel CPUs, SYSRET with non-canonical RCX/RIP will #GP
|
||||
* in kernel space. This essentially lets the user take over
|
||||
* the kernel, since userspace controls RSP.
|
||||
*
|
||||
* If width of "canonical tail" ever becomes variable, this will need
|
||||
* to be updated to remain correct on both old and new CPUs.
|
||||
*
|
||||
* Change top bits to match most significant bit (47th or 56th bit
|
||||
* depending on paging mode) in the address.
|
||||
*/
|
||||
#ifdef CONFIG_X86_5LEVEL
|
||||
ALTERNATIVE "shl $(64 - 48), %rcx; sar $(64 - 48), %rcx", \
|
||||
"shl $(64 - 57), %rcx; sar $(64 - 57), %rcx", X86_FEATURE_LA57
|
||||
#else
|
||||
shl $(64 - (__VIRTUAL_MASK_SHIFT+1)), %rcx
|
||||
sar $(64 - (__VIRTUAL_MASK_SHIFT+1)), %rcx
|
||||
#endif
|
||||
|
||||
/* If this changed %rcx, it was not canonical */
|
||||
cmpq %rcx, %r11
|
||||
jne swapgs_restore_regs_and_return_to_usermode
|
||||
|
||||
cmpq $__USER_CS, CS(%rsp) /* CS must match SYSRET */
|
||||
jne swapgs_restore_regs_and_return_to_usermode
|
||||
|
||||
movq R11(%rsp), %r11
|
||||
cmpq %r11, EFLAGS(%rsp) /* R11 == RFLAGS */
|
||||
jne swapgs_restore_regs_and_return_to_usermode
|
||||
|
||||
/*
|
||||
* SYSCALL clears RF when it saves RFLAGS in R11 and SYSRET cannot
|
||||
* restore RF properly. If the slowpath sets it for whatever reason, we
|
||||
* need to restore it correctly.
|
||||
*
|
||||
* SYSRET can restore TF, but unlike IRET, restoring TF results in a
|
||||
* trap from userspace immediately after SYSRET. This would cause an
|
||||
* infinite loop whenever #DB happens with register state that satisfies
|
||||
* the opportunistic SYSRET conditions. For example, single-stepping
|
||||
* this user code:
|
||||
*
|
||||
* movq $stuck_here, %rcx
|
||||
* pushfq
|
||||
* popq %r11
|
||||
* stuck_here:
|
||||
*
|
||||
* would never get past 'stuck_here'.
|
||||
*/
|
||||
testq $(X86_EFLAGS_RF|X86_EFLAGS_TF), %r11
|
||||
jnz swapgs_restore_regs_and_return_to_usermode
|
||||
|
||||
/* nothing to check for RSP */
|
||||
|
||||
cmpq $__USER_DS, SS(%rsp) /* SS must match SYSRET */
|
||||
jne swapgs_restore_regs_and_return_to_usermode
|
||||
ALTERNATIVE "testb %al, %al; jz swapgs_restore_regs_and_return_to_usermode", \
|
||||
"jmp swapgs_restore_regs_and_return_to_usermode", X86_FEATURE_XENPV
|
||||
|
||||
/*
|
||||
* We win! This label is here just for ease of understanding
|
||||
@@ -1163,8 +1101,8 @@ SYM_CODE_START(asm_exc_nmi)
|
||||
* anyway.
|
||||
*
|
||||
* To handle this case we do the following:
|
||||
* Check the a special location on the stack that contains
|
||||
* a variable that is set when NMIs are executing.
|
||||
* Check a special location on the stack that contains a
|
||||
* variable that is set when NMIs are executing.
|
||||
* The interrupted task's stack is also checked to see if it
|
||||
* is an NMI stack.
|
||||
* If the variable is not set and the stack is not the NMI
|
||||
@@ -1237,7 +1175,6 @@ SYM_CODE_START(asm_exc_nmi)
|
||||
*/
|
||||
|
||||
movq %rsp, %rdi
|
||||
movq $-1, %rsi
|
||||
call exc_nmi
|
||||
|
||||
/*
|
||||
@@ -1295,8 +1232,8 @@ SYM_CODE_START(asm_exc_nmi)
|
||||
* end_repeat_nmi, then we are a nested NMI. We must not
|
||||
* modify the "iret" frame because it's being written by
|
||||
* the outer NMI. That's okay; the outer NMI handler is
|
||||
* about to about to call exc_nmi() anyway, so we can just
|
||||
* resume the outer NMI.
|
||||
* about to call exc_nmi() anyway, so we can just resume
|
||||
* the outer NMI.
|
||||
*/
|
||||
|
||||
movq $repeat_nmi, %rdx
|
||||
@@ -1451,7 +1388,6 @@ end_repeat_nmi:
|
||||
UNWIND_HINT_REGS
|
||||
|
||||
movq %rsp, %rdi
|
||||
movq $-1, %rsi
|
||||
call exc_nmi
|
||||
|
||||
/* Always restore stashed SPEC_CTRL value (see paranoid_entry) */
|
||||
@@ -1511,18 +1447,16 @@ nmi_restore:
|
||||
iretq
|
||||
SYM_CODE_END(asm_exc_nmi)
|
||||
|
||||
#ifndef CONFIG_IA32_EMULATION
|
||||
/*
|
||||
* This handles SYSCALL from 32-bit code. There is no way to program
|
||||
* MSRs to fully disable 32-bit SYSCALL.
|
||||
*/
|
||||
SYM_CODE_START(ignore_sysret)
|
||||
SYM_CODE_START(entry_SYSCALL32_ignore)
|
||||
UNWIND_HINT_END_OF_STACK
|
||||
ENDBR
|
||||
mov $-ENOSYS, %eax
|
||||
sysretl
|
||||
SYM_CODE_END(ignore_sysret)
|
||||
#endif
|
||||
SYM_CODE_END(entry_SYSCALL32_ignore)
|
||||
|
||||
.pushsection .text, "ax"
|
||||
__FUNC_ALIGN
|
||||
|
||||
@@ -118,9 +118,6 @@ SYM_INNER_LABEL(entry_SYSENTER_compat_after_hwframe, SYM_L_GLOBAL)
|
||||
|
||||
movq %rsp, %rdi
|
||||
call do_SYSENTER_32
|
||||
/* XEN PV guests always use IRET path */
|
||||
ALTERNATIVE "testl %eax, %eax; jz swapgs_restore_regs_and_return_to_usermode", \
|
||||
"jmp swapgs_restore_regs_and_return_to_usermode", X86_FEATURE_XENPV
|
||||
jmp sysret32_from_system_call
|
||||
|
||||
.Lsysenter_fix_flags:
|
||||
@@ -212,13 +209,15 @@ SYM_INNER_LABEL(entry_SYSCALL_compat_after_hwframe, SYM_L_GLOBAL)
|
||||
|
||||
movq %rsp, %rdi
|
||||
call do_fast_syscall_32
|
||||
|
||||
sysret32_from_system_call:
|
||||
/* XEN PV guests always use IRET path */
|
||||
ALTERNATIVE "testl %eax, %eax; jz swapgs_restore_regs_and_return_to_usermode", \
|
||||
ALTERNATIVE "testb %al, %al; jz swapgs_restore_regs_and_return_to_usermode", \
|
||||
"jmp swapgs_restore_regs_and_return_to_usermode", X86_FEATURE_XENPV
|
||||
|
||||
/* Opportunistic SYSRET */
|
||||
sysret32_from_system_call:
|
||||
/*
|
||||
* Opportunistic SYSRET
|
||||
*
|
||||
* We are not going to return to userspace from the trampoline
|
||||
* stack. So let's erase the thread stack right now.
|
||||
*/
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* Copyright 2008 by Steven Rostedt, Red Hat, Inc
|
||||
* (inspired by Andi Kleen's thunk_64.S)
|
||||
*/
|
||||
#include <linux/export.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/asm.h>
|
||||
#include <asm/export.h>
|
||||
|
||||
/* put return address in eax (arg1) */
|
||||
.macro THUNK name, func, put_ret_addr_in_eax=0
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
* disturbance of register allocation in some inline assembly constructs.
|
||||
* Copyright 2001,2002 by Andi Kleen, SuSE Labs.
|
||||
*/
|
||||
#include <linux/export.h>
|
||||
#include <linux/linkage.h>
|
||||
#include "calling.h"
|
||||
#include <asm/asm.h>
|
||||
#include <asm/export.h>
|
||||
|
||||
/* rdi: arg1 ... normal C conventions. rax is saved/restored. */
|
||||
.macro THUNK name, func
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/export.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/enclu.h>
|
||||
|
||||
|
||||
+722
-394
File diff suppressed because it is too large
Load Diff
@@ -1887,9 +1887,9 @@ ssize_t events_hybrid_sysfs_show(struct device *dev,
|
||||
|
||||
str = pmu_attr->event_str;
|
||||
for (i = 0; i < x86_pmu.num_hybrid_pmus; i++) {
|
||||
if (!(x86_pmu.hybrid_pmu[i].cpu_type & pmu_attr->pmu_type))
|
||||
if (!(x86_pmu.hybrid_pmu[i].pmu_type & pmu_attr->pmu_type))
|
||||
continue;
|
||||
if (x86_pmu.hybrid_pmu[i].cpu_type & pmu->cpu_type) {
|
||||
if (x86_pmu.hybrid_pmu[i].pmu_type & pmu->pmu_type) {
|
||||
next_str = strchr(str, ';');
|
||||
if (next_str)
|
||||
return snprintf(page, next_str - str + 1, "%s", str);
|
||||
@@ -2169,7 +2169,7 @@ static int __init init_hw_perf_events(void)
|
||||
hybrid_pmu->pmu.capabilities |= PERF_PMU_CAP_EXTENDED_HW_TYPE;
|
||||
|
||||
err = perf_pmu_register(&hybrid_pmu->pmu, hybrid_pmu->name,
|
||||
(hybrid_pmu->cpu_type == hybrid_big) ? PERF_TYPE_RAW : -1);
|
||||
(hybrid_pmu->pmu_type == hybrid_big) ? PERF_TYPE_RAW : -1);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
||||
+257
-228
@@ -211,6 +211,14 @@ static struct event_constraint intel_slm_event_constraints[] __read_mostly =
|
||||
EVENT_CONSTRAINT_END
|
||||
};
|
||||
|
||||
static struct event_constraint intel_grt_event_constraints[] __read_mostly = {
|
||||
FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
|
||||
FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */
|
||||
FIXED_EVENT_CONSTRAINT(0x0300, 2), /* pseudo CPU_CLK_UNHALTED.REF */
|
||||
FIXED_EVENT_CONSTRAINT(0x013c, 2), /* CPU_CLK_UNHALTED.REF_TSC_P */
|
||||
EVENT_CONSTRAINT_END
|
||||
};
|
||||
|
||||
static struct event_constraint intel_skl_event_constraints[] = {
|
||||
FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
|
||||
FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */
|
||||
@@ -299,7 +307,7 @@ static struct extra_reg intel_icl_extra_regs[] __read_mostly = {
|
||||
EVENT_EXTRA_END
|
||||
};
|
||||
|
||||
static struct extra_reg intel_spr_extra_regs[] __read_mostly = {
|
||||
static struct extra_reg intel_glc_extra_regs[] __read_mostly = {
|
||||
INTEL_UEVENT_EXTRA_REG(0x012a, MSR_OFFCORE_RSP_0, 0x3fffffffffull, RSP_0),
|
||||
INTEL_UEVENT_EXTRA_REG(0x012b, MSR_OFFCORE_RSP_1, 0x3fffffffffull, RSP_1),
|
||||
INTEL_UEVENT_PEBS_LDLAT_EXTRA_REG(0x01cd),
|
||||
@@ -309,11 +317,12 @@ static struct extra_reg intel_spr_extra_regs[] __read_mostly = {
|
||||
EVENT_EXTRA_END
|
||||
};
|
||||
|
||||
static struct event_constraint intel_spr_event_constraints[] = {
|
||||
static struct event_constraint intel_glc_event_constraints[] = {
|
||||
FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
|
||||
FIXED_EVENT_CONSTRAINT(0x0100, 0), /* INST_RETIRED.PREC_DIST */
|
||||
FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */
|
||||
FIXED_EVENT_CONSTRAINT(0x0300, 2), /* CPU_CLK_UNHALTED.REF */
|
||||
FIXED_EVENT_CONSTRAINT(0x013c, 2), /* CPU_CLK_UNHALTED.REF_TSC_P */
|
||||
FIXED_EVENT_CONSTRAINT(0x0400, 3), /* SLOTS */
|
||||
METRIC_EVENT_CONSTRAINT(INTEL_TD_METRIC_RETIRING, 0),
|
||||
METRIC_EVENT_CONSTRAINT(INTEL_TD_METRIC_BAD_SPEC, 1),
|
||||
@@ -349,7 +358,7 @@ static struct event_constraint intel_spr_event_constraints[] = {
|
||||
EVENT_CONSTRAINT_END
|
||||
};
|
||||
|
||||
static struct extra_reg intel_gnr_extra_regs[] __read_mostly = {
|
||||
static struct extra_reg intel_rwc_extra_regs[] __read_mostly = {
|
||||
INTEL_UEVENT_EXTRA_REG(0x012a, MSR_OFFCORE_RSP_0, 0x3fffffffffull, RSP_0),
|
||||
INTEL_UEVENT_EXTRA_REG(0x012b, MSR_OFFCORE_RSP_1, 0x3fffffffffull, RSP_1),
|
||||
INTEL_UEVENT_PEBS_LDLAT_EXTRA_REG(0x01cd),
|
||||
@@ -473,7 +482,7 @@ static u64 intel_pmu_event_map(int hw_event)
|
||||
return intel_perfmon_event_map[hw_event];
|
||||
}
|
||||
|
||||
static __initconst const u64 spr_hw_cache_event_ids
|
||||
static __initconst const u64 glc_hw_cache_event_ids
|
||||
[PERF_COUNT_HW_CACHE_MAX]
|
||||
[PERF_COUNT_HW_CACHE_OP_MAX]
|
||||
[PERF_COUNT_HW_CACHE_RESULT_MAX] =
|
||||
@@ -552,7 +561,7 @@ static __initconst const u64 spr_hw_cache_event_ids
|
||||
},
|
||||
};
|
||||
|
||||
static __initconst const u64 spr_hw_cache_extra_regs
|
||||
static __initconst const u64 glc_hw_cache_extra_regs
|
||||
[PERF_COUNT_HW_CACHE_MAX]
|
||||
[PERF_COUNT_HW_CACHE_OP_MAX]
|
||||
[PERF_COUNT_HW_CACHE_RESULT_MAX] =
|
||||
@@ -2556,16 +2565,6 @@ static int icl_set_topdown_event_period(struct perf_event *event)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adl_set_topdown_event_period(struct perf_event *event)
|
||||
{
|
||||
struct x86_hybrid_pmu *pmu = hybrid_pmu(event->pmu);
|
||||
|
||||
if (pmu->cpu_type != hybrid_big)
|
||||
return 0;
|
||||
|
||||
return icl_set_topdown_event_period(event);
|
||||
}
|
||||
|
||||
DEFINE_STATIC_CALL(intel_pmu_set_topdown_event_period, x86_perf_event_set_period);
|
||||
|
||||
static inline u64 icl_get_metrics_event_value(u64 metric, u64 slots, int idx)
|
||||
@@ -2708,16 +2707,6 @@ static u64 icl_update_topdown_event(struct perf_event *event)
|
||||
x86_pmu.num_topdown_events - 1);
|
||||
}
|
||||
|
||||
static u64 adl_update_topdown_event(struct perf_event *event)
|
||||
{
|
||||
struct x86_hybrid_pmu *pmu = hybrid_pmu(event->pmu);
|
||||
|
||||
if (pmu->cpu_type != hybrid_big)
|
||||
return 0;
|
||||
|
||||
return icl_update_topdown_event(event);
|
||||
}
|
||||
|
||||
DEFINE_STATIC_CALL(intel_pmu_update_topdown_event, x86_perf_event_update);
|
||||
|
||||
static void intel_pmu_read_topdown_event(struct perf_event *event)
|
||||
@@ -3869,7 +3858,7 @@ static inline bool require_mem_loads_aux_event(struct perf_event *event)
|
||||
return false;
|
||||
|
||||
if (is_hybrid())
|
||||
return hybrid_pmu(event->pmu)->cpu_type == hybrid_big;
|
||||
return hybrid_pmu(event->pmu)->pmu_type == hybrid_big;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -4273,7 +4262,7 @@ icl_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
|
||||
}
|
||||
|
||||
static struct event_constraint *
|
||||
spr_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
|
||||
glc_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
|
||||
struct perf_event *event)
|
||||
{
|
||||
struct event_constraint *c;
|
||||
@@ -4361,9 +4350,9 @@ adl_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
|
||||
{
|
||||
struct x86_hybrid_pmu *pmu = hybrid_pmu(event->pmu);
|
||||
|
||||
if (pmu->cpu_type == hybrid_big)
|
||||
return spr_get_event_constraints(cpuc, idx, event);
|
||||
else if (pmu->cpu_type == hybrid_small)
|
||||
if (pmu->pmu_type == hybrid_big)
|
||||
return glc_get_event_constraints(cpuc, idx, event);
|
||||
else if (pmu->pmu_type == hybrid_small)
|
||||
return tnt_get_event_constraints(cpuc, idx, event);
|
||||
|
||||
WARN_ON(1);
|
||||
@@ -4409,7 +4398,7 @@ rwc_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
|
||||
{
|
||||
struct event_constraint *c;
|
||||
|
||||
c = spr_get_event_constraints(cpuc, idx, event);
|
||||
c = glc_get_event_constraints(cpuc, idx, event);
|
||||
|
||||
/* The Retire Latency is not supported by the fixed counter 0. */
|
||||
if (event->attr.precise_ip &&
|
||||
@@ -4433,9 +4422,9 @@ mtl_get_event_constraints(struct cpu_hw_events *cpuc, int idx,
|
||||
{
|
||||
struct x86_hybrid_pmu *pmu = hybrid_pmu(event->pmu);
|
||||
|
||||
if (pmu->cpu_type == hybrid_big)
|
||||
if (pmu->pmu_type == hybrid_big)
|
||||
return rwc_get_event_constraints(cpuc, idx, event);
|
||||
if (pmu->cpu_type == hybrid_small)
|
||||
if (pmu->pmu_type == hybrid_small)
|
||||
return cmt_get_event_constraints(cpuc, idx, event);
|
||||
|
||||
WARN_ON(1);
|
||||
@@ -4446,18 +4435,18 @@ static int adl_hw_config(struct perf_event *event)
|
||||
{
|
||||
struct x86_hybrid_pmu *pmu = hybrid_pmu(event->pmu);
|
||||
|
||||
if (pmu->cpu_type == hybrid_big)
|
||||
if (pmu->pmu_type == hybrid_big)
|
||||
return hsw_hw_config(event);
|
||||
else if (pmu->cpu_type == hybrid_small)
|
||||
else if (pmu->pmu_type == hybrid_small)
|
||||
return intel_pmu_hw_config(event);
|
||||
|
||||
WARN_ON(1);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static u8 adl_get_hybrid_cpu_type(void)
|
||||
static enum hybrid_cpu_type adl_get_hybrid_cpu_type(void)
|
||||
{
|
||||
return hybrid_big;
|
||||
return HYBRID_INTEL_CORE;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4490,7 +4479,7 @@ static void nhm_limit_period(struct perf_event *event, s64 *left)
|
||||
*left = max(*left, 32LL);
|
||||
}
|
||||
|
||||
static void spr_limit_period(struct perf_event *event, s64 *left)
|
||||
static void glc_limit_period(struct perf_event *event, s64 *left)
|
||||
{
|
||||
if (event->attr.precise_ip == 3)
|
||||
*left = max(*left, 128LL);
|
||||
@@ -4618,6 +4607,23 @@ static void intel_pmu_check_num_counters(int *num_counters,
|
||||
int *num_counters_fixed,
|
||||
u64 *intel_ctrl, u64 fixed_mask);
|
||||
|
||||
static void intel_pmu_check_event_constraints(struct event_constraint *event_constraints,
|
||||
int num_counters,
|
||||
int num_counters_fixed,
|
||||
u64 intel_ctrl);
|
||||
|
||||
static void intel_pmu_check_extra_regs(struct extra_reg *extra_regs);
|
||||
|
||||
static inline bool intel_pmu_broken_perf_cap(void)
|
||||
{
|
||||
/* The Perf Metric (Bit 15) is always cleared */
|
||||
if ((boot_cpu_data.x86_model == INTEL_FAM6_METEORLAKE) ||
|
||||
(boot_cpu_data.x86_model == INTEL_FAM6_METEORLAKE_L))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void update_pmu_cap(struct x86_hybrid_pmu *pmu)
|
||||
{
|
||||
unsigned int sub_bitmaps = cpuid_eax(ARCH_PERFMON_EXT_LEAF);
|
||||
@@ -4628,27 +4634,83 @@ static void update_pmu_cap(struct x86_hybrid_pmu *pmu)
|
||||
&eax, &ebx, &ecx, &edx);
|
||||
pmu->num_counters = fls(eax);
|
||||
pmu->num_counters_fixed = fls(ebx);
|
||||
intel_pmu_check_num_counters(&pmu->num_counters, &pmu->num_counters_fixed,
|
||||
&pmu->intel_ctrl, ebx);
|
||||
}
|
||||
|
||||
|
||||
if (!intel_pmu_broken_perf_cap()) {
|
||||
/* Perf Metric (Bit 15) and PEBS via PT (Bit 16) are hybrid enumeration */
|
||||
rdmsrl(MSR_IA32_PERF_CAPABILITIES, pmu->intel_cap.capabilities);
|
||||
}
|
||||
}
|
||||
|
||||
static void intel_pmu_check_hybrid_pmus(struct x86_hybrid_pmu *pmu)
|
||||
{
|
||||
intel_pmu_check_num_counters(&pmu->num_counters, &pmu->num_counters_fixed,
|
||||
&pmu->intel_ctrl, (1ULL << pmu->num_counters_fixed) - 1);
|
||||
pmu->max_pebs_events = min_t(unsigned, MAX_PEBS_EVENTS, pmu->num_counters);
|
||||
pmu->unconstrained = (struct event_constraint)
|
||||
__EVENT_CONSTRAINT(0, (1ULL << pmu->num_counters) - 1,
|
||||
0, pmu->num_counters, 0, 0);
|
||||
|
||||
if (pmu->intel_cap.perf_metrics)
|
||||
pmu->intel_ctrl |= 1ULL << GLOBAL_CTRL_EN_PERF_METRICS;
|
||||
else
|
||||
pmu->intel_ctrl &= ~(1ULL << GLOBAL_CTRL_EN_PERF_METRICS);
|
||||
|
||||
if (pmu->intel_cap.pebs_output_pt_available)
|
||||
pmu->pmu.capabilities |= PERF_PMU_CAP_AUX_OUTPUT;
|
||||
else
|
||||
pmu->pmu.capabilities |= ~PERF_PMU_CAP_AUX_OUTPUT;
|
||||
|
||||
intel_pmu_check_event_constraints(pmu->event_constraints,
|
||||
pmu->num_counters,
|
||||
pmu->num_counters_fixed,
|
||||
pmu->intel_ctrl);
|
||||
|
||||
intel_pmu_check_extra_regs(pmu->extra_regs);
|
||||
}
|
||||
|
||||
static struct x86_hybrid_pmu *find_hybrid_pmu_for_cpu(void)
|
||||
{
|
||||
u8 cpu_type = get_this_hybrid_cpu_type();
|
||||
int i;
|
||||
|
||||
/*
|
||||
* This is running on a CPU model that is known to have hybrid
|
||||
* configurations. But the CPU told us it is not hybrid, shame
|
||||
* on it. There should be a fixup function provided for these
|
||||
* troublesome CPUs (->get_hybrid_cpu_type).
|
||||
*/
|
||||
if (cpu_type == HYBRID_INTEL_NONE) {
|
||||
if (x86_pmu.get_hybrid_cpu_type)
|
||||
cpu_type = x86_pmu.get_hybrid_cpu_type();
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* This essentially just maps between the 'hybrid_cpu_type'
|
||||
* and 'hybrid_pmu_type' enums:
|
||||
*/
|
||||
for (i = 0; i < x86_pmu.num_hybrid_pmus; i++) {
|
||||
enum hybrid_pmu_type pmu_type = x86_pmu.hybrid_pmu[i].pmu_type;
|
||||
|
||||
if (cpu_type == HYBRID_INTEL_CORE &&
|
||||
pmu_type == hybrid_big)
|
||||
return &x86_pmu.hybrid_pmu[i];
|
||||
if (cpu_type == HYBRID_INTEL_ATOM &&
|
||||
pmu_type == hybrid_small)
|
||||
return &x86_pmu.hybrid_pmu[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool init_hybrid_pmu(int cpu)
|
||||
{
|
||||
struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
|
||||
u8 cpu_type = get_this_hybrid_cpu_type();
|
||||
struct x86_hybrid_pmu *pmu = NULL;
|
||||
int i;
|
||||
struct x86_hybrid_pmu *pmu = find_hybrid_pmu_for_cpu();
|
||||
|
||||
if (!cpu_type && x86_pmu.get_hybrid_cpu_type)
|
||||
cpu_type = x86_pmu.get_hybrid_cpu_type();
|
||||
|
||||
for (i = 0; i < x86_pmu.num_hybrid_pmus; i++) {
|
||||
if (x86_pmu.hybrid_pmu[i].cpu_type == cpu_type) {
|
||||
pmu = &x86_pmu.hybrid_pmu[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (WARN_ON_ONCE(!pmu || (pmu->pmu.type == -1))) {
|
||||
cpuc->pmu = NULL;
|
||||
return false;
|
||||
@@ -4661,6 +4723,8 @@ static bool init_hybrid_pmu(int cpu)
|
||||
if (this_cpu_has(X86_FEATURE_ARCH_PERFMON_EXT))
|
||||
update_pmu_cap(pmu);
|
||||
|
||||
intel_pmu_check_hybrid_pmus(pmu);
|
||||
|
||||
if (!check_hw_exists(&pmu->pmu, pmu->num_counters, pmu->num_counters_fixed))
|
||||
return false;
|
||||
|
||||
@@ -5337,14 +5401,14 @@ static struct attribute *icl_tsx_events_attrs[] = {
|
||||
EVENT_ATTR_STR(mem-stores, mem_st_spr, "event=0xcd,umask=0x2");
|
||||
EVENT_ATTR_STR(mem-loads-aux, mem_ld_aux, "event=0x03,umask=0x82");
|
||||
|
||||
static struct attribute *spr_events_attrs[] = {
|
||||
static struct attribute *glc_events_attrs[] = {
|
||||
EVENT_PTR(mem_ld_hsw),
|
||||
EVENT_PTR(mem_st_spr),
|
||||
EVENT_PTR(mem_ld_aux),
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute *spr_td_events_attrs[] = {
|
||||
static struct attribute *glc_td_events_attrs[] = {
|
||||
EVENT_PTR(slots),
|
||||
EVENT_PTR(td_retiring),
|
||||
EVENT_PTR(td_bad_spec),
|
||||
@@ -5357,7 +5421,7 @@ static struct attribute *spr_td_events_attrs[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute *spr_tsx_events_attrs[] = {
|
||||
static struct attribute *glc_tsx_events_attrs[] = {
|
||||
EVENT_PTR(tx_start),
|
||||
EVENT_PTR(tx_abort),
|
||||
EVENT_PTR(tx_commit),
|
||||
@@ -5699,7 +5763,7 @@ static bool is_attr_for_this_pmu(struct kobject *kobj, struct attribute *attr)
|
||||
struct perf_pmu_events_hybrid_attr *pmu_attr =
|
||||
container_of(attr, struct perf_pmu_events_hybrid_attr, attr.attr);
|
||||
|
||||
return pmu->cpu_type & pmu_attr->pmu_type;
|
||||
return pmu->pmu_type & pmu_attr->pmu_type;
|
||||
}
|
||||
|
||||
static umode_t hybrid_events_is_visible(struct kobject *kobj,
|
||||
@@ -5736,7 +5800,7 @@ static umode_t hybrid_format_is_visible(struct kobject *kobj,
|
||||
container_of(attr, struct perf_pmu_format_hybrid_attr, attr.attr);
|
||||
int cpu = hybrid_find_supported_cpu(pmu);
|
||||
|
||||
return (cpu >= 0) && (pmu->cpu_type & pmu_attr->pmu_type) ? attr->mode : 0;
|
||||
return (cpu >= 0) && (pmu->pmu_type & pmu_attr->pmu_type) ? attr->mode : 0;
|
||||
}
|
||||
|
||||
static struct attribute_group hybrid_group_events_td = {
|
||||
@@ -5880,40 +5944,105 @@ static void intel_pmu_check_extra_regs(struct extra_reg *extra_regs)
|
||||
}
|
||||
}
|
||||
|
||||
static void intel_pmu_check_hybrid_pmus(u64 fixed_mask)
|
||||
static const struct { enum hybrid_pmu_type id; char *name; } intel_hybrid_pmu_type_map[] __initconst = {
|
||||
{ hybrid_small, "cpu_atom" },
|
||||
{ hybrid_big, "cpu_core" },
|
||||
};
|
||||
|
||||
static __always_inline int intel_pmu_init_hybrid(enum hybrid_pmu_type pmus)
|
||||
{
|
||||
unsigned long pmus_mask = pmus;
|
||||
struct x86_hybrid_pmu *pmu;
|
||||
int i;
|
||||
int idx = 0, bit;
|
||||
|
||||
for (i = 0; i < x86_pmu.num_hybrid_pmus; i++) {
|
||||
pmu = &x86_pmu.hybrid_pmu[i];
|
||||
x86_pmu.num_hybrid_pmus = hweight_long(pmus_mask);
|
||||
x86_pmu.hybrid_pmu = kcalloc(x86_pmu.num_hybrid_pmus,
|
||||
sizeof(struct x86_hybrid_pmu),
|
||||
GFP_KERNEL);
|
||||
if (!x86_pmu.hybrid_pmu)
|
||||
return -ENOMEM;
|
||||
|
||||
intel_pmu_check_num_counters(&pmu->num_counters,
|
||||
&pmu->num_counters_fixed,
|
||||
&pmu->intel_ctrl,
|
||||
fixed_mask);
|
||||
static_branch_enable(&perf_is_hybrid);
|
||||
x86_pmu.filter = intel_pmu_filter;
|
||||
|
||||
if (pmu->intel_cap.perf_metrics) {
|
||||
pmu->intel_ctrl |= 1ULL << GLOBAL_CTRL_EN_PERF_METRICS;
|
||||
pmu->intel_ctrl |= INTEL_PMC_MSK_FIXED_SLOTS;
|
||||
for_each_set_bit(bit, &pmus_mask, ARRAY_SIZE(intel_hybrid_pmu_type_map)) {
|
||||
pmu = &x86_pmu.hybrid_pmu[idx++];
|
||||
pmu->pmu_type = intel_hybrid_pmu_type_map[bit].id;
|
||||
pmu->name = intel_hybrid_pmu_type_map[bit].name;
|
||||
|
||||
pmu->num_counters = x86_pmu.num_counters;
|
||||
pmu->num_counters_fixed = x86_pmu.num_counters_fixed;
|
||||
pmu->max_pebs_events = min_t(unsigned, MAX_PEBS_EVENTS, pmu->num_counters);
|
||||
pmu->unconstrained = (struct event_constraint)
|
||||
__EVENT_CONSTRAINT(0, (1ULL << pmu->num_counters) - 1,
|
||||
0, pmu->num_counters, 0, 0);
|
||||
|
||||
pmu->intel_cap.capabilities = x86_pmu.intel_cap.capabilities;
|
||||
if (pmu->pmu_type & hybrid_small) {
|
||||
pmu->intel_cap.perf_metrics = 0;
|
||||
pmu->intel_cap.pebs_output_pt_available = 1;
|
||||
pmu->mid_ack = true;
|
||||
} else if (pmu->pmu_type & hybrid_big) {
|
||||
pmu->intel_cap.perf_metrics = 1;
|
||||
pmu->intel_cap.pebs_output_pt_available = 0;
|
||||
pmu->late_ack = true;
|
||||
}
|
||||
|
||||
if (pmu->intel_cap.pebs_output_pt_available)
|
||||
pmu->pmu.capabilities |= PERF_PMU_CAP_AUX_OUTPUT;
|
||||
|
||||
intel_pmu_check_event_constraints(pmu->event_constraints,
|
||||
pmu->num_counters,
|
||||
pmu->num_counters_fixed,
|
||||
pmu->intel_ctrl);
|
||||
|
||||
intel_pmu_check_extra_regs(pmu->extra_regs);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __always_inline bool is_mtl(u8 x86_model)
|
||||
static __always_inline void intel_pmu_ref_cycles_ext(void)
|
||||
{
|
||||
return (x86_model == INTEL_FAM6_METEORLAKE) ||
|
||||
(x86_model == INTEL_FAM6_METEORLAKE_L);
|
||||
if (!(x86_pmu.events_maskl & (INTEL_PMC_MSK_FIXED_REF_CYCLES >> INTEL_PMC_IDX_FIXED)))
|
||||
intel_perfmon_event_map[PERF_COUNT_HW_REF_CPU_CYCLES] = 0x013c;
|
||||
}
|
||||
|
||||
static __always_inline void intel_pmu_init_glc(struct pmu *pmu)
|
||||
{
|
||||
x86_pmu.late_ack = true;
|
||||
x86_pmu.limit_period = glc_limit_period;
|
||||
x86_pmu.pebs_aliases = NULL;
|
||||
x86_pmu.pebs_prec_dist = true;
|
||||
x86_pmu.pebs_block = true;
|
||||
x86_pmu.flags |= PMU_FL_HAS_RSP_1;
|
||||
x86_pmu.flags |= PMU_FL_NO_HT_SHARING;
|
||||
x86_pmu.flags |= PMU_FL_INSTR_LATENCY;
|
||||
x86_pmu.rtm_abort_event = X86_CONFIG(.event=0xc9, .umask=0x04);
|
||||
x86_pmu.lbr_pt_coexist = true;
|
||||
x86_pmu.num_topdown_events = 8;
|
||||
static_call_update(intel_pmu_update_topdown_event,
|
||||
&icl_update_topdown_event);
|
||||
static_call_update(intel_pmu_set_topdown_event_period,
|
||||
&icl_set_topdown_event_period);
|
||||
|
||||
memcpy(hybrid_var(pmu, hw_cache_event_ids), glc_hw_cache_event_ids, sizeof(hw_cache_event_ids));
|
||||
memcpy(hybrid_var(pmu, hw_cache_extra_regs), glc_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
|
||||
hybrid(pmu, event_constraints) = intel_glc_event_constraints;
|
||||
hybrid(pmu, pebs_constraints) = intel_glc_pebs_event_constraints;
|
||||
|
||||
intel_pmu_ref_cycles_ext();
|
||||
}
|
||||
|
||||
static __always_inline void intel_pmu_init_grt(struct pmu *pmu)
|
||||
{
|
||||
x86_pmu.mid_ack = true;
|
||||
x86_pmu.limit_period = glc_limit_period;
|
||||
x86_pmu.pebs_aliases = NULL;
|
||||
x86_pmu.pebs_prec_dist = true;
|
||||
x86_pmu.pebs_block = true;
|
||||
x86_pmu.lbr_pt_coexist = true;
|
||||
x86_pmu.flags |= PMU_FL_HAS_RSP_1;
|
||||
x86_pmu.flags |= PMU_FL_INSTR_LATENCY;
|
||||
|
||||
memcpy(hybrid_var(pmu, hw_cache_event_ids), glp_hw_cache_event_ids, sizeof(hw_cache_event_ids));
|
||||
memcpy(hybrid_var(pmu, hw_cache_extra_regs), tnt_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
|
||||
hybrid_var(pmu, hw_cache_event_ids)[C(ITLB)][C(OP_READ)][C(RESULT_ACCESS)] = -1;
|
||||
hybrid(pmu, event_constraints) = intel_grt_event_constraints;
|
||||
hybrid(pmu, pebs_constraints) = intel_grt_pebs_event_constraints;
|
||||
hybrid(pmu, extra_regs) = intel_grt_extra_regs;
|
||||
|
||||
intel_pmu_ref_cycles_ext();
|
||||
}
|
||||
|
||||
__init int intel_pmu_init(void)
|
||||
@@ -6194,28 +6323,10 @@ __init int intel_pmu_init(void)
|
||||
break;
|
||||
|
||||
case INTEL_FAM6_ATOM_GRACEMONT:
|
||||
x86_pmu.mid_ack = true;
|
||||
memcpy(hw_cache_event_ids, glp_hw_cache_event_ids,
|
||||
sizeof(hw_cache_event_ids));
|
||||
memcpy(hw_cache_extra_regs, tnt_hw_cache_extra_regs,
|
||||
sizeof(hw_cache_extra_regs));
|
||||
hw_cache_event_ids[C(ITLB)][C(OP_READ)][C(RESULT_ACCESS)] = -1;
|
||||
|
||||
x86_pmu.event_constraints = intel_slm_event_constraints;
|
||||
x86_pmu.pebs_constraints = intel_grt_pebs_event_constraints;
|
||||
x86_pmu.extra_regs = intel_grt_extra_regs;
|
||||
|
||||
x86_pmu.pebs_aliases = NULL;
|
||||
x86_pmu.pebs_prec_dist = true;
|
||||
x86_pmu.pebs_block = true;
|
||||
x86_pmu.lbr_pt_coexist = true;
|
||||
x86_pmu.flags |= PMU_FL_HAS_RSP_1;
|
||||
x86_pmu.flags |= PMU_FL_INSTR_LATENCY;
|
||||
|
||||
intel_pmu_init_grt(NULL);
|
||||
intel_pmu_pebs_data_source_grt();
|
||||
x86_pmu.pebs_latency_data = adl_latency_data_small;
|
||||
x86_pmu.get_event_constraints = tnt_get_event_constraints;
|
||||
x86_pmu.limit_period = spr_limit_period;
|
||||
td_attr = tnt_events_attrs;
|
||||
mem_attr = grt_mem_attrs;
|
||||
extra_attr = nhm_format_attr;
|
||||
@@ -6225,28 +6336,11 @@ __init int intel_pmu_init(void)
|
||||
|
||||
case INTEL_FAM6_ATOM_CRESTMONT:
|
||||
case INTEL_FAM6_ATOM_CRESTMONT_X:
|
||||
x86_pmu.mid_ack = true;
|
||||
memcpy(hw_cache_event_ids, glp_hw_cache_event_ids,
|
||||
sizeof(hw_cache_event_ids));
|
||||
memcpy(hw_cache_extra_regs, tnt_hw_cache_extra_regs,
|
||||
sizeof(hw_cache_extra_regs));
|
||||
hw_cache_event_ids[C(ITLB)][C(OP_READ)][C(RESULT_ACCESS)] = -1;
|
||||
|
||||
x86_pmu.event_constraints = intel_slm_event_constraints;
|
||||
x86_pmu.pebs_constraints = intel_grt_pebs_event_constraints;
|
||||
intel_pmu_init_grt(NULL);
|
||||
x86_pmu.extra_regs = intel_cmt_extra_regs;
|
||||
|
||||
x86_pmu.pebs_aliases = NULL;
|
||||
x86_pmu.pebs_prec_dist = true;
|
||||
x86_pmu.lbr_pt_coexist = true;
|
||||
x86_pmu.pebs_block = true;
|
||||
x86_pmu.flags |= PMU_FL_HAS_RSP_1;
|
||||
x86_pmu.flags |= PMU_FL_INSTR_LATENCY;
|
||||
|
||||
intel_pmu_pebs_data_source_cmt();
|
||||
x86_pmu.pebs_latency_data = mtl_latency_data_small;
|
||||
x86_pmu.get_event_constraints = cmt_get_event_constraints;
|
||||
x86_pmu.limit_period = spr_limit_period;
|
||||
td_attr = cmt_events_attrs;
|
||||
mem_attr = grt_mem_attrs;
|
||||
extra_attr = cmt_format_attr;
|
||||
@@ -6563,44 +6657,23 @@ __init int intel_pmu_init(void)
|
||||
case INTEL_FAM6_SAPPHIRERAPIDS_X:
|
||||
case INTEL_FAM6_EMERALDRAPIDS_X:
|
||||
x86_pmu.flags |= PMU_FL_MEM_LOADS_AUX;
|
||||
x86_pmu.extra_regs = intel_spr_extra_regs;
|
||||
x86_pmu.extra_regs = intel_glc_extra_regs;
|
||||
fallthrough;
|
||||
case INTEL_FAM6_GRANITERAPIDS_X:
|
||||
case INTEL_FAM6_GRANITERAPIDS_D:
|
||||
pmem = true;
|
||||
x86_pmu.late_ack = true;
|
||||
memcpy(hw_cache_event_ids, spr_hw_cache_event_ids, sizeof(hw_cache_event_ids));
|
||||
memcpy(hw_cache_extra_regs, spr_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
|
||||
|
||||
x86_pmu.event_constraints = intel_spr_event_constraints;
|
||||
x86_pmu.pebs_constraints = intel_spr_pebs_event_constraints;
|
||||
intel_pmu_init_glc(NULL);
|
||||
if (!x86_pmu.extra_regs)
|
||||
x86_pmu.extra_regs = intel_gnr_extra_regs;
|
||||
x86_pmu.limit_period = spr_limit_period;
|
||||
x86_pmu.extra_regs = intel_rwc_extra_regs;
|
||||
x86_pmu.pebs_ept = 1;
|
||||
x86_pmu.pebs_aliases = NULL;
|
||||
x86_pmu.pebs_prec_dist = true;
|
||||
x86_pmu.pebs_block = true;
|
||||
x86_pmu.flags |= PMU_FL_HAS_RSP_1;
|
||||
x86_pmu.flags |= PMU_FL_NO_HT_SHARING;
|
||||
x86_pmu.flags |= PMU_FL_INSTR_LATENCY;
|
||||
|
||||
x86_pmu.hw_config = hsw_hw_config;
|
||||
x86_pmu.get_event_constraints = spr_get_event_constraints;
|
||||
x86_pmu.get_event_constraints = glc_get_event_constraints;
|
||||
extra_attr = boot_cpu_has(X86_FEATURE_RTM) ?
|
||||
hsw_format_attr : nhm_format_attr;
|
||||
extra_skl_attr = skl_format_attr;
|
||||
mem_attr = spr_events_attrs;
|
||||
td_attr = spr_td_events_attrs;
|
||||
tsx_attr = spr_tsx_events_attrs;
|
||||
x86_pmu.rtm_abort_event = X86_CONFIG(.event=0xc9, .umask=0x04);
|
||||
x86_pmu.lbr_pt_coexist = true;
|
||||
intel_pmu_pebs_data_source_skl(pmem);
|
||||
x86_pmu.num_topdown_events = 8;
|
||||
static_call_update(intel_pmu_update_topdown_event,
|
||||
&icl_update_topdown_event);
|
||||
static_call_update(intel_pmu_set_topdown_event_period,
|
||||
&icl_set_topdown_event_period);
|
||||
mem_attr = glc_events_attrs;
|
||||
td_attr = glc_td_events_attrs;
|
||||
tsx_attr = glc_tsx_events_attrs;
|
||||
intel_pmu_pebs_data_source_skl(true);
|
||||
pr_cont("Sapphire Rapids events, ");
|
||||
name = "sapphire_rapids";
|
||||
break;
|
||||
@@ -6610,47 +6683,17 @@ __init int intel_pmu_init(void)
|
||||
case INTEL_FAM6_RAPTORLAKE:
|
||||
case INTEL_FAM6_RAPTORLAKE_P:
|
||||
case INTEL_FAM6_RAPTORLAKE_S:
|
||||
case INTEL_FAM6_METEORLAKE:
|
||||
case INTEL_FAM6_METEORLAKE_L:
|
||||
/*
|
||||
* Alder Lake has 2 types of CPU, core and atom.
|
||||
*
|
||||
* Initialize the common PerfMon capabilities here.
|
||||
*/
|
||||
x86_pmu.hybrid_pmu = kcalloc(X86_HYBRID_NUM_PMUS,
|
||||
sizeof(struct x86_hybrid_pmu),
|
||||
GFP_KERNEL);
|
||||
if (!x86_pmu.hybrid_pmu)
|
||||
return -ENOMEM;
|
||||
static_branch_enable(&perf_is_hybrid);
|
||||
x86_pmu.num_hybrid_pmus = X86_HYBRID_NUM_PMUS;
|
||||
intel_pmu_init_hybrid(hybrid_big_small);
|
||||
|
||||
x86_pmu.pebs_aliases = NULL;
|
||||
x86_pmu.pebs_prec_dist = true;
|
||||
x86_pmu.pebs_block = true;
|
||||
x86_pmu.flags |= PMU_FL_HAS_RSP_1;
|
||||
x86_pmu.flags |= PMU_FL_NO_HT_SHARING;
|
||||
x86_pmu.flags |= PMU_FL_INSTR_LATENCY;
|
||||
x86_pmu.lbr_pt_coexist = true;
|
||||
x86_pmu.pebs_latency_data = adl_latency_data_small;
|
||||
x86_pmu.num_topdown_events = 8;
|
||||
static_call_update(intel_pmu_update_topdown_event,
|
||||
&adl_update_topdown_event);
|
||||
static_call_update(intel_pmu_set_topdown_event_period,
|
||||
&adl_set_topdown_event_period);
|
||||
|
||||
x86_pmu.filter = intel_pmu_filter;
|
||||
x86_pmu.get_event_constraints = adl_get_event_constraints;
|
||||
x86_pmu.hw_config = adl_hw_config;
|
||||
x86_pmu.limit_period = spr_limit_period;
|
||||
x86_pmu.get_hybrid_cpu_type = adl_get_hybrid_cpu_type;
|
||||
/*
|
||||
* The rtm_abort_event is used to check whether to enable GPRs
|
||||
* for the RTM abort event. Atom doesn't have the RTM abort
|
||||
* event. There is no harmful to set it in the common
|
||||
* x86_pmu.rtm_abort_event.
|
||||
*/
|
||||
x86_pmu.rtm_abort_event = X86_CONFIG(.event=0xc9, .umask=0x04);
|
||||
|
||||
td_attr = adl_hybrid_events_attrs;
|
||||
mem_attr = adl_hybrid_mem_attrs;
|
||||
@@ -6660,9 +6703,7 @@ __init int intel_pmu_init(void)
|
||||
|
||||
/* Initialize big core specific PerfMon capabilities.*/
|
||||
pmu = &x86_pmu.hybrid_pmu[X86_HYBRID_PMU_CORE_IDX];
|
||||
pmu->name = "cpu_core";
|
||||
pmu->cpu_type = hybrid_big;
|
||||
pmu->late_ack = true;
|
||||
intel_pmu_init_glc(&pmu->pmu);
|
||||
if (cpu_feature_enabled(X86_FEATURE_HYBRID_CPU)) {
|
||||
pmu->num_counters = x86_pmu.num_counters + 2;
|
||||
pmu->num_counters_fixed = x86_pmu.num_counters_fixed + 1;
|
||||
@@ -6687,54 +6728,45 @@ __init int intel_pmu_init(void)
|
||||
pmu->unconstrained = (struct event_constraint)
|
||||
__EVENT_CONSTRAINT(0, (1ULL << pmu->num_counters) - 1,
|
||||
0, pmu->num_counters, 0, 0);
|
||||
pmu->intel_cap.capabilities = x86_pmu.intel_cap.capabilities;
|
||||
pmu->intel_cap.perf_metrics = 1;
|
||||
pmu->intel_cap.pebs_output_pt_available = 0;
|
||||
|
||||
memcpy(pmu->hw_cache_event_ids, spr_hw_cache_event_ids, sizeof(pmu->hw_cache_event_ids));
|
||||
memcpy(pmu->hw_cache_extra_regs, spr_hw_cache_extra_regs, sizeof(pmu->hw_cache_extra_regs));
|
||||
pmu->event_constraints = intel_spr_event_constraints;
|
||||
pmu->pebs_constraints = intel_spr_pebs_event_constraints;
|
||||
pmu->extra_regs = intel_spr_extra_regs;
|
||||
pmu->extra_regs = intel_glc_extra_regs;
|
||||
|
||||
/* Initialize Atom core specific PerfMon capabilities.*/
|
||||
pmu = &x86_pmu.hybrid_pmu[X86_HYBRID_PMU_ATOM_IDX];
|
||||
pmu->name = "cpu_atom";
|
||||
pmu->cpu_type = hybrid_small;
|
||||
pmu->mid_ack = true;
|
||||
pmu->num_counters = x86_pmu.num_counters;
|
||||
pmu->num_counters_fixed = x86_pmu.num_counters_fixed;
|
||||
pmu->max_pebs_events = x86_pmu.max_pebs_events;
|
||||
pmu->unconstrained = (struct event_constraint)
|
||||
__EVENT_CONSTRAINT(0, (1ULL << pmu->num_counters) - 1,
|
||||
0, pmu->num_counters, 0, 0);
|
||||
pmu->intel_cap.capabilities = x86_pmu.intel_cap.capabilities;
|
||||
pmu->intel_cap.perf_metrics = 0;
|
||||
pmu->intel_cap.pebs_output_pt_available = 1;
|
||||
intel_pmu_init_grt(&pmu->pmu);
|
||||
|
||||
memcpy(pmu->hw_cache_event_ids, glp_hw_cache_event_ids, sizeof(pmu->hw_cache_event_ids));
|
||||
memcpy(pmu->hw_cache_extra_regs, tnt_hw_cache_extra_regs, sizeof(pmu->hw_cache_extra_regs));
|
||||
pmu->hw_cache_event_ids[C(ITLB)][C(OP_READ)][C(RESULT_ACCESS)] = -1;
|
||||
pmu->event_constraints = intel_slm_event_constraints;
|
||||
pmu->pebs_constraints = intel_grt_pebs_event_constraints;
|
||||
pmu->extra_regs = intel_grt_extra_regs;
|
||||
if (is_mtl(boot_cpu_data.x86_model)) {
|
||||
x86_pmu.hybrid_pmu[X86_HYBRID_PMU_CORE_IDX].extra_regs = intel_gnr_extra_regs;
|
||||
x86_pmu.pebs_latency_data = mtl_latency_data_small;
|
||||
extra_attr = boot_cpu_has(X86_FEATURE_RTM) ?
|
||||
mtl_hybrid_extra_attr_rtm : mtl_hybrid_extra_attr;
|
||||
mem_attr = mtl_hybrid_mem_attrs;
|
||||
intel_pmu_pebs_data_source_mtl();
|
||||
x86_pmu.get_event_constraints = mtl_get_event_constraints;
|
||||
pmu->extra_regs = intel_cmt_extra_regs;
|
||||
pr_cont("Meteorlake Hybrid events, ");
|
||||
name = "meteorlake_hybrid";
|
||||
} else {
|
||||
x86_pmu.flags |= PMU_FL_MEM_LOADS_AUX;
|
||||
intel_pmu_pebs_data_source_adl();
|
||||
pr_cont("Alderlake Hybrid events, ");
|
||||
name = "alderlake_hybrid";
|
||||
}
|
||||
x86_pmu.flags |= PMU_FL_MEM_LOADS_AUX;
|
||||
intel_pmu_pebs_data_source_adl();
|
||||
pr_cont("Alderlake Hybrid events, ");
|
||||
name = "alderlake_hybrid";
|
||||
break;
|
||||
|
||||
case INTEL_FAM6_METEORLAKE:
|
||||
case INTEL_FAM6_METEORLAKE_L:
|
||||
intel_pmu_init_hybrid(hybrid_big_small);
|
||||
|
||||
x86_pmu.pebs_latency_data = mtl_latency_data_small;
|
||||
x86_pmu.get_event_constraints = mtl_get_event_constraints;
|
||||
x86_pmu.hw_config = adl_hw_config;
|
||||
|
||||
td_attr = adl_hybrid_events_attrs;
|
||||
mem_attr = mtl_hybrid_mem_attrs;
|
||||
tsx_attr = adl_hybrid_tsx_attrs;
|
||||
extra_attr = boot_cpu_has(X86_FEATURE_RTM) ?
|
||||
mtl_hybrid_extra_attr_rtm : mtl_hybrid_extra_attr;
|
||||
|
||||
/* Initialize big core specific PerfMon capabilities.*/
|
||||
pmu = &x86_pmu.hybrid_pmu[X86_HYBRID_PMU_CORE_IDX];
|
||||
intel_pmu_init_glc(&pmu->pmu);
|
||||
pmu->extra_regs = intel_rwc_extra_regs;
|
||||
|
||||
/* Initialize Atom core specific PerfMon capabilities.*/
|
||||
pmu = &x86_pmu.hybrid_pmu[X86_HYBRID_PMU_ATOM_IDX];
|
||||
intel_pmu_init_grt(&pmu->pmu);
|
||||
pmu->extra_regs = intel_cmt_extra_regs;
|
||||
|
||||
intel_pmu_pebs_data_source_mtl();
|
||||
pr_cont("Meteorlake Hybrid events, ");
|
||||
name = "meteorlake_hybrid";
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -6846,9 +6878,6 @@ __init int intel_pmu_init(void)
|
||||
if (!is_hybrid() && x86_pmu.intel_cap.perf_metrics)
|
||||
x86_pmu.intel_ctrl |= 1ULL << GLOBAL_CTRL_EN_PERF_METRICS;
|
||||
|
||||
if (is_hybrid())
|
||||
intel_pmu_check_hybrid_pmus((u64)fixed_mask);
|
||||
|
||||
if (x86_pmu.intel_cap.pebs_timing_info)
|
||||
x86_pmu.flags |= PMU_FL_RETIRE_LATENCY;
|
||||
|
||||
|
||||
@@ -336,6 +336,9 @@ static int cstate_pmu_event_init(struct perf_event *event)
|
||||
cfg = array_index_nospec((unsigned long)cfg, PERF_CSTATE_PKG_EVENT_MAX);
|
||||
if (!(pkg_msr_mask & (1 << cfg)))
|
||||
return -EINVAL;
|
||||
|
||||
event->event_caps |= PERF_EV_CAP_READ_ACTIVE_PKG;
|
||||
|
||||
event->hw.event_base = pkg_msr[cfg].msr;
|
||||
cpu = cpumask_any_and(&cstate_pkg_cpu_mask,
|
||||
topology_die_cpumask(event->cpu));
|
||||
|
||||
@@ -261,7 +261,7 @@ static u64 __adl_latency_data_small(struct perf_event *event, u64 status,
|
||||
{
|
||||
u64 val;
|
||||
|
||||
WARN_ON_ONCE(hybrid_pmu(event->pmu)->cpu_type == hybrid_big);
|
||||
WARN_ON_ONCE(hybrid_pmu(event->pmu)->pmu_type == hybrid_big);
|
||||
|
||||
dse &= PERF_PEBS_DATA_SOURCE_MASK;
|
||||
val = hybrid_var(event->pmu, pebs_data_source)[dse];
|
||||
@@ -1058,7 +1058,7 @@ struct event_constraint intel_icl_pebs_event_constraints[] = {
|
||||
EVENT_CONSTRAINT_END
|
||||
};
|
||||
|
||||
struct event_constraint intel_spr_pebs_event_constraints[] = {
|
||||
struct event_constraint intel_glc_pebs_event_constraints[] = {
|
||||
INTEL_FLAGS_UEVENT_CONSTRAINT(0x100, 0x100000000ULL), /* INST_RETIRED.PREC_DIST */
|
||||
INTEL_FLAGS_UEVENT_CONSTRAINT(0x0400, 0x800000000ULL),
|
||||
|
||||
|
||||
@@ -736,6 +736,7 @@ static bool topa_table_full(struct topa *topa)
|
||||
/**
|
||||
* topa_insert_pages() - create a list of ToPA tables
|
||||
* @buf: PT buffer being initialized.
|
||||
* @cpu: CPU on which to allocate.
|
||||
* @gfp: Allocation flags.
|
||||
*
|
||||
* This initializes a list of ToPA tables with entries from
|
||||
@@ -1207,8 +1208,11 @@ static void pt_buffer_fini_topa(struct pt_buffer *buf)
|
||||
/**
|
||||
* pt_buffer_init_topa() - initialize ToPA table for pt buffer
|
||||
* @buf: PT buffer.
|
||||
* @size: Total size of all regions within this ToPA.
|
||||
* @cpu: CPU on which to allocate.
|
||||
* @nr_pages: No. of pages to allocate.
|
||||
* @gfp: Allocation flags.
|
||||
*
|
||||
* Return: 0 on success or error code.
|
||||
*/
|
||||
static int pt_buffer_init_topa(struct pt_buffer *buf, int cpu,
|
||||
unsigned long nr_pages, gfp_t gfp)
|
||||
@@ -1281,7 +1285,7 @@ out:
|
||||
|
||||
/**
|
||||
* pt_buffer_setup_aux() - set up topa tables for a PT buffer
|
||||
* @cpu: Cpu on which to allocate, -1 means current.
|
||||
* @event: Performance event
|
||||
* @pages: Array of pointers to buffer pages passed from perf core.
|
||||
* @nr_pages: Number of pages in the buffer.
|
||||
* @snapshot: If this is a snapshot/overwrite counter.
|
||||
|
||||
@@ -652,10 +652,29 @@ enum {
|
||||
#define PERF_PEBS_DATA_SOURCE_MAX 0x10
|
||||
#define PERF_PEBS_DATA_SOURCE_MASK (PERF_PEBS_DATA_SOURCE_MAX - 1)
|
||||
|
||||
enum hybrid_cpu_type {
|
||||
HYBRID_INTEL_NONE,
|
||||
HYBRID_INTEL_ATOM = 0x20,
|
||||
HYBRID_INTEL_CORE = 0x40,
|
||||
};
|
||||
|
||||
enum hybrid_pmu_type {
|
||||
not_hybrid,
|
||||
hybrid_small = BIT(0),
|
||||
hybrid_big = BIT(1),
|
||||
|
||||
hybrid_big_small = hybrid_big | hybrid_small, /* only used for matching */
|
||||
};
|
||||
|
||||
#define X86_HYBRID_PMU_ATOM_IDX 0
|
||||
#define X86_HYBRID_PMU_CORE_IDX 1
|
||||
|
||||
#define X86_HYBRID_NUM_PMUS 2
|
||||
|
||||
struct x86_hybrid_pmu {
|
||||
struct pmu pmu;
|
||||
const char *name;
|
||||
u8 cpu_type;
|
||||
enum hybrid_pmu_type pmu_type;
|
||||
cpumask_t supported_cpus;
|
||||
union perf_capabilities intel_cap;
|
||||
u64 intel_ctrl;
|
||||
@@ -721,18 +740,6 @@ extern struct static_key_false perf_is_hybrid;
|
||||
__Fp; \
|
||||
})
|
||||
|
||||
enum hybrid_pmu_type {
|
||||
hybrid_big = 0x40,
|
||||
hybrid_small = 0x20,
|
||||
|
||||
hybrid_big_small = hybrid_big | hybrid_small,
|
||||
};
|
||||
|
||||
#define X86_HYBRID_PMU_ATOM_IDX 0
|
||||
#define X86_HYBRID_PMU_CORE_IDX 1
|
||||
|
||||
#define X86_HYBRID_NUM_PMUS 2
|
||||
|
||||
/*
|
||||
* struct x86_pmu - generic x86 pmu
|
||||
*/
|
||||
@@ -940,7 +947,7 @@ struct x86_pmu {
|
||||
*/
|
||||
int num_hybrid_pmus;
|
||||
struct x86_hybrid_pmu *hybrid_pmu;
|
||||
u8 (*get_hybrid_cpu_type) (void);
|
||||
enum hybrid_cpu_type (*get_hybrid_cpu_type) (void);
|
||||
};
|
||||
|
||||
struct x86_perf_task_context_opt {
|
||||
@@ -1521,7 +1528,7 @@ extern struct event_constraint intel_skl_pebs_event_constraints[];
|
||||
|
||||
extern struct event_constraint intel_icl_pebs_event_constraints[];
|
||||
|
||||
extern struct event_constraint intel_spr_pebs_event_constraints[];
|
||||
extern struct event_constraint intel_glc_pebs_event_constraints[];
|
||||
|
||||
struct event_constraint *intel_pebs_constraints(struct perf_event *event);
|
||||
|
||||
|
||||
+9
-13
@@ -115,7 +115,7 @@ struct rapl_pmu {
|
||||
struct rapl_pmus {
|
||||
struct pmu pmu;
|
||||
unsigned int maxdie;
|
||||
struct rapl_pmu *pmus[];
|
||||
struct rapl_pmu *pmus[] __counted_by(maxdie);
|
||||
};
|
||||
|
||||
enum rapl_unit_quirk {
|
||||
@@ -179,15 +179,11 @@ static u64 rapl_event_update(struct perf_event *event)
|
||||
s64 delta, sdelta;
|
||||
int shift = RAPL_CNTR_WIDTH;
|
||||
|
||||
again:
|
||||
prev_raw_count = local64_read(&hwc->prev_count);
|
||||
rdmsrl(event->hw.event_base, new_raw_count);
|
||||
|
||||
if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
|
||||
new_raw_count) != prev_raw_count) {
|
||||
cpu_relax();
|
||||
goto again;
|
||||
}
|
||||
do {
|
||||
rdmsrl(event->hw.event_base, new_raw_count);
|
||||
} while (!local64_try_cmpxchg(&hwc->prev_count,
|
||||
&prev_raw_count, new_raw_count));
|
||||
|
||||
/*
|
||||
* Now we have the new raw value and have updated the prev
|
||||
@@ -537,11 +533,11 @@ static struct perf_msr intel_rapl_spr_msrs[] = {
|
||||
* - want to use same event codes across both architectures
|
||||
*/
|
||||
static struct perf_msr amd_rapl_msrs[] = {
|
||||
[PERF_RAPL_PP0] = { 0, &rapl_events_cores_group, 0, false, 0 },
|
||||
[PERF_RAPL_PP0] = { 0, &rapl_events_cores_group, NULL, false, 0 },
|
||||
[PERF_RAPL_PKG] = { MSR_AMD_PKG_ENERGY_STATUS, &rapl_events_pkg_group, test_msr, false, RAPL_MSR_MASK },
|
||||
[PERF_RAPL_RAM] = { 0, &rapl_events_ram_group, 0, false, 0 },
|
||||
[PERF_RAPL_PP1] = { 0, &rapl_events_gpu_group, 0, false, 0 },
|
||||
[PERF_RAPL_PSYS] = { 0, &rapl_events_psys_group, 0, false, 0 },
|
||||
[PERF_RAPL_RAM] = { 0, &rapl_events_ram_group, NULL, false, 0 },
|
||||
[PERF_RAPL_PP1] = { 0, &rapl_events_gpu_group, NULL, false, 0 },
|
||||
[PERF_RAPL_PSYS] = { 0, &rapl_events_psys_group, NULL, false, 0 },
|
||||
};
|
||||
|
||||
static int rapl_cpu_offline(unsigned int cpu)
|
||||
|
||||
@@ -10,5 +10,4 @@ generated-y += unistd_64_x32.h
|
||||
generated-y += xen-hypercalls.h
|
||||
|
||||
generic-y += early_ioremap.h
|
||||
generic-y += export.h
|
||||
generic-y += mcs_spinlock.h
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
#define ANNOTATE_IGNORE_ALTERNATIVE \
|
||||
"999:\n\t" \
|
||||
".pushsection .discard.ignore_alts\n\t" \
|
||||
".long 999b - .\n\t" \
|
||||
".long 999b\n\t" \
|
||||
".popsection\n\t"
|
||||
|
||||
/*
|
||||
@@ -352,7 +352,7 @@ static inline int alternatives_text_reserved(void *start, void *end)
|
||||
.macro ANNOTATE_IGNORE_ALTERNATIVE
|
||||
.Lannotate_\@:
|
||||
.pushsection .discard.ignore_alts
|
||||
.long .Lannotate_\@ - .
|
||||
.long .Lannotate_\@
|
||||
.popsection
|
||||
.endm
|
||||
|
||||
|
||||
@@ -293,6 +293,9 @@ static __always_inline unsigned long variable_ffz(unsigned long word)
|
||||
*/
|
||||
static __always_inline 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)
|
||||
: "rm" (word));
|
||||
@@ -360,6 +363,9 @@ static __always_inline 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
|
||||
@@ -401,6 +407,9 @@ static __always_inline int fls(unsigned int x)
|
||||
static __always_inline 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
|
||||
|
||||
@@ -85,6 +85,8 @@ 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;
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_X86_BOOT_H */
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
#include <linux/thread_info.h>
|
||||
|
||||
#include <asm/ia32.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/user.h>
|
||||
#include <asm/auxvec.h>
|
||||
@@ -149,7 +150,7 @@ do { \
|
||||
((x)->e_machine == EM_X86_64)
|
||||
|
||||
#define compat_elf_check_arch(x) \
|
||||
(elf_check_arch_ia32(x) || \
|
||||
((elf_check_arch_ia32(x) && ia32_enabled()) || \
|
||||
(IS_ENABLED(CONFIG_X86_X32_ABI) && (x)->e_machine == EM_X86_64))
|
||||
|
||||
static inline void elf_common_init(struct thread_struct *t,
|
||||
|
||||
@@ -68,6 +68,20 @@ extern void ia32_pick_mmap_layout(struct mm_struct *mm);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_IA32_EMULATION */
|
||||
extern bool __ia32_enabled;
|
||||
|
||||
static inline bool ia32_enabled(void)
|
||||
{
|
||||
return __ia32_enabled;
|
||||
}
|
||||
|
||||
#else /* !CONFIG_IA32_EMULATION */
|
||||
|
||||
static inline bool ia32_enabled(void)
|
||||
{
|
||||
return IS_ENABLED(CONFIG_X86_32);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_X86_IA32_H */
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#ifndef _ASM_X86_INIT_H
|
||||
#define _ASM_X86_INIT_H
|
||||
|
||||
#define __head __section(".head.text")
|
||||
|
||||
struct x86_mapping_info {
|
||||
void *(*alloc_pgt_page)(void *); /* allocate buf for page table */
|
||||
void *context; /* context for alloc_pgt_page */
|
||||
|
||||
@@ -19,8 +19,10 @@
|
||||
|
||||
#ifdef CONFIG_X86_MEM_ENCRYPT
|
||||
void __init mem_encrypt_init(void);
|
||||
void __init mem_encrypt_setup_arch(void);
|
||||
#else
|
||||
static inline void mem_encrypt_init(void) { }
|
||||
static inline void __init mem_encrypt_setup_arch(void) { }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_AMD_MEM_ENCRYPT
|
||||
@@ -43,7 +45,6 @@ void __init sme_map_bootdata(char *real_mode_data);
|
||||
void __init sme_unmap_bootdata(char *real_mode_data);
|
||||
|
||||
void __init sme_early_init(void);
|
||||
void __init sev_setup_arch(void);
|
||||
|
||||
void __init sme_encrypt_kernel(struct boot_params *bp);
|
||||
void __init sme_enable(struct boot_params *bp);
|
||||
@@ -73,7 +74,6 @@ static inline void __init sme_map_bootdata(char *real_mode_data) { }
|
||||
static inline void __init sme_unmap_bootdata(char *real_mode_data) { }
|
||||
|
||||
static inline void __init sme_early_init(void) { }
|
||||
static inline void __init sev_setup_arch(void) { }
|
||||
|
||||
static inline void __init sme_encrypt_kernel(struct boot_params *bp) { }
|
||||
static inline void __init sme_enable(struct boot_params *bp) { }
|
||||
|
||||
@@ -638,12 +638,16 @@
|
||||
#define MSR_AMD64_LBR_SELECT 0xc000010e
|
||||
|
||||
/* Zen4 */
|
||||
#define MSR_ZEN4_BP_CFG 0xc001102e
|
||||
#define MSR_ZEN4_BP_CFG 0xc001102e
|
||||
#define MSR_ZEN4_BP_CFG_SHARED_BTB_FIX_BIT 5
|
||||
|
||||
/* Fam 19h MSRs */
|
||||
#define MSR_F19H_UMC_PERF_CTL 0xc0010800
|
||||
#define MSR_F19H_UMC_PERF_CTR 0xc0010801
|
||||
|
||||
/* Zen 2 */
|
||||
#define MSR_ZEN2_SPECTRAL_CHICKEN 0xc00110e3
|
||||
#define MSR_ZEN2_SPECTRAL_CHICKEN_BIT BIT_ULL(1)
|
||||
#define MSR_ZEN2_SPECTRAL_CHICKEN 0xc00110e3
|
||||
#define MSR_ZEN2_SPECTRAL_CHICKEN_BIT BIT_ULL(1)
|
||||
|
||||
/* Fam 17h MSRs */
|
||||
#define MSR_F17H_IRPERF 0xc00000e9
|
||||
|
||||
@@ -196,7 +196,7 @@
|
||||
.macro ANNOTATE_RETPOLINE_SAFE
|
||||
.Lhere_\@:
|
||||
.pushsection .discard.retpoline_safe
|
||||
.long .Lhere_\@ - .
|
||||
.long .Lhere_\@
|
||||
.popsection
|
||||
.endm
|
||||
|
||||
@@ -320,7 +320,7 @@
|
||||
#define ANNOTATE_RETPOLINE_SAFE \
|
||||
"999:\n\t" \
|
||||
".pushsection .discard.retpoline_safe\n\t" \
|
||||
".long 999b - .\n\t" \
|
||||
".long 999b\n\t" \
|
||||
".popsection\n\t"
|
||||
|
||||
typedef u8 retpoline_thunk_t[RETPOLINE_THUNK_SIZE];
|
||||
|
||||
@@ -12,13 +12,6 @@
|
||||
|
||||
#define NR_NODE_MEMBLKS (MAX_NUMNODES*2)
|
||||
|
||||
/*
|
||||
* Too small node sizes may confuse the VM badly. Usually they
|
||||
* result from BIOS bugs. So dont recognize nodes as standalone
|
||||
* NUMA entities that have less than this amount of RAM listed:
|
||||
*/
|
||||
#define NODE_MIN_SIZE (4*1024*1024)
|
||||
|
||||
extern int numa_off;
|
||||
|
||||
/*
|
||||
|
||||
@@ -210,6 +210,25 @@ do { \
|
||||
(typeof(_var))(unsigned long) pco_old__; \
|
||||
})
|
||||
|
||||
#define percpu_try_cmpxchg_op(size, qual, _var, _ovalp, _nval) \
|
||||
({ \
|
||||
bool success; \
|
||||
__pcpu_type_##size *pco_oval__ = (__pcpu_type_##size *)(_ovalp); \
|
||||
__pcpu_type_##size pco_old__ = *pco_oval__; \
|
||||
__pcpu_type_##size pco_new__ = __pcpu_cast_##size(_nval); \
|
||||
asm qual (__pcpu_op2_##size("cmpxchg", "%[nval]", \
|
||||
__percpu_arg([var])) \
|
||||
CC_SET(z) \
|
||||
: CC_OUT(z) (success), \
|
||||
[oval] "+a" (pco_old__), \
|
||||
[var] "+m" (_var) \
|
||||
: [nval] __pcpu_reg_##size(, pco_new__) \
|
||||
: "memory"); \
|
||||
if (unlikely(!success)) \
|
||||
*pco_oval__ = pco_old__; \
|
||||
likely(success); \
|
||||
})
|
||||
|
||||
#if defined(CONFIG_X86_32) && !defined(CONFIG_UML)
|
||||
#define percpu_cmpxchg64_op(size, qual, _var, _oval, _nval) \
|
||||
({ \
|
||||
@@ -223,26 +242,63 @@ do { \
|
||||
old__.var = _oval; \
|
||||
new__.var = _nval; \
|
||||
\
|
||||
asm qual (ALTERNATIVE("leal %P[var], %%esi; call this_cpu_cmpxchg8b_emu", \
|
||||
asm qual (ALTERNATIVE("call this_cpu_cmpxchg8b_emu", \
|
||||
"cmpxchg8b " __percpu_arg([var]), X86_FEATURE_CX8) \
|
||||
: [var] "+m" (_var), \
|
||||
"+a" (old__.low), \
|
||||
"+d" (old__.high) \
|
||||
: "b" (new__.low), \
|
||||
"c" (new__.high) \
|
||||
: "memory", "esi"); \
|
||||
"c" (new__.high), \
|
||||
"S" (&(_var)) \
|
||||
: "memory"); \
|
||||
\
|
||||
old__.var; \
|
||||
})
|
||||
|
||||
#define raw_cpu_cmpxchg64(pcp, oval, nval) percpu_cmpxchg64_op(8, , pcp, oval, nval)
|
||||
#define this_cpu_cmpxchg64(pcp, oval, nval) percpu_cmpxchg64_op(8, volatile, pcp, oval, nval)
|
||||
|
||||
#define percpu_try_cmpxchg64_op(size, qual, _var, _ovalp, _nval) \
|
||||
({ \
|
||||
bool success; \
|
||||
u64 *_oval = (u64 *)(_ovalp); \
|
||||
union { \
|
||||
u64 var; \
|
||||
struct { \
|
||||
u32 low, high; \
|
||||
}; \
|
||||
} old__, new__; \
|
||||
\
|
||||
old__.var = *_oval; \
|
||||
new__.var = _nval; \
|
||||
\
|
||||
asm qual (ALTERNATIVE("call this_cpu_cmpxchg8b_emu", \
|
||||
"cmpxchg8b " __percpu_arg([var]), X86_FEATURE_CX8) \
|
||||
CC_SET(z) \
|
||||
: CC_OUT(z) (success), \
|
||||
[var] "+m" (_var), \
|
||||
"+a" (old__.low), \
|
||||
"+d" (old__.high) \
|
||||
: "b" (new__.low), \
|
||||
"c" (new__.high), \
|
||||
"S" (&(_var)) \
|
||||
: "memory"); \
|
||||
if (unlikely(!success)) \
|
||||
*_oval = old__.var; \
|
||||
likely(success); \
|
||||
})
|
||||
|
||||
#define raw_cpu_try_cmpxchg64(pcp, ovalp, nval) percpu_try_cmpxchg64_op(8, , pcp, ovalp, nval)
|
||||
#define this_cpu_try_cmpxchg64(pcp, ovalp, nval) percpu_try_cmpxchg64_op(8, volatile, pcp, ovalp, nval)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
#define raw_cpu_cmpxchg64(pcp, oval, nval) percpu_cmpxchg_op(8, , pcp, oval, nval);
|
||||
#define this_cpu_cmpxchg64(pcp, oval, nval) percpu_cmpxchg_op(8, volatile, pcp, oval, nval);
|
||||
|
||||
#define raw_cpu_try_cmpxchg64(pcp, ovalp, nval) percpu_try_cmpxchg_op(8, , pcp, ovalp, nval);
|
||||
#define this_cpu_try_cmpxchg64(pcp, ovalp, nval) percpu_try_cmpxchg_op(8, volatile, pcp, ovalp, nval);
|
||||
|
||||
#define percpu_cmpxchg128_op(size, qual, _var, _oval, _nval) \
|
||||
({ \
|
||||
union { \
|
||||
@@ -255,20 +311,54 @@ do { \
|
||||
old__.var = _oval; \
|
||||
new__.var = _nval; \
|
||||
\
|
||||
asm qual (ALTERNATIVE("leaq %P[var], %%rsi; call this_cpu_cmpxchg16b_emu", \
|
||||
asm qual (ALTERNATIVE("call this_cpu_cmpxchg16b_emu", \
|
||||
"cmpxchg16b " __percpu_arg([var]), X86_FEATURE_CX16) \
|
||||
: [var] "+m" (_var), \
|
||||
"+a" (old__.low), \
|
||||
"+d" (old__.high) \
|
||||
: "b" (new__.low), \
|
||||
"c" (new__.high) \
|
||||
: "memory", "rsi"); \
|
||||
"c" (new__.high), \
|
||||
"S" (&(_var)) \
|
||||
: "memory"); \
|
||||
\
|
||||
old__.var; \
|
||||
})
|
||||
|
||||
#define raw_cpu_cmpxchg128(pcp, oval, nval) percpu_cmpxchg128_op(16, , pcp, oval, nval)
|
||||
#define this_cpu_cmpxchg128(pcp, oval, nval) percpu_cmpxchg128_op(16, volatile, pcp, oval, nval)
|
||||
|
||||
#define percpu_try_cmpxchg128_op(size, qual, _var, _ovalp, _nval) \
|
||||
({ \
|
||||
bool success; \
|
||||
u128 *_oval = (u128 *)(_ovalp); \
|
||||
union { \
|
||||
u128 var; \
|
||||
struct { \
|
||||
u64 low, high; \
|
||||
}; \
|
||||
} old__, new__; \
|
||||
\
|
||||
old__.var = *_oval; \
|
||||
new__.var = _nval; \
|
||||
\
|
||||
asm qual (ALTERNATIVE("call this_cpu_cmpxchg16b_emu", \
|
||||
"cmpxchg16b " __percpu_arg([var]), X86_FEATURE_CX16) \
|
||||
CC_SET(z) \
|
||||
: CC_OUT(z) (success), \
|
||||
[var] "+m" (_var), \
|
||||
"+a" (old__.low), \
|
||||
"+d" (old__.high) \
|
||||
: "b" (new__.low), \
|
||||
"c" (new__.high), \
|
||||
"S" (&(_var)) \
|
||||
: "memory"); \
|
||||
if (unlikely(!success)) \
|
||||
*_oval = old__.var; \
|
||||
likely(success); \
|
||||
})
|
||||
|
||||
#define raw_cpu_try_cmpxchg128(pcp, ovalp, nval) percpu_try_cmpxchg128_op(16, , pcp, ovalp, nval)
|
||||
#define this_cpu_try_cmpxchg128(pcp, ovalp, nval) percpu_try_cmpxchg128_op(16, volatile, pcp, ovalp, nval)
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -343,6 +433,9 @@ do { \
|
||||
#define raw_cpu_cmpxchg_1(pcp, oval, nval) percpu_cmpxchg_op(1, , pcp, oval, nval)
|
||||
#define raw_cpu_cmpxchg_2(pcp, oval, nval) percpu_cmpxchg_op(2, , pcp, oval, nval)
|
||||
#define raw_cpu_cmpxchg_4(pcp, oval, nval) percpu_cmpxchg_op(4, , pcp, oval, nval)
|
||||
#define raw_cpu_try_cmpxchg_1(pcp, ovalp, nval) percpu_try_cmpxchg_op(1, , pcp, ovalp, nval)
|
||||
#define raw_cpu_try_cmpxchg_2(pcp, ovalp, nval) percpu_try_cmpxchg_op(2, , pcp, ovalp, nval)
|
||||
#define raw_cpu_try_cmpxchg_4(pcp, ovalp, nval) percpu_try_cmpxchg_op(4, , pcp, ovalp, nval)
|
||||
|
||||
#define this_cpu_add_return_1(pcp, val) percpu_add_return_op(1, volatile, pcp, val)
|
||||
#define this_cpu_add_return_2(pcp, val) percpu_add_return_op(2, volatile, pcp, val)
|
||||
@@ -350,6 +443,9 @@ do { \
|
||||
#define this_cpu_cmpxchg_1(pcp, oval, nval) percpu_cmpxchg_op(1, volatile, pcp, oval, nval)
|
||||
#define this_cpu_cmpxchg_2(pcp, oval, nval) percpu_cmpxchg_op(2, volatile, pcp, oval, nval)
|
||||
#define this_cpu_cmpxchg_4(pcp, oval, nval) percpu_cmpxchg_op(4, volatile, pcp, oval, nval)
|
||||
#define this_cpu_try_cmpxchg_1(pcp, ovalp, nval) percpu_try_cmpxchg_op(1, volatile, pcp, ovalp, nval)
|
||||
#define this_cpu_try_cmpxchg_2(pcp, ovalp, nval) percpu_try_cmpxchg_op(2, volatile, pcp, ovalp, nval)
|
||||
#define this_cpu_try_cmpxchg_4(pcp, ovalp, nval) percpu_try_cmpxchg_op(4, volatile, pcp, ovalp, nval)
|
||||
|
||||
/*
|
||||
* Per cpu atomic 64 bit operations are only available under 64 bit.
|
||||
@@ -364,6 +460,7 @@ do { \
|
||||
#define raw_cpu_add_return_8(pcp, val) percpu_add_return_op(8, , pcp, val)
|
||||
#define raw_cpu_xchg_8(pcp, nval) raw_percpu_xchg_op(pcp, nval)
|
||||
#define raw_cpu_cmpxchg_8(pcp, oval, nval) percpu_cmpxchg_op(8, , pcp, oval, nval)
|
||||
#define raw_cpu_try_cmpxchg_8(pcp, ovalp, nval) percpu_try_cmpxchg_op(8, , pcp, ovalp, nval)
|
||||
|
||||
#define this_cpu_read_8(pcp) percpu_from_op(8, volatile, "mov", pcp)
|
||||
#define this_cpu_write_8(pcp, val) percpu_to_op(8, volatile, "mov", (pcp), val)
|
||||
@@ -373,6 +470,7 @@ do { \
|
||||
#define this_cpu_add_return_8(pcp, val) percpu_add_return_op(8, volatile, pcp, val)
|
||||
#define this_cpu_xchg_8(pcp, nval) percpu_xchg_op(8, volatile, pcp, nval)
|
||||
#define this_cpu_cmpxchg_8(pcp, oval, nval) percpu_cmpxchg_op(8, volatile, pcp, oval, nval)
|
||||
#define this_cpu_try_cmpxchg_8(pcp, ovalp, nval) percpu_try_cmpxchg_op(8, volatile, pcp, ovalp, nval)
|
||||
#endif
|
||||
|
||||
static __always_inline bool x86_this_cpu_constant_test_bit(unsigned int nr,
|
||||
|
||||
@@ -112,6 +112,13 @@
|
||||
(AMD64_PERFMON_V2_EVENTSEL_EVENT_NB | \
|
||||
AMD64_PERFMON_V2_EVENTSEL_UMASK_NB)
|
||||
|
||||
#define AMD64_PERFMON_V2_ENABLE_UMC BIT_ULL(31)
|
||||
#define AMD64_PERFMON_V2_EVENTSEL_EVENT_UMC GENMASK_ULL(7, 0)
|
||||
#define AMD64_PERFMON_V2_EVENTSEL_RDWRMASK_UMC GENMASK_ULL(9, 8)
|
||||
#define AMD64_PERFMON_V2_RAW_EVENT_MASK_UMC \
|
||||
(AMD64_PERFMON_V2_EVENTSEL_EVENT_UMC | \
|
||||
AMD64_PERFMON_V2_EVENTSEL_RDWRMASK_UMC)
|
||||
|
||||
#define AMD64_NUM_COUNTERS 4
|
||||
#define AMD64_NUM_COUNTERS_CORE 6
|
||||
#define AMD64_NUM_COUNTERS_NB 4
|
||||
@@ -232,6 +239,8 @@ union cpuid_0x80000022_ebx {
|
||||
unsigned int lbr_v2_stack_sz:6;
|
||||
/* Number of Data Fabric Counters */
|
||||
unsigned int num_df_pmc:6;
|
||||
/* Number of Unified Memory Controller Counters */
|
||||
unsigned int num_umc_pmc:6;
|
||||
} split;
|
||||
unsigned int full;
|
||||
};
|
||||
|
||||
@@ -1716,6 +1716,14 @@ static inline bool pud_user_accessible_page(pud_t pud)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86_SGX
|
||||
int arch_memory_failure(unsigned long pfn, int flags);
|
||||
#define arch_memory_failure arch_memory_failure
|
||||
|
||||
bool arch_is_platform_page(u64 paddr);
|
||||
#define arch_is_platform_page arch_is_platform_page
|
||||
#endif
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* _ASM_X86_PGTABLE_H */
|
||||
|
||||
@@ -31,11 +31,11 @@ static __always_inline void preempt_count_set(int pc)
|
||||
{
|
||||
int old, new;
|
||||
|
||||
old = raw_cpu_read_4(pcpu_hot.preempt_count);
|
||||
do {
|
||||
old = raw_cpu_read_4(pcpu_hot.preempt_count);
|
||||
new = (old & PREEMPT_NEED_RESCHED) |
|
||||
(pc & ~PREEMPT_NEED_RESCHED);
|
||||
} while (raw_cpu_cmpxchg_4(pcpu_hot.preempt_count, old, new) != old);
|
||||
} while (!raw_cpu_try_cmpxchg_4(pcpu_hot.preempt_count, &old, new));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -399,7 +399,7 @@ static inline unsigned long cpu_kernelmode_gs_base(int cpu)
|
||||
return (unsigned long)per_cpu(fixed_percpu_data.gs_base, cpu);
|
||||
}
|
||||
|
||||
extern asmlinkage void ignore_sysret(void);
|
||||
extern asmlinkage void entry_SYSCALL32_ignore(void);
|
||||
|
||||
/* Save actual FS/GS selectors and bases to current->thread */
|
||||
void current_save_fsgs(void);
|
||||
@@ -724,14 +724,6 @@ enum mds_mitigations {
|
||||
MDS_MITIGATION_VMWERV,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_X86_SGX
|
||||
int arch_memory_failure(unsigned long pfn, int flags);
|
||||
#define arch_memory_failure arch_memory_failure
|
||||
|
||||
bool arch_is_platform_page(u64 paddr);
|
||||
#define arch_is_platform_page arch_is_platform_page
|
||||
#endif
|
||||
|
||||
extern bool gds_ucode_mitigated(void);
|
||||
|
||||
#endif /* _ASM_X86_PROCESSOR_H */
|
||||
|
||||
@@ -36,6 +36,9 @@ void entry_INT80_compat(void);
|
||||
#ifdef CONFIG_XEN_PV
|
||||
void xen_entry_INT80_compat(void);
|
||||
#endif
|
||||
#else /* !CONFIG_IA32_EMULATION */
|
||||
#define entry_SYSCALL_compat NULL
|
||||
#define entry_SYSENTER_compat NULL
|
||||
#endif
|
||||
|
||||
void x86_configure_nx(void);
|
||||
|
||||
@@ -37,6 +37,8 @@ extern int phys_to_target_node(phys_addr_t start);
|
||||
#define phys_to_target_node phys_to_target_node
|
||||
extern int memory_add_physaddr_to_nid(u64 start);
|
||||
#define memory_add_physaddr_to_nid memory_add_physaddr_to_nid
|
||||
extern int numa_fill_memblks(u64 start, u64 end);
|
||||
#define numa_fill_memblks numa_fill_memblks
|
||||
#endif
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
|
||||
@@ -126,12 +126,12 @@ static inline int syscall_get_arch(struct task_struct *task)
|
||||
? AUDIT_ARCH_I386 : AUDIT_ARCH_X86_64;
|
||||
}
|
||||
|
||||
void do_syscall_64(struct pt_regs *regs, int nr);
|
||||
bool do_syscall_64(struct pt_regs *regs, int nr);
|
||||
|
||||
#endif /* CONFIG_X86_32 */
|
||||
|
||||
void do_int80_syscall_32(struct pt_regs *regs);
|
||||
long do_fast_syscall_32(struct pt_regs *regs);
|
||||
long do_SYSENTER_32(struct pt_regs *regs);
|
||||
bool do_fast_syscall_32(struct pt_regs *regs);
|
||||
bool do_SYSENTER_32(struct pt_regs *regs);
|
||||
|
||||
#endif /* _ASM_X86_SYSCALL_H */
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
#include <asm/intel-family.h>
|
||||
#include <asm/cpu_device_id.h>
|
||||
#include <asm/uv/uv.h>
|
||||
#include <asm/ia32.h>
|
||||
#include <asm/set_memory.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/sev.h>
|
||||
@@ -1114,18 +1115,34 @@ void get_cpu_cap(struct cpuinfo_x86 *c)
|
||||
void get_cpu_address_sizes(struct cpuinfo_x86 *c)
|
||||
{
|
||||
u32 eax, ebx, ecx, edx;
|
||||
bool vp_bits_from_cpuid = true;
|
||||
|
||||
if (c->extended_cpuid_level >= 0x80000008) {
|
||||
if (!cpu_has(c, X86_FEATURE_CPUID) ||
|
||||
(c->extended_cpuid_level < 0x80000008))
|
||||
vp_bits_from_cpuid = false;
|
||||
|
||||
if (vp_bits_from_cpuid) {
|
||||
cpuid(0x80000008, &eax, &ebx, &ecx, &edx);
|
||||
|
||||
c->x86_virt_bits = (eax >> 8) & 0xff;
|
||||
c->x86_phys_bits = eax & 0xff;
|
||||
} else {
|
||||
if (IS_ENABLED(CONFIG_X86_64)) {
|
||||
c->x86_clflush_size = 64;
|
||||
c->x86_phys_bits = 36;
|
||||
c->x86_virt_bits = 48;
|
||||
} else {
|
||||
c->x86_clflush_size = 32;
|
||||
c->x86_virt_bits = 32;
|
||||
c->x86_phys_bits = 32;
|
||||
|
||||
if (cpu_has(c, X86_FEATURE_PAE) ||
|
||||
cpu_has(c, X86_FEATURE_PSE36))
|
||||
c->x86_phys_bits = 36;
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_X86_32
|
||||
else if (cpu_has(c, X86_FEATURE_PAE) || cpu_has(c, X86_FEATURE_PSE36))
|
||||
c->x86_phys_bits = 36;
|
||||
#endif
|
||||
c->x86_cache_bits = c->x86_phys_bits;
|
||||
c->x86_cache_alignment = c->x86_clflush_size;
|
||||
}
|
||||
|
||||
static void identify_cpu_without_cpuid(struct cpuinfo_x86 *c)
|
||||
@@ -1579,17 +1596,6 @@ static void __init cpu_parse_early_param(void)
|
||||
*/
|
||||
static void __init early_identify_cpu(struct cpuinfo_x86 *c)
|
||||
{
|
||||
#ifdef CONFIG_X86_64
|
||||
c->x86_clflush_size = 64;
|
||||
c->x86_phys_bits = 36;
|
||||
c->x86_virt_bits = 48;
|
||||
#else
|
||||
c->x86_clflush_size = 32;
|
||||
c->x86_phys_bits = 32;
|
||||
c->x86_virt_bits = 32;
|
||||
#endif
|
||||
c->x86_cache_alignment = c->x86_clflush_size;
|
||||
|
||||
memset(&c->x86_capability, 0, sizeof(c->x86_capability));
|
||||
c->extended_cpuid_level = 0;
|
||||
|
||||
@@ -1601,7 +1607,6 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
|
||||
cpu_detect(c);
|
||||
get_cpu_vendor(c);
|
||||
get_cpu_cap(c);
|
||||
get_cpu_address_sizes(c);
|
||||
setup_force_cpu_cap(X86_FEATURE_CPUID);
|
||||
cpu_parse_early_param();
|
||||
|
||||
@@ -1617,6 +1622,8 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
|
||||
setup_clear_cpu_cap(X86_FEATURE_CPUID);
|
||||
}
|
||||
|
||||
get_cpu_address_sizes(c);
|
||||
|
||||
setup_force_cpu_cap(X86_FEATURE_ALWAYS);
|
||||
|
||||
cpu_set_bug_bits(c);
|
||||
@@ -2074,24 +2081,24 @@ void syscall_init(void)
|
||||
wrmsr(MSR_STAR, 0, (__USER32_CS << 16) | __KERNEL_CS);
|
||||
wrmsrl(MSR_LSTAR, (unsigned long)entry_SYSCALL_64);
|
||||
|
||||
#ifdef CONFIG_IA32_EMULATION
|
||||
wrmsrl_cstar((unsigned long)entry_SYSCALL_compat);
|
||||
/*
|
||||
* This only works on Intel CPUs.
|
||||
* On AMD CPUs these MSRs are 32-bit, CPU truncates MSR_IA32_SYSENTER_EIP.
|
||||
* This does not cause SYSENTER to jump to the wrong location, because
|
||||
* AMD doesn't allow SYSENTER in long mode (either 32- or 64-bit).
|
||||
*/
|
||||
wrmsrl_safe(MSR_IA32_SYSENTER_CS, (u64)__KERNEL_CS);
|
||||
wrmsrl_safe(MSR_IA32_SYSENTER_ESP,
|
||||
(unsigned long)(cpu_entry_stack(smp_processor_id()) + 1));
|
||||
wrmsrl_safe(MSR_IA32_SYSENTER_EIP, (u64)entry_SYSENTER_compat);
|
||||
#else
|
||||
wrmsrl_cstar((unsigned long)ignore_sysret);
|
||||
wrmsrl_safe(MSR_IA32_SYSENTER_CS, (u64)GDT_ENTRY_INVALID_SEG);
|
||||
wrmsrl_safe(MSR_IA32_SYSENTER_ESP, 0ULL);
|
||||
wrmsrl_safe(MSR_IA32_SYSENTER_EIP, 0ULL);
|
||||
#endif
|
||||
if (ia32_enabled()) {
|
||||
wrmsrl_cstar((unsigned long)entry_SYSCALL_compat);
|
||||
/*
|
||||
* This only works on Intel CPUs.
|
||||
* On AMD CPUs these MSRs are 32-bit, CPU truncates MSR_IA32_SYSENTER_EIP.
|
||||
* This does not cause SYSENTER to jump to the wrong location, because
|
||||
* AMD doesn't allow SYSENTER in long mode (either 32- or 64-bit).
|
||||
*/
|
||||
wrmsrl_safe(MSR_IA32_SYSENTER_CS, (u64)__KERNEL_CS);
|
||||
wrmsrl_safe(MSR_IA32_SYSENTER_ESP,
|
||||
(unsigned long)(cpu_entry_stack(smp_processor_id()) + 1));
|
||||
wrmsrl_safe(MSR_IA32_SYSENTER_EIP, (u64)entry_SYSENTER_compat);
|
||||
} else {
|
||||
wrmsrl_cstar((unsigned long)entry_SYSCALL32_ignore);
|
||||
wrmsrl_safe(MSR_IA32_SYSENTER_CS, (u64)GDT_ENTRY_INVALID_SEG);
|
||||
wrmsrl_safe(MSR_IA32_SYSENTER_ESP, 0ULL);
|
||||
wrmsrl_safe(MSR_IA32_SYSENTER_EIP, 0ULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Flags to clear on syscall; clear as much as possible
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
* Copyright (C) 2017 Steven Rostedt, VMware Inc.
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/page_types.h>
|
||||
#include <asm/segment.h>
|
||||
#include <asm/export.h>
|
||||
#include <asm/ftrace.h>
|
||||
#include <asm/nospec-branch.h>
|
||||
#include <asm/frame.h>
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
* Copyright (C) 2014 Steven Rostedt, Red Hat Inc
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/cfi_types.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/ftrace.h>
|
||||
#include <asm/export.h>
|
||||
#include <asm/nospec-branch.h>
|
||||
#include <asm/unwind_hints.h>
|
||||
#include <asm/frame.h>
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include <asm/trapnr.h>
|
||||
#include <asm/sev.h>
|
||||
#include <asm/tdx.h>
|
||||
#include <asm/init.h>
|
||||
|
||||
/*
|
||||
* Manage page tables very early on.
|
||||
@@ -69,7 +70,7 @@ EXPORT_SYMBOL(vmemmap_base);
|
||||
/*
|
||||
* GDT used on the boot CPU before switching to virtual addresses.
|
||||
*/
|
||||
static struct desc_struct startup_gdt[GDT_ENTRIES] = {
|
||||
static struct desc_struct startup_gdt[GDT_ENTRIES] __initdata = {
|
||||
[GDT_ENTRY_KERNEL32_CS] = GDT_ENTRY_INIT(0xc09b, 0, 0xfffff),
|
||||
[GDT_ENTRY_KERNEL_CS] = GDT_ENTRY_INIT(0xa09b, 0, 0xfffff),
|
||||
[GDT_ENTRY_KERNEL_DS] = GDT_ENTRY_INIT(0xc093, 0, 0xfffff),
|
||||
@@ -79,13 +80,11 @@ static struct desc_struct startup_gdt[GDT_ENTRIES] = {
|
||||
* Address needs to be set at runtime because it references the startup_gdt
|
||||
* while the kernel still uses a direct mapping.
|
||||
*/
|
||||
static struct desc_ptr startup_gdt_descr = {
|
||||
.size = sizeof(startup_gdt),
|
||||
static struct desc_ptr startup_gdt_descr __initdata = {
|
||||
.size = sizeof(startup_gdt)-1,
|
||||
.address = 0,
|
||||
};
|
||||
|
||||
#define __head __section(".head.text")
|
||||
|
||||
static void __head *fixup_pointer(void *ptr, unsigned long physaddr)
|
||||
{
|
||||
return ptr - (void *)_text + (void *)physaddr;
|
||||
@@ -211,7 +210,7 @@ unsigned long __head __startup_64(unsigned long physaddr,
|
||||
|
||||
/* Fixup the physical addresses in the page table */
|
||||
|
||||
pgd = fixup_pointer(&early_top_pgt, physaddr);
|
||||
pgd = fixup_pointer(early_top_pgt, physaddr);
|
||||
p = pgd + pgd_index(__START_KERNEL_map);
|
||||
if (la57)
|
||||
*p = (unsigned long)level4_kernel_pgt;
|
||||
@@ -220,11 +219,11 @@ unsigned long __head __startup_64(unsigned long physaddr,
|
||||
*p += _PAGE_TABLE_NOENC - __START_KERNEL_map + load_delta;
|
||||
|
||||
if (la57) {
|
||||
p4d = fixup_pointer(&level4_kernel_pgt, physaddr);
|
||||
p4d = fixup_pointer(level4_kernel_pgt, physaddr);
|
||||
p4d[511] += load_delta;
|
||||
}
|
||||
|
||||
pud = fixup_pointer(&level3_kernel_pgt, physaddr);
|
||||
pud = fixup_pointer(level3_kernel_pgt, physaddr);
|
||||
pud[510] += load_delta;
|
||||
pud[511] += load_delta;
|
||||
|
||||
@@ -588,7 +587,7 @@ static void set_bringup_idt_handler(gate_desc *idt, int n, void *handler)
|
||||
}
|
||||
|
||||
/* This runs while still in the direct mapping */
|
||||
static void startup_64_load_idt(unsigned long physbase)
|
||||
static void __head startup_64_load_idt(unsigned long physbase)
|
||||
{
|
||||
struct desc_ptr *desc = fixup_pointer(&bringup_idt_descr, physbase);
|
||||
gate_desc *idt = fixup_pointer(bringup_idt_table, physbase);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
|
||||
.text
|
||||
#include <linux/export.h>
|
||||
#include <linux/threads.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/linkage.h>
|
||||
@@ -25,7 +26,6 @@
|
||||
#include <asm/nops.h>
|
||||
#include <asm/nospec-branch.h>
|
||||
#include <asm/bootparam.h>
|
||||
#include <asm/export.h>
|
||||
#include <asm/pgtable_32.h>
|
||||
|
||||
/* Physical address */
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* Copyright (C) 2005 Eric Biederman <ebiederm@xmission.com>
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/threads.h>
|
||||
#include <linux/init.h>
|
||||
@@ -22,7 +22,6 @@
|
||||
#include <asm/percpu.h>
|
||||
#include <asm/nops.h>
|
||||
#include "../entry/calling.h"
|
||||
#include <asm/export.h>
|
||||
#include <asm/nospec-branch.h>
|
||||
#include <asm/apicdef.h>
|
||||
#include <asm/fixmap.h>
|
||||
@@ -180,8 +179,8 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL)
|
||||
movl $0, %ecx
|
||||
#endif
|
||||
|
||||
/* Enable PAE mode, PGE and LA57 */
|
||||
orl $(X86_CR4_PAE | X86_CR4_PGE), %ecx
|
||||
/* Enable PAE mode, PSE, PGE and LA57 */
|
||||
orl $(X86_CR4_PAE | X86_CR4_PSE | X86_CR4_PGE), %ecx
|
||||
#ifdef CONFIG_X86_5LEVEL
|
||||
testl $1, __pgtable_l5_enabled(%rip)
|
||||
jz 1f
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <asm/proto.h>
|
||||
#include <asm/desc.h>
|
||||
#include <asm/hw_irq.h>
|
||||
#include <asm/ia32.h>
|
||||
#include <asm/idtentry.h>
|
||||
|
||||
#define DPL0 0x0
|
||||
@@ -116,6 +117,9 @@ static const __initconst struct idt_data def_idts[] = {
|
||||
#endif
|
||||
|
||||
SYSG(X86_TRAP_OF, asm_exc_overflow),
|
||||
};
|
||||
|
||||
static const struct idt_data ia32_idt[] __initconst = {
|
||||
#if defined(CONFIG_IA32_EMULATION)
|
||||
SYSG(IA32_SYSCALL_VECTOR, entry_INT80_compat),
|
||||
#elif defined(CONFIG_X86_32)
|
||||
@@ -225,6 +229,9 @@ void __init idt_setup_early_traps(void)
|
||||
void __init idt_setup_traps(void)
|
||||
{
|
||||
idt_setup_from_table(idt_table, def_idts, ARRAY_SIZE(def_idts), true);
|
||||
|
||||
if (ia32_enabled())
|
||||
idt_setup_from_table(idt_table, ia32_idt, ARRAY_SIZE(ia32_idt), true);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#include <asm/asm.h>
|
||||
#include <asm/export.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/linkage.h>
|
||||
|
||||
/*
|
||||
|
||||
@@ -507,12 +507,13 @@ DEFINE_IDTENTRY_RAW(exc_nmi)
|
||||
}
|
||||
this_cpu_write(nmi_state, NMI_EXECUTING);
|
||||
this_cpu_write(nmi_cr2, read_cr2());
|
||||
|
||||
nmi_restart:
|
||||
if (IS_ENABLED(CONFIG_NMI_CHECK_CPU)) {
|
||||
WRITE_ONCE(nsp->idt_seq, nsp->idt_seq + 1);
|
||||
WARN_ON_ONCE(!(nsp->idt_seq & 0x1));
|
||||
WRITE_ONCE(nsp->recv_jiffies, jiffies);
|
||||
}
|
||||
nmi_restart:
|
||||
|
||||
/*
|
||||
* Needs to happen before DR7 is accessed, because the hypervisor can
|
||||
@@ -548,16 +549,16 @@ nmi_restart:
|
||||
|
||||
if (unlikely(this_cpu_read(nmi_cr2) != read_cr2()))
|
||||
write_cr2(this_cpu_read(nmi_cr2));
|
||||
if (this_cpu_dec_return(nmi_state))
|
||||
goto nmi_restart;
|
||||
|
||||
if (user_mode(regs))
|
||||
mds_user_clear_cpu_buffers();
|
||||
if (IS_ENABLED(CONFIG_NMI_CHECK_CPU)) {
|
||||
WRITE_ONCE(nsp->idt_seq, nsp->idt_seq + 1);
|
||||
WARN_ON_ONCE(nsp->idt_seq & 0x1);
|
||||
WRITE_ONCE(nsp->recv_jiffies, jiffies);
|
||||
}
|
||||
if (this_cpu_dec_return(nmi_state))
|
||||
goto nmi_restart;
|
||||
|
||||
if (user_mode(regs))
|
||||
mds_user_clear_cpu_buffers();
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_KVM_INTEL)
|
||||
|
||||
@@ -1120,7 +1120,7 @@ void __init setup_arch(char **cmdline_p)
|
||||
* Needs to run after memblock setup because it needs the physical
|
||||
* memory size.
|
||||
*/
|
||||
sev_setup_arch();
|
||||
mem_encrypt_setup_arch();
|
||||
|
||||
efi_fake_memmap();
|
||||
efi_find_mirror();
|
||||
|
||||
@@ -85,7 +85,7 @@ static struct orc_entry *__orc_find(int *ip_table, struct orc_entry *u_table,
|
||||
{
|
||||
int *first = ip_table;
|
||||
int *last = ip_table + num_entries - 1;
|
||||
int *mid = first, *found = first;
|
||||
int *mid, *found = first;
|
||||
|
||||
if (!num_entries)
|
||||
return NULL;
|
||||
|
||||
@@ -21,10 +21,10 @@
|
||||
* converted to pure assembler
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/asm.h>
|
||||
#include <asm/export.h>
|
||||
#include <asm/nospec-branch.h>
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
#include <linux/export.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/asm.h>
|
||||
#include <asm/export.h>
|
||||
|
||||
/*
|
||||
* Most CPUs support enhanced REP MOVSB/STOSB instructions. It is
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/export.h>
|
||||
#include <asm/percpu.h>
|
||||
#include <asm/processor-flags.h>
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Written 2003 by Andi Kleen, based on a kernel by Evandro Menezes */
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/cpufeatures.h>
|
||||
#include <asm/alternative.h>
|
||||
#include <asm/export.h>
|
||||
|
||||
/*
|
||||
* Some CPUs run faster using the string copy instructions (sane microcode).
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
* Functions to copy from and to user space.
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/cpufeatures.h>
|
||||
#include <asm/alternative.h>
|
||||
#include <asm/asm.h>
|
||||
#include <asm/export.h>
|
||||
|
||||
/*
|
||||
* rep_movs_alternative - memory copy with exception handling.
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
* Copyright 2023 Linus Torvalds <torvalds@linux-foundation.org>
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/asm.h>
|
||||
#include <asm/export.h>
|
||||
|
||||
/*
|
||||
* copy_user_nocache - Uncached memory copy with exception handling
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
* @src: source address (user space)
|
||||
* @dst: destination address
|
||||
* @len: number of bytes to be copied.
|
||||
* @isum: initial sum that is added into the result (32bit unfolded)
|
||||
* @errp: set to -EFAULT for an bad source address.
|
||||
*
|
||||
* Returns an 32bit unfolded checksum of the buffer.
|
||||
* src and dst are best aligned to 64bits.
|
||||
@@ -38,8 +36,6 @@ csum_and_copy_from_user(const void __user *src, void *dst, int len)
|
||||
* @src: source address
|
||||
* @dst: destination address (user space)
|
||||
* @len: number of bytes to be copied.
|
||||
* @isum: initial sum that is added into the result (32bit unfolded)
|
||||
* @errp: set to -EFAULT for an bad destination address.
|
||||
*
|
||||
* Returns an 32bit unfolded checksum of the buffer.
|
||||
* src and dst are best aligned to 64bits.
|
||||
@@ -62,7 +58,6 @@ csum_and_copy_to_user(const void *src, void __user *dst, int len)
|
||||
* @src: source address
|
||||
* @dst: destination address
|
||||
* @len: number of bytes to be copied.
|
||||
* @sum: initial sum that is added into the result (32bit unfolded)
|
||||
*
|
||||
* Returns an 32bit unfolded checksum of the buffer.
|
||||
*/
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
* as they get called from within inline assembly.
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/page_types.h>
|
||||
#include <asm/errno.h>
|
||||
@@ -33,7 +34,6 @@
|
||||
#include <asm/thread_info.h>
|
||||
#include <asm/asm.h>
|
||||
#include <asm/smap.h>
|
||||
#include <asm/export.h>
|
||||
|
||||
#define ASM_BARRIER_NOSPEC ALTERNATIVE "", "lfence", X86_FEATURE_LFENCE_RDTSC
|
||||
|
||||
|
||||
+7
-15
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#include <linux/export.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/export.h>
|
||||
|
||||
#include <asm/asm.h>
|
||||
|
||||
@@ -36,8 +36,12 @@ SYM_FUNC_START(__sw_hweight32)
|
||||
SYM_FUNC_END(__sw_hweight32)
|
||||
EXPORT_SYMBOL(__sw_hweight32)
|
||||
|
||||
SYM_FUNC_START(__sw_hweight64)
|
||||
/*
|
||||
* No 32-bit variant, because it's implemented as an inline wrapper
|
||||
* on top of __arch_hweight32():
|
||||
*/
|
||||
#ifdef CONFIG_X86_64
|
||||
SYM_FUNC_START(__sw_hweight64)
|
||||
pushq %rdi
|
||||
pushq %rdx
|
||||
|
||||
@@ -66,18 +70,6 @@ SYM_FUNC_START(__sw_hweight64)
|
||||
popq %rdx
|
||||
popq %rdi
|
||||
RET
|
||||
#else /* CONFIG_X86_32 */
|
||||
/* We're getting an u64 arg in (%eax,%edx): unsigned long hweight64(__u64 w) */
|
||||
pushl %ecx
|
||||
|
||||
call __sw_hweight32
|
||||
movl %eax, %ecx # stash away result
|
||||
movl %edx, %eax # second part of input
|
||||
call __sw_hweight32
|
||||
addl %ecx, %eax # result
|
||||
|
||||
popl %ecx
|
||||
RET
|
||||
#endif
|
||||
SYM_FUNC_END(__sw_hweight64)
|
||||
EXPORT_SYMBOL(__sw_hweight64)
|
||||
#endif
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Copyright 2002 Andi Kleen */
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/cfi_types.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/cpufeatures.h>
|
||||
#include <asm/alternative.h>
|
||||
#include <asm/export.h>
|
||||
|
||||
.section .noinstr.text, "ax"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/export.h>
|
||||
|
||||
SYM_FUNC_START(memmove)
|
||||
/*
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
* This assembly file is re-written from memmove_64.c file.
|
||||
* - Copyright 2011 Fenghua Yu <fenghua.yu@intel.com>
|
||||
*/
|
||||
#include <linux/export.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/cpufeatures.h>
|
||||
#include <asm/alternative.h>
|
||||
#include <asm/export.h>
|
||||
|
||||
#undef memmove
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright 2002 Andi Kleen, SuSE Labs */
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/cpufeatures.h>
|
||||
#include <asm/alternative.h>
|
||||
#include <asm/export.h>
|
||||
|
||||
.section .noinstr.text, "ax"
|
||||
|
||||
|
||||
@@ -11,13 +11,12 @@
|
||||
* return an error value in addition to the "real"
|
||||
* return value.
|
||||
*/
|
||||
#include <linux/export.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/thread_info.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/asm.h>
|
||||
#include <asm/smap.h>
|
||||
#include <asm/export.h>
|
||||
|
||||
|
||||
/*
|
||||
* __put_user_X
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/stringify.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/dwarf2.h>
|
||||
#include <asm/cpufeatures.h>
|
||||
#include <asm/alternative.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
#include <asm/export.h>
|
||||
#include <asm/nospec-branch.h>
|
||||
#include <asm/unwind_hints.h>
|
||||
#include <asm/percpu.h>
|
||||
|
||||
+14
-5
@@ -9,12 +9,21 @@ bool copy_from_kernel_nofault_allowed(const void *unsafe_src, size_t size)
|
||||
unsigned long vaddr = (unsigned long)unsafe_src;
|
||||
|
||||
/*
|
||||
* Range covering the highest possible canonical userspace address
|
||||
* as well as non-canonical address range. For the canonical range
|
||||
* we also need to include the userspace guard page.
|
||||
* Do not allow userspace addresses. This disallows
|
||||
* normal userspace and the userspace guard page:
|
||||
*/
|
||||
return vaddr >= TASK_SIZE_MAX + PAGE_SIZE &&
|
||||
__is_canonical_address(vaddr, boot_cpu_data.x86_virt_bits);
|
||||
if (vaddr < TASK_SIZE_MAX + PAGE_SIZE)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Allow everything during early boot before 'x86_virt_bits'
|
||||
* is initialized. Needed for instruction decoding in early
|
||||
* exception handlers.
|
||||
*/
|
||||
if (!boot_cpu_data.x86_virt_bits)
|
||||
return true;
|
||||
|
||||
return __is_canonical_address(vaddr, boot_cpu_data.x86_virt_bits);
|
||||
}
|
||||
#else
|
||||
bool copy_from_kernel_nofault_allowed(const void *unsafe_src, size_t size)
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <linux/swiotlb.h>
|
||||
#include <linux/cc_platform.h>
|
||||
#include <linux/mem_encrypt.h>
|
||||
#include <linux/virtio_anchor.h>
|
||||
|
||||
/* Override for DMA direct allocation check - ARCH_HAS_FORCE_DMA_UNENCRYPTED */
|
||||
bool force_dma_unencrypted(struct device *dev)
|
||||
@@ -86,3 +87,36 @@ void __init mem_encrypt_init(void)
|
||||
|
||||
print_mem_encrypt_feature_info();
|
||||
}
|
||||
|
||||
void __init mem_encrypt_setup_arch(void)
|
||||
{
|
||||
phys_addr_t total_mem = memblock_phys_mem_size();
|
||||
unsigned long size;
|
||||
|
||||
if (!cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT))
|
||||
return;
|
||||
|
||||
/*
|
||||
* For SEV and TDX, all DMA has to occur via shared/unencrypted pages.
|
||||
* Kernel uses SWIOTLB to make this happen without changing device
|
||||
* drivers. However, depending on the workload being run, the
|
||||
* default 64MB of SWIOTLB may not be enough and SWIOTLB may
|
||||
* run out of buffers for DMA, resulting in I/O errors and/or
|
||||
* performance degradation especially with high I/O workloads.
|
||||
*
|
||||
* Adjust the default size of SWIOTLB using a percentage of guest
|
||||
* memory for SWIOTLB buffers. Also, as the SWIOTLB bounce buffer
|
||||
* memory is allocated from low memory, ensure that the adjusted size
|
||||
* is within the limits of low available memory.
|
||||
*
|
||||
* The percentage of guest memory used here for SWIOTLB buffers
|
||||
* is more of an approximation of the static adjustment which
|
||||
* 64MB for <1G, and ~128M to 256M for 1G-to-4G, i.e., the 6%
|
||||
*/
|
||||
size = total_mem * 6 / 100;
|
||||
size = clamp_val(size, IO_TLB_DEFAULT_SIZE, SZ_1G);
|
||||
swiotlb_adjust_size(size);
|
||||
|
||||
/* Set restricted memory access for virtio. */
|
||||
virtio_set_mem_acc_cb(virtio_require_restricted_mem_acc);
|
||||
}
|
||||
|
||||
@@ -19,8 +19,6 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/virtio_config.h>
|
||||
#include <linux/virtio_anchor.h>
|
||||
#include <linux/cc_platform.h>
|
||||
|
||||
#include <asm/tlbflush.h>
|
||||
@@ -215,40 +213,6 @@ void __init sme_map_bootdata(char *real_mode_data)
|
||||
__sme_early_map_unmap_mem(__va(cmdline_paddr), COMMAND_LINE_SIZE, true);
|
||||
}
|
||||
|
||||
void __init sev_setup_arch(void)
|
||||
{
|
||||
phys_addr_t total_mem = memblock_phys_mem_size();
|
||||
unsigned long size;
|
||||
|
||||
if (!cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT))
|
||||
return;
|
||||
|
||||
/*
|
||||
* For SEV, all DMA has to occur via shared/unencrypted pages.
|
||||
* SEV uses SWIOTLB to make this happen without changing device
|
||||
* drivers. However, depending on the workload being run, the
|
||||
* default 64MB of SWIOTLB may not be enough and SWIOTLB may
|
||||
* run out of buffers for DMA, resulting in I/O errors and/or
|
||||
* performance degradation especially with high I/O workloads.
|
||||
*
|
||||
* Adjust the default size of SWIOTLB for SEV guests using
|
||||
* a percentage of guest memory for SWIOTLB buffers.
|
||||
* Also, as the SWIOTLB bounce buffer memory is allocated
|
||||
* from low memory, ensure that the adjusted size is within
|
||||
* the limits of low available memory.
|
||||
*
|
||||
* The percentage of guest memory used here for SWIOTLB buffers
|
||||
* is more of an approximation of the static adjustment which
|
||||
* 64MB for <1G, and ~128M to 256M for 1G-to-4G, i.e., the 6%
|
||||
*/
|
||||
size = total_mem * 6 / 100;
|
||||
size = clamp_val(size, IO_TLB_DEFAULT_SIZE, SZ_1G);
|
||||
swiotlb_adjust_size(size);
|
||||
|
||||
/* Set restricted memory access for virtio. */
|
||||
virtio_set_mem_acc_cb(virtio_require_restricted_mem_acc);
|
||||
}
|
||||
|
||||
static unsigned long pg_level_to_pfn(int level, pte_t *kpte, pgprot_t *ret_prot)
|
||||
{
|
||||
unsigned long pfn = 0;
|
||||
|
||||
+80
-7
@@ -12,6 +12,7 @@
|
||||
#include <linux/nodemask.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/topology.h>
|
||||
#include <linux/sort.h>
|
||||
|
||||
#include <asm/e820/api.h>
|
||||
#include <asm/proto.h>
|
||||
@@ -602,13 +603,6 @@ static int __init numa_register_memblks(struct numa_meminfo *mi)
|
||||
if (start >= end)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Don't confuse VM with a node that doesn't have the
|
||||
* minimum amount of memory:
|
||||
*/
|
||||
if (end && (end - start) < NODE_MIN_SIZE)
|
||||
continue;
|
||||
|
||||
alloc_node_data(nid);
|
||||
}
|
||||
|
||||
@@ -964,4 +958,83 @@ int memory_add_physaddr_to_nid(u64 start)
|
||||
return nid;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
|
||||
|
||||
static int __init cmp_memblk(const void *a, const void *b)
|
||||
{
|
||||
const struct numa_memblk *ma = *(const struct numa_memblk **)a;
|
||||
const struct numa_memblk *mb = *(const struct numa_memblk **)b;
|
||||
|
||||
return ma->start - mb->start;
|
||||
}
|
||||
|
||||
static struct numa_memblk *numa_memblk_list[NR_NODE_MEMBLKS] __initdata;
|
||||
|
||||
/**
|
||||
* numa_fill_memblks - Fill gaps in numa_meminfo memblks
|
||||
* @start: address to begin fill
|
||||
* @end: address to end fill
|
||||
*
|
||||
* Find and extend numa_meminfo memblks to cover the @start-@end
|
||||
* physical address range, such that the first memblk includes
|
||||
* @start, the last memblk includes @end, and any gaps in between
|
||||
* are filled.
|
||||
*
|
||||
* RETURNS:
|
||||
* 0 : Success
|
||||
* NUMA_NO_MEMBLK : No memblk exists in @start-@end range
|
||||
*/
|
||||
|
||||
int __init numa_fill_memblks(u64 start, u64 end)
|
||||
{
|
||||
struct numa_memblk **blk = &numa_memblk_list[0];
|
||||
struct numa_meminfo *mi = &numa_meminfo;
|
||||
int count = 0;
|
||||
u64 prev_end;
|
||||
|
||||
/*
|
||||
* Create a list of pointers to numa_meminfo memblks that
|
||||
* overlap start, end. Exclude (start == bi->end) since
|
||||
* end addresses in both a CFMWS range and a memblk range
|
||||
* are exclusive.
|
||||
*
|
||||
* This list of pointers is used to make in-place changes
|
||||
* that fill out the numa_meminfo memblks.
|
||||
*/
|
||||
for (int i = 0; i < mi->nr_blks; i++) {
|
||||
struct numa_memblk *bi = &mi->blk[i];
|
||||
|
||||
if (start < bi->end && end >= bi->start) {
|
||||
blk[count] = &mi->blk[i];
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (!count)
|
||||
return NUMA_NO_MEMBLK;
|
||||
|
||||
/* Sort the list of pointers in memblk->start order */
|
||||
sort(&blk[0], count, sizeof(blk[0]), cmp_memblk, NULL);
|
||||
|
||||
/* Make sure the first/last memblks include start/end */
|
||||
blk[0]->start = min(blk[0]->start, start);
|
||||
blk[count - 1]->end = max(blk[count - 1]->end, end);
|
||||
|
||||
/*
|
||||
* Fill any gaps by tracking the previous memblks
|
||||
* end address and backfilling to it if needed.
|
||||
*/
|
||||
prev_end = blk[0]->end;
|
||||
for (int i = 1; i < count; i++) {
|
||||
struct numa_memblk *curr = blk[i];
|
||||
|
||||
if (prev_end >= curr->start) {
|
||||
if (prev_end < curr->end)
|
||||
prev_end = curr->end;
|
||||
} else {
|
||||
curr->start = prev_end;
|
||||
prev_end = curr->end;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -310,11 +310,16 @@ static int __init acpi_parse_cfmws(union acpi_subtable_headers *header,
|
||||
start = cfmws->base_hpa;
|
||||
end = cfmws->base_hpa + cfmws->window_size;
|
||||
|
||||
/* Skip if the SRAT already described the NUMA details for this HPA */
|
||||
node = phys_to_target_node(start);
|
||||
if (node != NUMA_NO_NODE)
|
||||
/*
|
||||
* The SRAT may have already described NUMA details for all,
|
||||
* or a portion of, this CFMWS HPA range. Extend the memblks
|
||||
* found for any portion of the window to cover the entire
|
||||
* window.
|
||||
*/
|
||||
if (!numa_fill_memblks(start, end))
|
||||
return 0;
|
||||
|
||||
/* No SRAT description. Create a new node. */
|
||||
node = acpi_map_pxm_to_node(*fake_pxm);
|
||||
|
||||
if (node == NUMA_NO_NODE) {
|
||||
|
||||
@@ -108,13 +108,6 @@ lib-y := $(patsubst %.o,%.stub.o,$(lib-y))
|
||||
# https://bugs.llvm.org/show_bug.cgi?id=46480
|
||||
STUBCOPY_FLAGS-y += --remove-section=.note.gnu.property
|
||||
|
||||
#
|
||||
# For x86, bootloaders like systemd-boot or grub-efi do not zero-initialize the
|
||||
# .bss section, so the .bss section of the EFI stub needs to be included in the
|
||||
# .data section of the compressed kernel to ensure initialization. Rename the
|
||||
# .bss section here so it's easy to pick out in the linker script.
|
||||
#
|
||||
STUBCOPY_FLAGS-$(CONFIG_X86) += --rename-section .bss=.bss.efistub,load,alloc
|
||||
STUBCOPY_RELOC-$(CONFIG_X86_32) := R_386_32
|
||||
STUBCOPY_RELOC-$(CONFIG_X86_64) := R_X86_64_64
|
||||
|
||||
|
||||
@@ -449,9 +449,8 @@ void __noreturn efi_stub_entry(efi_handle_t handle,
|
||||
efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
|
||||
efi_system_table_t *sys_table_arg)
|
||||
{
|
||||
struct boot_params *boot_params;
|
||||
struct setup_header *hdr;
|
||||
void *image_base;
|
||||
static struct boot_params boot_params __page_aligned_bss;
|
||||
struct setup_header *hdr = &boot_params.hdr;
|
||||
efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;
|
||||
int options_size = 0;
|
||||
efi_status_t status;
|
||||
@@ -469,30 +468,9 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
|
||||
efi_exit(handle, status);
|
||||
}
|
||||
|
||||
image_base = efi_table_attr(image, image_base);
|
||||
|
||||
status = efi_allocate_pages(sizeof(struct boot_params),
|
||||
(unsigned long *)&boot_params, ULONG_MAX);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_err("Failed to allocate lowmem for boot params\n");
|
||||
efi_exit(handle, status);
|
||||
}
|
||||
|
||||
memset(boot_params, 0x0, sizeof(struct boot_params));
|
||||
|
||||
hdr = &boot_params->hdr;
|
||||
|
||||
/* Copy the setup header from the second sector to boot_params */
|
||||
memcpy(&hdr->jump, image_base + 512,
|
||||
sizeof(struct setup_header) - offsetof(struct setup_header, jump));
|
||||
|
||||
/*
|
||||
* Fill out some of the header fields ourselves because the
|
||||
* EFI firmware loader doesn't load the first sector.
|
||||
*/
|
||||
/* Assign the setup_header fields that the kernel actually cares about */
|
||||
hdr->root_flags = 1;
|
||||
hdr->vid_mode = 0xffff;
|
||||
hdr->boot_flag = 0xAA55;
|
||||
|
||||
hdr->type_of_loader = 0x21;
|
||||
|
||||
@@ -501,25 +479,13 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
|
||||
if (!cmdline_ptr)
|
||||
goto fail;
|
||||
|
||||
efi_set_u64_split((unsigned long)cmdline_ptr,
|
||||
&hdr->cmd_line_ptr, &boot_params->ext_cmd_line_ptr);
|
||||
efi_set_u64_split((unsigned long)cmdline_ptr, &hdr->cmd_line_ptr,
|
||||
&boot_params.ext_cmd_line_ptr);
|
||||
|
||||
hdr->ramdisk_image = 0;
|
||||
hdr->ramdisk_size = 0;
|
||||
|
||||
/*
|
||||
* Disregard any setup data that was provided by the bootloader:
|
||||
* setup_data could be pointing anywhere, and we have no way of
|
||||
* authenticating or validating the payload.
|
||||
*/
|
||||
hdr->setup_data = 0;
|
||||
|
||||
efi_stub_entry(handle, sys_table_arg, boot_params);
|
||||
efi_stub_entry(handle, sys_table_arg, &boot_params);
|
||||
/* not reached */
|
||||
|
||||
fail:
|
||||
efi_free(sizeof(struct boot_params), (unsigned long)boot_params);
|
||||
|
||||
efi_exit(handle, status);
|
||||
}
|
||||
|
||||
@@ -849,7 +815,7 @@ void __noreturn efi_stub_entry(efi_handle_t handle,
|
||||
unsigned long kernel_entry;
|
||||
efi_status_t status;
|
||||
|
||||
boot_params_pointer = boot_params;
|
||||
boot_params_ptr = boot_params;
|
||||
|
||||
efi_system_table = sys_table_arg;
|
||||
/* Check if we were booted by the EFI firmware */
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
#include <linux/efi.h>
|
||||
|
||||
extern struct boot_params *boot_params_pointer asm("boot_params");
|
||||
|
||||
extern void trampoline_32bit_src(void *, bool);
|
||||
extern const u16 trampoline_ljmp_imm_offset;
|
||||
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_pci.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#define MSI_IRQS_PER_MSIR 32
|
||||
@@ -334,20 +335,17 @@ MODULE_DEVICE_TABLE(of, ls_scfg_msi_id);
|
||||
|
||||
static int ls_scfg_msi_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *match;
|
||||
struct ls_scfg_msi *msi_data;
|
||||
struct resource *res;
|
||||
int i, ret;
|
||||
|
||||
match = of_match_device(ls_scfg_msi_id, &pdev->dev);
|
||||
if (!match)
|
||||
return -ENODEV;
|
||||
|
||||
msi_data = devm_kzalloc(&pdev->dev, sizeof(*msi_data), GFP_KERNEL);
|
||||
if (!msi_data)
|
||||
return -ENOMEM;
|
||||
|
||||
msi_data->cfg = (struct ls_scfg_msi_cfg *) match->data;
|
||||
msi_data->cfg = (struct ls_scfg_msi_cfg *)device_get_match_data(&pdev->dev);
|
||||
if (!msi_data->cfg)
|
||||
return -ENODEV;
|
||||
|
||||
msi_data->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||
if (IS_ERR(msi_data->regs)) {
|
||||
|
||||
@@ -247,6 +247,7 @@ static const struct irq_chip irqc_chip = {
|
||||
.irq_set_irqchip_state = irq_chip_set_parent_state,
|
||||
.irq_retrigger = irq_chip_retrigger_hierarchy,
|
||||
.irq_set_type = rzg2l_irqc_set_type,
|
||||
.irq_set_affinity = irq_chip_set_affinity_parent,
|
||||
.flags = IRQCHIP_MASK_ON_SUSPEND |
|
||||
IRQCHIP_SET_TYPE_MASKED |
|
||||
IRQCHIP_SKIP_SET_WAKE,
|
||||
|
||||
@@ -532,17 +532,18 @@ done:
|
||||
}
|
||||
|
||||
/*
|
||||
* We can have multiple PLIC instances so setup cpuhp state only
|
||||
* when context handler for current/boot CPU is present.
|
||||
* We can have multiple PLIC instances so setup cpuhp state
|
||||
* and register syscore operations only when context handler
|
||||
* for current/boot CPU is present.
|
||||
*/
|
||||
handler = this_cpu_ptr(&plic_handlers);
|
||||
if (handler->present && !plic_cpuhp_setup_done) {
|
||||
cpuhp_setup_state(CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING,
|
||||
"irqchip/sifive/plic:starting",
|
||||
plic_starting_cpu, plic_dying_cpu);
|
||||
register_syscore_ops(&plic_irq_syscore_ops);
|
||||
plic_cpuhp_setup_done = true;
|
||||
}
|
||||
register_syscore_ops(&plic_irq_syscore_ops);
|
||||
|
||||
pr_info("%pOFP: mapped %d interrupts with %d handlers for"
|
||||
" %d contexts.\n", node, nr_irqs, nr_handlers, nr_contexts);
|
||||
|
||||
@@ -204,7 +204,6 @@ enum cpuhp_state {
|
||||
CPUHP_AP_KVM_ONLINE,
|
||||
CPUHP_AP_SCHED_WAIT_EMPTY,
|
||||
CPUHP_AP_SMPBOOT_THREADS,
|
||||
CPUHP_AP_X86_VDSO_VMA_ONLINE,
|
||||
CPUHP_AP_IRQ_AFFINITY_ONLINE,
|
||||
CPUHP_AP_BLK_MQ_ONLINE,
|
||||
CPUHP_AP_ARM_MVEBU_SYNC_CLOCKS,
|
||||
|
||||
@@ -174,7 +174,7 @@ struct irq_domain {
|
||||
irq_hw_number_t hwirq_max;
|
||||
unsigned int revmap_size;
|
||||
struct radix_tree_root revmap_tree;
|
||||
struct irq_data __rcu *revmap[];
|
||||
struct irq_data __rcu *revmap[] __counted_by(revmap_size);
|
||||
};
|
||||
|
||||
/* Irq domain flags */
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#define MAX_NUMNODES (1 << NODES_SHIFT)
|
||||
|
||||
#define NUMA_NO_NODE (-1)
|
||||
#define NUMA_NO_MEMBLK (-1)
|
||||
|
||||
/* optionally keep NUMA memory info available post init */
|
||||
#ifdef CONFIG_NUMA_KEEP_MEMINFO
|
||||
@@ -43,6 +44,12 @@ static inline int phys_to_target_node(u64 start)
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#ifndef numa_fill_memblks
|
||||
static inline int __init numa_fill_memblks(u64 start, u64 end)
|
||||
{
|
||||
return NUMA_NO_MEMBLK;
|
||||
}
|
||||
#endif
|
||||
#else /* !CONFIG_NUMA */
|
||||
static inline int numa_nearest_node(int node, unsigned int state)
|
||||
{
|
||||
|
||||
@@ -48,13 +48,13 @@
|
||||
#define ANNOTATE_NOENDBR \
|
||||
"986: \n\t" \
|
||||
".pushsection .discard.noendbr\n\t" \
|
||||
".long 986b - .\n\t" \
|
||||
".long 986b\n\t" \
|
||||
".popsection\n\t"
|
||||
|
||||
#define ASM_REACHABLE \
|
||||
"998:\n\t" \
|
||||
".pushsection .discard.reachable\n\t" \
|
||||
".long 998b - .\n\t" \
|
||||
".long 998b\n\t" \
|
||||
".popsection\n\t"
|
||||
|
||||
#else /* __ASSEMBLY__ */
|
||||
@@ -66,7 +66,7 @@
|
||||
#define ANNOTATE_INTRA_FUNCTION_CALL \
|
||||
999: \
|
||||
.pushsection .discard.intra_function_calls; \
|
||||
.long 999b - .; \
|
||||
.long 999b; \
|
||||
.popsection;
|
||||
|
||||
/*
|
||||
@@ -118,7 +118,7 @@
|
||||
.macro ANNOTATE_NOENDBR
|
||||
.Lhere_\@:
|
||||
.pushsection .discard.noendbr
|
||||
.long .Lhere_\@ - .
|
||||
.long .Lhere_\@
|
||||
.popsection
|
||||
.endm
|
||||
|
||||
@@ -142,7 +142,7 @@
|
||||
.macro REACHABLE
|
||||
.Lhere_\@:
|
||||
.pushsection .discard.reachable
|
||||
.long .Lhere_\@ - .
|
||||
.long .Lhere_\@
|
||||
.popsection
|
||||
.endm
|
||||
|
||||
|
||||
+26
-8
@@ -1624,6 +1624,8 @@ struct msix_entry {
|
||||
u16 entry; /* Driver uses to specify entry, OS writes */
|
||||
};
|
||||
|
||||
struct msi_domain_template;
|
||||
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
int pci_msi_vec_count(struct pci_dev *dev);
|
||||
void pci_disable_msi(struct pci_dev *dev);
|
||||
@@ -1656,6 +1658,11 @@ void pci_msix_free_irq(struct pci_dev *pdev, struct msi_map map);
|
||||
void pci_free_irq_vectors(struct pci_dev *dev);
|
||||
int pci_irq_vector(struct pci_dev *dev, unsigned int nr);
|
||||
const struct cpumask *pci_irq_get_affinity(struct pci_dev *pdev, int vec);
|
||||
bool pci_create_ims_domain(struct pci_dev *pdev, const struct msi_domain_template *template,
|
||||
unsigned int hwsize, void *data);
|
||||
struct msi_map pci_ims_alloc_irq(struct pci_dev *pdev, union msi_instance_cookie *icookie,
|
||||
const struct irq_affinity_desc *affdesc);
|
||||
void pci_ims_free_irq(struct pci_dev *pdev, struct msi_map map);
|
||||
|
||||
#else
|
||||
static inline int pci_msi_vec_count(struct pci_dev *dev) { return -ENOSYS; }
|
||||
@@ -1719,6 +1726,25 @@ static inline const struct cpumask *pci_irq_get_affinity(struct pci_dev *pdev,
|
||||
{
|
||||
return cpu_possible_mask;
|
||||
}
|
||||
|
||||
static inline bool pci_create_ims_domain(struct pci_dev *pdev,
|
||||
const struct msi_domain_template *template,
|
||||
unsigned int hwsize, void *data)
|
||||
{ return false; }
|
||||
|
||||
static inline struct msi_map pci_ims_alloc_irq(struct pci_dev *pdev,
|
||||
union msi_instance_cookie *icookie,
|
||||
const struct irq_affinity_desc *affdesc)
|
||||
{
|
||||
struct msi_map map = { .index = -ENOSYS, };
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
static inline void pci_ims_free_irq(struct pci_dev *pdev, struct msi_map map)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -2616,14 +2642,6 @@ static inline bool pci_is_thunderbolt_attached(struct pci_dev *pdev)
|
||||
void pci_uevent_ers(struct pci_dev *pdev, enum pci_ers_result err_type);
|
||||
#endif
|
||||
|
||||
struct msi_domain_template;
|
||||
|
||||
bool pci_create_ims_domain(struct pci_dev *pdev, const struct msi_domain_template *template,
|
||||
unsigned int hwsize, void *data);
|
||||
struct msi_map pci_ims_alloc_irq(struct pci_dev *pdev, union msi_instance_cookie *icookie,
|
||||
const struct irq_affinity_desc *affdesc);
|
||||
void pci_ims_free_irq(struct pci_dev *pdev, struct msi_map map);
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#define pci_printk(level, pdev, fmt, arg...) \
|
||||
|
||||
@@ -879,6 +879,7 @@ struct perf_event_pmu_context {
|
||||
unsigned int embedded : 1;
|
||||
|
||||
unsigned int nr_events;
|
||||
unsigned int nr_cgroups;
|
||||
|
||||
atomic_t refcount; /* event <-> epc */
|
||||
struct rcu_head rcu_head;
|
||||
@@ -1592,7 +1593,7 @@ extern int sysctl_perf_cpu_time_max_percent;
|
||||
|
||||
extern void perf_sample_event_took(u64 sample_len_ns);
|
||||
|
||||
int perf_proc_update_handler(struct ctl_table *table, int write,
|
||||
int perf_event_max_sample_rate_handler(struct ctl_table *table, int write,
|
||||
void *buffer, size_t *lenp, loff_t *ppos);
|
||||
int perf_cpu_time_max_percent_handler(struct ctl_table *table, int write,
|
||||
void *buffer, size_t *lenp, loff_t *ppos);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user