00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "src/common/shared.hpp"
00020 #include "src/ipc/lock.hpp"
00021 #include "src/arch/x86/interr.hpp"
00022 #include "src/arch/x86/except_c.hpp"
00023 #include "src/arch/x86/rtc.hpp"
00024 #include "src/thread/thread.hpp"
00025 #include "src/thread/scheduler.hpp"
00026 #include "src/thread/process.hpp"
00027 #include "src/memory/memset.hpp"
00028 #include "src/memory/alloc4k.hpp"
00029 #include "src/memory/align.hpp"
00030 #include "src/memory/heap.hpp"
00031 #include "src/memory/pager.hpp"
00032
00033 namespace Memory {
00034 namespace Pager {
00035
00036
00037
00038 IPC::Lock::lock_t lock_frame(const_cast<char*>("frame"));
00039 void *virtual_frame;
00040 memtree kmem;
00041
00042
00043
00044 uint32 lazy_enable=0;
00045
00046
00047
00048
00049
00050 void init() { _Pf("Pager::init");
00051 addr_t *pgd;
00052
00053 virtual_frame = (void*) Memory::Physical::ballocate(PAGE_SIZE, PAGE_ALIGN);
00054 __asm__ __volatile__ ("mov %%cr3, %%eax" : "=a" (pgd));
00055 kmem.cr3=(uint32)pgd;
00056 kmem.init((addr_t*)((uint32)pgd+mem_kernel_start-mem_physical), &Memory::Heap::heap0);
00057 kmem.memory_map.init(mem_space_start, mem_space_krnend, &Memory::Heap::heap0);
00058
00059 kmem.pte_map(0xfffff000 & (uint32)&CRT_STACK, PTE_STACKGUARD);
00060
00061 preturn();
00062 }
00063
00064
00065 void init_pf()
00066 { _Pf("Pager::init_pf");
00067 lazy_enable=true;
00068 Arch::x86::Interr::add2interr_chain(Arch::x86::Interr::INT_PF, &PageFaultHandler);
00069
00070 preturn();
00071 }
00072
00073
00074 int PageFaultHandler(struct Arch::x86::Interr::except2_t *code)
00075 {
00076
00077
00078
00079
00080
00081
00082 _Pf("'PageFaultHandler");
00083 struct env_t env;
00084 env.code=code;
00085 env.thread=(Thread::Scheduler::multitasking_running? (Thread::thread_t*)current_thread:NULL);
00086 env.proc=(Thread::Scheduler::multitasking_running? current_thread->proc:NULL);
00087 uint32 virt= code->cr2;
00088 env.mtree=(Thread::Scheduler::multitasking_running? current_thread->proc->mem : &kmem);
00089 uint32 phys=env.mtree->pte_val(virt&0xfffff000);
00090
00091
00092
00093 if (shmem_paging_pfh(&env, virt, phys)==ESUCCESS) preturn( ESUCCESS );
00094
00095 if (lazy_paging_pfh(&env, virt, phys)==ESUCCESS) preturn( ESUCCESS );
00096
00097 preturn( EFAIL);
00098 }
00099
00100
00101 int lazy_paging_pfh(struct env_t *env, uint32 virt, uint32 phys)
00102 { _Pf("P'lazy_paging_pfh");
00103 uint32 new_phys;
00104 if (phys & PTE_LAZY)
00105 {
00106 new_phys= alloc4k(1,false);
00107 if ((new_phys==NULL)||(new_phys==0xffffffff))
00108 { complain("insufficient memory!"); preturn( EFAIL ); }
00109
00110 env->mtree->pte_map(virt&0xfffff000, new_phys|(phys-PTE_LAZY)|PTE_PRESENT|PTE_WRITEABLE|PTE_USER);
00111 preturn( ESUCCESS );
00112 }
00113 preturn( EFAIL);
00114 }
00115
00116
00117 int allocate_memtree(class memtree *mtree, bool supervisor, class Memory::Heap::heapbox *hp)
00118 { _Pf("P'allocate_memtree");
00119 uint32 *pgd;
00120 void *dest, *src;
00121 uint32 cnt;
00122
00123 memset(mtree,0,sizeof(class memtree));
00124
00125 pgd= (uint32*)hp->malloc(4096, PAGE_ALIGN, FAC_MEMORY|FAC_PGD, NULL);
00126 memset(pgd,0,4096);
00127
00128
00129 dest= pgd+(mem_kernel_start/PGT_WIDE);
00130 src= Memory::Pager::kmem.page_directory+(mem_kernel_start/PGT_WIDE);
00131 cnt= 1024-(mem_kernel_start/PGT_WIDE);
00132 memmove(dest,src,cnt*sizeof(uint32));
00133
00134 mtree->init(pgd, hp);
00135 mtree->cr3=Memory::Pager::kmem.pte_val((uint32)pgd)&0xfffff000;
00136
00137 pgd[mem_pgd_start/PGT_WIDE]= mtree->cr3|PTE_PRESENT|PTE_WRITEABLE;
00138
00139 preturn( ESUCCESS );
00140 }
00141
00142
00143
00144 void memtree::init(addr_t *pgd, Memory::Heap::heapbox *hp)
00145 {
00146
00147 page_directory=pgd;
00148
00149 memory_map.init(mem_user_start, mem_user_end, hp);
00150
00151
00152
00153
00154 }
00155
00156
00157 void memtree::done()
00158 {
00159
00160 }
00161
00162
00163 void memtree::pte_map (addr_t virt, uint32 value)
00164 { _Pf("memtree::pte_map");
00165 addr_t *page_table=(addr_t*) page_directory[virt>>22];
00166
00167 if (page_table == NULL)
00168 {page_directory[virt>>22]=alloc4k(1,true)|(value&PTE_MASK)|PTE_PRESENT|PTE_WRITEABLE;
00169 page_table=(addr_t*)page_directory[virt>>22];}
00170
00171
00172 page_table=(addr_t*)((uint32)page_table & 0xFFFFF000);
00173 frame_assign((uint32)page_table);
00174
00175 ((uint32*)virtual_frame)[(virt & 0x3fffff)>>12] = value;
00176 frame_release();
00177
00178 invalidate (virt);
00179
00180 preturn();
00181 }
00182
00183
00184 uint32 memtree::pte_val (addr_t virt)
00185 { _Pf("memtree::pte_val");
00186 uint32 ret;
00187
00188
00189
00190
00191 uint32 fl;
00192 asm volatile("pushf\npopl %0\ncli" : "=g" (fl));
00193
00194 if (page_directory[virt>>22]==NULL)
00195 preturn (NULL);
00196
00197 frame_assign(page_directory[virt>>22] & 0xfffff000);
00198 ret=((uint32*)virtual_frame)[(virt & 0x3fffff)>>12];
00199 frame_release();
00200
00201 asm volatile("pushl %0\npopf" : : "g"(fl));
00202
00203 preturn (ret);
00204 }
00205
00206
00207 void memtree::pte_umap (addr_t virt) {
00208 pte_map(virt, NULL);
00209 }
00210
00211
00212 void memtree::pte_lazy(addr_t virt, uint32 flags) {
00213 pte_map(virt, NULL | PTE_LAZY | flags);
00214 }
00215
00216
00217 int memtree::pte_alloc(addr_t virt, uint32 flags)
00218 {
00219 addr_t r;
00220 if (lazy_enable)
00221 { pte_lazy(virt,flags); return ESUCCESS; }
00222 r= alloc4k(1,false);
00223 if ((r==NULL)||(r==0xffffffff)) return EINVAL;
00224 pte_map(virt, r|flags|PTE_PRESENT);
00225
00226 return ESUCCESS;
00227 }
00228
00229
00230
00231 void frame_assign (addr_t physical) {
00232 FrameAssign(virtual_frame, &lock_frame, physical);
00233 }
00234
00235
00236 void frame_release() {
00237 lock_frame.ulock();
00238 }
00239
00240
00241 void FrameAssign (void *frame, class IPC::Lock::lock_t *l, addr_t physical)
00242 { _Pf("Pager::FrameAssign");
00243 addr_t *PGT;
00244 uint32 i;
00245 l->lock();
00246
00247
00248
00249 i = ((uint32)frame) >> 22;
00250 PGT = (addr_t*) (0xFF800000 + i * 0x1000);
00251
00252 i = ((uint32) frame) & 0x3FFFFF;
00253 PGT[(uint32) i >> 12] = (addr_t)((uint32)physical + 3);
00254
00255 invalidate((addr_t)frame);
00256 preturn();
00257 }
00258
00259
00260 void FrameRelease(class IPC::Lock::lock_t *l) {
00261 l->ulock();
00262 }
00263
00264
00265 void cpypage(uint32 dest, uint32 src)
00266 {_Pf("Memory::cpypage");
00267 char buf[PAGE_SIZE];
00268
00269 frame_assign(src);
00270 memmove(buf,virtual_frame,PAGE_SIZE);
00271 frame_release();
00272
00273
00274 frame_assign(dest);
00275 memmove(virtual_frame, buf, PAGE_SIZE);
00276 frame_release();
00277 preturn();
00278 }
00279
00280
00281 void memmove2(class memtree *d1, void *d2, class memtree *s1, void *s2, uint32 cnt)
00282 { _Pf("Pager::memmove2");
00283 char *buf;
00284 uint32 dest,src,ct,ct2=0;
00285 buf=(char*)Memory::Heap::heap0.malloc(cnt,NO_ALIGN,"memmove2 buf",NULL);
00286
00287
00288 if ((Thread::Scheduler::multitasking_running)&&(current_thread->proc->mem == s1))
00289 memmove(buf,s2,cnt); else {
00290 while (ct2<cnt)
00291 {
00292 src=(uint32)virtual_frame+(((uint32)s2+ct2)&0xfff);
00293 ct= MIN(0x1000-(((uint32)s2+ct2)&0xfff), cnt-ct2);
00294 dest= (uint32)buf+ct2;
00295 frame_assign(s1->pte_val(((uint32)s2+ct2)&0xfffff000)&0xfffff000);
00296 memmove((void*)dest,(void*)src,ct);
00297 frame_release();
00298 ct2+=ct;
00299 } }
00300
00301
00302 if ((Thread::Scheduler::multitasking_running)&&(current_thread->proc->mem == d1))
00303 memmove(d2,buf,cnt); else {
00304 ct2=0;
00305 while (ct2<cnt)
00306 {
00307 src=(uint32)buf+ct2;
00308 dest=(uint32)virtual_frame+(((uint32)d2+ct2)&0xfff);
00309 ct= MIN(0x1000-(((uint32)d2+ct2)&0xfff), cnt-ct2);
00310 frame_assign(d1->pte_val(((uint32)d2+ct2)&0xfffff000)&0xfffff000);
00311 memmove((void*)dest,(void*)src,ct);
00312 frame_release();
00313 ct2+=ct;
00314 } }
00315
00316 Memory::Heap::heap0.free(buf);
00317 preturn();
00318 }
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328 };
00329 };
00330
00331
00332
00333
00334
00335
00336