summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authoraiju <aiju@phicode.de>2011-07-19 15:42:00 +0200
committeraiju <aiju@phicode.de>2011-07-19 15:42:00 +0200
commit03d71535eca82570372650678eb91e447eacfb86 (patch)
tree5f41b81e2e8b1f87012e3067dc5d79360a5e4f0f /sys
parenteee8fc8f2a9a17f194d6ecf0ddcf46bbcf6f9a66 (diff)
reading from/writing to non-existant MSRs via /dev/msr no longer crashes the system
Diffstat (limited to 'sys')
-rw-r--r--sys/src/9/pc/devarch.c6
-rw-r--r--sys/src/9/pc/fns.h4
-rw-r--r--sys/src/9/pc/l.s21
-rw-r--r--sys/src/9/pc/trap.c8
4 files changed, 36 insertions, 3 deletions
diff --git a/sys/src/9/pc/devarch.c b/sys/src/9/pc/devarch.c
index 3228736ee..46c98b19c 100644
--- a/sys/src/9/pc/devarch.c
+++ b/sys/src/9/pc/devarch.c
@@ -397,7 +397,8 @@ archread(Chan *c, void *a, long n, vlong offset)
error(Ebadarg);
vp = a;
for(port = offset; port < offset+n; port += 8)
- rdmsr(port, vp++);
+ if(tryrdmsr(port, vp++) < 0)
+ error(Ebadarg);
return n;
case Qioalloc:
@@ -475,7 +476,8 @@ archwrite(Chan *c, void *a, long n, vlong offset)
error(Ebadarg);
vp = a;
for(port = offset; port < offset+n; port += 8)
- wrmsr(port, *vp++);
+ if(trywrmsr(port, *vp++) < 0)
+ error(Ebadarg);
return n;
default:
diff --git a/sys/src/9/pc/fns.h b/sys/src/9/pc/fns.h
index c612a2c59..123abca5c 100644
--- a/sys/src/9/pc/fns.h
+++ b/sys/src/9/pc/fns.h
@@ -167,6 +167,10 @@ void trapenable(int, void (*)(Ureg*, void*), void*, char*);
void trapinit(void);
void trapinit0(void);
int tas(void*);
+int tryrdmsr(int, vlong*);
+void tryrdmsrbody(void);
+int trywrmsr(int, vlong);
+void trywrmsrbody(void);
uvlong tscticks(uvlong*);
ulong umbmalloc(ulong, int, int);
void umbfree(ulong, int);
diff --git a/sys/src/9/pc/l.s b/sys/src/9/pc/l.s
index 3cc9170dc..6618421a2 100644
--- a/sys/src/9/pc/l.s
+++ b/sys/src/9/pc/l.s
@@ -691,6 +691,17 @@ TEXT rdmsr(SB), $0 /* model-specific register */
MOVL AX, 0(CX) /* lo */
MOVL DX, 4(CX) /* hi */
RET
+
+TEXT tryrdmsr(SB), $0 /* model-specific register */
+ MOVL $0, BP
+ MOVL index+0(FP), CX
+TEXT tryrdmsrbody(SB), $0
+ RDMSR
+ MOVL vlong+4(FP), CX /* &vlong */
+ MOVL AX, 0(CX) /* lo */
+ MOVL DX, 4(CX) /* hi */
+ MOVL BP, AX
+ RET
TEXT wrmsr(SB), $0
MOVL index+0(FP), CX
@@ -699,6 +710,16 @@ TEXT wrmsr(SB), $0
WRMSR
RET
+TEXT trywrmsr(SB), $0
+ MOVL $0, BP
+ MOVL index+0(FP), CX
+ MOVL lo+4(FP), AX
+ MOVL hi+8(FP), DX
+TEXT trywrmsrbody(SB), $0
+ WRMSR
+ MOVL BP, AX
+ RET
+
/*
* Try to determine the CPU type which requires fiddling with EFLAGS.
* If the Id bit can be toggled then the CPUID instruction can be used
diff --git a/sys/src/9/pc/trap.c b/sys/src/9/pc/trap.c
index 661aa06e8..ba52895ea 100644
--- a/sys/src/9/pc/trap.c
+++ b/sys/src/9/pc/trap.c
@@ -463,7 +463,13 @@ trap(Ureg* ureg)
return;
}
}
-
+ if(vno == VectorGPF && !user &&
+ (ureg->pc == (ulong)(void*)tryrdmsrbody ||
+ ureg->pc == (ulong)(void*)trywrmsrbody)){
+ ureg->bp = -1;
+ ureg->pc += 2;
+ return;
+ }
dumpregs(ureg);
if(!user){
ureg->sp = (ulong)&ureg->sp;