summaryrefslogtreecommitdiff
path: root/sys/src/cmd/vmx/x86.c
diff options
context:
space:
mode:
authoraiju <devnull@localhost>2017-06-27 09:21:30 +0000
committeraiju <devnull@localhost>2017-06-27 09:21:30 +0000
commitdffbc1e45d61bb928ea6a9d0b1206d641daf24fe (patch)
tree8a80a3a2c7e964fc89b8776a6dd8326f545a53dc /sys/src/cmd/vmx/x86.c
parentb5a6dc7849cbd9f1fd23183ba46f0d5deb24e81d (diff)
vmx(1): I/O string instructions, incomplete support for IDE disks, misc fixes
Diffstat (limited to 'sys/src/cmd/vmx/x86.c')
-rw-r--r--sys/src/cmd/vmx/x86.c184
1 files changed, 170 insertions, 14 deletions
diff --git a/sys/src/cmd/vmx/x86.c b/sys/src/cmd/vmx/x86.c
index 2846504b7..73397b28c 100644
--- a/sys/src/cmd/vmx/x86.c
+++ b/sys/src/cmd/vmx/x86.c
@@ -11,20 +11,22 @@ struct VMemReq {
uintptr va, len;
void *buf;
uintptr rc;
+ int wr;
};
static uintptr
-translateflat(uintptr va, uintptr *pa, uintptr)
+translateflat(uintptr va, uintptr *pa, int *perm)
{
if(sizeof(uintptr) != 4 && va >> 32 != 0) return 0;
*pa = va;
if(va == 0)
return 0xFFFFFFFFUL;
+ if(perm != 0) *perm = -1;
return -va;
}
static uintptr
-translate32(uintptr va, uintptr *pa, uintptr cr4)
+translate32(uintptr va, uintptr *pa, int *perm)
{
void *pd, *pt;
u32int pde, pte;
@@ -33,35 +35,37 @@ translate32(uintptr va, uintptr *pa, uintptr cr4)
pd = gptr(rget("cr3") & ~0xfff, 4096);
if(pd == nil) return 0;
pde = GET32(pd, (va >> 22) * 4);
+ if(perm != nil) *perm = pde;
if((pde & 1) == 0) return 0;
- if((pde & 0x80) != 0 && (cr4 & Cr4Pse) != 0){
- *pa = pde & (1<<22) - 1 | (uintptr)(pde & 0xfe000) << 19;
- return (1<<22) - (va & (1<<22)-1);
+ if((pde & 0x80) != 0 && (rget("cr4real") & Cr4Pse) != 0){
+ *pa = pde & 0xffc00000 | (uintptr)(pde & 0x3fe000) << 19 | va & 0x3fffff;
+ return 0x400000 - (va & 0x3fffff);
}
pt = gptr(pde & ~0xfff, 4096);
if(pt == nil) return 0;
pte = GET32(pt, va >> 10 & 0xffc);
if((pte & 1) == 0) return 0;
+ if(perm != nil) *perm &= pte;
*pa = pte & ~0xfff | va & 0xfff;
return 0x1000 - (va & 0xfff);
}
static uintptr
-translatepae(uintptr, uintptr *, uintptr)
+translatepae(uintptr, uintptr *, int *)
{
vmerror("PAE translation not implemented");
return 0;
}
static uintptr
-translate64(uintptr, uintptr *, uintptr)
+translate64(uintptr, uintptr *, int *)
{
vmerror("long mode translation not implemented");
return 0;
}
static uintptr (*
-translator(uintptr *cr4p))(uintptr, uintptr *, uintptr)
+translator(void))(uintptr, uintptr *, int *)
{
uintptr cr0, cr4, efer;
@@ -72,7 +76,6 @@ translator(uintptr *cr4p))(uintptr, uintptr *, uintptr)
if((efer & EferLme) != 0)
return translate64;
cr4 = rget("cr4real");
- *cr4p = cr4;
if((cr4 & Cr4Pae) != 0)
return translatepae;
return translate32;
@@ -82,25 +85,30 @@ static void
vmemread0(void *aux)
{
VMemReq *req;
- uintptr va, pa, n, ok, pok, cr4;
+ uintptr va, pa, n, ok, pok;
void *v;
- uintptr (*trans)(uintptr, uintptr *, uintptr);
+ uintptr (*trans)(uintptr, uintptr *, int *);
uchar *p;
+ int wr;
req = aux;
va = req->va;
n = req->len;
p = req->buf;
- trans = translator(&cr4);
+ wr = req->wr;
+ trans = translator();
while(n > 0){
- ok = trans(va, &pa, cr4);
+ ok = trans(va, &pa, nil);
if(ok == 0) break;
if(ok > n) ok = n;
v = gptr(pa, 1);
if(v == nil) break;
pok = gavail(v);
if(ok > pok) ok = pok;
- memmove(p, v, ok);
+ if(wr)
+ memmove(v, p, ok);
+ else
+ memmove(p, v, ok);
n -= ok;
p += ok;
va += ok;
@@ -115,6 +123,7 @@ vmemread(void *buf, uintptr len, uintptr va)
VMemReq req;
memset(&req, 0, sizeof(VMemReq));
+ req.wr = 0;
req.buf = buf;
req.len = len;
req.va = va;
@@ -123,3 +132,150 @@ vmemread(void *buf, uintptr len, uintptr va)
qlock(&req);
return req.rc;
}
+
+uintptr
+vmemwrite(void *buf, uintptr len, uintptr va)
+{
+ VMemReq req;
+
+ memset(&req, 0, sizeof(VMemReq));
+ req.wr = 1;
+ req.buf = buf;
+ req.len = len;
+ req.va = va;
+ qlock(&req);
+ sendnotif(vmemread0, &req);
+ qlock(&req);
+ return req.rc;
+}
+
+int
+x86access(int seg, uintptr addr0, int asz, uvlong *val, int sz, int acc, TLB *tlb)
+{
+ int cpl;
+ static char *baser[] = {"csbase", "dsbase", "esbase", "fsbase", "gsbase", "ssbase"};
+ static char *limitr[] = {"cslimit", "dslimit", "eslimit", "fslimit", "gslimit", "sslimit"};
+ static char *permr[] = {"csperm", "dsperm", "esperm", "fsperm", "gsperm", "ssperm"};
+ u32int limit, perm;
+ uintptr addr, base, szmax;
+ int pperm, wp, i;
+ uintptr pa[8], pav;
+ uintptr l;
+ uchar *ptr;
+
+ switch(asz){
+ case 2: addr0 = (u16int)addr0; break;
+ case 4: addr0 = (u32int)addr0; break;
+ case 8: break;
+ default:
+ vmerror("invalid asz=%d in x86access", asz);
+ assert(0);
+ }
+ assert(seg < SEGMAX && (uint)acc <= ACCX);
+ addr = addr0;
+ if(tlb != nil && tlb->asz == asz && tlb->seg == seg && tlb->acc == acc && addr >= tlb->start && addr + sz >= addr && addr + sz < tlb->end){
+ ptr = tlb->base + addr;
+ goto fast;
+ }
+ if(sizeof(uintptr) == 8 && asz == 8){
+ if(seg == SEGFS || seg == SEGGS)
+ addr += rget(baser[seg]);
+ if((u16int)((addr >> 48) + 1) > 1){
+ gpf:
+ vmdebug("gpf");
+ postexc("#gp", 0);
+ return -1;
+ }
+ if((vlong)addr >= 0)
+ szmax = (1ULL<<48) - addr;
+ else
+ szmax = -addr;
+ }else{
+ limit = rget(limitr[seg]);
+ perm = rget(permr[seg]);
+ if((perm & 0xc) == 0x4){
+ if((u32int)(addr + sz - 1) < addr || addr <= limit)
+ goto limfault;
+ szmax = (u32int)-addr;
+ }else{
+ if((u64int)addr + sz - 1 >= limit){
+ limfault:
+ vmdebug("limit fault");
+ postexc(seg == SEGSS ? "#ss" : "#gp", 0);
+ return -1;
+ }
+ szmax = limit - addr + 1;
+ }
+ if((perm & 0x10080) != 0x80)
+ goto gpf;
+ switch(acc){
+ case ACCR: if((perm & 0xa) == 8) goto gpf; break;
+ case ACCW: if((perm & 0xa) != 2) goto gpf; break;
+ case ACCX: if((perm & 8) == 0) goto gpf; break;
+ }
+ base = rget(baser[seg]);
+ addr = (u32int)(addr + base);
+ }
+ cpl = rget("cs") & 3;
+ wp = (rget("cr0real") & 1<<16) != 0;
+ for(i = 0; i < sz; ){
+ l = translator()(addr+i, &pav, &pperm);
+ if(l == 0){
+ pf:
+ vmdebug("page fault @ %#p", addr+i);
+ postexc("#pf", pperm & 1 | (acc == ACCW) << 1 | (cpl == 3) << 2 | (acc == ACCX) << 4);
+ rset("cr2", addr+i);
+ return -1;
+ }
+ if((cpl == 3 || wp) && acc == ACCW && (pperm & 2) == 0)
+ goto pf;
+ if(cpl == 3 && (pperm & 4) == 0)
+ goto pf;
+ if(i == 0 && l < szmax) szmax = l;
+ while(i < sz && l-- > 0)
+ pa[i++] = pav++;
+ }
+ if(szmax >= sz){
+ ptr = gptr(pa[0], sz);
+ if(ptr == nil) goto slow;
+ if(tlb != nil){
+ l = gavail(ptr);
+ if(l < szmax) szmax = l;
+ tlb->asz = asz;
+ tlb->seg = seg;
+ tlb->acc = acc;
+ tlb->start = addr0;
+ tlb->end = addr0 + szmax;
+ tlb->base = ptr - addr0;
+ }
+ fast:
+ if(acc == ACCW)
+ switch(sz){
+ case 1: PUT8(ptr, 0, *val); break;
+ case 2: PUT16(ptr, 0, *val); break;
+ case 4: PUT32(ptr, 0, *val); break;
+ case 8: PUT64(ptr, 0, *val); break;
+ }
+ else
+ switch(sz){
+ case 1: *val = GET8(ptr, 0); break;
+ case 2: *val = GET16(ptr, 0); break;
+ case 4: *val = GET32(ptr, 0); break;
+ case 8: *val = GET64(ptr, 0); break;
+ }
+ }else{
+ slow:
+ if(acc != ACCW)
+ *val = 0;
+ for(i = 0; i < sz; i++){
+ ptr = gptr(pa[i], 1);
+ if(ptr == nil)
+ vmerror("x86access: access to unmapped address %#p", pa[i]);
+ else if(acc == ACCW)
+ *ptr = GET8(val, i);
+ else
+ PUT8(val, i, *ptr);
+ }
+ }
+ return 0;
+}