| 28 | | |
| 29 | | struct Cache* areaCache,*mapCache; |
| 30 | | |
| 31 | | /*********************************************************************** |
| 32 | | * |
| 33 | | * FUNCTION: VmLookupAddress |
| 34 | | * |
| 35 | | * DESCRIPTION: Look up an address in the process's region list. |
| 36 | | * |
| 37 | | * PARAMETERS: process - the process in question. |
| 38 | | * address - the address in question. |
| 39 | | * |
| 40 | | * RETURNS: area that the address is contained in. |
| 41 | | * |
| 42 | | ***********************************************************************/ |
| 43 | | |
| 44 | | struct VMArea* VmLookupAddress(struct Process* process,DWORD address) |
| 45 | | { |
| 46 | | struct VMArea* curr; |
| 47 | | |
| 48 | | ListForEachEntry(curr,&process->areaList,list) |
| 49 | | { |
| 50 | | /* Ordered by vm area start address, so don't have to search through |
| 51 | | the whole list if the address has already been passed. */ |
| 52 | | if (curr->start > address) |
| 53 | | break; |
| 54 | | |
| 55 | | /* Is the address in the virtual mapping? */ |
| 56 | | if (address >= curr->start && address < (curr->start+curr->length)) |
| 57 | | return curr; |
| 58 | | } |
| 59 | | |
| 60 | | return NULL; |
| 61 | | } |
| 62 | | |
| 63 | | SYMBOL_EXPORT(VmLookupAddress); |
| 64 | | |
| 65 | | /*********************************************************************** |
| 66 | | * |
| 67 | | * FUNCTION: VmLookupPage |
| 68 | | * |
| 69 | | * DESCRIPTION: Looks up a page in a vNode by file offset to see if anyone |
| 70 | | * has mapped the page already. |
| 71 | | * |
| 72 | | * PARAMETERS: vNode - vNode that contains the shared list. |
| 73 | | * offset - file offset needed. |
| 74 | | * |
| 75 | | * RETURNS: the virtual page containing the file data. |
| 76 | | * |
| 77 | | ***********************************************************************/ |
| 78 | | |
| 79 | | static struct VMMapPage* VmLookupPage(struct VNode* vNode,DWORD offset) |
| 80 | | { |
| 81 | | struct VMMapPage* page; |
| 82 | | |
| 83 | | /* Has anyone else mapped it in? */ |
| 84 | | if (!vNode || vNode->refs == 1 || ListEmpty(&vNode->sharedList)) |
| 85 | | return NULL; |
| 86 | | |
| 87 | | /* Loop through the shared list and return the one with the offset we need. */ |
| 88 | | ListForEachEntry(page,&vNode->sharedList,list) |
| 89 | | if (page->offset == offset) |
| 90 | | return page; |
| 91 | | |
| 92 | | /* Not found - it will be mapped in and added to the shared list */ |
| 93 | | return NULL; |
| 94 | | } |
| 95 | | |
| 96 | | /*********************************************************************** |
| 97 | | * |
| 98 | | * FUNCTION: VmCreateMappedPage |
| 99 | | * |
| 100 | | * DESCRIPTION: Looks up a page in a vNode by file offset. |
| 101 | | * |
| 102 | | * PARAMETERS: vNode - vNode that contains the shared list. |
| 103 | | * offset - file offset needed. |
| 104 | | * |
| 105 | | * RETURNS: the virtual page containing the file data. |
| 106 | | * |
| 107 | | ***********************************************************************/ |
| 108 | | |
| 109 | | static struct VMMapPage* VmCreateMappedPage(DWORD offset,struct PhysPage* page) |
| 110 | | { |
| 111 | | struct VMMapPage* mappedPage=(struct VMMapPage*)MemCacheAlloc(mapCache); |
| 112 | | |
| 113 | | if (!mappedPage) |
| 114 | | return NULL; |
| 115 | | |
| 116 | | mappedPage->offset=offset; |
| 117 | | mappedPage->page=page; |
| 118 | | |
| 119 | | return mappedPage; |
| 120 | | } |
| 121 | | |
| 122 | | /*********************************************************************** |
| 123 | | * |
| 124 | | * FUNCTION: VmFreeMappedPage |
| 125 | | * |
| 126 | | * DESCRIPTION: Free a mapped page by physical address. |
| 127 | | * |
| 128 | | * PARAMETERS: vNode - VFS node containing the reference to the page. |
| 129 | | * physAddr - physical address of the page. |
| 130 | | * |
| 131 | | * RETURNS: Usual error codes. |
| 132 | | * |
| 133 | | ***********************************************************************/ |
| 134 | | |
| 135 | | static int VmFreeMappedPage(struct VNode* vNode,DWORD physAddr) |
| 136 | | { |
| 137 | | struct VMMapPage* page=NULL; |
| 138 | | |
| 139 | | if (!vNode) |
| 140 | | return -EFAULT; |
| 141 | | |
| 142 | | /* Remove a physical page from the list, because there are no references and it will be freed */ |
| 143 | | |
| 144 | | ListForEachEntry(page,&vNode->sharedList,list) |
| 145 | | if (page->page->physAddr == physAddr) |
| 146 | | { |
| 147 | | ListRemove(&page->list); |
| 148 | | return 0; |
| 149 | | } |
| 150 | | |
| 151 | | return -ENOENT; |
| 152 | | } |
| 153 | | |
| 154 | | /*********************************************************************** |
| 155 | | * |
| 156 | | * FUNCTION: VmWaitOnPage |
| 157 | | * |
| 158 | | * DESCRIPTION: Wait for another thread to stop altering the page. |
| 159 | | * A single waitqueue is shared between a number of pages |
| 160 | | * (one per 4mb+ or so) since there are not many conflicts |
| 161 | | * for a single page - it is very unlikely that a page will |
| 162 | | * be locked and someone else try to access it. |
| 163 | | * |
| 164 | | * PARAMETERS: page - page in question. |
| 165 | | * |
| 166 | | * RETURNS: Nothing. |
| 167 | | * |
| 168 | | ***********************************************************************/ |
| 169 | | |
| 170 | | static void VmWaitOnPage(struct VMMapPage* page) |
| 171 | | { |
| 172 | | WaitQueue* waitQueue; |
| 173 | | |
| 174 | | if (!(page->flags & MPAGE_BUSY)) |
| 175 | | return; |
| 176 | | |
| 177 | | waitQueue=PageGetWaitQueue(page->page); |
| 178 | | |
| 179 | | if (UNLIKELY(page->flags & MPAGE_BUSY)) |
| 180 | | WAIT_ON(*waitQueue,!(page->flags & MPAGE_BUSY)); |
| 181 | | } |
| 182 | | |
| 183 | | /*********************************************************************** |
| 184 | | * |
| 185 | | * FUNCTION: VmLockPage |
| 186 | | * |
| 187 | | * DESCRIPTION: Locks a page to alter data. |
| 188 | | * |
| 189 | | * PARAMETERS: page - page in question. |
| 190 | | * |
| 191 | | * RETURNS: Nothing. |
| 192 | | * |
| 193 | | ***********************************************************************/ |
| 194 | | |
| 195 | | static void VmLockPage(struct VMMapPage* page) |
| 196 | | { |
| 197 | | VmWaitOnPage(page); |
| 198 | | page->flags |= MPAGE_BUSY; |
| 199 | | } |
| 200 | | |
| 201 | | /*********************************************************************** |
| 202 | | * |
| 203 | | * FUNCTION: VmUnlockPage |
| 204 | | * |
| 205 | | * DESCRIPTION: Unlock the page, let any thread access it. |
| 206 | | * |
| 207 | | * PARAMETERS: page - page in question. |
| 208 | | * |
| 209 | | * RETURNS: Nothing. |
| 210 | | * |
| 211 | | ***********************************************************************/ |
| 212 | | |
| 213 | | static void VmUnlockPage(struct VMMapPage* page) |
| 214 | | { |
| 215 | | page->flags &= ~MPAGE_BUSY; |
| 216 | | WakeUp(PageGetWaitQueue(page->page)); |
| 217 | | } |
| | 28 | #include <sys.h> |
| | 29 | |
| | 30 | extern struct Cache* areaCache,*mapCache; |
| | 31 | |
| | 32 | /* FIXME: Move more functions into vmm.c */ |
| 809 | | int VirtCheckArea(void* beginAddr,DWORD size,int mask) |
| 810 | | { |
| 811 | | DWORD begin=(DWORD)beginAddr; |
| 812 | | struct VMArea* area,*next; |
| 813 | | |
| 814 | | /* Don't have to check */ |
| 815 | | if (!size) |
| 816 | | return 0; |
| 817 | | |
| 818 | | area=VmLookupAddress(current,begin); |
| 819 | | |
| 820 | | if (!area) |
| 821 | | return -EFAULT; |
| 822 | | |
| 823 | | /* Cannot write to a read-only area */ |
| 824 | | if (!(area->protection & PAGE_RW) && (mask & VER_WRITE)) |
| 825 | | return -EFAULT; |
| 826 | | |
| 827 | | /* Doesn't overrun */ |
| 828 | | if ((area->start+area->length)-begin >= size) |
| 829 | | return 0; |
| 830 | | |
| 831 | | /* Check when size overruns the area */ |
| 832 | | while (1) |
| 833 | | { |
| 834 | | /* Assumes all areas are at least readable */ |
| 835 | | if (!(area->protection & PAGE_RW) && (mask & VER_WRITE)) |
| 836 | | return -EFAULT; |
| 837 | | |
| 838 | | /* Cannot let the user let the kernel write to it's own pages */ |
| 839 | | if (!(area->protection & PAGE_USER)) |
| 840 | | return -EFAULT; |
| 841 | | |
| 842 | | if ((area->start+area->length)-begin >= size) |
| 843 | | break; |
| 844 | | |
| 845 | | next=ListEntry(area->list.next,struct VMArea,list); |
| 846 | | if (area->list.next == ¤t->areaList || next->start == area->start+area->length) /* Does next even exist? */ |
| 847 | | return -EFAULT; |
| 848 | | |
| 849 | | area=next; |
| 850 | | } |
| 851 | | |
| 852 | | return 0; |
| 853 | | } |
| 854 | | |
| | 628 | /* FIXME: Legacy system call. */ |