summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuiz Souza <luiz@netgate.com>2018-02-23 19:43:41 -0300
committerLuiz Souza <luiz@netgate.com>2018-02-23 19:43:41 -0300
commit5eb256fe165c6037cc5a8564ef05b24836d97ffb (patch)
tree5f30bc0fe169f671265c34992427db447f9abd73
parentf2d4631b091fcc0fb94bee855637c6d006257bcd (diff)
downloadFreeBSD-src-5eb256fe165c6037cc5a8564ef05b24836d97ffb.zip
FreeBSD-src-5eb256fe165c6037cc5a8564ef05b24836d97ffb.tar.gz
Revert "Revert "MFC r321899""
This reverts commit 364d23417fdf8cd90b896af94c6857c6ba13be8c.
-rw-r--r--sys/amd64/amd64/elf_machdep.c19
-rw-r--r--sys/amd64/amd64/initcpu.c27
-rw-r--r--sys/amd64/include/md_var.h5
-rw-r--r--sys/amd64/linux/linux_sysvec.c2
4 files changed, 52 insertions, 1 deletions
diff --git a/sys/amd64/amd64/elf_machdep.c b/sys/amd64/amd64/elf_machdep.c
index ca07adc..4e9476a 100644
--- a/sys/amd64/amd64/elf_machdep.c
+++ b/sys/amd64/amd64/elf_machdep.c
@@ -84,6 +84,25 @@ struct sysentvec elf64_freebsd_sysvec = {
};
INIT_SYSENTVEC(elf64_sysvec, &elf64_freebsd_sysvec);
+void
+amd64_lower_shared_page(struct sysentvec *sv)
+{
+ if (hw_lower_amd64_sharedpage != 0) {
+ sv->sv_maxuser -= PAGE_SIZE;
+ sv->sv_shared_page_base -= PAGE_SIZE;
+ sv->sv_usrstack -= PAGE_SIZE;
+ sv->sv_psstrings -= PAGE_SIZE;
+ }
+}
+
+/*
+ * Do this fixup before INIT_SYSENTVEC (SI_ORDER_ANY) because the latter
+ * uses the value of sv_shared_page_base.
+ */
+SYSINIT(elf64_sysvec_fixup, SI_SUB_EXEC, SI_ORDER_FIRST,
+ (sysinit_cfunc_t) amd64_lower_shared_page,
+ &elf64_freebsd_sysvec);
+
static Elf64_Brandinfo freebsd_brand_info = {
.brand = ELFOSABI_FREEBSD,
.machine = EM_X86_64,
diff --git a/sys/amd64/amd64/initcpu.c b/sys/amd64/amd64/initcpu.c
index 63c0f20..ff3b6be 100644
--- a/sys/amd64/amd64/initcpu.c
+++ b/sys/amd64/amd64/initcpu.c
@@ -48,6 +48,11 @@ __FBSDID("$FreeBSD$");
static int hw_instruction_sse;
SYSCTL_INT(_hw, OID_AUTO, instruction_sse, CTLFLAG_RD,
&hw_instruction_sse, 0, "SIMD/MMX2 instructions available in CPU");
+static int lower_sharedpage_init;
+int hw_lower_amd64_sharedpage;
+SYSCTL_INT(_hw, OID_AUTO, lower_amd64_sharedpage, CTLFLAG_RDTUN,
+ &hw_lower_amd64_sharedpage, 0,
+ "Lower sharedpage to work around Ryzen issue with executing code near the top of user memory");
/*
* -1: automatic (default)
* 0: keep enable CLFLUSH
@@ -122,6 +127,28 @@ init_amd(void)
wrmsr(0xc0011020, msr);
}
}
+
+ /*
+ * Work around a problem on Ryzen that is triggered by executing
+ * code near the top of user memory, in our case the signal
+ * trampoline code in the shared page on amd64.
+ *
+ * This function is executed once for the BSP before tunables take
+ * effect so the value determined here can be overridden by the
+ * tunable. This function is then executed again for each AP and
+ * also on resume. Set a flag the first time so that value set by
+ * the tunable is not overwritten.
+ *
+ * The stepping and/or microcode versions should be checked after
+ * this issue is fixed by AMD so that we don't use this mode if not
+ * needed.
+ */
+ if (lower_sharedpage_init == 0) {
+ lower_sharedpage_init = 1;
+ if (CPUID_TO_FAMILY(cpu_id) == 0x17) {
+ hw_lower_amd64_sharedpage = 1;
+ }
+ }
}
/*
diff --git a/sys/amd64/include/md_var.h b/sys/amd64/include/md_var.h
index 706ffc6..7a84631 100644
--- a/sys/amd64/include/md_var.h
+++ b/sys/amd64/include/md_var.h
@@ -34,12 +34,15 @@
#include <x86/x86_var.h>
-extern uint64_t *vm_page_dump;
+extern uint64_t *vm_page_dump;
+extern int hw_lower_amd64_sharedpage;
struct savefpu;
+struct sysentvec;
void amd64_conf_fast_syscall(void);
void amd64_db_resume_dbreg(void);
+void amd64_lower_shared_page(struct sysentvec *);
void amd64_syscall(struct thread *td, int traced);
void doreti_iret(void) __asm(__STRING(doreti_iret));
void doreti_iret_fault(void) __asm(__STRING(doreti_iret_fault));
diff --git a/sys/amd64/linux/linux_sysvec.c b/sys/amd64/linux/linux_sysvec.c
index f77c2c9..942819b 100644
--- a/sys/amd64/linux/linux_sysvec.c
+++ b/sys/amd64/linux/linux_sysvec.c
@@ -833,6 +833,8 @@ static void
linux_vdso_install(void *param)
{
+ amd64_lower_shared_page(&elf_linux_sysvec);
+
linux_szsigcode = (&_binary_linux_locore_o_end -
&_binary_linux_locore_o_start);
OpenPOWER on IntegriCloud