diff options
author | aiju <devnull@localhost> | 2017-06-12 19:03:07 +0000 |
---|---|---|
committer | aiju <devnull@localhost> | 2017-06-12 19:03:07 +0000 |
commit | 773be02aa18095e857c6659416d84951ceb60d41 (patch) | |
tree | 26daede4230e14d46d42efbcd6eab8e68adc7687 /sys/src/9/pc/devarch.c | |
parent | 1cfa405d0a272cbd7df22d4b9767eb57e21cc21f (diff) |
kernel: add support for hardware watchpoints
Diffstat (limited to 'sys/src/9/pc/devarch.c')
-rw-r--r-- | sys/src/9/pc/devarch.c | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/sys/src/9/pc/devarch.c b/sys/src/9/pc/devarch.c index 7870ad6d4..0523ce84e 100644 --- a/sys/src/9/pc/devarch.c +++ b/sys/src/9/pc/devarch.c @@ -49,6 +49,9 @@ enum { /* cpuid standard function codes */ Procsig, Proctlbcache, Procserial, + + Highextfunc = 0x80000000, + Procextfeat, }; typedef long Rdwrfn(Chan*, void*, long, vlong); @@ -874,6 +877,23 @@ cpuidentify(void) hwrandbuf = rdrandbuf; else hwrandbuf = nil; + + /* 8-byte watchpoints are supported in Long Mode */ + if(sizeof(uintptr) == 8) + m->havewatchpt8 = 1; + else if(strcmp(m->cpuidid, "GenuineIntel") == 0){ + /* some random CPUs that support 8-byte watchpoints */ + if(family == 15 && (model == 3 || model == 4 || model == 6) + || family == 6 && (model == 15 || model == 23 || model == 28)) + m->havewatchpt8 = 1; + /* Intel SDM claims amd64 support implies 8-byte watchpoint support */ + cpuid(Highextfunc, regs); + if(regs[0] >= Procextfeat){ + cpuid(Procextfeat, regs); + if((regs[3] & 1<<29) != 0) + m->havewatchpt8 = 1; + } + } cputype = t; return t->family; @@ -1229,3 +1249,61 @@ dumpmcregs(void) iprint("\n"); } } + +void +setupwatchpts(Proc *pr, Watchpt *wp, int nwp) +{ + int i; + u8int cfg; + Watchpt *p; + + if(nwp > 4) + error("there are four watchpoints."); + if(nwp == 0){ + memset(pr->dr, 0, sizeof(pr->dr)); + return; + } + for(p = wp; p < wp + nwp; p++){ + switch(p->type){ + case WATCHRD|WATCHWR: case WATCHWR: + break; + case WATCHEX: + if(p->len != 1) + error("length must be 1 on breakpoints"); + break; + default: + error("type must be rw-, -w- or --x"); + } + switch(p->len){ + case 1: case 2: case 4: + break; + case 8: + if(m->havewatchpt8) break; + default: + error(m->havewatchpt8 ? "length must be 1,2,4,8" : "length must be 1,2,4"); + } + if((p->addr & p->len - 1) != 0) + error("address must be aligned according to length"); + } + + memset(pr->dr, 0, sizeof(pr->dr)); + pr->dr[6] = 0xffff8ff0; + for(i = 0; i < nwp; i++){ + pr->dr[i] = wp[i].addr; + switch(wp[i].type){ + case WATCHRD|WATCHWR: cfg = 3; break; + case WATCHWR: cfg = 1; break; + case WATCHEX: cfg = 0; break; + default: continue; + } + switch(wp[i].len){ + case 1: break; + case 2: cfg |= 4; break; + case 4: cfg |= 12; break; + case 8: cfg |= 8; break; + default: continue; + } + pr->dr[7] |= cfg << 16 + 4 * i; + pr->dr[7] |= 1 << 2 * i + 1; + } +} |