powerpc64: Add the DSCR facility on POWER8 and later

The Data Stream Control Register (DSCR) is privileged on POWER7, but
unprivileged (different register) on POWER8 and later.  However, it's now
guarded by a new register, the Facility Status and Control Register, instead of
the MSR like other pre-existing facilities (FPU, Altivec).  The FSCR must be
managed explicitly, since it's effectively an extension of the MSR.

Tested by:	Brandon Bergren
This commit is contained in:
Justin Hibbits 2019-04-27 16:28:34 +00:00
parent c711d88236
commit 8b7f0d83e6
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=346790
6 changed files with 70 additions and 11 deletions

View File

@ -47,6 +47,7 @@ struct pcb {
register_t pcb_toc; /* toc pointer */
register_t pcb_lr; /* link register */
register_t pcb_dscr; /* dscr value */
register_t pcb_fscr;
struct pmap *pcb_pm; /* pmap of our vmspace */
jmp_buf *pcb_onfault; /* For use during
copyin/copyout */
@ -57,6 +58,7 @@ struct pcb {
#define PCB_VSX 0x8 /* Process had VSX initialized */
#define PCB_CDSCR 0x10 /* Process had Custom DSCR initialized */
#define PCB_HTM 0x20 /* Process had HTM initialized */
#define PCB_CFSCR 0x40 /* Process had FSCR updated */
struct fpu {
union {
double fpr;

View File

@ -93,11 +93,12 @@
#define SPR_MQ 0x000 /* .6. 601 MQ register */
#define SPR_XER 0x001 /* 468 Fixed Point Exception Register */
#define SPR_DSCR 0x003 /* .6. Data Stream Control Register (Unprivileged) */
#define SPR_RTCU_R 0x004 /* .6. 601 RTC Upper - Read */
#define SPR_RTCL_R 0x005 /* .6. 601 RTC Lower - Read */
#define SPR_LR 0x008 /* 468 Link Register */
#define SPR_CTR 0x009 /* 468 Count Register */
#define SPR_DSCR 0x011 /* Data Stream Control Register */
#define SPR_DSCRP 0x011 /* Data Stream Control Register (Privileged) */
#define SPR_DSISR 0x012 /* .68 DSI exception source */
#define DSISR_DIRECT 0x80000000 /* Direct-store error exception */
#define DSISR_NOTFOUND 0x40000000 /* Translation not found */
@ -135,6 +136,7 @@
#define FSCR_IC_STOP 0x0900000000000000ULL /* Access to the 'stop' instruction in privileged non-hypervisor state */
#define FSCR_IC_MSG 0x0A00000000000000ULL /* Access to 'msgsndp' or 'msgclrp' instructions */
#define FSCR_IC_SCV 0x0C00000000000000ULL /* Execution of a 'scv' instruction */
#define FSCR_DSCR 0x0000000000000004ULL /* DSCR available in PR state */
#define SPR_USPRG0 0x100 /* 4.. User SPR General 0 */
#define SPR_VRSAVE 0x100 /* .6. AltiVec VRSAVE */
#define SPR_SPRG0 0x110 /* 468 SPR General 0 */

View File

@ -124,6 +124,8 @@ static int grab_mcontext32(struct thread *td, mcontext32_t *, int flags);
static int grab_mcontext(struct thread *, mcontext_t *, int);
static void cleanup_power_extras(struct thread *);
#ifdef __powerpc64__
extern struct sysentvec elf64_freebsd_sysvec_v2;
#endif
@ -505,6 +507,30 @@ set_mcontext(struct thread *td, mcontext_t *mcp)
return (0);
}
/*
* Clean up extra POWER state. Some per-process registers and states are not
* managed by the MSR, so must be cleaned up explicitly on thread exit.
*
* Currently this includes:
* DSCR -- Data stream control register (PowerISA 2.06+)
* FSCR -- Facility Status and Control Register (PowerISA 2.07+)
*/
static void
cleanup_power_extras(struct thread *td)
{
uint32_t pcb_flags;
if (td != curthread)
return;
pcb_flags = td->td_pcb->pcb_flags;
/* Clean up registers not managed by MSR. */
if (pcb_flags & PCB_CFSCR)
mtspr(SPR_FSCR, 0);
if (pcb_flags & PCB_CDSCR)
mtspr(SPR_DSCRP, 0);
}
/*
* Set set up registers on exec.
*/
@ -549,6 +575,7 @@ exec_setregs(struct thread *td, struct image_params *imgp, u_long stack)
tf->fixreg[12] = imgp->entry_addr;
#endif
tf->srr1 = psl_userset | PSL_FE_DFLT;
cleanup_power_extras(td);
td->td_pcb->pcb_flags = 0;
}
@ -574,6 +601,7 @@ ppc32_setregs(struct thread *td, struct image_params *imgp, u_long stack)
tf->srr0 = imgp->entry_addr;
tf->srr1 = psl_userset32 | PSL_FE_DFLT;
cleanup_power_extras(td);
td->td_pcb->pcb_flags = 0;
}
#endif
@ -912,6 +940,7 @@ cpu_set_syscall_retval(struct thread *td, int error)
void
cpu_thread_exit(struct thread *td)
{
cleanup_power_extras(td);
}
void
@ -1052,10 +1081,10 @@ emulate_mfspr(int spr, int reg, struct trapframe *frame){
td = curthread;
if (spr == SPR_DSCR) {
if (spr == SPR_DSCR || spr == SPR_DSCRP) {
// If DSCR was never set, get the default DSCR
if ((td->td_pcb->pcb_flags & PCB_CDSCR) == 0)
td->td_pcb->pcb_dscr = mfspr(SPR_DSCR);
td->td_pcb->pcb_dscr = mfspr(SPR_DSCRP);
frame->fixreg[reg] = td->td_pcb->pcb_dscr;
frame->srr0 += 4;
@ -1070,9 +1099,10 @@ emulate_mtspr(int spr, int reg, struct trapframe *frame){
td = curthread;
if (spr == SPR_DSCR) {
if (spr == SPR_DSCR || spr == SPR_DSCRP) {
td->td_pcb->pcb_flags |= PCB_CDSCR;
td->td_pcb->pcb_dscr = frame->fixreg[reg];
mtspr(SPR_DSCRP, frame->fixreg[reg]);
frame->srr0 += 4;
return 0;
} else

View File

@ -196,6 +196,7 @@ ASSYM(CF_SIZE, sizeof(struct callframe));
ASSYM(PCB_CONTEXT, offsetof(struct pcb, pcb_context));
ASSYM(PCB_CR, offsetof(struct pcb, pcb_cr));
ASSYM(PCB_DSCR, offsetof(struct pcb, pcb_dscr));
ASSYM(PCB_FSCR, offsetof(struct pcb, pcb_fscr));
ASSYM(PCB_SP, offsetof(struct pcb, pcb_sp));
ASSYM(PCB_TOC, offsetof(struct pcb, pcb_toc));
ASSYM(PCB_LR, offsetof(struct pcb, pcb_lr));
@ -204,6 +205,7 @@ ASSYM(PCB_FLAGS, offsetof(struct pcb, pcb_flags));
ASSYM(PCB_FPU, PCB_FPU);
ASSYM(PCB_VEC, PCB_VEC);
ASSYM(PCB_CDSCR, PCB_CDSCR);
ASSYM(PCB_CFSCR, PCB_CFSCR);
ASSYM(PCB_AIM_USR_VSID, offsetof(struct pcb, pcb_cpu.aim.usr_vsid));
ASSYM(PCB_BOOKE_DBCR0, offsetof(struct pcb, pcb_cpu.booke.dbcr0));

View File

@ -87,6 +87,10 @@ ENTRY(cpu_throw)
* struct mutex *mtx);
*
* Switch to a new thread saving the current state in the old thread.
*
* Internally clobbers (not visible outside of this file):
* r18 - old thread pcb_flags
* r19 - new thread pcb_flags
*/
ENTRY(cpu_switch)
ld %r6,TD_PCB(%r3) /* Get the old thread's PCB ptr */
@ -126,11 +130,15 @@ ENTRY(cpu_switch)
stdu %r1,-48(%r1)
lwz %r18, PCB_FLAGS(%r17)
andi. %r7, %r18, PCB_CFSCR
beq 1f
mfspr %r6, SPR_FSCR
std %r6, PCB_FSCR(%r17)
1:
andi. %r7, %r18, PCB_CDSCR
beq .L0
/* Custom DSCR was set. Reseting it to enter kernel */
li %r6, 0x0
mtspr SPR_DSCR, %r6
mfspr %r6, SPR_DSCRP
std %r6, PCB_DSCR(%r17)
.L0:
/* Save FPU context if needed */
@ -201,11 +209,20 @@ blocked_loop:
nop
.L31:
/* Restore Custom DSCR if needed */
andi. %r6, %r19, PCB_CDSCR
beq .L4
/* Load custom DSCR on PowerISA 2.06+ CPUs. */
/* Load changed FSCR on PowerISA 2.07+ CPUs. */
or %r18,%r18,%r19
/* Restore Custom DSCR if needed (zeroes if in old but not new) */
andi. %r6, %r18, PCB_CDSCR
beq .L32
ld %r7, PCB_DSCR(%r17) /* Load the DSCR register*/
mtspr SPR_DSCR, %r7
mtspr SPR_DSCRP, %r7
.L32:
/* Restore FSCR if needed (zeroes if in old but not new) */
andi. %r6, %r18, PCB_CFSCR
beq .L4
ld %r7, PCB_FSCR(%r17) /* Load the FSCR register*/
mtspr SPR_FSCR, %r7
/* thread to restore is in r3 */
.L4:

View File

@ -307,6 +307,12 @@ trap(struct trapframe *frame)
fscr = mfspr(SPR_FSCR);
if ((fscr & FSCR_IC_MASK) == FSCR_IC_HTM) {
CTR0(KTR_TRAP, "Hardware Transactional Memory subsystem disabled");
} else if ((fscr & FSCR_IC_MASK) == FSCR_IC_DSCR) {
td->td_pcb->pcb_flags |= PCB_CFSCR | PCB_CDSCR;
fscr &= ~FSCR_IC_MASK;
mtspr(SPR_FSCR, fscr | FSCR_DSCR);
mtspr(SPR_DSCR, 0);
break;
}
sig = SIGILL;
ucode = ILL_ILLOPC;