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:
parent
526d242299
commit
a058a87622
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user