00001
00002
00003 #include "../../kernel.h"
00004 #include "../../proc.h"
00005 #include "../../vm.h"
00006
00007 #include <minix/type.h>
00008 #include <minix/syslib.h>
00009 #include <minix/cpufeature.h>
00010 #include <string.h>
00011
00012 #include <sys/vm_i386.h>
00013
00014 #include <minix/portio.h>
00015
00016 #include "proto.h"
00017 #include "../../proto.h"
00018 #include "../../proto.h"
00019 #include "../../debug.h"
00020
00021 #ifdef CONFIG_APIC
00022 #include "apic.h"
00023 #ifdef CONFIG_WATCHDOG
00024 #include "../../watchdog.h"
00025 #endif
00026 #endif
00027
00028 PRIVATE int psok = 0;
00029
00030 #define PROCPDEPTR(pr, pi) ((u32_t *) ((u8_t *) vm_pagedirs +\
00031 I386_PAGE_SIZE * pr->p_nr + \
00032 I386_VM_PT_ENT_SIZE * pi))
00033
00034 PUBLIC u8_t *vm_pagedirs = NULL;
00035
00036 #define NOPDE (-1)
00037 #define PDEMASK(n) (1L << (n))
00038 PUBLIC u32_t dirtypde;
00039 #define WANT_FREEPDES (sizeof(dirtypde)*8-5)
00040 PRIVATE int nfreepdes = 0, freepdes[WANT_FREEPDES], inusepde = NOPDE;
00041
00042 #define HASPT(procptr) ((procptr)->p_seg.p_cr3 != 0)
00043
00044 FORWARD _PROTOTYPE( u32_t phys_get32, (phys_bytes v) );
00045 FORWARD _PROTOTYPE( void vm_enable_paging, (void) );
00046 FORWARD _PROTOTYPE( void set_cr3, (void) );
00047
00048
00049
00050
00051 PUBLIC void vm_init(struct proc *newptproc)
00052 {
00053 if(vm_running)
00054 minix_panic("vm_init: vm_running", NO_NUM);
00055 vm_set_cr3(newptproc);
00056 level0(vm_enable_paging);
00057 vm_running = 1;
00058
00059 }
00060
00061 #define TYPEDIRECT 0
00062 #define TYPEPROCMAP 1
00063 #define TYPEPHYS 2
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078 #define CREATEPDE(PROC, PTR, LINADDR, REMAIN, BYTES, PDE, TYPE) { \
00079 u32_t *pdeptr = NULL; \
00080 int proc_pde_index; \
00081 proc_pde_index = I386_VM_PDE(LINADDR); \
00082 PDE = NOPDE; \
00083 if((PROC) && (((PROC) == ptproc) || !HASPT(PROC))) { \
00084 PTR = LINADDR; \
00085 TYPE = TYPEDIRECT; \
00086 } else { \
00087 int fp; \
00088 int mustinvl; \
00089 u32_t pdeval, *pdevalptr, mask; \
00090 phys_bytes offset; \
00091 vmassert(psok); \
00092 if(PROC) { \
00093 TYPE = TYPEPROCMAP; \
00094 vmassert(!iskernelp(PROC)); \
00095 vmassert(HASPT(PROC)); \
00096 pdeptr = PROCPDEPTR(PROC, proc_pde_index); \
00097 pdeval = *pdeptr; \
00098 } else { \
00099 TYPE = TYPEPHYS; \
00100 pdeval = (LINADDR & I386_VM_ADDR_MASK_4MB) | \
00101 I386_VM_BIGPAGE | I386_VM_PRESENT | \
00102 I386_VM_WRITE | I386_VM_USER; \
00103 } \
00104 for(fp = 0; fp < nfreepdes; fp++) { \
00105 int k = freepdes[fp]; \
00106 if(inusepde == k) \
00107 continue; \
00108 *PROCPDEPTR(ptproc, k) = 0; \
00109 PDE = k; \
00110 vmassert(k >= 0); \
00111 vmassert(k < sizeof(dirtypde)*8); \
00112 mask = PDEMASK(PDE); \
00113 if(dirtypde & mask) \
00114 continue; \
00115 break; \
00116 } \
00117 vmassert(PDE != NOPDE); \
00118 vmassert(mask); \
00119 if(dirtypde & mask) { \
00120 mustinvl = 1; \
00121 } else { \
00122 mustinvl = 0; \
00123 } \
00124 inusepde = PDE; \
00125 *PROCPDEPTR(ptproc, PDE) = pdeval; \
00126 offset = LINADDR & I386_VM_OFFSET_MASK_4MB; \
00127 PTR = I386_BIG_PAGE_SIZE*PDE + offset; \
00128 REMAIN = MIN(REMAIN, I386_BIG_PAGE_SIZE - offset); \
00129 if(1 || mustinvl) { \
00130 level0(reload_cr3); \
00131 } \
00132 } \
00133 }
00134
00135 #define DONEPDE(PDE) { \
00136 if(PDE != NOPDE) { \
00137 vmassert(PDE > 0); \
00138 vmassert(PDE < sizeof(dirtypde)*8); \
00139 dirtypde |= PDEMASK(PDE); \
00140 } \
00141 }
00142
00143 #define WIPEPDE(PDE) { \
00144 if(PDE != NOPDE) { \
00145 vmassert(PDE > 0); \
00146 vmassert(PDE < sizeof(dirtypde)*8); \
00147 *PROCPDEPTR(ptproc, PDE) = 0; \
00148 } \
00149 }
00150
00151
00152
00153
00154 PRIVATE int lin_lin_copy(struct proc *srcproc, vir_bytes srclinaddr,
00155 struct proc *dstproc, vir_bytes dstlinaddr, vir_bytes bytes)
00156 {
00157 u32_t addr;
00158 int procslot;
00159
00160 NOREC_ENTER(linlincopy);
00161
00162 vmassert(vm_running);
00163 vmassert(nfreepdes >= 3);
00164
00165 vmassert(ptproc);
00166 vmassert(proc_ptr);
00167 vmassert(read_cr3() == ptproc->p_seg.p_cr3);
00168
00169 procslot = ptproc->p_nr;
00170
00171 vmassert(procslot >= 0 && procslot < I386_VM_DIR_ENTRIES);
00172
00173 while(bytes > 0) {
00174 phys_bytes srcptr, dstptr;
00175 vir_bytes chunk = bytes;
00176 int srcpde, dstpde;
00177 int srctype, dsttype;
00178
00179
00180 inusepde = NOPDE;
00181 CREATEPDE(srcproc, srcptr, srclinaddr, chunk, bytes, srcpde, srctype);
00182 CREATEPDE(dstproc, dstptr, dstlinaddr, chunk, bytes, dstpde, dsttype);
00183
00184
00185 PHYS_COPY_CATCH(srcptr, dstptr, chunk, addr);
00186
00187 DONEPDE(srcpde);
00188 DONEPDE(dstpde);
00189
00190 if(addr) {
00191
00192
00193 if(addr >= srcptr && addr < (srcptr + chunk)) {
00194 WIPEPDE(srcpde);
00195 WIPEPDE(dstpde);
00196 NOREC_RETURN(linlincopy, EFAULT_SRC);
00197 }
00198 if(addr >= dstptr && addr < (dstptr + chunk)) {
00199 WIPEPDE(srcpde);
00200 WIPEPDE(dstpde);
00201 NOREC_RETURN(linlincopy, EFAULT_DST);
00202 }
00203
00204 minix_panic("lin_lin_copy fault out of range", NO_NUM);
00205
00206
00207 NOREC_RETURN(linlincopy, EFAULT);
00208 }
00209
00210 WIPEPDE(srcpde);
00211 WIPEPDE(dstpde);
00212
00213
00214 bytes -= chunk;
00215 srclinaddr += chunk;
00216 dstlinaddr += chunk;
00217 }
00218
00219 NOREC_RETURN(linlincopy, OK);
00220 }
00221
00222
00223 PRIVATE u32_t phys_get32(phys_bytes addr)
00224 {
00225 u32_t v;
00226 int r;
00227
00228 if(!vm_running) {
00229 phys_copy(addr, vir2phys(&v), sizeof(v));
00230 return v;
00231 }
00232
00233 if((r=lin_lin_copy(NULL, addr,
00234 proc_addr(SYSTEM), vir2phys(&v), sizeof(v))) != OK) {
00235 minix_panic("lin_lin_copy for phys_get32 failed", r);
00236 }
00237
00238 return v;
00239 }
00240
00241 PRIVATE u32_t vm_cr3;
00242
00243 PRIVATE void set_cr3()
00244 {
00245 write_cr3(vm_cr3);
00246 }
00247
00248 PUBLIC void vm_set_cr3(struct proc *newptproc)
00249 {
00250 int u = 0;
00251 if(!intr_disabled()) { lock; u = 1; }
00252 vm_cr3= newptproc->p_seg.p_cr3;
00253 if(vm_cr3) {
00254 level0(set_cr3);
00255 ptproc = newptproc;
00256 }
00257 if(u) { unlock; }
00258 }
00259
00260 PRIVATE char *cr0_str(u32_t e)
00261 {
00262 static char str[80];
00263 strcpy(str, "");
00264 #define FLAG(v) do { if(e & (v)) { strcat(str, #v " "); e &= ~v; } } while(0)
00265 FLAG(I386_CR0_PE);
00266 FLAG(I386_CR0_MP);
00267 FLAG(I386_CR0_EM);
00268 FLAG(I386_CR0_TS);
00269 FLAG(I386_CR0_ET);
00270 FLAG(I386_CR0_PG);
00271 FLAG(I386_CR0_WP);
00272 if(e) { strcat(str, " (++)"); }
00273 return str;
00274 }
00275
00276 PRIVATE char *cr4_str(u32_t e)
00277 {
00278 static char str[80];
00279 strcpy(str, "");
00280 FLAG(I386_CR4_VME);
00281 FLAG(I386_CR4_PVI);
00282 FLAG(I386_CR4_TSD);
00283 FLAG(I386_CR4_DE);
00284 FLAG(I386_CR4_PSE);
00285 FLAG(I386_CR4_PAE);
00286 FLAG(I386_CR4_MCE);
00287 FLAG(I386_CR4_PGE);
00288 if(e) { strcat(str, " (++)"); }
00289 return str;
00290 }
00291
00292 PRIVATE void vm_enable_paging(void)
00293 {
00294 u32_t cr0, cr4;
00295 int pgeok;
00296
00297 psok = _cpufeature(_CPUF_I386_PSE);
00298 pgeok = _cpufeature(_CPUF_I386_PGE);
00299
00300 cr0= read_cr0();
00301 cr4= read_cr4();
00302
00303
00304 write_cr0(cr0 & ~I386_CR0_PG);
00305 write_cr4(cr4 & ~(I386_CR4_PGE | I386_CR4_PSE));
00306
00307 cr0= read_cr0();
00308 cr4= read_cr4();
00309
00310
00311 if(psok)
00312 cr4 |= I386_CR4_PSE;
00313
00314 write_cr4(cr4);
00315
00316
00317 cr0 |= I386_CR0_PG;
00318 write_cr0(cr0 );
00319 cr0 |= I386_CR0_WP;
00320 write_cr0(cr0);
00321
00322
00323 if(pgeok)
00324 cr4 |= I386_CR4_PGE;
00325
00326 write_cr4(cr4);
00327 }
00328
00329 PUBLIC vir_bytes alloc_remote_segment(u32_t *selector,
00330 segframe_t *segments, int index, phys_bytes phys, vir_bytes size,
00331 int priv)
00332 {
00333 phys_bytes offset = 0;
00334
00335
00336
00337
00338
00339 if (size < BYTE_GRAN_MAX) {
00340 init_dataseg(&segments->p_ldt[EXTRA_LDT_INDEX+index],
00341 phys, size, priv);
00342 *selector = ((EXTRA_LDT_INDEX+index)*0x08) | (1*0x04) | priv;
00343 offset = 0;
00344 } else {
00345 init_dataseg(&segments->p_ldt[EXTRA_LDT_INDEX+index],
00346 phys & ~0xFFFF, 0, priv);
00347 *selector = ((EXTRA_LDT_INDEX+index)*0x08) | (1*0x04) | priv;
00348 offset = phys & 0xFFFF;
00349 }
00350
00351 return offset;
00352 }
00353
00354 PUBLIC phys_bytes umap_remote(struct proc* rp, int seg,
00355 vir_bytes vir_addr, vir_bytes bytes)
00356 {
00357
00358 struct far_mem *fm;
00359
00360 #if 0
00361 if(rp->p_misc_flags & MF_FULLVM) return 0;
00362 #endif
00363
00364 if (bytes <= 0) return( (phys_bytes) 0);
00365 if (seg < 0 || seg >= NR_REMOTE_SEGS) return( (phys_bytes) 0);
00366
00367 fm = &rp->p_priv->s_farmem[seg];
00368 if (! fm->in_use) return( (phys_bytes) 0);
00369 if (vir_addr + bytes > fm->mem_len) return( (phys_bytes) 0);
00370
00371 return(fm->mem_phys + (phys_bytes) vir_addr);
00372 }
00373
00374
00375
00376
00377 PUBLIC phys_bytes umap_local(rp, seg, vir_addr, bytes)
00378 register struct proc *rp;
00379 int seg;
00380 vir_bytes vir_addr;
00381 vir_bytes bytes;
00382 {
00383
00384 vir_clicks vc;
00385 phys_bytes pa;
00386 phys_bytes seg_base;
00387
00388 if(seg != T && seg != D && seg != S)
00389 minix_panic("umap_local: wrong seg", seg);
00390
00391 if (bytes <= 0) return( (phys_bytes) 0);
00392 if (vir_addr + bytes <= vir_addr) return 0;
00393 vc = (vir_addr + bytes - 1) >> CLICK_SHIFT;
00394
00395 if (seg != T)
00396 seg = (vc < rp->p_memmap[D].mem_vir + rp->p_memmap[D].mem_len ? D : S);
00397 else if (rp->p_memmap[T].mem_len == 0)
00398 seg = D;
00399
00400 if ((vir_addr>>CLICK_SHIFT) >= rp->p_memmap[seg].mem_vir +
00401 rp->p_memmap[seg].mem_len) return( (phys_bytes) 0 );
00402
00403 if (vc >= rp->p_memmap[seg].mem_vir +
00404 rp->p_memmap[seg].mem_len) return( (phys_bytes) 0 );
00405
00406 seg_base = (phys_bytes) rp->p_memmap[seg].mem_phys;
00407 seg_base = seg_base << CLICK_SHIFT;
00408 pa = (phys_bytes) vir_addr;
00409 pa -= rp->p_memmap[seg].mem_vir << CLICK_SHIFT;
00410 return(seg_base + pa);
00411 }
00412
00413
00414
00415
00416 PUBLIC phys_bytes umap_virtual(rp, seg, vir_addr, bytes)
00417 register struct proc *rp;
00418 int seg;
00419 vir_bytes vir_addr;
00420 vir_bytes bytes;
00421 {
00422 vir_bytes linear;
00423 u32_t phys = 0;
00424
00425 if(seg == MEM_GRANT) {
00426 return umap_grant(rp, vir_addr, bytes);
00427 }
00428
00429 if(!(linear = umap_local(rp, seg, vir_addr, bytes))) {
00430 kprintf("SYSTEM:umap_virtual: umap_local failed\n");
00431 phys = 0;
00432 } else {
00433 if(vm_lookup(rp, linear, &phys, NULL) != OK) {
00434 kprintf("SYSTEM:umap_virtual: vm_lookup of %s: seg 0x%lx: 0x%lx failed\n", rp->p_name, seg, vir_addr);
00435 phys = 0;
00436 }
00437 if(phys == 0)
00438 minix_panic("vm_lookup returned phys", phys);
00439 }
00440
00441
00442 if(phys == 0) {
00443 kprintf("SYSTEM:umap_virtual: lookup failed\n");
00444 return 0;
00445 }
00446
00447
00448
00449
00450 if(bytes > 0 && !vm_contiguous(rp, linear, bytes)) {
00451 kprintf("umap_virtual: %s: %d at 0x%lx (vir 0x%lx) not contiguous\n",
00452 rp->p_name, bytes, linear, vir_addr);
00453 return 0;
00454 }
00455
00456
00457
00458
00459 vmassert(phys);
00460
00461 return phys;
00462 }
00463
00464
00465
00466
00467
00468 PUBLIC int vm_lookup(struct proc *proc, vir_bytes virtual, vir_bytes *physical, u32_t *ptent)
00469 {
00470 u32_t *root, *pt;
00471 int pde, pte;
00472 u32_t pde_v, pte_v;
00473 NOREC_ENTER(vmlookup);
00474
00475 vmassert(proc);
00476 vmassert(physical);
00477 vmassert(!isemptyp(proc));
00478
00479 if(!HASPT(proc)) {
00480 *physical = virtual;
00481 NOREC_RETURN(vmlookup, OK);
00482 }
00483
00484
00485 root = (u32_t *) proc->p_seg.p_cr3;
00486 vmassert(!((u32_t) root % I386_PAGE_SIZE));
00487 pde = I386_VM_PDE(virtual);
00488 vmassert(pde >= 0 && pde < I386_VM_DIR_ENTRIES);
00489 pde_v = phys_get32((u32_t) (root + pde));
00490
00491 if(!(pde_v & I386_VM_PRESENT)) {
00492 NOREC_RETURN(vmlookup, EFAULT);
00493 }
00494
00495
00496 if(pde_v & I386_VM_BIGPAGE) {
00497 *physical = pde_v & I386_VM_ADDR_MASK_4MB;
00498 if(ptent) *ptent = pde_v;
00499 *physical += virtual & I386_VM_OFFSET_MASK_4MB;
00500 } else {
00501
00502 pt = (u32_t *) I386_VM_PFA(pde_v);
00503 vmassert(!((u32_t) pt % I386_PAGE_SIZE));
00504 pte = I386_VM_PTE(virtual);
00505 vmassert(pte >= 0 && pte < I386_VM_PT_ENTRIES);
00506 pte_v = phys_get32((u32_t) (pt + pte));
00507 if(!(pte_v & I386_VM_PRESENT)) {
00508 NOREC_RETURN(vmlookup, EFAULT);
00509 }
00510
00511 if(ptent) *ptent = pte_v;
00512
00513
00514 *physical = I386_VM_PFA(pte_v);
00515 *physical += virtual % I386_PAGE_SIZE;
00516 }
00517
00518 NOREC_RETURN(vmlookup, OK);
00519 }
00520
00521
00522
00523
00524 PUBLIC int vm_contiguous(struct proc *targetproc, u32_t vir_buf, size_t bytes)
00525 {
00526 int first = 1, r, boundaries = 0;
00527 u32_t prev_phys, po;
00528 u32_t prev_vir;
00529
00530 vmassert(targetproc);
00531 vmassert(bytes > 0);
00532
00533 if(!HASPT(targetproc))
00534 return 1;
00535
00536
00537 po = vir_buf % I386_PAGE_SIZE;
00538 if(po > 0) {
00539 bytes += po;
00540 vir_buf -= po;
00541 }
00542 po = (vir_buf + bytes) % I386_PAGE_SIZE;
00543 if(po > 0)
00544 bytes += I386_PAGE_SIZE - po;
00545
00546
00547 while(bytes > 0) {
00548 u32_t phys;
00549
00550 if((r=vm_lookup(targetproc, vir_buf, &phys, NULL)) != OK) {
00551 kprintf("vm_contiguous: vm_lookup failed, %d\n", r);
00552 kprintf("kernel stack: ");
00553 util_stacktrace();
00554 return 0;
00555 }
00556
00557 if(!first) {
00558 if(prev_phys+I386_PAGE_SIZE != phys) {
00559 kprintf("vm_contiguous: no (0x%lx, 0x%lx)\n",
00560 prev_phys, phys);
00561 kprintf("kernel stack: ");
00562 util_stacktrace();
00563 return 0;
00564 }
00565 }
00566
00567 first = 0;
00568
00569 prev_phys = phys;
00570 prev_vir = vir_buf;
00571 vir_buf += I386_PAGE_SIZE;
00572 bytes -= I386_PAGE_SIZE;
00573 boundaries++;
00574 }
00575
00576 return 1;
00577 }
00578
00579
00580
00581
00582 PRIVATE int vm_suspend(struct proc *caller, struct proc *target,
00583 vir_bytes linaddr, vir_bytes len, int wrflag, int type)
00584 {
00585
00586
00587
00588 vmassert(!RTS_ISSET(caller, RTS_VMREQUEST));
00589 vmassert(!RTS_ISSET(target, RTS_VMREQUEST));
00590
00591 RTS_LOCK_SET(caller, RTS_VMREQUEST);
00592
00593 #if DEBUG_VMASSERT
00594 caller->p_vmrequest.stacktrace[0] = '\0';
00595 util_stacktrace_strcat(caller->p_vmrequest.stacktrace);
00596 #endif
00597
00598 caller->p_vmrequest.req_type = VMPTYPE_CHECK;
00599 caller->p_vmrequest.target = target->p_endpoint;
00600 caller->p_vmrequest.params.check.start = linaddr;
00601 caller->p_vmrequest.params.check.length = len;
00602 caller->p_vmrequest.params.check.writeflag = 1;
00603 caller->p_vmrequest.type = type;
00604
00605
00606 if(!(caller->p_vmrequest.nextrequestor = vmrequest))
00607 mini_notify(proc_addr(SYSTEM), VM_PROC_NR);
00608 vmrequest = caller;
00609 }
00610
00611
00612
00613
00614 int delivermsg(struct proc *rp)
00615 {
00616 phys_bytes addr;
00617 int r;
00618 NOREC_ENTER(deliver);
00619
00620 vmassert(rp->p_misc_flags & MF_DELIVERMSG);
00621 vmassert(rp->p_delivermsg.m_source != NONE);
00622
00623 vmassert(rp->p_delivermsg_lin);
00624 #if DEBUG_VMASSERT
00625 if(rp->p_delivermsg_lin !=
00626 umap_local(rp, D, rp->p_delivermsg_vir, sizeof(message))) {
00627 printf("vir: 0x%lx lin was: 0x%lx umap now: 0x%lx\n",
00628 rp->p_delivermsg_vir, rp->p_delivermsg_lin,
00629 umap_local(rp, D, rp->p_delivermsg_vir, sizeof(message)));
00630 minix_panic("that's wrong", NO_NUM);
00631 }
00632
00633 #endif
00634
00635 vm_set_cr3(rp);
00636
00637 PHYS_COPY_CATCH(vir2phys(&rp->p_delivermsg),
00638 rp->p_delivermsg_lin, sizeof(message), addr);
00639
00640 if(addr) {
00641 vm_suspend(rp, rp, rp->p_delivermsg_lin, sizeof(message), 1,
00642 VMSTYPE_DELIVERMSG);
00643 r = VMSUSPEND;
00644 } else {
00645 #if DEBUG_VMASSERT
00646 rp->p_delivermsg.m_source = NONE;
00647 rp->p_delivermsg_lin = 0;
00648 #endif
00649 rp->p_misc_flags &= ~MF_DELIVERMSG;
00650 r = OK;
00651 }
00652
00653 NOREC_RETURN(deliver, r);
00654 }
00655
00656 PRIVATE char *flagstr(u32_t e, int dir)
00657 {
00658 static char str[80];
00659 strcpy(str, "");
00660 FLAG(I386_VM_PRESENT);
00661 FLAG(I386_VM_WRITE);
00662 FLAG(I386_VM_USER);
00663 FLAG(I386_VM_PWT);
00664 FLAG(I386_VM_PCD);
00665 FLAG(I386_VM_GLOBAL);
00666 if(dir)
00667 FLAG(I386_VM_BIGPAGE);
00668 else
00669 FLAG(I386_VM_DIRTY);
00670 return str;
00671 }
00672
00673 PRIVATE void vm_pt_print(u32_t *pagetable, u32_t v)
00674 {
00675 int pte;
00676 int col = 0;
00677
00678 vmassert(!((u32_t) pagetable % I386_PAGE_SIZE));
00679
00680 for(pte = 0; pte < I386_VM_PT_ENTRIES; pte++) {
00681 u32_t pte_v, pfa;
00682 pte_v = phys_get32((u32_t) (pagetable + pte));
00683 if(!(pte_v & I386_VM_PRESENT))
00684 continue;
00685 pfa = I386_VM_PFA(pte_v);
00686 kprintf("%4d:%08lx:%08lx %2s ",
00687 pte, v + I386_PAGE_SIZE*pte, pfa,
00688 (pte_v & I386_VM_WRITE) ? "rw":"RO");
00689 col++;
00690 if(col == 3) { kprintf("\n"); col = 0; }
00691 }
00692 if(col > 0) kprintf("\n");
00693
00694 return;
00695 }
00696
00697 PRIVATE void vm_print(u32_t *root)
00698 {
00699 int pde;
00700
00701 vmassert(!((u32_t) root % I386_PAGE_SIZE));
00702
00703 printf("page table 0x%lx:\n", root);
00704
00705 for(pde = 0; pde < I386_VM_DIR_ENTRIES; pde++) {
00706 u32_t pde_v;
00707 u32_t *pte_a;
00708 pde_v = phys_get32((u32_t) (root + pde));
00709 if(!(pde_v & I386_VM_PRESENT))
00710 continue;
00711 if(pde_v & I386_VM_BIGPAGE) {
00712 kprintf("%4d: 0x%lx, flags %s\n",
00713 pde, I386_VM_PFA(pde_v), flagstr(pde_v, 1));
00714 } else {
00715 pte_a = (u32_t *) I386_VM_PFA(pde_v);
00716 kprintf("%4d: pt %08lx %s\n",
00717 pde, pte_a, flagstr(pde_v, 1));
00718 vm_pt_print(pte_a, pde * I386_VM_PT_ENTRIES * I386_PAGE_SIZE);
00719 kprintf("\n");
00720 }
00721 }
00722
00723
00724 return;
00725 }
00726
00727 u32_t thecr3;
00728
00729 u32_t read_cr3(void)
00730 {
00731 level0(getcr3val);
00732 return thecr3;
00733 }
00734
00735
00736
00737
00738
00739 int vm_phys_memset(phys_bytes ph, u8_t c, phys_bytes bytes)
00740 {
00741 u32_t p;
00742 NOREC_ENTER(physmemset);
00743
00744 p = c | (c << 8) | (c << 16) | (c << 24);
00745
00746 if(!vm_running) {
00747 phys_memset(ph, p, bytes);
00748 NOREC_RETURN(physmemset, OK);
00749 }
00750
00751 vmassert(nfreepdes >= 3);
00752
00753
00754
00755
00756 while(bytes > 0) {
00757 int pde, t;
00758 vir_bytes chunk = (vir_bytes) bytes;
00759 phys_bytes ptr;
00760 inusepde = NOPDE;
00761 CREATEPDE(((struct proc *) NULL), ptr, ph, chunk, bytes, pde, t);
00762
00763
00764
00765 phys_memset(ptr, p, chunk);
00766 DONEPDE(pde);
00767 bytes -= chunk;
00768 ph += chunk;
00769 }
00770
00771
00772 NOREC_RETURN(physmemset, OK);
00773 }
00774
00775
00776
00777
00778 PUBLIC int virtual_copy_f(src_addr, dst_addr, bytes, vmcheck)
00779 struct vir_addr *src_addr;
00780 struct vir_addr *dst_addr;
00781 vir_bytes bytes;
00782 int vmcheck;
00783 {
00784
00785
00786
00787 struct vir_addr *vir_addr[2];
00788 phys_bytes phys_addr[2];
00789 int seg_index;
00790 int i;
00791 struct proc *procs[2];
00792 NOREC_ENTER(virtualcopy);
00793
00794
00795 if (bytes <= 0) return(EDOM);
00796
00797
00798 vir_addr[_SRC_] = src_addr;
00799 vir_addr[_DST_] = dst_addr;
00800
00801 for (i=_SRC_; i<=_DST_; i++) {
00802 int proc_nr, type;
00803 struct proc *p;
00804
00805 type = vir_addr[i]->segment & SEGMENT_TYPE;
00806 if((type != PHYS_SEG && type != BIOS_SEG) &&
00807 isokendpt(vir_addr[i]->proc_nr_e, &proc_nr))
00808 p = proc_addr(proc_nr);
00809 else
00810 p = NULL;
00811
00812 procs[i] = p;
00813
00814
00815 switch(type) {
00816 case LOCAL_SEG:
00817 case LOCAL_VM_SEG:
00818 if(!p) {
00819 NOREC_RETURN(virtualcopy, EDEADSRCDST);
00820 }
00821 seg_index = vir_addr[i]->segment & SEGMENT_INDEX;
00822 if(type == LOCAL_SEG)
00823 phys_addr[i] = umap_local(p, seg_index, vir_addr[i]->offset,
00824 bytes);
00825 else
00826 phys_addr[i] = umap_virtual(p, seg_index, vir_addr[i]->offset,
00827 bytes);
00828 if(phys_addr[i] == 0) {
00829 kprintf("virtual_copy: map 0x%x failed for %s seg %d, "
00830 "offset %lx, len %d, i %d\n",
00831 type, p->p_name, seg_index, vir_addr[i]->offset,
00832 bytes, i);
00833 }
00834 break;
00835 case REMOTE_SEG:
00836 if(!p) {
00837 NOREC_RETURN(virtualcopy, EDEADSRCDST);
00838 }
00839 seg_index = vir_addr[i]->segment & SEGMENT_INDEX;
00840 phys_addr[i] = umap_remote(p, seg_index, vir_addr[i]->offset, bytes);
00841 break;
00842 #if _MINIX_CHIP == _CHIP_INTEL
00843 case BIOS_SEG:
00844 phys_addr[i] = umap_bios(vir_addr[i]->offset, bytes );
00845 break;
00846 #endif
00847 case PHYS_SEG:
00848 phys_addr[i] = vir_addr[i]->offset;
00849 break;
00850 default:
00851 kprintf("virtual_copy: strange type 0x%x\n", type);
00852 NOREC_RETURN(virtualcopy, EINVAL);
00853 }
00854
00855
00856 if (phys_addr[i] <= 0 && vir_addr[i]->segment != PHYS_SEG) {
00857 kprintf("virtual_copy EFAULT\n");
00858 NOREC_RETURN(virtualcopy, EFAULT);
00859 }
00860 }
00861
00862 if(vm_running) {
00863 int r;
00864 struct proc *caller;
00865
00866 caller = proc_addr(who_p);
00867
00868 if(RTS_ISSET(caller, RTS_VMREQUEST)) {
00869 vmassert(caller->p_vmrequest.vmresult != VMSUSPEND);
00870 RTS_LOCK_UNSET(caller, RTS_VMREQUEST);
00871 if(caller->p_vmrequest.vmresult != OK) {
00872 #if DEBUG_VMASSERT
00873 printf("virtual_copy: returning VM error %d\n",
00874 caller->p_vmrequest.vmresult);
00875 #endif
00876 NOREC_RETURN(virtualcopy, caller->p_vmrequest.vmresult);
00877 }
00878 }
00879
00880 if((r=lin_lin_copy(procs[_SRC_], phys_addr[_SRC_],
00881 procs[_DST_], phys_addr[_DST_], bytes)) != OK) {
00882 struct proc *target;
00883 int wr;
00884 phys_bytes lin;
00885 if(r != EFAULT_SRC && r != EFAULT_DST)
00886 minix_panic("lin_lin_copy failed", r);
00887 if(!vmcheck) {
00888 NOREC_RETURN(virtualcopy, r);
00889 }
00890
00891 vmassert(procs[_SRC_] && procs[_DST_]);
00892
00893 if(r == EFAULT_SRC) {
00894 lin = phys_addr[_SRC_];
00895 target = procs[_SRC_];
00896 wr = 0;
00897 } else if(r == EFAULT_DST) {
00898 lin = phys_addr[_DST_];
00899 target = procs[_DST_];
00900 wr = 1;
00901 } else {
00902 minix_panic("r strange", r);
00903 }
00904
00905 #if 0
00906 printf("virtual_copy: suspending caller %d / %s, target %d / %s\n",
00907 caller->p_endpoint, caller->p_name,
00908 target->p_endpoint, target->p_name);
00909 #endif
00910
00911 vmassert(proc_ptr->p_endpoint == SYSTEM);
00912 vm_suspend(caller, target, lin, bytes, wr, VMSTYPE_KERNELCALL);
00913
00914 NOREC_RETURN(virtualcopy, VMSUSPEND);
00915 }
00916
00917 NOREC_RETURN(virtualcopy, OK);
00918 }
00919
00920 vmassert(!vm_running);
00921
00922
00923 #define NOPT(p) (!(p) || !HASPT(p))
00924 if(!NOPT(procs[_SRC_])) {
00925 kprintf("ignoring page table src: %s / %d at 0x%lx\n",
00926 procs[_SRC_]->p_name, procs[_SRC_]->p_endpoint, procs[_SRC_]->p_seg.p_cr3);
00927 }
00928 if(!NOPT(procs[_DST_])) {
00929 kprintf("ignoring page table dst: %s / %d at 0x%lx\n",
00930 procs[_DST_]->p_name, procs[_DST_]->p_endpoint,
00931 procs[_DST_]->p_seg.p_cr3);
00932 }
00933
00934
00935 if(phys_copy(phys_addr[_SRC_], phys_addr[_DST_], (phys_bytes) bytes))
00936 NOREC_RETURN(virtualcopy, EFAULT);
00937
00938 NOREC_RETURN(virtualcopy, OK);
00939 }
00940
00941
00942
00943
00944 PUBLIC int data_copy(
00945 endpoint_t from_proc, vir_bytes from_addr,
00946 endpoint_t to_proc, vir_bytes to_addr,
00947 size_t bytes)
00948 {
00949 struct vir_addr src, dst;
00950
00951 src.segment = dst.segment = D;
00952 src.offset = from_addr;
00953 dst.offset = to_addr;
00954 src.proc_nr_e = from_proc;
00955 dst.proc_nr_e = to_proc;
00956
00957 return virtual_copy(&src, &dst, bytes);
00958 }
00959
00960
00961
00962
00963 PUBLIC int data_copy_vmcheck(
00964 endpoint_t from_proc, vir_bytes from_addr,
00965 endpoint_t to_proc, vir_bytes to_addr,
00966 size_t bytes)
00967 {
00968 struct vir_addr src, dst;
00969
00970 src.segment = dst.segment = D;
00971 src.offset = from_addr;
00972 dst.offset = to_addr;
00973 src.proc_nr_e = from_proc;
00974 dst.proc_nr_e = to_proc;
00975
00976 return virtual_copy_vmcheck(&src, &dst, bytes);
00977 }
00978
00979
00980
00981
00982 PUBLIC int arch_pre_exec(struct proc *pr, u32_t ip, u32_t sp)
00983 {
00984
00985 memset(pr->p_seg.p_ldt + EXTRA_LDT_INDEX, 0,
00986 sizeof(pr->p_seg.p_ldt[0]) * (LDT_SIZE - EXTRA_LDT_INDEX));
00987 pr->p_reg.pc = ip;
00988 pr->p_reg.sp = sp;
00989 }
00990
00991
00992
00993
00994 PUBLIC int arch_umap(struct proc *pr, vir_bytes offset, vir_bytes count,
00995 int seg, phys_bytes *addr)
00996 {
00997 switch(seg) {
00998 case BIOS_SEG:
00999 *addr = umap_bios(offset, count);
01000 return OK;
01001 }
01002
01003
01004
01005
01006
01007 return EINVAL;
01008 }
01009
01010
01011 void i386_freepde(int pde)
01012 {
01013 if(nfreepdes >= WANT_FREEPDES)
01014 return;
01015 freepdes[nfreepdes++] = pde;
01016 }
01017
01018 PUBLIC arch_phys_map(int index, phys_bytes *addr, phys_bytes *len, int *flags)
01019 {
01020 #ifdef CONFIG_APIC
01021
01022 if (index == 0 && lapic_addr) {
01023 *addr = vir2phys(lapic_addr);
01024 *len = 4 << 10 ;
01025 *flags = VMMF_UNCACHED;
01026 return OK;
01027 }
01028 return EINVAL;
01029 #else
01030
01031 return EINVAL;
01032 #endif
01033 }
01034
01035 PUBLIC int arch_phys_map_reply(int index, vir_bytes addr)
01036 {
01037 #ifdef CONFIG_APIC
01038
01039 if (index == 0 && lapic_addr) {
01040 lapic_addr_vaddr = addr;
01041 }
01042 #endif
01043 return OK;
01044 }
01045
01046 PUBLIC int arch_enable_paging(void)
01047 {
01048 #ifdef CONFIG_APIC
01049
01050 if (lapic_addr) {
01051 lapic_addr = lapic_addr_vaddr;
01052 lapic_eoi_addr = LAPIC_EOI;
01053 }
01054 #endif
01055 #ifdef CONFIG_WATCHDOG
01056
01057
01058
01059
01060
01061
01062 level0(i386_watchdog_start);
01063 #endif
01064
01065 return OK;
01066 }