Skip to content

Commit 146c3d3

Browse files
committed
Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 fixes from Thomas Gleixner: "A few fixes for x86: - Fix a boot regression caused by the recent bootparam sanitizing change, which escaped the attention of all people who reviewed that code. - Address a boot problem on machines with broken E820 tables caused by an underflow which ended up placing the trampoline start at physical address 0. - Handle machines which do not advertise a legacy timer of any form, but need calibration of the local APIC timer gracefully by making the calibration routine independent from the tick interrupt. Marked for stable as well as there seems to be quite some new laptops rolled out which expose this. - Clear the RDRAND CPUID bit on AMD family 15h and 16h CPUs which are affected by broken firmware which does not initialize RDRAND correctly after resume. Add a command line parameter to override this for machine which either do not use suspend/resume or have a fixed BIOS. Unfortunately there is no way to detect this on boot, so the only safe decision is to turn it off by default. - Prevent RFLAGS from being clobbers in CALL_NOSPEC on 32bit which caused fast KVM instruction emulation to break. - Explain the Intel CPU model naming convention so that the repeating discussions come to an end" * 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/retpoline: Don't clobber RFLAGS during CALL_NOSPEC on i386 x86/boot: Fix boot regression caused by bootparam sanitizing x86/CPU/AMD: Clear RDRAND CPUID bit on AMD family 15h/16h x86/boot/compressed/64: Fix boot on machines with broken E820 table x86/apic: Handle missing global clockevent gracefully x86/cpu: Explain Intel model naming convention
2 parents 5a13fc3 + b63f20a commit 146c3d3

File tree

9 files changed

+227
-33
lines changed

9 files changed

+227
-33
lines changed

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4090,6 +4090,13 @@
40904090
Run specified binary instead of /init from the ramdisk,
40914091
used for early userspace startup. See initrd.
40924092

4093+
rdrand= [X86]
4094+
force - Override the decision by the kernel to hide the
4095+
advertisement of RDRAND support (this affects
4096+
certain AMD processors because of buggy BIOS
4097+
support, specifically around the suspend/resume
4098+
path).
4099+
40934100
rdt= [HW,X86,RDT]
40944101
Turn on/off individual RDT features. List is:
40954102
cmt, mbmtotal, mbmlocal, l3cat, l3cdp, l2cat, l2cdp,

arch/x86/boot/compressed/pgtable_64.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ static unsigned long find_trampoline_placement(void)
7272

7373
/* Find the first usable memory region under bios_start. */
7474
for (i = boot_params->e820_entries - 1; i >= 0; i--) {
75+
unsigned long new;
76+
7577
entry = &boot_params->e820_table[i];
7678

7779
/* Skip all entries above bios_start. */
@@ -84,15 +86,20 @@ static unsigned long find_trampoline_placement(void)
8486

8587
/* Adjust bios_start to the end of the entry if needed. */
8688
if (bios_start > entry->addr + entry->size)
87-
bios_start = entry->addr + entry->size;
89+
new = entry->addr + entry->size;
8890

8991
/* Keep bios_start page-aligned. */
90-
bios_start = round_down(bios_start, PAGE_SIZE);
92+
new = round_down(new, PAGE_SIZE);
9193

9294
/* Skip the entry if it's too small. */
93-
if (bios_start - TRAMPOLINE_32BIT_SIZE < entry->addr)
95+
if (new - TRAMPOLINE_32BIT_SIZE < entry->addr)
9496
continue;
9597

98+
/* Protect against underflow. */
99+
if (new - TRAMPOLINE_32BIT_SIZE > bios_start)
100+
break;
101+
102+
bios_start = new;
96103
break;
97104
}
98105

arch/x86/include/asm/bootparam_utils.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ static void sanitize_boot_params(struct boot_params *boot_params)
5959
BOOT_PARAM_PRESERVE(apm_bios_info),
6060
BOOT_PARAM_PRESERVE(tboot_addr),
6161
BOOT_PARAM_PRESERVE(ist_info),
62-
BOOT_PARAM_PRESERVE(acpi_rsdp_addr),
6362
BOOT_PARAM_PRESERVE(hd0_info),
6463
BOOT_PARAM_PRESERVE(hd1_info),
6564
BOOT_PARAM_PRESERVE(sys_desc_table),
@@ -71,6 +70,7 @@ static void sanitize_boot_params(struct boot_params *boot_params)
7170
BOOT_PARAM_PRESERVE(eddbuf_entries),
7271
BOOT_PARAM_PRESERVE(edd_mbr_sig_buf_entries),
7372
BOOT_PARAM_PRESERVE(edd_mbr_sig_buffer),
73+
BOOT_PARAM_PRESERVE(hdr),
7474
BOOT_PARAM_PRESERVE(e820_table),
7575
BOOT_PARAM_PRESERVE(eddbuf),
7676
};

