rendered paste bodyclass PhysMem { u32 get_page(); void free_page();};class AddressSpace { void map(u32 phys,u32 virt); u32 unmap(u32 virt); void destroy(); void clone(); directory_entry& get_dir_entry(u32 index); table_entry* get_page_table(u32 virt); u32 virt_to_phys(u32 virt);};u32 AddressSpace::virt_to_phys(u32 virt) { u32 pte = (virt>>12) & 0x3ff; return get_page_table(virt)[pte].frame<<12;}PhysMem physmem;static table_entry** page_tables(0xffc00000);// 1111 1111 1100 0000 0000 | 0000 0000 0000static directory_entry* current_page_dir=0xFFFFF000;static directory_entry* other_page_dir=0xFFFFF000;static table_entry* other_page_tables=0xFF800000;static int kernel_start_directory_entry=768;void copy_page_table(int pt) { table_entry* other=other_page_tables+(pt<<10); table_entry* current=page_tables+(pt<<10); for(int i=0;i<1024;++i) { other[i].zero(); if(current[i].present) { u32 newp=get_page(); other[i]=current[i]; other[i].frame=newp>>12; copy_4k_page(current[i].frame<<12,newp); } }}u32 AddressSpace::clone() { u32 npd=get_page(); current_page_dir[1022].set(npd,0,1); for(int i=0;i<1022;++i) { if(current_page_dir[i].present) { u32 npt=get_page(); other_page_dir[i]=current_page_dir[i]; other_page_dir[i].frame=npt>>12; copy_page_table(i); } else { other_page_dir[i].zero(); } } other_page_dir[1023].set(npd,0,1);}// gets the page directory entry associated with the virtual address addr.directory_entry& AddressSpace::get_dir_entry(u32 virt) { return current_page_dir[virt>>22];}table_entry* AddressSpace::get_page_table(u32 virt) { u32 offset = virt&0xfff; u32 pde = virt>>22; u32 pte = (virt>>12) & 0x3ff; return page_tables+(pde<<12);}// make sure there's a page table at the relevant address.void ensure_page_table(u32 virt) { directory_entry& entry=get_dir_entry(virt); if(!entry.present) { u32 pt=physmem.get_page(); entry.set_base_address(pt); table_entry*t=get_page_table(virt); memset(t,0,4096); }}// map phys at virt with the relevant protections.void AddressSpace::map(u32 phys,u32 virt,bool user,bool writable) { directory_entry& entry=get_dir_entry(virt); ensure_page_table(virt); table_entry*pt=get_page_table(virt); pt[virt&0xfff].set(phys,user,writable);}u32 AddressSpace::unmap(u32 virt) { table_entry*pt = get_page_table(virt)+(virt&0xfff); u32 frame = pt->frame; pt->present=0; return frame>>12;}struct table_entry{ void zero() { memset(this,0,sizeof(*this)); } void set(u32 frame,bool user,bool writable) { Page p; p.zero(); p.preset=1; p.rw=writable?1:0; p.user=user?1:0; p.frame=frame>>12; *this = p; // we want to set this atomically. } u32 present : 1; // Page present in memory u32 rw : 1; // Read-only if clear, readwrite if set u32 user : 1; // Supervisor level only if clear u32 accessed : 1; // Has the page been accessed since last refresh? u32 dirty : 1; // Has the page been written to since last refresh? u32 unused : 7; // Amalgamation of unused and reserved bits u32 frame : 20; // Frame address (shifted right 12 bits)};typedef struct directory_entry { bool is_present() { return present; } u32 present:1; // whether it is in memory. u32 readwrite:1; // 1 if it's writable. u32 user:1; // 1 if it's a user page, 0 for supervisor. u32 write_through:1; // don't bother u32 cache_disabled:1; // don't bother u32 accessed:1; // whether the 4mb block has been accessed since clearing this flag. u32 dirty:1; // whether it's been written to. u32 superpage:1; // 1 for 4mb, 2 otherwise. u32 global:1; u32 available:3; // must think of something to put here (reference count?) u32 PAT :1; // always 0 atm. u32 reserved:9; // always 0 atm. u32 frame:10; // top 10 bit of address in physical ram. /** * Gets where this points in physical ram */ u32 get_base_address() const { return frame<<22; } /** Sets where this points in physical ram */ void set_base_address(u32 addr) { frame=addr>>22; } void clear() { memset(this,0,sizeof(directory_entry)); } void set(u32 frame,bool user,bool writable) { directory_entry d; d.clear(); d.frame=frame>>22; d.present=1; d.writable=writable?1:0; d.user=user?1:0; *this=d; }};