home *** CD-ROM | disk | FTP | other *** search
/ PC Extra Super CD 1998 January / PCPLUS131.iso / DJGPP / V2MISC / CSDPMI3S.ZIP / SRC / CWSDPMI / PAGING.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-28  |  15.0 KB  |  541 lines

  1. /* Copyright (C) 1995,1996 CW Sandmann (sandmann@clio.rice.edu) 1206 Braelinn, Sugarland, TX 77479
  2. ** Copyright (C) 1993 DJ Delorie, 24 Kirsten Ave, Rochester NH 03867-2954
  3. **
  4. ** This file is distributed under the terms listed in the document
  5. ** "copying.cws", available from CW Sandmann at the address above.
  6. ** A copy of "copying.cws" should accompany this file; if not, a copy
  7. ** should be available from where this file was obtained.  This file
  8. ** may not be distributed without a verbatim copy of "copying.cws".
  9. **
  10. ** This file is distributed WITHOUT ANY WARRANTY; without even the implied
  11. ** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. */
  13. /* Modified for VCPI Implement by Y.Shibata Aug 5th 1991 */
  14. /* NUR paging algorithm by rcharif@math.utexas.edu */
  15.  
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <dos.h>
  19. #include <string.h>
  20.  
  21. #include "gotypes.h"
  22. #include "paging.h"
  23. #include "tss.h"
  24. #include "idt.h"
  25. #include "gdt.h"
  26. #include "valloc.h"
  27. #include "dalloc.h"
  28. #include "utils.h"
  29. #include "vcpi.h"
  30. #include "exphdlr.h"
  31. #include "control.h"
  32. #include "mswitch.h"
  33.  
  34. #ifdef VERBOSE
  35. static FILE *dfp = NULL;
  36. #endif
  37.  
  38. #define DOS_PAGE 256        /*  1MB / 4KB = 256 Pages  */
  39.  
  40. struct {
  41.   word16 limit;
  42.   word32 base;
  43. } gdt_phys, idt_phys;
  44.  
  45. static CLIENT client;        /*  VCPI Change Mode Structure  */
  46. word32 abs_client;        /*  _DS * 16L + &client         */
  47. far32 vcpi_entry;
  48.  
  49. AREAS *firstarea = NULL;
  50.  
  51. static word32 far *pd = 0;
  52. static word8 pd_seg[1024];
  53. word32 far *vcpi_pt = 0;
  54. static word8 paging_buffer[4096];
  55.  
  56. word32 ptr2linear(void far *ptr)
  57. {
  58.   return (word32)FP_SEG(ptr) * 16L + (word32)FP_OFF(ptr);
  59. }
  60.  
  61. static word32 far2pte(void far *ptr, word16 flags)
  62. {
  63.   return (vcpi_pt[(int)(((word32)ptr) >> 24)] & 0xfffff000L) | flags;
  64. }
  65.  
  66. static word32 pn2pte(unsigned pn, word16 flags)
  67. {
  68.   return (vcpi_pt[pn] & 0xfffff000L) | flags;
  69. }
  70.  
  71. /*  VCPI Get Interface  */
  72. static void link_vcpi(word32 far *dir, word32 far *table)
  73. {
  74.   vcpi_entry.selector = g_vcpicode * 8;
  75.   vcpi_entry.offset32 = get_interface(table,&gdt[g_vcpicode]);
  76.   client.page_table   = far2pte(dir, 0);
  77.   client.gdt_address  = ptr2linear(&gdt_phys);
  78.   client.idt_address  = ptr2linear(&idt_phys);
  79.   client.ldt_selector = g_ldt * 8;
  80.   client.tss_selector = g_ctss * 8;
  81.   client.entry_eip    = (word16)protect_entry;
  82.   client.entry_cs     = g_rcode * 8;
  83.  
  84.   abs_client = ptr2linear(&client);
  85. }
  86.  
  87. word32 reserved;        /* Pages */
  88.  
  89. void paging_setup(void)
  90. {
  91.   word32 far *pt;
  92.   int i;
  93.  
  94. #ifdef VERBOSE
  95.   dfp = fopen("paging.cws","w");
  96. #endif
  97.  
  98.   reserved = 0;
  99.   
  100.   while(firstarea) {
  101.     free(firstarea);
  102.     firstarea = firstarea->next;
  103.   }
  104.  
  105.   pd = (word32 far *)((long)valloc_640() << 24);
  106.   vcpi_pt = pt = (word32 far *)((long)valloc_640() << 24);
  107.   for (i=0; i<1024; i++) {
  108.     pd[i] = 0;
  109.     pd_seg[i] = 0;
  110.   }
  111.   
  112.   if (vcpi_installed) {
  113.     link_vcpi(pd,pt);           /*  Get VCPI Page Table  */
  114. /*    for (i=0; i<1024; i++)
  115.       if ((word16)pt[i] & PT_P)
  116.         (word16)pt[i] |= PT_I; */
  117.   } else {
  118.     for (i=0; i < DOS_PAGE; i++)
  119.       pt[i] = ((unsigned long)i<<12) | PT_P | PT_U | PT_W /*| PT_I*/;
  120.     for (; i<1024; i++)
  121.       pt[i] = 0;
  122.   }
  123.  
  124.   pd[0] = far2pte(pt, PT_P | PT_U | PT_W | PT_I);  /* map 1:1 1st Mb */
  125.   pd_seg[0] = (word32)pt >> 24;
  126.   
  127.   gdt_phys.limit = gdt[g_gdt].lim0;
  128.   gdt_phys.base = ptr2linear(&gdt);
  129.   idt_phys.limit = gdt[g_idt].lim0;
  130.   idt_phys.base = ptr2linear(&idt);
  131.   
  132.   c_tss.tss_cr3 = 
  133.   o_tss.tss_cr3 = 
  134.   i_tss.tss_cr3 = 
  135.   f_tss.tss_cr3 = 
  136.   a_tss.tss_cr3 = far2pte(pd, 0);
  137. }
  138.  
  139. int cant_ask_for(int32 amount)        /* amount is in bytes */
  140. {
  141.   word32 max;
  142.   
  143.   amount >>= 12;
  144.   if (amount <= 0) {
  145.     reserved += amount;
  146.     return 0;
  147.   }
  148.   amount += reserved;
  149.   max = valloc_max_size();
  150.  
  151.   if (amount >= max)
  152.     max += dalloc_max_size();        /* Slow, hits disk, avoid if can */
  153.  
  154.   if (amount < max) {
  155.     reserved = amount;
  156.     return 0;
  157.   }
  158.   return 1;
  159. }
  160.  
  161. int page_is_valid(word32 vaddr)
  162. {
  163.   AREAS *area = firstarea;
  164.   while (area) {
  165.     if ((vaddr <= area->last_addr) && (vaddr >= area->first_addr))
  166.       return 1;
  167.     area = area->next;
  168.   }
  169.   return 0;
  170. }
  171.  
  172. static word32 far *getpte(word32 vaddr)
  173. {
  174.   word32 far *pt;
  175.   int pdi, pti, pn;
  176.  
  177.   pdi = (word16)(vaddr >> 22) & 0x3ff;
  178.   if (!((word16)pd[pdi] & PT_P)) {  /* put in an empty page table if required */
  179.     pn = valloc_640();
  180.     pt = (word32 far *)((word32)pn << 24);
  181.     if ((word16)pd[pdi] & PT_I) {
  182.       da_pn dblock;
  183. #ifdef VERBOSE
  184.       fprintf(dfp," swap_pd"); fflush(dfp);
  185. #endif
  186.       dblock = (da_pn)(pd[pdi] >> 12);
  187.       dread(paging_buffer, dblock);
  188.       dfree(dblock);
  189.       movedata(_DS, FP_OFF(paging_buffer), FP_SEG(pt), FP_OFF(pt), 4096);
  190.       pd[pdi] = pn2pte(pn, PT_P | PT_U | PT_W | PT_I | PT_S);
  191.       pd_seg[pdi] = pn;
  192.     } else {
  193. #ifdef VERBOSE
  194.       fprintf(dfp, " new_pd"); fflush(dfp);
  195. #endif
  196.       pd[pdi] = pn2pte(pn, PT_P | PT_U | PT_W | PT_I | PT_S);
  197.       pd_seg[pdi] = pn;
  198.       for (pti=0; pti<1024; pti++)
  199.         pt[pti] = PT_U | PT_W | PT_S;
  200.     }
  201.   }
  202.   else
  203.     pt = (word32 far *)((word32)(pd_seg[pdi]) << 24);
  204.   pti = (word16)(vaddr >> 12) & 0x3ff;
  205.   return &pt[pti];
  206. }
  207.  
  208. int page_in(void)
  209. {
  210.   word32 far *pte;
  211.   word32 vaddr;
  212.   int pn;
  213.   da_pn dblock;
  214.  
  215. #ifdef VERBOSE
  216.   fprintf(dfp, "Paging (err: 0x%x) in vaddr %#010lx -", (word16)tss_ptr->tss_error&15, tss_ptr->tss_cr2); fflush(dfp);
  217. #endif
  218.   vaddr = tss_ptr->tss_cr2;
  219.   if (!page_is_valid(vaddr)) {
  220. #ifdef VERBOSE
  221.     fprintf(dfp, "invalid\n"); fflush(dfp);
  222. #endif
  223.     return 1;
  224.   }
  225.  
  226.   if((word8)tss_ptr->tss_error & 1) {
  227. #ifdef VERBOSE
  228.     fprintf(dfp, "protection\n"); fflush(dfp);
  229. #endif
  230.     return 1;        /* Protection violation, we don't handle */
  231.   }
  232.  
  233.   (word16)vaddr &= 0xF000;  /* points to beginning of page */
  234.  
  235.   pte = getpte(vaddr);
  236.  
  237.   if (!((word16)*pte & PT_P)) {
  238.     int accdirty;
  239.     TSS *old_util_tss;
  240.  
  241.     if(!((word16)*pte & PT_S)) {
  242. #ifdef VERBOSE
  243.       fprintf(dfp, "non-committed\n"); fflush(dfp);
  244. #endif
  245.       return 1;                    /* Non-committed page */
  246.     }
  247.  
  248.     old_util_tss = utils_tss;
  249.     utils_tss = &f_tss;
  250.  
  251.     dblock = (da_pn)(*pte >> 12);
  252.     pn = valloc();
  253.     if(pn == -1) {
  254. #ifdef VERBOSE
  255.      fprintf(dfp, "valloc failed\n"); fflush(dfp);
  256. #endif
  257.       utils_tss = old_util_tss;
  258.       return 1;
  259.     }
  260.     accdirty = (word16)*pte & (PT_A | PT_D);    /* Save old access/dirty bits */
  261.     *pte &= 0xfffL & ~(word32)(PT_A | PT_D);    /* Clear dblock and bits */
  262.     *pte |= ((word32)pn << 12) | PT_P;    /* Set present and virt add */
  263.  
  264.     if ((word16)*pte & PT_I) {
  265. #ifdef VERBOSE
  266.       fprintf(dfp, " swap"); fflush(dfp);
  267. #endif
  268.       dread(paging_buffer, dblock);
  269.       dfree(dblock);
  270.       memput(g_core*8, vaddr, paging_buffer, 4096);
  271.       (word16)*pte &= ~(PT_A | PT_D);  /* clean dirty & accessed bits (set by memput) */
  272.       (word16)*pte |= accdirty;        /* restore to previous */
  273.     } else {
  274. #ifdef VERBOSE
  275.       fprintf(dfp, " new"); fflush(dfp);
  276. #endif
  277.       (word16)*pte |= (PT_I | PT_C);        /* Once accessed save contents */
  278.     }
  279.     utils_tss = old_util_tss;
  280.   }
  281. #ifdef VERBOSE
  282.   fprintf(dfp, "\n"); fflush(dfp);
  283. #endif
  284.   return 0;
  285. }
  286.  
  287. unsigned page_out_640(void) /* return >= 0 page which is paged out, 0xffff if not */
  288. {
  289.   static last_pti = 0;
  290.   int pti;
  291.   da_pn dblock;
  292.   for (pti = last_pti+1; pti != last_pti; pti = (pti+1)%1024)
  293.     if (((word16)pd[pti] & (PT_P | PT_S)) == (PT_P | PT_S)) {
  294.       movedata(pd_seg[pti]<<8, 0, _DS, FP_OFF(paging_buffer), 4096);
  295.       dblock = dalloc();
  296.       dwrite(paging_buffer, dblock);
  297. #ifdef VERBOSE
  298.       fprintf(dfp, "out_640 %d\n", pti); fflush(dfp);
  299. #endif
  300.       pd[pti] &= 0xfff & ~(word32)(PT_P); /* no longer present */
  301.       pd[pti] |= (word32)dblock << 12;
  302.       last_pti = pti;
  303.       return pd_seg[pti];
  304.     }
  305.   return 0xffff;
  306. }
  307.  
  308. unsigned page_out(void) /* return >= 0 page which is paged out, 0xffff if not */
  309. {
  310.   static last_po_pdi = 1;    /* Skip low 4Mb */
  311.   static last_po_pti = 0;
  312.   int start_pdi, start_pti;
  313.   word32 far *pt, v;
  314.   word16 rv;
  315.   da_pn dblock;
  316.   start_pdi = last_po_pdi;
  317.   start_pti = last_po_pti;
  318.   do {
  319.     if ((word16)pd[last_po_pdi] & PT_P) {
  320.       pt = (word32 far *)((word32)(pd_seg[last_po_pdi]) << 24);
  321.       if (((word16)pt[last_po_pti] & (PT_P | PT_S)) == (PT_P | PT_S)) {
  322.         rv = (word16)(pt[last_po_pti] >> 12);
  323.         v = ((word32)last_po_pdi << 22) | ((word32)last_po_pti << 12);
  324.         if ((word16)pt[last_po_pti] & (PT_C | PT_D)) {
  325.           int accessed = (word16)pt[last_po_pti] & PT_A; /* Save accessed bit */
  326.           (word16)pt[last_po_pti] |= PT_C;
  327.           memget(g_core*8, v, paging_buffer, 4096);
  328. #ifdef VERBOSE
  329.           fprintf(dfp, "dout %08lx", ((word32)last_po_pdi<<22) | ((word32)last_po_pti<<12)); fflush(dfp);
  330. #endif
  331.           dblock = dalloc();
  332.           dwrite(paging_buffer, dblock);
  333.           pt[last_po_pti] &= 0xfff & ~(PT_P | PT_A); /* no longer present */
  334.           pt[last_po_pti] |= (word32)dblock << 12;
  335.           (word16)pt[last_po_pti] |= accessed;
  336.         } else {
  337.           pt[last_po_pti] = PT_U | PT_W | PT_S;
  338. #ifdef VERBOSE
  339.           fprintf(dfp, "dflush %08lx", ((word32)last_po_pdi<<22) | ((word32)last_po_pti<<12)); fflush(dfp);
  340. #endif
  341.         }
  342.         return rv;
  343.       }
  344.     }
  345.     else /* imagine we just checked the last entry */
  346.       last_po_pti = 1023;    /* Stupid.  If table not there, page them */
  347.  
  348. bad_choice:
  349.     if (++last_po_pti == 1024) {
  350.       last_po_pti = 0;
  351.       if (++last_po_pdi == 1024)
  352.         last_po_pdi = 1;    /* Skip low 4Mb */
  353.     }
  354.   } while ((start_pdi != last_po_pdi) || (start_pti != last_po_pti));
  355.   return 0xffff;
  356. }
  357.  
  358. /* We map physical addresses 1:1 here.  We also set up pd & pt so that they
  359.    never generate a page fault (are not tested above) and are not cached */
  360. void physical_map(word32 physical, word32 size, word32 vaddr)
  361. {
  362.   word32 address2;
  363.   int pdi;
  364.   word32 far *pte;
  365.  
  366. #ifdef VERBOSE
  367.   fprintf(dfp, "Map: 0x%lx for 0x%lx bytes to 0x%lx\n",physical,size,vaddr); fflush(dfp);
  368. #endif
  369.   address2 = vaddr + size;
  370.   (word16)vaddr &= 0xf000;        /* page align */
  371.   (word16)physical &= 0xf000;        /* page align */
  372.   free_memory(vaddr,address2-1);    /* Should make all pages not present */
  373.   /* Minor bug - if using 640K page before overwritting, loose forever here */
  374.   while(vaddr < address2) {
  375.     pte = getpte(vaddr);
  376.     pdi = (word16)(vaddr >> 22) & 0x3ff;
  377.     (word16)pd[pdi] &= ~PT_S;        /* Make sure directory no swap */
  378.     *pte = PT_P | PT_U | PT_W | PT_CD | physical;
  379.     vaddr += 4096L;
  380.     physical += 4096L;
  381.   }
  382. }
  383.  
  384. int lock_memory(word32 vaddr, word32 size, word8 unlock)
  385. {
  386.   int pdi;
  387.   word32 far *pte;
  388.   word32 vaddr2;
  389. #ifdef VERBOSE
  390.   fprintf(dfp, "Lock(%d): 0x%lx for 0x%lx bytes\n",unlock,vaddr,size); fflush(dfp);
  391. #endif
  392.   size += vaddr;
  393.   (word16)vaddr &= 0xf000;        /* page align */
  394.   vaddr2 = vaddr;
  395.   while(vaddr < size && page_is_valid(vaddr)) {
  396.     pte = getpte(vaddr);
  397.     if (!unlock) {
  398.       pdi = (word16)(vaddr >> 22) & 0x3ff;
  399.       (word16)pd[pdi] &= ~PT_S;        /* Make sure no swap */
  400.     }
  401.     if ((word16)*pte & PT_P) {
  402.       if (unlock)
  403.         (word16)*pte |= PT_S;        /* enable swap bit */
  404.       else
  405.         (word16)*pte &= ~PT_S;        /* clear swap bit */
  406.     } else {
  407.       /* Wasn't locked if no PT present, skip.  Unlocked due to no count?*/
  408.       if (!unlock) {
  409.         /* paged out or never accessed */
  410.         tss_ptr->tss_cr2 = vaddr;
  411.         (word8)tss_ptr->tss_error = 0;
  412.         if(page_in()) {
  413.           lock_memory(vaddr2,vaddr-vaddr2,1);    /* Undo the locking */
  414.           return 1;                /* show error */
  415.         }
  416.         tss_ptr->tss_cr2 = 0L;
  417.         (word16)*pte &= ~PT_S;            /* clear swap bit */
  418.       }
  419.     }
  420.     vaddr += 4096L;
  421.   }
  422.   return 0;
  423. }
  424.  
  425. /* vfirst always page aligned, vaddr maybe not (but free last page anyway) */
  426. /* we free in reverse in the hope of freeing up pages in valloc */
  427. void free_memory(word32 vfirst, word32 vaddr)
  428. {
  429.   word32 far *pte;
  430.  
  431.   (word16)vaddr &= 0xf000;        /* page align */
  432.   while(vfirst <= vaddr) {
  433.     pte = getpte(vaddr);
  434.     if ((word16)*pte & PT_P) {
  435.       if (!((word16)*pte & PT_I) || vfree((word16)(*pte>>12)))
  436.     *pte = PT_U | PT_W | PT_S;        /* Back in pool */
  437.       else 
  438.         (word16)*pte &= ~(PT_C | PT_D);    /* So it will be flushed */
  439.     } else if (!((word16)*pte & PT_S)) {    /* Uncommitted */
  440.       *pte = PT_U | PT_W | PT_S;        /* Back in pool */
  441.     } else if ((word16)*pte & PT_I) {
  442.       dfree((da_pn)(*pte >> 12));        /* Free swap space usage */
  443.       *pte = PT_U | PT_W | PT_S;
  444.     }
  445.     vaddr -= 4096L;
  446.   }
  447. }
  448.  
  449. int free_memory_area(word32 vaddr)
  450. {
  451.   AREAS *area = firstarea;
  452.   AREAS **lasta = &firstarea;
  453.   while (area) {
  454.     if (vaddr == area->first_addr) {
  455.       free_memory(area->first_addr,area->last_addr);
  456.       cant_ask_for(area->first_addr-area->last_addr-1); /* Adjust reserved */
  457.       *lasta = area->next;
  458.       free(area);
  459.       return 1;
  460.     }
  461.     lasta = &area->next;
  462.     area = area->next;
  463.   }
  464.   return 0;
  465. }
  466.  
  467. /* Get: Bits 0-2 page type (0=uncommit, 1=normal, 2=mapped) (PT_P, PT_I, PT_S)
  468.              3 page is writable (PT_W)
  469.              4 accessed/dirty available (1)
  470.              5-6 accessed/dirty (PT_A | PT_D) (same locations)
  471.    Set: Bits 0-2 page type (0=uncommit, 1=normal, 3=no change)
  472.    Bugs: slow since mode swap for every page!
  473. */
  474. int page_attributes(word8 set, word32 vaddr, word16 count)
  475. {
  476.   int ic, pte, uval;
  477.   word32 far *pt;
  478. #ifdef VERBOSE
  479.   fprintf(dfp, "Attrib(%d): 0x%lx for %d pages\n",set,vaddr,count); fflush(dfp);
  480. #endif
  481.   (word16)vaddr &= 0xf000;        /* page align */
  482.   for(ic=0;ic<count;ic++) {
  483.     if(set)
  484.       memget(tss_ptr->tss_es, tss_ptr->tss_edx+(ic*2), &uval, 2);
  485.     pt = getpte(vaddr);
  486.     pte = (word16)*pt;
  487.     if(!set) {
  488.       uval = pte & (PT_P | PT_I | PT_S);
  489.       uval *= 2;    /* Trickery.  Map 0 to 0, 1 to 2, others to > 2 */
  490.       if(uval > 2)
  491.         uval = 1;
  492.       if(pte & PT_W)
  493.         uval |= 8;
  494.       uval |= 0x10;
  495.       uval |= pte & (PT_A | PT_D);
  496.     } else {
  497.       int flags = uval & 7;
  498.       if(flags == 0) {            /* uncommitted */
  499.         free_memory(vaddr,vaddr);
  500.         (word16)*pt &= ~PT_S;
  501.       } else if(flags == 1) {        /* normal */
  502.         flags = pte & (PT_P | PT_I | PT_S);
  503.         if(!flags || flags == PT_P)    /* was uncommitted or mapped */
  504.           *pt = PT_U | PT_W | PT_S;
  505.       }
  506.       if(uval & 8)
  507.         (word16)*pt |= PT_W;
  508.       else
  509.         (word16)*pt &= ~PT_W;
  510.       if(uval & 0x10) {
  511.         (word16)*pt &= ~(PT_A | PT_D);
  512.         (word16)*pt |= (uval & (PT_A | PT_D));
  513.       }
  514.     }
  515.     vaddr += 4096L;
  516.     if(!set)
  517.       memput(tss_ptr->tss_es, tss_ptr->tss_edx+(ic*2), &uval, 2);
  518.   }
  519.   return 0;
  520. }
  521.  
  522. void move_pt(word32 vorig, word32 vend, word32 vnew)
  523. {
  524.   word32 far *pte;
  525.   word32 save;
  526.  
  527.   while(vorig <= vend) {
  528.     pte = getpte(vorig);
  529.     save = *pte;
  530.     *pte = PT_U | PT_W | PT_S;
  531.     pte = getpte(vnew);
  532.     *pte = save;
  533.     if(!((word16)save & PT_S)) {
  534.       int pdi = (word16)(vnew >> 22) & 0x3ff;
  535.       (word16)pd[pdi] &= ~PT_S;        /* Make sure no swap */
  536.     }
  537.     vorig += 4096L;
  538.     vnew  += 4096L;
  539.   }
  540. }
  541.