arch/x86/include/asm/intel-family.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,21 @@
1111
* While adding a new CPUID for a new microarchitecture, add a new
1212
* group to keep logically sorted out in chronological order. Within
1313
* that group keep the CPUID for the variants sorted by model number.
14+
*
15+
* The defined symbol names have the following form:
16+
* INTEL_FAM6{OPTFAMILY}_{MICROARCH}{OPTDIFF}
17+
* where:
18+
* OPTFAMILY Describes the family of CPUs that this belongs to. Default
19+
* is assumed to be "_CORE" (and should be omitted). Other values
20+
* currently in use are _ATOM and _XEON_PHI
21+
* MICROARCH Is the code name for the micro-architecture for this core.
22+
* N.B. Not the platform name.
23+
* OPTDIFF If needed, a short string to differentiate by market segment.
24+
* Exact strings here will vary over time. _DESKTOP, _MOBILE, and
25+
* _X (short for Xeon server) should be used when they are
26+
* appropriate.
27+
*
28+
* The #define line may optionally include a comment including platform names.
1429
*/
1530

1631
#define INTEL_FAM6_CORE_YONAH 0x0E

arch/x86/include/asm/msr-index.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,7 @@
381381
#define MSR_AMD64_PATCH_LEVEL 0x0000008b
382382
#define MSR_AMD64_TSC_RATIO 0xc0000104
383383
#define MSR_AMD64_NB_CFG 0xc001001f
384+
#define MSR_AMD64_CPUID_FN_1 0xc0011004
384385
#define MSR_AMD64_PATCH_LOADER 0xc0010020
385386
#define MSR_AMD64_OSVW_ID_LENGTH 0xc0010140
386387
#define MSR_AMD64_OSVW_STATUS 0xc0010141

arch/x86/include/asm/nospec-branch.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@
192192
" lfence;\n" \
193193
" jmp 902b;\n" \
194194
" .align 16\n" \
195-
"903: addl $4, %%esp;\n" \
195+
"903: lea 4(%%esp), %%esp;\n" \
196196
" pushl %[thunk_target];\n" \
197197
" ret;\n" \
198198
" .align 16\n" \

arch/x86/kernel/apic/apic.c

Lines changed: 53 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -722,7 +722,7 @@ static __initdata unsigned long lapic_cal_pm1, lapic_cal_pm2;
722722
static __initdata unsigned long lapic_cal_j1, lapic_cal_j2;
723723

