home *** CD-ROM | disk | FTP | other *** search
- /*
- * pager.c
- * Part of the !Virtual distribution
- * (c) bdb/nas/fo, 1992-3
- */
-
- #include "swis.h"
- #include "swiv.h"
- #include "wimp.h"
-
- #include "virtual.h"
- #include "lib.h"
- #include "output.h"
- #include "pager.h"
-
- /* #define DEBUG */
-
- void Initourmem(WKSP *w)
- {
- int i;
- w->stacktop = (char *)alloc(STACKSIZE)+STACKSIZE;
-
- swi(OS_ReadMemMapInfo, OUT(R0|R1), &w->pagesize, &w->numpages);
-
- w->pageshift = 15;
- if (w->pagesize == K32/2) w->pageshift = 14;
- if (w->pagesize == K32/4) w->pageshift = 13;
-
- w->numplaces = PLACE(M24);
- w->ourmem = alloc(sizeof(int) * w->numplaces);
-
- w->oldpages = alloc(sizeof(PAGEENTRY)*(w->numpages + 1));
- w->newpages = alloc(sizeof(PAGEENTRY)*(w->numpages + 1));
- FindPages(w);
-
- w->nslots = 0; /* page file empty */
- w->index = alloc(sizeof(int)*w->numplaces);
-
- for ( i=PLACE(K32); i<w->numplaces; i++)
- { w->ourmem[i] = TAGLOC(ABORT, 0);
- }
- w->losepage = 0;
- }
-
- void SetWimpMemMap(WKSP *w)
- {
- int i;
- #ifdef DEBUG
- printf("Places %d..%d match wimp map\n",PLACE(K32),w->numourpages+PLACE(K32));
- #endif
- for ( i = 0; i<w->numourpages; i++ )
- { w->newpages[i].addr = ADDR(i)+K32;
- w->newpages[i].access = ACCESS_READWRITE;
- w->ourmem[i+PLACE(K32)] = TAGLOC(DIRTY,i);
- }
- for ( i=w->numourpages+PLACE(K32); i<w->numplaces; i++ )
- w->ourmem[i] = TAGLOC(ABORT, 0);
- for (i=0;i<w->nslots;i++)
- w->index[i] = -1;
- }
-
- void Finishourmem(WKSP *w)
- {
- free(w->oldpages);
- free(w->newpages);
- free(w->ourmem);
- free(w->index);
- }
-
- int SetVirtualSlot(WKSP *w, int size)
- { int i,m;
- i = PLACE(K32);
- m = i + PLACE(size);
- #ifdef DEBUG
- printf("Places %d..%d abort->zerofill\n",i,m);
- #endif
- for (;i<m;i++)
- if (TAG(w->ourmem[i])==ABORT)
- w->ourmem[i] = TAGLOC(ZERO,0);
- return size;
- }
-
-
- void virtualmem(WKSP *w)
- {
- swi(OS_SetMemMapEntries, IN(R0), w->newpages);
- }
-
- void normalmem(WKSP *w)
- {
- swi(OS_SetMemMapEntries, IN(R0), w->oldpages);
- }
-
- /* Find us a set of pysical pages, preserving newpages[0..numourpages].addr,access */
-
- void FindPages(WKSP *w)
- {
- int i;
- int appspace;
- int a, b;
- for (i = 0; i<w->numpages ; i++)
- w->oldpages[i].pagenum = i;
- w->oldpages[w->numpages].pagenum = -1;
- swi(OS_ReadMemMapEntries, IN(R0), w->oldpages);
- swi(OS_ChangeEnvironment, IN(R0|R1)|OUT(R1), 14, 0, &appspace);
- w->numourpages = PLACE(appspace - K32);
- b = w->numourpages; /* We accumulate pages that must be moved out the way here */
- for (i = 0; i<w->numpages; i++)
- { if (w->oldpages[i].addr < K32) /* OS workspace will get protected */
- /*w->newpages[b++] = w->oldpages[i] */;
- else if (w->oldpages[i].addr < appspace) /* Useable page */
- { a = PLACE(w->oldpages[i].addr-K32); /* its current place */
- w->newpages[a].pagenum = i; /* it becomes our page */
- }
- else if (w->oldpages[i].addr < M24) /* page needs moving */
- w->newpages[b++] = w->oldpages[i];
- }
- for (i=0; i<w->numourpages; i++)
- { w->oldpages[i].pagenum = w->newpages[i].pagenum;
- w->oldpages[i].addr = ADDR(i)+K32;
- w->oldpages[i].access = ACCESS_READWRITE;
- }
- for (i = w->numourpages; i<b; i++)
- { w->oldpages[i] = w->newpages[i];
- if (w->newpages[i].addr<K32)
- w->newpages[i].access = ACCESS_READONLY;
- else
- { w->newpages[i].addr = DUMPADDR;
- w->newpages[i].access = ACCESS_BAD;
- } }
- w->oldpages[b].pagenum = -1;
- w->newpages[b].pagenum = -1;
- }
-
- static int pageout(WKSP *w, int page, int addr)
- {
- int place, Normaddr, slot;
- place = PLACE(addr);
- Normaddr = w->oldpages[page].addr;
- slot = LOC(w->ourmem[place]);
- switch (TAG(w->ourmem[place]))
- { case DIRTY:
- for (slot = 0; slot<w->nslots; slot++)
- if (w->index[slot] == -1)
- break;
- if (slot>=w->nslots)
- { w->nslots = slot+1;
- #ifdef DEBUG
- printf("nslots = %d\n",w->nslots);
- #endif
- }
- swi(OS_GBPB, IN(R0|R1|R2|R3|R4), 1, w->pagefile, Normaddr, w->pagesize, ADDR(slot));
- /* FALL THROUGH */
- case SAVED:
- w->index[slot] = place;
- w->ourmem[place] = TAGLOC(PAGED, slot);
- break;
- default:
- printf("*** ILLEGAL page out tag page %d addr %d place %d Normaddr %d slot %d tag %d\n",
- page,addr,place,Normaddr,slot,TAG(w->ourmem[place]));
- RealDoOff(w);
- break;
- }
- #ifdef DEBUG
- printf("Paging place %d out from page %d to slot %d\n",place,page,slot);
- #endif
- return page;
- }
-
- static int findpageout(WKSP *w)
- {
- int addr, page;
- loop:
- page = w->losepage;
- if (++w->losepage >= w->numourpages)
- w->losepage = 0;
- addr = w->newpages[page].addr;
- if (addr == DUMPADDR)
- return page;
- if (addr & LOCKADDRBIT)
- goto loop;
- return pageout(w,page,addr);
- }
-
- static void pagein(WKSP *w, int page, int place, int write)
- { int Normaddr = w->oldpages[page].addr;
- int slot = LOC(w->ourmem[place]);
- swi(OS_GBPB, IN(R0|R1|R2|R3|R4), 3, w->pagefile, Normaddr, w->pagesize, ADDR(slot));
- w->newpages[page].addr = ADDR(place);
- if (write)
- { w->newpages[page].access = ACCESS_READWRITE;
- w->index[slot] = -1;
- w->ourmem[place] = TAGLOC(DIRTY, page);
- }
- else
- { w->newpages[page].access = ACCESS_READONLY;
- w->index[slot] = page;
- w->ourmem[place] = TAGLOC(SAVED, slot);
- }
- #ifdef DEBUG
- printf("Paging place %d in to page %d from slot %d %s",place,page,slot,write?"writeable":"readonly");
- #endif
- }
-
- /*
- * First page out all DIRTY places whose address is not as RISC OS expects
- * Then page in all place which should be in that page.
- */
- void FixMemoryPages(WKSP *w)
- {
- int i;
- for (i = 0; i < w->numourpages; i++)
- if (w->newpages[i].addr != ADDR(i) + K32 &&
- w->newpages[i].access != ACCESS_BAD)
- switch (TAG(w->ourmem[PLACE(w->newpages[i].addr)])) {
- case DIRTY:
- pageout(w, i, w->newpages[i].addr);
- break;
- } /* switch */
- for (i = 0; i < w->numourpages; i++) {
- if (w->newpages[i].addr != ADDR(i) + K32) {
- switch (TAG(w->ourmem[i+PLACE(K32)])) {
- case PAGED:
- pagein(w, i, i + PLACE(K32), 1);
- break;
- case ZERO:
- /*
- * This page was just recieved from the wimp by a wimplsot drag.
- * I'm not really sure if the tag, the place recieves here
- * should be DIRTY; maybe ZERO is ok. But, to be consistent with Brian's
- * code in SetWimpMemMap, all places paged in at the right page,
- * get the DIRTY tag.
- */
- w->ourmem[i+PLACE(K32)] = TAGLOC(DIRTY, i);
- w->newpages[i].addr = ADDR(i) + K32;
- w->newpages[i].access = ACCESS_READWRITE;
- break;
- } /* switch */
- }
- }
- }
-
- void SetRealMem(WKSP*w, int size)
- {
- int newnumourpages=PLACE(size);
- int i,newslot;
- if (newnumourpages<2)
- newnumourpages=2;
- if (newnumourpages!=w->numourpages)
- { for (i = newnumourpages; i < w->numourpages; i++)
- {
- if (w->newpages[i].addr!=DUMPADDR)
- pageout(w, i, w->newpages[i].addr);
- }
- swi(Wimp_SlotSize,IN(R0|R1)|OUT(R0),ADDR(newnumourpages),-1,&newslot);
- newnumourpages = PLACE(newslot);
- for (i = w->numourpages; i<newnumourpages; i++)
- { w->newpages[i].addr=DUMPADDR;
- w->newpages[i].access=ACCESS_BAD;
- }
-
- /*
- * When the user drags our slotbar, we often will receive more than one
- * wimp_MSETSLOT message at once. In the old code, w->losepage would then
- * be set at the *end* of a big block of DUMPADDR pages. This is a waste.
- * The code below ensures w->losepage is always on the first DUMPADDR page.
- */
- if (w->numourpages < newnumourpages) {
- for (i = 0; i < newnumourpages; i++)
- if (w->newpages[i].addr == DUMPADDR) {
- w->losepage = i;
- break;
- }
- }
- else
- w->losepage = 0;
- w->numourpages = newnumourpages;
-
- #ifdef DEBUG
- printf("numourpages=%d\n",newnumourpages);
- #endif
- } }
-
- static int GetPlace(WKSP *w, int place, int write)
- { int page,slot;
- page = LOC(w->ourmem[place]);
- switch (TAG(w->ourmem[place]))
- {
- case SAVED:
- slot = page;
- page = w->index[slot];
- if (!write)
- return page;
- w->newpages[page].access = ACCESS_READWRITE;
- w->index[slot] = -1;
- w->ourmem[place]=TAGLOC(DIRTY,page);
- #ifdef DEBUG
- printf("Dirtying place %d in page %d free slot %d\n",place,page,slot);
- #endif
- if ( slot == w->nslots-1 ) /* last slot in file freed */
- { while (slot>=0 && w->index[slot]==-1)
- slot--;
- w->nslots = slot+1;
- swi(OS_Args,IN(R0|R1|R2),3,w->pagefile,ADDR(w->nslots));
- #ifdef DEBUG
- printf("nslots down = %d\n",w->nslots);
- #endif
- }
- return page;
- case PAGED:
- page=findpageout(w);
- pagein(w, page, place, write);
- return page;
- case ZERO:
- page=findpageout(w);
- w->ourmem[place] = TAGLOC(DIRTY, page);
- w->newpages[page].addr = ADDR(place);
- w->newpages[page].access = ACCESS_READWRITE;
- #ifdef DEBUG
- printf("Place %d gets page %d zeroed",place,page);
- #endif
- return page;
- case DIRTY:
- return page;
- case ABORT:
- printf("***ABORT: place %d\n",place);
- return -1;
- default:
- printf("***ILLEGAL tag: place %d in page %d tag %d\n",place,page,TAG(w->ourmem[place]));
- RealDoOff(w);
- return -1;
- }
- }
-
- static int VGetPlace(WKSP *w, int place, int write)
- { int page;
- switch (TAG(w->ourmem[place]))
- { case DIRTY:
- return LOC(w->ourmem[place]);
- case SAVED:
- if (!write)
- return LOC(w->ourmem[place]);
- default:
- Normal(w);
- page = GetPlace(w,place,write);
- Virtual(w);
- return page;
- }
- }
-
- RANGE Locate(WKSP *w, int start, int end)
- { int place,page;
- RANGE r;
- #ifdef DEBUG
- printf("Locate: %x-%x",start,end);
- #endif
- if (start<K32)
- return r.start=start,r.end=end<K32?end:K32,r;
- if (start>=M24)
- return r.start=start,r.end=end,r;
- place=PLACE(start);
- page=LOC(w->ourmem[place]);
- switch (TAG(w->ourmem[place]))
- {
- case DIRTY:
- case SAVED:
- r.start=w->oldpages[page].addr+SHUFT(start);
- break;
- case ZERO:
- r.start = 0;
- break;
- case ABORT:
- r.start = -1;
- break;
- case PAGED:
- r.start = (1u<<31) + ADDR(page) + SHUFT(start);
- break;
- }
- r.end = r.start + w->pagesize - SHUFT(start);
- if (r.end>r.start+end-start)
- r.end = r.start+end-start;
- #ifdef DEBUG
- printf("==>%x-%x\n",r.start,r.end);
- #endif
- return r;
- }
-
- RANGE Physical(WKSP *w, int start, int end)
- { int place,page;
- RANGE r;
- #ifdef DEBUG
- printf("Physical: %x-%x",start,end);printflush(w);
- #endif
- if (end<start)
- RealDoOff(w);
- if (start<K32)
- return r.start=start,r.end=end<K32?end:K32,r;
- if (start>=M24)
- return r.start=start,r.end=end,r;
- place=PLACE(start);
- page=GetPlace(w,place,1);
- if (page==-1)
- return r.start=0,r.end=0,r;
- r.start=w->oldpages[page].addr+SHUFT(start);
- r.end = w->oldpages[page].addr+w->pagesize;
- if (r.end>r.start+end-start)
- r.end = r.start+end-start;
- #ifdef DEBUG
- printf("==>%x-%x\n",r.start,r.end); printflush(w);
- #endif
- return r;
- }
-
- int ToMem(WKSP *w, void *src, int dest, int size)
- { RANGE r;
- int l;
- while (size>0)
- { r = Physical(w, dest, dest+size);
- if (!r.end)
- return 0;
- l=r.end-r.start;
- memcpy((void*)r.start,src,l);
- src=(char*)src+l;
- dest+=l;
- size-=l;
- }
- return 1;
- }
-
- int FromMem(WKSP *w, int src, void *dest, int size)
- { RANGE r;
- int l;
- while (size>0)
- { r = Physical(w, src, src+size);
- if (!r.end)
- return 0;
- l=r.end-r.start;
- memcpy(dest,(void *)r.start,l);
- src+=l;
- dest=(char*)dest+l;
- size-=l;
- }
- return 1;
- }
-
-
- /* Called in virtual, svc mode to ensure range all accessable */
-
- int ReadRange(WKSP *w, int start, int end)
- {
- int place1,place2,page1,page2;
- if (start<K32)
- return 0;
- if (start>=M24)
- return 1;
- if (end>M24)
- end=M24;
- place1 = PLACE(start);
- place2 = PLACE(end-1);
- page1=VGetPlace(w,place1,0);
- if (page1==-1)
- return 0;
- if (place2!=place1)
- { w->newpages[page1].addr |= LOCKADDRBIT;
- page2 = VGetPlace(w,place2,0);
- w->newpages[page1].addr &= ~LOCKADDRBIT;
- if (page2==-1)
- return 0;
- }
- return 1;
- }
-
- int WriteRange(WKSP *w, int start, int end)
- {
- int place1,place2,page1,page2;
- if (start<K32)
- return 0;
- if (start>=M24)
- return 1;
- if (end>M24)
- end=M24;
- place1 = PLACE(start);
- place2 = PLACE(end-1);
- page1=VGetPlace(w,place1,1);
- if (page1==-1)
- return 0;
- if (place2!=place1)
- { w->newpages[page1].addr |= LOCKADDRBIT;
- page2 = VGetPlace(w,place2,1);
- w->newpages[page1].addr &= ~LOCKADDRBIT;
- if (page2==-1)
- return 0;
- }
- return 1;
- }
-
- int ReadPtr(WKSP *w, int start)
- { int place,page;
- if (start<K32)
- return 0;
- if (start>=M24)
- return 1;
- place = PLACE(start);
- page=VGetPlace(w,place,0);
- if (page==-1)
- return 0;
- return 1;
- }
-
- int WritePtr(WKSP *w, int start)
- { int place,page;
- if (start<K32)
- return 0;
- if (start>=M24)
- return 1;
- place = PLACE(start);
- page=VGetPlace(w,place,1);
- if (page==-1)
- return 0;
- return 1;
- }
-