Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F151273727
D55829.id174054.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
50 KB
Referenced Files
None
Subscribers
None
D55829.id174054.diff
View Options
diff --git a/sys/amd64/amd64/cpu_switch.S b/sys/amd64/amd64/cpu_switch.S
--- a/sys/amd64/amd64/cpu_switch.S
+++ b/sys/amd64/amd64/cpu_switch.S
@@ -187,13 +187,23 @@
cmpq %rax,%rdx
jne do_tss
done_tss:
+ movq %r8,PCPU(CURPCB)
+ cmpb $0,fred
+ jne 1f
movq TD_MD_STACK_BASE(%r12),%r9
movq %r9,PCPU(RSP0)
- movq %r8,PCPU(CURPCB)
movq PCPU(PTI_RSP0),%rax
cmpq $~0,PCPU(UCR3)
cmove %r9,%rax
movq %rax,TSS_RSP0(%rdx)
+ jmp 2f
+1:
+ movq TD_MD_STACK_BASE(%r12),%rdx
+ movl %edx,%eax
+ shrq $32,%rdx
+ movl $MSR_FRED_RSP0,%ecx
+ wrmsr
+2:
movq %r12,PCPU(CURTHREAD) /* into next thread */
/* Test if debug registers should be restored. */
@@ -365,8 +375,37 @@
movl %eax,PCB_SFMASK(%rdi)
movl %edx,PCB_SFMASK+4(%rdi)
+ cmpb $0, fred
+ je 1f
+ movl $MSR_FRED_RSP0,%ecx
+ rdmsr
+ movl %eax,PCB_FRED_RSP0(%rdi)
+ movl %edx,PCB_FRED_RSP0+4(%rdi)
+ movl $MSR_FRED_RSP1,%ecx
+ rdmsr
+ movl %eax,PCB_FRED_RSP1(%rdi)
+ movl %edx,PCB_FRED_RSP1+4(%rdi)
+ movl $MSR_FRED_RSP2,%ecx
+ rdmsr
+ movl %eax,PCB_FRED_RSP2(%rdi)
+ movl %edx,PCB_FRED_RSP2+4(%rdi)
+ movl $MSR_FRED_RSP3,%ecx
+ rdmsr
+ movl %eax,PCB_FRED_RSP3(%rdi)
+ movl %edx,PCB_FRED_RSP3+4(%rdi)
+ movl $MSR_FRED_STKLVLS,%ecx
+ rdmsr
+ movl %eax,PCB_FRED_STKLVLS(%rdi)
+ movl %edx,PCB_FRED_STKLVLS+4(%rdi)
+ movl $MSR_FRED_CONFIG,%ecx
+ rdmsr
+ movl %eax,PCB_FRED_CONFIG(%rdi)
+ movl %edx,PCB_FRED_CONFIG+4(%rdi)
+ jmp 2f
+
+1: sidt PCB_IDT(%rdi)
+2:
sgdt PCB_GDT(%rdi)
- sidt PCB_IDT(%rdi)
sldt PCB_LDT(%rdi)
str PCB_TR(%rdi)
@@ -442,8 +481,35 @@
movq %rax,%cr3
/* Restore descriptor tables. */
+ cmpb $0,fred
+ jne 1f
lidt PCB_IDT(%rdi)
- lldt PCB_LDT(%rdi)
+ jmp 2f
+1: movl $MSR_FRED_RSP0,%ecx
+ movl PCB_FRED_RSP0(%rdi),%eax
+ movl 4 + PCB_FRED_RSP0(%rdi),%edx
+ wrmsr
+ movl $MSR_FRED_RSP1,%ecx
+ movl PCB_FRED_RSP1(%rdi),%eax
+ movl 4 + PCB_FRED_RSP1(%rdi),%edx
+ wrmsr
+ movl $MSR_FRED_RSP2,%ecx
+ movl PCB_FRED_RSP2(%rdi),%eax
+ movl 4 + PCB_FRED_RSP2(%rdi),%edx
+ wrmsr
+ movl $MSR_FRED_RSP3,%ecx
+ movl PCB_FRED_RSP3(%rdi),%eax
+ movl 4 + PCB_FRED_RSP3(%rdi),%edx
+ wrmsr
+ movl $MSR_FRED_STKLVLS,%ecx
+ movl PCB_FRED_STKLVLS(%rdi),%eax
+ movl 4 + PCB_FRED_STKLVLS(%rdi),%edx
+ wrmsr
+ movl $MSR_FRED_CONFIG,%ecx
+ movl PCB_FRED_CONFIG(%rdi),%eax
+ movl 4 + PCB_FRED_CONFIG(%rdi),%edx
+ wrmsr
+2: lldt PCB_LDT(%rdi)
#define SDT_SYSTSS 9
#define SDT_SYSBSY 11
diff --git a/sys/amd64/amd64/exception.S b/sys/amd64/amd64/exception.S
--- a/sys/amd64/amd64/exception.S
+++ b/sys/amd64/amd64/exception.S
@@ -1063,6 +1063,8 @@
movq %rbx,%rsi /* arg1 */
movq %rsp,%rdx /* trapframe pointer */
call fork_exit
+ cmpb $0, fred
+ jne fred_checkast
jmp doreti /* Handle any ASTs */
/*
@@ -1370,6 +1372,233 @@
movq $0,PCB_GSBASE(%r8)
jmp doreti
+/*
+ * FRED guarantees that on entry, %rflags is set to '2', which in
+ * particular means that interrupts are disabled, and DF/AC are clear.
+ * Interrupts are re-enabled by the C handler, if appropriate.
+ */
+ ALIGN_TEXT
+user_fred:
+ movq %rdi,TF_RDI(%rsp)
+ movq %rdx,TF_RDX(%rsp)
+ movq %rcx,TF_RCX(%rsp)
+ movq %rsi,TF_RSI(%rsp)
+ movq %r8,TF_R8(%rsp)
+ movq %r9,TF_R9(%rsp)
+ movq %rbx,TF_RBX(%rsp)
+ movq %rbp,TF_RBP(%rsp)
+ movq %r10,TF_R10(%rsp)
+ movq %r11,TF_R11(%rsp)
+ movq %r12,TF_R12(%rsp)
+ movq %r13,TF_R13(%rsp)
+ movq %r14,TF_R14(%rsp)
+ movq %r15,TF_R15(%rsp)
+ SAVE_SEGS
+ movq PCPU(CURTHREAD),%r9
+ movq TD_PCB(%r9),%r8
+ rdfsbase %rax
+ movq %rax,PCB_FSBASE(%r8)
+ rdgsbase %rax
+ movq %rax,PCB_GSBASE(%r8)
+ movl $TF_HASSEGS,TF_FLAGS(%rsp)
+ KMSAN_ENTER
+ movq %rsp, %rdi
+ call trap_fred_u
+ KMSAN_LEAVE
+fred_checkast:
+ cli
+ movq PCPU(CURTHREAD),%rax
+ movq TD_PCB(%rax),%r8
+ cmpl $0,TD_AST(%rax)
+ je fred_gouser
+ sti
+ movq %rsp,%rdi /* pass a pointer to the trapframe */
+ call ast
+ jmp fred_checkast
+fred_gouser:
+ testl $PCB_FULL_IRET,PCB_FLAGS(%r8)
+ jz fred_u_regs
+ andl $~PCB_FULL_IRET,PCB_FLAGS(%r8)
+ testl $TF_HASSEGS,TF_FLAGS(%rsp)
+ jne fred_do_segs
+ movw $KUDSEL,%ax
+ movw %ax,TF_DS(%rsp)
+ movw %ax,TF_ES(%rsp)
+ movw $KUF32SEL,TF_FS(%rsp)
+ movw $KUG32SEL,TF_GS(%rsp)
+fred_do_segs:
+ /* Restore %fs and fsbase */
+ movw TF_FS(%rsp),%ax
+ .globl fred_ld_fs
+fred_ld_fs:
+ movw %ax,%fs
+ movq PCB_FSBASE(%r8),%rax
+ .globl fred_ld_fsbase
+fred_ld_fsbase:
+ wrfsbase %rax
+ /* Restore %gs and kgsbase */
+ movw TF_GS(%rsp),%ax
+ .globl fred_lkgs
+fred_lkgs:
+ lkgs %ax
+ movl PCB_GSBASE(%r8),%eax
+ movl PCB_GSBASE+4(%r8),%edx
+ movl $MSR_KGSBASE,%ecx
+ .globl fred_ld_kgsbase
+fred_ld_kgsbase:
+ wrmsr
+ .globl fred_ld_es
+fred_ld_es:
+ movw TF_ES(%rsp),%es
+ .globl fred_ld_ds
+fred_ld_ds:
+ movw TF_DS(%rsp),%ds
+fred_u_regs:
+ RESTORE_REGS
+ addq $TF_ERR,%rsp
+ .globl fred_eretu
+fred_eretu:
+ eretu
+
+ .globl fred_ld_fs_fault
+fred_ld_fs_fault:
+ movl $(TF_FRED_EVINFO2_TYPE_EXC | IDT_NP), TF_FRED_EVINFO2(%rsp)
+ movq %rsp,%rdi
+ call trap_fred_u
+ movw $KUF32SEL,TF_FS(%rsp)
+ jmp fred_checkast
+
+ .globl fred_ld_fsbase_fault
+fred_ld_fsbase_fault:
+ movl $(TF_FRED_EVINFO2_TYPE_EXC | IDT_NP), TF_FRED_EVINFO2(%rsp)
+ movq %rsp,%rdi
+ call trap_fred_u
+ movq PCPU(CURTHREAD),%r9
+ movq TD_PCB(%r9),%r8
+ movq $0,PCB_FSBASE(%r8)
+ jmp fred_checkast
+
+ .globl fred_lkgs_fault
+fred_lkgs_fault:
+ movl $(TF_FRED_EVINFO2_TYPE_EXC | IDT_NP), TF_FRED_EVINFO2(%rsp)
+ movq %rsp,%rdi
+ call trap_fred_u
+ movw $KUG32SEL,TF_GS(%rsp)
+ jmp fred_checkast
+
+ .globl fred_ld_kgsbase_fault
+fred_ld_kgsbase_fault:
+ movl $(TF_FRED_EVINFO2_TYPE_EXC | IDT_NP), TF_FRED_EVINFO2(%rsp)
+ movq %rsp,%rdi
+ call trap_fred_u
+ movq PCPU(CURTHREAD),%r9
+ movq TD_PCB(%r9),%r8
+ movq $0,PCB_GSBASE(%r8)
+ jmp fred_checkast
+
+ .globl fred_ld_es_fault
+fred_ld_es_fault:
+ movl $(TF_FRED_EVINFO2_TYPE_EXC | IDT_NP), TF_FRED_EVINFO2(%rsp)
+ movq %rsp,%rdi
+ call trap_fred_u
+ movw $KUDSEL,TF_ES(%rsp)
+ jmp fred_checkast
+
+ .globl fred_ld_ds_fault
+fred_ld_ds_fault:
+ movl $(TF_FRED_EVINFO2_TYPE_EXC | IDT_NP), TF_FRED_EVINFO2(%rsp)
+ movq %rsp,%rdi
+ call trap_fred_u
+ movw $KUDSEL,TF_DS(%rsp)
+ jmp fred_checkast
+
+ .globl fred_eretu_fault
+fred_eretu_fault:
+ subq $TF_ERR,%rsp
+ movq %rdi,TF_RDI(%rsp)
+ movq %rdx,TF_RDX(%rsp)
+ movq %rcx,TF_RCX(%rsp)
+ movq %rsi,TF_RSI(%rsp)
+ movq %r8,TF_R8(%rsp)
+ movq %r9,TF_R9(%rsp)
+ movq %rbx,TF_RBX(%rsp)
+ movq %rbp,TF_RBP(%rsp)
+ movq %r10,TF_R10(%rsp)
+ movq %r11,TF_R11(%rsp)
+ movq %r12,TF_R12(%rsp)
+ movq %r13,TF_R13(%rsp)
+ movq %r14,TF_R14(%rsp)
+ movq %r15,TF_R15(%rsp)
+ SAVE_SEGS
+ movl $(TF_FRED_EVINFO2_TYPE_EXC | IDT_GP), TF_FRED_EVINFO2(%rsp)
+ movq %rsp, %rdi
+ KMSAN_ENTER
+ call trap_fred_u
+ KMSAN_LEAVE
+ jmp fred_checkast
+
+ ALIGN_TEXT
+kernel_fred:
+ movq %rdi,TF_RDI(%rsp)
+ movq %rdx,TF_RDX(%rsp)
+ movq %rcx,TF_RCX(%rsp)
+ movq %rsi,TF_RSI(%rsp)
+ movq %r8,TF_R8(%rsp)
+ movq %r9,TF_R9(%rsp)
+ movq %rbx,TF_RBX(%rsp)
+ movq %rbp,TF_RBP(%rsp)
+ movq %r10,TF_R10(%rsp)
+ movq %r11,TF_R11(%rsp)
+ movq %r12,TF_R12(%rsp)
+ movq %r13,TF_R13(%rsp)
+ movq %r14,TF_R14(%rsp)
+ movq %r15,TF_R15(%rsp)
+ movq %rsp, %rdi
+ KMSAN_ENTER
+ call trap_fred_k
+ KMSAN_LEAVE
+ RESTORE_REGS
+ addq $TF_ERR,%rsp
+ erets
+
+/*
+ * Content for the FRED entries page. The code is copied to the
+ * allocated page, handlers must be PIC.
+ */
+ .globl fred_events_handlers, fred_events_handlers_end
+fred_events_handlers:
+ subq $TF_ERR,%rsp
+ movq %rax,TF_RAX(%rsp)
+ movq $user_fred, %rax
+ jmp *%rax
+ . = fred_events_handlers + 256
+ subq $TF_ERR,%rsp
+ movq %rax,TF_RAX(%rsp)
+ movq $kernel_fred, %rax
+ jmp *%rax
+fred_events_handlers_end:
+
+ .globl fred_out_of_nmi
+fred_out_of_nmi:
+ pushq %rbp
+ movq %rsp,%rbp
+ xorl %eax,%eax
+ pushq $0
+ pushq $0
+ movw %ss,%ax
+ orl $(1<<18),%eax /* NMI block release for ERETS */
+ pushq %rax
+ pushq %rbp
+ pushfq
+ xorl %eax,%eax
+ movw %cs,%ax
+ pushq %rax
+ pushq $1f
+ pushq $0
+ erets
+1: popq %rbp
+ retq
+
#ifdef HWPMC_HOOKS
ENTRY(end_exceptions)
#endif
diff --git a/sys/amd64/amd64/genassym.c b/sys/amd64/amd64/genassym.c
--- a/sys/amd64/amd64/genassym.c
+++ b/sys/amd64/amd64/genassym.c
@@ -149,6 +149,12 @@
ASSYM(PCB_LSTAR, offsetof(struct pcb, pcb_lstar));
ASSYM(PCB_CSTAR, offsetof(struct pcb, pcb_cstar));
ASSYM(PCB_SFMASK, offsetof(struct pcb, pcb_sfmask));
+ASSYM(PCB_FRED_RSP0, offsetof(struct pcb, pcb_fred_rsp0));
+ASSYM(PCB_FRED_RSP1, offsetof(struct pcb, pcb_fred_rsp1));
+ASSYM(PCB_FRED_RSP2, offsetof(struct pcb, pcb_fred_rsp2));
+ASSYM(PCB_FRED_RSP3, offsetof(struct pcb, pcb_fred_rsp3));
+ASSYM(PCB_FRED_STKLVLS, offsetof(struct pcb, pcb_fred_stklvls));
+ASSYM(PCB_FRED_CONFIG, offsetof(struct pcb, pcb_fred_config));
ASSYM(PCB_SIZE, sizeof(struct pcb));
ASSYM(PCB_FULL_IRET, PCB_FULL_IRET);
ASSYM(PCB_DBREGS, PCB_DBREGS);
@@ -183,9 +189,11 @@
ASSYM(TF_ES, offsetof(struct trapframe, tf_es));
ASSYM(TF_FS, offsetof(struct trapframe, tf_fs));
ASSYM(TF_GS, offsetof(struct trapframe, tf_gs));
+ASSYM(TF_FRED_EVINFO2, offsetof(struct trapframe, tf_fred_evinfo2));
ASSYM(TF_FLAGS, offsetof(struct trapframe, tf_flags));
ASSYM(TF_SIZE, sizeof(struct trapframe));
ASSYM(TF_HASSEGS, TF_HASSEGS);
+ASSYM(TF_FRED_EVINFO2_TYPE_EXC, TF_FRED_EVINFO2_TYPE_EXC);
ASSYM(PTI_RDX, offsetof(struct pti_frame, pti_rdx));
ASSYM(PTI_RAX, offsetof(struct pti_frame, pti_rax));
@@ -275,6 +283,9 @@
ASSYM(LDTSEL, GSEL(GUSERLDT_SEL, SEL_KPL));
ASSYM(SEL_RPL_MASK, SEL_RPL_MASK);
+ASSYM(IDT_NP, IDT_NP);
+ASSYM(IDT_GP, IDT_GP);
+
ASSYM(__FreeBSD_version, __FreeBSD_version);
#ifdef HWPMC_HOOKS
diff --git a/sys/amd64/amd64/initcpu.c b/sys/amd64/amd64/initcpu.c
--- a/sys/amd64/amd64/initcpu.c
+++ b/sys/amd64/amd64/initcpu.c
@@ -397,3 +397,40 @@
cpu_stdext_feature &= ~CPUID_STDEXT_CLFLUSHOPT;
}
}
+
+void
+amd64_cpu_init_fred(void)
+{
+ /*
+ * 128b = 0x2 * 64b redzone
+ * SLC 0 for EXTINT
+ * SLC 0 current
+ */
+ wrmsr(MSR_FRED_CONFIG, (uintptr_t)fred_page |
+ (0x2 << IA32_FRED_CONFIG_REDZONESZ_SHIFT) |
+ (0 << IA32_FRED_CONFIG_EXTINT_SLC_SHIFT) | 0);
+
+ /*
+ * With FRED, there is no need for workarounds requiring
+ * dedicated stack for #DB. Also, there is no need to have
+ * separate stacks for #NM and #MC, because CSL rules ensure
+ * that interrupted frame is safe even if NMI was interrupted
+ * by machine check or vice versa.
+ *
+ * Still, we need to provide a stack for events that can occur
+ * with the interrupts disabled, to avoid caring about the
+ * ordering of the context update in cpu_switch.S. Use CSL 1
+ * for #NM and #MC.
+ *
+ * Since double fault handler is used to handle stack
+ * overflow, it gets the dedicated stack, of the highest used
+ * CSL 2.
+ *
+ * CSL 3 is unused, and we have some space to re-arrange this
+ * if a need in the future appears.
+ */
+ wrmsr(MSR_FRED_STKLVLS, (1ul << (IDT_NM * 2)) |
+ (1ul << (IDT_MC * 2)) | (2ul << (IDT_DF * 2)));
+ wrmsr(MSR_FRED_RSP3, 0);
+ load_cr4(rcr4() | CR4_FRED);
+}
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -160,6 +160,7 @@
offsetof(struct pti_frame, pti_rip));
extern u_int64_t hammer_time(u_int64_t, u_int64_t);
+extern const char fred_events_handlers[], fred_events_handlers_end[];
static void cpu_startup(void *);
SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL);
@@ -205,11 +206,12 @@
long realmem = 0;
int late_console = 1;
int lass_enabled = 0;
+int fred = 0;
struct kva_md_info kmi;
struct region_descriptor r_idt;
-
+char *fred_page;
struct pcpu *__pcpu;
struct pcpu temp_bsp_pcpu;
@@ -347,9 +349,9 @@
static struct gate_descriptor idt0[NIDT];
struct gate_descriptor *idt = &idt0[0]; /* interrupt descriptor table */
-static char dblfault_stack[DBLFAULT_STACK_SIZE] __aligned(16);
+static char dblfault_stack[DBLFAULT_STACK_SIZE] __aligned(64);
static char mce0_stack[MCE_STACK_SIZE] __aligned(16);
-static char nmi0_stack[NMI_STACK_SIZE] __aligned(16);
+static char nmi0_stack[NMI_STACK_SIZE] __aligned(64);
static char dbg0_stack[DBG_STACK_SIZE] __aligned(16);
CTASSERT(sizeof(struct nmi_pcpu) == 16);
@@ -1186,9 +1188,11 @@
msr = rdmsr(MSR_EFER) | EFER_SCE;
wrmsr(MSR_EFER, msr);
- wrmsr(MSR_LSTAR, pti ? (u_int64_t)IDTVEC(fast_syscall_pti) :
- (u_int64_t)IDTVEC(fast_syscall));
- wrmsr(MSR_CSTAR, (u_int64_t)IDTVEC(fast_syscall32));
+ if (!fred) {
+ wrmsr(MSR_LSTAR, pti ? (u_int64_t)IDTVEC(fast_syscall_pti) :
+ (u_int64_t)IDTVEC(fast_syscall));
+ wrmsr(MSR_CSTAR, (u_int64_t)IDTVEC(fast_syscall32));
+ }
msr = ((u_int64_t)GSEL(GCODE_SEL, SEL_KPL) << 32) |
((u_int64_t)GSEL(GUCODE32_SEL, SEL_UPL) << 48);
wrmsr(MSR_STAR, msr);
@@ -1230,33 +1234,49 @@
tssp = &pc->pc_common_tss;
- /* doublefault stack space, runs on ist1 */
- np = ((struct nmi_pcpu *)&dblfault_stack[sizeof(dblfault_stack)]) - 1;
- np->np_pcpu = (register_t)pc;
- tssp->tss_ist1 = (long)np;
+ /* Doublefault stack space, runs on ist1 for IDT. */
+ if (fred) {
+ wrmsr(MSR_FRED_RSP2, (uint64_t)&dblfault_stack[
+ sizeof(dblfault_stack)]);
+ } else {
+ np = ((struct nmi_pcpu *)&dblfault_stack[sizeof(
+ dblfault_stack)]) - 1;
+ np->np_pcpu = (register_t)pc;
+ tssp->tss_ist1 = (long)np;
+ }
/*
- * NMI stack, runs on ist2. The pcpu pointer is stored just
- * above the start of the ist2 stack.
+ * NMI stack.
*/
- np = ((struct nmi_pcpu *)&nmi0_stack[sizeof(nmi0_stack)]) - 1;
- np->np_pcpu = (register_t)pc;
- tssp->tss_ist2 = (long)np;
+ if (fred) {
+ wrmsr(MSR_FRED_RSP1, (uint64_t)&nmi0_stack[
+ sizeof(nmi0_stack)]);
+ } else {
+ /*
+ * Runs on ist2 for IDT. The pcpu pointer is stored
+ * just above the start of the ist2 stack.
+ */
+ np = ((struct nmi_pcpu *)&nmi0_stack[sizeof(nmi0_stack)]) - 1;
+ np->np_pcpu = (register_t)pc;
+ tssp->tss_ist2 = (long)np;
+ }
- /*
- * MC# stack, runs on ist3. The pcpu pointer is stored just
- * above the start of the ist3 stack.
- */
- np = ((struct nmi_pcpu *)&mce0_stack[sizeof(mce0_stack)]) - 1;
- np->np_pcpu = (register_t)pc;
- tssp->tss_ist3 = (long)np;
+ if (!fred) {
+ /*
+ * MC# stack for IDT, runs on ist3. The pcpu pointer
+ * is stored just above the start of the ist3 stack.
+ */
+ np = ((struct nmi_pcpu *)&mce0_stack[sizeof(mce0_stack)]) - 1;
+ np->np_pcpu = (register_t)pc;
+ tssp->tss_ist3 = (long)np;
- /*
- * DB# stack, runs on ist4.
- */
- np = ((struct nmi_pcpu *)&dbg0_stack[sizeof(dbg0_stack)]) - 1;
- np->np_pcpu = (register_t)pc;
- tssp->tss_ist4 = (long)np;
+ /*
+ * DB# stack for IDT, runs on ist4.
+ */
+ np = ((struct nmi_pcpu *)&dbg0_stack[sizeof(dbg0_stack)]) - 1;
+ np->np_pcpu = (register_t)pc;
+ tssp->tss_ist4 = (long)np;
+ }
}
/*
@@ -1352,6 +1372,13 @@
TUNABLE_INT_FETCH("hw.use_xsave", &use_xsave);
}
+ if ((cpu_stdext_feature4 & (CPUID_STDEXT4_FRED | CPUID_STDEXT4_LKGS)) ==
+ (CPUID_STDEXT4_FRED | CPUID_STDEXT4_LKGS) &&
+ (cpu_stdext_feature & CPUID_STDEXT_FSGSBASE) != 0 && !pti) {
+ fred = 1;
+ TUNABLE_INT_FETCH("hw.fred", &fred);
+ }
+
sched_instance_select();
link_elf_ireloc();
@@ -1419,55 +1446,57 @@
mtx_init(&icu_lock, "icu", NULL, MTX_SPIN | MTX_NOWITNESS);
mtx_init(&dt_lock, "descriptor tables", NULL, MTX_DEF);
- /* exceptions */
- for (x = 0; x < NIDT; x++)
- setidt(x, pti ? &IDTVEC(rsvd_pti) : &IDTVEC(rsvd), SDT_SYSIGT,
- SEL_KPL, 0);
- setidt(IDT_DE, pti ? &IDTVEC(div_pti) : &IDTVEC(div), SDT_SYSIGT,
- SEL_KPL, 0);
- setidt(IDT_DB, &IDTVEC(dbg), SDT_SYSIGT, SEL_KPL, 4);
- setidt(IDT_NMI, &IDTVEC(nmi), SDT_SYSIGT, SEL_KPL, 2);
- setidt(IDT_BP, pti ? &IDTVEC(bpt_pti) : &IDTVEC(bpt), SDT_SYSIGT,
- SEL_UPL, 0);
- setidt(IDT_OF, pti ? &IDTVEC(ofl_pti) : &IDTVEC(ofl), SDT_SYSIGT,
- SEL_UPL, 0);
- setidt(IDT_BR, pti ? &IDTVEC(bnd_pti) : &IDTVEC(bnd), SDT_SYSIGT,
- SEL_KPL, 0);
- setidt(IDT_UD, pti ? &IDTVEC(ill_pti) : &IDTVEC(ill), SDT_SYSIGT,
- SEL_KPL, 0);
- setidt(IDT_NM, pti ? &IDTVEC(dna_pti) : &IDTVEC(dna), SDT_SYSIGT,
- SEL_KPL, 0);
- setidt(IDT_DF, &IDTVEC(dblfault), SDT_SYSIGT, SEL_KPL, 1);
- setidt(IDT_FPUGP, pti ? &IDTVEC(fpusegm_pti) : &IDTVEC(fpusegm),
- SDT_SYSIGT, SEL_KPL, 0);
- setidt(IDT_TS, pti ? &IDTVEC(tss_pti) : &IDTVEC(tss), SDT_SYSIGT,
- SEL_KPL, 0);
- setidt(IDT_NP, pti ? &IDTVEC(missing_pti) : &IDTVEC(missing),
- SDT_SYSIGT, SEL_KPL, 0);
- setidt(IDT_SS, pti ? &IDTVEC(stk_pti) : &IDTVEC(stk), SDT_SYSIGT,
- SEL_KPL, 0);
- setidt(IDT_GP, pti ? &IDTVEC(prot_pti) : &IDTVEC(prot), SDT_SYSIGT,
- SEL_KPL, 0);
- setidt(IDT_PF, pti ? &IDTVEC(page_pti) : &IDTVEC(page), SDT_SYSIGT,
- SEL_KPL, 0);
- setidt(IDT_MF, pti ? &IDTVEC(fpu_pti) : &IDTVEC(fpu), SDT_SYSIGT,
- SEL_KPL, 0);
- setidt(IDT_AC, pti ? &IDTVEC(align_pti) : &IDTVEC(align), SDT_SYSIGT,
- SEL_KPL, 0);
- setidt(IDT_MC, &IDTVEC(mchk), SDT_SYSIGT, SEL_KPL, 3);
- setidt(IDT_XF, pti ? &IDTVEC(xmm_pti) : &IDTVEC(xmm), SDT_SYSIGT,
- SEL_KPL, 0);
+ if (!fred) {
+ /* exceptions */
+ for (x = 0; x < NIDT; x++)
+ setidt(x, pti ? &IDTVEC(rsvd_pti) : &IDTVEC(rsvd),
+ SDT_SYSIGT, SEL_KPL, 0);
+ setidt(IDT_DE, pti ? &IDTVEC(div_pti) : &IDTVEC(div),
+ SDT_SYSIGT, SEL_KPL, 0);
+ setidt(IDT_DB, &IDTVEC(dbg), SDT_SYSIGT, SEL_KPL, 4);
+ setidt(IDT_NMI, &IDTVEC(nmi), SDT_SYSIGT, SEL_KPL, 2);
+ setidt(IDT_BP, pti ? &IDTVEC(bpt_pti) : &IDTVEC(bpt),
+ SDT_SYSIGT, SEL_UPL, 0);
+ setidt(IDT_OF, pti ? &IDTVEC(ofl_pti) : &IDTVEC(ofl),
+ SDT_SYSIGT, SEL_UPL, 0);
+ setidt(IDT_BR, pti ? &IDTVEC(bnd_pti) : &IDTVEC(bnd),
+ SDT_SYSIGT, SEL_KPL, 0);
+ setidt(IDT_UD, pti ? &IDTVEC(ill_pti) : &IDTVEC(ill),
+ SDT_SYSIGT, SEL_KPL, 0);
+ setidt(IDT_NM, pti ? &IDTVEC(dna_pti) : &IDTVEC(dna),
+ SDT_SYSIGT, SEL_KPL, 0);
+ setidt(IDT_DF, &IDTVEC(dblfault), SDT_SYSIGT, SEL_KPL, 1);
+ setidt(IDT_FPUGP, pti ? &IDTVEC(fpusegm_pti) :
+ &IDTVEC(fpusegm), SDT_SYSIGT, SEL_KPL, 0);
+ setidt(IDT_TS, pti ? &IDTVEC(tss_pti) : &IDTVEC(tss),
+ SDT_SYSIGT, SEL_KPL, 0);
+ setidt(IDT_NP, pti ? &IDTVEC(missing_pti) : &IDTVEC(missing),
+ SDT_SYSIGT, SEL_KPL, 0);
+ setidt(IDT_SS, pti ? &IDTVEC(stk_pti) : &IDTVEC(stk),
+ SDT_SYSIGT, SEL_KPL, 0);
+ setidt(IDT_GP, pti ? &IDTVEC(prot_pti) : &IDTVEC(prot),
+ SDT_SYSIGT, SEL_KPL, 0);
+ setidt(IDT_PF, pti ? &IDTVEC(page_pti) : &IDTVEC(page),
+ SDT_SYSIGT, SEL_KPL, 0);
+ setidt(IDT_MF, pti ? &IDTVEC(fpu_pti) : &IDTVEC(fpu),
+ SDT_SYSIGT, SEL_KPL, 0);
+ setidt(IDT_AC, pti ? &IDTVEC(align_pti) : &IDTVEC(align),
+ SDT_SYSIGT, SEL_KPL, 0);
+ setidt(IDT_MC, &IDTVEC(mchk), SDT_SYSIGT, SEL_KPL, 3);
+ setidt(IDT_XF, pti ? &IDTVEC(xmm_pti) : &IDTVEC(xmm),
+ SDT_SYSIGT, SEL_KPL, 0);
#ifdef KDTRACE_HOOKS
- setidt(IDT_DTRACE_RET, pti ? &IDTVEC(dtrace_ret_pti) :
- &IDTVEC(dtrace_ret), SDT_SYSIGT, SEL_UPL, 0);
+ setidt(IDT_DTRACE_RET, pti ? &IDTVEC(dtrace_ret_pti) :
+ &IDTVEC(dtrace_ret), SDT_SYSIGT, SEL_UPL, 0);
#endif
#ifdef XENHVM
- setidt(IDT_EVTCHN, pti ? &IDTVEC(xen_intr_upcall_pti) :
- &IDTVEC(xen_intr_upcall), SDT_SYSIGT, SEL_KPL, 0);
+ setidt(IDT_EVTCHN, pti ? &IDTVEC(xen_intr_upcall_pti) :
+ &IDTVEC(xen_intr_upcall), SDT_SYSIGT, SEL_KPL, 0);
#endif
- r_idt.rd_limit = sizeof(idt0) - 1;
- r_idt.rd_base = (long) idt;
- lidt(&r_idt);
+ r_idt.rd_limit = sizeof(idt0) - 1;
+ r_idt.rd_base = (long) idt;
+ lidt(&r_idt);
+ }
TUNABLE_INT_FETCH("hw.ibrs_disable", &hw_ibrs_disable);
TUNABLE_INT_FETCH("machdep.mitigations.ibrs.disable", &hw_ibrs_disable);
@@ -1558,6 +1587,14 @@
if (getenv_is_true("debug.dump_modinfo_at_boot"))
preload_dump();
+ if (fred) {
+ memset(fred_page, 0x90, PAGE_SIZE);
+ memcpy(fred_page, fred_events_handlers,
+ fred_events_handlers_end - fred_events_handlers);
+
+ amd64_cpu_init_fred();
+ }
+
#ifdef DEV_ISA
#ifdef DEV_ATPIC
elcr_probe();
@@ -1566,12 +1603,16 @@
/* Reset and mask the atpics and leave them shut down. */
atpic_reset();
- /*
- * Point the ICU spurious interrupt vectors at the APIC spurious
- * interrupt handler.
- */
- setidt(IDT_IO_INTS + 7, IDTVEC(spuriousint), SDT_SYSIGT, SEL_KPL, 0);
- setidt(IDT_IO_INTS + 15, IDTVEC(spuriousint), SDT_SYSIGT, SEL_KPL, 0);
+ if (!fred) {
+ /*
+ * Point the ICU spurious interrupt vectors at the
+ * APIC spurious interrupt handler.
+ */
+ setidt(IDT_IO_INTS + 7, IDTVEC(spuriousint), SDT_SYSIGT,
+ SEL_KPL, 0);
+ setidt(IDT_IO_INTS + 15, IDTVEC(spuriousint), SDT_SYSIGT,
+ SEL_KPL, 0);
+ }
#endif
#else
#error "have you forgotten the isa device?"
@@ -1823,6 +1864,11 @@
extern const char wrmsr_early_safe_gp_handler[];
static struct region_descriptor wrmsr_early_safe_orig_efi_idt;
+/*
+ * Note about FRED. wrmsr_early_safe_start() is used before we
+ * switched CPU to the FRED mode. We use IDT to catch #GP from MSR
+ * write even if BSP is switched to the FRED mode later.
+ */
void
wrmsr_early_safe_start(void)
{
diff --git a/sys/amd64/amd64/mp_machdep.c b/sys/amd64/amd64/mp_machdep.c
--- a/sys/amd64/amd64/mp_machdep.c
+++ b/sys/amd64/amd64/mp_machdep.c
@@ -125,33 +125,36 @@
cpu_apic_ids[i] = -1;
}
- /* Install an inter-CPU IPI for cache and TLB invalidations. */
- setidt(IPI_INVLOP, pti ? IDTVEC(invlop_pti) : IDTVEC(invlop),
- SDT_SYSIGT, SEL_KPL, 0);
+ if (!fred) {
+ /* Install an inter-CPU IPI for cache and TLB invalidations. */
+ setidt(IPI_INVLOP, pti ? IDTVEC(invlop_pti) : IDTVEC(invlop),
+ SDT_SYSIGT, SEL_KPL, 0);
- /* Install an inter-CPU IPI for all-CPU rendezvous */
- setidt(IPI_RENDEZVOUS, pti ? IDTVEC(rendezvous_pti) :
- IDTVEC(rendezvous), SDT_SYSIGT, SEL_KPL, 0);
+ /* Install an inter-CPU IPI for all-CPU rendezvous */
+ setidt(IPI_RENDEZVOUS, pti ? IDTVEC(rendezvous_pti) :
+ IDTVEC(rendezvous), SDT_SYSIGT, SEL_KPL, 0);
- /* Install generic inter-CPU IPI handler */
- setidt(IPI_BITMAP_VECTOR, pti ? IDTVEC(ipi_intr_bitmap_handler_pti) :
- IDTVEC(ipi_intr_bitmap_handler), SDT_SYSIGT, SEL_KPL, 0);
+ /* Install generic inter-CPU IPI handler */
+ setidt(IPI_BITMAP_VECTOR, pti ?
+ IDTVEC(ipi_intr_bitmap_handler_pti) :
+ IDTVEC(ipi_intr_bitmap_handler), SDT_SYSIGT, SEL_KPL, 0);
- /* Install an inter-CPU IPI for CPU stop/restart */
- setidt(IPI_STOP, pti ? IDTVEC(cpustop_pti) : IDTVEC(cpustop),
- SDT_SYSIGT, SEL_KPL, 0);
+ /* Install an inter-CPU IPI for CPU stop/restart */
+ setidt(IPI_STOP, pti ? IDTVEC(cpustop_pti) : IDTVEC(cpustop),
+ SDT_SYSIGT, SEL_KPL, 0);
- /* Install an inter-CPU IPI for CPU offline */
- setidt(IPI_OFF, pti ? IDTVEC(cpuoff_pti) : IDTVEC(cpuoff),
- SDT_SYSIGT, SEL_KPL, 0);
+ /* Install an inter-CPU IPI for CPU offline */
+ setidt(IPI_OFF, pti ? IDTVEC(cpuoff_pti) : IDTVEC(cpuoff),
+ SDT_SYSIGT, SEL_KPL, 0);
- /* Install an inter-CPU IPI for CPU suspend/resume */
- setidt(IPI_SUSPEND, pti ? IDTVEC(cpususpend_pti) : IDTVEC(cpususpend),
- SDT_SYSIGT, SEL_KPL, 0);
+ /* Install an inter-CPU IPI for CPU suspend/resume */
+ setidt(IPI_SUSPEND, pti ? IDTVEC(cpususpend_pti) :
+ IDTVEC(cpususpend), SDT_SYSIGT, SEL_KPL, 0);
- /* Install an IPI for calling delayed SWI */
- setidt(IPI_SWI, pti ? IDTVEC(ipi_swi_pti) : IDTVEC(ipi_swi),
- SDT_SYSIGT, SEL_KPL, 0);
+ /* Install an IPI for calling delayed SWI */
+ setidt(IPI_SWI, pti ? IDTVEC(ipi_swi_pti) : IDTVEC(ipi_swi),
+ SDT_SYSIGT, SEL_KPL, 0);
+ }
/* Set boot_cpu_id if needed. */
if (boot_cpu_id == -1) {
@@ -240,25 +243,51 @@
IOPERM_BITMAP_SIZE;
pc->pc_common_tss.tss_rsp0 = 0;
- /* The doublefault stack runs on IST1. */
- np = ((struct nmi_pcpu *)&doublefault_stack[DBLFAULT_STACK_SIZE]) - 1;
- np->np_pcpu = (register_t)pc;
- pc->pc_common_tss.tss_ist1 = (long)np;
+ /*
+ * The doublefault stack.
+ * Runs on IST1 for IDT.
+ * Uses CSL 2 for FRED.
+ */
+ if (fred) {
+ wrmsr(MSR_FRED_RSP2, (uint64_t)&doublefault_stack[
+ DBLFAULT_STACK_SIZE]);
+ } else {
+ np = ((struct nmi_pcpu *)&doublefault_stack[
+ DBLFAULT_STACK_SIZE]) - 1;
+ np->np_pcpu = (register_t)pc;
+ pc->pc_common_tss.tss_ist1 = (long)np;
+ }
- /* The NMI stack runs on IST2. */
- np = ((struct nmi_pcpu *)&nmi_stack[NMI_STACK_SIZE]) - 1;
- np->np_pcpu = (register_t)pc;
- pc->pc_common_tss.tss_ist2 = (long)np;
+ /*
+ * The NMI stack.
+ * Runs on IST2 for IDT.
+ * Uses CSL 1 for FRED.
+ */
+ if (fred) {
+ wrmsr(MSR_FRED_RSP1, (uint64_t)&nmi_stack[NMI_STACK_SIZE]);
+ } else {
+ np = ((struct nmi_pcpu *)&nmi_stack[NMI_STACK_SIZE]) - 1;
+ np->np_pcpu = (register_t)pc;
+ pc->pc_common_tss.tss_ist2 = (long)np;
+ }
- /* The MC# stack runs on IST3. */
- np = ((struct nmi_pcpu *)&mce_stack[MCE_STACK_SIZE]) - 1;
- np->np_pcpu = (register_t)pc;
- pc->pc_common_tss.tss_ist3 = (long)np;
+ /*
+ * The MC# stack.
+ * Runs on IST3 for IDT.
+ * Shares CSL 1 with NMI for FRED.
+ */
+ if (!fred) {
+ np = ((struct nmi_pcpu *)&mce_stack[MCE_STACK_SIZE]) - 1;
+ np->np_pcpu = (register_t)pc;
+ pc->pc_common_tss.tss_ist3 = (long)np;
+ }
- /* The DB# stack runs on IST4. */
- np = ((struct nmi_pcpu *)&dbg_stack[DBG_STACK_SIZE]) - 1;
- np->np_pcpu = (register_t)pc;
- pc->pc_common_tss.tss_ist4 = (long)np;
+ if (!fred) {
+ /* The DB# stack, used for for IDT, runs on IST4. */
+ np = ((struct nmi_pcpu *)&dbg_stack[DBG_STACK_SIZE]) - 1;
+ np->np_pcpu = (register_t)pc;
+ pc->pc_common_tss.tss_ist4 = (long)np;
+ }
/* Prepare private GDT */
gdt_segs[GPROC0_SEL].ssd_base = (long)&pc->pc_common_tss;
@@ -278,7 +307,10 @@
wrmsr(MSR_KGSBASE, 0); /* User value */
fix_cpuid();
- lidt(&r_idt);
+ if (fred)
+ amd64_cpu_init_fred();
+ else
+ lidt(&r_idt);
gsel_tss = GSEL(GPROC0_SEL, SEL_KPL);
ltr(gsel_tss);
@@ -430,12 +462,17 @@
M_WAITOK | M_ZERO);
doublefault_stack = kmem_malloc(DBLFAULT_STACK_SIZE,
M_WAITOK | M_ZERO);
- mce_stack = kmem_malloc(MCE_STACK_SIZE,
- M_WAITOK | M_ZERO);
+ if (!fred) {
+ mce_stack = kmem_malloc(MCE_STACK_SIZE,
+ M_WAITOK | M_ZERO);
+ }
nmi_stack = kmem_malloc_domainset(
DOMAINSET_PREF(domain), NMI_STACK_SIZE, M_WAITOK | M_ZERO);
- dbg_stack = kmem_malloc_domainset(
- DOMAINSET_PREF(domain), DBG_STACK_SIZE, M_WAITOK | M_ZERO);
+ if (!fred) {
+ dbg_stack = kmem_malloc_domainset(
+ DOMAINSET_PREF(domain), DBG_STACK_SIZE,
+ M_WAITOK | M_ZERO);
+ }
dpcpu = kmem_malloc_domainset(DOMAINSET_PREF(domain),
DPCPU_SIZE, M_WAITOK | M_ZERO);
diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c
--- a/sys/amd64/amd64/pmap.c
+++ b/sys/amd64/amd64/pmap.c
@@ -2066,9 +2066,9 @@
pmap_bootstrap(vm_paddr_t *firstaddr)
{
vm_offset_t va;
- pt_entry_t *pte, *pcpu_pte;
+ pt_entry_t *fred_page_pte, *pte, *pcpu_pte;
struct region_descriptor r_gdt;
- uint64_t cr4, pcpu0_phys;
+ uint64_t cr4, fred_phys, pcpu0_phys;
u_long res;
int i;
@@ -2086,6 +2086,8 @@
create_pagetables(firstaddr);
pcpu0_phys = allocpages(firstaddr, 1);
+ if (fred)
+ fred_phys = allocpages(firstaddr, 1);
/*
* Add a physical memory segment (vm_phys_seg) corresponding to the
@@ -2175,6 +2177,12 @@
va = virtual_avail;
pte = vtopte(va);
+ if (fred) {
+ SYSMAP(caddr_t, fred_page_pte, fred_page, 1);
+ *fred_page_pte = fred_phys | X86_PG_V | X86_PG_RW | pg_g |
+ X86_PG_M | X86_PG_A;
+ }
+
/*
* Crashdump maps. The first page is reused as CMAP1 for the
* memory test.
diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c
--- a/sys/amd64/amd64/trap.c
+++ b/sys/amd64/amd64/trap.c
@@ -41,6 +41,7 @@
* AMD64 Trap and System call handling
*/
+#include "opt_atpic.h"
#include "opt_clock.h"
#include "opt_cpu.h"
#include "opt_hwpmc_hooks.h"
@@ -61,6 +62,7 @@
#include <sys/mutex.h>
#include <sys/resourcevar.h>
#include <sys/signalvar.h>
+#include <sys/smp.h>
#include <sys/syscall.h>
#include <sys/sysctl.h>
#include <sys/sysent.h>
@@ -83,6 +85,8 @@
#include <machine/cpu.h>
#include <machine/intr_machdep.h>
+#include <x86/apicreg.h>
+#include <x86/apicvar.h>
#include <x86/mca.h>
#include <machine/md_var.h>
#include <machine/pcb.h>
@@ -90,11 +94,19 @@
#include <machine/stack.h>
#include <machine/trap.h>
#include <machine/tss.h>
+#include <x86/isa/icu.h>
#ifdef KDTRACE_HOOKS
#include <sys/dtrace_bsd.h>
#endif
+#ifdef XENHVM
+#include <sys/interrupt.h>
+#include <xen/xen-os.h>
+#include <xen/xen_intr.h>
+#include <machine/xen/arch-intr.h>
+#endif
+
extern inthand_t IDTVEC(bpt), IDTVEC(bpt_pti), IDTVEC(dbg),
IDTVEC(fast_syscall), IDTVEC(fast_syscall_pti), IDTVEC(fast_syscall32),
IDTVEC(int0x80_syscall_pti), IDTVEC(int0x80_syscall);
@@ -1004,6 +1016,12 @@
printf("r13: %016lx r14: %016lx r15: %016lx\n", frame->tf_r13,
frame->tf_r14, frame->tf_r15);
+ if (fred) {
+ printf("evdata %016lx evinfo1 %04x evinfo2 %08x\n",
+ frame->tf_fred_evdata, frame->tf_fred_evinfo1,
+ frame->tf_fred_evinfo2);
+ }
+
printf("trap number = %d\n", type);
}
@@ -1079,6 +1097,11 @@
frame->tf_cs, frame->tf_ss, frame->tf_ds, frame->tf_es,
frame->tf_fs, frame->tf_gs,
rdmsr(MSR_FSBASE), rdmsr(MSR_GSBASE), rdmsr(MSR_KGSBASE));
+ if (fred) {
+ printf("evdata %016lx evinfo1 %04x evinfo2 %08x\n",
+ frame->tf_fred_evdata, frame->tf_fred_evinfo1,
+ frame->tf_fred_evinfo2);
+ }
/* Print these separately in case pcpu accesses trap. */
printf("cpuid = %d; apic id = %02x\n", PCPU_GET(cpuid),
PCPU_GET(apic_id));
@@ -1305,3 +1328,526 @@
amd64_syscall_ret_flush_l1d_check_inline(td->td_errno);
}
+
+static void
+trap_fred_extint(struct trapframe *frame, u_int vec)
+{
+ switch (vec) {
+ case IPI_RENDEZVOUS:
+#ifdef COUNT_IPIS
+ ipi_rendezvous_counts[PCPU_GET(cpuid)]++;
+#endif
+ smp_rendezvous_action();
+ lapic_eoi();
+ break;
+ case IPI_INVLOP:
+ invlop_handler();
+ lapic_eoi();
+ break;
+ case IPI_BITMAP_VECTOR:
+ lapic_eoi();
+ ipi_bitmap_handler(frame);
+ break;
+ case IPI_STOP:
+ lapic_eoi();
+ cpustop_handler();
+ break;
+ case IPI_SUSPEND:
+ cpususpend_handler();
+ lapic_eoi();
+ break;
+ case IPI_SWI:
+ lapic_eoi();
+ ipi_swi_handler(frame);
+ break;
+ case IPI_OFF:
+ cpuoff_handler();
+ lapic_eoi();
+ break;
+ case APIC_SPURIOUS_INT:
+ break;
+ case APIC_TIMER_INT:
+ lapic_handle_timer(frame);
+ break;
+ case APIC_CMC_INT:
+ lapic_handle_cmc();
+ break;
+ case APIC_ERROR_INT:
+ lapic_handle_error();
+ break;
+#ifdef XENHVM
+ case IDT_EVTCHN:
+ xen_arch_intr_handle_upcall(frame);
+ break;
+#endif
+ default:
+ if (vec >= IPI_DYN_FIRST && vec <= IPI_DYN_LAST) {
+ void (*fi)(struct trapframe *);
+
+ fi = fred_ipi_handlers[vec - IPI_DYN_FIRST];
+ if (fi != NULL) {
+ fi(frame);
+ lapic_eoi();
+ } else {
+ panic("DYN IPI %d without FRED handler", vec);
+ }
+ break;
+ }
+#ifdef DEV_ISA
+#ifdef DEV_ATPIC
+ if (vec >= IDT_IO_INTS && vec < IDT_IO_INTS + NUM_ISA_IRQS) {
+ atpic_handle_intr(vec - IDT_IO_INTS, frame);
+ break;
+ }
+#endif
+#endif
+ /* apic ioint */
+ lapic_handle_intr(vec, frame);
+ break;
+ }
+}
+
+void fred_out_of_nmi(void);
+
+static const int fred_ev_to_trapno_table[] = {
+ [IDT_DE] = T_DIVIDE,
+ [IDT_DB] = T_TRCTRAP,
+ [IDT_NMI] = T_RESERVED,
+ [IDT_BP] = T_BPTFLT,
+ [IDT_OF] = T_OFLOW,
+ [IDT_BR] = T_BOUND,
+ [IDT_UD] = T_PRIVINFLT,
+ [IDT_NM] = T_DNA,
+ [IDT_DF] = T_DOUBLEFLT,
+ [IDT_FPUGP] = T_FPOPFLT,
+ [IDT_TS] = T_TSSFLT,
+ [IDT_NP] = T_SEGNPFLT,
+ [IDT_SS] = T_STKFLT,
+ [IDT_GP] = T_PROTFLT,
+ [IDT_PF] = T_PAGEFLT,
+ [15] = T_RESERVED,
+ [IDT_MF] = T_ARITHTRAP,
+ [IDT_AC] = T_ALIGNFLT,
+ [IDT_MC] = T_MCHK,
+ [IDT_XF] = T_XMMFLT,
+ [20] = T_RESERVED,
+ [21] = T_RESERVED,
+ [22] = T_RESERVED,
+ [23] = T_RESERVED,
+ [24] = T_RESERVED,
+ [25] = T_RESERVED,
+ [26] = T_RESERVED,
+ [27] = T_RESERVED,
+ [28] = T_RESERVED,
+ [29] = T_RESERVED,
+ [30] = T_RESERVED,
+ [31] = T_RESERVED,
+};
+
+static void
+trap_fred_ev_to_trapno(struct trapframe *frame, u_int exc)
+{
+ frame->tf_trapno = fred_ev_to_trapno_table[exc];
+}
+
+static void
+trap_fred_handle_u_exc(struct thread *td, struct trapframe *frame, u_int exc,
+ ksiginfo_t *ksi, bool *do_trapsig)
+{
+ struct proc *p;
+ register_t addr;
+ int pf, signo, ucode;
+
+ addr = frame->tf_rip;
+ signo = 0;
+ ucode = 0;
+ frame->tf_addr = 0;
+ trap_check_intr_user(td, frame);
+
+ switch (exc) {
+ case IDT_DE:
+ ucode = FPE_INTDIV;
+ signo = SIGFPE;
+ break;
+ case IDT_DB:
+ signo = SIGTRAP;
+ ucode = TRAP_TRACE;
+ if ((frame->tf_fred_evdata & TF_FRED_EVDATA_BS) != 0)
+ trap_clear_step(td, frame);
+ break;
+ case IDT_BP:
+#ifdef KDTRACE_HOOKS
+ if (trap_user_dtrace(frame, &dtrace_pid_probe_ptr))
+ return;
+#endif
+ signo = SIGTRAP;
+ ucode = TRAP_BRKPT;
+ break;
+ case IDT_OF:
+ ucode = FPE_INTOVF;
+ signo = SIGFPE;
+ break;
+ case IDT_BR:
+ ucode = FPE_FLTSUB;
+ signo = SIGFPE;
+ break;
+ case IDT_UD:
+ signo = SIGILL;
+ ucode = ILL_PRVOPC;
+ break;
+ case IDT_NM:
+ KASSERT(PCB_USER_FPU(td->td_pcb),
+ ("kernel FPU ctx has leaked"));
+ fpudna();
+ return;
+ case IDT_DF:
+ signo = SIGBUS;
+ ucode = BUS_OBJERR;
+ break;
+ case IDT_FPUGP:
+ ucode = ILL_COPROC;
+ signo = SIGILL;
+ break;
+ case IDT_TS:
+ signo = SIGBUS;
+ ucode = BUS_OBJERR;
+ break;
+ case IDT_NP:
+ signo = SIGBUS;
+ ucode = BUS_ADRERR;
+ break;
+ case IDT_SS:
+ signo = SIGBUS;
+ ucode = BUS_ADRERR;
+ break;
+ case IDT_GP:
+ signo = SIGBUS;
+ ucode = BUS_OBJERR;
+ break;
+ case IDT_PF:
+ p = td->td_proc;
+ frame->tf_addr = addr = frame->tf_fred_evdata;
+ if (*p->p_sysent->sv_trap != NULL &&
+ (*p->p_sysent->sv_trap)(td) == 0)
+ return;
+ pf = trap_pfault(frame, true, &signo, &ucode);
+ if (pf == -1 || pf == 0)
+ return;
+ break;
+ case IDT_MF:
+ ucode = fputrap_x87();
+ if (ucode == -1)
+ return;
+ signo = SIGFPE;
+ break;
+ case IDT_AC:
+ signo = SIGBUS;
+ ucode = BUS_ADRALN;
+ break;
+ case IDT_MC:
+ mca_intr();
+ return;
+ case IDT_XF:
+ ucode = fputrap_sse();
+ if (ucode == -1)
+ return;
+ signo = SIGFPE;
+ break;
+ default:
+ panic("missed FRED handler for exception %d", exc);
+ }
+
+ ksiginfo_init_trap(ksi);
+ ksi->ksi_signo = signo;
+ ksi->ksi_code = ucode;
+ ksi->ksi_trapno = frame->tf_trapno;
+ ksi->ksi_addr = (void *)addr;
+ trap_uprintf_signal(td, frame, addr, signo, ucode);
+ KASSERT((read_rflags() & PSL_I) != 0, ("interrupts disabled"));
+ *do_trapsig = true;
+}
+
+static u_int
+fred_inst_len(const struct trapframe *frame)
+{
+ return ((frame->tf_fred_evinfo2 & TF_FRED_EVINFO2_INSTLENMASK) >>
+ TF_FRED_EVINFO2_INSTLENSHIFT);
+}
+
+int fred_verbose_events;
+
+void trap_fred_u(struct trapframe *frame);
+void
+trap_fred_u(struct trapframe *frame)
+{
+ struct thread *td;
+ ksiginfo_t ksi;
+ u_int type, vec;
+ bool do_trapsig;
+
+ td = curthread;
+ type = frame->tf_fred_evinfo2 & TF_FRED_EVINFO2_TYPEMASK;
+ vec = frame->tf_fred_evinfo2 & TF_FRED_EVINFO2_VECMASK;
+ do_trapsig = false;
+ if (fred_verbose_events) {
+ printf("pid %d tid %d type %d vec %d rax %#lx\n",
+ td->td_proc->p_pid, td->td_tid,
+ (frame->tf_fred_evinfo2 & TF_FRED_EVINFO2_TYPEMASK) >> 16,
+ vec, frame->tf_rax);
+ }
+ if (__predict_true((td->td_proc->p_sysent->sv_flags &
+ (SV_ABI_MASK | SV_LP64)) == (SV_ABI_FREEBSD | SV_LP64) &&
+ (type == TF_FRED_EVINFO2_TYPE_SYSCALL ||
+ type == TF_FRED_EVINFO2_TYPE_EXTINT ||
+ (type == TF_FRED_EVINFO2_TYPE_EXC && vec == IDT_PF))))
+ clear_pcb_flags(td->td_pcb, PCB_FULL_IRET);
+ else
+ set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
+ switch (type) {
+ case TF_FRED_EVINFO2_TYPE_EXTINT:
+ trap_fred_extint(frame, vec);
+ break;
+ case TF_FRED_EVINFO2_TYPE_NMI:
+ frame->tf_trapno = T_NMI;
+ nmi_handle_intr(frame);
+#ifdef HWPMC_HOOKS
+ if ((td->td_pflags & TDP_CALLCHAIN) != 0) {
+ int (*ph)(struct thread *, int, void *);
+
+ fred_out_of_nmi();
+ ph = atomic_load_ptr(&pmc_hook);
+ if (ph != NULL) {
+ enable_intr();
+ ph(td, PMC_FN_USER_CALLCHAIN, frame);
+ }
+ }
+#endif
+ break;
+ case TF_FRED_EVINFO2_TYPE_INT1:
+ case TF_FRED_EVINFO2_TYPE_INT3:
+ case TF_FRED_EVINFO2_TYPE_EXC:
+ enable_intr();
+ trap_fred_ev_to_trapno(frame, vec);
+#ifdef KDTRACE_HOOKS
+ if (dtrace_trap_func != NULL &&
+ (*dtrace_trap_func)(frame, frame->tf_trapno) != 0)
+ return;
+#endif
+ td->td_pticks = 0;
+ td->td_frame = frame;
+ if (td->td_cowgen != atomic_load_int(&td->td_proc->p_cowgen))
+ thread_cow_update(td);
+ trap_fred_handle_u_exc(td, frame, vec, &ksi, &do_trapsig);
+ break;
+ case TF_FRED_EVINFO2_TYPE_INTn:
+ enable_intr();
+#ifdef COMPAT_FREEBSD32
+ if (vec == IDT_SYSCALL) {
+ frame->tf_err = fred_inst_len(frame);
+ ia32_syscall(frame);
+ break;
+ }
+#endif
+ frame->tf_trapno = vec;
+ ksiginfo_init_trap(&ksi);
+ ksi.ksi_signo = SIGBUS;
+ ksi.ksi_code = BUS_OBJERR;
+ ksi.ksi_trapno = frame->tf_trapno;
+ ksi.ksi_addr = (void *)frame->tf_rip;
+ do_trapsig = true;
+ break;
+ case TF_FRED_EVINFO2_TYPE_SYSCALL:
+ enable_intr();
+ if (vec == TF_FRED_EVINFO2_VEC_SYSCALL) {
+ frame->tf_err = fred_inst_len(frame);
+ td->td_frame = frame;
+ amd64_syscall(td, (frame->tf_rflags & PSL_T) != 0);
+ } else {
+ /* SYSENTER returns without action */
+ }
+ break;
+ default:
+ __unreachable();
+ }
+ if (do_trapsig)
+ trapsignal(td, &ksi);
+ userret(td, frame);
+ KASSERT(PCB_USER_FPU(td->td_pcb),
+ ("Return from trap with kernel FPU ctx leaked"));
+}
+
+extern const char fred_ld_fs[];
+extern const char fred_ld_fs_fault[];
+extern const char fred_ld_fsbase[];
+extern const char fred_ld_fsbase_fault[];
+extern const char fred_lkgs[];
+extern const char fred_lkgs_fault[];
+extern const char fred_ld_kgsbase[];
+extern const char fred_ld_kgsbase_fault[];
+extern const char fred_ld_es[];
+extern const char fred_ld_es_fault[];
+extern const char fred_ld_ds[];
+extern const char fred_ld_ds_fault[];
+extern const char fred_eretu[];
+extern const char fred_eretu_fault[];
+
+static const struct sfhandler fred_sfhandlers[] = {
+ {
+ .faddr = (uintptr_t)fred_ld_fs,
+ .fhandler = (uintptr_t)fred_ld_fs_fault,
+ },
+ {
+ .faddr = (uintptr_t)fred_ld_fsbase,
+ .fhandler = (uintptr_t)fred_ld_fsbase_fault,
+ },
+ {
+ .faddr = (uintptr_t)fred_lkgs,
+ .fhandler = (uintptr_t)fred_lkgs_fault,
+ },
+ {
+ .faddr = (uintptr_t)fred_ld_kgsbase,
+ .fhandler = (uintptr_t)fred_ld_kgsbase_fault,
+ },
+ {
+ .faddr = (uintptr_t)fred_ld_es,
+ .fhandler = (uintptr_t)fred_ld_es_fault,
+ },
+ {
+ .faddr = (uintptr_t)fred_ld_ds,
+ .fhandler = (uintptr_t)fred_ld_ds_fault,
+ },
+ {
+ .faddr = (uintptr_t)fred_eretu,
+ .fhandler = (uintptr_t)fred_eretu_fault,
+ },
+};
+
+static void
+trap_fred_handle_k_exc(struct thread *td, struct trapframe *frame, u_int exc)
+{
+ register_t addr;
+ int i;
+
+ addr = frame->tf_rip;
+ frame->tf_addr = 0;
+ KASSERT(cold || td->td_ucred != NULL,
+ ("kernel trap doesn't have ucred"));
+
+ /*
+ * FRED exception handler runs with the interrupts disabled,
+ * unlike the IDT case. Only for page faults the interrupts
+ * are enabled, since this is the only legitimate exception
+ * from the kernel mode. Anything else results in panic, so
+ * there is no sense to enable interrupts.
+ */
+
+ if (exc != IDT_PF && trap_check_pcb_onfault(td, frame))
+ return;
+
+ switch (exc) {
+ case IDT_DE:
+ break;
+ case IDT_DB:
+ if (user_dbreg_trap(frame->tf_fred_evdata))
+ return;
+ /* FALLTHROUGH */
+ case IDT_BP:
+#ifdef KDB
+ if (kdb_trap(frame->tf_trapno, frame->tf_fred_evdata, frame))
+ return;
+#endif
+ break;
+ case IDT_OF:
+ break;
+ case IDT_BR:
+ break;
+ case IDT_UD:
+ break;
+ case IDT_NM:
+ if (PCB_USER_FPU(td->td_pcb))
+ panic("Unregistered use of FPU in kernel");
+ fpudna();
+ return;
+ case IDT_DF:
+ dblfault_handler(frame);
+ break;
+ case IDT_FPUGP:
+ break;
+ case IDT_TS:
+ /*
+ * PSL_NT is cleared automatically by FRED entry.
+ */
+ break;
+ case IDT_NP:
+ case IDT_SS:
+ case IDT_GP:
+ if (td->td_intr_nesting_level != 0)
+ break;
+ for (i = 0; i < nitems(fred_sfhandlers); i++) {
+ if (frame->tf_rip == fred_sfhandlers[i].faddr) {
+ KASSERT((read_rflags() & PSL_I) == 0,
+ ("interrupts enabled"));
+ frame->tf_rip = fred_sfhandlers[i].fhandler;
+ return;
+ }
+ }
+ if (curpcb->pcb_onfault != NULL) {
+ frame->tf_rip = (long)curpcb->pcb_onfault;
+ return;
+ }
+ break;
+ case IDT_PF:
+ frame->tf_addr = addr = frame->tf_fred_evdata;
+ if ((frame->tf_rflags & PSL_I) != 0)
+ enable_intr();
+ trap_pfault(frame, false, NULL, NULL);
+ return;
+ case IDT_MF:
+ break;
+ case IDT_AC:
+ break;
+ case IDT_MC:
+ mca_intr();
+ return;
+ case IDT_XF:
+ break;
+ default:
+ printf("Missing FRED handler for exception %d", exc);
+ trap_fatal(frame, 0);
+ }
+ trap_fatal(frame, 0);
+}
+
+void trap_fred_k(struct trapframe *frame);
+void
+trap_fred_k(struct trapframe *frame)
+{
+ struct thread *td;
+ u_int vec;
+
+ td = curthread;
+ vec = frame->tf_fred_evinfo2 & TF_FRED_EVINFO2_VECMASK;
+ switch (frame->tf_fred_evinfo2 & TF_FRED_EVINFO2_TYPEMASK) {
+ case TF_FRED_EVINFO2_TYPE_EXTINT:
+ trap_fred_extint(frame, vec);
+ break;
+ case TF_FRED_EVINFO2_TYPE_NMI:
+ frame->tf_trapno = T_NMI;
+ nmi_handle_intr(frame);
+ break;
+ case TF_FRED_EVINFO2_TYPE_INT1:
+ case TF_FRED_EVINFO2_TYPE_INT3:
+ case TF_FRED_EVINFO2_TYPE_EXC:
+ trap_fred_ev_to_trapno(frame, vec);
+ trap_fred_handle_k_exc(td, frame, vec);
+ break;
+ case TF_FRED_EVINFO2_TYPE_INTn:
+ panic("INT%d from kernel", vec);
+ break;
+ case TF_FRED_EVINFO2_TYPE_SYSCALL:
+ panic("syscall from kernel");
+ break;
+ default:
+ __unreachable();
+ }
+}
diff --git a/sys/amd64/include/md_var.h b/sys/amd64/include/md_var.h
--- a/sys/amd64/include/md_var.h
+++ b/sys/amd64/include/md_var.h
@@ -46,6 +46,7 @@
extern int nmi_flush_l1d_sw;
extern int syscall_ret_l1d_flush_mode;
extern int lass_enabled;
+extern char *fred_page;
extern vm_paddr_t intel_graphics_stolen_base;
extern vm_paddr_t intel_graphics_stolen_size;
@@ -65,12 +66,14 @@
struct trapframe;
void amd64_conf_fast_syscall(void);
+void amd64_cpu_init_fred(void);
void amd64_db_resume_dbreg(void);
vm_paddr_t amd64_loadaddr(void);
void amd64_lower_shared_page(struct sysentvec *);
void amd64_bsp_pcpu_init1(struct pcpu *pc);
void amd64_bsp_pcpu_init2(uint64_t rsp0);
void amd64_bsp_ist_init(struct pcpu *pc);
+void amd64_bsp_fred_csl_init(struct pcpu *pc);
void amd64_syscall(struct thread *td, int traced);
void amd64_syscall_ret_flush_l1d(int error);
void amd64_syscall_ret_flush_l1d_recalc(void);
diff --git a/sys/amd64/include/pcb.h b/sys/amd64/include/pcb.h
--- a/sys/amd64/include/pcb.h
+++ b/sys/amd64/include/pcb.h
@@ -102,11 +102,17 @@
register_t pcb_lstar;
register_t pcb_cstar;
register_t pcb_sfmask;
+ /* FRED MSRs */
+ register_t pcb_fred_rsp0;
+ register_t pcb_fred_rsp1;
+ register_t pcb_fred_rsp2;
+ register_t pcb_fred_rsp3;
+ register_t pcb_fred_stklvls;
+ register_t pcb_fred_config;
struct savefpu *pcb_save;
register_t pcb_tlsbase; /* not same as pcb_fsbase */
- uint64_t pcb_pad[4];
};
/* Per-CPU state saved during suspend and resume. */
diff --git a/sys/amd64/vmm/intel/vmx.c b/sys/amd64/vmm/intel/vmx.c
--- a/sys/amd64/vmm/intel/vmx.c
+++ b/sys/amd64/vmm/intel/vmx.c
@@ -894,7 +894,7 @@
&tmp);
if (error == 0) {
pirvec = lapic_ipi_alloc(pti ? &IDTVEC(justreturn1_pti) :
- &IDTVEC(justreturn));
+ &IDTVEC(justreturn), vmm_justreturn);
if (pirvec < 0) {
if (bootverbose) {
printf("vmx_modinit: unable to "
diff --git a/sys/amd64/vmm/vmm.c b/sys/amd64/vmm/vmm.c
--- a/sys/amd64/vmm/vmm.c
+++ b/sys/amd64/vmm/vmm.c
@@ -287,7 +287,7 @@
vmm_host_state_init();
vmm_ipinum = lapic_ipi_alloc(pti ? &IDTVEC(justreturn1_pti) :
- &IDTVEC(justreturn));
+ &IDTVEC(justreturn), vmm_justreturn);
if (vmm_ipinum < 0)
vmm_ipinum = IPI_AST;
diff --git a/sys/amd64/vmm/vmm_lapic.h b/sys/amd64/vmm/vmm_lapic.h
--- a/sys/amd64/vmm/vmm_lapic.h
+++ b/sys/amd64/vmm/vmm_lapic.h
@@ -71,4 +71,6 @@
int lapic_intr_msi(struct vm *vm, uint64_t addr, uint64_t msg);
+void vmm_justreturn(struct trapframe *);
+
#endif
diff --git a/sys/amd64/vmm/vmm_lapic.c b/sys/amd64/vmm/vmm_lapic.c
--- a/sys/amd64/vmm/vmm_lapic.c
+++ b/sys/amd64/vmm/vmm_lapic.c
@@ -237,3 +237,8 @@
error = vlapic_read(vlapic, 1, off, rval, arg);
return (error);
}
+
+void
+vmm_justreturn(struct trapframe *frame)
+{
+}
diff --git a/sys/dev/hyperv/vmbus/x86/vmbus_x86.c b/sys/dev/hyperv/vmbus/x86/vmbus_x86.c
--- a/sys/dev/hyperv/vmbus/x86/vmbus_x86.c
+++ b/sys/dev/hyperv/vmbus/x86/vmbus_x86.c
@@ -151,7 +151,8 @@
* free IDT vector for Hyper-V ISR and set it up.
*/
sc->vmbus_idtvec = lapic_ipi_alloc(
- pti ? IDTVEC(vmbus_isr_pti) : IDTVEC(vmbus_isr));
+ pti ? IDTVEC(vmbus_isr_pti) : IDTVEC(vmbus_isr),
+ vmbus_handle_intr);
if (sc->vmbus_idtvec < 0) {
#if defined(__amd64__) && defined(KLD_MODULE)
pmap_pti_remove_kva(VMBUS_ISR_ADDR, VMBUS_ISR_ADDR + PAGE_SIZE);
diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c
--- a/sys/i386/i386/machdep.c
+++ b/sys/i386/i386/machdep.c
@@ -191,6 +191,8 @@
struct mem_range_softc mem_range_softc;
+int fred;
+
extern char start_exceptions[], end_exceptions[];
extern struct sysentvec elf32_freebsd_sysvec;
diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c
--- a/sys/kern/kern_thread.c
+++ b/sys/kern/kern_thread.c
@@ -92,7 +92,7 @@
"struct thread KBI td_pflags");
_Static_assert(offsetof(struct thread, td_frame) == 0x4e8,
"struct thread KBI td_frame");
-_Static_assert(offsetof(struct thread, td_emuldata) == 0x6f0,
+_Static_assert(offsetof(struct thread, td_emuldata) == 0x700,
"struct thread KBI td_emuldata");
_Static_assert(offsetof(struct proc, p_flag) == 0xb8,
"struct proc KBI p_flag");
diff --git a/sys/x86/include/apicvar.h b/sys/x86/include/apicvar.h
--- a/sys/x86/include/apicvar.h
+++ b/sys/x86/include/apicvar.h
@@ -247,7 +247,8 @@
}
int lapic_ipi_wait(int delay);
-int lapic_ipi_alloc(inthand_t *ipifunc);
+int lapic_ipi_alloc(inthand_t *ipifunc,
+ void (*fred_ipifunc)(struct trapframe *));
void lapic_ipi_free(int vector);
enum LAPIC_REGISTERS;
uint32_t lapic_read32_ext(enum LAPIC_REGISTERS reg);
diff --git a/sys/x86/include/frame.h b/sys/x86/include/frame.h
--- a/sys/x86/include/frame.h
+++ b/sys/x86/include/frame.h
@@ -196,7 +196,6 @@
#define TF_HASBASES 0x00000002
#define TF_HASFPXSTATE 0x00000004
#define TF_RESERV0 0x00000008 /* no tlsbase in the trapframe */
-#define TF_FRED 0x00000010
#endif /* __amd64__ */
#endif /* _MACHINE_FRAME_H_ */
diff --git a/sys/x86/include/x86_var.h b/sys/x86/include/x86_var.h
--- a/sys/x86/include/x86_var.h
+++ b/sys/x86/include/x86_var.h
@@ -97,6 +97,7 @@
extern int zenbleed_enable;
extern int cpu_amdc1e_bug;
extern char bootmethod[16];
+extern int fred;
struct pcb;
struct thread;
@@ -114,6 +115,8 @@
*/
typedef void alias_for_inthand_t(void);
+extern void (*fred_ipi_handlers[])(struct trapframe *);
+
bool acpi_get_fadt_bootflags(uint16_t *flagsp);
void *alloc_fpusave(int flags);
u_int cpu_auxmsr(void);
diff --git a/sys/x86/isa/atpic.c b/sys/x86/isa/atpic.c
--- a/sys/x86/isa/atpic.c
+++ b/sys/x86/isa/atpic.c
@@ -466,9 +466,11 @@
continue;
ai->at_intsrc.is_count = &ai->at_count;
ai->at_intsrc.is_straycount = &ai->at_straycount;
- setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase +
- ai->at_irq, pti ? ai->at_intr_pti : ai->at_intr, SDT_ATPIC,
- SEL_KPL, GSEL_ATPIC);
+ if (!fred) {
+ setidt(((struct atpic *)ai->at_intsrc.is_pic)->
+ at_intbase + ai->at_irq, pti ? ai->at_intr_pti :
+ ai->at_intr, SDT_ATPIC, SEL_KPL, GSEL_ATPIC);
+ }
}
/*
diff --git a/sys/x86/x86/local_apic.c b/sys/x86/x86/local_apic.c
--- a/sys/x86/x86/local_apic.c
+++ b/sys/x86/x86/local_apic.c
@@ -580,9 +580,11 @@
lapic_map = NULL;
}
- /* Setup the spurious interrupt handler. */
- setidt(APIC_SPURIOUS_INT, IDTVEC(spuriousint), SDT_APIC, SEL_KPL,
- GSEL_APIC);
+ if (!fred) {
+ /* Setup the spurious interrupt handler. */
+ setidt(APIC_SPURIOUS_INT, IDTVEC(spuriousint), SDT_APIC,
+ SEL_KPL, GSEL_APIC);
+ }
/* Perform basic initialization of the BSP's local APIC. */
lapic_enable();
@@ -591,19 +593,22 @@
/* Set BSP's per-CPU local APIC ID. */
PCPU_SET(apic_id, lapic_id());
- /* Local APIC timer interrupt. */
- setidt(APIC_TIMER_INT, pti ? IDTVEC(timerint_pti) : IDTVEC(timerint),
- SDT_APIC, SEL_KPL, GSEL_APIC);
+ if (!fred) {
+ /* Local APIC timer interrupt. */
+ setidt(APIC_TIMER_INT, pti ? IDTVEC(timerint_pti) :
+ IDTVEC(timerint), SDT_APIC, SEL_KPL, GSEL_APIC);
- /* Local APIC error interrupt. */
- setidt(APIC_ERROR_INT, pti ? IDTVEC(errorint_pti) : IDTVEC(errorint),
- SDT_APIC, SEL_KPL, GSEL_APIC);
+ /* Local APIC error interrupt. */
+ setidt(APIC_ERROR_INT, pti ? IDTVEC(errorint_pti) :
+ IDTVEC(errorint),
+ SDT_APIC, SEL_KPL, GSEL_APIC);
- /* XXX: Thermal interrupt */
+ /* XXX: Thermal interrupt */
- /* Local APIC CMCI. */
- setidt(APIC_CMC_INT, pti ? IDTVEC(cmcint_pti) : IDTVEC(cmcint),
- SDT_APIC, SEL_KPL, GSEL_APIC);
+ /* Local APIC CMCI. */
+ setidt(APIC_CMC_INT, pti ? IDTVEC(cmcint_pti) : IDTVEC(cmcint),
+ SDT_APIC, SEL_KPL, GSEL_APIC);
+ }
if ((resource_int_value("apic", 0, "clock", &i) != 0 || i != 0)) {
/* Set if APIC timer runs in C3. */
@@ -1762,8 +1767,11 @@
KASSERT(vector != IDT_DTRACE_RET,
("Attempt to overwrite DTrace entry"));
#endif
- setidt(vector, (pti ? ioint_pti_handlers : ioint_handlers)[vector / 32],
- SDT_APIC, SEL_KPL, GSEL_APIC);
+ if (!fred) {
+ setidt(vector, (pti ? ioint_pti_handlers :
+ ioint_handlers)[vector / 32], SDT_APIC, SEL_KPL,
+ GSEL_APIC);
+ }
}
void
@@ -2272,6 +2280,8 @@
void (*ipi_vectored)(u_int, int) = &native_lapic_ipi_vectored;
#endif /* SMP */
+void (*fred_ipi_handlers[IPI_DYN_LAST - IPI_DYN_FIRST])(struct trapframe *);
+
/*
* Since the IDT is shared by all CPUs the IPI slot update needs to be globally
* visible.
@@ -2286,10 +2296,9 @@
* the IDT slot update is globally visible before the IPI is delivered.
*/
int
-lapic_ipi_alloc(inthand_t *ipifunc)
+lapic_ipi_alloc(inthand_t *ipifunc, void (*fred_ipifunc)(struct trapframe *))
{
- struct gate_descriptor *ip;
- long func;
+ void (*fip)(struct trapframe *);
int idx, vector;
KASSERT(ipifunc != &IDTVEC(rsvd) && ipifunc != &IDTVEC(rsvd_pti),
@@ -2298,15 +2307,14 @@
vector = -1;
mtx_lock_spin(&icu_lock);
for (idx = IPI_DYN_FIRST; idx <= IPI_DYN_LAST; idx++) {
- ip = &idt[idx];
- func = (ip->gd_hioffset << 16) | ip->gd_looffset;
-#ifdef __i386__
- func -= setidt_disp;
-#endif
- if ((!pti && func == (uintptr_t)&IDTVEC(rsvd)) ||
- (pti && func == (uintptr_t)&IDTVEC(rsvd_pti))) {
+ fip = fred_ipi_handlers[idx - IPI_DYN_FIRST];
+ if (fip == NULL) {
vector = idx;
- setidt(vector, ipifunc, SDT_APIC, SEL_KPL, GSEL_APIC);
+ fred_ipi_handlers[idx - IPI_DYN_FIRST] = fred_ipifunc;
+ if (!fred) {
+ setidt(vector, ipifunc, SDT_APIC, SEL_KPL,
+ GSEL_APIC);
+ }
break;
}
}
@@ -2324,15 +2332,20 @@
("%s: invalid vector %d", __func__, vector));
mtx_lock_spin(&icu_lock);
- ip = &idt[vector];
- func = (ip->gd_hioffset << 16) | ip->gd_looffset;
+ KASSERT(fred_ipi_handlers[vector - IPI_DYN_FIRST] != NULL,
+ ("NULL fred func %d", vector));
+ fred_ipi_handlers[vector - IPI_DYN_FIRST] = NULL;
+ if (!fred) {
+ ip = &idt[vector];
+ func = (ip->gd_hioffset << 16) | ip->gd_looffset;
#ifdef __i386__
- func -= setidt_disp;
+ func -= setidt_disp;
#endif
- KASSERT(func != (uintptr_t)&IDTVEC(rsvd) &&
- func != (uintptr_t)&IDTVEC(rsvd_pti),
- ("invalid idtfunc %#lx", func));
- setidt(vector, pti ? &IDTVEC(rsvd_pti) : &IDTVEC(rsvd), SDT_APIC,
- SEL_KPL, GSEL_APIC);
+ KASSERT(func != (uintptr_t)&IDTVEC(rsvd) &&
+ func != (uintptr_t)&IDTVEC(rsvd_pti),
+ ("invalid idtfunc %d %#lx", vector, func));
+ setidt(vector, pti ? &IDTVEC(rsvd_pti) : &IDTVEC(rsvd),
+ SDT_APIC, SEL_KPL, GSEL_APIC);
+ }
mtx_unlock_spin(&icu_lock);
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Apr 8, 6:22 AM (18 h, 19 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31082303
Default Alt Text
D55829.id174054.diff (50 KB)
Attached To
Mode
D55829: amd64: FRED support
Attached
Detach File
Event Timeline
Log In to Comment