00001
00002
00003
00004
00005
00006
00007
00008 #ifndef __ia32_mmu_h
00009 #define __ia32_mmu_h
00010
00011 #include <cpu.h>
00012 #include <mmu.h>
00013 #include <utility/string.h>
00014 #include <utility/list.h>
00015 #include __HEADER_MACH(memory_map)
00016
00017 __BEGIN_SYS
00018
00019 class IA32_MMU: public MMU_Common<10, 10, 12>
00020 {
00021 private:
00022 typedef Traits<IA32_MMU> Traits;
00023 static const Type_Id _TYPE = Type<IA32_MMU>::TYPE;
00024
00025 typedef Grouping_List<Frame> List;
00026
00027 static const unsigned int PHY_MEM = Memory_Map<Machine>::PHY_MEM;
00028 static const unsigned int SYS_PT = Memory_Map<Machine>::PHY_MEM;
00029
00030 public:
00031
00032 class IA32_Flags
00033 {
00034 public:
00035 enum {
00036 PRE = 0x001,
00037 RW = 0x002,
00038 USR = 0x004,
00039 PWT = 0x008,
00040 PCD = 0x010,
00041 ACC = 0x020,
00042 DRT = 0x040,
00043 PS = 0x080,
00044 GLB = 0X100,
00045 EX = 0x200,
00046 CT = 0x400,
00047 IO = 0x800,
00048 SYS = (PRE | RW | ACC),
00049 APP = (PRE | RW | ACC | USR),
00050 PCI = (SYS | PCD | IO)
00051 };
00052
00053 public:
00054 IA32_Flags() {}
00055 IA32_Flags(const IA32_Flags & f) : _flags(f._flags) {}
00056 IA32_Flags(unsigned int f) : _flags(f) {}
00057 IA32_Flags(Flags f) : _flags(PRE |
00058 (f & Flags::RW) ? RW : 0 |
00059 (f & Flags::USR) ? USR : 0 |
00060 (f & Flags::CWT) ? PWT : 0 |
00061 (f & Flags::CD) ? PCD : 0 |
00062 (f & Flags::CT) ? CT : 0 |
00063 (f & Flags::IO) ? PCI : 0 ) {}
00064
00065 operator unsigned int() const { return _flags; }
00066
00067 friend Debug & operator << (Debug & db, IA32_Flags f)
00068 { db << (void *)f._flags; return db; }
00069
00070 private:
00071 unsigned int _flags;
00072 };
00073
00074
00075 class Page_Table
00076 {
00077 public:
00078 Page_Table() {}
00079
00080 PT_Entry & operator[](unsigned int i) { return _entry[i]; }
00081
00082 void map(int from, int to, IA32_Flags flags) {
00083 for( ; from <= to; from++)
00084 _entry[from] = alloc() | flags;
00085 }
00086 void map_contiguous(int from, int to, IA32_Flags flags) {
00087 remap(alloc(to - from + 1), from, to, flags);
00088 }
00089 void remap(Phy_Addr addr, int from, int to, IA32_Flags flags) {
00090 addr = align_page(addr);
00091 for( ; from <= to; from++) {
00092 _entry[from] = addr | flags;
00093 addr+= sizeof(Page);
00094 }
00095 }
00096 void unmap(int from, int to) {
00097 for( ; from <= to; from++) {
00098 free(_entry[from]);
00099 _entry[from] = 0;
00100 }
00101 }
00102
00103 private:
00104 PT_Entry _entry[PT_ENTRIES];
00105 };
00106
00107
00108 class Chunk
00109 {
00110 public:
00111 Chunk() {}
00112 Chunk(unsigned int bytes, Flags flags)
00113 : _from(0), _to(pages(bytes)), _pts(page_tables(_to - _from)),
00114 _flags(IA32_Flags(flags)), _pt(calloc(_pts))
00115 {
00116 if(flags & IA32_Flags::CT)
00117 _pt->map_contiguous(_from, _to, _flags);
00118 else
00119 _pt->map(_from, _to, _flags);
00120 }
00121 Chunk(Phy_Addr phy_addr, unsigned int bytes, Flags flags)
00122 : _from(0), _to(pages(bytes)), _pts(page_tables(_to - _from)),
00123 _flags(IA32_Flags(flags)), _pt(calloc(_pts))
00124 {
00125 _pt->remap(phy_addr, _from, _to, flags);
00126 }
00127 ~Chunk() {
00128 if(!(_flags & IA32_Flags::IO))
00129 if(_flags & IA32_Flags::CT)
00130 free((*_pt)[_from], _to - _from);
00131 else
00132 for(unsigned int i = _from; i < _to; i++)
00133 free((*_pt)[i]);
00134 free(_pt, _pts);
00135 }
00136
00137 unsigned int pts() const { return _pts; }
00138 IA32_Flags flags() const { return _flags; }
00139 Page_Table * pt() const { return _pt; }
00140 unsigned int size() const { return (_to - _from) * sizeof(Page); }
00141 Phy_Addr phy_address() const {
00142 return (_flags & IA32_Flags::CT) ? (*_pt)[_from] : Phy_Addr(false);
00143 }
00144
00145 int resize(unsigned int amount) {
00146 if(_flags & IA32_Flags::CT)
00147 return 0;
00148
00149 unsigned int pgs = pages(amount);
00150 if((_pts * PT_ENTRIES - _to - 1) < pgs)
00151 return 0;
00152
00153 _pt->map(_to + 1, _to + 1 + pgs, _flags);
00154 _to += pgs;
00155
00156 return pgs * sizeof(Page);
00157 }
00158
00159 private:
00160 unsigned int _from;
00161 unsigned int _to;
00162 unsigned int _pts;
00163 IA32_Flags _flags;
00164 Page_Table * _pt;
00165 };
00166
00167
00168 typedef Page_Table Page_Directory;
00169
00170
00171 class Directory
00172 {
00173 public:
00174 Directory() : _pd(calloc(1)) {}
00175 Directory(Page_Directory * pd) : _pd(pd) {}
00176 ~Directory() { free(_pd); }
00177
00178 Log_Addr attach(const Chunk & chunk) {
00179 for(unsigned int i = 0; i < PD_ENTRIES; i++)
00180 if(attach(i, chunk.pt(), chunk.pts(), chunk.flags()))
00181 return i << DIRECTORY_SHIFT;
00182 return false;
00183 }
00184 Log_Addr attach(const Chunk & chunk, Log_Addr addr) {
00185 unsigned int from = directory(addr);
00186 if(!attach(from, chunk.pt(), chunk.pts(), chunk.flags()))
00187 return Log_Addr(false);
00188
00189 return from << DIRECTORY_SHIFT;
00190 }
00191 void detach(const Chunk & chunk) {
00192 for(unsigned int i = 0; i < PD_ENTRIES; i++)
00193 if(indexes((*_pd)[i]) == indexes(chunk.pt())) {
00194 detach(i, chunk.pt(), chunk.pts());
00195 return;
00196 }
00197 db<IA32_MMU>(WRN) << "IA32_MMU::Directory::detach(pt="
00198 << chunk.pt() << ") failed!\n";
00199 }
00200 void detach(const Chunk & chunk, Log_Addr addr) {
00201 unsigned int from = directory(addr);
00202 if(indexes((*_pd)[from]) != indexes(chunk.pt())) {
00203 db<IA32_MMU>(WRN) << "IA32_MMU::Directory::detach(pt="
00204 << chunk.pt() << ",addr="
00205 << addr << ") failed!\n";
00206 return;
00207 }
00208 detach(from, chunk.pt(), chunk.pts());
00209 }
00210
00211 Phy_Addr physical(Log_Addr addr) {
00212 Page_Table * pt = (Page_Table *)(void *)(*_pd)[directory(addr)];
00213 return (*pt)[page(addr)] | offset(addr);
00214 }
00215
00216 private:
00217 bool attach(unsigned int from, const Page_Table * pt,
00218 unsigned int n, IA32_Flags flags) {
00219 for(unsigned int i = from; i < from + n; i++)
00220 if((*_pd)[i])
00221 return false;
00222 for(unsigned int i = from; i < from + n; i++)
00223 (*_pd)[i] = Phy_Addr(pt + (i * PT_ENTRIES)) | flags;
00224
00225 return true;
00226 }
00227 void detach(unsigned int from, const Page_Table * pt, unsigned int n) {
00228 for(unsigned int i = from; i < from + n; i++)
00229 (*_pd)[i] = 0;
00230 }
00231
00232 private:
00233 Page_Directory * _pd;
00234 };
00235
00236 public:
00237 IA32_MMU() {}
00238 ~IA32_MMU() {}
00239
00240 static void flush_tlb() {
00241 db<IA32_MMU>(TRC) << "IA32_MMU::flush_tlb()\n";
00242
00243 ASMV("movl %cr3,%eax");
00244 ASMV("movl %eax,%cr3");
00245 }
00246 static void flush_tlb(Log_Addr addr) {
00247 db<IA32_MMU>(TRC) << "IA32_MMU::flush_tlb(" << addr << ")\n";
00248 ASMV("invlpg %0" : : "m"(addr));
00249 }
00250
00251 static Phy_Addr alloc(unsigned int frames = 1) {
00252 Phy_Addr phy(false);
00253 if(frames) {
00254 List::Element * e = _free.search_decrementing(frames);
00255 if(e)
00256 phy = e->object() + e->size();
00257 else
00258 db<IA32_MMU>(WRN) << "IA32_MMU::alloc() failed!\n";
00259 }
00260 db<IA32_MMU>(TRC) << "IA32_MMU::alloc(frames=" << frames << ") => " << (void *)phy << "\n";
00261 return phy;
00262 }
00263 static Phy_Addr calloc(unsigned int frames = 1) {
00264 Phy_Addr phy = alloc(frames);
00265 memset(phy2log(phy), sizeof(Frame) * frames, 0);
00266 return phy;
00267 }
00268 static void free(Phy_Addr frame, int n = 1) {
00269 db<IA32_MMU>(TRC) << "IA32_MMU::free(frame=" << (void *)frame
00270 << ",n=" << n << ")\n";
00271
00272 if(frame && n) {
00273 List::Element * e = new (phy2log(frame)) List::Element(frame, n);
00274 List::Element * m1, * m2;
00275 _free.insert_merging(e, &m1, &m2);
00276 }
00277 }
00278
00279 static Page_Directory * volatile current() {
00280 return reinterpret_cast<Page_Directory * volatile>(CPU::pdp());
00281 }
00282
00283 static Phy_Addr physical(Log_Addr addr) {
00284 Page_Directory * pd = current();
00285 Page_Table * pt = (*pd)[directory(addr)];
00286 return (*pt)[page(addr)] | offset(addr);
00287 }
00288
00289 static int init(System_Info * si);
00290
00291 private:
00292 static Log_Addr phy2log(Phy_Addr log) { return log | PHY_MEM; }
00293
00294 private:
00295 static List _free;
00296 };
00297
00298 typedef IA32_MMU MMU;
00299
00300 __END_SYS
00301
00302 #endif