724724
/*
725-
* Temporary interrupt handler.
725+
* Temporary interrupt handler and polled calibration function.
726726
*/
727727
static void __init lapic_cal_handler(struct clock_event_device *dev)
728728
{
@@ -851,7 +851,8 @@ bool __init apic_needs_pit(void)
851851
static int __init calibrate_APIC_clock(void)
852852
{
853853
struct clock_event_device *levt = this_cpu_ptr(&lapic_events);
854-
void (*real_handler)(struct clock_event_device *dev);
854+
u64 tsc_perj = 0, tsc_start = 0;
855+
unsigned long jif_start;
855856
unsigned long deltaj;
856857
long delta, deltatsc;
857858
int pm_referenced = 0;
@@ -878,28 +879,64 @@ static int __init calibrate_APIC_clock(void)
878879
apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n"
879880
"calibrating APIC timer ...\n");
880881

882+
/*
883+
* There are platforms w/o global clockevent devices. Instead of
884+
* making the calibration conditional on that, use a polling based
885+
* approach everywhere.
886+
*/
881887
local_irq_disable();
882888

883-
/* Replace the global interrupt handler */
884-
real_handler = global_clock_event->event_handler;
885-
global_clock_event->event_handler = lapic_cal_handler;
886-
887889
/*
888890
* Setup the APIC counter to maximum. There is no way the lapic
889891
* can underflow in the 100ms detection time frame
890892
*/
891893
__setup_APIC_LVTT(0xffffffff, 0, 0);
892894

893-
/* Let the interrupts run */
895+
/*
896+
* Methods to terminate the calibration loop:
897+
* 1) Global clockevent if available (jiffies)
898+
* 2) TSC if available and frequency is known
899+
*/
900+
jif_start = READ_ONCE(jiffies);
901+
902+
if (tsc_khz) {
903+
tsc_start = rdtsc();
904+
tsc_perj = div_u64((u64)tsc_khz * 1000, HZ);
905+
}
906+
907+
/*
908+
* Enable interrupts so the tick can fire, if a global
909+
* clockevent device is available
910+
*/
894911
local_irq_enable();
895912

896-
while (lapic_cal_loops <= LAPIC_CAL_LOOPS)
897-
cpu_relax();
913+
while (lapic_cal_loops <= LAPIC_CAL_LOOPS) {
914+
/* Wait for a tick to elapse */
915+
while (1) {
916+
if (tsc_khz) {
917+
u64 tsc_now = rdtsc();
918+
if ((tsc_now - tsc_start) >= tsc_perj) {
919+
tsc_start += tsc_perj;
920+
break;
921+
}
922+
} else {
923+
unsigned long jif_now = READ_ONCE(jiffies);
898924

899-
local_irq_disable();
925+
if (time_after(jif_now, jif_start)) {
926+
jif_start = jif_now;
927+
break;
928+
}
929+
}
930+
cpu_relax();
931+
}
900932

901-
/* Restore the real event handler */
902-
global_clock_event->event_handler = real_handler;
933+
/* Invoke the calibration routine */
934+
local_irq_disable();
935+
lapic_cal_handler(NULL);
936+
local_irq_enable();
937+
}
938+
939+
local_irq_disable();
903940

904941
/* Build delta t1-t2 as apic timer counts down */
905942
delta = lapic_cal_t1 - lapic_cal_t2;
@@ -943,10 +980,11 @@ static int __init calibrate_APIC_clock(void)
943980
levt->features &= ~CLOCK_EVT_FEAT_DUMMY;
944981

945982
/*
946-
* PM timer calibration failed or not turned on
947-
* so lets try APIC timer based calibration
983+
* PM timer calibration failed or not turned on so lets try APIC
984+
* timer based calibration, if a global clockevent device is
985+
* available.
948986
*/
949-
if (!pm_referenced) {
987+
if (!pm_referenced && global_clock_event) {
950988
apic_printk(APIC_VERBOSE, "... verify APIC timer\n");
951989

952990
/*

arch/x86/kernel/cpu/amd.c

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,64 @@ static void init_amd_ln(struct cpuinfo_x86 *c)
804804
msr_set_bit(MSR_AMD64_DE_CFG, 31);
805805
}
806806

807+
static bool rdrand_force;
808+
809+
static int __init rdrand_cmdline(char *str)
810+
{
811+
if (!str)
812+
return -EINVAL;
813+
814+
if (!strcmp(str, "force"))
815+
rdrand_force = true;
816+
else
817+
return -EINVAL;
818+
819+
return 0;
820+
}
821+
early_param("rdrand", rdrand_cmdline);
822+
823+
static void clear_rdrand_cpuid_bit(struct cpuinfo_x86 *c)
824+
{
825+
/*
826+
* Saving of the MSR used to hide the RDRAND support during
827+
* suspend/resume is done by arch/x86/power/cpu.c, which is
828+
* dependent on CONFIG_PM_SLEEP.
829+
*/
830+
if (!IS_ENABLED(CONFIG_PM_SLEEP))
831+
return;
832+
833+
/*
834+
* The nordrand option can clear X86_FEATURE_RDRAND, so check for
835+
* RDRAND support using the CPUID function directly.
836+
*/
837+
if (!(cpuid_ecx(1) & BIT(30)) || rdrand_force)
838+
return;
839+
840+
msr_clear_bit(MSR_AMD64_CPUID_FN_1, 62);
841+
842+
/*
843+
* Verify that the CPUID change has occurred in case the kernel is
844+
* running virtualized and the hypervisor doesn't support the MSR.
845+
*/
846+
if (cpuid_ecx(1) & BIT(30)) {
847+
pr_info_once("BIOS may not properly restore RDRAND after suspend, but hypervisor does not support hiding RDRAND via CPUID.\n");
848+
return;
849+
}
850+
851+
clear_cpu_cap(c, X86_FEATURE_RDRAND);
852+
pr_info_once("BIOS may not properly restore RDRAND after suspend, hiding RDRAND via CPUID. Use rdrand=force to reenable.\n");
853+
}
854+
855+
static void init_amd_jg(struct cpuinfo_x86 *c)
856+
{
857+
/*
858+
* Some BIOS implementations do not restore proper RDRAND support
859+
* across suspend and resume. Check on whether to hide the RDRAND
860+
* instruction support via CPUID.
861+
*/
862+
clear_rdrand_cpuid_bit(c);
863+
}
864+
807865
static void init_amd_bd(struct cpuinfo_x86 *c)
808866
{
809867
u64 value;
@@ -818,6 +876,13 @@ static void init_amd_bd(struct cpuinfo_x86 *c)
818876
wrmsrl_safe(MSR_F15H_IC_CFG, value);
819877
}
820878
}
879+
880+
/*
881+
* Some BIOS implementations do not restore proper RDRAND support
882+
* across suspend and resume. Check on whether to hide the RDRAND
883+
* instruction support via CPUID.
884+
*/
885+
clear_rdrand_cpuid_bit(c);
821886
}
822887

823888
static void init_amd_zn(struct cpuinfo_x86 *c)
@@ -860,6 +925,7 @@ static void init_amd(struct cpuinfo_x86 *c)
860925
case 0x10: init_amd_gh(c); break;
861926
case 0x12: init_amd_ln(c); break;
862927
case 0x15: init_amd_bd(c); break;
928+
case 0x16: init_amd_jg(c); break;
863929
case 0x17: init_amd_zn(c); break;
864930
}
865931

0 commit comments

Comments
 (0)